You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift开发中如何调整已录制音频的音高与播放速度且不破坏原有功能

不需要完全重写AudioPlayer.swift,也不需要维护两套播放逻辑,直接统一用AVAudioEngine替换原有AVAudioPlayer的内部实现即可,对外接口保持和原有实现一致,上层业务代码无需任何改动。

具体改造方案

  1. 替换内部核心属性
    删掉原有AVAudioPlayer相关属性,新增AVAudioEngine链路核心节点:
class AudioPlayer {
    private let engine = AVAudioEngine()
    private let playerNode = AVAudioPlayerNode()
    // 该节点同时支持调速、调pitch,无需额外新增节点
    private let pitchControl = AVAudioUnitTimePitch()
    private var currentAudioFile: AVAudioFile?
}
  1. 初始化时完成链路配置
init() {
    // 挂载节点到引擎
    engine.attach(playerNode)
    engine.attach(pitchControl)
    // 配置节点链路:播放节点 -> 音效处理节点 -> 输出混音器
    engine.connect(playerNode, to: pitchControl, format: nil)
    engine.connect(pitchControl, to: engine.mainMixerNode, format: nil)
    // 提前启动引擎,避免首次播放延迟
    try? engine.start()
}
  1. 兼容原有对外接口
    保持原有方法名、参数、返回值完全不变,仅替换内部实现逻辑,上层调用无需修改:
// 原有播放方法,对外接口完全对齐原实现
func startPlayback(audio: URL) throws {
    // 先重置之前的播放状态
    stopPlayback()
    // 加载音频文件
    currentAudioFile = try AVAudioFile(forReading: audio)
    guard let file = currentAudioFile else { return }
    // 调度音频播放
    playerNode.scheduleFile(file, at: nil)
    playerNode.play()
}

// 原有停止方法,兼容旧逻辑
func stopPlayback() {
    playerNode.stop()
    playerNode.reset()
}

// 兼容原有播放进度获取逻辑
var currentTime: TimeInterval {
    guard let lastRenderTime = playerNode.lastRenderTime,
          let playerTime = playerNode.playerTime(forNodeTime: lastRenderTime),
          let file = currentAudioFile else {
        return 0
    }
    return Double(playerTime.sampleTime) / file.processingFormat.sampleRate
}

// 兼容原有总时长获取逻辑
var duration: TimeInterval {
    currentAudioFile?.duration ?? 0
}
  1. 新增音高、速度调整接口
    直接对外暴露音效节点的参数即可:
// 播放速度,建议取值范围0.5~2.0,默认1.0为原始速度
var playbackRate: Float {
    get { pitchControl.rate }
    set { pitchControl.rate = newValue }
}

// 音高,单位为音分,100音分对应1个半音,建议取值范围-2400~2400,默认0为原始音高
var playbackPitch: Float {
    get { pitchControl.pitch }
    set { pitchControl.pitch = newValue }
}

注意事项

AVAudioUnitTimePitch默认rate=1、pitch=0时,播放效果和原生AVAudioPlayer完全一致,无需区分是否开启音效,所有播放场景都可以用这套实现,性能远高于切换两套播放逻辑的方案。
如果需要支持暂停功能,新增pause()方法调用playerNode.pause()即可,原有逻辑无需调整。

内容的提问来源于stack exchange,提问作者phiredrop

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 04:30:03