Skip to content

Commit

Permalink
Relay graph events to webview
Browse files Browse the repository at this point in the history
  • Loading branch information
nick-thompson committed Jan 14, 2024
1 parent 0705128 commit 8a4b430
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 0 deletions.
28 changes: 28 additions & 0 deletions native/LambdaTimer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#pragma once

#include <juce_core/juce_core.h>


//==============================================================================
// A small helper class for invoking a lambda periodically
// via juce::Timer
template <typename Fn>
class LambdaTimer : public juce::Timer {
public:
LambdaTimer(int rate, Fn&& f) : callback(std::move(f)) {
startTimerHz(rate);
}

~LambdaTimer() {
stopTimer();
}

void timerCallback() override {
if (callback) {
callback();
}
}

private:
Fn callback;
};
34 changes: 34 additions & 0 deletions native/PluginProcessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,11 @@ void EffectsPluginProcessor::handleAsyncUpdate()
// TODO: This is definitely not thread-safe! It could delete a Runtime instance while
// the real-time thread is using it. Depends on when the host will call prepareToPlay.
runtime = std::make_unique<elem::Runtime<float>>(lastKnownSampleRate, lastKnownBlockSize);

eventsTimer = std::make_unique<LambdaTimer<std::function<void()>>>(60, [this]() {
dispatchGraphEvents();
});

initJavaScriptEngine();
}

Expand Down Expand Up @@ -371,6 +376,35 @@ void EffectsPluginProcessor::dispatchStateChange()
jsContext.evaluate(expr);
}

void EffectsPluginProcessor::dispatchGraphEvents()
{
const auto* kDispatchScript = R"script(
(function() {
if (typeof globalThis.__receiveGraphEvents__ !== 'function')
return false;
globalThis.__receiveGraphEvents__(%);
return true;
})();
)script";

if (runtime) {
elem::js::Array batch;

runtime->processQueuedEvents([this, &batch](std::string const& type, elem::js::Value evt) {
batch.push_back(elem::js::Object({
{"type", type},
{"event", evt}
}));
});

if (auto* editor = static_cast<WebViewEditor*>(getActiveEditor())) {
auto expr = juce::String(kDispatchScript).replace("%", elem::js::serialize(elem::js::serialize(batch))).toStdString();
editor->getWebViewPtr()->evaluateJavascript(expr);
}
}
}

void EffectsPluginProcessor::dispatchError(std::string const& name, std::string const& message)
{
const auto* kDispatchScript = R"script(
Expand Down
4 changes: 4 additions & 0 deletions native/PluginProcessor.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
#include <choc_javascript.h>
#include <elem/Runtime.h>

#include "LambdaTimer.h"


//==============================================================================
class EffectsPluginProcessor
Expand Down Expand Up @@ -64,6 +66,7 @@ class EffectsPluginProcessor

/** Internal helper for propagating processor state changes. */
void dispatchStateChange();
void dispatchGraphEvents();
void dispatchError(std::string const& name, std::string const& message);

private:
Expand All @@ -78,6 +81,7 @@ class EffectsPluginProcessor
juce::AudioBuffer<float> scratchBuffer;

std::unique_ptr<elem::Runtime<float>> runtime;
std::unique_ptr<LambdaTimer<std::function<void()>>> eventsTimer;

//==============================================================================
// A simple "dirty list" abstraction here for propagating realtime parameter
Expand Down
4 changes: 4 additions & 0 deletions src/main.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ globalThis.__receiveStateChange__ = function(state) {
store.setState(JSON.parse(state));
};

globalThis.__receiveGraphEvents__ = function(eventBatch) {
console.log(JSON.parse(eventBatch));
};

globalThis.__receiveError__ = (err) => {
errorStore.setState({ error: err });
};
Expand Down

0 comments on commit 8a4b430

Please sign in to comment.