Arduino FM Synth

Arduino FM Synth

I have wanted to get into building things with Arduino for a while. I ran into a project on Instructables.com that looked easy, I thought I’d jump in and give it a try!

The project creates a simple synth/sound generator with two oscillators. The oscillators are ring modulated with a frequency control for each. There is also a modulators and two modulation depth/intensity controls. A five knob space noise box.

I felt the original project description left out some information which I’ll try and fill in here.

What is Mozzi?

Mozzi is a library of code you can use to make sounds and music with your Arduino. Normally the Arduino is limited to very basic 8bit square wave sounds. With Mozzi your Arduino can start playing pitches with sine waves, triangle waves, and more. Mozzi also has support for LFO, Envelopes, effects like delay, phase shifting, and reverb, and more.

Mozzi is a library, it contains many files with code that you can add to your Arduino projects. This code consists of Objects, Functions, and Tables that you’ll make use of in the Arduino Sketches you write.

Mozzi – https://sensorium.github.io/Mozzi/

What do you need?

You’ll need an Arduino and a solder less breadboard along with some other basic electronic components. I used an Arduino Nano, this should work with most of the popular Arduino boards but will look different from the pictures and diagrams here!

  • Arduino Nano
  • Wire
  • 5 x 100k potentiometers
  • 1/8″ or 1/4″ speaker jack
  • Solderless breadboard

Getting started

Start by setting up your environment. You’ll need the Arduino IDE (Integrated Developement Environment) to write, compile, and upload code to your Arduino.

Download the Arduino IDE here: https://www.arduino.cc/en/software

You’ll need to install the driver for your Arduino board, if it’s not already installed. Open then Arduino IDE and got to:

  1. Tools > Board > Board Manager
  2. Search for your Arduino board. I searched for “Nano”
  3. Click “Install”

Download and install the Mozzi library.

  1. Goto: https://github.com/sensorium/Mozzi
  2. Find the green “Code” button and choose “Download Zip”
  3. Back in the Arduino IDE choose: Sketch > Include Library > Add .ZIP library…
  4. Find Mozzi-master.zip which you downloaded in step 2 and select it

The Code

Arduin is programmed with C and C++. Arduino projects are called “sketches”. You’ll write your code for this project in a sketch. A default Arduino Sketch looks like this:

void setup() {
  // put your setup code here, to run once:

}

void loop() {
  // put your main code here, to run repeatedly:

}

setup() is where you initialize your code. The code here happens once when the Arduino starts up

loop() is where the main part of program runs. The code here runs after setup() and repeats for ever.

Mozzi sketches use similar boilerplate code with some extras that are required for Mozzi to work correctly.

#include <MozziGuts.h>   // at the top of your sketch import Mozzi code

void setup() {
	startMozzi(); // Start up the Mozzi code
}

void updateControl() {
	// your control code. For things like knobs and switches
}

int updateAudio() {
	// your audio code which returns an int between -244 and 243. Audio processing goes here
}

void loop() {
	audioHook(); // Required
}

#include <MozziGuts.h> adds the Mozzi code, from the library, to your sketch.

startMozzi() initializes relevant parts of the Mozzi library.

updateControl() is used to read values from controls connected to your Arduino. This is things like pots and switches that might be used by your program to control what is happening in the Arduino.

updateAudio() is where you will update the audio produced by Mozzi. This where you might do some calculations to generate the new frequency that Mozzi should output or modify a wave form.

audioHook() tells the Mozzi code to update.

The project sketch

Here is the code for this project sketch. This is modified from the code in the original article. I’ve cleaned it up, added comments, and changed the variables naming to be more consistent.

Mozzi FM Synth Sketch

/* 

  Simple ring mod mozzi synth
  Adapted from Mozzi Example: Knob_lightLevel_FMsynth
  Originally modded by: https://www.instructables.com/Using-Mozzi-Library-with-5-potentiometers/ 

  This creates an FM synth with 5 knobs. It makes alien spaceship noises! 
  
*/

