更改“发声器”的音频音高

Posted

技术标签:

【中文标题】更改“发声器”的音频音高【英文标题】:Changing Audio Pitch of "sounder" 【发布时间】:2018-06-03 18:09:18 【问题描述】:

编辑:在底部添加了新代码。

我对编码很陌生,所以我从创建一个音板应用开始。我已经能够使用“rate”命令来减慢或加快音频的速度,但现在我也想改变音高。理想情况下,我想要两个开关。一种可以加快音频速度并提高音调,一种可以减慢和降低,如果它们都关闭,则播放正常。下面是我的代码,它适用于除了改变音高之外的所有东西。非常感谢任何输入。作为参考,sass 慢,chip 快。

import UIKit
import AVFoundation

var Sounder1 = AVAudioPlayer()
var Sounder2 = AVAudioPlayer()

let sassFloat: Float = 0.5
let myInt = Int(sassFloat)

let chipFloat: Float = 3.0
let myInt2 = Int(chipFloat)

class ViewController: UIViewController 

@IBOutlet weak var sassSwitch: UISwitch!

@IBOutlet weak var chipSwitch: UISwitch!

override func viewDidLoad() 
    super.viewDidLoad()

    do 
        Sounder1 = try AVAudioPlayer(contentsOf: URL.init(fileURLWithPath: Bundle.main.path(forResource: "Sound1", ofType: "mp3")!))
        Sounder1.prepareToPlay()
        Sounder1.enableRate = true
    catch

    

    do 
        Sounder2 = try AVAudioPlayer(contentsOf: URL.init(fileURLWithPath: Bundle.main.path(forResource: "Sound2", ofType: "wav")!))
        Sounder2.prepareToPlay()
        Sounder2.enableRate = true
    catch

    
    // Do any additional setup after loading the view, typically from a nib.


@IBAction func sassAction(_ sender: UISwitch) 
    chipSwitch.setOn(false, animated: true)


@IBAction func chipAction(_ sender: UISwitch) 
    sassSwitch.setOn(false, animated: true)


@IBAction func play(_ sender: Any) 
    if sassSwitch.isOn 
        Sounder1.rate = sassFloat
        Sounder1.play()
     else if chipSwitch.isOn 
        Sounder1.rate = chipFloat
        Sounder1.play()
     else 
        Sounder1.rate = 1.0
        Sounder1.play()
    



@IBAction func play2(_ sender: Any) 
    if sassSwitch.isOn 
        Sounder2.rate = sassFloat
        Sounder2.play()
     else if chipSwitch.isOn 
        Sounder2.rate = chipFloat
        Sounder2.play()
     else 
        Sounder2.rate = 1.0
        Sounder2.play()
    



override func didReceiveMemoryWarning() 
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.




这是我根据@ericl 的建议提出的新代码。我仍然需要reset() audioEngine 但我也有一些问题。 1) if else if else 语句在这种情况下真的有效吗? 2) 我在哪里添加reset() 语句。 3)播放完每个声音后我需要分离节点吗?还是只是重置?

class ViewController: UIViewController 

@IBOutlet weak var sassSwitch: UISwitch!
@IBOutlet weak var chipSwitch: UISwitch!

@IBAction func sassAction(_ sender: UISwitch) 
    chipSwitch.setOn(false, animated: true)

@IBAction func chipSwitch(_ sender: UISwitch) 
    sassSwitch.setOn(false, animated: true)



///Playback Engine
private let audioEngine = AVAudioEngine()

///Player's Nodes
private let pitchPlayer = AVAudioPlayerNode()
private let timePitch = AVAudioUnitTimePitch()

///Audio Files to be played
private var audioFile1 = AVAudioFile()
private var audioFile2 = AVAudioFile()

override func viewDidLoad() 
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

    if let filePath = Bundle.main.path(forResource: "PeteNope", ofType:
        "mp3") 
        let filePathURL = URL(fileURLWithPath: filePath)

        setPlayerFile(filePathURL)

    

    if let filePath2 = Bundle.main.path(forResource: "Law_WOW", ofType:
        "mp3") 
        let filePath2URL = URL(fileURLWithPath: filePath2)

        setPlayerFile2(filePath2URL)

    


private func setPlayerFile(_ fileURL: URL) 
    do 
        let file = try AVAudioFile(forReading: fileURL)

        self.audioFile1 = file


     catch 
        fatalError("Could not create AVAudioFile instance. error: \(error).")
    


private func setPlayerFile2(_ fileURL: URL) 
    do 
        let file = try AVAudioFile(forReading: fileURL)

        self.audioFile2 = file


     catch 
        fatalError("Could not create AVAudioFile instance. error: \(error).")
    



