2016-04-11 92 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数据。你可以处理这些数据。

我没有时间为此设置测试床或进行调试。这些是一般方向和你必须照顾的东西。