Created
January 21, 2019 09:28
-
-
Save standy66/c8ac19ea1a05be0a5b62f45732a640d4 to your computer and use it in GitHub Desktop.
Voice-Processing I/O MacOS example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <cmath> | |
#include <fstream> | |
#include <AudioToolbox/AudioToolbox.h> | |
// Files with raw float32 data | |
std::ifstream ifile("ifile.f32"); | |
std::ofstream file("file.f32"); | |
OSStatus inputCallback(void* opaque, AudioUnitRenderActionFlags* ioActionFlags, | |
const AudioTimeStamp* inTimeStamp, uint32_t inBusNumber, | |
uint32_t inNumberFrames, AudioBufferList* ioData) { | |
AudioUnit unit = *reinterpret_cast<AudioUnit*>(opaque); | |
AudioBufferList list { 1, {1, static_cast<uint32_t>(inNumberFrames * sizeof(float)), nullptr} }; | |
if (AudioUnitRender(unit, ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, &list) != 0) { | |
std::cerr << "Failed to render\n"; | |
exit(-1); | |
} | |
float* float_data = reinterpret_cast<float*>(list.mBuffers[0].mData); | |
char* char_data = reinterpret_cast<char*>(list.mBuffers[0].mData); | |
std::cerr << "Input callback got buffer with " << list.mBuffers[0].mDataByteSize << " bytes, first element: " << float_data[0] << "\n"; | |
file.write(char_data, list.mBuffers[0].mDataByteSize); | |
return noErr; | |
} | |
OSStatus outputCallback(void* opaque, AudioUnitRenderActionFlags* ioActionFlags, | |
const AudioTimeStamp* inTimeStamp, uint32_t inBusNumber, | |
uint32_t inNumberFrames, AudioBufferList* ioData) { | |
char* bytes = reinterpret_cast<char*>(ioData->mBuffers->mData); | |
ifile.read(bytes, inNumberFrames * sizeof(float)); | |
std::cerr << "Output callback wrote " << inNumberFrames * sizeof(float) << " bytes.\n"; | |
return noErr; | |
} | |
void SetAudioUnitStreamFormat(AudioUnit* unit) { | |
AudioStreamBasicDescription asbd; | |
asbd.mSampleRate = 48000; | |
asbd.mFormatID = kAudioFormatLinearPCM; | |
asbd.mFormatFlags = kAudioFormatFlagsCanonical; | |
asbd.mBytesPerPacket = 4; | |
asbd.mFramesPerPacket = 1; | |
asbd.mBytesPerFrame = 4; | |
asbd.mChannelsPerFrame = 1; | |
asbd.mBitsPerChannel = 32; | |
if (AudioUnitSetProperty(*unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, | |
0, &asbd, sizeof(asbd)) != 0) { | |
std::cerr << "Error setting stream format for input stream\n"; | |
exit(-1); | |
} | |
if (AudioUnitSetProperty(*unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, | |
1, &asbd, sizeof(asbd)) != 0) { | |
std::cerr << "Error setting stream format for output stream\n"; | |
exit(-1); | |
} | |
} | |
void SetAudioUnitCallbacks(AudioUnit* unit) { | |
AURenderCallbackStruct inputCallbackStruct { &inputCallback, unit }; | |
AURenderCallbackStruct outputCallbackStruct { &outputCallback, unit }; | |
if (AudioUnitSetProperty(*unit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, | |
1, &inputCallbackStruct, sizeof(inputCallbackStruct)) != 0) { | |
std::cerr << "Error setting input callback\n"; | |
exit(-1); | |
} | |
if (AudioUnitSetProperty(*unit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Global, | |
0, &outputCallbackStruct, sizeof(inputCallbackStruct)) != 0) { | |
std::cerr << "Error setting output callback\n"; | |
exit(-1); | |
} | |
} | |
void EnableAGC(AudioUnit* unit) { | |
uint32_t one = 1; | |
std::cerr << "Enabling AGC\n"; | |
if (AudioUnitSetProperty(*unit, kAUVoiceIOProperty_VoiceProcessingEnableAGC, kAudioUnitScope_Global, | |
1, &one, sizeof(one)) != 0) { | |
std::cerr << "Error enabling AGC\n"; | |
exit(-1); | |
} | |
std::cerr << "Enabling AGC\n"; | |
if (AudioUnitSetProperty(*unit, kAUVoiceIOProperty_VoiceProcessingEnableAGC, kAudioUnitScope_Global, | |
0, &one, sizeof(one)) != 0) { | |
std::cerr << "Error enabling AGC\n"; | |
exit(-1); | |
} | |
} | |
void BuildVoiceProcessingUnit(AudioUnit* unit) { | |
AudioComponentDescription desc { | |
kAudioUnitType_Output, | |
kAudioUnitSubType_VoiceProcessingIO, | |
kAudioUnitManufacturer_Apple, | |
0, 0 | |
}; | |
AudioComponent comp = AudioComponentFindNext(nullptr, &desc); | |
if (comp == nullptr) { | |
std::cerr << "Failed to create AudioComponent\n"; | |
exit(-1); | |
} | |
if (AudioComponentInstanceNew(comp, unit) != 0) { | |
std::cerr << "Failed to create AudioComponentInstance\n"; | |
exit(-1); | |
} | |
// EnableAGC(unit); | |
SetAudioUnitStreamFormat(unit); | |
SetAudioUnitCallbacks(unit); | |
} | |
int main(int argc, const char * argv[]) { | |
std::cout << "Hello, World!\n"; | |
AudioUnit unit; | |
BuildVoiceProcessingUnit(&unit); | |
if (AudioUnitInitialize(unit) != 0) { | |
std::cerr << "Error initializing AudioUnit\n"; | |
return -1; | |
} | |
if (AudioOutputUnitStart(unit) != 0) { | |
std::cerr << "Error starting AudioUnit\n"; | |
return -1; | |
} | |
sleep(10); | |
if (AudioOutputUnitStop(unit) != 0) { | |
std::cerr << "Error stopping AudioUnit\n"; | |
return -1; | |
} | |
if (AudioUnitUninitialize(unit) != 0) { | |
std::cerr << "Error unintializing AudioUnit\n"; | |
return -1; | |
} | |
if (AudioComponentInstanceDispose(unit) != 0) { | |
std::cerr << "Error disposing AudioUnit\n"; | |
return -1; | |
} | |
file.close(); | |
sleep(1); | |
system("play -r 48000 -t f32 file.f32"); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment