//-------------------------------------------------------------------- // This program was developed using code from the following file: // // name: twilight-redux-kb.ck // desc: twilight instrument redux, keyboard edition // // author: Ge Wang (ge@ccrma.stanford.edu) //-------------------------------------------------------------------- 0.5 => dac.gain; // sndbuf volumes float MAIN_VOLUME[4]; // tracks which sndbufs are muted int MUTED[4]; // tracks which sndbufs are populated int POPULATED[4]; // tracks sndbuf playrates int PLAY_RATE[4]; // current sndbuf modified 0 => int cur; // keep track of which SndBuf is actually being recorded to 0 => int currentlyRecording; // controller variables false => int leftJoyLocked; false => int rightJoyLocked; 1 => float freqMultiplier; int buttonsDown[11]; false => int record; false => int recordDeadzone; // prepare SndBuf array (use one SndBuf per sound) SndBuf sndbufs[4]; SndBuf sndbuf0 => sndbufs[0]; SndBuf sndbuf1 => sndbufs[1]; SndBuf sndbuf2 => sndbufs[2]; SndBuf sndbuf3 => sndbufs[3]; Shred @ loops[4]; // patch it PoleZero blocker => Echo del => PRCRev rev => LPF lpf => dac; // pole location to block DC and ultra low frequencies .99 => blocker.blockZero; // set up delay and reverb 100::ms => del.delay; 0 => del.mix; 0 => rev.mix; 20000 => lpf.freq; 2 => lpf.Q; // initialization function for (0 => int i; i < 4; i++) { 1 => MAIN_VOLUME[i]; 0 => MUTED[i]; 0 => POPULATED[i]; 1 => PLAY_RATE[i]; sndbufs[i] => blocker; } fun void loop(int which) { while(true) { 0 => sndbufs[which].pos; sndbufs[which].length() => now; } } fun void recordW(int which) { adc => WvOut2 w => blackhole; me.dir()+Std.itoa(which)+"Output" => w.wavFilename; 1 => w.fileGain; null @=> w; while(record) { 1::ms => now; } } fun void recordDZ() { true => recordDeadzone; 1::second => now; false => recordDeadzone; } // HID objects Hid hi; HidMsg msg; // which joystick 0 => int device; // get from command line if(me.args()) me.arg(0) => Std.atoi => device; // open joystick 0, exit on fail if(!hi.openJoystick(device)) me.exit(); // log <<< "joystick '" + hi.name() + "' ready", "" >>>; // spork it spork ~ joy(); spork ~ adjustLPF(); spork ~ paramAdjust(); // constant application of freqMultiplier to lpf freq fun void adjustLPF() { while (true) { lpf.freq() => float newFreq; freqMultiplier *=> newFreq; if (newFreq < 200) { 200 => newFreq; } else if (newFreq > 20000) { 20000 => newFreq; } newFreq => lpf.freq; 5::ms => now; } } // print while(true) { // values string recordingStr; if (record) { "RECORDING" => recordingStr; } else { "" => recordingStr; } <<< "(sndbuf", Std.itoa(cur)+")", "muted:", MUTED[cur], "gain:", MAIN_VOLUME[cur], "rate:", PLAY_RATE[cur], recordingStr, "\n(global) lpf:", lpf.freq(), "Hz reverb:", rev.mix(), "delay:", del.mix(), "left joy locked:", leftJoyLocked, "right joy locked:", rightJoyLocked >>>; // advance time 10::ms => now; } // joystick control fun void joy() { // infinite event loop while( true ) { // wait on HidIn as event hi => now; // messages received while(hi.recv(msg)) { // joystick axis motion if(msg.isAxisMotion()) { if (msg.which != 2 && Std.fabs(msg.axisPosition) > 0.05) { // joysticks if (!leftJoyLocked) { // global delay/reverb if (msg.which == 0 && msg.axisPosition > 0) { // right axis, delay //<<< "instrument reverb mix:", msg.axisPosition / 4 >>>; msg.axisPosition => del.mix; } else if (msg.which == 1 && msg.axisPosition < 0) { // up axis, reverb //<<< "drum reverb mix:", -1*msg.axisPosition / 4 >>>; -1*msg.axisPosition => rev.mix; } } if (!rightJoyLocked) { // figure out what to do here if (msg.which == 3) { // grain pos randomness //<<< "instrument delay mix:", msg.axisPosition / 4 >>>; //.0025+.0025*msg.axisPosition => GRAIN_POSITION_RANDOM[cur]; } } } else if (msg.which == 2) { // triggers 1 => freqMultiplier; if (Math.fabs(msg.axisPosition) > 0.25) { // 0.75 to 1 on left, 1 to 1.25 on right if (msg.axisPosition > 0) { 1-(msg.axisPosition-0.25)/15 => freqMultiplier; } else { 1-(msg.axisPosition+0.25)/15 => freqMultiplier; } } } } // joystick button down else if(msg.isButtonDown()) { 1 => buttonsDown[msg.which]; if (msg.which == 0) { // toggle recording if (!recordDeadzone) { if (!record) { if (loops[cur] != null) { Machine.remove(loops[cur].id()); 10::ms => now; } true => record; spork ~ recordW(cur); cur => currentlyRecording; } else { false => record; 10::ms => now; me.dir()+Std.itoa(currentlyRecording)+"Output.wav" => sndbufs[currentlyRecording].read; spork ~ loop(currentlyRecording) @=> loops[currentlyRecording]; 1 => POPULATED[currentlyRecording]; spork ~ recordDZ(); } } } else if (msg.which == 8) { // toggle left joystick lock !leftJoyLocked => leftJoyLocked; } else if (msg.which == 9) { // toggle right joystick lock !rightJoyLocked => rightJoyLocked; } else if (msg.which == 10 && POPULATED[cur]) { // toggle local gain if (MAIN_VOLUME[cur] != 0) { if (sndbufs[cur].gain() == 0) { for (0 => int i; i < 1000; i++) { sndbufs[cur].gain(sndbufs[cur].gain()+MAIN_VOLUME[cur]/1000); 0.5::ms => now; } MAIN_VOLUME[cur] => sndbufs[cur].gain; sndbufs[cur].gain() => MAIN_VOLUME[cur]; 0 => MUTED[cur]; } else { for (0 => int i; i < 1000; i++) { sndbufs[cur].gain(sndbufs[cur].gain()-MAIN_VOLUME[cur]/1000); 0.5::ms => now; } 0 => sndbufs[cur].gain; 1 => MUTED[cur]; } } } } // joystick button up else if(msg.isButtonUp()) { 0 => buttonsDown[msg.which]; } // joystick hat/POV switch/d-pad motion else if(msg.isHatMotion()) { if (msg.idata == 1) { // w 0 => cur; } else if (msg.idata == 2) { // x 1 => cur; } else if (msg.idata == 4) { // y 2 => cur; } else if (msg.idata == 8) { // z 3 => cur; } } } } } // adjust parameters in real time if the button is being held fun void paramAdjust() { while(true) { if (POPULATED[cur]) { if (buttonsDown[0]) { // grain size down //.99 *=> GRAIN_LENGTH[cur]; //if( GRAIN_LENGTH[cur] < 1::ms ) 1::ms => GRAIN_LENGTH[cur]; } if (buttonsDown[1]) { // gain position right //.001 +=> GRAIN_POSITION_GOAL[cur]; //if( GRAIN_POSITION_GOAL[cur] > 1 ) 1 => GRAIN_POSITION_GOAL[cur]; } if (buttonsDown[2]) { // grain position left //.001 -=> GRAIN_POSITION_GOAL[cur]; //if( GRAIN_POSITION_GOAL[cur] < 0 ) 0 => GRAIN_POSITION_GOAL[cur]; } if (buttonsDown[3]) { // grain size up //1.01 *=> GRAIN_LENGTH[cur]; //if( GRAIN_LENGTH[cur] > 1::second ) 1::second => GRAIN_LENGTH[cur]; } if (buttonsDown[4]) { // local gain decrease if (MAIN_VOLUME[cur] > 0) { 0.01 -=> MAIN_VOLUME[cur]; if (MAIN_VOLUME[cur] < 0) 0 => MAIN_VOLUME[cur]; if (!MUTED[cur]) { MAIN_VOLUME[cur] => sndbufs[cur].gain; sndbufs[cur].gain() => MAIN_VOLUME[cur]; } } } if (buttonsDown[5]) { // local gain increase if (MAIN_VOLUME[cur] < 1) { 0.01 +=> MAIN_VOLUME[cur]; if (MAIN_VOLUME[cur] > 1) 1 => MAIN_VOLUME[cur]; if (!MUTED[cur]) { MAIN_VOLUME[cur] => sndbufs[cur].gain; sndbufs[cur].gain() => MAIN_VOLUME[cur]; } } } if (buttonsDown[6]) { // decrease grain play rate //.0025 -=> GRAIN_PLAY_RATE[cur]; //if( GRAIN_PLAY_RATE[cur] < 0 ) 0 => GRAIN_PLAY_RATE[cur]; } if (buttonsDown[7]) { // increase grain play rate //.0025 +=> GRAIN_PLAY_RATE[cur]; //if( GRAIN_PLAY_RATE[cur] > 2 ) 2 => GRAIN_PLAY_RATE[cur]; } } 10::ms => now; } }