| @@ -6,11 +6,8 @@ adc => LiSa sample => mixer; // Sampler | |||
| //Times | |||
| 10::second => sample.duration; | |||
| 0::second => sample.recPos; | |||
| 1::second => sample.playPos => sample.loopEnd => sample.loopEndRec; | |||
| // Start recording and playing in a loop | |||
| 1 => sample.loop => sample.record => sample.play; | |||
| 0::second => sample.recPos => sample.playPos; | |||
| 1::second => sample.loopEnd => sample.loopEndRec; | |||
| // Levels | |||
| //0 => adc.gain; | |||
| @@ -18,60 +15,39 @@ adc => LiSa sample => mixer; // Sampler | |||
| .5 => sample.gain; | |||
| .5 => adcThru.gain; | |||
| // OSC listener class | |||
| class OSCListener { | |||
| fun void run(int port, string address) { | |||
| OscRecv recv; port => recv.port; recv.listen(); | |||
| recv.event(address) @=> OscEvent oe; | |||
| while (true) { oe => now; while (oe.nextMsg() != 0) { this.handle(oe); } } | |||
| me.yield(); | |||
| } | |||
| fun void handle(OscEvent oe){}; | |||
| } | |||
| // Start recording and playing in a loop | |||
| 1 => sample.loop => sample.record => sample.play; | |||
| // define child class Y | |||
| class InputListener extends OSCListener { | |||
| fun void handle(OscEvent oe){ | |||
| oe.getFloat() => adc.gain; | |||
| oe.getFloat() => adcThru.gain; | |||
| <<< "Edit input" >>>; | |||
| } | |||
| // Listen to OSC messages | |||
| OscIn oin; 9000 => oin.port; | |||
| oin.listenAll(); | |||
| OscMsg msg; | |||
| // Event loop | |||
| while (true) { | |||
| oin => now; | |||
| while (oin.recv(msg)) { | |||
| <<<msg.address>>>; | |||
| if (msg.address=="/input") | |||
| controlInput(msg); | |||
| else if(msg.address=="/delay") | |||
| controlDelay(msg); | |||
| else if(msg.address=="/channel") | |||
| controlChannel(msg); | |||
| } | |||
| } | |||
| // define child class Y | |||
| class DelayListener extends OSCListener | |||
| { | |||
| fun void handle(OscEvent oe){ | |||
| //TODO: this doesn't work | |||
| // oe.getFloat()::second => sample.recPos => sample.loopEnd => sample.loopEndRec; | |||
| //oe.getFloat()::second => sample.playPos => sample.loopEnd => sample.loopEndRec; | |||
| oe.getFloat(); | |||
| oe.getFloat() => sample.feedback; | |||
| <<< "Edit delay" >>>; | |||
| } | |||
| fun void controlInput(OscMsg msg){ | |||
| msg.getFloat(0) => adc.gain; | |||
| msg.getFloat(1) => adcThru.gain; | |||
| } | |||
| // define child class Y | |||
| class ChannelListener extends OSCListener | |||
| { | |||
| fun void handle(OscEvent oe){ | |||
| oe.getInt() => int channel; | |||
| oe.getFloat(); | |||
| oe.getFloat(); | |||
| <<< "Edit channel" >>>; | |||
| } | |||
| fun void controlDelay(OscMsg msg){ | |||
| msg.getFloat(0)::second => sample.loopEnd => sample.loopEndRec; | |||
| msg.getFloat(1) => sample.feedback; | |||
| } | |||
| InputListener il; | |||
| DelayListener dl; | |||
| ChannelListener cl; | |||
| spork ~ il.run(9000, "/input, f, f"); | |||
| spork ~ dl.run(9000, "/delay, f, f"); | |||
| spork ~ cl.run(9000, "/channel, i, f, f"); | |||
| // Loop forever | |||
| while(true) { 1::second => now; } | |||
| fun void controlChannel(OscMsg msg){ | |||
| msg.getInt(0) => int channel; | |||
| msg.getFloat(1) => sample.gain; | |||
| } | |||
| @@ -12,7 +12,8 @@ class OSCSlider(wx.Panel): | |||
| self.slider=wx.Slider(self, value=default_value*100, minValue=min_value*100, maxValue=max_value*100) | |||
| sizer.Add(self.slider, 1, wx.EXPAND) | |||
| self.SetSizerAndFit(sizer) | |||
| self.Bind=self.Bind | |||
| self.Bind=self.slider.Bind | |||
| self.GetValue=self.slider.GetValue | |||
| class CommsPanel(wx.Panel): | |||
| @@ -62,6 +63,7 @@ class InputPanel(wx.Panel): | |||
| self.gain.Bind(wx.EVT_SCROLL, self.update) | |||
| self.thru.Bind(wx.EVT_SCROLL, self.update) | |||
| self.mute.Bind(wx.EVT_TOGGLEBUTTON, self.update) | |||
| self.update() | |||
| def update(self, evt=None): | |||
| @@ -91,6 +93,9 @@ class DelayPanel(wx.Panel): | |||
| self.feedback=OSCSlider(self, "Feedback", default_value=.99) | |||
| sizer.Add(self.feedback, 0, wx.EXPAND|wx.ALL, 5) | |||
| self.metronome=wx.ToggleButton(self, 0, "Metronome") | |||
| sizer.Add(self.metronome, 0, wx.EXPAND|wx.ALL, 5) | |||
| self.SetSizerAndFit(sizer) | |||
| self.delayTime.Bind(wx.EVT_SCROLL, self.update) | |||
| self.feedback.Bind(wx.EVT_SCROLL, self.update) | |||
| @@ -116,10 +121,8 @@ class Channel(wx.Panel): | |||
| font = label.GetFont(); font.SetWeight(wx.BOLD); label.SetFont(font) | |||
| sizer.Add(label, 0, wx.TOP|wx.BOTTOM|wx.RIGHT, 5) | |||
| self.gain = OSCSlider(self, "Gain", default_value=0, align=False) | |||
| self.gain = OSCSlider(self, "Gain", default_value=1, max_value=1.3, align=False) | |||
| sizer.Add(self.gain, 0, wx.ALL|wx.EXPAND, 3) | |||
| self.pan = OSCSlider(self, "Pan", min_value=-1, max_value=1, default_value=0, align=False) | |||
| sizer.Add(self.pan, 0, wx.ALL|wx.EXPAND, 3) | |||
| self.record = wx.ToggleButton(self, 1, "Arm") | |||
| sizer.Add(self.record, 0, wx.ALL|wx.EXPAND if index==0 else wx.ALL|wx.EXPAND, 3) | |||
| @@ -130,12 +133,17 @@ class Channel(wx.Panel): | |||
| self.SetSizerAndFit(sizer) | |||
| self.gain.Bind(wx.EVT_SCROLL, self.update) | |||
| self.pan.Bind(wx.EVT_SCROLL, self.update) | |||
| self.mute.Bind(wx.EVT_TOGGLEBUTTON, self.update) | |||
| self.update() | |||
| def update(self, evt): | |||
| def update(self, evt=None): | |||
| print "Channel %d: send gain, pan, mute" % self.index | |||
| gain=self.gain.GetValue()/100. | |||
| if self.mute.GetValue(): gain=0.0; | |||
| try: | |||
| sendOSCMsg("/channel", [self.index, gain]) | |||
| except OSCClientError: | |||
| pass | |||
| class Mixer(wx.Panel): | |||
| @@ -151,6 +159,7 @@ class Mixer(wx.Panel): | |||
| c.record.Bind(wx.EVT_TOGGLEBUTTON, self.switch_record) | |||
| c.record.index=i | |||
| c.clear.Bind(wx.EVT_BUTTON, self.clear_channel) | |||
| c.clear.index=i | |||
| self.channels.append(c) | |||
| sizer.Add(c, 1, wx.EXPAND) | |||
| @@ -163,10 +172,15 @@ class Mixer(wx.Panel): | |||
| for i, c in enumerate(self.channels): | |||
| c.record.SetValue(0) | |||
| self.channels[index].record.SetValue(value) | |||
| if value: | |||
| print "Record on channel %d" % index | |||
| else: | |||
| print "Stop recording on all channels" | |||
| def clear_channel(self, evt): | |||
| """ Send OSC message to clear a channel """ | |||
| pass | |||
| index = evt.GetEventObject().index | |||
| print "Clear channel %d" % index | |||
| @@ -1,4 +1,5 @@ | |||
| #!/bin/bash | |||
| #chuck --bufsize64 scratch.ck | |||
| chuck --bufsize64 main.ck & | |||
| python ./main.py | |||
| pkill -SIGINT chuck | |||
| @@ -1,29 +1,27 @@ | |||
| //signal chain; record a sine wave, play it back | |||
| adc => LiSa saveme => dac; | |||
| adc => dac; //monitor the input | |||
| 0.5 => adc.gain; | |||
| // Effects chain | |||
| Gain mixer => dac; // Main mixer | |||
| adc => Gain adcThru => mixer; // Monitor the input | |||
| adc => LiSa sample => mixer; // Sampler | |||
| // TODO: turn off adcThru when recording | |||
| //alloc memory; required | |||
| 2::second => saveme.duration; | |||
| //start recording input | |||
| 1 => saveme.loop; | |||
| 0::second => saveme.playPos; | |||
| 2::second => saveme.recPos; | |||
| 2::second => saveme.loopEnd; | |||
| // Start recording, wait one second, then start playing | |||
| 1 => saveme.record; | |||
| 1 => saveme.play; | |||
| 1 => saveme.feedback; | |||
| while(true) | |||
| { | |||
| 1::second => now; | |||
| } | |||
| //Times | |||
| 10::second => sample.duration; | |||
| 0::second => sample.recPos; | |||
| 0::second => sample.playPos; | |||
| 1::second => sample.loopEnd => sample.loopEndRec; | |||
| // Start recording and playing in a loop | |||
| 1 => sample.loop => sample.record => sample.play; | |||
| // Levels | |||
| //0 => adc.gain; | |||
| 1 => sample.feedback; | |||
| .5 => sample.gain; | |||
| .5 => adcThru.gain; | |||
| .5::second => now; | |||
| 2::second => sample.loopEnd => sample.loopEndRec; | |||
| while(true) { 1::second => now; } | |||