Смешиваем цифровой звук

Как смешать 2 или более каналов цифрового звука? — Полагаю, такой вопрос возникает довольно часто, если вы не пользуетесь каким-либо API/DLL/и прочим. Итак начнем.

Теория

Возьмем два звука(сэмпла), которые нам нужно смешать.

Но-но-но. У нас ведь цифровой звук. Значит, на выходе будет стоять ЦАП, предположим, — 8бит ЦАП, частота дискретизации — 16KHz. То, естественно, это сказывается на форме сигнала. Осциллограмма двух каналов будет примерно такой:

И теперь затык. Как смешать звук, состоящий из чисел? Первое, что приходит в голову — сложение цифровых амплитуд, что и является самым правильным способом. «+«! Максимальная амплитуда каждого звука: 256, а ЦАП у нас — 8бит, соответственно, при сложении будет такая картина:

Этого следовало ожидать. Все значения амплитуд, которые выше половины возможности ЦАП-а — назовем их — Пик-ами.

Тут несколько возможных путей:

  • Делить на 2, перед смешиванием
  • Нормализовать «пики»
  • Увеличить запас ЦАП, т.е. повысить разрядность.

Делить на 2 — это самое простое, но это уменьшает качество звука. Если два канала, то разрядность каждого уменьшится до 7бит. А если звуков > 2? Противоречие налицо. С одной стороны нужно понизить уровень каналов во избежание переполнения ЦАП-а, с другой — иметь максимально возможный уровень в канале для полного использования всех разрядов.

Нормализация и т.п. — небольшая потеря качества, но вариант хороший.

Повысить разрядность — ну, это крайние меры.

Дело в том, что время «пиков» может совпадать у двух каналов, поэтому происходит переполнение ЦАП-а. Почему в «природе» этого не происходит?

Пример: хор из 100 человек. Если бы они пели полностью синхронно, то у нас давно бы взорвались перепонки. Если звук в природе был бы цифровой, то частота дискретизации стремилась к бесконечности. А разрядность «природного ЦАП-а» была бы то же не маленькой.

Снижая частоту дискретизации — совпадений «пиков» становится еще больше:

Здесь сразу видно, что переполнение ЦАП-а будет очень часто, чтобы уменьшить этот шанс — нужно увеличить частоту дискретизации, либо уменьшить разрядность.

Есть еще один способ смешивания звука: поднять общую частоту дискретизации в 2 раза и выводить сэмплы(значения амплитуд) последовательно. Четные — звук1, нечетные — звук2. Потерь качества — 0%.

Ну, а если вы считаете каждый такт вашей программы, то можно выводить каждый звук на отдельный ЦАП, а смешивать их уже аналоговым микшером или просто резистором.

Программные решения

Среднее арифметическое.
Z = (A + B) / 2
Теряем качество на один бит, но этот способ имеет право на жизнь. Также все типы данных должны быть знаковыми.

1
2
3
4
5
6
int8_t SoundBuf1[xxx];
int8_t SoundBuf2[xxx];
 
void tranferDAC() {
   DAC = (SoundBuf1[countBuf_1]+SoundBuf2[countBuf_2])>>1;
}

Последовательный вывод.
Z = A, … Z = B, …
Условие: частота дискретизации должна быть умножена на 2.

1
2
3
4
5
6
7
8
9
10
11
12
boolean flag = false;
 
void tranferDAC() {
 if (flag) {
   DAC = SoundBuf1[countBuf_1];
   countBuf_1++;
 } else {
   DAC = SoundBuf2[countBuf_2];
   countBuf_2++;
 }
 flag=!flag;
}

Нормализация.
Z = 2(A + B) — (A * B)/128 — 256
via (для знаковых чисел)

1
2
3
4
5
6
int8_t SoundBuf1[xxx];
int8_t SoundBuf2[xxx];
 
void transferDAC() {
   DAC = (((SoundBuf1[countBuf_1] + SoundBuf2[countBuf_2])<<1)((SoundBuf1[countBuf_1]*SoundBuf2[countBuf_2])>>7)256);
}

Z = A + B — (A * B)/256
(для беззнаковых)

1
2
3
4
5
6
uint8_t SoundBuf1[xxx];
uint8_t SoundBuf2[xxx];
 
void transferDAC() {
   DAC = (SoundBuf1[countBuf_1] + SoundBuf2[countBuf_2]((SoundBuf1[countBuf_1]*SoundBuf2[countBuf_2])>>8));
}

Аппаратные решения

Питание — двуполярное, естественно. (можно использовать преобразователь из этой статьи)

То же очень простой микшер. (транзистор можно брать с любой буквой)
Автор микшеров — Vadim.
 

FIN

0
0

About Кирилл Васин

Прохожий из шапки сайта

2 Comments

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *