Программный декодер MP3(+MOD) на STM32F10x. Часть 4. Трекерная музыка

Поколению, воспитанному ZX-Спектрумом, посвящается...

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


Своему рождению трекерная музыка обязана компьютеру под названием «Амига». Это целое семейство домашних компьютеров, мегапопулярных «там» в середине 80-х — 90-х годов. Пока мы, после падения железного занавеса, дружно осваивали 8-битные компьютеры (легендарный Спектрум), заграница от ZX уже остыла и вовсю развлекалась взрослым компьютером Амига.


Лично я узнал о существовании Амиги совсем недавно. Не удивительно, ведь рядовому советскому человеку такой заграничный девайс стоимостью до 2 тыс. долларов в то время был практически недоступен. Более того,
поставкам Амиг в Советский Союз мешало то обстоятельство, что процессоры Motorola серии 680x0 использовались в системах наведения крылатых и баллистических ракет США, из-за чего были включены в список КОКОМ (список оборудования, материалов и технологий, поставка которых социалистическим странам запрещена).
Несколько позже (середина 90-х) последующие модификации Амиги стали существенно дешевле, и некоторым из нас всё же посчастливилось стать их обладателями.

Если кто заинтересуется, историю данного аппарата можно посмотреть и послушать в изложении Дмитрия Бачило. Кстати, у Дмитрия есть масса других толковых и интересных видеообзоров разнообразных компьютерных технологий. Рекомендую. В Википедии также есть немного стартовой информации и несколько полезных ссылок.


Немного о железе
Характерной особенностью компьютера «Амига» была тщательно продуманная архитектура. Это позволяло, имея не самый мощный (хотя микропроцессор с внутренним 32-разрядным ядром слабым не назовёшь), но весьма популярный процессор Motorola 68000 с тактовой частотой 8 МГц, обеспечивать великолепную графику и звук.
Чип, отвечающий за звук, имел кодовое название Paula:
Paula прежде всего выполняет функции процессора звука c 4-мя независимыми и аппаратно микшируемыми 8-ми битными PCM-каналами стерео-звука. Обеспечивает 65 уровней громкости и аппаратную поддержку воспроизведения инструментов с любой частотой дискретизации в диапазоне от 20 Гц до 29 кГц.
Структурная схема этого «Паулабластера» имеет следующий упрощённый вид:

Звуковой сопроцессор состоит из четырёх идентичных каналов. Каждый канал включает:
  • 8-битный ЦАП;
  • масштабирующий усилитель с 65 уровнями громкости (усиления);
  • канал прямого доступа памяти DMA, загружающий отсчёт из общей памяти RAM компьютера в ЦАП;
  • таймер-делитель с настраиваемым коэффициентом деления; этот таймер тактирует DMA (т.е. определяет частоту дискретизации).
Каналы попарно суммируются-микшируются и поступают наружу в виде стереосигнала. Дополнительно предусмотрен отключаемый ФНЧ с частотой среза 4 кГц.
Сигнал тактирования 3,546895 МГц формируется генератором цветного видеосигнала, это поднесущая цветоразностного сигнала в стандарте PAL-N. В версии с видеовыходом NTSC частота была немного другая — 3.579545 МГц. Из-за особенностей аппаратного построения частота выборки DMA не могла превышать 28,9 кГц.

Также в Пауле присутствуют дополнительные возможности в виде режима «NON DMA» (прямой записи сэмпла в ЦАП) и использования одного канала в паре как модулятора второго по амплитуде/частоте. Однако не случайно самым востребованным оказался режим «DMA», так как он позволял генерировать четырёхголосную музыку с минимальной нагрузкой на микропроцессор.

Подробнее об устройстве Амиги (схема и описание работы железа на примере «Амиги-500») можно посмотреть в прилагаемых pdf-мануалах.

Software
Мощное железо требовало и соответствующей программной поддержки. Что не заставило себя долго ждать.

Формат файлов MOD разработан для создания, хранения и воспроизведения музыкальных композиций на ПК Amiga. Своё название получил от того, что стал первым форматом, хранящим свои фрагменты (например, сэмплы) в других файлах (принцип модульности). Файлы этого формата имеют, как правило, расширение «.mod».

Первая версия модульного формата была разработана и реализована в 1987 году Карстеном Обарски на ПК Amiga для хранения файлов его трекера Ultimate Soundtracker.

