Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added setVolume(), setTempo(), mute() and loop mode features #7

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 50 additions & 6 deletions src/melody_player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,23 +86,30 @@ void changeTone(MelodyPlayer* player) {
+ " iteration=" + player->melodyState->getIndex());

if (player->melodyState->isSilence()) {
if(!player->muted)
{
#ifdef ESP32
ledcWriteTone(player->pwmChannel, 0);
ledcWriteTone(player->pwmChannel, 0);
#else
tone(player->pin, 0);
tone(player->pin, 0);
#endif
}

#ifdef ESP32
player->ticker.once_ms(duration, changeTone, player);
#else
player->ticker.once_ms_scheduled(duration, std::bind(changeTone, player));
#endif
} else {
if(!player->muted)
{
#ifdef ESP32
ledcWriteTone(player->pwmChannel, computedNote.frequency);
ledcWriteTone(player->pwmChannel, computedNote.frequency);
ledcWrite(player->pwmChannel,player->volume);
#else
tone(player->pin, computedNote.frequency);
tone(player->pin, computedNote.frequency);
#endif
}

#ifdef ESP32
player->ticker.once_ms(duration, changeTone, player);
Expand All @@ -112,7 +119,16 @@ void changeTone(MelodyPlayer* player) {
}
player->supportSemiNote = millis() + duration;
} else {
// End of the melody
player->stop();
if(player->loop)
{ // Loop mode => start over
player->playAsync();
}
else if(player->stopCallback != NULL)
{
player->stopCallback();
}
}
}

Expand All @@ -130,9 +146,11 @@ void MelodyPlayer::playAsync() {
#endif
}

void MelodyPlayer::playAsync(Melody& melody) {
void MelodyPlayer::playAsync(Melody& melody, bool loopMelody, void(*callback)(void)) {
if (!melody) { return; }
melodyState = make_unique<MelodyState>(melody);
loop = loopMelody;
stopCallback = callback;
playAsync();
}

Expand Down Expand Up @@ -211,7 +229,17 @@ void MelodyPlayer::turnOn() {
// 2000 is a frequency, it will be changed at the first play
ledcSetup(pwmChannel, 2000, resolution);
ledcAttachPin(pin, pwmChannel);
ledcWrite(pwmChannel, 125);
ledcWrite(pwmChannel, volume);
#endif
}

void MelodyPlayer::setVolume(byte newVolume) {
volume = newVolume/2;
#ifdef ESP32
if(state == State::PLAY)
{
ledcWrite(pwmChannel, volume);
}
#endif
}

Expand All @@ -228,3 +256,19 @@ void MelodyPlayer::turnOff() {
pinMode(pin, OUTPUT);
digitalWrite(pin, offLevel);
}

void MelodyPlayer::mute() {
muted = true;
}

void MelodyPlayer::unmute() {
#ifdef ESP32
ledcAttachPin(pin, pwmChannel);
#endif
muted = false;
}

void MelodyPlayer::changeTempo(int newTempo) {
if (melodyState == nullptr) { return; }
melodyState->changeTempo(newTempo);
}
43 changes: 39 additions & 4 deletions src/melody_player.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,10 @@ class MelodyPlayer {
/**
* Play the given melody in asynchronous way (return immediately).
* If the melody is not valid, this call has no effect.
* Set loop to true if you want the melody to start over after at the end.
* A call back can be provided to be called at the end of the melody (only used if loop is false)
*/
void playAsync(Melody& melody);
void playAsync(Melody& melody, bool loop = false, void(*stopCallback)(void) = NULL);

/**
* Stop the current melody.
Expand All @@ -73,13 +75,37 @@ class MelodyPlayer {
*/
void pause();

/**
* Mute the sound of the current melody without stoppig it
* When unmute will be called the melody be resumed
*/
void mute();

/**
* Unmute the current melody
*/
void unmute();

/**
* Tell if playing.
*/
bool isPlaying() const {
return state == State::PLAY;
}

/**
* Change the tempo of the current melody to the proided value
*/
void changeTempo(int newTempo);

/**
* Set the volume (0-255 value) of the player (only works on ESP32 platform)
* The volume is changed by adjusting the duty-cycle of the pwm signal sent to the piezo
* A value of 0 will produce no sound while a value of 255 will set the duty cycle to 50%,
* wich will produce the highest possible volume for the piezo.
*/
void setVolume(byte volume);

/**
* 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
Expand All @@ -96,6 +122,10 @@ class MelodyPlayer {

private:
unsigned char pin;
byte volume = 125;
bool loop = false;
bool muted = false;
void (*stopCallback)(void) = NULL;

#ifdef ESP32
unsigned char pwmChannel;
Expand All @@ -116,9 +146,9 @@ class MelodyPlayer {
*/
class MelodyState {
public:
MelodyState() : first(true), index(0), remainingNoteTime(0){};
MelodyState() : first(true), index(0), remainingNoteTime(0), timeUnit(0) {};
MelodyState(const Melody& melody)
: melody(melody), first(true), silence(false), index(0), remainingNoteTime(0){};
: melody(melody), first(true), silence(false), index(0), remainingNoteTime(0), timeUnit(melody.getTimeUnit()){};
Melody melody;

unsigned short getIndex() const {
Expand All @@ -129,6 +159,10 @@ class MelodyPlayer {
return silence;
}

void changeTempo(int newTempo) {
timeUnit = (60 * 1000 * 4 / newTempo / 32);
}

/**
* Advance the melody index by one step. If there is a pending partial note it hasn't any
* effect.
Expand Down Expand Up @@ -192,7 +226,7 @@ class MelodyPlayer {
*/
NoteDuration getCurrentComputedNote() const {
NoteDuration note = melody.getNote(getIndex());
note.duration = melody.getTimeUnit() * note.duration;
note.duration = timeUnit * note.duration;
// because the fixed point notation
note.duration /= 2;
return note;
Expand All @@ -202,6 +236,7 @@ class MelodyPlayer {
bool first;
bool silence;
unsigned short index;
unsigned short timeUnit;

/**
* Variable to support precise pauses and move/duplicate melodies between Players.
Expand Down
Loading