diff --git a/gtr.scd b/gtr.scd new file mode 100644 index 0000000..657507f --- /dev/null +++ b/gtr.scd @@ -0,0 +1,263 @@ +//////////////////////////////////////////////////// +/* GRANULATING SAMPLER INSTRUMENT ////////////////// +////////////////////////////////////rc@kiben.net//// +//////////////////////////////////////////////////// + +| .-. +| / \ .-. +| / \ / \ .-. .-. _ ++--/-------\-----/-----\-----/---\---/---\---/-\- +| / \ / \ / '-' '-' +|/ '-' '-' + +Ljudmila OTF Hackathon, Maribor 1-6 March 2022 */ + +//////////////////////////////////////////// + +// guitar MAC address 98:CD:AC:63:78:E2 + +// RUNME 0 ========================================= +s.boot(); + +// RUNME 1 ========================================= +// ------------------------------------------------- +( // SETUP ----------------------------------------- - +// --------------------------------------------------- +// Allocate a 4 second mono buffer +b = Buffer.alloc(s, s.sampleRate * 4.0, 1); +// load a test file +f = Buffer.read(s, thisProcess.nowExecutingPath.dirname + +/+ "sounds/selo-thunder-cicadas-01.wav"); + +// Open port 57121 for ESP32 UDP OSC +thisProcess.openUDPPort(57121); +); + +// RUNME 2 ========================================== +// ------------------------------------------------- +( // DEFINE SYNTHS --------------------------------- <-- +// ------------------------------------------------- + +( // direct signal + reverb ------------------------- + +SynthDef("dryIn", { arg in=0, out=0; + var signal, dry, wet; + dry = SoundIn.ar(in); + wet = FreeVerb.ar(dry, mix:0.4, room:0.55, damp:0); + signal = Pan2.ar(wet, 0); + signal = signal * 0.9; + Out.ar(0, signal); +}).add; +); + +( // mono buffer recorder ---------------------------- +// with loop and overdub modes ///////////////////// +// make record togglable between looping, direct or onset detection trigger +SynthDef("recBuf",{ arg in=0, out=0, bufnum=0, t_trig=0, l=0, overdub=0; + + var sig, chain, onsets; + sig = SoundIn.ar(in); + + // Onsets + chain = FFT(LocalBuf(512), sig); + onsets = Onsets.kr(chain, MouseX.kr(0,1), \rcomplex); + + RecordBuf.ar(sig, bufnum, loop:l, + preLevel: overdub, + doneAction: 0, trigger:t_trig,); +}).add; +); + +// ---------------------------------------------------- +( // Granulator -------------------------------------- +// ---------------------------------------------------- + +// a custom envelope +//var winenv; +//winenv = Env([0, 1, 0], [0.5, 0.5], [8, -8]); +//z = Buffer.sendCollection(s, winenv.discretize, 1); +// ~rndpos = LFNoise2.kr(0.1).range(0, 1); + +SynthDef(\buf_grain, { | out, gate = 1, amp = 1, + + sndbuf, envbuf, pan=0, imp=50, + pitchmodeindex=0, sensorpitch=1, + positionmodeindex=0, sensorposition=0, + impulsemodeindex=0, sensorimpulse=0, + rlow= -1, rhigh=1 | + + var signal, env, freqdev, pos, + pitchmode0, pitchmode1, pitch, + positionmode0, positionmode1, position, + impulsemode0, impulsemode1, impulse; + + // grain pitch mode -untransposed, random, or sensor controlled + pitchmode0 = 1; + pitchmode1 = LFNoise1.kr.range(rlow, rhigh); + pitch = Select.kr(pitchmodeindex, + [pitchmode0, pitchmode1, sensorpitch]); + + // granular playhead mode - fixed random or sensor controlled + positionmode0 = 1; + positionmode1 = LFNoise1.kr.range(0, 1); + position = Select.kr(positionmodeindex, + [positionmode0, positionmode1, sensorposition]); + + // grain impulse frequency mode - random, metric or sensor based impulse modes + impulsemode0 = Impulse.kr(imp); + impulsemode1 = Dust.kr(imp); + impulse = Select.kr(impulsemodeindex, + [impulsemode0, impulsemode1, sensorimpulse]); + + env = EnvGen.kr( + Env([0, 1, 0], [1, 1], \sin, 1), gate, levelScale: amp, doneAction: 2); + signal = GrainBuf.ar(2, + impulse, // selectable between impulse.kr and dust.kr + 0.1, sndbuf, pitch, position, 2, pan, envbuf); + signal = FreeVerb2.ar(signal[0], signal[1], + mix:0.4, room:0.5, damp:0 + ); + + signal = signal* env; + + Out.ar(0,signal); +}).add; +); +) + +// RUNME 3 ========================================== + +// ---------------------------------------------------- +(( // START SYNTHS --------------------------------- +// ---------------------------------------------------- + + r = Synth(\recBuf, [\in, 0, \out, 0, \bufnum, b, \t_trig, 0]); // recorder + ~granulator1 = Synth(\buf_grain, [\sndbuf, b, \envbuf, -1]); // granulate + ~gtrIn = Synth(\dryIn); // dry audio signaL + +)) +~gtrIn.free; + +// RUNME 4 ========================================== + +// ---------------------------------------------------- +( // OSC Receivers // ENABLE SENSOR AND SWITCH VALUES <-- +// ---------------------------------------------------- + +~pitchmode = 0; ~positionmode = 2; ~impulsemode = 0; + +( // accel gyro quaternion mapping /////////////////// +// msg[1] msg[2] msg[3] X Y Z ==> ROLL, PITCH, YAW + +o = OSCdef(\test, { arg msg, time, addr, recvPort, rlow, rhigh; + + // PAN ------- X Roll + ~granulator1.set(\pan, msg[1].linlin(-0.3, 0.3, -1, 1)); + + // PITCH ------- Y Pitch + ~granulator1.set(\sensorpitch, msg[3].linlin(-1, 1, 0, 4)); + ~granulator1.set(\pitchmodeindex, ~pitchmode ); + + // POSITION ------- Z Yaw + ~granulator1.set(\sensorposition, msg[2].linlin(-1, 1, 0, 4)); + ~granulator1.set(\positionmodeindex, ~positionmode ); + + // RATE ------- X (roll [with PAN]) + ~granulator1.set(\sensorimpulse, msg[2].linlin(-1, 1, 5, 50)); + ~granulator1.set(\impulsemodeindex, ~impulsemode ); + msg.postln; +}; , '/euler'); +); + +// ---------------------------------------------------- +// button press mapping /////////////////////////////// +// ---------------------------------------------------- + +( p = OSCdef(\keys, { arg msg, time, addr, recvPort; + // TODO toggle logic + case + // BUTTON 1 ----> RECORD + { msg[1] == 1 } { r.set( \t_trig, 1); msg.postln; } // + + // BUTTON 2 ----> ZERO SENSORS (todo) + { msg[5] == 0 } { ~granulator1.set(\positionmodeindex, 1 ); } + { msg[5] == 1 } { ~granulator1.set(\positionmodeindex, 2 ); } + + // 1 && 2 RESET/ZERO SENSORS + + // BUTTON 3 ----> LOOP RECORDING MODE ON/OFF + { msg[3] == 0 } { r.set(\l, 0); } + { msg[3] == 1 } { r.set(\l, 1); } + + // BUTTON 4 ----> OVERDUB MODE ON/OFF + { msg[4] == 0 } { ~pitchmode, 1 ); } + { msg[4] == 1 } { ~pitchmode, 2 ); } + +} , '/keys'); +//msg.postln; +); +) + +// ---------------------------------------------------- +// ---------------------------------------------------- +// PERFORMABLE PARAMETERS ///////////////////////////// +// ---------------------------------------------------- +// ---------------------------------------------------- + +// start recording (without button) +r.set(\in, 0, \l, 0, \t_trig, 1); + +// set recorder loop and overdub modes +r.set(\l, 1); // looping record on - MAPPED TO SWITCH 3 +r.set(\l, 0); // off + +r.set(\overdub, 1); // overdub mode on - MAPPED TO SWITCH 4 +r.set(\overdub, 0); // off + +/// random pitch/rate low and high values +~granulator1.set(\rlow, 0); +~granulator1.set(\rlow, -10); +~granulator1.set(\rhigh, 1); +~granulator1.set(\rhigh, 10); + +~impulsemode = 0; // impulse +~impulsemode = 1; // dust +~impulsemode = 2; // sensor + +~pitchmode = 0; // no transpose +~pitchmode = 1; // random +~pitchmode = 2; // sensor (pitch) input + +~positionmode = 0; // middle of sample +~positionmode = 1; // random position +~positionmode = 2; // sensor (position) input + +// set grain impulse rate +~granulator1.set(\imp, 50); + +// fix doneaction +~granulator1.set(\gate, 1); // granulator on +~granulator1.set(\gate, 0); // granulator off + +///////////////////////////////////////////////// + +// ----------------------------------------------- +// ----------------------------------------------- +// ----------------------------------------------- + +// DUMP ALL OSC MESSAGES (for debugging) //////// + +OSCFunc.trace(true); +OSCFunc.trace(false); +thisProcess.openPorts; // list all open ports + +// ----------------------------------------------- +// CODE DUMP ZONE /////////////////////////////// + +// switch to the custom env +//~granulator1.set(\envbuf, z); +//~granulator1.set(\envbuf, -1); +//n = NetAddr("127.0.0.1", NetAddr.langPort); +//n = NetAddr.new("224.0.1.9", 6696); + +