Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
ddea7bf
Merge pull request #1 from biologist79/master
Joe91 Dec 18, 2022
c669a67
Merge pull request #2 from biologist79/master
Joe91 Jan 6, 2023
6fee1a6
feature tts as playmode and button-action
Joe91 Jan 8, 2023
db08969
fix English translation
Joe91 Jan 8, 2023
7077626
some cleanup on the website
Joe91 Jan 8, 2023
5ac8e09
english translation review
Joe91 Jan 8, 2023
d97ac88
Merge pull request #3 from biologist79/master
Joe91 Feb 6, 2023
33c09ce
Merge pull request #4 from biologist79/master
Joe91 Feb 7, 2023
48605b3
Merge branch 'master' into feature_tts
Joe91 Feb 9, 2023
72856e3
removed web-stuff and start to add them again.
Joe91 Feb 9, 2023
fb64bb9
try to add command-selection
Joe91 Feb 9, 2023
fef0288
Bugfix for automatic file generation
laszloh Feb 10, 2023
9e46a7f
Merge pull request #5 from laszloh/i18n_bugfix
Joe91 Feb 11, 2023
ca36576
Merge pull request #6 from biologist79/master
Joe91 Feb 11, 2023
f9189a7
Merge remote-tracking branch 'origin/master' into feature_tts
Joe91 Feb 11, 2023
2d72990
add custom-text-command again
Joe91 Feb 9, 2023
80af63d
bugfix: UTF8 encoding & missing translation
laszloh Feb 13, 2023
8c9e94b
Merge pull request #7 from biologist79/master
Joe91 Feb 14, 2023
31bc052
Merge branch 'master' into feature_tts
Joe91 Feb 14, 2023
cede224
execute modification works again
Joe91 Feb 14, 2023
3136802
prepare for custom-text
Joe91 Feb 14, 2023
0fcf902
Merge pull request #8 from laszloh/i18n_bugfix
Joe91 Feb 14, 2023
857fe25
add custom-text again
Joe91 Feb 14, 2023
abd804e
don't require text anymore
Joe91 Feb 14, 2023
4e2f34b
Merge pull request #9 from biologist79/master
Joe91 Feb 14, 2023
11497bf
fix assignment in webserver
Joe91 Feb 14, 2023
9f2e300
Merge pull request #10 from biologist79/master
Joe91 Feb 23, 2023
bddd713
Merge remote-tracking branch 'origin/master' into feature_tts
Joe91 Feb 23, 2023
5fdeb92
fix merge issues
Joe91 Feb 23, 2023
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
16 changes: 13 additions & 3 deletions html/locales/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"submit": "Absenden",
"restart": "Neustart",
"reset": "Reset",
"execute": "Ausführen",
"title": "ESPuino-Konfiguration",
"shutdown": "Ausschalten",
"log": "Log",
Expand Down Expand Up @@ -50,7 +51,8 @@
"volume": "Lautstärke",
"voldown": "Leiser",
"volup": "Lauter",
"current": "Aktueller Titel"
"current": "Aktueller Titel",
"command": "Modifikation Ausführen"
},
"files": {
"title": "Dateien",
Expand Down Expand Up @@ -109,7 +111,8 @@
"9":"Alle Titel eines Verzeichnis (zufällig, Endlosschleife)",
"13":"Alle Titel aus einem zufälligen Unterverzeichnis (sortiert)",
"8":"Webradio",
"11":"Liste (Dateien von SD und/oder Webstreams) aus lokaler .m3u-Datei"
"11":"Liste (Dateien von SD und/oder Webstreams) aus lokaler .m3u-Datei",
"14":"Gesprochener Text"
}
},
"mod": {
Expand Down Expand Up @@ -139,7 +142,8 @@
"173":"Erster Titel",
"174":"Letzter Titel",
"180":"Springe vorwärts (n Sekunden)",
"181":"Springe rückwärts (n Sekunden)"
"181":"Springe rückwärts (n Sekunden)",
"152":"Lese Benutzertext"
}
}
}
Expand Down Expand Up @@ -212,6 +216,12 @@
"lowCritical": "Eine LED leuchtet bei dieser Spannung",
"high": "Alle LEDs leuchten bei dieser Spannung",
"measureInterval": "Zeitabstand der Messung (in Minuten)"
},
"customtext": {
"title": "Benutzerdefinierte Ansage",
"desc": "Benuterdefinierte Ansage des ESPUINO",
"textLabel": "Text der Ansage",
"textDefault": "Dies ist der ESPUINO von Torsten"
}
},
"tools": {
Expand Down
18 changes: 14 additions & 4 deletions html/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"submit": "Submit",
"restart": "Restart",
"reset": "Reset",
"execute": "Execute",
"title": "ESPuino-Settings",
"shutdown": "Shutdown",
"log": "Log",
Expand Down Expand Up @@ -50,7 +51,8 @@
"volume": "Volume",
"voldown": "Volume Down",
"volup": "Volume Up",
"current": "Current track"
"current": "Current track",
"command": "Excecute Modification"
},
"files": {
"title": "Files",
Expand Down Expand Up @@ -109,7 +111,8 @@
"9":"All tracks of a directory (random, loop)",
"13":"All tracks of a random subdirectory (sorted alph.)",
"8":"Webradio",
"11":"List (files from SD and/or webstreams) from local .m3u-File"
"11":"List (files from SD and/or webstreams) from local .m3u-File",
"14":"Text To Speech"
}
},
"mod": {
Expand Down Expand Up @@ -139,7 +142,8 @@
"173":"First track",
"174":"Last track",
"180":"Seek forwards (n seconds)",
"181":"Seek backwards (n seconds)"
"181":"Seek backwards (n seconds)",
"152":"Read Custom Text"
}
}
}
Expand Down Expand Up @@ -212,7 +216,13 @@
"lowCritical": "Lowest voltage, that is indicated by one LED",
"high": "Voltage, that is indicated by all LEDs",
"measureInterval": "Interval between measurements (in minutes)"
}
},
"customtext": {
"title": "User defined speech",
"desc": "User defined speech of the ESPUINO",
"textLabel": "Text of speech",
"textDefault": "This is the ESPUINO of Torsten"
}
},
"tools": {
"nvserase": {
Expand Down
65 changes: 63 additions & 2 deletions html/management.html
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,43 @@
<legend data-i18n="control.current"></legend>
<div id="track"></div>
</div>
<br/>
<div class="form-group col-md-12">
<legend data-i18n="control.command"></legend>
<div class="tab-pane " id="rfidmod" role="tabpanel">
<label for="modId" data-i18n="files.rfid.mod.title"></label>
<select class="form-control" id="commandId" name="modId">
<option class="placeholder" disabled selected value="" data-i18n="files.rfid.mod.placeholder"></option>
<option value="100" data-i18n="files.rfid.mod.cmd.100"></option>
<option value="179" data-i18n="files.rfid.mod.cmd.179"></option>
<option value="101" data-i18n="files.rfid.mod.cmd.101"></option>
<option value="102" data-i18n="files.rfid.mod.cmd.102"></option>
<option value="103" data-i18n="files.rfid.mod.cmd.103"></option>
<option value="104" data-i18n="files.rfid.mod.cmd.104"></option>
<option value="105" data-i18n="files.rfid.mod.cmd.105"></option>
<option value="106" data-i18n="files.rfid.mod.cmd.106"></option>
<option value="107" data-i18n="files.rfid.mod.cmd.107"></option>
<option value="110" data-i18n="files.rfid.mod.cmd.110"></option>
<option value="111" data-i18n="files.rfid.mod.cmd.111"></option>
<option value="120" data-i18n="files.rfid.mod.cmd.120"></option>
<option value="130" data-i18n="files.rfid.mod.cmd.130"></option>
<option value="140" data-i18n="files.rfid.mod.cmd.140"></option>
<option value="141" data-i18n="files.rfid.mod.cmd.141"></option>
<option value="150" data-i18n="files.rfid.mod.cmd.150"></option>
<option value="0" data-i18n="files.rfid.mod.cmd.0"></option>
<option value="170" data-i18n="files.rfid.mod.cmd.170"></option>
<option value="171" data-i18n="files.rfid.mod.cmd.171"></option>
<option value="172" data-i18n="files.rfid.mod.cmd.172"></option>
<option value="173" data-i18n="files.rfid.mod.cmd.173"></option>
<option value="174" data-i18n="files.rfid.mod.cmd.174"></option>
<option value="180" data-i18n="files.rfid.mod.cmd.180"></option>
<option value="181" data-i18n="files.rfid.mod.cmd.181"></option>
<option value="152" data-i18n="files.rfid.mod.cmd.152"></option>
</select>
</div>
<br>
<button type="button" class="btn btn-primary" onclick="executeCommand()" data-i18n="execute">Execute</button>
</div>
</div>
</div>
<div class="tab-pane fade show active" id="nav-rfid" role="tabpanel" aria-labelledby="nav-rfid-tab">
Expand Down Expand Up @@ -305,6 +342,7 @@
<option class="option-folder" value="13" data-i18n="files.rfid.playmode.mode.13"></option>
<option class="option-stream" value="8" data-i18n="files.rfid.playmode.mode.8"></option>
<option class="option-stream" value="11" data-i18n="files.rfid.playmode.mode.11"></option>
<option class="option-stream" value="14" data-i18n="files.rfid.playmode.mode.14"></option>
</select>
</div>
<div class="tab-pane " id="rfidmod" role="tabpanel">
Expand Down Expand Up @@ -335,6 +373,7 @@
<option value="174" data-i18n="files.rfid.mod.cmd.174"></option>
<option value="180" data-i18n="files.rfid.mod.cmd.180"></option>
<option value="181" data-i18n="files.rfid.mod.cmd.181"></option>
<option value="152" data-i18n="files.rfid.mod.cmd.152"></option>
</select>
</div>
</div>
Expand Down Expand Up @@ -502,7 +541,19 @@

</fieldset>
</div>
<br>
<br>

<div class="form-group col-md-12">
<fieldset>
<legend data-i18n="general.customtext.title"></legend>
<div data-i18n="general.customtext.desc"></div>
<br>
<label for="customText" data-i18n="[prepend]general.customtext.textLabel">:</label>
<input type="text" class="form-control" id="customText" maxlength="255" pattern="^[^\^#]+$"
data-i18n="[placeholder]general.customtext.textDefault" name="customText">
</fieldset>
</div>

<div class="text-center">
<button type="reset" class="btn btn-secondary" data-i18n="reset"></button>&nbsp
<button type="submit" class="btn btn-primary" data-i18n="submit"></button>
Expand Down Expand Up @@ -1245,7 +1296,8 @@
vWarning: document.getElementById('warningLowVoltage').value,
vIndLow: document.getElementById('voltageIndicatorLow').value,
vIndHi: document.getElementById('voltageIndicatorHigh').value,
vInt: document.getElementById('voltageCheckInterval').value
vInt: document.getElementById('voltageCheckInterval').value,
vCustText: document.getElementById('customText').value
}
};
var myJSON = JSON.stringify(myObj);
Expand Down Expand Up @@ -1346,6 +1398,15 @@
var myJSON = JSON.stringify(myObj);
socket.send(myJSON);
}
function executeCommand() {
var myObj = {
"controls": {
action: document.getElementById('commandId').value
}
};
var myJSON = JSON.stringify(myObj);
socket.send(myJSON);
}
function sendVolume(vol) {
var myObj = {
"controls": {
Expand Down
66 changes: 62 additions & 4 deletions src/AudioPlayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ static uint8_t AudioPlayer_InitVolume = AUDIOPLAYER_VOLUME_INIT;
static void AudioPlayer_Task(void *parameter);
static void AudioPlayer_HeadphoneVolumeManager(void);
static char **AudioPlayer_ReturnPlaylistFromWebstream(const char *_webUrl);
static char **AutioPlayer_ReturnPlaylistFromTextToSpeech(const char *_textToInsert);
static int AudioPlayer_ArrSortHelper(const void *a, const void *b);
static void AudioPlayer_SortPlaylist(const char **arr, int n);
static void AudioPlayer_SortPlaylist(char *str[], const uint32_t count);
Expand Down Expand Up @@ -624,6 +625,12 @@ void AudioPlayer_Task(void *parameter) {
if (gPlayProperties.playMode == WEBSTREAM || (gPlayProperties.playMode == LOCAL_M3U && gPlayProperties.isWebstream)) { // Webstream
audioReturnCode = audio->connecttohost(*(gPlayProperties.playlist + gPlayProperties.currentTrackNumber));
gPlayProperties.playlistFinished = false;
} else if (gPlayProperties.playMode == TEXT_TO_SPEECH) {
audioReturnCode = true; // is handled later
gPlayProperties.tellCustomText = true;
gPlayProperties.currentSpeechActive = true;
gPlayProperties.lastSpeechActive = true;
gPlayProperties.playlistFinished = false;
} else if (gPlayProperties.playMode != WEBSTREAM && !gPlayProperties.isWebstream) {
// Files from SD
if (!gFSystem.exists(*(gPlayProperties.playlist + gPlayProperties.currentTrackNumber))) { // Check first if file/folder exists
Expand Down Expand Up @@ -657,6 +664,8 @@ void AudioPlayer_Task(void *parameter) {
} else {
Audio_setTitle("Webradio");
}
} else if (gPlayProperties.tellCustomText) {
Audio_setTitle("Text To Speech");
} else {
if (gPlayProperties.numberOfTracks > 1) {
Audio_setTitle("(%u/%u): %s", gPlayProperties.currentTrackNumber+1, gPlayProperties.numberOfTracks, *(gPlayProperties.playlist + gPlayProperties.currentTrackNumber));
Expand Down Expand Up @@ -719,10 +728,32 @@ void AudioPlayer_Task(void *parameter) {
}
}

// Handle custom text
if (gPlayProperties.tellCustomText) {
gPlayProperties.tellCustomText = false;
bool speechOk;
String customText = "";
if (gPlayProperties.playMode == TEXT_TO_SPEECH){
customText = *(gPlayProperties.playlist);
} else {
customText = gPrefsSettings.getString("customText", "");
}
#if (LANGUAGE == DE)
speechOk = audio->connecttospeech(customText.c_str(), "de");
#else
speechOk = audio->connecttospeech(customText.c_str(), "en");
#endif
if (!speechOk) {
System_IndicateError();
}
}

// If speech is over, go back to predefined state
if (!gPlayProperties.currentSpeechActive && gPlayProperties.lastSpeechActive) {
gPlayProperties.lastSpeechActive = false;
if (gPlayProperties.playMode != NO_PLAYLIST) {
if (gPlayProperties.playMode == TEXT_TO_SPEECH) {
gPlayProperties.playMode = NO_PLAYLIST;
} else if (gPlayProperties.playMode != NO_PLAYLIST) {
xQueueSend(gRfidCardQueue, gPlayProperties.playRfidTag, 0); // Re-inject previous RFID-ID in order to continue playback
}
}
Expand Down Expand Up @@ -866,7 +897,11 @@ void AudioPlayer_TrackQueueDispatcher(const char *_itemToPlay, const uint32_t _l
gPlayProperties.currentTrackNumber = _trackLastPlayed;
char **musicFiles;

if (_playMode != WEBSTREAM) {
if (_playMode == WEBSTREAM) {
musicFiles = AudioPlayer_ReturnPlaylistFromWebstream(filename);
} else if (_playMode == TEXT_TO_SPEECH) {
musicFiles = AutioPlayer_ReturnPlaylistFromTextToSpeech(filename); // no modification needed
} else {
if (_playMode == RANDOM_SUBDIRECTORY_OF_DIRECTORY) {
filename = SdCard_pickRandomSubdirectory(filename); // *filename (input): target-directory // *filename (output): random subdirectory
if (filename == NULL) { // If error occured while extracting random subdirectory
Expand All @@ -877,8 +912,6 @@ void AudioPlayer_TrackQueueDispatcher(const char *_itemToPlay, const uint32_t _l
} else {
musicFiles = SdCard_ReturnPlaylist(filename, _playMode);
}
} else {
musicFiles = AudioPlayer_ReturnPlaylistFromWebstream(filename);
}

// Catch if error occured (e.g. file not found)
Expand All @@ -888,6 +921,7 @@ void AudioPlayer_TrackQueueDispatcher(const char *_itemToPlay, const uint32_t _l
if (gPlayProperties.playMode != NO_PLAYLIST) {
AudioPlayer_TrackControlToQueueSender(STOP);
}
free(filename);
return;
}

Expand Down Expand Up @@ -1009,6 +1043,18 @@ void AudioPlayer_TrackQueueDispatcher(const char *_itemToPlay, const uint32_t _l
break;
}

case TEXT_TO_SPEECH: { // This is also always just one "track"
Log_Println((char *) FPSTR(modeWebstream), LOGLEVEL_NOTICE);
if (Wlan_IsConnected()) {
xQueueSend(gTrackQueue, &(musicFiles), 0);
} else {
Log_Println((char *) FPSTR(webstreamNotAvailable), LOGLEVEL_ERROR);
System_IndicateError();
gPlayProperties.playMode = NO_PLAYLIST;
}
break;
}

case LOCAL_M3U: { // Can be one or multiple SD-files or webradio-stations; or a mix of both
Log_Println((char *) FPSTR(modeWebstreamM3u), LOGLEVEL_NOTICE);
xQueueSend(gTrackQueue, &(musicFiles), 0);
Expand Down Expand Up @@ -1084,6 +1130,18 @@ char **AudioPlayer_ReturnPlaylistFromWebstream(const char *_webUrl) {
return ++url;
}

// Adds Text To Speech to playlist; same like SdCard_ReturnPlaylist() but always only one entry
char **AutioPlayer_ReturnPlaylistFromTextToSpeech(const char *_textToInsert) {
char *textToInsert = x_strdup(_textToInsert);
static char **playlist;
playlist = (char **)x_malloc(sizeof(char *) * 2);
playlist[0] = x_strdup("1"); // Number of files is always 1 in url-mode
playlist[1] = x_strdup(textToInsert);

free(textToInsert);
return ++playlist;
}

// Adds new control-command to control-queue
void AudioPlayer_TrackControlToQueueSender(const uint8_t trackCommand) {
xQueueSend(gTrackControlQueue, &trackCommand, 0);
Expand Down
1 change: 1 addition & 0 deletions src/AudioPlayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ typedef struct { // Bit field
bool currentPlayMono: 1; // true if mono; false if stereo
bool isWebstream: 1; // Indicates if track currenty played is a webstream
bool tellIpAddress: 1; // If true current IP-address is spoken
bool tellCustomText: 1; // If true current IP-address is spoken
bool currentSpeechActive: 1; // If speech-play is active
bool lastSpeechActive: 1; // If speech-play was active
size_t coverFilePos; // current cover file position
Expand Down
16 changes: 16 additions & 0 deletions src/Cmd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,22 @@ void Cmd_Action(const uint16_t mod) {
break;
}

case CMD_TELL_CUSTOM_TEXT: {
if (Wlan_IsConnected()) {
if (!gPlayProperties.pausePlay) {
AudioPlayer_TrackControlToQueueSender(PAUSEPLAY);
}
gPlayProperties.tellCustomText = true;
gPlayProperties.currentSpeechActive = true;
gPlayProperties.lastSpeechActive = true;
System_IndicateOk();
} else {
Log_Println(unableToTellIpAddress, LOGLEVEL_ERROR);
System_IndicateError();
}
break;
}

case CMD_PLAYPAUSE: {
if (OPMODE_NORMAL == System_GetOperationMode()) {
AudioPlayer_TrackControlToQueueSender(PAUSEPLAY);
Expand Down
2 changes: 2 additions & 0 deletions src/Web.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,7 @@ bool processJsonRequest(char *_serialJson) {
float vIndLow = doc["general"]["vIndLow"].as<float>();
float vIndHi = doc["general"]["vIndHi"].as<float>();
uint8_t vInt = doc["general"]["vInt"].as<uint8_t>();
const char *_customText = object["general"]["vCustText"];

gPrefsSettings.putUInt("initVolume", iVol);
gPrefsSettings.putUInt("maxVolumeSp", mVolSpeaker);
Expand All @@ -509,6 +510,7 @@ bool processJsonRequest(char *_serialJson) {
gPrefsSettings.putFloat("vIndicatorLow", vIndLow);
gPrefsSettings.putFloat("vIndicatorHigh", vIndHi);
gPrefsSettings.putUInt("vCheckIntv", vInt);
gPrefsSettings.putString("customText", _customText);

// Check if settings were written successfully
if (gPrefsSettings.getUInt("initVolume", 0) != iVol ||
Expand Down
Loading