@IBAction func sound1Play(_ sender: UIButton) 
    if sassSwitch.isOn 
        timePitch.pitch = -300
        timePitch.rate = 0.5
        audioEngine.attach(pitchPlayer)
        audioEngine.attach(timePitch)

        audioEngine.connect(pitchPlayer, to: timePitch, format: audioFile1.processingFormat)
        audioEngine.connect(timePitch, to: audioEngine.outputNode, format: audioFile1.processingFormat)
        pitchPlayer.scheduleFile(audioFile1, at: nil, completionHandler: nil)

        // Start the engine.
        do 
            try audioEngine.start()
         catch 
            fatalError("Could not start engine. error: \(error).")
        

        pitchPlayer.play()

     else if chipSwitch.isOn 
        timePitch.pitch = +500
        timePitch.rate = 2.0
        audioEngine.attach(pitchPlayer)
        audioEngine.attach(timePitch)

        audioEngine.connect(pitchPlayer, to: timePitch, format: audioFile1.processingFormat)
        audioEngine.connect(timePitch, to: audioEngine.outputNode, format: audioFile1.processingFormat)
        pitchPlayer.scheduleFile(audioFile1, at: nil, completionHandler: nil)

        // Start the engine.
        do 
            try audioEngine.start()
         catch 
            fatalError("Could not start engine. error: \(error).")
        

        pitchPlayer.play()

     else 
        timePitch.pitch = +0
        timePitch.rate = 1.0
        audioEngine.attach(pitchPlayer)
        audioEngine.attach(timePitch)

        audioEngine.connect(pitchPlayer, to: timePitch, format: audioFile1.processingFormat)
        audioEngine.connect(timePitch, to: audioEngine.outputNode, format: audioFile1.processingFormat)
        pitchPlayer.scheduleFile(audioFile1, at: nil, completionHandler: nil)

        // Start the engine.
        do 
            try audioEngine.start()
         catch 
            fatalError("Could not start engine. error: \(error).")
        
        pitchPlayer.play()
    



override func didReceiveMemoryWarning() 
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.




【问题讨论】:

你不尝试在任何地方改变音高吗?当你做你使用什么价值观?在我的项目中,我将音高设置为 1000(花栗鼠模式)或 -1000(darth vadar 模式)。 正确,这就是我要设置的。基本上,这两个开关我都有减慢或加快速度。我想将音高变化与这些开关联系起来。一旦音高进入,我什至可能不需要改变速率,但我想我会尝试将两者都绑在开关上,然后在需要时将其中一个去掉。 【参考方案1】:

您将使用AVAudioEngineAVAudioPlayerNode 附加到AVAudioUnitTimePitch 效果。我检查了 Apple 的 AudioUnitV3Example 示例代码并从中拼凑出一个工作示例。您将希望实现更多可以在其中找到的状态和错误处理。无论如何,这里是:

在类的顶部定义一些私有变量:

   /// Playback engine.
    private let audioEngine = AVAudioEngine()

    /// Engine's player node.
    private let pitchPlayer = AVAudioPlayerNode()
    private let timePitch = AVAudioUnitTimePitch()

    /// File to play.
    private var audioFile: AVAudioFile?

检查有效的音频文件:

     override func viewDidLoad() 
         super.viewDidLoad()

     if let filePath = Bundle.main.path(forResource: "Sound1", ofType: 
 "mp3") 
         let filePathURL = URL(fileURLWithPath: filePath)

         setPlayerFile(filePathURL)

         
     

     private func setPlayerFile(_ fileURL: URL) 
         do 
             let file = try AVAudioFile(forReading: fileURL)

             self.audioFile = file


          catch 
             fatalError("Could not create AVAudioFile instance. error: \(error).")
         
     

     @IBAction func verySlowPlayback(sender: UIButton) 


    timePitch.pitch = -300
    timePitch.rate = 0.5
    audioEngine.attach(pitchPlayer)
    audioEngine.attach(timePitch)

    audioEngine.connect(pitchPlayer, to: timePitch, format: audioFile?.processingFormat)
    audioEngine.connect(timePitch, to: audioEngine.outputNode, format: audioFile?.processingFormat)
    pitchPlayer.scheduleFile(audioFile!, at: nil, completionHandler: nil)

    // Start the engine.
    do 
        try audioEngine.start()
     catch 
        fatalError("Could not start engine. error: \(error).")
    

    pitchPlayer.play()


【讨论】:

谢谢。当我可以在电脑前时,它将帮助我稍后开始。你对我如何将它们绑定到开关而不是按钮有什么建议吗?基本上我想要两个开关,一个用于快速和高音,一个用于慢速和低音。我想要多个按钮正常播放声音,但如果启用开关,它会加快或减慢它。 顺便说一句:我编辑了帖子以将rate 属性添加到AVAudioUnitTimePitch 类:timePitch.rate = 0.5 您可以让play1()play2() 开关更改AVAudioUnitTimePitch 属性。您将看到是否需要 reset() 音频引擎。 感谢@ericl 的所有帮助。我用一些新代码编辑了这篇文章,这些代码是我和你的编辑一起扔的。如果你有机会,就看看它,让我知道它是否有意义或者我是否偏离了基地。 我认为您应该使用一个文件和一个开关创建一个更简单的测试项目,然后让它工作。看一下 Apple 示例代码,了解一下兔子洞之旅,并考虑使用类似 `isPlaying' 的布尔值来检查状态。找出另一个问题的下一个最小完整和可验证示例,您可能会在此过程中找到答案! (我也是初学者;看到我的低分了吗?)无论如何,我确实回答了您最初的问题“如何改变音高”,所以请接受我的回答!

以上是关于更改“发声器”的音频音高的主要内容,如果未能解决你的问题,请参考以下文章

更改音频缓冲区的音高

如何更改录制音频的音高并在后台保存?

swift中的音频播放器没有获得音量和音高的价值

如何通过改变音高和速度 iOS 保存音频?

在 Windows 中更改原始波形数据的音高

Python 音频帧音高变化