LINUX.ORG.RU

[как] сложить два звука

 


0

0

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

Пусть есть два звука, для определенности, в signed int 16 low-endian.

Как их сложить?

Зачаток физика во мне говорит, что у нас простые амплитуды, да еще и signed - складывай и все. Зачаток программиста во мне с ужасом вспоминает, что int16 не резиновый и сумма туда просто не влезет. Физик продолжает оправдываться, что ничего не поделаешь, так и надо, среднее значение амплитуды примерно 0, а RMS вырастет, все сходится. Программист в непонятках - нужно просто принимать за максимум/минимум все, что вылезло из диапазона int16? Физик задумывается, его пугает то, что тогда RMS растет медленнее, чем надо и что-то бормочет про крайний случай, когда звуков 100500. Оба медленно сходят с ума.

Помогите пожалуйста.

★★★★★

Ну что уж тут поделаешь? Дели на 2.

Программист в непонятках - нужно просто принимать за максимум/минимум все, что вылезло из диапазона int16?

Тогда исскажения вылезут.

ЗЫ ну действительно тут ничего другого вроде как и не сделаешь. Либо надеяться, что не вылезет, либо делать.

Waterlaz ★★★★★
()
Ответ на: комментарий от Waterlaz

Прости, но вот пошел у меня первый звук, запускаю я второй - внезапно первый становится тише? Нет, так не пойдет, мне нужно как в dmix у alsa например.

t184256 ★★★★★
() автор топика

а тебе результат не обязательно в signed int 16 low-endian хранить.

А если обязательно то или по уровню источники(или результат) регулировать или смириться что будут искажения.

Третьего не дано.

true_admin ★★★★★
()
Ответ на: комментарий от t184256

Обязательно, т. е. 100500 звуков мне не свести? Обидно.

Переквантуй все каналы (увеличь разрядность), нормализуй (раздели данные в каждом канале на количество каналов), сложи, переквантуй в нужную битность. Просто складывать следующий канал и аккумулятор, с последующим сдвигом аккумулятора, нельзя - амплитуда первых каналов будет уменьшаться.

SSE/SSE2 будет в тему.

mv ★★★★★
()
Ответ на: комментарий от mv

Извини, не сильно понял. Сложить уже нормализованные почему нельзя? Без всякого переквантования... Типа *(sum++) = (*(buffer1++)/2 + *(buffer2++)/2) ?

SSE/SSE2 будет в тему

ARM, 200 BogoMIPS, предположительное число потоков - 5. посто сложить бы суметь))

t184256 ★★★★★
() автор топика
Ответ на: комментарий от t184256

Типа *(sum++) = (*(buffer1++)/2 + *(buffer2++)/2) ?

Это оно и есть в случае двух каналов :)

mv ★★★★★
()

*(sum++) = (*(buffer1++)/2 + *(buffer2++)/2) ?
Что будет если в одном из буферов звука нема или он очень тихий?

Booster ★★
()
Ответ на: комментарий от Booster

Как что будет, *(sum++) = (*(loudbuffer++)) / 2.

Т. е. один будет работать вполовинную громкость, второго не будет (почти).

t184256 ★★★★★
() автор топика
Ответ на: комментарий от Booster

Блин, нет! :-) Куда деваться, конечно, но хочется лучше - как-то же alsa сама звуки складывает и ничего, не жалуемся.

Писал же, у меня как минимум 5 каналов) Еще 5 - и придется дополнительный усилок купить)

t184256 ★★★★★
() автор топика
Ответ на: комментарий от t184256

Можно чуть похитерее. Вначале сложить, определить максимум и привести к изначальному/приемлемому диапазону.

Booster ★★
()
Ответ на: комментарий от azure

Можно, видимо пойду искать где оно в ядре спряталось. Вообще я именно его и использовал до этого, но реально много ест процессора, даже если не давать ему ресамплить.

t184256 ★★★★★
() автор топика
Ответ на: комментарий от t184256

>Угу, и громкость звука зависит от громкости других, если я вас правильно понял.
После первого прохода зависит. Но на втором проходе нормализуем(масштабируем) диапазон.

Booster ★★
()
Ответ на: комментарий от azure

почему бы не заглянуть в сорцы dmix и не посмотреть, как сделано там. И использовать их код. Опенсорц же.

dmix просто складывает два звука. И всё. Примерно так:

const int16_t *snd1, *snd2;
int32_t long_result;
int16_t *result;
size_t length;

