@@ -6,11 +6,8 @@ adc => LiSa sample => mixer; // Sampler | |||||
//Times | //Times | ||||
10::second => sample.duration; | 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 | // Levels | ||||
//0 => adc.gain; | //0 => adc.gain; | ||||
@@ -18,60 +15,39 @@ adc => LiSa sample => mixer; // Sampler | |||||
.5 => sample.gain; | .5 => sample.gain; | ||||
.5 => adcThru.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) | self.slider=wx.Slider(self, value=default_value*100, minValue=min_value*100, maxValue=max_value*100) | ||||
sizer.Add(self.slider, 1, wx.EXPAND) | sizer.Add(self.slider, 1, wx.EXPAND) | ||||
self.SetSizerAndFit(sizer) | self.SetSizerAndFit(sizer) | ||||
self.Bind=self.Bind | |||||
self.Bind=self.slider.Bind | |||||
self.GetValue=self.slider.GetValue | |||||
class CommsPanel(wx.Panel): | class CommsPanel(wx.Panel): | ||||
@@ -62,6 +63,7 @@ class InputPanel(wx.Panel): | |||||
self.gain.Bind(wx.EVT_SCROLL, self.update) | self.gain.Bind(wx.EVT_SCROLL, self.update) | ||||
self.thru.Bind(wx.EVT_SCROLL, self.update) | self.thru.Bind(wx.EVT_SCROLL, self.update) | ||||
self.mute.Bind(wx.EVT_TOGGLEBUTTON, self.update) | self.mute.Bind(wx.EVT_TOGGLEBUTTON, self.update) | ||||
self.update() | self.update() | ||||
def update(self, evt=None): | def update(self, evt=None): | ||||
@@ -91,6 +93,9 @@ class DelayPanel(wx.Panel): | |||||
self.feedback=OSCSlider(self, "Feedback", default_value=.99) | self.feedback=OSCSlider(self, "Feedback", default_value=.99) | ||||
sizer.Add(self.feedback, 0, wx.EXPAND|wx.ALL, 5) | 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.SetSizerAndFit(sizer) | ||||
self.delayTime.Bind(wx.EVT_SCROLL, self.update) | self.delayTime.Bind(wx.EVT_SCROLL, self.update) | ||||
self.feedback.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) | font = label.GetFont(); font.SetWeight(wx.BOLD); label.SetFont(font) | ||||
sizer.Add(label, 0, wx.TOP|wx.BOTTOM|wx.RIGHT, 5) | 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) | 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") | 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) | 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.SetSizerAndFit(sizer) | ||||
self.gain.Bind(wx.EVT_SCROLL, self.update) | 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.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 | 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): | class Mixer(wx.Panel): | ||||
@@ -151,6 +159,7 @@ class Mixer(wx.Panel): | |||||
c.record.Bind(wx.EVT_TOGGLEBUTTON, self.switch_record) | c.record.Bind(wx.EVT_TOGGLEBUTTON, self.switch_record) | ||||
c.record.index=i | c.record.index=i | ||||
c.clear.Bind(wx.EVT_BUTTON, self.clear_channel) | c.clear.Bind(wx.EVT_BUTTON, self.clear_channel) | ||||
c.clear.index=i | |||||
self.channels.append(c) | self.channels.append(c) | ||||
sizer.Add(c, 1, wx.EXPAND) | sizer.Add(c, 1, wx.EXPAND) | ||||
@@ -163,10 +172,15 @@ class Mixer(wx.Panel): | |||||
for i, c in enumerate(self.channels): | for i, c in enumerate(self.channels): | ||||
c.record.SetValue(0) | c.record.SetValue(0) | ||||
self.channels[index].record.SetValue(value) | 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): | def clear_channel(self, evt): | ||||
""" Send OSC message to clear a channel """ | """ Send OSC message to clear a channel """ | ||||
pass | |||||
index = evt.GetEventObject().index | |||||
print "Clear channel %d" % index | |||||
@@ -1,4 +1,5 @@ | |||||
#!/bin/bash | #!/bin/bash | ||||
#chuck --bufsize64 scratch.ck | |||||
chuck --bufsize64 main.ck & | chuck --bufsize64 main.ck & | ||||
python ./main.py | python ./main.py | ||||
pkill -SIGINT chuck | 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; } |