release
This commit is contained in:
248
lib/Melody Player/src/melody_player.h
Normal file
248
lib/Melody Player/src/melody_player.h
Normal file
@@ -0,0 +1,248 @@
|
||||
/***************************************************************************
|
||||
* This file is part of Melody Player, a library for Arduino *
|
||||
* to play notes on piezoelectric buzzers. *
|
||||
* *
|
||||
* Copyright (C) 2020-2022 Fabiano Riccardi *
|
||||
* *
|
||||
* This library is free software; you can redistribute *
|
||||
* it and/or modify it under the terms of the GNU Lesser General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2.1 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this library; if not, see <http://www.gnu.org/licenses/> *
|
||||
***************************************************************************/
|
||||
#ifndef MELODY_PLAYER_H
|
||||
#define MELODY_PLAYER_H
|
||||
|
||||
#include "melody.h"
|
||||
#include <Ticker.h>
|
||||
#include <memory>
|
||||
|
||||
class MelodyPlayer {
|
||||
public:
|
||||
#ifdef ESP32
|
||||
/**
|
||||
* pwmChannel is optional and you have to configure it only if you play will
|
||||
* simultaneous melodies.
|
||||
*/
|
||||
MelodyPlayer(unsigned char pin, unsigned char pwmChannel = 0, bool offLevel = HIGH);
|
||||
#else
|
||||
MelodyPlayer(unsigned char pin, bool offLevel = HIGH);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Play the last melody in a synchrounus (blocking) way.
|
||||
* If the melody is not valid, this call has no effect.
|
||||
*/
|
||||
void play();
|
||||
|
||||
/**
|
||||
* Play the given melody in a synchronous (blocking) way.
|
||||
* If the melody is not valid, this call has no effect.
|
||||
*/
|
||||
void play(Melody& melody);
|
||||
|
||||
/**
|
||||
* Play the last melody in asynchronous way (return immediately).
|
||||
* If the melody is not valid, this call has no effect.
|
||||
*/
|
||||
void playAsync();
|
||||
|
||||
/**
|
||||
* Play the given melody in asynchronous way (return immediately).
|
||||
* If the melody is not valid, this call has no effect.
|
||||
*/
|
||||
void playAsync(Melody& melody);
|
||||
|
||||
/**
|
||||
* Stop the current melody.
|
||||
* Then, if you will call play() or playAsync(), the melody restarts from the begin.
|
||||
*/
|
||||
void stop();
|
||||
|
||||
/**
|
||||
* Pause the current melody.
|
||||
* Then, if you will call play() or playAsync(), the melody continues from
|
||||
* where it was paused.
|
||||
*/
|
||||
void pause();
|
||||
|
||||
/**
|
||||
* Tell if playing.
|
||||
*/
|
||||
bool isPlaying() const {
|
||||
return state == State::PLAY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Move the current melody and player's state to the given destination Player.
|
||||
* The source player stops and lose the reference to the actual melody (i.e. you have to call
|
||||
* play(Melody) to make the source player play again).
|
||||
*/
|
||||
void transferMelodyTo(MelodyPlayer& destination);
|
||||
|
||||
/**
|
||||
* Duplicate the current melody and player's state to the given destination Player.
|
||||
* Both players remains indipendent from each other (e.g. the melody can be independently
|
||||
* stopped/paused/played).
|
||||
*/
|
||||
void duplicateMelodyTo(MelodyPlayer& destination);
|
||||
|
||||
private:
|
||||
unsigned char pin;
|
||||
|
||||
#ifdef ESP32
|
||||
unsigned char pwmChannel;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* The voltage to turn off the buzzer.
|
||||
*
|
||||
* NOTE: Passive buzzers have 2 states: the "rest" state (no power consumption) and the "active"
|
||||
* state (high power consumption). To emit sound, it have to oscillate between these 2 states. If
|
||||
* it stops in the active state, it doesn't emit sound, but it continues to consume energy,
|
||||
* heating the buzzer and possibly damaging itself.
|
||||
*/
|
||||
bool offLevel;
|
||||
|
||||
/**
|
||||
* Store the playback state of a melody and provide the methods to control it.
|
||||
*/
|
||||
class MelodyState {
|
||||
public:
|
||||
MelodyState() : first(true), index(0), remainingNoteTime(0){};
|
||||
MelodyState(const Melody& melody)
|
||||
: melody(melody), first(true), silence(false), index(0), remainingNoteTime(0){};
|
||||
Melody melody;
|
||||
|
||||
unsigned short getIndex() const {
|
||||
return index;
|
||||
}
|
||||
|
||||
bool isSilence() const {
|
||||
return silence;
|
||||
}
|
||||
|
||||
/**
|
||||
* Advance the melody index by one step. If there is a pending partial note it hasn't any
|
||||
* effect.
|
||||
*/
|
||||
void advance() {
|
||||
if (first) {
|
||||
first = false;
|
||||
return;
|
||||
}
|
||||
if (remainingNoteTime != 0) { return; }
|
||||
|
||||
if (melody.getAutomaticSilence()) {
|
||||
if (silence) {
|
||||
index++;
|
||||
silence = false;
|
||||
} else {
|
||||
silence = true;
|
||||
}
|
||||
} else {
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the state of the melody (i.e. a melody just loaded).
|
||||
*/
|
||||
void reset() {
|
||||
first = true;
|
||||
index = 0;
|
||||
remainingNoteTime = 0;
|
||||
silence = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the time to finish the current note.
|
||||
*/
|
||||
void saveRemainingNoteDuration(unsigned long supportSemiNote) {
|
||||
remainingNoteTime = supportSemiNote - millis();
|
||||
// Ignore partial reproduction if the current value is below the threshold. This is needed
|
||||
// since Ticker may struggle with tight timings.
|
||||
if (remainingNoteTime < 10) { remainingNoteTime = 0; }
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the partial note duration. It should be called after reproduction of the partial note
|
||||
* and it is propedeutic to advance() method.
|
||||
*/
|
||||
void resetRemainingNoteDuration() {
|
||||
remainingNoteTime = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the remaining duration of the latest "saved" note.
|
||||
*/
|
||||
unsigned short getRemainingNoteDuration() const {
|
||||
return remainingNoteTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current note. The duration is absolute and expressed in milliseconds.
|
||||
*/
|
||||
NoteDuration getCurrentComputedNote() const {
|
||||
NoteDuration note = melody.getNote(getIndex());
|
||||
note.duration = melody.getTimeUnit() * note.duration;
|
||||
// because the fixed point notation
|
||||
note.duration /= 2;
|
||||
return note;
|
||||
}
|
||||
|
||||
private:
|
||||
bool first;
|
||||
bool silence;
|
||||
unsigned short index;
|
||||
|
||||
/**
|
||||
* Variable to support precise pauses and move/duplicate melodies between Players.
|
||||
* Value are expressed in milliseconds.
|
||||
*/
|
||||
unsigned short remainingNoteTime;
|
||||
};
|
||||
|
||||
enum class State { STOP, PLAY, PAUSE };
|
||||
|
||||
State state;
|
||||
|
||||
std::unique_ptr<MelodyState> melodyState;
|
||||
|
||||
unsigned long supportSemiNote;
|
||||
|
||||
Ticker ticker;
|
||||
|
||||
const static bool debug = false;
|
||||
|
||||
/**
|
||||
* Change the current note with the next one.
|
||||
*/
|
||||
friend void changeTone(MelodyPlayer* melody);
|
||||
|
||||
/**
|
||||
* Halt the advancement of the melody reproduction.
|
||||
* This is the shared method for pause and stop.
|
||||
*/
|
||||
void haltPlay();
|
||||
|
||||
/**
|
||||
* Configure pin to emit PWM.
|
||||
*/
|
||||
void turnOn();
|
||||
|
||||
/**
|
||||
* Disable PWM and put the buzzer is low-power state.
|
||||
* This calls will fails if PWM is not initialized!
|
||||
*/
|
||||
void turnOff();
|
||||
};
|
||||
|
||||
#endif // END MELODY_PLAYER_H
|
||||
Reference in New Issue
Block a user