SCI: instead of queueing inside midiparser, we are queueing now globally in SciMusic, also some little cleanup

svn-id: r50130
This commit is contained in:
Martin Kiewitz 2010-06-21 22:07:03 +00:00
parent 6c854f30da
commit 1041067a0c
4 changed files with 117 additions and 70 deletions

View File

@ -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:

View File

@ -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

View File

@ -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();
}

View File

@ -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;
};