2020-11-11 23:48:14 +01:00
|
|
|
#include "wled.h"
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Handles playlists, timed sequences of presets
|
|
|
|
*/
|
|
|
|
|
|
|
|
typedef struct PlaylistEntry {
|
|
|
|
uint8_t preset;
|
|
|
|
uint16_t dur;
|
|
|
|
uint16_t tr;
|
|
|
|
} ple;
|
|
|
|
|
2021-06-07 14:16:29 +02:00
|
|
|
bool playlistEndless = false;
|
2021-02-05 17:36:53 +01:00
|
|
|
int8_t playlistRepeat = 1;
|
|
|
|
byte playlistEndPreset = 0;
|
|
|
|
byte *playlistEntries = nullptr;
|
|
|
|
byte playlistLen;
|
|
|
|
int8_t playlistIndex = -1;
|
|
|
|
uint16_t playlistEntryDur = 0;
|
2020-11-11 23:48:14 +01:00
|
|
|
|
|
|
|
|
2021-02-05 17:36:53 +01:00
|
|
|
void shufflePlaylist() {
|
2021-05-11 14:54:03 +02:00
|
|
|
int currentIndex = playlistLen;
|
2021-02-05 17:36:53 +01:00
|
|
|
|
|
|
|
PlaylistEntry temporaryValue, *entries = reinterpret_cast<PlaylistEntry*>(playlistEntries);
|
|
|
|
|
|
|
|
// While there remain elements to shuffle...
|
|
|
|
while (currentIndex--) {
|
|
|
|
// Pick a random element...
|
2021-05-11 14:54:03 +02:00
|
|
|
int randomIndex = random(0, currentIndex);
|
2021-02-05 17:36:53 +01:00
|
|
|
// And swap it with the current element.
|
|
|
|
temporaryValue = entries[currentIndex];
|
|
|
|
entries[currentIndex] = entries[randomIndex];
|
|
|
|
entries[randomIndex] = temporaryValue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-28 15:34:18 +01:00
|
|
|
void unloadPlaylist() {
|
|
|
|
if (playlistEntries != nullptr) {
|
|
|
|
delete[] playlistEntries;
|
|
|
|
playlistEntries = nullptr;
|
|
|
|
}
|
|
|
|
currentPlaylist = playlistIndex = -1;
|
|
|
|
playlistLen = playlistEntryDur = 0;
|
|
|
|
}
|
|
|
|
|
2020-11-11 23:48:14 +01:00
|
|
|
void loadPlaylist(JsonObject playlistObj) {
|
2021-02-28 15:34:18 +01:00
|
|
|
unloadPlaylist();
|
|
|
|
|
2020-11-11 23:48:14 +01:00
|
|
|
JsonArray presets = playlistObj["ps"];
|
|
|
|
playlistLen = presets.size();
|
|
|
|
if (playlistLen == 0) return;
|
|
|
|
if (playlistLen > 100) playlistLen = 100;
|
|
|
|
uint16_t dataSize = sizeof(ple) * playlistLen;
|
|
|
|
playlistEntries = new byte[dataSize];
|
|
|
|
PlaylistEntry* entries = reinterpret_cast<PlaylistEntry*>(playlistEntries);
|
|
|
|
|
|
|
|
byte it = 0;
|
|
|
|
for (int ps : presets) {
|
|
|
|
if (it >= playlistLen) break;
|
|
|
|
entries[it].preset = ps;
|
|
|
|
it++;
|
|
|
|
}
|
|
|
|
|
|
|
|
it = 0;
|
|
|
|
JsonArray durations = playlistObj["dur"];
|
|
|
|
if (durations.isNull()) {
|
|
|
|
entries[0].dur = playlistObj["dur"] | 100;
|
|
|
|
it = 1;
|
|
|
|
} else {
|
|
|
|
for (int dur : durations) {
|
|
|
|
if (it >= playlistLen) break;
|
|
|
|
entries[it].dur = dur;
|
|
|
|
it++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (int i = it; i < playlistLen; i++) entries[i].dur = entries[it -1].dur;
|
|
|
|
|
|
|
|
it = 0;
|
|
|
|
JsonArray tr = playlistObj["transition"];
|
|
|
|
if (tr.isNull()) {
|
|
|
|
entries[0].tr = playlistObj["transition"] | (transitionDelay / 100);
|
|
|
|
it = 1;
|
|
|
|
} else {
|
|
|
|
for (int transition : tr) {
|
|
|
|
if (it >= playlistLen) break;
|
|
|
|
entries[it].tr = transition;
|
|
|
|
it++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (int i = it; i < playlistLen; i++) entries[i].tr = entries[it -1].tr;
|
|
|
|
|
|
|
|
playlistRepeat = playlistObj[F("repeat")] | 0;
|
|
|
|
playlistEndPreset = playlistObj[F("end")] | 0;
|
|
|
|
|
2021-06-07 14:16:29 +02:00
|
|
|
playlistEndless = playlistRepeat < 1;
|
|
|
|
if (playlistEndless && playlistRepeat==0) playlistRepeat = 1; // it will never decrement
|
|
|
|
|
2020-11-11 23:48:14 +01:00
|
|
|
currentPlaylist = 0; //TODO here we need the preset ID where the playlist is saved
|
|
|
|
}
|
|
|
|
|
2021-02-05 17:36:53 +01:00
|
|
|
|
|
|
|
void handlePlaylist() {
|
2020-11-11 23:48:14 +01:00
|
|
|
if (currentPlaylist < 0 || playlistEntries == nullptr || presetCyclingEnabled) return;
|
|
|
|
|
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)
|
|
|
|
|
|
|
|
if (!playlistRepeat && !playlistIndex) { //stop if repeat == 0 and restart of playlist
|
2021-03-13 22:46:08 +01:00
|
|
|
unloadPlaylist();
|
2021-02-05 17:36:53 +01:00
|
|
|
if (playlistEndPreset) applyPreset(playlistEndPreset);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// playlist roll-over
|
|
|
|
if (!playlistIndex) {
|
2021-06-07 14:16:29 +02:00
|
|
|
if (!playlistEndless) playlistRepeat--; // decrease repeat count on each index reset if not an endless playlist
|
|
|
|
if (playlistRepeat < 0) {// playlistRepeat < 0 => endless loop with shuffling presets
|
2021-02-05 17:36:53 +01:00
|
|
|
shufflePlaylist(); // shuffle playlist and start over
|
2020-11-11 23:48:14 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
PlaylistEntry* entries = reinterpret_cast<PlaylistEntry*>(playlistEntries);
|
|
|
|
|
|
|
|
jsonTransitionOnce = true;
|
|
|
|
transitionDelayTemp = entries[playlistIndex].tr * 100;
|
|
|
|
|
|
|
|
applyPreset(entries[playlistIndex].preset);
|
|
|
|
playlistEntryDur = entries[playlistIndex].dur;
|
|
|
|
if (playlistEntryDur == 0) playlistEntryDur = 10;
|
|
|
|
}
|
2021-02-05 17:36:53 +01:00
|
|
|
}
|