Arduino Soundlab

2,639

15

30

Introduction: Arduino Soundlab

It is incredible what a wide range of amazing sounds can be generated with the FM synthesis technique, even using a plain Arduino. In a previous instructable this was illustrated with a synthesiser that had 12 pre-programmed sounds, but a viewer suggested that it'd be much cooler to have full control of the sound parameters with potentiometers, and so it is!

In this sound lab, tones can be controlled by 8 parameters: 4 for the ADSR envelope of the loudness and 4 for the frequency modulation that determines the texture.

The addition of the 8 potentiometers did not go at the cost of the number of keys: three sets of 8 keys are readout a few microseconds one after the other, for a total of 24 keys, corresponding to two full octaves. In fact, two Arduino pins are unused and expanding to 40 keys would be possible.

Look at the video for how to make wild sounds, here's a brief overview:

* A=attack: time for a tone to reach its maximum loudness (range 8ms-2s)

* D=decay: time for a tone to go down to its steady level of loudness (range 8ms-2s)

* S=sustain: steady level of loudness (range 0-100%)

* R=release: time for a tone to die out (range 8ms-2s)

* f_m : ratio of the modulation frequency to the carrier frequency (range 0.06-16) values below 1 result in undertones, higher values in overtones

* beta1 : amplitude of the FM modulation at the beginning of the note (range 0.06-16) small values result in minor variations of the sound texture. large values result in crazy sounds

* beta2 : amplitude of the FM modulation at the end of the note (range 0.06-16) Give beta2 a different value than beta1 to make the sound texture evolves in time.

* tau : speed at which the FM amplitude evolves from beta1 to beta 2 (range 8ms-2s) Small values give a short bang at the beginning of a note, large values a long and slow evolution.

Step 1: Construction

Clearly, this is still a prototype, I hope one day me or someone else will build this big and strong and beautiful with large keys and real dials for the potentiometers in an awesome enclosure....

Needed components:

