From 2d1fa6c3f8bdc635d49978ad48f72619707d6893 Mon Sep 17 00:00:00 2001 From: athrxx Date: Fri, 20 May 2011 16:06:14 +0200 Subject: FM-TOWNS AUDIO: fix thread lockups and cleanup - fixed lockup situation in imuse destructor (only concerning the fm-towns driver) - fixed lockup situation when AudioCDManager functions get called (in both cases both the main thread and the mixer thread would get locked in different mutex belonging to the other thread) --- audio/softsynth/fmtowns_pc98/towns_audio.cpp | 228 +++++++++++---------- audio/softsynth/fmtowns_pc98/towns_audio.h | 11 +- audio/softsynth/fmtowns_pc98/towns_midi.cpp | 68 +++--- audio/softsynth/fmtowns_pc98/towns_pc98_driver.cpp | 104 ++++++---- audio/softsynth/fmtowns_pc98/towns_pc98_driver.h | 34 +-- .../softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp | 60 +++--- audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h | 23 +-- 7 files changed, 284 insertions(+), 244 deletions(-) (limited to 'audio/softsynth/fmtowns_pc98') diff --git a/audio/softsynth/fmtowns_pc98/towns_audio.cpp b/audio/softsynth/fmtowns_pc98/towns_audio.cpp index 719bc981ee..635f9354cc 100644 --- a/audio/softsynth/fmtowns_pc98/towns_audio.cpp +++ b/audio/softsynth/fmtowns_pc98/towns_audio.cpp @@ -30,7 +30,7 @@ class TownsAudio_PcmChannel { -friend class TownsAudioInterfaceIntern; +friend class TownsAudioInterfaceInternal; public: TownsAudio_PcmChannel(); ~TownsAudio_PcmChannel(); @@ -80,7 +80,7 @@ private: }; class TownsAudio_WaveTable { -friend class TownsAudioInterfaceIntern; +friend class TownsAudioInterfaceInternal; public: TownsAudio_WaveTable(); ~TownsAudio_WaveTable(); @@ -101,12 +101,12 @@ private: int8 *data; }; -class TownsAudioInterfaceIntern : public TownsPC98_FmSynth { +class TownsAudioInterfaceInternal : public TownsPC98_FmSynth { public: - TownsAudioInterfaceIntern(Audio::Mixer *mixer, TownsAudioInterfacePluginDriver *driver); - ~TownsAudioInterfaceIntern(); + TownsAudioInterfaceInternal(Audio::Mixer *mixer, TownsAudioInterfacePluginDriver *driver); + ~TownsAudioInterfaceInternal(); - static TownsAudioInterfaceIntern *addNewRef(Audio::Mixer *mixer, TownsAudioInterfacePluginDriver *driver); + static TownsAudioInterfaceInternal *addNewRef(Audio::Mixer *mixer, TownsAudioInterfacePluginDriver *driver); static void releaseRef(); bool checkPluginDriver(TownsAudioInterfacePluginDriver *driver); @@ -127,7 +127,7 @@ private: void timerCallbackA(); void timerCallbackB(); - typedef int (TownsAudioInterfaceIntern::*TownsAudioIntfCallback)(va_list &); + typedef int (TownsAudioInterfaceInternal::*TownsAudioIntfCallback)(va_list &); const TownsAudioIntfCallback *_intfOpcodes; int intf_reset(va_list &args); @@ -223,9 +223,11 @@ private: void pcmCalcPhaseStep(TownsAudio_PcmChannel *p, TownsAudio_WaveTable *w); void updateOutputVolume(); + void updateOutputVolumeInternal(); uint8 _outputVolumeFlags; uint8 _outputLevel[16]; uint8 _outputMute[16]; + bool _updateOutputVol; const float _baserate; uint32 _timerBase; @@ -239,7 +241,7 @@ private: TownsAudioInterfacePluginDriver *_drv; bool _ready; - static TownsAudioInterfaceIntern *_refInstance; + static TownsAudioInterfaceInternal *_refInstance; static int _refCount; static const uint8 _chanFlags[]; @@ -250,15 +252,15 @@ private: static const uint16 _pcmPhase2[]; }; -TownsAudioInterfaceIntern::TownsAudioInterfaceIntern(Audio::Mixer *mixer, TownsAudioInterfacePluginDriver *driver) : TownsPC98_FmSynth(mixer, kTypeTowns), +TownsAudioInterfaceInternal::TownsAudioInterfaceInternal(Audio::Mixer *mixer, TownsAudioInterfacePluginDriver *driver) : TownsPC98_FmSynth(mixer, kTypeTowns), _fmInstruments(0), _pcmInstruments(0), _pcmChan(0), _waveTables(0), _waveTablesTotalDataSize(0), _baserate(55125.0f / (float)mixer->getOutputRate()), _tickLength(0), _timer(0), _drv(driver), _pcmSfxChanMask(0), _musicVolume(Audio::Mixer::kMaxMixerVolume), _sfxVolume(Audio::Mixer::kMaxMixerVolume), _outputVolumeFlags(0), _pcmChanOut(0), _pcmChanReserved(0), _pcmChanKeyPressed(0), _pcmChanEffectPlaying(0), _pcmChanKeyPlaying(0), _fmChanPlaying(0), - _numReservedChannels(0), _numWaveTables(0), _ready(false) { + _numReservedChannels(0), _numWaveTables(0), _updateOutputVol(false), _ready(false) { -#define INTCB(x) &TownsAudioInterfaceIntern::intf_##x +#define INTCB(x) &TownsAudioInterfaceInternal::intf_##x static const TownsAudioIntfCallback intfCb[] = { // 0 INTCB(reset), @@ -381,7 +383,7 @@ TownsAudioInterfaceIntern::TownsAudioInterfaceIntern(Audio::Mixer *mixer, TownsA _tickLength = 2 * _timerBase; } -TownsAudioInterfaceIntern::~TownsAudioInterfaceIntern() { +TownsAudioInterfaceInternal::~TownsAudioInterfaceInternal() { _ready = false; deinit(); @@ -393,19 +395,19 @@ TownsAudioInterfaceIntern::~TownsAudioInterfaceIntern() { delete[] _pcmChan; } -TownsAudioInterfaceIntern *TownsAudioInterfaceIntern::addNewRef(Audio::Mixer *mixer, TownsAudioInterfacePluginDriver *driver) { +TownsAudioInterfaceInternal *TownsAudioInterfaceInternal::addNewRef(Audio::Mixer *mixer, TownsAudioInterfacePluginDriver *driver) { _refCount++; if (_refCount == 1 && _refInstance == 0) - _refInstance = new TownsAudioInterfaceIntern(mixer, driver); + _refInstance = new TownsAudioInterfaceInternal(mixer, driver); else if (_refCount < 2 || _refInstance == 0) - error("TownsAudioInterfaceIntern::addNewRef(): Internal reference management failure"); + error("TownsAudioInterfaceInternal::addNewRef(): Internal reference management failure"); else if (!_refInstance->checkPluginDriver(driver)) - error("TownsAudioInterfaceIntern::addNewRef(): Plugin driver conflict"); + error("TownsAudioInterfaceInternal::addNewRef(): Plugin driver conflict"); return _refInstance; } -void TownsAudioInterfaceIntern::releaseRef() { +void TownsAudioInterfaceInternal::releaseRef() { if (!_refCount) return; @@ -417,7 +419,7 @@ void TownsAudioInterfaceIntern::releaseRef() { } } -bool TownsAudioInterfaceIntern::checkPluginDriver(TownsAudioInterfacePluginDriver *driver) { +bool TownsAudioInterfaceInternal::checkPluginDriver(TownsAudioInterfacePluginDriver *driver) { if (_refCount <= 1) return true; @@ -425,15 +427,13 @@ bool TownsAudioInterfaceIntern::checkPluginDriver(TownsAudioInterfacePluginDrive if (driver && driver != _drv) return false; } else { - lock(); _drv = driver; - unlock(); } return true; } -bool TownsAudioInterfaceIntern::init() { +bool TownsAudioInterfaceInternal::init() { if (_ready) return true; @@ -457,7 +457,7 @@ bool TownsAudioInterfaceIntern::init() { return true; } -int TownsAudioInterfaceIntern::callback(int command, ...) { +int TownsAudioInterfaceInternal::callback(int command, ...) { if (!_ready) return 1; @@ -470,40 +470,42 @@ int TownsAudioInterfaceIntern::callback(int command, ...) { return res; } -int TownsAudioInterfaceIntern::processCommand(int command, va_list &args) { +int TownsAudioInterfaceInternal::processCommand(int command, va_list &args) { if (!_ready) return 1; if (command < 0 || command > 81) return 4; - lock(); + Common::StackLock lock(_mutex); int res = (this->*_intfOpcodes[command])(args); - unlock(); return res; } -void TownsAudioInterfaceIntern::setMusicVolume(int volume) { +void TownsAudioInterfaceInternal::setMusicVolume(int volume) { _musicVolume = CLIP(volume, 0, Audio::Mixer::kMaxMixerVolume); setVolumeIntern(_musicVolume, _sfxVolume); } -void TownsAudioInterfaceIntern::setSoundEffectVolume(int volume) { +void TownsAudioInterfaceInternal::setSoundEffectVolume(int volume) { _sfxVolume = CLIP(volume, 0, Audio::Mixer::kMaxMixerVolume); setVolumeIntern(_musicVolume, _sfxVolume); } -void TownsAudioInterfaceIntern::setSoundEffectChanMask(int mask) { +void TownsAudioInterfaceInternal::setSoundEffectChanMask(int mask) { _pcmSfxChanMask = mask >> 6; mask &= 0x3f; setVolumeChannelMasks(~mask, mask); } -void TownsAudioInterfaceIntern::nextTickEx(int32 *buffer, uint32 bufferSize) { +void TownsAudioInterfaceInternal::nextTickEx(int32 *buffer, uint32 bufferSize) { if (!_ready) return; + if (_updateOutputVol) + updateOutputVolumeInternal(); + for (uint32 i = 0; i < bufferSize; i++) { _timer += _tickLength; while (_timer > 0x514767) { @@ -551,12 +553,12 @@ void TownsAudioInterfaceIntern::nextTickEx(int32 *buffer, uint32 bufferSize) { } } -void TownsAudioInterfaceIntern::timerCallbackA() { +void TownsAudioInterfaceInternal::timerCallbackA() { if (_drv && _ready) _drv->timerCallback(0); } -void TownsAudioInterfaceIntern::timerCallbackB() { +void TownsAudioInterfaceInternal::timerCallbackB() { if (_ready) { if (_drv) _drv->timerCallback(1); @@ -564,62 +566,62 @@ void TownsAudioInterfaceIntern::timerCallbackB() { } } -int TownsAudioInterfaceIntern::intf_reset(va_list &args) { +int TownsAudioInterfaceInternal::intf_reset(va_list &args) { fmReset(); pcmReset(); callback(68); return 0; } -int TownsAudioInterfaceIntern::intf_keyOn(va_list &args) { +int TownsAudioInterfaceInternal::intf_keyOn(va_list &args) { int chan = va_arg(args, int); int note = va_arg(args, int); int velo = va_arg(args, int); return (chan & 0x40) ? pcmKeyOn(chan, note, velo) : fmKeyOn(chan, note, velo); } -int TownsAudioInterfaceIntern::intf_keyOff(va_list &args) { +int TownsAudioInterfaceInternal::intf_keyOff(va_list &args) { int chan = va_arg(args, int); return (chan & 0x40) ? pcmKeyOff(chan) : fmKeyOff(chan); } -int TownsAudioInterfaceIntern::intf_setPanPos(va_list &args) { +int TownsAudioInterfaceInternal::intf_setPanPos(va_list &args) { int chan = va_arg(args, int); int mode = va_arg(args, int); return (chan & 0x40) ? pcmSetPanPos(chan, mode) : fmSetPanPos(chan, mode); } -int TownsAudioInterfaceIntern::intf_setInstrument(va_list &args) { +int TownsAudioInterfaceInternal::intf_setInstrument(va_list &args) { int chan = va_arg(args, int); int instrId = va_arg(args, int); return (chan & 0x40) ? pcmSetInstrument(chan, instrId) : fmSetInstrument(chan, instrId); } -int TownsAudioInterfaceIntern::intf_loadInstrument(va_list &args) { +int TownsAudioInterfaceInternal::intf_loadInstrument(va_list &args) { int chanType = va_arg(args, int); int instrId = va_arg(args, int); uint8 *instrData = va_arg(args, uint8 *); return (chanType & 0x40) ? pcmLoadInstrument(instrId, instrData) : fmLoadInstrument(instrId, instrData); } -int TownsAudioInterfaceIntern::intf_setPitch(va_list &args) { +int TownsAudioInterfaceInternal::intf_setPitch(va_list &args) { int chan = va_arg(args, int); int16 pitch = (int16)(va_arg(args, int) & 0xffff); return (chan & 0x40) ? pcmSetPitch(chan, pitch) : fmSetPitch(chan, pitch); } -int TownsAudioInterfaceIntern::intf_setLevel(va_list &args) { +int TownsAudioInterfaceInternal::intf_setLevel(va_list &args) { int chan = va_arg(args, int); int lvl = va_arg(args, int); return (chan & 0x40) ? pcmSetLevel(chan, lvl) : fmSetLevel(chan, lvl); } -int TownsAudioInterfaceIntern::intf_chanOff(va_list &args) { +int TownsAudioInterfaceInternal::intf_chanOff(va_list &args) { int chan = va_arg(args, int); return (chan & 0x40) ? pcmChanOff(chan) : fmChanOff(chan); } -int TownsAudioInterfaceIntern::intf_writeReg(va_list &args) { +int TownsAudioInterfaceInternal::intf_writeReg(va_list &args) { int part = va_arg(args, int) ? 1 : 0; int reg = va_arg(args, int); int val = va_arg(args, int); @@ -630,7 +632,7 @@ int TownsAudioInterfaceIntern::intf_writeReg(va_list &args) { return 0; } -int TownsAudioInterfaceIntern::intf_writeRegBuffer(va_list &args) { +int TownsAudioInterfaceInternal::intf_writeRegBuffer(va_list &args) { int part = va_arg(args, int) ? 1 : 0; int reg = va_arg(args, int); int val = va_arg(args, int); @@ -642,7 +644,7 @@ int TownsAudioInterfaceIntern::intf_writeRegBuffer(va_list &args) { return 0; } -int TownsAudioInterfaceIntern::intf_readRegBuffer(va_list &args) { +int TownsAudioInterfaceInternal::intf_readRegBuffer(va_list &args) { int part = va_arg(args, int) ? 1 : 0; int reg = va_arg(args, int); uint8 *dst = va_arg(args, uint8 *); @@ -655,7 +657,7 @@ int TownsAudioInterfaceIntern::intf_readRegBuffer(va_list &args) { return 0; } -int TownsAudioInterfaceIntern::intf_setTimerA(va_list &args) { +int TownsAudioInterfaceInternal::intf_setTimerA(va_list &args) { int enable = va_arg(args, int); int tempo = va_arg(args, int); @@ -670,7 +672,7 @@ int TownsAudioInterfaceIntern::intf_setTimerA(va_list &args) { return 0; } -int TownsAudioInterfaceIntern::intf_setTimerB(va_list &args) { +int TownsAudioInterfaceInternal::intf_setTimerB(va_list &args) { int enable = va_arg(args, int); int tempo = va_arg(args, int); @@ -684,17 +686,17 @@ int TownsAudioInterfaceIntern::intf_setTimerB(va_list &args) { return 0; } -int TownsAudioInterfaceIntern::intf_enableTimerA(va_list &args) { +int TownsAudioInterfaceInternal::intf_enableTimerA(va_list &args) { bufferedWriteReg(0, 0x27, _fmSaveReg[0][0x27] | 0x15); return 0; } -int TownsAudioInterfaceIntern::intf_enableTimerB(va_list &args) { +int TownsAudioInterfaceInternal::intf_enableTimerB(va_list &args) { bufferedWriteReg(0, 0x27, _fmSaveReg[0][0x27] | 0x2a); return 0; } -int TownsAudioInterfaceIntern::intf_loadSamples(va_list &args) { +int TownsAudioInterfaceInternal::intf_loadSamples(va_list &args) { uint32 dest = va_arg(args, uint32); int size = va_arg(args, int); uint8 *src = va_arg(args, uint8*); @@ -717,7 +719,7 @@ int TownsAudioInterfaceIntern::intf_loadSamples(va_list &args) { return 0; } -int TownsAudioInterfaceIntern::intf_reserveEffectChannels(va_list &args) { +int TownsAudioInterfaceInternal::intf_reserveEffectChannels(va_list &args) { int numChan = va_arg(args, int); if (numChan > 8) return 3; @@ -749,7 +751,7 @@ int TownsAudioInterfaceIntern::intf_reserveEffectChannels(va_list &args) { return 0; } -int TownsAudioInterfaceIntern::intf_loadWaveTable(va_list &args) { +int TownsAudioInterfaceInternal::intf_loadWaveTable(va_list &args) { uint8 *data = va_arg(args, uint8 *); if (_numWaveTables > 127) return 3; @@ -776,7 +778,7 @@ int TownsAudioInterfaceIntern::intf_loadWaveTable(va_list &args) { return 0; } -int TownsAudioInterfaceIntern::intf_unloadWaveTable(va_list &args) { +int TownsAudioInterfaceInternal::intf_unloadWaveTable(va_list &args) { int id = va_arg(args, int); if (id == -1) { @@ -803,7 +805,7 @@ int TownsAudioInterfaceIntern::intf_unloadWaveTable(va_list &args) { return 0; } -int TownsAudioInterfaceIntern::intf_pcmPlayEffect(va_list &args) { +int TownsAudioInterfaceInternal::intf_pcmPlayEffect(va_list &args) { int chan = va_arg(args, int); int note = va_arg(args, int); int velo = va_arg(args, int); @@ -853,13 +855,13 @@ int TownsAudioInterfaceIntern::intf_pcmPlayEffect(va_list &args) { return 0; } -int TownsAudioInterfaceIntern::intf_pcmChanOff(va_list &args) { +int TownsAudioInterfaceInternal::intf_pcmChanOff(va_list &args) { int chan = va_arg(args, int); pcmChanOff(chan); return 0; } -int TownsAudioInterfaceIntern::intf_pcmEffectPlaying(va_list &args) { +int TownsAudioInterfaceInternal::intf_pcmEffectPlaying(va_list &args) { int chan = va_arg(args, int); if (chan < 0x40 || chan > 0x47) return 1; @@ -867,54 +869,54 @@ int TownsAudioInterfaceIntern::intf_pcmEffectPlaying(va_list &args) { return (_pcmChanEffectPlaying & _chanFlags[chan]) ? 1 : 0; } -int TownsAudioInterfaceIntern::intf_fmKeyOn(va_list &args) { +int TownsAudioInterfaceInternal::intf_fmKeyOn(va_list &args) { int chan = va_arg(args, int); int note = va_arg(args, int); int velo = va_arg(args, int); return fmKeyOn(chan, note, velo); } -int TownsAudioInterfaceIntern::intf_fmKeyOff(va_list &args) { +int TownsAudioInterfaceInternal::intf_fmKeyOff(va_list &args) { int chan = va_arg(args, int); return fmKeyOff(chan); } -int TownsAudioInterfaceIntern::intf_fmSetPanPos(va_list &args) { +int TownsAudioInterfaceInternal::intf_fmSetPanPos(va_list &args) { int chan = va_arg(args, int); int mode = va_arg(args, int); return fmSetPanPos(chan, mode); } -int TownsAudioInterfaceIntern::intf_fmSetInstrument(va_list &args) { +int TownsAudioInterfaceInternal::intf_fmSetInstrument(va_list &args) { int chan = va_arg(args, int); int instrId = va_arg(args, int); return fmSetInstrument(chan, instrId); } -int TownsAudioInterfaceIntern::intf_fmLoadInstrument(va_list &args) { +int TownsAudioInterfaceInternal::intf_fmLoadInstrument(va_list &args) { int instrId = va_arg(args, int); uint8 *instrData = va_arg(args, uint8 *); return fmLoadInstrument(instrId, instrData); } -int TownsAudioInterfaceIntern::intf_fmSetPitch(va_list &args) { +int TownsAudioInterfaceInternal::intf_fmSetPitch(va_list &args) { int chan = va_arg(args, int); uint16 freq = va_arg(args, int) & 0xffff; return fmSetPitch(chan, freq); } -int TownsAudioInterfaceIntern::intf_fmSetLevel(va_list &args) { +int TownsAudioInterfaceInternal::intf_fmSetLevel(va_list &args) { int chan = va_arg(args, int); int lvl = va_arg(args, int); return fmSetLevel(chan, lvl); } -int TownsAudioInterfaceIntern::intf_fmReset(va_list &args) { +int TownsAudioInterfaceInternal::intf_fmReset(va_list &args) { fmReset(); return 0; } -int TownsAudioInterfaceIntern::intf_setOutputVolume(va_list &args) { +int TownsAudioInterfaceInternal::intf_setOutputVolume(va_list &args) { int chanType = va_arg(args, int); int left = va_arg(args, int); int right = va_arg(args, int); @@ -951,14 +953,14 @@ int TownsAudioInterfaceIntern::intf_setOutputVolume(va_list &args) { return 0; } -int TownsAudioInterfaceIntern::intf_resetOutputVolume(va_list &args) { +int TownsAudioInterfaceInternal::intf_resetOutputVolume(va_list &args) { memset(_outputLevel, 0, sizeof(_outputLevel)); _outputVolumeFlags = 0; updateOutputVolume(); return 0; } -int TownsAudioInterfaceIntern::intf_getOutputVolume(va_list &args) { +int TownsAudioInterfaceInternal::intf_getOutputVolume(va_list &args) { int chanType = va_arg(args, int); int *left = va_arg(args, int*); int *right = va_arg(args, int*); @@ -978,7 +980,7 @@ int TownsAudioInterfaceIntern::intf_getOutputVolume(va_list &args) { return 0; } -int TownsAudioInterfaceIntern::intf_setOutputMute(va_list &args) { +int TownsAudioInterfaceInternal::intf_setOutputMute(va_list &args) { int flags = va_arg(args, int); _outputVolumeFlags = flags; uint8 mute = flags & 3; @@ -1007,31 +1009,31 @@ int TownsAudioInterfaceIntern::intf_setOutputMute(va_list &args) { return 0; } -int TownsAudioInterfaceIntern::intf_cdaToggle(va_list &args) { +int TownsAudioInterfaceInternal::intf_cdaToggle(va_list &args) { //int mode = va_arg(args, int); //_unkMask = mode ? 0x7f : 0x3f; return 0; } -int TownsAudioInterfaceIntern::intf_getOutputVolume2(va_list &args) { +int TownsAudioInterfaceInternal::intf_getOutputVolume2(va_list &args) { return 0; } -int TownsAudioInterfaceIntern::intf_getOutputMute (va_list &args) { +int TownsAudioInterfaceInternal::intf_getOutputMute (va_list &args) { return 0; } -int TownsAudioInterfaceIntern::intf_pcmUpdateEnvelopeGenerator(va_list &args) { +int TownsAudioInterfaceInternal::intf_pcmUpdateEnvelopeGenerator(va_list &args) { for (int i = 0; i < 8; i++) pcmUpdateEnvelopeGenerator(i); return 0; } -int TownsAudioInterfaceIntern::intf_notImpl(va_list &args) { +int TownsAudioInterfaceInternal::intf_notImpl(va_list &args) { return 4; } -void TownsAudioInterfaceIntern::fmReset() { +void TownsAudioInterfaceInternal::fmReset() { TownsPC98_FmSynth::reset(); _fmChanPlaying = 0; @@ -1059,7 +1061,7 @@ void TownsAudioInterfaceIntern::fmReset() { } } -int TownsAudioInterfaceIntern::fmKeyOn(int chan, int note, int velo) { +int TownsAudioInterfaceInternal::fmKeyOn(int chan, int note, int velo) { if (chan > 5) return 1; if (note < 12 || note > 107 || (velo & 0x80)) @@ -1139,7 +1141,7 @@ int TownsAudioInterfaceIntern::fmKeyOn(int chan, int note, int velo) { return 0; } -int TownsAudioInterfaceIntern::fmKeyOff(int chan) { +int TownsAudioInterfaceInternal::fmKeyOff(int chan) { if (chan > 5) return 1; _fmChanPlaying &= ~_chanFlags[chan]; @@ -1149,7 +1151,7 @@ int TownsAudioInterfaceIntern::fmKeyOff(int chan) { return 0; } -int TownsAudioInterfaceIntern::fmChanOff(int chan) { +int TownsAudioInterfaceInternal::fmChanOff(int chan) { if (chan > 5) return 1; _fmChanPlaying &= ~_chanFlags[chan]; @@ -1167,7 +1169,7 @@ int TownsAudioInterfaceIntern::fmChanOff(int chan) { return 0; } -int TownsAudioInterfaceIntern::fmSetPanPos(int chan, int value) { +int TownsAudioInterfaceInternal::fmSetPanPos(int chan, int value) { if (chan > 5) return 1; @@ -1186,7 +1188,7 @@ int TownsAudioInterfaceIntern::fmSetPanPos(int chan, int value) { return 0; } -int TownsAudioInterfaceIntern::fmSetInstrument(int chan, int instrId) { +int TownsAudioInterfaceInternal::fmSetInstrument(int chan, int instrId) { if (chan > 5) return 1; if (instrId > 127) @@ -1230,7 +1232,7 @@ int TownsAudioInterfaceIntern::fmSetInstrument(int chan, int instrId) { return 0; } -int TownsAudioInterfaceIntern::fmLoadInstrument(int instrId, const uint8 *data) { +int TownsAudioInterfaceInternal::fmLoadInstrument(int instrId, const uint8 *data) { if (instrId > 127) return 3; assert(data); @@ -1238,7 +1240,7 @@ int TownsAudioInterfaceIntern::fmLoadInstrument(int instrId, const uint8 *data) return 0; } -int TownsAudioInterfaceIntern::fmSetPitch(int chan, int pitch) { +int TownsAudioInterfaceInternal::fmSetPitch(int chan, int pitch) { if (chan > 5) return 1; @@ -1325,7 +1327,7 @@ int TownsAudioInterfaceIntern::fmSetPitch(int chan, int pitch) { return 0; } -int TownsAudioInterfaceIntern::fmSetLevel(int chan, int lvl) { +int TownsAudioInterfaceInternal::fmSetLevel(int chan, int lvl) { if (chan > 5) return 1; if (lvl > 127) @@ -1348,12 +1350,12 @@ int TownsAudioInterfaceIntern::fmSetLevel(int chan, int lvl) { return 0; } -void TownsAudioInterfaceIntern::bufferedWriteReg(uint8 part, uint8 regAddress, uint8 value) { +void TownsAudioInterfaceInternal::bufferedWriteReg(uint8 part, uint8 regAddress, uint8 value) { _fmSaveReg[part][regAddress] = value; writeReg(part, regAddress, value); } -void TownsAudioInterfaceIntern::pcmReset() { +void TownsAudioInterfaceInternal::pcmReset() { _pcmChanOut = 0; _pcmChanReserved = _pcmChanKeyPressed = _pcmChanEffectPlaying = _pcmChanKeyPlaying = 0; _numReservedChannels = 0; @@ -1381,7 +1383,7 @@ void TownsAudioInterfaceIntern::pcmReset() { } } -int TownsAudioInterfaceIntern::pcmKeyOn(int chan, int note, int velo) { +int TownsAudioInterfaceInternal::pcmKeyOn(int chan, int note, int velo) { if (chan < 0x40 || chan > 0x47) return 1; @@ -1452,7 +1454,7 @@ int TownsAudioInterfaceIntern::pcmKeyOn(int chan, int note, int velo) { return 0; } -int TownsAudioInterfaceIntern::pcmKeyOff(int chan) { +int TownsAudioInterfaceInternal::pcmKeyOff(int chan) { if (chan < 0x40 || chan > 0x47) return 1; @@ -1462,7 +1464,7 @@ int TownsAudioInterfaceIntern::pcmKeyOff(int chan) { return 0; } -int TownsAudioInterfaceIntern::pcmChanOff(int chan) { +int TownsAudioInterfaceInternal::pcmChanOff(int chan) { if (chan < 0x40 || chan > 0x47) return 1; @@ -1476,7 +1478,7 @@ int TownsAudioInterfaceIntern::pcmChanOff(int chan) { return 0; } -int TownsAudioInterfaceIntern::pcmSetPanPos(int chan, int mode) { +int TownsAudioInterfaceInternal::pcmSetPanPos(int chan, int mode) { if (chan > 0x47) return 1; if (mode & 0x80) @@ -1499,7 +1501,7 @@ int TownsAudioInterfaceIntern::pcmSetPanPos(int chan, int mode) { return 0; } -int TownsAudioInterfaceIntern::pcmSetInstrument(int chan, int instrId) { +int TownsAudioInterfaceInternal::pcmSetInstrument(int chan, int instrId) { if (chan > 0x47) return 1; if (instrId > 31) @@ -1509,7 +1511,7 @@ int TownsAudioInterfaceIntern::pcmSetInstrument(int chan, int instrId) { return 0; } -int TownsAudioInterfaceIntern::pcmLoadInstrument(int instrId, const uint8 *data) { +int TownsAudioInterfaceInternal::pcmLoadInstrument(int instrId, const uint8 *data) { if (instrId > 31) return 3; assert(data); @@ -1517,7 +1519,7 @@ int TownsAudioInterfaceIntern::pcmLoadInstrument(int instrId, const uint8 *data) return 0; } -int TownsAudioInterfaceIntern::pcmSetPitch(int chan, int pitch) { +int TownsAudioInterfaceInternal::pcmSetPitch(int chan, int pitch) { if (chan > 0x47) return 1; @@ -1547,7 +1549,7 @@ int TownsAudioInterfaceIntern::pcmSetPitch(int chan, int pitch) { return 0; } -int TownsAudioInterfaceIntern::pcmSetLevel(int chan, int lvl) { +int TownsAudioInterfaceInternal::pcmSetLevel(int chan, int lvl) { if (chan > 0x47) return 1; @@ -1576,7 +1578,7 @@ int TownsAudioInterfaceIntern::pcmSetLevel(int chan, int lvl) { return 0; } -void TownsAudioInterfaceIntern::pcmUpdateEnvelopeGenerator(int chan) { +void TownsAudioInterfaceInternal::pcmUpdateEnvelopeGenerator(int chan) { TownsAudio_PcmChannel *p = &_pcmChan[chan]; if (!p->envCurrentLevel) { _pcmChanKeyPlaying &= ~_chanFlags[chan]; @@ -1618,7 +1620,7 @@ void TownsAudioInterfaceIntern::pcmUpdateEnvelopeGenerator(int chan) { p->velo = (p->envCurrentLevel >> 8) << 1; } -void TownsAudioInterfaceIntern::pcmCalcPhaseStep(TownsAudio_PcmChannel *p, TownsAudio_WaveTable *w) { +void TownsAudioInterfaceInternal::pcmCalcPhaseStep(TownsAudio_PcmChannel *p, TownsAudio_WaveTable *w) { int8 diff = p->note - w->baseNote; uint16 r = w->rate + w->rateOffs; uint16 bl = 0; @@ -1647,7 +1649,16 @@ void TownsAudioInterfaceIntern::pcmCalcPhaseStep(TownsAudio_PcmChannel *p, Towns p->step = (s * p->stepPitch) >> 14; } -void TownsAudioInterfaceIntern::updateOutputVolume() { +void TownsAudioInterfaceInternal::updateOutputVolume() { + // Avoid calls to g_system->getAudioCDManager() functions from the main thread + // since this can cause mutex lockups. + _updateOutputVol = true; +} + +void TownsAudioInterfaceInternal::updateOutputVolumeInternal() { + if (!_ready) + return; + // FM Towns seems to support volumes of 0 - 63 for each channel. // We recalculate sane values for our 0 to 255 volume range and // balance values for our -128 to 127 volume range @@ -1658,38 +1669,41 @@ void TownsAudioInterfaceIntern::updateOutputVolume() { int volume = (int)(((float)(maxVol * 255) / 63.0f)); int balance = maxVol ? (int)( ( ((int)_outputLevel[13] * (_outputMute[13] ^ 1) - _outputLevel[12] * (_outputMute[12] ^ 1)) * 127) / (float)maxVol) : 0; + Common::StackLock lock(_mutex); g_system->getAudioCDManager()->setVolume(volume); g_system->getAudioCDManager()->setBalance(balance); + + _updateOutputVol = false; } -TownsAudioInterfaceIntern *TownsAudioInterfaceIntern::_refInstance = 0; +TownsAudioInterfaceInternal *TownsAudioInterfaceInternal::_refInstance = 0; -int TownsAudioInterfaceIntern::_refCount = 0; +int TownsAudioInterfaceInternal::_refCount = 0; -const uint8 TownsAudioInterfaceIntern::_chanFlags[] = { +const uint8 TownsAudioInterfaceInternal::_chanFlags[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 }; -const uint16 TownsAudioInterfaceIntern::_frequency[] = { +const uint16 TownsAudioInterfaceInternal::_frequency[] = { 0x028C, 0x02B4, 0x02DC, 0x030A, 0x0338, 0x0368, 0x039C, 0x03D4, 0x040E, 0x044A, 0x048C, 0x04D0 }; -const uint8 TownsAudioInterfaceIntern::_carrier[] = { +const uint8 TownsAudioInterfaceInternal::_carrier[] = { 0x10, 0x10, 0x10, 0x10, 0x30, 0x70, 0x70, 0xF0 }; -const uint8 TownsAudioInterfaceIntern::_fmDefaultInstrument[] = { +const uint8 TownsAudioInterfaceInternal::_fmDefaultInstrument[] = { 0x45, 0x4C, 0x45, 0x50, 0x49, 0x41, 0x4E, 0x4F, 0x01, 0x0A, 0x02, 0x01, 0x1E, 0x32, 0x05, 0x00, 0x9C, 0xDC, 0x9C, 0xDC, 0x07, 0x03, 0x14, 0x08, 0x00, 0x03, 0x05, 0x05, 0x55, 0x45, 0x27, 0xA7, 0x04, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -const uint16 TownsAudioInterfaceIntern::_pcmPhase1[] = { +const uint16 TownsAudioInterfaceInternal::_pcmPhase1[] = { 0x879B, 0x0F37, 0x1F58, 0x306E, 0x4288, 0x55B6, 0x6A08, 0x7F8F, 0x965E, 0xAE88, 0xC882, 0xE341 }; -const uint16 TownsAudioInterfaceIntern::_pcmPhase2[] = { +const uint16 TownsAudioInterfaceInternal::_pcmPhase2[] = { 0xFEFE, 0xF1A0, 0xE411, 0xD744, 0xCB2F, 0xBFC7, 0xB504, 0xAAE2, 0xA144, 0x9827, 0x8FAC }; @@ -1841,11 +1855,11 @@ void TownsAudio_WaveTable::clear() { } TownsAudioInterface::TownsAudioInterface(Audio::Mixer *mixer, TownsAudioInterfacePluginDriver *driver) { - _intf = TownsAudioInterfaceIntern::addNewRef(mixer, driver); + _intf = TownsAudioInterfaceInternal::addNewRef(mixer, driver); } TownsAudioInterface::~TownsAudioInterface() { - TownsAudioInterfaceIntern::releaseRef(); + TownsAudioInterfaceInternal::releaseRef(); _intf = 0; } @@ -1874,3 +1888,11 @@ void TownsAudioInterface::setSoundEffectVolume(int volume) { void TownsAudioInterface::setSoundEffectChanMask(int mask) { _intf->setSoundEffectChanMask(mask); } + +void TownsAudioInterface::lockInternal() { + _intf->lock(); +} + +void TownsAudioInterface::unlockInternal() { + _intf->unlock(); +} diff --git a/audio/softsynth/fmtowns_pc98/towns_audio.h b/audio/softsynth/fmtowns_pc98/towns_audio.h index 2c58d46d06..b00243f610 100644 --- a/audio/softsynth/fmtowns_pc98/towns_audio.h +++ b/audio/softsynth/fmtowns_pc98/towns_audio.h @@ -25,7 +25,7 @@ #include "audio/mixer.h" -class TownsAudioInterfaceIntern; +class TownsAudioInterfaceInternal; class TownsAudioInterfacePluginDriver { public: @@ -48,8 +48,15 @@ public: // The first 6 bits are the 6 fm channels. The next 8 bits are pcm channels. void setSoundEffectChanMask(int mask); + // These methods should not be needed in standard situations, since the mutex + // is handled internally. However, they may be required to avoid lockup situations + // if the code using this class has a mutex of its own (example for a lockup + // situation: imuse.cpp, line 78). + void lockInternal(); + void unlockInternal(); + private: - TownsAudioInterfaceIntern *_intf; + TownsAudioInterfaceInternal *_intf; }; #endif diff --git a/audio/softsynth/fmtowns_pc98/towns_midi.cpp b/audio/softsynth/fmtowns_pc98/towns_midi.cpp index 3c7ce7d0e4..00f0d43b98 100644 --- a/audio/softsynth/fmtowns_pc98/towns_midi.cpp +++ b/audio/softsynth/fmtowns_pc98/towns_midi.cpp @@ -835,19 +835,6 @@ const uint8 TownsMidiInputChannel::_programAdjustLevel[] = { MidiDriver_TOWNS::MidiDriver_TOWNS(Audio::Mixer *mixer) : _timerProc(0), _timerProcPara(0), _channels(0), _out(0), _chanState(0), _operatorLevelTable(0), _tickCounter1(0), _tickCounter2(0), _rand(1), _allocCurPos(0), _isOpen(false) { _intf = new TownsAudioInterface(mixer, this); -} - -MidiDriver_TOWNS::~MidiDriver_TOWNS() { - close(); - delete _intf; -} - -int MidiDriver_TOWNS::open() { - if (_isOpen) - return MERR_ALREADY_OPEN; - - if (!_intf->init()) - return MERR_CANNOT_CONNECT; _channels = new TownsMidiInputChannel*[32]; for (int i = 0; i < 32; i++) @@ -866,6 +853,38 @@ int MidiDriver_TOWNS::open() { } for (int i = 0; i < 64; i++) _operatorLevelTable[i << 5] = 0; +} + +MidiDriver_TOWNS::~MidiDriver_TOWNS() { + close(); + delete _intf; + + if (_channels) { + for (int i = 0; i < 32; i++) + delete _channels[i]; + delete[] _channels; + } + _channels = 0; + + if (_out) { + for (int i = 0; i < 6; i++) + delete _out[i]; + delete[] _out; + } + _out = 0; + + delete[] _chanState; + _chanState = 0; + delete[] _operatorLevelTable; + _operatorLevelTable = 0; +} + +int MidiDriver_TOWNS::open() { + if (_isOpen) + return MERR_ALREADY_OPEN; + + if (!_intf->init()) + return MERR_CANNOT_CONNECT; _intf->callback(0); @@ -876,9 +895,7 @@ int MidiDriver_TOWNS::open() { _intf->callback(33, 8); _intf->setSoundEffectChanMask(~0x3f); - _tickCounter1 = _tickCounter2 = 0; - _allocCurPos = 0; - _rand = 1; + _allocCurPos = 0; _isOpen = true; @@ -893,25 +910,6 @@ void MidiDriver_TOWNS::close() { setTimerCallback(0, 0); g_system->delayMillis(20); - - if (_channels) { - for (int i = 0; i < 32; i++) - delete _channels[i]; - delete[] _channels; - } - _channels = 0; - - if (_out) { - for (int i = 0; i < 6; i++) - delete _out[i]; - delete[] _out; - } - _out = 0; - - delete[] _chanState; - _chanState = 0; - delete[] _operatorLevelTable; - _operatorLevelTable = 0; } void MidiDriver_TOWNS::send(uint32 b) { diff --git a/audio/softsynth/fmtowns_pc98/towns_pc98_driver.cpp b/audio/softsynth/fmtowns_pc98/towns_pc98_driver.cpp index e35da91cbb..ee20068e74 100644 --- a/audio/softsynth/fmtowns_pc98/towns_pc98_driver.cpp +++ b/audio/softsynth/fmtowns_pc98/towns_pc98_driver.cpp @@ -1145,7 +1145,7 @@ void TownsPC98_AudioDriver::loadMusicData(uint8 *data, bool loadPaused) { reset(); - lock(); + Common::StackLock lock(_mutex); uint8 *src_a = _trackPtr = _musicBuffer = data; for (uint8 i = 0; i < 3; i++) { @@ -1176,7 +1176,6 @@ void TownsPC98_AudioDriver::loadMusicData(uint8 *data, bool loadPaused) { _finishedChannelsFlag = _finishedSSGFlag = _finishedRhythmFlag = 0; _musicPlaying = (loadPaused ? false : true); - unlock(); } void TownsPC98_AudioDriver::loadSoundEffectData(uint8 *data, uint8 trackNum) { @@ -1195,17 +1194,16 @@ void TownsPC98_AudioDriver::loadSoundEffectData(uint8 *data, uint8 trackNum) { return; } - lock(); + Common::StackLock lock(_mutex); _sfxData = _sfxBuffer = data; _sfxOffsets[0] = READ_LE_UINT16(&_sfxData[(trackNum << 2)]); _sfxOffsets[1] = READ_LE_UINT16(&_sfxData[(trackNum << 2) + 2]); _sfxPlaying = true; _finishedSfxFlag = 0; - unlock(); } void TownsPC98_AudioDriver::reset() { - lock(); + Common::StackLock lock(_mutex); _musicPlaying = false; _sfxPlaying = false; @@ -1232,7 +1230,6 @@ void TownsPC98_AudioDriver::reset() { if (_rhythmChannel) _rhythmChannel->reset(); #endif - unlock(); } void TownsPC98_AudioDriver::fadeStep() { @@ -1263,37 +1260,30 @@ void TownsPC98_AudioDriver::fadeStep() { } } -void TownsPC98_AudioDriver::timerCallbackB() { - _sfxOffs = 0; - - if (_musicPlaying) { - _musicTickCounter++; - - for (int i = 0; i < _numChan; i++) { - if (_updateChannelsFlag & _channels[i]->_idFlag) { - _channels[i]->processEvents(); - _channels[i]->processFrequency(); - } - } +void TownsPC98_AudioDriver::pause() { + _musicPlaying = false; +} + +void TownsPC98_AudioDriver::cont() { + _musicPlaying = true; +} - for (int i = 0; i < _numSSG; i++) { - if (_updateSSGFlag & _ssgChannels[i]->_idFlag) { - _ssgChannels[i]->processEvents(); - _ssgChannels[i]->processFrequency(); - } - } +bool TownsPC98_AudioDriver::looping() { + return _looping == _updateChannelsFlag ? true : false; +} -#ifndef DISABLE_PC98_RHYTHM_CHANNEL - if (_hasPercussion) - if (_updateRhythmFlag & _rhythmChannel->_idFlag) - _rhythmChannel->processEvents(); -#endif - } +bool TownsPC98_AudioDriver::musicPlaying() { + return _musicPlaying; +} - toggleRegProtection(false); +void TownsPC98_AudioDriver::setMusicVolume(int volume) { + _musicVolume = volume; + setVolumeIntern(_musicVolume, _sfxVolume); +} - if (_finishedChannelsFlag == _updateChannelsFlag && _finishedSSGFlag == _updateSSGFlag && _finishedRhythmFlag == _updateRhythmFlag) - _musicPlaying = false; +void TownsPC98_AudioDriver::setSoundEffectVolume(int volume) { + _sfxVolume = volume; + setVolumeIntern(_musicVolume, _sfxVolume); } void TownsPC98_AudioDriver::timerCallbackA() { @@ -1321,15 +1311,37 @@ void TownsPC98_AudioDriver::timerCallbackA() { } } -void TownsPC98_AudioDriver::setMusicTempo(uint8 tempo) { - writeReg(0, 0x26, tempo); - writeReg(0, 0x27, 0x33); -} +void TownsPC98_AudioDriver::timerCallbackB() { + _sfxOffs = 0; -void TownsPC98_AudioDriver::setSfxTempo(uint16 tempo) { - writeReg(0, 0x24, tempo & 0xff); - writeReg(0, 0x25, tempo >> 8); - writeReg(0, 0x27, 0x33); + if (_musicPlaying) { + _musicTickCounter++; + + for (int i = 0; i < _numChan; i++) { + if (_updateChannelsFlag & _channels[i]->_idFlag) { + _channels[i]->processEvents(); + _channels[i]->processFrequency(); + } + } + + for (int i = 0; i < _numSSG; i++) { + if (_updateSSGFlag & _ssgChannels[i]->_idFlag) { + _ssgChannels[i]->processEvents(); + _ssgChannels[i]->processFrequency(); + } + } + +#ifndef DISABLE_PC98_RHYTHM_CHANNEL + if (_hasPercussion) + if (_updateRhythmFlag & _rhythmChannel->_idFlag) + _rhythmChannel->processEvents(); +#endif + } + + toggleRegProtection(false); + + if (_finishedChannelsFlag == _updateChannelsFlag && _finishedSSGFlag == _updateSSGFlag && _finishedRhythmFlag == _updateRhythmFlag) + _musicPlaying = false; } void TownsPC98_AudioDriver::startSoundEffect() { @@ -1352,6 +1364,16 @@ void TownsPC98_AudioDriver::startSoundEffect() { _sfxData = 0; } +void TownsPC98_AudioDriver::setMusicTempo(uint8 tempo) { + writeReg(0, 0x26, tempo); + writeReg(0, 0x27, 0x33); +} + +void TownsPC98_AudioDriver::setSfxTempo(uint16 tempo) { + writeReg(0, 0x24, tempo & 0xff); + writeReg(0, 0x25, tempo >> 8); + writeReg(0, 0x27, 0x33); +} const uint8 TownsPC98_AudioDriver::_drvTables[] = { // channel presets 0x00, 0x80, 0x00, 0x00, 0x00, 0x01, diff --git a/audio/softsynth/fmtowns_pc98/towns_pc98_driver.h b/audio/softsynth/fmtowns_pc98/towns_pc98_driver.h index 46ee23895b..ff58482227 100644 --- a/audio/softsynth/fmtowns_pc98/towns_pc98_driver.h +++ b/audio/softsynth/fmtowns_pc98/towns_pc98_driver.h @@ -50,33 +50,19 @@ public: void fadeStep(); - void pause() { - _musicPlaying = false; - } - void cont() { - _musicPlaying = true; - } + void pause(); + void cont(); - void timerCallbackB(); + bool looping(); + bool musicPlaying(); + + void setMusicVolume(int volume); + void setSoundEffectVolume(int volume); + +private: void timerCallbackA(); + void timerCallbackB(); - bool looping() { - return _looping == _updateChannelsFlag ? true : false; - } - bool musicPlaying() { - return _musicPlaying; - } - - void setMusicVolume(int volume) { - _musicVolume = volume; - setVolumeIntern(_musicVolume, _sfxVolume); - } - void setSoundEffectVolume(int volume) { - _sfxVolume = volume; - setVolumeIntern(_musicVolume, _sfxVolume); - } - -protected: void startSoundEffect(); void setMusicTempo(uint8 tempo); diff --git a/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp b/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp index bc5aa32823..b09a9f65d1 100644 --- a/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp +++ b/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp @@ -861,7 +861,7 @@ TownsPC98_FmSynth::TownsPC98_FmSynth(Audio::Mixer *mixer, EmuType type) : _hasPercussion(type == kType86 ? true : false), _oprRates(0), _oprRateshift(0), _oprAttackDecay(0), _oprFrq(0), _oprSinTbl(0), _oprLevelOut(0), _oprDetune(0), _rtt(type == kTypeTowns ? 0x514767 : 0x5B8D80), _baserate(55125.0f / (float)mixer->getOutputRate()), - _volMaskA(0), _volMaskB(0), _volumeA(255), _volumeB(255), _regProtectionFlag(false), _lock(0), _ready(false) { + _volMaskA(0), _volMaskB(0), _volumeA(255), _volumeB(255), _regProtectionFlag(false), _ready(false) { memset(&_timers[0], 0, sizeof(ChipTimer)); memset(&_timers[1], 0, sizeof(ChipTimer)); @@ -928,7 +928,7 @@ bool TownsPC98_FmSynth::init() { } void TownsPC98_FmSynth::reset() { - lock(); + Common::StackLock lock(_mutex); for (int i = 0; i < _numChan; i++) { for (int ii = 0; ii < 4; ii++) _chanInternal[i].opr[ii]->reset(); @@ -948,14 +948,13 @@ void TownsPC98_FmSynth::reset() { if (_prc) _prc->reset(); #endif - unlock(); } void TownsPC98_FmSynth::writeReg(uint8 part, uint8 regAddress, uint8 value) { if (_regProtectionFlag || !_ready) return; - lock(); + Common::StackLock lock(_mutex); static const uint8 oprOrdr[] = { 0, 2, 1, 3 }; @@ -1137,7 +1136,6 @@ void TownsPC98_FmSynth::writeReg(uint8 part, uint8 regAddress, uint8 value) { default: warning("TownsPC98_FmSynth: UNKNOWN ADDRESS %d", regAddress); } - unlock(); } int TownsPC98_FmSynth::readBuffer(int16 *buffer, const int numSamples) { @@ -1146,9 +1144,14 @@ int TownsPC98_FmSynth::readBuffer(int16 *buffer, const int numSamples) { int32 *tmpStart = tmp; memset(tmp, 0, sizeof(int32) * numSamples); int32 samplesLeft = numSamples >> 1; - _lock |= 0x10000; - while (_ready && !(_lock & 0xffff) && samplesLeft) { + bool locked = false; + if (_ready) { + lock(); + locked = true; + } + + while (_ready && samplesLeft) { int32 render = samplesLeft; for (int i = 0; i < 2; i++) { @@ -1197,17 +1200,38 @@ int TownsPC98_FmSynth::readBuffer(int16 *buffer, const int numSamples) { tmp += (render << 1); } - _lock &= ~0x10000; + if (locked) + unlock(); + delete[] tmpStart; return numSamples; } +bool TownsPC98_FmSynth::isStereo() const { + return true; +} + +bool TownsPC98_FmSynth::endOfData() const { + return false; +} + +int TownsPC98_FmSynth::getRate() const { + return _mixer->getOutputRate(); +} + +void TownsPC98_FmSynth::lock() { + _mutex.lock(); +} + +void TownsPC98_FmSynth::unlock() { + _mutex.unlock(); +} + void TownsPC98_FmSynth::deinit() { _ready = false; - while (_lock) - g_system->delayMillis(20); _mixer->stopHandle(_soundHandle); + Common::StackLock lock(_mutex); _timers[0].cb = _timers[1].cb = &TownsPC98_FmSynth::idleTimerCallback; } @@ -1216,7 +1240,7 @@ uint8 TownsPC98_FmSynth::readSSGStatus() { } void TownsPC98_FmSynth::setVolumeIntern(int volA, int volB) { - lock(); + Common::StackLock lock(_mutex); _volumeA = CLIP(volA, 0, Audio::Mixer::kMaxMixerVolume); _volumeB = CLIP(volB, 0, Audio::Mixer::kMaxMixerVolume); if (_ssg) @@ -1225,11 +1249,10 @@ void TownsPC98_FmSynth::setVolumeIntern(int volA, int volB) { if (_prc) _prc->setVolumeIntern(_volumeA, _volumeB); #endif - unlock(); } void TownsPC98_FmSynth::setVolumeChannelMasks(int channelMaskA, int channelMaskB) { - lock(); + Common::StackLock lock(_mutex); _volMaskA = channelMaskA; _volMaskB = channelMaskB; if (_ssg) @@ -1238,17 +1261,6 @@ void TownsPC98_FmSynth::setVolumeChannelMasks(int channelMaskA, int channelMaskB if (_prc) _prc->setVolumeChannelMasks(_volMaskA >> (_numChan + _numSSG), _volMaskB >> (_numChan + _numSSG)); #endif - unlock(); -} - -void TownsPC98_FmSynth::lock() { - _mutex.lock(); - _lock++; -} - -void TownsPC98_FmSynth::unlock() { - _mutex.unlock(); - _lock--; } void TownsPC98_FmSynth::generateTables() { diff --git a/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h b/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h index f7bcc90585..a1b09abd3a 100644 --- a/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h +++ b/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h @@ -69,15 +69,12 @@ public: // AudioStream interface int readBuffer(int16 *buffer, const int numSamples); - bool isStereo() const { - return true; - } - bool endOfData() const { - return false; - } - int getRate() const { - return _mixer->getOutputRate(); - } + bool isStereo() const; + bool endOfData() const; + int getRate() const; + + void lock(); + void unlock(); protected: void deinit(); @@ -102,13 +99,12 @@ protected: void setVolumeIntern(int volA, int volB); void setVolumeChannelMasks(int channelMaskA, int channelMaskB); - void lock(); - void unlock(); - const int _numChan; const int _numSSG; const bool _hasPercussion; + Common::Mutex _mutex; + private: void generateTables(); void nextTick(int32 *buffer, uint32 bufferSize); @@ -182,9 +178,6 @@ private: Audio::Mixer *_mixer; Audio::SoundHandle _soundHandle; - int _lock; - Common::Mutex _mutex; - #ifndef DISABLE_PC98_RHYTHM_CHANNEL static const uint8 _percussionData[]; #endif -- cgit v1.2.3