2016-04-11 4 views
-1

Я пытаюсь прочитать WAV-файл и найти наиболее доминирующую частоту сигнала. Я использовал this topic, чтобы прочитать файл, затем я использовал функцию bytesToFloat для преобразования результата в float.Интерпретация данных .wav для fftw

Наконец, после копирования массивов в fftw_complex, я запускаю план FFTW, нахожу модуль (sqrt(real*real + im*im)) и находим наивысшее значение, но результаты не соответствуют частоте сигнала, а выход обычно не является числом.

. WAV-файл, который я использую, - это частота 110 Гц (A2) found on Wikipedia.

Мои вопросы:

ли сделано преобразование поплавок правильно?

Почему выходной вектор возвращает NaN после fft?

Как я могу прочитать 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

Один вопрос на вопрос, пожалуйста. См. [How To Ask] (http://stackoverflow.com/help/how-to-ask). – CodeMouse92

+0

Ваш код поиска FFT и пика выглядит нормально (за исключением того, что вы должны [добавить функцию окна до БПФ] (http://stackoverflow.com/a/7339777/253056)). Однако я не уверен в отношении кода чтения WAV и конверсии с плавающей точкой. Попробуйте построить свой вход во временной области (floatBuffer) и спектр амплитуд (dest), чтобы убедиться, что они выглядят разумно. –

+0

Довольно точно, что ваш файл будет содержать только образцы в плавающей запятой, если 'AudioFormat'' 0x0003', aka WAVE_FORMAT_IEEE_FLOAT, описание формата 0x0001 несколько запутанно, это может быть какой-то поплавок. Мой реф: http://www-mmsp.ece.mcgill.ca/documents/audioformats/wave/wave.html – infixed

ответ

0

WAV является формат контейнера (тип RIFF контейнера). В качестве контейнера он может кодировать любой вид кодека/формата, который был зарегистрирован кодеком на записывающей машине. Каждый кодек имеет FOURCC. Даже если ваше преобразование с плавающей точкой было бы правильным для PCM (Импульсный код, модулированный - это означает, что сэмплы записаны как они являются (kinda)), он не сработает, если кодированный аудиопоток не PCM. Поэтому вы должны убедиться в том, что код AudioFormat равен 1 (PCM). Иногда это называется RAW-кодировкой.

Если это не грубое, mu-law и ADPCM кодеки не слишком сложны, но вам лучше, чем требуется RAW формат. Если нет, вам нужно интегрировать библиотеку декодирования в ваш проект. Способ сделать это во многом зависит от того, на какой платформе вы находитесь (Linux, Windows, Mac). В вашем коде я не вижу никаких намеков на библиотеки Windows, поэтому, если вы работаете в Linux, вам нужно установить пакеты lame и lame-dev (это зависит от того, какой дистрибутив вы используете) читайте около API.

Декодирование зависит от API фактической библиотеки, но, как правило:

  1. настроить до библиотеки декодирования с некоторыми мета-данных, считанного из контейнера заголовков (если это стерео - это своего рода тоже важно для вашей стороне , частота дискретизации, 16 или 24 бит или каково разрешение выборки и т. д.)
  2. извлечение аудиопотока из контейнера - это буфер RAW без плавающего преобразования, так как вы не знаете формат данных, это, скорее всего, сжато
  3. Пропустите его по кодеку и дайте ему сделать это.

После этого библиотека кодеков предоставит вам данные RAW PCM. И вы можете отработать эти данные.

У меня не было времени на установку тестовой кровати для этого или отладки. Это общие указания и все, что вам нужно позаботиться.