//////////////////////////////////////////////////// /* 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/Front_Left.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; //msg.postln; // BUTTON 0 + 3 ----> ZERO EULER / MPU6050 if (msg[9] == 1 && msg[10] == 1, { " ===== EULER ZEROED! =====".postln }, {}); if (msg[9] == 1, { r.set( \in, 0, \l, 0, \t_trig, 1); " /////////// SAMPLING!".postln }, {}); if (msg[10] == 1, { " /////////// SOOOOOOMMMEEETHIIIINNGGGG!".postln }, {}); if (msg[11] == 1, { " /////////// ////////////////////////////!".postln }, {}); if (msg[12] == 1, { "=========================================".postln }, {}); // TOGGLE 1 ----> LOOP RECORDING MODE ON/OFF /* if (msg[13] == 1, { r.set(\l, 1); "LOOPING ON".postln; }, { r.set(\l, 0); "LOOPING OFF".postln; }); // TOGGLE 2 ----> OVERDUB RECORDING MODE ON/OFF if (msg[14] == 1, { r.set(\overdub, 1); "OVERDUB ON".postln; }, { r.set(\overdub, 0); "OVERDUB OFF".postln; }, );*/ /* case //{ msg[14] == 0} {"result".postln; msg.postln} // BUTTON 0 && 3 RESET/ZERO SENSORS [in firmware] // BUTTON 0 ----> RECORD TO BUFFER 0 { msg[9] == 1 } { r.set( \in, 0, \l, 0, \t_trig, 1); msg.postln; msg[9].postln; "SAMPLING!".postln } // BUTTON 0 + 3 ----> ZERO EULER / MPU6050 // TOGGLE O ----> OVERDUB MODE ON/OFF { msg[14] == 0 } { r.set(\overdub, 0); "OVERDUB OFF".postln; } { msg[14] == 1 } { r.set(\overdub, 1); "OVERDUB ON".postln; } // TOGGLE 2 //{ msg[13] == 0 } { ~granulator1.set(\positionmodeindex, 1 ); } //{ msg[13] == 1 } { ~granulator1.set(\positionmodeindex, 2 ); } // TOGGLE 3 ----> LOOP RECORDING MODE ON/OFF { msg[13] == 0 } { "LOOPING OFF".postln; r.set(\l, 0); msg[13].postln;} { msg[13] == 1 } { "LOOPING ON! SAMPLING".postln; r.set(\l, 1); msg[13].postln; };*/ } , '/keys'); ); ); // ---------------------------------------------------- // ---------------------------------------------------- // 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);