//-------------------------------------------------------------------- // 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 float 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; 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; true => sndbufs[i].loop; } // records to file 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; } } // sets up a one second deadzone for rerecording 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 >>>; // 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 msg.axisPosition => del.mix; } else if (msg.which == 1 && msg.axisPosition < 0) { // up axis, reverb -1*msg.axisPosition => rev.mix; } } } 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) { // start recording, stop current sndbuf if (POPULATED[cur]) { false => sndbufs[cur].loop; 0 => sndbufs[cur].rate; 10::ms => now; } true => record; spork ~ recordW(cur); cur => currentlyRecording; } else { // read from file, populate sndbuf, initiate deadzone false => record; 10::ms => now; true => sndbufs[currentlyRecording].loop; 1 => sndbufs[currentlyRecording].rate; me.dir()+Std.itoa(currentlyRecording)+"Output.wav" => sndbufs[currentlyRecording].read; 1 => POPULATED[currentlyRecording]; spork ~ recordDZ(); } } } else if (msg.which == 8) { // toggle left joystick lock !leftJoyLocked => leftJoyLocked; } 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) { 0 => cur; } else if (msg.idata == 2) { 1 => cur; } else if (msg.idata == 4) { 2 => cur; } else if (msg.idata == 8) { 3 => cur; } } } } } // adjust parameters in real time if the button is being held fun void paramAdjust() { while(true) { if (POPULATED[cur]) { if (buttonsDown[1]) { // increase play rate .0125 +=> PLAY_RATE[cur]; if( PLAY_RATE[cur] > 5 ) 5 => PLAY_RATE[cur]; PLAY_RATE[cur] => sndbufs[cur].rate; } if (buttonsDown[2]) { // decrease play rate .0125 -=> PLAY_RATE[cur]; if( PLAY_RATE[cur] < 0.2 ) 0.2 => PLAY_RATE[cur]; PLAY_RATE[cur] => sndbufs[cur].rate; } 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]; } } } } 10::ms => now; } }