Попытка смешать два аудиоисточника PCM

У меня есть два аудиофайла, которые я читаю с помощью libsndfile.

SNDFILE* file1 = sf_open("D:\\audio1.wav", SFM_READ, &info);
SNDFILE* file2 = sf_open("D:\\audio2.wav", SFM_READ, &info2);

После того, как я сделал предыдущее, я сэмплирую x-количество сэмплов:

//Buffers that will hold the samples
short* buffer1 = new short[2 * sizeof(short) * 800000];
short* buffer2 = new short[2 * sizeof(short) * 800000];

// Read the samples using libsndfile
sf_readf_short(file1, buffer1, 800000);
sf_readf_short(file2, buffer2, 800000);

Теперь я хочу смешать эти два. Я читал, что нужно получить левый и правый канал отдельно, а затем суммировать их. Я пытался сделать это так:

short* mixdown = new short[channels * sizeof(short) * 800000];
for (int t = 0; t < 800000; ++t)
{
    mixdown[t] = buffer1[t] + buffer2[t] - ((buffer1[t]*buffer2[t]) / 65535);
    t++;
    mixdown[t] = buffer1[t] + buffer2[t] - ((buffer1[t]*buffer2[t]) / 65535);
}

После этого я кодирую новый звук с помощью ffmpeg:

FILE* process2 = _popen("ffmpeg -y -f s16le -acodec pcm_s16le -ar 44100 -ac 2 -i - -f vob -ac 2 D:\\audioMixdown.wav", "wb");
fwrite(mixdown, 2 * sizeof(short) * 800000, 1, process2);

Теперь проблема в том, что звук из буфера1 звучит нормально в сведении, но единственное, что «добавляется» к новому звуку, — это шум (например, если это старая аудиозапись), когда я кодирую сведение в файл.

Если я кодирую только один из двух в файл, он работает отлично.

Я понятия не имею, почему это идет не так. Я предполагаю, что это как-то связано с микшированием, очевидно, но я не знаю, что я делаю неправильно. Я получил алгоритм микширования здесь, но он не дает мне ожидаемые результаты.

Я также читал другую информацию о SO о людях, у которых есть похожие вопросы, но я не мог понять это с ними.

заранее спасибо


person Dries    schedule 24.02.2015    source источник
comment
Здесь вы невнимательно относитесь к стереоканалам — надеюсь, это потому, что это упрощенный пример.   -  person MSalters    schedule 24.02.2015
comment
Что ты имеешь в виду? Что мне следует изменить? (цикл for в моем вопросе теперь тот, что из ответа)   -  person Dries    schedule 24.02.2015
comment
Ну, вы не проверяете, что audio1.wav и audio2.wav имеют одинаковое количество каналов. Но разумно исключить такие проверки из упрощенного примера.   -  person MSalters    schedule 24.02.2015
comment
О да, я знаю это. Я сейчас думаю, как я это сделаю. Я думал о преобразовании монозвука в стерео, чтобы микширование оставалось прежним.   -  person Dries    schedule 24.02.2015
comment
@Dries Ответ, который вы приняли, неверен, и статья, на которую вы ссылаетесь, даже объясняет, почему. Ваш код выглядит нормально, но вы должны делить 32768, а не 65535. Это объясняет некоторые искажения.   -  person ElderBug    schedule 24.02.2015
comment
@ElderBug Хм ... Тогда позвольте мне сравнить две идеи. Я думаю, что это неправильно. Это работает для моего примера.   -  person Dries    schedule 24.02.2015
comment
@Dries Это действительно звучит правильно, но, как объясняется в статье, амплитуда одного сигнала уменьшается вдвое, если другой молчит.   -  person ElderBug    schedule 24.02.2015
comment
@ElderBug Я изменил код, и он действительно хорошо звучит с моим кодом. Итак, думаю, я оставлю свой код (с вашими изменениями). Было интересно увидеть самый простой пример, и я рад, что был почти прав :)   -  person Dries    schedule 24.02.2015
comment
@Dries: каков ваш вариант использования? Если это для высококачественного звука (например, музыки), то вы, вероятно, не хотите добавлять нелинейный термин. Если вы просто микшируете что-то вроде звуковых эффектов видеоигры, то нелинейный термин поможет сохранить динамический диапазон за счет некоторого искажения.   -  person Paul R    schedule 24.02.2015
comment
Кстати, вы выделяете в два раза больше памяти, чем вам нужно. new T[N] выделит N объекта, а не N байта, поэтому нет необходимости умножать на sizeof(short).   -  person Mike Seymour    schedule 24.02.2015
comment
@MikeSeymour О, хорошо, спасибо. я изменю это   -  person Dries    schedule 24.02.2015
comment
@PaulR Мне нужно смешать оба ваших примера. звуковые эффекты, а также фоновая музыка   -  person Dries    schedule 24.02.2015
comment
@Dries: к сожалению, идеального решения проблемы микширования не существует, если вам нужно делать это на лету. Если вы можете микшировать заранее, то можно нормализовать входные сэмплы и сохранить полный динамический диапазон, но в противном случае вам придется так или иначе идти на компромисс. Многое было написано на эту тему за эти годы.   -  person Paul R    schedule 24.02.2015
comment
@PaulR пока звучит нормально. Если есть небольшая потеря качества, это нормально. Спасибо за понимание темы. Я уверен, что смогу продолжить разработку со всей полученной информацией.   -  person Dries    schedule 24.02.2015


Ответы (2)


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

for (int t = 0; t < 800000 * 2; ++t)
{
    mixdown[t] = (buffer1[t] + buffer2[t]) / 2;
}

Обратите внимание, что деление на 2 необходимо для предотвращения искажения при наличии двух полномасштабных сигналов. Обратите также внимание, что я удалил двойное разворачивание цикла.

person Paul R    schedule 24.02.2015
comment
РЕДАКТИРОВАТЬ: nvm, это исправлено! Большое спасибо - person Dries; 24.02.2015
comment
Этот хак, вероятно, не для PCM. Я думаю, что хак был создан кем-то, кто не знал, что он работает с данными uLaw, и который, следовательно, попробовал несколько простых арифметических операций над целочисленной интерпретацией значения uLaw. - person MSalters; 24.02.2015
comment
@MSalters: ага - да - µLaw имело бы смысл. - person Paul R; 24.02.2015
comment
Алгоритм идеально подходит для PCM, и ваш ответ неверен, потому что он вызывает искажение амплитуды. Связанная статья OP объясняет, почему. - person ElderBug; 24.02.2015
comment
@Elderbug: это зависит от того, хотите ли вы сохранить качество - вводя нелинейный термин, вы вносите искажение. Преимущество в том, что вы получаете полный динамический диапазон, когда один семпл тихий, но за счет значительных искажений. Для звука низкого качества (например, микширования звуков аркадных игр) это может быть нормально, но для микширования музыки и т. д., вероятно, больше заботит минимизация искажений. - person Paul R; 24.02.2015
comment
Алгоритм может работать для обоих, но немного отличается для беззнакового PCM. Версия OP действительно предназначена для подписанного PCM. Статья также содержит неподписанную версию PCM, если вы хотите взглянуть. И это действительно не вызывает искажений. - person ElderBug; 24.02.2015
comment
Извините, я неправильно истолковал ваш комментарий и теперь исправил свой. Я не думаю, что здесь обязательно есть правильное или неправильное - это зависит от того, хотите ли вы отдать приоритет динамическому диапазону над точностью или наоборот. - person Paul R; 24.02.2015
comment
Я не слушал результат, но я не думаю, что это вызывает искажения, и ОП, кажется, тоже так думает после того, как он прослушал. - person ElderBug; 24.02.2015
comment
@Elderbug: любая нелинейность вносит искажения - слышите вы это или нет, зависит от характера источников и от того, насколько хороши ваши уши. ;-) - person Paul R; 24.02.2015

Ваш алгоритм правильный, но вы упустили важный момент: диапазон вашего ПКМ от -32768 до 32767. Таким образом, вы должны делить на 32768, а не 65535.

person ElderBug    schedule 24.02.2015