You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
MiniDexed/miditest.py

163 lines
6.2 KiB

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Send MIDI data to a MIDI device using the `python-rtmidi` library.
try:
import rtmidi
except ImportError:
print("Please install the python-rtmidi library: pip install python-rtmidi")
exit(1)
import time
import sys
import argparse
import os
import signal
import atexit
def signal_handler(sig, frame):
print("\nExiting...")
sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)
def cleanup_all_notes_off():
try:
midiout = rtmidi.MidiOut()
ports = midiout.get_ports()
if ports:
midiout.open_port(0)
all_notes_off(midiout, verbose=True)
time.sleep(0.5)
midiout.close_port()
except Exception as e:
print(f"Cleanup error: {e}")
atexit.register(cleanup_all_notes_off)
# Ask the user which MIDI port to use
def get_midi_port(midiout):
print("Available MIDI output ports:")
ports = midiout.get_ports()
for i, port in enumerate(ports):
print(f"{i}: {port}")
while True:
try:
choice = int(input("Select a port by number: "))
if 0 <= choice < len(ports):
return choice
else:
print("Invalid choice. Please select a valid port number.")
except ValueError:
print("Invalid input. Please enter a number.")
def play_chord(midiout, notes, velocity=100, channel=0, delay=0.25, verbose=True):
print("Playing chord:", notes)
for note in notes:
midiout.send_message([0x90 | channel, note, velocity])
time.sleep(delay)
time.sleep(0.5)
for note in notes:
midiout.send_message([0x80 | channel, note, 0])
def send_sysex(midiout, msg, verbose=True, label=None):
midiout.send_message(msg)
if verbose:
if label:
print(f"Sent: {label} {msg}")
else:
print(f"Sent: {msg}")
def all_notes_off(midiout, verbose=True):
# Send All Notes Off (CC 123) and individual Note Off for all notes 0-127 on all 16 MIDI channels
for channel in range(16):
midiout.send_message([0xB0 | channel, 120, 0])
if verbose:
print(f"Sent: All Sound Off (CC120) on channel {channel+1}")
def send_modwheel(midiout, value, channel=0, verbose=True):
# Modulation wheel is CC 1
midiout.send_message([0xB0 | channel, 1, value])
if verbose:
print(f"Sent: ModWheel CC1 value {value} on channel {channel+1}")
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Send MIDI messages to a device.")
parser.add_argument("-p", "--port", type=str, help="MIDI output port name or number")
# Always verbose, so remove the verbose switch and set verbose to True
args = parser.parse_args()
verbose = True
midiout = rtmidi.MidiOut()
ports = midiout.get_ports()
if args.port is not None:
# Allow port to be specified by number or name
try:
port_index = int(args.port)
except ValueError:
# Try to find by name
port_index = next((i for i, p in enumerate(ports) if args.port in p), None)
if port_index is None:
print(f"Port '{args.port}' not found.")
sys.exit(1)
else:
port_index = get_midi_port(midiout)
if verbose:
print(f"Using MIDI output port: {ports[port_index]}")
try:
midiout.open_port(port_index)
chord_notes = [60, 64, 67]
# Send all notes off before starting the test program
all_notes_off(midiout, verbose=verbose)
while True:
send_sysex(midiout, [0xF0, 0x43, 0x10, 0x04, 0x05, 0x00, 0xF7], verbose, "Portamento Time 0")
play_chord(midiout, chord_notes, verbose=verbose)
send_sysex(midiout, [0xF0, 0x43, 0x10, 0x04, 0x05, 0x02, 0xF7], verbose, "Portamento Time 2")
time.sleep(1)
# Test Detune
detune_msgs = [
([0xF0, 0x43, 0x10, 0x04, 0x40, 0x2F, 0xF7], "Detune TG1"),
([0xF0, 0x43, 0x11, 0x04, 0x40, 0x37, 0xF7], "Detune TG2"),
([0xF0, 0x43, 0x12, 0x04, 0x40, 0x40, 0xF7], "Detune TG3"),
([0xF0, 0x43, 0x13, 0x04, 0x40, 0x48, 0xF7], "Detune TG4"),
]
for msg, label in detune_msgs:
send_sysex(midiout, msg, verbose, label)
play_chord(midiout, chord_notes, verbose=verbose)
for ch in range(0x10, 0x14):
send_sysex(midiout, [0xF0, 0x43, ch, 0x04, 0x40, 0x40, 0xF7], verbose, f"Detune TG{ch-0x0F} reset")
time.sleep(1)
# Test Poly and Mono modes
send_sysex(midiout, [0xF0, 0x43, 0x13, 0x04, 0x02, 0x00, 0xF7], verbose, "TG4 Poly")
play_chord(midiout, chord_notes, verbose=verbose)
send_sysex(midiout, [0xF0, 0x43, 0x13, 0x04, 0x02, 0x01, 0xF7], verbose, "TG4 Mono")
time.sleep(1)
# Test ModWheel sensitivity
send_sysex(midiout, [0xF0, 0x43, 0x13, 0x04, 0x09, 0x01, 0xF7], verbose, "TG4 ModWheel Sensitivity ON")
send_modwheel(midiout, 127, channel=0, verbose=verbose)
play_chord(midiout, chord_notes, verbose=verbose)
send_modwheel(midiout, 0, channel=0, verbose=verbose)
send_sysex(midiout, [0xF0, 0x43, 0x13, 0x04, 0x09, 0x00, 0xF7], verbose, "TG4 ModWheel Sensitivity OFF")
send_modwheel(midiout, 127, channel=0, verbose=verbose)
play_chord(midiout, chord_notes, verbose=verbose)
send_modwheel(midiout, 0, channel=0, verbose=verbose)
time.sleep(1)
# Disable all Tone Generators except TG1
send_sysex(midiout, [0xF0, 0x43, 0x13, 0x04, 0x08, 0x00, 0xF7], verbose, "Disable TG2, TG3, TG4")
play_chord(midiout, chord_notes, verbose=verbose)
# Enable all Tone Generators
send_sysex(midiout, [0xF0, 0x43, 0x13, 0x04, 0x08, 0x01, 0xF7], verbose, "Enable TG2, TG3, TG4")
play_chord(midiout, chord_notes, verbose=verbose)
time.sleep(1)
# Send all notes off after each test program loop
all_notes_off(midiout, verbose=verbose)
except Exception as e:
print(f"Error: {e}")
sys.exit(1)