115 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			Python
		
	
	
	
			
		
		
	
	
			115 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			Python
		
	
	
	
| # -*- coding: utf-8 -*-
 | |
| 
 | |
| import rtmidi
 | |
| import random
 | |
| 
 | |
| # ------------------------------------------------------------------------------
 | |
| 
 | |
| class Midi:
 | |
|     InvalidType           = 0x00    # For notifying errors
 | |
|     NoteOff               = 0x80    # Note Off
 | |
|     NoteOn                = 0x90    # Note On
 | |
|     AfterTouchPoly        = 0xA0    # Polyphonic AfterTouch
 | |
|     ControlChange         = 0xB0    # Control Change / Channel Mode
 | |
|     ProgramChange         = 0xC0    # Program Change
 | |
|     AfterTouchChannel     = 0xD0    # Channel (monophonic) AfterTouch
 | |
|     PitchBend             = 0xE0    # Pitch Bend
 | |
|     SystemExclusive       = 0xF0    # System Exclusive
 | |
|     TimeCodeQuarterFrame  = 0xF1    # System Common - MIDI Time Code Quarter Frame
 | |
|     SongPosition          = 0xF2    # System Common - Song Position Pointer
 | |
|     SongSelect            = 0xF3    # System Common - Song Select
 | |
|     TuneRequest           = 0xF6    # System Common - Tune Request
 | |
|     Clock                 = 0xF8    # System Real Time - Timing Clock
 | |
|     Start                 = 0xFA    # System Real Time - Start
 | |
|     Continue              = 0xFB    # System Real Time - Continue
 | |
|     Stop                  = 0xFC    # System Real Time - Stop
 | |
|     ActiveSensing         = 0xFE    # System Real Time - Active Sensing
 | |
|     SystemReset           = 0xFF    # System Real Time - System Reset
 | |
| 
 | |
|     @staticmethod
 | |
|     def getChannel(statusByte):
 | |
|         return statusByte & 0x0f;
 | |
| 
 | |
|     @staticmethod
 | |
|     def getType(statusByte):
 | |
|         if statusByte >= 0xf0:
 | |
|             # System messages
 | |
|             return statusByte
 | |
|         else:
 | |
|             # Channel messages
 | |
|             return statusByte & 0xf0;
 | |
| 
 | |
| 
 | |
| # ------------------------------------------------------------------------------
 | |
| 
 | |
| class MidiInterface:
 | |
|     def __init__(self, listenerCallback = None):
 | |
|         self.input              = rtmidi.MidiIn()
 | |
|         self.output             = rtmidi.MidiOut()
 | |
|         self.listenerCallback   = listenerCallback
 | |
|         self.ports              = self.getAvailablePorts()
 | |
|         self.port               = self.connect(self.choosePorts())
 | |
| 
 | |
|     # --------------------------------------------------------------------------
 | |
| 
 | |
|     def handleMidiInput(self, message, timestamp):
 | |
|         midiData = message[0]
 | |
|         if self.listenerCallback:
 | |
|             self.listenerCallback(midiData)
 | |
| 
 | |
|     def send(self, message):
 | |
|         print('Sending', message)
 | |
|         self.output.send_message(message)
 | |
| 
 | |
|     # --------------------------------------------------------------------------
 | |
| 
 | |
|     def getAvailablePorts(self):
 | |
|         return {
 | |
|             'input' : self.input.get_ports(),
 | |
|             'output': self.output.get_ports(),
 | |
|         }
 | |
| 
 | |
|     def choosePorts(self):
 | |
|         return {
 | |
|             'input' : self.choosePort(self.ports['input'],  'input'),
 | |
|             'output': self.choosePort(self.ports['output'], 'output')
 | |
|         }
 | |
| 
 | |
|     def choosePort(self, ports, direction):
 | |
|         if not ports:
 | |
|             print('No MIDI ports available, bailing out.')
 | |
|             return None
 | |
| 
 | |
|         if len(ports) == 1:
 | |
|             return {
 | |
|                 'id':   0,
 | |
|                 'name': ports[0]
 | |
|             }
 | |
| 
 | |
|         else:
 | |
|             # Give a choice
 | |
|             print('Multiple %s ports available, please make a choice:' % direction)
 | |
|             choices = dict()
 | |
|             for port, i in zip(ports, range(0, len(ports))):
 | |
|                 choices[i] = port
 | |
|                 print('  [%d]' % i, port)
 | |
|             choiceIndex = int(input('-> '))
 | |
|             return {
 | |
|                 'id': choiceIndex,
 | |
|                 'name': choices[choiceIndex]
 | |
|             }
 | |
| 
 | |
|     # --------------------------------------------------------------------------
 | |
| 
 | |
|     def connect(self, ports):
 | |
|         if not ports:
 | |
|             return None
 | |
| 
 | |
|         print('Connecting input to %s'  % ports['input']['name'])
 | |
|         print('Connecting output to %s' % ports['output']['name'])
 | |
| 
 | |
|         self.input.set_callback(self.handleMidiInput)
 | |
|         self.input.open_port(ports['input']['id'])
 | |
|         self.output.open_port(ports['output']['id'])
 | |
|         return ports
 |