diff --git a/core/src/signal_path/stream.cpp b/core/src/signal_path/stream.cpp deleted file mode 100644 index b24ba2a9..00000000 --- a/core/src/signal_path/stream.cpp +++ /dev/null @@ -1,135 +0,0 @@ -#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, id); - - // 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(std::make_shared(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::createStream(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::destroyStream(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 index c519d63f..cc92a894 100644 --- a/core/src/signal_path/stream.h +++ b/core/src/signal_path/stream.h @@ -7,6 +7,8 @@ #include #include #include +#include +#include class AudioStream; @@ -22,24 +24,58 @@ private: }; class SinkEntry { + friend AudioStream; + SinkEntry(dsp::stream* stream, const std::string& type, int index); public: - SinkEntry(std::unique_ptr sink); ~SinkEntry(); - float getVolume(); + /** + * Change the type of the sink. + * @param type New sink type. + */ + void setType(const std::string& type); + + /** + * Get sink volume. + * @return Volume as value between 0 and 1. + */ + float getVolume() const; + + /** + * Set sink volume. + * @param volume Volume as value between 0 and 1. + */ void setVolume(float volume); - bool getMuted(); + /** + * Check if the sink is muted. + * @return True if muted, false if not. + */ + bool getMuted() const; + + /** + * Set wether or not the sink is muted + * @param muted True to mute, false to unmute. + */ void setMuted(bool muted); - float getPanning(); + /** + * Get sink panning. + * @return Panning as value between -1 and 1 meaning panning to the left and right respectively. + */ + float getPanning() const; + + /** + * Set sink panning. + * @param panning Panning as value between -1 and 1 meaning panning to the left and right respectively. + */ void setPanning(float panning); + private: - dsp::stream stream; dsp::audio::Volume volumeAdjust; - dsp::multirate::RationalResampler resamp; std::unique_ptr sink; + const int index; float volume = 1.0f; bool muted = false; float panning = 0.0f; @@ -49,8 +85,8 @@ class StreamManager; class AudioStream { friend StreamManager; -public: AudioStream(StreamManager* manager, const std::string& name, dsp::stream* stream, double samplerate); +public: /** * Set DSP stream input. @@ -58,18 +94,17 @@ public: */ void setInput(dsp::stream* stream); + /** + * Set the samplerate of the input stream. + * @param samplerate Samplerate in Hz. + */ + void setSamplerate(double samplerate); + /** * Get the name of the stream. * @return Name of the stream. */ - const std::string& getName(); - - // TODO: Maybe instead we want to resample the data? - void bindStream(dsp::stream* stream); - void unbindStream(dsp::stream* stream); - - double getSamplerate(); - void setSamplerate(double samplerate); + const std::string& getName() const; /** * Add a sink to the stream. @@ -78,33 +113,33 @@ public: */ int addSink(const std::string& type); - /** - * Change the type of a sink. - * @param index Index of the sink. - * @param type New sink type. - */ - void setSinkType(int index, const std::string& type); - /** * Remove a sink from a stream. * @param index Index of the sink. */ void removeSink(int index); + /** + * Aquire a lock for the sink list. + * @return Shared lock for the sink list. + */ + std::shared_lock getSinksLock(); + /** * Get the list of all sinks belonging to this stream. * @return Sink list. */ - const std::vector>& getSinks(); + const std::vector>& getSinks() const; private: - std::recursive_mutex mtx; StreamManager* manager; std::string name; double samplerate; dsp::routing::Splitter split; + std::vector> sinks; + std::shared_mutex sinksMtx; }; class SinkProvider { @@ -114,13 +149,13 @@ public: * @param name Name of the audio stream. * @param index Index of the sink in the menu. Should be use to keep settings. */ - std::unique_ptr createSink(const std::string& name, int index); + virtual std::unique_ptr createSink(dsp::stream* stream, const std::string& name, int index) = 0; /** * Destroy a sink instance. This function is so that the provide knows at all times how many instances there are. * @param sink Instance of the sink. */ - void destroySink(std::unique_ptr sink); + virtual void destroySink(std::unique_ptr sink) = 0; }; class StreamManager { @@ -137,9 +172,23 @@ public: /** * Destroy an audio stream. - * @param name Name of the stream. + * @param stream Stream to destroy. The passed shared pointer will be automatically reset. */ - void destroyStream(const std::string& name); + void destroyStream(std::shared_ptr& stream); + + /** + * Aquire a lock for the stream list. + * @return Shared lock for the stream list. + */ + std::shared_lock getStreamsLock() { + return std::shared_lock(streamsMtx); + } + + /** + * Get a list of streams and their associated names. + * @return Map of names to stream instance. + */ + const std::map>& getStreams() const; /** * Register a sink provider. @@ -152,17 +201,34 @@ public: * Unregister a sink provider. * @param name Name of the sink type. */ - void unregisterSinkProvider(const std::string& name); + void unregisterSinkProvider(SinkProvider* provider); - // TODO: Need a way to lock the list /** - * Get a list of streams and their associated names. - * @return Map of names to stream instance. + * Aquire a lock for the sink type list. + * @return Shared lock for the sink type list. */ - const std::map>& getStreams(); + std::shared_lock getSinkTypesLock(); + + /** + * Get a list of sink types. + * @return List of sink type names. + */ + const std::vector& getSinkTypes() const; + + // Emitted when a stream was created + NewEvent> onStreamCreated; + // Emitted when a stream is about to be destroyed + NewEvent> onStreamDestroy; + // Emitted when a sink provider was registered + NewEvent onSinkProviderRegistered; + // Emitted when a sink provider is about to be unregistered + NewEvent onSinkProviderUnregister; private: - std::recursive_mutex mtx; std::map> streams; + std::shared_mutex streamsMtx; + std::map providers; + std::vector sinkTypes; + std::shared_mutex providersMtx; }; \ No newline at end of file