How to get started writing your own firmware for Mutable Instruments Clouds
Over the last few months I’ve been learning the basics of DSP programming using a Mutable Instruments Clouds synth module. It’s been a lot of fun, and wanted to share what I’ve learned.
My amateur coding background has mostly been on Arduino, using their very friendly programming environment, so working in C++ and using command line tools was new to me.
Everything I know about this subject is in this post, so I can’t help you beyond what is written here. Read the disclaimers on the Mutable Instruments Clouds Open Source page:
“Past this point, we assume you know what you are doing and we are not responsible for any damage to your module!”
What you need to get started: Hardware
- A Mutable Instruments Clouds Module (I bought mine from Post Modular)
- A Computer. These instructions assume you’re on a Mac, but you can also use a PC or Linux machine.
- A Programmer. I use a ST-Link V2, which costs about £60. Émilie Gillet uses a Olimex ARM-USB-OCD-H JTAG, which is about the same price. There are also cheaper ways to do it — you can buy a differently branded ST-Link V2 for £7.99 on Amazon, or some development boards have the hardware built in. These cheaper tools may work, I don’t know. I wanted one less thing to go wrong, so bought the real thing.
- You also need this Olimex JTAG Adaptor to fit the tiny pins on the back of Mutable Instruments modules. It costs about £8.
PS: You can get started without buying a programmer. The tools we’re going to use can create the .wav files for the Audio Firmware Update method described in the Clouds manual. However, the whole process — creating the .wav, uploading it into the module — takes 3–4 minutes, which I would find pretty annoying while trying to write and test code.
PPS: If you just want to learn about DSP coding, there are many other cheaper platforms including Teensy, Axoloti or Bela.
Getting started: Installing your environment
The Mutable Development Environment was created by Émilie Gillet as a way to help people write firmware for Mutable modules.
This is how it works: Using free tools called VirtualBox and Vagrant, you create a virtual machine inside your computer, running Linux. All the hard work — compiling the firmware, uploading it to your module — is done by the Linux machine. You control the machine through the command line, using Terminal.
It’s a great way for anyone wanting to write firmware for a Mutable Instruments module to access a carbon copy of Émilie Gillet’s setup, without having to install and configure dozens of tools.
One directory (in this case a copy of the entire Mutable Instruments Eurorack firmware repository on GitHub) is shared between the virtual machine and your normal OSX system — so you can edit files within that folder, and the virtual machine can see and use them to compile the firmware.
The system is already very well documented and worked well for me, a complete noob to Linux, command lines or setting up an environment — please read these instructions and those on the environment GitHub page.
- Download the Mutable Environment files Follow this link to the GitHub page and click the green ‘Clone or download’ button. Choose ‘Download ZIP’. Open the zip file, and place the folder somewhere safe. I created a ‘MutableEnvironment’ folder inside Documents, with the ‘mutable-dev-environment-master’ folder unchanged within that.
- Install the software Follow the links in the Mutable Development Environment GitHub page for VirtualBox, VirtualBox Extension Pack and Vagrant. I found all three installed normally and didn’t need to use the command line for the Extension Pack.
- Get a text editor I’ve been using Text Wrangler, which is free and works fine, as will many others.
- Open the folder where you left the files in Terminal If you’re as clueless as I was with Terminal, this is how you do it:
1. Launch Terminal.
2. Arrange a finder window so you can see the “mutable-dev-environment-master” folder.
3. In terminal, type “cd” (change directory) and hit the space bar.
4. Drag the “mutable-dev-environment-master” folder into the terminal window.
5. Hit return in the Terminal window, and the prompt will show you’re now in the right directory.
6. Type “ls” and hit return to see a list of the files, just to make sure. - Launch the environment All the details are in the GitHub documentation, but it’s very simple: You type “vagrant up” and the system goes away to build the virtual machine — it takes 15–30 minutes the first time. Don’t get impatient and try to cancel it. Then you type “vagrant ssh” to enter the virtual machine. Now, if you type “ls” you’ll see a list of all the files in the Mutable Instruments GitHub; braids, branches etc.
- Check the shared folder If you go back to Finder, and look in mutable-dev-environment-master, you’ll find a folder called “eurorack-modules”. This is the shared folder. Edit the files here, compile and upload them through the virtual machine.
- Try it out As the documentation explains, if you type “make -f clouds/bootloader/makefile hex” and hit return, the system should go away and compile the bootloader for Clouds. The files the system creates appear in a folder called “build” inside “‘eurorack-modules”
- What if it doesn’t work? Well, I can’t help you there, beyond going back and reading the GitHub documentation again. You can try searching the Mutable Instruments forum with any error codes, or ask to join Facebook groups like “Euro SMD DIY Noobs”.
Uploading code to the Clouds module
The next step is connecting to the module.
I use a ST-Link V2. The drivers are included in the environment, but before uploading anything, you have to tell the system which programmer you’re using by following these customisation instructions. Each time I launch the system, I have to type:
export PGM_INTERFACE=stlink-v2
export PGM_INTERFACE_TYPE=hla
To check that the system can see your programmer, type “lsusb” which will list all the attached USB devices.
Connecting to the module
- Clouds needs power from your modular case and the STLink USB connection at the same time to receive firmware. I have mine installed in the case, with the STLink dangling round the back and a USB cable coming out into the computer.
- The cable with the little Red Olimex adaptor isn’t clearly labelled. For me, the pin marked 1 seems to be connected to the pin marked JTAG on the Clouds module. I tried it both ways round, and nothing blew up (but it didn’t work the other way).
You can compile the code and upload it with this command:
make -f clouds/makefile upload
Although I found that didn’t work — it gave an error — so I have to use this:(Thanks to a forum tip from bennelong.bicyclist)
make -f clouds/makefile upload_combo_jtag
So, when developing code, my workflow is this: Edit a file in Text Wrangler, hit cmd+s to save it, then switch to terminal and press the up arrow to get back the last command I used, which was inevitably “make -f clouds/makefile upload_combo_jtag”.
Hit return, and the system checks for errors, compiles the code and drops it into the module. It takes about 30 seconds, which is still an annoyingly long time. During that time the module freezes and makes strange noises. Terminal shows some worrying-looking messages like “current mode: Handler HardFault” and “shutdown command invoked” but that’s normal.
Lets write some code: Hello World for Clouds
When I started learning to use an Arduino, like most people I began with ‘Blink’:
void setup() {
pinMode(13, OUTPUT); // The LED is connected to Pin 13
}
void loop() {
digitalWrite(13, HIGH); // turn the LED on
delay(1000); // wait for a second
digitalWrite(13, LOW); // turn the LED off
delay(1000); // wait for a second
}
‘Blink’ is a classic Hello World. Once it works, you can look at the code and say things like “What happens if I change that first delay(1000) to delay(100)?” And then, suddenly, you’re coding.
Emilie’s code for Clouds is pretty much the opposite of ‘Hello World’. It is meticulously organised, properly optimised and often — to a novice coder like me — baffling.
Fortunately, I had a way in.
I recently met Matthias Puech, the computer scientist who writes the Parasites Alternative Firmware for Mutable modules (and also wrote the code for Xaoc Devices Batumi).
I asked Matthias where to start, and — very generously — he wrote a ‘Hello World’ for Clouds. Here it is — a simple version of clouds.cc (click ‘raw’ or ‘download ZIP’ to grab the code).
If you replace the stock version of clouds.cc with this code (it must still be named clouds.cc), leaving everything else unchanged, then compile and upload it to the module, you should immediately see a pattern of flickering orange and green LEDs.
What this ‘Hello World’ does:
- Flickers the LEDs
- Takes Left input to the Left output, with the volume controlled by the Position control (just like a passive attenuator!)
- Ring modulates the Left and Right inputs, sending the result to the Right output.
Once you have Hello World working, you are finally ready to start having fun. In the broadest possible sense of the word ‘fun’.
Lets write some code: Making changes
As you read down the Hello World code, it breaks up into clear blocks.
- At the top is the license, in comments.
- Then there are various setup lines, pulling in external libraries and doing things I don’t yet understand.
- One variable (counter) is created that will be used later.
- Then you find a function called SysTick_Handler. Anything in this block — as the comments explain — is called every millisecond. Some human interface things — checking knobs, turning LEDs off and on, might happen here. They’re not timing-critical, so don’t need to happen constantly.
- Below that is a function called FillBuffer. This is the beating heart of the module. It’s called every 32 samples, or 1,500 times a second, and it’s where the system fills up the buffers for the codec, the chip that takes audio input in and sends audio output out.
- Inside FillBuffer is a loop around while (n — ); this is where each individual sample is processed, so it has to run 48,000 times a second.
- Below that is Init(), which is run once at the startup of the module, where sample rates etc are set.
- Finally at the bottom is main(void), which is the empty main loop that does nothing while timers make all the other routines work.
Now, finally, everything is in place, you can start making changes.
In SysTick_Handler, find this line:
// a little LED animation for fun
for(int i=0; i<4; i++) {
Change the 4 to a 3, compile and upload to the module. Instead of 4 lights glowing, you now have three.
Congratulations. You’re writing your own firmware.
Now you can really start to experiment. Don’t be afraid to change things and experiment until you find something interesting.
Building a simple delay
You can create a very simple delay using an array with commands like this:
// create an array with space for one second of audiouint32_t delayLength = 48000;
int16_t delayLine[48000];// create variables to store record and playback positions
// Use floats for these because we might want to have them
// move faster or slower.
// Start playback one sample *ahead* of the record head, because
// they're going to be in a loop. double recordHead = 0;
double playHead = 1; // Write the Left input to the delay line// Using the modulo "% delayLength" means it writes in a loop
// starting again at the beginning when it gets to the end // Use (long) to convert the float into an integer, you can't
// use a float to set the index on an array delayLine[(long)recordHead % delayLength] = input->l;
recordHead++;// Read the Left output from the delay lineoutput->l = delayLine[(long)playHead % delayLength];
playHead++;
You can see these commands working together in this firmware. It’s simply a 1 second audio delay on the left channel — whatever you put in comes out 1 second later.
Obvious next steps would be to mix in the clean signal and add feedback. With a few more steps (including learning about linear interpolation), you can create something ridiculous like this:
Things I’ve learned along the way, in no particular order
- Audio comes in and goes out as 16-bit integers (int16_t); -32,768 to 32,767. Signal processing is normally done as 32-bit floats; where -1 to +1 represents the signal. To convert between the two:
int16_t y = static_cast<int16_t>(x * 32768.0);
float y = static cast<float>(x) / 32768.0;
- Adding two audio signals together works like mixing. Multiplying them works like amplitude (ring) modulation. In both cases, you’ll need to do some division afterwards, to ensure the output doesn’t clip (there are also other ways to do this.)
- When you get something ‘wrong’ you’ll hear weird crackling sounds at the outputs — for example if a number is overflowing and producing unexpected results every so often, that happening at 48khz sounds like weird crackling. Sometimes, the weird crackling sounds interesting. Sometimes wrong sounds great.
- Pots and CV inputs produce zero-to-one floats. That’s why multiplying the input by a pot position works as an attenuator. You can find a list of the available inputs in enum_AdcChannel here.
- A big difference between this and simple Arduino code is that it is designed to be non-blocking. Arduino code typically does one thing at a time. If you call “delay(1000)” the entire system stops and waits. Emilie’s code for Clouds works differently. If you call “ adc.Convert()” the system goes off to read all the potentiometers and CV inputs, which takes hundreds of microseconds, but it’s still able to do other things (like playing audio) at the same time.
- As you get more confident, start reading through the rest of the Clouds firmware, to find lots of useful routines and ideas.
Next steps and further reading
That’s really as far as I’ve got so far. I’m gradually flicking through The Computer Music Tutorial by Curtis Roads, and looking at sites like musicdsp.org.
Thanks for reading if you got this far, please post links to your inventions in the responses.