/* ... */

while (length--) {
    long_result = *snd1 + *snd2;
    if (long_result > INT16_MAX)
        long_result = INT16_MAX;
    else if (long_result < INT16_MIN)
        long_result = INT16_MIN;
    *result = (int16_t) long_result;

    ++snd1;
    ++snd2;
    ++result;
}

Deleted
()
Ответ на: комментарий от Booster

Прости, может я тупой, но сколько смотрю твои буквы - наоборот получается, после первого - не зависит, после второго - зависит. Проверяю на мысленном эксперименте: «играл себе первый и тут шарахнул второй, первый сразу притих».

t184256 ★★★★★
() автор топика
Ответ на: комментарий от Deleted

Спасибо большое, truncate threshold значит truncate threshold.

t184256 ★★★★★
() автор топика
Ответ на: комментарий от t184256

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

Booster ★★
()
Ответ на: комментарий от elipse

Спасибо огромное за эффект bend, очень потом понадобится, но вот так и не понял - ты предлагаешь sox --effects-file - и уже запущенному sox подавать по мере надобности команды? Или нет? Желания читать всю простыню уж что-то нет, понималка не на уровне, т.к. 16 часов как на ногах.

t184256 ★★★★★
() автор топика
Ответ на: комментарий от elipse

Пока ты тут:

% sox --effects-file - 60.wav -d sox FAIL sox: Cannot open effects file `-'

Где там как делают, можно поподробнее?

t184256 ★★★★★
() автор топика
Ответ на: комментарий от Puzan

> Z = A + B - A·B

facepalm.svgz, вот это да. За пределы не вышло - значит все ок! Тогда уж делить и то лучше, хоть как-то с реальностью связано.

t184256 ★★★★★
() автор топика
Ответ на: комментарий от t184256

--effects-file FILENAME
Use FILENAME to obtain all effects and their arguments. The file is parsed as if the values were specified on the command line. A new line can be used in place of the special ":" marker to separate effect chains

т.е., после ключа --effects-file должно следовать имя файла с перечнем аргументов описания эффектов

Где там как делают, можно поподробнее?


Multiple output mode is not very useful unless an effect that will stop the effects chain early is specified before the `newfile'. If end of file is reached before the effects chain stops itself then no new file will be created as it would be empty.

The following is an example of splitting the first 60 seconds of an input file in to two 30 second files and ignoring the rest.

sox song.wav ringtone%1n.wav trim 0 30 : newfile : trim 0 30

еще смотри опции splice, fade

elipse ★★★
()
Ответ на: комментарий от elipse

> т.е., после ключа --effects-file должно следовать имя файла с перечнем аргументов описания эффектов

stdin как ему скормить для интерактивности?

Ну и горазд же жрать этот sox. Погонял на target-железе - вот это тормоз, мама дорогая, ecли play -n synth 4 pluck кушает четверть ресурсов системы, но генерит достойно, то play -n synth 4 pluck pitch 50 сожрало весь CPU своими вычислениями и мой мозг результатом в наушниках.

Но все равно спасибо за него большое, чувствую, пригодится он мне не раз.

t184256 ★★★★★
() автор топика
Ответ на: комментарий от t184256

из man sox

Filenames:

SoX can be used as a part of pipe operations by using the special filenames of "-". If specified as an input name, it will read data from stdin. If specified as an output name, it will send data to stdout.

ну попробуй так ))

elipse ★★★
()
Ответ на: комментарий от elipse

А интегрировать libsox у меня нет настроения, надо аптайм сбросить, прежде чем такое предпринимать) Пока лучше набросаю решение из первого поста)

Спасибо еще раз.

t184256 ★★★★★
() автор топика
Ответ на: комментарий от t184256

> Тогда уж делить и то лучше, хоть как-то с реальностью связано.

Интересно было бы посмотреть на хор, который поет с такой же громкостью, как один солист.

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

Puzan ★★★★★
()
Ответ на: комментарий от Puzan

Те которые по модулю меньше пяти? Спасибо, кэп, переживу без них, как-никак int16.

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

t184256 ★★★★★
() автор топика
Ответ на: комментарий от t184256

>видимо пойду искать где оно в ядре спряталось

Оно не в ядре, а в юзерспейсе alsa-lib/src/pcm/pcm_dmix.c

