Esempio n. 1
0
    def test_transmission(self):
        import multiprocessing as mp
        if hasattr(mp, 'set_start_method'):
            mp.set_start_method('spawn')

        iq = mp.Queue()
        oq = mp.Queue()
        portName = 'TestVirtualPorts.%i' % time.time()
        senderProc = mp.Process(target=SenderProc, args=(oq, iq, portName))
        senderProc.start()

        # handshake
        self.assertEqual(iq.get(), 'init')  # virtual midi port is now open

        # Supposedly you can't just open a virtual port by name from
        # within the same proc or proc group? Anyway opening by index
        # works.
        device = RtMidiIn()
        for i in range(device.getPortCount()):
            if device.getPortName(i) == portName:
                device.openPort(i)
                break
        self.assertTrue(device.isPortOpen())

        # collect messages and print progress
        self.messages = []
        self.last_s = ''

        def put(m):
            self.messages.append(m)
            if len(self.messages) % 10 == 0:
                sys.stdout.write('\b' * len(self.last_s))  # backspace
                self.last_s = '%s: Received message %i / 32640' % (__name__, len(self.messages))
                sys.stdout.write(self.last_s)
                # sys.stdout.write('.')
                sys.stdout.flush()

        oq.put('start')
        for i in range(128):
            for j in range(1, 128):
                msg = device.getMessage(1000)
                self.assertTrue(msg is not None)
                self.assertTrue(msg.isNoteOn())
                self.assertEqual(msg.getNoteNumber(), i)
                self.assertEqual(msg.getVelocity(), j)
                put(msg)
                oq.put('next')

        for i in range(128):
            for j in range(128):
                msg = device.getMessage(1000)
                self.assertTrue(msg is not None)
                self.assertTrue(msg.isController())
                self.assertEqual(msg.getControllerNumber(), i)
                self.assertEqual(msg.getControllerValue(), j)
                put(msg)
                oq.put('next')

        self.assertEqual(len(self.messages), 32640)
        oq.put('done')
Esempio n. 2
0
class M2K:
    def __init__(self):
        self.config_path = Path().cwd() / "m2k.json"
        self.table: dict = {}
        self.midi = RtMidiIn()
        self.keyboard = Controller()

    def set_config(self) -> NoReturn:
        with open(str(self.config_path), "r") as j:
            self.table = json.load(j)

    def update_config(self, update: dict) -> NoReturn:
        with open(str(self.config_path), "w") as new:
            new.write(json.dumps(update))
        self.set_config()

    def send_key(self, midi_message) -> NoReturn:
        key = midi_message.getMidiNoteName(midi_message.getNoteNumber())
        if key not in self.table:
            return
        if midi_message.isNoteOn():
            self.keyboard.press(self.table[key])
        elif midi_message.isNoteOff():
            self.keyboard.release(self.table[key])

    def run(self) -> NoReturn:
        ports = range(self.midi.getPortCount())
        if ports:
            print("Running")
            self.midi.openPort(1)
            while True:
                if midi_message := self.midi.getMessage(0):
                    self.send_key(midi_message)