Каждый файл формата MOD содержит в себе оцифрованные записи реального звучания инструментов, так называемые сэмплы. Композитор, пишущий в формате MOD, использует программу, называемую трекером, в которой указывает, какой именно инструмент, в какое время, какой нотой и какой из октав должен прозвучать. Последовательность нот записывается в список — т. н. трек, а несколько параллельно звучащих треков образуют блок, называемый паттерном. Создаваемые композитором паттерны получают номера, после чего композитор может в свободной форме указывать какой паттерн и когда должен прозвучать. Совокупность паттернов и образует модуль — файл в формате MOD.

Сегодня этот формат, открывший в своё время новую эру в цифровом звучании и продемонстрировавший миру мультимедийные возможности Amiga (по сравнению с 1-битным звуком PC-спикера и только появившейся картой FM-синтеза AdLib в 1987 году) поддерживается сотнями программ на всех существующих платформах. Наиболее популярными трекерами являются: DigiBooster, OctaMED и легендарный ProTracker для AmigaOS, NoiseTracker для Mac OS X, MadTracker для Microsoft Windows и MilkyTracker для FreeBSD и GNU/Linux (существует в версиях для всех перечисленных платформ).

Оригинальные файлы формата MOD соответствуют возможностям чипсета OCS, используемого в первых классических Amiga и имеют ограничение в 15 инструментов. В более поздних модификациях, формат позволяет использовать до 32-х одновременно звучащих каналов (на каждом канале воспроизводится свой трек) и до 31 инструмента. Карстен Обарски исходил из возможности чипа Paula в чипсете OCS воспроизводить музыку через ЦАП Amiga посредством выборки PCM-данных из памяти по DMA-каналу, не загружая при этом процессор. Поэтому, сэмплы в оригинальных модульных файлах были 8-битными и хранились без компрессии.

… И всё попёрло: графика отличная, музыка достойна. Геймеры довольны, — денежки текут…

А чем всё в итоге закончилось?

Сегодня Амига вполне закономерно потеряла свою популярность. IBM PC быстро задавил её своими возможностями и открытой архитектурой. Но за время своей славы Амига набрала массу поклонников. Они ещё живы, иногда снимают любимый компьютер с полки, сдувают пыль и вспоминают свою молодость; другие запускают эмуляторы на Большом Брате; третьи сами эмулируют Амигу на ПЛИСах…

А трекерная музыка понемногу переселилась на IBM PC. Модульный формат получил дальнейшее развитие, были добавлены каналы, увеличено количество используемых инструментов, увеличена разрядность самих сэмплов. Качество звучания трекерной музыки существенно возросло. Теперь уже нет необходимости использования паулаобразных чипов, так как мощности обычного PC с большим запасом хватает для программного синтеза и простого вывода через звуковую карту в режиме PCM. На платформу PC были портированы и программы-трекеры, при помощи которых энтузиасты-композиторы до сих пор сочиняют музыку…

Не могу не упомянуть интересное направление компьютерного искусства под названием «Демосцена». Главным направлением творчества считается создание программ, отображающих сюжетные картинки под интересную музыку. Так как одним из требований является минимальный размер программы, довольно часто музыка в такой демке генерируется трекерным проигрывателем.

Посмотрите, например, что умеет товарищ Linus Akesson. К примеру, придумал чудо на ATtiny15 с «клаустрофобическим» объёмом RAM; классно играет на чиппофоне собственного изготовления. Закрываешь глаза, представляешь экран совкового телевизора с прыгающим Марио, и ностальгируешь :-).


Немного отвлёкся от темы. Продолжаем:

Не смотря на то, что Амига до сих пор выпускается в обновлённом варианте, её уже можно считать прошлым компьютерной индустрии. И как дань прошлому предлагаю эмулировать её небольшой «кусочек» — звуковую подсистему — на нашем контроллере STM32F10x.

Как звучит трекерная музыка?
Ну примерно так:

Или так:

А вообще, как говорится, лучше сто раз услышать, чем один раз увидеть непонятные картинки. Особо нетерпеливые могут залезть на keygenmusic.net, zxaaa.untergrund.net и прочие по списку из Гугла или Википедии и послушать Винампом (он умеет воспроизводить в том числе и MOD). После чего сказать «фу, какашка, Киркоров мне больше нравится». Но я всё же предлагаю дочитать статью, дружно достать свои отладочные платы, залить прошивку и получить удовольствие от прослушивания в общем-то неплохой музыки.

