Skip to content

Commit 288a1e8

Browse files
committed
Cocoa Port: Finish refactoring the audio output code. (Related to commit 3b07d28.)
1 parent a08de1b commit 288a1e8

File tree

16 files changed

+740
-719
lines changed

16 files changed

+740
-719
lines changed

desmume/src/frontend/cocoa/ClientAudioOutput.cpp

Lines changed: 234 additions & 63 deletions
Large diffs are not rendered by default.

desmume/src/frontend/cocoa/ClientAudioOutput.h

Lines changed: 53 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,36 +20,77 @@
2020

2121
#include "ClientEmulationOutput.h"
2222

23+
#include "rthreads.h"
2324
#include "../../SPU.h"
2425

2526

27+
class ClientAudioOutputEngine
28+
{
29+
protected:
30+
int _engineID;
31+
std::string _engineString;
32+
int _bufferSizeForSPUInit;
33+
bool _isPaused;
34+
35+
public:
36+
ClientAudioOutputEngine();
37+
virtual ~ClientAudioOutputEngine();
38+
39+
int GetEngineID() const;
40+
const char* GetEngineString() const;
41+
int GetBufferSizeForSPUInit() const;
42+
bool IsPaused() const;
43+
44+
virtual void Start();
45+
virtual void Stop();
46+
virtual void SetMute(bool theState);
47+
virtual void SetPause(bool theState);
48+
virtual void SetVolume(int volume);
49+
50+
virtual size_t GetAvailableSamples() const;
51+
virtual void WriteToBuffer(const void *inSamples, size_t numberSampleFrames);
52+
virtual void ClearBuffer();
53+
54+
virtual void HandleFetchSamples(s16 *sampleBuffer, size_t sampleCount, ESynchMode synchMode, ISynchronizingAudioBuffer *theSynchronizer);
55+
virtual size_t HandlePostProcessSamples(s16 *postProcessBuffer, size_t requestedSampleCount, ESynchMode synchMode, ISynchronizingAudioBuffer *theSynchronizer);
56+
57+
};
58+
59+
class DummyAudioOutputEngine : public ClientAudioOutputEngine
60+
{
61+
public:
62+
DummyAudioOutputEngine() {};
63+
};
64+
2665
class ClientAudioOutput : public ClientEmulationOutput
2766
{
2867
protected:
68+
DummyAudioOutputEngine *_dummyAudioEngine;
69+
ClientAudioOutputEngine *_audioEngine;
70+
SoundInterface_struct _spuCallbackStruct;
71+
2972
float _volume;
30-
int _engineID;
3173
bool _spuAdvancedLogic;
3274
SPUInterpolationMode _interpolationModeID;
3375
ESynchMode _syncModeID;
3476
ESynchMethod _syncMethodID;
3577
bool _isMuted;
36-
int _filterID;
3778

38-
std::string _engineString;
3979
std::string _spuInterpolationModeString;
4080
std::string _spuSyncMethodString;
4181

42-
pthread_mutex_t _mutexEngine;
43-
pthread_mutex_t _mutexVolume;
44-
pthread_mutex_t _mutexSpuAdvancedLogic;
45-
pthread_mutex_t _mutexSpuInterpolationMode;
46-
pthread_mutex_t _mutexSpuSyncMethod;
82+
slock_t *_mutexEngine;
83+
slock_t *_mutexVolume;
84+
slock_t *_mutexSpuAdvancedLogic;
85+
slock_t *_mutexSpuInterpolationMode;
86+
slock_t *_mutexSpuSyncMethod;
4787

4888
public:
4989
ClientAudioOutput();
5090
~ClientAudioOutput();
5191

52-
void SetEngineByID(int engineID);
92+
void SetEngine(ClientAudioOutputEngine *theEngine);
93+
ClientAudioOutputEngine* GetEngine();
5394
int GetEngineByID();
5495

5596
void SetVolume(float vol);
@@ -70,12 +111,12 @@ class ClientAudioOutput : public ClientEmulationOutput
70111
void SetMute(bool theState);
71112
bool IsMuted();
72113

73-
void SetFilterByID(int filterID);
74-
int GetFilterByID();
75-
76114
const char* GetEngineString();
77115
const char* GetSPUInterpolationModeString();
78116
const char* GetSPUSyncMethodString();
117+
118+
// ClientEmulationOutput methods
119+
virtual void SetIdle(bool theState);
79120
};
80121

