/* * Copyright (C) 2011 Apple Inc. All rights reserved. * * This document is the property of Apple Inc. * It is considered confidential and proprietary. * * This document may not be reproduced or transmitted in any form, * in whole or in part, without the express written permission of * Apple Inc. */ #if USE_SIDETONE #include "AUSidetone.h" #include "IIRFiltersA5.h" #include "VolumeA5.h" #include "string.h" #include // a basic fixed 16-bit mono 44.1 description static AudioStreamBasicDescription kDefaultMonoFormat = { 44100.0, 'lpcm', 0xC, 2, 1, 2, 1, 16, 0 }; static void SetDefaultSidetoneEQ(BiquadDescriptor *biquadValues, size_t numBands, uint32_t sampleRate) { size_t i = 0; if (i < numBands) { biquadValues[i].filterType = kAUNBandEQFilterType_2ndOrderButterworthLowPass; biquadValues[i].frequencyInHertz = (sampleRate == 8000) ? 3800.0f : 7400.0f; biquadValues[i].gain = 0.f; biquadValues[i].bw = 0.05; biquadValues[i].bypassBand = 0.f; ++i; } if (i < numBands) { biquadValues[i].filterType = kAUNBandEQFilterType_2ndOrderButterworthHighPass; biquadValues[i].frequencyInHertz = (sampleRate == 8000) ? 200.0f : 100.0f; biquadValues[i].gain = 0.f; biquadValues[i].bw = 0.05; biquadValues[i].bypassBand = 0.f; ++i; } for (; i < numBands; ++i) { biquadValues[i].filterType = 0; biquadValues[i].frequencyInHertz = 100.0f; biquadValues[i].gain = 0.f; biquadValues[i].bw = 0.05; biquadValues[i].bypassBand = 1.f; } } AUSidetone * AUSidetone::Create_AUSidetone(uint32_t sampleRate, uint32_t numChannels, uint32_t sampleSize) { AUSidetone *This = new AUSidetone; if (This) { if (This->InitWith(sampleRate, numChannels, sampleSize)) { This->Initialize(); } else { delete This; This = NULL; } } return This; } AUSidetone::AUSidetone() : mSampleRate(44100), mNumChannels(1), mSidetoneEQ(NULL), mVolume(NULL), mNumberBands(kMaxNumBands), mBiquadValues(NULL), mVolumeInDB(kDefaultSidetoneGain), mSidetoneEQBypass(false) { } bool AUSidetone::InitWith(uint32_t sampleRate, uint32_t numChannels, uint32_t sampleSize) { if (sampleSize != 2) { return false; } mSampleRate = sampleRate; mNumChannels = numChannels; AudioStreamBasicDescription thisFormat = kDefaultMonoFormat; thisFormat.mSampleRate = mSampleRate; thisFormat.mBytesPerPacket *= mNumChannels; thisFormat.mBytesPerFrame *= mNumChannels; thisFormat.mChannelsPerFrame *= mNumChannels; thisFormat.mBitsPerChannel *= mNumChannels; mSidetoneEQ = NewAE2IIRFilter(&thisFormat, &thisFormat, kMaxNumBands); dprintf(DEBUG_INFO, "sidetone eq %p\n", mSidetoneEQ); mBiquadValues = new BiquadDescriptor[mNumberBands]; if (mBiquadValues) { SetDefaultSidetoneEQ(mBiquadValues, mNumberBands, mSampleRate); if (mSidetoneEQ) { mVolume = NewVolume(thisFormat); dprintf(DEBUG_INFO, "volume %p\n", mVolume); if (mVolume) { if ((SetAE2IIRFilter(mSidetoneEQ, &thisFormat, mNumberBands, mBiquadValues) == noErr) && (SetGain(mVolume, mVolumeInDB) == noErr)) { dprintf(DEBUG_INFO, "it is all good\n"); return true; } DeleteVolume(mVolume); mVolume = NULL; } DeleteAE2IIRFilter(mSidetoneEQ); mSidetoneEQ = NULL; } delete [] mBiquadValues; mBiquadValues = NULL; } return false; } AUSidetone::~AUSidetone() { DeleteAE2IIRFilter(mSidetoneEQ); mSidetoneEQ = NULL; DeleteVolume(mVolume); mVolume = NULL; delete [] mBiquadValues; mBiquadValues = NULL; } // These conversion routines are for translating from UInt32 of the AP/AE2 bridge // to the floating point of the internal representation. Scaling and offsets applied here. Float32 AudioUnitParameterValue_To_BypassBand(AudioUnitParameterValue value) { dprintf(DEBUG_INFO, "%s %d value %d\n", __FUNCTION__, uint32_t(value), uint32_t((value == 0) ? 0.f : 1.f)); return (value == 0) ? 0.f : 1.f; } AudioUnitParameterValue BypassBand_To_AudioUnitParameterValue(Float32 value) { dprintf(DEBUG_INFO, "%s %d value %d\n", __FUNCTION__, uint32_t(value), uint32_t((value == 0.f) ? 0 : 1)); return (value == 0.f) ? 0 : 1; } UInt32 AudioUnitParameterValue_To_FilterType(AudioUnitParameterValue value) { dprintf(DEBUG_INFO, "%s %d value %d\n", __FUNCTION__, uint32_t(value), uint32_t(value)); return value; } AudioUnitParameterValue FilterType_To_AudioUnitParameterValue(UInt32 value) { dprintf(DEBUG_INFO, "%s %d value %d\n", __FUNCTION__, uint32_t(value), uint32_t(value)); return value; } Float32 AudioUnitParameterValue_To_Frequency(AudioUnitParameterValue value) { dprintf(DEBUG_INFO, "%s %d value %d\n", __FUNCTION__, uint32_t(value), uint32_t(value)); return value; } AudioUnitParameterValue Frequency_To_AudioUnitParameterValue(Float32 value) { dprintf(DEBUG_INFO, "%s %d value %d\n", __FUNCTION__, uint32_t(value), uint32_t(value)); return value; } Float32 AudioUnitParameterValue_To_Gain(AudioUnitParameterValue value) { dprintf(DEBUG_INFO, "%s %d value %d\n", __FUNCTION__, uint32_t(value), uint32_t(-96.0 + (value))); return -96.0 + (value); } AudioUnitParameterValue Gain_To_AudioUnitParameterValue(Float32 value) { dprintf(DEBUG_INFO, "%s %d value %d\n", __FUNCTION__, uint32_t(value), uint32_t((value) - (-96.0))); return (value) - (-96.0); } Float32 AudioUnitParameterValue_To_Bandwidth(AudioUnitParameterValue value) { dprintf(DEBUG_INFO, "%s %d value %d\n", __FUNCTION__, uint32_t(value), uint32_t(value / 100.0f)); return value / 100.0f; } AudioUnitParameterValue Bandwidth_To_AudioUnitParameterValue(Float32 value) { dprintf(DEBUG_INFO, "%s %d value %d\n", __FUNCTION__, uint32_t(value), uint32_t(value * 100.0f)); return value * 100.0f; } Float32 AudioUnitParameterValue_To_VolumeInDB(AudioUnitParameterValue value) { dprintf(DEBUG_INFO, "%s %d value %d\n", __FUNCTION__, uint32_t(value), uint32_t(-96.0 + (value))); return -96.0 + (value); } AudioUnitParameterValue VolumeInDB_To_AudioUnitParameterValue(Float32 value) { dprintf(DEBUG_INFO, "%s %d value %d\n", __FUNCTION__, uint32_t(value), uint32_t((value) - (-96.0))); return (value) - (-96.0); } OSStatus AUSidetone::SetParameter(AudioUnitParameterID paramID, AudioUnitParameterValue value) { dprintf(DEBUG_INFO, "SetParameter %d value %d\n", paramID, uint32_t(value)); if (paramID == kAUVolume_InDB) { mVolumeInDB = AudioUnitParameterValue_To_VolumeInDB(value); return SetGain(mVolume, mVolumeInDB); } AudioStreamBasicDescription thisFormat = kDefaultMonoFormat; thisFormat.mSampleRate = mSampleRate; thisFormat.mBytesPerPacket *= mNumChannels; thisFormat.mBytesPerFrame *= mNumChannels; thisFormat.mChannelsPerFrame *= mNumChannels; thisFormat.mBitsPerChannel *= mNumChannels; // get the index uint32_t which = paramID % 1000; uint32_t type = (paramID / 1000)*1000; bool success = false; if (which < mNumberBands) { success = true; switch (type) { case kAUNBandEQParam_BypassBand: mBiquadValues[which].bypassBand = AudioUnitParameterValue_To_BypassBand(value); break; case kAUNBandEQParam_FilterType: mBiquadValues[which].filterType = AudioUnitParameterValue_To_FilterType(value); break; case kAUNBandEQParam_Frequency: mBiquadValues[which].frequencyInHertz = AudioUnitParameterValue_To_Frequency(value); break; case kAUNBandEQParam_Gain: mBiquadValues[which].gain = AudioUnitParameterValue_To_Gain(value); break; case kAUNBandEQParam_Bandwidth: mBiquadValues[which].bw = AudioUnitParameterValue_To_Bandwidth(value); break; default: success = false; } } OSStatus result = 0; if (success) { result = SetAE2IIRFilter(mSidetoneEQ, &thisFormat, mNumberBands, mBiquadValues); } else { result = super::SetParameter(paramID, value); } dprintf(DEBUG_INFO, "result is %d\n", result); return result; } AudioUnitParameterValue AUSidetone::GetParameter(AudioUnitParameterID paramID) { if (paramID == kAUVolume_InDB) { return VolumeInDB_To_AudioUnitParameterValue(mVolumeInDB); } // get the index uint32_t which = paramID % 1000; uint32_t type = (paramID / 1000)*1000; if (which < mNumberBands) { switch (type) { case kAUNBandEQParam_BypassBand: return BypassBand_To_AudioUnitParameterValue(mBiquadValues[which].bypassBand); case kAUNBandEQParam_FilterType: return FilterType_To_AudioUnitParameterValue(mBiquadValues[which].filterType); case kAUNBandEQParam_Frequency: return Frequency_To_AudioUnitParameterValue(mBiquadValues[which].frequencyInHertz); case kAUNBandEQParam_Gain: return Gain_To_AudioUnitParameterValue(mBiquadValues[which].gain); case kAUNBandEQParam_Bandwidth: return Bandwidth_To_AudioUnitParameterValue(mBiquadValues[which].bw); } } return super::GetParameter(paramID); } OSStatus AUSidetone::GetPropertyInfo(AudioUnitPropertyID inID, uint32_t& outDataSize, bool& outWritable) { OSStatus result = -1; switch (inID) { case kAUSongbird_SidetoneState: result = GetPropertyInfo(kAUSongbird_SidetoneEQBlockData, outDataSize, outWritable); if (noErr == result) { // leave room for the mVolume field of the AU_SidetoneState; outDataSize += offsetof(AU_SidetoneState, mFilterDescription); } break; case kAUSongbird_SidetoneEQBlockData: outDataSize = sizeof(AU_BiquadFilterDescription) - sizeof(AU_BiquadFilter) + mNumberBands * sizeof(AU_BiquadFilter); outWritable = true; result = noErr; break; default: result = super::GetPropertyInfo(inID, outDataSize, outWritable); } return result; } OSStatus AUSidetone::GetProperty(AudioUnitPropertyID inID, void* outData) { OSStatus result = -1; switch (inID) { case kAUSongbird_SidetoneState: { AU_SidetoneState * state = static_cast(outData); state->mVolume = mVolumeInDB; state->mBypass = mSidetoneEQBypass; void * biquad_filter_description = &state->mFilterDescription; result = GetProperty(kAUSongbird_SidetoneEQBlockData, biquad_filter_description); } break; case kAUSongbird_SidetoneEQBlockData: { AU_BiquadFilterDescription * description = static_cast(outData); if (description) { description->mBypass = mSidetoneEQBypass; description->mNumberFilters = mNumberBands; BiquadCoefficientsDescriptor * filter = static_cast(static_cast(description->mFilters)); if (filter) { result = GetAE2IIRFilterCoefficients(mSidetoneEQ, mNumberBands, filter); } } } break; default: result = super::GetProperty(inID, outData); } return result; } OSStatus AUSidetone::SetProperty(AudioUnitPropertyID inID, const void* inData, uint32_t inDataSize) { OSStatus result = -1; switch (inID) { case kAUSongbird_SidetoneState: { // determine if have a valid data structure if (inDataSize < (offsetof(AU_SidetoneState, mFilterDescription))) { break; } const AU_SidetoneState * state = static_cast(inData); const void * biquad_filter_description = &state->mFilterDescription; result = SetProperty(kAUSongbird_SidetoneEQBlockData, biquad_filter_description, inDataSize - offsetof(AU_SidetoneState, mFilterDescription)); if (noErr == result) { mSidetoneEQBypass = state->mBypass; mVolumeInDB = state->mVolume; result = SetGain(mVolume, mVolumeInDB); } } break; case kAUSongbird_SidetoneEQBlockData: { // determine if we are talking to a valid structure if (inDataSize < sizeof(AU_BiquadFilterDescription) - sizeof(AU_BiquadFilter)) { break; } const AU_BiquadFilterDescription * description = static_cast(inData); if (inDataSize < ((sizeof(AU_BiquadFilterDescription) - sizeof(AU_BiquadFilter) + (sizeof(AU_BiquadFilter) * description->mNumberFilters)))) { break; } if (description->mNumberFilters > kMaxNumBands) { break; } const BiquadCoefficientsDescriptor * filter = static_cast(static_cast(description->mFilters)); result = SetAE2IIRFilterCoefficients(mSidetoneEQ, description->mNumberFilters, static_cast(filter)); if (!result) { mSidetoneEQBypass = description->mBypass; mNumberBands = description->mNumberFilters; } } break; default: result = super::SetProperty(inID, inData, inDataSize); } return result; } void AUSidetone::Process(const void *inSourceP, void *inDestP, UInt32 inFramesToProcess) { if (!mSidetoneEQBypass) { ProcessAE2IIRFilter(mSidetoneEQ, inFramesToProcess, inSourceP, inDestP); } ProcessVolumeInplace(mVolume, inFramesToProcess, inDestP); } #endif