Jump to content

Midi UDF


MattyD
 Share

Recommended Posts

Link to comment
Share on other sites

So _midi_ReadMsg() is just a splitter for our convenience. That's perfectly fine for my implementation. And the original midi data can always be recreated from the 4 integers. Besides the raw midi data can also be used.

@ptrex If I'm not mistaken, BF is a control change B0 (176) sent over channel F (15), together BF. So _midi_ReadMsg() correctly returns array [176, 15, control change, value]

Creator of the Peace equalizer, an interface for Equalizer APO. Besides Peace, my library of functions is also available on SourceForge.

Link to comment
Share on other sites

@PeterVerbeek

Hmmm, don't understand your analysis ...

See my previous print screen. the controller send BF over channel 16.

So the BF = 191

BO over channel 16 would give 176 + 16 = 192, which is C0

 

Indeed we can start using the RAW data input message.

But then there is no use in starting to use a UDF is we need to write our own functions is it ?

Edited by ptrex
Link to comment
Share on other sites

5 minutes ago, ptrex said:

But then there is no use in starting to use a UDF is we need to write our own functions is it ?

Yes indeed. I find _midi_ReadMsg() very convenient (good job Matty D!). In principle there's only one additional function needed to convert the output of _midi_ReadMsg() to raw midi.

Creator of the Peace equalizer, an interface for Equalizer APO. Besides Peace, my library of functions is also available on SourceForge.

Link to comment
Share on other sites

I know this ... but still it doesn't tie together with the output of the UDF see my print screen ?

Anyhow I don't want to spend more time on this for now, I can easily use the raw input message no problem.

But the confusion will remain for the other users in the future....

Link to comment
Share on other sites

Link to comment
Share on other sites

I've used multiple respected MIDI debugger apps in the meantime but never seen the B0 as output for a BF  ?

So I guess you are talking about the internal protocol handling stuff while I am talking about the MIDI message output data.

And that's the thing I'm after and counts for my use case...

If current UDF output works for your use case, that's good to hear.

 

BTW,  MattyD already provided a work around solution, as mentioned before reading the RAW data output ...

Link to comment
Share on other sites

yeah, so I'd say its best to conceptually seperate the two representations of the message.

 _midi_ReadMsg doesn't do [status, data1, data2] at the moment. It does [msg type, channel, param1, param2 ].

so note on, channel 4, middle c, full volume
[0x93, 0x3C, 0x7F] becomes [$MSG_NOTE_ON, 4, 60, 127]

pitch bend, channel 7, control in middle.
[0xE6, 0x00, 0x40] becomes [$MSG_BEND, 7, 0x2000, 0]. (param 2 is not in use.)

These are the message types:

$MSG_NOTE_OFF = 0x80
$MSG_NOTE_ON = 0x90
$MSG_KEY_PRES = 0xA0
$MSG_CC = 0xB0
$MSG_PC = 0xC0
$MSG_CHAN_PRES = 0xD0
$MSG_BEND = 0xE0

and how the parameters are represented.

Message type    Param 1                   Param 2
$MSG_NOTE_OFF   Note (0 - 127)            Velocity (0 - 127)
$MSG_NOTE_ON    Note (0 - 127)            Velocity (0 - 127)
$MSG_CHAN_PRES  Pressure (0 - 127)        -
$MSG_CC         Controller ID (0 - 127)   Value (0 - 127)
$MSG_PC         Program (1 - 128)         -
$MSG_KEY_PRES   Key (0 - 127)             Pressure (0 - 127)
$MSG_BEND       Bend Value (0 - 0x3FFF)   -

 

Edit:
As peter has eluded, It is possible to derive the status byte through BitOr($MsgType, ($Channel - 1)). If you're looking for the original message bytes [status, data1, data2] you will also need to handle pitch bends to seperate out the data bytes.  You can see _midi_ReadMsg was never really meant to be used in this fashion!

Getting the function to optionally return  [status, data1, data2] instead of [msg type, channel, param1, param2 ] is definately a legit request and support will be added :)

What I'm not  fussed on is a hybrid model like [status, channel, data1, data2], which I think (understandably) was the original assumption?. The channel info here is represented in two places, and because I'm using the array as a pseudo "message" thoughout the UDF we'll need rules for which takes precendence.

Edited by MattyD
Link to comment
Share on other sites

22 minutes ago, ptrex said:

I've used multiple respected MIDI debugger apps in the meantime but never seen the B0 as output for a BF 

I'm sorry to say but you're notion is wrong. When I'm using MIDI OX it says B0 on all 3 midi controllers I'm having. That's channel 1 so 00 plus control change type B0, so together B0. Other for other midi controllers this could be any number between B0 to BF, depending on the set channel.

MIDI OX 1.png

Creator of the Peace equalizer, an interface for Equalizer APO. Besides Peace, my library of functions is also available on SourceForge.

Link to comment
Share on other sites

This is what I see and what I have to stick too ...

MIDI-OX

image.png.74de7de6859d13b7c6892536cf9a4350.png

INTERNAL Debugger

image.png.6950d6520525021734cba3906fb2f6cf.png

MIDI ReadMsg

The Status xxx, line is coming from the ReadMsg function

The In : xxx, line comes from the RAW debug function

image.thumb.png.298209091fbe43d7fb681f031bcc2841.png

 

As MattyD already indicated the ReadMsg is not intended to send out RAW input message data.

I modified the ReadMsg to ReadMsgRAW function to facilitate this.

