О передискретизации в Ayumi
Введение
Эмулятор Ayumi был создан специально для музыкантов, с учетом их повышенных требований к качеству моделирования работы звуковых чипов AY-3-8910 и YM2149F. Он существует в двух версиях: аудио плагин для работы в реальном времени и отдельное приложение для генерирования файлов формата WAV. От уже существующих эмуляторов вышеупомянутых чипов Ayumi отличается, в первую очередь, подходом к передискретизации (resampling), о котором рассказано далее.
Для привлечения внимания уважаемой публики я решил погуглить какую-нибудь симпатичную японку с именем Аюми (раз уж название эмулятора образовалось таким образом из «AY» и «YM»).
В процессе записи сигнала с реальной микросхемы на звуковую карту компьютера происходит аппаратная передискретизация. Чип, на тактовый вход которого подается от 1 до 2 мГц, способен генерировать звуковые данные на частоте дискретизации в диапазоне 125–250 кГц (поскольку для генераторов тона используется делитель входной частоты, равный 16). Эти данные силами встроенных ЦАП микросхемы далее преобразуются в непрерывную (аналоговую) форму и заново оцифровываются компьютером уже на более низкой частоте, такой, например, как 44.1 кГц, попутно избавляя слушателя от сигналов из ультразвуковой области.
Насколько необходима для эмулятора передискретизация в программном виде? Если отказаться от потактового моделирования чипа, то можно заставить эмулятор генерировать отсчеты сразу на выходной частоте.
Здесь полезно сделать небольшое отступление, на тему того, как микросхема генерирует квадратную форму волны (меандр). Спектр такого сигнала представляет собой бесконечный ряд нечетных гармоник. При дискретизации следует ожидать эффекта наложения спектров (aliasing). Для борьбы с этим эффектом разработчики профессиональных синтезаторов используют специальные алгоритмы генерирования волн с ограниченным спектром. Моделируемый звуковой чип таких средств не имеет, но, тем не менее, в спектре создаваемых им квадратных тонов никаких паразитных частот не наблюдается. Секрет прост: отраженные частоты точно накладываются на гармоники из рабочего диапазона. Это возможно лишь для тонов, половина периода которых составляет целое число отсчетов (сэмплов). От «профессионального» варианта такой результат отличается лишь чуть измененными в результате наложения спектров амплитудами гармоник.
Спектр меандра на 441 Гц при частоте дискретизации 44100 Гц. Имеет целый полупериод, равный 50 отсчетам, наложения частот не наблюдается
Если, например, микросхема производит тон в 500 Гц на тактовой частоте в 2 мГц, то полупериод данного тона составит 250 отсчетов. Однако, при работе на частоте дискретизации в 44.1 кГц это количество отсчетов перестает быть целым (44.1 отсчета) и в спектре результата появляются отраженные гармоники. Результат показывает, что передискретизация действительно полезна.
Спектр меандра на 500 Гц при частоте дискретизации 44100 Гц. Его полупериод равен 44.1 отсчетам
Интуитивно понятно, как можно поднять частоту дискретизации в N раз. Для этого надо добавить между каждым отсчетом по N-1 промежуточных значений (интерполяция). Аналогично, для понижения частоты дискретизации в M раз следует оставлять лишь каждый M-й отсчет из всей последовательности (децимация или прореживание). В обоих случаях для борьбы с неприятными спектральными явлениями необходимо использовать фильтр нижних частот. На практике, увы, реализация передискретизации не настолько проста. Идеально подходящий для данной задачи КИХ-фильтр (FIR) потребовал бы бесконечного набора коэффициентов, соответствующих значениям sinc-функции. Кроме того, изменение частоты дискретизации не всегда происходит в целое число раз.
Алгоритм передискретизации, реализованный в Ayumi, прост и эффективен в достаточной степени, чтобы работать в реальном времени. Он состоит из двух этапов. Сначала с помощью кусочно-полиномиального интерполятора звуковые данные на внутренней частоте моделирования чипа (Fm) подвергаются сверхдискретизации (oversampling): «растягиваются» до состояния, соответствующего восьмикратной выходной частоте дискретизации. Затем используется КИХ-фильтр с коэффициентом прореживания равным 8, и окончательный результат выдается на выходной частоте дискретизации (Fs). Для музыкантов-экспериментаторов имеется возможность модулировать входной тактовый сигнал эмулятора чипа, изменяя тем самым коэффициент передискретизации на лету.
Интерполяция
В старой программе Fast Tracker II можно было включить интерполяцию, улучшая тем самым качество проигрывания сэмплов. Линейная интерполяция, которая использовалась в этом музыкальном трекере, является одним из простейших случаев интерполяции кусочно-полиномиальной, поскольку вычисление полинома первого порядка здесь происходит локально, между последовательно взятыми отсчетами. Этот вид интерполяции удобен для дробного изменения частоты дискретизации и является весьма быстродействующим (всего одно умножение на выходной отсчет в линейном случае).
В Ayumi шаг интерполяции равен Fm / (Fs * 8). При использовании полинома первого порядка отношение сигнал-шум результата на выходе эмулятора нельзя признать удовлетворительным. Очевидно, нужен более качественный интерполятор.
Результат работы линейной интерполяции в Ayumi при частоте дискретизации 44.1 кГц
В статье финского автора Олли Ниемиталло «Polynomial Interpolators for High-Quality Resampling of Oversampled Audio», известной среди специалистов, как «статья со слоном», подробно исследуются различные виды кусочно-полиномиальных интерполяторов. Даются практические рецепты по выбору того или иного интерполятора, в зависимости от коэффициента сверхдискретизации, а также желаемого отношения сигнал-шум и количества операций.
Для Ayumi был выбран вариант из статьи под названием parabolic 2x. Этот интерполятор (полином 2 порядка, 4 точки) требует 6 умножений. Легко заметить, что нет необходимости перевычислять коэффициенты полинома до того момента, когда модель чипа сгенерирует свой очередной отсчет. На прочие интерполированные значения приходится лишь по 2 умножения.
Результат работы интерполятора parabolic 2x в Ayumi при частоте дискретизации 44.1 кГц
С увеличением выходной частоты дискретизации улучшается и отношение сигнал-шум результата.
Результат работы интерполятора parabolic 2x в Ayumi при частоте дискретизации 88 кГц
Интересным альтернативным вариантом из той же статьи является интерполятор на основе B-сплайна (полином 3 порядка, 4 точки).
Результат работы интерполятора на основе B-сплайна в Ayumi при частоте дискретизации 88 кГц
Децимация
В рекламе современных синтезаторов часто встречаются словосочетания в духе «oversampling up to 8X», и даже музыканты, далекие от цифровой обработки сигналов уверены, что сверхдискретизация представляет собой нечто положительное для звука. В Ayumi, с помощью метода, описанного в предыдущем разделе, частота дискретизации на выходе моделируемого чипа умножается на довольно небольшой коэффициент, от 1.4112 до 3.072, при выходной частоте дискретизации в диапазоне 44.1–96 кГц. Далее применяется прореживающий фильтр и частота дискретизации звуковых данных понижается в 8 раз. О характеристиках подобного фильтра в вышеупомянутых рекламах ничего не говорят, хотя качество его работы оказывает большое влияние на звук в целом.
Параметры КИХ-фильтра нижних частот в случае с Ayumi известны заранее, поэтому фильтр-дециматор был предварительно спроектирован, а его вычисление было оптимизировано. Фильтр обладает линейной фазовой характеристикой, поскольку искажение фазы повлияло бы на звук. Был выбран особый вид КИХ-фильтров, называемых фильтрами Найквиста, у которых каждый N-й коэффициент, за исключением центрального, равен 0. В данной ситуации N = 8. Результат сгенерирован в MATLAB с помощью команды «mfilt.firdecim(8)». Полученный фильтр имеет 192 коэффициента. На частоте дискретизации 44.1 кГц у него наблюдается некоторый эффект наложения спектров в районе 20 кГц, это было видно по графикам из предыдущего раздела. Можно понизить частоту среза фильтра, но это привело бы к изменению тембра уже в слышимом диапазоне.
АЧХ фильтра-дециматора
Симметричность коэффициентов и нули фильтра Найквиста позволили сократить количество умножений в реализации фильтра до 85. Далее можно заметить, что из 8 отсчетов на выходе фильтра потребуется лишь один, а, следовательно, остальные можно не только отбросить, но и не считать вовсе.
Дециматор функционирует следующим образом. В буфер попадают новые 8 отсчетов. Вычисляется очередной результат работы фильтра на выходной частоте дискретизации. Данные в буфере сдвигаются для приема очередных 8 отсчетов. Далее процесс повторяется. При такой схеме на каждый входной отчет приходится всего по 10.625 умножений. Вычисление фильтра в коде организовано в виде длинной суммы произведений с литералами-коэффициентами. Это позволяет задействовать внеочередное исполнение (out-of-order execution) инструкций на современных микропроцессорах.
Заключение
Подход Ayumi предполагает простую и независимую замену интерполятора или фильтра-дециматора в поисках наилучших в заданных условиях характеристик передискретизации.
Кратко упомяну о других методах, полезных в задачах передискретизации. Не требующие умножений каскадные интеграторы-гребенчатые фильтры (CIC filters), хорошо себя проявляют при аппаратной реализации и больших коэффициентах передискретизации. В задачах дробной интерполяции могут быть востребованы структуры Фарроу (Farrow structure), которые представляют собой настраиваемые КИХ-фильтры с полиномами в качестве коэффициентов. В задачах передискретизации с низким временем отклика интерес могут представлять полифазные БИХ-фильтры (polyphase IIR filters).
Эмулятор Ay_emul Сергея Бульбы является неплохой альтернативой Ayumi для слушателя. Он обладает лишь несколько худшим качеством звучания, и большинство немузыкантов не заметит разницы между этим эмулятором и Ayumi. В Ay_emul используется КИХ-фильтр, генерируемый эмулятором в зависимости от коэффициента децимации и, далее, линейная интерполяция.
Похожий на Ay_emul подход, но в более наглядном и эффективном виде, использовал известный на демосцене автор с псевдонимом kb. Его TinyMOD представляет собой крохотный проигрыватель MOD-файлов с имитацией работы чипа Paula компьютера Amiga. Задача понижения частоты дискретизации с 3.5 мГц до такой, например, как 44.1 кГц потребовала КИХ-фильтра с 1024 коэффициентами. Эти коэффициенты вычисляются в начале программы, с использованием sinc-функции и окна Хэмминга. Процесс передискретизации происходит в кольцевом буфере, куда поступают данные на частоте чипа Paula. Фильтрации подвергаются два отсчета: тот, что на текущей позиции указателя, а также следующий за ним. Далее дробная часть указателя используется для линейной интерполяции между этой парой отсчетов, а целая его часть указывает на следующую позицию в кольцевом буфере, с учетом шага интерполяции.
Для задач передискретизации можно использовать готовую библиотеку r8brain-free-src, созданную Алексеем Ванеевым. Она отличается хорошим быстродействием и высоким качеством результата. Бесплатный ресэмплер r8brain того же автора показал себя одним из лучших в тестах (см. ссылку ниже).
Полезные ссылки
Ричард Лайонс, «Цифровая обработка сигналов»
AY-3-8910/8912 PROGRAMMABLE SOUND GENERATOR DATA MANUAL. www.cpcwiki.eu/imgs/d/dc/Ay3-891x.pdf
Olli Niemitalo, «Polynomial Interpolators for High-Quality Resampling of Oversampled Audio». yehar.com/blog/wp-content/uploads/2009/08/deip.pdf
Веб-страница эмулятора Ayumi со ссылкой на исходный код. sovietov.com/app/ayumi/ayumi.html
Исходный код эмулятора Ay_emul. bulba.untergrund.net/Ay_Emul29b11.src.7z
Исходный код проигрывателя TinyMOD. www.1337haxorz.de/drugs/tinymod.cpp
Библиотека r8brain-free-src. github.com/avaneev/r8brain-free-src
Тесты различных ресэмплеров. src.infinitewave.ca/
18 комментариев
Я не понял ни слова.
… впрочем, я тоже…
А вообще хорошо так проблемма описана, доступно
Огромнейшее спасибо за труд и исследования и добро пожаловать на Hype!
звуковоспроизводящего тракта, к которым привык слушатель. У меня реального чипа для проверки нет, но я помню, что MmcM делал тест на 96 кГц и остался доволен результатом.
Хочу добавить, что статья это была написана вовсе не для рекламы Ayumi. Задача передискретизации возникает и при моделировании Pokey, Paula и прочих звуковых чипов. Я надеюсь, что моя статья хоть немного облегчит жизнь авторам будущих эмуляторов. :)
Есть желание попробовать арифметику с фиксированной запятой?
Я померял скорость работы ayumi, получил примерно x46 (т.е. модуль рендерится в со скоростью в 46 раз превышающую нормальную. Для сравнения, в ZXTune это ~x315 в режиме с максимальным качеством) на 64-битной машине с 3ГГц процессором. Включение всяких mmx/sse дало копеешный прирост в районе 2%. Значит запустить это дело на всяких армах вообще нереально, не говоря уже о TurboSound.
Просто ко мне уже приходили запросы на тему «встроить ayumi в zxtune». Не обращая внимания на целесообразность сего действа или хотя бы различную специализацию этих инструментов.
Raspberry Pi (Linux, 700MHz)
armv6/vfp: x1.94/x1.91
3Q RC9731C (Android, 1.6GHz):
armv5te/soft-float/thumb: x0.58/x0.55
armv7-a/vfpv3-d16/thumb: x4.88/x4.77
В общем, неюзабельно в реалтайме.
Хочу добавить, что у ayumi скоро появится конкурент — Deathsoft совместно с Barmaley_m написали новую схему передискретизации для эмулятора Unreal, которая будет добавлено к основной ветке в одной из будущих версий. Качество обещает быть как минимум не хуже чем достигнутое в ayumi.