That’s a fair point about depending on prior state.
Still, I think many/most UGen tests could run in parallel. I’ll paste a proof of concept below. It depends on creating a file with some number of samples of given synth functions. If we take generated_test_signal absdif: baseline_signal, then “pass” means this is zero for every sample, which we could detect by integrating the absdif.
Unfortunately, I’m having the same experience with this POC as I always have with tests – this is not once in a while – this is every (multiple expletives deleted) time I try to write a test.
The theory is sound.
The test doesn’t work.
When it didn’t work at first, I added ~checkbuf (which shouldn’t be necessary in the end) to verify the signals being processed. The third channel represents the integrators. It’s zero, both in the plot and by doing d[2, 5 ..].sum
(also just tried d[2, 5 ..].every(_ == 0)
→ true). It’s incontrovertible that the signals being fed into Integrator are all 0.
But the Integrator results are nonzero. Again: multiple expletives deleted.
I’m going to have to give up for this morning, but… “technical debt”… it’s a fairly common experience for me that writing a test for one thing uncovers (sometimes multiple) unrelated bugs. Not rare. Common.
hjh
(
~tests = [
{ SinOsc.ar(440) },
{ RLPF.ar(Impulse.ar(0), 880, 0.1) },
{ RandSeed.ir(1, 56789); PinkNoise.ar }
];
)
// this part would be done only once
// should not be done per test cycle!
(
fork {
var cond = Condition.new;
var size = 512;
var numBlocks = size / s.options.blockSize;
var buf = Buffer.alloc(s, size * ~tests.size, 1);
var synth;
s.sync;
~tests.do { |func, i|
synth = {
RecordBuf.ar(func.value, buf, offset: size * i, loop: 0);
FreeSelf.kr(Phasor.kr(0, 1, 0, 1e6) >= numBlocks);
Silent.ar(1);
}.play;
synth.onFree { cond.unhang };
cond.hang;
};
buf.write("~/tmp/ugen-test-poc.wav".standardizePath, "wav", "float");
s.sync;
buf.free
};
)
~checkbuf = Buffer.alloc(s, 1024 * ~tests.size, 3); // deliberately longer than the test signals
~checkbuf.zero;
// this is the actual test
(
fork {
var cond = Condition.new;
var synth;
var baselineBuf = Buffer.read(s, "~/tmp/ugen-test-poc.wav".standardizePath);
var size = 512;
var numBlocks = size / s.options.blockSize;
var resp;
var results;
s.sync;
synth = SynthDef(\x, {
var signals = ~tests.collect(_.value);
var phasor = Phasor.ar(0, 1, 0, size + 1000);
var baselines = Array.fill(~tests.size, { |i|
BufRd.ar(1, baselineBuf, phasor + (size * i), loop: 0, interpolation: 1);
});
var trig = phasor >= size;
var not_trig = trig <= 0;
// the test seems to over-run
// stupid hack for now is to suppress the input
// when phasor gets too large
// this actually does work! But Integrator is still nonzero
var diff = not_trig * (signals absdif: baselines);
~tests.size.do { |i|
BufWr.ar([signals[i], baselines[i], diff[i]], ~checkbuf, phasor + (1024 * i), loop: 0);
};
SendReply.ar(trig, '/results', Integrator.ar(diff));
FreeSelf.kr(T2K.kr(trig));
Silent.ar(1);
}).play;
resp = OSCFunc({ |msg|
results = msg[3..];
cond.unhang;
}, '/results', s.addr).oneShot;
cond.hang;
results.do { |flag, i|
"Test % passed: % (%)\n".postf(i, flag == 0, flag);
};
baselineBuf.free;
};
)
~checkbuf.getToFloatArray(wait: -1, timeout: 5, action: { |data| d = data });
d.plot(numChannels: 3);
d[2, 5 ..].sum