/*
LPC - Linear Predictive Coding
two stages
- analysis stage (done with the CSound command line program)
- resynthesis, done with SC
*/
s.boot;
// first, load an LPC file
a = LPCFile.new("sounds/fate.lpc");
a.loadToBuffer;
// store it to a CtkBuffer
b = CtkBuffer.new(bufnum: a.buffer);
z = CtkNoteObject(
SynthDef(\lpc, {arg gate = 1, buffer, snddur, amp = 1;
var cps, rmso, err, voc, noise, lpc, timepoint, env;
env = EnvGen.kr(Env([0, 1, 0], [0.1, 1], \sin, 1), gate, doneAction: 2);
timepoint = LFSaw.kr(snddur.reciprocal, 1).range(0, 1);
// LPCVals will give you info from the soundfile
// freq, overall rms and error values
#cps, rmso, err = LPCVals.kr(buffer, timepoint);
// what we will use to resynth the 'vowel' parts of speech
voc = Blip.ar(cps, 200, 0.5);
// noise parts
noise = LFNoise1.ar(2000, err);
// send them through the LPC all-pole filter
lpc = LPCSynth.ar(buffer, voc + noise, timepoint, rmso);
Out.ar(0, Pan2.ar(lpc * env * amp, 0));
})
);
y = z.new.buffer_(b).snddur_(a.sndDur).amp_(1).play;
y.release;
z = CtkNoteObject(
SynthDef(\lpc, {arg gate = 1, buffer, snddur, amp = 1;
var cps, rmso, err, voc, noise, lpc, timepoint, env;
env = EnvGen.kr(Env([0, 1, 0], [1, 1], \sin, 1), gate, doneAction: 2);
timepoint = LFSaw.kr(snddur.reciprocal, 1).range(0, 1);
// LPCVals will give you info from the soundfile
// freq, overall rms and error values
#cps, rmso, err = LPCVals.kr(buffer, timepoint);
// what we will use to resynth the 'vowel' parts of speech
voc = Blip.ar(cps, 200, 0.5);
voc = voc + Resonz.ar(voc, cps, 0.01, 10);
// noise parts
noise = LFNoise1.ar(2000, err);
// send them through the LPC all-pole filter
lpc = LPCSynth.ar(buffer, voc + noise, timepoint, rmso);
Out.ar(0, Pan2.ar(lpc * env * amp, 0));
})
);
y = z.new.buffer_(b).snddur_(a.sndDur).amp_(1).play;
y.release;
/*
things to mess with - sound sources.. mul different parts (cps... volume levels, timepoint etc.)
*/
z = CtkNoteObject(
SynthDef(\lpc, {arg gate = 1, buffer, snddur, amp = 1;
var cps, rmso, err, voc, noise, lpc, timepoint, env;
env = EnvGen.kr(Env([0, 1, 0], [1, 1], \sin, 1), gate, doneAction: 2);
timepoint = Sweep.kr(MouseButton.kr(1, 0), MouseButton.kr(snddur.reciprocal, 0)).mod(1);
// LPCVals will give you info from the soundfile
// freq, overall rms and error values
#cps, rmso, err = LPCVals.kr(buffer, timepoint);
// what we will use to resynth the 'vowel' parts of speech
voc = Blip.ar(cps * MouseX.kr(0.8, 2), 200, 0.5);
voc = voc + Resonz.ar(voc, cps, 0.01, 10);
// noise parts
noise = LFNoise1.ar(2000, err);
// send them through the LPC all-pole filter
lpc = LPCSynth.ar(buffer, voc + noise, timepoint, rmso);
Out.ar(0, Pan2.ar(lpc * env * amp, 0));
})
);
y = z.new.buffer_(b).snddur_(a.sndDur).amp_(1).play;
y.release;
b.free;
/* Ambisonics (quick and dirty) */
/* basics - mono sound can be encoded onto a 'sphere' soundfield using a number of UGens. Here are mine (takes advantage of the z axis unlike the built in SC Ugens */
// a sound to spatialize
a = CtkBuffer.playbuf("sounds/accordian.wav").load;
b = CtkNoteObject(
SynthDef(\space, {arg gate = 1, buffer, outbus = 0;
var play, w, x, y, z, env;
env = EnvGen.kr(Env([0, 1, 0], [1, 1], \sin, 1), gate, doneAction: 2);
play = PlayBuf.ar(1, buffer, loop: 1);
// encode the sound
#w, x, y, z = BFEncode1.ar(play * env, MouseX.kr(0, 2pi), MouseY.kr(0.5pi, -0.5pi), 1);
// send it straight out
Out.ar(outbus, [w, x, y, z]);
// decode the sound
// Out.ar(outbus, B2Ster.ar(w, x, y));
})
);
c = b.new.buffer_(a).play;
c.release;
a.free;
// usually, I send all the sound out of a UGen encoded, and write to a virtual bus. I then have
// a single decoder catching everything
b = CtkNoteObject(
SynthDef(\decoder, {arg inbus, outbus, amp = 1;
var w, x, y, z;
#w, x, y, z = In.ar(inbus, 4);
// Out.ar(outbus, B2Ster.ar(w, x, y) * env);
Out.ar(outbus, [w, x, y, z] * amp);
})
);
d = CtkNoteObject(
SynthDef(\final, {arg gate = 1, dur = 1, buffer, outbus = 0, amp = 1;
var play, w, x, y, z, env, filt;
env = EnvGen.kr(Env([0, 1, 0], [0.05, 0.95], \sin), gate, timeScale: dur, doneAction: 2);
play = PlayBuf.ar(1, buffer, loop: 1);
filt = Ringz.ar(play, LFNoise2.ar(dur.reciprocal).range(1000, 3000), 1) * amp;
// encode the sound
#w, x, y, z = BFEncode1.ar(filt * env, LFNoise1.kr(dur.reciprocal, pi),
LFNoise1.kr(dur.reciprocal, 0.5pi), 1);
// send it straight out
Out.ar(outbus, [w, x, y, z]);
})
)
p = ProcMod(Env([0, 1, 0], [1, 1], \sin, 1)).function_({arg group, envbus, server;
Task({
var cond;
cond = Condition.new;
envbus = CtkControl.new(bus: envbus);
a = CtkAudio.new(numChans: 4);
c = CtkBuffer.playbuf("sounds/accordian.wav").load;
s.sync(cond);
// start the decoder
b.new(addAction: \tail, target: group).inbus_(a).outbus_(0).amp_(envbus).play; loop({
d.new(target: group).buffer_(c).outbus_(a.bus).amp_(0.001).play;
1.wait;
})
})
})
.releaseFunc_({c.free});
p.play;
p.release;
// there are a number of ways to transform the soundfield. See Rotate, Tilt and Tumble classdefs
// also, see BFDecode1 for other decoding options. See BFEncode2 for more encoding options