Cocoa Port: Refactor the hardware mic stuff out of CocoaDSController and into ClientInputHandler.

This commit is contained in:
rogerman 2017-09-21 00:33:28 -07:00
parent f8bbbec0ae
commit f521ab1164
11 changed files with 398 additions and 159 deletions

View File

@ -73,7 +73,14 @@ ClientInputHandler::ClientInputHandler()
_internalNoiseGenerator = new InternalNoiseGenerator; _internalNoiseGenerator = new InternalNoiseGenerator;
_whiteNoiseGenerator = new WhiteNoiseGenerator; _whiteNoiseGenerator = new WhiteNoiseGenerator;
_sineWaveGenerator = new SineWaveGenerator(250.0, MIC_SAMPLE_RATE); _sineWaveGenerator = new SineWaveGenerator(250.0, MIC_SAMPLE_RATE);
_selectedAudioFileGenerator = NULL; _selectedAudioFileGenerator = NULL; // Note that this value can be NULL.
_hardwareMicSampleGenerator = _nullSampleGenerator;
_avgMicLevel = 0.0f;
_avgMicLevelTotal = 0.0f;
_avgMicLevelsRead = 0.0f;
_isHardwareMicMuted = true;
_isHardwareMicPaused = true;
_enableAutohold = false; _enableAutohold = false;
@ -83,7 +90,9 @@ ClientInputHandler::ClientInputHandler()
_paddleValuePending = _paddleValueProcessing = _paddleValueApplied = 0; _paddleValuePending = _paddleValueProcessing = _paddleValueApplied = 0;
_paddleAdjustPending = _paddleAdjustProcessing = _paddleAdjustApplied = 0; _paddleAdjustPending = _paddleAdjustProcessing = _paddleAdjustApplied = 0;
_softwareMicSampleGeneratorPending = _softwareMicSampleGeneratorProcessing = _softwareMicSampleGeneratorApplied = _nullSampleGenerator; _softwareMicSampleGeneratorPending = _nullSampleGenerator;
_softwareMicSampleGeneratorProcessing = _nullSampleGenerator;
_softwareMicSampleGeneratorApplied = _nullSampleGenerator;
memset(_clientInputPending, 0, sizeof(_clientInputPending)); memset(_clientInputPending, 0, sizeof(_clientInputPending));
memset(_clientInputProcessing, 0, sizeof(_clientInputProcessing)); memset(_clientInputProcessing, 0, sizeof(_clientInputProcessing));
@ -257,6 +266,35 @@ void ClientInputHandler::SetSineWaveFrequency(double freq)
this->_sineWaveGenerator->setFrequency(freq); this->_sineWaveGenerator->setFrequency(freq);
} }
float ClientInputHandler::GetAverageMicLevel()
{
return this->_avgMicLevel;
}
void ClientInputHandler::AddSampleToAverageMicLevel(uint8_t sampleValue)
{
this->_avgMicLevelTotal += (float)( (MIC_NULL_SAMPLE_VALUE > sampleValue) ? MIC_NULL_SAMPLE_VALUE - sampleValue : sampleValue - MIC_NULL_SAMPLE_VALUE );
this->_avgMicLevelsRead += 1.0f;
this->_avgMicLevel = this->_avgMicLevelTotal / this->_avgMicLevelsRead;
}
void ClientInputHandler::ClearAverageMicLevel()
{
this->_avgMicLevelTotal = 0.0f;
this->_avgMicLevelsRead = 0.0f;
this->_avgMicLevel = 0.0f;
}
bool ClientInputHandler::IsMicrophoneIdle()
{
return (this->_avgMicLevel < MIC_NULL_LEVEL_THRESHOLD);
}
bool ClientInputHandler::IsMicrophoneClipping()
{
return (this->_avgMicLevel >= MIC_CLIP_LEVEL_THRESHOLD);
}
AudioGenerator* ClientInputHandler::GetClientSoftwareMicSampleGenerator() AudioGenerator* ClientInputHandler::GetClientSoftwareMicSampleGenerator()
{ {
pthread_mutex_lock(&this->_mutexInputsPending); pthread_mutex_lock(&this->_mutexInputsPending);
@ -287,6 +325,23 @@ void ClientInputHandler::SetClientSelectedAudioFileGenerator(AudioSampleBlockGen
pthread_mutex_unlock(&this->_mutexInputsPending); pthread_mutex_unlock(&this->_mutexInputsPending);
} }
void ClientInputHandler::SetClientHardwareMicSampleGeneratorApplied(AudioGenerator *hwGenerator)
{
if (hwGenerator == NULL)
{
this->_hardwareMicSampleGenerator = this->_nullSampleGenerator;
}
else
{
this->_hardwareMicSampleGenerator = hwGenerator;
}
}
AudioGenerator* ClientInputHandler::GetClientHardwareMicSampleGeneratorApplied()
{
return this->_hardwareMicSampleGenerator;
}
bool ClientInputHandler::GetClientSoftwareMicState() bool ClientInputHandler::GetClientSoftwareMicState()
{ {
pthread_mutex_lock(&this->_mutexInputsPending); pthread_mutex_lock(&this->_mutexInputsPending);
@ -611,3 +666,73 @@ void ClientInputHandler::ApplyInputs()
FCEUMOV_HandleRecording(); FCEUMOV_HandleRecording();
} }
} }
bool ClientInputHandler::IsHardwareMicAvailable()
{
// Do nothing. This is implementation-dependent.
return false;
}
void ClientInputHandler::ResetHardwareMic()
{
this->ClearAverageMicLevel();
this->ReportAverageMicLevel();
this->_hardwareMicSampleGenerator->resetSamples();
}
uint8_t ClientInputHandler::HandleMicSampleRead()
{
uint8_t theSample = MIC_NULL_SAMPLE_VALUE;
AudioGenerator *sampleGenerator = (this->GetClientSoftwareMicStateApplied()) ? this->GetClientSoftwareMicSampleGeneratorApplied() : this->_hardwareMicSampleGenerator;
theSample = sampleGenerator->generateSample();
this->AddSampleToAverageMicLevel(theSample);
return theSample;
}
void ClientInputHandler::ReportAverageMicLevel()
{
// Do nothing. This is implementation-dependent.
// This method mainly exists for implementations to do some stuff during the
// emulation loop.
}
bool ClientInputHandler::GetHardwareMicMute()
{
return this->_isHardwareMicMuted;
}
void ClientInputHandler::SetHardwareMicMute(bool muteState)
{
this->_isHardwareMicMuted = muteState;
if (muteState)
{
this->_hardwareMicSampleGenerator->resetSamples();
this->ClearAverageMicLevel();
}
}
bool ClientInputHandler::GetHardwareMicPause()
{
return this->_isHardwareMicPaused;
}
void ClientInputHandler::SetHardwareMicPause(bool pauseState)
{
this->_isHardwareMicPaused = pauseState;
}
float ClientInputHandler::GetHardwareMicNormalizedGain()
{
// Do nothing. This is implementation-dependent.
// The default value is 0.0f, which represents 0.0% of the hardware device's pickup sensitivity.
return 0.0f;
}
void ClientInputHandler::SetHardwareMicGainAsNormalized(float normalizedGain)
{
// Do nothing. This is implementation-dependent.
}

View File

@ -330,6 +330,8 @@ protected:
SineWaveGenerator *_sineWaveGenerator; SineWaveGenerator *_sineWaveGenerator;
AudioSampleBlockGenerator *_selectedAudioFileGenerator; AudioSampleBlockGenerator *_selectedAudioFileGenerator;
AudioGenerator *_hardwareMicSampleGenerator;
ClientInput _clientInputPending[NDSInputID_InputCount]; ClientInput _clientInputPending[NDSInputID_InputCount];
ClientInput _clientInputProcessing[NDSInputID_InputCount]; ClientInput _clientInputProcessing[NDSInputID_InputCount];
ClientInput _clientInputApplied[NDSInputID_InputCount]; ClientInput _clientInputApplied[NDSInputID_InputCount];
@ -354,6 +356,12 @@ protected:
int16_t _paddleValueApplied; int16_t _paddleValueApplied;
int16_t _paddleAdjustApplied; int16_t _paddleAdjustApplied;
float _avgMicLevel;
float _avgMicLevelTotal;
float _avgMicLevelsRead;
bool _isHardwareMicMuted;
bool _isHardwareMicPaused;
pthread_mutex_t _mutexInputsPending; pthread_mutex_t _mutexInputsPending;
public: public:
@ -374,11 +382,21 @@ public:
double GetSineWaveFrequency(); double GetSineWaveFrequency();
void SetSineWaveFrequency(double freq); void SetSineWaveFrequency(double freq);
float GetAverageMicLevel();
void AddSampleToAverageMicLevel(uint8_t sampleValue);
void ClearAverageMicLevel();
bool IsMicrophoneIdle();
bool IsMicrophoneClipping();
AudioGenerator* GetClientSoftwareMicSampleGenerator(); AudioGenerator* GetClientSoftwareMicSampleGenerator();
AudioGenerator* GetClientSoftwareMicSampleGeneratorApplied(); AudioGenerator* GetClientSoftwareMicSampleGeneratorApplied();
AudioSampleBlockGenerator* GetClientSelectedAudioFileGenerator(); AudioSampleBlockGenerator* GetClientSelectedAudioFileGenerator();
void SetClientSelectedAudioFileGenerator(AudioSampleBlockGenerator *selectedAudioFileGenerator); void SetClientSelectedAudioFileGenerator(AudioSampleBlockGenerator *selectedAudioFileGenerator);
void SetClientHardwareMicSampleGeneratorApplied(AudioGenerator *hwGenerator);
AudioGenerator* GetClientHardwareMicSampleGeneratorApplied();
bool GetClientSoftwareMicState(); bool GetClientSoftwareMicState();
bool GetClientSoftwareMicStateApplied(); bool GetClientSoftwareMicStateApplied();
void SetClientSoftwareMicState(bool pressedState, MicrophoneMode micMode); void SetClientSoftwareMicState(bool pressedState, MicrophoneMode micMode);
@ -395,6 +413,20 @@ public:
void ProcessInputs(); void ProcessInputs();
void ApplyInputs(); void ApplyInputs();
virtual bool IsHardwareMicAvailable();
virtual void ResetHardwareMic();
virtual uint8_t HandleMicSampleRead();
virtual void ReportAverageMicLevel();
virtual bool GetHardwareMicMute();
virtual void SetHardwareMicMute(bool muteState);
virtual bool GetHardwareMicPause();
virtual void SetHardwareMicPause(bool pauseState);
virtual float GetHardwareMicNormalizedGain();
virtual void SetHardwareMicGainAsNormalized(float normalizedGain);
}; };
#endif // _CLIENT_INPUT_HANDLER_H_ #endif // _CLIENT_INPUT_HANDLER_H_

View File

