Skip to content

Commit

Permalink
Equalizer settings to WebUI (#313)
Browse files Browse the repository at this point in the history
* adding equalizer controls to settings page and storing values in NVS

* restoring playMono behaviour

* appending " db" to the equalizer tooltips

* translations changed to less technical terms for lows, mids and highs

* German translation had one miss

* duplication in english log messages

* Equalizer settings moved to dialog on Control page

* Infos added

* Translations

* Fix for title translation

* Visual improvments for Equalizer button and slider sections

* Setting equalizer settings regardless of stereo/mono

---------

Co-authored-by: fabian <fabianjordan@posteo.at>
  • Loading branch information
Trainbird and fabian authored Apr 7, 2024
1 parent 9f25291 commit 9ed09f4
Show file tree
Hide file tree
Showing 13 changed files with 196 additions and 9 deletions.
7 changes: 7 additions & 0 deletions html/locales/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,13 @@
"speakerMax": "Maximal (Lautsprecher)",
"headphoneMax": "Maximal (Kopfhörer)"
},
"equalizer": {
"title": "Equalizer",
"gainLowPass": "Tiefen",
"gainBandPass": "Mitten",
"gainHighPass": "Höhen",
"info": "Die Frequenzen sind laut Bibliothek (ESP32-audioI2S) 500 Hz LowShelf, 3000 Hz PeakEQ und 6000 Hz HighShelf."
},
"neopixel": {
"title": "Neopixel (Helligkeit)",
"restart": "Nach dem Einschalten",
Expand Down
7 changes: 7 additions & 0 deletions html/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,13 @@
"speakerMax": "Max. volume (speaker)",
"headphoneMax": "Max. volume (headphones)"
},
"equalizer": {
"title": "Equalizer",
"gainLowPass": "Lows",
"gainBandPass": "Mids",
"gainHighPass": "Highs",
"info": "According to the library (ESP32-audioI2S), the frequencies are 500 Hz LowShelf, 3000 Hz PeakEQ and 6000 Hz HighShelf."
},
"neopixel": {
"title": "Neopixel (brightness)",
"restart": "After restart",
Expand Down
7 changes: 7 additions & 0 deletions html/locales/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,13 @@
"speakerMax": "Volume maximal (haut-parleur)",
"headphoneMax": "Volume maximal (écouteurs)"
},
"equalizer": {
"title": "Égaliseur",
"gainLowPass": "Graves",
"gainBandPass": "Médiums",
"gainHighPass": "Aigus",
"info": "Les fréquences sont, selon la bibliothèque (ESP32-audioI2S), 500 Hz LowShelf, 3000 Hz PeakEQ et 6000 Hz HighShelf."
},
"neopixel": {
"title": "Neopixel (luminosité)",
"restart": "Après le redémarrage",
Expand Down
113 changes: 112 additions & 1 deletion html/management.html
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,66 @@ <h5 class="modal-title">Infos</h5>
</div>
</div>
</div>
<!-- Modal dialog for equalizer-->
<div class="modal fade bd-info-modal-xl" id="modalEqualizer" role="dialog">
<div class="modal-dialog modal-xl modal-dialog-scrollable" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" data-i18n="general.equalizer.title"></h5>
<button type="button" class="close" data-dismiss="modal">&times;</button>
</div>
<div class="modal-body row" id="modalEqualizerContent">

<div class="col-12">
<label class="w-100" for="gainLowPass" data-i18n="[prepend]general.equalizer.gainLowPass">:</label>
<i class="col-auto fas fa-volume-down fa-2x icon-pos"></i>
<input id="gainLowPass" name="gainLowPass" class="form-control"
data-provide="slider" type="number" required
data-slider-min="-6" data-slider-max="6" min="-6" max="6"
data-slider-value="0" value="0">
<i class="col-auto fas fa-volume-up fa-2x icon-pos"></i>
</div>

<hr class="w-100" />

<div class="col-12">
<label class="w-100" for="gainBandPass" data-i18n="[prepend]general.equalizer.gainBandPass">:</label>
<i class="col-auto fas fa-volume-down fa-2x icon-pos"></i>
<input id="gainBandPass" name="gainBandPass" class="form-control"
data-provide="slider" type="number" required
data-slider-min="-6" data-slider-max="6" min="-6" max="6"
data-slider-value="0" value="0">
<i class="col-auto fas fa-volume-up fa-2x icon-pos"></i>
</div>

<hr class="w-100" />

<div class="col-12">
<label class="w-100" for="gainHighPass" data-i18n="[prepend]general.equalizer.gainHighPass">:</label>
<i class="col-auto fas fa-volume-down fa-2x icon-pos"></i>
<input id="gainHighPass" name="gainHighPass" class="form-control"
data-provide="slider" type="number" required
data-slider-min="-6" data-slider-max="6" min="-6" max="6"
data-slider-value="0" value="0">
<i class="col-auto fas fa-volume-up fa-2x icon-pos"></i>
</div>

<hr class="w-100" />

<div class="col-12">
<div class="row">
<i class="fas fa-info col-auto icon-pos"></i>
<span class="col" data-i18n="general.equalizer.info">
</span>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">OK</button>
</div>
</div>
</div>
</div>
<!-- Modal dialog for delete SSID-->
<div class="modal fade" id="deleteSSIDModal" role="dialog">
<div class="modal-dialog" role="document">
Expand Down Expand Up @@ -363,7 +423,12 @@ <h5 class="modal-title" data-i18n="tools.nvserase.title"></h5>
</div>
<br>
<div class="form-group col-md-12">
<legend data-i18n="control.volume"></legend>
<span class="row">
<legend data-i18n="control.volume" class="col-auto"></legend>
<button type="button" class="openPopupEqualizer btn btn-default btn-lg" data-i18n="[title]general.equalizer.title">
<span class="fas fa-sliders-h"></span>
</button>
</span>
<button type="button" class="btn btn-default btn-lg" onclick="sendControl(177)" data-i18n="[title]control.voldown">
<span class="fas fa-volume-down"></span>
</button>
Expand Down Expand Up @@ -1676,6 +1741,25 @@ <h5 class="modal-title" data-i18n="tools.nvserase.title"></h5>
$('#voltageCheckInterval').bootstrapSlider('setValue', defSettings.voltageCheckInterval);
$('#criticalVoltage').bootstrapSlider('setValue', defSettings.criticalVoltage);
$("#playlistSortMode").val(defSettings.sortMode).change();

$("#gainLowPass").bootstrapSlider('setValue', defSettings.gainLowPass);
$("#gainBandPass").bootstrapSlider('setValue', defSettings.gainBandPass);
$("#gainHighPass").bootstrapSlider('setValue', defSettings.gainHighPass);
// If there is any better way to overwrite the bootstrap slider tooltip - please change this abdomination!
formatDBTooltip($('#gainLowPass')[0].previousSibling, defSettings.gainLowPass);
formatDBTooltip($('#gainBandPass')[0].previousSibling, defSettings.gainBandPass);
formatDBTooltip($('#gainHighPass')[0].previousSibling, defSettings.gainHighPass);
}

let eqSettings = settings.equalizer;
if (eqSettings) {
$("#gainLowPass").bootstrapSlider('setValue', eqSettings.gainLowPass);
$("#gainBandPass").bootstrapSlider('setValue', eqSettings.gainBandPass);
$("#gainHighPass").bootstrapSlider('setValue', eqSettings.gainHighPass);
// If there is any better way to overwrite the bootstrap slider tooltip - please change this abdomination!
formatDBTooltip($('#gainLowPass')[0].previousSibling, eqSettings.gainLowPass);
formatDBTooltip($('#gainBandPass')[0].previousSibling, eqSettings.gainBandPass)
formatDBTooltip($('#gainHighPass')[0].previousSibling, eqSettings.gainHighPass);
}
// wifi
let wifiSettings = settings.wifi;
Expand Down Expand Up @@ -2273,6 +2357,10 @@ <h5 class="modal-title" data-i18n="tools.nvserase.title"></h5>
$('#navbar-heading').text(newTitle);
}

function formatDBTooltip(target, value) {
target.querySelector('.tooltip-main .tooltip-inner').innerHTML = `${value} dB`;
}

$(document).ready(function () {
connect();
buildFileSystemTree("/");
Expand Down Expand Up @@ -2312,6 +2400,29 @@ <h5 class="modal-title" data-i18n="tools.nvserase.title"></h5>
$('#modalInfoRefresh').hide();
shutdownDevice();
});
$('.openPopupEqualizer').on('click', () => {
$('#modalEqualizer .modal-title').text(i18next.t("general.equalizer.title"));
$('#modalEqualizer').modal({show: true});
});

