Skip to content

Commit 0368b12

Browse files
committed
Automation curve improvements to allow copy/paste of multiple curves at once
1 parent 6cd3bef commit 0368b12

File tree

5 files changed

+373
-10
lines changed

5 files changed

+373
-10
lines changed

modules/tracktion_engine/model/automation/tracktion_AutomationCurveList.test.cpp

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1102,6 +1102,102 @@ TEST_SUITE("tracktion_engine")
11021102
}
11031103
}
11041104

1105+
TEST_CASE ("Clipboard::AutomationPoints")
1106+
{
1107+
auto& engine = *tracktion::engine::Engine::getEngines()[0];
1108+
auto context = AutomationCurveListTestContext::create (engine);
1109+
1110+
context->edit->ensureNumberOfAudioTracks (2);
1111+
auto audioTracks = getAudioTracks (*context->edit);
1112+
auto at1 = audioTracks[0];
1113+
auto at2 = audioTracks[1];
1114+
1115+
auto volParam1 = at1->getVolumePlugin()->volParam;
1116+
auto panParam1 = at1->getVolumePlugin()->panParam;
1117+
auto volParam2 = at2->getVolumePlugin()->volParam;
1118+
1119+
// Add some automation points to volParam1
1120+
auto& curve1 = volParam1->getCurve();
1121+
curve1.addPoint (0_tp, 0.0f, 0.0f, nullptr);
1122+
curve1.addPoint (1_tp, 1.0f, 0.0f, nullptr);
1123+
curve1.addPoint (2_tp, 0.5f, 0.0f, nullptr);
1124+
1125+
SUBCASE ("Single-curve constructor populates curves vector")
1126+
{
1127+
// Test the AutomatableParameter& constructor
1128+
Clipboard::AutomationPoints content (*volParam1, curve1, TimeRange (0_tp, 2_tp));
1129+
1130+
// Verify curves[0] is populated (not legacy fields)
1131+
CHECK_EQ (content.curves.size(), 1);
1132+
CHECK_EQ (content.curves[0].points.size(), 3);
1133+
CHECK_EQ (content.curves[0].valueRange, volParam1->getValueRange());
1134+
CHECK_EQ (content.curves[0].paramID, volParam1->paramID);
1135+
}
1136+
1137+
SUBCASE ("Empty AutomationPoints returns false on paste")
1138+
{
1139+
// Create empty content by constructing with empty track array
1140+
juce::Array<Track*> emptyTracks;
1141+
Clipboard::AutomationPoints emptyContent (emptyTracks, TimeRange (0_tp, 2_tp));
1142+
1143+
CHECK (emptyContent.curves.empty());
1144+
1145+
// All paste methods should return false for empty content
1146+
auto& curve2 = volParam2->getCurve();
1147+
CHECK_FALSE (emptyContent.pasteAutomationCurve (*volParam2, curve2, TimeRange (0_tp, 2_tp)));
1148+
CHECK_FALSE (emptyContent.pasteAutomationCurveAtIndex (*volParam2, curve2, TimeRange (0_tp, 2_tp), 0));
1149+
1150+
juce::Array<Track*> targetTracks;
1151+
targetTracks.add (at2);
1152+
CHECK_FALSE (emptyContent.pasteIntoTracks (targetTracks, 0_tp));
1153+
}
1154+
1155+
SUBCASE ("pasteAutomationCurveAtIndex clamps out-of-range index")
1156+
{
1157+
Clipboard::AutomationPoints content (*volParam1, curve1, TimeRange (0_tp, 2_tp));
1158+
CHECK_EQ (content.curves.size(), 1);
1159+
1160+
auto& curve2 = volParam2->getCurve();
1161+
auto& curve2b = at2->getVolumePlugin()->panParam->getCurve();
1162+
1163+
// Both index 0 and index 100 should paste from curves[0]
1164+
bool result0 = content.pasteAutomationCurveAtIndex (*volParam2, curve2, TimeRange (0_tp, 2_tp), 0);
1165+
bool result100 = content.pasteAutomationCurveAtIndex (*at2->getVolumePlugin()->panParam, curve2b, TimeRange (0_tp, 2_tp), 100);
1166+
1167+
CHECK (result0);
1168+
CHECK (result100);
1169+
1170+
// Both should have pasted something (exact counts depend on mergeCurve behavior)
1171+
CHECK (curve2.getNumPoints() > 0);
1172+
CHECK (curve2b.getNumPoints() > 0);
1173+
}
1174+
1175+
SUBCASE ("Multi-parameter constructor populates multiple curves")
1176+
{
1177+
// Add automation to panParam1 as well
1178+
auto& panCurve1 = panParam1->getCurve();
1179+
panCurve1.addPoint (0_tp, 0.0f, 0.0f, nullptr);
1180+
panCurve1.addPoint (1_tp, 0.5f, 0.0f, nullptr);
1181+
1182+
juce::Array<AutomatableParameter*> params;
1183+
params.add (volParam1.get());
1184+
params.add (panParam1.get());
1185+
1186+
Clipboard::AutomationPoints content (params, TimeRange (0_tp, 2_tp));
1187+
1188+
// Should have 2 curves with correct metadata
1189+
CHECK_EQ (content.curves.size(), 2);
1190+
CHECK_EQ (content.curves[0].valueRange, volParam1->getValueRange());
1191+
CHECK_EQ (content.curves[1].valueRange, panParam1->getValueRange());
1192+
1193+
// pasteAutomationCurve should succeed (uses curves[0])
1194+
auto& curve2 = volParam2->getCurve();
1195+
bool result = content.pasteAutomationCurve (*volParam2, curve2, TimeRange (0_tp, 2_tp));
1196+
CHECK (result);
1197+
CHECK (curve2.getNumPoints() > 0);
1198+
}
1199+
}
1200+
11051201
TEST_CASE ("AutomationCurveList: Clip plugin")
11061202
{
11071203
auto& engine = *tracktion::engine::Engine::getEngines()[0];

modules/tracktion_engine/model/edit/tracktion_EditUtilities.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1189,6 +1189,19 @@ Track* getTrackContainingModifier (const Edit& edit, const Modifier::Ptr& m)
11891189
});
11901190
}
11911191

1192+
Track* getTrackShowingParameter (AutomatableParameter& param)
1193+
{
1194+
// First try the standard way
1195+
if (auto track = param.getTrack())
1196+
return track;
1197+
1198+
// Search all tracks for one that's currently showing this parameter
1199+
return findTrackForPredicate (param.getEdit(), [&param] (Track& t)
1200+
{
1201+
return t.getCurrentlyShownAutoParam() == &param;
1202+
});
1203+
}
1204+
11921205
//==============================================================================
11931206
juce::Array<MacroParameterList*> getAllMacroParameterLists (const Edit& edit)
11941207
{

modules/tracktion_engine/model/edit/tracktion_EditUtilities.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,11 @@ Modifier::Ptr findModifierForID (const RackType&, EditItemID);
265265
/** Returns the Track containing a Modifier. */
266266
Track* getTrackContainingModifier (const Edit&, const Modifier::Ptr&);
267267

268+
/** Returns the Track that is currently showing an AutomatableParameter's curve.
269+
First tries param.getTrack(), then searches all tracks for one displaying this parameter.
270+
*/
271+
Track* getTrackShowingParameter (AutomatableParameter&);
272+
268273

269274
//==============================================================================
270275
// Macros

0 commit comments

Comments
 (0)