Posted: 14th Jun 2007 7:19
<Warning> It's been a while since I've worked with this, so please try to be patient... </Warning>

A LOOOOONG Time Ago, in a galaxy not too far from here, I was involved in some heavy MIDI encoding and such. Being a throwback from the (old) Mac days, all MIDI hexidecimal code (numbers, values) are saved as Big-Endian, meaning the largest order first. But I'm confused about how to "bring it back" to decimal numbers when reading it from a disk file.

For instance, a MIDI Track starts a chunk header: 8 bytes that tell us what's going on:

The first four bytes look like: [4D][54][72][6b]
...and they really mean: [M] [T] [r] [k]

...and the next four bytes will tell us the track length (in bytes). And here is where I'm missing the boat. (I tell you, in 1989 this code seemed a lot easier - of course I was writing it in C... ...but I'm afraid some of this has gotten swapped out, and I can't find the GDT for it any more! Aaaargh!)

The next four bytes could look like this: [00][00][00][16]
which converts to 0x00000016 = 22 decimal - and that's exactly how I should read it. I think. So I know that this track (MTrk is a MIDI Track header definition ID) is going to be 22 bytes long.

But what if it looks like [00][00][05][BA]? I figured (wrongly) that these would be the hexadecimal digits for 0x000005BA, right? The calculator states that 0x05BA = 1466 :: so good, so far. But why? If I read that right, I'm looking at:
+ Code Snippet
   1 * (16^3) +          [16^3 = 4096]    = 4096
   4 * (16^2) +          [16^2 = 256]     + 1024
   6 * (16^1) +          [16^1 = 16]      +   96
   6 * (16^0)            [16^0 = 1]       +    6
                                          = 5222 (wrong!) (wrong?)

..so I've missed the boat somewhere here.

<And so he flings the remainder of his dignity to the four winds...>

Am I wrong? Did I miss a step? Or is the calculator in error, possibly due to bad data entry? Is there anybody out there who remembers this well enough to help me put it back into perspective? I seem to remember this - vaguely - but not enough to simply have it go "click" and resolve it immediately. And I kinda' need to resolve it soon...

Thanks for your time and patience... ...I've got my fireproof suit on, just in case...
Posted: 14th Jun 2007 7:43
+ Code Snippet
0 * 16^3 =    0
5 * 16^2 + 1280 
B * 16^1 +  176
A * 16^0 +   10
         = 1466

1 * 10^3 = 1000  = 3E8    
4 * 10^2 +  400  + 190
6 * 10^1 +   60  +  3C
6 * 10^0 +    6  +   6
                 = 5BA

right?
Posted: 14th Jun 2007 16:10
For shame: I should get more sleep! I awoke this morning realizing that I might have crossed my "bases" - 10 and 16 - which you (Heartbone) illustrated so nicely. And patiently. Thank you very much.

Yep - you're right. And I'm embarrassed. But - as some of my students like to point out - I'm gettin' up there in years, so a few "senior moments" shouldn't trouble me too much.

Maybe they're right...

Or would getting more sleep help?
Posted: 14th Jun 2007 17:23
Just so you know, I looked at my code, and found a few other "omissions" - I must really stop trying to pull all-nighters in series - it was even *more* embarrassing - glad nobody could see what I saw!!! If I drank, I'd've thought I was drunk when I wrote that... ...guess I got no real excuse, then, huh?

For what it's worth - to clarify everything (and try to restore some shred of my dignity - no hope there! ) - the four-byte hexadecimal values look like this in your Hex Editor:

[00] [00] [05] [BA]

