--- /dev/null
+*.pyc
+winmove
self._list.append(map)
self._callCallbacks()
+ def prepend(self, map):
+ self._list[:0] = [map]
+ self._callCallbacks()
+
+ def removeMap(self, map):
+ for i in (range(len(self._list))):
+ if self._list[i] is map:
+ self._list[i:i+1] = []
+ return
+
def replaceFromIndex(self, index, maps):
self._list[index:] = maps
self._callCallbacks()
handle. This handle will be poll()'ed and the eventsource will be
called, as sonn as input is available."""
-import select, Logger, Node
+import select, Logger, Node, Actions
-class _Event(tuple):
+class Event(object):
- def __init__(self, elts):
- tuple.__init__(self, elts)
+ def __init__(self, context, code):
+ self.context = context
+ self.code = code
- context = property(lambda self: self[0], None, None)
- code = property(lambda self: self[1], None, None)
+ def __getitem__(self, index):
+ rerturn (self.context, self.code)[index]
+ def __cmp__(self, other):
+ return cmp(self.context, other.context) or cmp(self.code, other.code)
-def Event(context, code):
- return _Event((context,code))
+ def __hash__(self):
+ return hash(self.context) ^ hash(self.code)
+
+ def __str__(self):
+ return repr((self.context, self.code))
+
+
+class ControlEvent(Event):
+
+ def __init__(self, context, code, value):
+ Event.__init__(self, context, code)
+ self.value = value
+
+ def __str__(self):
+ return repr((self.context, self.code, self.value))
class EventSource(Node.Node):
self._callbacks = []
self._keylist = keylist
self._poller = select.poll()
+ self._event = None
+ self._interval = None
+ self._idleCallback = None
def registerSource(self, eventSource):
self._sources[eventSource.fileno()] = eventSource
def unregisterCallback(self,cb):
self._callbacks.remove(cb)
+ def currentEvent(self):
+ return self._event
+
+ def setIdleCallback(self, cb, interval):
+ self._interval = interval
+ self._idleCallback = cb
+
+ def unsetIdleCallback(self):
+ self._interval = None
+ self._idleCallback = None
+
+ def emit(self, event):
+ binding = self._keylist.lookup(event)
+ if binding is not None:
+ self._event = event
+ binding.execute()
+ self._event = None
+
def run(self):
while 1:
for cb in self._callbacks : cb()
try:
- pollEvents = self._poller.poll()
+ pollEvents = self._poller.poll(self._interval)
except select.error, v:
if v[0]==4 : continue
else : raise
- if not pollEvents : return
+ if not pollEvents and self._idleCallback:
+ self._idleCallback()
for fd, pollEvent in pollEvents:
if pollEvent != select.POLLIN : return
for event in self._sources[fd].readEvents():
Logger.log('dispatcher', 'event: ' + str(event))
- binding = self._keylist.lookup(event)
- if binding is not None:
- binding.execute()
+ self.emit(event)
+
+class EmitEvent(Actions.Action):
+
+ def __init__(self, name, dispatcher, event):
+ Actions.Action.__init__(self, name)
+ self._dispatcher = dispatcher
+ self._event = event
+
+ def __call__(self, binding):
+ self._dispatcher.emit(self._event)
-import Views, Events, Logger
+import Views, Events, Logger, Bindings, Actions
from Views import EventWidget
-import time, os, struct
+import time, os, struct, curses
class View(Views.WidgetView):
- def __init__(self, context, label, numeric_switches, alpha_switches, x, y, size=11):
+ def __init__(self, context, label, numeric_switches, alpha_switches, x, y, dx=0, size=11):
size += 1
- Views.WidgetView.__init__(self, context, label, x, y,size*numeric_switches+3,7)
+ dx = max(dx,size*numeric_switches+3)
+ delta = dx - size*numeric_switches - 3
+ shift = delta / 2
+ delta = dx - size*numeric_switches - 2*shift
+ Views.WidgetView.__init__(self, context, label, x, y, dx, 7)
split = numeric_switches // 2
for i in range(split):
- self.add( EventWidget(i,str(i),size*i+1,4,size) )
+ self.add( EventWidget(i,str(i+1)[-1:],size*i+1+shift,4,size) )
for i in range(split,numeric_switches):
- self.add( EventWidget(i,str(i),size*i+3,4,size) )
+ self.add( EventWidget(i,str(i+1)[-1:],size*i+shift+delta,4,size) )
split = max(0,alpha_switches-(numeric_switches-split))
offset = size//2+(numeric_switches-alpha_switches-1)*size
for i in range(split):
- self.add( EventWidget(i+numeric_switches, chr(ord('A')+i), size*i+1+offset,1,size) )
+ self.add( EventWidget(i+numeric_switches, chr(ord('A')+i), size*i+1+offset+shift,1,size) )
for i in range(split, alpha_switches):
- self.add( EventWidget(i+numeric_switches, chr(ord('A')+i), size*i+3+offset,1,size) )
+ self.add( EventWidget(i+numeric_switches, chr(ord('A')+i), size*i+delta+offset+shift,1,size) )
class JSEvent:
return rv
readMultipleFrom=classmethod(readMultipleFrom)
+
class Source(Events.EventSource):
def __init__(self, joydev, context, bits=None, mindelay=100):
self._bits = bits
self._lastevent = 0
self._mindelay = mindelay
+ self._controllers = {}
def readEvents(self):
n = 0
time.sleep(0.0005)
jsevents = JSEvent.readMultipleFrom(self.fd())
for event in jsevents:
+ if event.type == JSEvent.TYPE_AXIS:
+ return self._controller(event.number, event.value)
if event.type == JSEvent.TYPE_BUTTON and event.value == 1:
self._lastevent = event.time
if event.time - lev < self._mindelay : return []
n -= 1
else:
event = JSEvent.readFrom(self.fd())
+ if event.type == JSEvent.TYPE_AXIS:
+ return self._controller(event.number, event.value)
if event.type == JSEvent.TYPE_BUTTON and event.value == 1:
self._lastevent = event.time
if event.time - lev < self._mindelay : return []
else:
return []
return [Events.Event(self.context(), n)]
+
+ def registerController(self, controller, low, high):
+ self._controllers[controller] = { 'low': low, 'high': high }
+
+ def _controller(self, number, value):
+ controller = self._controllers.get(number)
+ if controller:
+ value = (value - controller['low']) * 1000 / (controller['high']-controller['low'])
+ value = max(min(value,1000),0)
+ return [Events.ControlEvent(self.context(), 'p%d' % number, value)]
+ return []
+
+
+class Controller(Views.View):
+
+ def __init__(self, context, name, x, y, dx, dy, keylist, dispatcher,
+ controller, source, low, high):
+ Views.View.__init__(self, context, name, x, y, dx, dy)
+ self._valueEvent = None
+ self._setCommand = None
+ self._valueCommand = None
+ self._parameter = None
+ self._keylist = keylist
+ self._keymap = Bindings.KeyMap()
+ self._keymap.add( Bindings.Binding(Events.Event(source.context(), 'p%d' % controller), '',
+ Actions.Command('controllerChanged',
+ self._controllerChanged)) )
+ self._keylist.prepend(self._keymap)
+ source.registerController(controller, low, high)
+ self._dispatcher = dispatcher
+ self._min = None
+ self._max = None
+ self._stops = None
+ self._value = None
+ self._controlValue = None
+
+ def updateView(self, bindings):
+ pass
+
+ def init(self):
+ Views.View.init(self)
+ self._redraw()
+
+ def assign(self, parameter, setCommand, valueCommand, valueEvent, min, max, stops=[]):
+ self._keylist.removeMap(self._keymap)
+ if self._valueEvent is not None:
+ self._keymap.unbind(self._valueEvent)
+ self._parameter = parameter
+ self._valueEvent = valueEvent
+ self._setCommand = setCommand
+ self._valueCommand = valueCommand
+ self._min = min
+ self._max = max
+ self._stops = stops
+ self._keymap.add( Bindings.Binding( self._valueEvent, '',
+ Actions.Command('updateValue',
+ self._updateValue)) )
+ self._keylist.prepend(self._keymap)
+ self._value = None
+ self._valueCommand()
+ self._redraw()
+
+ def _updateValue(self, binding):
+ event = self._dispatcher.currentEvent()
+ self._value = event.value
+ self._redrawValue()
+
+ def _controllerChanged(self, binding):
+ event = self._dispatcher.currentEvent()
+ Logger.log('ctl',"value = %d" % event.value)
+ self._controlValue = event.value
+ if self._controlValue >= 999 or self._controlValue <= 1:
+ self._dispatcher.setIdleCallback(self._changeValue,50)
+ else:
+ self._dispatcher.unsetIdleCallback()
+ self._redrawController()
+
+ def _changeValue(self):
+ if self._value is None: return
+ if self._controlValue >= 999:
+ self.stepValue(+1)
+ elif self._controlValue <= 1:
+ self.stepValue(-1)
+
+ def stepValue(self, direction):
+ if direction > 0:
+ newValue = self._value + (self._max - self._min) / (3000/50)
+ crossed = [ x for x in self._stops if x > self._value*1.0001 and x <= newValue ]
+ elif direction < 0:
+ newValue = self._value - (self._max - self._min) / (3000/50)
+ crossed = [ x for x in self._stops if x < self._value/1.0001 and x >= newValue ]
+ if newValue >= self._max:
+ crossed = [ self._max ]
+ elif newValue <= self._min:
+ crossed = [ self._min ]
+ if crossed:
+ newValue = crossed[0]
+ self._dispatcher.unsetIdleCallback()
+ self._setCommand(newValue)
+ # Hmm ... why does value_command not work sometimes ??
+ self._value = newValue
+ self._redrawValue()
+ else:
+ self._setCommand(newValue)
+ self._valueCommand()
+
+ def _redraw(self):
+ height, width = self.win().getmaxyx()
+ if self._parameter is not None:
+ self.win().addstr(1,2,self._parameter[:width-4].ljust(width-4), curses.A_BOLD)
+ self._redrawValue(False)
+ self._redrawController()
+
+ def _flt(self, value, width):
+ return ('%.3f' % value)[:width].ljust(width)
+
+ def _redrawValue(self, refresh=True):
+ height, width = self.win().getmaxyx()
+ pos = None
+ if self._value is not None:
+ pos = height - 3 - int( (self._value - self._min) * (height-6)
+ / (self._max - self._min) + .5 )
+ if self._max is not None:
+ self.win().addstr(2,2, self._flt(self._max,width-7))
+ if pos is not None and pos == 3:
+ self.win().addstr(pos, 5, self._flt(self._value,width-7), curses.A_BOLD)
+ else:
+ self.win().addstr(3, 5, "".ljust(width-7))
+ for row in range(4,height-3):
+ if pos is not None and row == pos:
+ self.win().addch(pos,3,curses.ACS_PLUS)
+ self.win().addstr(pos, 5, self._flt(self._value,width-7), curses.A_BOLD)
+ else:
+ self.win().addch(row,3,curses.ACS_VLINE)
+ self.win().addstr(row, 5, "".ljust(width-7))
+ if pos is not None and pos == height-3:
+ self.win().addstr(pos, 5, self._flt(self._value,width-7), curses.A_BOLD)
+ else:
+ self.win().addstr(height-3, 5, "".ljust(width-7))
+ if self._min is not None:
+ self.win().addstr(height-2,2,self._flt(self._min,width-7))
+
+ if refresh:
+ self.win().refresh()
+
+ def _redrawController(self, refresh=True):
+ height, width = self.win().getmaxyx()
+ if self._controlValue is not None and self._controlValue >= 999:
+ self.win().addch(3,3,curses.ACS_UARROW)
+ else:
+ self.win().addch(3,3,curses.ACS_TTEE)
+ if self._controlValue is not None and self._controlValue <= 1:
+ self.win().addch(height-3,3,curses.ACS_DARROW)
+ else:
+ self.win().addch(height-3,3,curses.ACS_BTEE)
+
+ if refresh:
+ self.win().refresh()
+
+class StepController(Actions.Action):
+
+ def __init__(self, name, controller, direction):
+ Actions.Action.__init__(self, name)
+ self._controller = controller
+ self._direction = direction
+
+ def __call__(self, binding):
+ self._controller.stepValue(self._direction)
+
+
def register( viewmanager,
dispatcher,
context,
alpha_switches,
x,
y,
+ dx,
size,
device,
- bits = None ):
- viewmanager.registerView( View(context, label, numeric_switches, alpha_switches, x, y, size) )
- dispatcher.registerSource( Source(device, context, bits) )
+ bits = None,
+ controllers = []):
+ viewmanager.registerView( View(context, label, numeric_switches, alpha_switches, x, y, dx, size) )
+ source = Source(device, context, bits)
+ dispatcher.registerSource( source )
+ return source
+
+def registerController( viewmanager, dispatcher, keylist, source, context, name, x, y, dx, dy,
+ controller, low, high ):
+ controller = Controller(context, name, x, y, dx, dy, keylist, dispatcher,
+ controller, source, low, high)
+ viewmanager.registerView( controller )
+ return controller
keys = bindings.keys()
keys.sort()
column = 2
- row = 2
+ row = 1
for key in keys:
keyname = curses.keyname(key.code)
if keyname.startswith('KEY_'):
self.win().addstr(row, column, '%-6s %s'
% (keyname, bindings[key].label[:self._size]))
row += 1
- if row >= self.dy-2:
- row = 2
+ if row >= self.dy-1:
+ row = 1
column += self._size+10
if column+self._size+7 >= self.dx : break
self.win().vline(1,column-2,curses.ACS_VLINE,self.dy-2)
x,
y,
dx,
- dy ):
- viewmanager.registerView( View(context, label, x,y,dx,dy) )
+ dy,
+ size=9):
+ viewmanager.registerView( View(context, label, x,y,dx,dy,size) )
dispatcher.registerSource( Source(context, viewmanager.win()) )
logger = None
-def init(viewmanager, x, y, dx, dy):
+def init(viewmanager, x, y, dx, dy, logfile=None):
global logger
- logger = Logger(viewmanager.win(), x, y, dx, dy)
+ logger = Logger(viewmanager.win(), x, y, dx, dy, logfile)
class Logger(object):
- def __init__(self, win, x, y, dx, dy):
+ def __init__(self, win, x, y, dx, dy, logfile=None):
self._win = win.derwin(dy,dx,y,x)
self._win.border()
self._win.addstr(0,2,' Log ')
self._textwin.scrollok(1)
self._wrapper = textwrap.TextWrapper(width = dx-4,
subsequent_indent = ' '*4)
+ if logfile:
+ self._logfile = file(logfile,"a")
+ else:
+ self._logfile = None
def log(self, src, msg):
- lines = self._wrapper.wrap(
- '[%s] (%s) %s' % (time.strftime("%H:%M:%S",time.localtime()),src, msg))
+ text = '[%s] (%s) %s' % (time.strftime("%H:%M:%S",time.localtime()),src, msg)
+ if self._logfile:
+ self._logfile.write(text+"\n")
+ lines = self._wrapper.wrap(text)
+ lines = lines[max(0,len(lines)-self._textwin.getmaxyx()[0]):]
self._textwin.scroll(len(lines))
- for i in range(len(lines)):
+ for i in range(min(len(lines),self._textwin.getmaxyx()[0]-2)):
self._textwin.addstr(self._textwin.getmaxyx()[0]-len(lines)+i,0,
lines[i])
self._textwin.nooutrefresh()
-import socket, struct
-import Actions, Logger
-
-def osc_string(s) :
- n = (len(s)+1)%4
- if n : return s+'\0'*(5-n)
- else : return s+'\0'
-
-def osc_command(url,*args):
- tag=","
- argstring=""
- for arg in args :
- if type(arg) is int:
- tag += 'i'
- argstring += struct.pack(">I",arg)
- elif type(arg) is str:
- tag += 's'
- argstring += osc_string(arg)
+import Actions, OSC, Events
+
+class Controller(object):
+
+ def __init__(self, context, oscserver, remote):
+ self._context = context
+ self._server = oscserver
+ self._remote = remote
+ self._server.registerHandler(self._remote, self._oscEvent)
+
+ def hit(self, command, index=0):
+ self._server.command(self._remote,"/sl/%d/hit" % index, str(command))
+
+ def get(self, parameter, index=0):
+ if parameter.startswith('global_'):
+ path = "/get"
+ parameter = parameter[7:]
else:
- raise RunstimeError, "Invalid OSC argument"
- return osc_string(url) + osc_string(tag) + argstring
+ path = "/sl/%d/get" % index
+ self._server.command(self._remote, path, parameter, self._server.localUrl(), "")
-class OSCSender(object):
+ def set(self, parameter, value, index=0):
+ if parameter.startswith('global_'):
+ path = "/set"
+ parameter = parameter[7:]
+ else:
+ path = "/sl/%d/set" % index
+ self._server.command(self._remote, path, parameter, float(value))
- def __init__(self, host, port):
- self._sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
- self._target = (host,port)
+ def _oscEvent(self, path, data):
+ # data = (loop-number, parameter-name, value)
+ if len(data) != 3: return
+ if data[0]<0:
+ param = "global_%s" % data[1]
+ else:
+ param = "%s/%d" % (data[1], data[0])
+ return [ Events.ControlEvent(self._context, param, data[2]) ]
- def command(self, path, *args):
- if type(args[0]) in (tuple, list) : args = args[0]
- Logger.log('osc','osc://%s:%s%s %s'
- % (self._target[0], self._target[1], path,
- ' '.join(map(repr,args))))
- self._sock.sendto(osc_command(path, *args),self._target)
-
+ class ParamGetter(object):
-class Controller(object) :
+ def __init__(self, controller, parameter, index=0):
+ self._parameter = parameter
+ self._controller = controller
+ self._index = index
- def __init__(self, host, port):
- self._sender = OSCSender(host,port)
+ def __call__(self):
+ self._controller.get(self._parameter, self._index)
- def hit(self, command, index=0):
- self._sender.command("/sl/%d/hit" % index, str(command))
+ class ParamSetter(object):
+ def __init__(self, controller, parameter, index=0):
+ self._parameter = parameter
+ self._controller = controller
+ self._index = index
+ def __call__(self, value):
+ self._controller.set(self._parameter, value, self._index)
+
+ def assignController( self, controller, title, parameter, min, max, stops=[], index=0 ):
+ if parameter.startswith('global_'):
+ event = parameter
+ else:
+ event = "%s/%d" % (parameter, index)
+ controller.assign(title,
+ self.ParamSetter(self, parameter, index),
+ self.ParamGetter(self, parameter, index),
+ Events.Event(self._context, event),
+ min, max, stops)
+
class Command(Actions.Action):
def __init__(self, name, controller, command):
def __call__(self, binding):
self._controller.hit(self._command)
+
+class AssignController(Actions.Action):
+
+ def __init__(self, name, loopController, pedalController, title, parameter, min, max,
+ stops = [], index=0):
+ Actions.Action.__init__(self, name)
+ self._loopController = loopController
+ self._pedalController = pedalController
+ self._title = title
+ self._parameter = parameter
+ self._min = min
+ self._max = max
+ self._stops = stops
+ self._index = index
+
+ def __call__(self, binding):
+ self._loopController.assignController(self._pedalController,
+ self._title,
+ self._parameter,
+ self._min,
+ self._max,
+ self._stops,
+ self._index)
+
+def register( oscserver,
+ context,
+ remote ):
+ return Controller(context, oscserver, remote)
--- /dev/null
+import Actions, OSC, Events, Views, curses
+
+class Mixer(Views.View):
+
+ def __init__(self, context, label, x, y, dx, dy, channels, oscserver, remote):
+ Views.View.__init__(self, context, label, x, y, dx, dy)
+ self._context = context
+ self._server = oscserver
+ self._remote = remote
+ self._server.registerHandler(self._remote, self._oscEvent)
+ self._server.command(self._remote,'/mixer/get_channel_count')
+ self._channelNames = channels
+ self._channels = None
+ self._volume = None
+ self._muteState = None
+
+ def updateView(self, bindings):
+ pass
+
+ def init(self):
+ Views.View.init(self)
+
+ def _redraw(self):
+ if not self._channels : return
+ for i in range(self._channels):
+ self.win().addstr(i+1,2,self._channelNames[i][:8])
+ self._redrawValue(i+1)
+ self.win().refresh()
+
+ def _redrawValue(self, channel):
+ if self._muteState[channel-1] == self.MUTED:
+ self.win().addstr(channel,11,'Muted',curses.A_BOLD)
+ elif self._volume[channel-1] is not None:
+ self.win().addstr(channel,11, '%5.1f dB' % self._volume[channel-1])
+ self.win().refresh()
+
+ ACTIVE = 0
+ PENDING = 1
+ MUTED = 2
+
+ def _oscEvent(self, path, data):
+ if path == '/mixer/channel/gain':
+ # channel, gain
+ if self._muteState[data[0]-1] != self.MUTED:
+ self._volume[data[0]-1] = data[1]
+ if self._muteState[data[0]-1] == self.PENDING:
+ self._muteState[data[0]-1] = self.MUTED
+ self._set(data[0],-90.0)
+ self._redrawValue(data[0])
+ return [ Events.ControlEvent(self._context, data[0], data[1]) ]
+ elif path == '/mixer/channel_count':
+ # channel_count
+ self._channels = int(data[0])
+ self._volume = [ None ] * self._channels
+ self._muteState = [ self.ACTIVE ] * self._channels
+ while len(self._channelNames) < self._channels:
+ self._channelNames.append("Channel %d" % (len(self._channelNames)+1))
+ self._redraw()
+ for i in range(self._channels):
+ self._get(i+1)
+
+ return []
+
+ def mute(self, channel):
+ if self._muteState[channel-1] == self.ACTIVE:
+ self._muteState[channel-1] = self.PENDING
+ self._get(channel)
+
+ def unmute(self, channel):
+ if self._muteState[channel-1] != self.ACTIVE:
+ if self._muteState[channel-1] == self.MUTED:
+ self._set(channel, self._volume[channel-1])
+ self._muteState[channel-1] = self.ACTIVE
+
+ def muteToggle(self, channel):
+ if self._muteState[channel-1] == self.ACTIVE:
+ self.mute(channel)
+ else:
+ self.unmute(channel)
+
+ def muteToggleAll(self):
+ if [ x for x in self._muteState if x is not self.MUTED ]:
+ for i in range(self._channels):
+ self.mute(i+1)
+ else:
+ for i in range(self._channels):
+ self.unmute(i+1)
+
+ def get(self, channel):
+ if self._muteState is None or self._muteState[channel-1] == self.ACTIVE:
+ self._get(channel)
+
+ def _get(self, channel):
+ self._server.command(self._remote,'/mixer/channel/get_gain', channel)
+
+ def set(self, channel, value):
+ if self._muteState is None or self._muteState[channel-1] == self.ACTIVE:
+ self._set(channel, value)
+
+ def _set(self, channel, value):
+ self._server.command(self._remote,'/mixer/channel/set_gain', channel, value)
+
+ def cycleVolume(self, channel, volumes):
+ if self._muteState is None or self._muteState[channel-1] != self.ACTIVE:
+ return
+ elif self._volume[channel-1] is not None:
+ for i in range(len(volumes)):
+ if not volumes[i]-0.01 < self._volume[channel-1]:
+ self._set(channel,volumes[i])
+ return
+ self._set(channel, volumes[0])
+
+ class ParamGetter(object):
+
+ def __init__(self, mixer, channel):
+ self._mixer = mixer
+ self._channel = channel
+
+ def __call__(self):
+ self._mixer.get(self._channel)
+
+ class ParamSetter(object):
+
+ def __init__(self, mixer, channel):
+ self._mixer = mixer
+ self._channel = channel
+
+ def __call__(self, value):
+ self._mixer.set(self._channel, value)
+
+ def assignController(self, controller, title, channel, min=-12.0, max=6.0):
+ controller.assign(title,
+ self.ParamSetter(self, channel),
+ self.ParamGetter(self, channel),
+ Events.Event(self._context, channel),
+ min, max, [ 0.0 ])
+
+
+
+class AssignController(Actions.Action):
+
+ def __init__(self, name, mixer, controller, title, channel, min=-12.0, max=6.0):
+ Actions.Action.__init__(self, name)
+ self._mixer = mixer
+ self._controller = controller
+ self._title = title
+ self._channel = channel
+ self._min = min
+ self._max = max
+
+ def __call__(self, binding):
+ self._mixer.assignController(self._controller,
+ self._title,
+ self._channel,
+ self._min,
+ self._max)
+
+
+class MuteChannel(Actions.Action):
+
+ def __init__(self, name, mixer, channel):
+ Actions.Action.__init__(self, name)
+ self._mixer = mixer
+ self._channel = channel
+
+ def __call__(self, binding):
+ self._mixer.mute(self._channel)
+
+
+class UnmuteChannel(Actions.Action):
+
+ def __init__(self, name, mixer, channel):
+ Actions.Action.__init__(self, name, mixer, channel)
+ Actions.Action.__init__(self, name)
+ self._mixer = mixer
+ self._channel = channel
+
+ def __call__(self, binding):
+ self._mixer.unmute(self._channel)
+
+
+class ToggleMuteChannel(Actions.Action):
+
+ def __init__(self, name, mixer, channel):
+ Actions.Action.__init__(self, name)
+ self._mixer = mixer
+ self._channel = channel
+
+ def __call__(self, binding):
+ self._mixer.muteToggle(self._channel)
+
+class ToggleMuteAll(Actions.Action):
+
+ def __init__(self, name, mixer):
+ Actions.Action.__init__(self, name)
+ self._mixer = mixer
+
+ def __call__(self, binding):
+ self._mixer.muteToggleAll()
+
+class CycleVolume(Actions.Action):
+
+ def __init__(self, name, mixer, channel, volumes):
+ Actions.Action.__init__(self, name)
+ self._mixer = mixer
+ self._channel = channel
+ self._volumes = volumes
+
+ def __call__(self, binding):
+ self._mixer.cycleVolume(self._channel, self._volumes)
+
+def register( viewmanager,
+ oscserver,
+ context,
+ label,
+ x, y, dx, dy,
+ channels,
+ remote ):
+ mixer = Mixer(context, label, x, y, dx, dy, channels, oscserver, remote)
+ viewmanager.registerView( mixer )
+ return mixer
--- /dev/null
+import socket, struct
+import Events, Logger
+
+def osc_string(s) :
+ n = (len(s)+1)%4
+ if n : return s+'\0'*(5-n)
+ else : return s+'\0'
+
+
+def osc_command(url,*args):
+ tag=","
+ argstring=""
+ for arg in args :
+ if type(arg) is int:
+ tag += 'i'
+ argstring += struct.pack(">I",arg)
+ elif type(arg) is str:
+ tag += 's'
+ argstring += osc_string(arg)
+ elif type(arg) is float:
+ tag += 'f'
+ argstring += struct.pack(">f",arg)
+ else:
+ raise RunstimeError, "Invalid OSC argument"
+ return osc_string(url) + osc_string(tag) + argstring
+
+
+def osc_getstr(data):
+ i = data.index('\0')
+ s = data[:i]
+ n = (i+1)%4
+ if n : data = data[i+(5-n):]
+ else : data = data[i+1:]
+ return (s,data)
+
+
+def osc_parse(data):
+ url,data = osc_getstr(data)
+ tag,data = osc_getstr(data)
+ values = []
+ for code in tag[1:]:
+ if code == 'i':
+ values.append(struct.unpack(">i",data[:4])[0])
+ data = data[4:]
+ elif code == 's':
+ v,data = osc_getstr(data)
+ values.append(v)
+ elif code == 'f':
+ values.append(struct.unpack(">f",data[:4])[0])
+ data = data[4:]
+ else:
+ raise RuntimeError, "Unknown OSC parameter type received"
+ return (url, values)
+
+
+class OSCServer(Events.EventSource):
+
+ def __init__(self, addr, context):
+ Events.EventSource.__init__(self,
+ socket.socket(socket.AF_INET, socket.SOCK_DGRAM),
+ context)
+ self._addr = addr
+ self.fd().bind(addr)
+ self._handlers = {}
+
+ def registerHandler(self, addr, cb):
+ self._handlers[addr] = cb
+
+ def command(self, target, path, *args):
+ if args and type(args[0]) in (tuple, list) : args = args[0]
+ Logger.log('osc','osc://%s:%s%s %s'
+ % (target[0], target[1], path,
+ ' '.join(map(repr,args))))
+ self.fd().sendto(osc_command(path, *args),target)
+
+ def readEvents(self):
+ data, addr = self.fd().recvfrom(1024)
+ path, args = osc_parse(data)
+ Logger.log('oscrcv','osc://%s:%s%s %s' % (addr[0], addr[1], path,
+ ' '.join(map(repr,args))))
+ handler = self._handlers.get(addr)
+ if handler:
+ return handler(path, args)
+ else:
+ return []
+
+ def localUrl(self):
+ return 'osc://%s:%s' % self._addr
from Events import Event
import main
import Joyboard, Keyboard, Process
-import Looper
-import sys, curses
+import Looper, Mixer
+import sys, curses, time, os
from curses.ascii import alt, ctrl
def shift(letter) : return ord(chr(letter).upper())
def key(letter) : return ord(letter.lower())
+global_map = Bindings.KeyMap()
+
###########################################################################
# Setup views and controllers
#
-# Display size: 77x17
-
-Logger.init(main.viewmanager, 38, 0, 39, 10)
-
-Joyboard.register(
- viewmanager = main.viewmanager,
- dispatcher = main.dispatcher,
-
- context = 'jb0',
- label = 'Foot Switch',
- numeric_switches = 10,
- alpha_switches = 5,
- x = 2,
- y = 10,
- size = 6,
-
- device = '/dev/input/js0',
- bits = { 1:1, 3:2, 2:4, 0:8 }
-)
+# Display size: 88x22
+
+#Logger.init(main.viewmanager, 38, 0, 37, 10, 'audiocontroller.log')
+Logger.init(main.viewmanager, 0, 17, 88, 5)
+
+jb = None
+ctl = None
+if os.path.exists('/dev/input/js0'):
+ jb = Joyboard.register(
+ viewmanager = main.viewmanager,
+ dispatcher = main.dispatcher,
+
+ context = 'jb0',
+ label = 'Foot Switch',
+ numeric_switches = 10,
+ alpha_switches = 5,
+ x = 0,
+ y = 10,
+ dx = 88,
+ size = 7,
+
+ device = '/dev/input/js0',
+ bits = { 1:1, 3:2, 2:4, 0:8 },
+ )
+
+ ctl = Joyboard.registerController(
+ viewmanager = main.viewmanager,
+ dispatcher = main.dispatcher,
+ keylist = main.keylist,
+ source = jb,
+
+ context = 'c0',
+ name = 'Control',
+ x = 75,
+ y = 0,
+ dx = 13,
+ dy = 10,
+
+ controller = 0,
+ low = -27200,
+ high = -32700,
+ )
Keyboard.register(
viewmanager = main.viewmanager,
label = 'Key Bindings',
x = 0,
y = 0,
- dx = 38,
- dy = 10
+ dx = 52,
+ dy = 10,
+ size = 7
)
-jackd = Process.Process("jackd -d alsa -S -r 44100 -p 256",'jack')
-
###########################################################################
# Global keymap and auxilary actions
-global_map = Bindings.KeyMap()
-
@action
def quit(binding):
- sys.exit(0)
+ sys.exit(1)
-global_map.add( Binding( Event('jb0',0), '()', Actions.Nop() ) )
-global_map.add( Binding( Event('jb0',1), '()', Actions.Nop() ) )
-global_map.add( Binding( Event('jb0',10), '()', Actions.Nop() ) )
+@action
+def restart(binding):
+ sys.exit(0)
global_map.add( Binding( Event('kbd',key('q')), 'Quit', Action['quit'] ) )
+global_map.add( Binding( Event('kbd',ctrl(key('r'))), 'Restart', Action['restart'] ) )
+
+for i,k in enumerate(('1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'a', 'b', 'c', 'd', 'e' )):
+ Action.register( Events.EmitEvent('key_%s' % k, main.dispatcher, Event('jb0', i)) )
+ global_map.add( Binding( Event('kbd',key(k)), 'Foot %s' % k.upper(), Action['key_%s' % k] ) )
+
+if ctl is not None:
+ Action.register( Joyboard.StepController( 'controller_increment', ctl, +1 ) )
+ Action.register( Joyboard.StepController( 'controller_decrement', ctl, -1 ) )
+
+ global_map.add( Binding( Event('kbd', curses.KEY_UP), 'Increment', Action['controller_increment'] ) )
+ global_map.add( Binding( Event('kbd', curses.KEY_DOWN), 'Decrement', Action['controller_decrement'] ) )
Action.register( Actions.ChangeBindingsRelative( 'unset_this_map', 0, [] ) )
###########################################################################
-# Looper mode
+# Looper
looper_main_map = Bindings.KeyMap( 'Looper' )
-looper_aux_map = Bindings.KeyMap( 'Aux' )
+Action.register( Actions.ChangeBindingsRelative( 'mode_looper', 0, [ looper_main_map ] ) )
-Action.register( Actions.ChangeBindingsAbsolute('set_mode_looper', 1, [looper_main_map]) )
-Action.register( Actions.ChangeBindingsRelative('looper_set_aux_map', 1, [looper_aux_map]) )
+looper = Looper.register(
+ oscserver = main.oscserver,
-looper = Looper.Controller('localhost',9951)
+ context = 'sl',
+ remote = ('127.0.0.1',9951),
+)
Action.register( Looper.Command('looper_record', looper, 'record') )
Action.register( Looper.Command('looper_overdub', looper, 'overdub') )
Action.register( Looper.Command('looper_substitute', looper, 'substitute') )
Action.register( Looper.Command('looper_reverse', looper, 'reverse') )
Action.register( Looper.Command('looper_oneshot', looper, 'oneshot') )
-
-looper_main_map.add ( Binding( Event('jb0',2), 'Rec', Action['looper_record'] ) )
-looper_main_map.add ( Binding( Event('jb0',3), 'Over', Action['looper_overdub'] ) )
-looper_main_map.add ( Binding( Event('jb0',4), 'Mult', Action['looper_multiply'] ) )
-looper_main_map.add ( Binding( Event('jb0',5), 'Mute', Action['looper_mute'] ) )
-looper_main_map.add ( Binding( Event('jb0',6), 'Undo', Action['looper_undo'] ) )
-looper_main_map.add ( Binding( Event('jb0',7), 'Redo', Action['looper_redo'] ) )
-looper_main_map.add ( Binding( Event('jb0',8), 'Trig', Action['looper_trigger'] ) )
-looper_main_map.add ( Binding( Event('jb0',9), 'Aux', Action['looper_set_aux_map'] ) )
-
-looper_aux_map.add ( Binding( Event('jb0',2), 'Ins', Action['looper_insert'] ) )
-looper_aux_map.add ( Binding( Event('jb0',3), 'Repl', Action['looper_replace'] ) )
-looper_aux_map.add ( Binding( Event('jb0',4), 'Subst', Action['looper_substitute'] ) )
-looper_aux_map.add ( Binding( Event('jb0',6), 'Rev', Action['looper_reverse'] ) )
-looper_aux_map.add ( Binding( Event('jb0',7), 'Once', Action['looper_oneshot'] ) )
-looper_aux_map.add ( Binding( Event('jb0',9), 'Main', Action['unset_this_map'] ) )
+Action.register( Looper.Command('looper_undo_all', looper, 'undo_all') )
+Action.register( Looper.Command('looper_redo_all', looper, 'redo_all') )
+
+looper_main_map.add ( Binding( Event('jb0',0), 'Rec', Action['looper_record'] ) )
+looper_main_map.add ( Binding( Event('jb0',1), 'Over', Action['looper_overdub'] ) )
+looper_main_map.add ( Binding( Event('jb0',2), 'Mult', Action['looper_multiply'] ) )
+looper_main_map.add ( Binding( Event('jb0',3), 'Undo', Action['looper_undo'] ) )
+looper_main_map.add ( Binding( Event('jb0',4), 'Redo', Action['looper_redo'] ) )
+looper_main_map.add ( Binding( Event('jb0',5), 'Mute', Action['looper_mute'] ) )
+looper_main_map.add ( Binding( Event('jb0',6), 'Trig', Action['looper_trigger'] ) )
+looper_main_map.add ( Binding( Event('jb0',7), 'Once', Action['looper_oneshot'] ) )
+looper_main_map.add ( Binding( Event('jb0',8), 'Ins', Action['looper_insert'] ) )
+looper_main_map.add ( Binding( Event('jb0',9), 'Repl', Action['looper_replace'] ) )
+looper_main_map.add ( Binding( Event('jb0',12), 'Undo A', Action['looper_undo_all'] ) )
+looper_main_map.add ( Binding( Event('jb0',13), 'Redo A', Action['looper_redo_all'] ) )
+looper_main_map.add ( Binding( Event('jb0',14), 'Subst', Action['looper_substitute'] ) )
+
+
+looper_param_map = Bindings.KeyMap( 'Parameters' )
+Action.register( Actions.ChangeBindingsRelative('looper_set_param_map', 1, [looper_param_map] ) )
+looper_main_map.add ( Binding( Event('jb0',11), '[Param]', Action['looper_set_param_map'] ) )
+
+if ctl is not None:
+ Action.register( Looper.AssignController( 'looper_parm_rec_thresh', looper, ctl, 'Rec.Thresh.',
+ 'rec_thresh', 0.0, 1.0 ) )
+ Action.register( Looper.AssignController( 'looper_parm_feedback', looper, ctl, 'Feedback',
+ 'feedback', 0.0, 1.0 ) )
+ Action.register( Looper.AssignController( 'looper_parm_dry', looper, ctl, 'Dry Level',
+ 'global_dry', 0.0, 1.0 ) )
+ Action.register( Looper.AssignController( 'looper_parm_wet', looper, ctl, 'Wet Level',
+ 'global_wet', 0.0, 1.0 ) )
+ Action.register( Looper.AssignController( 'looper_parm_igain', looper, ctl, 'In. Gain',
+ 'global_input_gain', 0.0, 1.0 ) )
+
+ steps = [ 1.0 ]
+ for i in range(6):
+ x = pow(2.0,2.0*(i+1)/12.0)
+ steps.append(x)
+ steps[0:0] = [1/x]
+
+ Action.register( Looper.AssignController( 'looper_parm_rate', looper, ctl, 'Rate',
+ 'rate', 0.5, 2.0, steps ) )
+
+ looper_param_map.add( Binding( Event('jb0',5), 'Feedb', Action['looper_parm_feedback'] ) )
+ looper_param_map.add( Binding( Event('jb0',6), 'Dry', Action['looper_parm_dry'] ) )
+ looper_param_map.add( Binding( Event('jb0',7), 'Wet', Action['looper_parm_wet'] ) )
+ looper_param_map.add( Binding( Event('jb0',8), 'Gain', Action['looper_parm_igain'] ) )
+ looper_param_map.add( Binding( Event('jb0',9), 'Rec T', Action['looper_parm_rec_thresh'] ) )
+ looper_param_map.add( Binding( Event('jb0',12), '', Actions.Nop() ) )
+ looper_param_map.add( Binding( Event('jb0',13), 'Rev', Action['looper_reverse'] ) )
+ looper_param_map.add( Binding( Event('jb0',14), 'Rate', Action['looper_parm_rate'] ) )
+
+looper_param_map.add( Binding( Event('jb0',11), '[Main]', Action['unset_this_map'] ) )
+
+# Initialize looper: enable 'round' and set quantize to 'cycle'
+looper.set('quantize',1)
+looper.set('round',1)
+looper.set('sync',1)
###########################################################################
-# MegaPedal mode
+# Mixer and effects
-megapedal_main_map = Bindings.KeyMap( 'MegaPedal' )
+mixer_map = Bindings.KeyMap('Mixer & Effects')
+Action.register( Actions.ChangeBindingsRelative( 'mode_mixer', 0, [ mixer_map ] ) )
-Action.register( Actions.ChangeBindingsAbsolute('set_mode_megapedal', 1, [megapedal_main_map]) )
+looper_main_map.add( Binding( Event('jb0',10), '[Mixer]', Action['mode_mixer'] ) )
-megapedal_main_map.add ( Binding( Event('jb0',11), 'Looper', Action['set_mode_looper'] ) )
-global_map.add ( Binding( Event('jb0',11), 'MegaPedal', Action['set_mode_megapedal'] ) )
+mixer = Mixer.register(
+ viewmanager = main.viewmanager,
+ oscserver = main.oscserver,
-###########################################################################
-# RythmBox mode
+ context = 'mix',
+ label = 'Mixer',
+ x = 52,
+ y = 0,
+ dx = 23,
+ dy = 4,
+
+ channels = ( 'Guitar', 'Voice' ),
+ remote = ('127.0.0.1', 9901),
+)
-rythmbox_main_map = Bindings.KeyMap( 'RythmBox' )
+gain = Mixer.register(
+ viewmanager = main.viewmanager,
+ oscserver = main.oscserver,
-Action.register( Actions.ChangeBindingsAbsolute('set_mode_rythmbox', 1, [rythmbox_main_map]) )
+ context = 'gain',
+ label = 'Gain',
+ x = 52,
+ y = 7,
+ dx = 23,
+ dy = 3,
-rythmbox_main_map.add ( Binding( Event('jb0',11), 'MegaPedal', Action['set_mode_megapedal'] ) )
-global_map.add ( Binding( Event('jb0',11), 'RythmBox', Action['set_mode_rythmbox'] ) )
+ channels = ( 'Guitar', ),
+ remote = ('127.0.0.1', 9902),
+)
+Action.register( Mixer.AssignController( 'mixer_guitar_level', mixer, ctl, 'Guitar', 1 ) )
+Action.register( Mixer.ToggleMuteChannel( 'mixer_mute_guitar', mixer, 1 ) )
+Action.register( Mixer.AssignController( 'mixer_voice_level', mixer, ctl, 'Voice', 2 ) )
+Action.register( Mixer.ToggleMuteChannel( 'mixer_mute_voice', mixer, 2 ) )
+Action.register( Mixer.AssignController( 'mixer_master_level', mixer, ctl, 'Master', 0 ) )
+Action.register( Mixer.ToggleMuteAll( 'mixer_mute_all', mixer ) )
+Action.register( Mixer.CycleVolume( 'mixer_cycle_gain', gain, 1, ( 0.0, 2.0, 4.0 ) ) )
+
+mixer_map.add( Binding( Event('jb0',0), 'Rec', Action['looper_record'] ) )
+mixer_map.add( Binding( Event('jb0',1), 'Over', Action['looper_overdub'] ) )
+mixer_map.add( Binding( Event('jb0',2), 'Mult', Action['looper_multiply'] ) )
+mixer_map.add( Binding( Event('jb0',3), 'Undo', Action['looper_undo'] ) )
+mixer_map.add( Binding( Event('jb0',4), 'Redo', Action['looper_redo'] ) )
+mixer_map.add( Binding( Event('jb0',5), 'Un All', Action['looper_undo_all'] ) )
+
+mixer_map.add( Binding( Event('jb0',6), 'Lead', Action['mixer_cycle_gain'] ) )
+mixer_map.add( Binding( Event('jb0',7), 'Mute G', Action['mixer_mute_guitar'] ) )
+mixer_map.add( Binding( Event('jb0',8), 'Mute V', Action['mixer_mute_voice'] ) )
+mixer_map.add( Binding( Event('jb0',9), 'Mute', Action['mixer_mute_all'] ) )
+
+mixer_map.add( Binding( Event('jb0',13), 'Vol G', Action['mixer_guitar_level'] ) )
+mixer_map.add( Binding( Event('jb0',14), 'Vol V', Action['mixer_voice_level'] ) )
+
+mixer.set(1,0.0)
+mixer.set(2,0.0)
+mixer.assignController( ctl, 'Guitar', 1 )
+gain.set(1,0.0)
+
###########################################################################
+mixer_map.add( Binding( Event('jb0',10), '[Loop]', Action['mode_looper'] ) )
+
main.keylist.append(global_map)
-main.keylist.append(looper_main_map)
+main.keylist.append(mixer_map)
-import Bindings, Events, Views, curses.wrapper
+import Bindings, Events, Views, OSC, curses.wrapper
keylist = None
dispatcher = None
viewmanager = None
stdscr = None
+oscserver = None
def run(scr):
global dispatcher
global viewmanager
global stdscr
+ global oscserver
keylist = Bindings.KeyList()
dispatcher = Events.Dispatcher(keylist)
viewmanager = Views.ViewManager(keylist, dispatcher, scr)
stdscr = scr
+ oscserver = OSC.OSCServer(('127.0.0.1', 9900), 'osc')
+ dispatcher.registerSource(oscserver)
import config
--- /dev/null
+#!/bin/sh
+
+cd "`dirname "$0"`"
+
+displaysize="`xdpyinfo | awk '/^ dimensions:/{print $2}'`"
+displaywidth="${displaysize%x*}"
+offset=`expr $displaywidth - 1920`
+
+clients=""
+
+move() {
+ local x
+ local y
+ local w
+ local h
+ local name
+ local winid
+ x=`expr $1 + $offset`
+ y=$2
+ w=$3
+ h=$4
+ name="$5"
+ winid=""
+ while [ -z "$winid" ]; do
+ winid=`xwininfo -name "$name" | awk '/^xwininfo:/{print $4}'`
+ [ -n "$winid" ] || sleep 1
+ done
+ ./winmove $winid $x $y $w $h
+}
+
+start() {
+ local x
+ local y
+ local w
+ local h
+ local name
+ local winid
+ x=$1
+ y=$2
+ w=$3
+ h=$4
+ name="$5"
+ shift; shift; shift; shift; shift
+ "$@" &
+ clients="$clients $!"
+ move $x $y $w $h "$name"
+}
+
+lsof -n | grep dev | grep -e snd -e dsp | awk '{print $2}' | xargs -r kill
+
+# Make sure nothing is running
+killall slgui
+killall sooperlooper
+killall meterbridge
+killall qjackctl
+killall jack-rack
+killall alsamixer
+killall jackminimix
+killall jackd
+
+amixer sset Master 80% on
+amixer sset PCM 100% on
+amixer sset Capture 50% on
+
+start 0 25 496 100 "JACK Audio Connection Kit [(default)] Started." \
+ qjackctl
+
+sooperlooper -l 1 -c 1 -t 300 &
+clients="$clients $!"
+
+cd loops
+start 582 25 794 220 "SooperLooper" \
+ slgui
+cd ..
+
+# start 0 153 496 600 "JACK Rack (voice) - voice.rack" \
+start 0 153 496 972 "JACK Rack (voice) - voice.rack" \
+ jack-rack -c 1 -s voice voice.rack
+
+# start 0 781 496 344 "JACK Rack (guitar) - guitar.rack" \
+# jack-rack -c 1 -s guitar guitar.rack
+
+start 502 25 74 210 "dpm meter" \
+ meterbridge -r 0 -t dpm -n meter alsa_pcm:capture_1 jack_rack_voice:out_1
+
+x=`expr $offset + 1382`
+xterm -fn 6x12 -bg black -fg white -cr white -geometry 88x18+${x}+25 +sb -title Mixer \
+ -e alsamixer -V all &
+clients="$clients $!"
+
+jackminimix -c 2 -p 9901 &
+clients="$clients $!"
+
+jackminimix -c 1 -p 9902 -n inputgain &
+clients="$clients $!"
+
+sleep 1
+
+jack_connect alsa_pcm:capture_1 inputgain:in1_left
+jack_connect inputgain:out_left sooperlooper:common_in_1
+jack_connect sooperlooper:common_out_1 minimixer:in1_left
+jack_connect sooperlooper:common_out_1 minimixer:in1_right
+jack_connect alsa_pcm:capture_2 jack_rack_voice:in_1
+jack_connect jack_rack_voice:out_1 minimixer:in2_left
+jack_connect jack_rack_voice:out_1 minimixer:in2_right
+jack_connect minimixer:out_left alsa_pcm:playback_1
+jack_connect minimixer:out_right alsa_pcm:playback_2
+
+x=`expr $offset + 502`
+xterm -fn '-dejavu-dejavu sans mono-medium-r-normal--*-260-75-75-m-0-iso10646-1' \
+ -bg black -fg white -cr white -geometry 88x22+${x}+273 +sb \
+ -title "Audio Controller" # -e /bin/sh -c "while ./audiocontroller; do true; done"
+
+kill $clients 2>/dev/null
+killall jackd 2>/dev/null
--- /dev/null
+// $Id$
+//
+// Copyright (C) 2007
+
+#include <Xlib.h>
+#include <Xutil.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+int main(int argc, char ** argv)
+{
+ int winid = strtol(argv[1],0,0);
+ int x = strtol(argv[2],0,0);
+ int y = strtol(argv[3],0,0);
+ int w = strtol(argv[4],0,0);
+ int h = strtol(argv[5],0,0);
+ Display * display = XOpenDisplay(0);
+
+ printf("Window %d on %p -geometry %dx%d+%d+%d\n", winid, display, w,h,x,y);
+ XMoveResizeWindow(display, winid, x, y, w, h);
+ XSync(display, False);
+ return 0;
+}
+
+\f
+// Local Variables:
+// mode: c++
+// compile-command: "gcc -Wall -o winmove winmove.c -I/usr/include/X11 -lX11"
+// End: