2016-07-26 70 views
1

渠道如何訪問使用AVFoundation比1-2其他額外的音頻硬件輸出?我在寫SWIFT代碼爲它通過各種輸出設備播放MP3文件的Mac OS-X的應用程序(USB接口,但丁,soundflower),它看起來像下面這樣:訪問多個音頻硬件輸出/使用AVFoundation和斯威夫特

myPlayer = AVPlayer(URL: myFilePathURL) 
myPlayer.audioOutputDeviceUniqueID = myAudioOutputDevices[1].deviceUID() 
myPlayer.play() 

但是,我不知道怎麼樣將音頻文件播放到除1-2以外的頻道。例如,我想播放一個MP3輸出3-4。

我能做到這一點通過AVPlayer?或者我需要去其他地方看看?也許AVAudioEngine與調音臺節點一起?我查看了AVAudioEngine示例,並且找不到任何地方引用的硬件通道。謝謝你的幫助!

+0

這是我的理解是AVAudioEngine僅在iOS框架 - 這樣就不會工作。 iOS和OS-X框架的蘋果文檔非常相互交織 - 很遺憾,沒有對每個平臺單獨提供什麼解釋。 –

+0

我在嘗試使用AVAudioEngine和AVAudioPlayerNode以及mainMixerNode的另一個路徑。我還沒有弄清楚我是否可以將mainMixerNode分配給除默認值以外的其他硬件通道。也許這比使用AVPlayer更好? –

+0

入門頻道地圖工作作爲描述這裏](https://developer.apple.com/library/prerelease/content/technotes/tn2091/_index.html#//apple_ref/doc/uid/DTS10003118-CH1-CHANNELMAPPING)還沒有工作,但希望很快。 –

回答

1

我有正在與2個通道設置頻道地圖屬性迅速版本。我沒有使用完整的多通道系統進行測試,但原理應該是相同的。

let engine = AVAudioEngine() 
let player = AVAudioPlayerNode() 

func testCode(){ 

    // get output hardware format 
    let output = engine.outputNode 
    let outputHWFormat = output.outputFormatForBus(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.attachNode(player) 


    //find the audiofile 
    guard let audioFileURL = NSBundle.mainBundle().URLForResource("tones", withExtension: "wav") else { 
     fatalError("audio file is not in bundle.") 
    } 


    var songFile:AVAudioFile? 
    do { 
     songFile = try AVAudioFile(forReading: audioFileURL) 
     print(songFile!.processingFormat) 

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

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



    let channelMap: [Int32] = [0, 1] //left out left, right out right 
    //let channelMap: [Int32] = [1, 0] //right out left, left out right 


    let propSize: UInt32 = UInt32(channelMap.count) * UInt32(sizeof(sint32)) 

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

    print(code) 


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

    player.scheduleFile(songFile!, atTime: nil) { 
     print("done") 
     self.player.play() 
    } 

    player.play() 



} 
+0

你知道如何用輸入做到這一點嗎?我有一個8ch接口,但只希望我的調音臺節點能夠監聽接口上的特定通道。 – JoeBayLD

+0

我試過這個例子,它仍然播放左右聲道的文件... – tsugua

+0

我還沒有做到這一點與輸入端。但我用它與輸出端發送飼料到16個立體聲輸出(硬件或通過聲音花/虛擬dante)。 –

0

我已經迭代了這段代碼 - 但基本大綱將起作用。這是我目前的設置代碼,用於將音頻發送到多通道設置。我目前正在做這與但丁虛擬聲卡使用下面的代碼16立體聲實例化流:

func setupAudioPath(){ 
    //print("setupAudioPath") 

    // get output hardware format 
    let output = engine.outputNode 
    outputHWFormat = output.outputFormat(forBus: 0) 

    //print("outputHWFormat = \(outputHWFormat)") 
    //print("outputHWFormat.channelCount = \(outputHWFormat.channelCount)") 

    // connect mixer to output 
    mixer = engine.mainMixerNode 

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

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

    var channelMap: [sint32] = [] 
    //UInt32 numOfChannels = fileFormat.NumberChannels(); 
    let numOfChannels: UInt32 = UInt32(numberOfStreams) * UInt32(2); // Number of output device channels 
    let mapSize: UInt32 = numOfChannels * UInt32(MemoryLayout<sint32>.size); 
    for _ in 0...(numOfChannels-1) { 
     channelMap.append(-1) 
    } 
    //channelMap[desiredInputChannel] = deviceOutputChannel; 
    channelMap[leftChannel - 1] = 0; 
    channelMap[leftChannel]  = 1; 


    //print(channelMap) 
    //print("number of channels in my map: \(channelMap.count)") 

    let code: OSStatus = AudioUnitSetProperty((engine.outputNode.audioUnit)!, 
               kAudioOutputUnitProperty_ChannelMap, 
               kAudioUnitScope_Global, 
               1, 
               channelMap, 
               mapSize); 


    print("osstatus = \(code)") 
}