Found while building a JUCE + Tracktion Engine DAW. Measured on 494e91d (develop) and re-checked against develop 18e307f: the code referenced is unchanged. Happy to provide the test fixture.
Where: AudioClipBase::checkFadeLengthsForOverrun(), called from the
constructor; it rescales fadeIn/fadeOut through a CachedValue with the
Edit's UndoManager.
What goes wrong: a clip rebuilt DURING an undo re-enters
UndoManager::perform, which JUCE refuses ("Don't call perform() recursively
... these actions will be discarded") and asserts at
juce_UndoManager.cpp:128. The fade correction is then silently lost. Undoing
a Record does exactly this: the clip is reconstructed via valueTreeChildAdded
inside the undo transaction.
Reproduction: an edit whose undo history contains the deletion of a clip
that was transiently over-long-faded - e.g. a comp remnant of length
0.00999... carrying a 0.02 s convex crossfade (state captured below). Undo to
the transaction that rebuilds it.
<AUDIOCLIP name="Take 1" start="2.0" length="0.00999999999999979"
smCompSource="1016" fadeIn="0.0" fadeOut="0.02" fadeOutType="2" .../>
Fix: a constructor has no business performing an undoable write. Clamp the
fades with a null UndoManager (the geometry is derived, not user data), or defer
the correction out of construction.
Found while building a JUCE + Tracktion Engine DAW. Measured on
494e91d(develop) and re-checked against develop18e307f: the code referenced is unchanged. Happy to provide the test fixture.Where:
AudioClipBase::checkFadeLengthsForOverrun(), called from theconstructor; it rescales
fadeIn/fadeOutthrough aCachedValuewith theEdit's UndoManager.
What goes wrong: a clip rebuilt DURING an undo re-enters
UndoManager::perform, which JUCE refuses ("Don't call perform() recursively... these actions will be discarded") and asserts at
juce_UndoManager.cpp:128. The fade correction is then silently lost. Undoinga Record does exactly this: the clip is reconstructed via
valueTreeChildAddedinside the undo transaction.
Reproduction: an edit whose undo history contains the deletion of a clip
that was transiently over-long-faded - e.g. a comp remnant of length
0.00999... carrying a 0.02 s convex crossfade (state captured below). Undo to
the transaction that rebuilds it.
Fix: a constructor has no business performing an undoable write. Clamp the
fades with a null UndoManager (the geometry is derived, not user data), or defer
the correction out of construction.