
Un lecteur C++ sans dépendance pour les sonneries Yamaha SMAF (.mmf) : le format polyphonique des puces téléphoniques MA-3 / MA-5 des années 2000, reconstruit avec son propre moteur FM sans ROM. Le lecteur ouvert que personne n'a terminé. Prouvé dans FXChainPlayer.
par Akustikrausch (Andreas Wendorf)
un petit lecteur de sonneries Yamaha SMAF (.mmf) en C++, sans dépendances.
vous lui donnez un de ces fichiers qui faisaient deedle-deedle-dee sur votre
Samsung, Sharp ou Panasonic en 2004, et il vous restitue un audio stéréo propre.
pas de téléphone, pas de firmware, pas de ROM d'échantillons. juste la puce FM,
reconstruite en logiciel.
c'est le son de toute une décennie que presque personne n'a pris la peine de préserver en code ouvert. il y a des millions de ces fichiers qui traînent encore, et personne n'a jamais terminé un lecteur ouvert pour eux : les tentatives ont calé en 2004 ou contournent complètement le synthétiseur. alors voici un en C++, écrit depuis le format, avec son propre cœur de synthèse FM.
🎧 ce code est livré dans un vrai produit : FXChainPlayer. un lecteur audio Windows natif qui joue vos vieilles sonneries à côté de vos FLAC, SID et modules Amiga. c'est là que ce moteur tourne tous les jours, sur un corpus de centaines de sonneries réelles de téléphones. prenez le lecteur pour simplement écouter, ou lisez la suite pour comprendre comment la puce fonctionne.
la série Yamaha MA (YMU762 = MA-3, YMU765 = MA-5) était la puce sonore
d'une grande partie des téléphones du début des années 2000. c'est un véritable
synthétiseur FM, un proche cousin des puces OPL/OPN de l'ère Adlib et Sega
Genesis, miniaturisé pour un mobile. les fichiers qu'elle lisait, SMAF
(.mmf), transportent une partition FM plus des échantillons ADPCM optionnels.
la sonnerie polyphonique est née ici.
puis les smartphones sont arrivés, les sonneries MP3 ont pris le dessus, et tout le format est mort tranquillement. Yamaha a retiré son SDK. et contrairement aux scènes Amiga ou C64, presque personne n'a écrit d'émulateur. ce qui existe :
umjammer/vavi-sound (Java) parse et joue du SMAF, et c'est une référence
comportementale brillante, mais il ne fait aucune synthèse FM : il ré-emballe
les sonorités en General MIDI et laisse le synthétiseur Java les approximer.
et c'est du Java.donc un lecteur natif, sous licence permissive et sans ROM, de la véritable puce FM n'existait pas. voici ce lecteur. chaque octet du parseur et chaque opérateur du synthétiseur ont été écrits à partir de la description publique du format SMAF, plus beaucoup d'observation de fichiers réels dans un éditeur hexadécimal, jamais en copiant un autre lecteur.
le moteur est composé de cinq petites pièces, chacune testable indépendamment :
src/
smaf_file le conteneur MMMD : chunks TLV big-endian (CNTI/OPDA/MTR/ATR),
deux générations de partition (HandyPhone pour MA-1/2, Mobile pour MA-3/5)
ma_player les deux décodeurs d'événements (+ Huffman d'Okumura pour la
variante compressée), un ordonnanceur qui fonctionne en millisecondes
comme la puce, et la boucle de rendu qui pilote un pool de voix FM
ma_fm_core le DSP FM : opérateurs 2-op et 4-op, enveloppes ADSR exponentielles,
les algorithmes de connexion de type OPL, et sa propre banque de patches
approximant le General MIDI
smaf_voice décode les blocs sysex de voix Yamaha (VM35 pour MA-3/5, VMA pour
MA-1/2) en patches FM, y compris la forme compressée au niveau du bit du MA-3
yamaha_adpcm le codec ADPCM 4 bits de la famille YM2608, pour les voix échantillonnées
le modèle temporel est la bonne surprise : SMAF n'a pas d'événements de tempo, le temps est purement métrique (temps d'événement = somme des durées multipliée par une base de temps, en millisecondes), donc un tick correspond directement à une milliseconde puis à des échantillons. le cœur FM tourne directement à votre taux de sortie, donc il n'y a pas de rééchantillonnage sur le chemin de la synthèse.
les puces MA embarquaient également une petite ROM d'échantillons General MIDI pour qu'une sonnerie puisse dire « joue le programme 5 » et obtenir un piano prédéfini. cette ROM appartient à Yamaha, elle n'a jamais été dumpée publiquement, et ce projet ne la fournit pas, n'en veut pas, et ne l'inclura jamais. c'est une ligne rouge.
à la place, ma_fm_core contient sa propre banque de patches FM construite à
la main qui se substitue à la ROM : un fichier qui demande « programme 5 »
obtient une voix FM plausible de la bonne famille. Ce ne sera pas bit à bit
identique à un téléphone de 2003, et c'est le compromis honnête. Ce que vous
obtenez, c'est la vraie partition FM, le vrai timing des notes, la vraie ADSR,
jouées par un synthétiseur qui lui est propre. Reconnu, et ça joue.
Les fichiers qui transportent leurs propres voix personnalisées (beaucoup le font) sonnent exactement comme prévu, car ces voix résident dans le fichier, pas dans la ROM.
cmake -B build && cmake --build build
./build/smaf-render votre_sonnerie.mmf out.wav 30
ou intégrez la bibliothèque dans votre propre code :
#include "smaf_file.h"
#include "ma_player.h"
using namespace fxchain::smaf;
SmafFile file;
file.parse(bytes.data(), bytes.size()); // conteneur MMMD
MaPlayer player;
player.init(file, 44100); // construit les voix + décode la partition
float buf[1024 * 2]; // stéréo entrelacée
int frames = player.render(buf, 1024); // pompe le synthétiseur
43 79 06 7F 03) dans lequel
quelques fichiers de pur kit de batterie transportent leurs échantillons ; et
les formes d'onde supérieures spécifiques au SD-1. voir
ROADMAP.md..mld) (un cousin ; voir
ROADMAP.md m3).ce parseur est destiné à consommer des fichiers non fiables, donc il est écrit de manière défensive : chaque longueur de chunk est bornée au tampon réel, le dégonflage Huffman a des gardes de nœud+profondeur et un plafond de sortie, et les décodeurs d'événements ont des limites d'itération et d'événements totaux. Il dégrade en « pas un fichier SMAF valide » plutôt que de planter. Détails et signalement dans SECURITY.md.
src/ le moteur (quatre petites unités de traduction plus un codec header-only,
sans dépendances). example/smaf-render.cpp le CLI WAV en moins de 100 lignes.
CMakeLists.txt construit une lib statique smaf plus l'exemple. C'est tout.
Apache License 2.0 (voir LICENSE). le parseur et le synthétiseur sont un travail original ; aucun code tiers n'est fourni, et aucun matériel ROM ou SDK Yamaha n'est inclus. La connaissance du format provient de la spécification publique SMAF et de l'observation.
non affilié à, autorisé par, ou approuvé par Yamaha. « SMAF » et les noms des puces MA appartiennent à Yamaha. C'est un travail d'interopérabilité : un lecteur indépendant d'un format de fichier ouvert, construit sans aucun code Yamaha ni la ROM d'échantillons protégée.
grüße à tous ceux qui se rappellent encore de quoi ressemblait leur sonnerie.