The HMP music format: (determined by hexdumping many hmp's) 1. ==== ORIGINAL FORMAT (as used in descent) ====================== Header 0x00 - 0x07: "HMIMIDIP" 0x08 - 0x1F: 0's 0x20 - 0x23: LSB int32, file length. 0x24 - 0x2F: ?? (in all examined hmp's: zero's) 0x30 - 0x33: LSB int32, number of chunks. 0x34 - 0x37: ?? looks like an LSB number (which is one of 78, C0, 180, 1E0 in all hmp's I've seen) 0x38 - 0x3B: LSB int32, midi division (with tempo = 1.0 s/beat (i.e. 60 beats per minute)) 0x3C - 0x3F: LSB int32, duration of the song (in seconds) 0x40 - 0x307: ?????? looks like 4 bytes per instrument (175 instruments + 3 extra?). Data 0x308 .. : music chunks. Chunk format (positions are relative to the start position of the chunk): 0x00 - 0x03: LSB int32, chunk number. 0x04 - 0x07: LSB int32, chunk length (i.e. including chunk header). 0x08 - 0x0B: LSB int32, track number (?) 0x0C .. : MIDI data, which is standard MIDI, except for variable length encoded numbers, which have the LSB first (and a byte here means 7 bits), with bit 7=1 except for the last byte. 2. ==== 31-1-1995 FORMAT (frontier, slipstream 5000) ============== Header 0x00 - 0x0C: "HMIMIDIP013195" 0x0E - 0x1F: 0's 0x20 - 0x3F: same as old format. 0x40 - 0x387: ?????? looks same as in the old format but with extra 0's added .. Data 0x388 .. : music chunks. Chunk format is the same as in the original format. 3. ==== 15-6-1995 FORMAT (abuse) ================================== Header 0x00 - 0x11: "HMI-MIDISONG061595" 0x12 - 0x1F: 0's 0x20 - 0x2D: 0's 0x2e - 0xAD: ?? FF's, with numbers 0-9 interspersed. 0xAE - 0xCF: ?? 0xD0 - 0xD1: LSB int16, ?? 0xD2 - 0xD3: LSB int16, midi division 0xD4 - 0xD7: LSB int32, song duration (in seconds) 0xD8 - 0xDB: LSB int32, ?? 0xDC - 0xDF: LSB int32, ?? 0xE4 : number of tracks 0x172 - 0x175: LSB int32, offset of first track 0x176 - 0x179: ditto for the second track etc. Tracks: (positions are relative to the start position of the track): 0x00 - 0x0C: "HMI-MIDITRACK" 0x57 - 0x5A: LSB int32, track header size 0x5B - 0x5E: LSB int32, same. [track header size] - ... : midi data. Sort of. Not yet deciphered... The HMQ music format: Hmp & hmq are really the same format, but hmq is only used for OPL synthesizers and uses many more (non general midi) drum instruments which is why hmq's don't sound nicely when playing them with a standard midi player. WHS (whs@xs4all.nl) ------------------------------------------------------------------------------- Descent Developer Network - HMP/HMQ specs Safe MIDI composition (i.e. hmp's that won't crash the game.. WHS) 1) OK first of all it's good practice to place all non-note midi events (chorus/reverb/pan/volume/patch/expression etc) before any note events start. So for example... [ here was hmp1.gif => converted to text: ] ____________________|1___.___.___.___|2___.___.___.___|3___._ track 1 | * |$ track 2 | * |$ You'd want to first shift the whole song to begin at measure 2. And place all non-note events (initializing channels) somewhere between the second beat of the first measure (*) and the first beat of the second measure ($) where the note data would begin to play. 2) I'm not sure about other conversion utilities, but this is required for HMI. Track one should be labeled "Loop" and contain only the events mentioned in the next step. * All instrument tracks for General midi songs need to be named with "[G]" preceding whatever instrument name is used (instrument name is optional but good to do for reference) For example "[G] grand piano." * FM song's instrument tracks need to start with [F]. * Furthermore, GUS cards can't read instruments unless you include a "U" So for a safe guard, D2's midi tracks all started with "[GUF]" to cover all bases. * Track names may NOT contain a hyphen! 3) Here's the fun part; Loop points. Say your song is 48 measures long, 4:4 time signature and you're using 120 ticks per quarter note. You would need to insert event messages as followings. Forgive the crude use of symbology :) [ here was hmp2.gif => converted to text: ] ____________________|1___.___.___.___|2___.___.___ ... _|47___.___.___.___|48 track 1 LOOP | *|$ | @|# track 2 [G]piano | ^|$ | &| track 3 [G]bass | ^|$ | &| * LOOP TRACK ONLY: "*" is at 1:4:119, Event message 110 with a value of 0 "@" 47:4:119, 111 set to 0. "#" 48:1:000, 1 set to 0 * FOR ALL OTHER INSTRUMENT TRACKS: "^" 1:4:119, Event message 1 with a value of 0 "&" 48:1:000, 1 set to 0 All midi events on Tracks 2.3 etc that occur between Track 1's event (*)110/0 and (#)1/0 will loop. Note that the alignment of messages need to be precise for each respective track. 4) Drums always are assigned to Midi channel 10 (duh) :) 5) Voices are always prioritized to the lower midi channels. So long sustained notes, or melodies that need to be assured to play with full duration, need to be placed on the lower channels. Bass, etc (anything that doesn't need to sustain as long) should be placed higher. 6) Always beware of cluttering midi events. Depending on your sequencer, you may be able to automate volume/pan etc. Try not to place too many successive midi events within the song. This will put a higher tax on your cpu and isn't necessary. 7) It's always a good idea to manually set each patch with a proper event message. See (1) for best placement.