cabbage-react 1.0.24 → 1.0.26
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/dist/cabbage/cabbage.d.ts +73 -54
- package/dist/cabbage/cabbage.d.ts.map +1 -1
- package/dist/hooks/useCabbageProperties.d.ts +1 -1
- package/dist/hooks/useCabbageState.d.ts +3 -3
- package/dist/hooks/useCabbageState.d.ts.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.mjs +214 -223
- package/package.json +1 -1
|
@@ -1,15 +1,11 @@
|
|
|
1
1
|
export class Cabbage {
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* Send a widget value change to the Cabbage backend.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* -
|
|
9
|
-
* The value is sent to the DAW for automation recording and also forwarded to Csound.
|
|
10
|
-
*
|
|
11
|
-
* - `automatable=false`: Routes to `sendChannelData()` for non-automatable data.
|
|
12
|
-
* The value is sent directly to Csound without DAW parameter involvement.
|
|
5
|
+
* The backend automatically determines whether the channel is DAW-automatable
|
|
6
|
+
* and routes accordingly:
|
|
7
|
+
* - Automatable channels -> DAW parameter system -> Csound
|
|
8
|
+
* - Non-automatable channels -> Csound directly
|
|
13
9
|
*
|
|
14
10
|
* **When to use**: Call this from widget event handlers (e.g., pointer events, input changes)
|
|
15
11
|
* when the user interacts with a widget.
|
|
@@ -17,65 +13,64 @@ export class Cabbage {
|
|
|
17
13
|
* **When NOT to use**: Do not call this when handling incoming `parameterChange` messages
|
|
18
14
|
* from the backend. Those messages are for display updates only.
|
|
19
15
|
*
|
|
20
|
-
* @param {Object}
|
|
21
|
-
* @param {string}
|
|
22
|
-
* @param {number}
|
|
23
|
-
* @param {
|
|
16
|
+
* @param {Object} data - The control data to send
|
|
17
|
+
* @param {string} data.channel - The channel name
|
|
18
|
+
* @param {number|string} data.value - The value to send in its natural/meaningful range (e.g., 20-20000 Hz for filter frequency). The backend handles all normalization needed by the host DAW. This value can be a number or string depending on the widget type.
|
|
19
|
+
* @param {string} [data.gesture="complete"] - The gesture type: "begin" (start of interaction), "value" (during interaction), "end" (end of continuous interaction), or "complete" (discrete action e.g. button click).
|
|
24
20
|
* @param {Object|null} vscode - VS Code API object (null for plugin mode)
|
|
25
|
-
* @param {boolean} automatable - Whether this widget is DAW-automatable
|
|
26
21
|
*/
|
|
27
|
-
static
|
|
22
|
+
static sendControlData({ channel, value, gesture }: {
|
|
28
23
|
channel: string;
|
|
29
|
-
paramIdx: number;
|
|
30
24
|
value: number | string;
|
|
31
|
-
|
|
25
|
+
gesture?: string | undefined;
|
|
26
|
+
}, vscode?: Object | null): void;
|
|
32
27
|
/**
|
|
33
|
-
*
|
|
34
|
-
* Use `sendChannelUpdate()` instead - it will route here automatically for automatable widgets.
|
|
28
|
+
* Signal that the UI is ready to load and initialize.
|
|
35
29
|
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
*
|
|
42
|
-
* 2. DAW receives and records/processes the value
|
|
43
|
-
* 3. DAW sends `parameterChange` back to the plugin
|
|
44
|
-
* 4. Plugin updates Csound and sends `parameterChange` to UI
|
|
45
|
-
* 5. UI updates its display (but does NOT call sendParameterUpdate again!)
|
|
30
|
+
* @param {Object|null} vscode - VS Code API object (null for plugin mode)
|
|
31
|
+
* @param {Object} additionalData - Additional initialization data
|
|
32
|
+
*/
|
|
33
|
+
static isReadyToLoad(vscode?: Object | null, additionalData?: Object): void;
|
|
34
|
+
/**
|
|
35
|
+
* Send a MIDI message from the UI to the Cabbage backend.
|
|
46
36
|
*
|
|
47
|
-
* @param {
|
|
48
|
-
* @param {number}
|
|
49
|
-
* @param {
|
|
50
|
-
* @param {number} message.value - The parameter value (full range, not normalized)
|
|
51
|
-
* @param {string} [message.channelType="number"] - The channel type
|
|
37
|
+
* @param {number} statusByte - MIDI status byte
|
|
38
|
+
* @param {number} dataByte1 - First MIDI data byte
|
|
39
|
+
* @param {number} dataByte2 - Second MIDI data byte
|
|
52
40
|
* @param {Object|null} vscode - VS Code API object (null for plugin mode)
|
|
53
41
|
*/
|
|
54
|
-
static
|
|
55
|
-
paramIdx: number;
|
|
56
|
-
channel: string;
|
|
57
|
-
value: number;
|
|
58
|
-
channelType?: string | undefined;
|
|
59
|
-
}, vscode?: Object | null): void;
|
|
60
|
-
static sendCustomCommand(command: any, vscode?: null, additionalData?: {}): void;
|
|
61
|
-
static sendWidgetUpdate(widget: any, vscode?: null): void;
|
|
62
|
-
static sendMidiMessageFromUI(statusByte: any, dataByte1: any, dataByte2: any, vscode?: null): void;
|
|
42
|
+
static sendMidiMessageFromUI(statusByte: number, dataByte1: number, dataByte2: number, vscode?: Object | null): void;
|
|
63
43
|
/**
|
|
64
|
-
*
|
|
65
|
-
* Use `sendChannelUpdate()` instead - it will route here automatically for non-automatable widgets.
|
|
44
|
+
* Handle incoming MIDI messages from the backend.
|
|
66
45
|
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
46
|
+
* @param {number} statusByte - MIDI status byte
|
|
47
|
+
* @param {number} dataByte1 - First MIDI data byte
|
|
48
|
+
* @param {number} dataByte2 - Second MIDI data byte
|
|
49
|
+
*/
|
|
50
|
+
static MidiMessageFromHost(statusByte: number, dataByte1: number, dataByte2: number): void;
|
|
51
|
+
/**
|
|
52
|
+
* Trigger a native file open dialog for file selection widgets.
|
|
70
53
|
*
|
|
71
|
-
* @param {string} channel - The Csound channel name
|
|
72
|
-
* @param {number|string} data - The data to send (number or string)
|
|
73
54
|
* @param {Object|null} vscode - VS Code API object (null for plugin mode)
|
|
55
|
+
* @param {string} channel - The associated channel name
|
|
56
|
+
* @param {Object} options - Dialog options
|
|
57
|
+
* @param {string} [options.directory] - Starting directory path
|
|
58
|
+
* @param {string} [options.filters="*"] - File filters (e.g., "*.wav;*.aiff")
|
|
59
|
+
* @param {boolean} [options.openAtLastKnownLocation=true] - Whether to open at last known location
|
|
74
60
|
*/
|
|
75
|
-
static
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
61
|
+
static triggerFileOpenDialog(vscode: Object | null, channel: string, options?: {
|
|
62
|
+
directory?: string | undefined;
|
|
63
|
+
filters?: string | undefined;
|
|
64
|
+
openAtLastKnownLocation?: boolean | undefined;
|
|
65
|
+
}): void;
|
|
66
|
+
/**
|
|
67
|
+
* Open a URL or file in the system's default application.
|
|
68
|
+
*
|
|
69
|
+
* @param {Object|null} vscode - VS Code API object (null for plugin mode)
|
|
70
|
+
* @param {string} url - URL to open
|
|
71
|
+
* @param {string} file - File path to open
|
|
72
|
+
*/
|
|
73
|
+
static openUrl(vscode: Object | null, url: string, file: string): void;
|
|
79
74
|
/**
|
|
80
75
|
* Request a resize of the plugin GUI window.
|
|
81
76
|
* This is only supported in plugin mode (CLAP/VST3/AUv2).
|
|
@@ -89,5 +84,29 @@ export class Cabbage {
|
|
|
89
84
|
* {command: "resizeResponse", accepted: boolean, width: number, height: number}
|
|
90
85
|
*/
|
|
91
86
|
static requestResize(width: number, height: number, vscode?: object): void;
|
|
87
|
+
/**
|
|
88
|
+
* Send channel data directly to Csound without DAW automation involvement.
|
|
89
|
+
*
|
|
90
|
+
* @param {string} channel - The Csound channel name
|
|
91
|
+
* @param {number|string} data - The data to send (number or string)
|
|
92
|
+
* @param {Object|null} vscode - VS Code API object (null for plugin mode)
|
|
93
|
+
*/
|
|
94
|
+
static sendChannelData(channel: string, data: number | string, vscode?: Object | null): void;
|
|
95
|
+
/**
|
|
96
|
+
* Send a widget state update to the Cabbage backend (used by property panel).
|
|
97
|
+
*
|
|
98
|
+
* @private
|
|
99
|
+
* @param {Object} widget - The widget configuration object to update
|
|
100
|
+
* @param {Object|null} vscode - VS Code API object (null for plugin mode)
|
|
101
|
+
*/
|
|
102
|
+
private static sendWidgetUpdate;
|
|
103
|
+
/**
|
|
104
|
+
* Send a custom command to the Cabbage backend.
|
|
105
|
+
*
|
|
106
|
+
* @param {string} command - The command name to send
|
|
107
|
+
* @param {Object|null} vscode - VS Code API object (null for plugin mode)
|
|
108
|
+
* @param {Object} additionalData - Additional data to include in the command
|
|
109
|
+
*/
|
|
110
|
+
static sendCustomCommand(command: string, vscode?: Object | null, additionalData?: Object): void;
|
|
92
111
|
}
|
|
93
112
|
//# sourceMappingURL=cabbage.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cabbage.d.ts","sourceRoot":"","sources":["../../src/cabbage/cabbage.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"cabbage.d.ts","sourceRoot":"","sources":["../../src/cabbage/cabbage.js"],"names":[],"mappings":"AA4FA;IACC;;;;;;;;;;;;;;;;;;;OAmBG;IACH,oDALG;QAAqB,OAAO,EAApB,MAAM;QACc,KAAK,EAAzB,MAAM,GAAC,MAAM;QACC,OAAO;KAC7B,WAAQ,MAAM,GAAC,IAAI,QAyBrB;IAED;;;;;OAKG;IACH,8BAHW,MAAM,GAAC,IAAI,mBACX,MAAM,QAIhB;IACD;;;;;;;OAOG;IACH,yCALW,MAAM,aACN,MAAM,aACN,MAAM,WACN,MAAM,GAAC,IAAI,QA+BrB;IAED;;;;;;OAMG;IACH,uCAJW,MAAM,aACN,MAAM,aACN,MAAM,QAWhB;IAED;;;;;;;;;OASG;IACH,qCAPW,MAAM,GAAC,IAAI,WACX,MAAM,YAEd;QAAyB,SAAS;QACT,OAAO;QACN,uBAAuB;KACnD,QA4BA;IAED;;;;;;OAMG;IACH,uBAJW,MAAM,GAAC,IAAI,OACX,MAAM,QACN,MAAM,QAwBhB;IAED;;;;;;;;;;;OAWG;IACH,4BAPW,MAAM,UACN,MAAM,WACN,MAAM,QA4BhB;IAED;;;;;;OAMG;IACH,gCAJW,MAAM,QACN,MAAM,GAAC,MAAM,WACb,MAAM,GAAC,IAAI,QAsCrB;IAED;;;;;;OAMG;IACH,gCAiBC;IAED;;;;;;OAMG;IACH,kCAJW,MAAM,WACN,MAAM,GAAC,IAAI,mBACX,MAAM,QAmChB;CACD"}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Custom hook to get a parameter's properties from Cabbage.
|
|
3
3
|
* This hook listens for updates to parameter properties via Cabbage and updates the local state
|
|
4
4
|
* whenever new data is received.
|
|
5
|
-
* @param channelId - The
|
|
5
|
+
* @param channelId - The channel name
|
|
6
6
|
*/
|
|
7
7
|
export declare const useCabbageProperties: (channelId: string) => {
|
|
8
8
|
properties: Record<string, any> | undefined;
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
* Custom hook to sync a parameter with Cabbage.
|
|
3
3
|
* This hook listens for updates to a parameter value from Cabbage and
|
|
4
4
|
* sends updates to Cabbage when the parameter value changes locally (e.g., through a UI slider).
|
|
5
|
-
* @param channelId - The
|
|
6
|
-
* @param
|
|
5
|
+
* @param channelId - The channel name
|
|
6
|
+
* @param gesture - The gesture type: "begin" (start of interaction), "value" (during interaction), "end" (end of continuous interaction), or "complete" (discrete action e.g. button click).
|
|
7
7
|
*/
|
|
8
|
-
export declare const useCabbageState: <T>(channelId: string,
|
|
8
|
+
export declare const useCabbageState: <T>(channelId: string, gesture?: "begin" | "value" | "end" | "complete") => {
|
|
9
9
|
value: T | undefined;
|
|
10
10
|
setValue: (value: T) => void;
|
|
11
11
|
parameterIndex: number | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useCabbageState.d.ts","sourceRoot":"","sources":["../../src/hooks/useCabbageState.ts"],"names":[],"mappings":"AAIA;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,GAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"useCabbageState.d.ts","sourceRoot":"","sources":["../../src/hooks/useCabbageState.ts"],"names":[],"mappings":"AAIA;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,GAAI,CAAC,aACrB,MAAM,YACR,OAAO,GAAG,OAAO,GAAG,KAAK,GAAG,UAAU;;sBAOb,CAAC;;CAyFnC,CAAC"}
|
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const m=require("react");console.log("Cabbage: loading cabbage.js");class
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const m=require("react");console.log("Cabbage: loading cabbage.js");class p{static sendControlData({channel:o,value:e,gesture:a="complete"},n=null){const s={command:"controlData",channel:o,value:e,gesture:a};n!==null?n.postMessage(s):typeof window.sendMessageFromUI=="function"?window.sendMessageFromUI(s):console.error("Cabbage: window.sendMessageFromUI is not available. Message:",s)}static isReadyToLoad(o=null,e={}){this.sendCustomCommand("isReadyToLoad",o)}static sendMidiMessageFromUI(o,e,a,n=null){var s={statusByte:o,dataByte1:e,dataByte2:a};const d={command:"midiMessage",obj:JSON.stringify(s)};n!==null?n.postMessage(d):typeof window.sendMessageFromUI=="function"?window.sendMessageFromUI(d):console.error("Cabbage: window.sendMessageFromUI is not available. Message:",d)}static MidiMessageFromHost(o,e,a){console.log("Cabbage: Got MIDI Message"+o+":"+e+":"+a)}static triggerFileOpenDialog(o,e,a={}){var n={channel:e,directory:a.directory||"",filters:a.filters||"*",openAtLastKnownLocation:a.openAtLastKnownLocation!==void 0?a.openAtLastKnownLocation:!0};const s={command:"fileOpen",obj:JSON.stringify(n)};o!==null?o.postMessage(s):typeof window.sendMessageFromUI=="function"?window.sendMessageFromUI(s):console.error("Cabbage: window.sendMessageFromUI is not available. Message:",s)}static openUrl(o,e,a){var n={url:e,file:a};const s={command:"openUrl",obj:JSON.stringify(n)};o!==null?o.postMessage(s):typeof window.sendMessageFromUI=="function"?window.sendMessageFromUI(s):console.error("Cabbage: window.sendMessageFromUI is not available. Message:",s)}static requestResize(o,e,a=null){const n={command:"requestResize",width:o,height:e};if(a!==null){console.warn("Cabbage: requestResize is not supported in VS Code extension mode");return}else typeof window.sendMessageFromUI=="function"?window.sendMessageFromUI(n):console.error("Cabbage: window.sendMessageFromUI is not available. Message:",n)}static sendChannelData(o,e,a=null){var n={channel:o};if(typeof e=="string")n.stringData=e;else if(typeof e=="number")n.floatData=e;else{console.warn("Cabbage: sendChannelData received unsupported data type:",typeof e);return}const s={command:"channelData",obj:JSON.stringify(n)};console.log("Cabbage: sending channel data from UI",n),a!==null?a.postMessage(s):typeof window.sendMessageFromUI=="function"?window.sendMessageFromUI(s):console.error("Cabbage: window.sendMessageFromUI is not available. Message:",s)}static sendWidgetUpdate(o,e=null){const a={command:"widgetStateUpdate",obj:JSON.stringify(CabbageUtils.sanitizeForEditor(o))};e!==null?e.postMessage(a):typeof window.sendMessageFromUI=="function"?window.sendMessageFromUI(a):console.error("Cabbage: window.sendMessageFromUI is not available. Message:",a)}static sendCustomCommand(o,e=null,a={}){const n={command:o,text:JSON.stringify(a)};if(e!==null)e.postMessage(n);else if(typeof window.sendMessageFromUI=="function"){console.log("Cabbage: Calling window.sendMessageFromUI with:",n);try{const s=window.sendMessageFromUI(n);console.log("Cabbage: sendMessageFromUI returned:",s)}catch(s){console.error("Cabbage: sendMessageFromUI threw error:",s),console.error("Cabbage: Error stack:",s.stack)}}else console.error("Cabbage: window.sendMessageFromUI is not available yet. Message:",n),console.error("Cabbage: typeof window.sendMessageFromUI:",typeof window.sendMessageFromUI),console.error("Cabbage: window.sendMessageFromUI value:",window.sendMessageFromUI)}}const C=r=>{const[o,e]=m.useState();return m.useEffect(()=>{const a=n=>{const{id:s,widgetJson:d,command:w}=n.data;if(s===r&&d&&w==="widgetUpdate"){const t=JSON.parse(d);console.log(`[Cabbage-React] Received properties for channelId ${s}`,t),e(t)}};return window.addEventListener("message",a),()=>{window.removeEventListener("message",a)}},[]),{properties:o}},I=(r,o="complete")=>{const{properties:e}=C(r),[a,n]=m.useState(),[s,d]=m.useState(),w=t=>{n(t),p.sendControlData({channel:r,value:t,gesture:o})};return m.useEffect(()=>{var b;const t=e==null?void 0:e.channels.find(i=>i.id===r);if(!t)return;const l=t==null?void 0:t.parameterIndex;s===void 0&&l!==void 0&&(console.log(`[Cabbage-React] Received parameterIndex for channelId "${t.id}"`,l),d(l));const g=(b=t.range)==null?void 0:b.defaultValue;a===void 0&&g!==void 0&&(console.log(`[Cabbage-React] Received default value for channelId "${t.id}"`,g),n(g))},[e]),m.useEffect(()=>{const t=l=>{var b;const{command:g}=l.data;if(g==="parameterChange"){const{value:i,paramIdx:c}=l.data.data;if(c!==s||i===null)return;console.log(`[Cabbage-React] Received parameterChange for parameterIndex ${c}`,i),n(i)}else if(g==="batchWidgetUpdate"){const i=l.data.widgets,c=i==null?void 0:i.find(f=>f.id===r);if(!c)return;const u=JSON.parse(c.widgetJson).channels.find(f=>f.id===r),M=(b=u==null?void 0:u.range)==null?void 0:b.value;console.log(`[Cabbage-React] Received batch widget update for channelId ${c.id}`,M),n(M)}};return window.addEventListener("message",t),()=>{window.removeEventListener("message",t)}},[s]),{value:a,setValue:w,parameterIndex:s}};exports.Cabbage=p;exports.useCabbageProperties=C;exports.useCabbageState=I;
|
package/dist/index.mjs
CHANGED
|
@@ -1,17 +1,13 @@
|
|
|
1
|
-
import { useState as
|
|
1
|
+
import { useState as u, useEffect as M } from "react";
|
|
2
2
|
console.log("Cabbage: loading cabbage.js");
|
|
3
|
-
class
|
|
3
|
+
class I {
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
5
|
+
* Send a widget value change to the Cabbage backend.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* -
|
|
11
|
-
* The value is sent to the DAW for automation recording and also forwarded to Csound.
|
|
12
|
-
*
|
|
13
|
-
* - `automatable=false`: Routes to `sendChannelData()` for non-automatable data.
|
|
14
|
-
* The value is sent directly to Csound without DAW parameter involvement.
|
|
7
|
+
* The backend automatically determines whether the channel is DAW-automatable
|
|
8
|
+
* and routes accordingly:
|
|
9
|
+
* - Automatable channels -> DAW parameter system -> Csound
|
|
10
|
+
* - Non-automatable channels -> Csound directly
|
|
15
11
|
*
|
|
16
12
|
* **When to use**: Call this from widget event handlers (e.g., pointer events, input changes)
|
|
17
13
|
* when the user interacts with a widget.
|
|
@@ -19,191 +15,113 @@ class f {
|
|
|
19
15
|
* **When NOT to use**: Do not call this when handling incoming `parameterChange` messages
|
|
20
16
|
* from the backend. Those messages are for display updates only.
|
|
21
17
|
*
|
|
22
|
-
* @param {Object}
|
|
23
|
-
* @param {string}
|
|
24
|
-
* @param {number}
|
|
25
|
-
* @param {
|
|
18
|
+
* @param {Object} data - The control data to send
|
|
19
|
+
* @param {string} data.channel - The channel name
|
|
20
|
+
* @param {number|string} data.value - The value to send in its natural/meaningful range (e.g., 20-20000 Hz for filter frequency). The backend handles all normalization needed by the host DAW. This value can be a number or string depending on the widget type.
|
|
21
|
+
* @param {string} [data.gesture="complete"] - The gesture type: "begin" (start of interaction), "value" (during interaction), "end" (end of continuous interaction), or "complete" (discrete action e.g. button click).
|
|
26
22
|
* @param {Object|null} vscode - VS Code API object (null for plugin mode)
|
|
27
|
-
* @param {boolean} automatable - Whether this widget is DAW-automatable
|
|
28
23
|
*/
|
|
29
|
-
static
|
|
30
|
-
if (n === !0 || n === 1)
|
|
31
|
-
f.sendParameterUpdate(e, a);
|
|
32
|
-
else {
|
|
33
|
-
const s = e.value !== void 0 ? e.value : e.stringData || e.floatData;
|
|
34
|
-
f.sendChannelData(e.channel, s, a);
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* Internal: Send a parameter update to the DAW for automation recording.
|
|
39
|
-
* Use `sendChannelUpdate()` instead - it will route here automatically for automatable widgets.
|
|
40
|
-
*
|
|
41
|
-
* This function sends the parameter value to the DAW's automation system.
|
|
42
|
-
* The DAW will then send the value back via a `parameterChange` message,
|
|
43
|
-
* which updates both the UI and Csound.
|
|
44
|
-
*
|
|
45
|
-
* **Important**: This creates a round-trip through the DAW:
|
|
46
|
-
* 1. UI calls `sendParameterUpdate()` with value
|
|
47
|
-
* 2. DAW receives and records/processes the value
|
|
48
|
-
* 3. DAW sends `parameterChange` back to the plugin
|
|
49
|
-
* 4. Plugin updates Csound and sends `parameterChange` to UI
|
|
50
|
-
* 5. UI updates its display (but does NOT call sendParameterUpdate again!)
|
|
51
|
-
*
|
|
52
|
-
* @param {Object} message - The parameter message
|
|
53
|
-
* @param {number} message.paramIdx - The parameter index (must be >= 0)
|
|
54
|
-
* @param {string} message.channel - The channel name
|
|
55
|
-
* @param {number} message.value - The parameter value (full range, not normalized)
|
|
56
|
-
* @param {string} [message.channelType="number"] - The channel type
|
|
57
|
-
* @param {Object|null} vscode - VS Code API object (null for plugin mode)
|
|
58
|
-
*/
|
|
59
|
-
static sendParameterUpdate(e, a = null) {
|
|
60
|
-
if (e.paramIdx === void 0 || e.paramIdx === null) {
|
|
61
|
-
console.error(
|
|
62
|
-
"Cabbage.sendParameterUpdate: message missing paramIdx!",
|
|
63
|
-
e
|
|
64
|
-
);
|
|
65
|
-
return;
|
|
66
|
-
}
|
|
67
|
-
if (e.paramIdx < 0) {
|
|
68
|
-
console.warn(
|
|
69
|
-
"Cabbage.sendParameterUpdate: paramIdx is -1, skipping (non-automatable widget)",
|
|
70
|
-
e
|
|
71
|
-
);
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
const n = {
|
|
75
|
-
command: "parameterChange",
|
|
76
|
-
paramIdx: e.paramIdx,
|
|
77
|
-
channel: e.channel,
|
|
78
|
-
value: e.value,
|
|
79
|
-
channelType: e.channelType || "number"
|
|
80
|
-
};
|
|
81
|
-
a !== null ? a.postMessage(n) : typeof window.sendMessageFromUI == "function" ? window.sendMessageFromUI(n) : console.error(
|
|
82
|
-
"Cabbage: window.sendMessageFromUI is not available. Message:",
|
|
83
|
-
n
|
|
84
|
-
);
|
|
85
|
-
}
|
|
86
|
-
static sendCustomCommand(e, a = null, n = {}) {
|
|
24
|
+
static sendControlData({ channel: o, value: e, gesture: a = "complete" }, n = null) {
|
|
87
25
|
const s = {
|
|
88
|
-
command:
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
a.postMessage(s);
|
|
93
|
-
else if (typeof window.sendMessageFromUI == "function") {
|
|
94
|
-
console.log("Cabbage: Calling window.sendMessageFromUI with:", s);
|
|
95
|
-
try {
|
|
96
|
-
const o = window.sendMessageFromUI(s);
|
|
97
|
-
console.log("Cabbage: sendMessageFromUI returned:", o);
|
|
98
|
-
} catch (o) {
|
|
99
|
-
console.error("Cabbage: sendMessageFromUI threw error:", o), console.error("Cabbage: Error stack:", o.stack);
|
|
100
|
-
}
|
|
101
|
-
} else
|
|
102
|
-
console.error(
|
|
103
|
-
"Cabbage: window.sendMessageFromUI is not available yet. Message:",
|
|
104
|
-
s
|
|
105
|
-
), console.error(
|
|
106
|
-
"Cabbage: typeof window.sendMessageFromUI:",
|
|
107
|
-
typeof window.sendMessageFromUI
|
|
108
|
-
), console.error(
|
|
109
|
-
"Cabbage: window.sendMessageFromUI value:",
|
|
110
|
-
window.sendMessageFromUI
|
|
111
|
-
);
|
|
112
|
-
}
|
|
113
|
-
static sendWidgetUpdate(e, a = null) {
|
|
114
|
-
const n = {
|
|
115
|
-
command: "widgetStateUpdate",
|
|
116
|
-
obj: JSON.stringify(CabbageUtils.sanitizeForEditor(e))
|
|
26
|
+
command: "controlData",
|
|
27
|
+
channel: o,
|
|
28
|
+
value: e,
|
|
29
|
+
gesture: a
|
|
117
30
|
};
|
|
118
|
-
|
|
31
|
+
n !== null ? n.postMessage(s) : typeof window.sendMessageFromUI == "function" ? window.sendMessageFromUI(s) : console.error(
|
|
119
32
|
"Cabbage: window.sendMessageFromUI is not available. Message:",
|
|
120
|
-
|
|
121
|
-
);
|
|
122
|
-
}
|
|
123
|
-
static sendMidiMessageFromUI(e, a, n, s = null) {
|
|
124
|
-
var o = {
|
|
125
|
-
statusByte: e,
|
|
126
|
-
dataByte1: a,
|
|
127
|
-
dataByte2: n
|
|
128
|
-
};
|
|
129
|
-
const l = {
|
|
130
|
-
command: "midiMessage",
|
|
131
|
-
obj: JSON.stringify(o)
|
|
132
|
-
};
|
|
133
|
-
s !== null ? s.postMessage(l) : typeof window.sendMessageFromUI == "function" ? window.sendMessageFromUI(l) : console.error(
|
|
134
|
-
"Cabbage: window.sendMessageFromUI is not available. Message:",
|
|
135
|
-
l
|
|
33
|
+
s
|
|
136
34
|
);
|
|
137
35
|
}
|
|
138
36
|
/**
|
|
139
|
-
*
|
|
140
|
-
* Use `sendChannelUpdate()` instead - it will route here automatically for non-automatable widgets.
|
|
37
|
+
* Signal that the UI is ready to load and initialize.
|
|
141
38
|
*
|
|
142
|
-
*
|
|
143
|
-
*
|
|
144
|
-
|
|
39
|
+
* @param {Object|null} vscode - VS Code API object (null for plugin mode)
|
|
40
|
+
* @param {Object} additionalData - Additional initialization data
|
|
41
|
+
*/
|
|
42
|
+
static isReadyToLoad(o = null, e = {}) {
|
|
43
|
+
this.sendCustomCommand("isReadyToLoad", o);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Send a MIDI message from the UI to the Cabbage backend.
|
|
145
47
|
*
|
|
146
|
-
* @param {
|
|
147
|
-
* @param {number
|
|
48
|
+
* @param {number} statusByte - MIDI status byte
|
|
49
|
+
* @param {number} dataByte1 - First MIDI data byte
|
|
50
|
+
* @param {number} dataByte2 - Second MIDI data byte
|
|
148
51
|
* @param {Object|null} vscode - VS Code API object (null for plugin mode)
|
|
149
52
|
*/
|
|
150
|
-
static
|
|
53
|
+
static sendMidiMessageFromUI(o, e, a, n = null) {
|
|
151
54
|
var s = {
|
|
152
|
-
|
|
55
|
+
statusByte: o,
|
|
56
|
+
dataByte1: e,
|
|
57
|
+
dataByte2: a
|
|
153
58
|
};
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
else if (typeof a == "number")
|
|
157
|
-
s.floatData = a;
|
|
158
|
-
else {
|
|
159
|
-
console.warn(
|
|
160
|
-
"Cabbage: sendChannelData received unsupported data type:",
|
|
161
|
-
typeof a
|
|
162
|
-
);
|
|
163
|
-
return;
|
|
164
|
-
}
|
|
165
|
-
const o = {
|
|
166
|
-
command: "channelData",
|
|
59
|
+
const d = {
|
|
60
|
+
command: "midiMessage",
|
|
167
61
|
obj: JSON.stringify(s)
|
|
168
62
|
};
|
|
169
|
-
|
|
63
|
+
n !== null ? n.postMessage(d) : typeof window.sendMessageFromUI == "function" ? window.sendMessageFromUI(d) : console.error(
|
|
170
64
|
"Cabbage: window.sendMessageFromUI is not available. Message:",
|
|
171
|
-
|
|
65
|
+
d
|
|
172
66
|
);
|
|
173
67
|
}
|
|
174
|
-
|
|
68
|
+
/**
|
|
69
|
+
* Handle incoming MIDI messages from the backend.
|
|
70
|
+
*
|
|
71
|
+
* @param {number} statusByte - MIDI status byte
|
|
72
|
+
* @param {number} dataByte1 - First MIDI data byte
|
|
73
|
+
* @param {number} dataByte2 - Second MIDI data byte
|
|
74
|
+
*/
|
|
75
|
+
static MidiMessageFromHost(o, e, a) {
|
|
175
76
|
console.log(
|
|
176
|
-
"Cabbage: Got MIDI Message" +
|
|
77
|
+
"Cabbage: Got MIDI Message" + o + ":" + e + ":" + a
|
|
177
78
|
);
|
|
178
79
|
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
80
|
+
/**
|
|
81
|
+
* Trigger a native file open dialog for file selection widgets.
|
|
82
|
+
*
|
|
83
|
+
* @param {Object|null} vscode - VS Code API object (null for plugin mode)
|
|
84
|
+
* @param {string} channel - The associated channel name
|
|
85
|
+
* @param {Object} options - Dialog options
|
|
86
|
+
* @param {string} [options.directory] - Starting directory path
|
|
87
|
+
* @param {string} [options.filters="*"] - File filters (e.g., "*.wav;*.aiff")
|
|
88
|
+
* @param {boolean} [options.openAtLastKnownLocation=true] - Whether to open at last known location
|
|
89
|
+
*/
|
|
90
|
+
static triggerFileOpenDialog(o, e, a = {}) {
|
|
91
|
+
var n = {
|
|
92
|
+
channel: e,
|
|
93
|
+
directory: a.directory || "",
|
|
94
|
+
filters: a.filters || "*",
|
|
95
|
+
openAtLastKnownLocation: a.openAtLastKnownLocation !== void 0 ? a.openAtLastKnownLocation : !0
|
|
185
96
|
};
|
|
186
|
-
const
|
|
97
|
+
const s = {
|
|
187
98
|
command: "fileOpen",
|
|
188
|
-
obj: JSON.stringify(
|
|
99
|
+
obj: JSON.stringify(n)
|
|
189
100
|
};
|
|
190
|
-
|
|
101
|
+
o !== null ? o.postMessage(s) : typeof window.sendMessageFromUI == "function" ? window.sendMessageFromUI(s) : console.error(
|
|
191
102
|
"Cabbage: window.sendMessageFromUI is not available. Message:",
|
|
192
|
-
|
|
103
|
+
s
|
|
193
104
|
);
|
|
194
105
|
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
106
|
+
/**
|
|
107
|
+
* Open a URL or file in the system's default application.
|
|
108
|
+
*
|
|
109
|
+
* @param {Object|null} vscode - VS Code API object (null for plugin mode)
|
|
110
|
+
* @param {string} url - URL to open
|
|
111
|
+
* @param {string} file - File path to open
|
|
112
|
+
*/
|
|
113
|
+
static openUrl(o, e, a) {
|
|
114
|
+
var n = {
|
|
115
|
+
url: e,
|
|
116
|
+
file: a
|
|
199
117
|
};
|
|
200
|
-
const
|
|
118
|
+
const s = {
|
|
201
119
|
command: "openUrl",
|
|
202
|
-
obj: JSON.stringify(
|
|
120
|
+
obj: JSON.stringify(n)
|
|
203
121
|
};
|
|
204
|
-
|
|
122
|
+
o !== null ? o.postMessage(s) : typeof window.sendMessageFromUI == "function" ? window.sendMessageFromUI(s) : console.error(
|
|
205
123
|
"Cabbage: window.sendMessageFromUI is not available. Message:",
|
|
206
|
-
|
|
124
|
+
s
|
|
207
125
|
);
|
|
208
126
|
}
|
|
209
127
|
/**
|
|
@@ -218,110 +136,183 @@ class f {
|
|
|
218
136
|
* The response will be sent via hostMessageCallback with:
|
|
219
137
|
* {command: "resizeResponse", accepted: boolean, width: number, height: number}
|
|
220
138
|
*/
|
|
221
|
-
static requestResize(e, a
|
|
222
|
-
const
|
|
139
|
+
static requestResize(o, e, a = null) {
|
|
140
|
+
const n = {
|
|
223
141
|
command: "requestResize",
|
|
224
|
-
width:
|
|
225
|
-
height:
|
|
142
|
+
width: o,
|
|
143
|
+
height: e
|
|
226
144
|
};
|
|
227
|
-
if (
|
|
145
|
+
if (a !== null) {
|
|
228
146
|
console.warn(
|
|
229
147
|
"Cabbage: requestResize is not supported in VS Code extension mode"
|
|
230
148
|
);
|
|
231
149
|
return;
|
|
232
150
|
} else
|
|
233
|
-
typeof window.sendMessageFromUI == "function" ? window.sendMessageFromUI(
|
|
151
|
+
typeof window.sendMessageFromUI == "function" ? window.sendMessageFromUI(n) : console.error(
|
|
234
152
|
"Cabbage: window.sendMessageFromUI is not available. Message:",
|
|
235
|
-
|
|
153
|
+
n
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Send channel data directly to Csound without DAW automation involvement.
|
|
158
|
+
*
|
|
159
|
+
* @param {string} channel - The Csound channel name
|
|
160
|
+
* @param {number|string} data - The data to send (number or string)
|
|
161
|
+
* @param {Object|null} vscode - VS Code API object (null for plugin mode)
|
|
162
|
+
*/
|
|
163
|
+
static sendChannelData(o, e, a = null) {
|
|
164
|
+
var n = {
|
|
165
|
+
channel: o
|
|
166
|
+
};
|
|
167
|
+
if (typeof e == "string")
|
|
168
|
+
n.stringData = e;
|
|
169
|
+
else if (typeof e == "number")
|
|
170
|
+
n.floatData = e;
|
|
171
|
+
else {
|
|
172
|
+
console.warn(
|
|
173
|
+
"Cabbage: sendChannelData received unsupported data type:",
|
|
174
|
+
typeof e
|
|
175
|
+
);
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
const s = {
|
|
179
|
+
command: "channelData",
|
|
180
|
+
obj: JSON.stringify(n)
|
|
181
|
+
};
|
|
182
|
+
console.log("Cabbage: sending channel data from UI", n), a !== null ? a.postMessage(s) : typeof window.sendMessageFromUI == "function" ? window.sendMessageFromUI(s) : console.error(
|
|
183
|
+
"Cabbage: window.sendMessageFromUI is not available. Message:",
|
|
184
|
+
s
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Send a widget state update to the Cabbage backend (used by property panel).
|
|
189
|
+
*
|
|
190
|
+
* @private
|
|
191
|
+
* @param {Object} widget - The widget configuration object to update
|
|
192
|
+
* @param {Object|null} vscode - VS Code API object (null for plugin mode)
|
|
193
|
+
*/
|
|
194
|
+
static sendWidgetUpdate(o, e = null) {
|
|
195
|
+
const a = {
|
|
196
|
+
command: "widgetStateUpdate",
|
|
197
|
+
obj: JSON.stringify(CabbageUtils.sanitizeForEditor(o))
|
|
198
|
+
};
|
|
199
|
+
e !== null ? e.postMessage(a) : typeof window.sendMessageFromUI == "function" ? window.sendMessageFromUI(a) : console.error(
|
|
200
|
+
"Cabbage: window.sendMessageFromUI is not available. Message:",
|
|
201
|
+
a
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Send a custom command to the Cabbage backend.
|
|
206
|
+
*
|
|
207
|
+
* @param {string} command - The command name to send
|
|
208
|
+
* @param {Object|null} vscode - VS Code API object (null for plugin mode)
|
|
209
|
+
* @param {Object} additionalData - Additional data to include in the command
|
|
210
|
+
*/
|
|
211
|
+
static sendCustomCommand(o, e = null, a = {}) {
|
|
212
|
+
const n = {
|
|
213
|
+
command: o,
|
|
214
|
+
text: JSON.stringify(a)
|
|
215
|
+
};
|
|
216
|
+
if (e !== null)
|
|
217
|
+
e.postMessage(n);
|
|
218
|
+
else if (typeof window.sendMessageFromUI == "function") {
|
|
219
|
+
console.log("Cabbage: Calling window.sendMessageFromUI with:", n);
|
|
220
|
+
try {
|
|
221
|
+
const s = window.sendMessageFromUI(n);
|
|
222
|
+
console.log("Cabbage: sendMessageFromUI returned:", s);
|
|
223
|
+
} catch (s) {
|
|
224
|
+
console.error("Cabbage: sendMessageFromUI threw error:", s), console.error("Cabbage: Error stack:", s.stack);
|
|
225
|
+
}
|
|
226
|
+
} else
|
|
227
|
+
console.error(
|
|
228
|
+
"Cabbage: window.sendMessageFromUI is not available yet. Message:",
|
|
229
|
+
n
|
|
230
|
+
), console.error(
|
|
231
|
+
"Cabbage: typeof window.sendMessageFromUI:",
|
|
232
|
+
typeof window.sendMessageFromUI
|
|
233
|
+
), console.error(
|
|
234
|
+
"Cabbage: window.sendMessageFromUI value:",
|
|
235
|
+
window.sendMessageFromUI
|
|
236
236
|
);
|
|
237
237
|
}
|
|
238
238
|
}
|
|
239
|
-
const
|
|
240
|
-
const [
|
|
239
|
+
const C = (r) => {
|
|
240
|
+
const [o, e] = u();
|
|
241
241
|
return M(() => {
|
|
242
|
-
const
|
|
243
|
-
const { id:
|
|
244
|
-
if (
|
|
245
|
-
const t = JSON.parse(
|
|
242
|
+
const a = (n) => {
|
|
243
|
+
const { id: s, widgetJson: d, command: w } = n.data;
|
|
244
|
+
if (s === r && d && w === "widgetUpdate") {
|
|
245
|
+
const t = JSON.parse(d);
|
|
246
246
|
console.log(
|
|
247
|
-
`[Cabbage-React] Received properties for channelId ${
|
|
247
|
+
`[Cabbage-React] Received properties for channelId ${s}`,
|
|
248
248
|
t
|
|
249
|
-
),
|
|
249
|
+
), e(t);
|
|
250
250
|
}
|
|
251
251
|
};
|
|
252
|
-
return window.addEventListener("message",
|
|
253
|
-
window.removeEventListener("message",
|
|
252
|
+
return window.addEventListener("message", a), () => {
|
|
253
|
+
window.removeEventListener("message", a);
|
|
254
254
|
};
|
|
255
255
|
}, []), {
|
|
256
|
-
properties:
|
|
256
|
+
properties: o
|
|
257
257
|
};
|
|
258
|
-
},
|
|
259
|
-
const { properties:
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
`[Cabbage-React] parameterIndex not ready for "${d}"`
|
|
263
|
-
);
|
|
264
|
-
return;
|
|
265
|
-
}
|
|
266
|
-
const r = {
|
|
267
|
-
paramIdx: o,
|
|
268
|
-
channel: d,
|
|
258
|
+
}, y = (r, o = "complete") => {
|
|
259
|
+
const { properties: e } = C(r), [a, n] = u(), [s, d] = u(), w = (t) => {
|
|
260
|
+
n(t), I.sendControlData({
|
|
261
|
+
channel: r,
|
|
269
262
|
value: t,
|
|
270
|
-
|
|
271
|
-
};
|
|
272
|
-
f.sendParameterUpdate(r, null);
|
|
263
|
+
gesture: o
|
|
264
|
+
});
|
|
273
265
|
};
|
|
274
266
|
return M(() => {
|
|
275
267
|
var m;
|
|
276
|
-
const t =
|
|
277
|
-
(i) => i.id ===
|
|
268
|
+
const t = e == null ? void 0 : e.channels.find(
|
|
269
|
+
(i) => i.id === r
|
|
278
270
|
);
|
|
279
271
|
if (!t) return;
|
|
280
|
-
const
|
|
281
|
-
|
|
272
|
+
const l = t == null ? void 0 : t.parameterIndex;
|
|
273
|
+
s === void 0 && l !== void 0 && (console.log(
|
|
282
274
|
`[Cabbage-React] Received parameterIndex for channelId "${t.id}"`,
|
|
283
|
-
|
|
284
|
-
), l
|
|
275
|
+
l
|
|
276
|
+
), d(l));
|
|
285
277
|
const g = (m = t.range) == null ? void 0 : m.defaultValue;
|
|
286
|
-
|
|
278
|
+
a === void 0 && g !== void 0 && (console.log(
|
|
287
279
|
`[Cabbage-React] Received default value for channelId "${t.id}"`,
|
|
288
280
|
g
|
|
289
|
-
),
|
|
290
|
-
}, [
|
|
291
|
-
const t = (
|
|
281
|
+
), n(g));
|
|
282
|
+
}, [e]), M(() => {
|
|
283
|
+
const t = (l) => {
|
|
292
284
|
var m;
|
|
293
|
-
const { command: g } =
|
|
285
|
+
const { command: g } = l.data;
|
|
294
286
|
if (g === "parameterChange") {
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
if (c !== o || i === null) return;
|
|
287
|
+
const { value: i, paramIdx: c } = l.data.data;
|
|
288
|
+
if (c !== s || i === null) return;
|
|
298
289
|
console.log(
|
|
299
290
|
`[Cabbage-React] Received parameterChange for parameterIndex ${c}`,
|
|
300
291
|
i
|
|
301
|
-
),
|
|
292
|
+
), n(i);
|
|
302
293
|
} else if (g === "batchWidgetUpdate") {
|
|
303
|
-
const i =
|
|
294
|
+
const i = l.data.widgets, c = i == null ? void 0 : i.find((b) => b.id === r);
|
|
304
295
|
if (!c) return;
|
|
305
|
-
const
|
|
306
|
-
(b) => b.id ===
|
|
307
|
-
),
|
|
296
|
+
const f = JSON.parse(c.widgetJson).channels.find(
|
|
297
|
+
(b) => b.id === r
|
|
298
|
+
), p = (m = f == null ? void 0 : f.range) == null ? void 0 : m.value;
|
|
308
299
|
console.log(
|
|
309
300
|
`[Cabbage-React] Received batch widget update for channelId ${c.id}`,
|
|
310
|
-
|
|
311
|
-
),
|
|
301
|
+
p
|
|
302
|
+
), n(p);
|
|
312
303
|
}
|
|
313
304
|
};
|
|
314
305
|
return window.addEventListener("message", t), () => {
|
|
315
306
|
window.removeEventListener("message", t);
|
|
316
307
|
};
|
|
317
|
-
}, [
|
|
318
|
-
value:
|
|
308
|
+
}, [s]), {
|
|
309
|
+
value: a,
|
|
319
310
|
setValue: w,
|
|
320
|
-
parameterIndex:
|
|
311
|
+
parameterIndex: s
|
|
321
312
|
};
|
|
322
313
|
};
|
|
323
314
|
export {
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
315
|
+
I as Cabbage,
|
|
316
|
+
C as useCabbageProperties,
|
|
317
|
+
y as useCabbageState
|
|
327
318
|
};
|