WLED/wled00/playlist.cpp

168 lines
5.6 KiB
C++
Raw Normal View History

2020-11-11 23:48:14 +01:00
#include "wled.h"
/*
* Handles playlists, timed sequences of presets
*/
typedef struct PlaylistEntry {
2021-06-10 02:52:20 +02:00
uint8_t preset; //ID of the preset to apply
uint16_t dur; //Duration of the entry (in tenths of seconds)
uint16_t tr; //Duration of the transition TO this entry (in tenths of seconds)
2020-11-11 23:48:14 +01:00
} ple;
2021-06-10 02:52:20 +02:00
byte playlistRepeat = 1; //how many times to repeat the playlist (0 = infinitely)
byte playlistEndPreset = 0; //what preset to apply after playlist end (0 = stay on last preset)
byte playlistOptions = 0; //bit 0: shuffle playlist after each iteration. bits 1-7 TBD
2021-06-07 21:05:31 +02:00
PlaylistEntry *playlistEntries = nullptr;
2021-06-10 02:52:20 +02:00
byte playlistLen; //number of playlist entries
2021-06-07 21:05:31 +02:00
int8_t playlistIndex = -1;
2021-06-10 02:52:20 +02:00
uint16_t playlistEntryDur = 0; //duration of the current entry in tenths of seconds
//values we need to keep about the parent playlist while inside sub-playlist
//int8_t parentPlaylistIndex = -1;
//byte parentPlaylistRepeat = 0;
//byte parentPlaylistPresetId = 0; //for re-loading
2020-11-11 23:48:14 +01:00
2021-02-05 17:36:53 +01:00
void shufflePlaylist() {
int currentIndex = playlistLen;
2021-06-07 21:05:31 +02:00
PlaylistEntry temporaryValue;
2021-02-05 17:36:53 +01:00
// While there remain elements to shuffle...
while (currentIndex--) {
// Pick a random element...
int randomIndex = random(0, currentIndex);
2021-02-05 17:36:53 +01:00
// And swap it with the current element.
2021-06-07 21:05:31 +02:00
temporaryValue = playlistEntries[currentIndex];
playlistEntries[currentIndex] = playlistEntries[randomIndex];
playlistEntries[randomIndex] = temporaryValue;
2021-02-05 17:36:53 +01:00
}
2021-06-07 21:05:31 +02:00
DEBUG_PRINTLN(F("Playlist shuffle."));
2021-02-05 17:36:53 +01:00
}
2021-06-07 21:05:31 +02:00
2021-02-28 15:34:18 +01:00
void unloadPlaylist() {
if (playlistEntries != nullptr) {
delete[] playlistEntries;
playlistEntries = nullptr;
}
currentPlaylist = playlistIndex = -1;
2021-06-10 02:52:20 +02:00
playlistLen = playlistEntryDur = playlistOptions = 0;
2021-06-07 21:05:31 +02:00
DEBUG_PRINTLN(F("Playlist unloaded."));
2021-02-28 15:34:18 +01:00
}
2021-06-07 21:05:31 +02:00
int16_t loadPlaylist(JsonObject playlistObj, byte presetId) {
2021-02-28 15:34:18 +01:00
unloadPlaylist();
2023-01-06 09:24:29 +01:00
2020-11-11 23:48:14 +01:00
JsonArray presets = playlistObj["ps"];
playlistLen = presets.size();
if (playlistLen == 0) return -1;
2020-11-11 23:48:14 +01:00
if (playlistLen > 100) playlistLen = 100;
2021-06-07 21:05:31 +02:00
playlistEntries = new PlaylistEntry[playlistLen];
if (playlistEntries == nullptr) return -1;
2020-11-11 23:48:14 +01:00
byte it = 0;
for (int ps : presets) {
if (it >= playlistLen) break;
2021-06-07 21:05:31 +02:00
playlistEntries[it].preset = ps;
2020-11-11 23:48:14 +01:00
it++;
}
it = 0;
JsonArray durations = playlistObj["dur"];
if (durations.isNull()) {
2021-06-10 02:52:20 +02:00
playlistEntries[0].dur = playlistObj["dur"] | 100; //10 seconds as fallback
2020-11-11 23:48:14 +01:00
it = 1;
} else {
for (int dur : durations) {
if (it >= playlistLen) break;
2021-06-10 02:52:20 +02:00
playlistEntries[it].dur = (dur > 1) ? dur : 100;
2020-11-11 23:48:14 +01:00
it++;
}
}
2021-06-07 21:05:31 +02:00
for (int i = it; i < playlistLen; i++) playlistEntries[i].dur = playlistEntries[it -1].dur;
2020-11-11 23:48:14 +01:00
it = 0;
2021-06-07 21:05:31 +02:00
JsonArray tr = playlistObj[F("transition")];
2020-11-11 23:48:14 +01:00
if (tr.isNull()) {
2021-06-07 21:05:31 +02:00
playlistEntries[0].tr = playlistObj[F("transition")] | (transitionDelay / 100);
2020-11-11 23:48:14 +01:00
it = 1;
} else {
for (int transition : tr) {
if (it >= playlistLen) break;
2021-06-07 21:05:31 +02:00
playlistEntries[it].tr = transition;
2020-11-11 23:48:14 +01:00
it++;
}
}
2021-06-07 21:05:31 +02:00
for (int i = it; i < playlistLen; i++) playlistEntries[i].tr = playlistEntries[it -1].tr;
2020-11-11 23:48:14 +01:00
2021-06-10 02:52:20 +02:00
int rep = playlistObj[F("repeat")];
bool shuffle = false;
if (rep < 0) { //support negative values as infinite + shuffle
rep = 0; shuffle = true;
}
2020-11-11 23:48:14 +01:00
2021-06-10 02:52:20 +02:00
playlistRepeat = rep;
if (playlistRepeat > 0) playlistRepeat++; //add one extra repetition immediately since it will be deducted on first start
playlistEndPreset = playlistObj["end"] | 0;
// if end preset is 255 restore original preset (if any running) upon playlist end
if (playlistEndPreset == 255 && currentPreset > 0) playlistEndPreset = currentPreset;
if (playlistEndPreset > 250) playlistEndPreset = 0;
2021-06-10 02:52:20 +02:00
shuffle = shuffle || playlistObj["r"];
if (shuffle) playlistOptions += PL_OPTION_SHUFFLE;
2021-06-07 14:16:29 +02:00
2021-06-10 02:52:20 +02:00
currentPlaylist = presetId;
2021-06-07 21:05:31 +02:00
DEBUG_PRINTLN(F("Playlist loaded."));
return currentPlaylist;
2020-11-11 23:48:14 +01:00
}
2021-02-05 17:36:53 +01:00
void handlePlaylist() {
static unsigned long presetCycledTime = 0;
// if fileDoc is not null JSON buffer is in use so just quit
if (currentPlaylist < 0 || playlistEntries == nullptr || fileDoc != nullptr) return;
2021-06-07 21:05:31 +02:00
2021-02-05 17:36:53 +01:00
if (millis() - presetCycledTime > (100*playlistEntryDur)) {
2020-11-11 23:48:14 +01:00
presetCycledTime = millis();
if (bri == 0 || nightlightActive) return;
2021-02-05 17:36:53 +01:00
++playlistIndex %= playlistLen; // -1 at 1st run (limit to playlistLen)
// playlist roll-over
if (!playlistIndex) {
2021-06-10 02:52:20 +02:00
if (playlistRepeat == 1) { //stop if all repetitions are done
unloadPlaylist();
if (playlistEndPreset) applyPreset(playlistEndPreset);
return;
}
if (playlistRepeat > 1) playlistRepeat--; // decrease repeat count on each index reset if not an endless playlist
// playlistRepeat == 0: endless loop
if (playlistOptions & PL_OPTION_SHUFFLE) shufflePlaylist(); // shuffle playlist and start over
2020-11-11 23:48:14 +01:00
}
jsonTransitionOnce = true;
2021-06-07 21:05:31 +02:00
transitionDelayTemp = playlistEntries[playlistIndex].tr * 100;
playlistEntryDur = playlistEntries[playlistIndex].dur;
applyPreset(playlistEntries[playlistIndex].preset);
2020-11-11 23:48:14 +01:00
}
2021-02-05 17:36:53 +01:00
}
2022-10-08 18:25:51 +02:00
void serializePlaylist(JsonObject sObj) {
2022-10-09 13:39:17 +02:00
JsonObject playlist = sObj.createNestedObject(F("playlist"));
2022-10-08 18:25:51 +02:00
JsonArray ps = playlist.createNestedArray("ps");
JsonArray dur = playlist.createNestedArray("dur");
JsonArray transition = playlist.createNestedArray(F("transition"));
playlist[F("repeat")] = (playlistRepeat > 0) ? playlistRepeat - 1 : 0; // remove added repetition count
2022-10-08 18:25:51 +02:00
playlist["end"] = playlistEndPreset;
playlist["r"] = playlistOptions & PL_OPTION_SHUFFLE;
for (int i=0; i<playlistLen; i++) {
ps.add(playlistEntries[i].preset);
dur.add(playlistEntries[i].dur);
transition.add(playlistEntries[i].tr);
}
}