Подробнее о формате MOD
О формате MOD предлагаю снова почитать самостоятельно. На нашем родном языке (правда, в переводе) немного написано в книге Тима Кинтцеля «Руководство программиста по работе со звуком» (в Сети есть). И ещё где-то валяется англоязычное описание в текстовом формате «MODFIL10.TXT» и «documentation_mod.txt». Прикладываю к проекту, может кому пригодится. Но основные моменты всё же следует рассмотреть.

Итак, файл MOD состоит из:
Начнём по порядку, т.е. с конца. В конце файла хранятся сэмплы — оцифрованные представления реальных и нереальных инструментов. Сэмплы монофонические 8-битные, т.е. каждый отсчёт начинается со следующего байта. Значения представлены знаковым числом (-128...+127). Максимальный размер сэмпла — 128 кБ отсчётов.
Сэмпл — это именно то, что запихивается в ЦАП при помощи DMA. Рассмотрим примеры.

1. Барабан:


автор, не стесняясь, довёл сэмпл до ограничения, подрезав вершины атаки. Чтоб громче бумкало.

2. Какой-то клавишный музыкальный инструмент:


Видим, что у клавишного сэмпла и у барабана периоды колебаний сравнимы. А частота при воспроизведении отличается в десятки раз. Вот здесь как раз и используется предделитель, задающий частоту дискретизации (тактирующий DMA). Барабан отправляем в ЦАП медленно, а клавишник — побыстрее. Причём, меняя частоту вывода клавишного сэмпла, мы можем менять высоту тона — т.е. высоту играемой ноты. Таким образом, имея всего один сэмпл, можно синтезировать проигрывание нескольких октав.

Частота (высота тона) определяется не только частотой дискретизации ЦАП, но и частотой дискретизации звука инструмента. Например, если DMA тактируется от 7046 Гц, а период сэмпла составляет 16 отсчётов, то на выходе имеем 7046/16=440 Гц — нота ля первой октавы.

3. Тарелочки:


Наблюдаем шумо-звоно-подобный сигнал.

4. Не мудрствуя лукаво, рисуем звук мышкой:


И такое тоже бывает. Кстати, звучит интересно, если поверх наложить эффекты.

Сэмпл обычно состоит из двух частей: атаки и периода повторения (см. второй пример). Первая часть играет однократно, а вторая может воспроизводиться циклически, пока её не остановят принудительно. Т.е. длительность воспроизведения сэмпла может быть любой необходимой.

Сэмпл может содержать абсолютно любые звуки, в том числе «айн-цвай-драй-фир», шум толпы, звуки природы и прочее. Всё зависит от фантазии композитора.

Далее. Все записанные звуки надо воспроизводить в соответствии с мелодией, звучащей в голове композитора. Для этого составляется паттерн («Pattern», «Трафарет»). В трекере паттерн выглядит например так:


Паттерн обычно содержит 64 такта. Каждый такт (одна строчка) — минимальная неделимая «единица» музыкального произведения. В такте указывается номер сэмпла, его период и номер эффекта для каждого из 4-х каналов. Программа-трекер обычно оперирует нотами, но в паттерне всё же хранятся периоды таймеров-делителей.

Ещё одной суперважной особенностью трекерной музыки является широкое использование эффектов. Именно эффекты позволяют даже при помощи такого убогого сэмпла (см. пример №4) синтезировать интересную музыку. К эффектам относятся:
  • разнообразные модуляции частоты и амплитуды (арпеджио, портаменто, вибрато, тремоло);
  • регулировка громкости;
  • изменение темпа игры;
  • goto-переходы между паттернами.

Важно: все эффекты влияют на параметры воспроизведения сэмпла (частота — предделителем, амплитуда — выходным усилителем), не изменяя сами сэмплы в памяти компьютера.

Таким образом, паттерн является некой целой «единицей» музыкального произведения. Файл может содержать до 64/128 паттернов. Далее из этих паттернов собирается вся композиция.

