PageSourceSearch

https://studio.skytracks.io/assets/js/effects/io-wam-processor.js

js skytracks.io collected 2026-10-03 23:41:45 UTC 10,420 bytes, 276 lines download raw bytes

1// WAM AudioWorkletProcessor
2// Jari Kleimola 2017-18 ([email protected])
3//
4// work in progress
5// helper class for WASM data marshalling and C function call binding
6// also provides midi, patch data, parameter and arbitrary message support
7
8if (!AudioWorkletGlobalScope.IoWAMProcessor) {
9    class IoWAMProcessor extends AudioWorkletProcessor {
10        static get parameterDescriptors() {
11            return [];
12        }
13
14        constructor(options) {
15            options = options || {};
16            if (options.numberOfInputs === undefined)
17                options.numberOfInputs = 1;
18            if (options.numberOfOutputs === undefined)
19                options.numberOfOutputs = 1;
20            if (options.inputChannelCount === undefined)
21                options.inputChannelCount = [2];
22            if (options.outputChannelCount === undefined)
23                options.outputChannelCount = [2];
24            if (options.inputChannelCount.length != options.numberOfInputs)
25                throw new Error('InvalidArgumentException');
26            if (options.outputChannelCount.length != options.numberOfOutputs)
27                throw new Error('InvalidArgumentException');
28
29            super(options);
30            this.bufsize = 128;
31            this.sr = AudioWorkletGlobalScope.sampleRate || sampleRate;
32            this.audiobufs = [[], []];
33
34            var WAM = options.mod;
35            this.WAM = WAM;
36            WAM.port = this.port;
37
38            // -- construction C function wrappers
39            var wam_ctor = WAM.cwrap('createModule', 'number', []);
40            var wam_init = WAM.cwrap('wam_init', null, [
41                'number',
42                'number',
43                'number',
44                'string',
45            ]);
46
47            // -- runtime C function wrappers
48            this.wam_terminate = WAM.cwrap('wam_terminate', null, ['number']);
49            this.wam_onmidi = WAM.cwrap('wam_onmidi', null, [
50                'number',
51                'number',
52                'number',
53                'number',
54            ]);
55            this.wam_onpatch = WAM.cwrap('wam_onpatch', null, [
56                'number',
57                'number',
58                'number',
59            ]);
60            this.wam_onprocess = WAM.cwrap('wam_onprocess', 'number', [
61                'number',
62                'number',
63                'number',
64            ]);
65            this.wam_onparam = WAM.cwrap('wam_onparam', 'string', [
66                'number',
67                'string',
68                'number',
69            ]);
70            this.wam_onsysex = WAM.cwrap('wam_onsysex', null, [
71                'number',
72                'number',
73                'number',
74            ]);
75            this.wam_onmessageN = WAM.cwrap('wam_onmessageN', null, [
76                'number',
77                'string',
78                'string',
79                'number',
80            ]);
81            this.wam_onmessageS = WAM.cwrap('wam_onmessageS', null, [
82                'number',
83                'string',
84                'string',
85                'string',
86            ]);
87            this.wam_ongetparams = WAM.cwrap('wam_ongetparams', 'string', [
88                'number',
89                'string',
90                'string',
91            ]);
92
93            // -- supress warnings for older WAMs
94            if (WAM['_wam_onmessageA'])
95                this.wam_onmessageA = WAM.cwrap('wam_onmessageA', null, [
96                    'number',
97                    'string',
98                    'string',
99                    'number',
100                    'number',
101                ]);
102
103            this.inst = wam_ctor();
104            var desc = wam_init(this.inst, this.bufsize, this.sr, '');
105
106            // -- audio io configuration
107            this.numInputs = options.numberOfInputs;
108            this.numOutputs = options.numberOfOutputs;
109            this.numInChannels = options.inputChannelCount;
110            this.numOutChannels = options.outputChannelCount;
111
112            var ibufs = this.numInputs > 0 ? WAM._malloc(this.numInputs) : 0;
113            var obufs = this.numOutputs > 0 ? WAM._malloc(this.numOutputs) : 0;
114            this.audiobus = WAM._malloc(2 * 4);
115            WAM.setValue(this.audiobus, ibufs, 'i32');
116            WAM.setValue(this.audiobus + 4, obufs, 'i32');
117
118            for (var i = 0; i < this.numInputs; i++) {
119                var numChannels = this.numInChannels[i];
120                for (var c = 0; c < numChannels; c++) {
121                    var buf = WAM._malloc(this.bufsize * 4);
122                    WAM.setValue(ibufs + (i * numChannels + c) * 4, buf, 'i32');
123                    this.audiobufs[0].push(buf / 4);
124                }
125            }
126            for (var i = 0; i < this.numOutputs; i++) {
127                var numChannels = this.numOutChannels[i];
128                for (var c = 0; c < numChannels; c++) {
129                    var buf = WAM._malloc(this.bufsize * 4);
130                    WAM.setValue(obufs + (i * numChannels + c) * 4, buf, 'i32');
131                    this.audiobufs[1].push(buf / 4);
132                }
133            }
134
135            this.port.onmessage = this.onmessage.bind(this);
136            this.port.start();
137        }
138
139        onmessage(e) {
140            var msg = e.data;
141            var data = msg.data;
142            switch (msg.type) {
143                case 'midi':
144                    this.onmidi(data[0], data[1], data[2]);
145                    break;
146                case 'sysex':
147                    this.onsysex(data);
148                    break;
149                case 'patch':
150                    this.onpatch(data);
151                    break;
152                case 'param':
153                    if (msg.value === 'undefined')
154                        var real_value_return = this.onparam(msg.key, -1);
155                    else
156                        var real_value_return = this.onparam(
157                            msg.key,
158                            msg.value,
159                        );
160                    this.port.postMessage({
161                        type: 'getrealparam',
162                        data: {
163                            param_name: msg.key,
164                            real_value: real_value_return,
165                        },
166                    });
167                    break;
168                case 'getparams':
169                    var value_return = this.ongetparams(msg);
170
171                    this.port.postMessage({
172                        type: 'getparams',
173                        value: value_return,
174                    });
175                    break;
176                case 'msg':
177                    this.onmsg(msg.verb, msg.prop, msg.data);
178                    break;
179                //case "osc":   this.onmsg(msg.prop, msg.type, msg.data); break;
180            }
181        }
182
183        onmidi(status, data1, data2) {
184            this.wam_onmidi(this.inst, status, data1, data2);
185        }
186
187        onparam(key, value) {
188            return this.wam_onparam(this.inst, key, value);
189        }
190
191        ongetparams(key) {
192            return this.wam_ongetparams(this.inst, key);
193        }
194
195        onmsg(verb, prop, data) {
196            if (data instanceof ArrayBuffer) {
197                var buffer = new Uint8Array(data);
198                var len = data.byteLength;
199                var WAM = this.WAM;
200                var buf = WAM._malloc(data.byteLength);
201                for (var i = 0; i < len; i++)
202                    WAM.setValue(buf + i, buffer[i], 'i8');
203                this.wam_onmessageA(this.inst, verb, prop, buf, len);
204                WAM._free(buf);
205            } else if (typeof data === 'string')
206                this.wam_onmessageS(this.inst, verb, prop, data);
207            else this.wam_onmessageN(this.inst, verb, prop, data);
208        }
209
210        onpatch(data) {
211            var buffer = new Uint8Array(data);
212            var len = data.byteLength;
213            var WAM = this.WAM;
214            var buf = WAM._malloc(len);
215            for (var i = 0; i < len; i++)
216                WAM.setValue(buf + i, buffer[i], 'i8');
217            this.wam_onpatch(this.inst, buf, len);
218            WAM._free(buf);
219        }
220
221        onsysex(data) {
222            var WAM = this.WAM;
223            var buf = WAM._malloc(data.length);
224            for (var i = 0; i < data.length; i++)
225                WAM.setValue(buf + i, data[i], 'i8');
226            this.wam_onsysex(this.inst, buf, data.length);
227            WAM._free(buf);
228        }
229
230        process(inputs, outputs, params) {
231            // var WAM = this.WAM;
232            // -- inputs
233            // console.log("process number inputs: " + this.numInputs);
234            // console.log(inputs);
235
236            for (var i = 0; i < this.numInputs; i++) {
237                // console.log("process number input channels: " + this.numInChannels[i]);
238                var numChannels = this.numInChannels[i];
239                for (var c = 0; c < numChannels; c++) {
240                    var waain = inputs[i][0];
241
242                    if (!waain) {
243                        return true;
244                    }
245
246                    var wamin = this.audiobufs[0][i * numChannels + c];
247                    if (waain === undefined)
248                        break;
249                    this.WAM.HEAPF32.set(waain, wamin);
250                }
251            }
252
253            this.wam_onprocess(this.inst, this.audiobus, inputs);
254
255            // -- outputs
256            // console.log("process number outputs: " + this.numOutputs);
257            for (var i = 0; i < this.numOutputs; i++) {
258                var numChannels = this.numOutChannels[i];
259                for (var c = 0; c < numChannels; c++) {
260                    var waaout = outputs[i][c];
261                    var wamout = this.audiobufs[1][i * numChannels + c];
262                    waaout.set(
263                        this.WAM.HEAPF32.subarray(wamout, wamout + this.bufsize),
264                    );
265                }
266            }
267
268            return true;
269        }
270    }
271
272    // -- hack to share data between addModule() calls
273    AudioWorkletGlobalScope.IoWAMProcessor = IoWAMProcessor;
274}
275!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="17d45d05-070a-50f9-9882-9db19f45022d")}catch(e){}}();
276//# debugId=17d45d05-070a-50f9-9882-9db19f45022d

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.