@@ -359,6 +359,11 @@ TScreenEditSub = class(TMenu)
359359
360360 // medley
361361 MedleyNotes: TMedleyNotes;
362+ PendingSaveRelative: boolean;
363+ TimingErrorTrack: Integer;
364+ TimingErrorLine: Integer;
365+ TimingErrorBeat: Integer;
366+ TimingErrorValid: boolean;
362367
363368 procedure ChangeBPM (newBPM: real);
364369 procedure ResetBeatTracking ;
@@ -435,6 +440,9 @@ TScreenEditSub = class(TMenu)
435440 function DuetMoveLine : boolean;
436441 procedure CopyLine (SrcTrack, SrcLine, DstTrack, DstLine: Integer);
437442 function CheckTimingSyntaxErrors (out ErrorMessages: UTF8String): boolean;
443+ procedure GoToLineAndBeat (const TrackIndex, LineIndex, Beat: Integer);
444+ procedure GoToFirstTimingError ;
445+ function SaveSongToFile (const SaveRelative: boolean): boolean;
438446 procedure Refresh ;
439447 procedure CopyToUndo ; // copy current lines, mouse position and headers
440448 procedure CopyFromUndo ; // undo last lines, mouse position and headers
@@ -520,6 +528,20 @@ procedure OnSaveEncodingError(Value: boolean; Data: Pointer);
520528 ScreenPopupError.ShowPopup(Language.Translate(' ERROR_SAVE_FILE_FAILED' ));
521529end ;
522530
531+ procedure OnSaveTimingErrorChoice (Value : integer; Data: Pointer);
532+ var
533+ EditScreen: TScreenEditSub;
534+ begin
535+ if Data = nil then
536+ Exit;
537+
538+ EditScreen := TScreenEditSub(Data);
539+ case Value of
540+ 0 : EditScreen.SaveSongToFile(EditScreen.PendingSaveRelative);
541+ 1 : EditScreen.GoToFirstTimingError;
542+ end ;
543+ end ;
544+
523545procedure OnExit (Value : boolean; Data: Pointer);
524546begin
525547 Display.CheckOK := Value ;
@@ -640,81 +662,26 @@ function TScreenEditSub.ParseInput(PressedKey: cardinal; CharCode: UCS4Char; Pre
640662 // SDLK_S: HandleSaveSong
641663procedure TScreenEditSub.HandleSaveSong (SDL_ModState: word);
642664var
643- SResult: TSaveSongResult;
644665 TimingErrors: UTF8String;
666+ SaveRelative: boolean;
645667begin
646- // run timing checks before saving and abort on serious problems
668+ SaveRelative := (SDL_ModState = KMOD_LSHIFT);
669+ PendingSaveRelative := SaveRelative;
670+
647671 if CheckTimingSyntaxErrors(TimingErrors) then
648672 begin
649673 if TimingErrors <> ' ' then
650- ScreenPopupError.ShowPopup(TimingErrors);
674+ ScreenPopupError.ShowPopup(
675+ TimingErrors,
676+ [' Save anyways' , ' Go to Error' , ' Cancel' ],
677+ OnSaveTimingErrorChoice,
678+ Self,
679+ 1 ,
680+ 2 );
651681 Exit;
652682 end ;
653683
654- // handle medley tags first
655- if CurrentSong.isDuet then
656- begin
657- CurrentSong.Medley.Source := msNone;
658- end
659- else if (MedleyNotes.isStart and MedleyNotes.isEnd and MedleyNotes.isCustom) and
660- (MedleyNotes.start.line < MedleyNotes.end_.line) and
661- (Length(CurrentSong.Tracks[CurrentTrack].Lines)> MedleyNotes.end_.line) and
662- (Length(CurrentSong.Tracks[CurrentTrack].Lines[MedleyNotes.end_.line].Notes) > MedleyNotes.end_.note) and
663- (Length(CurrentSong.Tracks[CurrentTrack].Lines[MedleyNotes.start.line].Notes) > MedleyNotes.start.note) then
664- begin
665- CurrentSong.Medley.Source := msTag;
666- CurrentSong.Medley.StartBeat := CurrentSong.Tracks[CurrentTrack].Lines[MedleyNotes.start.line].Notes[MedleyNotes.start.note].StartBeat;
667- CurrentSong.Medley.EndBeat := CurrentSong.Tracks[CurrentTrack].Lines[MedleyNotes.end_.line].Notes[MedleyNotes.end_.note].StartBeat +
668- CurrentSong.Tracks[CurrentTrack].Lines[MedleyNotes.end_.line].Notes[MedleyNotes.end_.note].Duration;
669- CurrentSong.Medley.FadeIn_time := DEFAULT_FADE_IN_TIME;
670- CurrentSong.Medley.FadeOut_time := DEFAULT_FADE_OUT_TIME;
671- end
672- else if MedleyNotes.isCustom then
673- begin
674- CurrentSong.Medley.Source := msNone;
675- CurrentSong.Medley.StartBeat := 0 ;
676- CurrentSong.Medley.EndBeat := 0 ;
677- end ;
678-
679- // Save Song (SHIFT = relative)
680- if SDL_ModState = KMOD_LSHIFT then
681- begin
682- if (CurrentSong.isDuet) then
683- begin
684- ScreenPopupError.ShowPopup(Language.Translate(' EDIT_INFO_DUET_RELATIVE_UNSUPPORTED' ));
685- Exit;
686- end ;
687-
688- if (CurrentSong.Medley.Source = msTag) then
689- begin
690- ScreenPopupError.ShowPopup(Language.Translate(' EDIT_INFO_MEDLEY_RELATIVE_UNSUPPORTED' ) + ' ' + Language.Translate(' EDIT_INFO_MEDLEY_DELETED' ));
691- end ;
692-
693- CurrentSong.Medley.Source := msNone;
694- CurrentSong.Relative := true;
695- SResult := SaveSong(CurrentSong, CurrentSong.Tracks, CurrentSong.Path.Append(CurrentSong.FileName), CurrentSong.Relative); // save with relative timings
696- end else
697- begin
698- CurrentSong.Relative := false;
699- SResult := SaveSong(CurrentSong, CurrentSong.Tracks, CurrentSong.Path.Append(CurrentSong.FileName), CurrentSong.Relative); // save with absolute timings
700- end ;
701-
702- if (SResult = ssrOK) then // saving was successful
703- begin
704- Text[TextInfo].Text := Language.Translate(' INFO_FILE_SAVED' );
705- SetLength(UndoLines, 0 , High(CurrentSong.Tracks)); // clear undo lines
706- SetLength(UndoStateNote, 0 , Length(CurrentSong.Tracks)); // clear undo CurrentNote[CurrentTrack] state
707- SetLength(Undoheader, 0 ); // clear undo headers
708- CurrentUndoLines := 0 ;
709- // if not CheckSong then
710- // ScreenPopupError.ShowPopup(Language.Translate(''));
711-
712- // CatSongs.Song[SongIndex] := CurrentSong;
713- end
714- else // saving was unsuccessful
715- begin
716- ScreenPopupError.ShowPopup(Language.Translate(' ERROR_SAVE_FILE_FAILED' ));
717- end ;
684+ SaveSongToFile(SaveRelative);
718685end ;
719686
720687
@@ -1131,7 +1098,11 @@ procedure TScreenEditSub.HandleVideo(SDL_ModState: word);
11311098 end ;
11321099 if (SDL_ModState = KMOD_LALT) then
11331100 begin
1101+ { $IFDEF UseMIDIPort}
11341102 PlaySentenceMidi := true;
1103+ { $ELSE}
1104+ PlaySentenceMidi := false;
1105+ { $ENDIF}
11351106 ConfigureMidiPlayback(AudioPlayback.Position, PlayStopTime);
11361107 end ;
11371108 PlaySentence := true;
@@ -1925,7 +1896,11 @@ procedure TScreenEditSub.ToggleTextEditMode(SDL_ModState: word);
19251896 begin
19261897 CurrentSong.Tracks[CurrentTrack].Lines[CurrentSong.Tracks[CurrentTrack].CurrentLine].Notes[CurrentNote[CurrentTrack]].Color := 1 ;
19271898 CurrentNote[CurrentTrack] := 0 ;
1899+ { $IFDEF UseMIDIPort}
19281900 PlaySentenceMidi := true;
1901+ { $ELSE}
1902+ PlaySentenceMidi := false;
1903+ { $ENDIF}
19291904 PlayVideo := false;
19301905 StopVideoPreview;
19311906 LastClick := -100 ;
@@ -1946,7 +1921,11 @@ procedure TScreenEditSub.ToggleTextEditMode(SDL_ModState: word);
19461921 begin
19471922 CurrentSong.Tracks[CurrentTrack].Lines[CurrentSong.Tracks[CurrentTrack].CurrentLine].Notes[CurrentNote[CurrentTrack]].Color := 1 ;
19481923 CurrentNote[CurrentTrack] := 0 ;
1924+ { $IFDEF UseMIDIPort}
19491925 PlaySentenceMidi := true;
1926+ { $ELSE}
1927+ PlaySentenceMidi := false;
1928+ { $ENDIF}
19501929 PlayVideo := false;
19511930 StopVideoPreview;
19521931 PlaySentence := true;
@@ -4997,12 +4976,27 @@ function TScreenEditSub.CheckTimingSyntaxErrors(out ErrorMessages: UTF8String):
49974976 procedure AppendMsg (const Msg: UTF8String);
49984977 begin
49994978 if Messages <> ' ' then
5000- Messages := Messages + ' ' + Msg
4979+ Messages := Messages + ' \n ' + Msg
50014980 else
50024981 Messages := Msg;
50034982 end ;
4983+
4984+ procedure RememberFirstError (const TrackIndex, LineIndex, Beat: Integer);
4985+ begin
4986+ if TimingErrorValid then
4987+ Exit;
4988+
4989+ TimingErrorValid := true;
4990+ TimingErrorTrack := TrackIndex;
4991+ TimingErrorLine := LineIndex;
4992+ TimingErrorBeat := Beat;
4993+ end ;
50044994begin
50054995 Messages := ' ' ;
4996+ TimingErrorValid := false;
4997+ TimingErrorTrack := 0 ;
4998+ TimingErrorLine := 0 ;
4999+ TimingErrorBeat := 0 ;
50065000
50075001 for TrackIndex := 0 to High(CurrentSong.Tracks) do
50085002 begin
@@ -5033,6 +5027,7 @@ function TScreenEditSub.CheckTimingSyntaxErrors(out ErrorMessages: UTF8String):
50335027 // any later note starting before previous note ended is an overlap
50345028 if NoteStart < PrevNoteEnd then
50355029 begin
5030+ RememberFirstError(TrackIndex, LineIndex, NoteStart);
50365031 AppendMsg(Format(Language.Translate(' EDIT_INFO_TIMING_NOTE_OVERLAP' ),
50375032 [TrackIndex + 1 , LineIndex + 1 , NoteIndex + 1 ,
50385033 NoteStart, NoteEnd - 1 , PrevNoteEnd - 1 ]));
@@ -5052,6 +5047,7 @@ function TScreenEditSub.CheckTimingSyntaxErrors(out ErrorMessages: UTF8String):
50525047 // forbidden: NoteStart < LineEndBeat < NoteEnd
50535048 if (NoteStart < LineEndBeat) and (LineEndBeat < NoteEnd) then
50545049 begin
5050+ RememberFirstError(TrackIndex, LineIndex, LineEndBeat);
50555051 AppendMsg(Format(Language.Translate(' EDIT_INFO_TIMING_LINEBREAK_OVERLAP' ),
50565052 [TrackIndex + 1 , LineIndex + 1 , LineEndBeat,
50575053 NoteIndex + 1 , NoteStart, NoteEnd - 1 ]));
@@ -5082,6 +5078,7 @@ function TScreenEditSub.CheckTimingSyntaxErrors(out ErrorMessages: UTF8String):
50825078
50835079 if (NoteStart < LineEndBeat) and (LineEndBeat < NoteEnd) then
50845080 begin
5081+ RememberFirstError(TrackIndex, LineIndex, LineEndBeat);
50855082 AppendMsg(Format(Language.Translate(' EDIT_INFO_TIMING_LINEBREAK_OVERLAP' ),
50865083 [TrackIndex + 1 , LineIndex + 1 , LineEndBeat,
50875084 NoteIndex + 1 , NoteStart, NoteEnd - 1 ]));
@@ -5093,7 +5090,7 @@ function TScreenEditSub.CheckTimingSyntaxErrors(out ErrorMessages: UTF8String):
50935090
50945091 if Messages <> ' ' then
50955092 begin
5096- ErrorMessages := Language.Translate(' EDIT_INFO_SYNTAX_ERRORS_TIMING_HEADER' ) + ' ' + Messages;
5093+ ErrorMessages := Language.Translate(' EDIT_INFO_SYNTAX_ERRORS_TIMING_HEADER' ) + ' \n\n ' + Messages;
50975094 Result := true;
50985095 end
50995096 else
@@ -5103,6 +5100,114 @@ function TScreenEditSub.CheckTimingSyntaxErrors(out ErrorMessages: UTF8String):
51035100 end ;
51045101end ;
51055102
5103+ procedure TScreenEditSub.GoToLineAndBeat (const TrackIndex, LineIndex, Beat: Integer);
5104+ var
5105+ NoteIndex: Integer;
5106+ begin
5107+ if (TrackIndex < 0 ) or (TrackIndex > High(CurrentSong.Tracks)) then
5108+ Exit;
5109+ if (LineIndex < 0 ) or (LineIndex > CurrentSong.Tracks[TrackIndex].High) then
5110+ Exit;
5111+ if CurrentSong.Tracks[TrackIndex].Lines[LineIndex].HighNote < 0 then
5112+ Exit;
5113+
5114+ AudioPlayback.Stop;
5115+ PlaySentence := false;
5116+ PlaySentenceMidi := false;
5117+ PlayOne := false;
5118+ PlayVideo := false;
5119+ StopVideoPreview;
5120+ { $IFDEF UseMIDIPort}
5121+ StopMidi;
5122+ { $ENDIF}
5123+
5124+ CurrentSong.Tracks[CurrentTrack].Lines[CurrentSong.Tracks[CurrentTrack].CurrentLine].Notes[CurrentNote[CurrentTrack]].Color := 1 ;
5125+ CurrentTrack := TrackIndex;
5126+ CurrentSong.Tracks[CurrentTrack].CurrentLine := LineIndex;
5127+ CurrentNote[CurrentTrack] := 0 ;
5128+
5129+ for NoteIndex := 0 to CurrentSong.Tracks[CurrentTrack].Lines[LineIndex].HighNote do
5130+ begin
5131+ CurrentNote[CurrentTrack] := NoteIndex;
5132+ if CurrentSong.Tracks[CurrentTrack].Lines[LineIndex].Notes[NoteIndex].EndBeat >= Beat then
5133+ Break;
5134+ end ;
5135+
5136+ UpdateLineBaseNote(CurrentTrack, CurrentSong.Tracks[CurrentTrack].CurrentLine);
5137+ CurrentSong.Tracks[CurrentTrack].Lines[CurrentSong.Tracks[CurrentTrack].CurrentLine].Notes[CurrentNote[CurrentTrack]].Color := P1_INVERTED;
5138+ EditorLyrics[CurrentTrack].AddLine(CurrentTrack, CurrentSong.Tracks[CurrentTrack].CurrentLine);
5139+ EditorLyrics[CurrentTrack].Selected := CurrentNote[CurrentTrack];
5140+ ShowInteractiveBackground;
5141+ GoldenRec.KillAll;
5142+ Text[TextInfo].Text := Language.Translate(' EDIT_INFO_CURRENT_BEAT' ) + ' ' + IntToStr(Beat);
5143+ end ;
5144+
5145+ procedure TScreenEditSub.GoToFirstTimingError ;
5146+ begin
5147+ if TimingErrorValid then
5148+ GoToLineAndBeat(TimingErrorTrack, TimingErrorLine, TimingErrorBeat);
5149+ end ;
5150+
5151+ function TScreenEditSub.SaveSongToFile (const SaveRelative: boolean): boolean;
5152+ var
5153+ SResult: TSaveSongResult;
5154+ begin
5155+ if CurrentSong.isDuet then
5156+ begin
5157+ CurrentSong.Medley.Source := msNone;
5158+ end
5159+ else if (MedleyNotes.isStart and MedleyNotes.isEnd and MedleyNotes.isCustom) and
5160+ (MedleyNotes.start.line < MedleyNotes.end_.line) and
5161+ (Length(CurrentSong.Tracks[CurrentTrack].Lines) > MedleyNotes.end_.line) and
5162+ (Length(CurrentSong.Tracks[CurrentTrack].Lines[MedleyNotes.end_.line].Notes) > MedleyNotes.end_.note) and
5163+ (Length(CurrentSong.Tracks[CurrentTrack].Lines[MedleyNotes.start.line].Notes) > MedleyNotes.start.note) then
5164+ begin
5165+ CurrentSong.Medley.Source := msTag;
5166+ CurrentSong.Medley.StartBeat := CurrentSong.Tracks[CurrentTrack].Lines[MedleyNotes.start.line].Notes[MedleyNotes.start.note].StartBeat;
5167+ CurrentSong.Medley.EndBeat := CurrentSong.Tracks[CurrentTrack].Lines[MedleyNotes.end_.line].Notes[MedleyNotes.end_.note].StartBeat +
5168+ CurrentSong.Tracks[CurrentTrack].Lines[MedleyNotes.end_.line].Notes[MedleyNotes.end_.note].Duration;
5169+ CurrentSong.Medley.FadeIn_time := DEFAULT_FADE_IN_TIME;
5170+ CurrentSong.Medley.FadeOut_time := DEFAULT_FADE_OUT_TIME;
5171+ end
5172+ else if MedleyNotes.isCustom then
5173+ begin
5174+ CurrentSong.Medley.Source := msNone;
5175+ CurrentSong.Medley.StartBeat := 0 ;
5176+ CurrentSong.Medley.EndBeat := 0 ;
5177+ end ;
5178+
5179+ if SaveRelative then
5180+ begin
5181+ if CurrentSong.isDuet then
5182+ begin
5183+ ScreenPopupError.ShowPopup(Language.Translate(' EDIT_INFO_DUET_RELATIVE_UNSUPPORTED' ));
5184+ Exit(false);
5185+ end ;
5186+
5187+ if CurrentSong.Medley.Source = msTag then
5188+ ScreenPopupError.ShowPopup(Language.Translate(' EDIT_INFO_MEDLEY_RELATIVE_UNSUPPORTED' ) + ' ' + Language.Translate(' EDIT_INFO_MEDLEY_DELETED' ));
5189+
5190+ CurrentSong.Medley.Source := msNone;
5191+ CurrentSong.Relative := true;
5192+ end
5193+ else
5194+ CurrentSong.Relative := false;
5195+
5196+ SResult := SaveSong(CurrentSong, CurrentSong.Tracks, CurrentSong.Path.Append(CurrentSong.FileName), CurrentSong.Relative);
5197+ Result := (SResult = ssrOK);
5198+
5199+ if Result then
5200+ begin
5201+ Text[TextInfo].Text := Language.Translate(' INFO_FILE_SAVED' );
5202+ SetLength(UndoLines, 0 , High(CurrentSong.Tracks));
5203+ SetLength(UndoStateNote, 0 , Length(CurrentSong.Tracks));
5204+ SetLength(Undoheader, 0 );
5205+ CurrentUndoLines := 0 ;
5206+ end ;
5207+ if not Result then
5208+ ScreenPopupError.ShowPopup(Language.Translate(' ERROR_SAVE_FILE_FAILED' ));
5209+ end ;
5210+
51065211constructor TScreenEditSub.Create;
51075212begin
51085213 inherited Create;
@@ -5112,6 +5217,8 @@ constructor TScreenEditSub.Create;
51125217 fCurrentVideo := nil ;
51135218
51145219 ResetBeatTracking;
5220+ PendingSaveRelative := false;
5221+ TimingErrorValid := false;
51155222
51165223 EditorLyrics[0 ] := TEditorLyrics.Create;
51175224 EditorLyrics[1 ] := TEditorLyrics.Create;
0 commit comments