@grame/faustwasm 0.8.0 → 0.9.0

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.
Files changed (67) hide show
  1. package/assets/standalone/create-node.js +46 -9
  2. package/assets/standalone/faust-ui/index.js +2 -2
  3. package/assets/standalone/faust-ui/index.js.map +1 -1
  4. package/assets/standalone/faustwasm/index.d.ts +42 -2
  5. package/assets/standalone/faustwasm/index.js +117 -66
  6. package/assets/standalone/faustwasm/index.js.map +2 -2
  7. package/assets/standalone/index-pwa.js +125 -90
  8. package/assets/standalone/index-template.js +43 -22
  9. package/assets/standalone/index.js +36 -19
  10. package/assets/standalone/service-worker.js +58 -5
  11. package/dist/cjs/index.d.ts +42 -2
  12. package/dist/cjs/index.js +117 -66
  13. package/dist/cjs/index.js.map +2 -2
  14. package/dist/cjs-bundle/index.d.ts +42 -2
  15. package/dist/cjs-bundle/index.js +117 -66
  16. package/dist/cjs-bundle/index.js.map +2 -2
  17. package/dist/esm/index.d.ts +42 -2
  18. package/dist/esm/index.js +117 -66
  19. package/dist/esm/index.js.map +2 -2
  20. package/dist/esm-bundle/index.d.ts +42 -2
  21. package/dist/esm-bundle/index.js +117 -66
  22. package/dist/esm-bundle/index.js.map +2 -2
  23. package/package.json +2 -2
  24. package/src/FaustAudioWorkletNode.ts +14 -30
  25. package/src/FaustAudioWorkletProcessor.ts +16 -0
  26. package/src/FaustOfflineProcessor.ts +2 -0
  27. package/src/FaustScriptProcessorNode.ts +6 -30
  28. package/src/FaustWebAudioDsp.ts +88 -0
  29. package/src/copyWebStandaloneAssets.js +14 -0
  30. package/test/faustlive-wasm/faust-ui/index.js +2 -2
  31. package/test/faustlive-wasm/faust-ui/index.js.map +1 -1
  32. package/test/faustlive-wasm/faustwasm/index.d.ts +42 -2
  33. package/test/faustlive-wasm/faustwasm/index.js +117 -66
  34. package/test/faustlive-wasm/faustwasm/index.js.map +2 -2
  35. package/test/midi/create-node.js +177 -0
  36. package/test/midi/dsp-meta.json +133 -0
  37. package/test/midi/dsp-module.wasm +0 -0
  38. package/test/midi/faust-ui/index.css +442 -0
  39. package/test/midi/faust-ui/index.css.map +1 -0
  40. package/test/midi/faust-ui/index.d.ts +1 -0
  41. package/test/midi/faust-ui/index.js +3729 -0
  42. package/test/midi/faust-ui/index.js.map +1 -0
  43. package/test/midi/faustwasm/index.d.ts +1680 -0
  44. package/test/midi/faustwasm/index.js +4884 -0
  45. package/test/midi/faustwasm/index.js.map +7 -0
  46. package/test/midi/icon.png +0 -0
  47. package/test/midi/index.html +76 -0
  48. package/test/midi/index.js +183 -0
  49. package/test/midi/manifest.json +17 -0
  50. package/test/midi/service-worker.js +165 -0
  51. package/test/midi.dsp +8 -1
  52. package/test/organ1/create-node.js +177 -0
  53. package/test/organ1/dsp-meta.json +126 -0
  54. package/test/organ1/dsp-module.wasm +0 -0
  55. package/test/organ1/faust-ui/index.css +442 -0
  56. package/test/organ1/faust-ui/index.css.map +1 -0
  57. package/test/organ1/faust-ui/index.d.ts +1 -0
  58. package/test/organ1/faust-ui/index.js +3729 -0
  59. package/test/organ1/faust-ui/index.js.map +1 -0
  60. package/test/organ1/faustwasm/index.d.ts +1656 -0
  61. package/test/organ1/faustwasm/index.js +4783 -0
  62. package/test/organ1/faustwasm/index.js.map +7 -0
  63. package/test/organ1/icon.png +0 -0
  64. package/test/organ1/index.html +76 -0
  65. package/test/organ1/index.js +203 -0
  66. package/test/organ1/manifest.json +17 -0
  67. package/test/organ1/service-worker.js +181 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@grame/faustwasm",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "description": "WebAssembly version of Faust Compiler",
