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);
369 void setPluginParameterDisplayOrder(const std::vector<int>& order);
371 const std::vector<int>& getPluginParameterDisplayOrder() const;
373 bool isPluginParameterRemoteControllable(int parameterIndex);
375 juce::AudioProcessorParameter* getPluginParameter(int parameterIndex) const;
376 std::function<void(int pluginParameterIndex, float newValue)> onPluginParameterChanged;
377 std::function<void()> onPluginParameterInfosChanged;
378 std::function<void(bool enabled, bool post)> onPluginProcessingStateChanged;
379
380 //==============================================================================
382 AudioDeviceManager* getDeviceManager();
383
384 //==============================================================================
390 std::map<int, std::pair<double, bool>> getNetworkHealth();
391
392 //==============================================================================
394 JUCEAppBasics::SessionServiceTopology getDiscoveredServicesTopology();
395
396 //==============================================================================
398 const String getName() const override;
406 void prepareToPlay(double sampleRate, int maximumExpectedSamplesPerBlock) override;
408 void releaseResources() override;
415 void processBlock(AudioBuffer<float>& buffer, MidiBuffer& midiMessages) override;
416
417 double getTailLengthSeconds() const override;
418 bool acceptsMidi() const override;
419 bool producesMidi() const override;
420
421 AudioProcessorEditor* createEditor() override;
422 bool hasEditor() const override;
423
424 int getNumPrograms() override;
425 int getCurrentProgram() override;
426 void setCurrentProgram(int index) override;
427 const String getProgramName(int index) override;
428 void changeProgramName(int index, const String& newName) override;
429
430 void getStateInformation(juce::MemoryBlock& destData) override;
431 void setStateInformation(const void* data, int sizeInBytes) override;
432
433 //==============================================================================
448 void audioDeviceIOCallbackWithContext(const float* const* inputChannelData,
449 int numInputChannels,
450 float* const* outputChannelData,
451 int numOutputChannels,
452 int numSamples,
453 const AudioIODeviceCallbackContext& context) override;
454
460 void audioDeviceAboutToStart(AudioIODevice* device) override;
462 void audioDeviceStopped() override;
463
464 //==============================================================================
466 void changeListenerCallback(ChangeBroadcaster* source) override;
467
468 //==============================================================================
477 void handleMessage(const Message& message) override;
478
479 //==============================================================================
487 void parameterValueChanged(int parameterIndex, float newValue) override;
489 void parameterGestureChanged(int parameterIndex, bool gestureIsStarting) override;
490
491 //==============================================================================
493 std::unique_ptr<XmlElement> createStateXml() override;
495 bool setStateXml(XmlElement* stateXml) override;
496
497 //==============================================================================
499 void environmentChanged();
500
507 void triggerIOUpdate();
508
509 //==============================================================================
518 void setTrafficTypesForConnectionId(const std::vector<SerializableMessage::SerializableMessageType>& trafficTypes, int connectionId);
519
520 //==============================================================================
521 static constexpr int s_maxChannelCount = 64;
522 static constexpr int s_maxNumSamples = 1024;
523
524 static constexpr int s_minInputsCount = 1;
525 static constexpr int s_minOutputsCount = 1;
526
527 //==============================================================================
529 bool isTimedConfigurationDumpPending() { return m_timedConfigurationDumpPending; };
531 void setTimedConfigurationDumpPending() { m_timedConfigurationDumpPending = true; };
533 void resetTimedConfigurationDumpPending() { m_timedConfigurationDumpPending = false; };
534
535 //==============================================================================
538
539protected:
540 //==============================================================================
541 void initializeCtrlValues(int inputCount, int outputCount);
542 void initializeCtrlValuesToUnity(int inputCount, int outputCount);
543
544private:
545 //==============================================================================
546 void sendMessageToClients(const MemoryBlock& messageMemoryBlock, const std::vector<int>& sendIds);
547
548 //==============================================================================
556 void configurePluginForCurrentPosition();
557
558 //==============================================================================
559 juce::String m_Name;
560
561 //==============================================================================
562 juce::CriticalSection m_audioDeviceIOCallbackLock;
563
564 float** m_processorChannels;
565
566 //==============================================================================
567 std::unique_ptr<AudioDeviceManager> m_deviceManager;
568
569 //==============================================================================
570 std::unique_ptr<ProcessorDataAnalyzer> m_inputDataAnalyzer;
571 std::unique_ptr<ProcessorDataAnalyzer> m_outputDataAnalyzer;
572
573 //==============================================================================
574 std::vector<MemaInputCommander*> m_inputCommanders;
575 std::vector<MemaOutputCommander*> m_outputCommanders;
576 std::vector<MemaCrosspointCommander*> m_crosspointCommanders;
577 std::vector<MemaPluginCommander*> m_pluginCommanders;
578
579 //==============================================================================
580 std::map<std::uint16_t, bool> m_inputMuteStates;
581 std::map<std::uint16_t, bool> m_outputMuteStates;
582
583 //==============================================================================
584 int m_inputChannelCount{ 1 };
585 int m_outputChannelCount{ 1 };
586
587 //==============================================================================
588 std::map<std::uint16_t, std::map<std::uint16_t, bool>> m_matrixCrosspointStates;
589 std::map<std::uint16_t, std::map<std::uint16_t, float>> m_matrixCrosspointValues;
590
591 //==============================================================================
592 std::unique_ptr<MemaProcessorEditor> m_processorEditor;
593
594 //==============================================================================
595 juce::CriticalSection m_pluginProcessingLock;
596 std::unique_ptr<juce::AudioPluginInstance> m_pluginInstance;
597 bool m_pluginEnabled = false;
598 bool m_pluginPost = false;
599 int m_pluginConfiguredChannelCount{ 0 };
600 std::unique_ptr<ResizeableWindowWithTitleBarAndCloseCallback> m_pluginEditorWindow;
601 std::vector<PluginParameterInfo> m_pluginParameterInfos;
602 std::vector<int> m_pluginParameterDisplayOrder;
603
604 //==============================================================================
605 std::unique_ptr<juce::XmlElement> m_lastAppliedDeviceConfigXml;
606
607 //==============================================================================
608 std::unique_ptr<JUCEAppBasics::ServiceTopologyManager> m_serviceTopologyManager;
609 std::shared_ptr<InterprocessConnectionServerImpl> m_networkServer;
610 std::unique_ptr<MemaNetworkClientCommanderWrapper> m_networkCommanderWrapper;
611 std::map<int, std::vector<SerializableMessage::SerializableMessageType>> m_trafficTypesPerConnection;
612
613 std::unique_ptr<juce::TimedCallback> m_timedConfigurationDumper;
614 bool m_timedConfigurationDumpPending = false;
615
616 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MemaProcessor)
617};
618
619} // 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 setPluginParameterDisplayOrder(const std::vector< int > &order)
Sets the display order in which plugin parameters are presented to Mema.Re clients.
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.
std::function< void(bool enabled, bool post)> onPluginProcessingStateChanged
Fired when the plugin enabled or pre/post state changes externally (e.g. from a Mema....
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.
const std::vector< int > & getPluginParameterDisplayOrder() const
Returns the current display order vector, or an empty vector if none has been set.
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.