Making some progress!
Now I don’t get a SuperCollider Fail, but so far my file isn’t being analysed when the script is loaded, and I get an SC error. I have a feeling it’s something simple, though…
Current version:
Main SC file (‘engine_pvscrub.sc’):
Engine_PVScrub : CroneEngine {
var pg;
var fftSize = 1024;
var wavPath = "/home/we/dust/code/pvscrub/analysis/demo.wav";
var fftPath = "/home/we/dust/code/pvscrub/analysis/demo-fft.wav";
var pitchPath = "/home/we/dust/code/pvscrub/analysis/demo-pitch.wav";
var amp=0.3;
var release=0.5;
var pw=0.5;
var cutoff=1000;
var gain=2;
*new { arg context, doneCallback;
^super.new(context, doneCallback);
}
alloc {
// NRT Analysis
"/home/we/dust/code/pvscrub/lib/analyser.scd".load();
analyseWav(~wavPath, ~fftPath, ~pitchPath).value;
pg = ParGroup.tail(context.xg);
SynthDef("PolyPerc", {
arg out, freq = 440, pw=pw, amp=amp, cutoff=cutoff, gain=gain, release=release;
var snd = Pulse.ar(freq, pw);
var filt = MoogFF.ar(snd,cutoff,gain);
var env = Env.perc(level: amp, releaseTime: release).kr(2);
// out.poll;
Out.ar(out, (filt*env).dup
);
}).add;
this.addCommand("hz", "f", { arg msg;
var val = msg[1];
Synth("PolyPerc", [\out, context.out_b, \freq,val,\pw,pw,\amp,amp,\cutoff,cutoff,\gain,gain,\release,release], target:pg);
});
this.addCommand("noteOn", "f", { arg msg;
var val = msg[1];
Synth("PolyPerc", [\out, context.out_b, \freq,val,\pw,pw,\amp,amp,\cutoff,cutoff,\gain,gain,\release,release], target:pg);
});
this.addCommand("amp", "f", { arg msg;
amp = msg[1];
});
this.addCommand("pw", "f", { arg msg;
pw = msg[1];
});
this.addCommand("release", "f", { arg msg;
release = msg[1];
});
this.addCommand("cutoff", "f", { arg msg;
cutoff = msg[1];
});
this.addCommand("gain", "f", { arg msg;
gain = msg[1];
});
}
}
Analyser function:
///////////////////////////////////////
// Non-Realtime FFT Analysis To File //
///////////////////////////////////////
analyseWav = {
arg wavIn, fftOut, pitchOut, action;
// Define function vars
var inBuf, fftBuf, pitchBuf, fftSize = ~fftSize, f, nrtServer, nrtScore, env;
var cond = Condition.new;
fork {
f = SoundFile.openRead(wavIn);
f.close;
// Define Non-RealTime server
//nrtServer = Server(\nrt, NetAddr("127.0.0.1", 57110),
nrtServer = Server(\nrt, NetAddr("127.0.0.1", 57111),
ServerOptions.new
.numOutputBusChannels_(2)
.numInputBusChannels_(2)
.sampleRate_(44100)
);
// Create buffer for input file
inBuf = Buffer(nrtServer, 65536, 1);
// Create output buffer for FFT analysis data
fftBuf = Buffer.alloc(nrtServer, f.duration.calcPVRecSize(fftSize, 0.5, nrtServer.options.sampleRate), 1);
pitchBuf = Buffer.alloc(nrtServer, (f.numFrames / nrtServer.options.blockSize).roundUp.asInteger, 2);
// Create score for recording of FFT analysis to WAV file
nrtScore = Score([
[0, inBuf.allocMsg],
[0, fftBuf.allocMsg],
[0, pitchBuf.allocMsg],
[0, inBuf.readMsg(wavIn, leaveOpen: true)],
[0, [\d_recv, SynthDef(\pv_ana, {
var sig = VDiskIn.ar(1, inBuf, f.sampleRate / SampleRate.ir);
var fft = FFT(LocalBuf(fftSize, 1), sig);
var pitch = Tartini.kr(sig);
RecordBuf.kr(pitch, pitchBuf, loop: 0);
fft = PV_RecordBuf(fft, fftBuf, run: 1);
Out.ar(0, sig);
}).asBytes]],
[0, Synth.basicNew(\pv_ana, nrtServer).newMsg],
[f.duration + (fftSize / nrtServer.options.sampleRate),
fftBuf.writeMsg(fftOut, "wav", "float");
],
[f.duration + (fftSize / nrtServer.options.sampleRate),
pitchBuf.writeMsg(pitchOut, "wav", "float");
]
]);
nrtScore.score.do(_.postln);
// Run score
nrtScore.recordNRT(
outputFilePath: if(thisProcess.platform.name == \windows) { "NUL" } { "/dev/null" },
headerFormat: "wav",
sampleRate: nrtServer.options.sampleRate,
options: nrtServer.options,
duration: f.duration + (fftSize / nrtServer.options.sampleRate),
action: { "done".postln; cond.unhang }
);
cond.hang;
// Free score
nrtScore.free;
// Free NRT server
nrtServer.remove;
action.value;
};
}
SuperCollider error:
a CroneAudioContext
ERROR: Variable 'analyseWav' not defined.
in interpreted text
line 80 char 1:
-----------------------------------
ERROR: Message 'analyseWav' not understood.
RECEIVER:
nil
ARGS:
nil
nil
CALL STACK:
DoesNotUnderstandError:reportError
arg this = <instance of DoesNotUnderstandError>
Nil:handleError
arg this = nil
arg error = <instance of DoesNotUnderstandError>
Thread:handleError
arg this = <instance of Thread>
arg error = <instance of DoesNotUnderstandError>
Thread:handleError
arg this = <instance of Routine>
arg error = <instance of DoesNotUnderstandError>
Object:throw
arg this = <instance of DoesNotUnderstandError>
Object:doesNotUnderstand
arg this = nil
arg selector = 'analyseWav'
arg args = [*2]
Engine_PVScrub:alloc
arg this = <instance of Engine_PVScrub>
< FunctionDef in Method CroneEngine:init > (no arguments or variables)
Routine:prStart
arg this = <instance of Routine>
arg inval = 28.834867233
^^ The preceding error dump is for ERROR: Message 'analyseWav' not understood.
RECEIVER: nil