-
Notifications
You must be signed in to change notification settings - Fork 872
/
Copy pathBufferedAudioBus.hpp
134 lines (108 loc) · 4.7 KB
/
BufferedAudioBus.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
/*
See LICENSE.txt for this sample’s 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;
}
}
};