From 0a271d786be4cc1a1691fa38f184a091721a5251 Mon Sep 17 00:00:00 2001 From: ailurux Date: Tue, 16 Jul 2024 01:23:43 +0000 Subject: daniel/playlist-queue (#83) Reviewed-on: https://codeberg.org/cool-tech-zone/tangara-fw/pulls/83 Reviewed-by: cooljqln Co-authored-by: ailurux Co-committed-by: ailurux --- src/tangara/audio/track_queue.cpp | 158 +++++++++++++------------------------- 1 file changed, 53 insertions(+), 105 deletions(-) (limited to 'src/tangara/audio/track_queue.cpp') diff --git a/src/tangara/audio/track_queue.cpp b/src/tangara/audio/track_queue.cpp index 603b0de1..1689f06a 100644 --- a/src/tangara/audio/track_queue.cpp +++ b/src/tangara/audio/track_queue.cpp @@ -28,6 +28,7 @@ #include "memory_resource.hpp" #include "tasks.hpp" #include "ui/ui_fsm.hpp" +#include "track_queue.hpp" namespace audio { @@ -83,65 +84,67 @@ auto notifyChanged(bool current_changed, Reason reason) -> void { events::Audio().Dispatch(ev); } -TrackQueue::TrackQueue(tasks::WorkerPool& bg_worker) +TrackQueue::TrackQueue(tasks::WorkerPool& bg_worker, database::Handle db) : mutex_(), bg_worker_(bg_worker), - pos_(0), - tracks_(&memory::kSpiRamResource), + db_(db), + playlist_("queue.playlist"), // TODO shuffle_(), repeat_(false), replay_(false) {} -auto TrackQueue::current() const -> std::optional { +auto TrackQueue::current() const -> TrackItem { const std::shared_lock lock(mutex_); - if (pos_ >= tracks_.size()) { + std::string val = playlist_.value(); + if (val.empty()) { return {}; } - return tracks_[pos_]; + return val; } -auto TrackQueue::peekNext(std::size_t limit) const - -> std::vector { +auto TrackQueue::currentPosition() const -> size_t { const std::shared_lock lock(mutex_); - std::vector out; - for (size_t i = pos_ + 1; i < pos_ + limit + 1 && i < tracks_.size(); i++) { - out.push_back(i); - } - return out; + return playlist_.currentPosition(); } -auto TrackQueue::peekPrevious(std::size_t limit) const - -> std::vector { +auto TrackQueue::totalSize() const -> size_t { const std::shared_lock lock(mutex_); - std::vector out; - for (size_t i = pos_ - 1; i < pos_ - limit - 1 && i >= tracks_.size(); i--) { - out.push_back(i); - } - return out; + return playlist_.size(); } -auto TrackQueue::currentPosition() const -> size_t { - const std::shared_lock lock(mutex_); - return pos_; +auto TrackQueue::open() -> bool { + // FIX ME: If playlist opening fails, should probably fall back to a vector of tracks or something + // so that we're not necessarily always needing mounted storage + return playlist_.open(); } -auto TrackQueue::totalSize() const -> size_t { - const std::shared_lock lock(mutex_); - return tracks_.size(); +auto TrackQueue::getFilepath(database::TrackId id) -> std::optional { + auto db = db_.lock(); + if (!db) { + return {}; + } + return db->getTrackPath(id); } + +// TODO WIP: Atm only appends are allowed, this will only ever append regardless of what index +// is given. But it is kept like this for compatability for now. auto TrackQueue::insert(Item i, size_t index) -> void { + append(i); +} + +auto TrackQueue::append(Item i) -> void { bool was_queue_empty; bool current_changed; { const std::shared_lock lock(mutex_); - was_queue_empty = pos_ == tracks_.size(); - current_changed = was_queue_empty || index == pos_; + was_queue_empty = playlist_.currentPosition() >= playlist_.size(); + current_changed = was_queue_empty; // Dont support inserts yet } auto update_shuffler = [=, this]() { if (shuffle_) { - shuffle_->resize(tracks_.size()); + shuffle_->resize(playlist_.size()); // If there wasn't anything already playing, then we should make sure we // begin playback at a random point, instead of always starting with // whatever was inserted first and *then* shuffling. @@ -149,7 +152,7 @@ auto TrackQueue::insert(Item i, size_t index) -> void { // 'play this track now' (by inserting at the current pos) to work even // when shuffling is enabled. if (was_queue_empty) { - pos_ = shuffle_->current(); + playlist_.skipTo(shuffle_->current()); } } }; @@ -157,10 +160,11 @@ auto TrackQueue::insert(Item i, size_t index) -> void { if (std::holds_alternative(i)) { { const std::unique_lock lock(mutex_); - if (index <= tracks_.size()) { - tracks_.insert(tracks_.begin() + index, std::get(i)); - update_shuffler(); + auto filename = getFilepath(std::get(i)); + if (filename) { + playlist_.append(*filename); } + update_shuffler(); } notifyChanged(current_changed, Reason::kExplicitUpdate); } else if (std::holds_alternative(i)) { @@ -169,7 +173,6 @@ auto TrackQueue::insert(Item i, size_t index) -> void { // doesn't block. bg_worker_.Dispatch([=, this]() { database::TrackIterator it = std::get(i); - size_t working_pos = index; while (true) { auto next = *it; if (!next) { @@ -179,11 +182,11 @@ auto TrackQueue::insert(Item i, size_t index) -> void { // like current(). { const std::unique_lock lock(mutex_); - if (working_pos <= tracks_.size()) { - tracks_.insert(tracks_.begin() + working_pos, *next); + auto filename = *getFilepath(*next); + if (!filename.empty()) { + playlist_.append(filename); } } - working_pos++; it++; } { @@ -195,15 +198,6 @@ auto TrackQueue::insert(Item i, size_t index) -> void { } } -auto TrackQueue::append(Item i) -> void { - size_t end; - { - const std::shared_lock lock(mutex_); - end = tracks_.size(); - } - insert(i, end); -} - auto TrackQueue::next() -> void { next(Reason::kExplicitUpdate); } @@ -215,17 +209,16 @@ auto TrackQueue::next(Reason r) -> void { const std::unique_lock lock(mutex_); if (shuffle_) { shuffle_->next(); - pos_ = shuffle_->current(); + playlist_.skipTo(shuffle_->current()); } else { - if (pos_ + 1 >= tracks_.size()) { + if (playlist_.atEnd()) { if (replay_) { - pos_ = 0; + playlist_.skipTo(0); } else { - pos_ = tracks_.size(); changed = false; } } else { - pos_++; + playlist_.next(); } } } @@ -240,16 +233,16 @@ auto TrackQueue::previous() -> void { const std::unique_lock lock(mutex_); if (shuffle_) { shuffle_->prev(); - pos_ = shuffle_->current(); + playlist_.skipTo(shuffle_->current()); } else { - if (pos_ == 0) { + if (playlist_.currentPosition() == 0) { if (repeat_) { - pos_ = tracks_.size() - 1; + playlist_.skipTo(playlist_.size()-1); } else { changed = false; } } else { - pos_--; + playlist_.prev(); } } } @@ -265,39 +258,10 @@ auto TrackQueue::finish() -> void { } } -auto TrackQueue::skipTo(database::TrackId id) -> void { - // Defer this work to the background not because it's particularly - // long-running (although it could be), but because we want to ensure we - // only search for the given id after any previously pending iterator - // insertions have finished. - bg_worker_.Dispatch([=, this]() { - bool found = false; - { - const std::unique_lock lock(mutex_); - for (size_t i = 0; i < tracks_.size(); i++) { - if (tracks_[i] == id) { - pos_ = i; - found = true; - break; - } - } - } - if (found) { - notifyChanged(true, Reason::kExplicitUpdate); - } - }); -} - auto TrackQueue::clear() -> void { { const std::unique_lock lock(mutex_); - if (tracks_.empty()) { - return; - } - - pos_ = 0; - tracks_.clear(); - + playlist_.clear(); if (shuffle_) { shuffle_->resize(0); } @@ -309,10 +273,8 @@ auto TrackQueue::clear() -> void { auto TrackQueue::random(bool en) -> void { { const std::unique_lock lock(mutex_); - // Don't check for en == true already; this has the side effect that - // repeated calls with en == true will re-shuffle. if (en) { - shuffle_.emplace(tracks_.size()); + shuffle_.emplace(playlist_.size()); shuffle_->replay(replay_); } else { shuffle_.reset(); @@ -360,14 +322,11 @@ auto TrackQueue::replay() const -> bool { auto TrackQueue::serialise() -> std::string { cppbor::Array tracks{}; - for (database::TrackId track : tracks_) { - tracks.add(cppbor::Uint(track)); - } cppbor::Map encoded; encoded.add(cppbor::Uint{0}, cppbor::Array{ - cppbor::Uint{pos_}, cppbor::Bool{repeat_}, cppbor::Bool{replay_}, + cppbor::Uint{playlist_.currentPosition()}, }); if (shuffle_) { encoded.add(cppbor::Uint{1}, cppbor::Array{ @@ -376,7 +335,6 @@ auto TrackQueue::serialise() -> std::string { cppbor::Uint{shuffle_->pos()}, }); } - encoded.add(cppbor::Uint{2}, std::move(tracks)); return encoded.toString(); } @@ -401,9 +359,6 @@ cppbor::ParseClient* TrackQueue::QueueParseClient::item( case 1: state_ = State::kShuffle; break; - case 2: - state_ = State::kTracks; - break; default: state_ = State::kFinished; } @@ -412,7 +367,8 @@ cppbor::ParseClient* TrackQueue::QueueParseClient::item( if (item->type() == cppbor::ARRAY) { i_ = 0; } else if (item->type() == cppbor::UINT) { - queue_.pos_ = item->asUint()->unsignedValue(); + auto val = item->asUint()->unsignedValue(); + queue_.playlist_.skipTo(val); } else if (item->type() == cppbor::SIMPLE) { bool val = item->asBool()->value(); if (i_ == 0) { @@ -444,10 +400,6 @@ cppbor::ParseClient* TrackQueue::QueueParseClient::item( } i_++; } - } else if (state_ == State::kTracks) { - if (item->type() == cppbor::UINT) { - queue_.tracks_.push_back(item->asUint()->unsignedValue()); - } } else if (state_ == State::kFinished) { } return this; @@ -470,10 +422,6 @@ cppbor::ParseClient* TrackQueue::QueueParseClient::itemEnd( if (item->type() == cppbor::ARRAY) { state_ = State::kRoot; } - } else if (state_ == State::kTracks) { - if (item->type() == cppbor::ARRAY) { - state_ = State::kRoot; - } } else if (state_ == State::kFinished) { } return this; -- cgit v1.2.3 From bc2527135a2ae4b905015bd6d0fa105cda200b8e Mon Sep 17 00:00:00 2001 From: ailurux Date: Tue, 16 Jul 2024 14:39:01 +1000 Subject: Fix std::optional access --- src/tangara/audio/track_queue.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/tangara/audio/track_queue.cpp') diff --git a/src/tangara/audio/track_queue.cpp b/src/tangara/audio/track_queue.cpp index 1689f06a..1aeecf8a 100644 --- a/src/tangara/audio/track_queue.cpp +++ b/src/tangara/audio/track_queue.cpp @@ -160,9 +160,9 @@ auto TrackQueue::append(Item i) -> void { if (std::holds_alternative(i)) { { const std::unique_lock lock(mutex_); - auto filename = getFilepath(std::get(i)); - if (filename) { - playlist_.append(*filename); + auto filename = getFilepath(std::get(i)).value_or(""); + if (!filename.empty()) { + playlist_.append(filename); } update_shuffler(); } @@ -182,7 +182,7 @@ auto TrackQueue::append(Item i) -> void { // like current(). { const std::unique_lock lock(mutex_); - auto filename = *getFilepath(*next); + auto filename = getFilepath(*next).value_or(""); if (!filename.empty()) { playlist_.append(filename); } -- cgit v1.2.3 From b34959917446ac5d47ddec7bb6d98a6397045558 Mon Sep 17 00:00:00 2001 From: ailurux Date: Tue, 30 Jul 2024 04:36:48 +0000 Subject: daniel/playlist-queue (#84) Support for playlist files being opened along side the queue's own playlist. Playlists can be opened from the file browser, if the file ends in ".playlist" (will add support for .m3u as well eventually) Reviewed-on: https://codeberg.org/cool-tech-zone/tangara-fw/pulls/84 Co-authored-by: ailurux Co-committed-by: ailurux --- src/tangara/audio/track_queue.cpp | 115 ++++++++++++++++++++++++-------------- 1 file changed, 73 insertions(+), 42 deletions(-) (limited to 'src/tangara/audio/track_queue.cpp') diff --git a/src/tangara/audio/track_queue.cpp b/src/tangara/audio/track_queue.cpp index 1aeecf8a..399d6717 100644 --- a/src/tangara/audio/track_queue.cpp +++ b/src/tangara/audio/track_queue.cpp @@ -84,18 +84,25 @@ auto notifyChanged(bool current_changed, Reason reason) -> void { events::Audio().Dispatch(ev); } + TrackQueue::TrackQueue(tasks::WorkerPool& bg_worker, database::Handle db) : mutex_(), bg_worker_(bg_worker), db_(db), - playlist_("queue.playlist"), // TODO + playlist_(".queue.playlist"), + position_(0), shuffle_(), repeat_(false), replay_(false) {} auto TrackQueue::current() const -> TrackItem { const std::shared_lock lock(mutex_); - std::string val = playlist_.value(); + std::string val; + if (opened_playlist_ && position_ < opened_playlist_->size()) { + val = opened_playlist_->value(); + } else { + val = playlist_.value(); + } if (val.empty()) { return {}; } @@ -104,12 +111,21 @@ auto TrackQueue::current() const -> TrackItem { auto TrackQueue::currentPosition() const -> size_t { const std::shared_lock lock(mutex_); - return playlist_.currentPosition(); + return position_; } auto TrackQueue::totalSize() const -> size_t { - const std::shared_lock lock(mutex_); - return playlist_.size(); + size_t sum = playlist_.size(); + if (opened_playlist_) { + sum += opened_playlist_->size(); + } + return sum; +} + +auto TrackQueue::updateShuffler() -> void { + if (shuffle_) { + shuffle_->resize(totalSize()); + } } auto TrackQueue::open() -> bool { @@ -118,6 +134,17 @@ auto TrackQueue::open() -> bool { return playlist_.open(); } +auto TrackQueue::openPlaylist(const std::string& playlist_file) -> bool { + opened_playlist_.emplace(playlist_file); + auto res = opened_playlist_->open(); + if (!res) { + return false; + } + updateShuffler(); + notifyChanged(true, Reason::kExplicitUpdate); + return true; +} + auto TrackQueue::getFilepath(database::TrackId id) -> std::optional { auto db = db_.lock(); if (!db) { @@ -142,20 +169,15 @@ auto TrackQueue::append(Item i) -> void { current_changed = was_queue_empty; // Dont support inserts yet } - auto update_shuffler = [=, this]() { - if (shuffle_) { - shuffle_->resize(playlist_.size()); - // If there wasn't anything already playing, then we should make sure we - // begin playback at a random point, instead of always starting with - // whatever was inserted first and *then* shuffling. - // We don't base this purely off of current_changed because we would like - // 'play this track now' (by inserting at the current pos) to work even - // when shuffling is enabled. - if (was_queue_empty) { - playlist_.skipTo(shuffle_->current()); - } - } - }; + // If there wasn't anything already playing, then we should make sure we + // begin playback at a random point, instead of always starting with + // whatever was inserted first and *then* shuffling. + // We don't base this purely off of current_changed because we would like + // 'play this track now' (by inserting at the current pos) to work even + // when shuffling is enabled. + if (was_queue_empty && shuffle_) { + playlist_.skipTo(shuffle_->current()); + } if (std::holds_alternative(i)) { { @@ -164,7 +186,7 @@ auto TrackQueue::append(Item i) -> void { if (!filename.empty()) { playlist_.append(filename); } - update_shuffler(); + updateShuffler(); } notifyChanged(current_changed, Reason::kExplicitUpdate); } else if (std::holds_alternative(i)) { @@ -191,7 +213,7 @@ auto TrackQueue::append(Item i) -> void { } { const std::unique_lock lock(mutex_); - update_shuffler(); + updateShuffler(); } notifyChanged(current_changed, Reason::kExplicitUpdate); }); @@ -202,6 +224,20 @@ auto TrackQueue::next() -> void { next(Reason::kExplicitUpdate); } +auto TrackQueue::goTo(size_t position) { + position_ = position; + if (opened_playlist_) { + if (position_ < opened_playlist_->size()) { + opened_playlist_->skipTo(position_); + } else { + playlist_.skipTo(position_ - opened_playlist_->size()); + } + } else { + playlist_.skipTo(position_); + } +} + + auto TrackQueue::next(Reason r) -> void { bool changed = true; @@ -209,18 +245,13 @@ auto TrackQueue::next(Reason r) -> void { const std::unique_lock lock(mutex_); if (shuffle_) { shuffle_->next(); - playlist_.skipTo(shuffle_->current()); + position_ = shuffle_->current(); } else { - if (playlist_.atEnd()) { - if (replay_) { - playlist_.skipTo(0); - } else { - changed = false; - } - } else { - playlist_.next(); + if (position_ + 1 < totalSize()) { + position_++; } } + goTo(position_); } notifyChanged(changed, r); @@ -233,18 +264,13 @@ auto TrackQueue::previous() -> void { const std::unique_lock lock(mutex_); if (shuffle_) { shuffle_->prev(); - playlist_.skipTo(shuffle_->current()); + position_ = shuffle_->current(); } else { - if (playlist_.currentPosition() == 0) { - if (repeat_) { - playlist_.skipTo(playlist_.size()-1); - } else { - changed = false; - } - } else { - playlist_.prev(); + if (position_ > 0) { + position_--; } } + goTo(position_); } notifyChanged(changed, Reason::kExplicitUpdate); @@ -262,6 +288,7 @@ auto TrackQueue::clear() -> void { { const std::unique_lock lock(mutex_); playlist_.clear(); + opened_playlist_.reset(); if (shuffle_) { shuffle_->resize(0); } @@ -274,7 +301,7 @@ auto TrackQueue::random(bool en) -> void { { const std::unique_lock lock(mutex_); if (en) { - shuffle_.emplace(playlist_.size()); + shuffle_.emplace(totalSize()); shuffle_->replay(replay_); } else { shuffle_.reset(); @@ -326,7 +353,8 @@ auto TrackQueue::serialise() -> std::string { encoded.add(cppbor::Uint{0}, cppbor::Array{ cppbor::Bool{repeat_}, cppbor::Bool{replay_}, - cppbor::Uint{playlist_.currentPosition()}, + cppbor::Uint{position_}, + cppbor::Tstr{opened_playlist_->filepath()} }); if (shuffle_) { encoded.add(cppbor::Uint{1}, cppbor::Array{ @@ -368,7 +396,10 @@ cppbor::ParseClient* TrackQueue::QueueParseClient::item( i_ = 0; } else if (item->type() == cppbor::UINT) { auto val = item->asUint()->unsignedValue(); - queue_.playlist_.skipTo(val); + queue_.goTo(val); + } else if (item->type() == cppbor::TSTR) { + auto val = item->asTstr(); + queue_.openPlaylist(val->value()); } else if (item->type() == cppbor::SIMPLE) { bool val = item->asBool()->value(); if (i_ == 0) { -- cgit v1.2.3 From 2811a3c899fdb5e4e3ba68a242055b1d43c29446 Mon Sep 17 00:00:00 2001 From: jacqueline Date: Wed, 7 Aug 2024 14:21:28 +1000 Subject: Don't try to serialise a missing playlist name --- src/tangara/audio/track_queue.cpp | 42 ++++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 18 deletions(-) (limited to 'src/tangara/audio/track_queue.cpp') diff --git a/src/tangara/audio/track_queue.cpp b/src/tangara/audio/track_queue.cpp index 399d6717..91bdda39 100644 --- a/src/tangara/audio/track_queue.cpp +++ b/src/tangara/audio/track_queue.cpp @@ -27,8 +27,8 @@ #include "events/event_queue.hpp" #include "memory_resource.hpp" #include "tasks.hpp" -#include "ui/ui_fsm.hpp" #include "track_queue.hpp" +#include "ui/ui_fsm.hpp" namespace audio { @@ -84,7 +84,6 @@ auto notifyChanged(bool current_changed, Reason reason) -> void { events::Audio().Dispatch(ev); } - TrackQueue::TrackQueue(tasks::WorkerPool& bg_worker, database::Handle db) : mutex_(), bg_worker_(bg_worker), @@ -129,8 +128,9 @@ auto TrackQueue::updateShuffler() -> void { } auto TrackQueue::open() -> bool { - // FIX ME: If playlist opening fails, should probably fall back to a vector of tracks or something - // so that we're not necessarily always needing mounted storage + // FIX ME: If playlist opening fails, should probably fall back to a vector of + // tracks or something so that we're not necessarily always needing mounted + // storage return playlist_.open(); } @@ -145,7 +145,8 @@ auto TrackQueue::openPlaylist(const std::string& playlist_file) -> bool { return true; } -auto TrackQueue::getFilepath(database::TrackId id) -> std::optional { +auto TrackQueue::getFilepath(database::TrackId id) + -> std::optional { auto db = db_.lock(); if (!db) { return {}; @@ -153,9 +154,8 @@ auto TrackQueue::getFilepath(database::TrackId id) -> std::optional return db->getTrackPath(id); } - -// TODO WIP: Atm only appends are allowed, this will only ever append regardless of what index -// is given. But it is kept like this for compatability for now. +// TODO WIP: Atm only appends are allowed, this will only ever append regardless +// of what index is given. But it is kept like this for compatability for now. auto TrackQueue::insert(Item i, size_t index) -> void { append(i); } @@ -166,7 +166,7 @@ auto TrackQueue::append(Item i) -> void { { const std::shared_lock lock(mutex_); was_queue_empty = playlist_.currentPosition() >= playlist_.size(); - current_changed = was_queue_empty; // Dont support inserts yet + current_changed = was_queue_empty; // Dont support inserts yet } // If there wasn't anything already playing, then we should make sure we @@ -182,7 +182,7 @@ auto TrackQueue::append(Item i) -> void { if (std::holds_alternative(i)) { { const std::unique_lock lock(mutex_); - auto filename = getFilepath(std::get(i)).value_or(""); + auto filename = getFilepath(std::get(i)).value_or(""); if (!filename.empty()) { playlist_.append(filename); } @@ -204,7 +204,7 @@ auto TrackQueue::append(Item i) -> void { // like current(). { const std::unique_lock lock(mutex_); - auto filename = getFilepath(*next).value_or(""); + auto filename = getFilepath(*next).value_or(""); if (!filename.empty()) { playlist_.append(filename); } @@ -237,7 +237,6 @@ auto TrackQueue::goTo(size_t position) { } } - auto TrackQueue::next(Reason r) -> void { bool changed = true; @@ -350,12 +349,19 @@ auto TrackQueue::replay() const -> bool { auto TrackQueue::serialise() -> std::string { cppbor::Array tracks{}; cppbor::Map encoded; - encoded.add(cppbor::Uint{0}, cppbor::Array{ - cppbor::Bool{repeat_}, - cppbor::Bool{replay_}, - cppbor::Uint{position_}, - cppbor::Tstr{opened_playlist_->filepath()} - }); + + cppbor::Array metadata{ + cppbor::Bool{repeat_}, + cppbor::Bool{replay_}, + cppbor::Uint{position_}, + }; + + if (opened_playlist_) { + metadata.add(cppbor::Tstr{opened_playlist_->filepath()}); + } + + encoded.add(cppbor::Uint{0}, std::move(metadata)); + if (shuffle_) { encoded.add(cppbor::Uint{1}, cppbor::Array{ cppbor::Uint{shuffle_->size()}, -- cgit v1.2.3 From 326cc42a63ec1bd8ff4e62da44658e8facd181c2 Mon Sep 17 00:00:00 2001 From: jacqueline Date: Tue, 13 Aug 2024 16:25:47 +1000 Subject: Don't spuriously report that the current track has changed Fixes the last track in the queue repeating forever --- src/tangara/audio/track_queue.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/tangara/audio/track_queue.cpp') diff --git a/src/tangara/audio/track_queue.cpp b/src/tangara/audio/track_queue.cpp index 91bdda39..5d730a09 100644 --- a/src/tangara/audio/track_queue.cpp +++ b/src/tangara/audio/track_queue.cpp @@ -242,6 +242,8 @@ auto TrackQueue::next(Reason r) -> void { { const std::unique_lock lock(mutex_); + auto pos = position_; + if (shuffle_) { shuffle_->next(); position_ = shuffle_->current(); @@ -250,7 +252,9 @@ auto TrackQueue::next(Reason r) -> void { position_++; } } + goTo(position_); + changed = pos != position_; } notifyChanged(changed, r); -- cgit v1.2.3 From 022aa38396cecb11b9de4b61665a6416378b4a95 Mon Sep 17 00:00:00 2001 From: ailurux Date: Wed, 14 Aug 2024 10:19:26 +1000 Subject: Fix for position persisting when queue reset --- src/tangara/audio/track_queue.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/tangara/audio/track_queue.cpp') diff --git a/src/tangara/audio/track_queue.cpp b/src/tangara/audio/track_queue.cpp index 91bdda39..fb4ff696 100644 --- a/src/tangara/audio/track_queue.cpp +++ b/src/tangara/audio/track_queue.cpp @@ -286,6 +286,7 @@ auto TrackQueue::finish() -> void { auto TrackQueue::clear() -> void { { const std::unique_lock lock(mutex_); + position_ = 0; playlist_.clear(); opened_playlist_.reset(); if (shuffle_) { -- cgit v1.2.3 From 5ab4c2f0d6eda97b73ac789f3d8fd39bd97eeddb Mon Sep 17 00:00:00 2001 From: ailurux Date: Thu, 15 Aug 2024 12:42:57 +1000 Subject: Update position when updating the shuffler --- src/tangara/audio/track_queue.cpp | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) (limited to 'src/tangara/audio/track_queue.cpp') diff --git a/src/tangara/audio/track_queue.cpp b/src/tangara/audio/track_queue.cpp index fb4ff696..51f17a8f 100644 --- a/src/tangara/audio/track_queue.cpp +++ b/src/tangara/audio/track_queue.cpp @@ -121,9 +121,12 @@ auto TrackQueue::totalSize() const -> size_t { return sum; } -auto TrackQueue::updateShuffler() -> void { +auto TrackQueue::updateShuffler(bool andUpdatePosition) -> void { if (shuffle_) { shuffle_->resize(totalSize()); + if (andUpdatePosition) { + goTo(shuffle_->current()); + } } } @@ -140,7 +143,7 @@ auto TrackQueue::openPlaylist(const std::string& playlist_file) -> bool { if (!res) { return false; } - updateShuffler(); + updateShuffler(true); notifyChanged(true, Reason::kExplicitUpdate); return true; } @@ -169,16 +172,6 @@ auto TrackQueue::append(Item i) -> void { current_changed = was_queue_empty; // Dont support inserts yet } - // If there wasn't anything already playing, then we should make sure we - // begin playback at a random point, instead of always starting with - // whatever was inserted first and *then* shuffling. - // We don't base this purely off of current_changed because we would like - // 'play this track now' (by inserting at the current pos) to work even - // when shuffling is enabled. - if (was_queue_empty && shuffle_) { - playlist_.skipTo(shuffle_->current()); - } - if (std::holds_alternative(i)) { { const std::unique_lock lock(mutex_); @@ -186,7 +179,7 @@ auto TrackQueue::append(Item i) -> void { if (!filename.empty()) { playlist_.append(filename); } - updateShuffler(); + updateShuffler(was_queue_empty); } notifyChanged(current_changed, Reason::kExplicitUpdate); } else if (std::holds_alternative(i)) { @@ -213,7 +206,7 @@ auto TrackQueue::append(Item i) -> void { } { const std::unique_lock lock(mutex_); - updateShuffler(); + updateShuffler(was_queue_empty); } notifyChanged(current_changed, Reason::kExplicitUpdate); }); @@ -224,7 +217,7 @@ auto TrackQueue::next() -> void { next(Reason::kExplicitUpdate); } -auto TrackQueue::goTo(size_t position) { +auto TrackQueue::goTo(size_t position) -> void { position_ = position; if (opened_playlist_) { if (position_ < opened_playlist_->size()) { -- cgit v1.2.3 From 978429109ed421a8e49b7a155f3e043247d905b1 Mon Sep 17 00:00:00 2001 From: ailurux Date: Mon, 26 Aug 2024 11:15:27 +1000 Subject: Fix queue serialisation so that the position is correctly applied --- src/tangara/audio/track_queue.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'src/tangara/audio/track_queue.cpp') diff --git a/src/tangara/audio/track_queue.cpp b/src/tangara/audio/track_queue.cpp index ecf33c74..761ea09a 100644 --- a/src/tangara/audio/track_queue.cpp +++ b/src/tangara/audio/track_queue.cpp @@ -137,14 +137,16 @@ auto TrackQueue::open() -> bool { return playlist_.open(); } -auto TrackQueue::openPlaylist(const std::string& playlist_file) -> bool { +auto TrackQueue::openPlaylist(const std::string& playlist_file, bool notify) -> bool { opened_playlist_.emplace(playlist_file); auto res = opened_playlist_->open(); if (!res) { return false; } updateShuffler(true); - notifyChanged(true, Reason::kExplicitUpdate); + if (notify) { + notifyChanged(true, Reason::kExplicitUpdate); + } return true; } @@ -371,7 +373,7 @@ auto TrackQueue::serialise() -> std::string { } TrackQueue::QueueParseClient::QueueParseClient(TrackQueue& queue) - : queue_(queue), state_(State::kInit), i_(0) {} + : queue_(queue), state_(State::kInit), i_(0), position_to_set_(0) {} cppbor::ParseClient* TrackQueue::QueueParseClient::item( std::unique_ptr& item, @@ -400,10 +402,11 @@ cppbor::ParseClient* TrackQueue::QueueParseClient::item( i_ = 0; } else if (item->type() == cppbor::UINT) { auto val = item->asUint()->unsignedValue(); - queue_.goTo(val); + // 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()); + queue_.openPlaylist(val->value(), false); } else if (item->type() == cppbor::SIMPLE) { bool val = item->asBool()->value(); if (i_ == 0) { @@ -448,6 +451,7 @@ cppbor::ParseClient* TrackQueue::QueueParseClient::itemEnd( if (state_ == State::kInit) { state_ = State::kFinished; } else if (state_ == State::kRoot) { + queue_.goTo(position_to_set_); state_ = State::kFinished; } else if (state_ == State::kMetadata) { if (item->type() == cppbor::ARRAY) { -- cgit v1.2.3 From 9ec8d6dafcee6c9722672eefad28ee3aeba4feb9 Mon Sep 17 00:00:00 2001 From: jacqueline Date: Wed, 28 Aug 2024 12:45:10 +1000 Subject: Handle the loading state whilst appending many tracks better 1) Update the queue length periodically so that the user can see we're working 2) Clear any previous track and display "loading..." instead --- src/tangara/audio/track_queue.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'src/tangara/audio/track_queue.cpp') diff --git a/src/tangara/audio/track_queue.cpp b/src/tangara/audio/track_queue.cpp index 761ea09a..4f90e2ea 100644 --- a/src/tangara/audio/track_queue.cpp +++ b/src/tangara/audio/track_queue.cpp @@ -26,6 +26,7 @@ #include "database/track.hpp" #include "events/event_queue.hpp" #include "memory_resource.hpp" +#include "random.hpp" #include "tasks.hpp" #include "track_queue.hpp" #include "ui/ui_fsm.hpp" @@ -190,6 +191,8 @@ auto TrackQueue::append(Item i) -> void { // doesn't block. bg_worker_.Dispatch([=, this]() { database::TrackIterator it = std::get(i); + + size_t next_update_at = 10; while (true) { auto next = *it; if (!next) { @@ -205,7 +208,16 @@ auto TrackQueue::append(Item i) -> void { } } it++; + + // Appending very large iterators can take a while. Send out periodic + // queue updates during them so that the user has an idea what's going + // on. + if (!--next_update_at) { + next_update_at = util::sRandom->RangeInclusive(10, 20); + notifyChanged(false, Reason::kBulkLoadingUpdate); + } } + { const std::unique_lock lock(mutex_); updateShuffler(was_queue_empty); -- cgit v1.2.3 From 32869129fff6a0fc434ab2d9ae30d244c020636b Mon Sep 17 00:00:00 2001 From: jacqueline Date: Wed, 28 Aug 2024 12:46:17 +1000 Subject: clang-format --- src/tangara/audio/track_queue.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/tangara/audio/track_queue.cpp') diff --git a/src/tangara/audio/track_queue.cpp b/src/tangara/audio/track_queue.cpp index 4f90e2ea..6fa5511c 100644 --- a/src/tangara/audio/track_queue.cpp +++ b/src/tangara/audio/track_queue.cpp @@ -138,7 +138,8 @@ auto TrackQueue::open() -> bool { return playlist_.open(); } -auto TrackQueue::openPlaylist(const std::string& playlist_file, bool notify) -> bool { +auto TrackQueue::openPlaylist(const std::string& playlist_file, bool notify) + -> bool { opened_playlist_.emplace(playlist_file); auto res = opened_playlist_->open(); if (!res) { @@ -414,7 +415,8 @@ 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 + // 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(); -- cgit v1.2.3 From af7a70450e3ceaaf291aa09b9383b50b879759d9 Mon Sep 17 00:00:00 2001 From: jacqueline Date: Wed, 28 Aug 2024 15:30:25 +1000 Subject: Support adding filepaths to the track queue --- src/tangara/audio/track_queue.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'src/tangara/audio/track_queue.cpp') diff --git a/src/tangara/audio/track_queue.cpp b/src/tangara/audio/track_queue.cpp index 6fa5511c..cc4770ae 100644 --- a/src/tangara/audio/track_queue.cpp +++ b/src/tangara/audio/track_queue.cpp @@ -161,12 +161,6 @@ auto TrackQueue::getFilepath(database::TrackId id) return db->getTrackPath(id); } -// TODO WIP: Atm only appends are allowed, this will only ever append regardless -// of what index is given. But it is kept like this for compatability for now. -auto TrackQueue::insert(Item i, size_t index) -> void { - append(i); -} - auto TrackQueue::append(Item i) -> void { bool was_queue_empty; bool current_changed; @@ -186,6 +180,16 @@ auto TrackQueue::append(Item i) -> void { updateShuffler(was_queue_empty); } notifyChanged(current_changed, Reason::kExplicitUpdate); + } else if (std::holds_alternative(i)) { + auto& path = std::get(i); + if (!path.empty()) { + { + const std::unique_lock lock(mutex_); + playlist_.append(std::get(i)); + updateShuffler(was_queue_empty); + } + notifyChanged(current_changed, Reason::kExplicitUpdate); + } } else if (std::holds_alternative(i)) { // Iterators can be very large, and retrieving items from them often // requires disk i/o. Handle them asynchronously so that inserting them -- cgit v1.2.3 From 96a224c0df4f647b3e5dbbcbbedad3a1d38470ba Mon Sep 17 00:00:00 2001 From: ailurux Date: Thu, 29 Aug 2024 15:20:22 +1000 Subject: Lua API improvements and fixes Co-authored-by: jacqueline --- src/tangara/audio/track_queue.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'src/tangara/audio/track_queue.cpp') diff --git a/src/tangara/audio/track_queue.cpp b/src/tangara/audio/track_queue.cpp index cc4770ae..2c1faf96 100644 --- a/src/tangara/audio/track_queue.cpp +++ b/src/tangara/audio/track_queue.cpp @@ -236,6 +236,21 @@ auto TrackQueue::next() -> void { next(Reason::kExplicitUpdate); } +auto TrackQueue::currentPosition(size_t position) -> bool { + { + const std::shared_lock lock(mutex_); + if (position >= totalSize()) { + return false; + } + goTo(position); + } + + // If we're explicitly setting the position, we want to treat it as though + // the current track has changed, even if the position was the same + notifyChanged(true, Reason::kExplicitUpdate); + return true; +} + auto TrackQueue::goTo(size_t position) -> void { position_ = position; if (opened_playlist_) { -- cgit v1.2.3