@mmisin1
Студент

Как обработать и отфильтровать звуковой сигнал?

Здравствуйте. Очень нужен ваш совет. В университете задали написать программу фильтрации звука. (удаления шума и лишних гармоник). За основу взял, перевёл и немного изменил готовый пример из bass.dll.

Далее мой план таков:
  1. Считываю сигналы порциями определенной длины
  2. Для каждой "порции" провожу быстрое преобразование Фурье.
  3. В результате получаю массив частот. Из него удаляю лишнее.
  4. Выполняю обратное преобразование Фурье этого массива.
  5. Вывожу график без шумов на экран.


В общем: В режиме реального времени с минимальной задержкой должно строиться 2 графика. Первый - звук с шумами. Второй - звук без шумов. (потом ещё должен быть добавлен график функции автокорреляции... но это потом)

На первом этапе у меня возникли следующие вопросы:
  1. Если я хочу в данной программе организовать считывание сигнала порциями по 4096 байт, то как это лучше реализовать, и какой временной промежуток мне использовать? Какая формула для его расчета мне необходима?
  2. Каким образом организовать данное преобразование звука без потерь при его буферизации и лишних наложений? Как правильно рассчитать время, чтобы между двумя выборками БПП не оказывалось потерянной информации и чтобы одна выборка не накладывалась на другую?
  3. Что в качестве аргументов принимает функция RecordingCallback?
#define FREQ 44100               // частота дискретизации
#define BUFSTEP 200000        // блок распределения памяти
#define CHANS 1                   // количество каналов
char *recbuf=NULL;		  // буфер записи
int reclen;			          // длина записи
HRECORD rchan=0;		  // канал записи
HSTREAM chan=0;		  // канал воспроизведения

BOOL CALLBACK RecordingCallback(HRECORD handle, const void *buffer, DWORD length, void *user)  //вызывается каждые 100 мс.
  {
  if ((reclen%BUFSTEP)+length>=BUFSTEP)    // увеличить размер буфера при необходимости
    	{
    	recbuf = (char *)realloc(recbuf,((reclen+length)/BUFSTEP+1)*BUFSTEP);
    	if (!recbuf)
	       {
	       rchan=0;
	       return FALSE; // стоп
	       }
    	}
  memcpy(recbuf+reclen,buffer,length);        // буфер данных
  reclen+=length;
  return TRUE; // продолжить запись
  }

void StartRecording()
  {
  WAVEFORMATEX *wf;
  if(recbuf)
    	{
    	BASS_StreamFree(chan);     // освободить старый канал
    	chan=0;
	    free(recbuf);
	    recbuf=NULL;
    	BASS_Free();
	    }
  recbuf=(char *)malloc(BUFSTEP);  // выделить персональный буфер и освободить место для заголовка
  reclen=44;
  memcpy(recbuf,"RIFF\0\0\0\0WAVEfmt \20\0\0\0",20);     // заполнить заголовок
  memcpy(recbuf+36,"data\0\0\0\0",8);
  wf=(WAVEFORMATEX*)(recbuf+20);
  wf->wFormatTag=1;                                      // тип аудио сигнала
  wf->nChannels=CHANS;                                   // количество каналов аудиоданных
  wf->wBitsPerSample=16;                                 // количество бит на сэмпл
  wf->nSamplesPerSec=FREQ;                               // частота дискретизации
  wf->nBlockAlign=wf->nChannels*wf->wBitsPerSample/8;      // выравнивание блока в байтах
  wf->nAvgBytesPerSec=wf->nSamplesPerSec*wf->nBlockAlign;   // скорость передачи данных в байтах в секунду
  rchan = BASS_RecordStart(FREQ,CHANS,0,RecordingCallback,0);  // начать запись
  }


Пересмотрел кучу тем, но для данного случая ничего не нашел... Да, я тупой, но очень хочу в этом разобраться...
Только не говорите что как всё плохо :)
  • Вопрос задан
  • 2742 просмотра
Решения вопроса 1
jcmvbkbc
@jcmvbkbc
"I'm here to consult you" © Dogbert
Что в качестве аргументов принимает функция RecordingCallback?

BOOL CALLBACK RecordingCallback(HRECORD handle, const void *buffer, DWORD length, void *user)
handle процесса записи, через который можно как-то этим процессом управлять,
буфер сэмплов, длина буфера в байтах и указатель, переданный в BASS_RecordStart последним аргументом.

Сэмпл -- это значение амплитуды звукового сигнала в одном канале. Формат сэмпла задаётся младшими битами третьего параметра функции BASS_RecordStart. Если там 0, то формат -- 16-битное целое число со знаком. При записи многоканального звука сэмплы каналов идут по очереди.

Сам коллбэк вызывается периодически, длина периода может быть задана старшими битами третьего параметра.
См. www.un4seen.com/doc/#bass/BASS_RecordStart.html
Ответ написан
Пригласить эксперта
Ответы на вопрос 2
@nehyrb
Экспериментировал с ДПФ, прогоняя через него сигнал. Брал по 1024 выборки и прогонял прямое+обратное. Сигнал восстанавливается, однако, на стыках происходит скачок, таким образом каждое окно отделяется щелчком, итого в полученном сигнале слышно постоянное щелканье.
Очень интересно, каким образом стыковать границы, чтобы избежать искажений?
Ответ написан
@mmisin1 Автор вопроса
Студент
jcmvbkbc: Из справки понял, что колбэк вызывается каждые 100 миллисекунд. При каждом вызове этого колбэка я вывел на экран параметр leght. Он оказался не статичен. Вот его вывод: 5512 11024 8268 8268 8268 11024 8268 и тд. Его можно как-то изменить и зафиксировать?
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы