iPlug2 - C++ Audio Plug-in Framework
Loading...
Searching...
No Matches
IPlugWeb.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 "IPlugWeb.h"
12
13#include <memory>
14
15#include <emscripten.h>
16#include <emscripten/bind.h>
17
18using namespace iplug;
19using namespace emscripten;
20
21static const int kNumMsgHeaderBytes = 6;
22static const int kNumSPVFUIBytes = 18;
23static const int kNumSMMFUIBytes = 9;
24static const int kNumSSMFUIBytes = 10; // + data size
25static const int kNumSAMFUIBytes = 18; // + data size
26
27IPlugWeb::IPlugWeb(const InstanceInfo& info, const Config& config)
28: IPlugAPIBase(config, kAPIWEB)
29{
30 mSPVFUIBuf.Resize(kNumSPVFUIBytes); memcpy(mSPVFUIBuf.GetData(), "SPVFUI", kNumMsgHeaderBytes);
31 mSMMFUIBuf.Resize(kNumSMMFUIBytes); memcpy(mSMMFUIBuf.GetData(), "SMMFUI", kNumMsgHeaderBytes);
32 mSSMFUIBuf.Resize(kNumSSMFUIBytes); memcpy(mSSMFUIBuf.GetData(), "SSMFUI", kNumMsgHeaderBytes);
33 mSAMFUIBuf.Resize(kNumSAMFUIBytes); memcpy(mSAMFUIBuf.GetData(), "SAMFUI", kNumMsgHeaderBytes);
34
35 mWAMCtrlrJSObjectName.SetFormatted(32, "%s_WAM", GetPluginName());
36}
37
38void IPlugWeb::SendParameterValueFromUI(int paramIdx, double value)
39{
40#if WEBSOCKET_CLIENT
41 int pos = kNumMsgHeaderBytes;
42 *((int*)(mSPVFUIBuf.GetData() + pos)) = paramIdx; pos += sizeof(int);
43 *((double*)(mSPVFUIBuf.GetData() + pos)) = value; pos += sizeof(double);
44
45 EM_ASM({
46 var jsbuff = Module.HEAPU8.subarray($0, $0 + $1);
47 ws.send(jsbuff);
48 }, (int) mSPVFUIBuf.GetData(), kNumSPVFUIBytes);
49
50#else
51 val::global(mWAMCtrlrJSObjectName.Get()).call<void>("setParam", paramIdx, value);
52#endif
53 IPlugAPIBase::SendParameterValueFromUI(paramIdx, value); // call super class in order to make sure OnParamChangeUI() gets triggered
54};
55
56void IPlugWeb::SendMidiMsgFromUI(const IMidiMsg& msg)
57{
58#if WEBSOCKET_CLIENT
59 int pos = kNumMsgHeaderBytes;
60 mSMMFUIBuf.GetData()[pos] = msg.mStatus; pos++;
61 mSMMFUIBuf.GetData()[pos] = msg.mData1; pos++;
62 mSMMFUIBuf.GetData()[pos] = msg.mData2; pos++;
63
64 EM_ASM({
65 var jsbuff = Module.HEAPU8.subarray($0, $0 + $1);
66 ws.send(jsbuff);
67 }, (int) mSMMFUIBuf.GetData(), kNumSMMFUIBytes);
68
69#else
70 WDL_String dataStr;
71 dataStr.SetFormatted(16, "%i:%i:%i", msg.mStatus, msg.mData1, msg.mData2);
72 val::global(mWAMCtrlrJSObjectName.Get()).call<void>("sendMessage", std::string("SMMFUI"), std::string(dataStr.Get()));
73#endif
74}
75
76void IPlugWeb::SendSysexMsgFromUI(const ISysEx& msg)
77{
78 DBGMSG("TODO: SendSysexMsgFromUI");
79
80// EM_ASM({
81// window[Module.UTF8ToString($0)]["midiOut"].send(0x90, 0x45, 0x7f);
82// }, mWAMCtrlrJSObjectName.Get());
83// val::global(mWAMCtrlrJSObjectName.Get())["midiOut"].call<void>("send", {0x90, 0x45, 0x7f} );
84
85// #if WEBSOCKET_CLIENT
86// mSSMFUIBuf.Resize(kNumSSMFUIBytes + msg.mSize);
87// int pos = kNumMsgHeaderBytes;
88//
89// *((int*)(mSSMFUIBuf.GetData() + pos)) = msg.mSize; pos += sizeof(int);
90// memcpy(mSSMFUIBuf.GetData() + pos, msg.mData, msg.mSize);
91//
92// EM_ASM({
93// var jsbuff = Module.HEAPU8.subarray($0, $0 + $1);
94// ws.send(jsbuff);
95// }, (int) mSSMFUIBuf.GetData(), mSSMFUIBuf.Size());
96// #else
97// EM_ASM({
98// window[Module.UTF8ToString($0)].sendMessage('SSMFUI', $1, Module.HEAPU8.slice($1, $1 + $2).buffer);
99// }, mWAMCtrlrJSObjectName.Get(), (int) msg.mData, msg.mSize);
100// #endif
101}
102
103void IPlugWeb::SendArbitraryMsgFromUI(int msgTag, int ctrlTag, int dataSize, const void* pData)
104{
105 mSAMFUIBuf.Resize(kNumSAMFUIBytes + dataSize);
106 int pos = kNumMsgHeaderBytes;
107
108 *((int*)(mSAMFUIBuf.GetData() + pos)) = msgTag; pos += sizeof(int);
109 *((int*)(mSAMFUIBuf.GetData() + pos)) = ctrlTag; pos += sizeof(int);
110 *((int*)(mSAMFUIBuf.GetData() + pos)) = dataSize; pos += sizeof(int);
111
112 memcpy(mSAMFUIBuf.GetData() + pos, pData, dataSize);
113
114#if WEBSOCKET_CLIENT
115 EM_ASM({
116 var jsbuff = Module.HEAPU8.subarray($0, $0 + $1);
117 ws.send(jsbuff);
118 }, (int) mSAMFUIBuf.GetData(), mSAMFUIBuf.Size());
119#else
120 EM_ASM({
121 if(typeof window[Module.UTF8ToString($0)] === 'undefined' ) {
122 console.log("warning - SAMFUI called before controller exists");
123 }
124 else {
125 window[Module.UTF8ToString($0)].sendMessage('SAMFUI', "", Module.HEAPU8.slice($1, $1 + $2).buffer);
126 }
127 }, mWAMCtrlrJSObjectName.Get(), (int) mSAMFUIBuf.GetData() + kNumMsgHeaderBytes, mSAMFUIBuf.Size() - kNumMsgHeaderBytes); // Non websocket doesn't need "SAMFUI" bytes at beginning
128#endif
129}
130
131void IPlugWeb::SendDSPIdleTick()
132{
133 EM_ASM({
134 if(typeof window[Module.UTF8ToString($0)] === 'undefined' ) {
135 console.log("warning - SendDSPIdleTick called before controller exists");
136 }
137 else {
138 window[Module.UTF8ToString($0)].sendMessage("TICK", "", 0.);
139 }
140 }, mWAMCtrlrJSObjectName.Get());
141}
142
143extern std::unique_ptr<IPlugWeb> gPlug;
144
145// could probably do this without these extra functions
146// https://kripken.github.io/emscripten-site/docs/porting/connecting_cpp_and_javascript/embind.html#deriving-from-c-classes-in-javascript
147static void _SendArbitraryMsgFromDelegate(int msgTag, int dataSize, uintptr_t pData)
148{
149 const uint8_t* pDataPtr = reinterpret_cast<uint8_t*>(pData); // embind doesn't allow us to pass raw pointers
150 gPlug->SendArbitraryMsgFromDelegate(msgTag, dataSize, pDataPtr);
151}
152
153static void _SendControlMsgFromDelegate(int ctrlTag, int msgTag, int dataSize, uintptr_t pData)
154{
155 const uint8_t* pDataPtr = reinterpret_cast<uint8_t*>(pData); // embind doesn't allow us to pass raw pointers
156 gPlug->SendControlMsgFromDelegate(ctrlTag, msgTag, dataSize, pDataPtr);
157}
158
159static void _SendControlValueFromDelegate(int ctrlTag, double normalizedValue)
160{
161 gPlug->SendControlValueFromDelegate(ctrlTag, normalizedValue);
162}
163
164static void _SendParameterValueFromDelegate(int paramIdx, double normalizedValue)
165{
166 gPlug->SendParameterValueFromDelegate(paramIdx, normalizedValue, true);
167}
168
169static void _SendMidiMsgFromDelegate(int status, int data1, int data2)
170{
171 IMidiMsg msg {0, (uint8_t) status, (uint8_t) data1, (uint8_t) data2};
172 gPlug->SendMidiMsgFromDelegate(msg);
173}
174
175static void _SendSysexMsgFromDelegate(int dataSize, uintptr_t pData)
176{
177 const uint8_t* pDataPtr = reinterpret_cast<uint8_t*>(pData); // embind doesn't allow us to pass raw pointers
178 ISysEx msg(0, pDataPtr, dataSize);
179 gPlug->SendSysexMsgFromDelegate(msg);
180}
181
182static void _StartIdleTimer()
183{
184 gPlug->CreateTimer();
185}
186
187EMSCRIPTEN_BINDINGS(IPlugWeb) {
188 function("SPVFD", &_SendParameterValueFromDelegate);
189 function("SAMFD", &_SendArbitraryMsgFromDelegate);
190 function("SCMFD", &_SendControlMsgFromDelegate);
191 function("SCVFD", &_SendControlValueFromDelegate);
192 function("SMMFD", &_SendMidiMsgFromDelegate);
193 function("SSMFD", &_SendSysexMsgFromDelegate);
194 function("StartIdleTimer", &_StartIdleTimer);
195}
uint8_t * GetData()
Gets a ptr to the chunk data.
Definition: IPlugStructs.h:242
int Size() const
Returns the current size of the chunk.
Definition: IPlugStructs.h:221
int Resize(int newSize)
Resizes the chunk.
Definition: IPlugStructs.h:229
The base class of an IPlug plug-in, which interacts with the different plug-in APIs.
Definition: IPlugAPIBase.h:43
This is used for the UI "editor" - controller side of a WAM or remote editors that communicate with d...
Definition: IPlugWeb.h:26
Encapsulates a MIDI message and provides helper functions.
Definition: IPlugMidi.h:31
A struct for dealing with SysEx messages.
Definition: IPlugMidi.h:539