Library to play tones and melodies over the DAC.

Dependents:   1620_Project_Template 1620_App_Board_DAC 1620_App_Board_DAC_Melody 1620_Project_Template ... more

Committer:
eencae
Date:
Wed Mar 08 17:15:42 2017 +0000
Revision:
0:836cdf67dbdb
Child:
1:f17240b3e85e
Changed note and duration arrays to int

Who changed what in which revision?

UserRevisionLine numberNew contents of line
eencae 0:836cdf67dbdb 1 #include "Tone.h"
eencae 0:836cdf67dbdb 2
eencae 0:836cdf67dbdb 3 Tone::Tone(PinName dacPin)
eencae 0:836cdf67dbdb 4 {
eencae 0:836cdf67dbdb 5 dac = new AnalogOut(dacPin);
eencae 0:836cdf67dbdb 6 ticker = new Ticker;
eencae 0:836cdf67dbdb 7 timeout = new Timeout;
eencae 0:836cdf67dbdb 8 note_timeout = new Timeout;
eencae 0:836cdf67dbdb 9 }
eencae 0:836cdf67dbdb 10
eencae 0:836cdf67dbdb 11 Tone::~Tone()
eencae 0:836cdf67dbdb 12 {
eencae 0:836cdf67dbdb 13 delete dac;
eencae 0:836cdf67dbdb 14 delete[] _sample_array;
eencae 0:836cdf67dbdb 15 delete ticker;
eencae 0:836cdf67dbdb 16 delete timeout;
eencae 0:836cdf67dbdb 17 delete note_timeout;
eencae 0:836cdf67dbdb 18 }
eencae 0:836cdf67dbdb 19
eencae 0:836cdf67dbdb 20 void Tone::init()
eencae 0:836cdf67dbdb 21 {
eencae 0:836cdf67dbdb 22 _n = 16;
eencae 0:836cdf67dbdb 23 _sample_array = new float[_n];
eencae 0:836cdf67dbdb 24
eencae 0:836cdf67dbdb 25 // create sample array for one period between 0.0 and 1.0
eencae 0:836cdf67dbdb 26 for (int i = 0; i < _n ; i++) {
eencae 0:836cdf67dbdb 27 _sample_array[i] = 0.5f + 0.5f*sin(i*2*PI/_n);
eencae 0:836cdf67dbdb 28 //printf("y[%i] = %f\n",i,_sample_array[i]);
eencae 0:836cdf67dbdb 29 }
eencae 0:836cdf67dbdb 30
eencae 0:836cdf67dbdb 31 }
eencae 0:836cdf67dbdb 32
eencae 0:836cdf67dbdb 33 void Tone::play(float frequency,float duration)
eencae 0:836cdf67dbdb 34 {
eencae 0:836cdf67dbdb 35 // calculate time step between samples
eencae 0:836cdf67dbdb 36 float dt = 1.0/(frequency*_n);
eencae 0:836cdf67dbdb 37 // start from beginning of LUT
eencae 0:836cdf67dbdb 38 _sample = 0;
eencae 0:836cdf67dbdb 39
eencae 0:836cdf67dbdb 40 // setup ticker and timeout to stop ticker
eencae 0:836cdf67dbdb 41
eencae 0:836cdf67dbdb 42 // the ticker repeats every dt to plat each sample in turn
eencae 0:836cdf67dbdb 43 ticker->attach(callback(this, &Tone::ticker_isr), dt);
eencae 0:836cdf67dbdb 44 // the timeout stops the ticker after the required duration
eencae 0:836cdf67dbdb 45 timeout->attach(callback(this, &Tone::timeout_isr), duration );
eencae 0:836cdf67dbdb 46 }
eencae 0:836cdf67dbdb 47
eencae 0:836cdf67dbdb 48 void Tone::play_melody(int length,const int *notes,const int *durations,float bpm,bool repeat)
eencae 0:836cdf67dbdb 49 {
eencae 0:836cdf67dbdb 50 // copy arguments to member variables
eencae 0:836cdf67dbdb 51 _bpm = bpm;
eencae 0:836cdf67dbdb 52 _notes = notes; // pointer for array
eencae 0:836cdf67dbdb 53 _durations = durations; // pointer for array
eencae 0:836cdf67dbdb 54 _melody_length = length;
eencae 0:836cdf67dbdb 55 _repeat = repeat;
eencae 0:836cdf67dbdb 56
eencae 0:836cdf67dbdb 57 _note = 0; // start from first note
eencae 0:836cdf67dbdb 58
eencae 0:836cdf67dbdb 59 play_next_note(); // play the next note in the melody
eencae 0:836cdf67dbdb 60 }
eencae 0:836cdf67dbdb 61
eencae 0:836cdf67dbdb 62
eencae 0:836cdf67dbdb 63 void Tone::play_next_note()
eencae 0:836cdf67dbdb 64 {
eencae 0:836cdf67dbdb 65 // _note is the note index to play
eencae 0:836cdf67dbdb 66
eencae 0:836cdf67dbdb 67 // calculate the duration and frequency of the note
eencae 0:836cdf67dbdb 68 float duration = 60.0/(_bpm*_durations[_note]);
eencae 0:836cdf67dbdb 69 float frequency = float(_notes[_note]);
eencae 0:836cdf67dbdb 70 //printf("[%i] f = %f d = %f\n",_note,frequency,duration);
eencae 0:836cdf67dbdb 71
eencae 0:836cdf67dbdb 72 // check if the note is not a space and if not then play the note
eencae 0:836cdf67dbdb 73 if (frequency > 0) {
eencae 0:836cdf67dbdb 74 play(frequency,duration);
eencae 0:836cdf67dbdb 75 }
eencae 0:836cdf67dbdb 76
eencae 0:836cdf67dbdb 77 // the timeout goes to the next note in the melody
eencae 0:836cdf67dbdb 78 // double the duration to leave a bit of a gap in between notes to be better
eencae 0:836cdf67dbdb 79 // able to distinguish them
eencae 0:836cdf67dbdb 80 note_timeout->attach(callback(this, &Tone::note_timeout_isr), duration*2.0 );
eencae 0:836cdf67dbdb 81 }
eencae 0:836cdf67dbdb 82
eencae 0:836cdf67dbdb 83 // called when the next note needs playing
eencae 0:836cdf67dbdb 84 void Tone::note_timeout_isr()
eencae 0:836cdf67dbdb 85 {
eencae 0:836cdf67dbdb 86 _note++; // go onto next note
eencae 0:836cdf67dbdb 87
eencae 0:836cdf67dbdb 88 // if in repeat mode then reset the note counter when get to end of melody
eencae 0:836cdf67dbdb 89 if (_repeat && _note == _melody_length) {
eencae 0:836cdf67dbdb 90 _note=0;
eencae 0:836cdf67dbdb 91 }
eencae 0:836cdf67dbdb 92
eencae 0:836cdf67dbdb 93 // check if note is within the melody
eencae 0:836cdf67dbdb 94 if (_note < _melody_length) {
eencae 0:836cdf67dbdb 95 play_next_note();
eencae 0:836cdf67dbdb 96 }
eencae 0:836cdf67dbdb 97 }
eencae 0:836cdf67dbdb 98
eencae 0:836cdf67dbdb 99 void Tone::ticker_isr()
eencae 0:836cdf67dbdb 100 {
eencae 0:836cdf67dbdb 101 dac->write(_sample_array[_sample%_n]); // use modulo to get index to play
eencae 0:836cdf67dbdb 102 _sample++; // increment the sample ready for next time
eencae 0:836cdf67dbdb 103 }
eencae 0:836cdf67dbdb 104
eencae 0:836cdf67dbdb 105 void Tone::timeout_isr()
eencae 0:836cdf67dbdb 106 {
eencae 0:836cdf67dbdb 107 // stops the ticker to end the note
eencae 0:836cdf67dbdb 108 ticker->detach();
eencae 0:836cdf67dbdb 109 }