// Import libraries 
#include <MozziGuts.h>            // Required for a Mozzi Sketch
#include <Oscil.h>                // Oscillator 
#include <tables/cos2048_int8.h>  // Table for Oscils to play
#include <Smooth.h>               // Low pass filter
#include <AutoMap.h>              // Maps unpredictable inputs to a range
 
// Define carrier frequency max and min, for AutoMap
const int MIN_CARRIER_FREQ = 22;
const int MAX_CARRIER_FREQ = 440;

// Define intensity max and min, for AutoMap, note they're inverted for reverse dynamics
const int MIN_INTENSITY = 700;
const int MAX_INTENSITY = 10;

// Define frequency 2 intensity
const int MIN = 1;
const int MAX = 10;

// Define mod speed max and min, for AutoMap, note they're inverted for reverse dynamics
const int MIN_MOD_SPEED = 10000;
const int MAX_MOD_SPEED = 1;

// Define some auto maps. These scale values read from analog input to values used for audio operations
AutoMap kMapCarrierFreq(0, 1023, MIN_CARRIER_FREQ, MAX_CARRIER_FREQ);
AutoMap kMapIntensity(0, 1023, MIN_INTENSITY, MAX_INTENSITY);
AutoMap kMapModSpeed(0, 1023, MIN_MOD_SPEED, MAX_MOD_SPEED);
AutoMap kMapIntensity2(0, 1023, MIN, MAX);
                      
const int KNOB_0 = 0; // Analog pin A0 Carrier frequency
const int KNOB_1 = 1; // Analog pin A1 Modulator Frequency
const int KNOB_2 = 2; // Analog pin A2 Modulation speed 
const int KNOB_3 = 3; // Analog pin A3 Mod Frequency 2
const int KNOB_4 = 4; // Analog pin A4 Mod Intensity 2

Oscil<COS2048_NUM_CELLS, AUDIO_RATE> aCarrier(COS2048_DATA);        // Carrier Frequency Oscil
Oscil<COS2048_NUM_CELLS, AUDIO_RATE> aModulator(COS2048_DATA);      // Modulator Frequency Oscil
Oscil<COS2048_NUM_CELLS, CONTROL_RATE> kIntensityMod(COS2048_DATA); // Modulator intensity Oscil

int mod_ratio = 5; // brightness (harmonics)
long fm_intensity; // carries control info from updateControl to updateAudio

// smoothing for intensity to remove clicks on transitions
float smoothness = 0.95f;
Smooth <long> aSmoothIntensity(smoothness);

void setup(){
  Serial.begin(115200); // set up the Serial output so we can look at the light level
  startMozzi();         // :))
}

void updateControl() {
  
  // Read Knobs with mozziAnalogRead()
  
  int knob_0_value = mozziAnalogRead(KNOB_0); // value is 0 - 1023
  int knob_1_value = mozziAnalogRead(KNOB_1); // value is 0 - 1023
  int knob_2_value = mozziAnalogRead(KNOB_2); // value is 0 - 1023
  int knob_3_value = mozziAnalogRead(KNOB_3); // value is 0 - 1023
  int knob_4_value = mozziAnalogRead(KNOB_4); // value is 0 - 1023
  // These numbers need to converted (mapped) to values that makes sense for use with Mozzi

  // Map values from analog read to values used by synth
  
  int carrier_freq = kMapCarrierFreq(knob_0_value);           // map knob 0 to carrier frequency
  int intensity = kMapIntensity(knob_1_value);                // map knob 1 intenisty
  float mod_speed = (float)kMapModSpeed(knob_2_value) / 1000; // map knob 2 to mod speed use a float here for low frequencies
  int intensity_2 = kMapIntensity(knob_3_value);              // map knob 3 to frequency 1 intensity
  int knob_4_calibrated = kMapIntensity2(knob_4_value);       // map knob 4 to frequency 2 intensity

  // Calculate the modulation Frequency
  int mod_freq = carrier_freq * mod_ratio * intensity_2;
  
  // set the FM oscillator frequencies
  aCarrier.setFreq(carrier_freq); 
  aModulator.setFreq(mod_freq);
  
  // calculate the fm_intensity
  fm_intensity = ((long)intensity * knob_4_calibrated * (kIntensityMod.next() + 128)) >> 8; // shift back to range after 8 bit multiply
  
  kIntensityMod.setFreq(mod_speed);
}

