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
Diff: Tone.cpp
- Revision:
- 0:836cdf67dbdb
- Child:
- 1:f17240b3e85e
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Tone.cpp Wed Mar 08 17:15:42 2017 +0000 @@ -0,0 +1,109 @@ +#include "Tone.h" + +Tone::Tone(PinName dacPin) +{ + dac = new AnalogOut(dacPin); + ticker = new Ticker; + timeout = new Timeout; + note_timeout = new Timeout; +} + +Tone::~Tone() +{ + delete dac; + delete[] _sample_array; + delete ticker; + delete timeout; + delete note_timeout; +} + +void Tone::init() +{ + _n = 16; + _sample_array = new float[_n]; + + // create sample array for one period between 0.0 and 1.0 + for (int i = 0; i < _n ; i++) { + _sample_array[i] = 0.5f + 0.5f*sin(i*2*PI/_n); + //printf("y[%i] = %f\n",i,_sample_array[i]); + } + +} + +void Tone::play(float frequency,float duration) +{ + // calculate time step between samples + float dt = 1.0/(frequency*_n); + // start from beginning of LUT + _sample = 0; + + // setup ticker and timeout to stop ticker + + // the ticker repeats every dt to plat each sample in turn + ticker->attach(callback(this, &Tone::ticker_isr), dt); + // the timeout stops the ticker after the required duration + timeout->attach(callback(this, &Tone::timeout_isr), duration ); +} + +void Tone::play_melody(int length,const int *notes,const int *durations,float bpm,bool repeat) +{ + // copy arguments to member variables + _bpm = bpm; + _notes = notes; // pointer for array + _durations = durations; // pointer for array + _melody_length = length; + _repeat = repeat; + + _note = 0; // start from first note + + play_next_note(); // play the next note in the melody +} + + +void Tone::play_next_note() +{ + // _note is the note index to play + + // calculate the duration and frequency of the note + float duration = 60.0/(_bpm*_durations[_note]); + float frequency = float(_notes[_note]); + //printf("[%i] f = %f d = %f\n",_note,frequency,duration); + + // check if the note is not a space and if not then play the note + if (frequency > 0) { + play(frequency,duration); + } + + // the timeout goes to the next note in the melody + // double the duration to leave a bit of a gap in between notes to be better + // able to distinguish them + note_timeout->attach(callback(this, &Tone::note_timeout_isr), duration*2.0 ); +} + +// called when the next note needs playing +void Tone::note_timeout_isr() +{ + _note++; // go onto next note + + // if in repeat mode then reset the note counter when get to end of melody + if (_repeat && _note == _melody_length) { + _note=0; + } + + // check if note is within the melody + if (_note < _melody_length) { + play_next_note(); + } +} + +void Tone::ticker_isr() +{ + dac->write(_sample_array[_sample%_n]); // use modulo to get index to play + _sample++; // increment the sample ready for next time +} + +void Tone::timeout_isr() +{ + // stops the ticker to end the note + ticker->detach(); +} \ No newline at end of file