Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
422 views
in Technique[技术] by (71.8m points)

objective c - How can I change non-realtime pitch/samplerate of a sound?

I have an mp3 sound I'd like to play with pan, pitch/samplerate, and volume controls set once (not changing in realtime). I am using AVAudioPlayer at the moment, which works, but the rate setting performs time stretching instead of performing the samplerate change where the lower values cause a sound to get slower and lower-pitched, and the higher ones cause a sound to get faster and higher-pitched (kind of like tape speed). E.g., setting samplerate to 88200 HZ when your sound is actually 44100 will result in it playing at 200% speed/pitch. Is something like this possible with AVAudioPlayer, or is there another way to accomplish this? Here's what I have so far:

player=[[AVAudioPlayer alloc] initWithContentsOfURL:
[NSURL fileURLWithPath: @"sound.mp3"] error: nil];
player.volume=0.4f;
player.pan=-1f;
player.enableRate=YES;
player.rate=2.0f;
[player play];

Note: I'm not referring to the pitch method where time stretching is used in combination to keep the length of the sound aproximetly the same, or any "advanced" algorithms.

question from:https://stackoverflow.com/questions/65517928/how-can-i-change-non-realtime-pitch-samplerate-of-a-sound

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

AVAudioEngine can give you pitch, rate, pan and volume control:

self.engine = [[AVAudioEngine alloc] init];

NSError *error;

AVAudioPlayerNode *playerNode = [[AVAudioPlayerNode alloc] init];
AVAudioMixerNode *mixer = [[AVAudioMixerNode alloc] init];
AVAudioUnitVarispeed *varispeed = [[AVAudioUnitVarispeed alloc] init];

[self.engine attachNode:playerNode];
[self.engine attachNode:varispeed];
[self.engine attachNode:mixer];

[self.engine connect:playerNode to:varispeed format:nil];
[self.engine connect:varispeed to:mixer format:nil];
[self.engine connect:mixer to:self.engine.mainMixerNode format:nil];

BOOL result = [self.engine startAndReturnError: &error];
assert(result);

AVAudioFile *audioFile = [[AVAudioFile alloc] initForReading:url error:&error];
assert(audioFile);

// rate & pitch (fused), pan and volume controls
varispeed.rate = 0.5; // half pitch & rate
mixer.pan = -1;       // left speaker
mixer.volume = 0.5;   // half volume

[playerNode scheduleFile:audioFile atTime:nil completionHandler:nil];
[playerNode play];

If you want separate rate & pitch control, replace the AVAudioUnitVarispeed node with an AVAudioUnitTimePitch node.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...