О передискретизации в 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 комментариев

avatar
Охренительная статья, достойная научного журнала. Если бы тут было «золото» — она бы отправилась туда, прямиком к Райдерсам Лост Арта.
Я не понял ни слова.
  • sq
  • +5
avatar
sq , ты что, статью со слоном не читал???

… впрочем, я тоже…
avatar
Спасибо! У меня «Raiders of the Lost Art» тоже среди самых любимых! :)
avatar
Вывод: анимешную картинку можно найти к любому слову. правда на мой вкус она не в тему… ну если какой нить спек подрисовать чтоли :)
А вообще хорошо так проблемма описана, доступно
avatar
Рад, если получилось доступно изложить! Картинку заменил :)
avatar
Отличная статья и совершенно изумительный инструмент!
Огромнейшее спасибо за труд и исследования и добро пожаловать на Hype!
avatar
Итак, если коротко и для простого читателя — Аюми ядренее чем все прошлые AY-эмуляторы? Звук записанный напрямую с живого железа (при 192кГц например) как может быть сравним с результатами Аюми?
avatar
Мне думается, что каждый эмулятор хорош в свой области применения. Ayumi далеко до возможностей и быстродействия ZXTune. Звучание Ay_emul кому-то может показаться более приятным, чем «стерильный» звук Ayumi. НЧ-фильтр Ay_emul просто может более адекватно отражать особенности
звуковоспроизводящего тракта, к которым привык слушатель. У меня реального чипа для проверки нет, но я помню, что MmcM делал тест на 96 кГц и остался доволен результатом.

Хочу добавить, что статья это была написана вовсе не для рекламы Ayumi. Задача передискретизации возникает и при моделировании Pokey, Paula и прочих звуковых чипов. Я надеюсь, что моя статья хоть немного облегчит жизнь авторам будущих эмуляторов. :)
avatar
Кстати по поводу быстродействия.
Есть желание попробовать арифметику с фиксированной запятой?
Я померял скорость работы ayumi, получил примерно x46 (т.е. модуль рендерится в со скоростью в 46 раз превышающую нормальную. Для сравнения, в ZXTune это ~x315 в режиме с максимальным качеством) на 64-битной машине с 3ГГц процессором. Включение всяких mmx/sse дало копеешный прирост в районе 2%. Значит запустить это дело на всяких армах вообще нереально, не говоря уже о TurboSound.
avatar
Мой приоритет — достаточно эффективная работа аудио плагина в DAW на современном PC. В такой ситуации, думаю, нет особенного смысла переходить на фиксированную запятую (хотя такой вариант и сейчас востребован в приложениях, где требуется побитовая точность результата). Что касается микроконтроллеров, то я бы, скорее, изменил алгоритм передискретизации. Кстати, CIC-фильтры, о которых я упомянул в «Заключении», в данном случае интересны тем, что работают как раз на фиксированной запятой и не требуют операций умножения.
avatar
Я это понимаю:)
Просто ко мне уже приходили запросы на тему «встроить ayumi в zxtune». Не обращая внимания на целесообразность сего действа или хотя бы различную специализацию этих инструментов.
avatar
Забыл сказать спасибо за тестирование! Очень полезная информация.
avatar
Не за что:) Если не забуду, потестирую сегодня на ARM. Чисто поржать (на моем экземпляре нет аппаратной поддержки чисел с плавающей запятой) и попрофилировать. В области ЦОС я дуб полный, в разработке ПО больше соображаю.
avatar
Таки потестировал. Через дробь скорость без/с DC фильтром. Используются стандартные конфигурации сборки.

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

В общем, неюзабельно в реалтайме.
avatar
Спасибо! Ожидания подтвердились :)
avatar
Математику, конечно, так не поймёшь, но общая идея о процессе сложилась, спасибо.

Хочу добавить, что у ayumi скоро появится конкурент — Deathsoft совместно с Barmaley_m написали новую схему передискретизации для эмулятора Unreal, которая будет добавлено к основной ветке в одной из будущих версий. Качество обещает быть как минимум не хуже чем достигнутое в ayumi.
avatar
Вот это «как минимум» даже немного пугает :) Надеюсь, авторы намекнут, что же они такое использовали.
avatar
Они активно обсуждали свою технологию на #z80, собственно там всё и было договорено. Можно поднять логи за январь-февраль, там всё будет. Я не помню конкретные дни, но там очень сложно пропустить; техническое обсуждение было совершенно грандиозного масштаба :)
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.