【问题标题】:How can I change non-realtime pitch/samplerate of a sound?如何更改声音的非实时音高/采样率?
【发布时间】:2020-12-31 07:30:08
【问题描述】:

我想播放一个 mp3 声音,只需设置一次声像、音高/采样率和音量控制(不会实时更改)。 我目前正在使用 AVAudioPlayer,它可以工作,但是速率设置执行时间拉伸而不是执行采样率更改,其中较低的值会导致声音变得更慢和更低音调,而更高的值会导致声音变得更快和更高的音调(有点像磁带速度)。 例如,当您的声音实际为 44100 时,将采样率设置为 88200 HZ 将导致它以 200% 的速度/音高播放。 使用 AVAudioPlayer 是否可以实现类似的操作,或者是否有其他方法可以做到这一点? 到目前为止,这是我所拥有的:

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];

注意:我不是指结合使用时间拉伸以保持声音长度大致相同的音高方法,或任何“高级”算法。

【问题讨论】:

  • AvAudioPlayer 好像没有提供那种功能developer.apple.com/documentation/avfoundation/avaudioplayer
  • 改变播放速度不一定像改变采样率那么简单。支持一定数量的采样率,因此您可能必须采取不同的方法。我能想到的最明显的方法是使用音频单元在样本值之间进行插值,相应地降低或增加值
  • @fdcpp 那我还有其他方法吗?也许另一堂课?另一个框架?
  • 如果是非实时的,你可以摄取音频文件,获取样本,应用插值保存一个新的音频文件并回放。
  • 对于框架:JUCE 可能是笨手笨脚的。 OpenAL 可以做到,但是已经过时了。 AudioUnits 似乎确实是最有可能的竞争者

标签: objective-c macos cocoa audio avfoundation


【解决方案1】:

AVAudioEngine 可以为您提供音高、速率、平移和音量控制:

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];

如果您想要单独的速率和俯仰控制,请将 AVAudioUnitVarispeed 节点替换为 AVAudioUnitTimePitch 节点。

【讨论】:

  • 这绝对是达到预期效果的最佳方式。我可以建议的唯一补充是使用pitch.pitch = 1200 * log2(pitch.rate) 将音调与评分联系起来
  • 谢谢@fdcpp 我懒得迈出那一步
  • @Rhythmic Fistman 非常感谢!这非常有效,除了改变音高确实会导致时间拉伸,即即使保持默认速率,音频也不会随着音高变化而减慢或加速。我希望 -1200 音高大约是原始音高的两倍,等等。这就是 1200 * log2(pitch.rate) 公式应该做的吗?
  • 是的!试试那个。
  • 啊等等,你可能想要AVAudioUnitVarispeed。一秒钟,更新答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-11
  • 1970-01-01
  • 2020-04-11
  • 1970-01-01
相关资源
最近更新 更多