5
5
  "main": "dist/cjs/index.js",
6
6
  "types": "dist/esm/index.d.ts",
@@ -39,7 +39,7 @@
39
39
  "homepage": "https://github.com/grame-cncm/faustwasm#readme",
40
40
  "devDependencies": {
41
41
  "@aws-crypto/sha256-js": "^5.2.0",
42
- "@shren/faust-ui": "^1.1.13",
42
+ "@shren/faust-ui": "^1.1.16",
43
43
  "@types/node": "^20.12.7",
44
44
  "@types/webmidi": "^2.0.10",
45
45
  "@webaudiomodules/api": "^2.0.0-alpha.6",
@@ -95,21 +95,8 @@ export class FaustAudioWorkletNode<Poly extends boolean = false> extends (global
95
95
  async startSensors() {
96
96
  if (this.hasAccInput) {
97
97
  if (window.DeviceMotionEvent) {
98
- if (typeof (window.DeviceMotionEvent as any).requestPermission === "function") { // for iOS 13+
99
- try {
100
- const response = await (window.DeviceMotionEvent as any).requestPermission();
101
- if (response === "granted") {
102
- window.addEventListener("devicemotion", this.handleDeviceMotion, true);
103
- } else if (response === "denied") {
104
- alert('You have denied access to motion and orientation data. To enable it, go to Settings > Safari > Motion & Orientation Access.');
105
- throw new Error("Unable to access the accelerometer.");
106
- }
107
- } catch (error) {
108
- console.error(error);
109
- }
110
- } else {
111
- window.addEventListener("devicemotion", this.handleDeviceMotion, true);
112
- }
98
+ // iOS 13+ requires a user gesture to enable DeviceMotionEvent, to be done in the main thread
99
+ window.addEventListener("devicemotion", this.handleDeviceMotion, true);
113
100
  } else {
114
101
  // Browser doesn't support DeviceMotionEvent
115
102
  console.log("Cannot set the accelerometer handler.");
@@ -117,21 +104,8 @@ export class FaustAudioWorkletNode<Poly extends boolean = false> extends (global
117
104
  }
118
105
  if (this.hasGyrInput) {
119
106
  if (window.DeviceMotionEvent) {
120
- if (typeof (window.DeviceOrientationEvent as any).requestPermission === "function") { // for iOS 13+
121
- try {
122
- const response = await (window.DeviceOrientationEvent as any).requestPermission();
123
- if (response === "granted") {
124
- window.addEventListener("deviceorientation", this.handleDeviceOrientation, true);
125
- } else if (response === "denied") {
126
- alert('You have denied access to motion and orientation data. To enable it, go to Settings > Safari > Motion & Orientation Access.');
127
- throw new Error("Unable to access the gyroscope.");
128
- }
129
- } catch (error) {
130
- console.error(error);
131
- }
132
- } else {
133
- window.addEventListener("deviceorientation", this.handleDeviceOrientation, true);
134
- }
107
+ // iOS 13+ requires a user gesture to enable DeviceMotionEvent, to be done in the main thread
108
+ window.addEventListener("deviceorientation", this.handleDeviceOrientation, true);
135
109
  } else {
136
110
  // Browser doesn't support DeviceMotionEvent
137
111
  console.log("Cannot set the gyroscope handler.");
@@ -204,6 +178,8 @@ export class FaustAudioWorkletNode<Poly extends boolean = false> extends (global
204
178
  const data2 = data[2];
205
179
  if (cmd === 11) this.ctrlChange(channel, data1, data2);
206
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);
207
183
  else this.port.postMessage({ type: "midi", data: data });
208
184
  }
209
185
 
@@ -215,6 +191,14 @@ export class FaustAudioWorkletNode<Poly extends boolean = false> extends (global
215
191
  const e = { type: "pitchWheel", data: [channel, wheel] };
216
192
  this.port.postMessage(e);
217
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
+ }
218
202
 
219
203
  get hasAccInput() { return this.#hasAccInput; }
220
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); }
@@ -54,21 +54,8 @@ export class FaustScriptProcessorNode<Poly extends boolean = false> extends (glo
54
54
  async startSensors() {
55
55
  if (this.hasAccInput) {
56
56
  if (window.DeviceMotionEvent) {
57
- if (typeof (window.DeviceMotionEvent as any).requestPermission === "function") { // for iOS 13+
58
- try {
59
- const response = await (window.DeviceMotionEvent as any).requestPermission();
60
- if (response === "granted") {
61
- window.addEventListener("devicemotion", this.handleDeviceMotion, true);
62
- } else if (response === "denied") {
63
- alert('You have denied access to motion and orientation data. To enable it, go to Settings > Safari > Motion & Orientation Access.');
64
- throw new Error("Unable to access the accelerometer.");
65
- }
66
- } catch (error) {
67
- console.error(error);
68
- }
69
- } else {
70
- window.addEventListener("devicemotion", this.handleDeviceMotion, true);
71
- }
57
+ // iOS 13+ requires a user gesture to enable DeviceMotionEvent, to be done in the main thread
58
+ window.addEventListener("devicemotion", this.handleDeviceMotion, true);
72
59
  } else {
73
60
  // Browser doesn't support DeviceMotionEvent
74
61
  console.log("Cannot set the accelerometer handler.");
@@ -76,21 +63,8 @@ export class FaustScriptProcessorNode<Poly extends boolean = false> extends (glo
76
63
  }
77
64
  if (this.hasGyrInput) {
78
65
  if (window.DeviceMotionEvent) {
79
- if (typeof (window.DeviceOrientationEvent as any).requestPermission === "function") { // for iOS 13+
80
- try {
81
- const response = await (window.DeviceOrientationEvent as any).requestPermission();
82
- if (response === "granted") {
83
- window.addEventListener("deviceorientation", this.handleDeviceOrientation, true);
84
- } else if (response === "denied") {
85
- alert('You have denied access to motion and orientation data. To enable it, go to Settings > Safari > Motion & Orientation Access.');
86
- throw new Error("Unable to access the gyroscope.");
87
- }
88
- } catch (error) {
89
- console.error(error);
90
- }
91
- } else {
92
- window.addEventListener("deviceorientation", this.handleDeviceOrientation, true);
93
- }
66
+ // iOS 13+ requires a user gesture to enable DeviceMotionEvent, to be done in the main thread
67
+ window.addEventListener("deviceorientation", this.handleDeviceOrientation, true);
94
68
  } else {
95
69
  // Browser doesn't support DeviceMotionEvent
96
70
  console.log("Cannot set the gyroscope handler.");
@@ -128,6 +102,8 @@ export class FaustScriptProcessorNode<Poly extends boolean = false> extends (glo
128
102
 
129
103
  ctrlChange(chan: number, ctrl: number, value: number) { this.fDSPCode.ctrlChange(chan, ctrl, value); }
130
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); }
131
107
 
132
108
  setParamValue(path: string, value: number) { this.fDSPCode.setParamValue(path, value); }
133
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
 
@@ -946,10 +946,10 @@ class Group extends _AbstractComponent__WEBPACK_IMPORTED_MODULE_0__["default"] {
946
946
  if (!metaIn) return { metaObject };
947
947
  metaIn.forEach((m) => Object.assign(metaObject, m));
948
948
  if (metaObject.style) {
949
- const enumsRegex = /\{(?:(?:'|_|-)(.+?)(?:'|_|-):([-+]?[0-9]*\.?[0-9]+?);)+(?:(?:'|_|-)(.+?)(?:'|_|-):([-+]?[0-9]*\.?[0-9]+?))\}/;
949
+ const enumsRegex = /\{(?:(?:'|_|-)(.+?)(?:'|_|-):([-+]?[0-9]*\.?[0-9]+);)+(?:(?:'|_|-)(.+?)(?:'|_|-):([-+]?[0-9]*\.?[0-9]+))\}/;
950
950
  const matched = metaObject.style.match(enumsRegex);
951
951
  if (matched) {
952
- const itemsRegex = /(?:(?:'|_|-)(.+?)(?:'|_|-):([-+]?[0-9]*\.?[0-9]+?))/g;
952
+ const itemsRegex = /(?:(?:'|_|-)(.+?)(?:'|_|-):([-+]?[0-9]*\.?[0-9]+))/g;
953
953
  const enums = {};
954
954
  let item;
955
955
  while (item = itemsRegex.exec(matched[0])) {