Page 1 of 2

MIDI

Posted: Fri Dec 12, 2014 12:53 am
by Ju4n
Hello! I couldn't find any support on MIDI. I was looking to achieve what I finally got to do with GlovePie: use a secondary keyboard as a midi controller.
Everything works fine, I use loopMIDI to generate a midi input for the secondary usb keyboard, chose it in Ableton Live and voilĂ ! New MIDI Controller out of a cheap kb.
Now the thing is that as it says here: http://glovepie.org/w/index.php?title=P ... 5#Keyboard if I want to swallow this keys not to interfere with anything else, it will also swallow my primary laptop keyboard.
Since FreePie is newer I thought this issue/feature would be overcome. Anyway, is there a way to swallow just one keyboard and send midi data to a virtual midi input from it?
Thank you in advance for everything.
Cheers!
JM

Re: MIDI

Posted: Fri Dec 12, 2014 3:32 am
by CyberVillain
We had a discussion about this a long time ago, I recall that we didnt find a solution for swallowing keyboard presses
edit: Midi is currently not supported, basicly because I dont have such hardware myself, but If someone would fix a plugin I would pull that code. Also there might be python code that can do it

Re: MIDI

Posted: Mon Dec 15, 2014 4:23 pm
by Ju4n
Thank you for your response.
What exactly would you need coded in order to pull code from? Sorry if a Google search would answer the question but being new to this input world I find it hard to relate.

Re: MIDI

Posted: Sat Dec 20, 2014 3:36 am
by CyberVillain
There are a .NET library for Midi, but since I dont have any midi device its hard for me to try it. Do you have any experience in Visual Studio and .Net?

Re: MIDI

Posted: Tue Dec 23, 2014 8:50 pm
by Ju4n
Hmmm I used to program (even study IT engineering) but I'm far from that now... I do own some MIDI hardware though. With a lot of time, I could try to learn something again.. but I should step aside for someone who knows better.
I recently acquired a taiwanese copy of Novation's Launchpad called Midiplus Smartpad. So, after some research, reached the conclusion that for it to correctly function with Ableton Live I should code its behaviour in python. When I saw Live's API just surrenderd... :? :woot

Re: MIDI

Posted: Mon Jan 05, 2015 4:45 am
by DrDim
Hi!
I just want to say, that FreePIE would immensely benefit from MIDI support.

DJ equipment is ridiculously cheap compared to e.g. flightsim enthusiast panels (those poor dudes get milked for their enthusiasm) but essentially they do the same thing:
Lots of different knobs and sliders, just a different interface: MIDI.
It would be totally awesome to feed e.g. VJoy with those MIDI devices!

Re: MIDI

Posted: Mon Jan 05, 2015 10:07 am
by CyberVillain
Yes, it would be really nice, but it would be great if a dev with MIDI hardware would step forward, because if I did it it would be like coding in the dark since I cant test it

Re: MIDI

Posted: Mon Jan 05, 2015 10:20 am
by CyberVillain

Re: MIDI

Posted: Mon Jan 05, 2015 10:26 am
by CyberVillain
Looks pretty staight forward to connect to a midi port with that API


https://midinet.codeplex.com/SourceCont ... eceiver.cs

edit: I can try to fix a plugin using this API and then you gusy can test it?

It seems there are two types of data, short data which is a int?
And long data which is a byte buffer, i guess we need to support both of these?

Re: MIDI

Posted: Mon Jan 05, 2015 5:32 pm
by DrDim
Midi Channels have 32 14bit and 32 7bit controls - maybe that's what long and short is referencing?

Of course I would test it with my device :D

It's only a simple slider which uses only one MIDI controller. Hopefully someone with more complex hardware or an actual instrument can test a wider range of input.

Re: MIDI

Posted: Tue Jan 06, 2015 6:26 am
by CyberVillain
Please try this little program i made, see if you receive anything

Re: MIDI

Posted: Tue Jan 06, 2015 12:15 pm
by DrDim
Works like a charm on my MIDI slider (Curious Inventor VMeter)

"S" ranges from 5296 to 8328368. I don't really know what this represents, but the device is using MIDI Channel 1, Controller 20, 0-127 or, in bytespeak: B0 14 00 to B0 14 7F - maybe thats related to those numbers?

"Time" is just that :)

EDIT: yes - of course they're related :D: If you put 5296 into a hexadecimal calculator you'll get "14B0". 8328368 equals "7F14B0"

Re: MIDI

Posted: Tue Jan 06, 2015 1:57 pm
by CyberVillain
Hmm ok so your device only sends short data (S), we would probably need to try this with a device that also sends long data. But cool that it worked as easy.

edit: antoher question, would it be better to represent that 32 bit integer as a 4 byte word?

That way I could make long and short data more the same, return a byte word each time (Byte buffer)

edit: Also looks like the endian differs from what you want

Re: MIDI

Posted: Tue Jan 06, 2015 2:36 pm
by CyberVillain
Heres a version that outputs the data as a byte word instead

Re: MIDI

Posted: Tue Jan 06, 2015 5:49 pm
by DrDim
Yes, I can read that version perfectly! e.g. at 100% slider it displays Data: B0 14 7F 0.

I don't know what the zero at the end means, (something with long and short data, because there's no "S" this time?) but the rest is something I can work with.

For 100% user friendliness you would need to convert those bytewords into their actual meaning in the MIDI context like "Control 20, 127" for the example above but there's the documentation of the standard and probing programs like Bome's which can do that as well. I think implementing that would be asking too much from you, considering you don't have a MIDI device.

Re: MIDI

Posted: Wed Jan 07, 2015 2:25 am
by CyberVillain
The data is 32 bits not 24 thats why there is a zero at the end, the FreePIE plugin will have a byte array so you will have to parse that yourself as the user of the plugin, so getting the 0-127 bit would be somethign like

Code: Select all

midi[0].data[2]

Re: MIDI

Posted: Wed Jan 07, 2015 6:03 am
by CyberVillain
I found this post

https://forums.frontier.co.uk/showthrea ... ost1410445

Would this be a better syntax?

Code: Select all

midi[0].control[20]
0x14 is the control (20) but what does 0xB0 (176) stand for?

edit: This synstax better supports FreePIE's code completion etc

Code: Select all

def onMidi(): 
	diagnostics.watch(midi[0].getControl(20))

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

Re: MIDI

Posted: Wed Jan 07, 2015 7:45 am
by DrDim
B0 defines the status byte (aka midi message type) and MIDI channel [0-15 + 1]

B0 equals "control change in channel 1"

E2 would be "pitch bending in channel 3"

The german wikipedia page on MIDI has a nice overview of status bytes and control channels (with english descriptions as well)
https://de.wikipedia.org/wiki/Musical_I ... chtentypen
https://de.wikipedia.org/wiki/Musical_I ... Controller

EDIT: Of course there's the official documentation as well:
http://www.midi.org/techspecs/midimessages.php#2

Re: MIDI

Posted: Wed Jan 07, 2015 7:53 am
by CyberVillain
Ok, so its port / channel / control?

Anyway, so I ignore first byte (Status byte) and use second byte for channel then?

Re: MIDI

Posted: Wed Jan 07, 2015 8:01 am
by DrDim
you could ignore it in the case of my device as it uses only "B" aka control anyway.

of course other MIDI devices would use all kinds of different status bytes [and channels] like notes etc.

the port is only the number the actual device got assigned to differenciate it from other MIDI devices
(which can be different for input and output on the same device - e.g. my slider has Port 0 for input and Port 5 for output)

Re: MIDI

Posted: Wed Jan 07, 2015 8:04 am
by CyberVillain
But it belongs to the channel so this would seem logical?

Code: Select all

midi[0].getChannel(0).status  #will be 0xB in your case, also midi[0] means port 0
midi[0].getChannel(0).getControl(20) #will be value from your slider
edit: Acutally getControl(20) will return a byte array with two slots because there are two data bytes (Yours only use one) http://www.midi.org/techspecs/midimessages.php#2

Re: MIDI

Posted: Wed Jan 07, 2015 8:25 am
by DrDim
So in the potential case when I would have a MIDI usb piano (on port 1) and play note "1"

Code: Select all

midi[1].getChannel(0).status  #will be 0x9
midi[1].getChannel(0).getNote(1) #will be the velocity of note "1"
Wouldn't it be better to call it "get2ndByte" to be more generic insteat of implementing all status byte types?

Re: MIDI

Posted: Wed Jan 07, 2015 8:28 am
by CyberVillain
getControl would return a array of bytes so

Code: Select all

midi[0].getChannel(0).getControl(20)[0] #returns first byte
midi[0].getChannel(0).getControl(20)[1] #returns second byte
edit: ah, control is a bad name, its only true if satus byte = 0xB, maybe getData then?

Re: MIDI

Posted: Wed Jan 07, 2015 8:36 am
by DrDim
yes - that would be a better name!

Re: MIDI

Posted: Wed Jan 07, 2015 8:36 am
by CyberVillain
Will get to work now :D Just to be clear, first version will only support reading MIDI

Re: MIDI

Posted: Wed Jan 07, 2015 8:46 am
by DrDim
Aweseome! :D

(also congrats on finding my thread ;) - it will be a blessing when I can use 2/3 of my keyboard in the game again insteat of using the keystrokes for that crude hack I described there ^^)

Re: MIDI

Posted: Wed Jan 07, 2015 8:49 am
by CyberVillain
Why is glovepie calling it control btw? And not data etc?

Re: MIDI

