1

I am trying to shift the pitch of an audio file multiple time to indicate changes in the state to the user. I wasn't sure how to do this in objective-c

I found this article about a question that discusses it, but it was for swift. Also, I wasn't sure how to load audio files with this library.

I tried this code, but every time I run it, I got an error because of the lines 3-4. The other thing, as I'm newbie to this, I wasn't sure how to load the mp3 file with this library. Can anyone help please?

//This is the file I need to shift its pitch
NSString *path = [NSString stringWithFormat:@"%@/Beep5.mp3", [[NSBundle mainBundle] resourcePath]];
NSURL *soundUrl = [NSURL fileURLWithPath:path];
AVAudioFile *file=[[AVAudioFile alloc] initForReading:soundUrl error:nil];
AVAudioFormat *format=file.processingFormat;
AVAudioFrameCount capacity= (AVAudioFrameCount)file.length;
AVAudioPCMBuffer *buffer=[[AVAudioPCMBuffer alloc] initWithPCMFormat:format frameCapacity:capacity];
[file readIntoBuffer:buffer error:nil];
[playerNode scheduleBuffer:buffer completionHandler:nil];


AVAudioEngine *engine;
AVAudioPlayerNode *playerNode;

//get the error in one of the following two LOC
engine = [[AVAudioPlayerNode alloc] init];
[engine attachNode: playerNode];

AVAudioMixerNode *mixer = engine.mainMixerNode;
AVAudioUnitTimePitch *auTimePitch;
auTimePitch.pitch=1200.0;// In cents. The default value is 1.0. The range of values is -2400 to 2400
auTimePitch.rate = 2.0; //The default value is 1.0. The range of supported values is 1/32 to 32.0.
[engine attachNode: auTimePitch];
[engine connect:playerNode to:auTimePitch format:[mixer outputFormatForBus:0]];
[engine connect:playerNode to:mixer format:[mixer outputFormatForBus:0]];
    playerNode.play;
Community
  • 1
  • 1
user1564015
  • 65
  • 1
  • 9

2 Answers2

2

Please add following headers and try -

#import <AVFoundation/AVAudioPlayerNode.h>
#import <AVFoundation/AVAudioEngine.h>

engine = [[AVAudioEngine alloc] init];

playerNode = [[AVAudioPlayerNode alloc] init];
Avi
  • 2,196
  • 18
  • 18
  • The error is thrown at the line that contains (engine = [[AVAudioPlayerNode alloc] init];) and I saw a warning sign saying: incompatible pointer size – user1564015 May 01 '15 at 14:43
  • Dont you think its obvious, engine is AVAudioEngine property, u r assigning AVAudioPlayerNode instance to it, that's why it complains for incompatibility. What you have to do is mentioned in edited answer. – Avi May 01 '15 at 20:32
  • Thanks Avi for the hint. I am still getting error on the line when attaching auTimePitch to engine. Any thoughts? – user1564015 May 01 '15 at 22:00
  • AVAudioPlayerNode.mm:334: Start: required condition is false: _engine->IsRunning() – user1564015 May 01 '15 at 22:42
  • The goal of my code is to load an mp3 file, change its pitch then play it. I'm newbie so bare with me :) – user1564015 May 02 '15 at 01:22
0

your code looks fine but you skiped the creation of new object of AVAudioPlayerNode and AVAudioEngine.

this should look like this

     @interface ViewController (){

            AVAudioEngine *engine;
        }
        AVAudioPlayerNode* node = [AVAudioPlayerNode new];    
        engine= [[AVAudioEngine alloc] init];

and your complete code after adding these line.

    //AVAudioEngine *engine should be declare in @interface section

    @interface ViewController (){

            AVAudioEngine *engine;
        }

- (void)viewDidLoad {    
    [super viewDidLoad];
     NSString* path=[[NSBundle mainBundle] pathForResource:@"test" ofType:@"mp3"];
        NSURL *soundUrl = [NSURL fileURLWithPath:path];
        AVAudioFile* File = [[AVAudioFile alloc] initForReading: soundUrl error: nil];
        AVAudioPlayerNode* node = [AVAudioPlayerNode new];
        engine= [[AVAudioEngine alloc] init];

        [node stop];
        [engine stop];
        [engine reset];
        [engine attachNode: node];
        AVAudioUnitTimePitch* changeAudioUnitTime = [AVAudioUnitTimePitch new];
        changeAudioUnitTime.rate = 1;
        changeAudioUnitTime.pitch = 1000;
        [engine attachNode: changeAudioUnitTime];
        [engine connect:node to: changeAudioUnitTime format: nil];
        [engine connect:changeAudioUnitTime to: engine.outputNode format:nil];
        [node scheduleFile:File atTime: nil completionHandler: nil];
        [engine startAndReturnError: nil];
        [node play];
    }

Note :: this code is tested on actual device and working fine in my project. don't forget to add CoreAudio.framework , AVFoundation.framework.

Mehsam Saeed
  • 235
  • 2
  • 14