//////////////////////////////////////////////////// /* GRANULATING SAMPLER INSTRUMENT ////////////////// ////////////////////////////////////rc@kiben.net//// //////////////////////////////////////////////////// | .-. | / \ .-. | / \ / \ .-. .-. _ +--/-------\-----/-----\-----/---\---/---\---/-\- | / \ / \ / '-' '-' |/ '-' '-' Ljudmila OTF Hackathon, Maribor 1-6 March 2022 */ // GTR MAC address: 10:97:BD:36:D6:4E // 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; ); // ---------~positionmode = 1; ------------------------------------------- ( // 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, sensorgdur=0.1, sensorgpan=0, positionmodeindex=0, gdurmodeindex=0, gpanmodeindex=0, sensorposition=0, impulsemodeindex=0, sensorimpulse=0, rlow= -1, rhigh=1 | var signal, env, freqdev, pos, pitchmode0, pitchmode1, pitch, gdurmode0, gdurmode1, gdurmode2, gdur, gpanmode0, gpanmode1, gpan, positionmode0, positionmode1, position, impulsemode0, impulsemode1, impulse; // grain duration mode -untransposed, random, or sensor controlled gdurmode0 = 0.1; gdurmode1 = LFNoise1.kr.range(0.2, 3.3); gdurmode2 = LFNoise1.kr.range(0.2, 3.3); gdur = Select.kr(gdurmodeindex, [gdurmode0, gdurmode1, gdurmode2, sensorgdur]); // grain pan mode -untransposed, random, or sensor controlled gpanmode0 = 0.1; gpanmode1 = LFNoise1.kr.range(0.1, 10.3); gpan = Select.kr(gpanmodeindex, [gpanmode0, gpanmode1, sensorgpan]); // 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 gdur, sndbuf, pitch, position, 2, gpan, 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 = 0; ~impulsemode = 0; ~gdurmode=0; ~gpanmode=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)); ~granulator1.set(\panmodeindex, ~panmode ); // 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 ); ~granulator1.set(\sensorgdur, msg[2].linlin(-1, 1, 0.1, 1)); ~granulator1.set(\gdurmodeindex, ~gdurmode ); ~granulator1.set(\sensorgpan, msg[2].linlin(-1, 1, -1, 1)); ~granulator1.set(\gpanmodeindex, ~gpanmode ); //msg.postln; }; , '/euler'); ); // ---------------------------------------------------- // button press mapping /////////////////////////////// // ---------------------------------------------------- ~btn0val = 0; ~btn1val = 0; ~btn2val = 0; ~btn3val = 0; ~btn4val = 0; ~btn5val = 0; ~btn6val = 0; ~btn7val = 0; ~btn8val = 0; // shift buttons m = NetAddr("127.0.0.1", 57120); // loopback m.sendMsg("/chat", "Hello App 1"); p = OSCdef(\keys, { arg msg, time, addr, recvPort; //msg.println; // ============================== // BUTTON MAPPING // ============================== // TRIGGER BUTTONS (3) ------------------------------ // if SHIFT key is 0: if (msg[9] == 0, { // BUTTON X ----- TRIGGER ONESHOT BUFFER RECORD if (msg[10] == 1, { r.set( \in, 0, \l, 0, \t_trig, 1); " /////////// SAMPLING!".postln }, {}); // BUTTON X ----> LOOP RECORDING MODE ON/OFF if (msg[11]==1, { ( ~btn4val = (~btn4val + 1) % 3 ) ; switch( ~btn4val, 0, { r.set(\l, 0); "RECORD LOOPING OFF".postln; }, 1, { r.set(\l, 1); "RECORD LOOPING ON".postln; }, 2, { r.set(\l, 1); "RECORDING ONSET DETECTION ON".postln; }, //todo ) }); // BUTTON X ----> OVERDUB RECORDING MODE ON/OFF if (msg[12]==1, { ( ~btn2val = (~btn2val + 1) % 2 ) ; switch( ~btn2val, 0, { r.set(\overdub, 0); "SAMPLE OVERDUB OFF".postln; }, 1, { r.set(\overdub, 1); "SAMPLE OVERDUB ON".postln; }, ) }); }, /// SHIFT 0 LOGIC ENDS HERE { // SHIFT IN STATE 1 ======================= // BUTTON X ----- GRAIN DURATION MODE if (msg[15]==1, { ( ~btn8val = (~btn8val + 1) % 4 ) ; switch(~btn8val, 0, { ~gdurmode = 0; "DURATION MODE 0".postln; }, 1, { ~gdurmode = 1; "DURATION MODE 1".postln; }, 2, { ~gdurmode = 2; "DURATION MODE 2".postln; }, 3, { ~gdurmode = 3; "DURATION MODE 3".postln; }, ) }); // BUTTON X ----- GRANULAR POSITION MODE if (msg[13]==1, { ( ~btn3val = (~btn3val + 1) % 3 ) ; switch(~btn3val, 0, { ~positionmode = 0; "POSITION MODE FIXED".postln; }, 1, { ~positionmode = 1; "POSITION MODE RANDOM".postln; }, 2, { ~positionmode = 2; "POSITION MODE SENSOR".postln; }, ) }); // BUTTON X ----- GRANULAR PITCH MODE if (msg[14]==1, { ( ~btn6val = (~btn6val + 1) % 3 ) ; switch(~btn6val, 0, { ~pitchmode = 0; "PITCH MODE FIXED".postln; }, 1, { ~pitchmode = 1; "PITCH MODE RANDOM".postln; }, 2, { ~pitchmode = 2; "PITCH MODE SENSOR".postln; }, ) }); // BUTTON X ----- GRANULAR IMPULSE MODE if (msg[16]==1, { ( ~btn7val = (~btn7val + 1) % 3 ) ; switch( ~btn7val, 0, { ~granulator1.set(\impulsemodeindex, 0 ); "IMPULSE MODE FIXED".postln; }, 1, { ~granulator1.set(\impulsemodeindex, 1 ); "IMPULSE MODE DUST".postln; }, 2, { ~granulator1.set(\impulsemodeindex, 2 ); "IMPULSE MODE SENSOR".postln; }, ) }); // BUTTON X && X RESET/ZERO SENSORS [in firmware just here for notificaton] if (msg[12] == 1, { " ===== EULER ZEROED! =====".postln }, {}); // GTR INPUT ======================= if (msg[11]==1, { ( ~btn2val = (~btn2val + 1) % 3 ) ; switch(~btn2val, 0, { ~gtrIn.set(\in, 1 ); "DRY SIGNAL OFF".postln; }, 1, { ~gtrIn.set(\in, 0 ); "DRY SIGNAL ON".postln; }, 2, { ~gtrIn.set(\in, 1 ); "DRY + REVERB ON".postln; }, ) }); } // SHIFT ONE LOGIC ENDS HERE ================ ); /// closes SHIFT 1 } , '/keys'); ); ); GUI // ---------------------------------------------------- // ---------------------------------------------------- // 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, -1); ~granulator1.set(\rhigh, 1); ~granulator1.set(\rhigh, 2); ~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 ~gdurmode = 0 ; // random position ~gdurmode = 1 ; // random position ~gdurmode = 2 ; // random position ~gpanmode = 0 ; // random position ~gpanmode = 1 ; // random position ~gpanmode = 2 ; // random position // 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);