Последовательность воспроизведения паттернов помещается в область Pattern Table («Order List», «Плей-лист»). Здесь есть ещё одно важное понятие: паттерны могут воспроизводиться в произвольном порядке и повторяться несколько раз.

Например, обычная попсовая песня состоит из куплетов и припевов. Причём мелодия (и слова) этих припевов может быть совершенно одинаковая. Тогда зачем несколько раз хранить одно и то же, когда можно составить один паттерн-припев. И повторять его после каждого куплета, а в конце композиции — ещё раз 20. Для этого, кстати, в формате предусмотрен специальный эффект.

Перемещаемся выше по файлу. Sample Info — заголовки сэмплов, описывающих их некие уникальные особенности. Это название, длина, описание области повторения, начальная громкость и подстройка частоты воспроизведения. В MOD-файле может храниться и менее 31 сэмпла, но заголовков — всегда 31. Заголовок и сэмплы-отсчёты имеют обобщающее название "инструмент".

Самое верхнее поле — 20-символьное название трека.

Осталось ещё три служебных поля:
  • количество паттернов, играемых согласно информации в Pattern Table.
  • Song end position используется по усмотрению проигрывателя.
  • поле File Format tag описывает формат файла. Общепринято название формата хранить в самом начале, а здесь он запрятан куда-то вовнутрь файла.

Известны форматы «M.K.», «M!K!», «FLT4», «6CHN», «8CHN» и др. Видим, что энтузиасты-затейники расширили формат MOD до 6/8 каналов. Такой формат естественно не будет полностью поддерживаться железом Амиги и предназначен только для более взрослых машин.

Приступая к разработке декодера...
Сведений, предоставленных в описании «MODFIL10.TXT» и в книге «Руководство программиста по работе со звуком» достаточно, чтобы соорудить проигрыватель. В отличие от MP3, формат MOD открыт и документирован. Чтобы не начинать с нуля, снова копаемся в интернете.

Для любителей написания собственных программ предлагается несколько интересных библиотек. Среди них:

1. FMOD — мультиплатформенная библиотека для проигрывания многоканального музыкального сопровождения и аудио эффектов. Поддерживает форматы WAV, MP3, OGG, WMA, AIFF, XM, S3M, MOD, IT и другие. Исходники закрыты, но библиотека может использоваться бесплатно для некоммерческих задач.
Дочерний проект — MiniFMOD с открытыми исходниками и без ограничений. Единственная проблема — проигрывает только формат XM. Можно покопаться в её внутренностях.

Умелец с Хабры описал, как можно использовать данную библиотеку. Ещё немного информации по MiniFMOD можно почерпнуть тут.

2. Библиотека MIDAS — мультиплатформенная библиотека для проигрывания трекерной музыки в форматах XM, S3M, MOD, IT. Проект в настоящее время не поддерживается. Последний релиз выпущен в 1998г., какой-то патч — в 2004. Тем не менее по указанному адресу можно скачать исходники.

Есть достижения и народного творчества. Вот что получилось накопать:

3. TRAXMOD-плейер, я про него уже говорил. Неплохой игрун, но с ограничениями. Подсмотрим его исходники и кое-что используем у себя.

4. Stanislav Maslan разработал и любезно описал несколько (6!) вариантов исполнения своего проигрывателя. Конструкция хорошо продумана, сделано качественное описание устройства, но — преимущественно на чешском. Использован ATMega644/32, внешняя память RAM, внешний ЦАП, интерфейс IDE, ЖКИ, кнопочки. Рай для программиста. Программа написана аккуратно, но на ASMе. Что не удивительно, учитывая не шибко быстрый контроллер. На любителя, как говорится… На Ю-трубе где-то есть и демонстрационное видео. (Я не стал бы ограничивать свои возможности таким дохлым контроллером...)
Кстати — осторожно, его сайт заражён какой-то порнушной гадостью.

5. Stellaris Launchpad MOD Player. Аппаратное обеспечение — одноимённая отладочная плата с Кортекс-М4-подобным контроллером от TI. Автор справился с задачей, но честно признаётся, что спёр портировал код из следующего проекта:

6. Проект от SERVEURPERSO (видео, исходники) на PIC32. Исходники могут оказаться полезными.

И немного по мелочи:

7.AmigaVR. Основан на ATXMega128a1 с внешней дополнительной памятью. Вероятно, автор наигрался и забросил проект в конце 2010г. Исходники сырые недоделанные.

8. Проект на ATmega16. Кроме исходников больше информации не наблюдается. Проект является одним из примеров самоотверженного труда программиста на асме. Код практически не документирован, — кроме автора там никто не разберётся. Поэтому ценность проекта как примера для подражания незначительна. Внешней памяти нет, MOD-песня пожизненно хранится в памяти FLASH контроллера. Такой вариант исполнения имеет право на жизнь в виде «музыкальной шкатулки» либо крутого дверного звонка. Хотя, обычный PCM проиграть конечно было бы проще.

9. Есть любительский проект и на Ардуине.

Итак, как показал гуглинг, воспроизведение трекерной музыки микроконтроллером довольно популярно. Проекты на Мегах обычно скромнее, с трудом играют музыку из своей FLASH-памяти. На взрослых АРМах и на Пике32 уже получаются вполне достойные и интересные плейеры.

Структура декодера
Наш проект будет содержать следующие модули:
  • mod_decoder — инициализация/деинициализация декодера, первоначальное чтение файла;
  • mod_effects — модуль обработки эффектов;
  • mod_memo — модуль чтения сэмплов (из собственной буферной RAM и с карты памяти);
  • mod_mixer — головной модуль; собирает и обрабатывает сэмплы, вызывает функции эффектов, подготавливает буфер сэмплов для ЦАП.

Начнём как обычно с конца. Задача модуля mod_mixer — эмуляция Паулы. Т.е. нужно замутить подобие 4-х каналов Timer + DMA + ЦАП + усилитель + сумматор + фильтр и подготовить данные для нашего ЦАП. Задача на самом деле нетривиальная. Нужно собрать сэмплы, поступающие с четырёх каналов с разной и непостоянной частотой дискретизации, и представить их в подходящем для ЦАП формате.

Вариантов решения задачи просматривается два:
  1. Аппаратно-программный. Используем четыре аппаратных таймера, которые работают аналогично таймерам-делителям Паулы, каждый на своей частоте. А по прерываниям укладываем отсчёты в ЦАП. Вариант вполне нормальный и простой для реализации. Но есть и минусы. На каждый канал звука необходим аппаратный таймер (ну таймеров у нас вроде достаточно, это же не проблема?). Если захотим поддержать более продвинутый формат IT или XM, нам понадобится уже 32 таймера. Прерывания могут накладываться, в результате чего будем иметь взаимную перекрёстную межканальную помеху. А DMA использовать не получится. И также не получится сделать выходной цифровой ФНЧ. Поэтому мне больше нравится вариант номер 2:
  2. Программный микшер с фиксированной частотой дискретизации. Четырёхканальные сэмплы ресемплируются и микшируются. Подготавливается буфер данных, который затем скармливается нашему модулю ЦАП (см. предыдущий проект с декодером MP3). Количество микшируемых каналов будет ограничено только производительностью контроллера.


Ремастеринг: как свести четыре канала в один
А вот дальше начинается развлекуха. Кто не в теме — читать основы теории ЦОС. А почему четыре, а не два в два — с заделом на будущее. Продвинутые форматы позволяют микшировать инструмент сразу в оба стереоканала.

Допустим, требуется сэмпл с частотой дискретизации 8 кГц проиграть на нашем ЦАП с частотой тактирования 44,1 кГц. Смотрим картинку. Белыми кружками отмечены сэмплы, красная трасса — интерполированная огибающая, чёрные точки — выборка для ЦАП:

Наша задача — определить (интерполировать) положение чёрных точек при известных белых. По науке этот процесс называется передискретизацией.

Рассмотрим варианты реализации.

1. «Правильная» передискретизация при помощи цифровых фильтров:

  • в исходный сигнал с частотой дискретизации F1 между отсчётами добавляем N-1 нулевых отсчётов; чтобы восстановить энергетику сигнала, наши полезные отсчёты увеличиваем в N раз (хотя это можно сделать и потом, главное — не потерять точность вычислений);
  • данная операция приводит к расширению сознания спектра; спектр полезного сигнала дублируется n раз; частота дискретизации тоже увеличивается в n раз;
  • применяется цифровой ФНЧ для фильтрации ненужных alias-откликов; цифровой фильтр восстанавливает низкочастотную огибающую;
  • выполняется децимация (прореживание) — берётся каждый m-отсчёт.

