2011-05-07 122 views
3

我注意到pcm.c和speaker-test.c中的正弦發生器在一個循環中生成一個新的正弦緩衝區。所以它不斷重新創建相同的緩衝區。我想播放緩衝區,而不是每次都重新創建,以節省一些CPU時間。但是,當我試圖通過首先構建緩衝區來運行代碼,然後將相同的緩衝區發送到snd_pcm_writei時,我會在每個緩衝區的末尾發出點擊聲。然而,當它每次被重建,然後發送到snd_pcm_writei時,緩衝區末尾不會有點擊。爲什麼每次播放正弦緩衝區前都需要重建正弦緩衝區,以免發出咔噠聲?alsa snd_pcm_writei

任何幫助將不勝感激?

從pcm.c:

while (1) { 
    generate_sine(areas, 0, period_size, &phase); 
    ptr = samples; 
    cptr = period_size; 

回答

4

你假設有相同的正弦波產生的每一次,但因爲有使用phase變量和正弦波並不總是完全適合在緩衝區中,在每次迭代中產生不同的正弦波,稍微偏移一點。

每次都不會產生正弦波會導致正弦波中斷。

我會用鋸齒波而不是正弦波嘗試一些可視化。想象的緩衝區大小爲16和波值範圍從A到H.

// Old way 
    phase = 0  phase = 2  phase = 4 
ABCDEFGHGFEDCBAB|CDEFGHGFEDCBABCD|EFGHGFEDCBABCDEF.... 

// New way 
    phase = 0  phase = 0  phase = 0 
ABCDEFGHGFEDCBAB|ABCDEFGHGFEDCBAB|ABCDEFGHGFEDCBAB.... 

注意,有僅圍繞緩衝器的邊緣,其中的聲音是「畸形」(例如AB|AB代替AB|CD)小片。這就是爲什麼大多數時候它聽起來正確,在兩次之間出現一些令人不安的短暫「點擊」。

對於一些極少數情況,如果緩衝區長度是波長的倍數或phase與以前的迭代值具有相同的值,那麼您可能確實會跳過生成緩衝區,但無法每次都這樣做。

編輯:看generate_sine功能怎麼看phase改變:

static void generate_sine(const snd_pcm_channel_area_t *areas, 
          snd_pcm_uframes_t offset, 
          int count, double *_phase) 
{ 
    static double max_phase = 2. * M_PI; 
    double phase = *_phase; 
    double step = max_phase*freq/(double)rate; 

    [...] 

      phase += step; 
      if (phase >= max_phase) 
        phase -= max_phase; 
    } 
    *_phase = phase; 
} 

EDIT2:此圖片可能是一個更好/更清晰的可視化:

enter image description here

+0

你也許可以使用HTTP ://codegolf.stackexchange.com/questions/951/print-triangle-wave-of-numbers更好的例子:) – ninjalj 2011-05-07 11:29:54

+0

@ninjalj:謝謝,但我現在決定添加一個圖像。更好的是一個交互式小程序,你可以改變緩衝區長度並聽聲音,但我想這是過度的:) – schnaader 2011-05-07 11:47:03

+0

謝謝你們的幫助。我剛剛開始看到緩衝區長度結束時的相位值是關鍵因素。然後基於您的確認,我應該能夠創建一個單獨的緩衝區,通過確保緩衝區的開始和結束時該階段始終爲0,可以連續重播。 – 2011-05-07 12:40:38