gtr/gtr.scd

576 lines
18 KiB
Plaintext

////////////////////////////////////////////////////
/* GRANULATING SAMPLER INSTRUMENT //////////////////
////////////////////////////////////rc@kiben.net////
////////////////////////////////////////////////////
| .-.
| / \ .-.
| / \ / \ .-. .-. _
+--/-------\-----/-----\-----/---\---/---\---/-\-
| / \ / \ / '-' '-'
|/ '-' '-'
Ljudmila OTF Hackathon, Maribor 1-6 March 2022 */
// GTR MAC address: 10:97:BD:36:D6:4E
(
s.reboot{
s.options.numBuffers = 1024 * 256; // increase this if you need to load more samples
s.options.sampleRate = 44100; // also tried with 44000 value
s.options.memSize = 8192 * 32; // increase this if you get "alloc failed" messages
s.options.numWireBufs = 64; // increase this if you get "exceeded number of interconnect buffers" messages
s.options.maxNodes = 1024 * 32; // increase this if you are getting drop outs and the message "too many nodes"
s.options.numInputBusChannels = 4;
s.options.numOutputBusChannels = 4;
} )
// 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 = 0.5,
sndbuf, envbuf, pan=0, imp=50,
pitchmodeindex=0, sensorpitch=1, sensorgdur=0.1, sensorgpan=0,
positionmodeindex=1, gdurmodeindex=0, gpanmodeindex=0,
sensorposition=0, impulsemodeindex=0, sensorimpulse=0,
signalChannelIndex=1,
rlow= -1, rhigh=10 |
var signal, env, freqdev, pos,
pitchmode0, pitchmode1, pitch,
gdurmode0, gdurmode1, gdurmode2, gdurmode3, gdurmode4, gdurmode5, gdurmode6, gdur,
gpanmode0, gpanmode1, gpan,
positionmode0, positionmode1, positionmode2, position,
impulsemode0, impulsemode1, impulse,
stereosignal, quadsignalL, quadsignalR, quadsignal, signalchannels;
// grain duration mode -untransposed, random, or sensor controlled
gdurmode0 = 0.05;
gdurmode1 = 0.1;
gdurmode2 = LFNoise1.kr.range(0.1, 0.3);
gdurmode3 = LFNoise1.kr.range(0.1, 0.6);
gdurmode4 = LFNoise1.kr.range(0.6, 0.6);
gdurmode5 = LFNoise1.kr.range(0.1, 2.6);
gdurmode6 = LFNoise1.kr.range(1, 2);
gdur = Select.kr(gdurmodeindex,
[gdurmode0, gdurmode1, gdurmode2, gdurmode3, gdurmode4, gdurmode5, gdurmode6, sensorgdur]);
// grain pan mode -untransposed, random, or sensor controlled
gpanmode0 = 0;
gpanmode1 = LFNoise1.kr(100).range(-1, 1);
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, sensorpitch, pitchmode1 ]);
// granular playhead mode - fixed random or sensor controlled
positionmode0 = 0.1;
positionmode0 = (Phasor.ar(0, 1 * BufRateScale.ir(b), 0, BufSamples.ir(b)-1) + LFNoise1.ar(100).bipolar(0.1 * SampleRate.ir) ) / BufSamples.ir(b);
positionmode1 = LFNoise1.kr.range(0.05, 0.98);
positionmode2 = LFNoise1.kr.range(0.1, 0.2);
position = Select.kr(positionmodeindex,
[positionmode0, positionmode1, positionmode2, 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(~gpanmode=1;
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 = TGrains.ar(4, impulse, b, pitch, position, gdur, gpan, amp, 4);
stereosignal = signal* env;
quadsignalL = PanAz.ar(4, signal[0], MouseX.kr(0,2));
quadsignalR = PanAz.ar(4, signal[1], MouseX.kr(0,2).range(2,0));
quadsignal = signal; //Mix.ar([quadsignalL, quadsignalR]);
signalchannels = Select.ar(signalChannelIndex, [stereosignal, quadsignal]);
//signal = signalchannels;
Out.ar(0, signalchannels);
}).add;
);
SynthDef(\buf_tgrain, { | out, gate = 1, amp = 0.5,
sndbuf, envbuf, pan=0, imp=50,
pitchmodeindex=0, sensorpitch=1, sensorgdur=0.1, sensorgpan=0,
positionmodeindex=1, gdurmodeindex=0, gpanmodeindex=0,
sensorposition=0, impulsemodeindex=0, sensorimpulse=0,
signalChannelIndex=1,
rlow= -1, rhigh=10 |
var signal, env, freqdev, pos,
pitchmode0, pitchmode1, pitch,
gdurmode0, gdurmode1, gdurmode2, gdurmode3, gdurmode4, gdurmode5, gdurmode6, gdur,
gpanmode0, gpanmode1, gpan,
positionmode0, positionmode1, positionmode2, position,
impulsemode0, impulsemode1, impulse,
stereosignal, quadsignalL, quadsignalR, quadsignal, signalchannels;
// grain duration mode -untransposed, random, or sensor controlled
gdurmode0 = 0.05;
gdurmode1 = 0.1;
gdurmode2 = LFNoise1.kr.range(0.1, 0.3);
gdurmode3 = LFNoise1.kr.range(0.1, 0.6);
gdurmode4 = LFNoise1.kr.range(0.6, 0.6);
gdurmode5 = LFNoise1.kr.range(0.1, 2.6);
gdurmode6 = LFNoise1.kr.range(1, 2);
gdur = Select.kr(gdurmodeindex,
[gdurmode0, gdurmode1, gdurmode2, gdurmode3, gdurmode4, gdurmode5, gdurmode6, sensorgdur]);
// grain pan mode -untransposed, random, or sensor controlled
gpanmode0 = 0;
gpanmode1 = LFNoise1.kr(100).range(-1, 1);
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, sensorpitch, pitchmode1 ]);
// granular playhead mode - fixed random or sensor controlled
positionmode0 = 0.1;
positionmode0 = (Phasor.ar(0, 1 * BufRateScale.ir(b), 0, BufSamples.ir(b)-1) + LFNoise1.ar(100).bipolar(0.1 * SampleRate.ir) ) / BufSamples.ir(b);
positionmode1 = LFNoise1.kr.range(0.05, 0.98);
positionmode2 = LFNoise1.kr.range(0.1, 0.2);
position = Select.kr(positionmodeindex,
[positionmode0, positionmode1, positionmode2, 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(~gpanmode=1;
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 = TGrains.ar(4, impulse, b, pitch, position, gdur, gpan, amp, 4);
//signal = FreeVerb2.ar(signal[0], signal[1], mix:0.4, room:0.5, damp:0);
stereosignal = signal* env;
quadsignalL = PanAz.ar(4, signal[0], MouseX.kr(0,2));
quadsignalR = PanAz.ar(4, signal[1], MouseX.kr(0,2).range(2,0));
quadsignal = signal; //Mix.ar([quadsignalL, quadsignalR]);
signalchannels = Select.ar(signalChannelIndex, [stereosignal, quadsignal]);
//signal = signalchannels;
Out.ar(0, signalchannels);
}).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=1; ~channelmode=0;
~btnstate = [];
~btnsA = [];
~btnsB = [];
~btnsC = [];
~btn0val = 0; ~btn1val = 0; ~btn2val = 0; ~btn3val = 0;
~btn4val = 0; ~btn5val = 0; ~btn6val = 0; ~btn7val = 0;
~btn8val = 0; // shift buttons
( // 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.05, 3.99));
~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 );
~granulator1.set(\sensorgpan, msg[2].linlin(-1, 1, -1, 1));
~granulator1.set(\signalChannelIndex, ~channelmode );
//msg.postln;
}; , '/euler');
);
// ----------------------------------------------------
// button press mapping ///////////////////////////////
// ----------------------------------------------------
// send message back to nodejs
m = NetAddr("127.0.0.1", 57100);
m.sendMsg("/xyzc", 1);
m.sendMsg("/xyzc", 0);
p = OSCdef(\keys, { arg msg, time, addr, recvPort;
~btnsA[~btn2val, ~btn3val];
~btnsB[~btn4val, ~btn5val, ~btn6val, ~btn7val];
~btnsC[~btn5val];
~btnstate = [~btnsA, ~btnsB, ~btnsC];
if (msg[9] == 1 && msg[10] == 1, {~btnstate.postln;});
//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) % 7 ) ;
switch(~btn8val,
0, { ~gdurmode = 0; ~granulator1.set(\imp, 40); "DURATION MODE 0".postln; },
1, { ~gdurmode = 1; ~granulator1.set(\imp, 0); "DURATION MODE 1".postln; },
2, { ~gdurmode = 2; ~granulator1.set(\imp, 20); "DURATION MODE 2".postln; },
3, { ~gdurmode = 3; ~granulator1.set(\imp, 15); "DURATION MODE 3".postln; },
4, { ~gdurmode = 4; ~granulator1.set(\imp, 10); "DURATION MODE 4".postln; },
5, { ~gdurmode = 5; ~granulator1.set(\imp, 5); "DURATION MODE 5".postln; },
6, { ~gdurmode = 6; ~granulator1.set(\imp, 3); "DURATION MODE 6".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) % 7 ) ;
switch(~btn6val,
0, { ~pitchmode = 0; "PITCH MODE FIXED".postln; },
1, { ~pitchmode = 1; "PITCH MODE SENSOR".postln; },
2, { ~pitchmode = 2; ~granulator1.set(\rlow, 0.8); ~granulator1.set(\rhigh, 1.2); "PITCH RANDOM 1".postln; },
3, { ~pitchmode = 2; ~granulator1.set(\rlow, 0); ~granulator1.set(\rhigh, 1.5); "PITCH MODE RANDOM 2".postln; },
4, { ~pitchmode = 2; ~granulator1.set(\rlow, -1.5 ); ~granulator1.set(\rhigh, 0); "PITCH MODE RANDOM 3".postln; },
5, { ~pitchmode = 2; ~granulator1.set(\rlow, -5 ); ~granulator1.set(\rhigh, 5); "PITCH MODE RANDOM 4".postln; },
6, { ~pitchmode = 2; ~granulator1.set(\rlow, -30 ); ~granulator1.set(\rhigh, 30); "PITCH MODE RANDOM 5".postln; },
7, { ~pitchmode = 2; ~granulator1.set(\rlow, -100 ); ~granulator1.set(\rhigh, 100); "PITCH MODE RANDOM 6".postln; },
~granulator1.set(\rhigh, 2);
2, { },
)
});
// 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');
);
);
// ----------------------------------------------------
// ----------------------------------------------------
// 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, -1);
~granulator1.set(\rlow, 0.2);
~granulator1.set(\rhigh, 2);
~granulator1.set(\rhigh, 1.2);
~impulsemode = 0; // impulse
~impulsemode = 1; // dust
~impulsemode = 2; // sensor
~pitchmode = 0; // no transpose
~pitchmode = 1; // sensor (pitch) input
~pitchmode = 2; // random2
~pitchmode = 3; // random3
~pitchmode = 4; // random4
~pitchmode = 5; // random5
~pitchmode = 6; //
~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
~gdurmode = 3 ; // random position
~gdurmode = 4 ; // random position
~gdurmode = 5 ; // random position
~gdurmode = 6 ; // random position
~gpanmode = 0 ; // random position
~gpanmode = 1 ; // random position
~gpanmode = 2 ; // random position
~channelmode = 1;
// set grain impulse rate
~granulator1.set(\imp, 10);
// fix doneaction
~granulator1.set(\gate, 1); // granulator on
~granulator1.set(\gate, 0); // granulator off
a = Scale.major;
/////////////////////////////////////////////////
// -----------------------------------------------
// -----------------------------------------------
// -----------------------------------------------
// 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);