Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% found this document useful (0 votes)
65 views

Arduino Synthesizer With FM

This document describes an Arduino synthesizer project that uses frequency modulation (FM) synthesis to generate musical tones. The synthesizer has a 31kHz sampling rate, 9-bit resolution, 4-voice polyphony, ADSR envelopes, and 12 preset instruments. It is built using an Arduino, buttons, a potentiometer, and other basic electronic components. Each instrument sound is defined by 10 parameters that control properties like attack, decay, sustain, release, frequency modulation, and more.

Uploaded by

David Clode
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
65 views

Arduino Synthesizer With FM

This document describes an Arduino synthesizer project that uses frequency modulation (FM) synthesis to generate musical tones. The synthesizer has a 31kHz sampling rate, 9-bit resolution, 4-voice polyphony, ADSR envelopes, and 12 preset instruments. It is built using an Arduino, buttons, a potentiometer, and other basic electronic components. Each instrument sound is defined by 10 parameters that control properties like attack, decay, sustain, release, frequency modulation, and more.

Uploaded by

David Clode
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 9

instructables

Arduino Synthesizer With FM

by rgco

It is quite possible to create decent sound with an Arduino as has been demonstrated in plenty of other projects,
for example:

The-Arduino-Synthesizer
The-Arduino-OctoSynth
Arduino-Chiptunes
Arduino-Step-Sequencer

Here is another demonstration of how a common Arduino Uno (or clone) can be used to generate a wide range of
musical sounds.

The specs are as follows:

31kHz sampling rate


9-bit resolution
4-fold polyphony (4 different tones can play simulateneously)
FM-synthesis with time-varying modulation amplitude
ADSR envelopes
12 preset instruments
18 keys covering 1.5 octave

Watch and listen to the video for a demo!

Of course it's nowhere close to the commercially digital synthesizers, but it's a big step from a simple 'beep' piano.

Instruments are defined by a set of 10 parameters, and it's easy to create new sounds by changing the
parameters. After playing around a bit I found came up with 12 instruments that sound good and named them as
follows:

Arduino Synthesizer With FM: Page 1


1. piano
2. xylophone
3. guitar
4. cymbal
5. bell
6. funky
7. vibrato
8. metal
9. violin
10. bass
11. trumpet
12. harmonica

Please tell me in the feedback if you find new good sounds, then I can add them to the code.

The project described has the 19-button keyboard built with microbuttons on breadboard, but it lends itself perfectly
to be built into existing objects, like furniture, toys or vintage equipment.

https://www.youtube.com/watch?v=MX-l05_u3gA

Arduino Synthesizer With FM: Page 2


Step 1: Construction and Operation

Required materials

an Arduino Uno or clone


an 830-hole breadboard
19 4-pin micro-push buttons
a 100muF electrolytic capacitor
a 10kOhm potentiometer
a 3.5 mm headphone jack
~50cm of single core hookup wire
21 jumper wires (14 long and 7 short)

Wire up all the components according to the indicated schematic. It's quite some work to get all the wiring in place,
so it makes sense to start with connecting only the audio circuit and one button, and upload the software. If that
works you can progressively add all the other buttons. For the electrolytic capacitor, make sure to connect the
positive terminal to the Arduino side and the negative terminal to the potentiometer. The short connections within
the breadboard are best done with short pieces of solid-core hookup wire, the longer connections to the Arduino
better with flexible jumper wires.

Note that the buttons may be connected to any pin, with software it is possible to assign any key to any note. The
only exception is pin D9, on which the audio signal is produced, it must not be used as a key input.

Load up the Arduino sketch from the next step and you can start playing.

The keys play the notes C4-F5, and the rightmost button changes the instrument. The time that a button is pushed
changes the length of a note, but since these are simple digital pushbuttons, the loudness of the tone cannot be
influenced by speed or force with which the keys are pushed.

Connect a stereo headphones to the 3.5 mm jack and with the potentiometer the volume can be regulated.

To hear the sound over a speaker, it needs to be amplified. Any amplifier that is designed to take headphone input
will work. Alternatively a cheap amplifier module base on the LM386 or PAM8403 should be sufficient to bring up
the volume.

Arduino Synthesizer With FM: Page 3


https://www.instructables.com/ORIG/F7F/S837/JSAOSXGR/F7FS837JSAOSXGR.pdf
… Download

Step 2: Code

Upload the attached with the Arduino IDE. I used of ADSR envelopes and FM sound synthesis .
version 1.8.7, but nothing fancy has been used so I
expect it to work well with most past and future IDE's. ldness: loudness
Moreover, no external libraries are used.
Keeping this at 64 or below guarantees that the
After the 'Verify' step, I see: output does not go in overflow and produce horrible
distortions. But for sounds that remain only very
Sketch uses 11630 bytes (36%) of program storage shortly at maximum amplitude, it's OK to go higher,
space. Maximum is 32256 bytes. Global variables since it's unlikely to have all 4 voices at maximum
use 757 bytes (36%) of dynamic memory, leaving amplitude.
1291 bytes for local variables. Maximum is 2048
bytes. pitch0: pitch offset

