I should clarify: when I say it’s been unreliable, I mean if I repeatedly attempt to analyse the same file, most of the time it fails, as I mentioned, and occasionally it appears to work.
It seems to work more reliably when I comment-out all the lines related to the pitch analysis.
I’ve also found that often (but not all the time) when I trigger a note to instantiate a synth, the server immediately quits, with status 0 (which isn’t very helpful).
Here’s the synth (note I’m not doing anything with the pitch analysis data yet):
(
b = Buffer.read(s, ~fftPath);
p = Buffer.read(s, ~pitchPath);
//////////////////
// Define Synth //
//////////////////
SynthDef(\pvscrub, {
arg out = 0, fBuf = 1,
pOffset = 0, pBend = 0,
amp = 0.1, gate = 1,
ampEnvAttack = 0.01, ampEnvDecay = 0, ampEnvSustain = 1.0, ampEnvRelease = 2,
grainSize = 0.1, grainPitchDispersion = 0.01, grainTimeDispersion = 0.004,
//filterCutoff, filterResonance, filterShape,
scrubPos = 0.1, scrubPosInertia = 0.01,
pvParam1 = 0, pvParam2 = 0;
var fftSize = ~fftSize, chain, bufNum, ampEnv, centerFreq, result;
// Amplitude envelope Attack Sustain Release type
// Free synth after envelope finishes
ampEnv = Env.adsr(ampEnvAttack, ampEnvDecay, ampEnvSustain, ampEnvRelease, amp).kr(2, gate);
// Read FFT buffer
bufNum = LocalBuf.new(fftSize);
chain = PV_BufRd(bufNum, fBuf, min(scrubPos.lag(scrubPosInertia), 1));
// FFT FX
chain = PV_RectComb(chain, pvParam1.lag(1), 0);
chain = PV_MagSmooth(chain, pvParam2.lag(1));
// TODO
// Resynthesise FFT
result = IFFT(chain).dup;
// Time-domain pitch-shift
result = PitchShift.ar(
result,
grainSize,
pOffset, // Pitch-shift ratio
grainPitchDispersion.lag(2),
grainTimeDispersion.lag(2)
);
// Filter
// TODO
// Resonant low-pass
// Non-resonant hi-Pass/shelf
// Final output
Out.ar(out, result * ampEnv);
}).add;
)
And here’s the MIDI setup
(
//////////////////
// Setup Busses //
//////////////////
~setupControls = {
// Setup control buses
~scrubControl = Bus.control(s, 1);
~scrubInertiaControl = Bus.control(s, 1);
~bendControl = Bus.control(s, 1);
~grainPitchDispersionControl = Bus.control(s, 1);
~pvParam1Control = Bus.control(s, 1);
~pvParam2Control = Bus.control(s, 1);
//~filterCutoffControl = Bus.control(s, 1);
//~filterResonanceControl = Bus.control(s, 1);
//~filterShapeControl = Bus.control(s, 1);
}.value;
////////////////
// Setup MIDI //
////////////////
~setupMIDI = {
var notes, on, off, cc, centreNote = 60;
MIDIClient.init;
MIDIIn.connectAll;
notes = Array.newClear(128); // array has one slot per possible MIDI note
// Handle note-on events
on = MIDIFunc.noteOn({
arg vel, note, chan, src;
var noteScaled, pOffsetRatio;
// Note clamped to 48..72 range
// 2 octaves either side of C4, -24..+24 semitone range
noteScaled = max(min(note, centreNote + 24), centreNote - 24) - centreNote;
// Pitch-offset as ratio
pOffsetRatio = noteScaled.midiratio;
// Push synth to notes array
notes[note] = Synth(\pvscrub, [\out: 0,\fBuf: b,\pOffset: pOffsetRatio,\amp: vel.linlin(0, 127, 0, 1)]);
// Setup control busses
notes[note].set(\scrubPos, ~scrubControl.asMap);
notes[note].set(\scrubPosInertia, ~scrubInertiaControl.asMap);
notes[note].set(\pBend, ~bendControl.asMap);
notes[note].set(\grainPitchDispersion, ~grainPitchDispersionControl.asMap);
notes[note].set(\pvParam1, ~pvParam1Control.asMap);
notes[note].set(\pvParam2, ~pvParam2Control.asMap);
//notes[note].set(\filterCutoff, ~filterCutoffControl.asMap);
//notes[note].set(\filterResonance, ~filterResonanceControl.asMap);
//notes[note].set(\filterShape, ~filterShapeControl.asMap);
});
// Handle note-off events
off = MIDIFunc.noteOff({
arg vel, note, chan, src;
notes[note].release;
});
// Handle CC events
cc = MIDIFunc.cc({
arg val, num, chan, src;
switch (num,
1, { ~scrubControl.set(linlin(val, 0, 127, 0.0, 1.0)); postln("scrub: " + val); },
76, { ~scrubInertiaControl.set(linlin(val, 0, 127, 0.01, 5.0)); postln("scrub inertia: " + val ); },
74, { ~grainPitchDispersionControl.set(linlin(val, 0, 127, 0.0, 0.5)); postln("grain pitch dispersion: " + val); },
71, { ~pvParam1Control.set(linlin(val, 0, 127, 0.0, 32)); postln("pv param 1: " + val); },
77, { ~pvParam2Control.set(linlin(val, 0, 127, 0.0, 0.99)); postln("pv param 2: " + val); }
);
//num.postln;
});
// Handle pitch-bend events
// TODO
}.value;
)
If the code is correct, perhaps it’s a SuperCollider bug. I’m using v3.11.2 on macOS 10.15.6.
It feels a bit like there may be an issue with the RecordBuf and PV_RecordBug uGens. Maybe files are being opened for writing, the write fails, for some reason, and the files are not properly closed again.
It could be that the RT server crashes with the synth are related to attempting to read from corrupt analysis files (though loading the files into the “b” and “p” buffers doesn’t report errors).