2016-05-24 67 views
2

我正在用C++做一個音樂可視化程序。它給出了音頻輸入的頻譜。我使用Aquila-dsp獲取音頻樣本,Kiss-fft用於執行FFT,SMFL用於播放音頻。輸入格式爲(.wav)格式。 OpenGL用於繪製圖形。如何將音頻與功率譜同步並選擇幀長度N(做fft)?

算法應用於:

1. *framePointer = 0, N = 10000;* 
2. Load audio file and play it using SFML. 
3. For *i* = framePointer to --> *framePointer* + *N* < *total_samples_count* 

Collect audio samples. 

4. Apply Window Function (Hann window) 
5. Apply *FFT* 
6. Calculate magnitude of first N/2 *FFT* data 

*Magnitude* = sqrt(re * re + im * im) 

7. Convert to dB(log) scale (optional) 

    10*log(magnitude) 

8. Plot N/2, log(magnitude) values 
9. If *framaPointer* >= *toatl_samples_count - N* 

Exit 

Else go to step 3. 

#define N 10000 
int framePointer = 0; 

void getData() 
{ 

int i,j,x; 
Aquila::WaveFile wav(fileName); 
double mag[N/2]; 

double roof = wav.getSamplesCount(); 

//Get first N samples 
for(i = framePointer, j = 0; i < (framePointer + N) 
            && framePointer < roof - N ; i++,j++ ){ 

    //Apply window function on the sample 
    double multiplier = 0.5 * (1 - cos(2*M_PI*j/(N-1))); 
    in[j].r = multiplier * wav.sample(i); 
    in[j].i = 0; //stores N samples 
} 


if(framePointer < roof-N -1){ 
    framePointer = i; 

} 
else { 
    printf("Frame pointer > roof - N \n"); 
    printf("Framepointer = %d\n",framePointer); 

    //get total time and exit 
    timestamp_t t1 = get_timestamp(); 
    double secs = (t1 - tmain)/1000000.0L; 
    std::cout<<"Program exit.\nTotal time: "<<secs<<std::endl; 
    exit(0); 
} 

// Apply FFT 
getFft(in,out); 

// calculate magnitude of first N/2 FFT 
for(i = 0; i < N/2; i++){ 
    mag[i] = sqrt((out[i].r * out[i].r) + (out[i].i * out[i].i)); 
    graph[i] = log(mag[i]) *10; 
} 
} 

我繪製使用OpenGL圖形。 Full source code

我得到的問題是在選擇幀長度(N值)。

對於具有音頻的一定長度:

Length: 237191 ms 
Sample frequency: 44100 Hz 
Channels: 2 
Byte rate: 172 kB/s 
Bits per sample: 16b 

該圖與音頻如果我選擇N = 10000或同步的至少它而音頻兩端停止。

如何選擇N(幀長),使音頻與頻譜同步。 音頻是雙通道的,這個算法能工作嗎?

+0

剛剛從臀部拍攝,但爲什麼不使用滾動窗口,因此轉換窗口以與音頻採樣流相同的速率向前移動?優化可以是在移動窗口之前重新使用「重疊」的計算,即上次進行的高速緩存計算。 –

+0

IMO在這種同步中使用'glutIdleFunc()'並不容易。 'glutTimerFunc()'也許是更好的選擇。另一種可能性是,如果您的代碼使用回調來生成譜圖,則在每個回調的呈現週期結束時調用'glutPostRedisplay()'以開始。 – user3078414

+0

@ user3078414我不擅長OpenGL。我用'https:// en.wikibooks.org/wiki/OpenGL_Programming/Scientific_OpenGL_Tutorial_02'中的這個圖來繪製頻譜圖。 – Indra

回答

1

首先決定您希望更新可視化工具的頻率。假設我們希望它每秒更新25次(類似於電視或電影幀速率)。這意味着每1/25秒或每40毫秒。在44.1 kHz的採樣率下,這轉換爲44100/25 = 1764個採樣。由於我們通常需要2 FFT大小的功率,因此我們假設N = 2048.

這給出了頻率軸44100/2048 = 21.5 Hz的分辨率。如果你想要更高的分辨率,那麼你可以重疊連續的FFT窗口,例如保持相同的更新率並重疊50%,那麼對於10.75 Hz的分辨率,您可以擁有N = 4096。

+0

當'N 2048'時,音樂在'Framepointer = 2942976'處結束,總數爲10460160個樣本。 – Indra

+0

@Indrajith:聽起來你的代碼實際上並沒有將可視化器與音頻播放同步 - 您需要添加一些計時代碼以確保您正在處理的幀與正在播放的幀相對應。 –

+0

@Paule我認爲是因爲算法複雜度,如果我們把N作爲'2048'。它可以處理的最多是'2942976'幀。我們如何增加處理時間。我們可以減少音頻處理時間而不影響正在播放的音樂嗎? – Indra