
مشغل C++ خالٍ من التبعيات لنغمات الرنين Yamaha SMAF (.mmf): تنسيق نغمات الرنين متعددة الأصوات لرقاقات الهواتف MA-3/MA-5 من العقد الأول من القرن الحادي والعشرين، أعيد بناؤه بمحرك FM خاص به خالٍ من ROM. المشغل المفتوح الذي لم يكمله أحد. مثبت في FXChainPlayer.
بواسطة Akustikrausch (Andreas Wendorf)
مشغل صغير خالٍ من التبعيات لنغمات الرنين SMAF من ياماها (.mmf) بلغة C++.
تسلمه أحد تلك الملفات التي جعلت هاتفك من سامسونج أو شارب أو باناسونيك يصدر صوت
ديدل-ديدل-دي في عام 2004، ويُخرج لك صوتًا ستيريو نظيفًا. لا هاتف، لا
برامج ثابتة، لا روم عينات. فقط شريحة FM، معاد بناؤها برمجيًا.
هذا هو صوت عقد كامل لم يكلف أحد تقريبًا عناء الحفاظ عليه في كود مفتوح. لا تزال الملايين من هذه الملفات طافية في الأرجاء، ولم يُكمل أحد أبدًا مشغلاً مفتوحًا لها: المحاولات توقفت في عام 2004 أو دارت حول المُركّب بالكامل. لذا ها هو واحد بلغة C++، مكتوب بدءًا من التنسيق صعودًا، مع نواة تركيب FM خاصة به.
🎧 هذا الكود يُشحن في منتج حقيقي: FXChainPlayer. مشغل صوتي أصلي لويندوز يشغل نغمات رنينك القديمة بجوار ملفات FLAC، وSID، ووحدات Amiga. هذا هو المكان الذي يعمل فيه هذا المحرك يوميًا، على مجموعة من مئات نغمات الهواتف الحقيقية. احصل على المشغل للاستماع فقط، أو تابع القراءة لمعرفة كيف تعمل الشريحة.
سلسلة MA من ياماها (YMU762 = MA-3، YMU765 = MA-5) كانت شريحة الصوت داخل
شريحة ضخمة من هواتف أوائل العقد الأول من القرن الحادي والعشرين. إنها مُركّب FM حقيقي،
قريب من رقائق OPL/OPN من عصر Adlib وSega Genesis، مُصغَّر ليلائم
الهاتف. الملفات التي شغّلتها، SMAF (.mmf)، تحمل مقطوعة FM بالإضافة إلى
عينات ADPCM اختيارية. نغمة الرنين متعددة الأصوات وُلدت هنا.
ثم وصلت الهواتف الذكية، وحلت نغمات الرنين MP3 محلها، ومات التنسيق بأكمله بهدوء. ياماها أزالت حزمة التطوير الخاصة بها من الإنترنت. وعلى عكس مشاهد Amiga أو C64، لا أحد تقريبًا كتب محاكيًا. ما هو موجود:
umjammer/vavi-sound (Java) يحلل ويشغل SMAF، وهو مرجع سلوكي رائع،
لكنه لا يقوم بتركيب FM على الإطلاق: يعيد تغليف النغمات كـ MIDI عام
ويجعل مُركّب Java يُقاربها. وهو Java.لذا، مشغل أصليّ، بترخيص متساهل، وخالٍ من الروم لشريحة FM الفعلية لم يكن موجودًا. هذا هو. كل بايت من المحلل وكل مُشغّل من المُركّب كُتب من وصف تنسيق SMAF العام بالإضافة إلى الكثير من التحديق في الملفات الحقيقية في محرر سداسي، ولم يتم أبدًا بنسخ مشغل آخر.
المحرك يتكون من خمس قطع صغيرة، كل واحدة قابلة للاختبار بمفردها:
src/
smaf_file حاوية MMMD: أجزاء TLV كبيرة النهاية (CNTI/OPDA/MTR/ATR)،
جيلين من المقطوعات (HandyPhone لـ MA-1/2، Mobile لـ MA-3/5)
ma_player مفككا الأحداث (+ تشفير هوفمان Okumura للنسخة المضغوطة)،
ومجدول يعمل بالميلي ثانية كما فعلت الشريحة،
وحلقة العرض التي تُحرك مجموعة من أصوات FM
ma_fm_core معالج FM الرقمي: مؤثرات ثنائية ورباعية المشغل، أغلفة ADSR أسية،
خوارزميات التوصيل على نمط OPL، ومجموعة الأصوات التقريبية
الخاصة به لـ MIDI العام
smaf_voice يفك تشفير كتل sysex للصوت من ياماها (VM35 لـ MA-3/5، VMA لـ
MA-1/2) إلى أصوات FM، بما في ذلك الشكل المضغوط بتاتًا لـ MA-3
yamaha_adpcm برنامج الترميز ADPCM 4-بت من عائلة YM2608، للأصوات المأخوذة من عينات
نموذج التوقيت هو المفاجأة السارة: SMAF لا يحتوي على أحداث إيقاع، الوقت زمني بحت (وقت الحدث = مجموع المدد مضروبًا في قاعدة زمنية، بالميلي ثانية)، لذا فإن النبضة الواحدة تُرسم مباشرة إلى ميلي ثانية واحدة ثم إلى عينات. نواة FM تعمل بمعدل خرجك مباشرة، لذا لا توجد إعادة أخذ عينات في مسار المُركّب.
رقائق MA حملت أيضًا روم عينات MIDI عام صغير حتى يمكن لنغمة الرنين أن تقول "شغّل البرنامج 5" وتحصل على بيانو مُعدّ مسبقًا. هذا الروم هو ملك ياماها، لم يُفرغ علنًا أبدًا، وهذا المشروع لا يُشحنه، ولا يريده، ولن يضمّه أبدًا. هذا خط أحمر.
بدلاً من ذلك، يحمل ma_fm_core مجموعة أصوات FM مبنية يدويًا خاصة به تحل محل
الروم: ملف يطلب "البرنامج 5" يحصل على صوت FM معقول من العائلة الصحيحة.
لن يكون مطابقًا للبتات بهاتف عام 2003، وهذه هي المقايضة الصادقة. ما تحصل عليه هو مقطوعة FM الحقيقية،
توقيت النوتات الحقيقي، وADSR الحقيقي، يعزفها مُركّب خاص به. معترف به، ويشغل.
الملفات التي تحمل أصواتًا مخصصة خاصة بها (الكثير منها يفعل ذلك) تبدو تمامًا كما أُلفت، لأن تلك الأصوات موجودة في الملف، وليس في الروم.
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 واجهة سطر الأوامر WAV في أقل من 100 سطر.
CMakeLists.txt يبني مكتبة smaf ثابتة بالإضافة إلى المثال. هذا هو كل شيء.
ترخيص Apache 2.0 (انظر LICENSE). المحلل والمُركّب عمل أصلي؛ لا توجد كودات طرف ثالث مُضمَّنة، ولا يتم تضمين أي مواد من روم ياماها أو حزمة التطوير. المعرفة بالتنسيق جاءت من مواصفات SMAF العامة والملاحظة.
غير تابع أو مصرح به أو معتمد من ياماها. "SMAF" وأسماء رقائق MA هي ملك ياماها. هذا عمل توافق: مشغل مستقل لتنسيق ملف مفتوح، مبني بدون أي كود ياماها أو روم العينات المحمي.
تحياتي لكل من لا يزال يتذكر كيف كانت تبدو نغمته.