2016-04-11 55 views
-1

私は.wavファイルを読み込み、信号の最も優勢な周波数を探しています。 this topicを使用してファイルを読み込んだ後、関数bytesToFloatを使用して結果をfloatに変換しました。fftwの.wavデータの解釈

最後に、配列をfftw_complexにコピーした後、FFTWの計画を実行し、モジュラス(sqrt(real*real + im*im))を見つけて最高値を見つけますが、結果は信号の周波数と一致せず、出力は通常数値ではありません。

私が使用している.wavファイルは、110Hz(A2)の周波数found on Wikipediaです。

私の質問は次のとおりです。

浮動変換が正しく行われていますか?

fftの後に出力ベクトルがNaNを返すのはなぜですか?

fftwを使用できるように.wavファイルを読むにはどうすればよいですか?

お手数をおかけしていただきありがとうございます。

フルコード:

#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

1つにつき1つの質問をしてください。 [How To Ask](http://stackoverflow.com/help/how-to-ask)を参照してください。 – CodeMouse92

+0

あなたのFFTとピーク検出コードはOKです(ただし、[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(Pulse Code Modulated - サンプルがそのままの形で記録されます)フォーマットのフロート変換が正しくても、エンコードされたオーディオストリームがPCMではないと失敗します。したがって、あなたのコードでAudioFormatが1(PCM)であることを確認する必要があります。 RAWエンコーディングと呼ばれることもあります。

mu-lawとADPCMのコーデックはあまり複雑ではありませんが、RAWの形式を必要とする方が良いでしょう。そうでなければ、デコードライブラリをプロジェクトに統合する必要があります。それを行う方法は、あなたがどのプラットフォーム(Linux、Windows、Mac)にいるかによって大きく異なります。あなたのコードでは、Windowsライブラリのヒントは表示されないので、もしあなたがLinux上にある場合は、のいくつかを読んで、lamelame-devのパッケージをインストールする必要があります。

復号化は、実際のライブラリのAPIに依存するが、通常は:

  1. が、それはステレオだ場合は(コンテナヘッダから読み取るいくつかのメタデータをデコードライブラリを設定する - それはあなたの側のためにあまりにもちょっと重要です、サンプリング周波数、16または24ビット、またはサンプリング解像度など)
  2. は、オーディオストリームをコンテナから抽出します。これは、RAWバッファであり、浮動変換はありません。データはかなり圧縮されている可能性があります。
  3. コーデックに沿って渡して、それを仕事にしましょう。

その後、コーデックライブラリからRAW PCMデータが返されます。そして、あなたはそのデータを処理することができます。

私はこれのためのテストベッドをセットアップするか、それをデバッグする時間がありませんでした。これらは一般的な指示であり、あなたが世話をしなければならないものです。