В ядре - это у ОSS4, причем миксят они в плавающей точке, поэтому в kernel.org их никогда не возьмут, потому что нельзя в ядре флоат использовать. А вот в юзерспейсе - вполне. Поэтому ответ на твой вопрос - используй флоат, если он у тебя есть, конечно. А чем он лучше - в блоге oss должно быть объяснено.

vga ★★
()
Ответ на: комментарий от Deleted

Poor man's synthetizer - замену fluidsynth, который откровенно плохо ворочается на моем ultra-low-end железе.

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

Первый прототип набросал на питоне с несколькими aplay и dmix. Полюбовался, сколько это жрет и теперь хочу весь этот комбайн запихать в одну программу на C, выдающую уже смешанный звук. Думал, за 2 часа напишу, а тут такой вопрос. Решил пока другим заняться, пока тут консенсус не родится, а если не родится - делить на пять, много каналов не надо.

Еще был бы я программистом при всем при этом) Я гораздо больше админ, чем программист, а т. к. и админ из меня, мягко говоря, посредственный, то как программист я вообще невесть что.

t184256 ★★★★★
() автор топика
Ответ на: комментарий от vga

В моем arm'е он вроде даже есть, но только это точно получается ответ на мой вопрос? Типа при кодировании в float все как в реале - максимума и минимума нет? Как-то не верится, честное слово.

t184256 ★★★★★
() автор топика
Ответ на: комментарий от t184256

А если внутри программы все семплы хранить во float'ах? И сделать возможность настройки экспорта - сжимать диапазон, обрезать верх и низ или как-нибудь ещё приводить к «стандартному» int16_t.

Deleted
()
Ответ на: комментарий от t184256

Типа при кодировании в float все как в реале - максимума и минимума нет? Как-то не верится, честное слово.

Максимум и минимум у float'а тоже есть, но ты до них на своей задаче никак не доберёшся.

http://en.wikipedia.org/wiki/Floating_point

Deleted
()
Ответ на: комментарий от t184256

Вот что по этому поводу сказал разраб oss

Hannu Savolainen said...

About floating point in kernel: This feature can be disabled when compiling OSS. It's enabled by default because there have not been any problems caused by it during past few years (which IMHO proves that there are no problems). Also the CPU load is exactly the same than without FP.

Believe or not the reason to use floating point in audio computations is precision. This may sound strange since all elementary computer programming books tell that integer computations are precise and floating point is not. You may think that I have misunderstood something important but this is not the case.

The alternative for floating point is fixed point. A common practice is to store a 24 bit sample in 32 bit integer so that the 8 most significant bits are unused (or used as headroom during computations). The problem with fixed point is that there is no footroom at all and the 8 bit headroom (24 dB) is far from enough.

For example if you attenuate a fixed point signal by 30 dB which is not that much. 30 dB attenuation means that the (originally) 24 bit sample is divided by ~1000. Let's select 1024 which is the same than shifting the sample 10 bit positions to right. Now you have only 14 bits of precision left and the least significant bits are lost forever. Even if you amplify the sample by 30 dB the 10 least significant bits will not return back. If the sample value was less than 1024 then the sample will drop to 0 and all information is lost.

Floating point doesn't have this problem. Single precision FP format has 24 bits for the mantissa (which is perfect for audio) and the remaining bits are used as the exponent. If you now divide the sample by 1024 then the actual sample stored in mantissa will not change at all. Just the exponent will change because the bits were shifted «virtually». During computations trhe mantissa will always store 24 most significant bits of the sample. Some information may leak on the floor but the lost information is about 70 dB below the current signal level.

Весь срач - http://insanecoding.blogspot.com/2009/06/state-of-sound-in-linux-not-so-sorry...

vga ★★
()
Ответ на: комментарий от Deleted

Зачем float? Для потерь? Уж лучше просто хранить в unsigned int, диапазона на 5 каналов хватит с лихвой. Затем да, нужно масштабировать в случае зашкала.

Booster ★★
()
Ответ на: комментарий от vga

Вот что по этому поводу сказал разраб oss

About floating point in kernel: This feature can be disabled when compiling OSS. It's enabled by default because there have not been any problems caused by it during past few years (which IMHO proves that there are no problems). Also the CPU load is exactly the same than without FP.

Ха-ха. Пусть он это попробует сказать разработчикам ASoC =).

Deleted
()
Ответ на: комментарий от vga

Адаптивное выравнивание диапазона применяется например в радио, правда по мне качество не очень. Для вашего случая может подойти хранить каждый канал, в 1/5 от максимума.

Booster ★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.