@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/assets/standalone/create-node.js +15 -8
- package/assets/standalone/faustwasm/index.d.ts +40 -0
- package/assets/standalone/faustwasm/index.js +109 -30
- package/assets/standalone/faustwasm/index.js.map +2 -2
- package/assets/standalone/index-pwa.js +1 -1
- package/assets/standalone/service-worker.js +58 -5
- package/dist/cjs/index.d.ts +40 -0
- package/dist/cjs/index.js +109 -30
- package/dist/cjs/index.js.map +2 -2
- package/dist/cjs-bundle/index.d.ts +40 -0
- package/dist/cjs-bundle/index.js +109 -30
- package/dist/cjs-bundle/index.js.map +2 -2
- package/dist/esm/index.d.ts +40 -0
- package/dist/esm/index.js +109 -30
- package/dist/esm/index.js.map +2 -2
- package/dist/esm-bundle/index.d.ts +40 -0
- package/dist/esm-bundle/index.js +109 -30
- package/dist/esm-bundle/index.js.map +2 -2
- package/package.json +1 -1
- package/src/FaustAudioWorkletNode.ts +10 -0
- package/src/FaustAudioWorkletProcessor.ts +16 -0
- package/src/FaustOfflineProcessor.ts +2 -0
- package/src/FaustScriptProcessorNode.ts +2 -0
- package/src/FaustWebAudioDsp.ts +88 -0
- package/src/copyWebStandaloneAssets.js +14 -0
- package/test/faustlive-wasm/faustwasm/index.d.ts +40 -0
- package/test/faustlive-wasm/faustwasm/index.js +109 -30
- package/test/faustlive-wasm/faustwasm/index.js.map +2 -2
- package/test/midi.dsp +8 -1
package/package.json
CHANGED
|
@@ -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); }
|
package/src/FaustWebAudioDsp.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
}
|