如何将AVAudioUnitVarispeed添加到可同时播放多种声音的有效AVAudioEngine中

问题描述 投票:0回答:1

我正在为iOS开发音乐应用。我想同时播放5个文件。这已经在此线程的帮助下起作用:How to play multiple sounds from buffer simultaneously using nodes connected to AVAudioEngine's mixer

现在,我需要使用AVAudioUnitVarispeed更快地播放所有文件。我无法使它正常工作。

这里是代码:

import AVFoundation

class Audio {

    // MARK: AUDIO VARIABLEN
    var engineFirst: AVAudioEngine = AVAudioEngine()
    var audioFilePlayer = [AVAudioPlayerNode]()
    var noteFilePath = [String]()

    // Speed
    var speedControl = [AVAudioUnitVarispeed]()

    var noteFileURL = [URL]()
    var noteAudioFile = [AVAudioFile]()
    var noteAudioFileBuffer = [AVAudioPCMBuffer]()
    let tonAnzahl = 5
    let latency = 0.03
    var playing = false

    // MARK: PLAY SOUND
    func playSound() {
        playing = true
        for i in 0...tonAnzahl - 1 {
            audioFilePlayer[i].scheduleBuffer(noteAudioFileBuffer[i], at: nil, completionHandler: nil)
            audioFilePlayer[i].play()
        }

    }

    // MARK: STOP SOUND
    func stopSound() {
        playing = false
        for i in 0...tonAnzahl - 1 {
            audioFilePlayer[i].volume = 0
        }
        DispatchQueue.main.asyncAfter(deadline: .now() + latency, execute: {
            for i in 0...self.tonAnzahl - 1 {
                self.audioFilePlayer[i].stop()
            }
        })
    }

    // MARK: SETUP AUDIO ENGINE
    func setupAudioEngine(bassFile: String, terzFile: String, septimeFile: String, tensionOneFile: String, tensionTwoFile: String) {
        do {
            noteAudioFile.removeAll()
            noteFileURL.removeAll()
            // For each note, read the note URL into an AVAudioFile,
            // setup the AVAudioPCMBuffer using data read from the file,
            // and read the AVAudioFile into the corresponding buffer
            for i in 0...tonAnzahl - 1 {
                noteFilePath = [
                    Bundle.main.path(forResource: bassFile, ofType: "mp3")!,
                    Bundle.main.path(forResource: terzFile, ofType: "mp3")!,
                    Bundle.main.path(forResource: septimeFile, ofType: "mp3")!,
                    Bundle.main.path(forResource: tensionOneFile, ofType: "mp3")!,
                    Bundle.main.path(forResource: tensionTwoFile, ofType: "mp3")!]
                noteFileURL.append(URL(fileURLWithPath: noteFilePath[i]))

                try noteAudioFile.append(AVAudioFile(forReading: noteFileURL[i]))

                let noteAudioFormat = noteAudioFile[i].processingFormat
                let noteAudioFrameCount = UInt32(noteAudioFile[i].length)
                noteAudioFileBuffer.append(AVAudioPCMBuffer(pcmFormat: noteAudioFormat, frameCapacity: noteAudioFrameCount)!)

                try noteAudioFile[i].read(into: noteAudioFileBuffer[i])
            }
            // For each note, attach the corresponding node to the engineFirst, and connect the node to the engineFirst's mixer.
            for i in 0...tonAnzahl - 1 {
                audioFilePlayer.append(AVAudioPlayerNode())
                engineFirst.attach(audioFilePlayer[i])


                // HERE IS THE PROBLEM
                speedControl.append(AVAudioUnitVarispeed())
                speedControl[i].rate = 2
                engineFirst.attach(speedControl[i])

                engineFirst.connect(audioFilePlayer[i], to: speedControl[i], fromBus: 0, toBus: i, format: noteAudioFileBuffer[i].format)
                engineFirst.connect(speedControl[i], to: engineFirst.mainMixerNode, fromBus: 0, toBus: i, format: noteAudioFileBuffer[i].format)

            }

            // Audio Engine Start
            try engineFirst.start()

            // Setup the audio session to play sound in the app, and activate the audio session
            try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.soloAmbient)
            try AVAudioSession.sharedInstance().setMode(AVAudioSession.Mode.default)
            try AVAudioSession.sharedInstance().setActive(true)
        }
        catch let error {
            print(error.localizedDescription)
        }
    }
}

如果我替换,此代码将同时播放5个音符

// HERE IS THE PROBLEM
speedControl.append(AVAudioUnitVarispeed())
speedControl[i].rate = 2
engineFirst.attach(speedControl[i])

engineFirst.connect(audioFilePlayer[i], to: speedControl[i], fromBus: 0, toBus: i, format: noteAudioFileBuffer[i].format)
engineFirst.connect(speedControl[i], to: engineFirst.mainMixerNode, fromBus: 0, toBus: i, format: noteAudioFileBuffer[i].format)

with

engineFirst.connect(audioFilePlayer[i], to: engineFirst.mainMixerNode, fromBus: 0, toBus: i, format: noteAudioFileBuffer[i].format)

...并调用playSound()。

但是然后我没有实现AVAudioUnitVarispeed(speedControl)...

所以,如何为AVAudioUnitVarispeed添加代码?

谢谢您的帮助。

avaudioengine avaudioplayernode
1个回答
0
投票
engineFirst.connect(audioFilePlayer[i], to: engineFirst.mainMixerNode, format: noteAudioFileBuffer[i].format) // And then put this outside of the loop to connect all audioFilePlayers engineFirst.connect(engineFirst.mainMixerNode, to: speedControl, format: noteAudioFileBuffer[0].format) engineFirst.connect(speedcontrol, to: engineFirst.outputNode, format: noteAudioFileBuffer[0].format)

这样,您只需要一个AVAudioUnitVarispeed实例,而不必分别更改每个玩家的速度。

希望这对您有用。 
© www.soinside.com 2019 - 2024. All rights reserved.