Skip to content

Instantly share code, notes, and snippets.

@standy66
Created January 21, 2019 09:28
Show Gist options
  • Save standy66/c8ac19ea1a05be0a5b62f45732a640d4 to your computer and use it in GitHub Desktop.
Save standy66/c8ac19ea1a05be0a5b62f45732a640d4 to your computer and use it in GitHub Desktop.
Voice-Processing I/O MacOS example
#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