2016-04-26 66 views
0

我寫了這個小信號生成方法。我的目標是在兩個通道(左和右)之間稍微有一段時間延遲或兩個通道之間的增益稍有差異時發出蜂鳴聲。 目前,我通過爲一個通道填充一個緩衝區來創建延遲,併爲第二個通道填充一個緩衝區值,並進一步減少通道之間的行爲(如果您有任何提示或想法如何更好地執行此操作,將不勝感激。) The下一階段正在做一些類似於增益的事情。我已經看到Java通過FloatControl給內置增益控制:單獨使用Java控制聲音通道的增益

FloatControl gainControl = 
      (FloatControl) sdl.getControl(FloatControl.Type.MASTER_GAIN); 

但我不確定如何分別控制每個通道的增益。有沒有內置的方法來做到這一點? 我需要兩個獨立的流,每個通道一個流?如果是這樣,我該如何同時播放它們? 我對聲音編程頗爲陌生,如果有更好的方法來做到這一點,請讓我知道。很感謝任何形式的幫助。

這是我到目前爲止的代碼:

public static void generateTone(int delayR, int delayL, double gainRightDB, double gainLeftDB) 
     throws LineUnavailableException, IOException { 

    // in hz, number of samples in one second 
    int sampleRate = 100000; // let sample rate and frequency be the same 

    // how much to add to each side: 
    double gainLeft = 100;//Math.pow(10.0, gainLeftDB/20.0); 
    double gainRight = 100;// Math.pow(10.0, gainRightDB/20.0);; 

    // click duration = 40 us 
    double duration = 0.08; 
    double durationInSamples = Math.ceil(duration * sampleRate); 

    // single delay window duration = 225 us 
    double baseDelay = 0.000225; 
    double samplesPerDelay = Math.ceil(baseDelay * sampleRate); 

    AudioFormat af; 

    byte buf[] = new byte[sampleRate * 4];     // one second of audio in total 
    af = new AudioFormat(sampleRate, 16, 2, true, true); // 44100 Hz, 16 bit, 2 channels 


    SourceDataLine sdl = AudioSystem.getSourceDataLine(af); 

    sdl.open(af); 

    sdl.start(); 

    // only one should be delayed at a time 
    int delayRight = delayR; 
    int delayLeft = delayL; 

    int freq = 1000; 

    /* 
    * NOTE: 
    * The buffer holds data in groups of 4. Every 4 bytes represent a single sample. The first 2 bytes 
    * are for the left side, the other two are for the right. We take 2 each time because of a 16 bit rate. 
    * 
    * 
    */ 
    for(int i = 0; i < sampleRate * 4; i++){ 
     double time = ((double)i/((double)sampleRate)); 

     // Left side: 
     if (i >= delayLeft * samplesPerDelay * 4    // when the left side plays 
       && i % 4 < 2         // access first two bytes in sample 
       && i <= (delayLeft * 4 * samplesPerDelay) 
       + (4 * durationInSamples))      // make sure to stop after your delay window 

      buf[i] = (byte) ((1+gainLeft) * Math.sin(2*Math.PI*(freq)*time));     // sound in left ear 
     //Right side: 
     else if (i >= delayRight * samplesPerDelay * 4   // time for right side 
       && i % 4 >= 2         // use second 2 bytes 
       && i <= (delayRight * 4 * samplesPerDelay) 
       + (4 * durationInSamples))      // stop after your delay window 


      buf[i] = (byte) ((1+gainRight) * Math.sin(2*Math.PI*(freq)*time));     // sound in right ear 

    } 

    for (byte b : buf) 
     System.out.print(b + " "); 
    System.out.println(); 

    sdl.write(buf,0,buf.length); 
    sdl.drain(); 
    sdl.stop(); 


    sdl.close(); 
} 
+0

*「..不知道如何分別控制每個通道的增益。」* ['FloatControl.Type.BALANCE'](http://docs.oracle.com/javase/8/docs/api/javax /sound/sampled/FloatControl.Type.html#BALANCE).. –

+0

爲了儘快提供更好的幫助,請發佈[MCVE]或[簡短,獨立包含,正確示例](http://www.sscce.org/)。 –

回答

1

相隔多遠你希望你的蜂鳴聲?我編寫了一個程序,使聲音的正弦鳴音高達幾百幀(以44100 fps),並且發佈了源代碼here,歡迎您檢查/複製/重寫。

在如此低的分離水平下,聲音保持融合,感知,但可以開始移動到一邊或另一邊。我寫這個是因爲我想比較音量平移和基於延遲的平移。爲了能夠靈活地測試多個文件,代碼比您開始的模塊略微更加模塊化。雖然我不會聲稱我寫的更好。

一個類需要一個單聲道PCM(範圍是浮點數,-1到1)數組,並將其轉換爲立體聲數組,並在聲道之間具有所需的幀延遲。同一班級還可以將單聲道文件分割爲立體聲文件,其中唯一的區別是音量,另外還有第三個選項,您可以在將單聲道數據轉換爲立體聲時使用延遲和音量差異的組合。

單文件:F1,F2,F3,... Stereofile F1L,F1R,F2L,F2R,F3L,F3R,...

但如果增加延遲,說2幀到右:

Stereofile F1L,0,F2L,0,F3L,F1R,F4L,F2R,...

其中F是歸一浮子表示音頻波(-1和1之間)。

製作第一個蜂鳴聲的單聲道陣列就像使用正弦函數一樣。您可以通過在某些幀的過程中逐漸增大音量來「減少邊緣」,以最大限度地減少突然啓動或停止不連續點發出的咔嗒聲。

編寫了另一個類,其唯一目的是通過SourceDataLine輸出立體浮點數組。通過將音頻輸出乘以範圍從0到1的因子來處理音量。標準化值乘以32767將其轉換爲帶符號的短褲,並將短褲拆分爲我使用的格式的字節(16位,44100 fps,立體聲,小端)。

有一個陣列播放音頻類是一種整潔。它的數組很像剪輯,但你可以直接訪問數據。通過這個課程,您可以構建和重複使用許多聲音陣列。我想我也有一些代碼將一個wav文件加載到這個DIY剪輯中。

this thread at Java-Gaming.org上有關於此代碼的更多討論。

我最終使用了一些我在這裏學到的東西來製作一個簡化的實時3D音響系統。然而,建立這樣的事情的「最佳」方式取決於你的目標。例如,對於我的3D,我編寫了一個延遲工具,允許從左右立體聲單獨讀取,並且音頻混合器的播放比簡單的數組到SourceDataLine播放器更爲複雜。

+0

非常感謝您的輸入,您的程序看起來可能非常有用。我會仔細研究一下。 本來聲音之間的距離應該是非常小的,大約40-100微秒。然而,在這一點上,我願意儘可能降低平均聲卡讓我的體驗。 作爲一個小的跟進問題,經過多次搜索後,我發現FloatControl也支持PAN和BALANCE操作。這些和你在這裏做的有什麼不同嗎? – TheFooBarWay

+0

我認爲聲卡的極限可以被認爲是它支持的最高幀速率。標準聲卡可以支持44100 fps,這意味着1幀大約是22.5微秒?使用線性插值可能會變得更小,例如,幀1 R獲得90%的幀1 L和10%的幀2 L.我還沒有發現PAN和BALANCE控件始終如一地可靠或與個人一起工作幀。當他們工作時,他們通常被綁定在一個完整的數據緩衝區上,而不是單個幀級別,因此粒度不是很大。 –

相關問題