SYNTHESIZER Made From Scratch
by Arnov Sharma in Circuits > Speakers
2342 Views, 18 Favorites, 0 Comments
SYNTHESIZER Made From Scratch
Hey everyone, what's up!
So here's a fun project that involves Music modulation, the MIDI SYNTH BOX made from scratch using PCBs and 3D Printed parts.
This MIDI SYNTH BOX is a simple Midi Sound modulation circuit based around Atmega328PU Minimal Setup uses the Mozzie library to generate tones that are controlled by the five potentiometers.
This project is a culmination of previously made versions that are now finished and are part of my synth projects.
Here are just a few of the synth projects I've been working on over the last two years.
https://www.instructables.com/Neko-Punk-Synth-V2/
https://www.instructables.com/Atari-Punk-Synth-Neko-Edition/
https://www.instructables.com/Arduino-Atari-Synth/
It has an onboard power source that powers the speaker and a small Atemga328 setup using a lithium ion battery.
A PCB that serves as the main control console and the lid for this device is combined with a 3D-printed body and speaker grill to create the entire object, which has dimensions of 95x95x50mm.
This instructables is about how this project was made and how you can prepare a simple synth with any dev board with few easy steps, so lets get started.
Supplies
These were the materials used in this small built-
- Atmega328PU
- Custom PCB
- IP5303 Power management IC
- 1uF Capacitor SMD 0805 Package
- 1uF Electrolitic Capacitor
- 4 Ohms speaker
- 3D Printed parts
- Arduino Nano
- USB Micro Port
- Potentiometers
- Vertical Switch
- 10K Resistance
- Indicator LED 0603 Package
- 1K Resistor
- 1uH Inductor
Concept and 3D Design
During Lockdown, I created the Atari Punk Synth Project, which is where it all began. The idea was to recreate the legendary "Atari Punk Synth" from the 1980s.
In this version, I've used an ATmega328PU with a simple configuration and some pots to imitate the so-called "Sound Synthesizer," which was typically based on a 556 dual timer IC.
Based on the Mozzie Library, my version consists of a square 95x95mm PCB, a base with speakers on the front and control PCBs on the back, and a lithium cell enclosed in a holder.
Fusion360 was used to create a basic CAD design, which was then 3D printed with clear PLA for the body and black PLA for the speaker grill.
PCB Design
In order to create the PCB design for this project, a simple Atmega328PU setup is first created. This setup consists of an Atmega328PU connected to a 10K resistor with a reset pin and a resonator circuit composed of two 22 pF capacitors connected to a 16 mHz crystal oscillator.
This circuit also includes a PAM8403 amplifier, which is used to power the 4 ohm speaker.
The 3.7V of the lithium cell is increased to a stable 5V for powering the Atmega configuration in this setup using the power management IC, the IP5303 IC.
We export the netlist and prepare the board in the PCB Editor after configuring the schematic.
The PCB editing procedure includes creating a 95x95mm outline, arranging the pots, power management IC, and atmega setup on it, and connecting them.
SEEED FUSION PCB SERVICE
After finalizing the PCB and generating its Gerber data, I send it to SEEED STUDIO for samples.
I ordered PCBs in red Solder mask with white silkscreen.
PCBs were received in a week, and their quality was super good considering the rate, which was also pretty low.
Seeed Fusion PCB Service offers one-stop prototyping for PCB manufacture and PCB assembly, and as a result, they produce superior quality PCBs and Fast turnkey PCBA within 7 working days.
PCB Quality of this MIDI BOX PCB WAS SUPER!
Seeed Studio Fusion PCB Assembly Service takes care of the entire fabrication process from Seeed Studio Fusion PCB Assembly Service takes care of the entire fabrication process from Seeed Studio Fusion Agile manufacturing and hardware customization, parts sourcing, assembly, and testing services, so you can be sure that they are getting a quality product.
After gauging market interest and verifying a working prototype, Seeed Propagate Service can help you bring the product to market with professional guidance and a strong network of connections.
Next, is the PCB assembly process.
PCB Assembly
Two main parts make up the PCB assembly procedure for this project: first, we add SMD components, and then we insert THT components.
- We begin by applying solder paste to each component pad individually using a solder paste dispensing syringe.
- Next, we pick and place all the components in their proper places using ESD tweezers.
- Following the pick and place process, we place this board on a mini reflow hotplate, which heats the PCB from the bottom up to the solder paste melting temperature.
- The USB port, potentiometers, and Atmega328PU are then placed in their correct locations together with the rest of the THT component
- After using a soldering iron to connect their pads, we add a lithium battery holder to the circuit's bottom side.
- The circuit is now fully assembled.
Power Source
A 3.7V 2900mAh 18650 lithium-ion battery serves as the power source for the complete system, while the IP5303 power management IC provides consistent 5V output to power the Atmega setup and speaker.
Programming the ATMEGA328PU
This project makes use of an ATMEGA328PU, a member of ATMEL's 8-bit MCUs and the same MCU found in the Arduino UNO.
With the help of a simple sketch called "Arduino as ISP," which can be found in the Arduino IDE example menu, we can program an ATMEGA328PU using an existing Arduino board.
The Atmega328PU has a little hex file onboard known as a bootloader, which is similar to the BIOS. Cheap Atmega328PU don't usually come with a preinstalled bootloader, so I have to burn the bootloader onto the MCU, and for that, I used one of my previous projects, which was an Arduino-based Attiny Programmer.
The Programmer was created to upload "Arduino as ISP Sketch" onto a standard Arduino Nano R3 with a few modifications in order to burn the bootloader and Flash code into the Attiny MCUs (adding 1uf Cap between reset and GND)
I attached the SPI pins of the Arduino Nano and the Atmega328PU, burned the bootloader for the Atmega328PU, and uploaded the main code to the microcontroller.
Main Code
This was the main code that was used in this build, and before using it, you need to install MOZZIE Library, which you can download from the below link.
https://sensorium.github.io/Mozzi/
Here's the main code-
(Please note that LDR are acually replaced with POTs)
#include <MozziGuts.h>
#include <Oscil.h> // oscillator
#include <tables/cos2048_int8.h> // table for Oscils to play
#include <Smooth.h>
#include <AutoMap.h> // maps unpredictable inputs to a range
// int freqVal;
// desired carrier frequency max and min, for AutoMap
const int MIN_CARRIER_FREQ = 22;
const int MAX_CARRIER_FREQ = 440;
const int MIN = 1;
const int MAX = 10;
const int MIN_2 = 1;
const int MAX_2 = 15;
// desired intensity max and min, for AutoMap, note they're inverted for reverse dynamics
const int MIN_INTENSITY = 700;
const int MAX_INTENSITY = 10;
// desired 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;
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 mapThis(0,1023,MIN,MAX);
AutoMap mapThisToo(0,1023,MIN_2,MAX_2);
const int KNOB_PIN = 0; // set the input for the knob to analog pin 0
const int LDR1_PIN=1; // set the analog input for fm_intensity to pin 1
const int LDR2_PIN=2; // set the analog input for mod rate to pin 2
const int LDR3_PIN=4;
const int LDR4_PIN=3;
Oscil<COS2048_NUM_CELLS, AUDIO_RATE> aCarrier(COS2048_DATA);
Oscil<COS2048_NUM_CELLS, AUDIO_RATE> aModulator(COS2048_DATA);
Oscil<COS2048_NUM_CELLS, CONTROL_RATE> kIntensityMod(COS2048_DATA);
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(){
// freqVal = map(LDR3_PIN, 0, 1023, 1, 100);
int freqVal = mozziAnalogRead(LDR3_PIN); // value is 0-1023
int FRQ = mapThis(freqVal);
int knob2 = mozziAnalogRead(LDR4_PIN); // value is 0-1023
int knob2Val = mapThis(knob2);
// read the knob
int knob_value = mozziAnalogRead(KNOB_PIN); // value is 0-1023
// map the knob to carrier frequency
int carrier_freq = kMapCarrierFreq(knob_value);
//calculate the modulation frequency to stay in ratio
int mod_freq = carrier_freq * mod_ratio * FRQ;
// set the FM oscillator frequencies
aCarrier.setFreq(carrier_freq);
aModulator.setFreq(mod_freq);
// read the light dependent resistor on the width Analog input pin
int LDR1_value= mozziAnalogRead(LDR1_PIN); // value is 0-1023
// print the value to the Serial monitor for debugging
//Serial.print("LDR1 = ");
// Serial.print(LDR1_value);
// Serial.print("\t"); // prints a tab
int LDR1_calibrated = kMapIntensity(LDR1_value);
// Serial.print("LDR1_calibrated = ");
// Serial.print(LDR1_calibrated);
// Serial.print("\t"); // prints a tab
// calculate the fm_intensity
fm_intensity = ((long)LDR1_calibrated * knob2Val * (kIntensityMod.next()+128))>>8; // shift back to range after 8 bit multiply
// Serial.print("fm_intensity = ");
// Serial.print(fm_intensity);
// Serial.print("\t"); // prints a tab
// read the light dependent resistor on the speed Analog input pin
int LDR2_value= mozziAnalogRead(LDR2_PIN); // value is 0-1023
// Serial.print("LDR2 = ");
// Serial.print(LDR2_value);
// Serial.print("\t"); // prints a tab
// use a float here for low frequencies
float mod_speed = (float)kMapModSpeed(LDR2_value)/1000;
//Serial.print(" mod_speed = ");
// Serial.print(mod_speed);
kIntensityMod.setFreq(mod_speed);
// Serial.println(); // finally, print a carraige return for the next line of debugging info
}
int updateAudio(){
long modulation = aSmoothIntensity.next(fm_intensity) * aModulator.next();
return aCarrier.phMod(modulation);
}
void loop(){
audioHook();
}
This code is an example of using the Mozzi library to generate audio modulation effects based on input from various sensors.
Here's a breakdown of the code:
1. The code includes several header files from the Mozzi library, which provide various functionalities for audio synthesis and control.
2. Constants are defined for minimum and maximum values of carrier frequency, intensity, and modulation speed. These values are used for mapping input values to the desired range.
3. AutoMap objects are created to map input values to the desired range of carrier frequency, intensity, and modulation speed.
4. Pin assignments are defined for the analog inputs, representing knobs and light-dependent resistors (LDRs) connected to the Arduino board.
5. Oscillator objects are created for the carrier, modulator, and intensity modulation signals. These oscillators generate audio waveforms based on pre-defined lookup tables.
6. Variables are defined for the modulation ratio, FM intensity, and smoothing factor for intensity transitions.
7. The `setup()` function initializes the serial communication and starts the Mozzi audio synthesis.
8. The `updateControl()` function is called repeatedly to read and process sensor inputs. It performs the following tasks:
- Reads the values of LDR3 and LDR4, representing frequency and knob inputs, respectively.
- Maps the frequency value to a desired range.
- Maps the knob value to the carrier frequency.
- Calculates the modulation frequency based on the carrier frequency, modulation ratio, and frequency value.
- Sets the frequencies of the carrier and modulator oscillators.
- Reads the value of LDR1, representing the intensity input.
- Calibrates the intensity value using the mapped value.
- Calculates the FM intensity based on the calibrated intensity, knob2 value, and the next value from the intensity modulation oscillator.
- Reads the value of LDR2, representing the modulation speed input.
- Maps the modulation speed value to a desired range and sets the frequency of the intensity modulation oscillator.
9. The `updateAudio()` function is called repeatedly to generate audio samples. It performs the following tasks:
- Calculates the modulation value by multiplying the smoothed FM intensity and the output of the modulator oscillator.
- Applies phase modulation to the carrier oscillator using the modulation value.
- Returns the resulting audio sample.
10. The `loop()` function continuously calls the `audioHook()` function, which updates the audio output.
In summary, this code sets up audio modulation effects based on sensor inputs. It maps the sensor values to control parameters such as carrier frequency, intensity, and modulation speed, and generates audio based on these parameters.
SPEAKER
It was decided to use a generic 4 ohm speaker as the main driver because it was adequate for this project. It is possible to add speakers that produce much higher tones, but doing so would necessitate the addition of a power amplifier. While this is technically possible, it is not advised because it will result in a variety of sounds with various pitches and frequencies. Do this only if you despise your neighbors.
We connect a 1uF capacitor in series with the output I/O port's positive terminal.
Adding a 1uF electrolytic capacitor in series with a speaker serves as a DC blocking mechanism. It prevents any direct current (DC) component present in the audio signal from reaching the speaker. This helps protect the speaker from potential damage that could occur if a DC offset were to drive the speaker cone to one extreme and keep it there. By blocking the DC component, only the alternating current (AC) audio signal is allowed to pass through and produce sound from the speaker.
Main Assembly
- Four M3 nuts and bolts are used to attach the speaker to the 3D-printed speaker grill as the first step in the main assembly.
- Next, using four M2 screws, we attach the speaker grill assembly to one side of the 3D-printed base.
- The assembly is then finished by attaching the main circuit to the bottom side of the mid body assembly using the same M2 screws.
RESULT
The outcome of this straightforward construction is a functional but odd-sounding MIDI synthesizer that can produce a variety of sci-fi sounds, including cat meowing, R2D2 beeping, and other sounds of a like sort.
All praise goes to the Mozzie Library for modifying the sound without the addition of any additional external ICs, which is like a 50% JOB.
That's it for now, everyone. Please leave a comment if you need any assistance with this project.
Check out my previous synth projects if you're into DIY SYNTH rigs.
https://www.instructables.com/Neko-Punk-Synth-V2/
https://www.instructables.com/Atari-Punk-Synth-Neko-Edition/
https://www.instructables.com/Arduino-Atari-Synth/
All the documents related to the project are attached, if you need any help regarding this project, DM me or comment.
Special thanks to Seeed Studio for providing PCBs for this project, do check them out if you need great PCB service for a lower cost.
Peace out, and I'll be back with a new project soon!