MIDI to physical keypress

Official forum for open source FreePIE discussion and development.
Post Reply
moxanthia
One Eyed Hopeful
Posts: 8
Joined: Wed Nov 27, 2019 6:06 pm

MIDI to physical keypress

Post by moxanthia »

Hi, I'm not a coder, nor do I see any examples of people mapping midi inputs to keypresses. If someone could give me a quick example script, that would be much appreciated. I assume that FreePIE can emulate physical keypresses, because I've tried a couple other programs that convert MIDI to keypresses, but their outputs weren't detected by the game I want to play with the controller. Thanks much!

Jabberwock
Cross Eyed!
Posts: 160
Joined: Mon Mar 02, 2015 3:58 pm

Re: MIDI to physical keypress

Post by Jabberwock »

It has been a while since I have used a MIDI device and I do not have one at the ready. What is worse, mine was rather unstandard...

Could you please run this script and write down what values are sent when you press and release a key on your instrument (or when you do whatever else to send a note and stop it)?

Code: Select all

def update():
    diagnostics.watch(midi[0].data.channel);
    diagnostics.watch(midi[0].data.status);
    diagnostics.watch(midi[0].data.buffer[0]);
    diagnostics.watch(midi[0].data.buffer[1]);

if starting:
    midi[0].update += update

moxanthia
One Eyed Hopeful
Posts: 8
Joined: Wed Nov 27, 2019 6:06 pm

Re: MIDI to physical keypress

Post by moxanthia »

Jabberwock wrote:It has been a while since I have used a MIDI device and I do not have one at the ready. What is worse, mine was rather unstandard...

Could you please run this script and write down what values are sent when you press and release a key on your instrument (or when you do whatever else to send a note and stop it)?

Code: Select all

def update():
    diagnostics.watch(midi[0].data.channel);
    diagnostics.watch(midi[0].data.status);
    diagnostics.watch(midi[0].data.buffer[0]);
    diagnostics.watch(midi[0].data.buffer[1]);

if starting:
    midi[0].update += update
Thanks for the assistance! I have an MPD218, so it's pads. I get the following:

midi[0].data.channel 9
midi[0].data.status NoteOn
midi[0].data.buffer[0] (different numerical value for each pad)
midi[0].data.buffer[1] 127 (I have it set to always send full velocity so this value is constant)

CyberVillain
Petrif-Eyed
Posts: 2166
Joined: Mon Jun 22, 2009 8:36 am
Location: Stockholm, Sweden

Re: MIDI to physical keypress

Post by CyberVillain »

moxanthia wrote:
Jabberwock wrote:It has been a while since I have used a MIDI device and I do not have one at the ready. What is worse, mine was rather unstandard...

Could you please run this script and write down what values are sent when you press and release a key on your instrument (or when you do whatever else to send a note and stop it)?

Code: Select all

def update():
    diagnostics.watch(midi[0].data.channel);
    diagnostics.watch(midi[0].data.status);
    diagnostics.watch(midi[0].data.buffer[0]);
    diagnostics.watch(midi[0].data.buffer[1]);

if starting:
    midi[0].update += update
Thanks for the assistance! I have an MPD218, so it's pads. I get the following:

midi[0].data.channel 9
midi[0].data.status NoteOn
midi[0].data.buffer[0] (different numerical value for each pad)
midi[0].data.buffer[1] 127 (I have it set to always send full velocity so this value is constant)
Something like this could work, not tested!

Code: Select all

def update():
	keyboard.setKey(keyMapping[midi[0].data.buffer[0]], midi[0].data.status == MidiStatus.NoteOn)	
	
if starting:
	keyMapping = {0: Key.A, 1: Key.Space}
	midi[0].update += update
Pad = 0 maps to Key A and Pad = 1 to space

moxanthia
One Eyed Hopeful
Posts: 8
Joined: Wed Nov 27, 2019 6:06 pm

Re: MIDI to physical keypress

Post by moxanthia »

CyberVillain wrote:
moxanthia wrote:
Jabberwock wrote:It has been a while since I have used a MIDI device and I do not have one at the ready. What is worse, mine was rather unstandard...

Could you please run this script and write down what values are sent when you press and release a key on your instrument (or when you do whatever else to send a note and stop it)?

Code: Select all

def update():
    diagnostics.watch(midi[0].data.channel);
    diagnostics.watch(midi[0].data.status);
    diagnostics.watch(midi[0].data.buffer[0]);
    diagnostics.watch(midi[0].data.buffer[1]);

if starting:
    midi[0].update += update
