@grame/faustwasm 0.8.2 → 0.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@grame/faustwasm",
3
- "version": "0.8.2",
3
+ "version": "0.9.1",
4
4
  "description": "WebAssembly version of Faust Compiler",
5
5
  "main": "dist/cjs/index.js",
6
6
  "types": "dist/esm/index.d.ts",
@@ -178,6 +178,8 @@ export class FaustAudioWorkletNode<Poly extends boolean = false> extends (global
178
178
  const data2 = data[2];
179
179
  if (cmd === 11) this.ctrlChange(channel, data1, data2);
180
180
  else if (cmd === 14) this.pitchWheel(channel, data2 * 128.0 + data1);
181
+ if (cmd === 8 || (cmd === 9 && data2 === 0)) this.keyOff(channel, data1, data2);
182
+ else if (cmd === 9) this.keyOn(channel, data1, data2);
181
183
  else this.port.postMessage({ type: "midi", data: data });
182
184
  }
183
185
 
@@ -189,6 +191,14 @@ export class FaustAudioWorkletNode<Poly extends boolean = false> extends (global
189
191
  const e = { type: "pitchWheel", data: [channel, wheel] };
190
192
  this.port.postMessage(e);
191
193
  }
194
+ keyOn(channel: number, pitch: number, velocity: number) {
195
+ const e = { type: "keyOn", data: [channel, pitch, velocity] };
196
+ this.port.postMessage(e);
197
+ }
198
+ keyOff(channel: number, pitch: number, velocity: number) {
199
+ const e = { type: "keyOff", data: [channel, pitch, velocity] };
200
+ this.port.postMessage(e);
201
+ }
192
202
 
