summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author2 * r + 2 * t <61896496+soramanew@users.noreply.github.com>2025-09-09 16:31:02 +1000
committer2 * r + 2 * t <61896496+soramanew@users.noreply.github.com>2025-09-09 16:31:02 +1000
commit6ae1a8e811f72bda251f8718fb148fcb6853bcc4 (patch)
tree4b4018628c9cc32a7f43a4a0d17b091eb852db2c
parentnix: fix build error with libcava (#585) (diff)
downloadcaelestia-shell-6ae1a8e811f72bda251f8718fb148fcb6853bcc4.tar.gz
caelestia-shell-6ae1a8e811f72bda251f8718fb148fcb6853bcc4.tar.bz2
caelestia-shell-6ae1a8e811f72bda251f8718fb148fcb6853bcc4.zip
plugin/ac: not singleton
Also add nodeId prop BeatTracker not singleton Move BeatTracker and Cava to Audio service
-rw-r--r--modules/background/Visualiser.qml4
-rw-r--r--modules/dashboard/Media.qml9
-rw-r--r--modules/dashboard/dash/Media.qml5
-rw-r--r--plugin/src/Caelestia/audiocollector.cpp56
-rw-r--r--plugin/src/Caelestia/audiocollector.hpp28
-rw-r--r--plugin/src/Caelestia/audioprovider.cpp59
-rw-r--r--plugin/src/Caelestia/audioprovider.hpp18
-rw-r--r--plugin/src/Caelestia/beattracker.cpp50
-rw-r--r--plugin/src/Caelestia/beattracker.hpp7
-rw-r--r--plugin/src/Caelestia/cavaprovider.cpp54
-rw-r--r--plugin/src/Caelestia/cavaprovider.hpp6
-rw-r--r--services/Audio.qml21
-rw-r--r--services/Cava.qml18
13 files changed, 241 insertions, 94 deletions
diff --git a/modules/background/Visualiser.qml b/modules/background/Visualiser.qml
index a8ada1e..ad726cc 100644
--- a/modules/background/Visualiser.qml
+++ b/modules/background/Visualiser.qml
@@ -16,7 +16,7 @@ Item {
required property Wallpaper wallpaper
ServiceRef {
- service: Cava.provider
+ service: Audio.cava
}
MultiEffect {
@@ -65,7 +65,7 @@ Item {
id: bar
required property int modelData
- property real value: Math.max(0, Math.min(1, Cava.values[side.isRight ? modelData : side.count - modelData - 1]))
+ property real value: Math.max(0, Math.min(1, Audio.cava.values[side.isRight ? modelData : side.count - modelData - 1]))
clip: true
diff --git a/modules/dashboard/Media.qml b/modules/dashboard/Media.qml
index 9d61eb5..163d271 100644
--- a/modules/dashboard/Media.qml
+++ b/modules/dashboard/Media.qml
@@ -2,7 +2,6 @@ pragma ComponentBehavior: Bound
import qs.components
import qs.components.effects
-import qs.components.misc
import qs.components.controls
import qs.services
import qs.utils
@@ -56,11 +55,11 @@ Item {
}
ServiceRef {
- service: Cava.provider
+ service: Audio.cava
}
ServiceRef {
- service: BeatTracker
+ service: Audio.beatTracker
}
Shape {
@@ -91,7 +90,7 @@ Item {
id: visualiserBar
required property int modelData
- readonly property real value: Math.max(1e-3, Math.min(1, Cava.values[modelData]))
+ readonly property real value: Math.max(1e-3, Math.min(1, Audio.cava.values[modelData]))
readonly property real angle: modelData * 2 * Math.PI / Config.services.visualiserBars
readonly property real magnitude: value * Config.dashboard.sizes.mediaVisualiserSize
@@ -530,7 +529,7 @@ Item {
height: visualiser.height * 0.75
playing: Players.active?.isPlaying ?? false
- speed: BeatTracker.bpm / 300
+ speed: Audio.beatTracker.bpm / 300
source: Paths.absolutePath(Config.paths.mediaGif)
asynchronous: true
fillMode: AnimatedImage.PreserveAspectFit
diff --git a/modules/dashboard/dash/Media.qml b/modules/dashboard/dash/Media.qml
index f3fbdbe..d4cccc8 100644
--- a/modules/dashboard/dash/Media.qml
+++ b/modules/dashboard/dash/Media.qml
@@ -1,5 +1,4 @@
import qs.components
-import qs.components.misc
import qs.services
import qs.config
import qs.utils
@@ -34,7 +33,7 @@ Item {
}
ServiceRef {
- service: BeatTracker
+ service: Audio.beatTracker
}
Shape {
@@ -214,7 +213,7 @@ Item {
anchors.margins: Appearance.padding.large * 2
playing: Players.active?.isPlaying ?? false
- speed: BeatTracker.bpm / 300
+ speed: Audio.beatTracker.bpm / 300
source: Paths.absolutePath(Config.paths.mediaGif)
asynchronous: true
fillMode: AnimatedImage.PreserveAspectFit
diff --git a/plugin/src/Caelestia/audiocollector.cpp b/plugin/src/Caelestia/audiocollector.cpp
index b9dfc23..04d609c 100644
--- a/plugin/src/Caelestia/audiocollector.cpp
+++ b/plugin/src/Caelestia/audiocollector.cpp
@@ -3,9 +3,9 @@
#include "service.hpp"
#include <algorithm>
#include <cstdint>
-#include <mutex>
#include <pipewire/pipewire.h>
#include <qdebug.h>
+#include <qmutex.h>
#include <spa/param/audio/format-utils.h>
#include <spa/param/latency-utils.h>
#include <stop_token>
@@ -25,6 +25,7 @@ PipeWireWorker::PipeWireWorker(std::stop_token token, AudioCollector* collector)
m_loop = pw_main_loop_new(nullptr);
if (!m_loop) {
qWarning() << "PipeWireWorker::init: failed to create PipeWire main loop";
+ pw_deinit();
return;
}
@@ -66,10 +67,17 @@ PipeWireWorker::PipeWireWorker(std::stop_token token, AudioCollector* collector)
m_stream = pw_stream_new_simple(pw_main_loop_get_loop(m_loop), "caelestia-shell", props, &events, this);
- pw_stream_connect(m_stream, PW_DIRECTION_INPUT, PW_ID_ANY,
+ const int success = pw_stream_connect(m_stream, PW_DIRECTION_INPUT, collector->nodeId(),
static_cast<pw_stream_flags>(
PW_STREAM_FLAG_AUTOCONNECT | PW_STREAM_FLAG_MAP_BUFFERS | PW_STREAM_FLAG_RT_PROCESS),
params, 1);
+ if (success < 0) {
+ qWarning() << "PipeWireWorker::init: failed to connect stream";
+ pw_stream_destroy(m_stream);
+ pw_main_loop_destroy(m_loop);
+ pw_deinit();
+ return;
+ }
pw_main_loop_run(m_loop);
@@ -155,27 +163,20 @@ unsigned int PipeWireWorker::nextPowerOf2(unsigned int n) {
return n;
}
-AudioCollector::AudioCollector(uint32_t sampleRate, uint32_t chunkSize, QObject* parent)
+AudioCollector::AudioCollector(QObject* parent)
: Service(parent)
- , m_buffer1(chunkSize)
- , m_buffer2(chunkSize)
+ , m_sampleRate(44100)
+ , m_chunkSize(512)
+ , m_nodeId(PW_ID_ANY)
+ , m_buffer1(m_chunkSize)
+ , m_buffer2(m_chunkSize)
, m_readBuffer(&m_buffer1)
- , m_writeBuffer(&m_buffer2)
- , m_sampleRate(sampleRate)
- , m_chunkSize(chunkSize) {}
+ , m_writeBuffer(&m_buffer2) {}
AudioCollector::~AudioCollector() {
stop();
}
-AudioCollector* AudioCollector::instance() {
- std::lock_guard<std::mutex> lock(s_mutex);
- if (s_instance == nullptr) {
- s_instance = new AudioCollector();
- }
- return s_instance;
-}
-
uint32_t AudioCollector::sampleRate() const {
return m_sampleRate;
}
@@ -184,6 +185,29 @@ uint32_t AudioCollector::chunkSize() const {
return m_chunkSize;
}
+uint32_t AudioCollector::nodeId() {
+ QMutexLocker locker(&m_nodeIdMutex);
+ return m_nodeId;
+}
+
+void AudioCollector::setNodeId(uint32_t nodeId) {
+ {
+ QMutexLocker locker(&m_nodeIdMutex);
+
+ if (nodeId == m_nodeId) {
+ return;
+ }
+
+ m_nodeId = nodeId;
+ }
+ emit nodeIdChanged();
+
+ if (m_thread.joinable()) {
+ stop();
+ start();
+ }
+}
+
void AudioCollector::clearBuffer() {
auto* writeBuffer = m_writeBuffer.load(std::memory_order_relaxed);
std::fill(writeBuffer->begin(), writeBuffer->end(), 0.0f);
diff --git a/plugin/src/Caelestia/audiocollector.hpp b/plugin/src/Caelestia/audiocollector.hpp
index 283b758..ecfae09 100644
--- a/plugin/src/Caelestia/audiocollector.hpp
+++ b/plugin/src/Caelestia/audiocollector.hpp
@@ -3,8 +3,9 @@
#include "service.hpp"
#include <atomic>
#include <cstdint>
-#include <mutex>
#include <pipewire/pipewire.h>
+#include <qmutex.h>
+#include <qqmlintegration.h>
#include <spa/param/audio/format-utils.h>
#include <stop_token>
#include <thread>
@@ -41,24 +42,35 @@ private:
class AudioCollector : public Service {
Q_OBJECT
+ QML_ELEMENT
+
+ Q_PROPERTY(uint32_t nodeId READ nodeId WRITE setNodeId NOTIFY nodeIdChanged)
public:
- explicit AudioCollector(uint32_t sampleRate = 44100, uint32_t chunkSize = 512, QObject* parent = nullptr);
+ explicit AudioCollector(QObject* parent = nullptr);
~AudioCollector();
- static AudioCollector* instance();
-
[[nodiscard]] uint32_t sampleRate() const;
[[nodiscard]] uint32_t chunkSize() const;
+ [[nodiscard]] uint32_t nodeId();
+ void setNodeId(uint32_t nodeId);
+
void clearBuffer();
void loadChunk(const int16_t* samples, uint32_t count);
uint32_t readChunk(float* out, uint32_t count = 0);
uint32_t readChunk(double* out, uint32_t count = 0);
+signals:
+ void sampleRateChanged();
+ void chunkSizeChanged();
+ void nodeIdChanged();
+
private:
- inline static AudioCollector* s_instance = nullptr;
- inline static std::mutex s_mutex;
+ const uint32_t m_sampleRate;
+ const uint32_t m_chunkSize;
+ uint32_t m_nodeId;
+ QMutex m_nodeIdMutex;
std::jthread m_thread;
std::vector<float> m_buffer1;
@@ -67,9 +79,7 @@ private:
std::atomic<std::vector<float>*> m_writeBuffer;
uint32_t m_sampleCount;
- const uint32_t m_sampleRate;
- const uint32_t m_chunkSize;
-
+ void reload();
void start() override;
void stop() override;
};
diff --git a/plugin/src/Caelestia/audioprovider.cpp b/plugin/src/Caelestia/audioprovider.cpp
index 4188460..f31480e 100644
--- a/plugin/src/Caelestia/audioprovider.cpp
+++ b/plugin/src/Caelestia/audioprovider.cpp
@@ -7,10 +7,9 @@
namespace caelestia {
-AudioProcessor::AudioProcessor(QObject* parent)
+AudioProcessor::AudioProcessor(AudioCollector* collector, QObject* parent)
: QObject(parent)
- , m_sampleRate(AudioCollector::instance()->sampleRate())
- , m_chunkSize(AudioCollector::instance()->chunkSize()) {}
+ , m_collector(collector) {}
AudioProcessor::~AudioProcessor() {
stop();
@@ -18,26 +17,53 @@ AudioProcessor::~AudioProcessor() {
void AudioProcessor::init() {
m_timer = new QTimer(this);
- m_timer->setInterval(static_cast<int>(m_chunkSize * 1000.0 / m_sampleRate));
+ if (m_collector) {
+ m_timer->setInterval(static_cast<int>(m_collector->chunkSize() * 1000.0 / m_collector->sampleRate()));
+ }
connect(m_timer, &QTimer::timeout, this, &AudioProcessor::process);
}
-void AudioProcessor::start() {
- AudioCollector::instance()->ref();
+void AudioProcessor::setCollector(AudioCollector* collector) {
+ if (m_collector == collector) {
+ return;
+ }
+
if (m_timer) {
+ if (m_timer->isActive()) {
+ if (m_collector) {
+ m_collector->unref();
+ }
+ if (collector) {
+ collector->ref();
+ }
+ }
+ if (collector) {
+ m_timer->setInterval(static_cast<int>(collector->chunkSize() * 1000.0 / collector->sampleRate()));
+ } else {
+ m_timer->stop();
+ }
+ }
+
+ m_collector = collector;
+}
+
+void AudioProcessor::start() {
+ if (m_timer && m_collector) {
+ m_collector->ref();
m_timer->start();
}
}
void AudioProcessor::stop() {
- if (m_timer) {
+ if (m_timer && m_collector) {
m_timer->stop();
+ m_collector->unref();
}
- AudioCollector::instance()->unref();
}
AudioProvider::AudioProvider(QObject* parent)
: Service(parent)
+ , m_collector(nullptr)
, m_processor(nullptr)
, m_thread(nullptr) {}
@@ -48,6 +74,23 @@ AudioProvider::~AudioProvider() {
}
}
+AudioCollector* AudioProvider::collector() const {
+ return m_collector;
+}
+
+void AudioProvider::setCollector(AudioCollector* collector) {
+ if (m_collector == collector) {
+ return;
+ }
+
+ m_collector = collector;
+ emit collectorChanged();
+
+ if (m_processor) {
+ QMetaObject::invokeMethod(m_processor, "setCollector", Qt::QueuedConnection, Q_ARG(AudioCollector*, collector));
+ }
+}
+
void AudioProvider::init() {
if (!m_processor) {
qWarning() << "AudioProvider::init: attempted to init with no processor set";
diff --git a/plugin/src/Caelestia/audioprovider.hpp b/plugin/src/Caelestia/audioprovider.hpp
index aa7fb83..c92b965 100644
--- a/plugin/src/Caelestia/audioprovider.hpp
+++ b/plugin/src/Caelestia/audioprovider.hpp
@@ -1,7 +1,7 @@
#pragma once
+#include "audiocollector.hpp"
#include "service.hpp"
-#include <cstdint>
#include <qqmlintegration.h>
#include <qtimer.h>
@@ -11,14 +11,15 @@ class AudioProcessor : public QObject {
Q_OBJECT
public:
- explicit AudioProcessor(QObject* parent = nullptr);
+ explicit AudioProcessor(AudioCollector* collector, QObject* parent = nullptr);
~AudioProcessor();
void init();
protected:
- uint32_t m_sampleRate;
- uint32_t m_chunkSize;
+ AudioCollector* m_collector;
+
+ Q_INVOKABLE virtual void setCollector(AudioCollector* collector);
private:
QTimer* m_timer;
@@ -32,11 +33,20 @@ private:
class AudioProvider : public Service {
Q_OBJECT
+ Q_PROPERTY(AudioCollector* collector READ collector WRITE setCollector NOTIFY collectorChanged)
+
public:
explicit AudioProvider(QObject* parent = nullptr);
~AudioProvider();
+ AudioCollector* collector() const;
+ void setCollector(AudioCollector* collector);
+
+signals:
+ void collectorChanged();
+
protected:
+ AudioCollector* m_collector;
AudioProcessor* m_processor;
void init();
diff --git a/plugin/src/Caelestia/beattracker.cpp b/plugin/src/Caelestia/beattracker.cpp
index a23d052..501739f 100644
--- a/plugin/src/Caelestia/beattracker.cpp
+++ b/plugin/src/Caelestia/beattracker.cpp
@@ -6,20 +6,52 @@
namespace caelestia {
-BeatProcessor::BeatProcessor(QObject* parent)
- : AudioProcessor(parent)
- , m_tempo(new_aubio_tempo("default", 1024, m_chunkSize, m_sampleRate))
- , m_in(new_fvec(m_chunkSize))
- , m_out(new_fvec(2)) {};
+BeatProcessor::BeatProcessor(AudioCollector* collector, QObject* parent)
+ : AudioProcessor(collector, parent)
+ , m_tempo(nullptr)
+ , m_in(nullptr)
+ , m_out(new_fvec(2)) {
+ if (collector) {
+ m_tempo = new_aubio_tempo("default", 1024, collector->chunkSize(), collector->sampleRate());
+ m_in = new_fvec(collector->chunkSize());
+ }
+};
BeatProcessor::~BeatProcessor() {
- del_aubio_tempo(m_tempo);
- del_fvec(m_in);
+ if (m_tempo) {
+ del_aubio_tempo(m_tempo);
+ }
+ if (m_in) {
+ del_fvec(m_in);
+ }
del_fvec(m_out);
}
+void BeatProcessor::setCollector(AudioCollector* collector) {
+ AudioProcessor::setCollector(collector);
+
+ if (m_tempo) {
+ del_aubio_tempo(m_tempo);
+ }
+ if (m_in) {
+ del_fvec(m_in);
+ }
+
+ if (collector) {
+ m_tempo = new_aubio_tempo("default", 1024, collector->chunkSize(), collector->sampleRate());
+ m_in = new_fvec(collector->chunkSize());
+ } else {
+ m_tempo = nullptr;
+ m_in = nullptr;
+ }
+}
+
void BeatProcessor::process() {
- AudioCollector::instance()->readChunk(m_in->data, m_chunkSize);
+ if (!m_collector || !m_tempo || !m_in) {
+ return;
+ }
+
+ m_collector->readChunk(m_in->data);
aubio_tempo_do(m_tempo, m_in, m_out);
if (m_out->data[0] != 0.0f) {
@@ -30,7 +62,7 @@ void BeatProcessor::process() {
BeatTracker::BeatTracker(QObject* parent)
: AudioProvider(parent)
, m_bpm(120) {
- m_processor = new BeatProcessor();
+ m_processor = new BeatProcessor(m_collector);
init();
connect(static_cast<BeatProcessor*>(m_processor), &BeatProcessor::beat, this, &BeatTracker::updateBpm);
diff --git a/plugin/src/Caelestia/beattracker.hpp b/plugin/src/Caelestia/beattracker.hpp
index c7737e1..ab18373 100644
--- a/plugin/src/Caelestia/beattracker.hpp
+++ b/plugin/src/Caelestia/beattracker.hpp
@@ -1,5 +1,6 @@
#pragma once
+#include "audiocollector.hpp"
#include "audioprovider.hpp"
#include <aubio/aubio.h>
#include <qqmlintegration.h>
@@ -10,12 +11,15 @@ class BeatProcessor : public AudioProcessor {
Q_OBJECT
public:
- explicit BeatProcessor(QObject* parent = nullptr);
+ explicit BeatProcessor(AudioCollector* collector, QObject* parent = nullptr);
~BeatProcessor();
signals:
void beat(smpl_t bpm);
+protected:
+ void setCollector(AudioCollector* collector) override;
+
private:
aubio_tempo_t* m_tempo;
fvec_t* m_in;
@@ -27,7 +31,6 @@ private:
class BeatTracker : public AudioProvider {
Q_OBJECT
QML_ELEMENT
- QML_SINGLETON
Q_PROPERTY(smpl_t bpm READ bpm NOTIFY bpmChanged)
diff --git a/plugin/src/Caelestia/cavaprovider.cpp b/plugin/src/Caelestia/cavaprovider.cpp
index d053702..76a1a10 100644
--- a/plugin/src/Caelestia/cavaprovider.cpp
+++ b/plugin/src/Caelestia/cavaprovider.cpp
@@ -9,16 +9,38 @@
namespace caelestia {
-CavaProcessor::CavaProcessor(QObject* parent)
- : AudioProcessor(parent)
+CavaProcessor::CavaProcessor(AudioCollector* collector, QObject* parent)
+ : AudioProcessor(collector, parent)
, m_plan(nullptr)
- , m_in(new double[static_cast<size_t>(m_chunkSize)])
+ , m_in(nullptr)
, m_out(nullptr)
- , m_bars(0) {};
+ , m_bars(0) {
+ if (collector) {
+ m_in = new double[collector->chunkSize()];
+ }
+};
CavaProcessor::~CavaProcessor() {
cleanup();
- delete[] m_in;
+ if (m_in) {
+ delete[] m_in;
+ }
+}
+
+void CavaProcessor::setCollector(AudioCollector* collector) {
+ AudioProcessor::setCollector(collector);
+
+ if (m_in) {
+ delete[] m_in;
+ }
+
+ if (collector) {
+ m_in = new double[collector->chunkSize()];
+ } else {
+ m_in = nullptr;
+ }
+
+ reload();
}
void CavaProcessor::setBars(int bars) {
@@ -39,13 +61,11 @@ void CavaProcessor::reload() {
}
void CavaProcessor::cleanup() {
- if (!m_plan) {
- return;
+ if (m_plan) {
+ cava_destroy(m_plan);
+ m_plan = nullptr;
}
- cava_destroy(m_plan);
- m_plan = nullptr;
-
if (m_out) {
delete[] m_out;
m_out = nullptr;
@@ -53,11 +73,11 @@ void CavaProcessor::cleanup() {
}
void CavaProcessor::initCava() {
- if (m_plan || m_bars == 0) {
+ if (m_plan || m_bars == 0 || !m_collector) {
return;
}
- m_plan = cava_init(m_bars, static_cast<unsigned int>(m_sampleRate), 1, 1, 0.85, 50, 10000);
+ m_plan = cava_init(m_bars, m_collector->sampleRate(), 1, 1, 0.85, 50, 10000);
if (m_plan->status == -1) {
qWarning() << "CavaProcessor::initCava: failed to initialise cava plan";
@@ -69,11 +89,11 @@ void CavaProcessor::initCava() {
}
void CavaProcessor::process() {
- if (!m_plan || m_bars == 0) {
+ if (!m_plan || m_bars == 0 || !m_collector || !m_in || !m_out) {
return;
}
- const int count = static_cast<int>(AudioCollector::instance()->readChunk(m_in));
+ const int count = static_cast<int>(m_collector->readChunk(m_in));
// Process in data via cava
cava_execute(m_in, count, m_out, m_plan);
@@ -100,8 +120,8 @@ void CavaProcessor::process() {
CavaProvider::CavaProvider(QObject* parent)
: AudioProvider(parent)
, m_bars(0)
- , m_values(m_bars) {
- m_processor = new CavaProcessor();
+ , m_values(m_bars, 0.0) {
+ m_processor = new CavaProcessor(m_collector);
init();
connect(static_cast<CavaProcessor*>(m_processor), &CavaProcessor::valuesChanged, this, &CavaProvider::updateValues);
@@ -121,7 +141,7 @@ void CavaProvider::setBars(int bars) {
return;
}
- m_values.resize(bars);
+ m_values.resize(bars, 0.0);
m_bars = bars;
emit barsChanged();
emit valuesChanged();
diff --git a/plugin/src/Caelestia/cavaprovider.hpp b/plugin/src/Caelestia/cavaprovider.hpp
index 131e166..6dab635 100644
--- a/plugin/src/Caelestia/cavaprovider.hpp
+++ b/plugin/src/Caelestia/cavaprovider.hpp
@@ -1,5 +1,6 @@
#pragma once
+#include "audiocollector.hpp"
#include "audioprovider.hpp"
#include <cava/cavacore.h>
#include <qqmlintegration.h>
@@ -10,12 +11,15 @@ class CavaProcessor : public AudioProcessor {
Q_OBJECT
public:
- explicit CavaProcessor(QObject* parent = nullptr);
+ explicit CavaProcessor(AudioCollector* collector, QObject* parent = nullptr);
~CavaProcessor();
signals:
void valuesChanged(QVector<double> values);
+protected:
+ void setCollector(AudioCollector* collector) override;
+
private:
struct cava_plan* m_plan;
double* m_in;
diff --git a/services/Audio.qml b/services/Audio.qml
index a0475d0..e638af5 100644
--- a/services/Audio.qml
+++ b/services/Audio.qml
@@ -1,6 +1,7 @@
pragma Singleton
import qs.config
+import Caelestia
import Quickshell
import Quickshell.Services.Pipewire
@@ -32,6 +33,9 @@ Singleton {
readonly property bool sourceMuted: !!source?.audio?.muted
readonly property real sourceVolume: source?.audio?.volume ?? 0
+ readonly property alias cava: cava
+ readonly property alias beatTracker: beatTracker
+
function setVolume(newVolume: real): void {
if (sink?.ready && sink?.audio) {
sink.audio.muted = false;
@@ -73,4 +77,21 @@ Singleton {
PwObjectTracker {
objects: [...root.sinks, ...root.sources]
}
+
+ AudioCollector {
+ id: collector
+ }
+
+ CavaProvider {
+ id: cava
+
+ collector: collector
+ bars: Config.services.visualiserBars
+ }
+
+ BeatTracker {
+ id: beatTracker
+
+ collector: collector
+ }
}
diff --git a/services/Cava.qml b/services/Cava.qml
deleted file mode 100644
index 3291bcd..0000000
--- a/services/Cava.qml
+++ /dev/null
@@ -1,18 +0,0 @@
-pragma Singleton
-
-import qs.config
-import Caelestia
-import Quickshell
-
-Singleton {
- id: root
-
- readonly property alias provider: provider
- readonly property alias values: provider.values
-
- CavaProvider {
- id: provider
-
- bars: Config.services.visualiserBars
- }
-}