——
#donluc #sound #simplekeyboard #synthesizer #555 #programming #arduino #fritzing #electronics #microcontrollers #consultant #vlog
——

——

——
It is 2015 an microcontroller-based (Arduino), 2 x 555 timer IC music synthesizer. It will be both a hardware and a software synthesizer.
DL2011Mk02
1 x Arduino Pro Mini 328 – 3.3V/8MHz
16 x Tactile Button
4 x 1K Potentiometer
4 x Knob
1 x Audio Jack 3.5mm
1 x SparkFun Audio Jack Breakout
1 x Hamburger Mini Speaker
2 x 555 Timer IC
1 x SparkFun Cerberus USB Cable
1 x SparkFun FTDI Basic Breakout – 3.3V
Etc…
Arduino Pro Mini 328 – 3.3V/8MHz
SPK – Digital 11
KY2 – Digital 2
KY3 – Digital 3
KY4 – Digital 4
KY5 – Digital 5
KY6 – Digital 6
KY7 – Digital 7
KY8 – Digital 8
KY9 – Digital 9
PO1 – Analog A2
VIN – +3.3V
GND – GND
DL2011Mk02p.ino
// ***** Don Luc Electronics © *****
// Software Version Information
// Project #16: Sound - Synthesizer - Mk08
// 11-02
// DL2011Mk02p.ino 16-08
// 1 x Arduino Pro Mini 328 - 3.3V/8MHz
// 16 x Tactile Button
// 4 x 1K Potentiometer
// 4 x Knob
// 1 x Audio Jack 3.5mm
// 1 x SparkFun Audio Jack Breakout
// 1 x Hamburger Mini Speaker
// 2 x 555 Timer IC
// 1 x SparkFun Cerberus USB Cable
// 1 x SparkFun FTDI Basic Breakout - 3.3V
// Etc...
// Include the Library Code
// Pitches
#include "pitches.h"
// Waveform - Chimes
#include "chimes.h"
using namespace Chimes;
// Sum of ADSR values must not exceed 100%
uint8_t envelope[] = {
0, // Attack[%]
20, // Decay[%]
0, // Sustain[%]
80, // Release[%]
15 // Sustain Level 1..32
};
// Simple Keyboard
// Minimum reading of the button that generates a note
const int iKeyboard2 = 2;
const int iKeyboard3 = 3;
const int iKeyboard4 = 4;
const int iKeyboard5 = 5;
const int iKeyboard6 = 6;
const int iKeyboard7 = 7;
const int iKeyboard8 = 8;
const int iKeyboard9 = 9;
// Button is pressed
int aa = 1;
int bb = 1;
int cc = 1;
int dd = 1;
int ee = 1;
int ff = 1;
int gg = 1;
int hh = 1;
// Frequency
int iCap = A2;
int iFreg = 0;
int iNoteA = 0;
int iNoteB = 0;
int iNoteC = 0;
int iNoteD = 0;
int iNoteE = 0;
int iNoteF = 0;
int iNoteG = 0;
int iNoteAA = 0;
// Software Version Information
String sver = "16-08";
void loop() {
// Rotary Switch
//isRotary();
// Frequency
isPitches();
// Keyboard
isKeyboard();
}
chimes.cpp
/*This work is licensed under the Creative Commons Attribution-ShareAlike 4.0 International License.
To view a copy of this license, visit https://creativecommons.org/licenses/by-sa/4.0/deed.en */
#include
#include "chimes.h"
#define ISR_CYCLE 16 //16s
char strbuf[255];
uint16_t ADSR_default[] = {0, 0, 100, 0, MAX_VOLUME};
uint16_t ADSR_env[5];
uint16_t nSamples; //Number of samples in Array
uint8_t adsrPhase;
uint32_t tPeriod;
uint8_t *samples; //Array with samples
uint8_t *_envelope, _waveform, _duty_cycle;
uint16_t &_sustain_lvl = ADSR_env[4];
enum ADSR_phase
{
ATTACK,
DECAY,
SUSTAIN,
RELEASE
};
namespace Chimes
{
void init(uint8_t waveform, uint8_t duty_cycle, uint8_t *envelope)
{
Serial.begin(115200);
//PWM Signal generation
DDRB |= (1 << PB3) + (1 << PB0); //OC2A, Pin 11
TCCR2A = (1 << WGM21) + (1 << WGM20); //Fast PWM
TCCR2A |= (0 << COM2A0) + (1 << COM2A1); //Set OC2A on compare match, clear OC2A at BOTTOM,(inverting mode).
TCCR2B = (0 << CS22) + (0 << CS21) + (1 << CS20); //No Prescaling
samples = (uint8_t *)malloc(0);
_waveform = waveform;
_duty_cycle = duty_cycle;
_envelope = envelope;
}
void play(uint16_t freq, uint16_t duration)
{
uint8_t waveform = _waveform;
//Init adsr according to the length of the note
for (int i = 0; i < 4; i++)
{
if (_envelope)
{
ADSR_env[i] = (uint32_t)_envelope[i] * duration / 100;
}
else
{
ADSR_env[i] = (uint32_t)ADSR_default[i] * duration / 100;
}
//Serial.println(ADSR_env[i]);
}
ADSR_env[4] = _envelope ? _envelope[4] : MAX_VOLUME;
//Serial.println(ADSR_env[4]);
if (freq == 0)
{ //Pause
tPeriod = ISR_CYCLE * 100;
waveform = PAUSE;
}
else
tPeriod = 1E6 / freq;
nSamples = tPeriod / ISR_CYCLE;
realloc(samples, nSamples);
uint16_t nDuty = (_duty_cycle * nSamples) / 100;
switch (waveform)
{
case SINE: //Sinewave
for (int i = 0; i < nSamples; i++)
{
samples[i] = 128 + 127 * sin(2 * PI * i / nSamples);
}
break;
case TRI: //Triangle
for (int16_t i = 0; i < nSamples; i++)
{
if (i < nDuty)
{
samples[i] = 255 * (double)i / nDuty; //Rise
}
else
{
samples[i] = 255 * (1 - (double)(i - nDuty) / (nSamples - nDuty)); //Fall
}
}
break;
case RECT: //Rectangle
for (int16_t i = 0; i < nSamples; i++)
{
i < nDuty ? samples[i] = 255 : samples[i] = 0;
}
break;
case PAUSE: //Rectangle
memset(samples, 0, nSamples);
}
TIMSK2 = (1 << TOIE2);
/*for(uint16_t i = 0; i < nSamples; i++) {
sprintf(strbuf, "%d: %d", i, samples[i]);
Serial.println(strbuf);
}*/
}
//Returns true, while note is playing
boolean isPlaying()
{
return (1 << TOIE2) & TIMSK2;
}
} // namespace Chimes
//Called every 16s, when TIMER1 overflows
ISR(TIMER2_OVF_vect)
{
static uint32_t adsr_timer, adsr_time;
static uint16_t cnt; //Index counter
static uint8_t sustain_lvl, vol;
//Set OCR2A to the next value in sample array, this will change the duty cycle accordingly
OCR2A = vol * samples[cnt] / MAX_VOLUME;
if (cnt < nSamples - 1)
{
cnt++;
}
else
{
cnt = 0;
adsr_timer += tPeriod;
if (adsr_timer >= 10000)
{ //every 10 millisecond
adsr_timer = 0;
switch (adsrPhase)
{
case ATTACK:
if (ADSR_env[ATTACK])
{
vol = MAX_VOLUME * (float)adsr_time / ADSR_env[ATTACK];
if (vol == MAX_VOLUME)
{ //Attack phase over
adsrPhase = DECAY;
adsr_time = 0;
}
}
else
{
adsrPhase = DECAY;
vol = MAX_VOLUME;
adsr_time = 0;
}
break;
case DECAY:
if (ADSR_env[DECAY])
{
sustain_lvl = _sustain_lvl;
vol = MAX_VOLUME - (MAX_VOLUME - _sustain_lvl) * (float)adsr_time / ADSR_env[DECAY];
if (vol <= sustain_lvl)
{
adsr_time = 0;
adsrPhase = SUSTAIN;
}
}
else
{
adsrPhase = SUSTAIN;
sustain_lvl = MAX_VOLUME;
adsr_time = 0;
}
break;
case SUSTAIN:
if (adsr_time > ADSR_env[SUSTAIN])
{
adsrPhase = RELEASE;
adsr_time = 0;
}
break;
case RELEASE:
if (ADSR_env[RELEASE])
{
vol = sustain_lvl * (1 - (float)adsr_time / ADSR_env[RELEASE]);
if (vol == 0)
{ //Attack phase over
adsr_time = 0;
TIMSK2 = (0 << TOIE2);
adsrPhase = ATTACK;
}
}
else
{
adsrPhase = ATTACK;
vol = 0;
adsr_time = 0;
TIMSK2 = (0 << TOIE2);
}
break;
}
adsr_time += 10;
}
}
}
chimes.h
/*This work is licensed under the Creative Commons Attribution-ShareAlike 4.0 International License.
To view a copy of this license, visit https://creativecommons.org/licenses/by-sa/4.0/deed.en */
#ifndef CHIMES_H
#define CHIMES_H
#include "Arduino.h"
enum waveform
{
SINE, //Sinus
RECT, //Triangle
TRI, //Rectangle
PAUSE //Internal, do not use
};
#define MAX_VOLUME 32
namespace Chimes
{
void init(uint8_t waveform = SINE, uint8_t duty_cycle = 50, uint8_t *envelope = NULL);
void play(uint16_t freq, uint16_t duration);
//Returns true while note is playing
boolean isPlaying();
} // namespace Chimes
#endif
getKeyboard.ino
// getKeyboard
// setupKeyboard
void setupKeyboard() {
// Initialize the pushbutton pin as an input
pinMode(iKeyboard2, INPUT_PULLUP);
pinMode(iKeyboard3, INPUT_PULLUP);
pinMode(iKeyboard4, INPUT_PULLUP);
pinMode(iKeyboard5, INPUT_PULLUP);
pinMode(iKeyboard6, INPUT_PULLUP);
pinMode(iKeyboard7, INPUT_PULLUP);
pinMode(iKeyboard8, INPUT_PULLUP);
pinMode(iKeyboard9, INPUT_PULLUP);
}
// isKeyboard
void isKeyboard() {
// Read the state of the pushbutton value
if ( digitalRead(iKeyboard2) == LOW ) {
// Button is pressed - pullup keeps pin high normally
aa = aa + 1;
// Waveform
isPlaying();
play(iNoteA, 500);
}
else
{
aa = aa - 1;
}
// Read the state of the pushbutton value
if ( digitalRead(iKeyboard3) == LOW ) {
// Button is pressed - pullup keeps pin high normally
bb = bb + 1;
// Waveform
isPlaying();
play(iNoteB, 500);
}
else
{
bb = bb - 1;
}
// Read the state of the pushbutton value
if ( digitalRead(iKeyboard4) == LOW ) {
// Button is pressed - pullup keeps pin high normally
cc = cc + 1;
// Waveform
isPlaying();
play(iNoteC, 500);
}
else
{
cc = cc - 1;
}
// Read the state of the pushbutton value
if ( digitalRead(iKeyboard5) == LOW ) {
// Button is pressed - pullup keeps pin high normally
dd = dd + 1;
// Waveform
isPlaying();
play(iNoteD, 500);
}
else
{
dd = dd - 1;
}
// Read the state of the pushbutton value
if ( digitalRead(iKeyboard6) == LOW ) {
// Button is pressed - pullup keeps pin high normally
ee = ee + 1;
// Waveform
isPlaying();
play(iNoteE, 500);
}
else
{
ee = ee - 1;
}
// Read the state of the pushbutton value
if ( digitalRead(iKeyboard7) == LOW ) {
// Button is pressed - pullup keeps pin high normally
ff = ff + 1;
// Waveform
isPlaying();
play(iNoteF, 500);
}
else
{
ff = ff - 1;
}
// Read the state of the pushbutton value
if ( digitalRead(iKeyboard8) == LOW ) {
// Button is pressed - pullup keeps pin high normally
gg = gg + 1;
// Waveform
isPlaying();
play(iNoteG, 500);
}
else
{
gg = gg - 1;
}
// Read the state of the pushbutton value
if ( digitalRead(iKeyboard9) == LOW ) {
// Button is pressed - pullup keeps pin high normally
hh = hh + 1;
// Waveform
isPlaying();
play(iNoteAA, 500);
}
else
{
hh = hh - 1;
}
// Waveform
isPlaying();
play(0, 50);
}
getPitches.ino
// Pitches
// isPitches
void isPitches(){
// Frequency
iFreg = analogRead(iCap);
iFreg = map(iFreg, 0, 1023, 1, 6);
// Range Frequency Note Low => High
switch ( iFreg ) {
case 1:
// NOTE A1
iNoteA = NOTE_A1;
iNoteB = NOTE_B1;
iNoteC = NOTE_C2;
iNoteD = NOTE_D2;
iNoteE = NOTE_E2;
iNoteF = NOTE_F2;
iNoteG = NOTE_G2;
iNoteAA = NOTE_A2;
break;
case 2:
// NOTE A2
iNoteA = NOTE_A2;
iNoteB = NOTE_B2;
iNoteC = NOTE_C3;
iNoteD = NOTE_D3;
iNoteE = NOTE_E3;
iNoteF = NOTE_F3;
iNoteG = NOTE_G3;
iNoteAA = NOTE_A3;
break;
case 3:
// NOTE A3
iNoteA = NOTE_A3;
iNoteB = NOTE_B3;
iNoteC = NOTE_C4;
iNoteD = NOTE_D4;
iNoteE = NOTE_E4;
iNoteF = NOTE_F4;
iNoteG = NOTE_G4;
iNoteAA = NOTE_A4;
break;
case 4:
// NOTE A4
iNoteA = NOTE_A4;
iNoteB = NOTE_B4;
iNoteC = NOTE_C5;
iNoteD = NOTE_D5;
iNoteE = NOTE_E5;
iNoteF = NOTE_F5;
iNoteG = NOTE_G5;
iNoteAA = NOTE_A5;
break;
case 5:
// NOTE A5
iNoteA = NOTE_A5;
iNoteB = NOTE_B5;
iNoteC = NOTE_C6;
iNoteD = NOTE_D6;
iNoteE = NOTE_E6;
iNoteF = NOTE_F6;
iNoteG = NOTE_G6;
iNoteAA = NOTE_A6;
break;
case 6:
// NOTE A6
iNoteA = NOTE_A6;
iNoteB = NOTE_B6;
iNoteC = NOTE_C7;
iNoteD = NOTE_D7;
iNoteE = NOTE_E7;
iNoteF = NOTE_F7;
iNoteG = NOTE_G7;
iNoteAA = NOTE_A7;
break;
}
}
pitches.h
/*****************************************************************
* Pitches NOTE_B0 <=> NOTE_DS8 - NOTE_A4 is "A" measured at 440Hz
*****************************************************************/
#define NOTE_B0 31
#define NOTE_C1 33
#define NOTE_CS1 35
#define NOTE_D1 37
#define NOTE_DS1 39
#define NOTE_E1 41
#define NOTE_F1 44
#define NOTE_FS1 46
#define NOTE_G1 49
#define NOTE_GS1 52
#define NOTE_A1 55
#define NOTE_AS1 58
#define NOTE_B1 62
#define NOTE_C2 65
#define NOTE_CS2 69
#define NOTE_D2 73
#define NOTE_DS2 78
#define NOTE_E2 82
#define NOTE_F2 87
#define NOTE_FS2 93
#define NOTE_G2 98
#define NOTE_GS2 104
#define NOTE_A2 110
#define NOTE_AS2 117
#define NOTE_B2 123
#define NOTE_C3 131
#define NOTE_CS3 139
#define NOTE_D3 147
#define NOTE_DS3 156
#define NOTE_E3 165
#define NOTE_F3 175
#define NOTE_FS3 185
#define NOTE_G3 196
#define NOTE_GS3 208
#define NOTE_A3 220
#define NOTE_AS3 233
#define NOTE_B3 247
#define NOTE_C4 262
#define NOTE_CS4 277
#define NOTE_D4 294
#define NOTE_DS4 311
#define NOTE_E4 330
#define NOTE_F4 349
#define NOTE_FS4 370
#define NOTE_G4 392
#define NOTE_GS4 415
#define NOTE_A4 440
#define NOTE_AS4 466
#define NOTE_B4 494
#define NOTE_C5 523
#define NOTE_CS5 554
#define NOTE_D5 587
#define NOTE_DS5 622
#define NOTE_E5 659
#define NOTE_F5 698
#define NOTE_FS5 740
#define NOTE_G5 784
#define NOTE_GS5 831
#define NOTE_A5 880
#define NOTE_AS5 932
#define NOTE_B5 988
#define NOTE_C6 1047
#define NOTE_CS6 1109
#define NOTE_D6 1175
#define NOTE_DS6 1245
#define NOTE_E6 1319
#define NOTE_F6 1397
#define NOTE_FS6 1480
#define NOTE_G6 1568
#define NOTE_GS6 1661
#define NOTE_A6 1760
#define NOTE_AS6 1865
#define NOTE_B6 1976
#define NOTE_C7 2093
#define NOTE_CS7 2217
#define NOTE_D7 2349
#define NOTE_DS7 2489
#define NOTE_E7 2637
#define NOTE_F7 2794
#define NOTE_FS7 2960
#define NOTE_G7 3136
#define NOTE_GS7 3322
#define NOTE_A7 3520
#define NOTE_AS7 3729
#define NOTE_B7 3951
#define NOTE_C8 4186
#define NOTE_CS8 4435
#define NOTE_D8 4699
#define NOTE_DS8 4978
setup.ino
// Setup
void setup() {
// Setup Keyboard
setupKeyboard();
// Waveform
init(
// SINE, TRI and RECT
SINE,
// Duty cycle 0..100%, only matters for Triangle and Rectangle
50,
// Envelope
envelope);
}
Technology Experience
- Single-Board Microcontrollers (PIC, Arduino, Raspberry Pi,Espressif, etc...)
- Robotics
- Research & Development (R & D)
- Desktop Applications (Windows, OSX, Linux, Multi-OS, Multi-Tier, etc...)
- Mobile Applications (Android, iOS, Blackberry, Windows Mobile, Windows CE, etc...)
- Web Applications (LAMP, Scripting, Java, ASP, ASP.NET, RoR, Wakanda, etc...)
- Social Media Programming & Integration (Facebook, Twitter, YouTube, Pinterest, etc...)
- Content Management Systems (WordPress, Drupal, Joomla, Moodle, etc...)
- Bulletin Boards (phpBB, SMF, Vanilla, jobberBase, etc...)
- eCommerce (WooCommerce, OSCommerce, ZenCart, PayPal Shopping Cart, etc...)
Instructor
- Arduino
- Raspberry Pi
- Espressif
- Robotics
- DOS, Windows, OSX, Linux, iOS, Android, Multi-OS
- Linux-Apache-PHP-MySQL
Follow Us
J. Luc Paquin – Curriculum Vitae
https://www.donluc.com/DLHackster/LucPaquinCVEngMk2020a.pdf
Web: https://www.donluc.com/
Web: http://www.jlpconsultants.com/
Web: https://www.donluc.com/DLHackster/
Web: https://www.hackster.io/neosteam-labs
Facebook: https://www.facebook.com/neosteam.labs.9/
YouTube: https://www.youtube.com/channel/UC5eRjrGn1CqkkGfZy0jxEdA
Twitter: https://twitter.com/labs_steam
Pinterest: https://www.pinterest.com/NeoSteamLabs/
Instagram: https://www.instagram.com/luc.paquin/
Don Luc