diff --git a/main.ck b/main.ck index 1b4268b..04b7fcc 100644 --- a/main.ck +++ b/main.ck @@ -1,29 +1,32 @@ //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 outputLimiter => dac; -outputLimiter.limit(); +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 -outputLimiter @=> UGen @ outputDry; // Reference to dry output -outputLimiter @=> UGen @ mainOutput; // Reference to main output // Capture mic/line in and monitor through DAC. Limit -adc => Dyno inputLimiter => Gain adcThru => mainOutput; // Monitor input +adc => Dyno inputLimiter => Gain adcThru => fxLimiter; // Monitor input inputLimiter.limit(); inputLimiter @=> UGen @ mainInput; // Default parameters -1 => float adcThruLevel; +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, outputDry); + pedals[i].outputTo(outputWet, outputDryLeft, outputDryRight); } // Create the metronome @@ -45,10 +48,10 @@ while (true) { adcThruLevel * adcThruMute => adcThru.gain; } else if(msg.address=="/delay") { - msg.getFloat(0)::second => dur loopTime; + msg.getFloat(0)::second => globalLoopTime; msg.getFloat(1) => float feedback; for( 0 => int i; i < pedals.cap(); i++ ) { - pedals[i].setLoopPoint(loopTime); + pedals[i].setLoopPoint(globalLoopTime); pedals[i].setFeedback(feedback); } } @@ -58,6 +61,10 @@ while (true) { 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=="/arm") { msg.getInt(0) => int channel; (channel<0) => adcThruMute; @@ -77,7 +84,10 @@ while (true) { msg.getFloat(2) => reverb.mix; } else if(msg.address=="/master") { - msg.getFloat(0) => mainOutput.gain; + msg.getFloat(0) => float masterGain; + masterGain => outputDryLeft.gain; + masterGain => outputDryRight.gain; + masterGain => fxLimiter.gain; } } } @@ -87,31 +97,34 @@ class LoopPedal // We are wrapping a live sampler, LiSa LiSa sample; sample => Gain wet; - sample => Gain dry; - dur loopTime; + 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; - /*.5 => sample.rate;*/ - setLoopPoint(1::second); + dur loopTime; + setLoopPoint(2::second); setWet(0.5); - public void setLoopPoint( dur length ) { length => loopTime => sample.loopEnd => sample.loopEndRec; } + public void setLoopPoint( dur length ) { + length => loopTime => sample.loopEnd => sample.loopEndRec; + } public void setFeedback( float fb ) { fb => sample.feedback; } public void setGain( float gain ) { gain => sample.gain; } - public void setPan( float pan ) { } //pan => panner.pan; } + 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 drySink) { + public void outputTo(UGen wetSink, UGen drySinkLeft, UGen drySinkRight) { 1 => sample.play; wet => wetSink; - dry => drySink; + dry.left => drySinkLeft; + dry.right => drySinkRight; } public void arm(int value) { @@ -125,7 +138,9 @@ class Metronome { // A simple metronome SinOsc s => ADSR a; + 60 => s.freq; 0.5 => s.gain; + 0.6 => s.gain; a.set(0.001, .1, .5, .13); 10::ms => dur plipTime; @@ -134,21 +149,21 @@ class Metronome } fun void run() { - while(true) { - // Compute the beat time - pedals[0].loopTime/4. - plipTime => dur beatTime; - - // Beep four times - 50 => s.freq; - a.keyOn(); plipTime => now; a.keyOff(); - beatTime => now; - 50 => s.freq; - 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 - } + 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 + } } } diff --git a/main.py b/main.py index b719ac3..aa0dea7 100644 --- a/main.py +++ b/main.py @@ -188,16 +188,18 @@ class Channel(wx.Panel): self.speed.SetValue(choices[0]) sizer.Add(self.speed, 0, wx.ALL | wx.EXPAND, 3) - choices = ["Live →", "Live ←", "Live ↔", "loop1.wav", "loop2.wav", "loop3.wav"] - self.speed = wx.ComboBox(self, choices=choices, style=wx.CB_READONLY, size=(25, 25)) - self.speed.SetValue(choices[0]) - sizer.Add(self.speed, 0, wx.ALL | wx.EXPAND, 3) + choices = ["Live →", "Live ←", "Live ↔", "Half speed"] + self.direction = wx.ComboBox(self, choices=choices, style=wx.CB_READONLY, size=(25, 25)) + self.direction.SetValue(choices[0]) + sizer.Add(self.direction, 0, wx.ALL | wx.EXPAND, 3) self.SetSizerAndFit(sizer) self.gain.Bind(wx.EVT_SCROLL, self.update) self.pan.Bind(wx.EVT_SCROLL, self.update) self.fxsend.Bind(wx.EVT_SCROLL, self.update) + self.speed.Bind(wx.EVT_COMBOBOX, self.update_multiplier) + self.direction.Bind(wx.EVT_TOGGLEBUTTON, self.update_direction) self.mute.Bind(wx.EVT_TOGGLEBUTTON, self.update) self.update() @@ -205,10 +207,23 @@ class Channel(wx.Panel): gain = self.gain.GetValue() pan = self.pan.GetValue() fxsend = self.fxsend.GetValue() - if self.mute.GetValue(): - gain = 0.0 + if self.mute.GetValue(): gain = 0.0 sendOSCSafe("/channel", [self.index, gain, pan, fxsend]) + def update_multiplier(self, evt=None): + multiplierTable = {"1 bar": 1., "2 bars": 2., "4 bars": 4., "Dephase": 1.3} + multiplier = multiplierTable[self.speed.GetValue()] + sendOSCSafe("/multiplier", [self.index, multiplier]) + + def update_direction(self, evt=None): + #multiplierTable = {"1 bar": 1., "2 bars": 2., "4 bars": 4., "Dephase": 1.3} + directionTable = {"Live →":0, "Live ←"1, "Live ↔"2, "Half speed"3} + + direction = directionTable[self.speed.GetValue()] + sendOSCSafe("/direction", [self.index, direction]) + + + class Mixer(wx.Panel): diff --git a/scratch.ck b/scratch.ck index c2fa206..12c0cc1 100644 --- a/scratch.ck +++ b/scratch.ck @@ -1,44 +1,18 @@ // the event -KBHit kb; +Dyno d; +SinOsc s => Pan2 p; +p.left => JCRev revr => dac.left; +p.right => JCRev revl => dac.right; +100 => s.freq; +.2 => s.gain; +.1 => p.gain; -class MetronomeEvent extends Event{ int value; } +-1 => p.pan; +1::second => now; -class Metronome { - MetronomeEvent metronomeEvent; - spork ~pulse(); +0 => p.pan; +1::second => now; - fun void listen(){ - while (true){ - metronomeEvent => now; - <<<"Metronome got event " + metronomeEvent.value>>>; - if (metronomeEvent.value==0){ - spork ~pulse(); - } - } - } +1 => p.pan; +1::second => now; - fun void pulse(){ - 1::second => now; - 0=>metronomeEvent.value; - metronomeEvent.signal(); - } - - fun void signal(){ - 1=>metronomeEvent.value; - metronomeEvent.signal(); - } -} - -Metronome m; -spork ~m.listen(); - -// time-loop -while( true ) -{ - kb => now; - while( kb.more() ) - { - <<< "ascii: ", kb.getchar() >>>; - m.signal(); - } -}