So it is far from exhausting the 2kB RAM, 32kB flash Setting this to 12 results in 'normal' configuration
of the Arduino Uno. where the leftmost key has the pitch of the C4.
Setting it to 0 results in a shift of a full octave down,
Instrument definitions
while the value 24 results in a full octave up.
Each instrument is defined by 10 parameters. To
discover new sounds, it's crucial to understand their
ADSR_a: attack parameter
meaning, and make sure you understand the basics

Arduino Synthesizer With FM: Page 4


Speed with which the tone rises from 0 to max. A multiples of the half the pitch frequency, thus creating
small number here means the sound starts very also undertones, but with more emphasis at the
slowly. Example: ADSR_a=8192 takes 4ms to rise to higher frequencies. Any number for FM_inc that is not
max. ADSR_a=256 takes 128ms to rise to max a multiple of 64 will result in anharmonic tone, typical
of cylindrical vibrations. A value of FM-inc that differs
ADSR_d: decay parameter slightly from a multiple of 256 will result in very
nearby-frequency bands, which then results in a
Speed with which the tone decays from max to vibrato effect.
sustain. A small number here means the sound
decays very slowly. Example: ADSR_d=8192 takes FM_a1: FM amplitude start
4ms to decay from max to 0 . ADSR_d=256 takes
128ms to decay from max to 0. If sustain is different Frequency modulation amplitude at the beginning of a
from 0, it actually takes less to reach the sustain note. FM_a1=256 means that at the beginning of a
value. note beta=1, resulting in a rich spectrum. A smaller
number results in fewer sidebands and thus a purer
ADSR_s: sustain parameter note. Very large values, like FM_a1=2048
corresponds to beta=8 and gives rather crazy
Relative loudness of the tone if the key remains waveforms, which may result in quite interesting
pushed. ADSR_s=255 means it sustains at maximum sounds.
volume. ADSR_s=192 means it sustains at 80% of
the maximum volume. ADSR_s=0 means the sound FM_a2: FM amplitude end
dies off even if the key stays pressed.
Frequency modulation amplitude at the end of a note.
ADSR_r: release parameter In most instruments the high frequencies damp faster
than the low frequencies, which can be emulated by a
Speed with which the tone decays after being decreasing value of the FM amplitude, or
released. A small number here means the sound FM_a2FM_a1 can help to create weird crazy funky
continues for a long time after key release Example: sounds.
ADSR_r=8192 takes 4ms to decay from max to 0 .
ADSR_r=256 takes 128ms to decay from max to 0. If FM_dec: FM decay
the tone was already below maximum at the moment
of release, it takes less time to die. The speed with which the FM amplitude changes
from its starting value to its end value is determined
FM_inc: FM frequency wrt pitch by Fm_dec. Note that this change follows an
exponential decay, so the transition is much smoother
The ratio of the modulation frequency to the pitch than for the ADSR envelope, where the transition is
FM_inc=256 corresponds to a modulation frequency linear. FM_dec=256 means that the time constant of
equal to the pitch, resulting in pure harmonics that are the exponential change is 128ms. A low value of
multiples of the pitch frequency. FM_inc=512, 768 or FM_dec means that the sound keeps changing
1024 corresponds to a modulation frequency 2,3 or 4 continuously. A high value of FM_dec results in a
times the pitch, resulting in pure harmonics that are short initial burst of change, followed by a quick
multiples of the pitch frequency, but with more transition to a more stable final sound.
emphasis at the higher frequencies. FM_inc=128
corresponds to a modulation frequency half to the Keys
tone, resulting in semi-pure harmonics that are The Arduino uno has 20 io ports. Pin 9 is needed for
multiples of the half the pitch frequency, thus creating audio out and one more pin for instrument select.
also undertones. FM_inc=384,640,896 corresponds Apart from that, any key can be connected to any i/o
to a modulation frequency 1.5, 2.5 or 3.,5 times the pin, and the corresponding note defined in software.
pitch, resulting in semi-pure harmonics that are For speed reasons, the keys are accessed though

Arduino Synthesizer With FM: Page 5


direct port manipulation. Thus, inside the code they generations if any of these keys accidentally gets
are accessed as PORTD, PORTB and PORTC. shorted to ground. All keys use the internal pull-up
However, in the block 'pin to key mapping', the resistors, thus avoiding the need for an extra 19
comments in the code indicate which bit of which port external pull-up resistors. The keys are read only
correspond to which Arduino pin. If you make a once every loop (once every 0.48ms), so the effects
version with fewer keys, you can define the of debounce are quite limited as well, and I found no
uninstrumented pins here as 'nokey': it results in need for hard- or software debounce protections.
smaller and faster code and avoids unwanted tone
Download
https://www.instructables.com/ORIG/FCE/BNVA/JSAOSXHI/FCEBNVAJSAOSXHI.ino

