/* 

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