File size: 3,089 Bytes
1af93a1
 
 
ef91ceb
 
 
1af93a1
ef91ceb
1af93a1
 
 
 
ef91ceb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7e3323d
 
ef91ceb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
242769f
 
ef91ceb
1af93a1
 
ef91ceb
 
1af93a1
ef91ceb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0548359
 
1af93a1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#pragma once

#include <juce_audio_processors/juce_audio_processors.h>
#include <juce_gui_basics/juce_gui_basics.h>
#include <thread>
#include <atomic>

#include "SharedAudioBuffer.h"

class HelperPluginHost
{
public:
    HelperPluginHost();
    ~HelperPluginHost();

    // Plugin lifecycle
    bool loadPlugin(const juce::String& path, double sampleRate, int blockSize);
    void unloadPlugin();
    bool isLoaded() const { return plugin != nullptr; }
    juce::String getPluginName() const;
    int getParameterCount() const;

    // Audio processing (shared memory)
    void setSharedAudio(SharedAudioBuffer* shm, SharedSemaphore* inSem, SharedSemaphore* outSem);
    void startProcessing();
    void stopProcessing();

    // Parameters
    struct ParamInfo {
        int index;
        juce::String id;
        juce::String name;
        float value;
        juce::String displayText;
    };
    std::vector<ParamInfo> searchParams(const juce::String& keyword) const;
    std::vector<std::pair<int, float>> getParams(const std::vector<int>& ids) const;
    bool setParams(const std::map<int, float>& values);

    // GUI via CARemoteLayerServer
    void showGui();
    void hideGui();
    int getGuiWidth() const { return guiWidth; }
    int getGuiHeight() const { return guiHeight; }
    void setLayerPortName(const juce::String& name) { layerPortName = name; }
    juce::String getLayerPortName() const { return layerPortName; }

    // Event injection (from host process)
    void injectMouseDown(float x, float y, int button);
    void injectMouseUp(float x, float y, int button);
    void injectMouseMove(float x, float y);
    void injectMouseDrag(float x, float y, int button);
    void injectMouseScroll(float x, float y, float dx, float dy);
    void injectKeyDown(int keyCode, const juce::String& chars, int modifiers);
    void injectKeyUp(int keyCode, const juce::String& chars, int modifiers);

    // State
    juce::String getStateBase64() const;
    bool setStateBase64(const juce::String& base64State);
    void configure(double sampleRate, int blockSize, int channels);

    // Callbacks
    std::function<void(const juce::String& portName, int width, int height)> onGuiCreated;
    std::function<void(int w, int h)> onGuiResized;

private:
    void audioProcessingLoop();

    juce::AudioPluginFormatManager formatManager;
    std::unique_ptr<juce::AudioPluginInstance> plugin;
    std::unique_ptr<juce::AudioProcessorEditor> editor;

    std::thread audioThread;
    std::atomic<bool> processing{false};

    SharedAudioBuffer* sharedAudio = nullptr;
    SharedSemaphore* inputSem = nullptr;
    SharedSemaphore* outputSem = nullptr;

    double currentSampleRate = 44100.0;
    int currentBlockSize = 512;
    int currentChannels = 2;

    // GUI
    int guiWidth = 0;
    int guiHeight = 0;
    juce::String layerPortName;

    // ObjC objects (stored as void* to avoid ObjC in header)
    void* caContext  = nullptr;   // CAContext* — cross-process layer server
    void* guiWindow  = nullptr;   // NSWindow* — off-screen, ordered-front for compositing
};