From ca876469cbe5e76a8ab5001469d7aca117775fb0 Mon Sep 17 00:00:00 2001 From: Pete Shadbolt Date: Wed, 7 Jan 2015 00:05:48 +0000 Subject: [PATCH] Added dry/wet FX, fixed limiters, better referencing --- main.ck | 104 ++++++++++++++++++++++++++++++++++++-------------------- main.py | 29 ++++++++-------- 2 files changed, 82 insertions(+), 51 deletions(-) diff --git a/main.ck b/main.ck index 8615755..e0c7746 100644 --- a/main.ck +++ b/main.ck @@ -1,32 +1,34 @@ // TODO: turn off adcThru when recording -// Effects chain -adc => Dyno limitIn => Gain adcThru => dac; // Monitor input through a mixer -// Global effects break panning for some unknown reason -/*Dyno limitOut => JCRev rev => dac;*/ -/*Dyno limitOut => JCRev rev => dac;*/ -limitIn.limit(); limitOut.limit(); -SampleChan channels[4]; - -// Levels -//0 => adc.gain; -.5 => adcThru.gain; +// TODO: Effects break panning for some unknown reason + +// Capture mic/line in and monitor through DAC. Limit +adc => Dyno inputLimiter => Gain adcThru => dac; // Monitor input +inputLimiter.limit(); +inputLimiter @=> UGen @ mainInput; -// Global loop time +// Effects chain with limiters, reverb, filters +PRCRev reverb => LPF lpf => Dyno outputLimiter => dac; +outputLimiter.limit(); +reverb @=> UGen @ outputWet; // Reference to wet output +outputLimiter @=> UGen @ outputDry; // Reference to dry output + +// Default parameters +.5 => adcThru.gain; +10000 => lpf.freq; 1::second => dur loopTime; -// Each channel should output to the mixer -for( 0 => int i; i < channels.cap(); i++ ) { channels[i].outputTo(limitOut); } +// Plug in the pedals +LoopPedal pedals[4]; +for( 0 => int i; i < pedals.cap(); i++ ) { + pedals[i].recordFrom(mainInput); + pedals[i].outputTo(outputWet, outputDry); +} -// Listen to OSC messages +// Start listening to OSC messages OscIn oin; 9000 => oin.port; oin.listenAll(); OscMsg msg; -// Start the metronome -0 => int metronomeLevel; -//spork ~plip(); -//spork ~vu_meter(); - // Event loop while (true) { oin => now; @@ -38,51 +40,61 @@ while (true) { else if(msg.address=="/delay") { msg.getFloat(0)::second => loopTime; msg.getFloat(1) => float feedback; - for( 0 => int i; i < channels.cap(); i++ ) { - channels[i].setLoopPoint(loopTime); - channels[i].setFeedback(feedback); + for( 0 => int i; i < pedals.cap(); i++ ) { + pedals[i].setLoopPoint(loopTime); + pedals[i].setFeedback(feedback); } } else if(msg.address=="/channel") { msg.getInt(0) => int i; - channels[i].setGain(msg.getFloat(1)); - channels[i].setPan(msg.getFloat(2)); + pedals[i].setGain(msg.getFloat(1)); + pedals[i].setPan(msg.getFloat(2)); + pedals[i].setWet(msg.getFloat(3)); } else if(msg.address=="/arm") { msg.getInt(0) => int channel; - for( 0 => int i; i < channels.cap(); i++ ) { channels[i].arm(i==channel); } + for( 0 => int i; i < pedals.cap(); i++ ) { pedals[i].arm(i==channel); } } else if(msg.address=="/metronome") { - msg.getInt(0) => metronomeLevel; + //msg.getInt(0) => metronomeLevel; } else if(msg.address=="/clear") { msg.getInt(0) => int channel; - channels[channel].clear(); + pedals[channel].clear(); + } + else if(msg.address=="/fx") { + (100+msg.getFloat(0)*10000) => lpf.freq; } } } -public class SampleChan +public class LoopPedal { - // Chain - adc => LiSa sample => Pan2 panner; + // We are wrapping a live sampler, LiSa + LiSa sample; + sample => Gain wet; + sample => Gain dry; // Setup - 10::second => sample.duration; //This is the max duration + 10::second => sample.duration; // Allocate max 10 secs of memory 0::second => sample.recPos => sample.playPos; 1.0 => sample.feedback; 1 => sample.loop; setLoopPoint(1::second); + setWet(0.5); public void setLoopPoint( dur length ) { length => sample.loopEnd => sample.loopEndRec; } public void setFeedback( float fb ) { fb => sample.feedback; } - public void setGain( float gain ) { gain => panner.gain; } - public void setPan( float pan ) { pan => panner.pan; } + public void setGain( float gain ) { gain => sample.gain; } + public void setPan( float pan ) { } //pan => panner.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; } - public void outputTo(UGen ugen) { + public void outputTo(UGen wetSink, UGen drySink) { 1 => sample.play; - panner => ugen; + wet => wetSink; + dry => drySink; } public void arm(int value) { @@ -91,6 +103,24 @@ public class SampleChan } } + + + + + + + + + + + +/* + +// Start the metronome and the vu meter (optional) +//0 => int metronomeLevel; +//spork ~plip(); +//spork ~vu_meter(); + fun void vu_meter() { // Analysis stuff @@ -114,6 +144,7 @@ fun void vu_meter() } + // TODO timing here should be done using events fun void plip() { @@ -131,3 +162,4 @@ fun void plip() } } +*/ diff --git a/main.py b/main.py index 522edba..8f4b1d5 100644 --- a/main.py +++ b/main.py @@ -163,14 +163,16 @@ class Channel(wx.Panel): 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.mute.Bind(wx.EVT_TOGGLEBUTTON, self.update) self.update() def update(self, evt=None): gain=self.gain.GetValue()/100. pan=self.pan.GetValue()/100. + fxsend=self.fxsend.GetValue()/100. if self.mute.GetValue(): gain=0.0; - sendOSCSafe("/channel", [self.index, gain, pan]) + sendOSCSafe("/channel", [self.index, gain, pan, fxsend]) class Mixer(wx.Panel): @@ -213,28 +215,25 @@ class FXPanel(wx.Panel): wx.Panel.__init__(self, parent) sizer = wx.BoxSizer(wx.HORIZONTAL) - label = wx.StaticText(self, label="FX:") + label = wx.StaticText(self, label="Filter:") font = label.GetFont(); font.SetWeight(wx.BOLD); label.SetFont(font) sizer.Add(label, 0, wx.EXPAND|wx.TOP|wx.BOTTOM|wx.RIGHT, 5) - choices=["Low pass filter", "High pass filter", "Reverb"] - self.fxtype= wx.ComboBox(self, choices=choices, style=wx.CB_READONLY, size=(25,25)) - sizer.Add(self.fxtype, 1, wx.ALL|wx.EXPAND, 5) - self.fxtype.SetValue(choices[0]) + #choices=["Low pass filter", "High pass filter", "Reverb"] + #self.fxtype= wx.ComboBox(self, choices=choices, style=wx.CB_READONLY, size=(25,25)) + #sizer.Add(self.fxtype, 1, wx.ALL|wx.EXPAND, 5) + #self.fxtype.SetValue(choices[0]) - self.fxStrength=OSCSlider(self, "", default_value=0, align=False) - sizer.Add(self.fxStrength, 2, wx.EXPAND|wx.ALL, 5) + self.lpf=OSCSlider(self, "", default_value=0, align=False) + sizer.Add(self.lpf, 2, wx.EXPAND|wx.ALL, 5) + self.lpf.Bind(wx.EVT_SCROLL, self.update) self.SetSizerAndFit(sizer) - #self.update(None) + self.update(None) - """ def update(self, evt): - # Send OSC messages - a=self.delayTime.slider.GetValue()/100. - b=self.feedback.slider.GetValue()/100. - sendOSCSafe("/delay", [a, b]) - """ + a=self.lpf.slider.GetValue()/100. + sendOSCSafe("/fx", [a]) class OutputPanel(wx.Panel): ''' Handle the ADC input settings '''