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:
parent
f9e77a9cf3
commit
8c676d8e71
@ -610,7 +610,7 @@ WARN_LOGFILE =
|
|||||||
# directories like "/usr/src/myproject". Separate the files or directories
|
# directories like "/usr/src/myproject". Separate the files or directories
|
||||||
# with spaces.
|
# 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
|
# 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
|
# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
|
||||||
|
219
libraries/Melody/Melody.cpp
Normal file
219
libraries/Melody/Melody.cpp
Normal 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
155
libraries/Melody/Melody.h
Normal 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
|
19
libraries/Melody/examples/PlayTone/PlayTone.pde
Normal file
19
libraries/Melody/examples/PlayTone/PlayTone.pde
Normal 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();
|
||||||
|
}
|
8
libraries/Melody/keywords.txt
Normal file
8
libraries/Melody/keywords.txt
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
Melody KEYWORD1
|
||||||
|
|
||||||
|
play KEYWORD2
|
||||||
|
stop KEYWORD2
|
||||||
|
setMelody KEYWORD2
|
||||||
|
loopCount KEYWORD2
|
||||||
|
setLoopCount KEYWORD2
|
||||||
|
isPlaying KEYWORD2
|
Loading…
x
Reference in New Issue
Block a user