I am using the mido library to control amsynth with python.
So far this is working beautifully...but I can only play one "preset" at a time however.
I'm trying to use "program_change" to switch instruments so I can play several instruments at once.
As a quick example:
import mido
from mido import Message
import time
outport = mido.open_output('amsynth:MIDI IN')
msg = Message('note_on', note = 64)
outport.send(msg)
time.sleep(2.0)
msg = Message('program_change', program = 1)
outport.send(msg)
msg = Message('note_on', note = 68)
outport.send(msg)
time.sleep(2.0)
msg = Message('note_off', note = 64)
outport.send(msg)
time.sleep(0.5)
msg = Message('note_off', note = 68)
outport.send(msg)
time.sleep(0.5)
But when I try this, the note from the first program is cut as soon as I switch channels.
So maybe the issue is each program needs to be on a different channel:
import mido
from mido import Message
import time
outport = mido.open_output('amsynth:MIDI IN')
msg = Message('note_on', note = 64, channel = 0)
outport.send(msg)
time.sleep(2.0)
msg = Message('program_change', program = 1)
outport.send(msg)
msg = Message('note_on', note = 68, channel = 1)
outport.send(msg)
time.sleep(2.0)
msg = Message('note_off', note = 64)
outport.send(msg)
time.sleep(0.5)
msg = Message('note_off', note = 68)
outport.send(msg)
time.sleep(0.5)
But this doesn't work either.
As a workaround, I have been considering running multiple instances of amsynth...but that just seems perverse to me.
How can I play several instruments at once?
Edit:
It sounds like I will need to assign programs to channels before starting playback, and then play back per channel like so:
msg = Message('program_change', program = 23, channel = 1)
outport.send(msg)
msg = Message('program_change', program = 3, channel = 2)
outport.send(msg)
msg = Message('note_on', note = 64, channel = 1)
outport.send(msg)
time.sleep(2.0)
msg = Message('note_on', note = 68, channel = 2)
outport.send(msg)
time.sleep(2.0)
msg = Message('note_off', note = 64, channel = 1)
outport.send(msg)
time.sleep(0.5)
msg = Message('note_off', note = 68, channel = 2)
outport.send(msg)
time.sleep(0.5)
However, this plays back both notes with program 3, so this doesn't work unfortunately.
With MIDI, there are 16 channels. Each channel can be on one program/patch at a given time. When you call
program_change
, you're changing the patch for that default channel. You should sendprogram_change
for another channel, and then send MIDI notes to that other channel as well.