summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--buttons.py246
-rw-r--r--callback.py27
-rw-r--r--console.py202
-rw-r--r--faders.py90
-rw-r--r--fw-1884-buttons.py194
-rw-r--r--strips.py56
-rw-r--r--tascam-fw-osc.py394
7 files changed, 815 insertions, 394 deletions
diff --git a/buttons.py b/buttons.py
new file mode 100644
index 0000000..89ae479
--- /dev/null
+++ b/buttons.py
@@ -0,0 +1,246 @@
+#!/usr/bin/env python3
+"""
+ Open Sound Control send/recieve daemon for Tascam Firewire control surface
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ :copyright: Copyright (c) 2012-2014 Scott Bahling
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program (see the file COPYING); if not, write to the
+ Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ :license: GPL-2.0, see COPYING for details
+"""
+
+import re
+import pyautogui
+from osc import osc
+
+
+keymap = {'CTRL': 'ctrl',
+ 'ALT': 'alt',
+ 'SHIFT': 'shift',
+ }
+
+
+osc_addrs = {'STOP': '/transport_stop',
+ 'PLAY': '/transport_play',
+ 'F.FWD': '/ffwd',
+ 'REW': '/rewind',
+ 'REC': '/rec_enable_toggle',
+ }
+
+re_strip_num = re.compile('.*([1-9])')
+
+current_bank = 1
+more_banks_up = False
+more_banks_down = False
+
+
+class Button():
+ def __init__(self, console, name):
+ self.name = name
+ self.state = 0
+ self.console = None
+
+ def press(self):
+ self.state = 1
+ print('%s pressed' % self.name)
+
+ def release(self):
+ self.state = 0
+ print('%s released' % self.name)
+
+ @property
+ def pressed(self):
+ if self.state:
+ return True
+ return False
+
+
+class EncoderButton(Button):
+ def __init__(self, console, name):
+ super().__init__(console, name)
+
+ def press(self):
+
+ encoder_mode = self.console.state.get('encoder_mode', None)
+ print(encoder_mode)
+ if encoder_mode == self.name:
+ return
+
+ self.state = 1
+ if encoder_mode:
+ self.console.unit.leds.turn_off(encoder_mode)
+ self.console.state[encoder_mode] = 0
+ self.console.unit.leds.turn_on(self.name)
+ self.console.state['encoder_mode'] = self.name
+ super().press()
+
+
+class StripSelButton(Button):
+ def __init__(self, console, name, strip):
+ super().__init__(console, name)
+ self.strip = strip
+ self.strip.select = self
+
+ def press(self):
+
+ strip = self.strip
+ print('handle_strip_sel', strip)
+ if self.get('REC ENABLE', 0):
+ if strip.recenable:
+ osc.send_message('/strip/recenable', (strip.num, 0))
+ else:
+ osc.send_message('/strip/recenable', (strip.num, 1))
+ super().press()
+
+
+class StripMuteButton(Button):
+ def __init__(self, console, name, strip):
+ super().__init__(console, name)
+ self.strip = strip
+ self.strip.mute = self
+
+ def press(self):
+
+ strip = self.strip
+ if strip.mute:
+ strip.mute = False
+ osc.send_message('/strip/mute', (strip.num, 0))
+ else:
+ strip.mute = True
+ osc.send_message('/strip/mute', (strip.num, 1))
+ super().press()
+
+
+class StripSoloButton(Button):
+ def __init__(self, console, name, strip):
+ super().__init__(console, name)
+ self.strip = strip
+ self.strip.solo = self
+
+ def press(self):
+
+ strip = self.strip
+ if strip.solo:
+ strip.solo = False
+ osc.send_message('/strip/solo', (strip.num, 0))
+ else:
+ strip.solo = True
+ osc.send_message('/strip/solo', (strip.num, 1))
+ super().press()
+
+
+class ArrowButton(Button):
+ def __init__(self, console, name):
+ super().__init__(console, name)
+
+ def press(self):
+ key = keymap.get(self.name.lower(), self.name.lower())
+ pyautogui.press(key)
+
+
+class ModButton(Button):
+ def __init__(self, console, name):
+ super().__init__(console, name)
+
+ def mod_button_press(self):
+ key = keymap.get(self.name, None)
+ if key is None:
+ return
+
+ pyautogui.keyDown(key)
+ super().press()
+
+ def release(self):
+ key = keymap.get(self.name, None)
+ if key is None:
+ return
+
+ pyautogui.keyUp(key)
+ super().release()
+
+
+class ComputerButton(Button):
+ def __init__(self, console, name):
+ super().__init__(console, name)
+
+ def press(self):
+ osc.send_message('/set_surface', (8, 7, 19, 1, 8, 11))
+ super().press()
+
+
+class ClrSoloButton(Button):
+ def __init__(self, console, name):
+ super().__init__(console, name)
+
+ def press(self):
+ osc.send_message('/cancel_all_solos', 1)
+ super().press()
+
+
+class LoopButton(Button):
+ def __init__(self, console, name):
+ super().__init__(console, name)
+
+ def press(self, *args):
+ if self.console.state.get('loop', 0):
+ print('******* loop off')
+ osc.send_message('/loop_toggle', 0)
+ else:
+ print('******* loop on')
+ osc.send_message('/loop_toggle', 1)
+ super().press()
+
+
+class TransportButton(Button):
+ def __init__(self, console, name):
+ super().__init__(console, name)
+
+ def press(self):
+ addr = osc_addrs.get(self.name, None)
+ if addr:
+ osc.send_message(addr, 1)
+ super().press()
+
+
+class BankSwitchButton(Button):
+ def __init__(self, console, name, direction):
+ super().__init__(console, name)
+ self.direction = direction
+
+ def press(self):
+
+ direction = self.direction
+ print(direction, more_banks_up, more_banks_down)
+ if direction > 0 and more_banks_up:
+ print('calling /bank_up 1')
+ osc.send_message('/bank_up', 1)
+ elif direction < 0 and more_banks_down:
+ print('calling /bank_down 1')
+ osc.send_message('/bank_down', 1)
+ super().press()
+
+
+class NudgeButton(Button):
+ def __init__(self, console, name, direction):
+ super().__init__(console, name)
+ self.direction = direction
+
+ def nudge_press(self):
+ direction = self.direction
+ print(direction)
+ if direction > 0:
+ osc.send_message('/access_action', 'Common/nudge-next-forward')
+ else:
+ osc.send_message('/access_action', 'Common/nudge-next-backward')
+ super().press()
diff --git a/callback.py b/callback.py
new file mode 100644
index 0000000..484b668
--- /dev/null
+++ b/callback.py
@@ -0,0 +1,27 @@
+#!/usr/bin/env python3
+"""
+ Open Sound Control send/recieve daemon for Tascam Firewire control surface
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ :copyright: Copyright (c) 2012-2014 Scott Bahling
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program (see the file COPYING); if not, write to the
+ Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ :license: GPL-2.0, see COPYING for details
+"""
+
+
+class CallBack():
+ def __init__(self, callback_function, **args):
+ self.call = callback_function
+ self.args = args
diff --git a/console.py b/console.py
new file mode 100644
index 0000000..a06c5ee
--- /dev/null
+++ b/console.py
@@ -0,0 +1,202 @@
+#!/usr/bin/env python3
+"""
+ Open Sound Control send/recieve daemon for Tascam Firewire control surface
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ :copyright: Copyright (c) 2012-2014 Scott Bahling
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program (see the file COPYING); if not, write to the
+ Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ :license: GPL-2.0, see COPYING for details
+"""
+
+import argparse
+import string
+import time
+import threading
+from pathlib import Path
+
+import strips
+import fw_1884_buttons
+
+import gi
+
+gi.require_version('Hinawa', '2.0')
+from gi.repository import Hinawa # noqa: E402
+from hinawa_utils.tscm.tscm_console_unit import TscmConsoleUnit # noqa: E402
+
+
+bits32 = '{:032b}'.format
+
+current_bank = 1
+more_banks_up = False
+more_banks_down = False
+
+
+def check_bitR2L(data, bit):
+ return bool(data & (0b1 << bit))
+
+
+class RunningStatusThread():
+ def __init__(self, console, interval=1):
+ """ Constructor
+ :type interval: int
+ :param interval: Check interval, in seconds
+ """
+ self.interval = interval
+
+ thread = threading.Thread(target=self.run, args=(console))
+ thread.daemon = True # Daemonize thread
+ thread.start() # Start the execution
+ self.callbacks = set()
+ self.last_status = []
+
+ def add_callback(self, obj):
+ self.callbacks.add(obj)
+
+ def remove_callback(self, obj):
+ self.callbacks.remove(obj)
+
+ def fetch_status_values(self, quadlets=None, first_bit=0, last_bit=32):
+ if quadlets is None:
+ quadlets = [i for i in range(0, 16)]
+
+ def getvalue(bits):
+ # reverse the bit order before slicing so the index '0' is the LSB
+ # and reverse back before converting to int
+ return int(bits32(bits)[::-1][first_bit:last_bit][::-1], 2)
+
+ values = [getvalue(self.last_status[q]) for q in quadlets]
+
+ if len(values) == 1:
+ return values[0]
+
+ return values
+
+ def run(self, console):
+ """ Method that runs forever """
+ while True:
+
+ if not self.callbacks:
+ continue
+
+ try:
+ self.last_status = console.unit.get_status()
+ except Exception:
+ continue # we should emit warning or error here!
+
+ for callback in self.callbacks:
+ callback.call(self.fetch_status_values(**callback.args))
+
+ time.sleep(self.interval)
+
+
+class Console():
+ def __init__(self, card):
+
+ fullpath = seek_snd_unit_path(card)
+ if fullpath:
+ self.unit = TscmConsoleUnit(fullpath)
+ else:
+ exit()
+
+ self.state = {}
+ self.strips = strips.init_strips(self.unit)
+ self.buttons = fw_1884_buttons.init_buttons(self)
+
+ self.unit.connect('control', self.handle_control)
+
+ status_thread = RunningStatusThread(self) # noqa F841
+
+ def handle_bit_flags(self, index, before, after):
+
+ changed = before ^ after
+
+ for bit in [i for i, b in enumerate(bits32(changed)) if int(b)]:
+ high = check_bitR2L(after, bit)
+ button = self.buttons[index][int(bit)]
+ if button is None:
+ print('unhandled control bit {}:{}'.format(index, bit))
+ continue
+
+ if high:
+ button.release()
+ else:
+ button.press()
+
+ def handle_control(self, index, before, after):
+
+ print('{0:02d}: {1:08x} {2:08x}'.format(index, before, after))
+
+ if index in [5, 6, 7, 8, 9]:
+ self.handle_bit_flags(index, before, after)
+ return
+
+ if index in [10, 11, 12, 13, 14, 15]:
+ self.handle_encoder(index, before, after)
+ return
+
+
+def _check_hexadecimal(literal):
+ if literal.find('0x') == 0:
+ literal = literal[2:]
+ if len(literal) != 16:
+ return False
+ for character in literal:
+ if character not in string.hexdigits:
+ return False
+ else:
+ return True
+
+
+def _seek_snd_unit_from_guid(guid):
+ for fullpath in Path('/dev/snd').glob('hw*'):
+ fullpath = str(fullpath)
+ try:
+ unit = Hinawa.SndUnit()
+ unit.open(fullpath)
+ if unit.get_property('guid') == guid:
+ return fullpath
+ except Exception as e:
+ pass
+ finally:
+ del unit
+ return None
+
+
+def seek_snd_unit_path(card_id):
+ # Assume as sound card number if it's digit literal.
+ if card_id.isdigit():
+ return '/dev/snd/hwC{0}D0'.format(card_id)
+ # Assume as GUID on IEEE 1394 bus if it's hexadecimal literal.
+ elif _check_hexadecimal(card_id):
+ return _seek_snd_unit_from_guid(int(card_id, base=16))
+ return None
+
+
+if __name__ == "__main__":
+
+ parser = argparse.ArgumentParser()
+ parser.add_argument("--card", default="1",
+ help="number of the ALSA sound card")
+ parser.add_argument("--listen-ip", default="127.0.0.1",
+ help="The ip to listen on")
+ parser.add_argument("--listen-port", type=int, default=5005,
+ help="The port to listen on")
+ parser.add_argument("--ip", default="127.0.0.1",
+ help="The ip of the OSC server")
+ parser.add_argument("--port", type=int, default=3819,
+ help="The port the OSC server is listening on")
+ args = parser.parse_args()
+
+ console = Console(args.card)
diff --git a/faders.py b/faders.py
new file mode 100644
index 0000000..ed202c5
--- /dev/null
+++ b/faders.py
@@ -0,0 +1,90 @@
+#!/usr/bin/env python3
+"""
+ Open Sound Control send/recieve daemon for Tascam Firewire control surface
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ :copyright: Copyright (c) 2012-2014 Scott Bahling
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program (see the file COPYING); if not, write to the
+ Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ :license: GPL-2.0, see COPYING for details
+"""
+
+from buttons import Button
+from osc import osc
+
+
+class Fader(Button):
+ def __init__(self, console, strip):
+ name = 'Strip {} Fader'. format(strip.num)
+ super().__init__(console, name)
+ self.strip = strip
+ self.pos = 0
+ self.addr = '/strip/fader'
+ self.console_callback = self.send_pos
+
+ @position.setter
+ def position(self, pos):
+ self.pos = pos
+ self.console.unit.strips
+
+
+ @property
+ def position(self):
+ return self.pos
+
+ def send_pos(self):
+ osc.send_message(self.addr, (self.strip, self.pos/1023))
+
+ def handle_console_status(self, pos):
+ if pos != self.pos:
+ print('{}: {}'.format(self.name, pos))
+ self.pos = pos
+ self.send_pos()
+
+ def press(self):
+ self.console.status_thread.add_callback(self)
+ super().press()
+
+ def release(self):
+ self.console.status_thread.remove_callback(self)
+ super().press()
+
+
+
+
+def strip_fader_handler(addr, args, ssid, pos):
+ unit = args[0]
+ strip = int(ssid)
+ print('fader_handler', addr, ssid, pos)
+ pos = pos * 1023
+ if strip_states[strip].name != ' ':
+ unit.strips[strip].fader.set_position(pos)
+ strip_states[strip].fader = pos
+
+ strips[strip].fader.set_position(pos)
+
+
+ unit = args[0]
+ if state:
+ unit.leds.rew.turn_on()
+ else:
+ unit.leds.rew.turn_off()
+
+
+
+def master_fader_handler(addr, args, pos):
+ unit = args[0]
+ print('master_fader_handler', pos)
+ unit.master_fader.set_position(1023 * pos)
+
diff --git a/fw-1884-buttons.py b/fw-1884-buttons.py
new file mode 100644
index 0000000..b9486d5
--- /dev/null
+++ b/fw-1884-buttons.py
@@ -0,0 +1,194 @@
+#!/usr/bin/env python3
+"""
+ Open Sound Control send/recieve daemon for Tascam Firewire control surface
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ :copyright: Copyright (c) 2012-2014 Scott Bahling
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program (see the file COPYING); if not, write to the
+ Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ :license: GPL-2.0, see COPYING for details
+"""
+
+import buttons.py
+
+
+def init_buttons(console):
+ unit = console.unit
+ strips = console.strips
+ return {5: [None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ strips[1].fader,
+ strips[2].fader,
+ strips[3].fader,
+ strips[4].fader,
+ strips[5].fader,
+ strips[6].fader,
+ strips[7].fader,
+ strips[8].fader,
+ strips[0].fader,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ ],
+ 6: [None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ buttons.StripSelButton(unit, 'Strip 1 Sel', strips[1]),
+ buttons.StripSelButton(unit, 'Strip 2 Sel', strips[2]),
+ buttons.StripSelButton(unit, 'Strip 3 Sel', strips[3]),
+ buttons.StripSelButton(unit, 'Strip 4 Sel', strips[4]),
+ buttons.StripSelButton(unit, 'Strip 5 Sel', strips[5]),
+ buttons.StripSelButton(unit, 'Strip 6 Sel', strips[6]),
+ buttons.StripSelButton(unit, 'Strip 7 Sel', strips[7]),
+ buttons.StripSelButton(unit, 'Strip 8 Sel', strips[8]),
+ buttons.StripSoloButton(unit, 'Strip 1 Solo', strips[1]),
+ buttons.StripSoloButton(unit, 'Strip 2 Solo', strips[2]),
+ buttons.StripSoloButton(unit, 'Strip 3 Solo', strips[3]),
+ buttons.StripSoloButton(unit, 'Strip 4 Solo', strips[4]),
+ buttons.StripSoloButton(unit, 'Strip 5 Solo', strips[5]),
+ buttons.StripSoloButton(unit, 'Strip 6 Solo', strips[6]),
+ buttons.StripSoloButton(unit, 'Strip 7 Solo', strips[7]),
+ buttons.StripSoloButton(unit, 'Strip 8 Solo', strips[8]),
+ ],
+ 7: [buttons.StripMuteButton(unit, 'Strip 1 Mute', strips[1]),
+ buttons.StripMuteButton(unit, 'Strip 2 Mute', strips[2]),
+ buttons.StripMuteButton(unit, 'Strip 3 Mute', strips[3]),
+ buttons.StripMuteButton(unit, 'Strip 4 Mute', strips[4]),
+ buttons.StripMuteButton(unit, 'Strip 5 Mute', strips[5]),
+ buttons.StripMuteButton(unit, 'Strip 6 Mute', strips[6]),
+ buttons.StripMuteButton(unit, 'Strip 7 Mute', strips[7]),
+ buttons.StripMuteButton(unit, 'Strip 8 Mute', strips[8]),
+ buttons.EncoderButton(unit, 'AUX5'),
+ buttons.EncoderButton(unit, 'AUX7'),
+ buttons.EncoderButton(unit, 'AUX6'),
+ buttons.EncoderButton(unit, 'AUX8'),
+ None,
+ None,
+ None,
+ None,
+ buttons.Button(unit, 'FLIP'),
+ buttons.EncoderButton(unit, 'AUX1'),
+ buttons.EncoderButton(unit, 'AUX3'),
+ buttons.EncoderButton(unit, 'PAN'),
+ buttons.EncoderButton(unit, 'AUX2'),
+ buttons.EncoderButton(unit, 'AUX4'),
+ None,
+ None,
+ buttons.Button(unit, 'Control Panel'),
+ buttons.Button(unit, 'F1'),
+ buttons.Button(unit, 'ALL SAFE'),
+ buttons.Button(unit, 'F5'),
+ buttons.Button(unit, 'CUT'),
+ buttons.Button(unit, 'COPY'),
+ buttons.ModButton(unit, 'ALT'),
+ buttons.ModButton(unit, 'SHIFT'),
+ ],
+ 8: [buttons.Button(unit, 'F2'),
+ buttons.ClrSoloButton(unit, 'CLR SOLO'),
+ buttons.LoopButton(unit, 'LOOP'),
+ buttons.Button(unit, 'DEL'),
+ buttons.Button(unit, 'PASTE'),
+ buttons.Button(unit, 'UNDO'),
+ buttons.ModButton(unit, 'CTRL'),
+ buttons.Button(unit, 'Foot Switch'),
+ buttons.Button(unit, 'Gain Enc A', None),
+ buttons.Button(unit, 'Gain Enc B', None),
+ buttons.Button(unit, 'Q Enc A', None),
+ buttons.Button(unit, 'Q Enc B', None),
+ None,
+ None,
+ None,
+ None,
+ buttons.Button(unit, 'Freq Enc A', None),
+ buttons.Button(unit, 'Freq Enc B', None),
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ buttons.ComputerButton(unit, 'COMPUTER'),
+ None,
+ None,
+ buttons.Button(unit, 'CLOCK'),
+ buttons.Button(unit, 'ROUTE'),
+ None,
+ None,
+ ],
+ 9: [buttons.Button(unit, 'F7'),
+ buttons.Button(unit, 'F8'),
+ buttons.Button(unit, 'F9'),
+ buttons.Button(unit, 'F10'),
+ buttons.Button(unit, 'READ'),
+ buttons.Button(unit, 'WRT'),
+ buttons.Button(unit, 'TCH'),
+ buttons.Button(unit, 'LATCH'),
+ buttons.Button(unit, 'HIGH'),
+ buttons.Button(unit, 'HI-MID'),
+ buttons.Button(unit, 'LOW-MID'),
+ buttons.Button(unit, 'LOW'),
+ buttons.ArrowButton(unit, 'UP'),
+ buttons.ArrowButton(unit, 'LEFT'),
+ buttons.ArrowButton(unit, 'DOWN'),
+ buttons.ArrowButton(unit, 'RIGHT'),
+ buttons.Button(unit, 'REC ENABLE'),
+ buttons.NudgeButton(unit, 'NUDGE LEFT', -1),
+ buttons.NudgeButton(unit, 'NUDGE RIGHT', 1),
+ buttons.BankSwitchButton(unit, 'BANK LEFT', -1),
+ buttons.BankSwitchButton(unit, 'BANK RIGHT', 1),
+ buttons.Button(unit, 'LOCATE LEFT'),
+ buttons.Button(unit, 'LOCATE RIGHT'),
+ buttons.Button(unit, 'SHTL'),
+ buttons.Button(unit, 'SET'),
+ buttons.Button(unit, 'IN'),
+ buttons.Button(unit, 'OUT'),
+ buttons.TransportButton(unit, 'REW'),
+ buttons.TransportButton(unit, 'F.FWD'),
+ buttons.TransportButton(unit, 'STOP'),
+ buttons.TransportButton(unit, 'PLAY'),
+ buttons.TransportButton(unit, 'REC'),
+ ]
+ }
diff --git a/strips.py b/strips.py
new file mode 100644
index 0000000..da656d1
--- /dev/null
+++ b/strips.py
@@ -0,0 +1,56 @@
+#!/usr/bin/env python3
+"""
+ Open Sound Control send/recieve daemon for Tascam Firewire control surface
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ :copyright: Copyright (c) 2012-2014 Scott Bahling
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program (see the file COPYING); if not, write to the
+ Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ :license: GPL-2.0, see COPYING for details
+"""
+
+from faders import Fader
+
+class Strip():
+
+ def __init__(self, unit, num):
+ self.num = 0
+ self.mute = None
+ self.solo = None
+ self.select = None
+ self.recenable = False
+ self.pan = 0.5
+ self.fader = Fader(unit, self)
+ self.name = None
+
+ def send_pan(self, delta):
+ addr = '/strip/pan_stereo_position'
+ pan = self.pan + delta * 0.02
+ if pan < 0:
+ pan = 0
+ if pan > 1.0:
+ pan = 1.0
+ osc.send_message(addr, (self.num, pan))
+
+ def recv_pan(self, pan):
+ print('Pan: {} {}'.format(self.num, pan))
+ self.pan = pan
+
+
+def init_strips(unit):
+ strips = []
+ for strip_num in range(0, 9):
+ strips.append(Strip(unit, strip_num))
+
+ return strips
diff --git a/tascam-fw-osc.py b/tascam-fw-osc.py
index 827d399..1062041 100644
--- a/tascam-fw-osc.py
+++ b/tascam-fw-osc.py
@@ -59,24 +59,6 @@ current_bank = 1
more_banks_up = False
more_banks_down = False
-class StripState():
-
- def __init__(self):
- self.mute = False
- self.solo = False
- self.select = False
- self.recenable = False
- self.pan = 0.5
- self.fader_touch = False
- self.fader = 0.0
- self.name = None
-
-
-strip_states = []
-for strip in range(0, 9):
- strip_states.append(StripState())
-
-
def check_bitR2L(data, bit):
return bool(data & (0b1 << bit))
@@ -120,38 +102,6 @@ def roll_over_delta(delta, ceiling=0xffff):
return delta
-def handle_encoder_button(index, flags, bit, bitstate, control, *args):
- if bitstate:
- return
-
- encoder_mode = control_state.get('encoder_mode', None)
- print(encoder_mode)
- if encoder_mode == control:
- return
-
- control_state[control] = 1
- if encoder_mode:
- unit.leds.turn_off(encoder_mode)
- control_state[encoder_mode] = 0
- unit.leds.turn_on(control)
- control_state['encoder_mode'] = control
-
-
-def send_pan(strip, delta):
- addr = '/strip/pan_stereo_position'
- pan = strip_states[strip].pan + delta * 0.02
- if pan < 0:
- pan = 0
- if pan > 1.0:
- pan = 1.0
- osc.send_message(addr, (strip, pan))
-
-
-def recv_pan(strip, pan):
- print('Pan: {} {}'.format(strip, pan))
- strip_states[strip].pan = pan
-
-
def handle_encoder(unit, index, flags):
strip1 = (index * 2 - 19)
strip2 = (index * 2 - 18)
@@ -175,39 +125,6 @@ def handle_encoder(unit, index, flags):
control_state[enc2] = val2
-def handle_encoder_inc(index, flags, bit, bitstate, control, encoder, sense):
- on = control_state.get(control, 0)
-
- high = bool(bitstate)
- low = not high
-
- print(sense, on, int(low))
- if (low and on) or (high and not on):
- print('no change')
- return
-
- if sense == 'a':
- complement = control_state.get(control.replace('a', 'b'))
- else:
- complement = control_state.get(control.replace('b', 'a'))
-
- if low:
- control_state[control] = 1
- if complement:
- delta = 0.02
- else:
- delta = -0.02
- else:
- control_state[control] = 0
- if not complement:
- delta = 0.02
- else:
- delta = -0.02
-
- if sense == 'a':
- delta = delta * -1
-
-
def handle_eq_encoder(unit, index, flags):
val1 = flags & 0xffff
val2 = flags >> 0x10
@@ -241,317 +158,6 @@ def handle_eq_encoder(unit, index, flags):
osc.send_message('/jog', delta2 * amount)
-def handle_strip_sel(index, flags, bits, bitstate, control, strip):
- if bitstate:
- return
-
- print('handle_strip_sel', strip)
- if button_state.get('REC ENABLE', 0):
- if strip_states[strip].recenable:
- osc.send_message('/strip/recenable', (strip, 0))
- else:
- osc.send_message('/strip/recenable', (strip, 1))
-
-
-def handle_strip_mute(index, flags, bits, bitstate, control, strip):
- high = bool(bitstate)
-
- # only react to button press
- if high:
- return
-
- if strip_states[strip].mute:
- strip_states[strip].mute = False
- osc.send_message('/strip/mute', (strip, 0))
- else:
- strip_states[strip].mute = True
- osc.send_message('/strip/mute', (strip, 1))
-
-
-def handle_strip_solo(index, flags, bits, bitstate, control, *args):
- high = bool(bitstate)
-
- # only react to button press
- if high:
- return
-
- try:
- strip = int(re_strip_num.match(control).group(1))
- except Exception as e:
- raise e
-
- if strip_states[strip].solo:
- strip_states[strip].solo = False
- osc.send_message('/strip/solo', (strip, 0))
- else:
- strip_states[strip].solo = True
- osc.send_message('/strip/solo', (strip, 1))
-
-
-def handle_button(index, flags, bit, bitstatus, control, *args):
- if bitstatus:
- print('Button Release: %s' % control)
- else:
- print('Button Press: %s' % control)
-
-
-def handle_arrow_button(index, flags, bit, bitstatus, control, *args):
- if bitstatus:
- return
-
- key = keymap.get(control.lower(), control.lower())
- pyautogui.press(key)
-
-
-def handle_mod_button(index, flags, bit, bitstatus, control, *args):
- key = keymap.get(control, None)
- if key is None:
- return
-
- if bitstatus:
- pyautogui.keyUp(key)
- else:
- pyautogui.keyDown(key)
-
-
-def handle_computer_button(index, flags, bit, bitstate, control, *args):
- if bitstate:
- return
- osc.send_message('/set_surface', (8, 7, 19, 1, 8, 11))
-
-
-def handle_clr_solo_button(index, flags, bit, bitstate, control, *args):
- if bitstate:
- return
- osc.send_message('/cancel_all_solos', 1)
-
-
-def handle_loop_button(index, flags, bit, bitstate, control, *args):
- if bitstate:
- return
- if control_state.get(control, 0):
- print('******* loop on')
- osc.send_message('/loop_toggle', 0)
- else:
- print('******* loop off')
- osc.send_message('/loop_toggle', 1)
-
-
-def handle_transport(index, flags, bit, bitstate, control, *args):
- if bitstate:
- return
-
- addr = osc_addrs.get(control, None)
- if addr:
- osc.send_message(addr, 1)
-
-
-def default_handler(index, flags, bit, bitstate, control, *args):
- print('no handler for %s' % control)
-
-
-def handle_fader_touch(index, flags, bit, bitstate, control, strip):
-
- if not bitstate:
- strip_states[strip].fader_touch = True
- else:
- strip_states[strip].fader_touch = False
-
-
-def handle_bank_switch(index, flags, bit, bitstate, control, direction):
- # only handle button press
- if bitstate:
- return
-
- print(direction, more_banks_up, more_banks_down)
- if direction > 0 and more_banks_up:
- print('calling /bank_up 1')
- osc.send_message('/bank_up', 1)
- elif direction < 0 and more_banks_down:
- print('calling /bank_down 1')
- osc.send_message('/bank_down', 1)
-
-
-def handle_nudge(index, flags, bit, bitstate, control, direction):
- # only handle button press
- if bitstate:
- return
-
- print(direction)
- if direction > 0:
- osc.send_message('/access_action', 'Common/nudge-next-forward')
- else:
- osc.send_message('/access_action', 'Common/nudge-next-backward')
-
-
-control_flags = {5: [None,
- None,
- None,
- None,
- None,
- None,
- None,
- None,
- None,
- None,
- None,
- None,
- None,
- None,
- None,
- None,
- ('Fader1 Touch', handle_fader_touch, 1),
- ('Fader2 Touch', handle_fader_touch, 2),
- ('Fader3 Touch', handle_fader_touch, 3),
- ('Fader4 Touch', handle_fader_touch, 4),
- ('Fader5 Touch', handle_fader_touch, 5),
- ('Fader6 Touch', handle_fader_touch, 6),
- ('Fader7 Touch', handle_fader_touch, 7),
- ('Fader8 Touch', handle_fader_touch, 8),
- ('Fader9 Touch', handle_fader_touch, 0),
- None,
- None,
- None,
- None,
- None,
- None,
- None,
- ],
- 6: [('enc1a', None, 1, 'a'),
- ('enc1b', None, 1, 'b'),
- ('enc3a', None, 2, 'a'),
- ('enc3b', None, 2, 'b'),
- ('enc5a', None, 3, 'a'),
- ('enc5b', None, 3, 'b'),
- ('enc7a', None, 4, 'a'),
- ('enc7b', None, 4, 'b'),
- ('enc2a', None, 5, 'a'),
- ('enc2b', None, 5, 'b'),
- ('enc4a', None, 6, 'a'),
- ('enc4b', None, 6, 'b'),
- ('enc6a', None, 7, 'a'),
- ('enc6b', None, 7, 'b'),
- ('enc8a', None, 8, 'a'),
- ('enc8b', None, 8, 'b'),
- ('Strip1 SEL', handle_strip_sel, 1),
- ('Strip2 SEL', handle_strip_sel, 2),
- ('Strip3 SEL', handle_strip_sel, 3),
- ('Strip4 SEL', handle_strip_sel, 4),
- ('Strip5 SEL', handle_strip_sel, 5),
- ('Strip6 SEL', handle_strip_sel, 6),
- ('Strip7 SEL', handle_strip_sel, 7),
- ('Strip8 SEL', handle_strip_sel, 8),
- ('Strip1 SOLO', handle_strip_solo, 1),
- ('Strip2 SOLO', handle_strip_solo, 2),
- ('Strip3 SOLO', handle_strip_solo, 3),
- ('Strip4 SOLO', handle_strip_solo, 4),
- ('Strip5 SOLO', handle_strip_solo, 5),
- ('Strip6 SOLO', handle_strip_solo, 6),
- ('Strip7 SOLO', handle_strip_solo, 7),
- ('Strip8 SOLO', handle_strip_solo, 8),
- ],
- 7: [('Strip1 MUTE', handle_strip_mute, 1),
- ('Strip2 MUTE', handle_strip_mute, 2),
- ('Strip3 MUTE', handle_strip_mute, 3),
- ('Strip4 MUTE', handle_strip_mute, 4),
- ('Strip5 MUTE', handle_strip_mute, 5),
- ('Strip6 MUTE', handle_strip_mute, 6),
- ('Strip7 MUTE', handle_strip_mute, 7),
- ('Strip8 MUTE', handle_strip_mute, 8),
- ('AUX5', handle_encoder_button),
- ('AUX7', handle_encoder_button),
- ('AUX6', handle_encoder_button),
- ('AUX8', handle_encoder_button),
- None,
- None,
- None,
- None,
- ('FLIP', handle_button),
- ('AUX1', handle_encoder_button),
- ('AUX3', handle_encoder_button),
- ('PAN', handle_encoder_button),
- ('AUX2', handle_encoder_button),
- ('AUX4', handle_encoder_button),
- None,
- None,
- ('Control Panel', handle_button),
- ('F1', handle_button),
- ('ALL SAFE', handle_button),
- ('F5', handle_button),
- ('CUT', handle_button),
- ('COPY', handle_button),
- ('ALT', handle_mod_button),
- ('SHIFT', handle_mod_button),
- ],
- 8: [('F2', handle_button),
- ('CLR SOLO', handle_clr_solo_button),
- ('LOOP', handle_loop_button),
- ('DEL', handle_button),
- ('PASTE', handle_button),
- ('UNDO', handle_button),
- ('CTRL', handle_mod_button),
- ('Foot Switch', handle_button),
- ('Gain Enc A', None),
- ('Gain Enc B', None),
- ('Q Enc A', None),
- ('Q Enc B', None),
- None,
- None,
- None,
- None,
- ('Freq Enc A', None),
- ('Freq Enc B', None),
- None,
- None,
- None,
- None,
- None,
- None,
- None,
- ('COMPUTER', handle_computer_button),
- None,
- None,
- ('CLOCK', handle_button),
- ('ROUTE', handle_button),
- None,
- None,
- ],
- 9: [('F7', handle_button),
- ('F8', handle_button),
- ('F9', handle_button),
- ('F10', handle_button),
- ('READ', handle_button),
- ('WRT', handle_button),
- ('TCH', handle_button),
- ('LATCH', handle_button),
- ('HIGH', handle_button),
- ('HI-MID', handle_button),
- ('LOW-MID', handle_button),
- ('LOW', handle_button),
- ('UP', handle_arrow_button),
- ('LEFT', handle_arrow_button),
- ('DOWN', handle_arrow_button),
- ('RIGHT', handle_arrow_button),
- ('REC ENABLE', handle_button),
- ('NUDGE LEFT', handle_nudge, -1),
- ('NUDGE RIGHT', handle_nudge, 1),
- ('BANK LEFT', handle_bank_switch, -1),
- ('BANK RIGHT', handle_bank_switch, 1),
- ('LOCATE LEFT', handle_button),
- ('LOCATE RIGHT', handle_button),
- ('SHTL', handle_button),
- ('SET', handle_button),
- ('IN', handle_button),
- ('OUT', handle_button),
- ('REW', handle_transport),
- ('F.FWD', handle_transport),
- ('STOP', handle_transport),
- ('PLAY', handle_transport),
- ('REC', handle_transport),
- ]
- }
-
-
def handle_bit_flags(unit, index, flags):
for bit in range(32):
high = check_bitR2L(flags, bit)