diff --git a/game/config.ini b/game/config.ini index 9f70f30d4..cbe0029eb 100644 --- a/game/config.ini +++ b/game/config.ini @@ -198,3 +198,7 @@ Effect=0 T1=1 T2=2 T3=3 + +[KeyBindings] +PianoKeysLow=92,97,122,115,120,100,99,118,103,98,104,110,109,107,44,108,46,59,47 +PianoKeysHigh=49,113,50,119,51,101,114,53,116,54,121,117,56,105,57,111,48,112,91,61,93 diff --git a/game/languages/English.ini b/game/languages/English.ini index b10ae0f76..12ba09c72 100644 --- a/game/languages/English.ini +++ b/game/languages/English.ini @@ -2108,6 +2108,7 @@ CTRL_SHIFT_4 = Paste LYRICS+NOTES over each of the next 4 lines CTRL_SHIFT_ALT_4 = Paste LYRICS+NOTES+LINE-END 4 times CTRL_SHIFT_5 = Paste LYRICS+NOTES over each of the next 5 lines CTRL_SHIFT_ALT_5 = Paste LYRICS+NOTES+LINE-END 5 times +F6 = Toggle Piano edit mode ;-------------------------------------------------------; ; ID_070: UScreenOptions ; ;-------------------------------------------------------; diff --git a/src/base/UCommon.pas b/src/base/UCommon.pas index 03f2b056e..478b43e56 100644 --- a/src/base/UCommon.pas +++ b/src/base/UCommon.pas @@ -69,11 +69,15 @@ interface function SplitString(const Str: string; MaxCount: integer = 0; Separators: TSysCharSet = SepWhitespace; RemoveEmpty: boolean = true): TStringDynArray; function StringInArray(const Value: string; Strings: array of string): Boolean; +function SplitStringToIntArray(const S: string): TArray; function StringDeleteFromArray(var InArray: TIntegerDynArray; const InIndex: integer): Boolean; overload; function StringDeleteFromArray(var InStrings: TStringDynArray; const InIndex: integer): Boolean; overload; function StringDeleteFromArray(var InStrings: TUTF8StringDynArray; const InIndex: integer): Boolean; overload; +type + TPianoKeyArray = array of Cardinal; + type TRGB = record R: single; @@ -134,6 +138,22 @@ implementation UMain, UUnicodeUtils; +function SplitStringToIntArray(const S: string): TArray; +var + StrList: TStringList; + I: Integer; +begin + StrList := TStringList.Create; + try + StrList.CommaText := S; + SetLength(Result, StrList.Count); + for I := 0 to StrList.Count - 1 do + Result[I] := StrToInt(StrList[I]); + finally + StrList.Free; + end; +end; + function StringInArray(const Value: string; Strings: array of string): Boolean; var I: Integer; begin diff --git a/src/base/UIni.pas b/src/base/UIni.pas index 8bc4f5044..966d33e94 100644 --- a/src/base/UIni.pas +++ b/src/base/UIni.pas @@ -268,6 +268,8 @@ TIni = class JukeboxNextLineOtherOColorG: integer; JukeboxNextLineOtherOColorB: integer; + PianoKeysLow: TPianoKeyArray; + PianoKeysHigh: TPianoKeyArray; // default encoding for texts (lyrics, song-name, ...) DefaultEncoding: TEncoding; @@ -1385,6 +1387,10 @@ procedure TIni.Load(); IShowWebScore: array of UTF8String; HexColor: string; Col: TRGB; + KeysLow: string; + KeysHigh: string; + ReadPianoKeysLow: TPianoKeyArray; + ReadPianoKeysHigh: TPianoKeyArray; begin LoadFontFamilyNames; ILyricsFont := FontFamilyNames; @@ -1715,6 +1721,20 @@ procedure TIni.Load(); Ini.JukeboxNextLineOtherOColorB := Round(Col.B); end; + KeysLow := IniFile.ReadString('KeyBindings', 'PianoKeysLow', ''); + KeysHigh := IniFile.ReadString('KeyBindings', 'PianoKeysHigh', ''); + PianoKeysLow := [60, 97, 121, 115, 120, 100, 99, 118, 103, 98, 104, 110, 109, 107, 44, 108, 46, 246, 45]; + PianoKeysHigh := [49, 113, 50, 119, 51, 101, 114, 53, 116, 54, 122, 117, 56, 105, 57, 111, 48, 112, 252, 96, 43]; + ReadPianoKeysLow := SplitStringToIntArray(KeysLow); + ReadPianoKeysHigh := SplitStringToIntArray(KeysHigh); + Log.LogWarn('Got ' + IntToStr(Length(ReadPianoKeysLow)) + ' Low keys', 'ScreenEditSub'); + Log.LogWarn('Got ' + IntToStr(Length(ReadPianoKeysHigh)) + ' high keys', 'ScreenEditSub'); + + if Length(ReadPianoKeysLow) = 19 then + PianoKeysLow := ReadPianoKeysLow; + if Length(ReadPianoKeysHigh) = 21 then + PianoKeysHigh := ReadPianoKeysHigh; + LoadPaths(IniFile); TranslateOptionValues; diff --git a/src/screens/UScreenEditSub.pas b/src/screens/UScreenEditSub.pas index 408b23e38..f755404aa 100644 --- a/src/screens/UScreenEditSub.pas +++ b/src/screens/UScreenEditSub.pas @@ -146,6 +146,10 @@ TScreenEditSub = class(TMenu) P1EditMode: boolean; P2EditMode: boolean; BPMEditMode: boolean; + PianoEditMode: boolean; + + PianoKeysLow: TPianoKeyArray; + PianoKeysHigh: TPianoKeyArray; // to interactive divide note LastClickTime: Integer; @@ -389,6 +393,7 @@ TScreenEditSub = class(TMenu) function ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean; override; function ParseInputEditText(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean; function ParseInputEditBPM(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean; + function ParseInputEditPiano(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean; function ParseMouse(MouseButton: Integer; BtnDown: boolean; X, Y: Integer): boolean; override; function Draw: boolean; override; procedure OnHide; override; @@ -472,6 +477,24 @@ function TScreenEditSub.ParseInput(PressedKey: cardinal; CharCode: UCS4Char; Pre begin Result := true; + SDL_ModState := SDL_GetModState and (KMOD_LSHIFT + KMOD_RSHIFT + + KMOD_LCTRL + KMOD_RCTRL + KMOD_LALT + KMOD_RALT {+ KMOD_CAPS}); + + if PianoEditMode then + begin + Result := ParseInputEditPiano(PressedKey, CharCode, PressedDown); + if (Result = true) then + begin + SDL_ModState := KMOD_LSHIFT or KMOD_LCTRL; + PressedKey := SDLK_SPACE; + end; + if (PressedKey = SDLK_RETURN) then + begin + PressedKey := SDLK_P; + end; + Result := true; + end; + if TextEditMode or TitleEditMode or ArtistEditMode or @@ -489,12 +512,9 @@ function TScreenEditSub.ParseInput(PressedKey: cardinal; CharCode: UCS4Char; Pre begin Result := ParseInputEditBPM(PressedKey, CharCode, PressedDown) end - else + else begin - SDL_ModState := SDL_GetModState and (KMOD_LSHIFT + KMOD_RSHIFT - + KMOD_LCTRL + KMOD_RCTRL + KMOD_LALT + KMOD_RALT {+ KMOD_CAPS}); - if (PressedDown) then // Key Down begin // check normal keys @@ -1423,7 +1443,7 @@ function TScreenEditSub.ParseInput(PressedKey: cardinal; CharCode: UCS4Char; Pre ShowInteractiveBackground; end; - SDLK_SLASH, SDLK_HASH: + SDLK_SLASH, SDLK_HASH, SDLK_KP_DIVIDE: begin CopyToUndo; if SDL_ModState = 0 then @@ -1484,6 +1504,12 @@ function TScreenEditSub.ParseInput(PressedKey: cardinal; CharCode: UCS4Char; Pre StartTextInput; end; + SDLK_F6: + begin + // Enter Piano Edit Mode + PianoEditMode := true; + end; + SDLK_SPACE: begin if (SDL_ModState = 0) or (SDL_ModState = KMOD_LSHIFT or KMOD_LCTRL) then @@ -2146,7 +2172,7 @@ function TScreenEditSub.ParseInput(PressedKey: cardinal; CharCode: UCS4Char; Pre end; end; // case - end; + end; end; // if end; @@ -2416,7 +2442,7 @@ function TScreenEditSub.ParseInputEditText(PressedKey: cardinal; CharCode: UCS4C end; end; end; - SDLK_SLASH: + SDLK_SLASH, SDLK_KP_DIVIDE: begin CopyToUndo; if SDL_ModState = KMOD_LCTRL then @@ -2543,6 +2569,80 @@ function TScreenEditSub.ParseInputEditBPM(PressedKey: cardinal; CharCode: UCS4Ch end; //if (PressedDown) end; +function TScreenEditSub.ParseInputEditPiano(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean; +var + SDL_ModState: word; + Shift: Integer; + NewNote: Integer; + i: Integer; +begin + // used when in Piano Edit Mode + Result := true; + NewNote := -1000; + SDL_ModState := SDL_GetModState and (KMOD_LSHIFT + KMOD_RSHIFT + + KMOD_LCTRL + KMOD_RCTRL + KMOD_LALT + KMOD_RALT {+ KMOD_CAPS}); + + Shift := 0; + if SDL_ModState = KMOD_LSHIFT then + begin + Shift := 12; + end; + + + if PressedDown then + begin + // check special keys + case PressedKey of + SDLK_ESCAPE, SDLK_F6: + begin + PianoEditMode := false; + end; + end; + if PianoEditMode = true then + begin + for i := Low(PianoKeysLow) to High(PianoKeysLow) do + begin + if PressedKey = PianoKeysLow[i] then + begin + NewNote := i - 7 + Shift; // Adjusted index to match existing logic + Break; + end; + end; + if NewNote = -1000 then // If not found in PianoKeysLow, check PianoKeysHigh + begin + for i := Low(PianoKeysHigh) to High(PianoKeysHigh) do + begin + if PressedKey = PianoKeysHigh[i] then + begin + NewNote := i + 6 + Shift; // Adjusted index to match existing logic + Break; + end; + end; + end; + + if NewNote <> -1000 then + begin + Tracks[CurrentTrack].Lines[Tracks[CurrentTrack].CurrentLine].Notes[CurrentNote[CurrentTrack]].Tone := NewNote; + // Play Midi + PlaySentenceMidi := false; + PlayVideo := false; + midinotefound := false; + PlayOne := true; + PlayOneMidi := true; + StopVideoPreview(); + {$IFDEF UseMIDIPort} MidiTime := USTime.GetTime; + MidiStart := GetTimeFromBeat(Tracks[CurrentTrack].Lines[Tracks[CurrentTrack].CurrentLine].Notes[CurrentNote[CurrentTrack]].StartBeat); + MidiStop := GetTimeFromBeat( + Tracks[CurrentTrack].Lines[Tracks[CurrentTrack].CurrentLine].Notes[CurrentNote[CurrentTrack]].StartBeat + + Tracks[CurrentTrack].Lines[Tracks[CurrentTrack].CurrentLine].Notes[CurrentNote[CurrentTrack]].Duration); {$ENDIF} + LastClick := -100; + end + else + Result := False; + end; //if (PianoEditMode) + end; //if (PressedDown) +end; + function TScreenEditSub.ParseMouse(MouseButton: Integer; BtnDown: boolean; X, Y: Integer): boolean; var nBut: Integer; @@ -4589,6 +4689,11 @@ constructor TScreenEditSub.Create; // in notes place -> for move notes by mouse //NotesBackgroundId := AddSelectSlide(Theme.EditSub.NotesBackground, i, Empty); + + // Initialize Piano Keys to default values + PianoKeysLow := Ini.PianoKeysLow; + PianoKeysHigh := Ini.PianoKeysHigh; + end; procedure TScreenEditSub.OnShow;