193
203
  get hasAccInput() { return this.#hasAccInput; }
194
204
 
@@ -181,6 +181,14 @@ const getFaustAudioWorkletProcessor = <Poly extends boolean = false>(dependencie
181
181
  this.pitchWheel(msg.data[0], msg.data[1]);
182
182
  break;
183
183
  }
184
+ case "keyOn": {
185
+ this.keyOn(msg.data[0], msg.data[1], msg.data[2]);
186
+ break;
187
+ }
188
+ case "keyOff": {
189
+ this.keyOff(msg.data[0], msg.data[1], msg.data[2]);
190
+ break;
191
+ }
184
192
  // Generic data message
185
193
  case "param": {
186
194
  this.setParamValue(msg.data.path, msg.data.value);
@@ -234,6 +242,14 @@ const getFaustAudioWorkletProcessor = <Poly extends boolean = false>(dependencie
234
242
  this.fDSPCode.pitchWheel(channel, wheel);
235
243
  }
236
244
 
245
+ protected keyOn(channel: number, pitch: number, velocity: number) {
246
+ this.fDSPCode.keyOn(channel, pitch, velocity);
247
+ }
248
+
249
+ protected keyOff(channel: number, pitch: number, velocity: number) {
250
+ this.fDSPCode.keyOff(channel, pitch, velocity);
251
+ }
252
+
237
253
  protected propagateAcc(accelerationIncludingGravity: NonNullable<DeviceMotionEvent["accelerationIncludingGravity"]>, invert: boolean = false) {
238
254
  this.fDSPCode.propagateAcc(accelerationIncludingGravity, invert);
239
255
  }
@@ -66,6 +66,8 @@ export class FaustOfflineProcessor<Poly extends boolean = false> {
66
66
 
67
67
  ctrlChange(chan: number, ctrl: number, value: number) { this.fDSPCode.ctrlChange(chan, ctrl, value); }
68
68
  pitchWheel(chan: number, value: number) { this.fDSPCode.pitchWheel(chan, value); }
69
+ keyOn(channel: number, pitch: number, velocity: number) { this.fDSPCode.keyOn(channel, pitch, velocity); }
70
+ keyOff(channel: number, pitch: number, velocity: number) { this.fDSPCode.keyOff(channel, pitch, velocity); }
69
71
 
70
72
  setParamValue(path: string, value: number) { this.fDSPCode.setParamValue(path, value); }
71
73
  getParamValue(path: string) { return this.fDSPCode.getParamValue(path); }
@@ -102,6 +102,8 @@ export class FaustScriptProcessorNode<Poly extends boolean = false> extends (glo
102
102
 
103
103
  ctrlChange(chan: number, ctrl: number, value: number) { this.fDSPCode.ctrlChange(chan, ctrl, value); }
104
104
  pitchWheel(chan: number, value: number) { this.fDSPCode.pitchWheel(chan, value); }
105
+ keyOn(channel: number, pitch: number, velocity: number) { this.fDSPCode.keyOn(channel, pitch, velocity); }
106
+ keyOff(channel: number, pitch: number, velocity: number) { this.fDSPCode.keyOff(channel, pitch, velocity); }
105
107
 
106
108
  setParamValue(path: string, value: number) { this.fDSPCode.setParamValue(path, value); }
107
109
  getParamValue(path: string) { return this.fDSPCode.getParamValue(path); }
@@ -444,6 +444,22 @@ export interface IFaustBaseWebAudioDsp {
444
444
  */
445
445
  pitchWheel(chan: number, value: number): void;
446
446
 
447
+ /**
448
+ * Handle MIDI keyOn messages.
449
+ * @param channel
450
+ * @param pitch
451
+ * @param velocity
452
+ */
453
+ keyOn(channel: number, pitch: number, velocity: number): void;
454
+
455
+ /**
456
+ * Handle MIDI keyOn messages.
457
+ * @param channel
458
+ * @param pitch
459
+ * @param velocity
460
+ */
461
+ keyOff(channel: number, pitch: number, velocity: number): void;
462
+
447
463
  /**
448
464
  * Set parameter value.
449
465
  *
@@ -612,6 +628,11 @@ export class FaustBaseWebAudioDsp implements IFaustBaseWebAudioDsp {
612
628
  // MIDI handling
613
629
  protected fPitchwheelLabel: { path: string; chan: number; min: number; max: number }[] = [];
614
630
  protected fCtrlLabel: { path: string; chan: number; min: number; max: number }[][] = new Array(128).fill(null).map(() => []);
631
+ // array of MIDI key handlers; array index is the MIDI note number
632
+ protected fMidiKeyLabel: { path: string; chan: number; min: number; max: number }[][] = new Array(128).fill(null).map(() => []);
633
+ protected fMidiKeyOnLabel: { path: string; chan: number; min: number; max: number }[][] = new Array(128).fill(null).map(() => []);
634
+ protected fMidiKeyOffLabel: { path: string; chan: number; min: number; max: number }[][] = new Array(128).fill(null).map(() => []);
635
+
615
636
  protected fPathTable: { [address: string]: number } = {};
616
637
  protected fUICallback: UIHandler = (item: FaustUIItem) => {
617
638
  if (item.type === "hbargraph" || item.type === "vbargraph") {
@@ -643,10 +664,28 @@ export class FaustBaseWebAudioDsp implements IFaustBaseWebAudioDsp {
643
664
  const matched2 = strMidi.match(/^ctrl\s(\d+)\s(\d+)/);
644
665
  // "ctrl num"
645
666
  const matched1 = strMidi.match(/^ctrl\s(\d+)/);
667
+ // match `key <note>[ <channel>]`
668
+ const matchedKey = strMidi.match(/^key\s+(\d+)(?:\s+(\d+))?$/);
669
+ //match `keyon <note>[ <channel>]`
670
+ const matchedKeyOn = strMidi.match(/^keyon\s+(\d+)(?:\s+(\d+))?$/);
671
+ //match `keyoff <note>[ <channel>]`
672
+ const matchedKeyOff = strMidi.match(/^keyoff\s+(\d+)(?:\s+(\d+))?$/);
646
673
  if (matched2) {
647
674
  this.fCtrlLabel[parseInt(matched2[1])].push({ path: item.address, chan: parseInt(matched2[2]), min: item.min as number, max: item.max as number });
648
675
  } else if (matched1) {
649
676
  this.fCtrlLabel[parseInt(matched1[1])].push({ path: item.address, chan: 0, min: item.min as number, max: item.max as number });
677
+ } else if (matchedKey) {
678
+ const note = parseInt(matchedKey[1]);
679
+ const channel = matchedKey[2] ? parseInt(matchedKey[2]) : 0;
680
+ this.fMidiKeyLabel[note].push({ path: item.address, chan: channel, min: item.min as number ?? 0, max: item.max as number ?? 1 });
681
+ } else if (matchedKeyOn) {
682
+ const note = parseInt(matchedKeyOn[1]);
683
+ const channel = matchedKeyOn[2] ? parseInt(matchedKeyOn[2]) : 0;
684
+ this.fMidiKeyOnLabel[note].push({ path: item.address, chan: channel, min: item.min as number ?? 0, max: item.max as number ?? 1 });
685
+ } else if (matchedKeyOff) {
686
+ const note = parseInt(matchedKeyOff[1]);
687
+ const channel = matchedKeyOff[2] ? parseInt(matchedKeyOff[2]) : 0;
688
+ this.fMidiKeyOffLabel[note].push({ path: item.address, chan: channel, min: item.min as number ?? 0, max: item.max as number ?? 1 });
650
689
  }
651
690
  }
652
691
  }
@@ -964,6 +1003,15 @@ export class FaustBaseWebAudioDsp implements IFaustBaseWebAudioDsp {
964
1003
  const data2 = data[2];
965
1004
  if (cmd === 11) return this.ctrlChange(channel, data1, data2);
966
1005
  if (cmd === 14) return this.pitchWheel(channel, (data2 * 128.0 + data1));
1006
+ if (cmd === 9) {
1007
+ if (data2 > 0)
1008
+ return this.keyOn(channel, data1, data2);
1009
+ else
1010
+ return this.keyOff(channel, data1, data2);
1011
+ }
1012
+ if (cmd === 8) {
1013
+ return this.keyOff(channel, data1, data2);
1014
+ }
967
1015
  }
968
1016
 
969
1017
  ctrlChange(channel: number, ctrl: number, value: number) {
@@ -980,6 +1028,46 @@ export class FaustBaseWebAudioDsp implements IFaustBaseWebAudioDsp {
980
1028
  }
981
1029
  }
982
1030
 
1031
+ keyOn(channel: number, pitch: number, velocity: number) {
1032
+ if (this.fPlotHandler) this.fCachedEvents.push({ type: "keyOn", data: [channel, pitch, velocity] });
1033
+ this.fMidiKeyOnLabel[pitch].forEach((key) => {
1034
+ const { path, chan } = key;
1035
+ if (chan === 0 || channel === chan - 1) {
1036
+ this.setParamValue(path, FaustBaseWebAudioDsp.remap(velocity, 0, 127, key.min, key.max));
1037
+ // Typically used to reflect parameter change on GUI
1038
+ if (this.fOutputHandler) this.fOutputHandler(path, this.getParamValue(path));
1039
+ }
1040
+ });
1041
+ this.fMidiKeyLabel[pitch].forEach((key) => {
1042
+ const { path, chan } = key;
1043
+ if (chan === 0 || channel === chan - 1) {
1044
+ this.setParamValue(path, FaustBaseWebAudioDsp.remap(velocity, 0, 127, key.min, key.max));
1045
+ // Typically used to reflect parameter change on GUI
1046
+ if (this.fOutputHandler) this.fOutputHandler(path, this.getParamValue(path));
1047
+ }
1048
+ });
1049
+ }
1050
+
1051
+ keyOff(channel: number, pitch: number, velocity: number) {
1052
+ if (this.fPlotHandler) this.fCachedEvents.push({ type: "keyOff", data: [channel, pitch, velocity] });
1053
+ this.fMidiKeyOffLabel[pitch].forEach((key) => {
1054
+ const { path, chan } = key;
1055
+ if (chan === 0 || channel === chan - 1) {
1056
+ this.setParamValue(path, FaustBaseWebAudioDsp.remap(velocity, 0, 127, key.min, key.max));
1057
+ // Typically used to reflect parameter change on GUI
1058
+ if (this.fOutputHandler) this.fOutputHandler(path, this.getParamValue(path));
1059
+ }
1060
+ });
1061
+ this.fMidiKeyLabel[pitch].forEach((key) => {
1062
+ const { path, chan } = key;
1063
+ if (chan === 0 || channel === chan - 1) {
1064
+ this.setParamValue(path, 0);
1065
+ // Typically used to reflect parameter change on GUI
1066
+ if (this.fOutputHandler) this.fOutputHandler(path, this.getParamValue(path));
1067
+ }
1068
+ });
1069
+ }
1070
+
983
1071
  pitchWheel(channel: number, wheel: number) {
984
1072
  if (this.fPlotHandler) this.fCachedEvents.push({ type: "pitchWheel", data: [channel, wheel] });
985
1073
  this.fPitchwheelLabel.forEach((pw) => {
@@ -17,6 +17,7 @@ const copyWebStandaloneAssets = (outputDir, dspName, poly = false, effect = fals
17
17
  console.log(`Writing assets files.`)
18
18
  if (!fs.existsSync(outputDir)) fs.mkdirSync(outputDir);
19
19
 
20
+ // Define find and replace patterns
20
21
  const findAndReplace = ["FAUST_DSP_NAME", dspName];
21
22
  if (poly) findAndReplace.push("FAUST_DSP_VOICES = 0", "FAUST_DSP_VOICES = 16");
22
23
  if (poly && effect) findAndReplace.push("FAUST_DSP_HAS_EFFECT = false", "FAUST_DSP_HAS_EFFECT = true");
@@ -57,7 +58,18 @@ const copyWebPWAAssets = (outputDir, dspName, poly = false, effect = false) => {
57
58
  console.log(`Writing assets files.`)
58
59
  if (!fs.existsSync(outputDir)) fs.mkdirSync(outputDir);
59
60
 
61
+ // Generate VERSION_DATE
62
+ const now = new Date();
63
+ const VERSION_DATE = now.getFullYear().toString() +
64
+ ("0" + (now.getMonth() + 1)).slice(-2) +
65
+ ("0" + now.getDate()).slice(-2) + "-" +
66
+ ("0" + now.getHours()).slice(-2) +
67
+ ("0" + now.getMinutes()).slice(-2);
68
+
69
+ // Define find and replace patterns
60
70
  const findAndReplace = ["FAUST_DSP_NAME", dspName];
71
+ findAndReplace.push("VERSION_DATE", VERSION_DATE);
72
+
61
73
  if (poly) findAndReplace.push("FAUST_DSP_VOICES = 0", "FAUST_DSP_VOICES = 16");
62
74
  if (poly && effect) findAndReplace.push("FAUST_DSP_HAS_EFFECT = false", "FAUST_DSP_HAS_EFFECT = true");
63
75
 
@@ -97,7 +109,9 @@ const copyWebTemplateAssets = (outputDir, dspName, poly = false, effect = false)
97
109
  // Create output directory if it doesn't exist
98
110
  if (!fs.existsSync(outputDir)) fs.mkdirSync(outputDir);
99
111
 
112
+ // Define find and replace patterns
100
113
  const findAndReplace = ["FAUST_DSP_NAME", dspName];
114
+
101
115
  if (poly) findAndReplace.push("FAUST_DSP_VOICES = 0", "FAUST_DSP_VOICES = 16");
102
116
  if (poly && effect) findAndReplace.push("FAUST_DSP_HAS_EFFECT = false", "FAUST_DSP_HAS_EFFECT = true");
103
117
 
@@ -618,6 +618,20 @@ export interface IFaustBaseWebAudioDsp {
618
618
  * @param value - the MIDI controller value (0..16383)
619
619
  */
620
620
  pitchWheel(chan: number, value: number): void;
621
+ /**
622
+ * Handle MIDI keyOn messages.
623
+ * @param channel
624
+ * @param pitch
625
+ * @param velocity
626
+ */
627
+ keyOn(channel: number, pitch: number, velocity: number): void;
628
+ /**
629
+ * Handle MIDI keyOn messages.
630
+ * @param channel
631
+ * @param pitch
632
+ * @param velocity
633
+ */
634
+ keyOff(channel: number, pitch: number, velocity: number): void;
621
635
  /**
622
636
  * Set parameter value.
623
637
  *
@@ -767,6 +781,24 @@ export declare class FaustBaseWebAudioDsp implements IFaustBaseWebAudioDsp {
767
781
  min: number;
768
782
  max: number;
769
783
  }[][];
784
+ protected fMidiKeyLabel: {
785
+ path: string;
786
+ chan: number;
787
+ min: number;
788
+ max: number;
789
+ }[][];
790
+ protected fMidiKeyOnLabel: {
791
+ path: string;
792
+ chan: number;
793
+ min: number;
794
+ max: number;
795
+ }[][];
796
+ protected fMidiKeyOffLabel: {
797
+ path: string;
798
+ chan: number;
799
+ min: number;
800
+ max: number;
801
+ }[][];
770
802
  protected fPathTable: {
771
803
  [address: string]: number;
772
804
  };
@@ -826,6 +858,8 @@ export declare class FaustBaseWebAudioDsp implements IFaustBaseWebAudioDsp {
826
858
  getNumOutputs(): number;
827
859
  midiMessage(data: number[] | Uint8Array): void;
828
860
  ctrlChange(channel: number, ctrl: number, value: number): void;
861
+ keyOn(channel: number, pitch: number, velocity: number): void;
862
+ keyOff(channel: number, pitch: number, velocity: number): void;
829
863
  pitchWheel(channel: number, wheel: number): void;
830
864
  setParamValue(path: string, value: number): void;
831
865
  getParamValue(path: string): number;
@@ -1180,6 +1214,8 @@ export declare class FaustOfflineProcessor<Poly extends boolean = false> {
1180
1214
  midiMessage(data: number[] | Uint8Array): void;
1181
1215
  ctrlChange(chan: number, ctrl: number, value: number): void;
1182
1216
  pitchWheel(chan: number, value: number): void;
1217
+ keyOn(channel: number, pitch: number, velocity: number): void;
1218
+ keyOff(channel: number, pitch: number, velocity: number): void;
1183
1219
  setParamValue(path: string, value: number): void;
1184
1220
  getParamValue(path: string): number;
1185
1221
  getParams(): string[];
@@ -1374,6 +1410,8 @@ export declare class FaustAudioWorkletNode<Poly extends boolean = false> extends
1374
1410
  midiMessage(data: number[] | Uint8Array): void;
1375
1411
  ctrlChange(channel: number, ctrl: number, value: number): void;
1376
1412
  pitchWheel(channel: number, wheel: number): void;
1413
+ keyOn(channel: number, pitch: number, velocity: number): void;
1414
+ keyOff(channel: number, pitch: number, velocity: number): void;
1377
1415
  get hasAccInput(): boolean;
1378
1416
  propagateAcc(accelerationIncludingGravity: NonNullable<DeviceMotionEvent["accelerationIncludingGravity"]>, invert?: boolean): void;
1379
1417
  get hasGyrInput(): boolean;
@@ -1441,6 +1479,8 @@ export declare class FaustScriptProcessorNode<Poly extends boolean = false> exte
1441
1479
  midiMessage(data: number[] | Uint8Array): void;
1442
1480
  ctrlChange(chan: number, ctrl: number, value: number): void;
1443
1481
  pitchWheel(chan: number, value: number): void;
1482
+ keyOn(channel: number, pitch: number, velocity: number): void;
1483
+ keyOff(channel: number, pitch: number, velocity: number): void;
1444
1484
  setParamValue(path: string, value: number): void;
1445
1485
  getParamValue(path: string): number;
1446
1486
  getParams(): string[];
@@ -186,6 +186,14 @@ var getFaustAudioWorkletProcessor = (dependencies, faustData, register = true) =
186
186
  this.pitchWheel(msg.data[0], msg.data[1]);
187
187
  break;
188
188
  }
189
+ case "keyOn": {
190
+ this.keyOn(msg.data[0], msg.data[1], msg.data[2]);
191
+ break;
192
+ }
193
+ case "keyOff": {
194
+ this.keyOff(msg.data[0], msg.data[1], msg.data[2]);
195
+ break;
196
+ }
189
197
  case "param": {
190
198
  this.setParamValue(msg.data.path, msg.data.value);
191
199
  break;
@@ -232,6 +240,12 @@ var getFaustAudioWorkletProcessor = (dependencies, faustData, register = true) =
232
240
  pitchWheel(channel, wheel) {
233
241
  this.fDSPCode.pitchWheel(channel, wheel);
234
242
  }
243
+ keyOn(channel, pitch, velocity) {
244
+ this.fDSPCode.keyOn(channel, pitch, velocity);
245
+ }
246
+ keyOff(channel, pitch, velocity) {
247
+ this.fDSPCode.keyOff(channel, pitch, velocity);
248
+ }
235
249
  propagateAcc(accelerationIncludingGravity, invert = false) {
236
250
  this.fDSPCode.propagateAcc(accelerationIncludingGravity, invert);
237
251
  }
@@ -2112,6 +2126,10 @@ var FaustBaseWebAudioDsp = class _FaustBaseWebAudioDsp {
2112
2126
  // MIDI handling
2113
2127
  this.fPitchwheelLabel = [];
2114
2128
  this.fCtrlLabel = new Array(128).fill(null).map(() => []);
2129
+ // array of MIDI key handlers; array index is the MIDI note number
2130
+ this.fMidiKeyLabel = new Array(128).fill(null).map(() => []);
2131
+ this.fMidiKeyOnLabel = new Array(128).fill(null).map(() => []);
2132
+ this.fMidiKeyOffLabel = new Array(128).fill(null).map(() => []);
2115
2133
  this.fPathTable = {};
2116
2134
  this.fUICallback = (item) => {
2117
2135
  if (item.type === "hbargraph" || item.type === "vbargraph") {
@@ -2124,6 +2142,7 @@ var FaustBaseWebAudioDsp = class _FaustBaseWebAudioDsp {
2124
2142
  if (!item.meta)
2125
2143
  return;
2126
2144
  item.meta.forEach((meta) => {
2145
+ var _a, _b, _c, _d, _e, _f;
2127
2146
  const { midi, acc, gyr } = meta;
2128
2147
  if (midi) {
2129
2148
  const strMidi = midi.trim();
@@ -2137,10 +2156,25 @@ var FaustBaseWebAudioDsp = class _FaustBaseWebAudioDsp {
2137
2156
  } else {
2138
2157
  const matched2 = strMidi.match(/^ctrl\s(\d+)\s(\d+)/);
2139
2158
  const matched1 = strMidi.match(/^ctrl\s(\d+)/);
2159
+ const matchedKey = strMidi.match(/^key\s+(\d+)(?:\s+(\d+))?$/);
2160
+ const matchedKeyOn = strMidi.match(/^keyon\s+(\d+)(?:\s+(\d+))?$/);
2161
+ const matchedKeyOff = strMidi.match(/^keyoff\s+(\d+)(?:\s+(\d+))?$/);
2140
2162
  if (matched2) {
2141
2163
  this.fCtrlLabel[parseInt(matched2[1])].push({ path: item.address, chan: parseInt(matched2[2]), min: item.min, max: item.max });
2142
2164
  } else if (matched1) {
2143
2165
  this.fCtrlLabel[parseInt(matched1[1])].push({ path: item.address, chan: 0, min: item.min, max: item.max });
2166
+ } else if (matchedKey) {
2167
+ const note = parseInt(matchedKey[1]);
2168
+ const channel = matchedKey[2] ? parseInt(matchedKey[2]) : 0;
2169
+ this.fMidiKeyLabel[note].push({ path: item.address, chan: channel, min: (_a = item.min) != null ? _a : 0, max: (_b = item.max) != null ? _b : 1 });
2170
+ } else if (matchedKeyOn) {
2171
+ const note = parseInt(matchedKeyOn[1]);
2172
+ const channel = matchedKeyOn[2] ? parseInt(matchedKeyOn[2]) : 0;
2173
+ this.fMidiKeyOnLabel[note].push({ path: item.address, chan: channel, min: (_c = item.min) != null ? _c : 0, max: (_d = item.max) != null ? _d : 1 });
2174
+ } else if (matchedKeyOff) {
2175
+ const note = parseInt(matchedKeyOff[1]);
2176
+ const channel = matchedKeyOff[2] ? parseInt(matchedKeyOff[2]) : 0;
2177
+ this.fMidiKeyOffLabel[note].push({ path: item.address, chan: channel, min: (_e = item.min) != null ? _e : 0, max: (_f = item.max) != null ? _f : 1 });
2144
2178
  }
2145
2179
  }
2146
2180
  }
@@ -2402,6 +2436,15 @@ var FaustBaseWebAudioDsp = class _FaustBaseWebAudioDsp {
2402
2436
  return this.ctrlChange(channel, data1, data2);
2403
2437
  if (cmd === 14)
2404
2438
  return this.pitchWheel(channel, data2 * 128 + data1);
2439
+ if (cmd === 9) {
2440
+ if (data2 > 0)
2441
+ return this.keyOn(channel, data1, data2);
2442
+ else
2443
+ return this.keyOff(channel, data1, data2);
2444
+ }
2445
+ if (cmd === 8) {
2446
+ return this.keyOff(channel, data1, data2);
2447
+ }
2405
2448
  }
2406
2449
  ctrlChange(channel, ctrl, value) {
2407
2450
  if (this.fPlotHandler)
@@ -2417,6 +2460,46 @@ var FaustBaseWebAudioDsp = class _FaustBaseWebAudioDsp {
2417
2460
  });
2418
2461
  }
2419
2462
  }
2463
+ keyOn(channel, pitch, velocity) {
2464
+ if (this.fPlotHandler)
2465
+ this.fCachedEvents.push({ type: "keyOn", data: [channel, pitch, velocity] });
2466
+ this.fMidiKeyOnLabel[pitch].forEach((key) => {
2467
+ const { path, chan } = key;
2468
+ if (chan === 0 || channel === chan - 1) {
2469
+ this.setParamValue(path, _FaustBaseWebAudioDsp.remap(velocity, 0, 127, key.min, key.max));
2470
+ if (this.fOutputHandler)
2471
+ this.fOutputHandler(path, this.getParamValue(path));
2472
+ }
2473
+ });
2474
+ this.fMidiKeyLabel[pitch].forEach((key) => {
2475
+ const { path, chan } = key;
2476
+ if (chan === 0 || channel === chan - 1) {
2477
+ this.setParamValue(path, _FaustBaseWebAudioDsp.remap(velocity, 0, 127, key.min, key.max));
2478
+ if (this.fOutputHandler)
2479
+ this.fOutputHandler(path, this.getParamValue(path));
2480
+ }
2481
+ });
2482
+ }
2483
+ keyOff(channel, pitch, velocity) {
2484
+ if (this.fPlotHandler)
2485
+ this.fCachedEvents.push({ type: "keyOff", data: [channel, pitch, velocity] });
2486
+ this.fMidiKeyOffLabel[pitch].forEach((key) => {
2487
+ const { path, chan } = key;
2488
+ if (chan === 0 || channel === chan - 1) {
2489
+ this.setParamValue(path, _FaustBaseWebAudioDsp.remap(velocity, 0, 127, key.min, key.max));
2490
+ if (this.fOutputHandler)
2491
+ this.fOutputHandler(path, this.getParamValue(path));
2492
+ }
2493
+ });
2494
+ this.fMidiKeyLabel[pitch].forEach((key) => {
2495
+ const { path, chan } = key;
2496
+ if (chan === 0 || channel === chan - 1) {
2497
+ this.setParamValue(path, 0);
2498
+ if (this.fOutputHandler)
2499
+ this.fOutputHandler(path, this.getParamValue(path));
2500
+ }
2501
+ });
2502
+ }
2420
2503
  pitchWheel(channel, wheel) {
2421
2504
  if (this.fPlotHandler)
2422
2505
  this.fCachedEvents.push({ type: "pitchWheel", data: [channel, wheel] });
@@ -3053,6 +3136,12 @@ var FaustOfflineProcessor = class {
3053
3136
  pitchWheel(chan, value) {
3054
3137
  this.fDSPCode.pitchWheel(chan, value);
3055
3138
  }
3139
+ keyOn(channel, pitch, velocity) {
3140
+ this.fDSPCode.keyOn(channel, pitch, velocity);
3141
+ }
3142
+ keyOff(channel, pitch, velocity) {
3143
+ this.fDSPCode.keyOff(channel, pitch, velocity);
3144
+ }
3056
3145
  setParamValue(path, value) {
3057
3146
  this.fDSPCode.setParamValue(path, value);
3058
3147
  }
@@ -3989,6 +4078,10 @@ var FaustAudioWorkletNode = class extends (globalThis.AudioWorkletNode || null)
3989
4078
  this.ctrlChange(channel, data1, data2);
3990
4079
  else if (cmd === 14)
3991
4080
  this.pitchWheel(channel, data2 * 128 + data1);
4081
+ if (cmd === 8 || cmd === 9 && data2 === 0)
4082
+ this.keyOff(channel, data1, data2);
4083
+ else if (cmd === 9)
4084
+ this.keyOn(channel, data1, data2);
3992
4085
  else
3993
4086
  this.port.postMessage({ type: "midi", data });
3994
4087
  }
@@ -4000,6 +4093,14 @@ var FaustAudioWorkletNode = class extends (globalThis.AudioWorkletNode || null)
4000
4093
  const e = { type: "pitchWheel", data: [channel, wheel] };
4001
4094
  this.port.postMessage(e);
4002
4095
  }
4096
+ keyOn(channel, pitch, velocity) {
4097
+ const e = { type: "keyOn", data: [channel, pitch, velocity] };
4098
+ this.port.postMessage(e);
4099
+ }
4100
+ keyOff(channel, pitch, velocity) {
4101
+ const e = { type: "keyOff", data: [channel, pitch, velocity] };
4102
+ this.port.postMessage(e);
4103
+ }
4003
4104
  get hasAccInput() {
4004
4105
  return __privateGet(this, _hasAccInput);
4005
4106
  }
@@ -4163,42 +4264,14 @@ var FaustScriptProcessorNode = class extends (globalThis.ScriptProcessorNode ||
4163
4264
  async startSensors() {
4164
4265
  if (this.hasAccInput) {
4165
4266
  if (window.DeviceMotionEvent) {
4166
- if (typeof window.DeviceMotionEvent.requestPermission === "function") {
4167
- try {
4168
- const response = await window.DeviceMotionEvent.requestPermission();
4169
- if (response === "granted") {
4170
- window.addEventListener("devicemotion", this.handleDeviceMotion, true);
4171
- } else if (response === "denied") {
4172
- alert("You have denied access to motion and orientation data. To enable it, go to Settings > Safari > Motion & Orientation Access.");
4173
- throw new Error("Unable to access the accelerometer.");
4174
- }
4175
- } catch (error) {
4176
- console.error(error);
4177
- }
4178
- } else {
4179
- window.addEventListener("devicemotion", this.handleDeviceMotion, true);
4180
- }
4267
+ window.addEventListener("devicemotion", this.handleDeviceMotion, true);
4181
4268
  } else {
4182
4269
  console.log("Cannot set the accelerometer handler.");
4183
4270
  }
4184
4271
  }
4185
4272
  if (this.hasGyrInput) {
4186
4273
  if (window.DeviceMotionEvent) {
4187
- if (typeof window.DeviceOrientationEvent.requestPermission === "function") {
4188
- try {
4189
- const response = await window.DeviceOrientationEvent.requestPermission();
4190
- if (response === "granted") {
4191
- window.addEventListener("deviceorientation", this.handleDeviceOrientation, true);
4192
- } else if (response === "denied") {
4193
- alert("You have denied access to motion and orientation data. To enable it, go to Settings > Safari > Motion & Orientation Access.");
4194
- throw new Error("Unable to access the gyroscope.");
4195
- }
4196
- } catch (error) {
4197
- console.error(error);
4198
- }
4199
- } else {
4200
- window.addEventListener("deviceorientation", this.handleDeviceOrientation, true);
4201
- }
4274
+ window.addEventListener("deviceorientation", this.handleDeviceOrientation, true);
4202
4275
  } else {
4203
4276
  console.log("Cannot set the gyroscope handler.");
4204
4277
  }
@@ -4251,6 +4324,12 @@ var FaustScriptProcessorNode = class extends (globalThis.ScriptProcessorNode ||
4251
4324
  pitchWheel(chan, value) {
4252
4325
  this.fDSPCode.pitchWheel(chan, value);
4253
4326
  }
4327
+ keyOn(channel, pitch, velocity) {
4328
+ this.fDSPCode.keyOn(channel, pitch, velocity);
4329
+ }
4330
+ keyOff(channel, pitch, velocity) {
4331
+ this.fDSPCode.keyOff(channel, pitch, velocity);
4332
+ }
4254
4333
  setParamValue(path, value) {
4255
4334
  this.fDSPCode.setParamValue(path, value);
4256
4335
  }