Esempio n. 3
0
class MidiReceiver:
    """
    Handles incoming MIDI messages from attached controllers or instruments.

    Incoming messages can be remapped to other MIDI events, OSC, or trigger
    events inside the app.
    """
    def __init__(self, usb_device_name, app):
        self._log = logging.getLogger(__name__)
        self._midi_in, self._midi_out = RtMidiIn(), RtMidiOut()
        self._connect_midi(usb_device_name)
        self._midi_in.setCallback(self._midi_message_cb)
        self._app = app
        self.enabled = True

    def _connect_midi(self, usb_device_name):
        def find_port(ports, name):
            for i, p in enumerate(ports):
                if p.startswith(name):
                    return i
            return None

        # Find the MIDI In port
        port = find_port([self._midi_in.getPortName(i) for i in range(self._midi_in.getPortCount())], usb_device_name)
        if port is None:
            raise ValueError('Could not find "{}" MIDI port'.format(usb_device_name))

        self._log.info("MidiIn connecting to {}".format(port))
        self._midi_in.openPort(port)

        # Find the MIDI Out port
        port = find_port([self._midi_out.getPortName(i) for i in range(self._midi_out.getPortCount())], usb_device_name)
        assert port is not None
        self._log.info("MidiOut connecting to {}".format(port))
        self._midi_out.openPort(port)

    def _midi_message_cb(self, msg):
        if not self.enabled:
            return

        ch = msg.getChannel()
        cc = msg.getControllerNumber()

        self._log.debug('Received MIDI message: {} {}'.format(ch, cc))

        # Mapping (channel, cc, value) to event
        self._mapping = [
            # single click
            MidiMapping(channel=2, cc=10, event_target=MidiMapping.EVENT_TARGET_MIDI_LOOP, payload=1),  # toggle loop 1
            # MidiMapping(channel=2, cc=11, event_target=MidiMapping.EVENT_TARGET_DRUMS, payload=1),  # play drums
            # MidiMapping(channel=2, cc=12, event_target=MidiMapping.EVENT_TARGET_LOOPER, payload='record'),  # record
            # MidiMapping(channel=2, cc=13, event_target=MidiMapping.EVENT_TARGET_LOOPER, payload='stop'),  # stop
            MidiMapping(channel=2, cc=14, event_target=MidiMapping.EVENT_TARGET_PRESET, payload=0),  # switch loops off
            MidiMapping(channel=2, cc=15, event_target=MidiMapping.EVENT_TARGET_PRESET, payload=1),  # switch to preset 1
            MidiMapping(channel=2, cc=16, event_target=MidiMapping.EVENT_TARGET_PRESET, payload=2),  # switch to preset 2
            MidiMapping(channel=2, cc=17, event_target=MidiMapping.EVENT_TARGET_PRESET, payload=3),  # switch to preset 3

            # long click
        ]

        def find_mapping(ch_, cc_):
            for m in self._mapping:
                if m.channel == ch_ and m.cc == cc_:
                    return m

        m = find_mapping(ch, cc)
        if m:
            self._log.info('Sending event {}:{}'.format(m.event_target, m.payload))
            self._app.send_event(m.event_target, m.payload)
Esempio n. 4
0
    def test_transmission(self):
        import multiprocessing as mp
        if hasattr(mp, 'set_start_method'):
            mp.set_start_method('spawn')

        iq = mp.Queue()
        oq = mp.Queue()
        portName = 'TestVirtualPorts.%i' % time.time()
        senderProc = mp.Process(target=SenderProc, args=(oq, iq, portName))
        senderProc.start()

        # handshake
        self.assertEqual(iq.get(), 'init')  # virtual midi port is now open

        # Supposedly you can't just open a virtual port by name from
        # within the same proc or proc group? Anyway opening by index
        # works.
        device = RtMidiIn()
        for i in range(device.getPortCount()):
            if device.getPortName(i) == portName:
                device.openPort(i)
                break
        self.assertTrue(device.isPortOpen())

        # collect messages and print progress
        self.messages = []
        self.last_s = ''

        def put(m):
            self.messages.append(m)
            if len(self.messages) % 10 == 0:
                sys.stdout.write('\b' * len(self.last_s))  # backspace
                self.last_s = '%s: Received message %i / 32640' % (
                    __name__, len(self.messages))
                sys.stdout.write(self.last_s)
                # sys.stdout.write('.')
                sys.stdout.flush()

        oq.put('start')
        for i in range(128):
            for j in range(1, 128):
                msg = device.getMessage(1000)
                self.assertTrue(msg is not None)
                self.assertTrue(msg.isNoteOn())
                self.assertEqual(msg.getNoteNumber(), i)
                self.assertEqual(msg.getVelocity(), j)
                put(msg)
                oq.put('next')

        for i in range(128):
            for j in range(128):
                msg = device.getMessage(1000)
                self.assertTrue(msg is not None)
                self.assertTrue(msg.isController())
                self.assertEqual(msg.getControllerNumber(), i)
                self.assertEqual(msg.getControllerValue(), j)
                put(msg)
                oq.put('next')

        self.assertEqual(len(self.messages), 32640)
        oq.put('done')
