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:
Fri Apr 20 13:59:18 2018 +0000
Revision:
1:f17240b3e85e
Parent:
0:836cdf67dbdb
Added set_bpm method.

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 1:f17240b3e85e 33 void Tone::set_bpm(float bpm)
eencae 1:f17240b3e85e 34 {
eencae 1:f17240b3e85e 35 _bpm = bpm;
eencae 1:f17240b3e85e 36 }
eencae 1:f17240b3e85e 37
eencae 1:f17240b3e85e 38
eencae 0:836cdf67dbdb 39 void Tone::play(float frequency,float duration)
eencae 0:836cdf67dbdb 40 {
eencae 0:836cdf67dbdb 41 // calculate time step between samples
eencae 0:836cdf67dbdb 42 float dt = 1.0/(frequency*_n);
eencae 0:836cdf67dbdb 43 // start from beginning of LUT
eencae 0:836cdf67dbdb 44 _sample = 0;
eencae 1:f17240b3e85e 45
eencae 0:836cdf67dbdb 46 // setup ticker and timeout to stop ticker
eencae 1:f17240b3e85e 47
eencae 0:836cdf67dbdb 48 // the ticker repeats every dt to plat each sample in turn
eencae 0:836cdf67dbdb 49 ticker->attach(callback(this, &Tone::ticker_isr), dt);
eencae 0:836cdf67dbdb 50 // the timeout stops the ticker after the required duration
eencae 0:836cdf67dbdb 51 timeout->attach(callback(this, &Tone::timeout_isr), duration );
eencae 0:836cdf67dbdb 52 }
eencae 0:836cdf67dbdb 53
eencae 0:836cdf67dbdb 54 void Tone::play_melody(int length,const int *notes,const int *durations,float bpm,bool repeat)
eencae 0:836cdf67dbdb 55 {
eencae 0:836cdf67dbdb 56 // copy arguments to member variables
eencae 0:836cdf67dbdb 57 _bpm = bpm;
eencae 0:836cdf67dbdb 58 _notes = notes; // pointer for array
eencae 0:836cdf67dbdb 59 _durations = durations; // pointer for array
eencae 1:f17240b3e85e 60 _melody_length = length;
eencae 1:f17240b3e85e 61 _repeat = repeat;
eencae 1:f17240b3e85e 62
eencae 0:836cdf67dbdb 63 _note = 0; // start from first note
eencae 0:836cdf67dbdb 64
eencae 0:836cdf67dbdb 65 play_next_note(); // play the next note in the melody
eencae 0:836cdf67dbdb 66 }
eencae 0:836cdf67dbdb 67
eencae 0:836cdf67dbdb 68
eencae 0:836cdf67dbdb 69 void Tone::play_next_note()
eencae 0:836cdf67dbdb 70 {
eencae 0:836cdf67dbdb 71 // _note is the note index to play
eencae 1:f17240b3e85e 72
eencae 0:836cdf67dbdb 73 // calculate the duration and frequency of the note
eencae 0:836cdf67dbdb 74 float duration = 60.0/(_bpm*_durations[_note]);
eencae 0:836cdf67dbdb 75 float frequency = float(_notes[_note]);
eencae 0:836cdf67dbdb 76 //printf("[%i] f = %f d = %f\n",_note,frequency,duration);
eencae 1:f17240b3e85e 77
eencae 0:836cdf67dbdb 78 // check if the note is not a space and if not then play the note
eencae 0:836cdf67dbdb 79 if (frequency > 0) {
eencae 1:f17240b3e85e 80 play(frequency,duration);
eencae 0:836cdf67dbdb 81 }
eencae 1:f17240b3e85e 82
eencae 0:836cdf67dbdb 83 // the timeout goes to the next note in the melody
eencae 0:836cdf67dbdb 84 // double the duration to leave a bit of a gap in between notes to be better
eencae 0:836cdf67dbdb 85 // able to distinguish them
eencae 0:836cdf67dbdb 86 note_timeout->attach(callback(this, &Tone::note_timeout_isr), duration*2.0 );
eencae 0:836cdf67dbdb 87 }
eencae 0:836cdf67dbdb 88
eencae 0:836cdf67dbdb 89 // called when the next note needs playing
eencae 0:836cdf67dbdb 90 void Tone::note_timeout_isr()
eencae 0:836cdf67dbdb 91 {
eencae 0:836cdf67dbdb 92 _note++; // go onto next note
eencae 1:f17240b3e85e 93
eencae 0:836cdf67dbdb 94 // if in repeat mode then reset the note counter when get to end of melody
eencae 0:836cdf67dbdb 95 if (_repeat && _note == _melody_length) {
eencae 1:f17240b3e85e 96 _note=0;
eencae 0:836cdf67dbdb 97 }
eencae 0:836cdf67dbdb 98
eencae 0:836cdf67dbdb 99 // check if note is within the melody
eencae 0:836cdf67dbdb 100 if (_note < _melody_length) {
eencae 0:836cdf67dbdb 101 play_next_note();
eencae 0:836cdf67dbdb 102 }
eencae 0:836cdf67dbdb 103 }
eencae 0:836cdf67dbdb 104
eencae 0:836cdf67dbdb 105 void Tone::ticker_isr()
eencae 0:836cdf67dbdb 106 {
eencae 0:836cdf67dbdb 107 dac->write(_sample_array[_sample%_n]); // use modulo to get index to play
eencae 0:836cdf67dbdb 108 _sample++; // increment the sample ready for next time
eencae 0:836cdf67dbdb 109 }
eencae 0:836cdf67dbdb 110
eencae 0:836cdf67dbdb 111 void Tone::timeout_isr()
eencae 0:836cdf67dbdb 112 {
eencae 0:836cdf67dbdb 113 // stops the ticker to end the note
eencae 0:836cdf67dbdb 114 ticker->detach();
eencae 0:836cdf67dbdb 115 }