int updateAudio(){
  // Ring mod the FM'd carrier with the modulator
  long modulation = aSmoothIntensity.next(fm_intensity) * aModulator.next();
  // Phase mod the carrier
  return aCarrier.phMod(modulation);
}


void loop(){
  audioHook();
}

Create a new sketch and replace the default code with this sketch in your Arduino IDE.

Wire up the breadboard

Below is a diagram showing how to wire up your Arduino on the breadboard. It’s important to connect the parts and pins to the correct parts and pins! You don’t have match the diagram exactly. But the connections need to do to the same places!

Arduino + Mozzi Synth

The Arduino is oriented with the USB connector at the top. Check the pin out of your Arduino. The drawing above shows the pin out for the Nano.

+5v and GND from the Arduino are connected to the outer strips of the breadboard. Red is +5v and Blue is GND.

The pots are all wired the same. The top pin connects to GND. The bottom pin connects to +5v. The center pin of each connects to one of the analog inputs of the Arduino. These are pins A0 – A8. We’re using A0 – A4 here.

The output jack, you’ll use this to connect your project to a speaker, computer, amplifier etc. The output jack tip is connected to pin D9 and the sleeve is connected to GND.

Compile and Run

To compile and run the code follow the steps below. To start you’ll load a test sketch to make sure things are working. Think of this as a sanity check.

The Arduino IDE has examples sketches built in and libraries you add will install new examples sketches. All of the example sketches should be under File > Examples in the Arduino IDE.

You’ll need a USB cable. Some cables are only good for charging and do not have a data line. IF you have problems loading code the cable might be the culprit.

Follow these steps to test your Arduino:

  1. Connect your Arduino to your computer with the USB cable.
  2. Open the Arduino IDE.
  3. Choose File > Examples > 01.Basics > Blink
  4. Choose Tools > Board > Arduino AVR Boards > Arduino Nano (or choose the board you are using.) If your board is not on the menu choose Board Manager and load your board.
  5. Choose Tools > Port > Select your USB port.

When using cheap Arduino clones I had to also choose: Tools > Processor > ATmega328P (Old Bootloader)

With the Official Arduino board I used the default setting: ATmega328P

At the top of the left of the sketch window there is a button with a check mark. This verifies your code. It doesn’t load the. It only verifies that the code is free from errors. Click that.

You should see a message at the bottom of the window telling you to code compiled successfully and how much of your storage it occupies.

Now click the Arrow button in the upper left. This button uploads the code to your Arduino.

This will take a moment provide a message when complete.

The Blink sketch only blinks the LED on the Arduino. Take a look at your Arduino. If everything is working one of the LEDs on the top of the board should be turning on and off once per second.

If that worked your system is functioning! Now it’s time to try out a Mozzi Sketch. Connect the output jack to an audio source like a speaker, some headphones, your computer headphone jack, or an amplifier.

Important! Neither the circuit or the sketch have a volume control! You need to control the volume from your amplifier or computer. If you are using headphones, don’t wear them before starting the sketch.

  1. Open the Mozzi FM Synth Sketch above.
  2. Verify the code with the ✅ button
  3. Load the code with the ➡️ button
  4. Connect the output jack to your speaker, headphones or amplifier.

If you are hearing audio similar to the examples it’s working! If not you’ll need to troubleshoot. Try these ideas:

  • Go back to the diagram and check the wiring.
  • Check your audio device with with audio from another to make sure it’s outputing audio.

Conclusion

This is an interesting start to creating audio with Arduino. There is a lot more to explore. The Mozzi library does a lot of heavy lifting. It has many more features you can explore. Check out these resources.


Leave a Reply

Your email address will not be published.