Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //
- // SNFViewController.m
- // TimePitchScratch
- //
- // Created by Chris Adamson on 10/13/12.
- // Copyright (c) 2012 Your Organization. All rights reserved.
- //
- #import "SNFViewController.h"
- #import <AVFoundation/AVFoundation.h>
- #import <AudioToolbox/AudioToolbox.h>
- @interface SNFViewController ()
- -(NSError*) setUpAudioSession;
- -(void) setUpAUGraph;
- -(void) resetRate;
- @property (atomic) AUGraph auGraph;
- @property (atomic) AudioUnit ioUnit;
- @property (atomic) AudioUnit effectUnit;
- @property (atomic) AudioUnit filePlayerUnit;
- @property (weak, nonatomic) IBOutlet UISlider *timeSlider;
- @property (weak, nonatomic) IBOutlet UILabel *rateLabel;
- - (IBAction)timeSliderChanged:(id)sender;
- - (IBAction)handleResetTo1Tapped:(id)sender;
- @property (weak, nonatomic) IBOutlet UISwitch *effectSwitch;
- - (IBAction)effectSwitchValueChanged:(id)sender;
- @end
- @implementation SNFViewController
- @synthesize auGraph = _auGraph;
- @synthesize ioUnit = _ioUnit;
- @synthesize effectUnit = _effectUnit;
- @synthesize filePlayerUnit = _filePlayerUnit;
- @synthesize graphSampleRate;
- @synthesize stereoStreamFormat;
- OSStatus MyAURenderCallback(void *inRefCon,
- AudioUnitRenderActionFlags *actionFlags,
- const AudioTimeStamp *inTimeStamp,
- UInt32 inBusNumber,
- UInt32 inNumberFrames,
- AudioBufferList *ioData) {
- AudioUnit mixerUnit = (AudioUnit)inRefCon;
- OSStatus status = AudioUnitRender(mixerUnit,
- actionFlags,
- inTimeStamp,
- 0,
- inNumberFrames,
- ioData);
- NSLog(@"%d",(int)status);
- //Store the Ramped Video
- NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
- NSString *outputURL = paths[0];
- NSFileManager *manager = [NSFileManager defaultManager];
- [manager createDirectoryAtPath:outputURL withIntermediateDirectories:YES attributes:nil error:nil];
- outputURL = [outputURL stringByAppendingPathComponent:@"outputRamp.aif"];
- OSStatus statusOne = ExtAudioFileWriteAsync((__bridge ExtAudioFileRef)(outputURL),
- inNumberFrames,
- ioData);
- OSStatus statusTwo = ExtAudioFileDispose((__bridge ExtAudioFileRef)(outputURL));
- NSLog(@"%d",(int)statusOne);
- NSLog(@"%d",(int)statusTwo);
- return noErr;
- }
- static void CheckError(OSStatus error, const char *operation)
- {
- if (error == noErr) return;
- char str[20];
- // see if it appears to be a 4-char-code
- *(UInt32 *)(str + 1) = CFSwapInt32HostToBig(error);
- if (isprint(str[1]) && isprint(str[2]) && isprint(str[3]) && isprint(str[4])) {
- str[0] = str[5] = '\'';
- str[6] = '\0';
- } else
- // no, format it as an integer
- sprintf(str, "%d", (int)error);
- fprintf(stderr, "Error: %s (%s)\n", operation, str);
- exit(1);
- }
- - (void)viewDidLoad
- {
- [super viewDidLoad];
- // Do any additional setup after loading the view, typically from a nib.
- [self setUpAudioSession];
- [self setUpAUGraph];
- [self resetRate];
- }
- - (void)didReceiveMemoryWarning
- {
- [super didReceiveMemoryWarning];
- // Dispose of any resources that can be recreated.
- }
- #pragma mark slider stuff
- - (IBAction)timeSliderChanged:(id)sender {
- [self resetRate];
- }
- - (IBAction)handleResetTo1Tapped:(id)sender {
- self.timeSlider.value = 5.0; // see math explainer in resetRate
- [self resetRate];
- }
- #pragma mark av foundation stuff
- -(NSError*) setUpAudioSession {
- NSError *sessionErr;
- [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord
- error:&sessionErr];
- if (sessionErr) { return sessionErr; }
- [[AVAudioSession sharedInstance] setActive:YES
- error:&sessionErr];
- if (sessionErr) { return sessionErr; }
- return nil;
- }
- #pragma mark core audio stuff
- -(void) setUpAUGraph {
- if (self.auGraph) {
- CheckError(AUGraphClose(self.auGraph),
- "Couldn't close old AUGraph");
- CheckError (DisposeAUGraph(self.auGraph),
- "Couldn't dispose old AUGraph");
- }
- CheckError(NewAUGraph(&_auGraph),
- "Couldn't create new AUGraph");
- CheckError(AUGraphOpen(self.auGraph),
- "Couldn't open AUGraph");
- // start with file player unit
- AudioComponentDescription fileplayercd = {0};
- fileplayercd.componentType = kAudioUnitType_Generator;
- fileplayercd.componentSubType = kAudioUnitSubType_AudioFilePlayer;
- fileplayercd.componentManufacturer = kAudioUnitManufacturer_Apple;
- AUNode filePlayerNode;
- CheckError(AUGraphAddNode(self.auGraph,
- &fileplayercd,
- &filePlayerNode),
- "Couldn't add file player node");
- // get the actual unit
- CheckError(AUGraphNodeInfo(self.auGraph,
- filePlayerNode,
- NULL,
- &_filePlayerUnit),
- "couldn't get file player node");
- // remote io unit
- AudioComponentDescription outputcd = {0};
- outputcd.componentType = kAudioUnitType_Output;
- outputcd.componentSubType = kAudioUnitSubType_RemoteIO;
- outputcd.componentManufacturer = kAudioUnitManufacturer_Apple;
- AUNode ioNode;
- CheckError(AUGraphAddNode(self.auGraph,
- &outputcd,
- &ioNode),
- "couldn't add remote io node");
- // get the remote io unit from the node
- CheckError(AUGraphNodeInfo(self.auGraph,
- ioNode,
- NULL,
- &_ioUnit),
- "couldn't get remote io unit");
- // effect unit here
- AudioComponentDescription effectcd = {0};
- effectcd.componentType = kAudioUnitType_FormatConverter;
- effectcd.componentSubType = kAudioUnitSubType_Varispeed;
- effectcd.componentManufacturer = kAudioUnitManufacturer_Apple;
- AUNode effectNode;
- CheckError(AUGraphAddNode(self.auGraph,
- &effectcd,
- &effectNode),
- "couldn't get effect node [time/pitch]");
- // get effect unit from the node
- CheckError(AUGraphNodeInfo(self.auGraph,
- effectNode,
- NULL,
- &_effectUnit),
- "couldn't get effect unit from node");
- // enable output to the remote io unit
- UInt32 oneFlag = 1;
- UInt32 busZero = 0;
- CheckError(AudioUnitSetProperty(self.ioUnit,
- kAudioOutputUnitProperty_EnableIO,
- kAudioUnitScope_Output,
- busZero,
- &oneFlag,
- sizeof(oneFlag)),
- "Couldn't enable output on bus 0");
- // get stream format that the effect wants
- AudioStreamBasicDescription streamFormat;
- UInt32 propertySize = sizeof (streamFormat);
- CheckError(AudioUnitGetProperty(self.effectUnit,
- kAudioUnitProperty_StreamFormat,
- kAudioUnitScope_Input,
- 0,
- &streamFormat,
- &propertySize),
- "Couldn't get effect unit stream format");
- // apply effect's format elsewhere in the graph
- CheckError(AudioUnitSetProperty(self.filePlayerUnit,
- kAudioUnitProperty_StreamFormat,
- kAudioUnitScope_Output,
- busZero,
- &streamFormat,
- sizeof(streamFormat)),
- "couldn't set stream format on file player bus 0 output");
- CheckError(AudioUnitSetProperty(self.ioUnit,
- kAudioUnitProperty_StreamFormat,
- kAudioUnitScope_Input,
- busZero,
- &streamFormat,
- sizeof(streamFormat)),
- "couldn't set stream format on iounit bus 0 input");
- // make connections
- CheckError(AUGraphConnectNodeInput(self.auGraph,
- filePlayerNode,
- 0,
- effectNode,
- 0),
- "couldn't connect file player bus 0 output to effect bus 0 input");
- // CheckError(AUGraphConnectNodeInput(self.auGraph,
- // effectNode,
- // 0,
- // ioNode,
- // 0),
- // "couldn't connect effect bus 0 output to remoteio bus 0 input");
- // AudioStreamBasicDescription dstFormat;
- // dstFormat.mSampleRate=44100.0;
- // dstFormat.mFormatID=kAudioFormatLinearPCM;
- // dstFormat.mFormatFlags=kAudioFormatFlagsNativeEndian|kAudioFormatFlagIsSignedInteger|kAudioFormatFlagIsPacked;
- //
- // dstFormat.mBytesPerPacket=4;
- // dstFormat.mBytesPerFrame=4;
- // dstFormat.mFramesPerPacket=1;
- // dstFormat.mChannelsPerFrame=2;
- // dstFormat.mBitsPerChannel=16;
- // dstFormat.mReserved=0;
- CheckError(AUGraphInitialize(self.auGraph),
- "Couldn't initialize AUGraph");
- AURenderCallbackStruct callbackStruct = {0};
- callbackStruct.inputProc = &MyAURenderCallback;
- callbackStruct.inputProcRefCon = self.effectUnit;
- OSStatus result = noErr;
- // Attach the render callback function to remoteIO's input on bus 0
- result = AUGraphSetNodeInputCallback (
- self.auGraph,
- ioNode,
- 0,
- &callbackStruct
- );
- CheckError(result, "AUGraphSetNodeInputCallback");
- // configure file player
- CFURLRef audioFileURL = CFBridgingRetain(
- [[NSBundle mainBundle] URLForResource:@"rampAudio"
- withExtension:@"m4a"]);
- NSLog (@"found URL %@", audioFileURL);
- AudioFileID audioFile;
- CheckError(AudioFileOpenURL(audioFileURL,
- kAudioFileReadPermission,
- kAudioFileCAFType,
- &audioFile),
- "Couldn't open audio file");
- AudioStreamBasicDescription fileStreamFormat;
- UInt32 propsize = sizeof (fileStreamFormat);
- CheckError(AudioFileGetProperty(audioFile,
- kAudioFilePropertyDataFormat,
- &propertySize,
- &fileStreamFormat),
- "couldn't get input file's stream format");
- CheckError(AudioUnitSetProperty(self.filePlayerUnit,
- kAudioUnitProperty_ScheduledFileIDs,
- kAudioUnitScope_Global,
- 0,
- &audioFile,
- sizeof(audioFile)),
- "AudioUnitSetProperty[kAudioUnitProperty_ScheduledFileIDs] failed");
- UInt64 nPackets;
- propsize = sizeof(nPackets);
- CheckError(AudioFileGetProperty(audioFile,
- kAudioFilePropertyAudioDataPacketCount,
- &propsize,
- &nPackets),
- "AudioFileGetProperty[kAudioFilePropertyAudioDataPacketCount] failed");
- // tell the file player AU to play the entire file
- ScheduledAudioFileRegion rgn;
- memset (&rgn.mTimeStamp, 0, sizeof(rgn.mTimeStamp));
- rgn.mTimeStamp.mFlags = kAudioTimeStampSampleTimeValid;
- rgn.mTimeStamp.mSampleTime = 0;
- rgn.mCompletionProc = NULL;
- rgn.mCompletionProcUserData = NULL;
- rgn.mAudioFile = audioFile;
- rgn.mLoopCount = 100;
- rgn.mStartFrame = 0;
- rgn.mFramesToPlay = nPackets * fileStreamFormat.mFramesPerPacket;
- CheckError(AudioUnitSetProperty(self.filePlayerUnit,
- kAudioUnitProperty_ScheduledFileRegion,
- kAudioUnitScope_Global,
- 0,
- &rgn,
- sizeof(rgn)),
- "AudioUnitSetProperty[kAudioUnitProperty_ScheduledFileRegion] failed");
- // prime the file player AU with default values
- UInt32 defaultVal = 0;
- CheckError(AudioUnitSetProperty(self.filePlayerUnit,
- kAudioUnitProperty_ScheduledFilePrime,
- kAudioUnitScope_Global,
- 0,
- &defaultVal,
- sizeof(defaultVal)),
- "AudioUnitSetProperty[kAudioUnitProperty_ScheduledFilePrime] failed");
- // tell the file player AU when to start playing (-1 sample time means next render cycle)
- AudioTimeStamp startTime;
- memset (&startTime, 0, sizeof(startTime));
- startTime.mFlags = kAudioTimeStampSampleTimeValid;
- startTime.mSampleTime = -1;
- CheckError(AudioUnitSetProperty(self.filePlayerUnit,
- kAudioUnitProperty_ScheduleStartTimeStamp,
- kAudioUnitScope_Global,
- 0,
- &startTime,
- sizeof(startTime)),
- "AudioUnitSetProperty[kAudioUnitProperty_ScheduleStartTimeStamp]");
- AURenderCallbackStruct inputCallbackStruct;
- inputCallbackStruct.inputProc = &MyAURenderCallback;
- inputCallbackStruct.inputProcRefCon = self.effectUnit;
- // OSStatus result = noErr;
- // // Attach the render callback function to remoteIO's input on bus 0
- // result = AUGraphSetNodeInputCallback (
- // self.auGraph,
- // ioNode,
- // 0,
- // &inputCallbackStruct
- // );
- //
- // CheckError(result, "AUGraphSetNodeInputCallback");
- CAShow(self.auGraph);
- CheckError(AUGraphStart(self.auGraph),
- "Couldn't start AUGraph");
- NSLog (@"bottom of setUpAUGraph");
- }
- //
- //- (void) setupStereoStreamFormat {
- //
- // AudioStreamBasicDescription dstFormat;
- // dstFormat.mSampleRate=44100.0;
- // dstFormat.mFormatID=kAudioFormatLinearPCM;
- // dstFormat.mFormatFlags=kAudioFormatFlagsNativeEndian|kAudioFormatFlagIsSignedInteger|kAudioFormatFlagIsPacked;
- //
- // dstFormat.mBytesPerPacket=4;
- // dstFormat.mBytesPerFrame=4;
- // dstFormat.mFramesPerPacket=1;
- // dstFormat.mChannelsPerFrame=2;
- // dstFormat.mBitsPerChannel=16;
- // dstFormat.mReserved=0;
- //
- //// // The AudioUnitSampleType data type is the recommended type for sample data in audio
- //// // units. This obtains the byte size of the type for use in filling in the ASBD.
- //// size_t bytesPerSample = sizeof (AudioUnitSampleType);
- ////
- //// // Fill the application audio format struct's fields to define a linear PCM,
- //// // stereo, noninterleaved stream at the hardware sample rate.
- //// stereoStreamFormat.mFormatID = kAudioFormatLinearPCM;
- //// stereoStreamFormat.mFormatFlags = kAudioFormatFlagsAudioUnitCanonical;
- //// stereoStreamFormat.mBytesPerPacket = bytesPerSample;
- //// stereoStreamFormat.mFramesPerPacket = 1;
- //// stereoStreamFormat.mBytesPerFrame = bytesPerSample;
- //// stereoStreamFormat.mChannelsPerFrame = 2; // 2 indicates stereo
- //// stereoStreamFormat.mBitsPerChannel = 8 * bytesPerSample;
- //// stereoStreamFormat.mSampleRate = graphSampleRate;
- ////
- ////
- //// NSLog (@"The stereo stream format for the \"guitar\" mixer input bus:");
- //// [self printASBD: stereoStreamFormat];
- //}
- -(void) resetRate {
- // available rates are from 1/32 to 32. slider runs 0 to 10, where each whole
- // value is a power of 2:
- // 1/32, 1/16, 1/8, 1/4, 1/2, 1, 2, 4, 8, 16, 32
- // so:
- // slider = 5, rateParam = 1.0
- // slider = 0, rateParam = 1/32
- // slider = 10, rateParam = 32
- Float32 rateParam = powf(2.0, [self.timeSlider value] - 5.0);
- // NSLog(@"Float :: %f",[self.timeSlider value] - 5.0);
- // Float32 rateParam = powf(2.0, -1.302817);
- self.rateLabel.text = [NSString stringWithFormat: @"%0.3f", rateParam];
- CheckError(AudioUnitSetParameter(self.effectUnit,
- kNewTimePitchParam_Rate,
- kAudioUnitScope_Global,
- 0,
- rateParam,
- 0),
- "couldn't set pitch parameter");
- // AURenderCallbackStruct callbackStruct = {0};
- // callbackStruct.inputProc = MyAURenderCallback;
- // callbackStruct.inputProcRefCon = self.ioUnit;
- //// callbackStruct.inputProcRefCon = (__bridge void *)self;
- //
- // AudioUnitSetProperty(self.effectUnit,
- // kAudioUnitProperty_SetRenderCallback,
- // kAudioUnitScope_Input,
- // 0,
- // &callbackStruct,
- // sizeof(callbackStruct));
- }
- -(void) resetEffectSwitchState {
- if (self.effectUnit) {
- UInt32 bypassed = 0;
- CheckError(AudioUnitGetProperty(self.effectUnit,
- kAudioUnitProperty_BypassEffect,
- kAudioUnitScope_Global,
- 0,
- &bypassed,
- sizeof(bypassed)),
- "Couldn't get bypass state of effect unit");
- self.effectSwitch.on = bypassed ? NO : YES;
- }
- }
- - (IBAction)effectSwitchValueChanged:(id)sender {
- if (self.effectUnit) {
- UInt32 bypassed = self.effectSwitch.on ? NO : YES;
- CheckError(AudioUnitSetProperty(self.effectUnit,
- kAudioUnitProperty_BypassEffect,
- kAudioUnitScope_Global,
- 0,
- &bypassed,
- sizeof(bypassed)),
- "Couldn't set bypass property");
- }
- }
- @end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement