diff --git a/core/src/signal_path/stream.cpp b/core/src/signal_path/stream.cpp new file mode 100644 index 00000000..f486bb23 --- /dev/null +++ b/core/src/signal_path/stream.cpp @@ -0,0 +1,136 @@ +#include "stream.h" +#include + +void Sink::showMenu() {} + +SinkEntry::SinkEntry(std::unique_ptr sink) { + this->sink = std::move(sink); +} + +float SinkEntry::getVolume() { + return volume; +} + +void SinkEntry::setVolume(float volume) { + this->volume = volume; + volumeAdjust.setVolume(volume); +} + +bool SinkEntry::getMuted() { + return muted; +} + +void SinkEntry::setMuted(bool muted) { + this->muted = muted; + volumeAdjust.setMuted(muted); +} + +float SinkEntry::getPanning() { + return panning; +} + +void SinkEntry::setPanning(float panning) { + this->panning = panning; + // TODO: Update DSP +} + +AudioStream::AudioStream(StreamManager* manager, const std::string& name, dsp::stream* stream, double samplerate) { + this->manager = manager; + this->name = name; + this->samplerate = samplerate; + + split.init(stream); +} + +void AudioStream::setInput(dsp::stream* stream) { + std::lock_guard lck(mtx); + split.setInput(stream); +} + +const std::string& AudioStream::getName() { + return name; +} + +void AudioStream::bindStream(dsp::stream* stream) { + std::lock_guard lck(mtx); + split.bindStream(stream); +} + +void AudioStream::unbindStream(dsp::stream* stream) { + std::lock_guard lck(mtx); + split.unbindStream(stream); +} + +int AudioStream::addSink(const std::string& type) { + std::lock_guard lck(mtx); + std::lock_guard lck2(manager->mtx); + + // Check that the sink provider is available + if (manager->providers.find(type) == manager->providers.end()) { + flog::error("Could not add sink of type '{}'. No provider is available for such a type.", type); + return -1; + } + + // Create sink instance + int id = sinks.size(); + auto sink = manager->providers[type]->createSink(this); + + // Check that the sink was created succesfully + if (!sink) { + flog::error("Could not create sink of type '{}'. Provider returned null.", type); + return -1; + } + + // Create and save entry + sinks.push_back(SinkEntry(std::move(sink))); + + return id; +} + +void AudioStream::removeSink(int index) { + std::lock_guard lck(mtx); + + // Check that the index exists + if (index >= sinks.size()) { + flog::error("Can't remove sink of index {} from stream '{}'. Index out of range.", index, name); + return; + } + + // TODO: Free stuff + +} + +const std::vector& AudioStream::getSinks() { + return sinks; +} + +std::shared_ptr StreamManager::registerStream(const std::string& name, dsp::stream* stream, double samplerate) { + std::lock_guard lck(mtx); + + // Check that an audio stream that name doesn't already exist + if (streams.find(name) != streams.end()) { + flog::error("Could not register audio stream with name '{}', a stream with this name already exists.", name); + return NULL; + } + + // Create stream and add to list + streams[name] = std::make_shared(this, stream, samplerate); +} + +void StreamManager::unregisterStream(const std::string& name) { + std::lock_guard lck(mtx); + + // Check that stream exists + auto it = streams.find(name); + if (it == streams.end()) { + flog::error("Could not unregister audio stream with name '{}', no stream exists with that name.", name); + return; + } + + // Remove from list + streams.erase(it); +} + +const std::map>& StreamManager::getStreams() { + return streams; +} \ No newline at end of file diff --git a/core/src/signal_path/stream.h b/core/src/signal_path/stream.h new file mode 100644 index 00000000..43b62d22 --- /dev/null +++ b/core/src/signal_path/stream.h @@ -0,0 +1,101 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include + +class AudioStream; + +class Sink { +public: + virtual void start() = 0; + virtual void stop() = 0; + virtual void showMenu(); + +private: + dsp::stream* stream; + AudioStream* audioStream = NULL; +}; + +class SinkEntry { +public: + SinkEntry(std::unique_ptr sink); + + float getVolume(); + void setVolume(float volume); + + bool getMuted(); + void setMuted(bool muted); + + float getPanning(); + void setPanning(float panning); +private: + dsp::audio::Volume volumeAdjust; + dsp::multirate::RationalResampler resamp; + + std::unique_ptr sink; + float volume = 1.0f; + bool muted = false; + float panning = 0.0f; +}; + +class StreamManager; + +class AudioStream { + friend Sink; + friend StreamManager; +public: + AudioStream(StreamManager* manager, const std::string& name, dsp::stream* stream, double samplerate); + + void setInput(dsp::stream* stream); + + const std::string& getName(); + + void bindStream(dsp::stream* stream); + void unbindStream(dsp::stream* stream); + + double getSamplerate(); + void setSamplerate(double samplerate); + + int addSink(const std::string& type); + void setSinkType(int index, const std::string& type); + void removeSink(int index); + const std::vector& getSinks(); + +private: + void setSinkInputSamplerate(Sink* sink, double samplerate); + + std::recursive_mutex mtx; + StreamManager* manager; + std::string name; + double samplerate; + dsp::routing::Splitter split; + std::vector sinks; +}; + +class SinkProvider { +public: + std::unique_ptr createSink(const std::string& name, int index); + void destroySink(std::unique_ptr sink); +}; + +class StreamManager { + friend AudioStream; +public: + std::shared_ptr registerStream(const std::string& name, dsp::stream* stream, double samplerate); + void unregisterStream(const std::string& name); + + void registerSinkProvider(const std::string& name, SinkProvider* provider); + void unregisterSinkProvider(const std::string& name); + + const std::map>& getStreams(); + +private: + std::recursive_mutex mtx; + std::map> streams; + std::map providers; +}; \ No newline at end of file