Step 3: Technical Details

PWM the compiler repeats this piece of code every time


Pulse-width modulation is a well-known method to that it is called. It takes up more space, but it is faster.
create semi-analog signals. For creating audio, it
must be done with a frequency well above our There is no time in 512 clock cycles to perform all
hearing limit. The timer is set up to give a pulse every other functions, such as checking the buttons,
512 clock cycles. Since the Arduino runs at 16MHz, changing the instrument, choosing the voice, and
this corresponds to a sampling frequency of modifying the time-evolution of the notes, so this
31250Hz, well above our hearing limit. This sampling functionality gets split up into 15 pieces and is
frequency allows to produce sounds of up to half that interspersed between the fast loops. This allows to do
frequency (according to the Nyquist theorem). some intermediate calculations with 32-bit precision,
needed for the multiplication of two 16-bit numbers.
Timing without interrupts
The full loop takes 0.48 ms which fast enough for
One method to keep track of time and update the
these functions.
pulse width at the right moment is to use interrupts.
However, interrupts have a significant overhead, so I FM synthesis
chose instead to base the timing on checking the A simple sine wave sounds dull since it has no higher
timer overflow bit. This way the available CPU time is harmonics. A computationally efficient way to create
divided more or less equally between the 'fast loop' complex sounds is frequency modulation. For
and the 'slow loop'. practical reasons, it is implemented as phase
modulation here, but for sinusoidal signals phase
In the fast loop (setPWM) the pulse width is modulation and frequency modulation are equivalent.
calculated for the 4 voices, at every tick of the timer. FM can produce a rich spectrum of sidebands next to
This is allowed to take up ~250 cycles, and it appears the main pitch. The modulation frequency determines
sufficient to update the 4 phases, do the frequency the position of these sidebands, and the amplitude
modulation, calculate the intensity and add up the 4 determines their intensity. If the modulation frequency
signals. To keep this fast, only 8- and 16-bit integer is not a simple ratio of the pitch, the resulting sound is
numbers are being used, and the sine values have anharmonic, and corresponds to the typical sound of
been tabulated. vibrating cylindrical objects, such as a bell. Real
musical instruments have a rich spectrum that varies
The call to fast loop is forced to be an inline functions, over time, since some vibrations damp faster than
using the __attribute__((always_inline)) attribute. This others.
means that the assembly code that is generated by

Arduino Synthesizer With FM: Page 6


Thank you for the amazing work! It really sounds great thanks to your speedy code. About that,
would it be possible to add a sort of arpeggiator function when a key is pressed? More importantly,
I was wondering if it would be possible to play a sequence of notes, automatically, without the
need of pressing a button (grounding the pins). As far as I can tell it's not possible to do this in 'the
loop()' and would take some time to rewrite. Can you prove me wrong? Thanks again, great
project!
Hi, I had to look up what an arpeggiator is! I have zero music education, anyway if it's about
playing a sequence of notes after a single button press, there's nothing impossible about that! The
coding is not trivial, but it's all a matter of putting little pieces of code in between the calls to update
the PWM output. The core of the code is perfectly capable to play up to 4 tones simultaneously,
even of different 'instruments'. Record and playback functions are tricky to program, I had a quick
try at some moment but wasn't really happy with it and so published a 'bare' version here, and and
even more basic versione here(https://www.instructables.com/id/Arduino-Soundlab/).
Hey rgco, thanks for the reply! It's indeed about play a sequence after a note press. Have not
managed yet tho haha. The sequence playing would be more about playing a stand-alone melody
(without the need of pressing buttons, but predefined in an array for example). The soundlab code
looks nice, indeed adding pots would be a next step. One question, did you forgot to add the link to
the 'bare' version you mentioned?
I have an ongoing project to compose and play rhythms, but I haven't touched it for a while. The
replay works but I'm not sure if it'll be feasible to have a display.
(with the 'bare' model I meant the one called 'soundlab' - it has pots for the instrument settings
instead of predefined instruments)
Ah thanks for clarifying! Can you give a hint in the direction of playing a sequence of notes? Im
having a go at it, but cant get it to work. Should i define an array beforehand and loop through that
in the main loop? It doesn't seem trivial indeed haha. Keep up the good work!
Here's the code as is. It plays a song, though not a terribly interesting one (the next step is to test if
it can play some interesting songs, then to make a user interface, squeeze the data format and
store in EEPROM)
First 8 instruments are defined. Then 8 sets of 8 sounds (defined by instrument, pitch, volume and
length). Then 8 short tunes, which are combined into a song.

