Shared Variables Among different plugins

Memory mapped files with proper synchronization is the best approach.

JUCE’ MemoryMappedFile and InterprocessLock are within the grasp of the average JUCE project.

In a more sophisticated setting, having your own ‘helper agent’ which accepts socket connections from your other plugins might be a fruitful approach as well, albeit with heavier load for the user.

[1] JUCE: MemoryMappedFile Class Reference
[2] JUCE: InterProcessLock Class Reference

#pragma once
#include <juce_core/juce_core.h>

// Manages shared memory for a single float variable
class SharedMemoryManager {
public:
    SharedMemoryManager(const juce::String& memoryName, const juce::String& lockName)
        : memoryName(memoryName), lockName(lockName) {
        // Initialize shared memory (size for one float)
        memoryFile = std::make_unique<juce::MemoryMappedFile>(
            memoryName, sizeof(float), juce::MemoryMappedFile::readWrite);

        // Initialize interprocess lock
        lock = std::make_unique<juce::InterprocessLock>(lockName);

        // Initialize the shared variable if it doesn't exist
        if (memoryFile->getData()) {
            juce::ScopedLock sl(*lock);
            *static_cast<float*>(memoryFile->getData()) = 0.0f; // Default value
        }
    }

    ~SharedMemoryManager() = default;

    bool write(float value) {
        if (!memoryFile->getData())
            return false;

        juce::ScopedLock sl(*lock);
        *static_cast<float*>(memoryFile->getData()) = value;
        return true;
    }

    bool read(float& value) {
        if (!memoryFile->getData())
            return false;

        juce::ScopedLock sl(*lock);
        value = *static_cast<float*>(memoryFile->getData());
        return true;
    }

private:
    juce::String memoryName;
    juce::String lockName;
    std::unique_ptr<juce::MemoryMappedFile> memoryFile;
    std::unique_ptr<juce::InterprocessLock> lock;
};
3 Likes