Posted: Wed Jan 07, 2015 9:06 am
by DrDim
GlovePIE uses all kinds of commands for MIDI IO. You can use actual notes like "csharp" or instruments like "maracas". Basically he (the developer) translated the most of the MIDI interface into GlovePIE

I personally think it's a little bit bloated esp. when you would use the GUI to create something because you have what feels like a 1km long scrollable dropdown list of MIDI inputs. Then again I know most what I know about MIDI from the GlovePIE documentation :)
http://glovepie.org/w/index.php?title=P ... v0.45#MIDI

EDIT: actually I found a "DataEntry" midi command in GlovePIE as well (it's undocumented though). I assume that's the more generic command you could use in GlovePIE instead of something specific and predefined like "Control".

Re: MIDI

Posted: Wed Jan 07, 2015 9:18 am
by CyberVillain
From a programmers perspective thats very ungeneric, and hard if you want todo some higly dynamic processing of the midi signal.. oh well
We will have to rewrite some of FreePIEs core functionally for this (code completion mainly) so it might take some time, but I could have a version workign without code completion very soon

Re: MIDI

Posted: Wed Jan 07, 2015 10:41 am
by CyberVillain
I am trying to minimize the footprint of the Midi API can you please try that it is still working please

Re: MIDI

Posted: Wed Jan 07, 2015 11:35 am
by DrDim
yep. still works on my end!

Re: MIDI

Posted: Wed Jan 07, 2015 1:03 pm
by CyberVillain
Ok, first test version, for now its stricly event driven, like this

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

Re: MIDI

Posted: Wed Jan 07, 2015 3:05 pm
by DrDim
The code above works well with my device.

Image

This is almost working too well :D . Can't believe there hasn't been any problems yet. I can only dream of doing anything like this which works right of the bat!

Re: MIDI

Posted: Wed Jan 07, 2015 3:36 pm
by CyberVillain
Cool that it works :D Let me know if you run into any problems using the code

Re: MIDI

Posted: Thu Jan 08, 2015 3:08 am
by CyberVillain
Since the midi plugin is purely event driven polling wont work that good (you might miss data that fires between script execution intevals) could you please try this script?

Code: Select all

def update():
	keyboard.setKey(Key.W, midi[0].data.buffer[1] < 64)
	keyboard.setKey(Key.S, midi[0].data.buffer[1] > 63)

if starting:
	midi[0].update += update
I'm not 100% sure the setkey command will work if you dont call it each script execution. Plase try it from a game because notepad wont catch more than one key.
values < 64 should make you character walk forward in game and values > 63 should make him walk backward

Re: MIDI

Posted: Thu Jan 08, 2015 4:32 am
by DrDim
https://www.youtube.com/watch?v=8ISyzGMe7YU

:)

Code: Select all

from System import Int16

def update():

   vJoy[0].rz = filters.mapRange(midi[0].data.buffer[1], 0, 127, -Int16.MaxValue, Int16.MaxValue)   
   diagnostics.watch(vJoy[0].rz)

if starting:
   midi[0].update += update
I'll have to work a bit on the ranges. Int16 seems to leave big deadzones.
Other than that I'm very happy with how this worked out overall! Thank you very much CyberVillain!

Re: MIDI

Posted: Thu Jan 08, 2015 5:30 am
by CyberVillain
Strange with the ranges, is the slider really linear? If you slide the slider 1/4 of the way buffer[1] should be close to 32

Re: MIDI

Posted: Thu Jan 08, 2015 5:43 am
by DrDim
I fixed it in a very analog way.
I measured the slider with a ruler. It has a lenth of ca. 11cm. Deadzones go from 0cm-2,5cm and 8,5cm-11cm
If you apply those values on the range of -32767 and 32767 with rule of three you get the approximate actual range of -17873 to 17873

When I use those values in the script it works like a charm :D

Code: Select all

def update():

   vJoy[0].rz = filters.mapRange(midi[0].data.buffer[1], 0, 127, -17873, 17873)
   
   diagnostics.watch(vJoy[0].rz)

if starting:
   midi[0].update += update
BTW: should I still test the setkey script?

Re: MIDI

Posted: Thu Jan 08, 2015 6:03 am
by CyberVillain
Strange that it has those deadzones, maybe has reason in the DJ world?

Yes, please try it, the keyboard plugin works different than vJoy

Re: MIDI

Posted: Thu Jan 08, 2015 6:36 am
by DrDim
I would rather assume that at least the rz axis of VJoy isn't using as much as -int16,int16. They were no deadzones when I used GlovePIE + PPJoy (actually I had to add deadzones).

The SetKey script seems to be rather accurate (I used A/D instead of W/S). No lag at all in Counter-Strike. You don't see it in the video, but I can do the tiniest sidesteps and it's still responsive, so I don't think anything gets eaten between intervals

https://www.youtube.com/watch?v=500BciVal5Y