播放多个WAV输出多个频道AVAudioEngine

时间:2017-09-04 17:06:41

标签: swift audio avaudioengine avaudioplayernode

我有15个WAV文件,我需要在各个频道上按顺序播放。我开始试图让两个文件使用左/右立体声分离。

我正在创建一个音频引擎,一个混音器和两个AVAudioPlayerNodes。音频文件是单声道的,我试图让PlayerA的文件从左边的频道出来,而来自PlayerB的文件出来正确的频道。我无法理解的是AudioUnitSetProperty的工作原理。它似乎只与单个文件有关,似乎每个audioUnit只能有一个?我想知道是否有一种方法可以将文件与audioUnit相关联?我似乎无法返回与每个轨道关联的audioUnit对象。

func testCode(){  

    // get output hardware format  
    let output = engine.outputNode  
    let outputHWFormat = output.outputFormat(forBus: 0)  
    // connect mixer to output  
    let mixer = engine.mainMixerNode  
    engine.connect(mixer, to: output, format: outputHWFormat)  


    //then work on the player end by first attaching the player to the engine  
    engine.attach(playerA)  
    engine.attach(playerB)  


    //find the audiofile  
    guard let audioFileURLA = Bundle.main.url(forResource: "test", withExtension: "wav") else {  
        fatalError("audio file is not in bundle.")  
    }  

    guard let audioFileURLB = Bundle.main.url(forResource: "test2", withExtension: "wav") else {  
        fatalError("audio file is not in bundle.")  
    }  

    var songFileA:AVAudioFile?  
    do {  
        songFileA = try AVAudioFile(forReading: audioFileURLA)  
        print(songFileA!.processingFormat)  

        // connect player to mixer  
        engine.connect(playerA, to: mixer, format: songFileA!.processingFormat)  

    } catch {  
        fatalError("canot create AVAudioFile \(error)")  
    }  


    let channelMap: [Int32] = [0, -1] //play channel in left  


    let propSize: UInt32 = UInt32(channelMap.count) * UInt32(MemoryLayout<sint32>.size)  

    print(propSize)  

    let code: OSStatus = AudioUnitSetProperty((engine.inputNode?.audioUnit)!,  
                                              kAudioOutputUnitProperty_ChannelMap,  
                                              kAudioUnitScope_Global,  
                                              1,  
                                              channelMap,  
                                              propSize);  
    print(code)  


    let channelMapB: [Int32] = [-1, 0] //play channel in left  

    var songFileB:AVAudioFile?  
    do {  
        songFileB = try AVAudioFile(forReading: audioFileURLB)  
        print(songFileB!.processingFormat)  

        // connect player to mixer  
        engine.connect(playerB, to: mixer, format: songFileB!.processingFormat)  

    } catch {  
        fatalError("canot create AVAudioFile \(error)")  
    }  

    let codeB: OSStatus = AudioUnitSetProperty((engine.inputNode?.audioUnit)!,  
                                              kAudioOutputUnitProperty_ChannelMap,  
                                              kAudioUnitScope_Global,  
                                              1,  
                                              channelMapB,  
                                              propSize);  

    print(codeB)  


    do {  
        try engine.start()  
    } catch {  
        fatalError("Could not start engine. error: \(error).")  
    }  

    playerA.scheduleFile(songFileA!, at: nil) {  
        print("done")  
        self.playerA.play()  
    }  
    playerB.scheduleFile(songFileA!, at: nil) {  
        print("done")  
        self.playerB.play()  
    }  

    playerA.play()  
    playerB.play()  

    print(playerA.isPlaying)  

}  

1 个答案:

答案 0 :(得分:0)

  

engine.connect(mixer,to:output,format:outputHWFormat)

这不是必需的,当访问时,混音器将被隐式连接。

至于平移:AudioUnitSetProperty也是不必要的。 AVAudioPlayerNode符合AVAudioMixing,因此播放器下游有一个混音器节点,您只需要这样做:

playerA.pan = -1
playerB.pan = 1