diff options
author | Max Horn | 2003-09-09 01:21:42 +0000 |
---|---|---|
committer | Max Horn | 2003-09-09 01:21:42 +0000 |
commit | 6adb8560a857d10f8d4730c184e131857a82d2a7 (patch) | |
tree | 3b5b2267c159415da2c9eebc76bed7ea25e81edf /scumm/resource.cpp | |
parent | 24560608eda1c834b55bcfbf5bf22b23d436e0d0 (diff) | |
download | scummvm-rg350-6adb8560a857d10f8d4730c184e131857a82d2a7.tar.gz scummvm-rg350-6adb8560a857d10f8d4730c184e131857a82d2a7.tar.bz2 scummvm-rg350-6adb8560a857d10f8d4730c184e131857a82d2a7.zip |
some initial work on Mac0 support. Everybody feel free to pick up here and implement the rest <g>
svn-id: r10119
Diffstat (limited to 'scumm/resource.cpp')
-rw-r--r-- | scumm/resource.cpp | 247 |
1 files changed, 150 insertions, 97 deletions
diff --git a/scumm/resource.cpp b/scumm/resource.cpp index 8109f40a49..b823f86b84 100644 --- a/scumm/resource.cpp +++ b/scumm/resource.cpp @@ -972,55 +972,70 @@ int Scumm::convert_extraflags(byte * ptr, byte * src_ptr) { return time; } +#define kMIDIHeaderSize 46 +static inline byte *writeMIDIHeader(byte *ptr, const char *type, int ppqn, int total_size) { + uint32 dw = TO_BE_32(total_size); + + memcpy(ptr, type, 4); ptr += 4; + memcpy(ptr, &dw, 4); ptr += 4; + memcpy(ptr, "MDhd", 4); ptr += 4; + ptr[0] = 0; ptr[1] = 0; ptr[2] = 0; ptr[3] = 8; + ptr += 4; + memset(ptr, 0, 8), ptr += 8; + memcpy(ptr, "MThd", 4); ptr += 4; + ptr[0] = 0; ptr[1] = 0; ptr[2] = 0; ptr[3] = 6; + ptr += 4; + ptr[0] = 0; ptr[1] = 0; ptr[2] = 0; ptr[3] = 1; // MIDI format 0 with 1 track + ptr += 4; + + *ptr++ = ppqn >> 8; + *ptr++ = ppqn & 0xFF; + + memcpy(ptr, "MTrk", 4); ptr += 4; + memcpy(ptr, &dw, 4); ptr += 4; + + return ptr; +} + +static inline byte *writeVLQ(byte *ptr, int value) { + if (value > 0x7f) { + if (value > 0x3fff) { + *ptr++ = (value >> 14) | 0x80; + value &= 0x3fff; + } + *ptr++ = (value >> 7) | 0x80; + value &= 0x7f; + } + *ptr++ = value; + return ptr; +} + +static inline byte Mac0ToGMInstrument(uint32 type) { + switch (type) { + case MKID('MARI'): return 13; + case MKID('PLUC'): return 46; + case MKID('HARM'): return 23; + case MKID('PIPE'): return 110; // 20 or 74 or 110 ? + case MKID('TROM'): return 58; + case MKID('STRI'): return 49; // 49 or 50 + case MKID('HORN'): return 61; // 61 or 70 + case MKID('VIBE'): return 12; + case MKID('SHAK'): return 78; + case MKID('PANP'): return 76; + case MKID('WHIS'): return 79; + case MKID('ORGA'): return 17; // 17-21 + case MKID('BONG'): return 116; + case MKID('BASS'): return 33; // 33-40 + default: + error("Unknown Mac0 instrument %c%c%c%c found", + (byte)type, + (byte)(type >> 8), + (byte)(type >> 16), + (byte)(type >> 24)); + } +} + void Scumm::convertMac0Resource(int type, int idx, byte *src_ptr, int size) { - /* Offset - 0x14, 0x1C, 0x20, 0x24 - offsets of channel 1/2/3/4 chunk- - Each channel has tag "Chan", followed by its length. At the end - of each chan follows either an empty "Done" chunk (length 0) or an - empty "Loop" chunk. Maybe "Loop" indicates the song should be - played forever?!?. - - There can be various different subchunks it seems. The - following combinations appear in Monkey Island: - 100: ORGA, TROM, BASS, - 101: ORGA, SHAK, BASS, - 103: PIPE, PIPE, PIPE, - 104: VIBE, WHIS, BASS, - 108: ORGA, MARI, BASS, - 110: ORGA, SHAK, VIBE, - 111: MARI, SHAK, BASS, - 115: PLUC, SHAK, WHIS, - One guess is that these are instrument names: Organ, Marimba, Whistle... - Maybe there is a mapping table someplace? Maybe these are even mapped to - Mac1 type "instruments" ? - - What follows are four byte "commands" it seems, like this (hex): - 01 68 4F 49 - 01 68 00 40 - 01 68 4F 49 - ... - 01 68 00 40 - 02 1C 5B 40 - 00 B4 00 40 - ... - 01 68 37 3C - 00 18 37 38 - 04 20 3E 34 - 01 68 4A 3C - - More data: - 00 09 3E 10 - 01 5F 00 40 - 00 9C 36 40 - 00 CC 00 40 - 00 18 42 49 - 00 18 45 3C - 01 29 4A 3C - 00 0F 00 40 - - Maybe I am mistaken when I think it's four byte, some other parts - seem to suggest it's 2 byte oriented, or even variable length... - */ /* From Markus Magnuson (superqult) we got this information: Mac0 @@ -1072,48 +1087,102 @@ void Scumm::convertMac0Resource(int type, int idx, byte *src_ptr, int size) { listed above. */ +#if 1 byte *ptr = createResource(type, idx, size); - - // TODO: Implement Mac0 -> GM conversion - // For now, just copy the resource data memcpy(ptr, src_ptr, size); -} - -static inline byte *writeMIDIHeader(byte *ptr, const char *type, int ppqn, int total_size) { - uint32 dw = TO_BE_32(total_size); +#else + const int ppqn = 480; + byte *ptr, *start_ptr; - memcpy(ptr, "ADL ", 4); ptr += 4; - memcpy(ptr, &dw, 4); ptr += 4; - memcpy(ptr, "MDhd", 4); ptr += 4; - ptr[0] = 0; ptr[1] = 0; ptr[2] = 0; ptr[3] = 8; - ptr += 4; - memset(ptr, 0, 8), ptr += 8; - memcpy(ptr, "MThd", 4); ptr += 4; - ptr[0] = 0; ptr[1] = 0; ptr[2] = 0; ptr[3] = 6; - ptr += 4; - ptr[0] = 0; ptr[1] = 0; ptr[2] = 0; ptr[3] = 1; // MIDI format 0 with 1 track - ptr += 4; + int total_size = 0; + total_size += kMIDIHeaderSize; // Header + total_size += 5; // end of song sysex + total_size += 3 * 2; // Three programm change mesages - *ptr++ = ppqn >> 8; - *ptr++ = ppqn & 0xFF; - - memcpy(ptr, "MTrk", 4); ptr += 4; - memcpy(ptr, &dw, 4); ptr += 4; + int i, len; + byte track_instr[3]; + int current_note[3]; + int track_time[3]; + byte *track_data[3]; + int track_len[3]; + bool looped = false; + + // TODO: Decipher the unknown bytes in the header. For now, skip 'em + src_ptr += 36; + + // Parse the three channels + for (i = 0; i < 3; i++) { + assert(READ_BE_UINT32(src_ptr) == MKID('Chan')); + len = READ_BE_UINT32(src_ptr + 4); + track_len[i] = (len - 24) / 4; + track_instr[i] = Mac0ToGMInstrument(READ_BE_UINT32(src_ptr + 8)); + track_data[i] = src_ptr + 8; + current_note[i] = -1; + track_time[i] = -1; + src_ptr += len; + looped = (READ_BE_UINT32(src_ptr - 8) == MKID('Loop')); + + // For each note event, we need up to 3 bytes for the VLQ, and 3 bytes + // for the note on. Finally, up to 3 bytes for the note off. + // That means up to 9 bytes may be used for each note. + total_size += 9 * track_len[i]; + } + assert(*src_ptr == 0x09); + + // Create sound resource + start_ptr = createResource(type, idx, total_size); + + // Insert MIDI header + ptr = writeMIDIHeader(start_ptr, "GMD ", ppqn, total_size); + +/* + // Write a tempo change Meta event + // 473 / 4 Hz, convert to micro seconds. + // FIXME: This is copied from the SFX case in convertADResource() + // and probably is not the proper value, but for now it's + // sufficient to act as placeholder. + uint32 dw = 1000000 * ppqn * 4 / 473; + memcpy(ptr, "\x00\xFF\x51\x03", 4); ptr += 4; + *ptr++ = (byte)((dw >> 16) & 0xFF); + *ptr++ = (byte)((dw >> 8) & 0xFF); + *ptr++ = (byte)(dw & 0xFF); +*/ + + // Time 0 +// ptr = writeVLQ(ptr, 0); + + // Insert programm change status messages + ptr[0] = 'C0'; ptr[1] = track_instr[0]; + ptr[2] = 'C1'; ptr[3] = track_instr[1]; + ptr[4] = 'C2'; ptr[5] = track_instr[2]; + ptr += 6; + + // TODO: now use the information computed above, and create a MIDI track, + // similiar to what is done in convertADResource + // ... - return ptr; + // Insert end of song sysex + memcpy(ptr, "\x00\xff\x2f\x00\x00", 5); ptr += 5; + + assert(ptr <= start_ptr + total_size); + + // Rewrite MIDI header, this time with true size + total_size = ptr - start_ptr; + ptr = writeMIDIHeader(start_ptr, "GMD ", ppqn, total_size); +#endif } void Scumm::convertADResource(int type, int idx, byte *src_ptr, int size) { // We will ignore the PPQN in the original resource, because // it's invalid anyway. We use a constant PPQN of 480. - const int ppqn = 480; + const int ppqn = 480; uint32 dw; int i, ch; byte *ptr; - int total_size = 8 + 16 + 14 + 8 + 7 + 8*sizeof(ADLIB_INSTR_MIDI_HACK) + size; + int total_size = kMIDIHeaderSize + 7 + 8 * sizeof(ADLIB_INSTR_MIDI_HACK) + size; total_size += 24; // Up to 24 additional bytes are needed for the jump sysex - + ptr = createResource(type, idx, total_size); src_ptr += 2; @@ -1284,7 +1353,7 @@ void Scumm::convertADResource(int type, int idx, byte *src_ptr, int size) { byte current_instr[3][14]; int current_note[3]; int track_time[3]; - byte *tracks[3]; + byte *track_data[3]; int track_ctr = 0; byte chunk_type = 0; @@ -1304,7 +1373,7 @@ void Scumm::convertADResource(int type, int idx, byte *src_ptr, int size) { } while (size > 0) { assert(track_ctr < 3); - tracks[track_ctr] = src_ptr; + track_data[track_ctr] = src_ptr; track_time[track_ctr] = 0; track_ctr++; while (size > 0) { @@ -1341,22 +1410,14 @@ void Scumm::convertADResource(int type, int idx, byte *src_ptr, int size) { if (mintime < 0) break; - src_ptr = tracks[ch]; + src_ptr = track_data[ch]; chunk_type = *src_ptr; if (current_note[ch] >= 0) { delay = mintime - curtime; curtime = mintime; - if (delay > 0x7f) { - if (delay > 0x3fff) { - *ptr++ = (delay >> 14) | 0x80; - delay &= 0x3fff; - } - *ptr++ = (delay >> 7) | 0x80; - delay &= 0x7f; - } - *ptr++ = delay; + ptr = writeVLQ(ptr, delay); *ptr++ = 0x80 + ch; // key off channel; *ptr++ = current_note[ch]; *ptr++ = 0; @@ -1446,15 +1507,7 @@ void Scumm::convertADResource(int type, int idx, byte *src_ptr, int size) { olddelay = mintime - curtime; curtime = mintime; - if (olddelay > 0x7f) { - if (olddelay > 0x3fff) { - *ptr++ = (olddelay >> 14) | 0x80; - olddelay &= 0x3fff; - } - *ptr++ = (olddelay >> 7) | 0x80; - olddelay &= 0x7f; - } - *ptr++ = olddelay; + ptr = writeVLQ(ptr, olddelay); { int freq = ((current_instr[ch][1] & 3) << 8) @@ -1495,7 +1548,7 @@ void Scumm::convertADResource(int type, int idx, byte *src_ptr, int size) { default: track_time[ch] = -1; } - tracks[ch] = src_ptr; + track_data[ch] = src_ptr; } } |