aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--audio/softsynth/fmtowns_pc98/towns_audio.cpp228
-rw-r--r--audio/softsynth/fmtowns_pc98/towns_audio.h11
-rw-r--r--audio/softsynth/fmtowns_pc98/towns_midi.cpp68
-rw-r--r--audio/softsynth/fmtowns_pc98/towns_pc98_driver.cpp104
-rw-r--r--audio/softsynth/fmtowns_pc98/towns_pc98_driver.h34
-rw-r--r--audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp60
-rw-r--r--audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h23
-rw-r--r--engines/scumm/player_towns.cpp9
8 files changed, 290 insertions, 247 deletions
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<uint16>(volume, 0, Audio::Mixer::kMaxMixerVolume);
setVolumeIntern(_musicVolume, _sfxVolume);
}
-void TownsAudioInterfaceIntern::setSoundEffectVolume(int volume) {
+void TownsAudioInterfaceInternal::setSoundEffectVolume(int volume) {
_sfxVolume = CLIP<uint16>(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<uint16>(volA, 0, Audio::Mixer::kMaxMixerVolume);
_volumeB = CLIP<uint16>(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
diff --git a/engines/scumm/player_towns.cpp b/engines/scumm/player_towns.cpp
index 5d49478cb0..15b2f65797 100644
--- a/engines/scumm/player_towns.cpp
+++ b/engines/scumm/player_towns.cpp
@@ -581,11 +581,14 @@ Player_Towns_v2::Player_Towns_v2(ScummEngine *vm, Audio::Mixer *mixer, IMuse *im
}
Player_Towns_v2::~Player_Towns_v2() {
- delete _intf;
- _intf = 0;
-
+ // Avoid lockup in imuse.cpp, line 78
+ _intf->lockInternal();
if (_imuseDispose)
delete _imuse;
+ _intf->unlockInternal();
+
+ delete _intf;
+ _intf = 0;
delete[] _sblData;
delete[] _soundOverride;