Sound system refactor

This commit is contained in:
elasota
2019-12-31 04:49:38 -05:00
parent b963aa9b5f
commit 62438ab4f3
7 changed files with 287 additions and 375 deletions

View File

@@ -14,6 +14,7 @@
#include "SoundSync.h" #include "SoundSync.h"
#include "HostMutex.h" #include "HostMutex.h"
#include "HostSystemServices.h" #include "HostSystemServices.h"
#include "MemoryManager.h"
#define kBaseBufferMusicID 2000 #define kBaseBufferMusicID 2000
@@ -22,15 +23,14 @@
#define kLastGamePiece 6 #define kLastGamePiece 6
void MusicCallBack (SndChannelPtr, SndCommand *); void MusicCallBack (PortabilityLayer::AudioChannel *channel);
PLError_t LoadMusicSounds (void); PLError_t LoadMusicSounds (void);
PLError_t DumpMusicSounds (void); PLError_t DumpMusicSounds (void);
PLError_t OpenMusicChannel (void); PLError_t OpenMusicChannel (void);
PLError_t CloseMusicChannel (void); PLError_t CloseMusicChannel (void);
SndCallBackUPP musicCallBackUPP; PortabilityLayer::AudioChannel *musicChannel;
SndChannelPtr musicChannel;
Ptr theMusicData[kMaxMusic]; Ptr theMusicData[kMaxMusic];
short musicScore[kLastMusicPiece]; short musicScore[kLastMusicPiece];
short gameScore[kLastGamePiece]; short gameScore[kLastGamePiece];
@@ -56,7 +56,6 @@ extern Boolean isSoundOn;
PLError_t StartMusic (void) PLError_t StartMusic (void)
{ {
SndCommand theCommand;
PLError_t theErr; PLError_t theErr;
short soundVolume; short soundVolume;
@@ -72,37 +71,16 @@ PLError_t StartMusic (void)
if ((soundVolume != 0) && (!failedMusic)) if ((soundVolume != 0) && (!failedMusic))
{ {
theCommand.cmd = bufferCmd; musicChannel->AddBuffer(theMusicData[musicState.musicSoundID], true);
theCommand.param1 = 0;
theCommand.param2 = (intptr_t)(theMusicData[musicState.musicSoundID]);
theErr = SndDoCommand(musicChannel, &theCommand, false);
if (theErr != PLErrors::kNone)
return (theErr);
// GP: No idea what "1964" means
theCommand.cmd = nullCmd;
theCommand.param1 = 1964;
theCommand.param2 = 0;
theErr = SndDoCommand(musicChannel, &theCommand, false);
if (theErr != PLErrors::kNone)
return (theErr);
// Don't need to lock here because the callback should not trigger until queued
musicState.musicCursor++; musicState.musicCursor++;
if (musicState.musicCursor >= kLastMusicPiece) if (musicState.musicCursor >= kLastMusicPiece)
musicState.musicCursor = 0; musicState.musicCursor = 0;
musicState.musicSoundID = musicScore[musicState.musicCursor]; musicState.musicSoundID = musicScore[musicState.musicCursor];
theCommand.cmd = bufferCmd; musicChannel->AddBuffer(theMusicData[musicState.musicSoundID], true);
theCommand.param1 = 0; musicChannel->AddCallback(MusicCallBack, true);
theCommand.param2 = (intptr_t)(theMusicData[musicState.musicSoundID]);
theErr = SndDoCommand(musicChannel, &theCommand, false);
if (theErr != PLErrors::kNone)
return (theErr);
theCommand.cmd = callBackCmd;
theCommand.param1 = 0;
theCommand.param2 = 0;
theErr = SndDoCommand(musicChannel, &theCommand, false);
isMusicOn = true; isMusicOn = true;
} }
@@ -114,7 +92,6 @@ PLError_t StartMusic (void)
void StopTheMusic (void) void StopTheMusic (void)
{ {
SndCommand theCommand;
PLError_t theErr; PLError_t theErr;
if (dontLoadMusic) if (dontLoadMusic)
@@ -123,15 +100,8 @@ void StopTheMusic (void)
theErr = PLErrors::kNone; theErr = PLErrors::kNone;
if ((isMusicOn) && (!failedMusic)) if ((isMusicOn) && (!failedMusic))
{ {
theCommand.cmd = flushCmd; musicChannel->ClearAllCommands();
theCommand.param1 = 0; musicChannel->Stop();
theCommand.param2 = 0L;
theErr = SndDoImmediate(musicChannel, &theCommand);
theCommand.cmd = quietCmd;
theCommand.param1 = 0;
theCommand.param2 = 0L;
theErr = SndDoImmediate(musicChannel, &theCommand);
isMusicOn = false; isMusicOn = false;
} }
@@ -186,13 +156,10 @@ void SetMusicalMode (short newMode)
//-------------------------------------------------------------- MusicCallBack //-------------------------------------------------------------- MusicCallBack
void MusicCallBack (SndChannelPtr theChannel, SndCommand *theCommand) void MusicCallBack (PortabilityLayer::AudioChannel *theChannel)
{ {
PLError_t theErr; PLError_t theErr;
// gameA5 = theCommand.param2;
// thisA5 = SetA5(gameA5);
musicMutex->Lock(); musicMutex->Lock();
switch (musicState.musicMode) switch (musicState.musicMode)
{ {
@@ -223,15 +190,8 @@ void MusicCallBack (SndChannelPtr theChannel, SndCommand *theCommand)
short musicSoundID = musicState.musicSoundID; short musicSoundID = musicState.musicSoundID;
musicMutex->Unlock(); musicMutex->Unlock();
theCommand->cmd = bufferCmd; theChannel->AddBuffer(theMusicData[musicSoundID], true);
theCommand->param1 = 0; theChannel->AddCallback(MusicCallBack, true);
theCommand->param2 = (intptr_t)(theMusicData[musicSoundID]);
theErr = SndDoCommand(musicChannel, theCommand, false);
theCommand->cmd = callBackCmd;
theCommand->param1 = 0;
theCommand->param2 = 0;
theErr = SndDoCommand(musicChannel, theCommand, false);
} }
//-------------------------------------------------------------- LoadMusicSounds //-------------------------------------------------------------- LoadMusicSounds
@@ -256,7 +216,7 @@ PLError_t LoadMusicSounds (void)
soundDataSize = GetHandleSize(theSound) - 20L; soundDataSize = GetHandleSize(theSound) - 20L;
theMusicData[i] = NewPtr(soundDataSize); theMusicData[i] = PortabilityLayer::MemoryManager::GetInstance()->Alloc(soundDataSize);
if (theMusicData[i] == nil) if (theMusicData[i] == nil)
return PLErrors::kOutOfMemory; return PLErrors::kOutOfMemory;
@@ -278,7 +238,7 @@ PLError_t DumpMusicSounds (void)
for (i = 0; i < kMaxMusic; i++) for (i = 0; i < kMaxMusic; i++)
{ {
if (theMusicData[i] != nil) if (theMusicData[i] != nil)
DisposePtr(theMusicData[i]); PortabilityLayer::MemoryManager::GetInstance()->Release(theMusicData[i]);
theMusicData[i] = nil; theMusicData[i] = nil;
} }
@@ -291,17 +251,15 @@ PLError_t OpenMusicChannel (void)
{ {
PLError_t theErr; PLError_t theErr;
musicCallBackUPP = NewSndCallBackProc(MusicCallBack);
theErr = PLErrors::kNone; theErr = PLErrors::kNone;
if (musicChannel != nil) if (musicChannel != nil)
return (theErr); return (theErr);
musicChannel = nil; musicChannel = PortabilityLayer::SoundSystem::GetInstance()->CreateChannel();
theErr = SndNewChannel(&musicChannel,
sampledSynth, initNoInterp + initMono, if (musicChannel == nil)
(SndCallBackUPP)musicCallBackUPP); theErr = PLErrors::kAudioError;
return (theErr); return (theErr);
} }
@@ -315,11 +273,9 @@ PLError_t CloseMusicChannel (void)
theErr = PLErrors::kNone; theErr = PLErrors::kNone;
if (musicChannel != nil) if (musicChannel != nil)
theErr = SndDisposeChannel(musicChannel, true); musicChannel->Destroy(false);
musicChannel = nil; musicChannel = nil;
DisposeSndCallBackUPP(musicCallBackUPP);
return (theErr); return (theErr);
} }

View File

@@ -9,6 +9,7 @@
#include "PLResources.h" #include "PLResources.h"
#include "PLSound.h" #include "PLSound.h"
#include "Externs.h" #include "Externs.h"
#include "MemoryManager.h"
#include "SoundSync.h" #include "SoundSync.h"
#include "VirtualDirectory.h" #include "VirtualDirectory.h"
@@ -17,17 +18,16 @@
#define kMaxSounds 64 #define kMaxSounds 64
void CallBack0 (SndChannelPtr, SndCommand *); void CallBack0 (PortabilityLayer::AudioChannel *);
void CallBack1 (SndChannelPtr, SndCommand *); void CallBack1 (PortabilityLayer::AudioChannel *);
void CallBack2 (SndChannelPtr, SndCommand *); void CallBack2 (PortabilityLayer::AudioChannel *);
PLError_t LoadBufferSounds (void); PLError_t LoadBufferSounds (void);
void DumpBufferSounds (void); void DumpBufferSounds (void);
PLError_t OpenSoundChannels (void); PLError_t OpenSoundChannels (void);
PLError_t CloseSoundChannels (void); void CloseSoundChannels (void);
SndCallBackUPP callBack0UPP, callBack1UPP, callBack2UPP; PortabilityLayer::AudioChannel *channel0, *channel1, *channel2;
SndChannelPtr channel0, channel1, channel2;
Ptr theSoundData[kMaxSounds]; Ptr theSoundData[kMaxSounds];
short numSoundsLoaded; short numSoundsLoaded;
Boolean soundLoaded[kMaxSounds], dontLoadSounds; Boolean soundLoaded[kMaxSounds], dontLoadSounds;
@@ -76,131 +76,97 @@ void PlayPrioritySound (short which, short priority)
void FlushAnyTriggerPlaying (void) void FlushAnyTriggerPlaying (void)
{ {
SndCommand theCommand;
PLError_t theErr;
SoundSyncState ss = SoundSync_ReadAll(); SoundSyncState ss = SoundSync_ReadAll();
if (ss.priority0 == kTriggerPriority) if (ss.priority0 == kTriggerPriority)
{ {
theCommand.cmd = quietCmd; channel0->ClearAllCommands();
theCommand.param1 = 0; channel0->Stop();
theCommand.param2 = 0;
theErr = SndDoImmediate(channel0, &theCommand);
theCommand.cmd = flushCmd;
theCommand.param1 = 0;
theCommand.param2 = 0;
theErr = SndDoImmediate(channel0, &theCommand);
} }
if (ss.priority1 == kTriggerPriority) if (ss.priority1 == kTriggerPriority)
{ {
theCommand.cmd = quietCmd; channel1->ClearAllCommands();
theCommand.param1 = 0; channel1->Stop();
theCommand.param2 = 0;
theErr = SndDoImmediate(channel1, &theCommand);
theCommand.cmd = flushCmd;
theCommand.param1 = 0;
theCommand.param2 = 0;
theErr = SndDoImmediate(channel1, &theCommand);
} }
if (ss.priority2 == kTriggerPriority) if (ss.priority2 == kTriggerPriority)
{ {
theCommand.cmd = quietCmd; channel2->ClearAllCommands();
theCommand.param1 = 0; channel2->Stop();
theCommand.param2 = 0;
theErr = SndDoImmediate(channel2, &theCommand);
theCommand.cmd = flushCmd;
theCommand.param1 = 0;
theCommand.param2 = 0;
theErr = SndDoImmediate(channel2, &theCommand);
}
}
//-------------------------------------------------------------- PlaySound0
void PlayExclusiveSoundChannel(short channelIndex, short soundID, short oldPriority, short newPriority)
{
SndCommand theCommand;
PLError_t theErr;
if (failedSound || dontLoadSounds)
return;
SndChannelPtr channel = nil;
switch (channelIndex)
{
case 0:
channel = channel0;
break;
case 1:
channel = channel2;
break;
case 2:
channel = channel2;
break;
default:
return;
}
theErr = PLErrors::kNone;
if (isSoundOn)
{
if (oldPriority != 0)
{
// Flush the queue and stop the channel, which will remove the pending callback
theCommand.cmd = flushCmd;
theCommand.param1 = 0;
theCommand.param2 = 0;
theErr = SndDoImmediate(channel, &theCommand);
theCommand.cmd = quietCmd;
theCommand.param1 = 0;
theCommand.param2 = 0;
theErr = SndDoImmediate(channel, &theCommand);
SoundSync_ClearPriority(channelIndex);
}
SoundSync_PutPriority(channelIndex, newPriority);
theCommand.cmd = bufferCmd;
theCommand.param1 = 0;
theCommand.param2 = (intptr_t)(theSoundData[soundID]);
theErr = SndDoCommand(channel, &theCommand, true);
theCommand.cmd = callBackCmd;
theCommand.param1 = 0;
theCommand.param2 = 0;
theErr = SndDoCommand(channel, &theCommand, true);
if (theErr != PLErrors::kNone)
SoundSync_ClearPriority(channelIndex);
} }
} }
//-------------------------------------------------------------- CallBack0 //-------------------------------------------------------------- CallBack0
void CallBack0 (SndChannelPtr theChannel, SndCommand *theCommand) void CallBack0(PortabilityLayer::AudioChannel *theChannel)
{ {
SoundSync_ClearPriority(0); SoundSync_ClearPriority(0);
} }
//-------------------------------------------------------------- CallBack1 //-------------------------------------------------------------- CallBack1
void CallBack1 (SndChannelPtr theChannel, SndCommand *theCommand) void CallBack1(PortabilityLayer::AudioChannel *theChannel)
{ {
SoundSync_ClearPriority(1); SoundSync_ClearPriority(1);
} }
//-------------------------------------------------------------- CallBack2 //-------------------------------------------------------------- CallBack2
void CallBack2 (SndChannelPtr theChannel, SndCommand *theCommand) void CallBack2(PortabilityLayer::AudioChannel *theChannel)
{ {
SoundSync_ClearPriority(2); SoundSync_ClearPriority(2);
} }
//-------------------------------------------------------------- PlaySound0
void PlayExclusiveSoundChannel(short channelIndex, short soundID, short oldPriority, short newPriority)
{
if (failedSound || dontLoadSounds)
return;
PortabilityLayer::AudioChannel *channel = nil;
PortabilityLayer::AudioChannelCallback_t callback = nil;
switch (channelIndex)
{
case 0:
channel = channel0;
callback = CallBack0;
break;
case 1:
channel = channel1;
callback = CallBack1;
break;
case 2:
channel = channel2;
callback = CallBack2;
break;
default:
return;
}
if (isSoundOn)
{
if (oldPriority != 0)
{
// Flush the queue and stop the channel, which will remove the pending callback
channel->ClearAllCommands();
channel->Stop();
SoundSync_ClearPriority(channelIndex);
}
SoundSync_PutPriority(channelIndex, newPriority);
bool succeeded = channel->AddBuffer(theSoundData[soundID], false);
succeeded &= channel->AddCallback(callback, false);
if (!succeeded)
SoundSync_ClearPriority(channelIndex);
}
}
//-------------------------------------------------------------- LoadTriggerSound //-------------------------------------------------------------- LoadTriggerSound
PLError_t LoadTriggerSound (short soundID) PLError_t LoadTriggerSound (short soundID)
@@ -225,7 +191,7 @@ PLError_t LoadTriggerSound (short soundID)
else else
{ {
soundDataSize = GetHandleSize(theSound) - 20L; soundDataSize = GetHandleSize(theSound) - 20L;
theSoundData[kMaxSounds - 1] = NewPtr(soundDataSize); theSoundData[kMaxSounds - 1] = PortabilityLayer::MemoryManager::GetInstance()->Alloc(soundDataSize);
if (theSoundData[kMaxSounds - 1] == nil) if (theSoundData[kMaxSounds - 1] == nil)
{ {
theSound.Dispose(); theSound.Dispose();
@@ -247,7 +213,7 @@ PLError_t LoadTriggerSound (short soundID)
void DumpTriggerSound (void) void DumpTriggerSound (void)
{ {
if (theSoundData[kMaxSounds - 1] != nil) if (theSoundData[kMaxSounds - 1] != nil)
DisposePtr(theSoundData[kMaxSounds - 1]); PortabilityLayer::MemoryManager::GetInstance()->Release(theSoundData[kMaxSounds - 1]);
theSoundData[kMaxSounds - 1] = nil; theSoundData[kMaxSounds - 1] = nil;
} }
@@ -270,7 +236,7 @@ PLError_t LoadBufferSounds (void)
soundDataSize = GetHandleSize(theSound) - 20L; soundDataSize = GetHandleSize(theSound) - 20L;
theSoundData[i] = NewPtr(soundDataSize); theSoundData[i] = PortabilityLayer::MemoryManager::GetInstance()->Alloc(soundDataSize);
if (theSoundData[i] == nil) if (theSoundData[i] == nil)
return (PLErrors::kOutOfMemory); return (PLErrors::kOutOfMemory);
@@ -292,7 +258,7 @@ void DumpBufferSounds (void)
for (i = 0; i < kMaxSounds; i++) for (i = 0; i < kMaxSounds; i++)
{ {
if (theSoundData[i] != nil) if (theSoundData[i] != nil)
DisposePtr(theSoundData[i]); PortabilityLayer::MemoryManager::GetInstance()->Release(theSoundData[i]);
theSoundData[i] = nil; theSoundData[i] = nil;
} }
} }
@@ -301,73 +267,50 @@ void DumpBufferSounds (void)
PLError_t OpenSoundChannels (void) PLError_t OpenSoundChannels (void)
{ {
PLError_t theErr;
callBack0UPP = NewSndCallBackProc(CallBack0);
callBack1UPP = NewSndCallBackProc(CallBack1);
callBack2UPP = NewSndCallBackProc(CallBack2);
theErr = PLErrors::kNone;
if (channelOpen) if (channelOpen)
return (theErr); return PLErrors::kAudioError;
theErr = SndNewChannel(&channel0, channel0 = PortabilityLayer::SoundSystem::GetInstance()->CreateChannel();
sampledSynth, initNoInterp + initMono, if (channel0)
(SndCallBackUPP)callBack0UPP);
if (theErr == PLErrors::kNone)
channelOpen = true; channelOpen = true;
else else
return (theErr); return PLErrors::kAudioError;
theErr = SndNewChannel(&channel1, channel1 = PortabilityLayer::SoundSystem::GetInstance()->CreateChannel();
sampledSynth, initNoInterp + initMono, if (channel1)
(SndCallBackUPP)callBack1UPP);
if (theErr == PLErrors::kNone)
channelOpen = true; channelOpen = true;
else else
return (theErr); return PLErrors::kAudioError;
theErr = SndNewChannel(&channel2, channel2 = PortabilityLayer::SoundSystem::GetInstance()->CreateChannel();
sampledSynth, initNoInterp + initMono, if (channel2)
(SndCallBackUPP)callBack2UPP);
if (theErr == PLErrors::kNone)
channelOpen = true; channelOpen = true;
else
return PLErrors::kAudioError;
return (theErr); return PLErrors::kNone;
} }
//-------------------------------------------------------------- CloseSoundChannels //-------------------------------------------------------------- CloseSoundChannels
PLError_t CloseSoundChannels (void) void CloseSoundChannels (void)
{ {
PLError_t theErr;
theErr = PLErrors::kNone;
if (!channelOpen) if (!channelOpen)
return (theErr); return;
if (channel0 != nil) if (channel0 != nil)
theErr = SndDisposeChannel(channel0, true); channel0->Destroy(false);
channel0 = nil; channel0 = nil;
if (channel1 != nil) if (channel1 != nil)
theErr = SndDisposeChannel(channel1, true); channel1->Destroy(false);
channel1 = nil; channel1 = nil;
if (channel2 != nil) if (channel2 != nil)
theErr = SndDisposeChannel(channel2, true); channel2->Destroy(false);
channel2 = nil; channel2 = nil;
if (theErr == PLErrors::kNone)
channelOpen = false; channelOpen = false;
DisposeSndCallBackUPP(callBack0UPP);
DisposeSndCallBackUPP(callBack1UPP);
DisposeSndCallBackUPP(callBack2UPP);
return (theErr);
} }
//-------------------------------------------------------------- InitSound //-------------------------------------------------------------- InitSound
@@ -411,13 +354,11 @@ void InitSound (void)
void KillSound (void) void KillSound (void)
{ {
PLError_t theErr;
if (dontLoadSounds) if (dontLoadSounds)
return; return;
DumpBufferSounds(); DumpBufferSounds();
theErr = CloseSoundChannels(); CloseSoundChannels();
} }
//-------------------------------------------------------------- SoundBytesNeeded //-------------------------------------------------------------- SoundBytesNeeded

View File

@@ -511,8 +511,8 @@ void UnivGetSoundVolume (short *volume, Boolean hasSM3)
// if (hasSM3) // if (hasSM3)
// { // {
theErr = GetDefaultOutputVolume(&longVol); longVol = PortabilityLayer::SoundSystem::GetInstance()->GetVolume();
*volume = LoWord(longVol) / 0x0024; *volume = longVol / 0x0024;
// } // }
// else // else
// GetSoundVol(volume); // GetSoundVol(volume);
@@ -530,7 +530,6 @@ void UnivGetSoundVolume (short *volume, Boolean hasSM3)
void UnivSetSoundVolume (short volume, Boolean hasSM3) void UnivSetSoundVolume (short volume, Boolean hasSM3)
{ {
long longVol; long longVol;
PLError_t theErr;
if (volume > 7) if (volume > 7)
volume = 7; volume = 7;
@@ -542,8 +541,8 @@ void UnivSetSoundVolume (short volume, Boolean hasSM3)
longVol = (long)volume * 0x0025; longVol = (long)volume * 0x0025;
if (longVol > 0x00000100) if (longVol > 0x00000100)
longVol = 0x00000100; longVol = 0x00000100;
longVol = longVol + (longVol << 16);
theErr = SetDefaultOutputVolume(longVol); PortabilityLayer::SoundSystem::GetInstance()->SetVolume(longVol);
// } // }
// else // else
// SetSoundVol(volume); // SetSoundVol(volume);

View File

@@ -12,25 +12,53 @@
namespace PortabilityLayer namespace PortabilityLayer
{ {
class AudioChannelImpl : public SndChannel, public ClientAudioChannelContext namespace AudioCommandTypes
{
enum AudioCommandType
{
kBuffer,
kCallback,
};
}
typedef AudioCommandTypes::AudioCommandType AudioCommandType_t;
struct AudioCommand
{
union AudioCommandParam
{
const void *m_ptr;
AudioChannelCallback_t m_callback;
};
AudioCommandType_t m_commandType;
AudioCommandParam m_param;
};
class AudioChannelImpl final : public AudioChannel, public ClientAudioChannelContext
{ {
public: public:
explicit AudioChannelImpl(PortabilityLayer::HostAudioChannel *channel, SndCallBackUPP callback, HostThreadEvent *threadEvent, HostMutex *mutex); explicit AudioChannelImpl(PortabilityLayer::HostAudioChannel *channel, HostThreadEvent *threadEvent, HostMutex *mutex);
~AudioChannelImpl(); ~AudioChannelImpl();
bool PushCommand(const SndCommand &command, bool blocking); void Destroy(bool wait) override;
void ClearAllCommands(); bool AddBuffer(const void *smBuffer, bool blocking) override;
void Stop(); bool AddCallback(AudioChannelCallback_t callback, bool blocking) override;
void ClearAllCommands() override;
void Stop() override;
void NotifyBufferFinished() override; void NotifyBufferFinished() override;
private: private:
bool PushCommand(const AudioCommand &command, bool blocking);
enum WorkingState enum WorkingState
{ {
State_Idle, // No thread is playing sound, the sound thread is out of work State_Idle, // No thread is playing sound, the sound thread is out of work
State_PlayingAsync, // Sound thread is playing sound. When it finishes, it will digest queue events under a lock. State_PlayingAsync, // Sound thread is playing sound. When it finishes, it will digest queue events under a lock.
State_PlayingBlocked, // Sound thread is playing sound. When it finishes, it will transition to Idle and fire the thread event. State_PlayingBlocked, // Sound thread is playing sound. When it finishes, it will transition to Idle and fire the thread event.
State_FlushStarting, // Sound thread is aborting. When it aborts, it will transition to Idle and fire the thread event. State_FlushStarting, // Sound thread is aborting. When it aborts, it will transition to Idle and fire the thread event.
State_ShuttingDown, // Sound thread is shutting down. When it finishes, it will transition to idle and fire the thread event.
}; };
static const unsigned int kMaxQueuedCommands = 64; static const unsigned int kMaxQueuedCommands = 64;
@@ -39,12 +67,12 @@ namespace PortabilityLayer
void DigestBufferCommand(const void *dataPointer); void DigestBufferCommand(const void *dataPointer);
PortabilityLayer::HostAudioChannel *m_audioChannel; PortabilityLayer::HostAudioChannel *m_audioChannel;
SndCallBackUPP m_callback; ;
HostMutex *m_mutex; HostMutex *m_mutex;
HostThreadEvent *m_threadEvent; HostThreadEvent *m_threadEvent;
SndCommand m_commandQueue[kMaxQueuedCommands]; AudioCommand m_commandQueue[kMaxQueuedCommands];
size_t m_numQueuedCommands; size_t m_numQueuedCommands;
size_t m_nextInsertCommandPos; size_t m_nextInsertCommandPos;
size_t m_nextDequeueCommandPos; size_t m_nextDequeueCommandPos;
@@ -52,9 +80,8 @@ namespace PortabilityLayer
bool m_isIdle; bool m_isIdle;
}; };
AudioChannelImpl::AudioChannelImpl(PortabilityLayer::HostAudioChannel *channel, SndCallBackUPP callback, HostThreadEvent *threadEvent, HostMutex *mutex) AudioChannelImpl::AudioChannelImpl(PortabilityLayer::HostAudioChannel *channel, HostThreadEvent *threadEvent, HostMutex *mutex)
: m_audioChannel(channel) : m_audioChannel(channel)
, m_callback(callback)
, m_threadEvent(threadEvent) , m_threadEvent(threadEvent)
, m_mutex(mutex) , m_mutex(mutex)
, m_nextInsertCommandPos(0) , m_nextInsertCommandPos(0)
@@ -81,7 +108,7 @@ namespace PortabilityLayer
m_state = State_Idle; m_state = State_Idle;
DigestQueueItems(); DigestQueueItems();
} }
else if (m_state == State_PlayingBlocked || m_state == State_FlushStarting) else if (m_state == State_PlayingBlocked || m_state == State_FlushStarting || m_state == State_ShuttingDown)
{ {
m_state = State_Idle; m_state = State_Idle;
m_threadEvent->Signal(); m_threadEvent->Signal();
@@ -90,6 +117,52 @@ namespace PortabilityLayer
m_mutex->Unlock(); m_mutex->Unlock();
} }
void AudioChannelImpl::Destroy(bool wait)
{
ClearAllCommands();
if (!wait)
Stop();
else
{
m_mutex->Lock();
if (m_state == State_PlayingAsync)
{
m_state = State_ShuttingDown;
m_mutex->Unlock();
m_threadEvent->Wait();
}
else
{
assert(m_state == State_Idle);
m_mutex->Unlock();
}
}
this->~AudioChannelImpl();
PortabilityLayer::MemoryManager::GetInstance()->Release(this);
}
bool AudioChannelImpl::AddBuffer(const void *smBuffer, bool blocking)
{
AudioCommand cmd;
cmd.m_commandType = AudioCommandTypes::kBuffer;
cmd.m_param.m_ptr = smBuffer;
return this->PushCommand(cmd, blocking);
}
bool AudioChannelImpl::AddCallback(AudioChannelCallback_t callback, bool blocking)
{
AudioCommand cmd;
cmd.m_commandType = AudioCommandTypes::kCallback;
cmd.m_param.m_ptr = callback;
return this->PushCommand(cmd, blocking);
}
void AudioChannelImpl::DigestQueueItems() void AudioChannelImpl::DigestQueueItems()
{ {
m_mutex->Lock(); m_mutex->Lock();
@@ -98,29 +171,22 @@ namespace PortabilityLayer
while (m_numQueuedCommands > 0) while (m_numQueuedCommands > 0)
{ {
const SndCommand &command = m_commandQueue[m_nextDequeueCommandPos]; const AudioCommand &command = m_commandQueue[m_nextDequeueCommandPos];
m_numQueuedCommands--; m_numQueuedCommands--;
m_nextDequeueCommandPos = (m_nextDequeueCommandPos + 1) % static_cast<size_t>(kMaxQueuedCommands); m_nextDequeueCommandPos = (m_nextDequeueCommandPos + 1) % static_cast<size_t>(kMaxQueuedCommands);
switch (command.cmd) switch (command.m_commandType)
{ {
case nullCmd: case AudioCommandTypes::kBuffer:
break; DigestBufferCommand(command.m_param.m_ptr);
case bufferCmd:
DigestBufferCommand(reinterpret_cast<const void*>(command.param2));
assert(m_state == State_PlayingAsync); assert(m_state == State_PlayingAsync);
m_mutex->Unlock(); m_mutex->Unlock();
return; return;
case callBackCmd: case AudioCommandTypes::kCallback:
{ command.m_param.m_callback(this);
SndCommand commandCopy = command;
m_callback(this, &commandCopy);
}
break; break;
default: default:
case flushCmd: assert(false);
case quietCmd:
assert(false); // These shouldn't be in the queue
break; break;
} }
} }
@@ -152,14 +218,14 @@ namespace PortabilityLayer
m_state = State_PlayingAsync; m_state = State_PlayingAsync;
} }
bool AudioChannelImpl::PushCommand(const SndCommand &command, bool failIfFull) bool AudioChannelImpl::PushCommand(const AudioCommand &command, bool blocking)
{ {
bool digestOnThisThread = false; bool digestOnThisThread = false;
m_mutex->Lock(); m_mutex->Lock();
if (m_numQueuedCommands == kMaxQueuedCommands) if (m_numQueuedCommands == kMaxQueuedCommands)
{ {
if (failIfFull) if (!blocking)
{ {
m_mutex->Unlock(); m_mutex->Unlock();
return false; return false;
@@ -250,28 +316,35 @@ PLError_t SetDefaultOutputVolume(long vol)
} }
SndCallBackUPP NewSndCallBackProc(SndCallBackProc callback) namespace PortabilityLayer
{ {
return callback; class SoundSystemImpl final : public SoundSystem
} {
public:
AudioChannel *CreateChannel() override;
void DisposeSndCallBackUPP(SndCallBackUPP upp) void SetVolume(uint8_t vol) override;
{ uint8_t GetVolume() const override;
}
PLError_t SndNewChannel(SndChannelPtr *outChannel, SndSynthType synthType, int initFlags, SndCallBackUPP callback) static SoundSystemImpl *GetInstance();
{
private:
static SoundSystemImpl ms_instance;
};
AudioChannel *SoundSystemImpl::CreateChannel()
{
PortabilityLayer::MemoryManager *mm = PortabilityLayer::MemoryManager::GetInstance(); PortabilityLayer::MemoryManager *mm = PortabilityLayer::MemoryManager::GetInstance();
void *storage = mm->Alloc(sizeof(PortabilityLayer::AudioChannelImpl)); void *storage = mm->Alloc(sizeof(PortabilityLayer::AudioChannelImpl));
if (!storage) if (!storage)
return PLErrors::kOutOfMemory; return nullptr;
PortabilityLayer::HostAudioDriver *audioDriver = PortabilityLayer::HostAudioDriver::GetInstance(); PortabilityLayer::HostAudioDriver *audioDriver = PortabilityLayer::HostAudioDriver::GetInstance();
PortabilityLayer::HostAudioChannel *audioChannel = audioDriver->CreateChannel(); PortabilityLayer::HostAudioChannel *audioChannel = audioDriver->CreateChannel();
if (!audioChannel) if (!audioChannel)
{ {
mm->Release(storage); mm->Release(storage);
return PLErrors::kAudioError; return nullptr;
} }
PortabilityLayer::HostMutex *mutex = PortabilityLayer::HostSystemServices::GetInstance()->CreateMutex(); PortabilityLayer::HostMutex *mutex = PortabilityLayer::HostSystemServices::GetInstance()->CreateMutex();
@@ -279,7 +352,7 @@ PLError_t SndNewChannel(SndChannelPtr *outChannel, SndSynthType synthType, int i
{ {
audioChannel->Destroy(); audioChannel->Destroy();
mm->Release(storage); mm->Release(storage);
return PLErrors::kAudioError; return nullptr;
} }
PortabilityLayer::HostThreadEvent *threadEvent = PortabilityLayer::HostSystemServices::GetInstance()->CreateThreadEvent(true, false); PortabilityLayer::HostThreadEvent *threadEvent = PortabilityLayer::HostSystemServices::GetInstance()->CreateThreadEvent(true, false);
@@ -288,60 +361,33 @@ PLError_t SndNewChannel(SndChannelPtr *outChannel, SndSynthType synthType, int i
mutex->Destroy(); mutex->Destroy();
audioChannel->Destroy(); audioChannel->Destroy();
mm->Release(storage); mm->Release(storage);
return PLErrors::kAudioError; return nullptr;
} }
*outChannel = new (storage) PortabilityLayer::AudioChannelImpl(audioChannel, callback, threadEvent, mutex); return new (storage) PortabilityLayer::AudioChannelImpl(audioChannel, threadEvent, mutex);
}
return PLErrors::kNone;
}
PLError_t SndDisposeChannel(SndChannelPtr channel, Boolean flush) void SoundSystemImpl::SetVolume(uint8_t vol)
{
if (flush)
{ {
SndCommand cmd; PL_NotYetImplemented_TODO("Volume");
cmd.cmd = flushCmd;
cmd.param1 = cmd.param2 = 0;
SndDoImmediate(channel, &cmd);
cmd.cmd = quietCmd;
cmd.param1 = cmd.param2 = 0;
SndDoImmediate(channel, &cmd);
} }
PortabilityLayer::AudioChannelImpl *audioChannelImpl = static_cast<PortabilityLayer::AudioChannelImpl*>(channel); uint8_t SoundSystemImpl::GetVolume() const
audioChannelImpl->~AudioChannelImpl();
PortabilityLayer::MemoryManager::GetInstance()->Release(audioChannelImpl);
return PLErrors::kNone;
}
PLError_t SndDoCommand(SndChannelPtr channel, const SndCommand *command, Boolean failIfFull)
{
PortabilityLayer::AudioChannelImpl *audioChannelImpl = static_cast<PortabilityLayer::AudioChannelImpl*>(channel);
if (!audioChannelImpl->PushCommand(*command, failIfFull == 0))
return PLErrors::kAudioError;
return PLErrors::kNone;
}
PLError_t SndDoImmediate(SndChannelPtr channel, const SndCommand *command)
{
PortabilityLayer::AudioChannelImpl *audioChannelImpl = static_cast<PortabilityLayer::AudioChannelImpl*>(channel);
if (command->cmd == flushCmd)
audioChannelImpl->ClearAllCommands();
else if (command->cmd == quietCmd)
audioChannelImpl->Stop();
else
{ {
assert(false); PL_NotYetImplemented_TODO("Volume");
return PLErrors::kAudioError; return 255;
} }
return PLErrors::kNone; SoundSystemImpl *SoundSystemImpl::GetInstance()
{
return &ms_instance;
}
SoundSystemImpl SoundSystemImpl::ms_instance;
SoundSystem *SoundSystem::GetInstance()
{
return SoundSystemImpl::GetInstance();
}
} }

View File

@@ -1,56 +1,30 @@
#pragma once #pragma once
#ifndef __PL_SOUND_H__
#define __PL_SOUND_H__
#include "PLCore.h" #include "PLCore.h"
enum SndCommandType namespace PortabilityLayer
{ {
nullCmd, struct AudioChannel;
bufferCmd, // Param1: 0 Param2: Offset to sound header
callBackCmd,
flushCmd,
quietCmd
};
struct SndChannel typedef void (*AudioChannelCallback_t)(PortabilityLayer::AudioChannel *channel);
{
};
struct SndCommand struct AudioChannel
{ {
SndCommandType cmd; virtual void Destroy(bool wait) = 0;
intptr_t param1; virtual bool AddBuffer(const void *smBuffer, bool blocking) = 0;
intptr_t param2; virtual bool AddCallback(AudioChannelCallback_t callback, bool blocking) = 0;
}; virtual void ClearAllCommands() = 0;
virtual void Stop() = 0;
};
enum SndSynthType class SoundSystem
{ {
sampledSynth public:
}; virtual AudioChannel *CreateChannel() = 0;
enum SndInitFlags virtual void SetVolume(uint8_t vol) = 0;
{ virtual uint8_t GetVolume() const = 0;
initNoInterp = 1,
initMono = 2,
};
typedef SndChannel *SndChannelPtr; static SoundSystem *GetInstance();
};
typedef void(*SndCallBackProc)(SndChannelPtr channel, SndCommand *command); }
typedef SndCallBackProc SndCallBackUPP;
// Vol seems to be a packed stereo DWord
PLError_t GetDefaultOutputVolume(long *vol);
PLError_t SetDefaultOutputVolume(long vol);
SndCallBackUPP NewSndCallBackProc(SndCallBackProc callback);
void DisposeSndCallBackUPP(SndCallBackUPP upp);
PLError_t SndNewChannel(SndChannelPtr *outChannel, SndSynthType synthType, int initFlags, SndCallBackUPP callback);
PLError_t SndDisposeChannel(SndChannelPtr channel, Boolean flush);
PLError_t SndDoCommand(SndChannelPtr channel, const SndCommand *command, Boolean failIfFull);
PLError_t SndDoImmediate(SndChannelPtr channel, const SndCommand *command);
#endif

View File

@@ -194,7 +194,6 @@
<ClInclude Include="PLDialogs.h" /> <ClInclude Include="PLDialogs.h" />
<ClInclude Include="PLErrorCodes.h" /> <ClInclude Include="PLErrorCodes.h" />
<ClInclude Include="PLEventQueue.h" /> <ClInclude Include="PLEventQueue.h" />
<ClInclude Include="PLFolders.h" />
<ClInclude Include="PLHacks.h" /> <ClInclude Include="PLHacks.h" />
<ClInclude Include="PLHandle.h" /> <ClInclude Include="PLHandle.h" />
<ClInclude Include="PLKeyEncoding.h" /> <ClInclude Include="PLKeyEncoding.h" />

View File

@@ -123,9 +123,6 @@
<ClInclude Include="PLTextUtils.h"> <ClInclude Include="PLTextUtils.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="PLFolders.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="PLScript.h"> <ClInclude Include="PLScript.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>