2016-04-11 90 views
-1

我試圖讀取.wav文件並找到信號的最主要頻率。 我用this topic來讀取文件,然後我使用函數bytesToFloat將結果轉換爲浮點數。fftw的解讀.wav數據

最後,我複製數組到fftw_complex我運行FFTW的計劃,找到模數(sqrt(real*real + im*im))並找到最高值,但結果不匹配信號的頻率和輸出通常不是一個數字。

我使用的.wav文件是110 Hz(A2)頻率found on Wikipedia

我的問題是:

是否正確地進行了浮點轉換?

爲什麼輸出向量在fft之後返回NaN?

如何讀取.wav文件以便我可以使用fftw?

感謝您閱讀任何幫助表示讚賞。

全碼:

#include <math.h> 
#include <fftw3.h> 
#include "Reader.h" 
#include <iostream> 
#include <string> 
#include <fstream> 
#include <cstdint> 

using namespace std; 

typedef struct WAV_HEADER 
{ 
    /* RIFF Chunk Descriptor */ 
    uint8_t   RIFF[4];  // RIFF Header Magic header 
    uint32_t  ChunkSize;  // RIFF Chunk Size 
    uint8_t   WAVE[4];  // WAVE Header 
            /* "fmt" sub-chunk */ 
    uint8_t   fmt[4];   // FMT header 
    uint32_t  Subchunk1Size; // Size of the fmt chunk 
    uint16_t  AudioFormat; // Audio format 1=PCM,6=mulaw,7=alaw,  257=IBM Mu-Law, 258=IBM A-Law, 259=ADPCM 
    uint16_t  NumOfChan;  // Number of channels 1=Mono 2=Sterio 
    uint32_t  SamplesPerSec; // Sampling Frequency in Hz 
    uint32_t  bytesPerSec; // bytes per second 
    uint16_t  blockAlign;  // 2=16-bit mono, 4=16-bit stereo 
    uint16_t  bitsPerSample; // Number of bits per sample 
            /* "data" sub-chunk */ 
    uint8_t   Subchunk2ID[4]; // "data" string 
    uint32_t  Subchunk2Size; // Sampled data length 
} wav_hdr; 

int getFileSize(FILE* inFile); 
float bytesToFloat(int8_t b0, int8_t b1, int8_t b2, int8_t b3); 
void WavRead(string fileName, int& samples, float* floatBuffer); 

using namespace std; 

int main(void) { 
    fftw_complex *in, *out; 
    fftw_plan p; 

    int numSamples=0; 

    float* floatBuffer; 
    float* dest; 

    floatBuffer = (float*)malloc(sizeof(float)); 

    WavRead("110.wav", numSamples, floatBuffer); 

    in = (fftw_complex*)fftw_malloc(numSamples*sizeof(fftw_complex)); 
    out = (fftw_complex*)fftw_malloc(numSamples*sizeof(fftw_complex)); 

    for (int i = 0; i < numSamples; i++) 
    { 
     in[i][0] = floatBuffer[i]; 
     in[i][1] = (float)0; 
    } 

    p = fftw_plan_dft_1d(numSamples, in, out, FFTW_FORWARD, FFTW_ESTIMATE); 

    fftw_execute(p); 

    dest = (float*)malloc(sizeof(float)*numSamples); 

    for (int i = 0; i < numSamples; i++) { 
     dest[i] = std::sqrt(out[i][0] * out[i][0] + out[i][1] * out[i][1]); 
    } 

    double max = 0; 
    int index=0; 
    for (int i = 0; i < numSamples; i++) { 
     if (dest[i] > max) { 
      max = dest[i]; 
      index = i; 
     } 
    } 

    cout << endl << index << endl << max << endl; 

    fftw_destroy_plan(p); 
    fftw_cleanup(); 

    system("pause"); 

    return 0; 

} 

void WavRead(string fileName, int& samples, float* floatBuffer) 
{ 
    wav_hdr wavHeader; 
    int headerSize = sizeof(wav_hdr), filelength = 0; 

    const char* filePath; 

    filePath = fileName.c_str(); 

    FILE* wavFile = fopen(filePath, "r"); 
    if (wavFile == nullptr) 
    { 
     fprintf(stderr, "Unable to open wave file: %s\n", filePath); 
     system("pause"); 
    } 

    //Read the header 
    size_t bytesRead = fread(&wavHeader, 1, headerSize, wavFile); 
    if (bytesRead > 0) 
    { 
     //Read the data 
     uint16_t bytesPerSample = wavHeader.bitsPerSample/8;  //Number  of bytes per sample 
     uint64_t numSamples = wavHeader.ChunkSize/bytesPerSample; //How many samples are in the wav file? 
     samples = numSamples; 
     static const uint16_t BUFFER_SIZE = numSamples*sizeof(float); 
     int8_t* buffer = new int8_t[BUFFER_SIZE]; 

     floatBuffer = (float*)malloc(sizeof(float)*numSamples); 

     while ((bytesRead = fread(buffer, sizeof buffer[0], BUFFER_SIZE/(sizeof buffer[0]), wavFile)) > 0) 
     { 
     } 

     for (int i = 0; i < numSamples * 4; i += 4) 
     { 
      floatBuffer[i/4] = bytesToFloat(i, i + 1, i + 2, i + 3); 
     } 

     delete[] buffer; 
     buffer = nullptr; 
    } 
    fclose(wavFile); 
} 

// find the file size 
int getFileSize(FILE* inFile) 
{ 
    int fileSize = 0; 
    fseek(inFile, 0, SEEK_END); 

    fileSize = ftell(inFile); 

    fseek(inFile, 0, SEEK_SET); 
    return fileSize; 
} 

float bytesToFloat(int8_t b0, int8_t b1, int8_t b2, int8_t b3) 
{ 
    int8_t byte_array[] = { b3, b2, b1, b0 }; 
    float result; 
    std::copy(reinterpret_cast<const char*>(&byte_array[0]), 
     reinterpret_cast<const char*>(&byte_array[4]), 
     reinterpret_cast<char*>(&result)); 
    return result; 
} 
+1

每個問題一個問題,請。參見[如何提問](http://stackoverflow.com/help/how-to-ask)。 – CodeMouse92

+0

您的FFT和峯值查找代碼看起來不錯(除非您應[在FFT之前添加窗口函數](http://stackoverflow.com/a/7339777/253056))。我不確定WAV閱讀和浮點轉換代碼。嘗試繪製您的時域輸入(floatBuffer)和幅度譜(dest),看看它們是否看起來健全。 –

+0

很確定,如果'AudioFormat'是'0x0003',又名WAVE_FORMAT_IEEE_FLOAT,格式0x0001的描述有點令人困惑,那麼你的文件將只包含浮點數的樣本,它可能也是某種浮點數。我的參考文獻是http://www-mmsp.ece.mcgill.ca/documents/audioformats/wave/wave.html – infixed

回答

0

WAV是一種容器格式(類型RIFF容器)。作爲一個容器,它可以編碼任何種類的編解碼器/格式,這些編解碼器/格式通過錄音機上的編解碼器進行註冊。每個編解碼器都有一個FOURCC。即使你的浮點數轉換對於PCM(脈衝編碼調製 - 意味着採樣被記錄爲(有))格式是正確的,如果編碼的音頻流不是PCM,它將失敗。所以你必須確保在你的代碼中AudioFormat是1(PCM)。有時候這叫做RAW編碼。

如果它不是原始的,mu-law和ADPCM編解碼器不是太複雜,但你更好的是要求RAW格式。如果沒有,您需要將解碼庫集成到您的項目中。要做到這一點主要取決於你在哪個平臺上(Linux,Windows,Mac)。在你的代碼中,我沒有看到任何Windows庫的提示,所以如果你在Linux上,你需要安裝lamelame-dev包(這取決於你使用的是什麼發行版),讀一些關於它的API

解碼取決於實際庫的API,但通常是:

  1. 配置了您從容器頭讀取(如果它是一個立體的一些元數據解碼庫 - 這還挺重要的太對你身邊,採樣頻率,16位或24位或什麼是採樣分辨率等)
  2. 從容器中提取出音頻流 - 這是RAW緩衝區,沒有任何浮動轉換,因爲您不知道其格式數據,它很可能被壓縮
  3. 傳遞它沿編解碼器,讓它做它的工作。

之後,編解碼器庫將爲您提供RAW PCM數據。你可以處理這些數據。

我沒有時間爲此設置測試牀或進行調試。這些是一般方向和你必須照顧的東西。