X-Git-Url: https://git.njae.me.uk/?a=blobdiff_plain;f=release%2Fmusic-maker-handler.py;fp=release%2Fmusic-maker-handler.py;h=c935c15fb8bf2bf773c5644f3abf7c408b494d43;hb=0b2beef777994ff9ad92fd8125c6bfeb6f4f46d5;hp=0000000000000000000000000000000000000000;hpb=ea73761744eee647caf88ebb7de986b844f0d7d2;p=miniband.git diff --git a/release/music-maker-handler.py b/release/music-maker-handler.py new file mode 100755 index 0000000..c935c15 --- /dev/null +++ b/release/music-maker-handler.py @@ -0,0 +1,181 @@ +# This code is copyright ...... under the GPL v2. +# This code is derived from scratch_gpio_handler by Simon Walters, which +# is derived from scratch_handler by Thomas Preston +# Version 0.1: It's kind of working. + +from array import * +import threading +import socket +import time +import sys +import struct +import serial +import io +import datetime as dt +import logging + +PORT = 42001 +DEFAULT_HOST = '127.0.0.1' +BUFFER_SIZE = 240 #used to be 100 +SOCKET_TIMEOUT = 1 +DEVICES = ['/dev/ttyACM0', '/dev/ttyACM1','/dev/ttyACM3'] +#DEVICES = ['/dev/ttyACM0','/dev/ttyACM1'] +#DRUM_DEVICE = '/dev/ttyACM0' +#GUITAR_DEVICE = '/dev/ttyUSB1' +#MARACAS_DEVICE = '/dev/ttyACM1' +ARDUINO_BAUD_RATE = 57600 + +BROADCAST_NAMES = {'guitar': 'guitar', + 'drum': {0: 'cymbal', + 1: 'hihat', + 2: 'slowdrum', + 3: 'snare', + 4: 'tomtom'}, + 'maracas': 'maracas'} + +SENSOR_NAMES = {'guitar': 'guitar_pitch'} + +logging.basicConfig(level = logging.INFO) +#logging.basicConfig(level = logging.DEBUG) + +class MyError(Exception): + def __init__(self, value): + self.value = value + + def __str__(self): + return repr(self.value) + +class ScratchSender(threading.Thread): + def __init__(self, socket): + threading.Thread.__init__(self) + self.scratch_socket = socket + self._stop = threading.Event() + + def join(self,timeout=None): + self._stop.set() + threading.Thread.join(self, timeout) + + def stopped(self): + return self._stop.isSet() + + def run(self): + while not self.stopped(): + time.sleep(0.01) # be kind to cpu - not certain why :) + + def send_scratch_command(self, cmd): + n = len(cmd) + a = array('c') + a.append(chr((n >> 24) & 0xFF)) + a.append(chr((n >> 16) & 0xFF)) + a.append(chr((n >> 8) & 0xFF)) + a.append(chr(n & 0xFF)) + self.scratch_socket.send(a.tostring() + cmd) + + +class ArduinoListener(threading.Thread): + def __init__(self, device, speed, sender, instruments, values): + threading.Thread.__init__(self) + self.arduino_device = serial.Serial(device, speed, timeout=0.5) + self._stop = threading.Event() + self.scratch_sender = sender + self.instruments = instruments + self.values = values + logging.info("Started listener on port %s" % device) + + def join(self,timeout=None): + self._stop.set() + threading.Thread.join(self, timeout) + + def stopped(self): + return self._stop.isSet() + + def run(self): + self.arduino_device.readline() # discard the first (partial) line + while not self.stopped(): + logging.debug('Thread waiting for a signal') + try: + device_line = self.arduino_device.readline() + if device_line : + instrument, instrument_value_string = device_line.rstrip().split(',', 1) + instrument_value = int(instrument_value_string) + logging.info('Instrument: %s, Value: %d' % (instrument, instrument_value)) + if instrument in self.values: + try: + logging.info("sensor-update %s %d" % (self.values[instrument], (instrument_value * 100) / 1024)) + self.scratch_sender.send_scratch_command("sensor-update %s %d" % (self.values[instrument], (instrument_value * 100) / 1024)) + except KeyError: + # Do nothing + pass + if instrument in self.instruments: + if isinstance(self.instruments[instrument], dict): + broadcast = self.instruments[instrument][instrument_value] + else: + broadcast = self.instruments[instrument] + try: + logging.info("broadcast %s" % broadcast) + self.scratch_sender.send_scratch_command('broadcast %s' % broadcast) + except KeyError: + # Do nothing + pass + + except serial.SerialException: + logging.error('Serial exception') + logging.debug('Thread run() exiting') + + +def create_socket(host, port): + while True: + try: + logging.info('Connecting to Scratch') + scratch_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + scratch_sock.connect((host, port)) + break + except socket.error: + logging.warning("There was an error connecting to Scratch!") + logging.warning("I couldn't find a Mesh session at host: %s, port: %s" % (host, port)) + time.sleep(3) + return scratch_sock + +def cleanup_threads(threads): + logging.debug("Stopping %d threads" % len(threads)) + for thread in threads: + thread.join() + logging.debug("Threads joined") + +if __name__ == '__main__': + if len(sys.argv) > 1: + host = sys.argv[1] + else: + host = DEFAULT_HOST + +cycle_trace = 'start' +while True: + if (cycle_trace == 'disconnected'): + logging.info("Scratch disconnected") + cleanup_threads(listeners + sender) + time.sleep(1) + cycle_trace = 'start' + + if (cycle_trace == 'start'): + # open the socket + logging.info('Connecting to Scratch...') + the_socket = create_socket(host, PORT) + logging.info('Connected to Scratch') + the_socket.settimeout(SOCKET_TIMEOUT) + sender = ScratchSender(the_socket) + listeners = [ArduinoListener(device, ARDUINO_BAUD_RATE, sender, BROADCAST_NAMES, SENSOR_NAMES) for device in DEVICES] + cycle_trace = 'running' + logging.info("Listeners running....") + sender.start() + for listener in listeners: + listener.start() + + # wait for ctrl+c + try: + #just pause + time.sleep(0.1) + except KeyboardInterrupt: + logging.warning("Interrrupted") + cleanup_threads(listeners + [sender]) + sys.exit() +