@ -33,6 +33,21 @@ static const uint8_t noiseSample[NUM_INTERNAL_NOISE_SAMPLES] =
0xF4, 0xE1, 0xBF, 0x9A, 0x71, 0x58, 0x5B, 0x5F, 0x62, 0xC2, 0x25, 0x05, 0x01, 0x01, 0x01, 0x01 0xF4, 0xE1, 0xBF, 0x9A, 0x71, 0x58, 0x5B, 0x5F, 0x62, 0xC2, 0x25, 0x05, 0x01, 0x01, 0x01, 0x01
}; };
size_t AudioGenerator::resetSamples()
{
// Do nothing. This is implementation-dependent.
//
// The return value represents the number of samples that were dropped.
// By default, return 0 to signify that no samples are dropped. In other
// words, all samples will continue to exist after the reset.
return 0;
}
uint8_t AudioGenerator::generateSample()
{
return MIC_NULL_SAMPLE_VALUE;
}
size_t AudioGenerator::generateSampleBlock(size_t sampleCount, uint8_t *outBuffer) size_t AudioGenerator::generateSampleBlock(size_t sampleCount, uint8_t *outBuffer)
{ {
if (outBuffer == NULL) if (outBuffer == NULL)
@ -48,11 +63,6 @@ size_t AudioGenerator::generateSampleBlock(size_t sampleCount, uint8_t *outBuffe
return sampleCount; return sampleCount;
} }
uint8_t AudioGenerator::generateSample()
{
return MIC_NULL_SAMPLE_VALUE;
}
AudioSampleBlockGenerator::AudioSampleBlockGenerator(const uint8_t *audioBuffer, const size_t sampleCount) AudioSampleBlockGenerator::AudioSampleBlockGenerator(const uint8_t *audioBuffer, const size_t sampleCount)
{ {
_buffer = (uint8_t *)malloc(sampleCount * sizeof(uint8_t)); _buffer = (uint8_t *)malloc(sampleCount * sizeof(uint8_t));

View File

@ -28,8 +28,9 @@ public:
AudioGenerator() {}; AudioGenerator() {};
virtual ~AudioGenerator() {}; virtual ~AudioGenerator() {};
virtual size_t generateSampleBlock(size_t sampleCount, uint8_t *outBuffer); virtual size_t resetSamples();
virtual uint8_t generateSample(); virtual uint8_t generateSample();
virtual size_t generateSampleBlock(size_t sampleCount, uint8_t *outBuffer);
}; };
class NullGenerator : public AudioGenerator {}; class NullGenerator : public AudioGenerator {};

View File

@ -870,7 +870,6 @@ volatile bool execute = true;
[self setMasterExecute:YES]; [self setMasterExecute:YES];
[self restoreCoreState]; [self restoreCoreState];
[[self cdsController] reset]; [[self cdsController] reset];
[[self cdsController] updateMicLevel];
} }
- (void) getTimedEmulatorStatistics:(NSTimer *)timer - (void) getTimedEmulatorStatistics:(NSTimer *)timer
@ -1159,6 +1158,10 @@ static void* RunCoreThread(void *arg)
NDSError ndsError = NDS_GetLastError(); NDSError ndsError = NDS_GetLastError();
pthread_mutex_unlock(&param->mutexThreadExecute); pthread_mutex_unlock(&param->mutexThreadExecute);
inputHandler->SetHardwareMicPause(true);
inputHandler->ClearAverageMicLevel();
inputHandler->ReportAverageMicLevel();
[cdsCore postNDSError:ndsError]; [cdsCore postNDSError:ndsError];
continue; continue;
} }
@ -1167,9 +1170,8 @@ static void* RunCoreThread(void *arg)
// of whether the NDS actually reads the mic or not. // of whether the NDS actually reads the mic or not.
if ((ndsFrameInfo.frameIndex & 0x07) == 0x07) if ((ndsFrameInfo.frameIndex & 0x07) == 0x07)
{ {
CocoaDSController *cdsController = [cdsCore cdsController]; inputHandler->ReportAverageMicLevel();
[cdsController updateMicLevel]; inputHandler->ClearAverageMicLevel();
[cdsController clearMicLevelMeasure];
} }
const uint8_t framesToSkip = execControl->GetFramesToSkip(); const uint8_t framesToSkip = execControl->GetFramesToSkip();

View File

