aboutsummaryrefslogtreecommitdiff
path: root/engines
diff options
context:
space:
mode:
Diffstat (limited to 'engines')
-rw-r--r--engines/gob/inter_fascin.cpp28
-rw-r--r--engines/gob/inter_v1.cpp2
-rw-r--r--engines/gob/sound/adlib.cpp769
-rw-r--r--engines/gob/sound/adlib.h81
-rw-r--r--engines/gob/sound/sound.cpp147
-rw-r--r--engines/gob/sound/sound.h16
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 &params) {
}
void Inter_Fascination::oFascin_geUnknown2(OpGobParams &params) {
- _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 &params) {
@@ -146,33 +146,33 @@ void Inter_Fascination::oFascin_geUnknown5(OpGobParams &params) {
}
void Inter_Fascination::oFascin_geUnknown6(OpGobParams &params) {
- _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 &params) {
- _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 &params) {
- _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 &params) {
- _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 &params) {
- _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 &params) {
- _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 &params) {
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 &params) {
}
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;