Files
project-vesper/vesper/classes.hpp

134 lines
4.0 KiB
C++

#pragma once
extern std::vector<uint16_t> melody_steps;
void PublishMqtt(const char * data);
class Player {
public:
uint16_t id; // The (internal) ID of the selected melody. Not specificly used anywhere atm. Might be used later.
std::string name = "melody1"; // Name of the Melody saved. Will be used to read the file: /name.bin
uint16_t speed = 500; // Time to wait per beat. (In Miliseconds)
uint32_t duration = 15000; // Total Duration that program will run (In Miliseconds)
uint32_t loop_duration = 0; // Duration of the playback per segment
uint32_t interval = 0; // Indicates the Duration of the Interval between finished segments, IF "inf" is true
bool infinite_play = false; // Infinite Loop Indicator (If True the melody will loop forever or until stoped, with pauses of "interval" in between loops)
bool isPlaying = false; // Indicates if the Melody is actually Playing right now.
bool isPaused = false; // If playing, indicates if the Melody is Paused
uint64_t startTime = 0; // The time-point the Melody started Playing
uint64_t loopStartTime = 0; // The time-point the current segment started Playing
bool hardStop = false; // Flags a hardstop, immediately.
uint64_t pauseTime = 0; // The time-point the melody paused
void play() {
isPlaying = true;
hardStop = false;
startTime = loopStartTime = millis();
LOG_DEBUG("Plbck: PLAY");
}
void forceStop() {
hardStop = true;
isPlaying = false;
LOG_DEBUG("Plbck: FORCE STOP");
}
void stop() {
hardStop = false;
isPlaying = false;
LOG_DEBUG("Plbck: STOP");
}
void pause() {
isPaused = true;
LOG_DEBUG("Plbck: PAUSE");
}
void unpause() {
isPaused = false;
loopStartTime = millis();
LOG_DEBUG("Plbck: RESUME");
}
// Handles Incoming Commands to PLAY or STOP
void command(JsonVariant content){
String action = content["action"];
LOG_DEBUG("Incoming Command: %s", action);
if (action == "play") {
play();
PublishMqtt("OK - PLAY");
} else if (action == "stop") {
forceStop();
PublishMqtt("OK - STOP");
}
}
// Sets incoming Attributes for the Melody, into the class' variables.
void setMelodyAttributes(JsonVariant doc){
if (doc.containsKey("name")) {
name = doc["name"].as<const char*>();
}
if (doc.containsKey("id")) {
id = doc["id"].as<uint16_t>();
}
if (doc.containsKey("duration")) {
duration = doc["duration"].as<uint32_t>();
}
if (doc.containsKey("infinite")) {
infinite_play = doc["infinite"].as<bool>();
}
if (doc.containsKey("interval")) {
interval = doc["interval"].as<uint32_t>();
}
if (doc.containsKey("speed")) {
speed = doc["speed"].as<uint16_t>();
}
if (doc.containsKey("loop_dur")) {
loop_duration = doc["loop_dur"].as<uint32_t>();
}
// Print Just for Debugging Purposes
LOG_DEBUG("Name: %s, ID: %d, Total Duration: %lu, Loop Duration: %lu, Interval: %d, Speed: %d, Inf: %s\n",
name.c_str(),
id,
duration,
loop_duration,
interval,
speed,
infinite_play ? "true" : "false"
);
}
// Loads the Selected melody from a .bin file on SD into RAM
void loadMelodyInRAM(std::vector<uint16_t> &melody_steps) {
String filePath = "/melodies/" + String(name.c_str()) + ".bin";
File bin_file = SD.open(filePath.c_str(), FILE_READ);
if (!bin_file) {
LOG_ERROR("Failed to open file: %s", filePath.c_str());
return;
}
size_t fileSize = bin_file.size();
if (fileSize % 2 != 0) {
LOG_ERROR("Invalid file size: %u (not a multiple of 2)", fileSize);
bin_file.close();
return;
}
melody_steps.resize(fileSize / 2);
for (size_t i = 0; i < melody_steps.size(); i++) {
uint8_t high = bin_file.read();
uint8_t low = bin_file.read();
melody_steps[i] = (high << 8) | low;
}
LOG_INFO("Melody Load Successful");
bin_file.close();
}
};