aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engines/sci/sound/midiparser_sci.cpp60
-rw-r--r--engines/sci/sound/midiparser_sci.h19
-rw-r--r--engines/sci/sound/music.cpp94
-rw-r--r--engines/sci/sound/music.h14
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;
};