aboutsummaryrefslogtreecommitdiff
path: root/audio/softsynth
diff options
context:
space:
mode:
authorathrxx2011-05-29 21:43:38 +0200
committerathrxx2011-05-30 01:48:59 +0200
commit7f8a69d6fc44ca5515a91f29ce5451c12f85daa5 (patch)
tree83c9b58bc64ee3769ec51bffdf27c3096fbd0c8e /audio/softsynth
parentaa78f068986a1db7cbffd1fd563fe1d8e16eb24e (diff)
downloadscummvm-rg350-7f8a69d6fc44ca5515a91f29ce5451c12f85daa5.tar.gz
scummvm-rg350-7f8a69d6fc44ca5515a91f29ce5451c12f85daa5.tar.bz2
scummvm-rg350-7f8a69d6fc44ca5515a91f29ce5451c12f85daa5.zip
FM-TOWNS AUDIO: fix destructors (thread safety)
Diffstat (limited to 'audio/softsynth')
-rw-r--r--audio/softsynth/fmtowns_pc98/towns_audio.cpp73
-rw-r--r--audio/softsynth/fmtowns_pc98/towns_pc98_driver.cpp2
-rw-r--r--audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp8
-rw-r--r--audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h8
4 files changed, 57 insertions, 34 deletions
diff --git a/audio/softsynth/fmtowns_pc98/towns_audio.cpp b/audio/softsynth/fmtowns_pc98/towns_audio.cpp
index 42a8252d53..efc9f9fb62 100644
--- a/audio/softsynth/fmtowns_pc98/towns_audio.cpp
+++ b/audio/softsynth/fmtowns_pc98/towns_audio.cpp
@@ -103,12 +103,11 @@ private:
class TownsAudioInterfaceInternal : public TownsPC98_FmSynth {
public:
- TownsAudioInterfaceInternal(Audio::Mixer *mixer, TownsAudioInterfacePluginDriver *driver, bool externalMutexHandling = false);
+ TownsAudioInterfaceInternal(Audio::Mixer *mixer, TownsAudioInterface *owner, TownsAudioInterfacePluginDriver *driver, bool externalMutexHandling = false);
~TownsAudioInterfaceInternal();
- static TownsAudioInterfaceInternal *addNewRef(Audio::Mixer *mixer, TownsAudioInterfacePluginDriver *driver, bool externalMutexHandling = false);
- static void releaseRef();
- bool checkPluginDriver(TownsAudioInterfacePluginDriver *driver, bool externalMutexHandling = false);
+ static TownsAudioInterfaceInternal *addNewRef(Audio::Mixer *mixer, TownsAudioInterface *owner, TownsAudioInterfacePluginDriver *driver, bool externalMutexHandling = false);
+ static void releaseRef(TownsAudioInterface *owner);
bool init();
@@ -122,6 +121,9 @@ public:
void setSoundEffectChanMask(int mask);
private:
+ bool assignPluginDriver(TownsAudioInterface *owner, TownsAudioInterfacePluginDriver *driver, bool externalMutexHandling = false);
+ void removePluginDriver(TownsAudioInterface *owner);
+
void nextTickEx(int32 *buffer, uint32 bufferSize);
void timerCallbackA();
@@ -239,6 +241,7 @@ private:
int _pcmSfxChanMask;
TownsAudioInterfacePluginDriver *_drv;
+ void *_drvOwner;
bool _ready;
static TownsAudioInterfaceInternal *_refInstance;
@@ -252,10 +255,10 @@ private:
static const uint16 _pcmPhase2[];
};
-TownsAudioInterfaceInternal::TownsAudioInterfaceInternal(Audio::Mixer *mixer, TownsAudioInterfacePluginDriver *driver, bool externalMutexHandling) :
+TownsAudioInterfaceInternal::TownsAudioInterfaceInternal(Audio::Mixer *mixer, TownsAudioInterface *owner, TownsAudioInterfacePluginDriver *driver, bool externalMutexHandling) :
TownsPC98_FmSynth(mixer, kTypeTowns, externalMutexHandling),
_fmInstruments(0), _pcmInstruments(0), _pcmChan(0), _waveTables(0), _waveTablesTotalDataSize(0),
- _baserate(55125.0f / (float)mixer->getOutputRate()), _tickLength(0), _timer(0), _drv(driver),
+ _baserate(55125.0f / (float)mixer->getOutputRate()), _tickLength(0), _timer(0), _drv(driver), _drvOwner(owner),
_pcmSfxChanMask(0), _musicVolume(Audio::Mixer::kMaxMixerVolume), _sfxVolume(Audio::Mixer::kMaxMixerVolume),
_outputVolumeFlags(0), _pcmChanOut(0), _pcmChanReserved(0), _pcmChanKeyPressed(0),
_pcmChanEffectPlaying(0), _pcmChanKeyPlaying(0), _fmChanPlaying(0),
@@ -388,6 +391,8 @@ TownsAudioInterfaceInternal::~TownsAudioInterfaceInternal() {
_ready = false;
deinit();
+ Common::StackLock lock(_mutex);
+
delete[] _fmSaveReg[0];
delete[] _fmSaveReg[1];
delete[] _fmInstruments;
@@ -396,45 +401,33 @@ TownsAudioInterfaceInternal::~TownsAudioInterfaceInternal() {
delete[] _pcmChan;
}
-TownsAudioInterfaceInternal *TownsAudioInterfaceInternal::addNewRef(Audio::Mixer *mixer, TownsAudioInterfacePluginDriver *driver, bool externalMutexHandling) {
+TownsAudioInterfaceInternal *TownsAudioInterfaceInternal::addNewRef(Audio::Mixer *mixer, TownsAudioInterface *owner, TownsAudioInterfacePluginDriver *driver, bool externalMutexHandling) {
_refCount++;
if (_refCount == 1 && _refInstance == 0)
- _refInstance = new TownsAudioInterfaceInternal(mixer, driver, externalMutexHandling);
+ _refInstance = new TownsAudioInterfaceInternal(mixer, owner, driver, externalMutexHandling);
else if (_refCount < 2 || _refInstance == 0)
error("TownsAudioInterfaceInternal::addNewRef(): Internal reference management failure");
- else if (!_refInstance->checkPluginDriver(driver, externalMutexHandling))
+ else if (!_refInstance->assignPluginDriver(owner, driver, externalMutexHandling))
error("TownsAudioInterfaceInternal::addNewRef(): Plugin driver conflict");
return _refInstance;
}
-void TownsAudioInterfaceInternal::releaseRef() {
+void TownsAudioInterfaceInternal::releaseRef(TownsAudioInterface *owner) {
if (!_refCount)
return;
_refCount--;
- if (!_refCount) {
+ if (_refCount) {
+ if (_refInstance)
+ _refInstance->removePluginDriver(owner);
+ } else {
delete _refInstance;
_refInstance = 0;
}
}
-bool TownsAudioInterfaceInternal::checkPluginDriver(TownsAudioInterfacePluginDriver *driver, bool externalMutexHandling) {
- if (_refCount <= 1)
- return true;
-
- if (_drv) {
- if (driver && driver != _drv)
- return false;
- } else {
- _drv = driver;
- _externalMutex = externalMutexHandling;
- }
-
- return true;
-}
-
bool TownsAudioInterfaceInternal::init() {
if (_ready)
return true;
@@ -501,6 +494,30 @@ void TownsAudioInterfaceInternal::setSoundEffectChanMask(int mask) {
setVolumeChannelMasks(~mask, mask);
}
+bool TownsAudioInterfaceInternal::assignPluginDriver(TownsAudioInterface *owner, TownsAudioInterfacePluginDriver *driver, bool externalMutexHandling) {
+ if (_refCount <= 1)
+ return true;
+
+ if (_drv) {
+ if (driver && driver != _drv)
+ return false;
+ } else {
+ Common::StackLock lock(_mutex);
+ _drv = driver;
+ _drvOwner = owner;
+ _externalMutex = externalMutexHandling;
+ }
+
+ return true;
+}
+
+void TownsAudioInterfaceInternal::removePluginDriver(TownsAudioInterface *owner) {
+ if (_drvOwner == owner) {
+ Common::StackLock lock(_mutex);
+ _drv = 0;
+ }
+}
+
void TownsAudioInterfaceInternal::nextTickEx(int32 *buffer, uint32 bufferSize) {
if (!_ready)
return;
@@ -1856,11 +1873,11 @@ void TownsAudio_WaveTable::clear() {
}
TownsAudioInterface::TownsAudioInterface(Audio::Mixer *mixer, TownsAudioInterfacePluginDriver *driver, bool externalMutexHandling) {
- _intf = TownsAudioInterfaceInternal::addNewRef(mixer, driver, externalMutexHandling);
+ _intf = TownsAudioInterfaceInternal::addNewRef(mixer, this, driver, externalMutexHandling);
}
TownsAudioInterface::~TownsAudioInterface() {
- TownsAudioInterfaceInternal::releaseRef();
+ TownsAudioInterfaceInternal::releaseRef(this);
_intf = 0;
}
diff --git a/audio/softsynth/fmtowns_pc98/towns_pc98_driver.cpp b/audio/softsynth/fmtowns_pc98/towns_pc98_driver.cpp
index ee20068e74..49fe97caf1 100644
--- a/audio/softsynth/fmtowns_pc98/towns_pc98_driver.cpp
+++ b/audio/softsynth/fmtowns_pc98/towns_pc98_driver.cpp
@@ -1054,6 +1054,8 @@ TownsPC98_AudioDriver::~TownsPC98_AudioDriver() {
_ready = false;
deinit();
+ Common::StackLock lock(_mutex);
+
if (_channels) {
for (int i = 0; i < _numChan; i++)
delete _channels[i];
diff --git a/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp b/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp
index f4dd3cf6cc..63007ba93c 100644
--- a/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp
+++ b/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp
@@ -875,6 +875,8 @@ TownsPC98_FmSynth::~TownsPC98_FmSynth() {
if (_ready)
deinit();
+ Common::StackLock lock(_mutex);
+
delete _ssg;
#ifndef DISABLE_PC98_RHYTHM_CHANNEL
delete _prc;
@@ -1166,7 +1168,7 @@ int TownsPC98_FmSynth::readBuffer(int16 *buffer, const int numSamples) {
(this->*_timers[i].cb)();
- if (_ready && !locked && _externalMutex) {
+ if (!locked && _externalMutex) {
_mutex.lock();
locked = true;
}
@@ -1240,6 +1242,10 @@ void TownsPC98_FmSynth::deinit() {
_timers[0].cb = _timers[1].cb = &TownsPC98_FmSynth::idleTimerCallback;
}
+void TownsPC98_FmSynth::toggleRegProtection(bool prot) {
+ _regProtectionFlag = prot;
+}
+
uint8 TownsPC98_FmSynth::readSSGStatus() {
return _ssg->chanEnable();
}
diff --git a/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h b/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h
index 50a05f92a9..4f81fa9a5c 100644
--- a/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h
+++ b/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h
@@ -80,17 +80,15 @@ protected:
// additional output that has to be inserted into the buffer.
virtual void nextTickEx(int32 *buffer, uint32 bufferSize) {}
- void toggleRegProtection(bool prot) {
- _regProtectionFlag = prot;
- }
+ void toggleRegProtection(bool prot);
uint8 readSSGStatus();
virtual void timerCallbackA() = 0;
virtual void timerCallbackB() = 0;
- // The audio driver can store and apply two different audio settings
+ // The audio driver can store and apply two different volume settings
// (usually for music and sound effects). The channel mask will determine
- // which channels get effected by the setting. The first bits will be
+ // which channels get effected by which setting. The first bits will be
// the normal fm channels, the next bits the ssg channels and the final
// bit the rhythm channel.
void setVolumeIntern(int volA, int volB);