diff options
author | Martin Kiewitz | 2010-06-20 10:25:46 +0000 |
---|---|---|
committer | Martin Kiewitz | 2010-06-20 10:25:46 +0000 |
commit | 81f64c9e3e8cacf106c36eff2f443f29ed1f50c3 (patch) | |
tree | 3525f4c2f0cf97dc83f746d2bb5429bd97d7f2f7 | |
parent | 41990883bf003ff075821bc484b605b1ba87c8ad (diff) | |
download | scummvm-rg350-81f64c9e3e8cacf106c36eff2f443f29ed1f50c3.tar.gz scummvm-rg350-81f64c9e3e8cacf106c36eff2f443f29ed1f50c3.tar.bz2 scummvm-rg350-81f64c9e3e8cacf106c36eff2f443f29ed1f50c3.zip |
SCI: storing all manual midi commands now and actually sending them to driver during onTimer() - fixes mt32 emulation crashing during lsl5 piano scene
svn-id: r50073
-rw-r--r-- | engines/sci/sound/midiparser_sci.cpp | 50 | ||||
-rw-r--r-- | engines/sci/sound/midiparser_sci.h | 10 | ||||
-rw-r--r-- | engines/sci/sound/music.cpp | 4 |
3 files changed, 43 insertions, 21 deletions
diff --git a/engines/sci/sound/midiparser_sci.cpp b/engines/sci/sound/midiparser_sci.cpp index 31d9d95116..640000235e 100644 --- a/engines/sci/sound/midiparser_sci.cpp +++ b/engines/sci/sound/midiparser_sci.cpp @@ -61,6 +61,8 @@ MidiParser_SCI::MidiParser_SCI(SciVersion soundVersion, SciMusic *music) : _dataincToAdd = 0; _resetOnPause = false; _pSnd = 0; + + _manualCommandCount = 0; } MidiParser_SCI::~MidiParser_SCI() { @@ -105,7 +107,7 @@ void MidiParser_SCI::sendInitCommands() { byte voiceCount = 0; if (_channelUsed[i]) { voiceCount = _pSnd->soundRes->getInitialVoiceCount(i); - _driver->send(0xB0 | i, 0x4B, voiceCount); + sendToDriverQueue(0xB0 | i, 0x4B, voiceCount); } } } @@ -113,8 +115,7 @@ void MidiParser_SCI::sendInitCommands() { // Send a velocity off signal to all channels for (int i = 0; i < 15; ++i) { - if (_channelUsed[i]) - sendToDriver(0xB0 | i, 0x4E, 0); // Reset velocity + sendToDriverQueue(0xB0 | i, 0x4E, 0); // Reset velocity } } @@ -145,17 +146,33 @@ void MidiParser_SCI::unloadMusic() { } // this is used for scripts sending direct midi commands to us. we verify in that case that the channel is actually -// used -void MidiParser_SCI::sendManuallyToDriver(uint32 b) { +// used and actually store the command for getting really sent when being onTimer() +void MidiParser_SCI::sendToDriverQueue(uint32 b) { byte midiChannel = b & 0xf; if (!_channelUsed[midiChannel]) { - // scripts trying to send to unused channel - // this happens at least in sq1vga right at the start, it's a script issue + // trying to send to an unused channel + // this happens for cmdSendMidi at least in sq1vga right at the start, it's a script issue return; } - sendToDriver(b); + if (_manualCommandCount >= 200) + error("driver queue is full"); + _manualCommands[_manualCommandCount] = b; + _manualCommandCount++; +} + +// This sends the stored commands from queue to driver (is supposed to get called only during onTimer()) +// at least mt32 emulation doesn't like getting note-on commands from main thread (if we directly send, we would get +// a crash during piano scene in lsl5) +void MidiParser_SCI::sendQueueToDriver() { + int curCommand = 0; + + while (curCommand < _manualCommandCount) { + sendToDriver(_manualCommands[curCommand]); + curCommand++; + } + _manualCommandCount = 0; } void MidiParser_SCI::sendToDriver(uint32 b) { @@ -375,9 +392,8 @@ void MidiParser_SCI::allNotesOff() { // Turn off all active notes for (i = 0; i < 128; ++i) { for (j = 0; j < 16; ++j) { - int16 realChannel = _channelRemap[j]; - if ((_active_notes[i] & (1 << j)) && realChannel != -1){ - _driver->send(0x80 | realChannel, i, 0); + if ((_active_notes[i] & (1 << j))){ + sendToDriverQueue(0x80 | j, i, 0); } } } @@ -385,7 +401,7 @@ void MidiParser_SCI::allNotesOff() { // Turn off all hanging notes for (i = 0; i < ARRAYSIZE(_hanging_notes); i++) { if (_hanging_notes[i].time_left) { - _driver->send(0x80 | _hanging_notes[i].channel, _hanging_notes[i].note, 0); + sendToDriverQueue(0x80 | _hanging_notes[i].channel, _hanging_notes[i].note, 0); _hanging_notes[i].time_left = 0; } } @@ -394,11 +410,8 @@ void MidiParser_SCI::allNotesOff() { // To be sure, send an "All Note Off" event (but not all MIDI devices // support this...). - for (i = 0; i < 16; ++i) { - int16 realChannel = _channelRemap[i]; - if (realChannel != -1) - _driver->send(0xB0 | realChannel, 0x7b, 0); // All notes off - } + for (i = 0; i < 16; ++i) + sendToDriverQueue(0xB0 | i, 0x7b, 0); // All notes off memset(_active_notes, 0, sizeof(_active_notes)); } @@ -659,8 +672,7 @@ void MidiParser_SCI::setVolume(byte volume) { case SCI_VERSION_1_LATE: // sending volume change to all used channels for (int i = 0; i < 15; i++) - if (_channelUsed[i]) - sendToDriver(0xB0 + i, 7, _volume); + sendToDriverQueue(0xB0 + i, 7, _volume); break; default: diff --git a/engines/sci/sound/midiparser_sci.h b/engines/sci/sound/midiparser_sci.h index 48de44555d..5abffdb3a1 100644 --- a/engines/sci/sound/midiparser_sci.h +++ b/engines/sci/sound/midiparser_sci.h @@ -81,7 +81,12 @@ public: void sendToDriver(byte status, byte firstOp, byte secondOp) { sendToDriver(status | ((uint32)firstOp << 8) | ((uint32)secondOp << 16)); } - void sendManuallyToDriver(uint32 b); + void sendToDriverQueue(uint32 b); + void sendToDriverQueue(byte status, byte firstOp, byte secondOp) { + sendToDriverQueue(status | ((uint32)firstOp << 8) | ((uint32)secondOp << 16)); + } + + void sendQueueToDriver(); protected: void parseNextEvent(EventInfo &info); @@ -107,6 +112,9 @@ protected: bool _channelUsed[16]; int16 _channelRemap[16]; bool _channelMuted[16]; + + int _manualCommandCount; + uint32 _manualCommands[200]; }; } // End of namespace Sci diff --git a/engines/sci/sound/music.cpp b/engines/sci/sound/music.cpp index 688b88a910..fbf37a78b1 100644 --- a/engines/sci/sound/music.cpp +++ b/engines/sci/sound/music.cpp @@ -465,7 +465,7 @@ void SciMusic::sendMidiCommand(uint32 cmd) { void SciMusic::sendMidiCommand(MusicEntry *pSnd, uint32 cmd) { Common::StackLock lock(_mutex); if (pSnd->pMidiParser) - pSnd->pMidiParser->sendManuallyToDriver(cmd); + pSnd->pMidiParser->sendToDriverQueue(cmd); else error("tried to cmdSendMidi on non midi slot (%04x:%04x)", PRINT_REG(pSnd->soundObj)); } @@ -573,6 +573,8 @@ void MusicEntry::onTimer() { // Only process MIDI streams in this thread, not digital sound effects if (pMidiParser) { + // Process manual commands first + pMidiParser->sendQueueToDriver(); pMidiParser->onTimer(); ticker = (uint16)pMidiParser->getTick(); } |