From 4ea2106791938f8d053084bba7143b18922e35d9 Mon Sep 17 00:00:00 2001 From: dosas Date: Tue, 23 Apr 2024 19:03:09 +0200 Subject: [PATCH] Add support for python-rtmidi while keeping backwards compatibility to rtmidi-python --- README.md | 26 ++++++++++++++++-------- samplerbox.py | 55 +++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 60 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 6b22746..fc589ae 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Website: [www.samplerbox.org](https://www.samplerbox.org) # Install -SamplerBox works with the RaspberryPi's built-in soundcard, but it is recommended to use a USB DAC (PCM2704 USB DAC for less than 10€ on eBay is fine) for better sound quality. +SamplerBox works with the RaspberryPi's built-in soundcard, but it is recommended to use a USB DAC (PCM2704 USB DAC for less than 10€ on eBay is fine) for better sound quality. You can use a ready-to-use ISO image from the [Releases](https://github.com/josephernest/SamplerBox/releases) page or do a manual install: @@ -22,12 +22,22 @@ You can use a ready-to-use ISO image from the [Releases](https://github.com/jose ~~~ sudo apt update - sudo apt -y install git python3-pip python3-smbus python3-numpy libportaudio2 + sudo apt -y install git python3-pip python3-smbus python3-numpy libportaudio2 libasound2-dev sudo apt -y install raspberrypi-kernel # quite long to install, do it only if necessary, it solves a "no sound before 25 second on boot" problem - sudo pip3 install cython rtmidi-python cffi sounddevice pyserial + sudo pip3 install cython cffi sounddevice pyserial ~~~ - -2. Download SamplerBox and build it with: + + For python < 3.9 + ~~~ + sudo pip3 install rtmidi-python + ~~~ + + For python >= 3.9 + ~~~ + sudo pip3 install python-rtmidi + ~~~ + +1. Download SamplerBox and build it with: ~~~ git clone https://github.com/josephernest/SamplerBox.git @@ -35,15 +45,15 @@ You can use a ready-to-use ISO image from the [Releases](https://github.com/jose sudo python3 setup.py build_ext --inplace ~~~ -3. Reboot the Pi, and run the soft with: - +1. Reboot the Pi, and run the soft with: + ~~~ sudo python3 samplerbox.py ~~~ Play some notes on the connected MIDI keyboard, you'll hear some sound! -4. *(Optional)* Modify `config.py` if you want to change root directory for sample-sets, default soundcard, etc. +1. *(Optional)* Modify `config.py` if you want to change root directory for sample-sets, default soundcard, etc. # How to use it diff --git a/samplerbox.py b/samplerbox.py index 2e7259a..9290fb2 100644 --- a/samplerbox.py +++ b/samplerbox.py @@ -23,7 +23,12 @@ import threading from chunk import Chunk import struct -import rtmidi_python as rtmidi +try: + import rtmidi_python as rtmidi + RTMIDI = False +except ModuleNotFoundError: + import rtmidi + RTMIDI = True import samplerbox_audio ######################################### @@ -165,7 +170,18 @@ def AudioCallback(outdata, frame_count, time_info, status): b *= globalvolume outdata[:] = b.reshape(outdata.shape) -def MidiCallback(message, time_stamp): + +def midi_callback(message, data=None): + message, deltatime = message + + return midi_callback_common(message, None) + + +def MidiCallback(message, timestamp): + return midi_callback_common(message, timestamp) + + +def midi_callback_common(message, timestamp): global playingnotes, sustain, sustainplayingnotes global preset messagetype = message[0] >> 4 @@ -424,14 +440,27 @@ def MidiSerialCallback(): # MAIN LOOP ######################################### -midi_in = [rtmidi.MidiIn(b'in')] -previous = [] -while True: - for port in midi_in[0].ports: - if port not in previous and b'Midi Through' not in port: - midi_in.append(rtmidi.MidiIn(b'in')) - midi_in[-1].callback = MidiCallback - midi_in[-1].open_port(port) - print('Opened MIDI: ' + str(port)) - previous = midi_in[0].ports - time.sleep(2) +if RTMIDI: + midi_in = [rtmidi.MidiIn()] + previous = [] + while True: + for num_port, port in enumerate(midi_in[0].get_ports()): + if port not in previous and 'Midi Through' not in port: + midi_in.append(rtmidi.MidiIn()) + midi_in[-1].set_callback(midi_callback) + midi_in[-1].open_port(num_port) + print('Opened MIDI: ' + str(port)) + previous = midi_in[0].get_ports() + time.sleep(2) +else: + midi_in = [rtmidi.MidiIn(b'in')] + previous = [] + while True: + for port in midi_in[0].ports: + if port not in previous and b'Midi Through' not in port: + midi_in.append(rtmidi.MidiIn(b'in')) + midi_in[-1].callback = MidiCallback + midi_in[-1].open_port(port) + print('Opened MIDI: ' + str(port)) + previous = midi_in[0].ports + time.sleep(2)