1 Arduino Nano (It won't work with the Uno, which has only 6 analog inputs)

24 push-buttons

8 potentiometers, in the 1kOhm - 100kOhm range

1 potentiometer of 10kOhm for volume control

1 capacitor - 10microfarad electrolitic

1 3.5mm earphone jack

1 LM386 audio amplifier chip

2 1000microfarad electrolitic capacitor

1 ceramic 1microfarad capacitor

1 microswitch

1 8Ohm 2Watt speaker

1 10x15cm prototype board

Make sure you understand the attached schematics. The 24 buttons get connected in 3 groups of 8, to be read out at D0-D7, and to be activated on D8, D10 and D11. The pots have +5V and ground on the end taps and the central taps are fed to the analog inputs A0-A7. D9 has the audio output and gets AC-coupled to a 10kOhm potentiometer for volume control. The sound can be directly listened to with earphones, or amplified with an LM386 audio amplifier chip.

It is all fits on a 10x15cm protoptype board, but the buttons are too close to play well, so it'd be better to construct a larger keyboard.

The circuit can be powered through the USB connection on the Arduino Nano, or with an external 5V power supply. A 2xAA battery box followed by a step-up converter is a perfect powering solution.

Step 2: Software

Upload the attached sketch to the Arduino Nano and all should work.

The code is straigthforward and easy to modify, there is no machine code and no interrupts, but there are a couple of direct interactions with the registers, to interact with the timer, to speed up the button readout and to control the behaviour of the ADC for the potentiometer readout

Step 3: Future Improvements

Ideas from the community are always welcome!

I am most bothered by the buttons: they are tiny and click hard when pushed. It'd be really nice to have larger buttons that more comfortable to push. Also, force- or speed-sensitivy buttons would allow to control the loudness of the notes. Maybe 3-way pushbuttons or touch-sensitive buttons could work?

Other nice things would be to store sound settings in EEPROM, Storing short tunes in EEPROM would also allow to make much more interesting music. Finally, more complex sounds could be generated, if anyone knows how to generate percussion sounds in a computationally efficient way, that'd be awesome...

Arduino Contest 2019

Participated in the
Arduino Contest 2019

3 People Made This Project!

Recommendations

  • Fabric Challenge

    Fabric Challenge
  • Sculpt & Carve Challenge

    Sculpt & Carve Challenge
  • First Time Author Contest

    First Time Author Contest

30 Comments

0
gerhard.et
gerhard.et

Question 1 year ago on Step 1

How should i manipulate the ports, if i use touchsensor as input keys? Only input, no pullup, with TTP223 capacitve touch-switch?

0
rgco
rgco

Answer 1 year ago

I never used those but i seems a good idea, since regular buttons click sound is disturbing. Yes, if these are set to active high, you will have to adapt the code to disable pullup and invert the logic (the present logic is for active low)

0
gerhard.et
gerhard.et

Reply 1 year ago

Hi rgco,
thank you for the quick answer.
It is correct, the sensors are set to active high, but this could be changed. But it might be less effort to change the settings for the input pins in the sketch. However, i have no idea how to do this. Could you please tell me, how i must change the code ( the lines "if(pinD0 != nokey){DDRD &=~(1<<0);PORTD |=(1<<0);}; ???)" for the pins?
For changing activation from active low to high i assume, that i have to interchange the values for "keypressed" and "keyreleased". Is this correct?
Thank you for answering again.
Gerhard

0
rgco
rgco

Reply 1 year ago

In principle it is a matter of changing the >0 to ==0 and vice versa in these lines:

if ( (butstatD1 & (1<<0)) == 0 and (prevbutstatD1 & (1<<0)) >0 ) keypressed=0;
if ( (butstatD1 & (1<<0)) >0 and (prevbutstatD1 & (1<<0)) == 0 ) keyreleased =0;

However, there are some more complications due to the matrix-setup. It's not obvious that the matrix-scheme will work for these touch-sensors. Basically the buttons are divided in 3 groups of 8, which get activated one after the other. with regular buttons, I had to introduce a delay of 3 microseconds between the reading of one row and the other. Those touch buttons are active components, which might need a lot more time. So to read 24 buttons, which is more than the Arduino has pins, I don't think the simple matrix methods works. Looks like it would need shift-registers but that's extra hardware.

Sorry I can only give some general advice, the coding you'll have to do yourself!
Cheers, -Rolf

0
gerhard.et
gerhard.et

Reply 1 year ago

Hi Rolf,
thank you again. I'm sorry, i did not inform you that i want to use your first version of the synth with only 19 buttons. As far as i understand the connection diagramm, these buttons connect to ground when pressed. I'm afraid the touch sensors could be destroyed when connecte to vcc via the internal pullup-restor of 10k . How can i change the definition of a pin to "INPUT" without "PULLUP"?
What i did not mention too:
My intension is to build three synths (e. g. three arduino nano), connected to a guitar-like keyboard with three "strings". For each "string" up to 14 keys are enough. Each synth may be monophon.
Cheers, Gerhard

0
rgco
rgco

Reply 1 year ago

Ah, pullup won't destroy anything, they are pulled up with a high resistance, somewhere in the 20-50kOhm range. Anyway the pullup is done with the PORTD PORTB PORTC writes, whenever a non-zero value is written there, it results in a pull-up, so just write zeros there instead of ones.

0
sebastien.berruyer
sebastien.berruyer

Reply 7 weeks ago

Hi, Rolf. I've tried your method to create a laser harp soundlab, but your suggestion doens't seems to work. Any further idea to change the code for a LDR instead of a push-button?

0
rgco
rgco

Reply 7 weeks ago

It's more than code. When you change input device you'll have to do some research or experimentation on its properties. An LDR may be too slow or its dark/light resistance may not match well a 1/0 transition. I suggest you first make the laser/LDR input work reliably and robustly as a single switch and then gradually recompose the soundlab code around it.

0
sebastien.berruyer
sebastien.berruyer

Reply 6 weeks ago

Hi, Rolf. Thank you for this quick response. On instructables I had found a good tutorial that used lasers and LDRs as digital input instead of analog, https://www.instructables.com/Laser-Piano-DIY/ and it worked fine: doing the same as a push button, but reversed; so I thought it would be possible to do the same thing for the soundlab. I'm just looking for the lines of code corresponding to the 1/0 position of the push buttons.
By the way, the version with push-buttons works perfectly! My 8 year old daughter is thrilled!!

0
astralaster2
astralaster2

7 months ago

This project is so inspiring. I was surprised that a arduino nano can handle a polyphonic fm synthesis. You need nearly no parts for this and the result is so good. Thanks for publishing this project here.
Ive managed to add a serial midi usb connection without interupts. So you can now use midi controllers and play more than 40 tones. You can even just play midi files on the synth.
Check out my code at: https://github.com/astralaster/Arduino-Soundlab
I will update it with more instructions on how to use the midi interface and Im planning to add more features like USB host connection and a LCD.

Thanks a lot!

0
rgco
rgco

Reply 7 months ago

Glad you like it and thanks for sharing the code! I did look a little bit into MIDI but found it too hard to grasp, so made something that played the infinitely simpler RTTL ringtones instead, see https://www.instructables.com/Arduino-Chrismas-Tun...
I'm playing with the idea of porting the method to the much more powerful raspberry pi pico microcontroller, it might be able to play mode complex sounds with higher resolution and/or higher level of polyphony.

0
rgco
rgco

Reply 6 months ago

Thanks! it is very noisy though! is is just the digitisation noise or is something else going on? The polyphony comes out very well thought!
PWM suffers from significant digitisation noise (9-bit is nowhere close to the 16-bit of a CD). A resistor-based DAC or delta-sigma modulation would be better.
The coding of this synthesizer took me a while honestly, but it was just driven by curiosity about the nature of musical notes, most of it is on Wikipedia. Of course a PhD in physics always helps ;)

0
astralaster2
astralaster2

Reply 6 months ago

Yes, its a bit noisy. Im not sure if its from the sustain (this gets noisy really quick) or just from using more voices than the code can handle really. I did found something really interesting: https://www.deeptronic.com/electronic-circuit-desi...
I already looked up the specs of the nano and there is a second pwm register which is currently unused by your code. So it should be possible to use two pwm pins to gain a higher resolution in audio with just some resistors.
The other thing I noticed, you wait for the timer to finish in the pwm function and then calculate the new values for the pwm register. Why dont you calculate them and then wait for the timer to finish? This should be more optimal if I did not miss anything.
And can you elaborate how critical the timing of the whole loop is for the audio? If I understand it correctly its very critical that the timer does not finish before I hit the pwm function, right? But does it matter how many pwm function calls I use?
I already ordered a pico, so I will join your journey of porting this code to the pico. :)

