Bytes, Nibbles & Bits for CoreMidi

March 12th, 2010 | Categories: Cocoa, Synth | Tags: ,

So I’m working on YAMP (yet another midi project :-) and it took me a while to recollect all the binary arithmetic required to parse MIDI packets.

Take a midi packet with 3 bytes in hexadecimal notation such as 99 3C 64. This stream encapsulates the following instructions:

Play middle C on channel 10 at velocity 100. Now lets strip it down to nibbles & bits.

9 -> Note on message. (Examples of other status messages are: 0xB for controller change, 0x C for program change & 0xE for pitch-bend)

9 -> Middle channel 10. (Range 0 -15)

3C ->Middle C -> Note 60

64 -> 100 in decimal

Determining if a stream begins with a status byte.

A set high-bit on the first byte identifies the byte as a status message. This can be accomplished visually by converting 99 from hex to binary 10011001,  and seeing if the first bit is 1. This can be tested mathematically with the following condtion:

0×99 > 0x7F

Once you have determined that the byte actually sets a status, you need to identify the actual status that is set. Some examples of status messages are: 0xB for controller change, 0xC for program change & 0xE for pitch-bend. To get the value of the left nibble, you can use the following expression.

0×99 >> 4 (Shift the 4 places) or 0×99 / 0×10

Determining the midi transmission channel.

The second nibble (99) of the first byte in the stream, represents the midi transmission channel. Channels are 0 indexed so they range from 0-F in hex or 0-15 in decimal. So we can tell quite easily that the transmission channel in our stream is 10 just by adding 1 to the second nibble. We can extract the 2nd nibble using the following expression:

0×99 % 0×10 (% = modulo)

and get the midi channel by adding 1 to the result

(0×99 % 0×10) + 1


Determining the note number and velocity.

These are pretty simple. Just convert the Hex values to a decimal values

0x3c = 60

0×64 = 100

I’ll post my parser here when I’m done with it this weekend.

  1. Robert
    May 7th, 2010 at 05:35
    Reply | Quote | #1

    Did you get your parser done before you bailed on the project? If so, please do post or email it still. I am working on a 16 track sequencer and I need all the help I can get. :) Thanks for your other CoreMIDI posts. (All two of them). :)

  2. admin
    May 7th, 2010 at 10:45
    Reply | Quote | #2

    Lol. Shame on me. That weekend never came. I’ll return to the project sometime this month when I’m done with a paying gig :-)

    I created a virtual receive port and I went as far as logging the received messages and updating my midi activity monitor. I’ll post what I have done so far and hope you find in useful. If not, I’ll post my complete parser soon.

    This is the midiReadProc from my virtual receive port.
    static void midiReadProc(const MIDIPacketList *midiPacketList, void *readProcRefCon, void *srcConnRefCon)
    {
    [[JXMidiSystem sharedInstance] updateReceiveActivityMonitor];

    int i, j;
    MIDIPacket *nextPacket = (MIDIPacket *)midiPacketList->packet;
    for (j=0 ; j < midiPacketList->numPackets; ++j)
    {
    for (i = 0; i < nextPacket->length; ++i)
    {
    NSLog(@"--%02X", nextPacket->data[i]);

    }
    nextPacket = MIDIPacketNext(nextPacket);
    NSLog(@"MIDIPacketNext");
    }

    //left nibble is 0x9A >> 4
    // right nibble 0x9A % 16
    // status bit >> 127
    //y = ((x >> 4) & 0x0f) | ((x < < 4) & 0xf0); swap nibbles

    }

  3. Robert
    May 8th, 2010 at 01:14
    Reply | Quote | #3

    Thanks for the post, and congrats on the paying gig. One of the challenges with my own project is figuring out how to handle the data I will be recording and outputting. It’s a pattern based beast, so will have a minimum 99 patterns of variable lengths, each with 16 tracks…and each track will have all the packet/packetlists and other data associated with that. Not sure how best to ‘struct’ all that. Then my other technical wonderment is going to be how to time all that on the way back out and still deal with interface updates, etc.? There’s not much roadmap for all this. Blogs likes yours and others are helpful, since googling on CoreMIDI provides not much information.

  4. admin
    May 8th, 2010 at 02:20
    Reply | Quote | #4

    @Robert
    I’m posting this without having had much time to think it through.

    I think timing shouldn’t be a big problem. Maybe you could deliver timestamped midi data in 2 measure chunks. Or you could make the chunk size dependent on the tempo of the pattern. The faster the tempo, the higher the chunk size.

    As far as how to structure it all, I would probably approach it like below. Mind you, I haven’t spent much time thinking about this.

    Song
    attributes: name, tempo, followSongOrPatternTempo?
    has a playlist

    Playlist
    has a list of slots.

    Slot
    attributes: length
    has one pattern

    Pattern
    attributes: name, tempo, length, swing
    has 16 tracks
    belongs to Song

    Track
    attributes: name, length, resolution, output, loop
    has many steps but resolution determines which steps are active
    belongs to a pattern

    Step
    attributes: active?, accent, index
    has one note or controller message
    belongs to a track

    Note
    attributes: pitch, velocity
    belongs to a step. time_stamp can be derived from the step.

  5. Robert
    May 9th, 2010 at 01:03
    Reply | Quote | #5

    Thanks, that’s a help. When I wrote pattern based, I meant parts actually, a la the Alesis MMT-8. It will alos be a live recorder (packetlists) Don’t know if that changes things. I work best that way, assembling chunks of different and similar sounding parts into songs. Thanks again for your time and thoughts.

  6. May 21st, 2010 at 02:02
    Reply | Quote | #6

    Thanks, that’s a help. When I wrote pattern based, I meant parts actually, a la the Alesis MMT-8. It will alos be a live recorder (packetlists) Don’t know if that changes things. I work best that way, assembling chunks of different and similar sounding parts into songs. Thanks again for your time and thoughts.

    [WORDPRESS HASHCASH] The poster sent us ’0 which is not a hashcash value.

Powered by WP Hashcash