1
0
mirror of https://github.com/taigrr/arduinolibs synced 2025-01-18 04:33:12 -08:00

Melody class for playing simple tunes using tone()

This commit is contained in:
Rhys Weatherley 2012-05-16 11:17:59 +10:00
parent f9e77a9cf3
commit 8c676d8e71
5 changed files with 402 additions and 1 deletions

View File

@ -610,7 +610,7 @@ WARN_LOGFILE =
# directories like "/usr/src/myproject". Separate the files or directories
# with spaces.
INPUT = ../libraries/FreetronicsLCD ../libraries/BlinkLED ../libraries/BitBangI2C .
INPUT = ../libraries/FreetronicsLCD ../libraries/BlinkLED ../libraries/BitBangI2C ../libraries/Melody .
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is

219
libraries/Melody/Melody.cpp Normal file
View File

@ -0,0 +1,219 @@
/*
* Copyright (C) 2012 Southern Storm Software, Pty Ltd.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "Melody.h"
#include <WProgram.h>
/**
* \class Melody Melody.h <Melody.h>
* \brief Plays a melody on a digital output pin using tone().
*
* The following example plays a simple tone three times on digital pin 8:
*
* \code
* #include <Melody.h>
*
* int notes[] = {
* NOTE_C4, NOTE_G3, NOTE_G3, NOTE_A3, NOTE_G3,
* NOTE_REST, NOTE_B3, NOTE_C4, NOTE_REST
* };
* byte lengths[] = {4, 8, 8, 4, 4, 4, 4, 4, 2};
*
* Melody melody(8);
*
* void setup() {
* melody.setMelody(notes, lengths, sizeof(lengths));
* melody.setLoopCount(3);
* melody.play();
* }
*
* void loop() {
* melody.run();
* }
* \endcode
*
* The \c notes array contains the frequency of the notes to be played,
* with the special value \c NOTE_REST indicating a rest where no notes
* are playing. The \c lengths array contains the lengths of each of the
* notes; a value of 4 indicates a quarter note, a value of 8 indicates
* an eighth note, etc.
*
* The run() method must be called from the application's main
* <tt>loop()</tt> method to ensure that the melody advances from
* one note to the next. It will not * block the application while
* notes are playing.
*
* The number of loops can also be specified with setLoopDuration() which
* sets a maximum amount of time that the melody will play before stopping.
* The following example plays the melody for no more than 60 seconds:
*
* \code
* void setup() {
* melody.setMelody(notes, lengths, sizeof(lengths));
* melody.setLoopDuration(60000UL);
* melody.play();
* }
* \endcode
*/
/**
* \brief Constructs a new melody playing object for \a pin.
*/
Melody::Melody(uint8_t pin)
: _pin(pin)
, playing(false)
, _loopCount(0)
, loopsLeft(0)
, notes(0)
, lengths(0)
, size(0)
, posn(0)
, duration(0)
, startNote(0)
{
}
/**
* \fn bool Melody::isPlaying() const
* \brief Returns true if the melody is currently playing; false if not.
*/
/**
* \fn int Melody::loopCount() const
* \brief Returns the number of times the melody should loop before stopping.
*
* The default value is zero, indicating that the melody will loop
* indefinitely.
*
* \sa setLoopCount(), setLoopDuration(), play()
*/
/**
* \fn void Melody::setLoopCount(int count)
* \brief Sets the number of times the melody should loop to \a count.
*
* If \a count is zero, then the melody will loop indefinitely.
*
* \sa loopCount(), setLoopDuration()
*/
/**
* \brief Sets the maximum number of loops to last no longer than \a ms milliseconds.
*
* This function must be called after the melody is specified with setMelody()
* as it uses the length of the melody and \a ms to determine the loopCount().
*
* \sa loopCount(), setLoopCount()
*/
void Melody::setLoopDuration(unsigned long ms)
{
unsigned long duration = 0;
for (unsigned int index = 0; index < size; ++index)
duration += (1000 / lengths[index]) * 13 / 10;
_loopCount = (int)(ms / duration);
if (!_loopCount)
_loopCount = 1; // Play the melody at least once.
}
/**
* \brief Starts playing the melody, or restarts it if already playing.
*
* \sa setMelody(), stop(), loopCount()
*/
void Melody::play()
{
stop();
if (size == 0)
return; // No melody to play.
loopsLeft = _loopCount;
posn = 0;
playing = true;
nextNote();
}
/**
* \brief Stops playing the melody.
*
* \sa play()
*/
void Melody::stop()
{
if (!playing)
return;
playing = false;
noTone(_pin);
}
/**
* \brief Sets the melody to the \a size elements of \a notes and \a lengths.
*
* If a melody is currently playing, then this function will stop playback.
*
* The \a notes array contains the frequency of the notes to be played,
* with the special value \c NOTE_REST indicating a rest where no notes
* are playing. The \a lengths array contains the lengths of each of the
* notes; a value of 4 indicates a quarter note, a value of 8 indicates
* an eighth note, etc.
*
* \sa play()
*/
void Melody::setMelody(const int *notes, const uint8_t *lengths, unsigned int size)
{
stop();
this->notes = notes;
this->lengths = lengths;
this->size = size;
}
/**
* \brief Runs the melody control loop.
*
* This function must be called by the application's main <tt>loop()</tt>
* function to cause the melody to advance from note to note. It will not
* block the application while notes are playing.
*/
void Melody::run()
{
if (!playing)
return;
if ((millis() - startNote) >= duration) {
noTone(_pin);
nextNote();
}
}
void Melody::nextNote()
{
if (posn >= size) {
if (loopsLeft != 0 && --loopsLeft <= 0) {
stop();
return;
}
posn = 0;
}
duration = 1000 / lengths[posn];
if (notes[posn] != NOTE_REST)
tone(_pin, notes[posn], duration);
++posn;
duration = duration * 13 / 10; // i.e., duration * 1.3
startNote = millis();
}

155
libraries/Melody/Melody.h Normal file
View File

@ -0,0 +1,155 @@
/*
* Copyright (C) 2012 Southern Storm Software, Pty Ltd.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef Melody_h
#define Melody_h
#include <inttypes.h>
// Note frequencies from http://arduino.cc/en/Tutorial/Tone
#define NOTE_B0 31
#define NOTE_C1 33
#define NOTE_CS1 35
#define NOTE_D1 37
#define NOTE_DS1 39
#define NOTE_E1 41
#define NOTE_F1 44
#define NOTE_FS1 46
#define NOTE_G1 49
#define NOTE_GS1 52
#define NOTE_A1 55
#define NOTE_AS1 58
#define NOTE_B1 62
#define NOTE_C2 65
#define NOTE_CS2 69
#define NOTE_D2 73
#define NOTE_DS2 78
#define NOTE_E2 82
#define NOTE_F2 87
#define NOTE_FS2 93
#define NOTE_G2 98
#define NOTE_GS2 104
#define NOTE_A2 110
#define NOTE_AS2 117
#define NOTE_B2 123
#define NOTE_C3 131
#define NOTE_CS3 139
#define NOTE_D3 147
#define NOTE_DS3 156
#define NOTE_E3 165
#define NOTE_F3 175
#define NOTE_FS3 185
#define NOTE_G3 196
#define NOTE_GS3 208
#define NOTE_A3 220
#define NOTE_AS3 233
#define NOTE_B3 247
#define NOTE_C4 262
#define NOTE_CS4 277
#define NOTE_D4 294
#define NOTE_DS4 311
#define NOTE_E4 330
#define NOTE_F4 349
#define NOTE_FS4 370
#define NOTE_G4 392
#define NOTE_GS4 415
#define NOTE_A4 440
#define NOTE_AS4 466
#define NOTE_B4 494
#define NOTE_C5 523
#define NOTE_CS5 554
#define NOTE_D5 587
#define NOTE_DS5 622
#define NOTE_E5 659
#define NOTE_F5 698
#define NOTE_FS5 740
#define NOTE_G5 784
#define NOTE_GS5 831
#define NOTE_A5 880
#define NOTE_AS5 932
#define NOTE_B5 988
#define NOTE_C6 1047
#define NOTE_CS6 1109
#define NOTE_D6 1175
#define NOTE_DS6 1245
#define NOTE_E6 1319
#define NOTE_F6 1397
#define NOTE_FS6 1480
#define NOTE_G6 1568
#define NOTE_GS6 1661
#define NOTE_A6 1760
#define NOTE_AS6 1865
#define NOTE_B6 1976
#define NOTE_C7 2093
#define NOTE_CS7 2217
#define NOTE_D7 2349
#define NOTE_DS7 2489
#define NOTE_E7 2637
#define NOTE_F7 2794
#define NOTE_FS7 2960
#define NOTE_G7 3136
#define NOTE_GS7 3322
#define NOTE_A7 3520
#define NOTE_AS7 3729
#define NOTE_B7 3951
#define NOTE_C8 4186
#define NOTE_CS8 4435
#define NOTE_D8 4699
#define NOTE_DS8 4978
// Special note value that indicates a rest.
#define NOTE_REST 0
class Melody {
public:
Melody(uint8_t pin);
bool isPlaying() const { return playing; }
int loopCount() const { return _loopCount; }
void setLoopCount(int count) { _loopCount = count; }
void setLoopDuration(unsigned long ms);
void play();
void stop();
void setMelody(const int *notes, const uint8_t *lengths, unsigned int size);
void run();
private:
uint8_t _pin;
bool playing;
int _loopCount;
int loopsLeft;
const int *notes;
const uint8_t *lengths;
unsigned int size;
unsigned int posn;
unsigned long duration;
unsigned long startNote;
void nextNote();
};
#endif

View File

@ -0,0 +1,19 @@
#include <Melody.h>
int notes[] = {
NOTE_C4, NOTE_G3, NOTE_G3, NOTE_A3, NOTE_G3,
NOTE_REST, NOTE_B3, NOTE_C4, NOTE_REST
};
byte lengths[] = {4, 8, 8, 4, 4, 4, 4, 4, 2};
Melody melody(8);
void setup() {
melody.setMelody(notes, lengths, sizeof(lengths));
melody.setLoopCount(3);
melody.play();
}
void loop() {
melody.run();
}

View File

@ -0,0 +1,8 @@
Melody KEYWORD1
play KEYWORD2
stop KEYWORD2
setMelody KEYWORD2
loopCount KEYWORD2
setLoopCount KEYWORD2
isPlaying KEYWORD2