// sending equalizer settings to API for
$('#modalEqualizer .slider').on('slideStop', function({target, value}){
formatDBTooltip(target, value);
let myObj = {
"equalizer": {
gainLowPass: Number(document.getElementById("gainLowPass").value),
gainBandPass: Number(document.getElementById("gainBandPass").value),
gainHighPass: Number(document.getElementById("gainHighPass").value)
}
};
var myJSON = JSON.stringify(myObj);
// update global settings
window.settings = { ...window.settings, ...myObj };
socket.send(myJSON);
});
$('#modalEqualizer .slider').on('slide', function({target, value}) {
formatDBTooltip(target, value);
});

$(function () {
$('[data-toggle="tooltip"]').tooltip();
Expand Down
21 changes: 15 additions & 6 deletions src/AudioPlayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ void AudioPlayer_Init(void) {

// initialize gPlayProperties
memset(&gPlayProperties, 0, sizeof(gPlayProperties));
gPlayProperties.playlistFinished = true;
gPlayProperties.playlistFinished = true;

// clear title and cover image
gPlayProperties.title[0] = '\0';
Expand Down Expand Up @@ -393,9 +393,8 @@ void AudioPlayer_Task(void *parameter) {
audio->setVolumeSteps(AUDIOPLAYER_VOLUME_MAX);
audio->setVolume(AudioPlayer_CurrentVolume, VOLUMECURVE);
audio->forceMono(gPlayProperties.currentPlayMono);
if (gPlayProperties.currentPlayMono) {
audio->setTone(3, 0, 0);
}
int8_t currentEqualizer[3] = {gPrefsSettings.getChar("gainLowPass", 0), gPrefsSettings.getChar("gainBandPass", 0), gPrefsSettings.getChar("gainHighPass", 0)};
audio->setTone(currentEqualizer[0], currentEqualizer[1], currentEqualizer[2]);

uint8_t currentVolume;
BaseType_t trackQStatus = pdFAIL;
Expand All @@ -420,6 +419,11 @@ void AudioPlayer_Task(void *parameter) {
#endif
}

if (xQueueReceive(gEqualizerQueue, &currentEqualizer, 0) == pdPASS) {
Log_Printf(LOGLEVEL_DEBUG, newEqualizerReceivedQueue, currentEqualizer[0], currentEqualizer[1], currentEqualizer[2]);
audio->setTone(currentEqualizer[0], currentEqualizer[1], currentEqualizer[2]);
}

if (xQueueReceive(gTrackControlQueue, &trackCommand, 0) == pdPASS) {
Log_Printf(LOGLEVEL_INFO, newCntrlReceivedQueue, trackCommand);
}
Expand Down Expand Up @@ -866,11 +870,10 @@ void AudioPlayer_Task(void *parameter) {
audio->forceMono(gPlayProperties.currentPlayMono);
if (gPlayProperties.currentPlayMono) {
Log_Println(newPlayModeMono, LOGLEVEL_NOTICE);
audio->setTone(3, 0, 0);
} else {
Log_Println(newPlayModeStereo, LOGLEVEL_NOTICE);
audio->setTone(0, 0, 0);
}
audio->setTone(gPlayProperties.gainLowPass, gPlayProperties.gainBandPass, gPlayProperties.gainHighPass);
}

audio->loop();
Expand Down Expand Up @@ -961,6 +964,12 @@ void AudioPlayer_VolumeToQueueSender(const int32_t _newVolume, bool reAdjustRota
}
}

// Adds equalizer settings low, band and high pass and readjusts the equalizer
void AudioPlayer_EqualizerToQueueSender(const int8_t gainLowPass, const int8_t gainBandPass, const int8_t gainHighPass) {
int8_t _equalizer[3] = {gainLowPass, gainBandPass, gainHighPass};
xQueueSend(gEqualizerQueue, &_equalizer, 0);
}

// Pauses playback if playback is active and volume is changes from minVolume+1 to minVolume (usually 0)
void AudioPlayer_PauseOnMinVolume(const uint8_t oldVolume, const uint8_t newVolume) {
#ifdef PAUSE_ON_MIN_VOLUME
Expand Down
4 changes: 4 additions & 0 deletions src/AudioPlayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ typedef struct { // Bit field
uint8_t tellMode : 2; // Tell mode for text to speech announcments
bool currentSpeechActive : 1; // If speech-play is active
bool lastSpeechActive : 1; // If speech-play was active
int8_t gainLowPass = 0; // Low Pass for EQ Control
int8_t gainBandPass = 0; // Band Pass for EQ Control
int8_t gainHighPass = 0; // High Pass for EQ Control
size_t coverFilePos; // current cover file position
size_t coverFileSize; // current cover file size
size_t audioFileSize; // file size of current audio file
Expand All @@ -51,6 +54,7 @@ void AudioPlayer_Exit(void);
void AudioPlayer_Cyclic(void);
uint8_t AudioPlayer_GetRepeatMode(void);
void AudioPlayer_VolumeToQueueSender(const int32_t _newVolume, bool reAdjustRotary);
void AudioPlayer_EqualizerToQueueSender(const int8_t gainLowPass, const int8_t gainBandPass, const int8_t gainHighPass);
void AudioPlayer_TrackQueueDispatcher(const char *_itemToPlay, const uint32_t _lastPlayPos, const uint32_t _playMode, const uint16_t _trackLastPlayed);
void AudioPlayer_TrackControlToQueueSender(const uint8_t trackCommand);
void AudioPlayer_PauseOnMinVolume(const uint8_t oldVolume, const uint8_t newVolume);
Expand Down
4 changes: 3 additions & 1 deletion src/LogMessages_DE.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const char reallocCalled[] = "Speicher reallokiert.";
const char unableToAllocateMemForLinearPlaylist[] = "Speicher für lineare Playlist konnte nicht allokiert werden!";
const char numberOfValidFiles[] = "Anzahl gültiger Files/Webstreams: %u";
const char newLoudnessReceivedQueue[] = "Neue Lautstärke empfangen via Queue: %u";
const char newEqualizerReceivedQueue[] = "Neue Equalizer-Einstellungen empfangen via Queue: %i, %i, %i";
const char newCntrlReceivedQueue[] = "Kontroll-Kommando empfangen via Queue: %u";
const char newPlaylistReceived[] = "Neue Playlist mit %d Titel(n) empfangen";
const char repeatTrackDueToPlaymode[] = "Wiederhole Titel aufgrund von Playmode.";
Expand Down Expand Up @@ -114,7 +115,8 @@ const char unableToMountSd[] = "SD-Karte konnte nicht gemountet werden.";
const char unableToCreateVolQ[] = "Konnte Volume-Queue nicht anlegen.";
const char unableToCreateRfidQ[] = "Konnte RFID-Queue nicht anlegen.";
const char unableToCreateMgmtQ[] = "Konnte Play-Management-Queue nicht anlegen.";
const char unableToCreatePlayQ[] = "Konnte Track-Queue nicht anlegen..";
const char unableToCreatePlayQ[] = "Konnte Track-Queue nicht anlegen.";
const char unableToCreateEqualizerQ[] = "Konnte Equalizer-Queue nicht anlegen.";
const char initialBrightnessfromNvs[] = "Initiale LED-Helligkeit wurde aus NVS geladen: %u";
const char wroteInitialBrightnessToNvs[] = "Initiale LED-Helligkeit wurde ins NVS geschrieben.";
const char restoredInitialBrightnessForNmFromNvs[] = "LED-Helligkeit für Nachtmodus wurde aus NVS geladen: %u";
Expand Down
4 changes: 3 additions & 1 deletion src/LogMessages_EN.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const char reallocCalled[] = "Reallocated memory.";
const char unableToAllocateMemForLinearPlaylist[] = "Unable to allocate memory for linear playlist!";
const char numberOfValidFiles[] = "Number of valid files/webstreams: %u";
const char newLoudnessReceivedQueue[] = "New volume received via queue: %u";
const char newEqualizerReceivedQueue[] = "New equalizer settings received via queue: %i, %i, %i";
const char newCntrlReceivedQueue[] = "Control-command received via queue: %u";
const char newPlaylistReceived[] = "New playlist received with %d track(s)";
const char repeatTrackDueToPlaymode[] = "Repeating track due to playmode configured.";
Expand Down Expand Up @@ -115,7 +116,8 @@ const char unableToMountSd[] = "Unable to mount sd-card.";
const char unableToCreateVolQ[] = "Unable to create volume-queue.";
const char unableToCreateRfidQ[] = "Unable to create RFID-queue.";
const char unableToCreateMgmtQ[] = "Unable to play-management-queue.";
const char unableToCreatePlayQ[] = "Unable to create track-queue..";
const char unableToCreatePlayQ[] = "Unable to create track-queue.";
const char unableToCreateEqualizerQ[] = "Unable to create equalizer-queue.";
const char initialBrightnessfromNvs[] = "Restoring initial LED-brightness from NVS: %u";
const char wroteInitialBrightnessToNvs[] = "Storing initial LED-brightness to NVS.";
const char restoredInitialBrightnessForNmFromNvs[] = "Restored LED-brightness for nightmode from NVS: %u";
Expand Down
2 changes: 2 additions & 0 deletions src/LogMessages_FR.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ const char reallocCalled[] = "Mémoire réallouée.";
const char unableToAllocateMemForLinearPlaylist[] = "Impossible d'allouer de la mémoire pour la liste de lecture linéaire !";
const char numberOfValidFiles[] = "Nombre de fichiers/webdiffusions valides : %u";
const char newLoudnessReceivedQueue[] = "Nouveau volume reçu via la file d'attente : %u";
const char newEqualizerReceivedQueue[] = "Nouveau paramètres d'égalisation reçus via la file d'attente: %i, %i, %i";
const char newCntrlReceivedQueue[] = "Commande de contrôle reçue via la file d'attente : %u";
const char newPlaylistReceived[] = "Nouvelle liste de lecture reçue avec %d piste(s)";
const char repeatTrackDueToPlaymode[] = "Piste répétée en raison du mode de lecture configuré.";
Expand Down Expand Up @@ -114,6 +115,7 @@ const char unableToCreateVolQ[] = "Impossible de créer la file d'attente de vol
const char unableToCreateRfidQ[] = "Impossible de créer la file d'attente RFID.";
const char unableToCreateMgmtQ[] = "Impossible de créer la file de gestion de lecture.";
const char unableToCreatePlayQ[] = "Impossible de créer la file d'attente de piste.";
const char unableToCreateEqualizerQ[] = "Impossible de créer la file d'attente de equalizer.";
const char initialBrightnessfromNvs[] = "Restauration de la luminosité LED initiale depuis NVS : %u";
const char wroteInitialBrightnessToNvs[] = "Stockage de la luminosité LED initiale dans NVS.";
const char restoredInitialBrightnessForNmFromNvs[] = "Luminosité LED restaurée pour le mode nuit depuis NVS : %u";
Expand Down
6 changes: 6 additions & 0 deletions src/Queues.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ QueueHandle_t gVolumeQueue;
QueueHandle_t gTrackQueue;
QueueHandle_t gTrackControlQueue;
QueueHandle_t gRfidCardQueue;
QueueHandle_t gEqualizerQueue;

void Queues_Init(void) {
// Create queues
Expand All @@ -31,4 +32,9 @@ void Queues_Init(void) {
if (gTrackQueue == NULL) {
Log_Println(unableToCreatePlayQ, LOGLEVEL_ERROR);
}

gEqualizerQueue = xQueueCreate(1, sizeof(int8_t [3]));
if (gEqualizerQueue == NULL) {
Log_Println(unableToCreateEqualizerQ, LOGLEVEL_ERROR);
}
}
1 change: 1 addition & 0 deletions src/Queues.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ extern QueueHandle_t gVolumeQueue;
extern QueueHandle_t gTrackQueue;
extern QueueHandle_t gTrackControlQueue;
extern QueueHandle_t gRfidCardQueue;
extern QueueHandle_t gEqualizerQueue;

void Queues_Init(void);
27 changes: 27 additions & 0 deletions src/Web.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -625,6 +625,22 @@ bool JSONToSettings(JsonObject doc) {
return false;
}
}
if (doc.containsKey("equalizer")) {
int8_t _gainLowPass = doc["equalizer"]["gainLowPass"].as<int8_t>();
int8_t _gainBandPass = doc["equalizer"]["gainBandPass"].as<int8_t>();
int8_t _gainHighPass = doc["equalizer"]["gainHighPass"].as<int8_t>();
// equalizer settings
if (
gPrefsSettings.putChar("gainLowPass", _gainLowPass) == 0 ||
gPrefsSettings.putChar("gainBandPass", _gainBandPass) == 0 ||
gPrefsSettings.putChar("gainHighPass", _gainHighPass) == 0
) {
Log_Printf(LOGLEVEL_ERROR, webSaveSettingsError, "equalizer");
return false;
} else {
AudioPlayer_EqualizerToQueueSender(_gainLowPass, _gainBandPass, _gainHighPass);
}
}
if (doc.containsKey("wifi")) {
// WiFi settings
String hostName = doc["wifi"]["hostname"];
Expand Down Expand Up @@ -796,6 +812,13 @@ static void settingsToJSON(JsonObject obj, const String section) {
generalObj["maxVolumeHp"].set(gPrefsSettings.getUInt("maxVolumeHp", 0));
generalObj["sleepInactivity"].set(gPrefsSettings.getUInt("mInactiviyT", 0));
}
if ((section == "") || (section == "equalizer")) {
// equalizer settings
JsonObject equalizerObj = obj.createNestedObject("equalizer");
equalizerObj["gainLowPass"].set(gPrefsSettings.getChar("gainLowPass", 0));
equalizerObj["gainBandPass"].set(gPrefsSettings.getChar("gainBandPass", 0));
equalizerObj["gainHighPass"].set(gPrefsSettings.getChar("gainHighPass", 0));
}
if ((section == "") || (section == "wifi")) {
// WiFi settings
JsonObject wifiObj = obj.createNestedObject("wifi");
Expand Down Expand Up @@ -851,6 +874,10 @@ static void settingsToJSON(JsonObject obj, const String section) {
defaultsObj["maxVolumeSp"].set(21u); // AUDIOPLAYER_VOLUME_MAX
defaultsObj["maxVolumeHp"].set(18u); // gPrefsSettings.getUInt("maxVolumeHp", 0));
defaultsObj["sleepInactivity"].set(10u); // System_MaxInactivityTime

defaultsObj["gainHighPass"].set(0);
defaultsObj["gainBandPass"].set(0);
defaultsObj["gainLowPass"].set(0);
#ifdef NEOPIXEL_ENABLE
defaultsObj["initBrightness"].set(16u); // LED_INITIAL_BRIGHTNESS
defaultsObj["nightBrightness"].set(2u); // LED_INITIAL_NIGHT_BRIGHTNESS
Expand Down
Loading

1 comment on commit 9ed09f4

@dandud100
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hat #define PLAY_MONO_SPEAKER nach diesem Commit noch eine Auswirkung auf den Ton? Bis jetzt war es ja so, dass dadurch die Mitten um 3 angehoben wurden.

Please sign in to comment.