Весёлые картинки:

Интерполятором, рассчитывающим положение нужных нам точек, в данном случае фактически является цифровой ФНЧ. И в итоге частота дискретизации изменяется в n/m раз.

Для общего развития поразвлекаемся и попробуем замоделировать такой алгоритм в SciLab. Смотрим получившиеся комиксы:

  • (1.1) — сэмпл из двух синусов с отношением частот 1 к 5. Вторая синусоида меньше по амплитуде. Частота дискретизации условно равна 100 попугаям;
  • (1.2) — спектр сигнала; для красоты в исходный сигнал добавлено немного шума;
  • (1.3) — АЧХ фильтра, который будем использовать для фильтрации гармоник;
  • (1.4) — пока пусто (рекламное место сдаётся);
  • (2.1) — между исходными отсчётами вставили 9 нулевых;
  • (2.2) — спектр результирующего сигнала; грязновато;
  • (2.3) — применяем ФНЧ; вся гадость отфильтровалась, остался alias-отклик возле несущей;
  • (2.4) — то же самое, только растянуто по иксу;
  • (3.1) — децимируем — удаляем каждый второй отсчёт; получаем новую частоту дискретизации 100*10/2=500 попугаев; форма сигнала практически не изменилась;
  • (3.2) — пример спектра после децимации, если бы не было ФНЧ;
  • (3.3) — результирующий спектр;
  • (3.4) — то же самое, растянуто по оси частоты; спектр повторяет входной, только шума немного добавилось.

Метод трудоёмок, но наиболее точен, спектр преобразуемого сигнала практически не искажается. Не зря его применяют при передискретизации аудиоматериалов 48<=>44,1 кГц. Однако есть один неприятный нюанс: граница пропускания ФНЧ должна быть согласована с входной частой дискретизации и быть чуть меньше её половины. А у нас частота дискретизации сэмпла — параметр переменный, следовательно и полоса пропускания ФНЧ тоже должна быть переменной. Т.е. нужно как минимум 5 октав * 12 нот = 60 вариантов фильтра. Можно конечно их проредить в 2-3 раза, но всё равно накладно как-то. Да и STM32F10x сразу с четырьмя каналами не справится.

Смотрим другие методы — там применяется обычная и местами высшая математика.

2. Интерполяция разнообразными многочленами-полиномами (кубический, сплайн, Лагранжа и т.д. и т.п.). Даёт неплохое приближение, но реализация по трудоёмкости может быть сравнима с цифровым ФНЧ.

3. Линейная интерполяция — частный случай интерполяции полиномом (первой степени) — восстановление промежуточной точки по двум соседним. Оптимальное соотношение качество/трудоёмкость. Такая интерполяция встречается в проектах MOD-плейера на ATmega.
Рисуем комиксы. Исходный сигнал тот же. Интерполируем с преобразованием частоты дискретизации в 2 и 2,1 раза:

Видим в выходном спектре лишние спуры. Наш полезный сигнал завернулся и продублировался вблизи верхней границы частотного диапазона. Уровень побочной составляющей около -35 дБ. Но с ростом частоты сигнала будет расти и его гармоника-отражение. При некруглой передискретизации появляется куча комбинационных частот.

4. Интерполяция методом ближайшего соседа (ступенчатая интерполяция)
метод интерполяции, при котором в качестве промежуточного значения выбирается ближайшее известное значение функции. Интерполяция методом ближайшего соседа является самым простым методом интерполяции.
Но и результат преобразования самый безобразный:

Звук (особенно при некратных преобразованиях частоты) будет обогащён множеством гармонических составляющих и станет похож на дешёвую синтезированную музыку. Как раз соответствующую по качеству нашему ЦАП. Поэтому принимаем данный вариант интерполяции как базовый. А линейную интерполяцию оставим на закуску.

Ну а далее — рутина, обычные программистские будни…

Чтение файла
Прошлый раз мы играли MP3 — потоковый формат. Фреймы читали не спеша, по порядку. В трекерном проигрывателе всё не так — всё гораздо сложнее. Сэмплы хранятся в файле в несжатом виде и проигрываются многократно в течение всей мелодии. Пиковая скорость чтения может составлять до 3,58 МГц / 57 * 4 канала = 250 кбайт/с. Для сравнения: MP3 320 кбит/с = всего 40 кбайт/с.

