AVAudioEngine和AVAudioPlayerNode的使用
AVAudioPlayer能通過(guò)rate屬性控制播放的速率,但是變速后會(huì)變調(diào),而AVAudioEngine能做到控制播放變速不變調(diào)。
//create Node
self.mbEngine = [AVAudioEngine new];
self.mbPlayerNode = [AVAudioPlayerNode new];
self.mbAudioUnitTimePitch = [AVAudioUnitTimePitch new];
self.mbAudioUnitVarispeed = [AVAudioUnitVarispeed new];
[self.mbEngine attachNode:self.mbPlayerNode];
[self.mbEngine attachNode:self.mbAudioUnitTimePitch];
[self.mbEngine attachNode:self.mbAudioUnitVarispeed];
//connectNode
[self.mbEngine connect:self.mbPlayerNode to:self.mbAudioUnitTimePitch format:self.mbAudioFile.processingFormat];
[self.mbEngine connect:self.mbAudioUnitTimePitch to:self.mbAudioUnitVarispeed format:self.mbAudioFile.processingFormat];
[self.mbEngine connect:self.mbAudioUnitVarispeed to:self.mbEngine.mainMixerNode format:self.mbAudioFile.processingFormat];
//start Engine
[self.mbEngine prepare];
[self.mbEngine startAndReturnError:&error];
//通過(guò)設(shè)置mbAudioUnitVarispeed和AVAudioUnitTimePitch來(lái)控制速度和音調(diào)。兩者間存在個(gè)關(guān)系。
float speed = 0.5;
float pitch = 0;
pitch = fabsf(log2f(speed)) *1200;
self.mbAudioUnitVarispeed.rate = speed;
self.mbAudioUnitTimePitch.pitch = pitch;
//然后是播放,控制一下兩邊極值
seekTime = seekTime > self.playerNodeDuration ? self.playerNodeDuration : seekTime;
seekTime = seekTime > 0 ? seekTime : 0;
AVAudioFramePosition seekFrame = seekTime * tempFile.processingFormat.sampleRate;
//記錄一下播放前的位置,用來(lái)計(jì)算當(dāng)前的播放時(shí)間
self.lastStartFramePosition = seekFrame;
AVAudioFrameCount frameCount = (AVAudioFrameCount)(tempFile.length - seekFrame);
BOOL isPlaying = self.mbPlayerNode.isPlaying;
[self.mbPlayerNode stop];
if (seekFrame < (AVAudioFramePosition)tempFile.length) {
[self.mbPlayerNode scheduleSegment:tempFile startingFrame:seekFrame frameCount:frameCount atTime:nil completionHandler:^{
}];
if (isPlaying) {
[self.mbPlayerNode play];
}
}
關(guān)于獲取總時(shí)間和當(dāng)前的播放時(shí)間
AVAudioTime *playerTime = [self.mbPlayerNode playerTimeForNodeTime:self.mbPlayerNode.lastRenderTime];
self.playerNodeCurrenttime = (self.lastStartFramePosition+playerTime.sampleTime)/playerTime.sampleRate;
NSLog(@"當(dāng)前時(shí)間%f",self.playerNodeCurrenttime);
可能會(huì)出現(xiàn)的一些問(wèn)題
//1,engine被置空為nil了
required condition is false: _engine != nil
//2,engine在node播放前未啟動(dòng)
required condition is false: _engine->IsRunning()