Thanks for the assistance! I have an MPD218, so it's pads. I get the following:

midi[0].data.channel 9
midi[0].data.status NoteOn
midi[0].data.buffer[0] (different numerical value for each pad)
midi[0].data.buffer[1] 127 (I have it set to always send full velocity so this value is constant)
Something like this could work, not tested!

Code: Select all

def update():
	keyboard.setKey(keyMapping[midi[0].data.buffer[0]], midi[0].data.status == MidiStatus.NoteOn)	
	
if starting:
	keyMapping = {0: Key.A, 1: Key.Space}
	midi[0].update += update
Pad = 0 maps to Key A and Pad = 1 to space
Okay, so I would test this out, but for some reason FreePIE only detected my midi input the very first time I ran it. Other software still detects my input though.

Jabberwock
Cross Eyed!
Posts: 160
Joined: Mon Mar 02, 2015 3:58 pm

Re: MIDI to physical keypress

Post by Jabberwock »

I am not sure if it is the case, but you might have the same issue as I did: the instrument sends a NoteOn signal, but never sends a NoteOff (which is, as I understand, rather unorthodox from the MIDI point of view). That means that detecting NoteOn (as CyberVillain's script does) might not be very helpful, as that state simply remains, only the notes change. Actually, it was one of the reasons I do not have a physical MIDI device any more: I have torn out the old board and replaced it with an Arduino...

However, not all hope is lost, if all you want to do is just detect the exact moment the note is sent and you do not care how long it lasts, which is rather reasonable for drum pads. If you run the script on MIDI updates, you might just send a momentary keypress, i.e. the key will be pressed only in the frame (single script execution) directly after an MIDI update. The issue is that it means the key is pressed for a VERY short time, which might not be enough for your purposes. Here is a quick and dirty script (of course you need to replace the relevant entries in the keyMapping dictionary):

Code: Select all

def update():
	
	global midipressed

	midipressed = midi[0].data.buffer[0]


if starting:
	midi[0].update += update
	
	keyMapping = {49: Key.A, 51: Key.Space}
	
	midipressed = 0
	

for mapping, keyName in keyMapping.items(): 

	keyboard.setKey(keyName, mapping == midipressed)
	
midipressed = 0
If the keypresses are too short to be detected by the target app, you would need to zero the midipressed variable not immediately, but after some predefined time. It must be long enough to be detected, but also short enough to detect repeated hits of the same pad.

CyberVillain
Petrif-Eyed
Posts: 2166
Joined: Mon Jun 22, 2009 8:36 am
Location: Stockholm, Sweden

Re: MIDI to physical keypress

Post by CyberVillain »

There is also a built in mechanic to send keypresses for a short timeperiod

keyboard.setPressed

Jabberwock
Cross Eyed!
Posts: 160
Joined: Mon Mar 02, 2015 3:58 pm

Re: MIDI to physical keypress

Post by Jabberwock »

I forgot about that... Then it gets even simpler:

Code: Select all

def update():
   
   keyboard.setPressed(keyMapping[midi[0].data.buffer[0]])
   
if starting:
   
   keyMapping = {24: Key.A, 25: Key.B, 26: Key.C}
   
   midi[0].update += update
I have tested it with a virtual MIDI device and it seems to work.

moxanthia
One Eyed Hopeful
Posts: 8
Joined: Wed Nov 27, 2019 6:06 pm

Re: MIDI to physical keypress

Post by moxanthia »

Jabberwock wrote:I am not sure if it is the case, but you might have the same issue as I did: the instrument sends a NoteOn signal, but never sends a NoteOff (which is, as I understand, rather unorthodox from the MIDI point of view). That means that detecting NoteOn (as CyberVillain's script does) might not be very helpful, as that state simply remains, only the notes change. Actually, it was one of the reasons I do not have a physical MIDI device any more: I have torn out the old board and replaced it with an Arduino...

However, not all hope is lost, if all you want to do is just detect the exact moment the note is sent and you do not care how long it lasts, which is rather reasonable for drum pads. If you run the script on MIDI updates, you might just send a momentary keypress, i.e. the key will be pressed only in the frame (single script execution) directly after an MIDI update. The issue is that it means the key is pressed for a VERY short time, which might not be enough for your purposes. Here is a quick and dirty script (of course you need to replace the relevant entries in the keyMapping dictionary):

Code: Select all

def update():
	
	global midipressed

	midipressed = midi[0].data.buffer[0]


if starting:
	midi[0].update += update
	
	keyMapping = {49: Key.A, 51: Key.Space}
	
	midipressed = 0
	

for mapping, keyName in keyMapping.items(): 

	keyboard.setKey(keyName, mapping == midipressed)
	
midipressed = 0
If the keypresses are too short to be detected by the target app, you would need to zero the midipressed variable not immediately, but after some predefined time. It must be long enough to be detected, but also short enough to detect repeated hits of the same pad.
The problem is that FreePIE won't even give me any information in the Watch window with the first script you gave me for figuring out values. It worked the first time I ran it, so I was able to send you the results, but now nothing works. I've tried reconnecting the controller and rebooting, but I know that it isn't the connection that's a problem because other MIDI software still works flawlessly. FreePIE doesn't seem to have a setting for MIDI configuration, but it did just automatically work at first so I'm not sure what happened.

moxanthia
One Eyed Hopeful
Posts: 8
Joined: Wed Nov 27, 2019 6:06 pm

Re: MIDI to physical keypress

Post by moxanthia »

Okay, still not sure about why FreePIE doesn't detect MIDI on my PC, but I just tested out my laptop and everything works fine with the first script CyberVillain posted. Thanks for both of your assistance! Hopefully, I can figure out the issue with my PC. I'll try reinstalling FreePIE for starters.

Edit: Reinstalling didn't help sadly.

Jabberwock
Cross Eyed!
Posts: 160
Joined: Mon Mar 02, 2015 3:58 pm

Re: MIDI to physical keypress

Post by Jabberwock »

Check your MIDI inputs. FreePIE does not let you select one, so possibly something else (e.g. a virtual MIDI port) gets selected as an input. I usually use MidiOX to see what is going with MIDI. The only problem is that when I use MidiOX and another MIDI program together with virtual loop software, Windows might report a feedback and I need to reboot to get everything in order.

If CyberVillain's script works, then your instrument behaves as it should and sends a NoteOff message.

moxanthia
One Eyed Hopeful
Posts: 8
Joined: Wed Nov 27, 2019 6:06 pm

Re: MIDI to physical keypress

Post by moxanthia »

Jabberwock wrote:Check your MIDI inputs. FreePIE does not let you select one, so possibly something else (e.g. a virtual MIDI port) gets selected as an input. I usually use MidiOX to see what is going with MIDI. The only problem is that when I use MidiOX and another MIDI program together with virtual loop software, Windows might report a feedback and I need to reboot to get everything in order.

If CyberVillain's script works, then your instrument behaves as it should and sends a NoteOff message.
MIDIOX did indeed have a virtual input show up, so I removed it and now everything works fine. Thanks for the help!

moxanthia
One Eyed Hopeful
Posts: 8
Joined: Wed Nov 27, 2019 6:06 pm

Re: MIDI to physical keypress

Post by moxanthia »

Actually I've run into another problem. I thought that setPressed would keep the mapped key pressed down, but it seems to instead be repeatedly pressing the key which doesn't work for my purposes.

Jabberwock
Cross Eyed!
Posts: 160
Joined: Mon Mar 02, 2015 3:58 pm

Re: MIDI to physical keypress

Post by Jabberwock »

setPressed, as CyberVillain mentioned above, is only for momentary key press (but it should fire only once, on MIDI update). setKey (or setKeyDown/Up) is for toggling the key state.

moxanthia
One Eyed Hopeful
Posts: 8
Joined: Wed Nov 27, 2019 6:06 pm

Re: MIDI to physical keypress

Post by moxanthia »

Jabberwock wrote:setPressed, as CyberVillain mentioned above, is only for momentary key press (but it should fire only once, on MIDI update). setKey (or setKeyDown/Up) is for toggling the key state.
So if I use setKeyDown with NoteOn and setKeyUp with NoteOff, it should keep the key pressed down until I let off the pad right? I tried that and it still only sends a single keypress. The pad sends NoteOn and NoteOff if pressed quickly, but if I hold it down it sends NoteOn, PloyphonicAftertouch(for the entire period that it is held down), and then NoteOff.

Jabberwock
Cross Eyed!
Posts: 160
Joined: Mon Mar 02, 2015 3:58 pm

Re: MIDI to physical keypress

Post by Jabberwock »

How are you checking the keypresses? Notepad etc. might not be too good, as they register keypresses differently. To be sure, you might first try driving virtual controller buttons with vJoy if you have it installed (if not, then it might not be worth it).

To isolate the problem, I would try to change and watch a variable each time setkeyUp is used. That way you would know how many times it is executed and when. If it is not and the key is not held down, something else is going on.

Post Reply

Return to “FreePIE”