В идеале сэмплы должны храниться в оперативной памяти (как в Амиге). Не зря в указанных выше проектах иногда в помощь контроллеру предоставляется внешняя RAM-память. В нашем контроллере в резерве остаётся примерно 32 кБ. А нужно больше, по максимуму 31 инструмент * 128 кБ сэмплов = 4 МБ. Но это лишний корпус, и контроллер менять на 100-ногий с FSMC… Лениво как-то. Лучше по максимуму задействуем имеющиеся ресурсы (в том числе ресурсы головного мозга).

В Траксмоде поступили проще — если инструмент не лезет в память — нафик его. Подумаешь, из целого оркестра выкинуть дырявый барабан и пару сломанных скрипок. Ну а вдруг это была главная партия или сольное выступление? Нее, такой подход не годится.

Поэтому придётся насиловать карту памяти: считаем в ОЗУ сколько сможем, а что не поместится, будем по мере необходимости читать с карты SD.

На первый взгляд, скорости работы файловой системы для прямого чтения сэмплов хватает с трёхкратным запасом. Однако помимо чтения, контроллеру нужно будет постоянно сэмплировать, микшировать и применять эффекты. Кроме того, хорошая скорость чтения обеспечивается только при последовательном считывании сразу нескольких страниц. Проверено — при прямой реализации декодер не справляется, слишком много времени уходит на поиск нужной страницы. Приходится изголяться.

Итак, свободную память микроконтроллера будем делить между:
  • двумя буферами данных для ЦАП (как в MP3-проигрывателе);
  • несколькими страницами кэш-памяти;
  • в оставшееся пространство полностью поместим самые короткие сэмплы.

Ну и конечно нужно будет хранить служебную информацию об инструментах, паттернах и плей-листе.

Чтение сэмплов будет выполняться не напрямую через драйвер FatFs, а посредством программно реализованной кэш-памяти (в виде драйвера-прослойки). Кэш может работать следующим образом:
  • если в памяти есть нужный байт, то он возвращается без участия файловой системы;
  • если нужного байта нет, с карты памяти читается целая страница; причём, после выдачи нужного байта можно запустить фоновый процесс чтения ещё нескольких следующих страниц. Вот здесь по полной можно использовать возможности DMA (интерфейс SD) и многозадачной операционной системы CoOS;
  • имеет смысл реализовать упреждающее чтение файла на основе статистики запроса данных из кэша. В этом случае мы снова экономим ресурсы микроконтроллера посредством доступа к SD при помощи аппаратного DMA.

Последовательность считывания сэмплов при проигрывании MOD практически непредсказуемая. Поэтому выбор алгоритма работы кэша и процентное распределение памяти между буфером ЦАП/кэшем/резидентной областью сэмплов определяется опытным путём.

Не утомил? Остальной код проигрывателя предоставляется для самостоятельного изучения.

Практические испытания

Поиграем в простенький MOD-файл (sample1.mod в архиве с проектом). Основные параметры:
  • размер 18442 байт
  • инструментов 16;
  • размер области сэмплов 3022 байт.
Играет!!!

Суммарная загрузка контроллера:

50% для такого файла это слишком много. Попробуем оптимизировать декодер.
Исходные параметры:
резидентное хранение сэмплов в памяти не используется;
количество кэш-страниц: 1;
размер кеш-страницы: 512 байт.

За каждым новым сэмплом декодер лезет в карту памяти. Добавим ещё страниц:
резидентное хранение сэмплов в памяти не используется;
количество кэш-страниц: 4;
размер кеш-страницы: 512 байт.


Количество обращений к карте памяти сократилось, загрузка существенно уменьшилась.

А если хранить сэмплы полностью в памяти?

Отлично, менее 20%. Всплески соответствуют обращению к карте памяти за паттернами.

Теперь запустим более серьёзный файл (sample2.mod)
  • размер 184964 байт
  • инструментов 24;
  • размер области сэмплов 137800 байт.
Все сэмплы поместить в RAM уже не получится. Параметры эксперимента:
резидентное хранение сэмплов в памяти не используется;
количество кэш-страниц: 4;
размер кеш-страницы: 512 байт.


