2009-08-19 147 views
5

我有一個程序可以產生應該同時播放的音頻信號。爲此,我每隔100 ms播放一段100 ms的音頻流。但是,在每個100毫秒音頻流的開始和結束時(由於DC),我有不希望的信號,因此即使信號值相同,輸出聲音也不平滑。我的代碼附在下面。請幫助我應該做些什麼才能獲得正確的實時音頻。如何從實時流播放音頻

using System; 
using System.Windows.Forms; 
using Microsoft.DirectX.DirectSound; 
using System.IO; 

namespace TestSound 
{ 
    class CSound : Form 
    { 
     const int HEADER_SIZE = 44; 
     const bool FLAG_STEREO = true; 
     const short BITS_PER_SAMPLE = 16; 
     const int SAMPLE_RATE = 44100; 

     int numberOfSamples; 
     MemoryStream stream; 
     BinaryWriter writer; 
     Device ApplicationDevice = null; 
     SecondaryBuffer buffer = null; 
     BufferDescription description; 

     public CSound() 
     { 
      try 
      { 
       ApplicationDevice = new Device(); 
      } 
      catch 
      { 
       MessageBox.Show("Unable to create sound device."); 
       ApplicationDevice = null; 
       return; 
      } 
      ApplicationDevice.SetCooperativeLevel(this, CooperativeLevel.Priority); 
      description = new BufferDescription(); 
      description.ControlEffects = false; 
      stream = new MemoryStream(); 
      writer = new BinaryWriter(stream); 
     } 

     private void AddHeader() 
     { 
      stream.Position = 0; 

      writer.Write(0x46464952); // "RIFF" in ASCII 
      writer.Write((int)(HEADER_SIZE + (numberOfSamples * BITS_PER_SAMPLE * (FLAG_STEREO ? 2 : 1)/8)) - 8); 
      writer.Write(0x45564157); // "WAVE" in ASCII 
      writer.Write(0x20746d66); // "fmt " in ASCII 
      writer.Write(16); 
      writer.Write((short)1); 
      writer.Write((short)(FLAG_STEREO ? 2 : 1)); 
      writer.Write(SAMPLE_RATE); 
      writer.Write(SAMPLE_RATE * (FLAG_STEREO ? 2 : 1) * BITS_PER_SAMPLE/8); 
      writer.Write((short)((FLAG_STEREO ? 2 : 1) * BITS_PER_SAMPLE/8)); 
      writer.Write(BITS_PER_SAMPLE); 
      writer.Write(0x61746164); // "data" in ASCII 
      writer.Write((int)(numberOfSamples * BITS_PER_SAMPLE * (FLAG_STEREO ? 2 : 1)/8)); 
     } 

     public void Play(short[] samples) 
     { 
      if (ApplicationDevice == null) 
       return; 

      stream.Position = HEADER_SIZE; 
      numberOfSamples = samples.Length; 
      for (int i = 0; i < numberOfSamples; i++) 
      { 
       writer.Write(samples[i]); 
       if (FLAG_STEREO) 
        writer.Write(samples[i]); 
      } 
      AddHeader(); 
      stream.Position = 0; 

      try 
      { 
       if (buffer != null) 
       { 
        buffer.Dispose(); 
        buffer = null; 
       } 
       buffer = new SecondaryBuffer(stream, description, ApplicationDevice); 
       buffer.Play(0, BufferPlayFlags.Default); 
      } 
      catch (Exception e) 
      { 
       MessageBox.Show(e.Message); 
      } 
     } 

     static short[] samples = new short[4410]; // 100 ms 
     static CSound sound; 

     static void Main() 
     { 
      Form form = new Form(); 
      form.Show(); 

      sound = new CSound(); 
      Random random = new Random(); 
      for (int i = 0; i < samples.Length; i++) 
       samples[i] = 1000; // constant value 

      while (true) 
      { 
       sound.Play(samples); 
       System.Threading.Thread.Sleep(100); // 100 ms 
      } 
     } 
    } 
} 

回答

1

此代碼有許多錯誤。我猜測,當你運行這個代碼時,你會聽到每100毫秒點擊或彈出一個聲音。這是因爲while(true)循環內的Thread.Sleep(100)調用。基本上,您的應用程序正在等待100毫秒(給予或佔用一小部分時間),然後調用Play(),稍後處理,然後將數組排隊等待播放。因此,每播放100毫秒的數組之間有一點時間差距,這會產生點擊。但是,如果您剛剛註釋掉了Thread.Sleep(100)行,則您的應用程序將進入無限循環,並在100 ms陣列後排隊等待100 ms數組,直到內存用完。但至少播放不會每100毫秒產生一次僞影。

如果將該行更改爲Thread.Sleep(80),它會工作得更好一點,因爲它會花費更長的時間來耗盡內存,但這仍然會發生,因爲您仍然會傾銷緩衝到音頻播放系統的速度比系統可以播放的速度快。另外,即使您每隔100 ms擺脫一次咔嗒聲,您仍然聽不到任何聲音從您的揚聲器中傳出,因爲您的代碼將每個樣本值設置爲1000.您將只聽到任何聲音如果您隨時間改變樣本值。順便說一下,您聽到單擊的唯一原因是因爲此示例值設置爲1000,並且在塊之間的這些小的時間間隔期間,回放值回到0.如果將每個樣本值設置爲0,聽到任何事情。

我可以幫助你進一步瞭解這一點,但我需要更好地瞭解你正在嘗試做什麼,確切地說。你是否試圖以某種頻率播放連續音?

4

如果您尋找一種方式,通過定義的流播放音頻輸出,你有沒有考慮n音訊http://naudio.codeplex.com/

您可以定義一個流,從文件或其他一些位置(即內存),然後填入你想要播放的數據流。只要您能夠在讀指針到達緩衝區末尾之前繼續向流提供音頻數據,您就不會在生成的音頻中聽到這些文物。

順便說一句 - 我想你知道,不再被開發爲.NET託管的Direct X庫和有效的是這種音頻發展的死衚衕?

0

如果「不良信號」你的意思是在兩端有輕微的爆裂聲,它可能是一個信封的問題,這在CSound的可以由「麻」操作碼或類似的東西來控制。這個想法是,你需要在前端加大幅度,在後端稍微加大一點,以避免揚聲器的咔噠聲突然停止在中波輸出,可以這麼說。幾ms就足夠了 - 試驗它,直到你擺脫了爆裂而不知道幅度調製。

看吧:http://www.csounds.com/journal/issue11/csoundEnvelopes.html

如果您正在試圖通過闡明相同的波形依次定期產生的無縫信號,那你會一直聽到這樣的爆裂聲,因爲一個波形的結尾不排隊隨着下一個波形的開始。讓波形準確排列非常困難,這並不是一個好策略。一個更好的策略是使用一個包絡(如上所述)並重疊波形(稱爲鴿尾),以便舊的關節的衰變與新關節的興起同時發生。

但是,這種策略不會產生完全純粹的聲音,因爲兩個有點相同的波形異步重疊的存在將相互抵消一點,並導致在波形的每個交界處振幅減小。