114 lines
3.0 KiB
C++
114 lines
3.0 KiB
C++
|
|
|
|
|
|
#include <AudioUnit/AudioUnit.h>
|
|
#include <AudioToolbox/AudioToolbox.h>
|
|
#include <cmath>
|
|
#include <iostream>
|
|
#include <unistd.h>
|
|
|
|
constexpr double SAMPLE_RATE = 44100.0;
|
|
constexpr double FREQUENCY = 440.0; // A4
|
|
constexpr double AMPLITUDE = 0.25;
|
|
|
|
struct SineState {
|
|
double phase = 0.0;
|
|
};
|
|
|
|
OSStatus renderCallback(
|
|
void* inRefCon,
|
|
AudioUnitRenderActionFlags* ioActionFlags,
|
|
const AudioTimeStamp* inTimeStamp,
|
|
UInt32 inBusNumber,
|
|
UInt32 inNumberFrames,
|
|
AudioBufferList* ioData)
|
|
{
|
|
auto* state = static_cast<SineState*>(inRefCon);
|
|
double phase = state->phase;
|
|
double phaseIncrement = 2.0 * M_PI * FREQUENCY / SAMPLE_RATE;
|
|
|
|
for (UInt32 frame = 0; frame < inNumberFrames; ++frame) {
|
|
float sample = static_cast<float>(std::sin(phase) * AMPLITUDE);
|
|
phase += phaseIncrement;
|
|
if (phase >= 2.0 * M_PI)
|
|
phase -= 2.0 * M_PI;
|
|
|
|
// Write same sample to all channels
|
|
for (UInt32 buffer = 0; buffer < ioData->mNumberBuffers; ++buffer) {
|
|
float* data = static_cast<float*>(ioData->mBuffers[buffer].mData);
|
|
data[frame] = sample;
|
|
}
|
|
}
|
|
|
|
state->phase = phase;
|
|
return noErr;
|
|
}
|
|
|
|
int main() {
|
|
AudioUnit audioUnit;
|
|
SineState state;
|
|
|
|
// Describe output unit
|
|
AudioComponentDescription desc{};
|
|
desc.componentType = kAudioUnitType_Output;
|
|
desc.componentSubType = kAudioUnitSubType_DefaultOutput;
|
|
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
|
|
|
|
AudioComponent comp = AudioComponentFindNext(nullptr, &desc);
|
|
if (!comp) {
|
|
std::cerr << "Failed to find audio component\n";
|
|
return 1;
|
|
}
|
|
|
|
AudioComponentInstanceNew(comp, &audioUnit);
|
|
|
|
// Set stream format
|
|
AudioStreamBasicDescription format{};
|
|
format.mSampleRate = SAMPLE_RATE;
|
|
format.mFormatID = kAudioFormatLinearPCM;
|
|
format.mFormatFlags = kAudioFormatFlagIsFloat | kAudioFormatFlagIsPacked;
|
|
format.mBitsPerChannel = 32;
|
|
format.mChannelsPerFrame = 2;
|
|
format.mBytesPerFrame = sizeof(float) * format.mChannelsPerFrame;
|
|
format.mFramesPerPacket = 1;
|
|
format.mBytesPerPacket = format.mBytesPerFrame;
|
|
|
|
AudioUnitSetProperty(
|
|
audioUnit,
|
|
kAudioUnitProperty_StreamFormat,
|
|
kAudioUnitScope_Input,
|
|
0,
|
|
&format,
|
|
sizeof(format)
|
|
);
|
|
|
|
// Set render callback
|
|
AURenderCallbackStruct callback{};
|
|
callback.inputProc = renderCallback;
|
|
callback.inputProcRefCon = &state;
|
|
|
|
AudioUnitSetProperty(
|
|
audioUnit,
|
|
kAudioUnitProperty_SetRenderCallback,
|
|
kAudioUnitScope_Input,
|
|
0,
|
|
&callback,
|
|
sizeof(callback)
|
|
);
|
|
|
|
AudioUnitInitialize(audioUnit);
|
|
AudioOutputUnitStart(audioUnit);
|
|
|
|
std::cout << "Playing sine wave (Ctrl+C to quit)...\n";
|
|
while (true) {
|
|
sleep(1);
|
|
}
|
|
|
|
AudioOutputUnitStop(audioUnit);
|
|
AudioUnitUninitialize(audioUnit);
|
|
AudioComponentInstanceDispose(audioUnit);
|
|
|
|
return 0;
|
|
}
|
|
|