All right, stop, collaborate and listen
Before you dive into writing your own firmware, or adding the next feature to your existing firmware, please read this, it may save you a lot of time and frustration.
First up, I'm not trying to discourage anyone - build the firmware, learn the thing, get your ideas out there. I'm not trying to call anyone out, not saying this for clout, karma, or whuffies - I just want people to know this stuff. Hopefully someone with more spare time than me will start a wiki (the easy part) and drive enough engagement there (the hard part) that it becomes a single point where people can share, correct, and expand on this kind of info, but 'til then:
CMake and Ninja ara a pair of excellent build tools. Use them! Your agent knows how to maintain CMake configurations with far less effort and potential confusion than the custom build.py it might offer to create for you.
The JieLi AC7911B8 MCU at the heart of the FM-1 / SMK-37 has a hardware floating point unit. You may still get better performance using integers, but you'd be mad not to enable it with the compiler switches "-mcpu=r3 -mfprev1". M-VAVE's open firmware gives you a good starting point for the compiler switches: github.com/m-vave/fm1_open/blob/4c7496daac04a95ff…
You might as well try out their linker switches too: github.com/m-vave/fm1_open/blob/4c7496daac04a95ff…
If you are using integers, sometimes you'll need 64 bits in the middle of a calculation, but the final result fits into 32 bits. Try to avoid storing the 64 bit values to actual variables - that way the compiler knows it can throw away certain data, and generates much more efficient assembly for the MCU:
int32_t bad_fn(int32_t a, int32_t b, int32_t c) {
int64_t acc = (int64_t)a * b;
acc = (acc >> 16) * c;
return (int32_t)(acc >> 16);
}
int32_t good_fn(int32_t a, int32_t b, int32_t c) {
int32_t step1 = (int32_t)(((int64_t)a * b) >> 16);
return (int32_t)(((int64_t)step1 * c) >> 16);
}
Likewise, multiplications are faster than divisions. So if you find yourself dividing by a constant (or infrequently changed) value one or more times per frame of audio, maybe calculate inv_const = 1/const at startup, then your code can just multiply by inv_const.
Not everything needs to be optimised the same way. Back to compiler switches: when you're trying to pack the 22nd synth engine into your kitchen-sink firmware, blanket size optimisations like "-Os" or "-Oz" can seem attractive, but can quickly kill performance. The key is to be selective - try to arrange your files so all your hot loop code (anything that runs one or more times per frame of audio) is kept separate from the code that runs less frequently. Apply "-O2" to the hot code, and "-Os" or "-Oz" for everything else.
Think about what really needs to be in the per-frame loop too. Some values might not change that much over time, so you can get away with only calculating them once every 32 frames, 64 frames, or 128 frames. Even where the value does need to change from one frame to the next, you might get away with only doing the heavyweight version of the calculation once per block of frames, then running a fast, per-frame linear interpolation.
Take care about where that hot code runs from. Ideally you want it sitting in SRAM permenantly rather than executing in place from the NOR flash. XiP sounds like a great deal until your otherwise lightly loaded system starts having buffer underruns because a background process on the other core was fetching some data from flash. If you've got so many complex sound engines they won't all fit in SRAM at once, and you're feeling spicy, you might like to create little loading harness, reserve some space in SRAM, and load the current engine code into it at runtime.
Speaking of cores - use them both, overclock them to 360MHz, increase the voltage the same way M-VAVE does, expect the same level of reliability as the stock ROM. This isn't a gaming PC with a BIOS that gives you the freedom to fry the CPU if it's not cooled with liquid nitrogen. It's a mass-market MCU where the biggest concern from increasing the voltage is decreased battery life.
Don't reinvent the wheel. You can make a perfectly capable, performant firmware running both cores under FreeRTOS, which takes care of a lot of things you'd probably be better off not worrying about, like scheduling low priority vs. high priority tasks. If you're really worried about the overheads, consider FreeRTOS on one core, and pure, bare metal DSP on the other.
Support the SMK-37. Okay this is just my personal barrow to push. It's basically the same electronics, just with a few more keys, some pads, and some faders.
Okay, that's all I've got for now, and it's late. I'll check in for your questions, additions, disagreements, insults, etc. in the morning.
80 points · 27 comments
Mentions
All right, stop, collaborate and listen Before you dive into writing your own firmware, or adding the next feature to your existing firmware, please read this, it may save you a lot of time and frustration. First up, I'm not trying to discourage anyone - build the firmware, learn the thing, get your ideas out there. I'm not trying to call anyone out, not saying this for clout, karma, or whuffies - I just want people to know this stuff. Hopefully someone with more spare time than me will start a wiki (the easy part) and drive enough engagement there (the hard part) that it becomes a single point where people can share, correct, and expand on this kind of info, but 'til then: CMake and Ninja ara a pair of excellent build tools. Use them! Your agent knows how to maintain CMake configurations with far less effort and potential confusion than the custom build.py it might offer to create for you. The JieLi AC7911B8 MCU at the heart of the FM-1 / SMK-37 has a hardware floating point unit. You may still get better performance using integers, but you'd be mad not to enable it with the compiler switches "-mcpu=r3 -mfprev1". M-VAVE's open firmware gives you a good starting point for the compiler switches: github.com/m-vave/fm1_open/blob/4c7496daac04a95ff… You might as well try out their linker switches too: github.com/m-vave/fm1_open/blob/4c7496daac04a95ff… If you are using integers, sometimes you'll need 64 bits in the middle of a calculation, but the final result fits into 32 bits. Try to avoid storing the 64 bit values to actual variables - that way the compiler knows it can throw away certain data, and generates much more efficient assembly for the MCU: int32_t bad_fn(int32_t a, int32_t b, int32_t c) { int64_t acc = (int64_t)a * b; acc = (acc >> 16) * c; return (int32_t)(acc >> 16); } int32_t good_fn(int32_t a, int32_t b, int32_t c) { int32_t step1 = (int32_t)(((int64_t)a * b) >> 16); return (int32_t)(((int64_t)step1 * c) >> 16); } Likewise, multiplications are faster than divisions. So if you find yourself dividing by a constant (or infrequently changed) value one or more times per frame of audio, maybe calculate inv_const = 1/const at startup, then your code can just multiply by inv_const. Not everything needs to be optimised the same way. Back to compiler switches: when you're trying to pack the 22nd synth engine into your kitchen-sink firmware, blanket size optimisations like "-Os" or "-Oz" can seem attractive, but can quickly kill performance. The key is to be selective - try to arrange your files so all your hot loop code (anything that runs one or more times per frame of audio) is kept separate from the code that runs less frequently. Apply "-O2" to the hot code, and "-Os" or "-Oz" for everything else. Think about what really needs to be in the per-frame loop too. Some values might not change that much over time, so you can get away with only calculating them once every 32 frames, 64 frames, or 128 frames. Even where the value does need to change from one frame to the next, you might get away with only doing the heavyweight version of the calculation once per block of frames, then running a fast, per-frame linear interpolation. Take care about where that hot code runs from. Ideally you want it sitting in SRAM permenantly rather than executing in place from the NOR flash. XiP sounds like a great deal until your otherwise lightly loaded system starts having buffer underruns because a background process on the other core was fetching some data from flash. If you've got so many complex sound engines they won't all fit in SRAM at once, and you're feeling spicy, you might like to create little loading harness, reserve some space in SRAM, and load the current engine code into it at runtime. Speaking of cores - use them both, overclock them to 360MHz, increase the voltage the same way M-VAVE does, expect the same level of reliability as the stock ROM. This isn't a gaming PC with a BIOS that gives you the freedom to fry the CPU if it's not cooled with liquid nitrogen. It's a mass-market MCU where the biggest concern from increasing the voltage is decreased battery life. Don't reinvent the wheel. You can make a perfectly capable, performant firmware running both cores under FreeRTOS, which takes care of a lot of things you'd probably be better off not worrying about, like scheduling low priority vs. high priority tasks. If you're really worried about the overheads, consider FreeRTOS on one core, and pure, bare metal DSP on the other. Support the SMK-37. Okay this is just my personal barrow to push. It's basically the same electronics, just with a few more keys, some pads, and some faders. Okay, that's all I've got for now, and it's late. I'll check in for your questions, additions, disagreements, insults, etc. in the morning.
This is the repository for the “FM1 Open” firmware from M-VAVE. FM1 Open is M-VAVE’s official, open-source C SDK for the FM-1’s JieLi chip. It allows developers to write their own synthesiser engines, MIDI functions and audio routines from scratch.
Context: The FM-1 is an inexpensive synth ($80ish on amazon/aliexpress) which was reverse engineered [0]. The company that makes it now endorses the open firmware movement around it [1] [2]. You can see a review for the synth here [3]. Wow, also see this Firmware Hub! [4] [0] aroum/fm1-custom-fw [1] m-vave/fm1_open [2] forum.m-vave.com [3] youtube.com [4] thefirmwarehub.com
FM-1のメーカー(M-VAVE)が自前でgithubリポジトリを作ったんですって。/"GitHub - m-vave/fm1_open · GitHub" m-vave/fm1_open
Official FM-1 Open from M-Wave: m-vave/fm1_open
いや草 もう全部好き放題にできるじゃん m-vave/fm1_open
FM-1公式がこれを出すのはすごいなー 教授が生きていたらどんな反応示すだろうか、 真っ先に反応して、ヘタしたら自分の作品に取り入れてるかもしれないなとか想像 m-vave/fm1_open
M-VAVEが公式「FM1 Open V13」を公開。8トラック・8サンプル枠・16種のFXデモに、ソースとSDK、ブラウザWorkbenchも。メーカー自身がCFW開発の土台を提供。ただし実機用エンジンの一部はバイナリ提供です。 m-vave/fm1_open
M-VAVEが公式のrepo公開 m-vave/fm1_open コレで全部終わった気がする...
M-vave FM−1 公式でオープン版のファーム出したっぽいですね。一瞬で引っ込めたのがもう一度出てきた。 open.m-vave.com m-vave/fm1_open