2013-11-14 94 views
1

我試圖發揮使用的portaudio C庫中的portaudiosharp綁定C#波形文件時遇到了問題設想用正確的方法去這樣做。我將粘貼我目前使用的代碼。它有點作用,但我認爲這不是正確的做事方式。使用回調來播放帶有端口音頻的音頻文件?

這是我的回調函數:

public PortAudio.PaStreamCallbackResult myPaStreamCallback(
      IntPtr input, 
      IntPtr output, 
      uint frameCount, 
      ref PortAudio.PaStreamCallbackTimeInfo timeInfo, 
      PortAudio.PaStreamCallbackFlags statusFlags, 
      IntPtr userData) 
      { 
       short[] mybuffer = (short[])myQ.Dequeue(); 
       Marshal.Copy(mybuffer, 0, output, (int)frameCount * 2); 
       return PortAudio.PaStreamCallbackResult.paContinue; 
      } 

然後,我有一個「主循環」:

PortAudio.Pa_Initialize(); 

    IntPtr stream; 
    IntPtr userdata = IntPtr.Zero; 
    PortAudio.Pa_OpenDefaultStream(out stream, 1, 2, 8, 
      48000, NUM_SAMPLES/2, new PortAudio.PaStreamCallbackDelegate(myPaStreamCallback), userdata); 

    PortAudio.Pa_StartStream(stream); 

    while (readerPosition < reader.Length) 
    { 
      short[] qBuffer = new short[NUM_SAMPLES]; 
      read = reader.Read(buffer, 0, NUM_SAMPLES * 2); //read a block out from my wave file 
      Buffer.BlockCopy(buffer, 0, qBuffer, 0, read); //copy them to the short buffer 
      myQ.Enqueue(qBuffer); 
      readerPosition += read; 
    } 

    while(PortAudio.Pa_IsStreamActive(stream) == 0) 
    { 
      //this while loop never gets entered -- why?? 
      Console.WriteLine("waiting"); 
    } 

    System.Threading.Thread.Sleep(5000); //need this so that the callback function fires 
    PortAudio.Pa_StopStream(stream); 

我試圖實現一個FIFO緩衝區,但我想我可能已經做到了以一種愚蠢的方式,基本上發生了什麼是隊列被填滿,直到沒有更多的樣本留在那裏,只有PA回調開始發射。

什麼是這樣做的更好的辦法?如何讓我的主循環良率,使回調函數可以啓動,而不必睡覺?

我正在使用NAudio wavreader從波形文件中讀取數據,但我不認爲這很重要。如果是,我可以發佈更多細節。

回答

1

一些明顯的事情:

  • 你應該調用StartStream之前填寫您的環形緩衝區()
  • 您希望您的主迴路通過將數據寫入到它保持緩衝區滿時,它不完全。您可以通過投票和睡眠來做到這一點。如果隊列足夠大,你可以一次睡一秒,開銷不會那麼大。
  • 「正確」的方法是使用一個Event對象,並在每次隊列變爲「未滿」時從回調中發出信號。 main()循環用WFSO阻塞該事件,並在其可以將數據寫入隊列時喚醒。 (提示:使用自動重置事件)。
  • 如果你想要做的就是發揮你可以使用PA的WriteStream()API,它確實這一切在內部一個音效檔。

其他說明:

  • 這是不平凡的寫一個正確的原子FIFO隊列。你沒有顯示你的代碼。
  • 您的回調不處理在隊列爲空的情況。在這種情況下,它可能會輸出沉默。
  • 你可能不希望newing了每個塊一個新的緩衝區。考慮通過第二個隊列將使用的塊返回給主線程並重用它們。
  • 您可能想要限制隊列的大小(3-5秒鐘的音頻對大多數場景來說已經足夠了) - 這就是我上面「不完整」的意思。另一種考慮這種情況的方法是使用高水印:PA回調在非空時釋放緩衝區,main()填充緩衝區,但不滿(例如5秒持續時間)水印。每當緩衝區低於水印時,回調喚醒主。