//TODO: turn off adcThru when recording, and turn it back on afterwards //TODO: Effects break panning for some unknown reason //TODO varying number of bars NRev reverb => LPF lpf => HPF hpf => Dyno fxLimiter => dac; Dyno outputDryLeft => dac.left; Dyno outputDryRight => dac.right; fxLimiter.limit(); outputDryLeft.limit(); outputDryRight.limit(); reverb @=> UGen @ outputWet; // Reference to wet output // Capture mic/line in and monitor through DAC. Limit adc => Dyno inputLimiter => Gain adcThru => fxLimiter; // Monitor input inputLimiter.limit(); inputLimiter @=> UGen @ mainInput; // Default parameters 0 => float adcThruLevel; 1 => int adcThruMute; adcThruLevel * adcThruMute => adcThru.gain; 10000 => lpf.freq; 10 => hpf.freq; 2::second => dur globalLoopTime; // Plug in the pedals LoopPedal pedals[4]; for( 0 => int i; i < pedals.cap(); i++ ) { pedals[i].recordFrom(mainInput); pedals[i].outputTo(outputWet, outputDryLeft, outputDryRight); } // Create the metronome Metronome metronome; spork ~metronome.run(); // Start listening to OSC messages OscIn oin; 9000 => oin.port; oin.listenAll(); OscMsg msg; // Event loop while (true) { oin => now; while (oin.recv(msg)) { if (msg.address=="/input") { msg.getFloat(0) => adc.gain; msg.getFloat(1) => adcThruLevel; adcThruLevel * adcThruMute => adcThru.gain; } else if(msg.address=="/delay") { msg.getFloat(0)::second => globalLoopTime; msg.getFloat(1) => float feedback; for( 0 => int i; i < pedals.cap(); i++ ) { pedals[i].setLoopPoint(globalLoopTime); pedals[i].setFeedback(feedback); } } else if(msg.address=="/channel") { msg.getInt(0) => int i; pedals[i].setGain(msg.getFloat(1)); pedals[i].setPan(msg.getFloat(2)); pedals[i].setWet(msg.getFloat(3)); } else if(msg.address=="/multiplier"){ msg.getInt(0) => int i; pedals[i].setLoopPoint(globalLoopTime * msg.getFloat(1)); } else if(msg.address=="/direction"){ msg.getInt(0) => int i; pedals[i].setDirection(msg.getFloat(1)); } else if(msg.address=="/arm") { msg.getInt(0) => int channel; (channel<0) => adcThruMute; adcThruLevel * adcThruMute => adcThru.gain; for( 0 => int i; i < pedals.cap(); i++ ) { pedals[i].arm(i==channel); } } else if(msg.address=="/metronome") { metronome.mute(msg.getInt(0)); } else if(msg.address=="/clear") { msg.getInt(0) => int channel; pedals[channel].clear(); } else if(msg.address=="/fx") { (100+msg.getFloat(0)*10000) => lpf.freq; (100+msg.getFloat(1)*10000) => hpf.freq; msg.getFloat(2) => reverb.mix; } else if(msg.address=="/master") { msg.getFloat(0) => float masterGain; masterGain => outputDryLeft.gain; masterGain => outputDryRight.gain; masterGain => fxLimiter.gain; } } } class LoopPedal { // We are wrapping a live sampler, LiSa LiSa sample; sample => Gain wet; sample => Pan2 dry; // Setup 10::second => sample.duration; // Allocate max 10 secs of memory 0::second => sample.recPos => sample.playPos; 1.0 => sample.feedback; 1 => sample.loop; dur loopTime; setLoopPoint(2::second); setWet(0.5); public void setLoopPoint( dur length ) { length => loopTime => sample.loopEnd => sample.loopEndRec; } public void setDirection( float direction ) { direction => sample.rate; } public void setFeedback( float fb ) { fb => sample.feedback; } public void setGain( float gain ) { gain => sample.gain; } public void setPan( float pan ) { pan => dry.pan; } public void setWet( float ratio ) { ratio => wet.gain; 1-ratio => dry.gain;} public void clear() { sample.clear(); } public void recordFrom(UGen ugen) { ugen => sample; } // TODO: maybe this should be % looptime/multiplier? public dur remaining() { return loopTime - sample.playPos(); } public void outputTo(UGen wetSink, UGen drySinkLeft, UGen drySinkRight) { 1 => sample.play; wet => wetSink; dry.left => drySinkLeft; dry.right => drySinkRight; } public void arm(int value) { sample.playPos() => sample.recPos; value => sample.record; } } class Metronome { // A simple metronome SinOsc s => ADSR a; 60 => s.freq; 0.6 => s.gain; a.set(0.001, .1, .5, .13); 10::ms => dur plipTime; fun void mute(int value) { if (value){ a => dac; } else { a =< dac; } } fun void run() { while(true) { // Compute the beat time globalLoopTime/4. - plipTime => dur beatTime; // Beep four times 0.15::second => a.releaseTime; a.keyOn(); plipTime => now; a.keyOff(); beatTime => now; 0.1::second => a.releaseTime; a.keyOn(); plipTime => now; a.keyOff(); beatTime => now; a.keyOn(); plipTime => now; a.keyOff(); beatTime => now; a.keyOn(); plipTime => now; a.keyOff(); pedals[0].remaining() => now; // Sync } } }