Add adlib music improvements for indy3/monkeyega/monkeyvga and cleanups from patch #770862

svn-id: r9480
This commit is contained in:
Travis Howell 2003-08-05 05:21:57 +00:00
parent 1eaf41eda4
commit 8bf012d966
5 changed files with 284 additions and 348 deletions

View file

@ -25,6 +25,8 @@
#include "common/engine.h" // for warning/error/debug
#include "common/util.h"
static int tick;
class MidiDriver_ADLIB;
struct AdlibVoice;
@ -156,7 +158,7 @@ struct Struct10 {
byte active;
int16 cur_val;
int16 count;
uint16 param;
uint16 max_value;
int16 start_value;
byte loop;
byte table_a[4];
@ -237,7 +239,7 @@ const byte param_table_1[16] = {
21, 30, 31, 0
};
const uint16 param_table_2[16] = {
const uint16 maxval_table[16] = {
0x2FF, 0x1F, 0x7, 0x3F,
0x0F, 0x0F, 0x0F, 0x3,
0x3F, 0x0F, 0x0F, 0x0F,
@ -1004,6 +1006,7 @@ void MidiDriver_ADLIB::generate_samples(int16 *data, int len) {
_next_tick -= step;
if (!_next_tick) {
tick++;
if (_timer_proc)
(*_timer_proc)(_timer_param);
on_timer();
@ -1210,7 +1213,7 @@ void MidiDriver_ADLIB::struct10_setup(Struct10 *s10) {
s10->num_steps = s10->speed_lo_max = e;
if (f != 2) {
c = s10->param;
c = s10->max_value;
g = s10->start_value;
t = s10->table_b[f];
d = lookup_volume(c, (t & 0x7F) - 31);
@ -1397,7 +1400,7 @@ void MidiDriver_ADLIB::adlib_setup_channel(int chan, AdlibInstrument *instr, byt
port = channel_mappings[chan];
adlib_write(port + 0x20, instr->flags_1);
if (!_game_SmallHeader ||(instr->feedback & 1))
if (!_game_SmallHeader)
adlib_write(port + 0x40, (instr->oplvl_1 | 0x3F) - vol_1 );
else
adlib_write(port + 0x40, instr->oplvl_1);
@ -1408,7 +1411,10 @@ void MidiDriver_ADLIB::adlib_setup_channel(int chan, AdlibInstrument *instr, byt
port = channel_mappings_2[chan];
adlib_write(port + 0x20, instr->flags_2);
adlib_write(port + 0x40, (instr->oplvl_2 | 0x3F) - vol_2 );
if (!_game_SmallHeader)
adlib_write(port + 0x40, (instr->oplvl_1 | 0x3F) - vol_1 );
else
adlib_write(port + 0x40, instr->oplvl_2 );
adlib_write(port + 0x60, 0xff & (~instr->atdec_2));
adlib_write(port + 0x80, 0xff & (~instr->sustrel_2));
adlib_write(port + 0xE0, instr->waveform_2);
@ -1434,7 +1440,7 @@ void MidiDriver_ADLIB::mc_init_stuff (AdlibVoice *voice, Struct10 * s10,
s10->loop = flags & 0x20;
s11->flag0x10 = flags & 0x10;
s11->param = param_table_1[flags & 0xF];
s10->param = param_table_2[flags & 0xF];
s10->max_value = maxval_table[flags & 0xF];
s10->unk3 = 31;
if (s11->flag0x40) {
s10->modwheel = part->_modwheel >> 2;

View file

@ -649,7 +649,6 @@ int Scumm::loadResource(int type, int idx) {
size = _fileHandle.readUint32LE();
tag = _fileHandle.readUint16LE();
_fileHandle.seek(-6, SEEK_CUR);
/* FIXME */
if ((type == rtSound) && !(_features & GF_AMIGA) && !(_features & GF_FMTOWNS)) {
return readSoundResourceSmallHeader(type, idx);
}
@ -889,166 +888,269 @@ int Scumm::readSoundResource(int type, int idx) {
return 0;
}
// FIXME: some default MIDI instruments for INDY3/MI1
static char OLD256_MIDI_HACK[] =
// 0
"\x00\xf0\x14\x7d\x00" // sysex 00: part on/off
"\x00\x00\x03" // part/channel
"\x00\x00\x07\x0f\x00\x00\x08\x00\x00\x00\x00\x02\x00\x00\xf7"
"\x04\xf0\x41\x7d\x10" // sysex 16: set instrument
"\x00" // part/channel
"\x01\x06\x02\x0a\x08\x09\x0d\x08\x04\x04"
"\x04\x06\x02\x02\x03\x07\x0f\x0d"
"\x05\x04\x0c\x00\x03\x01\x01\x00"
"\x00\x00\x01\x01\x0e\x00\x02\x02"
"\x01\x00\x01\x00\x01\x02\x00\x01"
"\x08\x00\x00\x00\x01\x02\x04\x00"
"\x06\x02\x00\x00\x04\x00\x03\x02"
"\x04\x00\x00\xf7"
"\x00\xb0\x07\x64" // Controller 7 = 100
// 1
"\x00\xf0\x14\x7d\x00" // sysex 00: part on/off
"\x01\x00\x03" // part/channel
"\x00\x00\x07\x0f\x00\x00\x08\x00\x00\x00\x00\x02\x00\x00\xf7"
"\x04\xf0\x41\x7d\x10" // sysex 16: set instrument
"\x01" // part/channel
"\x01\x06\x02\x0a\x08\x09\x0d\x08\x04\x04"
"\x04\x06\x02\x02\x03\x07\x0f\x0d"
"\x05\x04\x0c\x00\x03\x01\x01\x00"
"\x00\x00\x01\x01\x0e\x00\x02\x02"
"\x01\x00\x01\x00\x01\x02\x00\x01"
"\x08\x00\x00\x00\x01\x02\x04\x00"
"\x06\x02\x00\x00\x04\x00\x03\x02"
"\x04\x00\x00\xf7"
"\x00\xb1\x07\x64" // Controller 7 = 100
// 2
"\x00\xf0\x14\x7d\x00" // sysex 00: part on/off
"\x02\x00\x03" // part/channel
"\x00\x00\x07\x0f\x00\x00\x08\x00\x00\x00\x00\x02\x00\x00\xf7"
"\x04\xf0\x41\x7d\x10" // sysex 16: set instrument
"\x02" // part/channel
"\x01\x06\x02\x0a\x08\x09\x0d\x08\x04\x04"
"\x04\x06\x02\x02\x03\x07\x0f\x0d"
"\x05\x04\x0c\x00\x03\x01\x01\x00"
"\x00\x00\x01\x01\x0e\x00\x02\x02"
"\x01\x00\x01\x00\x01\x02\x00\x01"
"\x08\x00\x00\x00\x01\x02\x04\x00"
"\x06\x02\x00\x00\x04\x00\x03\x02"
"\x04\x00\x00\xf7"
"\x00\xb2\x07\x64" // Controller 7 = 100
// 3
"\x00\xf0\x14\x7d\x00" // sysex 00: part on/off
"\x03\x00\x03" // part/channel
"\x00\x00\x07\x0f\x00\x00\x08\x00\x00\x00\x00\x02\x00\x00\xf7"
"\x04\xf0\x41\x7d\x10" // sysex 16: set instrument
"\x03" // part/channel
"\x01\x06\x02\x0a\x08\x09\x0d\x08\x04\x04"
"\x04\x06\x02\x02\x03\x07\x0f\x0d"
"\x05\x04\x0c\x00\x03\x01\x01\x00"
"\x00\x00\x01\x01\x0e\x00\x02\x02"
"\x01\x00\x01\x00\x01\x02\x00\x01"
"\x08\x00\x00\x00\x01\x02\x04\x00"
"\x06\x02\x00\x00\x04\x00\x03\x02"
"\x04\x00\x00\xf7"
"\x00\xb3\x07\x64" // Controller 7 = 100
// 4
"\x00\xf0\x14\x7d\x00" // sysex 00: part on/off
"\x04\x00\x03" // part/channel
"\x00\x00\x07\x0f\x00\x00\x08\x00\x00\x00\x00\x02\x00\x00\xf7"
"\x04\xf0\x41\x7d\x10" // sysex 16: set instrument
"\x04" // part/channel
"\x01\x06\x02\x0a\x08\x09\x0d\x08\x04\x04"
"\x04\x06\x02\x02\x03\x07\x0f\x0d"
"\x05\x04\x0c\x00\x03\x01\x01\x00"
"\x00\x00\x01\x01\x0e\x00\x02\x02"
"\x01\x00\x01\x00\x01\x02\x00\x01"
"\x08\x00\x00\x00\x01\x02\x04\x00"
"\x06\x02\x00\x00\x04\x00\x03\x02"
"\x04\x00\x00\xf7"
"\x00\xb4\x07\x64" // Controller 7 = 100
// 5
"\x00\xf0\x14\x7d\x00" // sysex 00: part on/off
"\x05\x00\x03" // part/channel
"\x00\x00\x07\x0f\x00\x00\x08\x00\x00\x00\x00\x02\x00\x00\xf7"
"\x04\xf0\x41\x7d\x10" // sysex 16: set instrument
"\x05" // part/channel
"\x01\x06\x02\x0a\x08\x09\x0d\x08\x04\x04"
"\x04\x06\x02\x02\x03\x07\x0f\x0d"
"\x05\x04\x0c\x00\x03\x01\x01\x00"
"\x00\x00\x01\x01\x0e\x00\x02\x02"
"\x01\x00\x01\x00\x01\x02\x00\x01"
"\x08\x00\x00\x00\x01\x02\x04\x00"
"\x06\x02\x00\x00\x04\x00\x03\x02"
"\x04\x00\x00\xf7"
"\x00\xb5\x07\x64" // Controller 7 = 100
// 6
"\x00\xf0\x14\x7d\x00" // sysex 00: part on/off
"\x06\x00\x03" // part/channel
"\x00\x00\x07\x0f\x00\x00\x08\x00\x00\x00\x00\x02\x00\x00\xf7"
"\x04\xf0\x41\x7d\x10" // sysex 16: set instrument
"\x06" // part/channel
"\x01\x06\x02\x0a\x08\x09\x0d\x08\x04\x04"
"\x04\x06\x02\x02\x03\x07\x0f\x0d"
"\x05\x04\x0c\x00\x03\x01\x01\x00"
"\x00\x00\x01\x01\x0e\x00\x02\x02"
"\x01\x00\x01\x00\x01\x02\x00\x01"
"\x08\x00\x00\x00\x01\x02\x04\x00"
"\x06\x02\x00\x00\x04\x00\x03\x02"
"\x04\x00\x00\xf7"
"\x00\xb6\x07\x64" // Controller 7 = 100
// 7
"\x00\xf0\x14\x7d\x00" // sysex 00: part on/off
"\x07\x00\x03" // part/channel
"\x00\x00\x07\x0f\x00\x00\x08\x00\x00\x00\x00\x02\x00\x00\xf7"
"\x04\xf0\x41\x7d\x10" // sysex 16: set instrument
"\x07" // part/channel
"\x01\x06\x02\x0a\x08\x09\x0d\x08\x04\x04"
"\x04\x06\x02\x02\x03\x07\x0f\x0d"
"\x05\x04\x0c\x00\x03\x01\x01\x00"
"\x00\x00\x01\x01\x0e\x00\x02\x02"
"\x01\x00\x01\x00\x01\x02\x00\x01"
"\x08\x00\x00\x00\x01\x02\x04\x00"
"\x06\x02\x00\x00\x04\x00\x03\x02"
"\x04\x00\x00\xf7"
"\x00\xb7\x07\x64"; // Controller 7 = 100
// Adlib MIDI-SYSEX to set MIDI instruments for small header games.
static byte ADLIB_INSTR_MIDI_HACK[95] = {
0x00, 0xf0, 0x14, 0x7d, 0x00, // sysex 00: part on/off
0x00, 0x00, 0x03, // part/channel (offset 5)
0x00, 0x00, 0x07, 0x0f, 0x00, 0x00, 0x08, 0x00,
0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0xf7,
0x04, 0xf0, 0x41, 0x7d, 0x10, // sysex 16: set instrument
0x00, // part/channel (offset 28)
0x01, 0x06, 0x02, 0x0a, 0x08, 0x09, 0x0d, 0x08, 0x04, 0x04,
0x04, 0x06, 0x02, 0x02, 0x03, 0x07, 0x0f, 0x0d,
0x05, 0x04, 0x0c, 0x00, 0x03, 0x01, 0x01, 0x00,
0x00, 0x00, 0x01, 0x01, 0x0e, 0x00, 0x02, 0x02,
0x01, 0x00, 0x01, 0x00, 0x01, 0x02, 0x00, 0x01,
0x08, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x00,
0x06, 0x02, 0x00, 0x00, 0x04, 0x00, 0x03, 0x02,
0x04, 0x00, 0x00, 0xf7,
0x00, 0xb0, 0x07, 0x64 // Controller 7 = 100 (offset 92)
};
int Scumm::convertADResource(int type, int idx, byte * src_ptr, int size) {
byte * ptr;
byte ticks, play_once;
byte music_type, num_instr;
byte *channel, *instr, *track;
int i, ch;
src_ptr += 2;
size -= 2;
music_type = *(src_ptr); // 0x80: is music; otherwise not.
if (music_type != 0x80) {
// It's an SFX; we don't know how to handle those yet
debug(4, "Sound %d not played, format not yet supported", idx);
nukeResource(type, idx);
res.roomoffs[type][idx] = 0xFFFFFFFF;
return 0;
}
// The "speed" of the song
ticks = *(src_ptr + 1);
// Flag that tells us whether we should loop the song (0) or play it only once (1)
play_once = *(src_ptr + 2);
// Number of instruments used
num_instr = *(src_ptr + 8); // Normally 8
// copy the pointer to instrument data
channel = src_ptr + 9;
instr = src_ptr + 0x11;
// skip over the rest of the header and copy the MIDI data into a buffer
src_ptr += 0x11 + 8 * 16;
size -= 0x11 + 8 * 16;
CHECK_HEAP
track = src_ptr;
int total_size = 8 + 16 + 14 + 8 + 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);
memcpy(ptr, "ADL ", 4); ptr += 4;
uint32 dw = READ_BE_UINT32(&total_size);
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;
// We will ignore the PPQN in the original resource, because
// it's invalid anyway. We use a constant PPQN of 480.
// memcpy(ptr, &ticks, 2); ptr += 2;
*ptr++ = 480 >> 8;
*ptr++ = 480 & 0xFF;
memcpy(ptr, "MTrk", 4); ptr += 4;
dw = READ_BE_UINT32(&total_size);
memcpy(ptr, &dw, 4); ptr += 4;
// Conver the ticks into a MIDI tempo.
dw = (500000 * 256) / ticks;
debug(4, " ticks = %d, speed = %ld", ticks, dw);
// Write a tempo change SysEx
memcpy(ptr, "\x00\xFF\x51\x03", 4); ptr += 4;
*ptr++ = (byte)((dw >> 16) & 0xFF);
*ptr++ = (byte)((dw >> 8) & 0xFF);
*ptr++ = (byte)(dw & 0xFF);
// Copy our hardcoded instrument table into it
// Then, convert the instrument table as given in this song resource
// And write it *over* the hardcoded table.
// Note: we deliberately.
/* now fill in the instruments */
for (i = 0; i < num_instr; i++) {
ch = channel[i] - 1;
debug(4, "Sound %d: instrument %d on channel %d.",
idx, i, ch);
memcpy(ptr, ADLIB_INSTR_MIDI_HACK,
sizeof(ADLIB_INSTR_MIDI_HACK));
ptr[5] += ch;
ptr[28] += ch;
ptr[92] += ch;
/* flags_1 */
ptr[30 + 0] = (instr[i * 16 + 3] >> 4) & 0xf;
ptr[30 + 1] = instr[i * 16 + 3] & 0xf;
/* oplvl_1 */
ptr[30 + 2] = (instr[i * 16 + 4] >> 4) & 0xf;
ptr[30 + 3] = instr[i * 16 + 4] & 0xf;
/* atdec_1 */
ptr[30 + 4] = ((~instr[i * 16 + 5]) >> 4) & 0xf;
ptr[30 + 5] = (~instr[i * 16 + 5]) & 0xf;
/* sustrel_1 */
ptr[30 + 6] = ((~instr[i * 16 + 6]) >> 4) & 0xf;
ptr[30 + 7] = (~instr[i * 16 + 6]) & 0xf;
/* waveform_1 */
ptr[30 + 8] = (instr[i * 16 + 7] >> 4) & 0xf;
ptr[30 + 9] = instr[i * 16 + 7] & 0xf;
/* flags_2 */
ptr[30 + 10] = (instr[i * 16 + 8] >> 4) & 0xf;
ptr[30 + 11] = instr[i * 16 + 8] & 0xf;
/* oplvl_2 */
ptr[30 + 12] = (instr[i * 16 + 9] >> 4) & 0xf;
ptr[30 + 13] = instr[i * 16 + 9] & 0xf;
/* atdec_2 */
ptr[30 + 14] = ((~instr[i * 16 + 10]) >> 4) & 0xf;
ptr[30 + 15] = (~instr[i * 16 + 10]) & 0xf;
/* sustrel_2 */
ptr[30 + 16] = ((~instr[i * 16 + 11]) >> 4) & 0xf;
ptr[30 + 17] = (~instr[i * 16 + 11]) & 0xf;
/* waveform_2 */
ptr[30 + 18] = (instr[i * 16 + 12] >> 4) & 0xf;
ptr[30 + 19] = instr[i * 16 + 12] & 0xf;
/* feedback */
ptr[30 + 20] = (instr[i * 16 + 2] >> 4) & 0xf;
ptr[30 + 21] = instr[i * 16 + 2] & 0xf;
ptr += sizeof(ADLIB_INSTR_MIDI_HACK);
}
*ptr++ = 0; // delay 0;
// Now copy the actual music data
memcpy(ptr, track, size);
ptr += size;
if (!play_once) {
// The song is meant to be looped. We achieve this by inserting just
// before the song end a jump to the song start. More precisely we abuse
// a S&M sysex, "maybe_jump" to achieve this effect. We could also
// use a set_loop sysex, but it's a bit longer, a little more complicated,
// and has no advantage either.
// First, find the track end
byte *end = ptr;
ptr -= size;
for (; ptr < end; ptr++) {
if (*ptr == 0xff && *(ptr + 1) == 0x2f)
break;
}
assert(ptr < end);
// Now insert the jump. The jump offset is measured in ticks, and
// each instrument definition spans 4 ticks... so we jump to tick
// 8*4, although jumping to tick 0 would probably work fine, too.
// Note: it's possible that some musics don't loop from the start...
// in that case we'll have to figure out how the loop range is specified
// and then how to handle it appropriately (if it's specified in
// ticks, we are fine; but if it's a byte offset, it'll be nasty).
const int jump_offset = 8 * 4;
memcpy(ptr, "\xf0\x13\x7d\x30\00", 5); ptr += 5; // maybe_jump
memcpy(ptr, "\x00\x00", 2); ptr += 2; // cmd -> 0 means always jump
memcpy(ptr, "\x00\x00\x00\x00", 4); ptr += 4; // track -> there is only one track, 0
memcpy(ptr, "\x00\x00\x00\x01", 4); ptr += 4; // beat -> for now, 1 (first beat)
// Ticks
*ptr++ = (byte)((jump_offset >> 12) & 0x0F);
*ptr++ = (byte)((jump_offset >> 8) & 0x0F);
*ptr++ = (byte)((jump_offset >> 4) & 0x0F);
*ptr++ = (byte)(jump_offset & 0x0F);
memcpy(ptr, "\x00\xf7", 2); ptr += 2; // sysex end marker
}
// Finally we reinsert the end of song sysex, just in case
memcpy(ptr, "\x00\xff\x2f\x00\x00", 5); ptr += 5;
src_ptr+=size;
size = 0;
return 1;
}
int Scumm::readSoundResourceSmallHeader(int type, int idx) {
uint32 pos, total_size, size, dw, tag;
uint32 best_size = 0, best_offs = 0;
uint32 pos, total_size, size, tag;
uint32 ad_size = 0, ad_offs = 0;
uint32 wa_size = 0, wa_offs = 0;
debug(4, "readSoundResourceSmallHeader(%s,%d)", resTypeFromId(type), idx);
//if (_rescache->readResource(roomNr, type, idx))
// return 1;
total_size = size = _fileHandle.readUint32LE();
tag = _fileHandle.readUint16LE();
debug(4, " tag='%c%c', size=%d",
(char) (tag & 0xff),
(char) ((tag >> 8) & 0xff), size);
pos = 6;
while (pos < total_size) {
size = _fileHandle.readUint32LE();
if ((_features & GF_OLD_BUNDLE)) {
wa_offs = _fileHandle.pos();
wa_size = _fileHandle.readUint16LE();
_fileHandle.seek(wa_size - 2, SEEK_CUR);
ad_offs = _fileHandle.pos();
ad_size = _fileHandle.readUint16LE();
_fileHandle.seek(4, SEEK_CUR);
total_size = wa_size + ad_size;
} else {
total_size = size = _fileHandle.readUint32LE();
tag = _fileHandle.readUint16LE();
debug(4, " tag='%c%c', size=%d",
(char) (tag & 0xff),
(char) ((tag >> 8) & 0xff), size);
pos += size;
// MI1 and Indy3 uses one or more nested SO resources, which contains AD and WA
// resources.
if ((tag == 0x4441) && !(best_offs)) { // AD
best_size = size;
best_offs = _fileHandle.pos();
} else { // other AD, WA and nested SO resources
if (tag == 0x4F53) {
pos -= size;
size = 6;
pos += 6;
(char) (tag & 0xff),
(char) ((tag >> 8) & 0xff), size);
pos = 6;
while (pos < total_size) {
size = _fileHandle.readUint32LE();
tag = _fileHandle.readUint16LE();
debug(4, " tag='%c%c', size=%d",
(char) (tag & 0xff),
(char) ((tag >> 8) & 0xff), size);
pos += size;
// MI1 and Indy3 uses one or more nested SO resources, which contains AD and WA
// resources.
if ((tag == 0x4441) && !(ad_offs)) { // AD
ad_size = size;
ad_offs = _fileHandle.pos();
} else if ((tag == 0x4157) && !(wa_offs)) { // WA
wa_size = size;
wa_offs = _fileHandle.pos();
} else { // other AD, WA and nested SO resources
if (tag == 0x4F53) { // SO
pos -= size;
size = 6;
pos += 6;
}
}
_fileHandle.seek(size - 6, SEEK_CUR);
}
_fileHandle.seek(size - 6, SEEK_CUR);
}
// AD resources have a header, instrument definitions and one MIDI track.
@ -1063,197 +1165,19 @@ int Scumm::readSoundResourceSmallHeader(int type, int idx) {
// - proper handling of the short (non-music, SFX) AD resources format
// - check the LE/BE handling for platforms other than PC
if (best_offs != 0) {
byte *ptr, *track, *instr;
byte ticks, play_once;
byte music_type, num_instr;
_fileHandle.seek(best_offs - 6, SEEK_SET);
ptr = createResource(type, idx, best_size);
_fileHandle.read(ptr, best_size);
music_type = *(ptr + 8); // 0x80: is music; otherwise not.
if (music_type != 0x80) {
// It's an SFX; we don't know how to handle those yet
debug(4, "Sound %d not played, format not yet supported", idx);
nukeResource(type, idx);
res.roomoffs[type][idx] = 0xFFFFFFFF;
return 0;
}
// The "speed" of the song
ticks = *(ptr + 9);
// Flag that tells us whether we should loop the song (0) or play it only once (1)
play_once = *(ptr + 10);
// Number of instruments used
num_instr = *(ptr + 16); // Normally 8
if (num_instr != 8)
warning("Sound %d has %d instruments, expected 8", idx, num_instr);
// copy the instrument data in another memory area
instr = (byte *)calloc(8 * 16, 1);
assert(instr);
memcpy(instr, ptr + 0x19, 8*16);
// skip over the rest of the header and copy the MIDI data into a buffer
size = best_size;
ptr += 0x19 + 8 * 16;
size -= 0x19 + 8 * 16;
CHECK_HEAP
track = (byte *)calloc(size, 1);
if (track == NULL) {
error("Out of memory while allocating %d", size);
}
memcpy(track, ptr, size); // saving MIDI track data
// Now nuke the old resource, and replace it with a new one
nukeResource(type, idx);
total_size = 8 + 16 + 14 + 8 + 7 + sizeof(OLD256_MIDI_HACK) + size;
if (!play_once)
total_size += 24; // Up to 24 additional bytes are needed for the jump sysex
// Write the ADL header (see also above for more information)
ptr = createResource(type, idx, total_size);
memcpy(ptr, "ADL ", 4); ptr += 4;
dw = READ_BE_UINT32(&total_size);
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;
// We will ignore the PPQN in the original resource, because
// it's invalid anyway. We use a constant PPQN of 480.
// memcpy(ptr, &ticks, 2); ptr += 2;
*ptr++ = 480 >> 8;
*ptr++ = 480 & 0xFF;
memcpy(ptr, "MTrk", 4); ptr += 4;
*ptr++ = (byte)(((sizeof(OLD256_MIDI_HACK) + size + 7) >> 24) & 0xFF);
*ptr++ = (byte)(((sizeof(OLD256_MIDI_HACK) + size + 7) >> 16) & 0xFF);
*ptr++ = (byte)(((sizeof(OLD256_MIDI_HACK) + size + 7) >> 8) & 0xFF);
*ptr++ = (byte)(((sizeof(OLD256_MIDI_HACK) + size + 7) ) & 0xFF);
// Conver the ticks into a MIDI tempo.
dw = (500000 * 256) / ticks;
debug(4, " ticks = %d, speed = %u", ticks, dw);
// Write a tempo change SysEx
memcpy(ptr, "\x00\xFF\x51\x03", 4); ptr += 4;
*ptr++ = (byte)((dw >> 16) & 0xFF);
*ptr++ = (byte)((dw >> 8) & 0xFF);
*ptr++ = (byte)(dw & 0xFF);
// Copy our hardcoded instrument table into it
// Then, convert the instrument table as given in this song resource
// And write it *over* the hardcoded table.
// Note: we deliberately.
memcpy(ptr, OLD256_MIDI_HACK, sizeof(OLD256_MIDI_HACK));
/* now fill in the instruments */
for (int i = 0; i < 8; i++) {
/* flags_1 */
ptr[95 * i + 30 + 0] = (instr[i * 16 + 3] >> 4) & 0xf;
ptr[95 * i + 30 + 1] = instr[i * 16 + 3] & 0xf;
/* oplvl_1 */
ptr[95 * i + 30 + 2] = (instr[i * 16 + 4] >> 4) & 0xf;
ptr[95 * i + 30 + 3] = instr[i * 16 + 4] & 0xf;
/* atdec_1 */
ptr[95 * i + 30 + 4] = ((~instr[i * 16 + 5]) >> 4) & 0xf;
ptr[95 * i + 30 + 5] = (~instr[i * 16 + 5]) & 0xf;
/* sustrel_1 */
ptr[95 * i + 30 + 6] = ((~instr[i * 16 + 6]) >> 4) & 0xf;
ptr[95 * i + 30 + 7] = (~instr[i * 16 + 6]) & 0xf;
/* waveform_1 */
ptr[95 * i + 30 + 8] = (instr[i * 16 + 7] >> 4) & 0xf;
ptr[95 * i + 30 + 9] = instr[i * 16 + 7] & 0xf;
/* flags_2 */
ptr[95 * i + 30 + 10] = (instr[i * 16 + 8] >> 4) & 0xf;
ptr[95 * i + 30 + 11] = instr[i * 16 + 8] & 0xf;
/* oplvl_2 */
ptr[95 * i + 30 + 12] = 3;
ptr[95 * i + 30 + 13] = 0xF;
/* atdec_2 */
ptr[95 * i + 30 + 14] = ((~instr[i * 16 + 10]) >> 4) & 0xf;
ptr[95 * i + 30 + 15] = (~instr[i * 16 + 10]) & 0xf;
/* sustrel_2 */
ptr[95 * i + 30 + 16] = ((~instr[i * 16 + 11]) >> 4) & 0xf;
ptr[95 * i + 30 + 17] = (~instr[i * 16 + 11]) & 0xf;
/* waveform_2 */
ptr[95 * i + 30 + 18] = (instr[i * 16 + 12] >> 4) & 0xf;
ptr[95 * i + 30 + 19] = instr[i * 16 + 12] & 0xf;
/* feedback */
ptr[95 * i + 30 + 20] = (instr[i * 16 + 2] >> 4) & 0xf;
ptr[95 * i + 30 + 21] = instr[i * 16 + 2] & 0xf;
}
free(instr);
ptr += sizeof(OLD256_MIDI_HACK);
// Now copy the actual music data
memcpy(ptr, track, size);
free(track);
if (!play_once) {
// The song is meant to be looped. We achieve this by inserting just
// before the song end a jump to the song start. More precisely we abuse
// a S&M sysex, "maybe_jump" to achieve this effect. We could also
// use a set_loop sysex, but it's a bit longer, a little more complicated,
// and has no advantage either.
// First, find the track end
byte *end = ptr + size;
for (; ptr < end; ptr++) {
if (*ptr == 0xff && *(ptr + 1) == 0x2f)
break;
}
assert(ptr < end);
// Now insert the jump. The jump offset is measured in ticks, and
// each instrument definition spans 4 ticks... so we jump to tick
// 8*4, although jumping to tick 0 would probably work fine, too.
// Note: it's possible that some musics don't loop from the start...
// in that case we'll have to figure out how the loop range is specified
// and then how to handle it appropriately (if it's specified in
// ticks, we are fine; but if it's a byte offset, it'll be nasty).
const int jump_offset = 8 * 4;
memcpy(ptr, "\xf0\x13\x7d\x30\00", 5); ptr += 5; // maybe_jump
memcpy(ptr, "\x00\x00", 2); ptr += 2; // cmd -> 0 means always jump
memcpy(ptr, "\x00\x00\x00\x00", 4); ptr += 4; // track -> there is only one track, 0
memcpy(ptr, "\x00\x00\x00\x01", 4); ptr += 4; // beat -> for now, 1 (first beat)
// Ticks
*ptr++ = (byte)((jump_offset >> 12) & 0x0F);
*ptr++ = (byte)((jump_offset >> 8) & 0x0F);
*ptr++ = (byte)((jump_offset >> 4) & 0x0F);
*ptr++ = (byte)(jump_offset & 0x0F);
memcpy(ptr, "\x00\xf7", 2); ptr += 2; // sysex end marker
// Finally we reinsert the end of song sysex, just in case
memcpy(ptr, "\x00\xff\x2f\x00\x00", 5); ptr += 5;
}
return 1;
if (ad_offs != 0) {
byte *ptr;
if (_features & GF_OLD_BUNDLE) {
ptr = (byte *) calloc(ad_size - 4, 1);
_fileHandle.seek(ad_offs + 4, SEEK_SET);
_fileHandle.read(ptr, ad_size - 4);
return convertADResource(type, idx, ptr, ad_size - 4);
} else {
ptr = (byte *) calloc(ad_size - 6, 1);
_fileHandle.seek(ad_offs, SEEK_SET);
_fileHandle.read(ptr, ad_size - 6);
return convertADResource(type, idx, ptr, ad_size - 6);
}
}
res.roomoffs[type][idx] = 0xFFFFFFFF;
return 0;

View file

@ -642,6 +642,8 @@ public:
protected:
int readSoundResource(int type, int index);
int convert_extraflags(byte *ptr, byte * src_ptr);
int convertADResource(int type, int index, byte *ptr, int size);
int readSoundResourceSmallHeader(int type, int index);
void setResourceCounter(int type, int index, byte flag);
bool validateResource(const char *str, int type, int index) const;

View file

@ -616,8 +616,12 @@ Scumm::Scumm (GameDetector *detector, OSystem *syst)
_imuseDigital = new IMuseDigital(this);
_imuse = NULL;
_playerV2 = NULL;
} else if ((_features & GF_AMIGA) && (_features & GF_OLD_BUNDLE)) {
_playerV2 = NULL;
_imuse = NULL;
_imuseDigital = NULL;
} else if (_features & GF_OLD_BUNDLE) {
if ((_features & GF_AMIGA) || ((_version == 1) && (_gameId == GID_MANIAC)))
if ((_version == 1) && (_gameId == GID_MANIAC))
_playerV2 = NULL;
else
_playerV2 = new Player_V2(this);

View file

@ -323,7 +323,7 @@ void Sound::playSound(int soundID) {
memcpy(sound, ptr + 33, size);
_scumm->_mixer->playRaw(NULL, sound, size, rate, flags, soundID);
return;
} else if (_scumm->_features & GF_OLD256) {
} else if (_scumm->_features & GF_FMTOWNS) {
size = READ_LE_UINT32(ptr);
#if 0
// FIXME - this is just some debug output for Zak256