@@ -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; } |