Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alexbollbach/c06e68d589e7597e845a24f74fc315e4 to your computer and use it in GitHub Desktop.
Save alexbollbach/c06e68d589e7597e845a24f74fc315e4 to your computer and use it in GitHub Desktop.
//
// MyAudioUnit3AudioUnit.m
// MyAudioUnit3
//
// Created by Alexander Bollbach on 7/23/17.
// Copyright © 2017 Alexander Bollbach. All rights reserved.
//
#import "MyAudioUnit3.h"
#import <AVFoundation/AVFoundation.h>
@interface MyAudioUnit3 ()
@property (nonatomic, readwrite) AUParameterTree *parameterTree;
@property AUAudioUnitBusArray *outputBusArray;
@end
@implementation MyAudioUnit3
@synthesize parameterTree = _parameterTree;
AudioBufferList renderABL;
AUAudioUnitBus *_outputBus; // was BufferedInputBus in sample code
AVAudioPCMBuffer* pcmBuffer;
AUValue frequency = 200;
id pointerToSelf;
AudioBufferList const* originalAudioBufferList;
const AudioUnitParameterID frequencyAddress = 0;
- (instancetype)initWithComponentDescription:(AudioComponentDescription)componentDescription options:(AudioComponentInstantiationOptions)options error:(NSError **)outError {
self = [super initWithComponentDescription:componentDescription options:options error:outError];
if (self == nil) { return nil; }
pointerToSelf = self;
AudioUnitParameterOptions flags = kAudioUnitParameterFlag_IsWritable |
kAudioUnitParameterFlag_IsReadable;
AUParameter *param1 = [AUParameterTree createParameterWithIdentifier:@"frequency"
name:@"Frequency"
address:frequencyAddress
min:100
max:1000
unit:kAudioUnitParameterUnit_Hertz
unitName:nil
flags:flags
valueStrings:nil
dependentParameters:nil];
param1.value = 200;
_parameterTree = [AUParameterTree createTreeWithChildren:@[ param1 ]];
param1.implementorValueProvider = ^(AUParameter *param) {
switch (param.address) {
case frequencyAddress:
return frequency; // TODO: is this capturing self?
default:
return (AUValue) 0.0;
}
};
NSLog(@"self: %p", self);
NSLog(@"pointer to self: %p", pointerToSelf);
_parameterTree.implementorValueObserver = ^(AUParameter *param, AUValue value) {
switch (param.address) {
case frequencyAddress:
printf("pointer to self in value observer: %p \n", pointerToSelf);
frequency = value;
break;
default:
break;
}
};
AVAudioFormat *defaultFormat = [[AVAudioFormat alloc] initStandardFormatWithSampleRate:44100.0 channels:2];
_outputBus = [[AUAudioUnitBus alloc] initWithFormat:defaultFormat error:nil];
_outputBusArray = [[AUAudioUnitBusArray alloc] initWithAudioUnit:self busType:AUAudioUnitBusTypeOutput busses: @[_outputBus]];
self.maximumFramesToRender = 512;
return self;
}
- (AUAudioUnitBusArray *)outputBusses { return _outputBusArray; }
// Subclassers should call the superclass implementation.
- (BOOL)allocateRenderResourcesAndReturnError:(NSError **)outError {
if (![super allocateRenderResourcesAndReturnError:outError]) { return NO; }
renderABL.mNumberBuffers = 2; // this is actually needed
pcmBuffer = [[AVAudioPCMBuffer alloc] initWithPCMFormat:_outputBus.format frameCapacity: 512];
originalAudioBufferList = pcmBuffer.audioBufferList;
return YES;
}
- (void)deallocateRenderResources { [super deallocateRenderResources]; }
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 == NULL) {
outBufferList->mBuffers[i].mData = originalAudioBufferList->mBuffers[i].mData;
}
if (zeroFill) { memset(outBufferList->mBuffers[i].mData, 0, byteSize); }
}
}
#pragma mark - AUAudioUnit (AUAudioUnitImplementation)
- (AUInternalRenderBlock)internalRenderBlock {
AUValue * param1Capture = &frequency;
__block float phase = 0.0;
return ^AUAudioUnitStatus(AudioUnitRenderActionFlags *actionFlags, const AudioTimeStamp *timestamp, AVAudioFrameCount frameCount, NSInteger outputBusNumber, AudioBufferList *outputData, const AURenderEvent *realtimeEventListHead, AURenderPullInputBlock pullInputBlock) {
prepareOutputBufferList(outputData, frameCount, true);
float* outL = (float*)outputData->mBuffers[0].mData;
float* outR = (float*)outputData->mBuffers[1].mData;
float phaseIncrement = *param1Capture * (3.14159 * 2.0) / 44100;
for (int frame = 0; frame < frameCount; frame++) {
outL[frame] = outR[frame] = sin( phase );
phase += phaseIncrement;
}
return noErr;
};
};
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment