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
Tone.cpp@1:f17240b3e85e, 2018-04-20 (annotated)
- 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?
User | Revision | Line number | New 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 | } |