@ -20,6 +20,8 @@
#include <libkern/OSAtomic.h> #include <libkern/OSAtomic.h>
#include <vector> #include <vector>
#include "ClientInputHandler.h"
@class CocoaDSController; @class CocoaDSController;
class ClientInputHandler; class ClientInputHandler;
class CoreAudioInput; class CoreAudioInput;
@ -45,16 +47,7 @@ class AudioSampleBlockGenerator;
ClientInputHandler *inputHandler; ClientInputHandler *inputHandler;
NSInteger stylusPressure; NSInteger stylusPressure;
float micLevel;
float _micLevelTotal;
float _micLevelsRead;
BOOL hardwareMicMute;
size_t _availableMicSamples;
CoreAudioInput *CAInputDevice;
NSString *hardwareMicInfoString; NSString *hardwareMicInfoString;
NSString *hardwareMicNameString; NSString *hardwareMicNameString;
NSString *hardwareMicManufacturerString; NSString *hardwareMicManufacturerString;
@ -70,13 +63,9 @@ class AudioSampleBlockGenerator;
@property (readonly) BOOL isHardwareMicIdle; @property (readonly) BOOL isHardwareMicIdle;
@property (readonly) BOOL isHardwareMicInClip; @property (readonly) BOOL isHardwareMicInClip;
@property (assign) float micLevel; @property (assign) float micLevel;
@property (assign) BOOL hardwareMicEnabled;
@property (readonly) BOOL hardwareMicLocked;
@property (assign) float hardwareMicGain; @property (assign) float hardwareMicGain;
@property (assign) BOOL hardwareMicMute; @property (assign) BOOL hardwareMicMute;
@property (assign) BOOL hardwareMicPause; @property (assign) BOOL hardwareMicPause;
@property (readonly) CoreAudioInput *CAInputDevice;
@property (readonly) AudioGenerator *softwareMicSampleGenerator;
@property (assign) AudioSampleBlockGenerator *selectedAudioFileGenerator; @property (assign) AudioSampleBlockGenerator *selectedAudioFileGenerator;
@property (retain) NSString *hardwareMicInfoString; @property (retain) NSString *hardwareMicInfoString;
@property (retain) NSString *hardwareMicNameString; @property (retain) NSString *hardwareMicNameString;
@ -91,10 +80,8 @@ class AudioSampleBlockGenerator;
- (void) setSineWaveGeneratorFrequency:(const double)freq; - (void) setSineWaveGeneratorFrequency:(const double)freq;
- (void) clearAutohold; - (void) clearAutohold;
- (void) reset; - (void) reset;
- (void) startHardwareMicDevice;
- (void) clearMicLevelMeasure;
- (void) updateMicLevel;
- (uint8_t) handleMicSampleRead:(CoreAudioInput *)caInput softwareMic:(AudioGenerator *)sampleGenerator;
- (void) handleMicHardwareStateChanged:(CoreAudioInputDeviceInfo *)deviceInfo - (void) handleMicHardwareStateChanged:(CoreAudioInputDeviceInfo *)deviceInfo
isEnabled:(BOOL)isHardwareEnabled isEnabled:(BOOL)isHardwareEnabled
isLocked:(BOOL)isHardwareLocked; isLocked:(BOOL)isHardwareLocked;
@ -102,6 +89,33 @@ class AudioSampleBlockGenerator;
@end @end
class MacInputHandler : public ClientInputHandler
{
private:
CocoaDSController *_cdsController;
CoreAudioInput *_CAInputDevice;
public:
MacInputHandler();
~MacInputHandler();
CocoaDSController* GetCocoaController();
void SetCocoaController(CocoaDSController *theController);
void StartHardwareMicDevice();
virtual bool IsHardwareMicAvailable();
virtual void ReportAverageMicLevel();
virtual void SetHardwareMicMute(bool muteState);
virtual bool GetHardwareMicPause();
virtual void SetHardwareMicPause(bool pauseState);
virtual float GetHardwareMicNormalizedGain();
virtual void SetHardwareMicGainAsNormalized(float normalizedGain);
};
#ifdef __cplusplus #ifdef __cplusplus
extern "C" extern "C"
{ {

View File

@ -26,8 +26,6 @@
#include "../../slot2.h" #include "../../slot2.h"
#undef BOOL #undef BOOL
#include "ClientInputHandler.h"
@implementation CocoaDSController @implementation CocoaDSController
@ -39,14 +37,10 @@
@dynamic isHardwareMicAvailable; @dynamic isHardwareMicAvailable;
@dynamic isHardwareMicIdle; @dynamic isHardwareMicIdle;
@dynamic isHardwareMicInClip; @dynamic isHardwareMicInClip;
@synthesize micLevel; @dynamic micLevel;
@dynamic hardwareMicEnabled;
@dynamic hardwareMicLocked;
@dynamic hardwareMicGain; @dynamic hardwareMicGain;
@synthesize hardwareMicMute; @dynamic hardwareMicMute;
@dynamic hardwareMicPause; @dynamic hardwareMicPause;
@synthesize CAInputDevice;
@dynamic softwareMicSampleGenerator;
@dynamic selectedAudioFileGenerator; @dynamic selectedAudioFileGenerator;
@synthesize hardwareMicInfoString; @synthesize hardwareMicInfoString;
@synthesize hardwareMicNameString; @synthesize hardwareMicNameString;
@ -62,32 +56,20 @@
} }
delegate = nil; delegate = nil;
inputHandler = new ClientInputHandler;
_availableMicSamples = 0;
micLevel = 0.0f;
_micLevelTotal = 0.0f;
_micLevelsRead = 0.0f;
CAInputDevice = new CoreAudioInput;
CAInputDevice->SetCallbackHardwareStateChanged(&CAHardwareStateChangedCallback, self, NULL);
CAInputDevice->SetCallbackHardwareGainChanged(&CAHardwareGainChangedCallback, self, NULL);
hardwareMicInfoString = @"No hardware input detected."; hardwareMicInfoString = @"No hardware input detected.";
hardwareMicNameString = @"No hardware input detected."; hardwareMicNameString = @"No hardware input detected.";
hardwareMicManufacturerString = @"No hardware input detected."; hardwareMicManufacturerString = @"No hardware input detected.";
hardwareMicSampleRateString = @"No hardware input detected."; hardwareMicSampleRateString = @"No hardware input detected.";
Mic_SetResetCallback(&CAResetCallback, self, NULL); inputHandler = new MacInputHandler;
Mic_SetSampleReadCallback(&CASampleReadCallback, self, NULL); ((MacInputHandler *)inputHandler)->SetCocoaController(self);
return self; return self;
} }
- (void)dealloc - (void)dealloc
{ {
delete CAInputDevice;
[self setDelegate:nil]; [self setDelegate:nil];
[self setHardwareMicInfoString:nil]; [self setHardwareMicInfoString:nil];
[self setHardwareMicNameString:nil]; [self setHardwareMicNameString:nil];
@ -104,62 +86,66 @@
- (BOOL) isHardwareMicAvailable - (BOOL) isHardwareMicAvailable
{ {
return ( CAInputDevice->IsHardwareEnabled() && return (inputHandler->IsHardwareMicAvailable()) ? YES : NO;
!CAInputDevice->IsHardwareLocked() &&
!CAInputDevice->GetPauseState() ) ? YES : NO;
} }
- (BOOL) isHardwareMicIdle - (BOOL) isHardwareMicIdle
{ {
return (micLevel < MIC_NULL_LEVEL_THRESHOLD); return (inputHandler->IsMicrophoneIdle()) ? YES : NO;
} }
- (BOOL) isHardwareMicInClip - (BOOL) isHardwareMicInClip
{ {
return (micLevel >= MIC_CLIP_LEVEL_THRESHOLD); return (inputHandler->IsMicrophoneClipping()) ? YES : NO;
} }
- (void) setHardwareMicEnabled:(BOOL)micEnabled - (void) setMicLevel:(float)micLevelValue
{ {
if (micEnabled) // This method doesn't set the mic level, since the mic level is always an internally
// calculated value. What this method actually does is trigger updates for any
// KVO-compliant controls that are associated with this property.
if ( (delegate != nil) && [delegate respondsToSelector:@selector(doMicLevelUpdateFromController:)] )
{ {
CAInputDevice->Start(); NSAutoreleasePool *tempPool = [[NSAutoreleasePool alloc] init];
} [[self delegate] doMicLevelUpdateFromController:self];
else [tempPool release];
{
CAInputDevice->Stop();
} }
} }
- (BOOL) hardwareMicEnabled - (float) micLevel
{ {
return (CAInputDevice->IsHardwareEnabled()) ? YES : NO; return inputHandler->GetAverageMicLevel();
}
- (BOOL) hardwareMicLocked
{
return (CAInputDevice->IsHardwareLocked()) ? YES : NO;
} }
- (void) setHardwareMicGain:(float)micGain - (void) setHardwareMicGain:(float)micGain
{ {
CAInputDevice->SetGain(micGain); inputHandler->SetHardwareMicGainAsNormalized(micGain);
} }
- (float) hardwareMicGain - (float) hardwareMicGain
{ {
return CAInputDevice->GetGain(); return inputHandler->GetHardwareMicNormalizedGain();
}
- (void) setHardwareMicMute:(BOOL)isMicMuted
{
inputHandler->SetHardwareMicMute((isMicMuted) ? true : false);
}
- (BOOL) hardwareMicMute
{
return (inputHandler->GetHardwareMicMute()) ? YES : NO;
} }
- (void) setHardwareMicPause:(BOOL)isMicPaused - (void) setHardwareMicPause:(BOOL)isMicPaused
{ {
bool pauseState = (isMicPaused || [self hardwareMicMute]) ? true : false; inputHandler->SetHardwareMicPause((isMicPaused) ? true : false);
CAInputDevice->SetPauseState(pauseState);
} }
- (BOOL) hardwareMicPause - (BOOL) hardwareMicPause
{ {
return (CAInputDevice->GetPauseState()) ? YES : NO; return (inputHandler->GetHardwareMicPause()) ? YES : NO;
} }
- (void) setSoftwareMicState:(BOOL)theState mode:(NSInteger)micMode - (void) setSoftwareMicState:(BOOL)theState mode:(NSInteger)micMode
@ -172,11 +158,6 @@
return (inputHandler->GetClientSoftwareMicState()) ? YES : NO; return (inputHandler->GetClientSoftwareMicState()) ? YES : NO;
} }
- (AudioGenerator *) softwareMicSampleGenerator
{
return inputHandler->GetClientSoftwareMicSampleGenerator();
}
- (void) setSelectedAudioFileGenerator:(AudioSampleBlockGenerator *)audioGenerator - (void) setSelectedAudioFileGenerator:(AudioSampleBlockGenerator *)audioGenerator
{ {
inputHandler->SetClientSelectedAudioFileGenerator(audioGenerator); inputHandler->SetClientSelectedAudioFileGenerator(audioGenerator);
@ -246,63 +227,13 @@
- (void) reset - (void) reset
{ {
[self setAutohold:NO]; [self setAutohold:NO];
[self setMicLevel:0.0f];
[self clearMicLevelMeasure];
_availableMicSamples = 0; inputHandler->ResetHardwareMic();
} }
- (void) clearMicLevelMeasure - (void) startHardwareMicDevice
{ {
_micLevelTotal = 0.0f; ((MacInputHandler *)inputHandler)->StartHardwareMicDevice();
_micLevelsRead = 0.0f;
}
- (void) updateMicLevel
{
float avgMicLevel = (_micLevelsRead != 0) ? _micLevelTotal / _micLevelsRead : 0.0f;
NSAutoreleasePool *tempPool = [[NSAutoreleasePool alloc] init];
[self setMicLevel:avgMicLevel];
if (delegate != nil && [delegate respondsToSelector:@selector(doMicLevelUpdateFromController:)])
{
[[self delegate] doMicLevelUpdateFromController:self];
}
[tempPool release];
}
- (uint8_t) handleMicSampleRead:(CoreAudioInput *)caInput softwareMic:(AudioGenerator *)sampleGenerator
{
uint8_t theSample = MIC_NULL_SAMPLE_VALUE;
if (!inputHandler->GetClientSoftwareMicStateApplied() && (caInput != NULL))
{
if (caInput->GetPauseState())
{
return theSample;
}
else
{
if (_availableMicSamples == 0)
{
_availableMicSamples = CAInputDevice->Pull();
}
caInput->_samplesConverted->read(&theSample, 1);
theSample >>= 1; // Samples from CoreAudio are 8-bit, so we need to convert the sample to 7-bit
_availableMicSamples--;
}
}
else
{
theSample = sampleGenerator->generateSample();
}
_micLevelTotal += (float)( (MIC_NULL_SAMPLE_VALUE > theSample) ? MIC_NULL_SAMPLE_VALUE - theSample : theSample - MIC_NULL_SAMPLE_VALUE );
_micLevelsRead += 1.0f;
return theSample;
} }
- (void) handleMicHardwareStateChanged:(CoreAudioInputDeviceInfo *)deviceInfo - (void) handleMicHardwareStateChanged:(CoreAudioInputDeviceInfo *)deviceInfo
@ -329,10 +260,10 @@
[self setHardwareMicSampleRateString:[NSString stringWithFormat:@"%1.1f Hz", (double)deviceInfo->sampleRate]]; [self setHardwareMicSampleRateString:[NSString stringWithFormat:@"%1.1f Hz", (double)deviceInfo->sampleRate]];
} }
[self clearMicLevelMeasure]; inputHandler->ClearAverageMicLevel();
[self setMicLevel:0.0f]; inputHandler->ReportAverageMicLevel();
if (delegate != nil && [delegate respondsToSelector:@selector(doMicHardwareStateChangedFromController:isEnabled:isLocked:)]) if ( (delegate != nil) && [delegate respondsToSelector:@selector(doMicHardwareStateChangedFromController:isEnabled:isLocked:)] )
{ {
[[self delegate] doMicHardwareStateChangedFromController:self [[self delegate] doMicHardwareStateChangedFromController:self
isEnabled:isHardwareEnabled isEnabled:isHardwareEnabled
@ -344,7 +275,7 @@
- (void) handleMicHardwareGainChanged:(float)gainValue - (void) handleMicHardwareGainChanged:(float)gainValue
{ {
if (delegate != nil && [delegate respondsToSelector:@selector(doMicHardwareGainChangedFromController:gain:)]) if ( (delegate != nil) && [delegate respondsToSelector:@selector(doMicHardwareGainChangedFromController:gain:)] )
{ {
NSAutoreleasePool *tempPool = [[NSAutoreleasePool alloc] init]; NSAutoreleasePool *tempPool = [[NSAutoreleasePool alloc] init];
[[self delegate] doMicHardwareGainChangedFromController:self gain:gainValue]; [[self delegate] doMicHardwareGainChangedFromController:self gain:gainValue];
@ -354,16 +285,105 @@
@end @end
MacInputHandler::MacInputHandler()
{
_cdsController = nil;
_CAInputDevice = new CoreAudioInput;
_hardwareMicSampleGenerator = _CAInputDevice;
_isHardwareMicMuted = false;
_CAInputDevice->SetCallbackHardwareStateChanged(&CAHardwareStateChangedCallback, _cdsController, NULL);
_CAInputDevice->SetCallbackHardwareGainChanged(&CAHardwareGainChangedCallback, _cdsController, NULL);
Mic_SetResetCallback(&CAResetCallback, _CAInputDevice, NULL);
Mic_SetSampleReadCallback(&CASampleReadCallback, this, NULL);
}
MacInputHandler::~MacInputHandler()
{
delete this->_CAInputDevice;
}
CocoaDSController* MacInputHandler::GetCocoaController()
{
return this->_cdsController;
}
void MacInputHandler::SetCocoaController(CocoaDSController *theController)
{
this->_cdsController = theController;
this->_CAInputDevice->SetCallbackHardwareStateChanged(&CAHardwareStateChangedCallback, theController, NULL);
this->_CAInputDevice->SetCallbackHardwareGainChanged(&CAHardwareGainChangedCallback, theController, NULL);
}
void MacInputHandler::StartHardwareMicDevice()
{
this->_CAInputDevice->Start();
}
bool MacInputHandler::IsHardwareMicAvailable()
{
return ( this->_CAInputDevice->IsHardwareEnabled() && !this->_CAInputDevice->IsHardwareLocked() );
}
void MacInputHandler::ReportAverageMicLevel()
{
[this->_cdsController setMicLevel:this->GetAverageMicLevel()];
}
void MacInputHandler::SetHardwareMicMute(bool muteState)
{
const bool needSetMuteState = (this->_isHardwareMicMuted != muteState);
if (needSetMuteState)
{
if (muteState)
{
this->_hardwareMicSampleGenerator->resetSamples();
this->ClearAverageMicLevel();
}
this->_isHardwareMicMuted = muteState;
this->_CAInputDevice->SetPauseState(this->_isHardwareMicPaused || muteState);
}
}
bool MacInputHandler::GetHardwareMicPause()
{
return this->_CAInputDevice->GetPauseState();
}
void MacInputHandler::SetHardwareMicPause(bool pauseState)
{
const bool needSetPauseState = (this->_isHardwareMicPaused != pauseState);
if (needSetPauseState)
{
this->_isHardwareMicPaused = pauseState;
this->_CAInputDevice->SetPauseState(pauseState || this->_isHardwareMicMuted);
}
}
float MacInputHandler::GetHardwareMicNormalizedGain()
{
return this->_CAInputDevice->GetNormalizedGain();
}
void MacInputHandler::SetHardwareMicGainAsNormalized(float normalizedGain)
{
this->_CAInputDevice->SetGainAsNormalized(normalizedGain);
}
void CAResetCallback(void *inParam1, void *inParam2) void CAResetCallback(void *inParam1, void *inParam2)
{ {
CocoaDSController *cdsController = (CocoaDSController *)inParam1; CoreAudioInput *caInputDevice = (CoreAudioInput *)inParam1;
[cdsController CAInputDevice]->Start(); caInputDevice->Start();
} }
uint8_t CASampleReadCallback(void *inParam1, void *inParam2) uint8_t CASampleReadCallback(void *inParam1, void *inParam2)
{ {
CocoaDSController *cdsController = (CocoaDSController *)inParam1; ClientInputHandler *inputHandler = (ClientInputHandler *)inParam1;
return [cdsController handleMicSampleRead:[cdsController CAInputDevice] softwareMic:[cdsController softwareMicSampleGenerator]]; return inputHandler->HandleMicSampleRead();
} }
void CAHardwareStateChangedCallback(CoreAudioInputDeviceInfo *deviceInfo, void CAHardwareStateChangedCallback(CoreAudioInputDeviceInfo *deviceInfo,

View File

@ -47,7 +47,7 @@ CoreAudioInput::CoreAudioInput()
_hwDeviceInfo.deviceUID = CFSTR(""); _hwDeviceInfo.deviceUID = CFSTR("");
_hwDeviceInfo.modelUID = CFSTR(""); _hwDeviceInfo.modelUID = CFSTR("");
_hwDeviceInfo.sampleRate = 0.0; _hwDeviceInfo.sampleRate = 0.0;
_isPaused = false; _isPaused = true;
_isHardwareEnabled = false; _isHardwareEnabled = false;
_isHardwareLocked = true; _isHardwareLocked = true;
_captureFrames = 0; _captureFrames = 0;
@ -602,12 +602,12 @@ void CoreAudioInput::SetPauseState(bool pauseState)
this->_isPaused = (this->IsHardwareLocked()) ? true : pauseState; this->_isPaused = (this->IsHardwareLocked()) ? true : pauseState;
} }
float CoreAudioInput::GetGain() const float CoreAudioInput::GetNormalizedGain() const
{ {
return this->_inputGainNormalized; return this->_inputGainNormalized;
} }
void CoreAudioInput::SetGain(float normalizedGain) void CoreAudioInput::SetGainAsNormalized(float normalizedGain)
{ {
Float32 gainValue = normalizedGain; Float32 gainValue = normalizedGain;
UInt32 gainPropSize = sizeof(gainValue); UInt32 gainPropSize = sizeof(gainValue);
@ -698,6 +698,36 @@ void CoreAudioInput::UpdateHardwareLock()
this->_hwStateChangedCallbackParam2); this->_hwStateChangedCallbackParam2);
} }
size_t CoreAudioInput::resetSamples()
{
size_t samplesToDrop = this->_samplesConverted->getUsedElements();
this->_samplesConverted->clear();
return samplesToDrop;
}
uint8_t CoreAudioInput::generateSample()
{
uint8_t theSample = MIC_NULL_SAMPLE_VALUE;
if (this->_isPaused)
{
return theSample;
}
else
{
if (this->_samplesConverted->getUsedElements() == 0)
{
this->Pull();
}
this->_samplesConverted->read(&theSample, 1);
theSample >>= 1; // Samples from CoreAudio are 8-bit, so we need to convert the sample to 7-bit
}
return theSample;
}
void CoreAudioInput::SetCallbackHardwareStateChanged(CoreAudioInputHardwareStateChangedCallback callbackFunc, void *inParam1, void *inParam2) void CoreAudioInput::SetCallbackHardwareStateChanged(CoreAudioInputHardwareStateChangedCallback callbackFunc, void *inParam1, void *inParam2)
{ {
this->_hwStateChangedCallbackFunc = callbackFunc; this->_hwStateChangedCallbackFunc = callbackFunc;

View File

@ -22,8 +22,9 @@
#include <AudioUnit/AudioUnit.h> #include <AudioUnit/AudioUnit.h>
#include <AudioToolbox/AudioToolbox.h> #include <AudioToolbox/AudioToolbox.h>
#include <libkern/OSAtomic.h> #include <libkern/OSAtomic.h>
#include "ringbuffer.h"
#include "ringbuffer.h"
#include "audiosamplegenerator.h"
struct CoreAudioInputDeviceInfo struct CoreAudioInputDeviceInfo
{ {
@ -44,7 +45,7 @@ typedef void (*CoreAudioInputHardwareStateChangedCallback)(CoreAudioInputDeviceI
typedef void (*CoreAudioInputHardwareGainChangedCallback)(float normalizedGain, void *inParam1, void *inParam2); typedef void (*CoreAudioInputHardwareGainChangedCallback)(float normalizedGain, void *inParam1, void *inParam2);
class CoreAudioInput class CoreAudioInput : public AudioGenerator
{ {
private: private:
OSSpinLock *_spinlockAUHAL; OSSpinLock *_spinlockAUHAL;
@ -65,6 +66,8 @@ private:
AudioBufferList *_convertBufferList; AudioBufferList *_convertBufferList;
UInt32 _captureFrames; UInt32 _captureFrames;
RingBuffer *_samplesConverted;
float _inputGainNormalized; float _inputGainNormalized;
AudioUnitElement _inputElement; AudioUnitElement _inputElement;
@ -80,10 +83,9 @@ public:
AudioTimeStamp _timeStamp; AudioTimeStamp _timeStamp;
AudioBufferList *_captureBufferList; AudioBufferList *_captureBufferList;
RingBuffer *_samplesCaptured; RingBuffer *_samplesCaptured;
RingBuffer *_samplesConverted;
CoreAudioInput(); CoreAudioInput();
~CoreAudioInput(); virtual ~CoreAudioInput();
void Start(); void Start();
void Stop(); void Stop();
@ -93,13 +95,16 @@ public:
bool IsHardwareLocked() const; bool IsHardwareLocked() const;
bool GetPauseState() const; bool GetPauseState() const;
void SetPauseState(bool pauseState); void SetPauseState(bool pauseState);
float GetGain() const; float GetNormalizedGain() const;
void SetGain(float normalizedGain); void SetGainAsNormalized(float normalizedGain);
void UpdateHardwareGain(float normalizedGain); void UpdateHardwareGain(float normalizedGain);
void UpdateHardwareLock(); void UpdateHardwareLock();
void SetCallbackHardwareStateChanged(CoreAudioInputHardwareStateChangedCallback callbackFunc, void *inParam1, void *inParam2); void SetCallbackHardwareStateChanged(CoreAudioInputHardwareStateChangedCallback callbackFunc, void *inParam1, void *inParam2);
void SetCallbackHardwareGainChanged(CoreAudioInputHardwareGainChangedCallback callbackFunc, void *inParam1, void *inParam2); void SetCallbackHardwareGainChanged(CoreAudioInputHardwareGainChangedCallback callbackFunc, void *inParam1, void *inParam2);
virtual size_t resetSamples();
virtual uint8_t generateSample();
}; };
class CoreAudioOutput class CoreAudioOutput

View File

@ -810,7 +810,6 @@
const BOOL muteState = [CocoaDSUtil getIBActionSenderButtonStateBool:sender]; const BOOL muteState = [CocoaDSUtil getIBActionSenderButtonStateBool:sender];
CocoaDSCore *cdsCore = (CocoaDSCore *)[cdsCoreController content]; CocoaDSCore *cdsCore = (CocoaDSCore *)[cdsCoreController content];
[[cdsCore cdsController] setHardwareMicMute:muteState]; [[cdsCore cdsController] setHardwareMicMute:muteState];
[[cdsCore cdsController] setHardwareMicPause:([cdsCore coreState] != ExecutionBehavior_Run)];
[self updateMicStatusIcon]; [self updateMicStatusIcon];
} }
@ -1911,7 +1910,6 @@
[cdsCore setSlot1StatusText:NSSTRING_STATUS_EMULATION_NOT_RUNNING]; [cdsCore setSlot1StatusText:NSSTRING_STATUS_EMULATION_NOT_RUNNING];
[[cdsCore cdsController] reset]; [[cdsCore cdsController] reset];
[[cdsCore cdsController] updateMicLevel];
result = YES; result = YES;
@ -2016,7 +2014,11 @@
{ {
if ([cdsController isHardwareMicAvailable]) if ([cdsController isHardwareMicAvailable])
{ {
if ([cdsController isHardwareMicInClip]) if ([cdsController hardwareMicPause])
{
micIcon = iconMicDisabled;
}
else if ([cdsController isHardwareMicInClip])
{ {
micIcon = iconMicInClip; micIcon = iconMicInClip;
} }

View File

@ -186,7 +186,7 @@
// Init the DS controller. // Init the DS controller.
[[newCore cdsController] setDelegate:emuControl]; [[newCore cdsController] setDelegate:emuControl];
[[newCore cdsController] setHardwareMicEnabled:YES]; [[newCore cdsController] startHardwareMicDevice];
// Init the DS speakers. // Init the DS speakers.
CocoaDSSpeaker *newSpeaker = [[[CocoaDSSpeaker alloc] init] autorelease]; CocoaDSSpeaker *newSpeaker = [[[CocoaDSSpeaker alloc] init] autorelease];
@ -207,7 +207,6 @@
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification - (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{ {
CocoaDSCore *cdsCore = (CocoaDSCore *)[cdsCoreController content];
EmuControllerDelegate *emuControl = (EmuControllerDelegate *)[emuControlController content]; EmuControllerDelegate *emuControl = (EmuControllerDelegate *)[emuControlController content];
// Determine if the app was run for the first time. // Determine if the app was run for the first time.
@ -237,11 +236,10 @@
[[inputPrefsView inputPrefOutlineView] expandItem:nil expandChildren:YES]; [[inputPrefsView inputPrefOutlineView] expandItem:nil expandChildren:YES];
[[inputPrefsView inputProfileMenu] selectItemAtIndex:0]; [[inputPrefsView inputProfileMenu] selectItemAtIndex:0];
// Make sure that the mic is paused to start with. // Initialize the microphone status icon.
[[cdsCore cdsController] setHardwareMicPause:YES];
[emuControl updateMicStatusIcon]; [emuControl updateMicStatusIcon];
//Bring the application to the front // Bring the application to the front
[NSApp activateIgnoringOtherApps:YES]; [NSApp activateIgnoringOtherApps:YES];
[self restoreDisplayWindowStates]; [self restoreDisplayWindowStates];