81122
#endif // _CLIENT_AUDIO_OUTPUT_H_

desmume/src/frontend/cocoa/ClientExecutionControl.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright (C) 2017-2022 DeSmuME team
2+
Copyright (C) 2017-2025 DeSmuME team
33
44
This file is free software: you can redistribute it and/or modify
55
it under the terms of the GNU General Public License as published by
@@ -28,6 +28,7 @@
2828

2929
#include "ClientAVCaptureObject.h"
3030
#include "ClientExecutionControl.h"
31+
#include "cocoa_globals.h"
3132

3233
// Need to include assert.h this way so that GDB stub will work
3334
// with an optimized build.

desmume/src/frontend/cocoa/ClientExecutionControl.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright (C) 2017-2021 DeSmuME team
2+
Copyright (C) 2017-2025 DeSmuME team
33
44
This file is free software: you can redistribute it and/or modify
55
it under the terms of the GNU General Public License as published by
@@ -37,7 +37,6 @@
3737
#define SPEED_SCALAR_DOUBLE 2.0 // Speed scalar for double execution speed.
3838
#define SPEED_SCALAR_MIN 0.005 // Lower limit for the speed multiplier.
3939

40-
#define DS_FRAMES_PER_SECOND 59.8261 // Number of DS frames per second.
4140
#define DS_SECONDS_PER_FRAME (1.0 / DS_FRAMES_PER_SECOND) // The length of time in seconds that, ideally, a frame should be processed within.
4241

4342
#define FRAME_SKIP_AGGRESSIVENESS 1.0 // Must be a value between 0.0 (inclusive) and positive infinity.

desmume/src/frontend/cocoa/DeSmuME (Latest).xcodeproj/project.pbxproj

Lines changed: 24 additions & 24 deletions
Large diffs are not rendered by default.

desmume/src/frontend/cocoa/DeSmuME (XCode 3).xcodeproj/project.pbxproj

Lines changed: 14 additions & 14 deletions
Large diffs are not rendered by default.

desmume/src/frontend/cocoa/cocoa_globals.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,8 @@
189189

190190
#define WINDOW_STATUS_BAR_HEIGHT 24 // Height of an emulation window status bar in pixels.
191191

192+
#define DS_FRAMES_PER_SECOND 59.8261 // Number of DS frames per second.
193+
192194
//#define SPU_SAMPLE_RATE (44100.0 * DS_FRAMES_PER_SECOND / 60.0) // Samples per second
193195
#define SPU_SAMPLE_RATE 44100.0 // Samples per second
194196
#define SPU_SAMPLE_RESOLUTION 16 // Bits per sample; must be a multiple of 8

desmume/src/frontend/cocoa/coreaudiosound.cpp

Lines changed: 2 additions & 201 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright (C) 2012-2022 DeSmuME team
2+
Copyright (C) 2012-2025 DeSmuME team
33
44
This file is free software: you can redistribute it and/or modify
55
it under the terms of the GNU General Public License as published by
@@ -16,6 +16,7 @@
1616
*/
1717

1818
#include "coreaudiosound.h"
19+
#include "MacCoreAudioOutputEngine.h"
1920