...and it's pretty straight-forward how to convert those values to decimal from hexadecimal. but when you're in DBPro, those bytes are read as decimal values (not hexadecimal, even though that's how we display it in the Hex Editor). NOW what do you do? Your byte values will read [0] [0] [5] [186] in DBPro.

The secret is in knowing which "places" the bytes are found - and performing a little "scalar" multiplication before adding them all back together. "Scalar" is used to reference the "Scale of the Order of Magnitude" of the numbers, not necessarily "a quantity that has a magnitude but no direction". (Although the two definitions come pretty close to one another.)

But what should those multiplicative values be? That's the easy part: the rest falls into position. (Anybody here who has studied a little number theory will be with me on this part.)

If you think about it, the byte values are retrieved as decimal values, but their *places* are still in hexadecimal. No, I haven't gone mad: it's the truth! The places are in hex, but the values are in decimal:

+ Code Snippet
    ` 00 00 00 00    [0] [0] [0] [0]
    `  ^  ^  ^  ^
    `  |  |  |  |
    `  |  |  |  +--- byteVal * (16^0)
    `  |  |  +------ byteVal * (16^2)
    `  |  +--------- byteVal * (16^4)
    `  +------------ byteVal * (16^6)


So, if you open a file in your Hex Editor, and see the four-byte pattern [03][D1][09][A3], what do you think those four (byte) values will be when you read them into a DBPro variable? They will be the decimal values [3][209][9][163]. Trust me - go on and try it. I'll wait...

But what should they be? How do you get the correct decimal value from those four bytes? Well, if you looked into my explanation under the +Code+ button above, you'll have a formula for turning this value from four (hexadecimal) bytes to a decimal value:

+ Code Snippet
        Hex: [03][D1][09][A3]
               ^   ^   ^   ^
               |   |   |   |
               |   |   |   +--- byteVal * (16^0)
               |   |   +------- byteVal * (16^2)
               |   +----------- byteVal * (16^4)
               +--------------- byteVal * (16^6)

Byte Values: [3][209][9][163]
              ^    ^  ^    ^
              |    |  |    |
              |    |  |    +--- byteVal * (16^0)
              |    |  +-------- byteVal * (16^2)
              |    +----------- byteVal * (16^4)
              +---------------- byteVal * (16^6)


...is the relationship recognizable? I've got some pretty good "deer in the headlights" looks from the middle of the classroom, here. You see - the decimal values are the FULL values (for each place) of the hexadecimal numbers in those bytes - in those places. In this case, we know that there are four places, and each byte value is the FULL value that two hexadecimal digits occupy in our Hex Editor. So all we need to know is what "place" our value is occupying, in order to know what order of magnitude it belongs to - so we know what to multiply it with:

+ Code Snippet
Byte Values: [3][209][9][163]
              ^    ^  ^    ^
              |    |  |    |
              |    |  |    +--- byteVal * (16^0)
              |    |  +-------- byteVal * (16^2)
              |    +----------- byteVal * (16^4)
              +---------------- byteVal * (16^6)

   = (3 * (16^6)) + (209 * (16^4)) + (9 * (16^2)) + (163 * (16^0))
   = (3 * (16777216)) + (209 * (65536)) + (9 * (256)) + (163 * (1))
   = (50331648) + (13697024) + (2304) + (163)
   = 64028672 + (2304) + (163)
   = 64030976 + (163)
   = 64031139


Magic, right? Yep, just like magic. And once you know the trick, well, it still mystifies others.


...And the Big-Endian vs. Little-Endian thing is a Mac vs. Intel thing: for a given data type (which takes up a certain amount of memory, regardless of actual value) the data can be stored "Little End First", like the Intel people do it, or "Big End First", like the Mac guys used to. In "Big-Endian" format, our number above is stored as [03][D1][09][A3]. In "Little-Endian" format, the bytes are stored in the reverse order, [A3][09][D1][03]. That's it - that's the big difference.

Since I'm not teaching Basic Algorithms this summer, we won't need to discuss it any further. (Unless you really want to, that is...)


Thank your for your time and attention. Sorry I almost caused a stir about nothing. I included the above message to clarify what was going on, and to (hopefully) de-mystify a few things about MIDI data encoding. MIDI values are encoded/written in four-byte "big-endian" format. And once you know that, you're ready to parse MIDI at the file level...
Posted: 14th Jun 2007 20:29
And the Big-Endian vs. Little-Endian thing is a Mac vs. Intel thing


Err, no - that's overly simplistic. Besides, it goes back a lot further than that (into the 60's at least), and big vs little aren't the only combinations either.
Posted: 15th Jun 2007 16:16
Ah, but where MIDI code is concerned, it *is* a Mac vs. Intel thing. Sad but true: the Mac was the first platform to support the MIDI specification - PCs have always lagged where innovation is concerned - and thus the byte encoding was inherently Big-Endian.
Posted: 15th Jun 2007 17:22
LongFist, I've been there, no shame.
Brain farts are a part of life.

Actually the Atari 800 supported MIDI before the Mac.

Thru a Special Purchase, Best Electronics has purchased the remaining New stock of the Wizztronics MIDIMAX MIDI Keyboard interfaces (first released in 1985) recently unearthed at Wizztronics, for the Atari 8 Bit Computers (400 (48K), 800 (48K), 1200XL, 800XL, 65XE / 130XE or XE Game Machines with an Atari 8 bit Disk drive. With an inexpensive MIDI Compatible Keyboard you can now learn how to Play MIDI Synthesizers, Drum machines, Write/Save, Play and Modify Music without the normal High cost of a normal MIDI system and Computer. A Brand New application for your Classic Atari 8 bit Computer!! Less then 8 left in stock!! When they are gone, they pass into Atari 8 bit computer History!


Good luck on your project.
Posted: 15th Jun 2007 17:22
Posted: 15th Jun 2007 18:39
Never saw the MIDIMax Interface before, just remembering that I got my PC, set it up in preparation to build an interface for MIDI instruments, and discovered that the Mac (of all things) already spoke the language! Oh, yeah, we could buy the MPU-401, but only if we could scrounge up the money - and it wasn't cheap!

The Big-Endian/Little-Endian "war" is immaterial to the MIDI specification: it's just the little matter of "who got there first", and I'm pretty sure it was the Mac - at least I *was* pretty sure. The Atari 800, didn't that run on a MOS 6502 or something like that? They were a direct spin-off from Motorola (if memory serves) with all the legal troubles one might expect. But their 6500-series of processors were also big-endian, no? So I guess it wasn't Mac but Atari's influence that made the standard.

And all this time I thought it was a Mac that forged that particular standard. Just goes to show you how little you know... ...and I was there when all this was a-happening. Guess I didn't pay enough attention - but there were more than a few distractions around then. I mean, real-world distractions...
Posted: 15th Jun 2007 18:46
And I whole-heartedly agree: big-endian is so much more natural to data storage (in general) than little-endian. And since I started my low-level programming on Intel-based machines, you can bet that the "reversed order" bytes really screwed me up. And since I already knew the length of the data I was reading in, it just seemed like it would make more sense to do it that way (big endian).

Not that it matters any more. We've just got to beware which format is being used when we write our code, that's all.

And I'm so glad to have this all cleared up. I can safely say that - with all o' ya'll's help, we have unscrambled an egg. Miracles never cease!!!
Posted: 15th Jun 2007 20:21
Or use a higher level language to eliminate the petty details.

Good luck on your project.