且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

Xcode 8 Swift 3变音

更新时间:2022-11-23 23:34:39

每次播放声音时,都要重置引擎!而且您正在创建额外的播放器节点-实际上,如果您只想一次播放音调转换声音的一个实例,则比这要简单得多:

You're resetting the engine every time you play a sound! And you're creating extra player nodes - it's actually much simpler than that if you only want one instance of the pitch shifted sound playing at once:

// instance variables
let engine = AVAudioEngine()
let audioPlayerNode = AVAudioPlayerNode()
let changeAudioUnitTime = AVAudioUnitTimePitch()

致电setupAudioEngine()一次:

func setupAudioEngine() {
    engine.attach(self.audioPlayerNode)

    engine.attach(changeAudioUnitTime)
    engine.connect(audioPlayerNode, to: changeAudioUnitTime, format: nil)
    engine.connect(changeAudioUnitTime, to: engine.outputNode, format: nil)
    try? engine.start()
    audioPlayerNode.play()
}

并根据需要多次呼叫hitSound():

func hitSound(value: Float) {
    changeAudioUnitTime.pitch = value

    audioPlayerNode.scheduleFile(file, at: nil, completionHandler: nil) // File is an AVAudioFile defined previously
}

p.s.音调可以向上或向下移动两个八度音阶,范围为4个八度音阶,并且在[-2400,2400]的数值范围内,单位为分".

p.s. pitch can be shifted two octaves up or down, for a range of 4 octaves, and lies in the numerical range of [-2400, 2400], having the unit "cents".

p.p.s AVAudioUnitTimePitch是非常酷的技术.当我小时候,我们绝对没有类似的东西.

p.p.s AVAudioUnitTimePitch is very cool technology. We definitely didn't have anything like it when I was a kid.

更新

如果您想要多通道,则可以轻松地设置多个播放器和音高节点,但是 您必须在启动引擎之前选择通道数.这是您做两个的方法(很容易扩展到n个实例,您可能想选择自己的方法来选择在所有播放时中断哪个通道):

If you want multi channel, you can easily set up multiple player and pitch nodes, however you must choose the number of channels before you start the engine. Here's how you'd do two (it's easy to extend to n instances, and you'll probably want to choose your own method of choosing which channel to interrupt when all are playing):

// instance variables
let engine = AVAudioEngine()
var nextPlayerIndex = 0
let audioPlayers = [AVAudioPlayerNode(), AVAudioPlayerNode()]
let pitchUnits = [AVAudioUnitTimePitch(), AVAudioUnitTimePitch()]

func setupAudioEngine() {
    var i = 0
    for playerNode in audioPlayers {
        let pitchUnit = pitchUnits[i]

        engine.attach(playerNode)
        engine.attach(pitchUnit)
        engine.connect(playerNode, to: pitchUnit, format: nil)
        engine.connect(pitchUnit, to:engine.mainMixerNode, format: nil)

        i += 1
    }

    try? engine.start()

    for playerNode in audioPlayers {
        playerNode.play()
    }
}

func hitSound(value: Float) {
    let playerNode = audioPlayers[nextPlayerIndex]
    let pitchUnit = pitchUnits[nextPlayerIndex]

    pitchUnit.pitch = value

    // interrupt playing sound if you have to
    if playerNode.isPlaying {
        playerNode.stop()
        playerNode.play()
    }

    playerNode.scheduleFile(file, at: nil, completionHandler: nil) // File is an AVAudioFile defined previously

    nextPlayerIndex = (nextPlayerIndex + 1) % audioPlayers.count
}