Mema
Memory Matrix — multi-channel audio matrix monitor and router
Loading...
Searching...
No Matches
MemaProcessor.h
Go to the documentation of this file.
1/* Copyright (c) 2024, Christian Ahrens
2 *
3 * This file is part of Mema <https://github.com/ChristianAhrens/Mema>
4 *
5 * This tool is free software; you can redistribute it and/or modify it under
6 * the terms of the GNU Lesser General Public License version 3.0 as published
7 * by the Free Software Foundation.
8 *
9 * This tool is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12 * details.
13 *
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with this tool; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
19#pragma once
20
21#include <JuceHeader.h>
22
23#include "MemaMessages.h"
26#include "../MemaProcessorEditor/MemaProcessorEditor.h"
27#include "../MemaAppConfiguration.h"
28
29#include <ServiceTopologyManager.h>
30
31
32namespace Mema
33{
34
35class InterprocessConnectionImpl;
36class InterprocessConnectionServerImpl;
37class MemaChannelCommander;
38class MemaInputCommander;
39class MemaOutputCommander;
40class MemaCrosspointCommander;
41class MemaPluginCommander;
42class MemaNetworkClientCommanderWrapper;
43
44
45//==============================================================================
54class ResizeableWindowWithTitleBarAndCloseCallback : public juce::ResizableWindow
55{
56public:
57 ResizeableWindowWithTitleBarAndCloseCallback() : juce::ResizableWindow("", false) {};
58 ResizeableWindowWithTitleBarAndCloseCallback(const String& name, bool addToDesktop) : juce::ResizableWindow(name, addToDesktop) {};
60
61 //==============================================================================
62 int getDesktopWindowStyleFlags() const override
63 {
64 int styleFlags = juce::ComponentPeer::windowAppearsOnTaskbar
65 | juce::ComponentPeer::windowHasDropShadow
66 | juce::ComponentPeer::windowHasTitleBar
67 | juce::ComponentPeer::windowHasCloseButton;
68
69 return styleFlags;
70 }
71
72 void userTriedToCloseWindow() override
73 {
74 if (onClosed)
75 onClosed();
76 };
77
78 //==============================================================================
79 std::function<void()> onClosed;
80};
81
82//==============================================================================
91class PluginParameterInfosChangedMessage : public juce::Message
92{
93public:
96};
97
150class MemaProcessor : public juce::AudioProcessor,
151 public juce::AudioIODeviceCallback,
152 public juce::MessageListener,
153 public juce::ChangeListener,
154 public juce::AudioProcessorParameter::Listener,
155 public MemaAppConfiguration::XmlConfigurableElement
156{
157public:
163 MemaProcessor(XmlElement* stateXml);
165
166 //==============================================================================
181
182 //==============================================================================
187 void addInputCommander(MemaInputCommander* commander);
197
207
217
227
229 void updateCommanders();
230
231 //==============================================================================
237 bool getInputMuteState(std::uint16_t channelNumber);
246 void setInputMuteState(std::uint16_t channelNumber, bool muted, MemaChannelCommander* sender = nullptr, int userId = -1);
247
254 bool getMatrixCrosspointEnabledValue(std::uint16_t inputNumber, std::uint16_t outputNumber);
263 void setMatrixCrosspointEnabledValue(std::uint16_t inputNumber, std::uint16_t outputNumber, bool enabled, MemaChannelCommander* sender = nullptr, int userId = -1);
264
271 float getMatrixCrosspointFactorValue(std::uint16_t inputNumber, std::uint16_t outputNumber);
280 void setMatrixCrosspointFactorValue(std::uint16_t inputNumber, std::uint16_t outputNumber, float factor, MemaChannelCommander* sender = nullptr, int userId = -1);
281
287 float getPluginParameterValue(std::uint16_t pluginParameterIndex) const;
296 void setPluginParameterValue(std::uint16_t pluginParameterIndex, std::string id, float normalizedValue, MemaPluginCommander* sender = nullptr, int userId = -1);
297
303 bool getOutputMuteState(std::uint16_t channelNumber);
311 void setOutputMuteState(std::uint16_t channelNumber, bool muted, MemaChannelCommander* sender = nullptr, int userId = -1);
312
321 void setChannelCounts(std::uint16_t inputChannelCount, std::uint16_t outputChannelCount);
322
323 //==============================================================================
332 bool setPlugin(const juce::PluginDescription& pluginDescription);
334 juce::PluginDescription getPluginDescription();
336 void setPluginEnabledState(bool enabled);
338 bool isPluginEnabled();
343 void setPluginPrePostState(bool post);
345 bool isPluginPost();
347 void clearPlugin();
349 void openPluginEditor();
351 void closePluginEditor(bool deleteEditorWindow = true);
352 std::function<void(const juce::PluginDescription&)> onPluginSet;
353 // Parameter management
355 std::vector<PluginParameterInfo>& getPluginParameterInfos();
363 void setPluginParameterRemoteControlInfos(int pluginParameterIndex, bool remoteControllable, ParameterControlType type, int steps);
365 bool isPluginParameterRemoteControllable(int parameterIndex);
367 juce::AudioProcessorParameter* getPluginParameter(int parameterIndex) const;
368 std::function<void(int pluginParameterIndex, float newValue)> onPluginParameterChanged;
369 std::function<void()> onPluginParameterInfosChanged;
370
371 //==============================================================================
373 AudioDeviceManager* getDeviceManager();
374
375 //==============================================================================
381 std::map<int, std::pair<double, bool>> getNetworkHealth();
382
383 //==============================================================================
385 JUCEAppBasics::SessionServiceTopology getDiscoveredServicesTopology();
386
387 //==============================================================================
389 const String getName() const override;
397 void prepareToPlay(double sampleRate, int maximumExpectedSamplesPerBlock) override;
399 void releaseResources() override;
406 void processBlock(AudioBuffer<float>& buffer, MidiBuffer& midiMessages) override;
407
408 double getTailLengthSeconds() const override;
409 bool acceptsMidi() const override;
410 bool producesMidi() const override;
411
412 AudioProcessorEditor* createEditor() override;
413 bool hasEditor() const override;
414
415 int getNumPrograms() override;
416 int getCurrentProgram() override;
417 void setCurrentProgram(int index) override;
418 const String getProgramName(int index) override;
419 void changeProgramName(int index, const String& newName) override;
420
421 void getStateInformation(juce::MemoryBlock& destData) override;
422 void setStateInformation(const void* data, int sizeInBytes) override;
423
424 //==============================================================================
439 void audioDeviceIOCallbackWithContext(const float* const* inputChannelData,
440 int numInputChannels,
441 float* const* outputChannelData,
442 int numOutputChannels,
443 int numSamples,
444 const AudioIODeviceCallbackContext& context) override;
445
451 void audioDeviceAboutToStart(AudioIODevice* device) override;
453 void audioDeviceStopped() override;
454
455 //==============================================================================
457 void changeListenerCallback(ChangeBroadcaster* source) override;
458
459 //==============================================================================
468 void handleMessage(const Message& message) override;
469
470 //==============================================================================
478 void parameterValueChanged(int parameterIndex, float newValue) override;
480 void parameterGestureChanged(int parameterIndex, bool gestureIsStarting) override;
481
482 //==============================================================================
484 std::unique_ptr<XmlElement> createStateXml() override;
486 bool setStateXml(XmlElement* stateXml) override;
487
488 //==============================================================================
490 void environmentChanged();
491
498 void triggerIOUpdate();
499
500 //==============================================================================
509 void setTrafficTypesForConnectionId(const std::vector<SerializableMessage::SerializableMessageType>& trafficTypes, int connectionId);
510
511 //==============================================================================
512 static constexpr int s_maxChannelCount = 64;
513 static constexpr int s_maxNumSamples = 1024;
514
515 static constexpr int s_minInputsCount = 1;
516 static constexpr int s_minOutputsCount = 1;
517
518 //==============================================================================
520 bool isTimedConfigurationDumpPending() { return m_timedConfigurationDumpPending; };
522 void setTimedConfigurationDumpPending() { m_timedConfigurationDumpPending = true; };
524 void resetTimedConfigurationDumpPending() { m_timedConfigurationDumpPending = false; };
525
526 //==============================================================================
529
530protected:
531 //==============================================================================
532 void initializeCtrlValues(int inputCount, int outputCount);
533 void initializeCtrlValuesToUnity(int inputCount, int outputCount);
534
535private:
536 //==============================================================================
537 void sendMessageToClients(const MemoryBlock& messageMemoryBlock, const std::vector<int>& sendIds);
538
539 //==============================================================================
540 juce::String m_Name;
541
542 //==============================================================================
543 juce::CriticalSection m_audioDeviceIOCallbackLock;
544
545 float** m_processorChannels;
546
547 //==============================================================================
548 std::unique_ptr<AudioDeviceManager> m_deviceManager;
549
550 //==============================================================================
551 std::unique_ptr<ProcessorDataAnalyzer> m_inputDataAnalyzer;
552 std::unique_ptr<ProcessorDataAnalyzer> m_outputDataAnalyzer;
553
554 //==============================================================================
555 std::vector<MemaInputCommander*> m_inputCommanders;
556 std::vector<MemaOutputCommander*> m_outputCommanders;
557 std::vector<MemaCrosspointCommander*> m_crosspointCommanders;
558 std::vector<MemaPluginCommander*> m_pluginCommanders;
559
560 //==============================================================================
561 std::map<std::uint16_t, bool> m_inputMuteStates;
562 std::map<std::uint16_t, bool> m_outputMuteStates;
563
564 //==============================================================================
565 int m_inputChannelCount{ 1 };
566 int m_outputChannelCount{ 1 };
567
568 //==============================================================================
569 std::map<std::uint16_t, std::map<std::uint16_t, bool>> m_matrixCrosspointStates;
570 std::map<std::uint16_t, std::map<std::uint16_t, float>> m_matrixCrosspointValues;
571
572 //==============================================================================
573 std::unique_ptr<MemaProcessorEditor> m_processorEditor;
574
575 //==============================================================================
576 juce::CriticalSection m_pluginProcessingLock;
577 std::unique_ptr<juce::AudioPluginInstance> m_pluginInstance;
578 bool m_pluginEnabled = false;
579 bool m_pluginPost = false;
580 std::unique_ptr<ResizeableWindowWithTitleBarAndCloseCallback> m_pluginEditorWindow;
581 std::vector<PluginParameterInfo> m_pluginParameterInfos;
582
583 //==============================================================================
584 std::unique_ptr<JUCEAppBasics::ServiceTopologyManager> m_serviceTopologyManager;
585 std::shared_ptr<InterprocessConnectionServerImpl> m_networkServer;
586 std::unique_ptr<MemaNetworkClientCommanderWrapper> m_networkCommanderWrapper;
587 std::map<int, std::vector<SerializableMessage::SerializableMessageType>> m_trafficTypesPerConnection;
588
589 std::unique_ptr<juce::TimedCallback> m_timedConfigurationDumper;
590 bool m_timedConfigurationDumpPending = false;
591
592 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MemaProcessor)
593};
594
595} // namespace Mema
Core audio processor — owns the AudioDeviceManager, routing matrix, plugin host, and IPC server.
bool getOutputMuteState(std::uint16_t channelNumber)
Returns the mute state of a specific output channel.
bool acceptsMidi() const override
void openPluginEditor()
Opens (or raises) the plugin's editor UI in a floating ResizeableWindowWithTitleBarAndCloseCallback w...
std::function< void(const juce::PluginDescription &)> onPluginSet
Invoked on the message thread after a new plugin has been successfully loaded.
void addOutputCommander(MemaOutputCommander *commander)
Adds an output commander and immediately pushes the current mute states to it.
static constexpr int s_maxChannelCount
Maximum number of input or output channels supported by the routing matrix.
void changeListenerCallback(ChangeBroadcaster *source) override
Receives notifications from the AudioDeviceManager when the device configuration changes.
bool isTimedConfigurationDumpPending()
Returns true when a deferred XML configuration dump has been scheduled.
void initializePluginCommander(MemaPluginCommander *commander)
Pushes the current plugin parameter descriptors and values to an already-registered commander.
void setTrafficTypesForConnectionId(const std::vector< SerializableMessage::SerializableMessageType > &trafficTypes, int connectionId)
Updates the set of message types a specific TCP client has subscribed to receive.
void audioDeviceIOCallbackWithContext(const float *const *inputChannelData, int numInputChannels, float *const *outputChannelData, int numOutputChannels, int numSamples, const AudioIODeviceCallbackContext &context) override
Hot audio callback — implements the complete Mema signal chain.
void clearPlugin()
Unloads the hosted plugin, closes its editor window, and resets all plugin commander state.
double getTailLengthSeconds() const override
juce::PluginDescription getPluginDescription()
Returns the JUCE description of the currently loaded plugin.
bool getMatrixCrosspointEnabledValue(std::uint16_t inputNumber, std::uint16_t outputNumber)
Returns whether a specific crosspoint node is enabled (routing active).
void setMatrixCrosspointFactorValue(std::uint16_t inputNumber, std::uint16_t outputNumber, float factor, MemaChannelCommander *sender=nullptr, int userId=-1)
Sets the linear gain factor of a crosspoint node.
void initializeCtrlValuesToUnity()
Resets all crosspoint gains to 1.0 (unity) and enables all crosspoints. Used when creating a default ...
bool hasEditor() const override
void setCurrentProgram(int index) override
static constexpr int s_maxNumSamples
Maximum audio block size in samples.
void setInputMuteState(std::uint16_t channelNumber, bool muted, MemaChannelCommander *sender=nullptr, int userId=-1)
Sets the mute state of an input channel and notifies all commanders except the sender.
AudioDeviceManager * getDeviceManager()
Returns a raw pointer to the JUCE AudioDeviceManager. Used by the audio-setup UI component.
int getNumPrograms() override
bool producesMidi() const override
void setOutputMuteState(std::uint16_t channelNumber, bool muted, MemaChannelCommander *sender=nullptr, int userId=-1)
Sets the mute state of an output channel and notifies all commanders except the sender.
void addOutputListener(ProcessorDataAnalyzer::Listener *listener)
Registers a listener to receive output-channel level/spectrum data from the output analyzer.
void parameterValueChanged(int parameterIndex, float newValue) override
Called by the hosted plugin when a parameter value changes.
void removeInputCommander(MemaInputCommander *commander)
Removes a previously registered input commander.
std::function< void(int pluginParameterIndex, float newValue)> onPluginParameterChanged
Fired (on the message thread) when a hosted plugin parameter value changes; receives the zero-based i...
bool setStateXml(XmlElement *stateXml) override
Restores the processor state from a previously serialised <PROCESSORCONFIG> XmlElement.
juce::AudioProcessorParameter * getPluginParameter(int parameterIndex) const
Returns a pointer to the underlying JUCE AudioProcessorParameter at the given index.
bool isPluginPost()
Returns true when the plugin is inserted post-matrix.
void setPluginEnabledState(bool enabled)
Enables or disables plugin processing without unloading the plugin instance.
void updateCommanders()
Forces all registered commanders to re-synchronise with the current processor state.
void addInputCommander(MemaInputCommander *commander)
Adds an input commander and immediately pushes the current mute states to it.
bool getInputMuteState(std::uint16_t channelNumber)
Returns the mute state of a specific input channel.
std::map< int, std::pair< double, bool > > getNetworkHealth()
Returns per-client network health metrics.
void setStateInformation(const void *data, int sizeInBytes) override
int getCurrentProgram() override
void handleMessage(const Message &message) override
Dispatches JUCE messages posted to the message thread.
void setTimedConfigurationDumpPending()
Schedules a deferred XML configuration dump (called on state change to avoid excessive disk I/O).
JUCEAppBasics::SessionServiceTopology getDiscoveredServicesTopology()
Returns the most recent multicast service topology snapshot from ServiceTopologyManager.
void changeProgramName(int index, const String &newName) override
void resetTimedConfigurationDumpPending()
Clears the deferred dump flag after the dump has been performed.
void setPluginParameterValue(std::uint16_t pluginParameterIndex, std::string id, float normalizedValue, MemaPluginCommander *sender=nullptr, int userId=-1)
Sets a hosted plugin parameter to a normalised value.
void addInputListener(ProcessorDataAnalyzer::Listener *listener)
Registers a listener to receive input-channel level/spectrum data from the input analyzer.
void audioDeviceAboutToStart(AudioIODevice *device) override
Called when the audio device is about to start streaming.
void setChannelCounts(std::uint16_t inputChannelCount, std::uint16_t outputChannelCount)
Resizes all internal routing structures for a new input/output channel count.
void initializeCrosspointCommander(MemaCrosspointCommander *commander)
Pushes the current crosspoint enable/gain matrix to an already-registered commander.
float getMatrixCrosspointFactorValue(std::uint16_t inputNumber, std::uint16_t outputNumber)
Returns the linear gain factor of a crosspoint node.
void closePluginEditor(bool deleteEditorWindow=true)
Closes the plugin editor window.
void initializeCtrlValues(int inputCount, int outputCount)
void removePluginCommander(MemaPluginCommander *commander)
Removes a previously registered plugin commander.
float getPluginParameterValue(std::uint16_t pluginParameterIndex) const
Returns the current normalised value of a hosted plugin parameter.
void addPluginCommander(MemaPluginCommander *commander)
Adds a plugin commander and immediately pushes the current parameter infos and values.
void environmentChanged()
Called when the OS look-and-feel or palette changes; broadcasts EnvironmentParametersMessage to all c...
bool setPlugin(const juce::PluginDescription &pluginDescription)
Loads and instantiates a plugin from the given description.
void addCrosspointCommander(MemaCrosspointCommander *commander)
Adds a crosspoint commander and immediately pushes the full crosspoint state to it.
std::unique_ptr< XmlElement > createStateXml() override
Serialises the current processor state (mutes, crosspoints, plugin settings) to XML.
void getStateInformation(juce::MemoryBlock &destData) override
void initializeOutputCommander(MemaOutputCommander *commander)
Pushes the current output mute states to an already-registered commander.
static constexpr int s_minOutputsCount
Minimum number of output channels (always at least 1).
void parameterGestureChanged(int parameterIndex, bool gestureIsStarting) override
Called by the hosted plugin when a gesture (e.g. mouse drag) starts or ends.
bool isPluginParameterRemoteControllable(int parameterIndex)
Returns true if the given parameter is flagged as remotely controllable.
std::vector< PluginParameterInfo > & getPluginParameterInfos()
Returns a mutable reference to the loaded plugin's parameter descriptor list.
void triggerIOUpdate()
Forces a full re-broadcast of device parameters and routing state to all connected clients.
void prepareToPlay(double sampleRate, int maximumExpectedSamplesPerBlock) override
Called by the JUCE audio engine before playback starts.
const String getProgramName(int index) override
const String getName() const override
Returns the processor name ("Mema").
void releaseResources() override
Called when playback stops; releases audio processing resources.
void audioDeviceStopped() override
Called when the audio device stops; notifies analyzers to clear their state.
void setPluginParameterRemoteControlInfos(int pluginParameterIndex, bool remoteControllable, ParameterControlType type, int steps)
Marks a plugin parameter as remotely controllable (or not) and sets its control widget type.
void removeOutputCommander(MemaOutputCommander *comander)
Removes a previously registered output commander.
void processBlock(AudioBuffer< float > &buffer, MidiBuffer &midiMessages) override
Standard JUCE AudioProcessor entry point — not used for live audio.
void removeOutputListener(ProcessorDataAnalyzer::Listener *listener)
Unregisters a previously added output analyzer listener.
static constexpr int s_minInputsCount
Minimum number of input channels (always at least 1).
void setMatrixCrosspointEnabledValue(std::uint16_t inputNumber, std::uint16_t outputNumber, bool enabled, MemaChannelCommander *sender=nullptr, int userId=-1)
Enables or disables a crosspoint routing node.
AudioProcessorEditor * createEditor() override
std::function< void()> onPluginParameterInfosChanged
Fired when the set of exposed plugin parameters changes (plugin load/unload or controllability settin...
bool isPluginEnabled()
Returns true when a plugin is loaded and its processing is enabled.
void removeInputListener(ProcessorDataAnalyzer::Listener *listener)
Unregisters a previously added input analyzer listener.
void setPluginPrePostState(bool post)
Selects whether the plugin processes audio before or after the crosspoint matrix.
void initializeInputCommander(MemaInputCommander *commander)
Pushes the current input mute states to a commander that was already registered.
void removeCrosspointCommander(MemaCrosspointCommander *comander)
Removes a previously registered crosspoint commander.
Internal JUCE message posted to the message thread when plugin parameter descriptors change.
virtual ~PluginParameterInfosChangedMessage()=default
A resizable JUCE window with a title bar and close button that fires a callback on close.
ResizeableWindowWithTitleBarAndCloseCallback(const String &name, bool addToDesktop)
std::function< void()> onClosed
Invoked when the window is closed by the user or programmatically.
Definition Mema.cpp:27