Справляется, но запас небольшой. Семплы длинные, воспроизводятся с высокой частотой дискретизации — соответственно увеличивается нагрузка на карту SD.

А если всю доступную память заполнить самыми короткими сэмплами? Результат налицо:


Выводы
STM32F105 неплохо справляется с проигрыванием трекерной музыки. Но загрузка контроллера сильно зависит от её характера. Лимитирующим параметром является размер свободной памяти RAM. Недостаток оперативной памяти приходится компенсировать частым обращением к карте SD. Соответственно, скорость доступа/чтения должна быть максимально возможной.
В отличие от декодера MP3, здесь нет понятия требуемого размера RAM: чем больше, тем лучше.

TODO
  • осталась нереализованной линейная интерполяция; с ней звук должен быть немного мягче и приятнее;
  • не реализован интересный эффект Arpeggio (быстрая смена трёх нот);
  • довольно много музыки хранится в формате XM (расширение MOD`а); можно реализовать и его поддержку; однако потребуется другой (более мощный) контроллер (407-й например).



Оглавление
Программный декодер MP3 на STM32F10x. Демопроект (Введение)
Программный декодер MP3 на STM32F10x. Часть 2. Запуск ЦАП
Программный декодер MP3 на STM32F10x. Часть 3. Извлекаем звуки
Программный декодер MP3(+MOD) на STM32F10x. Часть 4. Трекерная музыка
Программный декодер MP3(+). Переход на платформу STM32F407

  • +23
  • 05 октября 2013, 20:16
  • MikeSmith
  • 4

Комментарии (13)

RSS свернуть / развернуть
«Проект на ATmega16. Кроме исходников больше информации не наблюдается.»
Хаха, автор — я :)
Писалось это 2 месяца, есть небольшие невыловленные баги. Зато играет 37кГц на частоте 19МГц, используется линейная интерполяция. Код годен не только для Атмеги16, но и на мегах с флэшем >64кБ. Там условная компиляция.
К сожалению, асм, увы. Вылизано по тактам. Любую внешнюю память подключить невозможно, ибо не влазит в быстродействие без значительной потери в качестве.
В данный момент я разрабатываю прошивку для проигрывания 32-канальных ХМ для СТМ32Ф4хх, 168МГц. В этот раз на С. Рабочий цикл микширования звука с линейной интерполяцией и панорамированием готов, по тактам влазит до 48 каналов.
Сорцы открыты, если вдруг кому-нить понадобятся.
+3
  • avatar
  • TSL
  • 05 октября 2013, 22:14
«Респект» и «уважуха» ассемблерописателям! А по поводу XM — это может быть темой следующей статьи. Можем объединить усилия и представить сообществу доступный (для понимания и повторения) проигрыватель.
0
Можем. Правда писатель статей из меня плохой.
0
Хорошо написано, читается с интересом.
+6
  • avatar
  • EW1UA
  • 06 октября 2013, 12:25
Думаю, мало кто знаком с понятием «трекерная музыка»
Как раз наоборот, я думаю, что многие тут как раз хорошо знакомы с этим понятием. :) А некоторые даже и музицировать пытались. :)

Под PC во времена DOS ещё были тракерный Cubic Player, и редактор Fasttracker2…
+1
оу, modplug, а плеер ещё и *.umx играл…
+1
umx — это те же самые xm и it.
(offtop) умели же игры делать (/offtop)
0
я тоже удивился про "мало кто знаком". причём я-то ваще молодой, можно сказать, в этом отношении: первый комп — целка-700, до этого тупо сега была.
ТС — респект, годноту нереальную запилил!
0
:-) Согласен, утверждение немного спорное, особенно для людей из Сообщества. Однако фраза подогревает интерес и настраивает читателя на благоприятную волну, поэтому оставлю как есть…
0
Предполагаю, что дело не в старости и не в молодости, а в области интересов, в «области определения», откуда следует и «область значений».
Вот я хоть и не стар, а супер стар ;-) ; но и не молод — данная область мне совершенно незнакома, хоть и весьма любопытна.
Первый мой компьютер — «Электроника БК 0010‑01», из писи́шек — P54C‑200 на плате ASUS TX‑97 в 1997 году.
+1
Вы очень круто пишете!
+2
Эта музыка навсегда останется в моём сердце :)
0
  • avatar
  • Kasym
  • 12 октября 2013, 15:16
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.