diff options
Diffstat (limited to 'engines/gob')
-rw-r--r-- | engines/gob/inter_fascin.cpp | 28 | ||||
-rw-r--r-- | engines/gob/inter_v1.cpp | 2 | ||||
-rw-r--r-- | engines/gob/sound/adlib.cpp | 769 | ||||
-rw-r--r-- | engines/gob/sound/adlib.h | 81 | ||||
-rw-r--r-- | engines/gob/sound/sound.cpp | 147 | ||||
-rw-r--r-- | engines/gob/sound/sound.h | 16 |
6 files changed, 594 insertions, 449 deletions
diff --git a/engines/gob/inter_fascin.cpp b/engines/gob/inter_fascin.cpp index 8f7a53c8f1..d1264021f7 100644 --- a/engines/gob/inter_fascin.cpp +++ b/engines/gob/inter_fascin.cpp @@ -129,8 +129,8 @@ void Inter_Fascination::oFascin_geUnknown1(OpGobParams ¶ms) { } void Inter_Fascination::oFascin_geUnknown2(OpGobParams ¶ms) { - _vm->_sound->adlibLoadTbr("extasy.tbr"); - _vm->_sound->adlibLoadMdy("extasy.mdy"); + _vm->_sound->adlibLoadTBR("extasy.tbr"); + _vm->_sound->adlibLoadMDY("extasy.mdy"); } void Inter_Fascination::oFascin_geUnknown3(OpGobParams ¶ms) { @@ -146,33 +146,33 @@ void Inter_Fascination::oFascin_geUnknown5(OpGobParams ¶ms) { } void Inter_Fascination::oFascin_geUnknown6(OpGobParams ¶ms) { - _vm->_sound->adlibLoadTbr("music1.tbr"); - _vm->_sound->adlibLoadMdy("music1.mdy"); + _vm->_sound->adlibLoadTBR("music1.tbr"); + _vm->_sound->adlibLoadMDY("music1.mdy"); } void Inter_Fascination::oFascin_geUnknown7(OpGobParams ¶ms) { - _vm->_sound->adlibLoadTbr("music2.tbr"); - _vm->_sound->adlibLoadMdy("music2.mdy"); + _vm->_sound->adlibLoadTBR("music2.tbr"); + _vm->_sound->adlibLoadMDY("music2.mdy"); } void Inter_Fascination::oFascin_geUnknown8(OpGobParams ¶ms) { - _vm->_sound->adlibLoadTbr("music3.tbr"); - _vm->_sound->adlibLoadMdy("music3.mdy"); + _vm->_sound->adlibLoadTBR("music3.tbr"); + _vm->_sound->adlibLoadMDY("music3.mdy"); } void Inter_Fascination::oFascin_geUnknown9(OpGobParams ¶ms) { - _vm->_sound->adlibLoadTbr("batt1.tbr"); - _vm->_sound->adlibLoadMdy("batt1.mdy"); + _vm->_sound->adlibLoadTBR("batt1.tbr"); + _vm->_sound->adlibLoadMDY("batt1.mdy"); } void Inter_Fascination::oFascin_geUnknown10(OpGobParams ¶ms) { - _vm->_sound->adlibLoadTbr("batt2.tbr"); - _vm->_sound->adlibLoadMdy("batt2.mdy"); + _vm->_sound->adlibLoadTBR("batt2.tbr"); + _vm->_sound->adlibLoadMDY("batt2.mdy"); } void Inter_Fascination::oFascin_geUnknown11(OpGobParams ¶ms) { - _vm->_sound->adlibLoadTbr("batt3.tbr"); - _vm->_sound->adlibLoadMdy("batt3.mdy"); + _vm->_sound->adlibLoadTBR("batt3.tbr"); + _vm->_sound->adlibLoadMDY("batt3.mdy"); } void Inter_Fascination::oFascin_geUnknown1000(OpGobParams ¶ms) { diff --git a/engines/gob/inter_v1.cpp b/engines/gob/inter_v1.cpp index 26d6d9b3d9..70a7e12849 100644 --- a/engines/gob/inter_v1.cpp +++ b/engines/gob/inter_v1.cpp @@ -1520,7 +1520,7 @@ bool Inter_v1::o1_playSound(OpFuncParams ¶ms) { } if (sample->getType() == SOUND_ADL) { - _vm->_sound->adlibLoad(sample->getData(), sample->size(), index); + _vm->_sound->adlibLoadADL(sample->getData(), sample->size(), index); _vm->_sound->adlibSetRepeating(repCount - 1); _vm->_sound->adlibPlay(); } else { diff --git a/engines/gob/sound/adlib.cpp b/engines/gob/sound/adlib.cpp index b55e9fb0c8..a888b6ee49 100644 --- a/engines/gob/sound/adlib.cpp +++ b/engines/gob/sound/adlib.cpp @@ -39,21 +39,34 @@ const unsigned char AdLib::_volRegNums[] = { }; AdLib::AdLib(Audio::Mixer &mixer) : _mixer(&mixer) { + init(); +} + +AdLib::~AdLib() { + Common::StackLock slock(_mutex); + + _mixer->stopHandle(_handle); + OPLDestroy(_opl); + if (_data && _freeData) + delete[] _data; +} + +void AdLib::init() { _index = -1; _data = 0; _playPos = 0; _dataSize = 0; _rate = _mixer->getOutputRate(); + _opl = makeAdlibOPL(_rate); _first = true; _ended = false; _playing = false; - _needFree = false; - _mdySong = false; + + _freeData = false; - _soundMode = 0; _repCount = -1; _samplesTillPoll = 0; @@ -65,15 +78,6 @@ AdLib::AdLib(Audio::Mixer &mixer) : _mixer(&mixer) { this, -1, 255, 0, false, true); } -AdLib::~AdLib() { - Common::StackLock slock(_mutex); - - _mixer->stopHandle(_handle); - OPLDestroy(_opl); - if (_data && _needFree) - delete[] _data; -} - int AdLib::readBuffer(int16 *buffer, const int numSamples) { Common::StackLock slock(_mutex); int samples; @@ -109,25 +113,17 @@ int AdLib::readBuffer(int16 *buffer, const int numSamples) { if (_ended) { _first = true; _ended = false; - if (_mdySong) - _playPos = _data; - else - _playPos = _data + 3 + (_data[1] + 1) * 0x38; + + rewind(); _samplesTillPoll = 0; if (_repCount == -1) { reset(); - if (_mdySong) - setVoicesTbr(); - else - setVoices(); + setVoices(); } else if (_repCount > 0) { _repCount--; reset(); - if (_mdySong) - setVoicesTbr(); - else - setVoices(); + setVoices(); } else _playing = false; @@ -182,126 +178,8 @@ void AdLib::reset() { // Authorize the control of the waveformes writeOPL(0x01, 0x20); - -// _soundMode 1 : Percussive mode. - if (_soundMode == 1) { - writeOPL(0xA6, 0); - writeOPL(0xB6, 0); - writeOPL(0xA7, 0); - writeOPL(0xB7, 0); - writeOPL(0xA8, 0); - writeOPL(0xB8, 0); - -// TODO set the correct frequency for the last 4 percussive voices - - } -} - -void AdLib::setVoices() { - // Definitions of the 9 instruments - for (int i = 0; i < 9; i++) - setVoice(i, i, true); -} - -void AdLib::setVoice(byte voice, byte instr, bool set) { - int i; - int j; - uint16 strct[27]; - byte channel; - byte *dataPtr; - - // i = 0 : 0 1 2 3 4 5 6 7 8 9 10 11 12 26 - // i = 1 : 13 14 15 16 17 18 19 20 21 22 23 24 25 27 - for (i = 0; i < 2; i++) { - dataPtr = _data + 3 + instr * 0x38 + i * 0x1A; - for (j = 0; j < 27; j++) { - strct[j] = READ_LE_UINT16(dataPtr); - dataPtr += 2; - } - channel = _operators[voice] + i * 3; - writeOPL(0xBD, 0x00); - writeOPL(0x08, 0x00); - writeOPL(0x40 | channel, ((strct[0] & 3) << 6) | (strct[8] & 0x3F)); - if (!i) - writeOPL(0xC0 | voice, - ((strct[2] & 7) << 1) | (1 - (strct[12] & 1))); - writeOPL(0x60 | channel, ((strct[3] & 0xF) << 4) | (strct[6] & 0xF)); - writeOPL(0x80 | channel, ((strct[4] & 0xF) << 4) | (strct[7] & 0xF)); - writeOPL(0x20 | channel, ((strct[9] & 1) << 7) | - ((strct[10] & 1) << 6) | ((strct[5] & 1) << 5) | - ((strct[11] & 1) << 4) | (strct[1] & 0xF)); - if (!i) - writeOPL(0xE0 | channel, (strct[26] & 3)); - else - writeOPL(0xE0 | channel, (strct[14] & 3)); - if (i && set) - writeOPL(0x40 | channel, 0); - } -} - -void AdLib::setVoicesTbr() { - int i; - byte *timbrePtr; - - timbrePtr = _timbres; - debugC(6, kDebugSound, "TBR version: %X.%X", timbrePtr[0], timbrePtr[1]); - timbrePtr += 2; - - _tbrCount = READ_LE_UINT16(timbrePtr); - debugC(6, kDebugSound, "Timbres counter: %d", _tbrCount); - timbrePtr += 2; - _tbrStart = READ_LE_UINT16(timbrePtr); - - timbrePtr += 2; - for (i = 0; i < _tbrCount ; i++) - { - setVoiceTbr (i, i, true); - } -} - -void AdLib::setVoiceTbr (byte voice, byte instr, bool set) { - int i; - int j; - uint16 strct[27]; - byte channel; - byte *timbrePtr; - char timbreName[10]; - - timbreName[9] = '\0'; - for (j = 0; j < 9; j++) - timbreName[j] = _timbres[6 + j + (instr * 9)]; - debugC(6, kDebugSound, "Loading timbre %s", timbreName); - - // i = 0 : 0 1 2 3 4 5 6 7 8 9 10 11 12 26 - // i = 1 : 13 14 15 16 17 18 19 20 21 22 23 24 25 27 - for (i = 0; i < 2; i++) { - timbrePtr = _timbres + _tbrStart + instr * 0x38 + i * 0x1A; - for (j = 0; j < 27; j++) { - strct[j] = READ_LE_UINT16(timbrePtr); - timbrePtr += 2; - } - channel = _operators[voice] + i * 3; - writeOPL(0xBD, 0x00); - writeOPL(0x08, 0x00); - writeOPL(0x40 | channel, ((strct[0] & 3) << 6) | (strct[8] & 0x3F)); - if (!i) - writeOPL(0xC0 | voice, - ((strct[2] & 7) << 1) | (1 - (strct[12] & 1))); - writeOPL(0x60 | channel, ((strct[3] & 0xF) << 4) | (strct[6] & 0xF)); - writeOPL(0x80 | channel, ((strct[4] & 0xF) << 4) | (strct[7] & 0xF)); - writeOPL(0x20 | channel, ((strct[9] & 1) << 7) | - ((strct[10] & 1) << 6) | ((strct[5] & 1) << 5) | - ((strct[11] & 1) << 4) | (strct[1] & 0xF)); - if (!i) - writeOPL(0xE0 | channel, (strct[26] & 3)); - else { - writeOPL(0xE0 | channel, (strct[14] & 3)); - writeOPL(0x40 | channel, 0); - } - } } - void AdLib::setKey(byte voice, byte note, bool on, bool spec) { short freq = 0; short octa = 0; @@ -374,206 +252,56 @@ void AdLib::setVolume(byte voice, byte volume) { } void AdLib::pollMusic() { - unsigned char instr; - byte channel; - byte note; - byte volume; - uint16 tempo; - - uint8 i, tempoMult, tempoFrac, ctrlByte1, ctrlByte2, timbre; - if ((_playPos > (_data + _dataSize)) && (_dataSize != 0xFFFFFFFF)) { _ended = true; return; } - if (_mdySong) - { - if (_first) { - for (i = 0; i < 11; i ++) - setVolume(i, 0); + interpret(); +} -// TODO : Set pitch range +void AdLib::unload() { + _playing = false; + _index = -1; - _tempo = _basicTempo; - _wait = *(_playPos++); - _first = false; - } - do { - instr = *_playPos; -// printf("instr 0x%X\n", instr); - switch(instr) { - case 0xF8: - _wait = *(_playPos++); - break; - case 0xFC: - _ended = true; - _samplesTillPoll = 0; - return; - case 0xF0: - _playPos++; - ctrlByte1 = *(_playPos++); - ctrlByte2 = *(_playPos++); - if (ctrlByte1 != 0x7F || ctrlByte2 != 0) { - _playPos -= 2; - while (*(_playPos++) != 0xF7); - } else { - tempoMult = *(_playPos++); - tempoFrac = *(_playPos++); - _tempo = _basicTempo * tempoMult + (unsigned)(((long)_basicTempo * tempoFrac) >> 7); - _playPos++; - } - _wait = *(_playPos++); - break; - default: - if (instr >= 0x80) { - _playPos++; - } - channel = (int)(instr & 0x0f); - - switch(instr & 0xf0) { - case 0x90: - note = *(_playPos++); - volume = *(_playPos++); - _pollNotes[channel] = note; - setVolume(channel, volume); - setKey(channel, note, true, false); - break; - case 0x80: - _playPos += 2; - note = _pollNotes[channel]; - setKey(channel, note, false, false); - break; - case 0xA0: - setVolume(channel, *(_playPos++)); - break; - case 0xC0: - timbre = *(_playPos++); - setVoiceTbr(channel, timbre, false); - break; - case 0xE0: - warning("Pitch bend not yet implemented\n"); - - note = *(_playPos)++; - note += (unsigned)(*(_playPos++)) << 7; - - setKey(channel, note, _notOn[channel], true); - - break; - case 0xB0: - _playPos += 2; - break; - case 0xD0: - _playPos++; - break; - default: - warning("Bad MIDI instr byte: 0%X", instr); - while ((*_playPos) < 0x80) - _playPos++; - if (*_playPos != 0xF8) - _playPos--; - break; - } //switch instr & 0xF0 - _wait = *(_playPos++); - break; - } //switch instr - } while (_wait == 0); + if (_data && _freeData) + delete[] _data; - if (_wait == 0xF8) { - _wait = 0xF0; - if (*_playPos != 0xF8) - _wait += *(_playPos++); - } -// _playPos++; - _samplesTillPoll = _wait * (_rate / 1000); - } else { - // First tempo, we'll ignore it... - if (_first) { - tempo = *(_playPos++); - // Tempo on 2 bytes - if (tempo & 0x80) - tempo = ((tempo & 3) << 8) | *(_playPos++); - } - _first = false; - - // Instruction - instr = *(_playPos++); - channel = instr & 0x0F; - - switch (instr & 0xF0) { - // Note on + Volume - case 0x00: - note = *(_playPos++); - _pollNotes[channel] = note; - setVolume(channel, *(_playPos++)); - setKey(channel, note, true, false); - break; - // Note on - case 0x90: - note = *(_playPos++); - _pollNotes[channel] = note; - setKey(channel, note, true, false); - break; - // Last note off - case 0x80: - note = _pollNotes[channel]; - setKey(channel, note, false, false); - break; - // Frequency on/off - case 0xA0: - note = *(_playPos++); - setKey(channel, note, _notOn[channel], true); - break; - // Volume - case 0xB0: - volume = *(_playPos++); - setVolume(channel, volume); - break; - // Program change - case 0xC0: - setVoice(channel, *(_playPos++), false); - break; - // Special - case 0xF0: - switch (instr & 0x0F) { - case 0xF: // End instruction - _ended = true; - _samplesTillPoll = 0; - return; - default: - warning("Unknown special command in ADL, stopping playback: %X", - instr & 0x0F); - _repCount = 0; - _ended = true; - break; - } - break; - default: - warning("Unknown command in ADL, stopping playback: %X", - instr & 0xF0); - _repCount = 0; - _ended = true; - break; - } - - // Temporization - tempo = *(_playPos++); - // End tempo - if (tempo == 0xFF) { - _ended = true; - return; - } - // Tempo on 2 bytes - if (tempo & 0x80) - tempo = ((tempo & 3) << 8) | *(_playPos++); - if (!tempo) - tempo ++; - - _samplesTillPoll = tempo * (_rate / 1000); - } + _freeData = false; +} + +bool AdLib::isPlaying() const { + return _playing; +} + +bool AdLib::getRepeating() const { + return _repCount != 0; +} + +void AdLib::setRepeating(int32 repCount) { + _repCount = repCount; +} + +int AdLib::getIndex() const { + return _index; +} + +void AdLib::startPlay() { + if (_data) _playing = true; +} + +void AdLib::stopPlay() { + Common::StackLock slock(_mutex); + _playing = false; +} + +ADLPlayer::ADLPlayer(Audio::Mixer &mixer) : AdLib(mixer) { +} + +ADLPlayer::~ADLPlayer() { } -bool AdLib::load(const char *fileName) { +bool ADLPlayer::load(const char *fileName) { Common::File song; unload(); @@ -581,9 +309,7 @@ bool AdLib::load(const char *fileName) { if (!song.isOpen()) return false; - _soundMode = 0; - - _needFree = true; + _freeData = true; _dataSize = song.size(); _data = new byte[_dataSize]; song.read(_data, _dataSize); @@ -596,12 +322,10 @@ bool AdLib::load(const char *fileName) { return true; } -bool AdLib::load(byte *data, uint32 size, int index) { +bool ADLPlayer::load(byte *data, uint32 size, int index) { unload(); _repCount = 0; - _soundMode = 0; - _dataSize = size; _data = data; _index = index; @@ -613,7 +337,168 @@ bool AdLib::load(byte *data, uint32 size, int index) { return true; } -bool AdLib::loadMdy(const char *fileName) { +void ADLPlayer::unload() { + AdLib::unload(); +} + +void ADLPlayer::interpret() { + unsigned char instr; + byte channel; + byte note; + byte volume; + uint16 tempo; + + // First tempo, we'll ignore it... + if (_first) { + tempo = *(_playPos++); + // Tempo on 2 bytes + if (tempo & 0x80) + tempo = ((tempo & 3) << 8) | *(_playPos++); + } + _first = false; + + // Instruction + instr = *(_playPos++); + channel = instr & 0x0F; + + switch (instr & 0xF0) { + // Note on + Volume + case 0x00: + note = *(_playPos++); + _pollNotes[channel] = note; + setVolume(channel, *(_playPos++)); + setKey(channel, note, true, false); + break; + // Note on + case 0x90: + note = *(_playPos++); + _pollNotes[channel] = note; + setKey(channel, note, true, false); + break; + // Last note off + case 0x80: + note = _pollNotes[channel]; + setKey(channel, note, false, false); + break; + // Frequency on/off + case 0xA0: + note = *(_playPos++); + setKey(channel, note, _notOn[channel], true); + break; + // Volume + case 0xB0: + volume = *(_playPos++); + setVolume(channel, volume); + break; + // Program change + case 0xC0: + setVoice(channel, *(_playPos++), false); + break; + // Special + case 0xF0: + switch (instr & 0x0F) { + case 0xF: // End instruction + _ended = true; + _samplesTillPoll = 0; + return; + default: + warning("Unknown special command in ADL, stopping playback: %X", + instr & 0x0F); + _repCount = 0; + _ended = true; + break; + } + break; + default: + warning("Unknown command in ADL, stopping playback: %X", + instr & 0xF0); + _repCount = 0; + _ended = true; + break; + } + + // Temporization + tempo = *(_playPos++); + // End tempo + if (tempo == 0xFF) { + _ended = true; + return; + } + // Tempo on 2 bytes + if (tempo & 0x80) + tempo = ((tempo & 3) << 8) | *(_playPos++); + if (!tempo) + tempo ++; + + _samplesTillPoll = tempo * (_rate / 1000); +} + +void ADLPlayer::reset() { + AdLib::reset(); +} + +void ADLPlayer::rewind() { + _playPos = _data + 3 + (_data[1] + 1) * 0x38; +} + +void ADLPlayer::setVoices() { + // Definitions of the 9 instruments + for (int i = 0; i < 9; i++) + setVoice(i, i, true); +} + +void ADLPlayer::setVoice(byte voice, byte instr, bool set) { + uint16 strct[27]; + byte channel; + byte *dataPtr; + + // i = 0 : 0 1 2 3 4 5 6 7 8 9 10 11 12 26 + // i = 1 : 13 14 15 16 17 18 19 20 21 22 23 24 25 27 + for (int i = 0; i < 2; i++) { + dataPtr = _data + 3 + instr * 0x38 + i * 0x1A; + for (int j = 0; j < 27; j++) { + strct[j] = READ_LE_UINT16(dataPtr); + dataPtr += 2; + } + channel = _operators[voice] + i * 3; + writeOPL(0xBD, 0x00); + writeOPL(0x08, 0x00); + writeOPL(0x40 | channel, ((strct[0] & 3) << 6) | (strct[8] & 0x3F)); + if (!i) + writeOPL(0xC0 | voice, + ((strct[2] & 7) << 1) | (1 - (strct[12] & 1))); + writeOPL(0x60 | channel, ((strct[3] & 0xF) << 4) | (strct[6] & 0xF)); + writeOPL(0x80 | channel, ((strct[4] & 0xF) << 4) | (strct[7] & 0xF)); + writeOPL(0x20 | channel, ((strct[9] & 1) << 7) | + ((strct[10] & 1) << 6) | ((strct[5] & 1) << 5) | + ((strct[11] & 1) << 4) | (strct[1] & 0xF)); + if (!i) + writeOPL(0xE0 | channel, (strct[26] & 3)); + else + writeOPL(0xE0 | channel, (strct[14] & 3)); + if (i && set) + writeOPL(0x40 | channel, 0); + } +} + + +MDYPlayer::MDYPlayer(Audio::Mixer &mixer) : AdLib(mixer) { + init(); +} + +MDYPlayer::~MDYPlayer() { +} + +void MDYPlayer::init() { + _soundMode = 0; + + _timbres = 0; + _tbrCount = 0; + _tbrStart = 0; + _timbresSize = 0; +} + +bool MDYPlayer::loadMDY(const char *fileName) { Common::File song; byte mdyHeader[70]; @@ -622,8 +507,7 @@ bool AdLib::loadMdy(const char *fileName) { if (!song.isOpen()) return false; - _needFree = true; - _mdySong = true; + _freeData = true; song.read(mdyHeader, 70); @@ -652,7 +536,7 @@ bool AdLib::loadMdy(const char *fileName) { return true; } -bool AdLib::loadTbr(const char *fileName) { +bool MDYPlayer::loadTBR(const char *fileName) { Common::File timbres; unload(); @@ -666,44 +550,203 @@ bool AdLib::loadTbr(const char *fileName) { timbres.close(); reset(); - setVoicesTbr(); + setVoices(); return true; } -void AdLib::unload() { - _playing = false; - _index = -1; +void MDYPlayer::unload() { + AdLib::unload(); - if (_data && _needFree) - delete[] _data; + delete[] _timbres; - _needFree = false; + _timbres = 0; + _timbresSize = 0; } -bool AdLib::isPlaying() const { - return _playing; -} +void MDYPlayer::interpret() { + unsigned char instr; + byte channel; + byte note; + byte volume; + uint8 tempoMult, tempoFrac; + uint8 ctrlByte1, ctrlByte2; + uint8 timbre; -bool AdLib::getRepeating() const { - return _repCount != 0; + if (_first) { + for (int i = 0; i < 11; i ++) + setVolume(i, 0); + +// TODO : Set pitch range + + _tempo = _basicTempo; + _wait = *(_playPos++); + _first = false; + } + do { + instr = *_playPos; +// printf("instr 0x%X\n", instr); + switch(instr) { + case 0xF8: + _wait = *(_playPos++); + break; + case 0xFC: + _ended = true; + _samplesTillPoll = 0; + return; + case 0xF0: + _playPos++; + ctrlByte1 = *(_playPos++); + ctrlByte2 = *(_playPos++); + if (ctrlByte1 != 0x7F || ctrlByte2 != 0) { + _playPos -= 2; + while (*(_playPos++) != 0xF7); + } else { + tempoMult = *(_playPos++); + tempoFrac = *(_playPos++); + _tempo = _basicTempo * tempoMult + (unsigned)(((long)_basicTempo * tempoFrac) >> 7); + _playPos++; + } + _wait = *(_playPos++); + break; + default: + if (instr >= 0x80) { + _playPos++; + } + channel = (int)(instr & 0x0f); + + switch(instr & 0xf0) { + case 0x90: + note = *(_playPos++); + volume = *(_playPos++); + _pollNotes[channel] = note; + setVolume(channel, volume); + setKey(channel, note, true, false); + break; + case 0x80: + _playPos += 2; + note = _pollNotes[channel]; + setKey(channel, note, false, false); + break; + case 0xA0: + setVolume(channel, *(_playPos++)); + break; + case 0xC0: + timbre = *(_playPos++); + setVoice(channel, timbre, false); + break; + case 0xE0: + warning("Pitch bend not yet implemented\n"); + + note = *(_playPos)++; + note += (unsigned)(*(_playPos++)) << 7; + + setKey(channel, note, _notOn[channel], true); + + break; + case 0xB0: + _playPos += 2; + break; + case 0xD0: + _playPos++; + break; + default: + warning("Bad MIDI instr byte: 0%X", instr); + while ((*_playPos) < 0x80) + _playPos++; + if (*_playPos != 0xF8) + _playPos--; + break; + } //switch instr & 0xF0 + _wait = *(_playPos++); + break; + } //switch instr + } while (_wait == 0); + + if (_wait == 0xF8) { + _wait = 0xF0; + if (*_playPos != 0xF8) + _wait += *(_playPos++); + } +// _playPos++; + _samplesTillPoll = _wait * (_rate / 1000); } -void AdLib::setRepeating(int32 repCount) { - _repCount = repCount; +void MDYPlayer::reset() { + AdLib::reset(); + +// _soundMode 1 : Percussive mode. + if (_soundMode == 1) { + writeOPL(0xA6, 0); + writeOPL(0xB6, 0); + writeOPL(0xA7, 0); + writeOPL(0xB7, 0); + writeOPL(0xA8, 0); + writeOPL(0xB8, 0); + +// TODO set the correct frequency for the last 4 percussive voices + } } -int AdLib::getIndex() const { - return _index; +void MDYPlayer::rewind() { + _playPos = _data; } -void AdLib::startPlay() { - if (_data) _playing = true; +void MDYPlayer::setVoices() { + byte *timbrePtr; + + timbrePtr = _timbres; + debugC(6, kDebugSound, "TBR version: %X.%X", timbrePtr[0], timbrePtr[1]); + timbrePtr += 2; + + _tbrCount = READ_LE_UINT16(timbrePtr); + debugC(6, kDebugSound, "Timbres counter: %d", _tbrCount); + timbrePtr += 2; + _tbrStart = READ_LE_UINT16(timbrePtr); + + timbrePtr += 2; + for (int i = 0; i < _tbrCount ; i++) + setVoice(i, i, true); } -void AdLib::stopPlay() { - Common::StackLock slock(_mutex); - _playing = false; +void MDYPlayer::setVoice(byte voice, byte instr, bool set) { + uint16 strct[27]; + byte channel; + byte *timbrePtr; + char timbreName[10]; + + timbreName[9] = '\0'; + for (int j = 0; j < 9; j++) + timbreName[j] = _timbres[6 + j + (instr * 9)]; + debugC(6, kDebugSound, "Loading timbre %s", timbreName); + + // i = 0 : 0 1 2 3 4 5 6 7 8 9 10 11 12 26 + // i = 1 : 13 14 15 16 17 18 19 20 21 22 23 24 25 27 + for (int i = 0; i < 2; i++) { + timbrePtr = _timbres + _tbrStart + instr * 0x38 + i * 0x1A; + for (int j = 0; j < 27; j++) { + strct[j] = READ_LE_UINT16(timbrePtr); + timbrePtr += 2; + } + channel = _operators[voice] + i * 3; + writeOPL(0xBD, 0x00); + writeOPL(0x08, 0x00); + writeOPL(0x40 | channel, ((strct[0] & 3) << 6) | (strct[8] & 0x3F)); + if (!i) + writeOPL(0xC0 | voice, + ((strct[2] & 7) << 1) | (1 - (strct[12] & 1))); + writeOPL(0x60 | channel, ((strct[3] & 0xF) << 4) | (strct[6] & 0xF)); + writeOPL(0x80 | channel, ((strct[4] & 0xF) << 4) | (strct[7] & 0xF)); + writeOPL(0x20 | channel, ((strct[9] & 1) << 7) | + ((strct[10] & 1) << 6) | ((strct[5] & 1) << 5) | + ((strct[11] & 1) << 4) | (strct[1] & 0xF)); + if (!i) + writeOPL(0xE0 | channel, (strct[26] & 3)); + else { + writeOPL(0xE0 | channel, (strct[14] & 3)); + writeOPL(0x40 | channel, 0); + } + } } } // End of namespace Gob diff --git a/engines/gob/sound/adlib.h b/engines/gob/sound/adlib.h index 0a7663bc09..3772b93551 100644 --- a/engines/gob/sound/adlib.h +++ b/engines/gob/sound/adlib.h @@ -38,7 +38,7 @@ class GobEngine; class AdLib : public Audio::AudioStream { public: AdLib(Audio::Mixer &mixer); - ~AdLib(); + virtual ~AdLib(); bool isPlaying() const; int getIndex() const; @@ -49,11 +49,7 @@ public: void startPlay(); void stopPlay(); - bool load(const char *fileName); - bool load(byte *data, uint32 size, int index = -1); - bool loadMdy(const char *fileName); - bool loadTbr(const char *fileName); - void unload(); + virtual void unload(); // AudioStream API int readBuffer(int16 *buffer, const int numSamples); @@ -75,10 +71,8 @@ protected: uint32 _rate; byte *_data; - byte *_timbres; byte *_playPos; uint32 _dataSize; - uint32 _timbresSize; short _freqs[25][12]; byte _notes[11]; @@ -93,32 +87,83 @@ protected: bool _playing; bool _first; bool _ended; - bool _needFree; - bool _mdySong; + + bool _freeData; int _index; - uint16 _tbrCount; - uint16 _tbrStart; unsigned char _wait; uint8 _tickBeat; uint8 _beatMeasure; uint32 _totalTick; uint32 _nrCommand; - byte _soundMode; uint16 _pitchBendRangeStep; uint16 _basicTempo, _tempo; void writeOPL(byte reg, byte val); void setFreqs(); - void reset(); - void setVoices(); - void setVoice(byte voice, byte instr, bool set); - void setVoicesTbr(); - void setVoiceTbr(byte voice, byte instr, bool set); void setKey(byte voice, byte note, bool on, bool spec); void setVolume(byte voice, byte volume); void pollMusic(); + + virtual void interpret() = 0; + + virtual void reset(); + virtual void rewind() = 0; + virtual void setVoices() = 0; + +private: + void init(); +}; + +class ADLPlayer : public AdLib { +public: + ADLPlayer(Audio::Mixer &mixer); + ~ADLPlayer(); + + bool load(const char *fileName); + bool load(byte *data, uint32 size, int index = -1); + + void unload(); + +protected: + void interpret(); + + void reset(); + void rewind(); + + void setVoices(); + void setVoice(byte voice, byte instr, bool set); +}; + +class MDYPlayer : public AdLib { +public: + MDYPlayer(Audio::Mixer &mixer); + ~MDYPlayer(); + + bool loadMDY(const char *fileName); + bool loadTBR(const char *fileName); + + void unload(); + +protected: + byte _soundMode; + + byte *_timbres; + uint16 _tbrCount; + uint16 _tbrStart; + uint32 _timbresSize; + + void interpret(); + + void reset(); + void rewind(); + + void setVoices(); + void setVoice(byte voice, byte instr, bool set); + +private: + void init(); }; } // End of namespace Gob diff --git a/engines/gob/sound/sound.cpp b/engines/gob/sound/sound.cpp index fba9ca3554..d6dd128f42 100644 --- a/engines/gob/sound/sound.cpp +++ b/engines/gob/sound/sound.cpp @@ -44,14 +44,15 @@ Sound::Sound(GobEngine *vm) : _vm(vm) { _pcspeaker = new PCSpeaker(*_vm->_mixer); _blaster = new SoundBlaster(*_vm->_mixer); - _adlib = 0; + _adlPlayer = 0; + _mdyPlayer = 0; _infogrames = 0; _protracker = 0; _cdrom = 0; _bgatmos = 0; - if (!_vm->_noMusic && _vm->hasAdlib()) - _adlib = new AdLib(*_vm->_mixer); + _hasAdLib = (!_vm->_noMusic && _vm->hasAdlib()); + if (!_vm->_noMusic && (_vm->getPlatform() == Common::kPlatformAmiga)) { _infogrames = new Infogrames(*_vm->_mixer); _protracker = new Protracker(*_vm->_mixer); @@ -69,7 +70,8 @@ Sound::Sound(GobEngine *vm) : _vm(vm) { Sound::~Sound() { delete _pcspeaker; delete _blaster; - delete _adlib; + delete _adlPlayer; + delete _mdyPlayer; delete _infogrames; delete _protracker; delete _cdrom; @@ -137,9 +139,14 @@ void Sound::sampleFree(SoundDesc *sndDesc, bool noteAdlib, int index) { if (sndDesc->getType() == SOUND_ADL) { - if (_adlib && noteAdlib) - if ((index == -1) || (_adlib->getIndex() == index)) - _adlib->stopPlay(); + if (noteAdlib) { + if (_adlPlayer) + if ((index == -1) || (_adlPlayer->getIndex() == index)) + _adlPlayer->stopPlay(); + if (_mdyPlayer) + if ((index == -1) || (_mdyPlayer->getIndex() == index)) + _mdyPlayer->stopPlay(); + } } else { @@ -230,68 +237,90 @@ void Sound::infogramesStop() { _infogrames->stop(); } -bool Sound::adlibLoad(const char *fileName) { - if (!_adlib) +bool Sound::adlibLoadADL(const char *fileName) { + if (!_hasAdLib) return false; - debugC(1, kDebugSound, "Adlib: Loading data (\"%s\")", fileName); + if (!_adlPlayer) + _adlPlayer = new ADLPlayer(*_vm->_mixer); - return _adlib->load(fileName); + debugC(1, kDebugSound, "Adlib: Loading ADL data (\"%s\")", fileName); + + return _adlPlayer->load(fileName); } -bool Sound::adlibLoad(byte *data, uint32 size, int index) { - if (!_adlib) +bool Sound::adlibLoadADL(byte *data, uint32 size, int index) { + if (!_hasAdLib) return false; - debugC(1, kDebugSound, "Adlib: Loading data (%d)", index); + if (!_adlPlayer) + _adlPlayer = new ADLPlayer(*_vm->_mixer); + + debugC(1, kDebugSound, "Adlib: Loading ADL data (%d)", index); - return _adlib->load(data, size, index); + return _adlPlayer->load(data, size, index); } void Sound::adlibUnload() { - if (!_adlib) + if (!_hasAdLib) return; debugC(1, kDebugSound, "Adlib: Unloading data"); - _adlib->unload(); + if (_adlPlayer) + _adlPlayer->unload(); + if (_mdyPlayer) + _mdyPlayer->unload(); } -bool Sound::adlibLoadMdy(const char *fileName) { - if (!_adlib) +bool Sound::adlibLoadMDY(const char *fileName) { + if (!_hasAdLib) return false; - debugC(1, kDebugSound, "Adlib: Loading data (\"%s\")", fileName); + if (!_mdyPlayer) + _mdyPlayer = new MDYPlayer(*_vm->_mixer); - return _adlib->loadMdy(fileName); + debugC(1, kDebugSound, "Adlib: Loading MDY data (\"%s\")", fileName); + + return _mdyPlayer->loadMDY(fileName); } -bool Sound::adlibLoadTbr(const char *fileName) { - if (!_adlib) +bool Sound::adlibLoadTBR(const char *fileName) { + if (!_hasAdLib) return false; - debugC(1, kDebugSound, "Adlib: Loading instruments (\"%s\")", fileName); + if (!_mdyPlayer) + _mdyPlayer = new MDYPlayer(*_vm->_mixer); + + debugC(1, kDebugSound, "Adlib: Loading MDY instruments (\"%s\")", fileName); - return _adlib->loadTbr(fileName); + return _mdyPlayer->loadTBR(fileName); } void Sound::adlibPlayTrack(const char *trackname) { - if (!_adlib || _adlib->isPlaying()) + if (!_hasAdLib) return; - debugC(1, kDebugSound, "Adlib: Playing track \"%s\"", trackname); + if (!_adlPlayer) + _adlPlayer = new ADLPlayer(*_vm->_mixer); + + if (_adlPlayer->isPlaying()) + return; - _adlib->unload(); - _adlib->load(trackname); - _adlib->startPlay(); + debugC(1, kDebugSound, "Adlib: Playing ADL track \"%s\"", trackname); + + _adlPlayer->unload(); + _adlPlayer->load(trackname); + _adlPlayer->startPlay(); } void Sound::adlibPlayBgMusic() { - int track; - - if (!_adlib) + if (!_hasAdLib) return; + if (!_adlPlayer) + _adlPlayer = new ADLPlayer(*_vm->_mixer); + static const char *tracksMac[] = { // "musmac1.adl", // TODO: This track isn't played correctly at all yet "musmac2.adl", @@ -310,58 +339,82 @@ void Sound::adlibPlayBgMusic() { }; if (_vm->getPlatform() == Common::kPlatformWindows) { - track = _vm->_util->getRandom(ARRAYSIZE(tracksWin)); + int track = _vm->_util->getRandom(ARRAYSIZE(tracksWin)); adlibPlayTrack(tracksWin[track]); } else { - track = _vm->_util->getRandom(ARRAYSIZE(tracksMac)); + int track = _vm->_util->getRandom(ARRAYSIZE(tracksMac)); adlibPlayTrack(tracksMac[track]); } } void Sound::adlibPlay() { - if (!_adlib) + if (!_hasAdLib) return; debugC(1, kDebugSound, "Adlib: Starting playback"); - _adlib->startPlay(); + if (_adlPlayer) + _adlPlayer->startPlay(); + if (_mdyPlayer) + _mdyPlayer->startPlay(); } void Sound::adlibStop() { - if (!_adlib) + if (!_hasAdLib) return; debugC(1, kDebugSound, "Adlib: Stopping playback"); - _adlib->stopPlay(); + if (_adlPlayer) + _adlPlayer->stopPlay(); + if (_mdyPlayer) + _mdyPlayer->stopPlay(); } bool Sound::adlibIsPlaying() const { - if (!_adlib) + if (!_hasAdLib) return false; - return _adlib->isPlaying(); + if (_adlPlayer && _adlPlayer->isPlaying()) + return true; + if (_mdyPlayer && _mdyPlayer->isPlaying()) + return true; + + return false; } int Sound::adlibGetIndex() const { - if (!_adlib) + if (!_hasAdLib) return -1; - return _adlib->getIndex(); + if (_adlPlayer) + return _adlPlayer->getIndex(); + if (_mdyPlayer) + return _mdyPlayer->getIndex(); + + return -1; } bool Sound::adlibGetRepeating() const { - if (!_adlib) + if (!_hasAdLib) return false; - return _adlib->getRepeating(); + if (_adlPlayer) + return _adlPlayer->getRepeating(); + if (_mdyPlayer) + return _mdyPlayer->getRepeating(); + + return false; } void Sound::adlibSetRepeating(int32 repCount) { - if (!_adlib) + if (!_hasAdLib) return; - _adlib->setRepeating(repCount); + if (_adlPlayer) + _adlPlayer->setRepeating(repCount); + if (_mdyPlayer) + _mdyPlayer->setRepeating(repCount); } void Sound::blasterPlay(SoundDesc *sndDesc, int16 repCount, diff --git a/engines/gob/sound/sound.h b/engines/gob/sound/sound.h index a48002df4a..6f6c1d0469 100644 --- a/engines/gob/sound/sound.h +++ b/engines/gob/sound/sound.h @@ -34,7 +34,8 @@ namespace Gob { class GobEngine; class PCSpeaker; class SoundBlaster; -class AdLib; +class ADLPlayer; +class MDYPlayer; class Infogrames; class Protracker; class CDROM; @@ -79,10 +80,10 @@ public: // AdLib - bool adlibLoad(const char *fileName); - bool adlibLoad(byte *data, uint32 size, int index = -1); - bool adlibLoadMdy(const char *fileName); - bool adlibLoadTbr(const char *fileName); + bool adlibLoadADL(const char *fileName); + bool adlibLoadADL(byte *data, uint32 size, int index = -1); + bool adlibLoadMDY(const char *fileName); + bool adlibLoadTBR(const char *fileName); void adlibUnload(); void adlibPlayTrack(const char *trackname); @@ -143,11 +144,14 @@ public: private: GobEngine *_vm; + bool _hasAdLib; + SoundDesc _sounds[kSoundsCount]; PCSpeaker *_pcspeaker; SoundBlaster *_blaster; - AdLib *_adlib; + ADLPlayer *_adlPlayer; + MDYPlayer *_mdyPlayer; Infogrames *_infogrames; Protracker *_protracker; CDROM *_cdrom; |