Learn-iOS-Swift-by-Examples/AudioUnitV3Example/Shared/BufferedAudioBus.hpp

135 lines
4.7 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
See LICENSE.txt for this samples licensing information.
Abstract:
Utility classes to manage audio formats and buffers for an audio unit implementation's input and output audio busses.
*/
#import <AudioToolbox/AudioToolbox.h>
#import <AudioUnit/AudioUnit.h>
#import <AVFoundation/AVFoundation.h>
#pragma mark BufferedAudioBus Utility Class
// Utility classes to manage audio formats and buffers for an audio unit implementation's input and output audio busses.
// Reusable non-ObjC class, accessible from render thread.
struct BufferedAudioBus {
AUAudioUnitBus* bus = nullptr;
AUAudioFrameCount maxFrames = 0;
AVAudioPCMBuffer* pcmBuffer = nullptr;
AudioBufferList const* originalAudioBufferList = nullptr;
AudioBufferList* mutableAudioBufferList = nullptr;
void init(AVAudioFormat* defaultFormat, AVAudioChannelCount maxChannels) {
maxFrames = 0;
pcmBuffer = nullptr;
originalAudioBufferList = nullptr;
mutableAudioBufferList = nullptr;
bus = [[AUAudioUnitBus alloc] initWithFormat:defaultFormat error:nil];
bus.maximumChannelCount = maxChannels;
}
void allocateRenderResources(AUAudioFrameCount inMaxFrames) {
maxFrames = inMaxFrames;
pcmBuffer = [[AVAudioPCMBuffer alloc] initWithPCMFormat:bus.format frameCapacity: maxFrames];
originalAudioBufferList = pcmBuffer.audioBufferList;
mutableAudioBufferList = pcmBuffer.mutableAudioBufferList;
}
void deallocateRenderResources() {
pcmBuffer = nullptr;
originalAudioBufferList = nullptr;
mutableAudioBufferList = nullptr;
}
};
#pragma mark - BufferedOutputBus: BufferedAudioBus
#pragma mark prepareOutputBufferList()
/*
BufferedOutputBus
This class provides a prepareOutputBufferList method to copy the internal buffer pointers
to the output buffer list in case the client passed in null buffer pointers.
*/
struct BufferedOutputBus: BufferedAudioBus {
void prepareOutputBufferList(AudioBufferList* outBufferList, AVAudioFrameCount frameCount, bool zeroFill) {
UInt32 byteSize = frameCount * sizeof(float);
for (UInt32 i = 0; i < outBufferList->mNumberBuffers; ++i) {
outBufferList->mBuffers[i].mNumberChannels = originalAudioBufferList->mBuffers[i].mNumberChannels;
outBufferList->mBuffers[i].mDataByteSize = byteSize;
if (outBufferList->mBuffers[i].mData == nullptr) {
outBufferList->mBuffers[i].mData = originalAudioBufferList->mBuffers[i].mData;
}
if (zeroFill) {
memset(outBufferList->mBuffers[i].mData, 0, byteSize);
}
}
}
};
#pragma mark - BufferedInputBus: BufferedAudioBus
#pragma mark pullInput()
#pragma mark prepareInputBufferList()
/*
BufferedInputBus
This class manages a buffer into which an audio unit with input busses can
pull its input data.
*/
struct BufferedInputBus : BufferedAudioBus {
/*
Gets input data for this input by preparing the input buffer list and pulling
the pullInputBlock.
*/
AUAudioUnitStatus pullInput(AudioUnitRenderActionFlags *actionFlags,
AudioTimeStamp const* timestamp,
AVAudioFrameCount frameCount,
NSInteger inputBusNumber,
AURenderPullInputBlock pullInputBlock) {
if (pullInputBlock == nullptr) {
return kAudioUnitErr_NoConnection;
}
/*
Important:
The Audio Unit must supply valid buffers in (inputData->mBuffers[x].mData) and mDataByteSize.
mDataByteSize must be consistent with frameCount.
The AURenderPullInputBlock may provide input in those specified buffers, or it may replace
the mData pointers with pointers to memory which it owns and guarantees will remain valid
until the next render cycle.
See prepareInputBufferList()
*/
prepareInputBufferList();
return pullInputBlock(actionFlags, timestamp, frameCount, inputBusNumber, mutableAudioBufferList);
}
/*
prepareInputBufferList populates the mutableAudioBufferList with the data
pointers from the originalAudioBufferList.
The upstream audio unit may overwrite these with its own pointers, so each
render cycle this function needs to be called to reset them.
*/
void prepareInputBufferList() {
UInt32 byteSize = maxFrames * sizeof(float);
mutableAudioBufferList->mNumberBuffers = originalAudioBufferList->mNumberBuffers;
for (UInt32 i = 0; i < originalAudioBufferList->mNumberBuffers; ++i) {
mutableAudioBufferList->mBuffers[i].mNumberChannels = originalAudioBufferList->mBuffers[i].mNumberChannels;
mutableAudioBufferList->mBuffers[i].mData = originalAudioBufferList->mBuffers[i].mData;
mutableAudioBufferList->mBuffers[i].mDataByteSize = byteSize;
}
}
};