diff options
| author | ailurux <ailuruxx@gmail.com> | 2024-12-19 04:29:23 +0000 |
|---|---|---|
| committer | cooljqln <cooljqln@noreply.codeberg.org> | 2024-12-19 04:29:23 +0000 |
| commit | 5cdc1141ee5f5c7b19809940457b4c4c21db9ae6 (patch) | |
| tree | 3d4484992bb819a4809ae828ee6cd7f571b00ad7 /src/tangara/audio/track_queue.cpp | |
| parent | ceb66b46eac7811a9e1ad4d8141b09947f7ee4b2 (diff) | |
| download | tangara-fw-5cdc1141ee5f5c7b19809940457b4c4c21db9ae6.tar.gz | |
Queue repeat modes (#126)
This replaces the previous system of a separate track and queue repeat, with a RepeatMode type with the following options and behaviours:
- OFF: No repeat, queue or track. When the current queue finishes, shuffled or otherwise, playback will stop.
- REPEAT_TRACK: The current track will loop indefinitely, unless next is explicitly called through some user action (ie using the next button in the now playing screen)
- REPEAT_QUEUE: The entire queue will repeat indefinitely. When shuffled is enabled this will repeat the queue with new combinations each cycle.
The repeat mode is persisted in non-volatile storage, so the behaviour will be consistent throughout restarts and queue replacements, and so the "queue repeat by default" use case can be met in this way.
In addition, I've made it work a little nicer when the queue runs out in the now playing screen, keeping the previously played track shown and playback can be continued by using the play button or by going to a previous song in the queue.
Reviewed-on: https://codeberg.org/cool-tech-zone/tangara-fw/pulls/126
Co-authored-by: ailurux <ailuruxx@gmail.com>
Co-committed-by: ailurux <ailuruxx@gmail.com>
Diffstat (limited to 'src/tangara/audio/track_queue.cpp')
| -rw-r--r-- | src/tangara/audio/track_queue.cpp | 99 |
1 files changed, 35 insertions, 64 deletions
diff --git a/src/tangara/audio/track_queue.cpp b/src/tangara/audio/track_queue.cpp index 0af8bee0..5689ecf0 100644 --- a/src/tangara/audio/track_queue.cpp +++ b/src/tangara/audio/track_queue.cpp @@ -38,25 +38,26 @@ namespace audio { using Reason = QueueUpdate::Reason; RandomIterator::RandomIterator() - : seed_(0), pos_(0), size_(0), replay_(false) {} + : seed_(0), pos_(0), size_(0) {} RandomIterator::RandomIterator(size_t size) - : seed_(), pos_(0), size_(size), replay_(false) { + : seed_(), pos_(0), size_(size) { esp_fill_random(&seed_, sizeof(seed_)); } auto RandomIterator::current() const -> size_t { - if (pos_ < size_ || replay_) { - return MillerShuffle(pos_, seed_, size_); - } - return size_; + return MillerShuffle(pos_, seed_, size_); } -auto RandomIterator::next() -> void { +auto RandomIterator::next(bool repeat) -> bool { // MillerShuffle behaves well with pos > size, returning different // permutations each 'cycle'. We therefore don't need to worry about wrapping // this value. - pos_++; + if (pos_ < size_ - 1 || repeat) { + pos_++; + return true; + } + return false; } auto RandomIterator::prev() -> void { @@ -72,10 +73,6 @@ auto RandomIterator::resize(size_t s) -> void { pos_ = 0; } -auto RandomIterator::replay(bool r) -> void { - replay_ = r; -} - auto notifyChanged(bool current_changed, Reason reason) -> void { QueueUpdate ev{ .current_changed = current_changed, @@ -95,15 +92,15 @@ auto notifyPlayFrom(uint32_t start_from_position) -> void { events::Audio().Dispatch(ev); } -TrackQueue::TrackQueue(tasks::WorkerPool& bg_worker, database::Handle db) +TrackQueue::TrackQueue(tasks::WorkerPool& bg_worker, database::Handle db, drivers::NvsStorage& nvs) : mutex_(), bg_worker_(bg_worker), db_(db), + nvs_(nvs), playlist_(".queue.playlist"), position_(0), shuffle_(), - repeat_(false), - replay_(false) {} + repeatMode_(static_cast<RepeatMode>(nvs.QueueRepeatMode())) {} auto TrackQueue::current() const -> TrackItem { const std::shared_lock<std::shared_mutex> lock(mutex_); @@ -293,26 +290,25 @@ auto TrackQueue::goTo(size_t position) -> void { } auto TrackQueue::next(Reason r) -> void { - bool changed = true; + bool changed = false; { const std::unique_lock<std::shared_mutex> lock(mutex_); - auto pos = position_; if (shuffle_) { - shuffle_->next(); + changed = shuffle_->next(repeatMode_ == RepeatMode::REPEAT_QUEUE); position_ = shuffle_->current(); } else { if (position_ + 1 < totalSize()) { position_++; // Next track - } - else { + changed = true; + } else if (repeatMode_ == RepeatMode::REPEAT_QUEUE) { position_ = 0; // Go to beginning + changed = true; } } goTo(position_); - changed = pos != position_; } notifyChanged(changed, r); @@ -329,9 +325,8 @@ auto TrackQueue::previous() -> void { } else { if (position_ > 0) { position_--; - } - else { - position_ = totalSize(); + } else if (repeatMode_ == RepeatMode::REPEAT_QUEUE) { + position_ = totalSize()-1; // Go to the end of the queue } } goTo(position_); @@ -341,7 +336,7 @@ auto TrackQueue::previous() -> void { } auto TrackQueue::finish() -> void { - if (repeat_) { + if (repeatMode_ == RepeatMode::REPEAT_TRACK) { notifyChanged(true, Reason::kRepeatingLastTrack); } else { next(Reason::kTrackFinished); @@ -367,7 +362,6 @@ auto TrackQueue::random(bool en) -> void { const std::unique_lock<std::shared_mutex> lock(mutex_); if (en) { shuffle_.emplace(totalSize()); - shuffle_->replay(replay_); } else { shuffle_.reset(); } @@ -382,34 +376,14 @@ auto TrackQueue::random() const -> bool { return shuffle_.has_value(); } -auto TrackQueue::repeat(bool en) -> void { - { - const std::unique_lock<std::shared_mutex> lock(mutex_); - repeat_ = en; - } - +auto TrackQueue::repeatMode(RepeatMode mode) -> void { + repeatMode_ = mode; + nvs_.QueueRepeatMode(repeatMode_); notifyChanged(false, Reason::kExplicitUpdate); } -auto TrackQueue::repeat() const -> bool { - const std::shared_lock<std::shared_mutex> lock(mutex_); - return repeat_; -} - -auto TrackQueue::replay(bool en) -> void { - { - const std::unique_lock<std::shared_mutex> lock(mutex_); - replay_ = en; - if (shuffle_) { - shuffle_->replay(en); - } - } - notifyChanged(false, Reason::kExplicitUpdate); -} - -auto TrackQueue::replay() const -> bool { - const std::shared_lock<std::shared_mutex> lock(mutex_); - return replay_; +auto TrackQueue::repeatMode() const -> RepeatMode { + return repeatMode_; } auto TrackQueue::serialise() -> std::string { @@ -417,9 +391,8 @@ auto TrackQueue::serialise() -> std::string { cppbor::Map encoded; cppbor::Array metadata{ - cppbor::Bool{repeat_}, - cppbor::Bool{replay_}, cppbor::Uint{position_}, + cppbor::Uint{repeatMode_}, }; if (opened_playlist_) { @@ -471,26 +444,24 @@ cppbor::ParseClient* TrackQueue::QueueParseClient::item( i_ = 0; } else if (item->type() == cppbor::UINT) { auto val = item->asUint()->unsignedValue(); - // Save the position so we can apply it later when we have finished - // serialising - position_to_set_ = val; - } else if (item->type() == cppbor::TSTR) { - auto val = item->asTstr(); - queue_.openPlaylist(val->value(), false); - } else if (item->type() == cppbor::SIMPLE) { - bool val = item->asBool()->value(); if (i_ == 0) { - queue_.repeat_ = val; + // First value == position + // Save the position so we can apply it later when we have finished + // serialising + position_to_set_ = val; } else if (i_ == 1) { - queue_.replay_ = val; + // Second value == repeat mode + queue_.repeatMode_ = static_cast<RepeatMode>(val); } i_++; + } else if (item->type() == cppbor::TSTR) { + auto val = item->asTstr(); + queue_.openPlaylist(val->value(), false); } } else if (state_ == State::kShuffle) { if (item->type() == cppbor::ARRAY) { i_ = 0; queue_.shuffle_.emplace(); - queue_.shuffle_->replay(queue_.replay_); } else if (item->type() == cppbor::UINT) { auto val = item->asUint()->unsignedValue(); switch (i_) { |