0
rgco
rgco

Reply 6 months ago

Yes, the link you sent is for a hybrid DAC, where PWM and R2R get combined. So 8 MSB by one timer and add them in analog to a 256x attenuated signal for 8 LSB's from a second timer. It's a possible direction...
Concerning the order between calculating and waiting I don't think it makes a difference, it's all in a loop anyway. Note that the calculated pulse length is for the next loop, so the newly set value of the pulse length will only be applied at the next loop (this is the so-called double buffering)
Timing is critical. Any code that takes more than 250 clock cycles between calls to setPWM() will make the sound distorted. That might be another reason for the noise you hear.

During development I had these two lines around the wait statement:

//wait for the timer2 to complete loop
PORTD = 0B00000000;
while ((TIFR2 & 0B00000001) == 0);
PORTD = 0B10000000;

so that with a scope I could see on a pin (here pin D7) how much time was left at the end of every loop, and thus monitor how many clock cycles the calculations were taking up.

0
JohnC1315
JohnC1315

Question 1 year ago

hey this project looks great! I'm building a nice wooden case with wooden keys for it.

I just want to ask: would it be silly to stick 2 of these soundlabs together to get 4 octaves and 8 voice (split by octave) polyphony? I have been studying theccode, but it's a bit hard for me to decipher: I have most of my experience with C# Unity programming.

Also, how would this work with a multiplexer?
Thanks for the great project!

IMG_20201122_075811.jpgIMG_20201122_144837.jpg
0
JohnC1315
JohnC1315

Answer 1 year ago

Hi again,
I'm having trouble with this one. I built the full size, 2 octave synth just as yours is, but the keys did not play a scale. I tore it down and fully rewired the keys, same issue. I have checked my connections twice after that. Still not playing in tune. Also, the lowest C did not play. There was a weird issue where the notes never turned off as well.

I took a break and returned to it this week, building again from scratch. I am trying to build with just 1 octave for simplicity. I tried connecting only 2 keys to test if they were playing correctly before moving on. They don't play correctly. Same issues, but even worse than before. Is there something I'm missing?

0
rgco
rgco

Reply 1 year ago

Sorry to hear your struggles! difficult to judge from a distance. There are many wires. I would debug in pieces. hack the code such that the values from the pots are fixed to central values. Play a single button. Activate the serial print and see if the buttons are being pressed.

Note that I have posted 2 simpler versions of this project:
https://www.instructables.com/Arduino-Synthesizer-...
https://www.instructables.com/Arduino-Chrismas-Tun...
The latter is good in particular to test the speaker

0
JohnC1315
JohnC1315

Reply 1 year ago

Thanks for the reply! I was able to get better sound and correct envelopes. However the 2 keys I wired up were D2 and E2, but they play the notes B1 and C1 respectively. There are only 4 connections, so it was easy to see that they were connected correctly. No other keys are wired up. Is the key press logic changed by having keys unwired?

I tried checking the code too. Would E2 be number 17 in those conditional statements? In those lines of code, I don't understand where/ how the pin names are tested. Sorry for my code illiteracy, but I wanted to focus on making a nice case

0
rgco
rgco

Reply 1 year ago

Hard to judge from what you're writing. I suggest you keep adding buttons. In the code it is trivial to change the note assignment to each button. The notes run 0-23 which have been set up to correspond to C4-B5. If it sounds weird or out of order with all buttons in place, you can fix it in either hardware or software.
NB. I have started with a new budget microcontroller, the raspberry pi pico, it has more pins, more memory and higher speed. It should be able to do more octaves, higher polyphony and fancier sounds. I'm sure it won't take long someone does it (sorry my interests are moving more towards instrumentation for citizen science)