aboutsummaryrefslogtreecommitdiff
path: root/scumm/resource.cpp
diff options
context:
space:
mode:
authorMax Horn2003-09-09 01:21:42 +0000
committerMax Horn2003-09-09 01:21:42 +0000
commit6adb8560a857d10f8d4730c184e131857a82d2a7 (patch)
tree3b5b2267c159415da2c9eebc76bed7ea25e81edf /scumm/resource.cpp
parent24560608eda1c834b55bcfbf5bf22b23d436e0d0 (diff)
downloadscummvm-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.cpp247
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;
}
}