2021
#include <CoreAudio/CoreAudio.h>
2122
#include "ClientInputHandler.h"
@@ -903,206 +904,6 @@ void CoreAudioInputDefaultHardwareGainChangedCallback(float normalizedGain, void
903904

904905
#pragma mark -
905906

906-
CoreAudioOutput::CoreAudioOutput(size_t bufferSamples, size_t sampleSize)
907-
{
908-
OSStatus error = noErr;
909-
910-
_unfairlockAU = apple_unfairlock_create();
911-
912-
_buffer = new RingBuffer(bufferSamples, sampleSize);
913-
_volume = 1.0f;
914-
915-
// Create a new audio unit
916-
#if !defined(FORCE_AUDIOCOMPONENT_10_5) && defined(MAC_OS_X_VERSION_10_6) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6)
917-
if (IsOSXVersionSupported(10, 6, 0))
918-
{
919-
AudioComponentDescription audioDesc;
920-
audioDesc.componentType = kAudioUnitType_Output;
921-
audioDesc.componentSubType = kAudioUnitSubType_DefaultOutput;
922-
audioDesc.componentManufacturer = kAudioUnitManufacturer_Apple;
923-
audioDesc.componentFlags = 0;
924-
audioDesc.componentFlagsMask = 0;
925-
926-
CreateAudioUnitInstance(&_au, &audioDesc);
927-
}
928-
else
929-
#endif
930-
{
931-
ComponentDescription audioDesc;
932-
audioDesc.componentType = kAudioUnitType_Output;
933-
audioDesc.componentSubType = kAudioUnitSubType_DefaultOutput;
934-
audioDesc.componentManufacturer = kAudioUnitManufacturer_Apple;
935-
audioDesc.componentFlags = 0;
936-
audioDesc.componentFlagsMask = 0;
937-
938-
CreateAudioUnitInstance(&_au, &audioDesc);
939-
}
940-
941-
// Set the render callback
942-
AURenderCallbackStruct callback;
943-
callback.inputProc = &CoreAudioOutputRenderCallback;
944-
callback.inputProcRefCon = _buffer;
945-
946-
error = AudioUnitSetProperty(_au,
947-
kAudioUnitProperty_SetRenderCallback,
948-
kAudioUnitScope_Input,
949-
0,
950-
&callback,
951-
sizeof(callback) );
952-
953-
if(error != noErr)
954-
{
955-
return;
956-
}
957-
958-
// Set up the audio unit for audio streaming
959-
AudioStreamBasicDescription outputFormat;
960-
outputFormat.mSampleRate = SPU_SAMPLE_RATE;
961-
outputFormat.mFormatID = kAudioFormatLinearPCM;
962-
outputFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kLinearPCMFormatFlagIsPacked;
963-
outputFormat.mBytesPerPacket = SPU_SAMPLE_SIZE;
964-
outputFormat.mFramesPerPacket = 1;
965-
outputFormat.mBytesPerFrame = SPU_SAMPLE_SIZE;
966-
outputFormat.mChannelsPerFrame = SPU_NUMBER_CHANNELS;
967-
outputFormat.mBitsPerChannel = SPU_SAMPLE_RESOLUTION;
968-
969-
error = AudioUnitSetProperty(_au,
970-
kAudioUnitProperty_StreamFormat,
971-
kAudioUnitScope_Input,
972-
0,
973-
&outputFormat,
974-
sizeof(outputFormat) );
975-
976-
if(error != noErr)
977-
{
978-
return;
979-
}
980-
981-
// Initialize our new audio unit
982-
error = AudioUnitInitialize(_au);
983-
if(error != noErr)
984-
{
985-
return;
986-
}
987-
}
988-
989-
CoreAudioOutput::~CoreAudioOutput()
990-
{
991-
apple_unfairlock_lock(this->_unfairlockAU);
992-
DestroyAudioUnitInstance(&this->_au);
993-
apple_unfairlock_unlock(this->_unfairlockAU);
994-
995-
delete this->_buffer;
996-
this->_buffer = NULL;
997-
998-
apple_unfairlock_destroy(this->_unfairlockAU);
999-
}
1000-
1001-
void CoreAudioOutput::start()
1002-
{
1003-
this->clearBuffer();
1004-
1005-
apple_unfairlock_lock(this->_unfairlockAU);
1006-
AudioUnitReset(this->_au, kAudioUnitScope_Global, 0);
1007-
AudioOutputUnitStart(this->_au);
1008-
apple_unfairlock_unlock(this->_unfairlockAU);
1009-
}
1010-
1011-
void CoreAudioOutput::pause()
1012-
{
1013-
apple_unfairlock_lock(this->_unfairlockAU);
1014-
AudioOutputUnitStop(this->_au);
1015-
apple_unfairlock_unlock(this->_unfairlockAU);
1016-
}
1017-
1018-
void CoreAudioOutput::unpause()
1019-
{
1020-
apple_unfairlock_lock(this->_unfairlockAU);
1021-
AudioOutputUnitStart(this->_au);
1022-
apple_unfairlock_unlock(this->_unfairlockAU);
1023-
}
1024-
1025-
void CoreAudioOutput::stop()
1026-
{
1027-
apple_unfairlock_lock(this->_unfairlockAU);
1028-
AudioOutputUnitStop(this->_au);
1029-
apple_unfairlock_unlock(this->_unfairlockAU);
1030-
1031-
this->clearBuffer();
1032-
}
1033-
1034-
void CoreAudioOutput::writeToBuffer(const void *buffer, size_t numberSampleFrames)
1035-
{
1036-
size_t availableSampleFrames = this->_buffer->getAvailableElements();
1037-
if (availableSampleFrames < numberSampleFrames)
1038-
{
1039-
this->_buffer->drop(numberSampleFrames - availableSampleFrames);
1040-
}
1041-
1042-
this->_buffer->write(buffer, numberSampleFrames);
1043-
}
1044-
1045-
void CoreAudioOutput::clearBuffer()
1046-
{
1047-
this->_buffer->clear();
1048-
}
1049-
1050-
void CoreAudioOutput::mute()
1051-
{
1052-
apple_unfairlock_lock(this->_unfairlockAU);
1053-
AudioUnitSetParameter(this->_au, kHALOutputParam_Volume, kAudioUnitScope_Global, 0, 0.0f, 0);
1054-
apple_unfairlock_unlock(this->_unfairlockAU);
1055-
}
1056-
1057-
void CoreAudioOutput::unmute()
1058-
{
1059-
apple_unfairlock_lock(this->_unfairlockAU);
1060-
AudioUnitSetParameter(this->_au, kHALOutputParam_Volume, kAudioUnitScope_Global, 0, this->_volume, 0);
1061-
apple_unfairlock_unlock(this->_unfairlockAU);
1062-
}
1063-
1064-
size_t CoreAudioOutput::getAvailableSamples() const
1065-
{
1066-
return this->_buffer->getAvailableElements();
1067-
}
1068-
1069-
float CoreAudioOutput::getVolume() const
1070-
{
1071-
return this->_volume;
1072-
}
1073-
1074-
void CoreAudioOutput::setVolume(float vol)
1075-
{
1076-
this->_volume = vol;
1077-
1078-
apple_unfairlock_lock(this->_unfairlockAU);
1079-
AudioUnitSetParameter(this->_au, kHALOutputParam_Volume, kAudioUnitScope_Global, 0, vol, 0);
1080-
apple_unfairlock_unlock(this->_unfairlockAU);
1081-
}
1082-
1083-
OSStatus CoreAudioOutputRenderCallback(void *inRefCon,
1084-
AudioUnitRenderActionFlags *ioActionFlags,
1085-
const AudioTimeStamp *inTimeStamp,
1086-
UInt32 inBusNumber,
1087-
UInt32 inNumberFrames,
1088-
AudioBufferList *ioData)
1089-
{
1090-
RingBuffer *__restrict__ audioBuffer = (RingBuffer *)inRefCon;
1091-
UInt8 *__restrict__ playbackBuffer = (UInt8 *)ioData->mBuffers[0].mData;
1092-
const size_t framesRead = audioBuffer->read(playbackBuffer, inNumberFrames);
1093-
1094-
// Pad any remaining samples.
1095-
if (framesRead < inNumberFrames)
1096-
{
1097-
const size_t frameSize = audioBuffer->getElementSize();
1098-
memset(playbackBuffer + (framesRead * frameSize), 0, (inNumberFrames - framesRead) * frameSize);
1099-
}
1100-
1101-
return noErr;
1102-
}
1103-
1104-
#pragma mark -
1105-
1106907
bool CreateAudioUnitInstance(AudioUnit *au, ComponentDescription *auDescription)
1107908
{
1108909
bool result = false;

0 commit comments

Comments
 (0)