summaryrefslogtreecommitdiff
path: root/src/audio/track_queue.cpp
diff options
context:
space:
mode:
authorjacqueline <me@jacqueline.id.au>2023-07-17 16:54:35 +1000
committerjacqueline <me@jacqueline.id.au>2023-07-17 16:54:35 +1000
commit7197da21f6bcc1aaa5d1905228e0e2ec1caf3fa8 (patch)
treef24f81cba08160d45d7e994dc31f48506e823e49 /src/audio/track_queue.cpp
parentb6bc6b9e47605ede9bffe50445d1afe3acf0ab49 (diff)
downloadtangara-fw-7197da21f6bcc1aaa5d1905228e0e2ec1caf3fa8.tar.gz
Basic playlists for upcoming
Beware under-testing and bugs. Just getting something barebones in so that I can do rN+1 bringup
Diffstat (limited to 'src/audio/track_queue.cpp')
-rw-r--r--src/audio/track_queue.cpp168
1 files changed, 113 insertions, 55 deletions
diff --git a/src/audio/track_queue.cpp b/src/audio/track_queue.cpp
index 1c233f8f..0709056f 100644
--- a/src/audio/track_queue.cpp
+++ b/src/audio/track_queue.cpp
@@ -8,10 +8,12 @@
#include <algorithm>
#include <mutex>
+#include <variant>
#include "audio_events.hpp"
#include "audio_fsm.hpp"
#include "event_queue.hpp"
+#include "source.hpp"
#include "track.hpp"
#include "ui_fsm.hpp"
@@ -21,107 +23,163 @@ TrackQueue::TrackQueue() {}
auto TrackQueue::GetCurrent() const -> std::optional<database::TrackId> {
const std::lock_guard<std::mutex> lock(mutex_);
- return current_;
+ if (enqueued_.empty()) {
+ return {};
+ }
+ auto item = enqueued_.front();
+ if (std::holds_alternative<database::TrackId>(item)) {
+ return std::get<database::TrackId>(item);
+ }
+ if (std::holds_alternative<std::shared_ptr<playlist::ISource>>(item)) {
+ return std::get<std::shared_ptr<playlist::ISource>>(item)->Current();
+ }
+ if (std::holds_alternative<std::shared_ptr<playlist::IResetableSource>>(
+ item)) {
+ return std::get<std::shared_ptr<playlist::IResetableSource>>(item)
+ ->Current();
+ }
+ return {};
}
auto TrackQueue::GetUpcoming(std::size_t limit) const
-> std::vector<database::TrackId> {
const std::lock_guard<std::mutex> lock(mutex_);
std::vector<database::TrackId> ret;
- limit = std::min(limit, upcoming_.size());
- std::for_each_n(upcoming_.begin(), limit,
- [&](const auto i) { ret.push_back(i); });
+
+ auto it = enqueued_.begin();
+ if (it == enqueued_.end()) {
+ return ret;
+ }
+
+ // Don't include the current track. This is only relevant to raw track ids,
+ // since sources include multiple tracks.
+ if (std::holds_alternative<database::TrackId>(*it)) {
+ it++;
+ }
+
+ while (limit > 0 && it != enqueued_.end()) {
+ auto item = *it;
+ if (std::holds_alternative<database::TrackId>(item)) {
+ ret.push_back(std::get<database::TrackId>(item));
+ limit--;
+ } else if (std::holds_alternative<std::shared_ptr<playlist::ISource>>(
+ item)) {
+ limit -=
+ std::get<std::shared_ptr<playlist::ISource>>(item)->Peek(limit, &ret);
+ } else if (std::holds_alternative<
+ std::shared_ptr<playlist::IResetableSource>>(item)) {
+ limit -=
+ std::get<std::shared_ptr<playlist::IResetableSource>>(item)->Peek(
+ limit, &ret);
+ }
+ it++;
+ }
+
return ret;
}
auto TrackQueue::AddNext(database::TrackId t) -> void {
const std::lock_guard<std::mutex> lock(mutex_);
- if (!current_) {
- current_ = t;
- } else {
- upcoming_.push_front(t);
- }
+ enqueued_.push_front(t);
+ events::Dispatch<QueueUpdate, AudioState, ui::UiState>({});
+}
+auto TrackQueue::AddNext(std::shared_ptr<playlist::ISource> src) -> void {
+ const std::lock_guard<std::mutex> lock(mutex_);
+ enqueued_.push_front(src);
events::Dispatch<QueueUpdate, AudioState, ui::UiState>({});
}
-auto TrackQueue::AddNext(const std::vector<database::TrackId>& t) -> void {
+auto TrackQueue::IncludeNext(std::shared_ptr<playlist::IResetableSource> src)
+ -> void {
const std::lock_guard<std::mutex> lock(mutex_);
- std::for_each(t.rbegin(), t.rend(),
- [&](const auto i) { upcoming_.push_front(i); });
- if (!current_) {
- current_ = upcoming_.front();
- upcoming_.pop_front();
- }
+ enqueued_.push_front(src);
events::Dispatch<QueueUpdate, AudioState, ui::UiState>({});
}
auto TrackQueue::AddLast(database::TrackId t) -> void {
const std::lock_guard<std::mutex> lock(mutex_);
- if (!current_) {
- current_ = t;
- } else {
- upcoming_.push_back(t);
- }
+ enqueued_.push_back(t);
+ events::Dispatch<QueueUpdate, AudioState, ui::UiState>({});
+}
+auto TrackQueue::AddLast(std::shared_ptr<playlist::ISource> src) -> void {
+ const std::lock_guard<std::mutex> lock(mutex_);
+ enqueued_.push_back(src);
events::Dispatch<QueueUpdate, AudioState, ui::UiState>({});
}
-auto TrackQueue::AddLast(const std::vector<database::TrackId>& t) -> void {
+auto TrackQueue::IncludeLast(std::shared_ptr<playlist::IResetableSource> src)
+ -> void {
const std::lock_guard<std::mutex> lock(mutex_);
- std::for_each(t.begin(), t.end(),
- [&](const auto i) { upcoming_.push_back(i); });
- if (!current_) {
- current_ = upcoming_.front();
- upcoming_.pop_front();
- }
+ enqueued_.push_back(src);
events::Dispatch<QueueUpdate, AudioState, ui::UiState>({});
}
auto TrackQueue::Next() -> void {
const std::lock_guard<std::mutex> lock(mutex_);
- if (current_) {
- played_.push_front(*current_);
+ if (enqueued_.empty()) {
+ return;
+ }
+
+ auto item = enqueued_.front();
+ if (std::holds_alternative<database::TrackId>(item)) {
+ played_.push_front(std::get<database::TrackId>(item));
+ enqueued_.pop_front();
+ }
+ if (std::holds_alternative<std::shared_ptr<playlist::ISource>>(item)) {
+ auto src = std::get<std::shared_ptr<playlist::ISource>>(item);
+ played_.push_front(*src->Current());
+ if (!src->Advance()) {
+ enqueued_.pop_front();
+ }
}
- if (!upcoming_.empty()) {
- current_ = upcoming_.front();
- upcoming_.pop_front();
- } else {
- current_.reset();
+ if (std::holds_alternative<std::shared_ptr<playlist::IResetableSource>>(
+ item)) {
+ auto src = std::get<std::shared_ptr<playlist::IResetableSource>>(item);
+ if (!src->Advance()) {
+ played_.push_back(src);
+ enqueued_.pop_front();
+ }
}
+
events::Dispatch<QueueUpdate, AudioState, ui::UiState>({});
}
auto TrackQueue::Previous() -> void {
const std::lock_guard<std::mutex> lock(mutex_);
- if (current_) {
- upcoming_.push_front(*current_);
+ if (!enqueued_.empty() &&
+ std::holds_alternative<std::shared_ptr<playlist::IResetableSource>>(
+ enqueued_.front())) {
+ auto src = std::get<std::shared_ptr<playlist::IResetableSource>>(
+ enqueued_.front());
+ if (src->Previous()) {
+ events::Dispatch<QueueUpdate, AudioState, ui::UiState>({});
+ return;
+ }
+ }
+
+ if (played_.empty()) {
+ return;
}
- if (!played_.empty()) {
- current_ = played_.front();
- played_.pop_front();
- } else {
- current_.reset();
+
+ auto item = played_.front();
+ if (std::holds_alternative<database::TrackId>(item)) {
+ enqueued_.push_front(std::get<database::TrackId>(item));
+ } else if (std::holds_alternative<
+ std::shared_ptr<playlist::IResetableSource>>(item)) {
+ enqueued_.push_front(
+ std::get<std::shared_ptr<playlist::IResetableSource>>(item));
}
+ played_.pop_front();
+
events::Dispatch<QueueUpdate, AudioState, ui::UiState>({});
}
auto TrackQueue::Clear() -> void {
const std::lock_guard<std::mutex> lock(mutex_);
played_.clear();
- upcoming_.clear();
- current_.reset();
- events::Dispatch<QueueUpdate, AudioState, ui::UiState>({});
-}
-
-auto TrackQueue::RemoveUpcoming(database::TrackId t) -> void {
- const std::lock_guard<std::mutex> lock(mutex_);
- for (auto it = upcoming_.begin(); it != upcoming_.end(); it++) {
- if (*it == t) {
- upcoming_.erase(it);
- return;
- }
- }
+ enqueued_.clear();
events::Dispatch<QueueUpdate, AudioState, ui::UiState>({});
}