; #FUNCTION# ====================================================================================================================
; Name ..........: _midi_ReadMsgRAW
; Description ...: Retrieves and deconstructs a short message from the input queue.
; Syntax ........: _midi_ReadMsg($hDevice)
; Parameters ....: $hDevice - A midi input device handle.
; Return values .: Succes: A 4 element array of integers.
;                  $aiMsg[0] = The message Status ($MSG_)
;                  $aiMsg[1] = The target midi channel, or basic channel (1 - 16)
;                  $aiMsg[2] = The first parameter of the message.
;                  $aiMsg[3] = The second parameter of the message if required.
;                  Failure: An empty 4 element array, @error <> 0
; Author ........: MattyD
; Modified ......:
; Remarks .......: Messages will be discarded from the input queue if the are not retrieved within 2 seconds of arrival.
;                  The parameter elements are implemented as below:
;                  Message type   | Param 1                 | Param 2
;                  $MSG_NOTE_OFF  | Note (0 - 127)          | Velocity (0 - 127)
;                  $MSG_NOTE_ON   | Note (0 - 127)          | Velocity (0 - 127)
;                  $MSG_CHAN_PRES | Pressure (0 - 127)      | -
;                  $MSG_CC        | Controller ID (0 - 127) | Value (0 - 127)
;                  $MSG_PC        | Program (1 - 128)       | -
;                  $MSG_KEY_PRES  | Key (0 - 127)           | Pressure (0 - 127)
;                  $MSG_BEND      | Bend Value (0 - 0x3FFF) | -
; Related .......: Modified version of ReadMsg by PTREX
; Link ..........:
; Example .......: Yes
; ===============================================================================================================================
Func _midi_ReadMsgRAW($hDevice)
    Local $iMsg, $aiMsg[4], $iIndex
    Local Static $tMsg = DllStructCreate("byte[3]")

    $iIndex = __midi_GetMsg($hDevice)
    If $iIndex < 0 Then Return SetError(1, $aiMsg)

    $iMsg = $__g_adInputQueue[$iIndex][1]

    DllStructSetData($tMsg, 1, $iMsg)
    $aiMsg[0] = DllStructGetData($tMsg, 1, 1)
    $aiMsg[1] = BitAND(0x0F, DllStructGetData($tMsg, 1, 1)) + 1
    $aiMsg[2] = DllStructGetData($tMsg, 1, 2)
    $aiMsg[3] = DllStructGetData($tMsg, 1, 3)

    Switch $aiMsg[0]
        Case $MSG_PC
            $aiMsg[2] += 1
        Case $MSG_BEND
            $aiMsg[2] = BitShift($aiMsg[3], -7) + $aiMsg[2]
            $aiMsg[3] = 0
    EndSwitch

    $__g_adInputQueue[$iIndex][3] = True

    Return $aiMsg
EndFunc   ;==>_midi_ReadMsg

 

image.png.104daf921a91e88e74cd6bb395f4c213.png

 

Link to comment
Share on other sites

@MattyD

Could you post an example for _midi_SendMsg  on how to send a MIDI Short Message using these 4 bytes

I tried already a variety of combinations but don't succeed to send it successfully.

In MIDI-OX it looks like this :

image.thumb.png.2d2157357afed1a387bf28db605c6274.png

I need to get the message Array filled up correctly, to make it work.

_midi_SendMsg($hOutDevice, $aMsg[0])

 

Appreciated !

Link to comment
Share on other sites

Link to comment
Share on other sites

Don't stick to BF as midi controllers will send B0 to BF. You need to AND the status byte with F0 (4 upper bits) to get the control change type B0. Then AND with 0F to get the lower 4 bits which is the channel number. In your screenshot of BF becomes B0 (= control type) and 0F (channel 16).

If sticking with BF any midi controller which sends another channel, for instance, 6 which becomes B5, can't work with your app. Or if you set your midi controller to another channel your app can't deal with this channel change.

Creator of the Peace equalizer, an interface for Equalizer APO. Besides Peace, my library of functions is also available on SourceForge.

Link to comment
Share on other sites

Sure, I know ... this is how it works internally.

But again I don't want to do all the back and forth calculations.

All debuggers I have used so far represent the data as shown in the previous print screens.

And that's fine for me . .. 

The only time I would need the correct Channel nr. is when sending messages to the controller, instead of reading input messages it.

Link to comment
Share on other sites

I understand. Unfortunately it's how midi data works on a byte level. Back then they decided to use 1 byte for 2 purposes, most likely to save transmitting time and capacity. It isn't that bad just 2 And operations. But if you always do things on channel 16 (sending and receiving) there's indeed no need for any calculation. For my Peace midi panel implementation the channel number is important. And Matty D did the And operation for me :)

Creator of the Peace equalizer, an interface for Equalizer APO. Besides Peace, my library of functions is also available on SourceForge.

Link to comment
Share on other sites

Indeed, if you look at the MIDI video series I posted earlier (PART 4 / 5) it is all explained nicely ....

Unfortunately MIDI is not only used by Music instrument manufacturers, but also in the DJ scene...

These hardware manufactures don't care that much about the MIDI standards,

That's why MIDI mapping is done in a different way...

I posted some examples here :

https://audministrator.wordpress.com/2023/01/27/mixxx-midi-debugging-tools/

https://audministrator.wordpress.com/2023/02/02/mixxx-midi-mapping-whithout-hardware-explained/

 

Edited by ptrex
Link to comment
Share on other sites

So basically you're saying that the status byte of some DJ controllers don't follow the midi specs template of higher 4 bits = message type and lower 4 bits = channel no (as explained on 14:46 in video part 4 you referred to). That's plain ugly of those manufacturers. The status byte is the first and most important byte to consider and implement correctly. It should for a control change be B0 plus a channel no (which may be fixed to 0F for example). Or perhaps DJ controllers don't use control changes? Anyway, no wonder you need to have these oddities coded in your app.

Creator of the Peace equalizer, an interface for Equalizer APO. Besides Peace, my library of functions is also available on SourceForge.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...