fftw 16-битного звука :: пик отображается неправильно на 2f

Я использую 32-битный звук с плавающей запятой (44,1 кГц) на своем ПК (от -1 до +1), используя Port Audio, и снимаю его с помощью fftw.

Теперь мне нужно взять 16-битный int Audio и проверить его fft. Я преобразовал образцы аудио в значения с плавающей запятой между -1 и +1. FFT работает, но пик возникает на частоте, в 2 раза превышающей ту, на которой он должен быть, и поэтому максимальное разрешение по частоте также уменьшается. Таким образом, при 44 кГц максимальный компонент, который я вижу, составляет около 10 кГц, тогда как с 32-битным int / float он составлял около 20 кГц.

Например, если я передаю сигнал 10 кГц от генератора знаков на звуковую карту, пик теперь отображается на частоте 20 кГц. А поменял только формат с paInt32 на paInt16. Он корректно работает в формате paInt32.

  outputStreamParam.channelCount = 1;
  outputStreamParam.device = Pa_GetDefaultOutputDevice();
  outputStreamParam.sampleFormat = paInt16;
  outputStreamParam.suggestedLatency = suggestedLatency;
  outputStreamParam.hostApiSpecificStreamInfo = NULL;

  inputStreamParam.channelCount = 1;
  inputStreamParam.device = Pa_GetDefaultInputDevice();
  inputStreamParam.sampleFormat = paInt16;
  inputStreamParam.suggestedLatency = suggestedLatency;
  inputStreamParam.hostApiSpecificStreamInfo = NULL; 

Преобразование int (16 или 32) в число с плавающей запятой между -1 и +1.

int audioProcessor::processingCallback(const void *inputBuffer,
                                        void *outputBuffer,
                                        unsigned long framesPerBuffer,
                                        const PaStreamCallbackTimeInfo* timeInfo,
                                       PaStreamCallbackFlags statusFlags)
{   unsigned int i;
     framesPerBuffer = framesPerBuffer/2;

      int *inint = (int*) inputBuffer;

    float *out = (float*) outputBuffer;
    float *in = (float*) inputBuffer;


     for( i=0; i<framesPerBuffer; i++ )
     {


        in[i] = inint[i]/2147483647.0f;


     }

Код процессора FFTW.

 this->fftSize = fftSize;
    cout << "Plan start " <<  endl;

  outArraySize = fftSize/2+1;
  cout << "fft Processor start \n";
  fftIn = (double*) fftw_malloc(sizeof(double) * fftSize);
  fftOut = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * outArraySize );
  fftOutAbs = (double*) fftw_malloc(sizeof(double) * outArraySize );

  // fftwPlan = fftw_plan_dft_r2c_1d(fftSize, fftIn, fftOut, FFTW_ESTIMATE);
  cout << "Plan succeed " <<  endl;

    fftwPlan = fftw_plan_dft_r2c_1d(fftSize, fftIn, fftOut, FFTW_MEASURE);
}

person jav321    schedule 08.06.2015    source источник
comment
вы используете одно и то же преобразование int- ›float как для 16-, так и для 32-битных кодов?   -  person jaket    schedule 08.06.2015


Ответы (1)


Вам нужно реализовать два разных метода конвертации. Один для int32, чтобы плавать, а другой для int16, чтобы плавать. В текущей реализации он использует преобразование int32 в случае int16. Одна из проблем заключается в том, что коэффициент масштабирования для преобразования в число с плавающей запятой неверен. Другая проблема заключается в том, что он проходит через входной сигнал в два раза быстрее, чем предполагалось, что приводит к отключению всех частот в 2 раза.

Для конвертации из int16 нужно сделать что-то вроде этого:

{   
   unsigned int i;
   framesPerBuffer = framesPerBuffer/2;

   short *in = (short*) inputBuffer;
   float *out = (float*) outputBuffer;

   for (i=0; i<framesPerBuffer; i++)
   {
      out[i] = in[i]/32767.0f;
   }

Другая проблема с опубликованным кодом заключается в том, что он записывает образцы с плавающей запятой обратно в неправильный буфер. Возможно, вы не заметили этого с int32 с sizeof(int)==sizeof(float).

Кроме того, framesPerFrameBuffer = framesPerFrameBuffer/2 вызывает подозрение. Не понимаю, зачем вам это нужно.

person jaket    schedule 08.06.2015
comment
Спасибо, я знал, что что-то не так с конвертацией. На самом деле преобразование из int16 в float также прошло нормально с моим кодом, возможно, компилятор сначала преобразовал образцы в 32-битное int, когда я объявил указатель. Однако, вероятно, причина, по которой я получал неправильную частоту, заключалась в том, что поскольку мой указатель увеличивался на 4 байта, я всегда терял одну выборку, а входной сигнал обрабатывался в 2 раза быстрее. Итак, теперь, когда я использовал ваш код, мои образцы не теряются, а частоты отображаются правильно, - person jav321; 10.06.2015
comment
А что касается [Code] framesperBuffer [/ Code] Это то, чего я не понимаю, потому что, когда я использую framesperBuffer для int32, он работает хорошо. Для int16 программа начинает выдавать ошибки памяти. Для int16 framesperBuffer / 2 работает нормально. Аналогично для int 8 framesperBuffer / 4 работает нормально? - person jav321; 10.06.2015
comment
Обычно термин «кадр» используется для обозначения единичной выборки, умноженной на количество каналов, так что если у вас есть два канала данных, то кадр будет составлять две выборки. Я предполагаю, что деление на 2 было необходимо, потому что вы проходили через данные в 2 раза. - person jaket; 10.06.2015