It is currently Sun Dec 08, 2019 3:04 am



 [ 16 posts ] 
 MIDI to physical keypress 
Author Message
One Eyed Hopeful

Joined: Wed Nov 27, 2019 6:06 pm
Posts: 8
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!


Wed Nov 27, 2019 6:12 pm
Cross Eyed!

Joined: Mon Mar 02, 2015 3:58 pm
Posts: 147
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:
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


Wed Nov 27, 2019 7:40 pm
One Eyed Hopeful

Joined: Wed Nov 27, 2019 6:06 pm
Posts: 8
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:
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)


Wed Nov 27, 2019 8:20 pm
Petrif-Eyed

Joined: Mon Jun 22, 2009 8:36 am
Posts: 2164
Location: Stockholm, Sweden
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:
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:
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

_________________
FreePIE
My blog


Thu Nov 28, 2019 6:26 am
One Eyed Hopeful

Joined: Wed Nov 27, 2019 6:06 pm
Posts: 8
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:
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:
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.


Fri Nov 29, 2019 1:41 am
Cross Eyed!

Joined: Mon Mar 02, 2015 3:58 pm
Posts: 147
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:
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.


Fri Nov 29, 2019 3:34 am
Petrif-Eyed

Joined: Mon Jun 22, 2009 8:36 am
Posts: 2164
Location: Stockholm, Sweden
There is also a built in mechanic to send keypresses for a short timeperiod

keyboard.setPressed

_________________
FreePIE
My blog


Fri Nov 29, 2019 6:18 am
Cross Eyed!

Joined: Mon Mar 02, 2015 3:58 pm
Posts: 147
I forgot about that... Then it gets even simpler:

Code:
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.


Fri Nov 29, 2019 8:51 am
One Eyed Hopeful

Joined: Wed Nov 27, 2019 6:06 pm
Posts: 8
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:
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.


Fri Nov 29, 2019 1:13 pm
One Eyed Hopeful

Joined: Wed Nov 27, 2019 6:06 pm
Posts: 8
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.


Fri Nov 29, 2019 6:59 pm
Cross Eyed!

Joined: Mon Mar 02, 2015 3:58 pm
Posts: 147
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.


Sat Nov 30, 2019 9:00 am
One Eyed Hopeful

Joined: Wed Nov 27, 2019 6:06 pm
Posts: 8
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!


Sat Nov 30, 2019 2:47 pm
One Eyed Hopeful

Joined: Wed Nov 27, 2019 6:06 pm
Posts: 8
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.


Sat Nov 30, 2019 4:01 pm
Cross Eyed!

Joined: Mon Mar 02, 2015 3:58 pm
Posts: 147
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.


Sat Nov 30, 2019 6:46 pm
One Eyed Hopeful

Joined: Wed Nov 27, 2019 6:06 pm
Posts: 8
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.


Sat Nov 30, 2019 7:32 pm
Cross Eyed!

Joined: Mon Mar 02, 2015 3:58 pm
Posts: 147
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.


Sun Dec 01, 2019 5:34 am
Display posts from previous:  Sort by  
   [ 16 posts ] 

Who is online

Users browsing this forum: No registered users and 2 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Powered by phpBB® Forum Software © phpBB Group
Designed by STSoftware.