Changed the playing code to use Playlists managed by a PlaylistManager. This allows you to have randomized playlists and stuff. Also, you can now access special functions via the contents of RFID tags. See the README for a list of available modes.
This commit is contained in:
267
src/player.cpp
267
src/player.cpp
@@ -15,8 +15,6 @@ Player::Player(SPIMaster* s) {
|
||||
_spi->disable();
|
||||
PIN_VS1053_DREQ_SETUP();
|
||||
|
||||
_fill_id_to_folder_map();
|
||||
|
||||
_init();
|
||||
}
|
||||
|
||||
@@ -70,14 +68,6 @@ void Player::_init() {
|
||||
|
||||
INFO("VS1053 initialization completed.\n");
|
||||
|
||||
INFO("Checking system sounds...\n");
|
||||
_spi->select_sd();
|
||||
_check_system_sound("no_prev_song.mp3");
|
||||
_check_system_sound("no_next_song.mp3");
|
||||
_check_system_sound("volume_max.mp3");
|
||||
_check_system_sound("volume_min.mp3");
|
||||
_spi->select_sd(false);
|
||||
|
||||
_state = idle;
|
||||
}
|
||||
|
||||
@@ -149,15 +139,6 @@ void Player::_record() {
|
||||
_state = recording;
|
||||
}
|
||||
|
||||
void Player::_check_system_sound(String filename) {
|
||||
String path = String("/system/") + filename;
|
||||
if (!SD.exists(path)) {
|
||||
ERROR("System sound %s is missing on the sd card!\n", path.c_str());
|
||||
} else {
|
||||
DEBUG("%s found.\n", path.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
inline void Player::_wait() {
|
||||
while(!PIN_VS1053_DREQ());
|
||||
}
|
||||
@@ -476,15 +457,15 @@ void Player::set_volume(uint8_t vol, bool save) {
|
||||
}
|
||||
|
||||
void Player::vol_up() {
|
||||
if (_volume == VOLUME_MAX) play_system_sound("volume_max.mp3");
|
||||
else if (_volume + VOLUME_STEP > VOLUME_MAX) set_volume(VOLUME_MAX);
|
||||
else set_volume(_volume + VOLUME_STEP);
|
||||
uint8_t vol = _volume + VOLUME_STEP;
|
||||
if (vol > VOLUME_MAX) vol=VOLUME_MAX;
|
||||
set_volume(vol);
|
||||
}
|
||||
|
||||
void Player::vol_down() {
|
||||
if (_volume >= VOLUME_MIN + VOLUME_STEP) set_volume(_volume - VOLUME_STEP);
|
||||
else if (_volume == VOLUME_MIN) play_system_sound("volume_min.mp3");
|
||||
else set_volume(VOLUME_MIN);
|
||||
uint8_t vol = _volume - VOLUME_STEP;
|
||||
if (vol < VOLUME_MIN) vol=VOLUME_MIN;
|
||||
set_volume(vol);
|
||||
}
|
||||
|
||||
void Player::_mute() {
|
||||
@@ -501,26 +482,27 @@ void Player::_unmute() {
|
||||
|
||||
void Player::track_next() {
|
||||
if (_state != playing) return;
|
||||
if (_playing_index + 1 >= _playing_album_songs) {
|
||||
play_system_sound("no_next_song.mp3");
|
||||
if (!_current_playlist->has_track_next()) {
|
||||
return;
|
||||
}
|
||||
stop();
|
||||
play_song(_playing_album, _playing_index + 1);
|
||||
_current_playlist->track_next();
|
||||
play();
|
||||
}
|
||||
|
||||
void Player::track_prev() {
|
||||
if (_state != playing) return;
|
||||
if (_current_play_position > 100000) {
|
||||
stop();
|
||||
play_song(_playing_album, _playing_index);
|
||||
_current_playlist->track_restart();
|
||||
play();
|
||||
} else {
|
||||
if (_playing_index == 0) {
|
||||
play_system_sound("no_prev_song.mp3");
|
||||
if (!_current_playlist->has_track_prev()) {
|
||||
return;
|
||||
}
|
||||
stop();
|
||||
play_song(_playing_album, _playing_index - 1);
|
||||
_current_playlist->track_prev();
|
||||
play();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -528,195 +510,21 @@ bool Player::is_playing() {
|
||||
return _state == playing;
|
||||
}
|
||||
|
||||
std::list<String> Player::ls(String path, bool withFiles, bool withDirs, bool withHidden) {
|
||||
_spi->select_sd();
|
||||
std::list<String> result;
|
||||
if (!SD.exists(path)) return result;
|
||||
File dir = SD.open(path);
|
||||
File entry;
|
||||
while (entry = dir.openNextFile()) {
|
||||
if (!withDirs && entry.isDirectory()) continue;
|
||||
if (!withFiles && !entry.isDirectory()) continue;
|
||||
String filename = entry.name();
|
||||
if (!withHidden && filename.startsWith(".")) continue;
|
||||
if (entry.isDirectory()) filename.concat("/");
|
||||
result.push_back(filename);
|
||||
}
|
||||
_spi->select_sd(false);
|
||||
result.sort();
|
||||
return result;
|
||||
bool Player::play(Playlist* p) {
|
||||
_current_playlist = p;
|
||||
return play();
|
||||
}
|
||||
|
||||
String Player::_find_album_dir(String id) {
|
||||
_spi->select_sd();
|
||||
if (id.endsWith("/")) id = id.substring(0, id.length() - 1);
|
||||
String id_with_divider = id + " - ";
|
||||
File root = SD.open("/");
|
||||
File entry;
|
||||
String result = String("");
|
||||
while ((result.length()==0) && (entry = root.openNextFile())) {
|
||||
String name = entry.name() + 1;
|
||||
TRACE("Checking if '%s' startsWith '%s'...\n", name.c_str(), id.c_str());
|
||||
if (entry.isDirectory() && (name.startsWith(id_with_divider) || name.equals(id))) {
|
||||
result = name;
|
||||
}
|
||||
entry.close();
|
||||
}
|
||||
root.close();
|
||||
_spi->select_sd(false);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::list<String> Player::_files_in_dir(String path) {
|
||||
_spi->select_sd();
|
||||
TRACE("Examining folder %s...\n", path.c_str());
|
||||
if (!path.startsWith("/")) path = String("/") + path;
|
||||
//if (!path.endsWith("/")) path.concat("/");
|
||||
std::list<String> result;
|
||||
if (!SD.exists(path)) {
|
||||
DEBUG("Could not open path '%s'.\n", path.c_str());
|
||||
_spi->select_sd(false);
|
||||
return result;
|
||||
}
|
||||
File dir = SD.open(path);
|
||||
File entry;
|
||||
while (entry = dir.openNextFile()) {
|
||||
String filename = entry.name();
|
||||
filename = filename.substring(path.length() + 1);
|
||||
if (!entry.isDirectory() &&
|
||||
!filename.startsWith(".") &&
|
||||
( filename.endsWith(".mp3") ||
|
||||
filename.endsWith(".ogg") ||
|
||||
filename.endsWith(".wma") ||
|
||||
filename.endsWith(".mp4") ||
|
||||
filename.endsWith(".mpa"))) {
|
||||
TRACE(" Adding entry %s\n", entry.name());
|
||||
result.push_back(entry.name());
|
||||
} else {
|
||||
TRACE(" Ignoring entry %s\n", filename.c_str());
|
||||
}
|
||||
entry.close();
|
||||
}
|
||||
dir.close();
|
||||
_spi->select_sd(false);
|
||||
result.sort();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void Player::_fill_id_to_folder_map() {
|
||||
DEBUG("_fill_id_to_folder_map() running...");
|
||||
_spi->select_sd();
|
||||
File root = SD.open("/");
|
||||
File entry;
|
||||
while (entry = root.openNextFile()) {
|
||||
String foldername = entry.name();
|
||||
// Remove trailing slash
|
||||
foldername.remove(foldername.length());
|
||||
TRACE("Looking at %s...\n", foldername.c_str());
|
||||
if (!entry.isDirectory() || foldername.startsWith("/.")) continue;
|
||||
if (!SD.exists(foldername + "/ids.txt")) {
|
||||
TRACE("Folder %s does not contain ids.txt -> ignoring\n", foldername.c_str());
|
||||
continue;
|
||||
}
|
||||
TRACE("Reading contents of %s...\n", (foldername + "/ids.txt").c_str());
|
||||
File f = SD.open(foldername + "/ids.txt");
|
||||
String buffer = "";
|
||||
while (f.available()) {
|
||||
char c = f.read();
|
||||
if (c=='\n' || c=='\r') {
|
||||
if (buffer.length() > 0) {
|
||||
id_to_folder_map[buffer] = foldername;
|
||||
DEBUG("Adding mapping '%s'=>'%s'\n", buffer.c_str(), foldername.c_str());
|
||||
buffer = "";
|
||||
}
|
||||
} else {
|
||||
buffer.concat(c);
|
||||
}
|
||||
}
|
||||
f.close();
|
||||
|
||||
if (buffer.length() > 0) {
|
||||
id_to_folder_map[buffer] = foldername;
|
||||
DEBUG("Adding mapping '%s'=>'%s'\n", buffer.c_str(), foldername.c_str());
|
||||
}
|
||||
entry.close();
|
||||
}
|
||||
root.close();
|
||||
DEBUG("fill_id_to_folder_map done.\n");
|
||||
_spi->select_sd(false);
|
||||
}
|
||||
|
||||
String Player::_random_album() {
|
||||
std::list<String> albums = ls("/", false, true, false);
|
||||
uint8_t rnd = random(albums.size());
|
||||
std::list<String>::iterator it = albums.begin();
|
||||
for (int i=0; i<rnd; i++) { it++; }
|
||||
return *it;
|
||||
}
|
||||
|
||||
void Player::play_random_album() {
|
||||
play_album(_random_album());
|
||||
}
|
||||
|
||||
bool Player::play_id(String id) {
|
||||
String folder = _foldername_for_id(id);
|
||||
if (folder.length()==0) return false;
|
||||
return play_album(folder);
|
||||
}
|
||||
|
||||
String Player::_foldername_for_id(String id) {
|
||||
DEBUG("Searching for id %s...\n", id.c_str());
|
||||
std::map<String, String>::iterator it = id_to_folder_map.find(id);
|
||||
if (it != id_to_folder_map.end()) {
|
||||
DEBUG("Found folder '%s' for id %s.\n", it->first.c_str(), it->second.c_str());
|
||||
return it->second;
|
||||
}
|
||||
DEBUG("No folder found for id %s.\n", id.c_str());
|
||||
return "";
|
||||
}
|
||||
|
||||
bool Player::play_album(String album) {
|
||||
album_state s = _last_tracks[album.c_str()];
|
||||
DEBUG("Last index for album '%s' was %d,%d\n", album.c_str(), s.index, s.position);
|
||||
return play_song(album, s.index, s.position);
|
||||
}
|
||||
|
||||
bool Player::play_song(String album, uint8_t index, uint32_t skip_to) {
|
||||
bool Player::play() {
|
||||
if (_state == sleeping || _state == recording) _wakeup();
|
||||
if (_state != idle) return false;
|
||||
DEBUG("Trying to play song at index %d, offset %d of album %s\n", index, skip_to, album.c_str());
|
||||
std::list<String> files = _files_in_dir(album);
|
||||
_playing_album_songs = files.size();
|
||||
DEBUG("Found %d songs in album\n", files.size());
|
||||
if (index >= files.size()) {
|
||||
ERROR("No matching file found - not playing.\n");
|
||||
return false;
|
||||
}
|
||||
String file = *(std::next(files.begin(), index));
|
||||
String file = _current_playlist->get_current_file();
|
||||
uint32_t position = _current_playlist->get_position();
|
||||
_state = playing;
|
||||
_playing_album = album;
|
||||
_playing_index = index;
|
||||
_set_last_track(album.c_str(), index, skip_to);
|
||||
_play_file(file, skip_to);
|
||||
_play_file(file, position);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Player::play_system_sound(String filename) {
|
||||
String file = filename;
|
||||
if (!SD.exists(file)) {
|
||||
ERROR("File %s does not exist!\n", file.c_str());
|
||||
return;
|
||||
}
|
||||
if (_state == playing) {
|
||||
stop();
|
||||
_state = system_sound_while_playing;
|
||||
} else {
|
||||
_state = system_sound_while_stopped;
|
||||
}
|
||||
_play_file(file, 0);
|
||||
}
|
||||
|
||||
void Player::_play_file(String file, uint32_t file_offset) {
|
||||
INFO("play_file('%s', %d)\n", file.c_str(), file_offset);
|
||||
_spi->select_sd();
|
||||
@@ -797,11 +605,10 @@ void Player::_finish_playing() {
|
||||
}
|
||||
|
||||
void Player::stop(bool turn_speaker_off) {
|
||||
if (_state != playing /* && _state != system_sound_while_playing && _state != system_sound_while_stopped*/) return;
|
||||
if (_state != playing) return;
|
||||
INFO("Stopping...\n");
|
||||
if (_state == playing) {
|
||||
_set_last_track(_playing_album.c_str(), _playing_index, (uint32_t)_file.position());
|
||||
}
|
||||
_current_playlist->set_position(_current_play_position);
|
||||
|
||||
_state = stopping;
|
||||
_stop_delay = 0;
|
||||
_write_control_register(SCI_MODE, _read_control_register(SCI_MODE) | SM_CANCEL);
|
||||
@@ -842,18 +649,12 @@ void Player::_refill() {
|
||||
DEBUG("EOF reached.\n");
|
||||
_skip_to = 0;
|
||||
_finish_playing();
|
||||
if (_state == system_sound_while_playing) {
|
||||
_finish_stopping(false);
|
||||
play_album(_playing_album);
|
||||
return;
|
||||
} else if (_state == system_sound_while_stopped) {
|
||||
_finish_stopping(true);
|
||||
return;
|
||||
}
|
||||
_finish_stopping(false);
|
||||
bool result = play_song(_playing_album, _playing_index + 1);
|
||||
if (!result) {
|
||||
_set_last_track(_playing_album.c_str(), 0, 0);
|
||||
if (_current_playlist->has_track_next()) {
|
||||
_current_playlist->track_next();
|
||||
play();
|
||||
} else {
|
||||
_current_playlist->reset();
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -880,10 +681,7 @@ void Player::_refill() {
|
||||
}
|
||||
|
||||
bool Player::_refill_needed() {
|
||||
return _state==playing ||
|
||||
_state==stopping ||
|
||||
_state==system_sound_while_playing ||
|
||||
_state==system_sound_while_stopped;
|
||||
return _state==playing || _state==stopping;
|
||||
}
|
||||
|
||||
bool Player::loop() {
|
||||
@@ -914,8 +712,3 @@ bool Player::loop() {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Player::_set_last_track(const char* album, uint8_t index, uint32_t position) {
|
||||
DEBUG("Setting _last_track[%s]=%d,%d.\n", album, index, position);
|
||||
_last_tracks[album] = {index, position};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user