From c5aa56749ebafb59fd1dda82549b1868d3cf870c Mon Sep 17 00:00:00 2001 From: Ambrose Bonnaire-Sergeant Date: Thu, 23 Feb 2023 23:58:13 -0500 Subject: [PATCH 1/8] ensure BPM is set on tempo points before moving them --- Breeder/BR_Tempo.cpp | 49 +++++++++++++++++++++++++++++++++++++------- Breeder/BR_Tempo.h | 6 ++++++ 2 files changed, 48 insertions(+), 7 deletions(-) diff --git a/Breeder/BR_Tempo.cpp b/Breeder/BR_Tempo.cpp index 9a543527b..53220a80f 100644 --- a/Breeder/BR_Tempo.cpp +++ b/Breeder/BR_Tempo.cpp @@ -284,7 +284,8 @@ static bool MoveGridInit (COMMAND_T* ct, bool init) if (init) { const int projgridframe = ConfigVar("projgridframe").value_or(0); - if (((int)ct->user == 1 || (int)ct->user == 2) && projgridframe&1) // frames grid line spacing + MoveGridToMouseCommand cmd = (MoveGridToMouseCommand)ct->user; + if ((cmd == MOVE_GRID_TO_MOUSE || cmd == MOVE_M_GRID_TO_MOUSE) && projgridframe&1) // frames grid line spacing { initSuccessful = false; static bool s_warnUser = true; @@ -332,11 +333,33 @@ static HCURSOR MoveGridCursor (COMMAND_T* ct, int window) return NULL; } +/** + * Explicitly set a tempo envelope point's tempo to its calculated tempo. + * + * Must call this on a point before creating a BR_Envelope that will change its bpm, + * otherwise tempo updates via BR_Envelope will be ignored. + * + * @param id The tempo envelope point id to ensure has tempo set. It must exist. + * @return whether a point was mutated + */ +static bool EnsureTempoSet(int id) +{ + double timeposOut, beat, bpm; + int measure, num, den; + bool linear; + GetTempoTimeSigMarker(NULL, id, &timeposOut, &measure, &beat, &bpm, &num, &den, &linear); + //TODO is there any way to tell whether bpm has already been explicitly set by this point? + SetTempoTimeSigMarker(NULL, id, timeposOut, measure, beat, bpm, num, den, linear); + return true; +} + static void MoveGridToMouse (COMMAND_T* ct) { static int s_lockedId = -1; static double s_lastPosition = 0; + MoveGridToMouseCommand cmd = (MoveGridToMouseCommand)ct->user; + // Action called for the first time: reset variables and cache tempo map for future calls if (!g_moveGridTempoMap) { @@ -344,13 +367,25 @@ static void MoveGridToMouse (COMMAND_T* ct) s_lastPosition = 0; // Make sure tempo map already has at least one point created (for some reason it won't work if creating it directly in chunk) - if ((int)ct->user != 0 && CountTempoTimeSigMarkers(NULL) == 0) // do it only if not moving tempo marker + if (cmd != MOVE_CLOSEST_TEMPO_MOUSE) { InitTempoMap(); g_didTempoMapInit = true; } g_moveGridTempoMap = new (nothrow) BR_Envelope(GetTempoEnv()); + + // Make sure previous point is editable via g_moveGridTempoMap. + if (g_moveGridTempoMap && cmd != MOVE_CLOSEST_TEMPO_MOUSE) + { + // ensure previous point's bpm is explicitly set, otherwise changes won't register in BR_Envelope. + if(EnsureTempoSet(g_moveGridTempoMap->FindPrevious(PositionAtMouseCursor(true)))) + { + delete g_moveGridTempoMap; + g_moveGridTempoMap = new (nothrow) BR_Envelope(GetTempoEnv()); + } + } + if (!g_moveGridTempoMap || !g_moveGridTempoMap->CountPoints() || g_moveGridTempoMap->IsLocked()) { ContinuousActionStopAll(); @@ -380,9 +415,9 @@ static void MoveGridToMouse (COMMAND_T* ct) int targetId; // Find closest grid tempo marker - if ((int)ct->user == 1 || (int)ct->user == 2) + if (cmd == MOVE_GRID_TO_MOUSE || cmd == MOVE_M_GRID_TO_MOUSE) { - grid = ((int)ct->user == 1) ? (GetClosestGridLine(mousePosition)) : (GetClosestMeasureGridLine(mousePosition)); + grid = (cmd == MOVE_GRID_TO_MOUSE) ? (GetClosestGridLine(mousePosition)) : (GetClosestMeasureGridLine(mousePosition)); targetId = g_moveGridTempoMap->Find(grid, MIN_TEMPO_DIST); } // Find closest tempo marker @@ -445,9 +480,9 @@ void MoveGridToMouseInit () //!WANT_LOCALIZE_1ST_STRING_BEGIN:sws_actions static COMMAND_T s_commandTable[] = { - { { DEFACCEL, "SWS/BR: Move closest tempo marker to mouse cursor (perform until shortcut released)" }, "BR_MOVE_CLOSEST_TEMPO_MOUSE", MoveGridToMouse, NULL, 0}, - { { DEFACCEL, "SWS/BR: Move closest grid line to mouse cursor (perform until shortcut released)" }, "BR_MOVE_GRID_TO_MOUSE", MoveGridToMouse, NULL, 1}, - { { DEFACCEL, "SWS/BR: Move closest measure grid line to mouse cursor (perform until shortcut released)" }, "BR_MOVE_M_GRID_TO_MOUSE", MoveGridToMouse, NULL, 2}, + { { DEFACCEL, "SWS/BR: Move closest tempo marker to mouse cursor (perform until shortcut released)" }, "BR_MOVE_CLOSEST_TEMPO_MOUSE", MoveGridToMouse, NULL, MOVE_CLOSEST_TEMPO_MOUSE}, + { { DEFACCEL, "SWS/BR: Move closest grid line to mouse cursor (perform until shortcut released)" }, "BR_MOVE_GRID_TO_MOUSE", MoveGridToMouse, NULL, MOVE_GRID_TO_MOUSE}, + { { DEFACCEL, "SWS/BR: Move closest measure grid line to mouse cursor (perform until shortcut released)" }, "BR_MOVE_M_GRID_TO_MOUSE", MoveGridToMouse, NULL, MOVE_M_GRID_TO_MOUSE}, { {}, LAST_COMMAND} }; //!WANT_LOCALIZE_1ST_STRING_END diff --git a/Breeder/BR_Tempo.h b/Breeder/BR_Tempo.h index f82c9da8f..48446423e 100644 --- a/Breeder/BR_Tempo.h +++ b/Breeder/BR_Tempo.h @@ -30,6 +30,12 @@ /****************************************************************************** * Commands: Tempo continuous actions * ******************************************************************************/ +enum MoveGridToMouseCommand +{ + MOVE_CLOSEST_TEMPO_MOUSE = 0, + MOVE_GRID_TO_MOUSE, + MOVE_M_GRID_TO_MOUSE +}; void MoveGridToMouseInit (); /****************************************************************************** From b1c96a688c68e6960ade988bd5bbd5459aa00fb0 Mon Sep 17 00:00:00 2001 From: Ambrose Bonnaire-Sergeant Date: Fri, 24 Feb 2023 16:13:53 -0500 Subject: [PATCH 2/8] [skip ci] another corner case --- Breeder/BR_EnvelopeUtil.cpp | 7 ++++++- Breeder/BR_EnvelopeUtil.h | 2 +- Breeder/BR_Tempo.cpp | 28 ++++++++++++++++++---------- 3 files changed, 25 insertions(+), 12 deletions(-) diff --git a/Breeder/BR_EnvelopeUtil.cpp b/Breeder/BR_EnvelopeUtil.cpp index da3b0a2e2..83a28c50e 100644 --- a/Breeder/BR_EnvelopeUtil.cpp +++ b/Breeder/BR_EnvelopeUtil.cpp @@ -2961,10 +2961,15 @@ void CalculateSplitMiddlePoints (double* time1, double* time2, double* bpm1, dou WritePtr(bpm2, val2); } -void InitTempoMap () +bool InitTempoMap () { if (!CountTempoTimeSigMarkers(NULL)) + { SetTempoTimeSigMarker(NULL, -1, 0, -1, -1, GetProjectSettingsTempo(NULL, NULL), 0, 0, false); + return true; + } + else + return false; } void RemoveTempoMap () diff --git a/Breeder/BR_EnvelopeUtil.h b/Breeder/BR_EnvelopeUtil.h index 96fe6ded5..66abde350 100644 --- a/Breeder/BR_EnvelopeUtil.h +++ b/Breeder/BR_EnvelopeUtil.h @@ -300,7 +300,7 @@ double CalculateMeasureAtPosition (double startBpm, double endBpm, double timeLe double CalculatePositionAtMeasure (double startBpm, double endBpm, double timeLen, double targetMeasure); void CalculateMiddlePoint (double* middleTime, double* middleBpm, double measure, double startTime, double endTime, double startBpm, double endBpm); void CalculateSplitMiddlePoints (double* time1, double* time2, double* bpm1, double* bpm2, double splitRatio, double measure, double startTime, double middleTime, double endTime, double startBpm, double middleBpm, double endBpm); -void InitTempoMap (); // will make sure there's at least one point in tempo map (we can't manipulate tempo map's chunk (i.e. insert new points) if there isn't at least one point in tempo map) +bool InitTempoMap (); // will make sure there's at least one point in tempo map (we can't manipulate tempo map's chunk (i.e. insert new points) if there isn't at least one point in tempo map) void RemoveTempoMap (); void UnselectAllTempoMarkers (); void UpdateTempoTimeline (); // UpdateTimeline() isn't enough after changing tempo points through chunk - call this instead diff --git a/Breeder/BR_Tempo.cpp b/Breeder/BR_Tempo.cpp index 53220a80f..c6da8f02f 100644 --- a/Breeder/BR_Tempo.cpp +++ b/Breeder/BR_Tempo.cpp @@ -344,13 +344,21 @@ static HCURSOR MoveGridCursor (COMMAND_T* ct, int window) */ static bool EnsureTempoSet(int id) { + char debugStr[256]; + snprintf(debugStr, sizeof(debugStr), "EnsureTempoSet: id: %d\n", id); + OutputDebugString(debugStr); + double timeposOut, beat, bpm; int measure, num, den; bool linear; - GetTempoTimeSigMarker(NULL, id, &timeposOut, &measure, &beat, &bpm, &num, &den, &linear); - //TODO is there any way to tell whether bpm has already been explicitly set by this point? - SetTempoTimeSigMarker(NULL, id, timeposOut, measure, beat, bpm, num, den, linear); - return true; + if(GetTempoTimeSigMarker(NULL, id, &timeposOut, &measure, &beat, &bpm, &num, &den, &linear)) + { + SetTempoTimeSigMarker(NULL, id, timeposOut, measure, beat, bpm, num, den, linear); + //TODO is there any way to tell whether bpm has already been explicitly set by this point? + return true; + } + else + return false; } static void MoveGridToMouse (COMMAND_T* ct) @@ -367,16 +375,16 @@ static void MoveGridToMouse (COMMAND_T* ct) s_lastPosition = 0; // Make sure tempo map already has at least one point created (for some reason it won't work if creating it directly in chunk) - if (cmd != MOVE_CLOSEST_TEMPO_MOUSE) - { - InitTempoMap(); - g_didTempoMapInit = true; - } + g_didTempoMapInit = InitTempoMap(); g_moveGridTempoMap = new (nothrow) BR_Envelope(GetTempoEnv()); // Make sure previous point is editable via g_moveGridTempoMap. - if (g_moveGridTempoMap && cmd != MOVE_CLOSEST_TEMPO_MOUSE) + // FIXME in MOVE_CLOSEST_TEMPO_MOUSE, we need the prev point relative to + // the closest point to be matched, not relative to the mouse. + // eg., 4/4 12bpm + // ^--this needs tempo + if (g_moveGridTempoMap && g_moveGridTempoMap->CountPoints()) { // ensure previous point's bpm is explicitly set, otherwise changes won't register in BR_Envelope. if(EnsureTempoSet(g_moveGridTempoMap->FindPrevious(PositionAtMouseCursor(true)))) From d79c9428a9c9899e2de925ce6c9cf958f98d0148 Mon Sep 17 00:00:00 2001 From: Ambrose Bonnaire-Sergeant Date: Fri, 24 Feb 2023 16:30:49 -0500 Subject: [PATCH 3/8] [skip ci] plan --- Breeder/BR_Tempo.cpp | 52 +++++++++++++++++++++++++++++++------------- 1 file changed, 37 insertions(+), 15 deletions(-) diff --git a/Breeder/BR_Tempo.cpp b/Breeder/BR_Tempo.cpp index c6da8f02f..029015264 100644 --- a/Breeder/BR_Tempo.cpp +++ b/Breeder/BR_Tempo.cpp @@ -367,10 +367,12 @@ static void MoveGridToMouse (COMMAND_T* ct) static double s_lastPosition = 0; MoveGridToMouseCommand cmd = (MoveGridToMouseCommand)ct->user; + bool firstTime = false; // Action called for the first time: reset variables and cache tempo map for future calls if (!g_moveGridTempoMap) { + firstTime = true; s_lockedId = -1; s_lastPosition = 0; @@ -379,21 +381,6 @@ static void MoveGridToMouse (COMMAND_T* ct) g_moveGridTempoMap = new (nothrow) BR_Envelope(GetTempoEnv()); - // Make sure previous point is editable via g_moveGridTempoMap. - // FIXME in MOVE_CLOSEST_TEMPO_MOUSE, we need the prev point relative to - // the closest point to be matched, not relative to the mouse. - // eg., 4/4 12bpm - // ^--this needs tempo - if (g_moveGridTempoMap && g_moveGridTempoMap->CountPoints()) - { - // ensure previous point's bpm is explicitly set, otherwise changes won't register in BR_Envelope. - if(EnsureTempoSet(g_moveGridTempoMap->FindPrevious(PositionAtMouseCursor(true)))) - { - delete g_moveGridTempoMap; - g_moveGridTempoMap = new (nothrow) BR_Envelope(GetTempoEnv()); - } - } - if (!g_moveGridTempoMap || !g_moveGridTempoMap->CountPoints() || g_moveGridTempoMap->IsLocked()) { ContinuousActionStopAll(); @@ -456,6 +443,41 @@ static void MoveGridToMouse (COMMAND_T* ct) } } + // reinitialize g_moveGridTempoMap so that tempo changes are recognized + if (firstTime && s_lockedId >= 0) + { + + // Make sure previous point is editable via g_moveGridTempoMap. + // FIXME in MOVE_CLOSEST_TEMPO_MOUSE, we need the prev point relative to + // the closest point to be matched, not relative to the mouse. + // eg., 4/4 <120bpm> + // ^--this needs tempo + // eg., 4/4 4/4 <120bpm> + // ^-- this needs tempo + // eg., 4/4 <4/4> 4/4 + // ^-- ^-- these need tempo + if (g_moveGridTempoMap && g_moveGridTempoMap->CountPoints()) + { + // if there's a point after the current one, then the current point must also have tempo. + // + // ensure previous point's bpm is explicitly set, otherwise changes won't register in BR_Envelope. + int prevId; + switch (cmd) + { + // + case MOVE_CLOSEST_TEMPO_MOUSE: + break; + default: + prevId = g_moveGridTempoMap->FindPrevious(PositionAtMouseCursor(true)); + } + if(EnsureTempoSet(prevId)) + { + delete g_moveGridTempoMap; + g_moveGridTempoMap = new (nothrow) BR_Envelope(GetTempoEnv()); + } + } + } + // Move grid and commit changes if (tDiff != 0 && s_lockedId >= 0) { From dc9d367760684319ff80074e86e581f74fb6a5ef Mon Sep 17 00:00:00 2001 From: Ambrose Bonnaire-Sergeant Date: Fri, 24 Feb 2023 16:55:06 -0500 Subject: [PATCH 4/8] [skip ci] edge case --- Breeder/BR_Tempo.cpp | 77 ++++++++++++++++++++++---------------------- 1 file changed, 39 insertions(+), 38 deletions(-) diff --git a/Breeder/BR_Tempo.cpp b/Breeder/BR_Tempo.cpp index 029015264..e81c5230d 100644 --- a/Breeder/BR_Tempo.cpp +++ b/Breeder/BR_Tempo.cpp @@ -361,6 +361,18 @@ static bool EnsureTempoSet(int id) return false; } +static bool InitGridTempoMap() +{ + g_moveGridTempoMap = new (nothrow) BR_Envelope(GetTempoEnv()); + + if (!g_moveGridTempoMap || !g_moveGridTempoMap->CountPoints() || g_moveGridTempoMap->IsLocked()) + { + ContinuousActionStopAll(); + return false; + } + return true; +} + static void MoveGridToMouse (COMMAND_T* ct) { static int s_lockedId = -1; @@ -379,13 +391,7 @@ static void MoveGridToMouse (COMMAND_T* ct) // Make sure tempo map already has at least one point created (for some reason it won't work if creating it directly in chunk) g_didTempoMapInit = InitTempoMap(); - g_moveGridTempoMap = new (nothrow) BR_Envelope(GetTempoEnv()); - - if (!g_moveGridTempoMap || !g_moveGridTempoMap->CountPoints() || g_moveGridTempoMap->IsLocked()) - { - ContinuousActionStopAll(); - return; - } + if (!InitGridTempoMap()) return; } // Find closest grid/tempo marker @@ -443,39 +449,34 @@ static void MoveGridToMouse (COMMAND_T* ct) } } - // reinitialize g_moveGridTempoMap so that tempo changes are recognized + // FIXME hovering over the first point with MOVE_CLOSEST_TEMPO_MOUSE and dragging right + // does not work if it the first point doesn't have tempo. + // e.g., <4/4> + // ^--- drag right... + // then, + // 120bpm,4/4 <120bpm, 4/4> + // ^--- stuck at 120bpm... ^-- not locked to grid + + // reinitialize g_moveGridTempoMap so that tempo changes are recognized on points + // that don't set bpm (like those that set time sigs or metronome patterns). if (firstTime && s_lockedId >= 0) { - - // Make sure previous point is editable via g_moveGridTempoMap. - // FIXME in MOVE_CLOSEST_TEMPO_MOUSE, we need the prev point relative to - // the closest point to be matched, not relative to the mouse. - // eg., 4/4 <120bpm> - // ^--this needs tempo - // eg., 4/4 4/4 <120bpm> - // ^-- this needs tempo - // eg., 4/4 <4/4> 4/4 - // ^-- ^-- these need tempo - if (g_moveGridTempoMap && g_moveGridTempoMap->CountPoints()) - { - // if there's a point after the current one, then the current point must also have tempo. - // - // ensure previous point's bpm is explicitly set, otherwise changes won't register in BR_Envelope. - int prevId; - switch (cmd) - { - // - case MOVE_CLOSEST_TEMPO_MOUSE: - break; - default: - prevId = g_moveGridTempoMap->FindPrevious(PositionAtMouseCursor(true)); - } - if(EnsureTempoSet(prevId)) - { - delete g_moveGridTempoMap; - g_moveGridTempoMap = new (nothrow) BR_Envelope(GetTempoEnv()); - } - } + // Any point immediately before one we are manipulating must have tempo. + // e.g., 4/4 <120bpm> + // ^--this needs tempo + // e.g., 4/4 4/4 <120bpm> + // ^-- this needs tempo + // e.g., 4/4 <4/4> 4/4 + // ^--------^-- these need tempo + int id1 = s_lockedId-1; + int id2 = s_lockedId; + int id3 = s_lockedId+1; + if (id2 > 0 || id1 == 0) + EnsureTempoSet(id1); + if (g_moveGridTempoMap->ValidateId(id3)) + EnsureTempoSet(id2); + delete g_moveGridTempoMap; + if (!InitGridTempoMap()) return; } // Move grid and commit changes From e18f7daa5fa0e6d634b155318a83090a319e497e Mon Sep 17 00:00:00 2001 From: Ambrose Bonnaire-Sergeant Date: Fri, 24 Feb 2023 17:21:24 -0500 Subject: [PATCH 5/8] [skip ci] rm enum --- Breeder/BR_Tempo.cpp | 18 ++++++++---------- Breeder/BR_Tempo.h | 6 ------ 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/Breeder/BR_Tempo.cpp b/Breeder/BR_Tempo.cpp index e81c5230d..56517452d 100644 --- a/Breeder/BR_Tempo.cpp +++ b/Breeder/BR_Tempo.cpp @@ -284,8 +284,7 @@ static bool MoveGridInit (COMMAND_T* ct, bool init) if (init) { const int projgridframe = ConfigVar("projgridframe").value_or(0); - MoveGridToMouseCommand cmd = (MoveGridToMouseCommand)ct->user; - if ((cmd == MOVE_GRID_TO_MOUSE || cmd == MOVE_M_GRID_TO_MOUSE) && projgridframe&1) // frames grid line spacing + if (((int)ct->user == 1 || (int)ct->user == 2) && projgridframe&1) // frames grid line spacing { initSuccessful = false; static bool s_warnUser = true; @@ -378,7 +377,6 @@ static void MoveGridToMouse (COMMAND_T* ct) static int s_lockedId = -1; static double s_lastPosition = 0; - MoveGridToMouseCommand cmd = (MoveGridToMouseCommand)ct->user; bool firstTime = false; // Action called for the first time: reset variables and cache tempo map for future calls @@ -416,9 +414,9 @@ static void MoveGridToMouse (COMMAND_T* ct) int targetId; // Find closest grid tempo marker - if (cmd == MOVE_GRID_TO_MOUSE || cmd == MOVE_M_GRID_TO_MOUSE) + if ((int)ct->user == 1 || (int)ct->user == 2) { - grid = (cmd == MOVE_GRID_TO_MOUSE) ? (GetClosestGridLine(mousePosition)) : (GetClosestMeasureGridLine(mousePosition)); + grid = ((int)ct->user == 1) ? (GetClosestGridLine(mousePosition)) : (GetClosestMeasureGridLine(mousePosition)); targetId = g_moveGridTempoMap->Find(grid, MIN_TEMPO_DIST); } // Find closest tempo marker @@ -471,9 +469,9 @@ static void MoveGridToMouse (COMMAND_T* ct) int id1 = s_lockedId-1; int id2 = s_lockedId; int id3 = s_lockedId+1; - if (id2 > 0 || id1 == 0) + if (id1 <= 0) EnsureTempoSet(id1); - if (g_moveGridTempoMap->ValidateId(id3)) + if (id2 == 0 || g_moveGridTempoMap->ValidateId(id3)) EnsureTempoSet(id2); delete g_moveGridTempoMap; if (!InitGridTempoMap()) return; @@ -511,9 +509,9 @@ void MoveGridToMouseInit () //!WANT_LOCALIZE_1ST_STRING_BEGIN:sws_actions static COMMAND_T s_commandTable[] = { - { { DEFACCEL, "SWS/BR: Move closest tempo marker to mouse cursor (perform until shortcut released)" }, "BR_MOVE_CLOSEST_TEMPO_MOUSE", MoveGridToMouse, NULL, MOVE_CLOSEST_TEMPO_MOUSE}, - { { DEFACCEL, "SWS/BR: Move closest grid line to mouse cursor (perform until shortcut released)" }, "BR_MOVE_GRID_TO_MOUSE", MoveGridToMouse, NULL, MOVE_GRID_TO_MOUSE}, - { { DEFACCEL, "SWS/BR: Move closest measure grid line to mouse cursor (perform until shortcut released)" }, "BR_MOVE_M_GRID_TO_MOUSE", MoveGridToMouse, NULL, MOVE_M_GRID_TO_MOUSE}, + { { DEFACCEL, "SWS/BR: Move closest tempo marker to mouse cursor (perform until shortcut released)" }, "BR_MOVE_CLOSEST_TEMPO_MOUSE", MoveGridToMouse, NULL, 0}, + { { DEFACCEL, "SWS/BR: Move closest grid line to mouse cursor (perform until shortcut released)" }, "BR_MOVE_GRID_TO_MOUSE", MoveGridToMouse, NULL, 1}, + { { DEFACCEL, "SWS/BR: Move closest measure grid line to mouse cursor (perform until shortcut released)" }, "BR_MOVE_M_GRID_TO_MOUSE", MoveGridToMouse, NULL, 2}, { {}, LAST_COMMAND} }; //!WANT_LOCALIZE_1ST_STRING_END diff --git a/Breeder/BR_Tempo.h b/Breeder/BR_Tempo.h index 48446423e..f82c9da8f 100644 --- a/Breeder/BR_Tempo.h +++ b/Breeder/BR_Tempo.h @@ -30,12 +30,6 @@ /****************************************************************************** * Commands: Tempo continuous actions * ******************************************************************************/ -enum MoveGridToMouseCommand -{ - MOVE_CLOSEST_TEMPO_MOUSE = 0, - MOVE_GRID_TO_MOUSE, - MOVE_M_GRID_TO_MOUSE -}; void MoveGridToMouseInit (); /****************************************************************************** From 71640e3cc4f801d9a1535483c687db4010cd7d52 Mon Sep 17 00:00:00 2001 From: Ambrose Bonnaire-Sergeant Date: Fri, 24 Feb 2023 17:54:35 -0500 Subject: [PATCH 6/8] [skip ci] init --- Breeder/BR_Tempo.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/Breeder/BR_Tempo.cpp b/Breeder/BR_Tempo.cpp index 56517452d..e2a0eb436 100644 --- a/Breeder/BR_Tempo.cpp +++ b/Breeder/BR_Tempo.cpp @@ -533,12 +533,7 @@ void MoveGridToEditPlayCursor (COMMAND_T* ct) PreventUIRefresh(1); // In case tempo map has no tempo points - bool didTempoMapInit = false; - if (CountTempoTimeSigMarkers(NULL) == 0) - { - InitTempoMap(); - didTempoMapInit = true; - } + bool didTempoMapInit = InitTempoMap(); BR_Envelope tempoMap(GetTempoEnv()); From 7b2d42d1e4c1fd10a2e65bdf81fbaec39207a876 Mon Sep 17 00:00:00 2001 From: Ambrose Bonnaire-Sergeant Date: Fri, 24 Feb 2023 20:40:10 -0500 Subject: [PATCH 7/8] [skip ci] experiment --- Breeder/BR_Tempo.cpp | 117 ++++++++++++++++++++++++------------------- 1 file changed, 66 insertions(+), 51 deletions(-) diff --git a/Breeder/BR_Tempo.cpp b/Breeder/BR_Tempo.cpp index e2a0eb436..4bc254500 100644 --- a/Breeder/BR_Tempo.cpp +++ b/Breeder/BR_Tempo.cpp @@ -50,6 +50,59 @@ static HWND g_tempoShapeWnd = NULL; /****************************************************************************** * Misc * ******************************************************************************/ + +/** + * Explicitly set a tempo envelope point's tempo to its calculated tempo. + * + * Must call this on a point before creating a BR_Envelope that will change its bpm, + * otherwise tempo updates via BR_Envelope will be ignored. + * + * @param id The tempo envelope point id to ensure has tempo set. It must exist. + * @return whether a point was mutated + */ +static bool EnsureTempoSet(int id) +{ + char debugStr[256]; + snprintf(debugStr, sizeof(debugStr), "EnsureTempoSet: id: %d\n", id); + OutputDebugString(debugStr); + + double timeposOut, beat, bpm; + int measure, num, den; + bool linear; + if(GetTempoTimeSigMarker(NULL, id, &timeposOut, &measure, &beat, &bpm, &num, &den, &linear)) + { + SetTempoTimeSigMarker(NULL, id, timeposOut, measure, beat, bpm, num, den, linear); + //TODO is there any way to tell whether bpm has already been explicitly set by this point? + return true; + } + else + return false; +} + + + // FIXME hovering over the first point with MOVE_CLOSEST_TEMPO_MOUSE and dragging right + // does not work if it the first point doesn't have tempo. + // e.g., <4/4> + // ^--- drag right... + // then, + // 120bpm,4/4 <120bpm, 4/4> + // ^--- stuck at 120bpm... ^-- not locked to grid +static void BeforeMoveTempo (BR_Envelope& tempoMap, int id2) +{ + // Any point immediately before one we are manipulating (changing bpm) must have tempo. + // e.g., 4/4 <120bpm> + // ^--this needs tempo + // e.g., 4/4 4/4 <120bpm> + // ^-- this needs tempo + // e.g., 4/4 <4/4> 4/4 + // ^--------^-- these need tempo + int id1 = id2-1; + int id3 = id2+1; + if (id1 <= 0) + EnsureTempoSet(id1); + if (id2 == 0 || tempoMap.ValidateId(id3)) + EnsureTempoSet(id2); +} static bool MoveTempo (BR_Envelope& tempoMap, int id, double timeDiff, bool checkEditedPoints) { // Get tempo points @@ -332,36 +385,9 @@ static HCURSOR MoveGridCursor (COMMAND_T* ct, int window) return NULL; } -/** - * Explicitly set a tempo envelope point's tempo to its calculated tempo. - * - * Must call this on a point before creating a BR_Envelope that will change its bpm, - * otherwise tempo updates via BR_Envelope will be ignored. - * - * @param id The tempo envelope point id to ensure has tempo set. It must exist. - * @return whether a point was mutated - */ -static bool EnsureTempoSet(int id) -{ - char debugStr[256]; - snprintf(debugStr, sizeof(debugStr), "EnsureTempoSet: id: %d\n", id); - OutputDebugString(debugStr); - - double timeposOut, beat, bpm; - int measure, num, den; - bool linear; - if(GetTempoTimeSigMarker(NULL, id, &timeposOut, &measure, &beat, &bpm, &num, &den, &linear)) - { - SetTempoTimeSigMarker(NULL, id, timeposOut, measure, beat, bpm, num, den, linear); - //TODO is there any way to tell whether bpm has already been explicitly set by this point? - return true; - } - else - return false; -} - static bool InitGridTempoMap() { + if (g_moveGridTempoMap) delete g_moveGridTempoMap; g_moveGridTempoMap = new (nothrow) BR_Envelope(GetTempoEnv()); if (!g_moveGridTempoMap || !g_moveGridTempoMap->CountPoints() || g_moveGridTempoMap->IsLocked()) @@ -447,33 +473,11 @@ static void MoveGridToMouse (COMMAND_T* ct) } } - // FIXME hovering over the first point with MOVE_CLOSEST_TEMPO_MOUSE and dragging right - // does not work if it the first point doesn't have tempo. - // e.g., <4/4> - // ^--- drag right... - // then, - // 120bpm,4/4 <120bpm, 4/4> - // ^--- stuck at 120bpm... ^-- not locked to grid - // reinitialize g_moveGridTempoMap so that tempo changes are recognized on points // that don't set bpm (like those that set time sigs or metronome patterns). if (firstTime && s_lockedId >= 0) { - // Any point immediately before one we are manipulating must have tempo. - // e.g., 4/4 <120bpm> - // ^--this needs tempo - // e.g., 4/4 4/4 <120bpm> - // ^-- this needs tempo - // e.g., 4/4 <4/4> 4/4 - // ^--------^-- these need tempo - int id1 = s_lockedId-1; - int id2 = s_lockedId; - int id3 = s_lockedId+1; - if (id1 <= 0) - EnsureTempoSet(id1); - if (id2 == 0 || g_moveGridTempoMap->ValidateId(id3)) - EnsureTempoSet(id2); - delete g_moveGridTempoMap; + BeforeMoveTempo(*g_moveGridTempoMap, s_lockedId); if (!InitGridTempoMap()) return; } @@ -634,6 +638,17 @@ void MoveTempo (COMMAND_T* ct) // Loop through selected points int skipped = 0; int count = (targetId != -1) ? (1) : (tempoMap.CountSelected()); + + // prepare to call MoveTempo + for (int i = 0; i < count; ++i) + { + int id = ((int)ct->user == 3) ? (targetId) : (tempoMap.GetSelected(i)); + if (id > 0) // skip first point + BeforeMoveTempo(tempoMap, id); + } + delete &tempoMap; + tempoMap = GetTempoEnv(); + for (int i = 0; i < count; ++i) { int id = ((int)ct->user == 3) ? (targetId) : (tempoMap.GetSelected(i)); From 5726dba8734df2c954188d9b85ba55fb862c1523 Mon Sep 17 00:00:00 2001 From: Ambrose Bonnaire-Sergeant Date: Fri, 24 Feb 2023 23:11:23 -0500 Subject: [PATCH 8/8] [skip ci] experiment --- Breeder/BR_Tempo.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/Breeder/BR_Tempo.cpp b/Breeder/BR_Tempo.cpp index 4bc254500..4a6c31566 100644 --- a/Breeder/BR_Tempo.cpp +++ b/Breeder/BR_Tempo.cpp @@ -62,15 +62,15 @@ static HWND g_tempoShapeWnd = NULL; */ static bool EnsureTempoSet(int id) { - char debugStr[256]; - snprintf(debugStr, sizeof(debugStr), "EnsureTempoSet: id: %d\n", id); - OutputDebugString(debugStr); double timeposOut, beat, bpm; int measure, num, den; bool linear; if(GetTempoTimeSigMarker(NULL, id, &timeposOut, &measure, &beat, &bpm, &num, &den, &linear)) { + char debugStr[256]; + snprintf(debugStr, sizeof(debugStr), "EnsureTempoSet: id: %d, bpm %d\n", id, bpm); + OutputDebugString(debugStr); SetTempoTimeSigMarker(NULL, id, timeposOut, measure, beat, bpm, num, den, linear); //TODO is there any way to tell whether bpm has already been explicitly set by this point? return true; @@ -647,18 +647,20 @@ void MoveTempo (COMMAND_T* ct) BeforeMoveTempo(tempoMap, id); } delete &tempoMap; - tempoMap = GetTempoEnv(); + BR_Envelope tempoMap2(GetTempoEnv()); + if (!tempoMap2.CountPoints()) + return; for (int i = 0; i < count; ++i) { - int id = ((int)ct->user == 3) ? (targetId) : (tempoMap.GetSelected(i)); + int id = ((int)ct->user == 3) ? (targetId) : (tempoMap2.GetSelected(i)); if (id > 0) // skip first point - skipped += (MoveTempo(tempoMap, id, tDiff, true)) ? (0) : (1); + skipped += (MoveTempo(tempoMap2, id, tDiff, true)) ? (0) : (1); } // Commit changes PreventUIRefresh(1); // prevent jumpy cursor - if (tempoMap.Commit()) + if (tempoMap2.Commit()) { if ((int)ct->user == 3) SetEditCurPos2(NULL, cursor, false, false); // always keep cursor position when moving to closest tempo marker @@ -668,7 +670,7 @@ void MoveTempo (COMMAND_T* ct) // Warn user if some points weren't processed static bool s_warnUser = true; - if (s_warnUser && skipped != 0 && !tempoMap.IsLocked()) + if (s_warnUser && skipped != 0 && !tempoMap2.IsLocked()) { char buffer[512]; snprintf(buffer, sizeof(buffer), __LOCALIZE_VERFMT("%d of the selected points didn't get processed because some points would end up with illegal BPM or position. Would you like to be warned if it happens again?", "sws_mbox"), skipped);