I am trying to make a polyphonic music player with buzzers & Arduino. I was following this tutorial as a guide but I can't figure out something. Code is like:
void playTone() {
long elapsed_time = 0;
if (tone_ > 0) { // if this isn't a Rest beat, while the tone has
// played less long than 'duration', pulse speaker HIGH and LOW
while (elapsed_time < duration) {
digitalWrite(speakerOut, HIGH);
delayMicroseconds(tone_ / 2);
// DOWN
digitalWrite(speakerOut, LOW);
delayMicroseconds(tone_ / 2);
// Keep track of how long we pulsed
elapsed_time += (tone_);
}
}
else { // Rest beat; loop times delay
for (int j = 0; j < rest_count; j++) { // See NOTE on rest_count
delayMicroseconds(duration);
}
}
}
void loop() {
// Set up a counter to pull from melody[] and beats[]
for (int i = 0; i<MAX_COUNT; i++) {
tone_ = melody[i];
beat = beats[i];
duration = beat * tempo; // Set up timing
playTone();
// A pause between notes...
delayMicroseconds(pause);
}
}
I am stucked at "digitalWrite(speakerOut, HIGH);" line. Ok before I call playTone function I set "tone_ = melody[i];" but in the function we only use this in delay function.
My question is how it follows the melody array? Based on that I will add one more buzzer and control it by another array but now I can't do anything...
I see your confusion as your program is blocking (just delay in loop) you can not add more melodies in parallel. The solution is to rewrite your code to non blocking interface using timer/counter and iterative process. For simplicity lets assume simple digital 1 bit sound. To ensure polyphony latter we need to have PWM so we can add more channels together.
Lets start with monophonic tone
for each sound channel you need to have actual state stored like:
T
[T] where T = ftimer/ftone
t
[T] where 0 <= t <= T
A
[-] or volume should be A <= T/2
on
(ON/OFF)
where [T] represents the period of some timer/counter this will be updated with (sampling rate) converting all the values into integers. Now you just create some update
function that will be called from some timer periodically with high enough frequency and which will decide the state of speaker (on/off).
Melody
simply add some counter n
[T] that represents how many cycles current tone should be playing. And in the update
decrement it and if it hits zero fetch new tone from your melody table. So you need to add also some index which tone from your melody is currently playing.
polyphony
well you can achieve it by HW by wire-oring more digital pins (one per each channel). But this is doable also by SW means. Simply add each channel logicaly together by oring the on
value of each should channel together and set the speaker by its result (A|B
). That work but the output quality is not very good. Much better is use arithmetic addition (A+B
) and use the result as a PWM for output that has some multiple of the sample frequency used for tone synthesis.
You can also use DAC instead of PWM too ...
I do not code for ARDUINO so I can not share full code. However on mine AVR32 the C/C++ code looks like this:
//---------------------------------------------------------------------------
#ifndef _music_h
#define _music_h
//---------------------------------------------------------------------------
#ifdef VCL_H
#define U8 BYTE
#define U16 WORD
#define U32 DWORD
#endif
//---------------------------------------------------------------------------
//#define _music_shifted_notes
//---------------------------------------------------------------------------
// volume
#define music_A 5
// max channels
#define music_sys_T 3
// _music update freq
#define music_f ftim0/music_sys_T
//---------------------------------------------------------------------------
// music frequency 100*f [Hz], C_0 means C#0, P means pause
//---------------------------------------------------------------------------
#define P 0
#ifdef _music_shifted_notes
// musics data shifted frequencies C4 -> C1
#define C1 26163
#define C_1 27718
#define D1 29366
#define D_1 31113
#define E1 32963
#define F1 34923
#define F_1 36999
#define G1 39200
#define G_1 41530
#define A1 44000
#define A_1 46616
#define B1 49388
#define C2 52325
#define C_2 55437
#define D2 58733
#define D_2 62225
#define E2 65925
#define F2 69846
#define F_2 73999
#define G2 78399
#define G_2 83061
#define A2 88000
#define A_2 93233
#define B2 98777
#define C3 104650
#define C_3 110873
#define D3 117466
#define D_3 124451
#define E3 131851
#define F3 139691
#define F_3 147998
#define G3 156798
#define G_3 166122
#define A3 176000
#define A_3 186466
#define B3 197553
#define C4 209300
#define C_4 221746
#define D4 234932
#define D_4 248902
#define E4 263702
#define F4 279383
#define F_4 295996
#define G4 313596
#define G_4 332244
#define A4 352000
#define A_4 372931
#define B4 395107
#else
// real note frequuencies
#define C0 1635
#define C_0 1732
#define D0 1835
#define D_0 1945
#define E0 2060
#define F0 2183
#define F_0 2312
#define G0 2450
#define G_0 2596
#define A0 2750
#define A_0 2914
#define B0 3087
#define C1 3270
#define C_1 3465
#define D1 3671
#define D_1 3889
#define E1 4120
#define F1 4365
#define F_1 4625
#define G1 4900
#define G_1 5191
#define A1 5500
#define A_1 5827
#define B1 6174
#define C2 6541
#define C_2 6930
#define D2 7342
#define D_2 7778
#define E2 8241
#define F2 8731
#define F_2 9250
#define G2 9800
#define G_2 10383
#define A2 11000
#define A_2 11654
#define B2 12347
#define C3 13081
#define C_3 13859
#define D3 14683
#define D_3 15556
#define E3 16481
#define F3 17461
#define F_3 18500
#define G3 19600
#define G_3 20765
#define A3 22000
#define A_3 23308
#define B3 24694
#define C4 26163
#define C_4 27718
#define D4 29366
#define D_4 31113
#define E4 32963
#define F4 34923
#define F_4 36999
#define G4 39200
#define G_4 41530
#define A4 44000
#define A_4 46616
#define B4 49388
#define C5 52325
#define C_5 55437
#define D5 58733
#define D_5 62225
#define E5 65925
#define F5 69846
#define F_5 73999
#define G5 78399
#define G_5 83061
#define A5 88000
#define A_5 93233
#define B5 98777
#define C6 104650
#define C_6 110873
#define D6 117466
#define D_6 124451
#define E6 131851
#define F6 139691
#define F_6 147998
#define G6 156798
#define G_6 166122
#define A6 176000
#define A_6 186466
#define B6 197553
#define C7 209300
#define C_7 221746
#define D7 234932
#define D_7 248902
#define E7 263702
#define F7 279383
#define F_7 295996
#define G7 313596
#define G_7 332244
#define A7 352000
#define A_7 372931
#define B7 395107
#define C8 418601
#define C_8 443492
#define D8 469863
#define D_8 497803
#define E8 527404
#define F8 558765
#define F_8 591991
#define G8 627193
#define G_8 664488
#define A8 704000
#define A_8 745862
#define B8 790213
#endif
#define H0 B0
#define H1 B1
#define H2 B2
#define H3 B3
#define H4 B4
#define H5 B5
#define H6 B6
#define H7 B7
#define H8 B8
#define H_0 B_0
#define H_1 B_1
#define H_2 B_2
#define H_3 B_3
#define H_4 B_4
#define H_5 B_5
#define H_6 B_6
#define H_7 B_7
#define H_8 B_8
//---------------------------------------------------------------------------
// music tempo delays [ms]
//---------------------------------------------------------------------------
#define T32 62
#define T20 100
#define T16 125
#define T10 200
#define T9 222
#define T8 250
#define T7 285
#define T6 333
#define T5 400
#define T4 500
#define T3 666
#define T2 1000
#define T1 2000
//---------------------------------------------------------------------------
typedef struct
{
U32 T,t,n,on;
U32 *melody;
} _music;
//---------------------------------------------------------------------------
void music_play(_music *m,U32 *melody)
{
m->melody=melody;
m->t=0;
m->T=0;
m->on=0;
m->n=1;
}
//---------------------------------------------------------------------------
void music_stop(_music *m)
{
m->melody=NULL;
m->t=0;
m->T=0;
m->on=0;
m->n=1;
}
//---------------------------------------------------------------------------
void music_update(_music *m)
{
if (m->melody==NULL) { m->on=0; return; }
m->n--; if (!m->n)
{
U32 x;
m->T=m->melody[0]; m->melody++;
if (m->T) m->T=(100*music_f)/m->T;
if (m->melody==NULL) { m->on=0; return; }
m->n=(m->melody[0]*music_f)/1000; m->melody++;
m->on=1; m->t=0;
if (m->n==0) m->melody=NULL;
}
m->t++; if (m->t==m->T){ m->on=1; m->t=0; }
if (m->t==music_A) m->on=0;
}
//---------------------------------------------------------------------------
void music_sys_init(_music *m,int n)
{
for (int i=0;i<n;i++) music_stop(m+i);
}
//---------------------------------------------------------------------------
void music_sys_update(_music *m,int n,U32 pin)
{
static U32 t=0,A=0;
int i;
t++;
if (t==music_sys_T)
{
t=0; A=0;
for (i=0;i<n;i++)
{
music_update(m+i);
if (m[i].on) A++;
}
if (A) gpio_set_gpio_pin(pin);
}
if (t==A) gpio_clr_gpio_pin(pin);
}
//---------------------------------------------------------------------------
#endif
//---------------------------------------------------------------------------
So I just have some array of _music
representing all my channels and call music_sys_update
for them in some timer with frequency ftim0
I am using ftim0=200000
[Hz].
#include "music.h"
#define music_channels 2
volatile _music music[music_channels];
const U32 music_data[]= // melody (frequency [0.01*Hz],duration [ms])
{
C5 ,400,D5 ,400,E5 ,400,C5 ,400,
C5 ,400,D5 ,400,E5 ,400,C5 ,400,
E5 ,400,F5 ,400,G5 ,800,E5 ,400,F5 ,400,G5 ,800,
G5 ,200,A5 ,200,G5 ,200,F5 ,200,E5 ,400,C5 ,400,
G5 ,200,A5 ,200,G5 ,200,F5 ,200,E5 ,400,C5 ,400,
C5 ,400,G4 ,400,C5 ,800,
C5 ,400,G4 ,400,C5 ,800,
0,0, // end of melody
};
// this do once for init
music_sys_init(music,music_channels);
// this starts playback on channel 0
music_play(&music[0],music_data);
// this should be inside timer but also blocking loop like this would do:
for (;;)
{
music_sys_update(music,music_channels,sound_pin);
wait 1000000/ftim0 [us]
}
so just port it to your environment and have fun :) ...