diff options
-rw-r--r-- | engines/sci/sound/midiparser_sci.cpp | 60 | ||||
-rw-r--r-- | engines/sci/sound/midiparser_sci.h | 19 | ||||
-rw-r--r-- | engines/sci/sound/music.cpp | 94 | ||||
-rw-r--r-- | engines/sci/sound/music.h | 14 |
4 files changed, 117 insertions, 70 deletions
diff --git a/engines/sci/sound/midiparser_sci.cpp b/engines/sci/sound/midiparser_sci.cpp index 9a6be1e1df..4766118f52 100644 --- a/engines/sci/sound/midiparser_sci.cpp +++ b/engines/sci/sound/midiparser_sci.cpp @@ -61,14 +61,20 @@ MidiParser_SCI::MidiParser_SCI(SciVersion soundVersion, SciMusic *music) : _dataincToAdd = 0; _resetOnPause = false; _pSnd = 0; - - _manualCommandCount = 0; } MidiParser_SCI::~MidiParser_SCI() { unloadMusic(); } +void MidiParser_SCI::mainThreadBegin() { + _mainThreadCalled = true; +} + +void MidiParser_SCI::mainThreadEnd() { + _mainThreadCalled = false; +} + bool MidiParser_SCI::loadMusic(SoundResource::Track *track, MusicEntry *psnd, int channelFilterMask, SciVersion soundVersion) { unloadMusic(); _track = track; @@ -107,7 +113,7 @@ void MidiParser_SCI::sendInitCommands() { byte voiceCount = 0; if (_channelUsed[i]) { voiceCount = _pSnd->soundRes->getInitialVoiceCount(i); - sendToDriverQueue(0xB0 | i, 0x4B, voiceCount); + sendToDriver(0xB0 | i, 0x4B, voiceCount); } } } @@ -115,7 +121,8 @@ void MidiParser_SCI::sendInitCommands() { // Send a velocity off signal to all channels for (int i = 0; i < 15; ++i) { - sendToDriverQueue(0xB0 | i, 0x4E, 0); // Reset velocity + if (_channelUsed[i]) + sendToDriver(0xB0 | i, 0x4E, 0); // Reset velocity } } @@ -145,44 +152,27 @@ 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 and actually store the command for getting really sent when being onTimer() -void MidiParser_SCI::sendToDriverQueue(uint32 b) { - byte midiChannel = b & 0xf; +// this is used for scripts sending midi commands to us. we verify in that case that the channel is actually +// used, so that channel remapping will work as well and then send them on +void MidiParser_SCI::sendFromScriptToDriver(uint32 midi) { + byte midiChannel = midi & 0xf; if (!_channelUsed[midiChannel]) { // 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; } - - if (_manualCommandCount >= 200) - error("driver queue is full"); - _manualCommands[_manualCommandCount] = b; - _manualCommandCount++; + sendToDriver(midi); } -// 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; +void MidiParser_SCI::sendToDriver(uint32 midi) { + byte midiChannel = midi & 0xf; - while (curCommand < _manualCommandCount) { - sendToDriver(_manualCommands[curCommand]); - curCommand++; - } - _manualCommandCount = 0; -} - -void MidiParser_SCI::sendToDriver(uint32 b) { - byte midiChannel = b & 0xf; - - if ((b & 0xFFF0) == 0x4EB0) { + if ((midi & 0xFFF0) == 0x4EB0) { // this is channel mute only for sci1 // it's velocity control for sci0 if (_soundVersion >= SCI_VERSION_1_EARLY) { - _channelMuted[midiChannel] = b & 0xFF0000 ? true : false; + _channelMuted[midiChannel] = midi & 0xFF0000 ? true : false; return; // don't send this to driver at all } } @@ -194,8 +184,11 @@ void MidiParser_SCI::sendToDriver(uint32 b) { int16 realChannel = _channelRemap[midiChannel]; assert(realChannel != -1); - b = (b & 0xFFFFFFF0) | realChannel; - _driver->send(b); + midi = (midi & 0xFFFFFFF0) | realChannel; + if (_mainThreadCalled) + _music->putMidiCommandInQueue(midi); + else + _driver->send(midi); } void MidiParser_SCI::parseNextEvent(EventInfo &info) { @@ -681,7 +674,8 @@ 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++) - sendToDriverQueue(0xB0 + i, 7, _volume); + if (_channelUsed[i]) + sendToDriver(0xB0 + i, 7, _volume); break; default: diff --git a/engines/sci/sound/midiparser_sci.h b/engines/sci/sound/midiparser_sci.h index 5abffdb3a1..dbd37018b1 100644 --- a/engines/sci/sound/midiparser_sci.h +++ b/engines/sci/sound/midiparser_sci.h @@ -55,6 +55,10 @@ class MidiParser_SCI : public MidiParser { public: MidiParser_SCI(SciVersion soundVersion, SciMusic *music); ~MidiParser_SCI(); + + void mainThreadBegin(); + void mainThreadEnd(); + bool loadMusic(SoundResource::Track *track, MusicEntry *psnd, int channelFilterMask, SciVersion soundVersion); bool loadMusic(byte *, uint32) { return false; @@ -77,16 +81,11 @@ public: const byte *getMixedData() const { return _mixedData; } void tryToOwnChannels(); - void sendToDriver(uint32 b); + void sendFromScriptToDriver(uint32 midi); + void sendToDriver(uint32 midi); void sendToDriver(byte status, byte firstOp, byte secondOp) { sendToDriver(status | ((uint32)firstOp << 8) | ((uint32)secondOp << 16)); } - 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); @@ -96,6 +95,9 @@ protected: SciMusic *_music; + // this is set, when main thread calls us -> we send commands to queue instead to driver + bool _mainThreadCalled; + SciVersion _soundVersion; byte *_mixedData; SoundResource::Track *_track; @@ -112,9 +114,6 @@ 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 6c697c86e5..b6ab7f9f70 100644 --- a/engines/sci/sound/music.cpp +++ b/engines/sci/sound/music.cpp @@ -46,6 +46,8 @@ SciMusic::SciMusic(SciVersion soundVersion) for (int i = 0; i < 16; i++) _usedChannel[i] = 0; + + _queuedCommandCount = 0; } SciMusic::~SciMusic() { @@ -102,6 +104,49 @@ void SciMusic::init() { _driverFirstChannel = _pMidiDrv->getFirstChannel(); } +void SciMusic::miditimerCallback(void *p) { + SciMusic *sciMusic = (SciMusic *)p; + + Common::StackLock lock(sciMusic->_mutex); + sciMusic->onTimer(); +} + +void SciMusic::onTimer() { + const MusicList::iterator end = _playList.end(); + // sending out queued commands that were "sent" via main thread + sendMidiCommandsFromQueue(); + + for (MusicList::iterator i = _playList.begin(); i != end; ++i) + (*i)->onTimer(); + + // for sending out fade commands immediately + sendMidiCommandsFromQueue(); +} + +void SciMusic::putMidiCommandInQueue(byte status, byte firstOp, byte secondOp) { + putMidiCommandInQueue(status | ((uint32)firstOp << 8) | ((uint32)secondOp << 16)); +} + +void SciMusic::putMidiCommandInQueue(uint32 midi) { + if (_queuedCommandCount >= 1000) + error("driver queue is full"); + _queuedCommands[_queuedCommandCount] = midi; + _queuedCommandCount++; +} + +// 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 SciMusic::sendMidiCommandsFromQueue() { + int curCommand = 0; + + while (curCommand < _queuedCommandCount) { + _pMidiDrv->send(_queuedCommands[curCommand]); + curCommand++; + } + _queuedCommandCount = 0; +} + void SciMusic::clearPlayList() { Common::StackLock lock(_mutex); @@ -127,14 +172,6 @@ void SciMusic::stopAll() { } } - -void SciMusic::miditimerCallback(void *p) { - SciMusic *aud = (SciMusic *)p; - - Common::StackLock lock(aud->_mutex); - aud->onTimer(); -} - void SciMusic::soundSetSoundOn(bool soundOnFlag) { Common::StackLock lock(_mutex); @@ -219,8 +256,10 @@ void SciMusic::soundInitSnd(MusicEntry *pSnd) { // Find out what channels to filter for SCI0 channelFilterMask = pSnd->soundRes->getChannelFilterMask(_pMidiDrv->getPlayId(), _pMidiDrv->hasRhythmChannel()); - pSnd->pMidiParser->loadMusic(track, pSnd, channelFilterMask, _soundVersion); + pSnd->pMidiParser->mainThreadBegin(); + pSnd->pMidiParser->loadMusic(track, pSnd, channelFilterMask, _soundVersion); + pSnd->pMidiParser->mainThreadEnd(); _mutex.unlock(); } } @@ -255,12 +294,6 @@ void SciMusic::freeChannels(MusicEntry *caller) { } } -void SciMusic::onTimer() { - const MusicList::iterator end = _playList.end(); - for (MusicList::iterator i = _playList.begin(); i != end; ++i) - (*i)->onTimer(); -} - void SciMusic::soundPlay(MusicEntry *pSnd) { _mutex.lock(); @@ -316,18 +349,21 @@ void SciMusic::soundPlay(MusicEntry *pSnd) { DisposeAfterUse::NO); } } else { - _mutex.lock(); if (pSnd->pMidiParser) { + _mutex.lock(); + pSnd->pMidiParser->mainThreadBegin(); pSnd->pMidiParser->tryToOwnChannels(); pSnd->pMidiParser->setVolume(pSnd->volume); if (pSnd->status == kSoundStopped) { pSnd->pMidiParser->sendInitCommands(); pSnd->pMidiParser->jumpToTick(0); - } else + } else { // Fast forward to the last position and perform associated events when loading pSnd->pMidiParser->jumpToTick(pSnd->ticker, true); + } + pSnd->pMidiParser->mainThreadEnd(); + _mutex.unlock(); } - _mutex.unlock(); } pSnd->status = kSoundPlaying; @@ -342,8 +378,10 @@ void SciMusic::soundStop(MusicEntry *pSnd) { if (pSnd->pMidiParser) { _mutex.lock(); + pSnd->pMidiParser->mainThreadBegin(); pSnd->pMidiParser->stop(); freeChannels(pSnd); + pSnd->pMidiParser->mainThreadEnd(); _mutex.unlock(); } } @@ -354,7 +392,9 @@ void SciMusic::soundSetVolume(MusicEntry *pSnd, byte volume) { _pMixer->setChannelVolume(pSnd->hCurrentAud, volume * 2); // Mixer is 0-255, SCI is 0-127 } else if (pSnd->pMidiParser) { _mutex.lock(); + pSnd->pMidiParser->mainThreadBegin(); pSnd->pMidiParser->setVolume(volume); + pSnd->pMidiParser->mainThreadEnd(); _mutex.unlock(); } } @@ -369,13 +409,15 @@ void SciMusic::soundSetPriority(MusicEntry *pSnd, byte prio) { void SciMusic::soundKill(MusicEntry *pSnd) { pSnd->status = kSoundStopped; - _mutex.lock(); if (pSnd->pMidiParser) { + _mutex.lock(); + pSnd->pMidiParser->mainThreadBegin(); pSnd->pMidiParser->unloadMusic(); + pSnd->pMidiParser->mainThreadEnd(); delete pSnd->pMidiParser; pSnd->pMidiParser = NULL; + _mutex.unlock(); } - _mutex.unlock(); if (pSnd->pStreamAud) { _pMixer->stopHandle(pSnd->hCurrentAud); @@ -409,8 +451,10 @@ void SciMusic::soundPause(MusicEntry *pSnd) { } else { if (pSnd->pMidiParser) { _mutex.lock(); + pSnd->pMidiParser->mainThreadBegin(); pSnd->pMidiParser->pause(); freeChannels(pSnd); + pSnd->pMidiParser->mainThreadEnd(); _mutex.unlock(); } } @@ -458,10 +502,12 @@ void SciMusic::sendMidiCommand(uint32 cmd) { void SciMusic::sendMidiCommand(MusicEntry *pSnd, uint32 cmd) { Common::StackLock lock(_mutex); - if (pSnd->pMidiParser) - pSnd->pMidiParser->sendToDriverQueue(cmd); - else + if (!pSnd->pMidiParser) error("tried to cmdSendMidi on non midi slot (%04x:%04x)", PRINT_REG(pSnd->soundObj)); + + pSnd->pMidiParser->mainThreadBegin(); + pSnd->pMidiParser->sendFromScriptToDriver(cmd); + pSnd->pMidiParser->mainThreadEnd(); } void SciMusic::printPlayList(Console *con) { @@ -567,8 +613,6 @@ 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(); } diff --git a/engines/sci/sound/music.h b/engines/sci/sound/music.h index 36db9a04bf..0a461cf76e 100644 --- a/engines/sci/sound/music.h +++ b/engines/sci/sound/music.h @@ -132,7 +132,15 @@ public: ~SciMusic(); void init(); + void onTimer(); + void putMidiCommandInQueue(byte status, byte firstOp, byte secondOp); + void putMidiCommandInQueue(uint32 midi); +private: + static void miditimerCallback(void *p); + void sendMidiCommandsFromQueue(); + +public: void clearPlayList(); void pauseAll(bool pause); void stopAll(); @@ -209,14 +217,16 @@ protected: // Mixed AdLib/MIDI mode: when enabled from the ScummVM sound options screen, // and a sound has a digital track, the sound from the AdLib track is played bool _bMultiMidi; -private: - static void miditimerCallback(void *p); +private: MusicList _playList; bool _soundOn; byte _masterVolume; MusicEntry *_usedChannel[16]; + int _queuedCommandCount; + uint32 _queuedCommands[1000]; + int _driverFirstChannel; }; |