#include #include "spi_master.h" #include "config.h" #include #include #include Playlist::Playlist(String path) { // Add files to _files SPIMaster::select_sd(); TRACE("Examining folder %s...\n", path.c_str()); if (!path.startsWith("/")) path = String("/") + path; if (!SD.exists(path)) { DEBUG("Could not open path '%s'.\n", path.c_str()); SPIMaster::select_sd(false); return; } File dir = SD.open(path); File entry; while (entry = dir.openNextFile()) { String filename = entry.name(); filename = filename.substring(path.length() + 1); String ext = filename.substring(filename.length() - 4); if (!entry.isDirectory() && !filename.startsWith(".") && ( ext.equals(".mp3") || ext.equals(".ogg") || ext.equals(".wma") || ext.equals(".mp4") || ext.equals(".mpa"))) { TRACE(" Adding entry %s\n", entry.name()); _files.push_back(entry.name()); bool non_ascii_chars = false; for(int i=0; i= 0x7F) { non_ascii_chars = true; break; } } if (non_ascii_chars) { ERROR("WARNING: File '%s' contains non-ascii chars!\n", filename.c_str()); } } else { TRACE(" Ignoring entry %s\n", filename.c_str()); } entry.close(); } dir.close(); SPIMaster::select_sd(false); std::sort(_files.begin(), _files.end()); } void Playlist::start() { _started = true; } bool Playlist::has_track_prev() { return _current_track > 0; } bool Playlist::has_track_next() { return _current_track < _files.size()-1; } bool Playlist::track_prev() { if (_current_track > 0) { _current_track--; _position = 0; return true; } return false; } bool Playlist::track_next() { if (_current_track < _files.size()-1) { _current_track++; _position = 0; return true; } return false; } bool Playlist::set_track(uint8_t track) { if (track < _files.size()) { _current_track = track; return true; } return false; } void Playlist::track_restart() { _position = 0; } void Playlist::shuffle(uint8_t random_offset) { DEBUG("Shuffling the playlist with an offset of %d...\n", random_offset); for (int i=random_offset; i<_files.size(); i++) { int j = random(random_offset, _files.size()-1); if (i!=j) { TRACE(" Swapping elements %d and %d.\n", i, j); String temp = _files[i]; _files[i] = _files[j]; _files[j] = temp; } } _shuffled = true; TRACE("Done.\n"); } void Playlist::advent_shuffle(uint8_t day) { if (day > 24) day = 24; if (day > _files.size()) return; _files.insert(_files.begin(), _files[day - 1]); _files.erase(_files.begin() + day - 1, _files.end()); } void Playlist::reset() { std::sort(_files.begin(), _files.end()); _current_track = 0; _position = 0; _shuffled = false; _started = false; } String Playlist::get_current_file() { return _files[_current_track]; } uint32_t Playlist::get_position() { return _position; } void Playlist::set_position(uint32_t p) { _position = p; } bool Playlist::is_fresh() { return !_shuffled && !_started && _position==0 && _current_track==0; } void Playlist::dump() { for (int i=0; i<_files.size(); i++) { DEBUG(" %02d %2s %s\n", i+1, (i==_current_track) ? "->" : "", _files[i].c_str()); } } void Playlist::json(JsonObject json) { json["_type"] = "playlist"; JsonArray files = json.createNestedArray("files"); for (String file: _files) { files.add(file); } json["current_track"] = _current_track; json["has_track_next"] = has_track_next(); json["has_track_prev"] = has_track_prev(); }