iPlug2 - C++ Audio Plug-in Framework
Loading...
Searching...
No Matches
IPlugWasmUI.cpp
1/*
2 ==============================================================================
3
4 This file is part of the iPlug 2 library. Copyright (C) the iPlug 2 developers.
5
6 See LICENSE.txt for more info.
7
8 ==============================================================================
9*/
10
11#include "IPlugWasmUI.h"
12
13#include <memory>
14
15#include <emscripten.h>
16#include <emscripten/bind.h>
17
18using namespace iplug;
19using namespace emscripten;
20
21IPlugWasmUI::IPlugWasmUI(const InstanceInfo& info, const Config& config)
22: IPlugAPIBase(config, kAPIWEB)
23{
24 mControllerName.SetFormatted(32, "%s_Hybrid", GetPluginName());
25}
26
27void IPlugWasmUI::SendParameterValueFromUI(int paramIdx, double value)
28{
29 // Send parameter value to DSP via controller
30 EM_ASM({
31 if (typeof window.iPlugController !== 'undefined') {
32 window.iPlugController.setParam($0, $1);
33 } else {
34 console.warn('IPlugWasmUI: controller not ready');
35 }
36 }, paramIdx, value);
37
38 // Call super class to trigger OnParamChangeUI()
39 IPlugAPIBase::SendParameterValueFromUI(paramIdx, value);
40}
41
42void IPlugWasmUI::SendMidiMsgFromUI(const IMidiMsg& msg)
43{
44 EM_ASM({
45 if (typeof window.iPlugController !== 'undefined') {
46 window.iPlugController.sendMidi($0, $1, $2);
47 } else {
48 console.warn('IPlugWasmUI: controller not ready');
49 }
50 }, msg.mStatus, msg.mData1, msg.mData2);
51}
52
53void IPlugWasmUI::SendSysexMsgFromUI(const ISysEx& msg)
54{
55 EM_ASM({
56 if (typeof window.iPlugController !== 'undefined') {
57 var data = new Uint8Array($1);
58 data.set(HEAPU8.subarray($0, $0 + $1));
59 window.iPlugController.sendSysex(data);
60 } else {
61 console.warn('IPlugWasmUI: controller not ready');
62 }
63 }, reinterpret_cast<intptr_t>(msg.mData), msg.mSize);
64}
65
66void IPlugWasmUI::SendArbitraryMsgFromUI(int msgTag, int ctrlTag, int dataSize, const void* pData)
67{
68 if (dataSize > 0 && pData)
69 {
70 EM_ASM({
71 if (typeof window.iPlugController !== 'undefined') {
72 var data = new Uint8Array($2);
73 data.set(HEAPU8.subarray($3, $3 + $2));
74 window.iPlugController.sendArbitraryMsg($0, $1, data);
75 } else {
76 console.warn('IPlugWasmUI: controller not ready');
77 }
78 }, msgTag, ctrlTag, dataSize, reinterpret_cast<intptr_t>(pData));
79 }
80 else
81 {
82 EM_ASM({
83 if (typeof window.iPlugController !== 'undefined') {
84 window.iPlugController.sendArbitraryMsg($0, $1, null);
85 }
86 }, msgTag, ctrlTag);
87 }
88}
89
90void IPlugWasmUI::SendDSPIdleTick()
91{
92 EM_ASM({
93 if (typeof window.iPlugController !== 'undefined') {
94 window.iPlugController.sendIdleTick();
95 }
96 });
97}
98
99// Global instance for Emscripten bindings
100extern std::unique_ptr<iplug::IPlugWasmUI> gPlug;
101
102// Callback functions called by JavaScript controller when DSP sends messages
103static void _SendParameterValueFromDelegate(int paramIdx, double normalizedValue)
104{
105 gPlug->SendParameterValueFromDelegate(paramIdx, normalizedValue, true);
106}
107
108static void _SendControlValueFromDelegate(int ctrlTag, double normalizedValue)
109{
110 gPlug->SendControlValueFromDelegate(ctrlTag, normalizedValue);
111}
112
113static void _SendControlMsgFromDelegate(int ctrlTag, int msgTag, int dataSize, uintptr_t pData)
114{
115 const uint8_t* pDataPtr = reinterpret_cast<uint8_t*>(pData);
116 gPlug->SendControlMsgFromDelegate(ctrlTag, msgTag, dataSize, pDataPtr);
117}
118
119static void _SendArbitraryMsgFromDelegate(int msgTag, int dataSize, uintptr_t pData)
120{
121 const uint8_t* pDataPtr = reinterpret_cast<uint8_t*>(pData);
122 gPlug->SendArbitraryMsgFromDelegate(msgTag, dataSize, pDataPtr);
123}
124
125static void _SendMidiMsgFromDelegate(int status, int data1, int data2)
126{
127 IMidiMsg msg{0, (uint8_t)status, (uint8_t)data1, (uint8_t)data2};
128 gPlug->SendMidiMsgFromDelegate(msg);
129}
130
131static void _SendSysexMsgFromDelegate(int dataSize, uintptr_t pData)
132{
133 const uint8_t* pDataPtr = reinterpret_cast<uint8_t*>(pData);
134 ISysEx msg(0, pDataPtr, dataSize);
135 gPlug->SendSysexMsgFromDelegate(msg);
136}
137
138static void _StartIdleTimer()
139{
140 gPlug->CreateTimer();
141}
142
143static void _OnParentWindowResize(int width, int height)
144{
145 if (gPlug)
146 gPlug->OnParentWindowResize(width, height);
147}
148
149EMSCRIPTEN_BINDINGS(IPlugWasmUI) {
150 function("SPVFD", &_SendParameterValueFromDelegate);
151 function("SCVFD", &_SendControlValueFromDelegate);
152 function("SCMFD", &_SendControlMsgFromDelegate);
153 function("SAMFD", &_SendArbitraryMsgFromDelegate);
154 function("SMMFD", &_SendMidiMsgFromDelegate);
155 function("SSMFD", &_SendSysexMsgFromDelegate);
156 function("StartIdleTimer", &_StartIdleTimer);
157 function("OnParentWindowResize", &_OnParentWindowResize);
158}
The base class of an IPlug plug-in, which interacts with the different plug-in APIs.
Definition: IPlugAPIBase.h:43
Hybrid UI class - IGraphics side for split DSP/UI builds.
Definition: IPlugWasmUI.h:32
Encapsulates a MIDI message and provides helper functions.
Definition: IPlugMidi.h:31
A struct for dealing with SysEx messages.
Definition: IPlugMidi.h:539