Использование библиотеки libsndfile для объединения и микширования файлов .wav - PullRequest
2 голосов
/ 15 апреля 2011

Мне нужна помощь, чтобы начать работу с libsndfile.

У меня есть четыре WAV-файла (все с одинаковой частотой дискретизации).

Я хочу соединить первые два вместе, затем следующие два вместе,

Затем смешайте 2 полученных файла .wav в один.

Ответы [ 2 ]

4 голосов
/ 28 июня 2011

Для микширования двух файлов WAV.

#include <cstdio>
#include <sndfile.h>
#include <windows.h>
#include <cstdlib>
#include <cmath>

#define BUFFER_LEN 1024
#define MAX_CHANNELS 6

static void data_processing (double *data, int count, int channels) ;

int main (void) {

  static double data [BUFFER_LEN] ;
  static double data2 [BUFFER_LEN] ;
  static double outdata [BUFFER_LEN] ;

  SNDFILE *infile, *outfile, *infile2 ;
  SF_INFO sfinfo ;
  int readcount ;
  SF_INFO sfinfo2 ;
  int readcount2 ;

  const char *infilename = "inputOne.wav" ;
  const char *infilename2 = "inputTwo.wav" ;
  const char *outfilename = "output.wav" ;

  if (! (infile = sf_open (infilename, SFM_READ, &sfinfo))) {
    /* Open failed so print an error message. */
    printf ("Not able to open input file %s.\n", infilename) ;

    /* Print the error message from libsndfile. */
    puts (sf_strerror (NULL)) ;
    return 1 ;
  } ;

  if (sfinfo.channels > MAX_CHANNELS) {
    printf ("Not able to process more than %d channels\n", MAX_CHANNELS) ;
    return 1 ;
  } ;

  if (! (infile2 = sf_open (infilename2, SFM_READ, &sfinfo2))) {
    /* Open failed so print an error message. */
    printf ("Not able to open input file %s.\n", infilename2) ;

    /* Print the error message from libsndfile. */
    puts (sf_strerror (NULL)) ;
    return 1 ;
  } ;

  if (sfinfo2.channels > MAX_CHANNELS) {
    printf ("Not able to process more than %d channels\n", MAX_CHANNELS) ;
    return 1 ;
  } ;

  /* Open the output file. */
  if (! (outfile = sf_open (outfilename, SFM_WRITE, &sfinfo))) {
    printf ("Not able to open output file %s.\n", outfilename) ;
    puts (sf_strerror (NULL)) ;
    return 1 ;
  } ;

  while ((readcount = sf_read_double (infile, data, BUFFER_LEN)) &&
         (readcount2 = sf_read_double (infile2, data2, BUFFER_LEN))) { 
    data_processing (data, readcount, sfinfo.channels) ;
data_processing(data2, readcount2, sfinfo2.channels) ;

    for(int i=0; i < 1024;++i) {
  outdata[i] = (data[i] + data2[i]) -(data[i])*(data2[i])/65535;
    }

    sf_write_double (outfile, outdata , readcount) ;
  } ;

  /* Close input and output files. */
  sf_close (infile) ;
  sf_close (infile2) ;
  sf_close (outfile) ;
  system("PAUSE");
  return 0 ;
} /* main */

static void data_processing(double *data, int count, int channels) { 
  double channel_gain [MAX_CHANNELS] = { 0.5, 0.8, 0.1, 0.4, 0.4, 0.9 } ;
  int k, chan ;

  for (chan = 0 ; chan < channels ; chan ++)
    for (k = chan ; k < count ; k+= channels)
      data [k] *= channel_gain [chan] ;

  return ;
} /* data_processing */

Вот как я микширую два простых файла WAV, которые представляют собой 16-битные сигналы.

Прежде всего, микширование звука не так просто, как одинмог подумать.После объединения двух сигналов может быть много неясностей.В моем случае он работает настолько хорошо, насколько мне это нужно, но если вам нужны точные результаты, вам может понадобиться больше гуглить для точного наложения сигналов друг на друга.

Для объединения двух файлов WAV вы можете просто прочитать свой первый файл WAV, скопировать данные в результирующий файл WAV и, наконец, добавить данные второго файла WAV в результирующий файл WAV.

Этоссылка также может быть полезна для вас http://www.vttoth.com/digimix.htm

3 голосов
/ 23 апреля 2013

Это старо, но я читаю это, так что кто-то другой неизбежно сделает это.

В целом я согласен с nishantmishra относительно использования libsndfile, но этот алгоритм микширования вызовет определенное искажение, если он делает то, что ожидает автор:

outdata[i] = (data[i] + data2[i]) -(data[i])*(data2[i])/65535;

(На самом деле, последний термин добавляет немного шума низкого уровня ... перед прочтением статьи V-Toth я подумал, что это интересная форма смешения), Предполагая, что это было применено способом, который работает как предполагалось (аудио с плавающей запятой колеблется от -1,0 до 1,0, поэтому деление на 65535 уменьшает произведение на 96 дБ, что делает его неслышимым для 16-битного звука). Если вы действительно хотите реализовать этот метод, то читайте в публикации V Toth о том, как делать это для подписанных данных.

Независимо от того, подписаны вы или нет, вы будете добавлять интермодуляционные искажения (даже если они не очень неприятные, они будут присутствовать). Другими словами, это отлично работает для голоса или звука с низкой скоростью передачи (телефонного), где искажение в канале передачи намного превышает искажение интермодуляции, добавляемое произведением каналов.

Если вы просто обрабатываете два файла, а не делаете это в режиме реального времени (воспроизведение при чтении блоков из файла или потока), вы можете нормализовать оба файла, применить усиление микширования так, чтобы gain1 + gain2 = 1.0 и суммируйте их вместе. Эти проблемы с низким разрешением, как упомянуто V Toth, не представляют большой проблемы с 32-битным плавающим или 64-битным двойным.

Наконец, если вас беспокоит то, что один источник слишком тихий, а другой молчит, вы можете применить компрессор динамического диапазона, сшитый с другим каналом. Другая тактика - применять тот же алгоритм, но к огибающим аудио, а не к отдельным сэмплам:

outEnvelope[i] = (envelope1[i] + envelope2[i]) \
-(envelope1[i])*(envelope2[i]);
outdata[i]=outEnvelope[i]*(data[i] + data2[i]);

Где конверт =

envelope1[i]=sqrt(lowPassFilter(data[i]*data[i]));//moving RMS representation

А частота среза фильтра низких частот составляет порядка 10 Гц, чтобы минимизировать гармонические искажения.

Действительно, я думаю, что все, что вы хотите сделать чаще всего, это отбросить этот последний член и использовать эту строку:

outdata[i] = (data[i] + data2[i]);

Пока сумма channel_gain [] = 1.0, вы получите хороший результат. Код от nishantmishra работает хорошо, потому что последний срок добавления искажений сводится к минимальному уровню шума, поэтому вы также можете сэкономить время ЦП и устранить его.

...