Skip to content

Commit 6fee1a6

Browse files
committed
feature tts as playmode and button-action
1 parent c669a67 commit 6fee1a6

File tree

7 files changed

+203
-6
lines changed

7 files changed

+203
-6
lines changed

html/management_DE.html

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,39 @@
228228
<legend>Aktueller Titel</legend>
229229
<div id="track"></div>
230230
</div>
231+
<div class="form-group col-md-12">
232+
<legend>Command Control</legend>
233+
<select class="form-control" id="commandId" name="commandId">
234+
<option class="placeholder" disabled selected value="">Modifikation auswählen</option>
235+
<option value="100">Tastensperre</option>
236+
<option value="179">Schlafe sofort</option>
237+
<option value="101">Schlafen nach 15 Minuten</option>
238+
<option value="102">Schlafen nach 30 Minuten</option>
239+
<option value="103">Schlafen nach 1 Stunde</option>
240+
<option value="104">Schlafen nach 2 Stunden</option>
241+
<option value="105">Schlafen nach Ende des Titels</option>
242+
<option value="106">Schlafen nach Ende der Playlist</option>
243+
<option value="107">Schlafen nach fünf Titeln</option>
244+
<option value="110">Wiederhole Playlist (endlos)</option>
245+
<option value="111">Wiederhole Titel (endlos)</option>
246+
<option value="120">Dimme LEDs (Nachtmodus)</option>
247+
<option value="130">Aktiviere/deaktive WLAN</option>
248+
<option value="140">Bluetooth Lautsprecher aktivieren/deaktivieren</option>
249+
<option value="141">Bluetooth Kopfhörer aktivieren/deaktivieren</option>
250+
<option value="150">Aktiviere FTP</option>
251+
<option value="152">Spreche Text</option>
252+
<option value="0">Lösche Zuordnung</option>
253+
<option value="170">Play/Pause</option>
254+
<option value="171">Vorheriger Titel</option>
255+
<option value="172">Nächster Titel</option>
256+
<option value="173">Erster Titel</option>
257+
<option value="174">Letzter Titel</option>
258+
<option value="180">Springe vorwärts (n Sekunden)</option>
259+
<option value="181">Springe rückwärts (n Sekunden)</option>
260+
</select>
261+
<button type="button" onclick="executeCommand()" class="btn btn-primary" >Ausführen</button>
262+
</div>
263+
231264
</div>
232265
</div>
233266
<div class="tab-pane fade show active" id="nav-rfid" role="tabpanel" aria-labelledby="nav-rfid-tab">
@@ -295,6 +328,7 @@
295328
<option class="option-folder" value="9">Alle Titel eines Verzeichnis (zufällig, Endlosschleife)</option>
296329
<option class="option-folder" value="13">Alle Titel aus einem zufälligen Unterverzeichnis (sortiert)</option>
297330
<option class="option-stream" value="8">Webradio</option>
331+
<option class="option-stream" value="14">Text To Speech</option>
298332
<option class="option-stream" value="11">Liste (Dateien von SD und/oder Webstreams) aus lokaler .m3u-Datei</option>
299333
</select>
300334
</div>
@@ -318,6 +352,7 @@
318352
<option value="140">Bluetooth Lautsprecher aktivieren/deaktivieren</option>
319353
<option value="141">Bluetooth Kopfhörer aktivieren/deaktivieren</option>
320354
<option value="150">Aktiviere FTP</option>
355+
<option value="152">Spreche Text</option>
321356
<option value="0">Lösche Zuordnung</option>
322357
<option value="170">Play/Pause</option>
323358
<option value="171">Vorheriger Titel</option>
@@ -464,6 +499,18 @@
464499
</fieldset>
465500
</div>
466501
<br>
502+
<div class="form-group col-md-12">
503+
<fieldset>
504+
<legend>Custom Text</legend>
505+
506+
<label for="customText">Custom Text:</label>
507+
<input type="text" class="form-control" id="customText" placeholder="CUSTOM TEXT" name="customText" required>
508+
<div class="invalid-feedback">
509+
Bitte Custom-Text eintragen.
510+
</div>
511+
</fieldset>
512+
</div>
513+
<br>
467514