Sounds amazing! The low bell wow! Of course the problem with interesting songs is that you have
to deal with both the composition and notation (and storage). Maybe look into existing standards
for this, such as RTTL https://en.wikipedia.org/wiki/Ring_Tone_Transfer_Language or of course
midi files.
Good idea! I had looked into midi but it seemed way too complicated. RTTTL seems doable, and
there seem to be thousands of them readily available! Thanks!
Exactly! Cant remember if it was monophonic only tho..

OK, you got me enthusiastic about RTTTL, I coded it up, did a few more tweaks and wrote it up as
a separate instructable:
https://www.instructables.com/id/Arduino-Chrismas-...

Ha! Amazing, just in time! Thanks for sharing =)))

Arduino Synthesizer With FM: Page 7


Thank you for sharing this with us! I'm using it in my undergraduate thesis in Electric Engineering.

I'd like to pose one more request of you, and that's to add a simple square wave and triangle wave
instruments. This thing was destined for chiptune.
I made a new version with 8 pots and 24 keys, it is much better indeed. Thanks for the suggestion!
https://www.instructables.com/id/Arduino-Soundlab/
That's amazing! Thanks for your work and I'm glad my feedback helped, if even a little.

Hey awesome work on this! I'm currently building it myself, but I was hoping to do a couple
modifications to it. I'm just not sure where to start.

I'd love to add an SPI OLED 128x64 screen that displays the current sound font, and maybe other
information.

Is there any way to increase the amount of keys you can press at once?

Also, would live modification of each font be possible with a few potentiometers?

I'm still fairly new to Arduino so I'm not sure where to start coding wise for these few things.
Glad you like it!
Adding a screen requires pins so reduces the number of available keys. Also updating the screen
might not be fast enough to do simultaneously with making sound, but that's not necessarily a
problem.
Increasing the level of polyphony from 4 to 8 is not trivial: It would take a reduction in sampling rate
to 16kHz or a reduction in sound complexity (giving up on FM synthesis). Both will reduce the
sound quality. May need to go to a faster microcontroller for that... In any case it would be a
complete rewrite of the code since the 4-fold polyphony is hardcoded everywhere to save CPU
cycles.
Live modification should be possible with pots on the analog inputs. Every pot will use a pin so one
key less (but the Arduino Nano has 2 extra analog pins A6 and A7). Regular 'analogRead' will be
too slow, but accessing registers directly (similar as done in
https://www.instructables.com/id/Another-Arduino-Oscilloscope/ ) it's possible to start an analog
readout, keep 'working', and read the result when it's ready (instead regular analogRead waits
doing nothing after the start of the ADC).
Good luck and let me know your progress!
Thanks for your reply! I actually have an expansion board if I run out of pins. I'd love to add those
potentiometers.
Would you happen to know how to code for say, 3 pots for sustain, attack, and decay?

This.is a.nice idea. 4 pots for adsr and 4 for the fm parameters would really allow to experiment
with sound synthesis. The black keys would have to go though. I might give it a try but it will take a
while. Just ordering the pots takes 2 months...
How about instead of losing keys, we use a pin expansion board/shift register? They're quite cheap
around where I am. I hear the 74HC595 IC is sufficient.
I have a bunch of those, they cost cents indeed, but they are output registers, they cannot be
directly used for input. But there may be tricks to use them for input (like scanning the 'power' to
sets of input devices) interesting...
I appreciate your work and your replies. I'm new at this sort of thing, but I figured it wouldn't hurt to
spitball a bit and see what can be done. I wasn't aware they were only output registers and not
extra pins. Is there another cheap micro controller we could use that has more input pins? Teensy

Arduino Synthesizer With FM: Page 8


maybe, or another arduino?
Actually, I think it should be possible to connect a lot more keys and pots without needing extra
components by using input multiplexing. 8 pins are set on input, and 6 on output, and up to 48
buttons can be connected in a matrix between them. All output pins except one are 'disconnected'
(set to high-impedance) and one 'row' of buttons is read. Then the next 'row' is activated etc. Speed
should not be an issue with direct port manipulation. Also up to 36 pots can be read out that way.
I also want to add that I'm planning on using my 3D printer to making a casing and keys for this
synth. I've got it basically built right now, and it's temporarily in an old computer keyboard case.
Really cool project though and super easy to put together!
As far as the screen goes, I just want to see which font I'm using at the time and maybe device
battery (which I'm adding). I don't really need anything else.
Honestly, this thing is cool enough, that just adding a few potentiometers to muck about with each
font, would bring this to a whole other level. I certainly know plenty who'd love a cheap, DIY synth
that they can record from (via 3.5mm jack). Especially some of my chiptune friends.

Arduino Synthesizer With FM: Page 9

You might also like