198 lines
6.5 KiB
C++
198 lines
6.5 KiB
C++
/**
|
|
* @file ArduboyPlaytune.h
|
|
* \brief An Arduino library that plays a one or two part musical score and
|
|
* generates tones. Intended for the Arduboy game system.
|
|
*/
|
|
|
|
/*****************************************************************************
|
|
* ArduboyPlaytune
|
|
*
|
|
* Plays a one or two part musical score and generates tones.
|
|
*
|
|
* Derived from:
|
|
* Playtune: An Arduino tune player library
|
|
* https://github.com/LenShustek/arduino-playtune
|
|
*
|
|
* Modified to work well with the Arduboy game system
|
|
* https://www.arduboy.com/
|
|
*
|
|
* The MIT License (MIT)
|
|
*
|
|
* (C) Copyright 2016, Chris J. Martinez, Kevin Bates, Josh Goebel, Scott Allen
|
|
* Based on work (C) Copyright 2011, 2015, Len Shustek
|
|
*
|
|
* 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.
|
|
*
|
|
* This was inspired by and adapted from "A Tone Generator Library",
|
|
* written by Brett Hagman, http://www.roguerobotics.com/
|
|
*
|
|
*****************************************************************************/
|
|
|
|
#ifndef ARDUBOY_PLAYTUNE_H
|
|
#define ARDUBOY_PLAYTUNE_H
|
|
|
|
#include <Arduino.h>
|
|
#include <avr/pgmspace.h>
|
|
|
|
#define AVAILABLE_TIMERS 2
|
|
|
|
// score commands
|
|
#define TUNE_OP_PLAYNOTE 0x90 /* play a note: low nibble is generator #, note is next byte */
|
|
#define TUNE_OP_STOPNOTE 0x80 /* stop a note: low nibble is generator # */
|
|
#define TUNE_OP_RESTART 0xe0 /* restart the score from the beginning */
|
|
#define TUNE_OP_STOP 0xf0 /* stop playing */
|
|
|
|
/** \brief
|
|
* The ArduboyPlaytune class for playing two part musical scores and
|
|
* sounding tones.
|
|
*/
|
|
class ArduboyPlaytune
|
|
{
|
|
public:
|
|
/** \brief
|
|
* The ArduboyPlaytune class constructor.
|
|
|
|
* \param outEn
|
|
* \parblock
|
|
* The function passed to the constructor must return `true` if
|
|
* sounds should be played or `false` if all sound should be muted.
|
|
*
|
|
* If muting control isn't required, provide a pointer to a function that
|
|
* always returns `true`.
|
|
*
|
|
* The provided function will be called from a timer interrupt service
|
|
* routine, at the start of each score note, so it should be as fast as
|
|
* possible.
|
|
* \endparblock
|
|
|
|
* \details
|
|
* When muting is in effect, scores and tones are still processed
|
|
* as usual but no sound is produced.
|
|
*
|
|
* \note
|
|
* If using the Arduboy2 library, `audio.enabled()` is appropriate
|
|
* to use as the mute function.
|
|
*/
|
|
ArduboyPlaytune(boolean (*outEn)());
|
|
|
|
/** \brief
|
|
* Assign an output pin to a score channel.
|
|
*
|
|
* \param pin The pin number to be used to produce sound for a score channel.
|
|
*
|
|
* \details
|
|
* \parblock
|
|
* Each time this function is called the next score channel is assigned
|
|
* to the provided pin number, so it should be called once or twice.
|
|
*
|
|
* If the `tone()` function is to be used, the second channel must be
|
|
* initialized since tones are alway played on it.
|
|
*
|
|
* The same pin number can be used for both channels, in which case only the
|
|
* first score channel will be played and tones will play on the same pin.
|
|
* Function `toneMutesScore(true)` can be use to prevent the strange sounds
|
|
* that occur from using the same pin for both the score and tones.
|
|
* \endparblock
|
|
*
|
|
* \note
|
|
* If using the Arduboy2 library, the defined values `PIN_SPEAKER_1` and
|
|
* `PIN_SPEAKER_2` should be used for the `pin` parameter.
|
|
*/
|
|
void static initChannel(byte pin);
|
|
|
|
/** \brief
|
|
* Start playing the provided score.
|
|
*
|
|
* \param score A pointer to an array of bytes containing the score data.
|
|
* The array must be placed in code space using `PROGMEM`.
|
|
*
|
|
* \details
|
|
* The score will be played in the background until an
|
|
* "End of score: stop playing" command is read or the `stopScore()` function
|
|
* is called. Any notes in the score for channels above the one or two that
|
|
* have been initialized will be ignored.
|
|
*/
|
|
void playScore(const byte *score);
|
|
|
|
/** \brief
|
|
* Stop playing a score started using `playScore()`.
|
|
*
|
|
* \details
|
|
* If a score is playing, it will stop. If nothing is playing,
|
|
* this function will do nothing.
|
|
*/
|
|
void stopScore();
|
|
|
|
/** \brief
|
|
* Close all (one or two) initialized channels.
|
|
*
|
|
* \details
|
|
* After calling this function, function `initChannel()` must be
|
|
* called, to reassign pins to channels, if more sound is to be produced.
|
|
*/
|
|
void closeChannels();
|
|
|
|
/** \brief
|
|
* Check if a score is currently playing.
|
|
*
|
|
* \return boolean `true` if playing (even if sound is muted).
|
|
*/
|
|
boolean playing();
|
|
|
|
/** \brief
|
|
* Play a tone of a given frequency and duration on the second channel.
|
|
*
|
|
* \param frequency The frequency of the tone in hertz (cycles per second).
|
|
* \param duration The duration of the tone in milliseconds.
|
|
*
|
|
* \details
|
|
* If a score is playing that uses the second channel, the notes for
|
|
* that channel are muted for the duration of the tone. Score notes on the
|
|
* first channel continue to play unless `toneMutesScore(true)` has been
|
|
* called.
|
|
*/
|
|
void tone(unsigned int frequency, unsigned long duration);
|
|
|
|
/** \brief
|
|
* Set a mode to specify whether playing a tone mutes the first score
|
|
* channel.
|
|
*
|
|
* \param mute
|
|
* \parblock
|
|
* If `true` a score part on the first channel will be muted when a tone
|
|
* is playing. (A score part playing on the second channel is always muted
|
|
* since the tone plays on it.)
|
|
*
|
|
* If `false` (the default) the first channel will continue to
|
|
* play when a tone is playing.
|
|
* \endparblock
|
|
*/
|
|
void toneMutesScore(boolean mute);
|
|
|
|
private:
|
|
void static playNote(byte chan, byte note);
|
|
void static stopNote(byte chan);
|
|
|
|
public:
|
|
// called via interrupt. Should not be called by a program.
|
|
void static step();
|
|
};
|
|
|
|
#endif
|