468515
<div class="form-group col-md-12">
469516
<fieldset>
@@ -1209,7 +1256,8 @@
12091256
vWarning: document.getElementById('warningLowVoltage').value,
12101257
vIndLow: document.getElementById('voltageIndicatorLow').value,
12111258
vIndHi: document.getElementById('voltageIndicatorHigh').value,
1212-
vInt: document.getElementById('voltageCheckInterval').value
1259+
vInt: document.getElementById('voltageCheckInterval').value,
1260+
vCustText: document.getElementById('customText').value
12131261
}
12141262
};
12151263
var myJSON = JSON.stringify(myObj);
@@ -1310,6 +1358,17 @@
13101358
var myJSON = JSON.stringify(myObj);
13111359
socket.send(myJSON);
13121360
}
1361+
1362+
function executeCommand() {
1363+
var myObj = {
1364+
"controls": {
1365+
action: document.getElementById('commandId').value
1366+
}
1367+
};
1368+
var myJSON = JSON.stringify(myObj);
1369+
socket.send(myJSON);
1370+
}
1371+
13131372
function sendVolume(vol) {
13141373
var myObj = {
13151374
"controls": {

html/management_EN.html

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,39 @@
228228
<legend>Current track</legend>
229229
<div id="track"></div>
230230
</div>
231+
<div class="form-group col-md-12">
232+
<legend>Command Control</legend>
233+
<select class="form-control" id="commandId" name="commandId">
234+
<option class="placeholder" disabled selected value="">Modifikation auswählen</option>
235+
<option value="100">Tastensperre</option>
236+
<option value="179">Schlafe sofort</option>
237+
<option value="101">Schlafen nach 15 Minuten</option>
238+
<option value="102">Schlafen nach 30 Minuten</option>
239+
<option value="103">Schlafen nach 1 Stunde</option>
240+
<option value="104">Schlafen nach 2 Stunden</option>
241+
<option value="105">Schlafen nach Ende des Titels</option>
242+
<option value="106">Schlafen nach Ende der Playlist</option>
243+
<option value="107">Schlafen nach fünf Titeln</option>
244+
<option value="110">Wiederhole Playlist (endlos)</option>
245+
<option value="111">Wiederhole Titel (endlos)</option>
246+
<option value="120">Dimme LEDs (Nachtmodus)</option>
247+
<option value="130">Aktiviere/deaktive WLAN</option>
248+
<option value="140">Bluetooth Lautsprecher aktivieren/deaktivieren</option>
249+
<option value="141">Bluetooth Kopfhörer aktivieren/deaktivieren</option>
250+
<option value="150">Aktiviere FTP</option>
251+
<option value="152">Spreche Text</option>
252+
<option value="0">Lösche Zuordnung</option>
253+
<option value="170">Play/Pause</option>
254+
<option value="171">Vorheriger Titel</option>
255+
<option value="172">Nächster Titel</option>
256+
<option value="173">Erster Titel</option>
257+
<option value="174">Letzter Titel</option>
258+
<option value="180">Springe vorwärts (n Sekunden)</option>
259+
<option value="181">Springe rückwärts (n Sekunden)</option>
260+
</select>
261+
<button type="button" onclick="executeCommand()" class="btn btn-primary" >Ausführen</button>
262+
</div>
263+
231264
</div>
232265
</div>
233266
<div class="tab-pane fade show active" id="nav-rfid" role="tabpanel" aria-labelledby="nav-rfid-tab">
@@ -295,6 +328,7 @@
295328
<option class="option-folder" value="9">All tracks of a directory (random, loop)</option>
296329
<option class="option-folder" value="13">All tracks of a random subdirectory (sorted alph.)</option>
297330
<option class="option-stream" value="8">Webradio</option>
331+
<option class="option-stream" value="14">Text To Speech</option>
298332
<option class="option-stream" value="11">List (files from SD and/or webstreams) from local .m3u-File</option>
299333
</select>
300334
</div>
@@ -317,6 +351,7 @@
317351
<option value="130">Toggle WiFi</option>
318352
<option value="140">Toggle Bluetooth</option>
319353
<option value="150">Enable FTP</option>
354+
<option value="152">Speek Text</option>
320355
<option value="0">Remove assignment</option>
321356
<option value="170">Toggle Play/Pause</option>
322357
<option value="171">Previous track</option>
@@ -463,6 +498,18 @@
463498
</fieldset>
464499
</div>
465500
<br>
501+
<div class="form-group col-md-12">
502+
<fieldset>
503+
<legend>Custom Text</legend>
504+
505+
<label for="customText">Custom Text:</label>
506+
<input type="text" class="form-control" id="customText" placeholder="CUSTOM TEXT" name="customText" required>
507+
<div class="invalid-feedback">
508+
Please enter custom-text.
509+
</div>
510+
</fieldset>
511+
</div>
512+
<br>
466513

467514
<div class="form-group col-md-12">
468515
<fieldset>
@@ -1208,7 +1255,8 @@
12081255
vWarning: document.getElementById('warningLowVoltage').value,
12091256
vIndLow: document.getElementById('voltageIndicatorLow').value,
12101257
vIndHi: document.getElementById('voltageIndicatorHigh').value,
1211-
vInt: document.getElementById('voltageCheckInterval').value
1258+
vInt: document.getElementById('voltageCheckInterval').value,
1259+
vCustText: document.getElementById('customText').value
12121260
}
12131261
};
12141262
var myJSON = JSON.stringify(myObj);
@@ -1309,6 +1357,17 @@
13091357
var myJSON = JSON.stringify(myObj);
13101358
socket.send(myJSON);
13111359
}
1360+
1361+
function executeCommand() {
1362+
var myObj = {
1363+
"controls": {
1364+
action: document.getElementById('commandId').value
1365+
}
1366+
};
1367+
var myJSON = JSON.stringify(myObj);
1368+
socket.send(myJSON);
1369+
}
1370+
13121371
function sendVolume(vol) {
13131372
var myObj = {
13141373
"controls": {

src/AudioPlayer.cpp

Lines changed: 62 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ static uint8_t AudioPlayer_InitVolume = AUDIOPLAYER_VOLUME_INIT;
4343
static void AudioPlayer_Task(void *parameter);
4444
static void AudioPlayer_HeadphoneVolumeManager(void);
4545
static char **AudioPlayer_ReturnPlaylistFromWebstream(const char *_webUrl);
46+
static char **AutioPlayer_ReturnPlaylistFromTextToSpeech(const char *_textToInsert);
4647
static int AudioPlayer_ArrSortHelper(const void *a, const void *b);
4748
static void AudioPlayer_SortPlaylist(const char **arr, int n);
4849
static void AudioPlayer_SortPlaylist(char *str[], const uint32_t count);
@@ -624,6 +625,12 @@ void AudioPlayer_Task(void *parameter) {
624625
if (gPlayProperties.playMode == WEBSTREAM || (gPlayProperties.playMode == LOCAL_M3U && gPlayProperties.isWebstream)) { // Webstream
625626
audioReturnCode = audio->connecttohost(*(gPlayProperties.playlist + gPlayProperties.currentTrackNumber));
626627
gPlayProperties.playlistFinished = false;
628+
} else if (gPlayProperties.playMode == TEXT_TO_SPEECH) {
629+
audioReturnCode = true; // is handled later
630+
gPlayProperties.tellCustomText = true;
631+
gPlayProperties.currentSpeechActive = true;
632+
gPlayProperties.lastSpeechActive = true;
633+
gPlayProperties.playlistFinished = false;
627634
} else if (gPlayProperties.playMode != WEBSTREAM && !gPlayProperties.isWebstream) {
628635
// Files from SD
629636
if (!gFSystem.exists(*(gPlayProperties.playlist + gPlayProperties.currentTrackNumber))) { // Check first if file/folder exists
@@ -657,6 +664,8 @@ void AudioPlayer_Task(void *parameter) {
657664
} else {
658665
Audio_setTitle("Webradio");
659666
}
667+
} else if (gPlayProperties.tellCustomText) {
668+
Audio_setTitle("Text To Speech");
660669
} else {
661670
if (gPlayProperties.numberOfTracks > 1) {
662671
Audio_setTitle("(%u/%u): %s", gPlayProperties.currentTrackNumber+1, gPlayProperties.numberOfTracks, *(gPlayProperties.playlist + gPlayProperties.currentTrackNumber));
@@ -719,10 +728,32 @@ void AudioPlayer_Task(void *parameter) {
719728
}
720729
}
721730

731+
// Handle custom text
732+
if (gPlayProperties.tellCustomText) {
733+
gPlayProperties.tellCustomText = false;
734+
bool speechOk;
735+
String customText = "";
736+
if (gPlayProperties.playMode == TEXT_TO_SPEECH){
737+
customText = *(gPlayProperties.playlist);
738+
} else {
739+
customText = gPrefsSettings.getString("customText", "");
740+
}
741+
#if (LANGUAGE == DE)
742+
speechOk = audio->connecttospeech(customText.c_str(), "de");
743+
#else
744+
speechOk = audio->connecttospeech(customText.c_str(), "en");
745+
#endif
746+
if (!speechOk) {
747+
System_IndicateError();
748+
}
749+
}
750+
722751
// If speech is over, go back to predefined state
723752
if (!gPlayProperties.currentSpeechActive && gPlayProperties.lastSpeechActive) {
724753
gPlayProperties.lastSpeechActive = false;
725-
if (gPlayProperties.playMode != NO_PLAYLIST) {
754+
if (gPlayProperties.playMode == TEXT_TO_SPEECH) {
755+
gPlayProperties.playMode = NO_PLAYLIST;
756+
} else if (gPlayProperties.playMode != NO_PLAYLIST) {
726757
xQueueSend(gRfidCardQueue, gPlayProperties.playRfidTag, 0); // Re-inject previous RFID-ID in order to continue playback
727758
}
728759
}
@@ -835,7 +866,11 @@ void AudioPlayer_TrackQueueDispatcher(const char *_itemToPlay, const uint32_t _l
835866
gPlayProperties.currentTrackNumber = _trackLastPlayed;
836867
char **musicFiles;
837868

838-
if (_playMode != WEBSTREAM) {
869+
if (_playMode == WEBSTREAM) {
870+
musicFiles = AudioPlayer_ReturnPlaylistFromWebstream(filename);
871+
} else if (_playMode == TEXT_TO_SPEECH) {
872+
musicFiles = AutioPlayer_ReturnPlaylistFromTextToSpeech(filename); // no modification needed
873+
} else {
839874
if (_playMode == RANDOM_SUBDIRECTORY_OF_DIRECTORY) {
840875
filename = SdCard_pickRandomSubdirectory(filename); // *filename (input): target-directory // *filename (output): random subdirectory
841876
if (filename == NULL) { // If error occured while extracting random subdirectory
@@ -846,8 +881,6 @@ void AudioPlayer_TrackQueueDispatcher(const char *_itemToPlay, const uint32_t _l
846881
} else {
847882
musicFiles = SdCard_ReturnPlaylist(filename, _playMode);
848883
}
849-
} else {
850-
musicFiles = AudioPlayer_ReturnPlaylistFromWebstream(filename);
851884
}
852885

853886
// Catch if error occured (e.g. file not found)
@@ -857,6 +890,7 @@ void AudioPlayer_TrackQueueDispatcher(const char *_itemToPlay, const uint32_t _l
857890
if (gPlayProperties.playMode != NO_PLAYLIST) {
858891
AudioPlayer_TrackControlToQueueSender(STOP);
859892
}
893+
free(filename);
860894
return;
861895
}
862896

@@ -978,6 +1012,18 @@ void AudioPlayer_TrackQueueDispatcher(const char *_itemToPlay, const uint32_t _l
9781012
break;
9791013
}
9801014

1015+
case TEXT_TO_SPEECH: { // This is also always just one "track"
1016+
Log_Println((char *) FPSTR(modeWebstream), LOGLEVEL_NOTICE);
1017+
if (Wlan_IsConnected()) {
1018+
xQueueSend(gTrackQueue, &(musicFiles), 0);
1019+
} else {
1020+
Log_Println((char *) FPSTR(webstreamNotAvailable), LOGLEVEL_ERROR);
1021+
System_IndicateError();
1022+
gPlayProperties.playMode = NO_PLAYLIST;
1023+
}
1024+
break;
1025+
}
1026+
9811027
case LOCAL_M3U: { // Can be one or multiple SD-files or webradio-stations; or a mix of both
9821028
Log_Println((char *) FPSTR(modeWebstreamM3u), LOGLEVEL_NOTICE);
9831029
xQueueSend(gTrackQueue, &(musicFiles), 0);
@@ -1053,6 +1099,18 @@ char **AudioPlayer_ReturnPlaylistFromWebstream(const char *_webUrl) {
10531099
return ++url;
10541100
}
10551101

1102+
// Adds Text To Speech to playlist; same like SdCard_ReturnPlaylist() but always only one entry
1103+
char **AutioPlayer_ReturnPlaylistFromTextToSpeech(const char *_textToInsert) {
1104+
char *textToInsert = x_strdup(_textToInsert);
1105+
static char **playlist;
1106+
playlist = (char **)x_malloc(sizeof(char *) * 2);
1107+
playlist[0] = x_strdup("1"); // Number of files is always 1 in url-mode
1108+
playlist[1] = x_strdup(textToInsert);
1109+
1110+
free(textToInsert);
1111+
return ++playlist;
1112+
}
1113+
10561114
// Adds new control-command to control-queue
10571115
void AudioPlayer_TrackControlToQueueSender(const uint8_t trackCommand) {
10581116
xQueueSend(gTrackControlQueue, &trackCommand, 0);

src/AudioPlayer.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ typedef struct { // Bit field
2424
bool currentPlayMono: 1; // true if mono; false if stereo
2525
bool isWebstream: 1; // Indicates if track currenty played is a webstream
2626
bool tellIpAddress: 1; // If true current IP-address is spoken
27+
bool tellCustomText: 1; // If true current IP-address is spoken
2728
bool currentSpeechActive: 1; // If speech-play is active
2829
bool lastSpeechActive: 1; // If speech-play was active
2930
size_t coverFilePos; // current cover file position

src/Cmd.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,22 @@ void Cmd_Action(const uint16_t mod) {
288288
break;
289289
}
290290

291+
case CMD_TELL_CUSTOM_TEXT: {
292+
if (Wlan_IsConnected()) {
293+
if (!gPlayProperties.pausePlay) {
294+
AudioPlayer_TrackControlToQueueSender(PAUSEPLAY);
295+
}
296+
gPlayProperties.tellCustomText = true;
297+
gPlayProperties.currentSpeechActive = true;
298+
gPlayProperties.lastSpeechActive = true;
299+
System_IndicateOk();
300+
} else {
301+
Log_Println(unableToTellIpAddress, LOGLEVEL_ERROR);
302+
System_IndicateError();
303+
}
304+
break;
305+
}
306+
291307
case CMD_PLAYPAUSE: {
292308
if (OPMODE_NORMAL == System_GetOperationMode()) {
293309
AudioPlayer_TrackControlToQueueSender(PAUSEPLAY);

src/Web.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,7 @@ bool processJsonRequest(char *_serialJson) {
448448
float vIndLow = doc["general"]["vIndLow"].as<float>();
449449
float vIndHi = doc["general"]["vIndHi"].as<float>();
450450
uint8_t vInt = doc["general"]["vInt"].as<uint8_t>();
451+
const char *_customText = object["general"]["vCustText"];
451452

452453
gPrefsSettings.putUInt("initVolume", iVol);
453454
gPrefsSettings.putUInt("maxVolumeSp", mVolSpeaker);
@@ -459,6 +460,7 @@ bool processJsonRequest(char *_serialJson) {
459460
gPrefsSettings.putFloat("vIndicatorLow", vIndLow);
460461
gPrefsSettings.putFloat("vIndicatorHigh", vIndHi);
461462
gPrefsSettings.putUInt("vCheckIntv", vInt);
463+
gPrefsSettings.putString("customText", _customText);
462464

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

0 commit comments

Comments
 (0)