From db8881a36841717d5ece2d599590514a0da8c3b5 Mon Sep 17 00:00:00 2001 From: Fred BORRY Date: Sat, 11 Nov 2023 22:03:06 +0100 Subject: [PATCH 1/6] Added volume support for ESP32 --- src/melody_player.cpp | 12 +++++++++++- src/melody_player.h | 14 ++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/melody_player.cpp b/src/melody_player.cpp index 9261368..c11936b 100644 --- a/src/melody_player.cpp +++ b/src/melody_player.cpp @@ -211,7 +211,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; +#ifdef ESP32 + if(state == State::PLAY) + { + ledcWrite(pwmChannel, volume); + } #endif } diff --git a/src/melody_player.h b/src/melody_player.h index af290e9..b9652db 100644 --- a/src/melody_player.h +++ b/src/melody_player.h @@ -80,6 +80,19 @@ class MelodyPlayer { 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 @@ -96,6 +109,7 @@ class MelodyPlayer { private: unsigned char pin; + byte volume = 125; #ifdef ESP32 unsigned char pwmChannel; From 30bf217bb9623f945aadec7192b82b19d087368b Mon Sep 17 00:00:00 2001 From: Fred BORRY Date: Sat, 11 Nov 2023 22:17:41 +0100 Subject: [PATCH 2/6] Fixed volume support --- src/melody_player.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/melody_player.cpp b/src/melody_player.cpp index c11936b..d55c0eb 100644 --- a/src/melody_player.cpp +++ b/src/melody_player.cpp @@ -100,6 +100,7 @@ void changeTone(MelodyPlayer* player) { } else { #ifdef ESP32 ledcWriteTone(player->pwmChannel, computedNote.frequency); + ledcWrite(player->pwmChannel,player->volume); #else tone(player->pin, computedNote.frequency); #endif @@ -216,7 +217,7 @@ void MelodyPlayer::turnOn() { } void MelodyPlayer::setVolume(byte newVolume) { - volume = newVolume; + volume = newVolume/2; #ifdef ESP32 if(state == State::PLAY) { From f3cf05e6b738bc3c1b5e852577d2ff9c22895e08 Mon Sep 17 00:00:00 2001 From: Fred BORRY Date: Sat, 11 Nov 2023 23:07:46 +0100 Subject: [PATCH 3/6] Added loop mode support --- src/melody_player.cpp | 8 +++++++- src/melody_player.h | 4 +++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/melody_player.cpp b/src/melody_player.cpp index d55c0eb..f271454 100644 --- a/src/melody_player.cpp +++ b/src/melody_player.cpp @@ -113,7 +113,12 @@ void changeTone(MelodyPlayer* player) { } player->supportSemiNote = millis() + duration; } else { + // End of the melody player->stop(); + if(player->loop) + { // Loop mode => start over + player->playAsync(); + } } } @@ -131,9 +136,10 @@ void MelodyPlayer::playAsync() { #endif } -void MelodyPlayer::playAsync(Melody& melody) { +void MelodyPlayer::playAsync(Melody& melody, bool loopMelody) { if (!melody) { return; } melodyState = make_unique(melody); + loop = loopMelody; playAsync(); } diff --git a/src/melody_player.h b/src/melody_player.h index b9652db..3475588 100644 --- a/src/melody_player.h +++ b/src/melody_player.h @@ -57,8 +57,9 @@ 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. */ - void playAsync(Melody& melody); + void playAsync(Melody& melody, bool loop = false); /** * Stop the current melody. @@ -110,6 +111,7 @@ void setVolume(byte volume); private: unsigned char pin; byte volume = 125; + bool loop = false; #ifdef ESP32 unsigned char pwmChannel; From 1df12dc04942451d6a1b5d1a41f445314771aaa0 Mon Sep 17 00:00:00 2001 From: Fred BORRY Date: Sat, 11 Nov 2023 23:36:20 +0100 Subject: [PATCH 4/6] Added support for end of melody callback --- src/melody_player.cpp | 7 ++++++- src/melody_player.h | 4 +++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/melody_player.cpp b/src/melody_player.cpp index f271454..9795e0a 100644 --- a/src/melody_player.cpp +++ b/src/melody_player.cpp @@ -119,6 +119,10 @@ void changeTone(MelodyPlayer* player) { { // Loop mode => start over player->playAsync(); } + else if(player->stopCallback != NULL) + { + player->stopCallback(); + } } } @@ -136,10 +140,11 @@ void MelodyPlayer::playAsync() { #endif } -void MelodyPlayer::playAsync(Melody& melody, bool loopMelody) { +void MelodyPlayer::playAsync(Melody& melody, bool loopMelody, void(*callback)(void)) { if (!melody) { return; } melodyState = make_unique(melody); loop = loopMelody; + stopCallback = callback; playAsync(); } diff --git a/src/melody_player.h b/src/melody_player.h index 3475588..2efc037 100644 --- a/src/melody_player.h +++ b/src/melody_player.h @@ -58,8 +58,9 @@ 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, bool loop = false); + void playAsync(Melody& melody, bool loop = false, void(*stopCallback)(void) = NULL); /** * Stop the current melody. @@ -112,6 +113,7 @@ void setVolume(byte volume); unsigned char pin; byte volume = 125; bool loop = false; + void (*stopCallback)(void) = NULL; #ifdef ESP32 unsigned char pwmChannel; From 869decd97eedb09db32d0b760ff4892a48e5d88b Mon Sep 17 00:00:00 2001 From: Fred BORRY Date: Sun, 12 Nov 2023 00:22:38 +0100 Subject: [PATCH 5/6] Added mute function --- src/melody_player.cpp | 27 ++++++++++++++++++++++----- src/melody_player.h | 30 +++++++++++++++++++++--------- 2 files changed, 43 insertions(+), 14 deletions(-) diff --git a/src/melody_player.cpp b/src/melody_player.cpp index 9795e0a..b1ae8c8 100644 --- a/src/melody_player.cpp +++ b/src/melody_player.cpp @@ -86,11 +86,14 @@ 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); @@ -98,12 +101,15 @@ void changeTone(MelodyPlayer* player) { player->ticker.once_ms_scheduled(duration, std::bind(changeTone, player)); #endif } else { + if(!player->muted) + { #ifdef ESP32 - ledcWriteTone(player->pwmChannel, computedNote.frequency); - ledcWrite(player->pwmChannel,player->volume); + 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); @@ -250,3 +256,14 @@ 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; +} diff --git a/src/melody_player.h b/src/melody_player.h index 2efc037..e5d84d6 100644 --- a/src/melody_player.h +++ b/src/melody_player.h @@ -75,6 +75,17 @@ 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. */ @@ -84,16 +95,16 @@ class MelodyPlayer { /** * Change the tempo of the current melody to the proided value - */ - void changeTempo(int newTempo); + */ + 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); + /** + * 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. @@ -113,6 +124,7 @@ void setVolume(byte volume); unsigned char pin; byte volume = 125; bool loop = false; + bool muted = false; void (*stopCallback)(void) = NULL; #ifdef ESP32 From 424ed1b64b2bb8ee40012fac8ecbbd556ddec7fe Mon Sep 17 00:00:00 2001 From: Fred BORRY Date: Sun, 12 Nov 2023 01:00:31 +0100 Subject: [PATCH 6/6] Added support for tempo change --- src/melody_player.cpp | 5 +++++ src/melody_player.h | 11 ++++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/melody_player.cpp b/src/melody_player.cpp index b1ae8c8..c8ad26c 100644 --- a/src/melody_player.cpp +++ b/src/melody_player.cpp @@ -267,3 +267,8 @@ void MelodyPlayer::unmute() { #endif muted = false; } + +void MelodyPlayer::changeTempo(int newTempo) { + if (melodyState == nullptr) { return; } + melodyState->changeTempo(newTempo); +} diff --git a/src/melody_player.h b/src/melody_player.h index e5d84d6..8f4d771 100644 --- a/src/melody_player.h +++ b/src/melody_player.h @@ -146,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 { @@ -159,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. @@ -222,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; @@ -232,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.