
Беззависимостный C++ ПЛЕЕР для рингтонов Yamaha SMAF (.mmf): полифонический формат рингтонов чипов телефонов MA-3/MA-5 2000-х годов, пересобранный с собственным FM-движком без ROM. Открытый плеер, который никто не завершил. Проверен в FXChainPlayer.
от Akustikrausch (Andreas Wendorf)
маленький, не зависящий от зависимостей плеер для рингтонов Yamaha SMAF (.mmf) на C++.
Вы передаёте ему один из тех файлов, которые заставляли ваш Samsung, Sharp или Panasonic издавать
deedle-deedle-dee в 2004 году, а он выдаёт чистый стереозвук. Ни телефона, ни
прошивки, ни семплового ROM. Только FM-чип, воссозданный в программном обеспечении.
Это звук целого десятилетия, которое почти никто не удосужился сохранить в открытом коде. Миллионы таких файлов до сих пор гуляют по просторам, и никто так и не завершил открытый плеер для них: попытки остановились в 2004 году или обходят синтезатор стороной. Так что вот он, на C++, написанный с нуля на основе формата, с собственным ядром FM-синтеза.
🎧 этот код поставляется в реальном продукте: FXChainPlayer. нативный аудиоплеер для Windows, который воспроизводит ваши старые рингтоны рядом с FLAC, SID и модулями Amiga. Именно здесь этот движок работает каждый день, на корпусе из сотен реальных тонов мобильных телефонов. Загрузите плеер, чтобы просто послушать, или читайте дальше, чтобы узнать, как работает чип.
Серия Yamaha MA (YMU762 = MA-3, YMU765 = MA-5) была звуковым чипом внутри
огромного количества телефонов начала 2000-х. Это полноценный FM-синтезатор, близкий родственник
чипов OPL/OPN эпохи Adlib и Sega Genesis, уменьшенный для
мобильного телефона. Файлы, которые он воспроизводил, SMAF (.mmf), содержат FM-партитуру плюс опциональные
ADPCM-сэмплы. Полифонический рингтон родился здесь.
Затем появились смартфоны, рингтоны в формате MP3 захватили рынок, и весь формат тихо умер. Yamaha убрала свой SDK из открытого доступа. И в отличие от сцен Amiga или C64, почти никто не написал эмулятор. Что существует:
umjammer/vavi-sound (Java) разбирает и воспроизводит SMAF, и это блестящий
поведенческий референс, но он вообще не занимается FM-синтезом: он переупаковывает
тона как General MIDI и позволяет синтезатору Java аппроксимировать их. И это Java.Таким образом, нативного, с разрешительной лицензией, не требующего ROM плеера настоящего FM-чипа не существовало. Вот он. Каждый байт парсера и каждый оператор синтезатора были написаны на основе публичного описания формата SMAF плюс долгого вглядывания в реальные файлы в hex-редакторе, и никогда не копированием другого плеера.
Движок состоит из пяти маленьких частей, каждую из которых можно тестировать отдельно:
src/
smaf_file контейнер MMMD: TLV-чанки с прямым порядком байт (CNTI/OPDA/MTR/ATR),
два поколения партитур (HandyPhone для MA-1/2, Mobile для MA-3/5)
ma_player два декодера событий (+ хаффман Окумуры для упакованного
варианта), планировщик, работающий в миллисекундах, как и чип,
и цикл рендеринга, управляющий пулом FM-голосов
ma_fm_core DSP FM: 2-операторные и 4-операторные операторы, экспоненциальные огибающие ADSR,
алгоритмы соединений в стиле OPL и собственная аппроксимированная
библиотека патчей General MIDI
smaf_voice декодирует блобы sysex голосов Yamaha (VM35 для MA-3/5, VMA для
MA-1/2) в FM-патчи, включая упакованную по битам форму MA-3
yamaha_adpcm кодек 4-бит ADPCM семейства YM2608 для семплированных голосов
Модель синхронизации — приятный сюрприз: в SMAF нет событий темпа, время чисто метрическое (время события = сумма длительностей, умноженная на временную базу, в миллисекундах), поэтому один тик соответствует одной миллисекунде, а затем — сэмплам. Ядро FM работает напрямую с вашей выходной частотой дискретизации, так что передискретизации на пути синтеза нет.
Чипы MA также содержали небольшой ROM семплов General MIDI, чтобы рингтон мог сказать «сыграй программу 5» и получить предустановленное фортепиано. Этот ROM принадлежит Yamaha, он никогда не был публично снят, и этот проект не содержит его, не хочет его и никогда не будет встраивать. Это жёсткая граница.
Вместо этого ma_fm_core содержит собственную библиотеку FM-патчей, созданную вручную, которая заменяет
ROM: файл, запрашивающий «программу 5», получает правдоподобный FM-голос соответствующего
семейства. Это не будет побитово идентично телефону 2003 года, и это честный
компромисс. То, что вы получаете, — это настоящая FM-партитура, настоящая синхронизация нот, настоящая
ADSR, воспроизведённые собственным синтезатором. Узнаваемо, и оно играет.
Файлы, которые содержат собственные пользовательские голоса (их много), звучат точно так, как задумано, потому что эти голоса хранятся в файле, а не в ROM.
cmake -B build && cmake --build build
./build/smaf-render your_ringtone.mmf out.wav 30
или подключите библиотеку к своему коду:
#include "smaf_file.h"
#include "ma_player.h"
using namespace fxchain::smaf;
SmafFile file;
file.parse(bytes.data(), bytes.size()); // контейнер MMMD
MaPlayer player;
player.init(file, 44100); // построить голоса + декодировать партитуру
float buf[1024 * 2]; // чередующееся стерео
int frames = player.render(buf, 1024); // запустить синтезатор
43 79 06 7F 03), в которых несколько чистых
файлов ударных наборов хранят свои сэмплы; и волновые формы высшего порядка, специфичные для SD-1. См.
ROADMAP.md..mld) (двоюродный брат; см.
ROADMAP.md m3).Этот парсер предназначен для обработки ненадёжных файлов, поэтому он написан с защитой: каждая длина чанка ограничена реальным буфером, распаковка Хаффмана имеет защиту узлов + глубины и потолок вывода, а декодеры событий имеют ограничения на итерации и общее количество событий. При ошибке он выводит «не является допустимым файлом SMAF» вместо падения. Подробности и отчётность в SECURITY.md.
src/ — движок (четыре маленьких файла трансляции плюс заголовочный кодек, без
зависимостей). example/smaf-render.cpp — CLI для WAV менее чем в 100 строк. CMakeLists.txt
собирает статическую библиотеку smaf плюс пример. Это всё.
Apache License 2.0 (см. LICENSE). Парсер и синтезатор являются оригинальной работой; сторонний код не включён, и никакой ROM от Yamaha или SDK-материал не содержится. Знание формата получено из публичной спецификации SMAF и наблюдений.
Не аффилировано, не авторизовано и не одобрено компанией Yamaha. «SMAF» и названия чипов MA являются торговыми марками Yamaha. Это работа по обеспечению совместимости: независимый плеер открытого файлового формата, созданный без какого-либо кода Yamaha или защищённого семплового ROM.
привет всем, кто до сих пор помнит, как звучал их рингтон.