
Yamaha SMAF (.mmf) 벨소리를 위한 의존성 없는 C++ 플레이어: 2000년대 MA-3 / MA-5 휴대폰 칩의 폴리포닉 벨소리 포맷이며, 자체 ROM 없는 FM 엔진으로 재구축되었습니다. 아무도 완성하지 못한 오픈 플레이어. FXChainPlayer에서 검증됨.
by Akustikrausch (Andreas Wendorf)
작고 의존성이 없는 Yamaha SMAF 벨소리(.mmf)용 C++ 플레이어입니다.
2004년에 여러분의 삼성, 샤프, 파나소닉 폰에서 띵띠리링 소리를 냈던 그 파일을 넘기면,
깨끗한 스테레오 오디오를 반환합니다. 전화기도, 펌웨어도, 샘플 ROM도 필요 없습니다.
소프트웨어로 재구성된 FM 칩만 있으면 됩니다.
이것은 거의 아무도 오픈 코드로 보존하려고 애쓰지 않은 한 시대의 소리입니다. 이런 파일은 아직도 수백만 개가 떠돌아다니고 있지만, 그 누구도 이들을 위한 오픈 플레이어를 완성하지 못했습니다: 시도는 2004년에 멈추거나, 합성기를 우회하는 데 그쳤습니다. 그래서 여기에 포맷부터 다시 작성하고 자체 FM 합성 코어를 탑재한 C++ 플레이어가 있습니다.
🎧 이 코드는 실제 제품인 FXChainPlayer에 탑재되어 있습니다. 네이티브 윈도우 오디오 플레이어로, 오래된 벨소리를 FLAC, SID, Amiga 모듈과 함께 재생합니다. 이 엔진은 매일 수백 개의 실제 핸드셋 톤 코퍼스를 대상으로 실행됩니다. 그냥 듣고 싶다면 플레이어를 받아가세요. 칩이 어떻게 동작하는지 알고 싶다면 계속 읽어보세요.
Yamaha MA 시리즈(YMU762 = MA-3, YMU765 = MA-5)는 2000년대 초반 휴대폰의 상당수에 탑재된 사운드 칩이었습니다.
이는 Adlib 및 Sega Genesis 시대의 OPL/OPN 칩과 가까운 친척인 적절한 FM 신시사이저로, 핸드셋용으로 축소된 것입니다.
이 칩이 재생한 파일, SMAF(.mmf)는 FM 악보와 옵션으로 ADPCM 샘플을 포함합니다.
다성 벨소리는 여기서 탄생했습니다.
그러다 스마트폰이 등장하고 MP3 벨소리가 자리 잡으면서 이 포맷은 조용히 사라졌습니다. Yamaha는 SDK를 내렸습니다. Amiga나 C64 씬과 달리, 에뮬레이터를 작성한 사람은 거의 없었습니다. 현존하는 것은:
umjammer/vavi-sound(Java)는 SMAF를 파싱하고 재생하며, 뛰어난 행동 참조 역할을 하지만 FM 합성을 전혀 하지 않습니다: 톤을 일반 MIDI로 다시 감싸서 Java의 신시사이저가 근사하도록 합니다. 게다가 Java입니다.따라서 네이티브이며 허용적인 라이선스의 ROM이 필요 없는 실제 FM 칩 플레이어는 존재하지 않았습니다. 이것이 바로 그 플레이어입니다. 파서의 모든 바이트와 합성기의 모든 오퍼레이터는 공개 SMAF 포맷 설명서와 실제 파일을 헥스 에디터로 오래 들여다본 결과물로 작성되었으며, 다른 플레이어를 복사한 적이 없습니다.
엔진은 다섯 개의 작은 조각으로 구성되어 있으며, 각각 독립적으로 테스트할 수 있습니다:
src/
smaf_file MMMD 컨테이너: 빅엔디안 TLV 청크 (CNTI/OPDA/MTR/ATR),
두 가지 악보 세대 (HandyPhone for MA-1/2, Mobile for MA-3/5)
ma_player 두 가지 이벤트 디코더 (+ 압축 변형을 위한 오쿠무라 허프만),
칩과 마찬가지로 밀리초 단위로 실행되는 스케줄러,
FM 음성 풀을 구동하는 렌더 루프
ma_fm_core FM DSP: 2-op 및 4-op 오퍼레이터, 지수 ADSR 엔벨로프,
OPL 스타일 연결 알고리즘, 자체 일반 MIDI 근사 패치 뱅크
smaf_voice Yamaha 음성 sysex 블롭 (MA-3/5용 VM35, MA-1/2용 VMA)을
FM 패치로 디코딩, MA-3 비트 압축 형식 포함
yamaha_adpcm YM2608 계열 4비트 ADPCM 코덱, 샘플 음성용
타이밍 모델은 좋은 놀라움입니다: SMAF에는 템포 이벤트가 없으며, 시간은 순전히 미터법(이벤트 시간 = 지속 시간 합계 * 타임베이스(밀리초))이므로, 1틱이 1밀리초에 직접 매핑되고 샘플로 이어집니다. FM 코어는 출력 레이트에서 직접 실행되므로 합성 경로에 리샘플링이 없습니다.
MA 칩에는 또한 작은 일반 MIDI 샘플 ROM이 탑재되어 있어, 벨소리가 "프로그램 5 재생"을 지시하면 미리 설정된 피아노를 얻을 수 있었습니다. 이 ROM은 Yamaha 소유이며 공개적으로 덤프된 적이 없으며, 이 프로젝트는 이를 제공하지도, 원하지도, 번들로 포함하지도 않습니다. 이것은 엄격한 경계선입니다.
대신, ma_fm_core는 ROM을 대신할 자체 수제 FM 패치 뱅크를 탑재합니다:
"프로그램 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/ 엔진 (4개의 작은 번역 단위와 헤더 전용 코덱, 의존성 없음).
example/smaf-render.cpp 100줄 미만의 wav CLI. CMakeLists.txt는 정적 smaf 라이브러리와 예제를 빌드합니다.
이게 전부입니다.
Apache License 2.0 (LICENSE 참조). 파서와 합성기는 독창적인 작업입니다; 서드파티 코드는 벤더링되지 않았으며, Yamaha ROM 또는 SDK 자료는 포함되지 않았습니다. 포맷 지식은 공개 SMAF 사양과 관찰에서 비롯되었습니다.
Yamaha와 제휴, 승인 또는 보증되지 않았습니다. "SMAF" 및 MA 칩 이름은 Yamaha의 상표입니다. 이는 상호 운용성 작업입니다: Yamaha 코드나 보호된 샘플 ROM 없이 구축된 개방형 파일 포맷의 독립적인 플레이어입니다.
자신의 벨소리가 어떻게 들렸는지 아직도 기억하는 모든 분들께 인사를 전합니다.