Closed tf198 closed 3 years ago
Unfortunately, I don't think so. FluidSynth doesn't expose any functions in its public API that I can bind to in order to catch note events. Control changes set a value that we can poll regularly to see if it's changed, but a note is more like a single event that happens at a specific time - so we would need to be able to pass some sort of callback function to FluidSynth I believe.
Are you certain your keyboard can't send any control changes? What's your keyboard model? If it has a sustain pedal, that sends CC#64, which you could bind to INC_PATCH, or if it has a modulation wheel (CC#1) you could bind that to SELECT_PATCH. Not ideal, but it would let you change patches. You could also get something like a MidiFoot (one of my other little toys 😉), and plug it into one of the other USB ports on the Pi.
Thanks for the quick reply - from looking in the source it seemed like a lot was going on in the fluidsynth 'black box'.
I'm looking at it for use in a show band to fill in some missing instruments and we normally use reasonably priced digital pianos rather than fancy stage keyboards hence the lack of controllers. Have used sustain before on other 'show patch' software and pianists just can't help using the sustain pedal at the wrong time!
Secondary pedal device would work but I think have a go at a custom interface with space bar advance instead. Thanks again for providing this!
In case this is still of interest to you - I discovered/figured some things out that led me to make a major update (still in progress) that makes it possible to catch any and all MIDI events to trigger other MIDI events/functions. This would make it possible to change patches in the headless Pi synth with a note. I'll reference this issue when I push the update, which should cause you to get an email ping 🤞
I did a quick test modifying headless to use rtmidi directly via mido and poll through the note events.
inport = mido.get_input('Virtual Keyboard:Virtual Keyboard 131:0')
while True:
# other loop code
for msg in inport.iter_pending():
if msg.type == 'note_on':
if msg.note == 48:
pno = (pno - 1) % pxr.patches_count()
select_patch(pno)
if msg.note == 49:
pno = (pno + 1) % pxr.patches_count()
select_patch(pno)
Two connections to the midi source doesn't seem to be a problem and everything changes as expected. Would need to run some tests to ensure it can keep up with the events during some epic solo.
Is this the same way you were thinking of going or did you find a more efficient way to hook the events from fluidsynth?
I've replaced the mido_get_input line with : inport = mido.open_input('Keystation 88 MIDI 2') And it start working but it take 2 note, the fist on push and the second on pull : Selected patch 1/26: Piano
note_on channel=0 note=98 velocity=127 time=0 Selected patch 26/26: Power Kit
note_on channel=0 note=98 velocity=0 time=0 Selected patch 25/26: Standard Kit
So this is what is working for me:
inport = mido.open_input('Keystation 88 MIDI 2')
while True:
# other loop code
for msg in inport.iter_pending():
if msg.type == 'note_on' and msg.velocity == 127:
if msg.note == 98:
pno = (pno - 1) % pxr.patches_count()
select_patch(pno)
if msg.note == 99:
pno = (pno + 1) % pxr.patches_count()
select_patch(pno)
And this is working.
Fyi, some logs of my M-Audio Keystation88: aconnect -i (...) client 20: 'Keystation 88' [type=noyau,card=1] 0 'Keystation 88 MIDI 1' 1 'Keystation 88 MIDI 2'
aseqdump -p 20:1 20:1 Note on 0, note 96, velocity 127 20:1 Note off 0, note 96
Up 96 Down 97 Left 98 Right 99 Center 100 Stop 93 Play 94 Record 95
aseqdump -p 20:0 Modulation : 20:0 Control change 0, controller 1, value 0 20:0 Control change 0, controller 1, value 127
Pitch: 20:0 Pitch bend 0, value 8191 20:0 Pitch bend 0, value 0 20:0 Pitch bend 0, value -8192
Volume: 20:0 Control change 0, controller 7, value 127 20:0 Control change 0, controller 7, value 0
Note : 20:0 Note on 0, note 21, velocity 6 20:0 Note off 0, note 21 20:0 Note on 0, note 108, velocity 23 20:0 Note off 0, note 108
@tf198 My method actually sets up a python function in fluid2x.py as the callback function that passes MIDI events from the MIDI driver to the synthesizer - this seems work very smoothly without adding any latency, and also processes events immediately, rather than forcing us to poll every 0.1ms or so to see if MIDI events have arrived or a CC has changed. However, I've tried a similar thing to what you're doing with mido, and for things like changing patches that aren't super time sensitive it works fine and doesn't seem to cause any audio or lagging problems. If it works for you, go for it!
@esver Some keyboards send a note-on message with a velocity of zero instead of a note-off, so it makes sense you might need to specify the velocity to get it to work properly. You might want to look for msg.velocity > 0
- just in case you don't hit the key at maximum volume. It does seem from the midi dump like your keyboard is sending note off messages - but it's also possible that aseqdump just reports a note-on message with a velocity of zero as a note-off.
I need to be able to change the current patch up and down using two notes (e.g. A1 and B1) on headless.py but my keyboard doesn't have any controllers.
Is there any way to achieve this, either through router_rules or the API?
Thanks for an excellent project!