Restore the bank fold and usage publish to the resume path, guard setActive against repeats, and make the meter fold's bound literal
The resume also hands back to a full reload when the fold moves the loaded capture's decode source, so the refs table and the audio cannot skew.
This commit is contained in:
@@ -20,7 +20,8 @@ static int g_fail = 0;
|
||||
|
||||
// Stands in for std::atomic<float> with ONE scripted interference: the first compare-exchange
|
||||
// runs the UI's consume (identity reinstalled, the window taken) and reports failure exactly as
|
||||
// the real CAS does — expected updated to what the consume left. Everything after is ordinary.
|
||||
// the real CAS does — expected updated to what the consume left. Everything after is ordinary,
|
||||
// which is what makes the retry count assertable: a strong CAS fails only under interference.
|
||||
struct ConsumingAccumulator {
|
||||
float value;
|
||||
float identity;
|
||||
@@ -29,8 +30,8 @@ struct ConsumingAccumulator {
|
||||
|
||||
float load(std::memory_order) const { return value; }
|
||||
|
||||
bool compare_exchange_weak(float& expected, float desired, std::memory_order,
|
||||
std::memory_order) {
|
||||
bool compare_exchange_strong(float& expected, float desired, std::memory_order,
|
||||
std::memory_order) {
|
||||
if (casCount++ == 0) {
|
||||
consumed = value;
|
||||
value = identity;
|
||||
|
||||
@@ -531,6 +531,43 @@ static void testRefreshRefsFromBankUpsertAndOwnership() {
|
||||
CHECK(refs.size() == 1 && refs[0].ref.rootNote == 40);
|
||||
}
|
||||
|
||||
static void testSameDecodeSourceTracksEveryDecodeInput() {
|
||||
// The predicate a resumed (already-decoded) instrument is gated on: every field that
|
||||
// changes what buildSampleData produces must read as different, and the display-only
|
||||
// name must not.
|
||||
SelectedSample a;
|
||||
a.relativePath = "b/a.wav";
|
||||
a.rootNote = 36;
|
||||
a.channelCount = 2;
|
||||
a.loop.hasLoop = true;
|
||||
a.loop.start = 100;
|
||||
a.loop.end = 900;
|
||||
CHECK(sameDecodeSource(a, a));
|
||||
|
||||
SelectedSample recaptured = a;
|
||||
recaptured.relativePath = "b/a2.wav"; // the recapture case: a new file behind one id
|
||||
CHECK(!sameDecodeSource(a, recaptured));
|
||||
|
||||
SelectedSample reRooted = a;
|
||||
reRooted.rootNote = 40;
|
||||
CHECK(!sameDecodeSource(a, reRooted));
|
||||
|
||||
SelectedSample reChanneled = a;
|
||||
reChanneled.channelCount = 1; // drives the channel-mode auto-default, hence the decode
|
||||
CHECK(!sameDecodeSource(a, reChanneled));
|
||||
|
||||
SelectedSample loopOff = a;
|
||||
loopOff.loop.hasLoop = false;
|
||||
CHECK(!sameDecodeSource(a, loopOff));
|
||||
|
||||
SelectedSample loopMoved = a;
|
||||
loopMoved.loop.start = 101;
|
||||
CHECK(!sameDecodeSource(a, loopMoved));
|
||||
loopMoved = a;
|
||||
loopMoved.loop.end = 901;
|
||||
CHECK(!sameDecodeSource(a, loopMoved));
|
||||
}
|
||||
|
||||
static void testRetainRefsFiltersToPlayedSet() {
|
||||
// getState hygiene: only the entries the instance currently plays persist — the table
|
||||
// cannot grow with browsing history. Order of survivors is preserved.
|
||||
@@ -1015,6 +1052,7 @@ int main() {
|
||||
testReferencedSampleIdsIsTheLoadedCapture();
|
||||
testFindRefLooksUpTheOwnedCopy();
|
||||
testRefreshRefsFromBankUpsertAndOwnership();
|
||||
testSameDecodeSourceTracksEveryDecodeInput();
|
||||
testRetainRefsFiltersToPlayedSet();
|
||||
testLegacyLiftDecision();
|
||||
testResolvePlayConvertsWallClockAtTheRate();
|
||||
|
||||
Reference in New Issue
Block a user