-
-
Save patrick99e99/9221d8d7165d610fd3e1 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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