Skip to content

Instantly share code, notes, and snippets.

@patrick99e99
Created March 21, 2015 03:33
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 patrick99e99/9221d8d7165d610fd3e1 to your computer and use it in GitHub Desktop.
Save patrick99e99/9221d8d7165d610fd3e1 to your computer and use it in GitHub Desktop.
#import "EffectMachine.h"
#import <AudioToolbox/AudioToolbox.h>
#import "AudioHelpers.h"
#import "Buffer.h"
@interface EffectMachine ()
@property (nonatomic, strong) Buffer *buffer;
-(void)stopGraph;
@end
typedef struct EffectPlayer {
NSUInteger index;
AUGraph graph;
AudioUnit lowPassAU;
AudioUnit outputUnit;
BOOL complete;
__unsafe_unretained Buffer *buffer;
__unsafe_unretained EffectMachine *effectMachine;
} EffectPlayer;
OSStatus LowpassInputRenderProc(void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList * ioData);
OSStatus LowpassInputRenderProc(void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList * ioData) {
struct EffectPlayer *player = (struct EffectPlayer *)inRefCon;
if (player->complete) return noErr;
for (int i = 0; i < inNumberFrames; i++) {
SInt16 sample = player->buffer.samples[player->index] * (1 << 15);
((SInt16 *)ioData->mBuffers[0].mData)[i] = sample;
if (player->index == player->buffer.size - 1) {
player->complete = YES;
[player->effectMachine performSelectorOnMainThread:@selector(stopGraph)
withObject:nil
waitUntilDone:NO];
} else {
player->index += 1;
}
}
return noErr;
}
@implementation EffectMachine {
EffectPlayer player;
}
-(instancetype)initWithBuffer:(Buffer *)buffer {
if (self = [super init]) {
self.buffer = buffer;
}
return self;
}
-(void)process {
struct EffectPlayer initialized = {0};
player = initialized;
player.buffer = self.buffer;
player.effectMachine = self;
[self setupAndStartAUGraph];
}
-(void)setupAndStartAUGraph {
CheckError(NewAUGraph(&player.graph),
"NewAUGraph failed");
AudioComponentDescription outputcd = {0};
outputcd.componentType = kAudioUnitType_Output;
outputcd.componentSubType = kAudioUnitSubType_GenericOutput;
outputcd.componentManufacturer = kAudioUnitManufacturer_Apple;
AUNode outputNode;
CheckError(AUGraphAddNode(player.graph, &outputcd, &outputNode),
"AUGraphAddNode[kAudioUnitSubType_DefaultOutput] failed");
AudioComponentDescription lowpasscd = {0};
lowpasscd.componentType = kAudioUnitType_Effect;
lowpasscd.componentSubType = kAudioUnitSubType_LowPassFilter;
lowpasscd.componentManufacturer = kAudioUnitManufacturer_Apple;
AUNode lowPassNode;
CheckError(AUGraphAddNode(player.graph, &lowpasscd, &lowPassNode),
"AUGraphAddNode[kAudioUnitSubType_LowPassFilter] failed");
CheckError(AUGraphOpen(player.graph),
"AUGraphOpen failed");
CheckError(AUGraphNodeInfo(player.graph, lowPassNode, NULL, &player.lowPassAU),
"AUGraphNodeInfo failed");
CheckError(AudioUnitSetParameter(player.lowPassAU,
kLowPassParam_CutoffFrequency,
kAudioUnitScope_Global,
0,
800,
0), "AudioUnitSetParameter for lowpass failed");
AURenderCallbackStruct callbackStruct;
callbackStruct.inputProc = LowpassInputRenderProc;
callbackStruct.inputProcRefCon = &player;
AudioUnitSetProperty(player.lowPassAU,
kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Input,
0,
&callbackStruct,
sizeof (callbackStruct));
CheckError(AUGraphConnectNodeInput(player.graph, lowPassNode, 0, outputNode, 0),
"AUGraphConnectNodeInput");
CheckError(AUGraphInitialize(player.graph),
"AUGraphInitialize failed");
CheckError(AUGraphStart(player.graph),
"AUGraphStart failed");
}
-(void)stopGraph {
AUGraphStop(player.graph);
AUGraphUninitialize(player.graph);
AUGraphClose(player.graph);
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment