Queue now keeps file offsets in memory to speed up search

custom
ailurux 9 months ago
parent 69cd284757
commit 514540d89c
  1. 68
      src/tangara/audio/playlist.cpp
  2. 9
      src/tangara/audio/playlist.hpp

@ -16,7 +16,12 @@ namespace audio {
[[maybe_unused]] static constexpr char kTag[] = "playlist";
Playlist::Playlist(std::string playlistFilepath)
: filepath_(playlistFilepath), mutex_(), total_size_(0), pos_(0) {}
: filepath_(playlistFilepath),
mutex_(),
total_size_(0),
pos_(-1),
offset_cache_(&memory::kSpiRamResource),
sample_size_(50) {}
auto Playlist::open() -> bool {
FRESULT res =
@ -47,8 +52,10 @@ auto Playlist::size() const -> size_t {
auto Playlist::append(Item i) -> void {
std::unique_lock<std::mutex> lock(mutex_);
auto offset = f_tell(&file_);
bool first_entry = current_value_.empty();
// Seek to end and append
auto res = f_lseek(&file_, f_size(&file_));
auto end = f_size(&file_);
auto res = f_lseek(&file_, end);
if (res != FR_OK) {
ESP_LOGE(kTag, "Seek to end of file failed? Error %d", res);
return;
@ -58,16 +65,19 @@ auto Playlist::append(Item i) -> void {
if (std::holds_alternative<std::string>(i)) {
path = std::get<std::string>(i);
f_printf(&file_, "%s\n", path.c_str());
total_size_++;
if (current_value_.empty()) {
if (total_size_ % sample_size_ == 0) {
offset_cache_.push_back(end);
}
if (first_entry) {
current_value_ = path;
}
total_size_++;
}
// Restore position
res = f_lseek(&file_, offset);
if (res != FR_OK) {
ESP_LOGE(kTag, "Failed to restore file position after append?");
return;
if (res != FR_OK) {
ESP_LOGE(kTag, "Failed to restore file position after append?");
return;
}
res = f_sync(&file_);
if (res != FR_OK) {
@ -77,8 +87,25 @@ auto Playlist::append(Item i) -> void {
}
auto Playlist::skipTo(size_t position) -> void {
std::unique_lock<std::mutex> lock(mutex_);
// Check our cache and go to nearest entry
pos_ = position;
consumeAndCount(position);
auto remainder = position % sample_size_;
auto quotient = (position - remainder) / sample_size_;
if (offset_cache_.size() < quotient) {
// Fall back case
ESP_LOGW(kTag, "File offset cache failed, falling back...");
f_rewind(&file_);
advanceBy(pos_);
}
auto entry = offset_cache_.at(quotient);
// Go to byte offset
auto res = f_lseek(&file_, entry);
if (res != FR_OK) {
ESP_LOGW(kTag, "Error going to byte offset %llu for playlist entry index %d", entry, pos_);
}
// Count ahead entries
advanceBy(remainder+1);
}
auto Playlist::next() -> void {
@ -99,6 +126,7 @@ auto Playlist::value() const -> std::string {
}
auto Playlist::clear() -> bool {
std::unique_lock<std::mutex> lock(mutex_);
auto res = f_close(&file_);
if (res != FR_OK) {
return false;
@ -110,6 +138,7 @@ auto Playlist::clear() -> bool {
}
total_size_ = 0;
current_value_.clear();
offset_cache_.clear();
pos_ = 0;
return true;
}
@ -128,6 +157,7 @@ auto Playlist::consumeAndCount(ssize_t upto) -> bool {
size_t count = 0;
f_rewind(&file_);
while (!f_eof(&file_)) {
auto offset = f_tell(&file_);
// TODO: Correctly handle lines longer than this
// TODO: Also correctly handle the case where the last entry doesn't end in
// \n
@ -136,6 +166,9 @@ auto Playlist::consumeAndCount(ssize_t upto) -> bool {
ESP_LOGW(kTag, "Error consuming playlist file at line %d", count);
return false;
}
if (count % sample_size_ == 0) {
offset_cache_.push_back(offset);
}
count++;
if (upto >= 0 && count > upto) {
@ -151,4 +184,23 @@ auto Playlist::consumeAndCount(ssize_t upto) -> bool {
return true;
}
auto Playlist::advanceBy(ssize_t amt) -> bool {
TCHAR buff[512];
size_t count = 0;
while (!f_eof(&file_)) {
auto res = f_gets(buff, 512, &file_);
if (res == NULL) {
ESP_LOGW(kTag, "Error consuming playlist file at line %d", count);
return false;
}
count++;
if (count >= amt) {
size_t len = strlen(buff);
current_value_.assign(buff, len - 1);
break;
}
}
return true;
}
} // namespace audio

@ -50,7 +50,16 @@ class Playlist {
FIL file_;
std::string current_value_;
std::pmr::vector<FSIZE_t> offset_cache_; // List of offsets determined by sample size;
/*
* How many tracks per offset saved (ie, a value of 100 means every 100 tracks the file offset is saved)
* This speeds up searches, especially in the case of shuffling a lot of tracks.
*/
const uint32_t sample_size_;
auto consumeAndCount(ssize_t upto) -> bool;
auto advanceBy(ssize_t amt) -> bool;
};
} // namespace audio
Loading…
Cancel
Save