Esempio n. 5
0
class MidiToOsc:
    """
    Translates MIDI messages from a controller to OSC messages for the main program.

    Sets up MIDI and OSC connects, then everything is handled through a callback.
    Uses ALSA/RtMidi to receive MIDI messages. Assumes the OSC server is on localhost at the default port.
    """
    def __init__(self, midi_controller):
        self._midi_in, self._midi_out = RtMidiIn(), RtMidiOut()
        self._connect_midi(midi_controller)
        self._midi_in.setCallback(self._midi_message_cb)
        self._osc_client = udp_client.SimpleUDPClient('127.0.0.1', 5005)
        self._osc_client.send_message('/ping', '1')

        # This part needs to be configurable per mode/user config/DIP switches/etc
        # At the moment, Arduino Micro MIDI device should do:
        # --------------
        # | 5  6  7  8 |
        # | 1  2  3  4 |
        # --------------
        #    Press         Press         Press         Long
        #    Preset        Stomp         Looper        Press
        #    Mode          Mode          Mode
        # 1) Preset 1[10]  Stomp1En[20]  Undo[30]     PresetMod[40]
        # 2) Preset 2[11]  Stomp2En[21]  Record[31]   StompMode[41]
        # 3) Preset 3[12]  Stomp3En[22]  Overdub[32]  LooperMod[42]
        # 4) Preset 4[13]  Stomp4En[23]               Tuner[43]
        # 5) Stomp1En[14]  Stomp5En[24]               Stomp1Sel[44]
        # 6) Stomp2En[15]  Stomp6En[25]               Stomp2Sel[45]
        # 7) Stomp3En[16]  Stomp7En[26]               Stomp3Sel[46]
        # 8) Stomp4En[17]  TapTempo[27]               Stomp4Sel[47]
        self._cc_osc_translation = {
            # Presets
            10: '/preset/1', 11: '/preset/2', 12: '/preset/3', 13: '/preset/4',
            14: '/stomp/1/enable', 15: '/stomp/2/enable', 16: '/stomp/3/enable', 17: '/stomp/4/enable',

            # Stompboxes
            20: '/stomp/1/enable', 21: '/stomp/2/enable', 22: '/stomp/3/enable', 23: '/stomp/4/enable',
            24: '/stomp/5/enable', 25: '/stomp/6/enable', 26: '/stomp/7/enable', 27: '/stomp/8/enable',

            # Looper
            30: '/looper/undo', 31: '/looper/record', 32: '/looper/overdub', 33: '/looper/mute_trigger',
            34: '/looper/redo', 35: '/looper/insert', 36: '/looper/multiply', 37: '/looper/pause',

            # Metronome
            40: '/metronome/pause', 41: '/metronome/dec_bpm', 42: '/metronome/inc_bpm', 43: '/metronome/tap',
            44: '', 45: '', 46: '', 47: '',

            # Long press
            100: '/mode/preset', 101: '/mode/stomp', 102: '/mode/looper', 103: '/mode/metronome',
            104: '/stomp/1/select', 105: '/stomp/2/select', 106: '/stomp/3/select', 107: '/stomp/4/select'
        }

    def _connect_midi(self, midi_controller):
        def find_port(ports, name):
            for i, p in enumerate(ports):
                if p.startswith(name):
                    return i
            return None

        # Find the MIDI In port the Arduino Micro is connected to
        arduino_port = find_port([self._midi_in.getPortName(i) for i in range(self._midi_in.getPortCount())], midi_controller)
        if arduino_port is None:
            raise ValueError('Could not find "Arduino Micro" MIDI port')

        print("MidiIn connecting to {}".format(arduino_port))
        self._midi_in.openPort(arduino_port)

        # Find the MIDI Out port the Arduino Micro is connected to
        arduino_port = find_port([self._midi_out.getPortName(i) for i in range(self._midi_out.getPortCount())], midi_controller)
        assert arduino_port is not None
        print("MidiOut connecting to {}".format(arduino_port))
        self._midi_out.openPort(arduino_port)

    def _midi_message_cb(self, msg):
        cc, value = msg.getControllerNumber(), msg.getControllerValue()
        osc_topic = self._cc_osc_translation.get(cc, None)
        print('{} -> {} -> {}'.format(cc, '1' if value > 0 else '0', str(osc_topic)))
        if osc_topic:
            self._osc_client.send_message(osc_topic, '1')
            print('sent.')
Esempio n. 6
0
        print '%s: OFF:' % port, msg.getNoteNumber(), "=", msg.getMidiNoteName(
            msg.getNoteNumber())
    elif msg.isController():
        print '%s: CONTROLLER' % port, msg.getControllerNumber(
        ), msg.getControllerValue()


if __name__ == '__main__':
    # increase stack size to avoid segfault
    resource.setrlimit(resource.RLIMIT_CORE,
                       (resource.RLIM_INFINITY, resource.RLIM_INFINITY))

    midi_in = RtMidiIn()
    midi_out = RtMidiOut()

    print "AVAILABLE PORTS:"
    for i in range(midi_in.getPortCount()):
        print "  ", i, midi_in.getPortName(i)

    in_port = raw_input("INPUT PORT  (1): ")
    in_port = 1 if in_port.strip() == "" else int(in_port)
    out_port = raw_input("OUTPUT PORT (0): ")
    out_port = 0 if out_port.strip() == "" else int(out_port)

    server = Server(midi_in, in_port, midi_out, out_port)
    server.start()

    print 'HIT ENTER TO EXIT'
    sys.stdin.read(1)
    server.end()