@signalsandsorcery/plugin-sdk 1.0.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.
- package/dist/index.d.mts +1136 -0
- package/dist/index.d.ts +1136 -0
- package/dist/index.js +1312 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +1261 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +49 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,1261 @@
|
|
|
1
|
+
// src/types/plugin-sdk.types.ts
|
|
2
|
+
var PluginError = class extends Error {
|
|
3
|
+
constructor(code, message, details) {
|
|
4
|
+
super(message);
|
|
5
|
+
this.name = "PluginError";
|
|
6
|
+
this.code = code;
|
|
7
|
+
this.details = details;
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
// src/types/fx-toggle.types.ts
|
|
12
|
+
var FX_CATEGORIES = [
|
|
13
|
+
"eq",
|
|
14
|
+
"compressor",
|
|
15
|
+
"chorus",
|
|
16
|
+
"phaser",
|
|
17
|
+
"delay",
|
|
18
|
+
"reverb"
|
|
19
|
+
];
|
|
20
|
+
var FX_CHAIN_ORDER = {
|
|
21
|
+
eq: 0,
|
|
22
|
+
compressor: 1,
|
|
23
|
+
chorus: 2,
|
|
24
|
+
phaser: 3,
|
|
25
|
+
delay: 4,
|
|
26
|
+
reverb: 5
|
|
27
|
+
};
|
|
28
|
+
var FX_ENGINE_PLUGIN_NAMES = {
|
|
29
|
+
eq: "4bandEq",
|
|
30
|
+
compressor: "compressor",
|
|
31
|
+
chorus: "chorus",
|
|
32
|
+
phaser: "phaser",
|
|
33
|
+
delay: "delay",
|
|
34
|
+
reverb: "reverb"
|
|
35
|
+
};
|
|
36
|
+
var FX_DISPLAY_LABELS = {
|
|
37
|
+
eq: "EQ",
|
|
38
|
+
compressor: "Comp",
|
|
39
|
+
chorus: "Chorus",
|
|
40
|
+
phaser: "Phaser",
|
|
41
|
+
delay: "Delay",
|
|
42
|
+
reverb: "Reverb"
|
|
43
|
+
};
|
|
44
|
+
var EMPTY_FX_STATE = {
|
|
45
|
+
eq: false,
|
|
46
|
+
compressor: false,
|
|
47
|
+
chorus: false,
|
|
48
|
+
phaser: false,
|
|
49
|
+
delay: false,
|
|
50
|
+
reverb: false
|
|
51
|
+
};
|
|
52
|
+
var DEFAULT_FX_DRY_WET = 0.33;
|
|
53
|
+
var DEFAULT_FX_CATEGORY_DETAIL = {
|
|
54
|
+
enabled: false,
|
|
55
|
+
presetIndex: 0,
|
|
56
|
+
dryWet: DEFAULT_FX_DRY_WET
|
|
57
|
+
};
|
|
58
|
+
var EMPTY_FX_DETAIL_STATE = {
|
|
59
|
+
eq: { ...DEFAULT_FX_CATEGORY_DETAIL },
|
|
60
|
+
compressor: { ...DEFAULT_FX_CATEGORY_DETAIL },
|
|
61
|
+
chorus: { ...DEFAULT_FX_CATEGORY_DETAIL },
|
|
62
|
+
phaser: { ...DEFAULT_FX_CATEGORY_DETAIL },
|
|
63
|
+
delay: { ...DEFAULT_FX_CATEGORY_DETAIL },
|
|
64
|
+
reverb: { ...DEFAULT_FX_CATEGORY_DETAIL }
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
// src/components/TrackRow.tsx
|
|
68
|
+
import { AlertCircle } from "lucide-react";
|
|
69
|
+
|
|
70
|
+
// src/components/InstrumentDrawer.tsx
|
|
71
|
+
import { useState, useMemo } from "react";
|
|
72
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
73
|
+
function InstrumentDrawer({
|
|
74
|
+
instruments,
|
|
75
|
+
currentPluginId,
|
|
76
|
+
isLoading,
|
|
77
|
+
onSelect,
|
|
78
|
+
onRefresh
|
|
79
|
+
}) {
|
|
80
|
+
const [search, setSearch] = useState("");
|
|
81
|
+
const SURGE_XT_DEFAULT_ID = "Surge XT";
|
|
82
|
+
const filtered = useMemo(() => {
|
|
83
|
+
const all = instruments.filter(
|
|
84
|
+
(i) => i.name !== "Surge XT"
|
|
85
|
+
);
|
|
86
|
+
if (!search.trim()) return all;
|
|
87
|
+
const q = search.toLowerCase();
|
|
88
|
+
return all.filter(
|
|
89
|
+
(i) => i.name.toLowerCase().includes(q) || i.manufacturer.toLowerCase().includes(q)
|
|
90
|
+
);
|
|
91
|
+
}, [instruments, search]);
|
|
92
|
+
const isDefaultSelected = currentPluginId === null;
|
|
93
|
+
const isSelected = (pluginId) => {
|
|
94
|
+
return pluginId === currentPluginId;
|
|
95
|
+
};
|
|
96
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
97
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
98
|
+
/* @__PURE__ */ jsx(
|
|
99
|
+
"input",
|
|
100
|
+
{
|
|
101
|
+
type: "text",
|
|
102
|
+
value: search,
|
|
103
|
+
onChange: (e) => setSearch(e.target.value),
|
|
104
|
+
placeholder: "Search instruments...",
|
|
105
|
+
className: "sas-input flex-1 px-2 py-1 text-xs"
|
|
106
|
+
}
|
|
107
|
+
),
|
|
108
|
+
/* @__PURE__ */ jsx(
|
|
109
|
+
"button",
|
|
110
|
+
{
|
|
111
|
+
onClick: onRefresh,
|
|
112
|
+
disabled: isLoading,
|
|
113
|
+
className: "px-2 py-1 text-xs rounded-sm border border-sas-border text-sas-muted hover:text-sas-accent hover:border-sas-accent transition-colors disabled:opacity-50",
|
|
114
|
+
title: "Re-scan plugins",
|
|
115
|
+
children: isLoading ? "..." : "Refresh"
|
|
116
|
+
}
|
|
117
|
+
)
|
|
118
|
+
] }),
|
|
119
|
+
isLoading && instruments.length === 0 ? /* @__PURE__ */ jsx("div", { className: "text-xs text-sas-muted/60 text-center py-3", children: "Scanning plugins..." }) : /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-3 gap-1 max-h-[140px] overflow-y-auto", children: [
|
|
120
|
+
/* @__PURE__ */ jsxs(
|
|
121
|
+
"button",
|
|
122
|
+
{
|
|
123
|
+
onClick: () => onSelect(SURGE_XT_DEFAULT_ID),
|
|
124
|
+
className: `flex flex-col items-start px-2 py-1.5 rounded-sm border text-left transition-colors ${isDefaultSelected ? "border-sas-accent bg-sas-accent/20 text-sas-accent" : "border-sas-border bg-sas-panel-alt text-sas-muted hover:border-sas-accent hover:text-sas-accent"}`,
|
|
125
|
+
title: "Surge XT \u2014 Default instrument",
|
|
126
|
+
children: [
|
|
127
|
+
/* @__PURE__ */ jsxs("span", { className: "text-xs font-medium truncate w-full", children: [
|
|
128
|
+
isDefaultSelected && "\u2713 ",
|
|
129
|
+
"Surge XT"
|
|
130
|
+
] }),
|
|
131
|
+
/* @__PURE__ */ jsx("span", { className: "text-[9px] text-sas-muted/50 truncate w-full", children: "Default" })
|
|
132
|
+
]
|
|
133
|
+
},
|
|
134
|
+
"__surge-xt-default__"
|
|
135
|
+
),
|
|
136
|
+
filtered.map((inst) => {
|
|
137
|
+
const selected = isSelected(inst.pluginId);
|
|
138
|
+
return /* @__PURE__ */ jsxs(
|
|
139
|
+
"button",
|
|
140
|
+
{
|
|
141
|
+
onClick: () => onSelect(inst.pluginId),
|
|
142
|
+
className: `flex flex-col items-start px-2 py-1.5 rounded-sm border text-left transition-colors ${selected ? "border-sas-accent bg-sas-accent/20 text-sas-accent" : inst.missing ? "border-amber-500/50 bg-amber-500/10 text-amber-400 hover:border-amber-500" : "border-sas-border bg-sas-panel-alt text-sas-muted hover:border-sas-accent hover:text-sas-accent"}`,
|
|
143
|
+
title: `${inst.name} by ${inst.manufacturer} (${inst.type.toUpperCase()})${inst.missing ? " \u2014 MISSING" : ""}`,
|
|
144
|
+
children: [
|
|
145
|
+
/* @__PURE__ */ jsxs("span", { className: "text-xs font-medium truncate w-full", children: [
|
|
146
|
+
selected && "\u2713 ",
|
|
147
|
+
inst.name
|
|
148
|
+
] }),
|
|
149
|
+
/* @__PURE__ */ jsx("span", { className: "text-[9px] text-sas-muted/50 truncate w-full", children: inst.manufacturer || inst.type.toUpperCase() })
|
|
150
|
+
]
|
|
151
|
+
},
|
|
152
|
+
inst.pluginId
|
|
153
|
+
);
|
|
154
|
+
}),
|
|
155
|
+
filtered.length === 0 && /* @__PURE__ */ jsx("div", { className: "col-span-2 text-xs text-sas-muted/60 text-center py-2", children: search.trim() ? "No matches" : "No other plugins found" })
|
|
156
|
+
] })
|
|
157
|
+
] });
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// src/components/VolumeSlider.tsx
|
|
161
|
+
import { useCallback, useState as useState2, useRef, useEffect } from "react";
|
|
162
|
+
|
|
163
|
+
// src/utils/volume-conversion.ts
|
|
164
|
+
var SLIDER_UNITY = 0.75;
|
|
165
|
+
var DB_MAX = 6;
|
|
166
|
+
var DB_MIN = -60;
|
|
167
|
+
var EXPONENT = Math.log(Math.pow(10, DB_MAX / 20)) / Math.log(1 / SLIDER_UNITY);
|
|
168
|
+
function sliderToDb(slider) {
|
|
169
|
+
if (slider <= 0) return DB_MIN;
|
|
170
|
+
const gain = Math.pow(slider / SLIDER_UNITY, EXPONENT);
|
|
171
|
+
const db = 20 * Math.log10(gain);
|
|
172
|
+
return Math.max(DB_MIN, Math.min(DB_MAX, db));
|
|
173
|
+
}
|
|
174
|
+
function dbToSlider(db) {
|
|
175
|
+
if (db <= DB_MIN) return 0;
|
|
176
|
+
if (db >= DB_MAX) return 1;
|
|
177
|
+
const gain = Math.pow(10, db / 20);
|
|
178
|
+
const slider = SLIDER_UNITY * Math.pow(gain, 1 / EXPONENT);
|
|
179
|
+
return Math.min(1, Math.max(0, slider));
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// src/components/VolumeSlider.tsx
|
|
183
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
184
|
+
function formatDb(value) {
|
|
185
|
+
const db = sliderToDb(value);
|
|
186
|
+
if (db <= -60) return "-\u221E dB";
|
|
187
|
+
const sign = db >= 0 ? "+" : "";
|
|
188
|
+
return `${sign}${db.toFixed(1)} dB`;
|
|
189
|
+
}
|
|
190
|
+
function useDebouncedCallback(callback, delay) {
|
|
191
|
+
const timeoutRef = useRef(null);
|
|
192
|
+
const callbackRef = useRef(callback);
|
|
193
|
+
useEffect(() => {
|
|
194
|
+
callbackRef.current = callback;
|
|
195
|
+
}, [callback]);
|
|
196
|
+
const debouncedCallback = useCallback(
|
|
197
|
+
(...args) => {
|
|
198
|
+
if (timeoutRef.current) {
|
|
199
|
+
clearTimeout(timeoutRef.current);
|
|
200
|
+
}
|
|
201
|
+
timeoutRef.current = setTimeout(() => {
|
|
202
|
+
callbackRef.current(...args);
|
|
203
|
+
}, delay);
|
|
204
|
+
},
|
|
205
|
+
[delay]
|
|
206
|
+
);
|
|
207
|
+
useEffect(() => {
|
|
208
|
+
return () => {
|
|
209
|
+
if (timeoutRef.current) {
|
|
210
|
+
clearTimeout(timeoutRef.current);
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
}, []);
|
|
214
|
+
return debouncedCallback;
|
|
215
|
+
}
|
|
216
|
+
var VolumeSlider = ({
|
|
217
|
+
value,
|
|
218
|
+
onChange,
|
|
219
|
+
disabled = false,
|
|
220
|
+
className = ""
|
|
221
|
+
}) => {
|
|
222
|
+
const [localValue, setLocalValue] = useState2(value);
|
|
223
|
+
const [isDragging, setIsDragging] = useState2(false);
|
|
224
|
+
useEffect(() => {
|
|
225
|
+
if (!isDragging) {
|
|
226
|
+
setLocalValue(value);
|
|
227
|
+
}
|
|
228
|
+
}, [value, isDragging]);
|
|
229
|
+
const debouncedOnChange = useDebouncedCallback(onChange, 50);
|
|
230
|
+
const handleChange = useCallback(
|
|
231
|
+
(e) => {
|
|
232
|
+
const newValue = parseFloat(e.target.value);
|
|
233
|
+
setLocalValue(newValue);
|
|
234
|
+
debouncedOnChange(newValue);
|
|
235
|
+
},
|
|
236
|
+
[debouncedOnChange]
|
|
237
|
+
);
|
|
238
|
+
const handleMouseDown = useCallback(() => {
|
|
239
|
+
setIsDragging(true);
|
|
240
|
+
}, []);
|
|
241
|
+
const handleMouseUp = useCallback(() => {
|
|
242
|
+
setIsDragging(false);
|
|
243
|
+
onChange(localValue);
|
|
244
|
+
}, [localValue, onChange]);
|
|
245
|
+
return /* @__PURE__ */ jsx2(
|
|
246
|
+
"div",
|
|
247
|
+
{
|
|
248
|
+
className: `flex items-center ${className}`,
|
|
249
|
+
title: `Volume: ${formatDb(localValue)}`,
|
|
250
|
+
children: /* @__PURE__ */ jsx2(
|
|
251
|
+
"input",
|
|
252
|
+
{
|
|
253
|
+
type: "range",
|
|
254
|
+
min: "0",
|
|
255
|
+
max: "1",
|
|
256
|
+
step: "0.01",
|
|
257
|
+
value: localValue,
|
|
258
|
+
onChange: handleChange,
|
|
259
|
+
onMouseDown: handleMouseDown,
|
|
260
|
+
onMouseUp: handleMouseUp,
|
|
261
|
+
onTouchStart: handleMouseDown,
|
|
262
|
+
onTouchEnd: handleMouseUp,
|
|
263
|
+
disabled,
|
|
264
|
+
className: `
|
|
265
|
+
w-full h-1.5 rounded-full appearance-none cursor-pointer
|
|
266
|
+
bg-gray-700
|
|
267
|
+
disabled:opacity-50 disabled:cursor-not-allowed
|
|
268
|
+
[&::-webkit-slider-thumb]:appearance-none
|
|
269
|
+
[&::-webkit-slider-thumb]:w-3
|
|
270
|
+
[&::-webkit-slider-thumb]:h-3
|
|
271
|
+
[&::-webkit-slider-thumb]:rounded-full
|
|
272
|
+
[&::-webkit-slider-thumb]:bg-sas-accent
|
|
273
|
+
[&::-webkit-slider-thumb]:cursor-pointer
|
|
274
|
+
[&::-webkit-slider-thumb]:transition-transform
|
|
275
|
+
[&::-webkit-slider-thumb]:hover:scale-110
|
|
276
|
+
[&::-moz-range-thumb]:w-3
|
|
277
|
+
[&::-moz-range-thumb]:h-3
|
|
278
|
+
[&::-moz-range-thumb]:rounded-full
|
|
279
|
+
[&::-moz-range-thumb]:bg-sas-accent
|
|
280
|
+
[&::-moz-range-thumb]:border-0
|
|
281
|
+
[&::-moz-range-thumb]:cursor-pointer
|
|
282
|
+
`
|
|
283
|
+
}
|
|
284
|
+
)
|
|
285
|
+
}
|
|
286
|
+
);
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
// src/components/PanSlider.tsx
|
|
290
|
+
import { useCallback as useCallback2, useState as useState3, useRef as useRef2, useEffect as useEffect2 } from "react";
|
|
291
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
292
|
+
function toPanDisplay(value) {
|
|
293
|
+
if (Math.abs(value) < 0.02) {
|
|
294
|
+
return "Center";
|
|
295
|
+
}
|
|
296
|
+
const percent = Math.abs(Math.round(value * 100));
|
|
297
|
+
return value < 0 ? `L${percent}` : `R${percent}`;
|
|
298
|
+
}
|
|
299
|
+
function useDebouncedCallback2(callback, delay) {
|
|
300
|
+
const timeoutRef = useRef2(null);
|
|
301
|
+
const callbackRef = useRef2(callback);
|
|
302
|
+
useEffect2(() => {
|
|
303
|
+
callbackRef.current = callback;
|
|
304
|
+
}, [callback]);
|
|
305
|
+
const debouncedCallback = useCallback2(
|
|
306
|
+
(...args) => {
|
|
307
|
+
if (timeoutRef.current) {
|
|
308
|
+
clearTimeout(timeoutRef.current);
|
|
309
|
+
}
|
|
310
|
+
timeoutRef.current = setTimeout(() => {
|
|
311
|
+
callbackRef.current(...args);
|
|
312
|
+
}, delay);
|
|
313
|
+
},
|
|
314
|
+
[delay]
|
|
315
|
+
);
|
|
316
|
+
useEffect2(() => {
|
|
317
|
+
return () => {
|
|
318
|
+
if (timeoutRef.current) {
|
|
319
|
+
clearTimeout(timeoutRef.current);
|
|
320
|
+
}
|
|
321
|
+
};
|
|
322
|
+
}, []);
|
|
323
|
+
return debouncedCallback;
|
|
324
|
+
}
|
|
325
|
+
var PanSlider = ({
|
|
326
|
+
value,
|
|
327
|
+
onChange,
|
|
328
|
+
disabled = false,
|
|
329
|
+
className = ""
|
|
330
|
+
}) => {
|
|
331
|
+
const [localValue, setLocalValue] = useState3(value);
|
|
332
|
+
const [isDragging, setIsDragging] = useState3(false);
|
|
333
|
+
useEffect2(() => {
|
|
334
|
+
if (!isDragging) {
|
|
335
|
+
setLocalValue(value);
|
|
336
|
+
}
|
|
337
|
+
}, [value, isDragging]);
|
|
338
|
+
const debouncedOnChange = useDebouncedCallback2(onChange, 50);
|
|
339
|
+
const handleChange = useCallback2(
|
|
340
|
+
(e) => {
|
|
341
|
+
const newValue = parseFloat(e.target.value);
|
|
342
|
+
setLocalValue(newValue);
|
|
343
|
+
debouncedOnChange(newValue);
|
|
344
|
+
},
|
|
345
|
+
[debouncedOnChange]
|
|
346
|
+
);
|
|
347
|
+
const handleMouseDown = useCallback2(() => {
|
|
348
|
+
setIsDragging(true);
|
|
349
|
+
}, []);
|
|
350
|
+
const handleMouseUp = useCallback2(() => {
|
|
351
|
+
setIsDragging(false);
|
|
352
|
+
onChange(localValue);
|
|
353
|
+
}, [localValue, onChange]);
|
|
354
|
+
const handleDoubleClick = useCallback2(() => {
|
|
355
|
+
setLocalValue(0);
|
|
356
|
+
onChange(0);
|
|
357
|
+
}, [onChange]);
|
|
358
|
+
return /* @__PURE__ */ jsx3(
|
|
359
|
+
"div",
|
|
360
|
+
{
|
|
361
|
+
className: `flex items-center ${className}`,
|
|
362
|
+
title: `Pan: ${toPanDisplay(localValue)}`,
|
|
363
|
+
children: /* @__PURE__ */ jsx3(
|
|
364
|
+
"input",
|
|
365
|
+
{
|
|
366
|
+
type: "range",
|
|
367
|
+
min: "-1",
|
|
368
|
+
max: "1",
|
|
369
|
+
step: "0.01",
|
|
370
|
+
value: localValue,
|
|
371
|
+
onChange: handleChange,
|
|
372
|
+
onMouseDown: handleMouseDown,
|
|
373
|
+
onMouseUp: handleMouseUp,
|
|
374
|
+
onTouchStart: handleMouseDown,
|
|
375
|
+
onTouchEnd: handleMouseUp,
|
|
376
|
+
onDoubleClick: handleDoubleClick,
|
|
377
|
+
disabled,
|
|
378
|
+
className: `
|
|
379
|
+
w-full h-1.5 rounded-full appearance-none cursor-pointer
|
|
380
|
+
bg-gray-700
|
|
381
|
+
disabled:opacity-50 disabled:cursor-not-allowed
|
|
382
|
+
[&::-webkit-slider-thumb]:appearance-none
|
|
383
|
+
[&::-webkit-slider-thumb]:w-3
|
|
384
|
+
[&::-webkit-slider-thumb]:h-3
|
|
385
|
+
[&::-webkit-slider-thumb]:rounded-full
|
|
386
|
+
[&::-webkit-slider-thumb]:bg-sas-accent
|
|
387
|
+
[&::-webkit-slider-thumb]:cursor-pointer
|
|
388
|
+
[&::-webkit-slider-thumb]:transition-transform
|
|
389
|
+
[&::-webkit-slider-thumb]:hover:scale-110
|
|
390
|
+
[&::-moz-range-thumb]:w-3
|
|
391
|
+
[&::-moz-range-thumb]:h-3
|
|
392
|
+
[&::-moz-range-thumb]:rounded-full
|
|
393
|
+
[&::-moz-range-thumb]:bg-sas-accent
|
|
394
|
+
[&::-moz-range-thumb]:border-0
|
|
395
|
+
[&::-moz-range-thumb]:cursor-pointer
|
|
396
|
+
`
|
|
397
|
+
}
|
|
398
|
+
)
|
|
399
|
+
}
|
|
400
|
+
);
|
|
401
|
+
};
|
|
402
|
+
|
|
403
|
+
// src/constants/fx-presets.ts
|
|
404
|
+
var EQ_PRESETS = {
|
|
405
|
+
presets: [
|
|
406
|
+
{
|
|
407
|
+
name: "The Smiley",
|
|
408
|
+
shortLabel: "SM",
|
|
409
|
+
params: {
|
|
410
|
+
"Low-shelf freq": 80,
|
|
411
|
+
"Low-shelf gain": 4,
|
|
412
|
+
"Low-shelf Q": 0.5,
|
|
413
|
+
"Mid freq 1": 500,
|
|
414
|
+
"Mid gain 1": -3,
|
|
415
|
+
"Mid Q 1": 0.7,
|
|
416
|
+
"Mid freq 2": 2e3,
|
|
417
|
+
"Mid gain 2": -2,
|
|
418
|
+
"Mid Q 2": 0.7,
|
|
419
|
+
"High-shelf freq": 12e3,
|
|
420
|
+
"High-shelf gain": 4,
|
|
421
|
+
"High-shelf Q": 0.5
|
|
422
|
+
}
|
|
423
|
+
},
|
|
424
|
+
{
|
|
425
|
+
name: "Telephone",
|
|
426
|
+
shortLabel: "TP",
|
|
427
|
+
params: {
|
|
428
|
+
"Low-shelf freq": 400,
|
|
429
|
+
"Low-shelf gain": -20,
|
|
430
|
+
"Low-shelf Q": 1,
|
|
431
|
+
"Mid freq 1": 1e3,
|
|
432
|
+
"Mid gain 1": 5,
|
|
433
|
+
"Mid Q 1": 2,
|
|
434
|
+
"Mid freq 2": 3e3,
|
|
435
|
+
"Mid gain 2": -5,
|
|
436
|
+
"Mid Q 2": 1,
|
|
437
|
+
"High-shelf freq": 5e3,
|
|
438
|
+
"High-shelf gain": -20,
|
|
439
|
+
"High-shelf Q": 1
|
|
440
|
+
}
|
|
441
|
+
},
|
|
442
|
+
{
|
|
443
|
+
name: "Warmth",
|
|
444
|
+
shortLabel: "WM",
|
|
445
|
+
params: {
|
|
446
|
+
"Low-shelf freq": 120,
|
|
447
|
+
"Low-shelf gain": 3,
|
|
448
|
+
"Low-shelf Q": 0.7,
|
|
449
|
+
"Mid freq 1": 400,
|
|
450
|
+
"Mid gain 1": 2,
|
|
451
|
+
"Mid Q 1": 1,
|
|
452
|
+
"Mid freq 2": 4e3,
|
|
453
|
+
"Mid gain 2": 0,
|
|
454
|
+
"Mid Q 2": 0.5,
|
|
455
|
+
"High-shelf freq": 1e4,
|
|
456
|
+
"High-shelf gain": -4,
|
|
457
|
+
"High-shelf Q": 0.5
|
|
458
|
+
}
|
|
459
|
+
},
|
|
460
|
+
{
|
|
461
|
+
name: "Vocal Air",
|
|
462
|
+
shortLabel: "VA",
|
|
463
|
+
params: {
|
|
464
|
+
"Low-shelf freq": 100,
|
|
465
|
+
"Low-shelf gain": -6,
|
|
466
|
+
"Low-shelf Q": 0.7,
|
|
467
|
+
"Mid freq 1": 300,
|
|
468
|
+
"Mid gain 1": -2,
|
|
469
|
+
"Mid Q 1": 1,
|
|
470
|
+
"Mid freq 2": 1500,
|
|
471
|
+
"Mid gain 2": 0,
|
|
472
|
+
"Mid Q 2": 0.5,
|
|
473
|
+
"High-shelf freq": 14e3,
|
|
474
|
+
"High-shelf gain": 6,
|
|
475
|
+
"High-shelf Q": 0.4
|
|
476
|
+
}
|
|
477
|
+
},
|
|
478
|
+
{
|
|
479
|
+
name: "De-Box",
|
|
480
|
+
shortLabel: "DB",
|
|
481
|
+
params: {
|
|
482
|
+
"Low-shelf freq": 60,
|
|
483
|
+
"Low-shelf gain": 0,
|
|
484
|
+
"Low-shelf Q": 0.5,
|
|
485
|
+
"Mid freq 1": 350,
|
|
486
|
+
"Mid gain 1": -5,
|
|
487
|
+
"Mid Q 1": 2,
|
|
488
|
+
"Mid freq 2": 800,
|
|
489
|
+
"Mid gain 2": -3,
|
|
490
|
+
"Mid Q 2": 2,
|
|
491
|
+
"High-shelf freq": 1e4,
|
|
492
|
+
"High-shelf gain": 0,
|
|
493
|
+
"High-shelf Q": 0.5
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
],
|
|
497
|
+
mixParamName: null,
|
|
498
|
+
mixInterpolation: "gain-scale"
|
|
499
|
+
};
|
|
500
|
+
var COMPRESSOR_PRESETS = {
|
|
501
|
+
presets: [
|
|
502
|
+
{
|
|
503
|
+
name: "Vocal Leveler",
|
|
504
|
+
shortLabel: "VL",
|
|
505
|
+
params: { "Threshold": 0.251, "Ratio": 0.5, "Attack": 20, "Release": 200, "Output": 2 }
|
|
506
|
+
},
|
|
507
|
+
{
|
|
508
|
+
name: "Drum Smash",
|
|
509
|
+
shortLabel: "DS",
|
|
510
|
+
params: { "Threshold": 0.1, "Ratio": 0.1, "Attack": 0.5, "Release": 100, "Output": 8 }
|
|
511
|
+
},
|
|
512
|
+
{
|
|
513
|
+
name: "Bus Glue",
|
|
514
|
+
shortLabel: "BG",
|
|
515
|
+
params: { "Threshold": 0.316, "Ratio": 0.666, "Attack": 80, "Release": 150, "Output": 1 }
|
|
516
|
+
},
|
|
517
|
+
{
|
|
518
|
+
name: "Bass Anchor",
|
|
519
|
+
shortLabel: "BA",
|
|
520
|
+
params: { "Threshold": 0.177, "Ratio": 0.25, "Attack": 10, "Release": 250, "Output": 4 }
|
|
521
|
+
},
|
|
522
|
+
{
|
|
523
|
+
name: "Safety Net",
|
|
524
|
+
shortLabel: "SN",
|
|
525
|
+
params: { "Threshold": 0.891, "Ratio": 0, "Attack": 0.3, "Release": 50, "Output": 0 }
|
|
526
|
+
}
|
|
527
|
+
],
|
|
528
|
+
mixParamName: null,
|
|
529
|
+
mixInterpolation: "ratio-scale"
|
|
530
|
+
};
|
|
531
|
+
var CHORUS_PRESETS = {
|
|
532
|
+
presets: [
|
|
533
|
+
{
|
|
534
|
+
name: "Dimension",
|
|
535
|
+
shortLabel: "DM",
|
|
536
|
+
params: {},
|
|
537
|
+
xmlStateParams: { depthMs: 1.5, speedHz: 0.5, width: 1, mixProportion: 0.5 }
|
|
538
|
+
},
|
|
539
|
+
{
|
|
540
|
+
name: "80s Crystal",
|
|
541
|
+
shortLabel: "80",
|
|
542
|
+
params: {},
|
|
543
|
+
xmlStateParams: { depthMs: 4, speedHz: 2.5, width: 0.8, mixProportion: 0.4 }
|
|
544
|
+
},
|
|
545
|
+
{
|
|
546
|
+
name: "Sea Sick",
|
|
547
|
+
shortLabel: "SS",
|
|
548
|
+
params: {},
|
|
549
|
+
xmlStateParams: { depthMs: 7, speedHz: 0.8, width: 0.3, mixProportion: 1 }
|
|
550
|
+
},
|
|
551
|
+
{
|
|
552
|
+
name: "Pseudo-Leslie",
|
|
553
|
+
shortLabel: "PL",
|
|
554
|
+
params: {},
|
|
555
|
+
xmlStateParams: { depthMs: 2, speedHz: 6, width: 0.9, mixProportion: 0.7 }
|
|
556
|
+
},
|
|
557
|
+
{
|
|
558
|
+
name: "Thickener",
|
|
559
|
+
shortLabel: "TK",
|
|
560
|
+
params: {},
|
|
561
|
+
xmlStateParams: { depthMs: 1, speedHz: 0.2, width: 1, mixProportion: 0.3 }
|
|
562
|
+
}
|
|
563
|
+
],
|
|
564
|
+
mixParamName: null,
|
|
565
|
+
mixXmlAttr: "mixProportion",
|
|
566
|
+
mixInterpolation: "direct"
|
|
567
|
+
};
|
|
568
|
+
var PHASER_PRESETS = {
|
|
569
|
+
presets: [
|
|
570
|
+
{
|
|
571
|
+
name: "Slow Burn",
|
|
572
|
+
shortLabel: "SB",
|
|
573
|
+
params: {},
|
|
574
|
+
xmlStateParams: { depth: 6, rate: 0.1, feedback: 0.3 }
|
|
575
|
+
},
|
|
576
|
+
{
|
|
577
|
+
name: "Funky Quack",
|
|
578
|
+
shortLabel: "FQ",
|
|
579
|
+
params: {},
|
|
580
|
+
xmlStateParams: { depth: 3, rate: 2, feedback: 0.8 }
|
|
581
|
+
},
|
|
582
|
+
{
|
|
583
|
+
name: "Jet Plane",
|
|
584
|
+
shortLabel: "JP",
|
|
585
|
+
params: {},
|
|
586
|
+
xmlStateParams: { depth: 8, rate: 0.2, feedback: 0.9 }
|
|
587
|
+
},
|
|
588
|
+
{
|
|
589
|
+
name: "Underwater",
|
|
590
|
+
shortLabel: "UW",
|
|
591
|
+
params: {},
|
|
592
|
+
xmlStateParams: { depth: 1.5, rate: 4, feedback: 0.1 }
|
|
593
|
+
},
|
|
594
|
+
{
|
|
595
|
+
name: "Static Notch",
|
|
596
|
+
shortLabel: "ST",
|
|
597
|
+
params: {},
|
|
598
|
+
xmlStateParams: { depth: 2, rate: 0.05, feedback: 0.6 }
|
|
599
|
+
}
|
|
600
|
+
],
|
|
601
|
+
mixParamName: null,
|
|
602
|
+
mixXmlAttr: "depth",
|
|
603
|
+
mixInterpolation: "direct"
|
|
604
|
+
};
|
|
605
|
+
var DELAY_PRESETS = {
|
|
606
|
+
presets: [
|
|
607
|
+
{
|
|
608
|
+
name: "Vocal Slap",
|
|
609
|
+
shortLabel: "VS",
|
|
610
|
+
fixedLengthMs: 110,
|
|
611
|
+
params: { "Feedback": -20, "Mix proportion": 0.25 }
|
|
612
|
+
},
|
|
613
|
+
{
|
|
614
|
+
name: "Grand Canyon",
|
|
615
|
+
shortLabel: "GC",
|
|
616
|
+
noteMultiplier: 1,
|
|
617
|
+
params: { "Feedback": -4, "Mix proportion": 0.45 }
|
|
618
|
+
},
|
|
619
|
+
{
|
|
620
|
+
name: "Wide Doubler",
|
|
621
|
+
shortLabel: "WD",
|
|
622
|
+
fixedLengthMs: 25,
|
|
623
|
+
params: { "Feedback": -30, "Mix proportion": 0.5 }
|
|
624
|
+
},
|
|
625
|
+
{
|
|
626
|
+
name: "Dub Echo",
|
|
627
|
+
shortLabel: "DE",
|
|
628
|
+
noteMultiplier: 0.6,
|
|
629
|
+
params: { "Feedback": -1.5, "Mix proportion": 0.4 }
|
|
630
|
+
},
|
|
631
|
+
{
|
|
632
|
+
name: "Rhythmic Wash",
|
|
633
|
+
shortLabel: "RW",
|
|
634
|
+
noteMultiplier: 0.75,
|
|
635
|
+
params: { "Feedback": -8, "Mix proportion": 0.2 }
|
|
636
|
+
}
|
|
637
|
+
],
|
|
638
|
+
mixParamName: "Mix proportion",
|
|
639
|
+
mixInterpolation: "direct"
|
|
640
|
+
};
|
|
641
|
+
var REVERB_PRESETS = {
|
|
642
|
+
presets: [
|
|
643
|
+
{
|
|
644
|
+
name: "Drum Room",
|
|
645
|
+
shortLabel: "DR",
|
|
646
|
+
params: { "Room Size": 0.2, "Damping": 0.2, "Wet Level": 0.15, "Dry Level": 0.5, "Width": 0.8 }
|
|
647
|
+
},
|
|
648
|
+
{
|
|
649
|
+
name: "Vocal Hall",
|
|
650
|
+
shortLabel: "VH",
|
|
651
|
+
params: { "Room Size": 0.8, "Damping": 0.6, "Wet Level": 0.25, "Dry Level": 0.5, "Width": 1 }
|
|
652
|
+
},
|
|
653
|
+
{
|
|
654
|
+
name: "Cathedral",
|
|
655
|
+
shortLabel: "CT",
|
|
656
|
+
params: { "Room Size": 1, "Damping": 0.1, "Wet Level": 0.333, "Dry Level": 0.2, "Width": 1 }
|
|
657
|
+
},
|
|
658
|
+
{
|
|
659
|
+
name: "Tile Bathroom",
|
|
660
|
+
shortLabel: "TB",
|
|
661
|
+
params: { "Room Size": 0.15, "Damping": 0, "Wet Level": 0.2, "Dry Level": 0.5, "Width": 0.5 }
|
|
662
|
+
},
|
|
663
|
+
{
|
|
664
|
+
name: "Vintage Plate",
|
|
665
|
+
shortLabel: "VP",
|
|
666
|
+
params: { "Room Size": 0.4, "Damping": 1, "Wet Level": 0.2, "Dry Level": 0.5, "Width": 1 }
|
|
667
|
+
}
|
|
668
|
+
],
|
|
669
|
+
mixParamName: "Wet Level",
|
|
670
|
+
mixInterpolation: "direct"
|
|
671
|
+
};
|
|
672
|
+
var FX_PRESET_CONFIGS = {
|
|
673
|
+
eq: EQ_PRESETS,
|
|
674
|
+
compressor: COMPRESSOR_PRESETS,
|
|
675
|
+
chorus: CHORUS_PRESETS,
|
|
676
|
+
phaser: PHASER_PRESETS,
|
|
677
|
+
delay: DELAY_PRESETS,
|
|
678
|
+
reverb: REVERB_PRESETS
|
|
679
|
+
};
|
|
680
|
+
|
|
681
|
+
// src/components/FxToggleBar.tsx
|
|
682
|
+
import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
683
|
+
var FX_COLORS = {
|
|
684
|
+
eq: "bg-blue-500",
|
|
685
|
+
compressor: "bg-orange-500",
|
|
686
|
+
chorus: "bg-teal-500",
|
|
687
|
+
phaser: "bg-purple-500",
|
|
688
|
+
delay: "bg-green-500",
|
|
689
|
+
reverb: "bg-cyan-500"
|
|
690
|
+
};
|
|
691
|
+
var FxToggleBar = ({
|
|
692
|
+
trackId,
|
|
693
|
+
fxState,
|
|
694
|
+
onToggle,
|
|
695
|
+
onPresetChange,
|
|
696
|
+
onDryWetChange,
|
|
697
|
+
disabled = false
|
|
698
|
+
}) => {
|
|
699
|
+
return /* @__PURE__ */ jsx4("div", { className: "flex flex-col gap-1", "data-testid": "fx-toggle-bar", children: FX_CATEGORIES.map((category) => {
|
|
700
|
+
const detail = fxState[category];
|
|
701
|
+
const isActive = detail.enabled;
|
|
702
|
+
const label = FX_DISPLAY_LABELS[category];
|
|
703
|
+
const activeColor = FX_COLORS[category];
|
|
704
|
+
const config = FX_PRESET_CONFIGS[category];
|
|
705
|
+
return /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-0.5", children: [
|
|
706
|
+
/* @__PURE__ */ jsx4(
|
|
707
|
+
"button",
|
|
708
|
+
{
|
|
709
|
+
"data-testid": `fx-toggle-${category}`,
|
|
710
|
+
disabled,
|
|
711
|
+
onClick: () => onToggle(trackId, category, !isActive),
|
|
712
|
+
className: `w-14 py-0.5 text-[10px] font-semibold rounded-sm transition-colors leading-none flex-shrink-0 text-center ${disabled ? "bg-sas-panel text-sas-muted/30 cursor-not-allowed" : isActive ? `${activeColor} text-white` : "bg-sas-panel-alt text-sas-muted/60 hover:bg-sas-border hover:text-sas-muted"}`,
|
|
713
|
+
title: `${isActive ? "Disable" : "Enable"} ${category.toUpperCase()}`,
|
|
714
|
+
children: label
|
|
715
|
+
}
|
|
716
|
+
),
|
|
717
|
+
config.presets.map((preset, idx) => /* @__PURE__ */ jsx4(
|
|
718
|
+
"button",
|
|
719
|
+
{
|
|
720
|
+
"data-testid": `fx-preset-${category}-${idx}`,
|
|
721
|
+
disabled: disabled || !isActive,
|
|
722
|
+
onClick: () => onPresetChange(trackId, category, idx),
|
|
723
|
+
className: `w-5 h-5 text-[9px] font-medium rounded-sm transition-colors leading-none flex-shrink-0 ${disabled || !isActive ? "bg-sas-panel text-sas-muted/20 cursor-not-allowed" : detail.presetIndex === idx ? `${activeColor} text-white` : "bg-sas-panel-alt text-sas-muted/50 hover:bg-sas-border hover:text-sas-muted"}`,
|
|
724
|
+
title: preset.name,
|
|
725
|
+
children: idx + 1
|
|
726
|
+
},
|
|
727
|
+
idx
|
|
728
|
+
)),
|
|
729
|
+
/* @__PURE__ */ jsx4(
|
|
730
|
+
"input",
|
|
731
|
+
{
|
|
732
|
+
type: "range",
|
|
733
|
+
"data-testid": `fx-drywet-${category}`,
|
|
734
|
+
min: "0",
|
|
735
|
+
max: "100",
|
|
736
|
+
value: Math.round(detail.dryWet * 100),
|
|
737
|
+
disabled: disabled || !isActive,
|
|
738
|
+
onChange: (e) => onDryWetChange(trackId, category, Number(e.target.value) / 100),
|
|
739
|
+
className: "flex-1 min-w-[30px] h-3 accent-sas-accent disabled:opacity-30 cursor-pointer disabled:cursor-not-allowed",
|
|
740
|
+
title: `Dry/Wet: ${Math.round(detail.dryWet * 100)}%`
|
|
741
|
+
}
|
|
742
|
+
),
|
|
743
|
+
/* @__PURE__ */ jsxs2("span", { className: "text-[8px] text-sas-muted/50 w-6 text-right flex-shrink-0", children: [
|
|
744
|
+
Math.round(detail.dryWet * 100),
|
|
745
|
+
"%"
|
|
746
|
+
] })
|
|
747
|
+
] }, category);
|
|
748
|
+
}) });
|
|
749
|
+
};
|
|
750
|
+
|
|
751
|
+
// src/components/SorceryProgressBar.tsx
|
|
752
|
+
import { useState as useState4, useEffect as useEffect3, useRef as useRef3 } from "react";
|
|
753
|
+
import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
754
|
+
function calculateTimeBasedTarget(elapsedMs, estimatedDurationMs) {
|
|
755
|
+
const t = elapsedMs / estimatedDurationMs;
|
|
756
|
+
if (t <= 0) return 0;
|
|
757
|
+
if (t <= 1) {
|
|
758
|
+
return 90 * (1 - Math.pow(1 - t, 2.5));
|
|
759
|
+
}
|
|
760
|
+
const overshootRatio = (elapsedMs - estimatedDurationMs) / estimatedDurationMs;
|
|
761
|
+
return 90 + 5 * (1 - Math.exp(-overshootRatio * 3));
|
|
762
|
+
}
|
|
763
|
+
function calculateNextProgress(currentProgress) {
|
|
764
|
+
if (currentProgress < 20) {
|
|
765
|
+
return currentProgress + Math.random() * 10 + 5;
|
|
766
|
+
}
|
|
767
|
+
if (currentProgress < 60) {
|
|
768
|
+
return currentProgress + Math.random() * 5 + 2;
|
|
769
|
+
}
|
|
770
|
+
if (currentProgress < 95) {
|
|
771
|
+
const remaining = 95 - currentProgress;
|
|
772
|
+
const increment = remaining * (Math.random() * 0.2 + 0.1);
|
|
773
|
+
return currentProgress + Math.max(increment, 0.1);
|
|
774
|
+
}
|
|
775
|
+
return 95;
|
|
776
|
+
}
|
|
777
|
+
function calculateNextTickInterval(progress) {
|
|
778
|
+
if (progress < 30) {
|
|
779
|
+
return Math.random() * 200 + 150;
|
|
780
|
+
}
|
|
781
|
+
if (progress < 70) {
|
|
782
|
+
return Math.random() * 300 + 200;
|
|
783
|
+
}
|
|
784
|
+
return Math.random() * 600 + 400;
|
|
785
|
+
}
|
|
786
|
+
var TIME_BASED_TICK_MIN = 200;
|
|
787
|
+
var TIME_BASED_TICK_RANGE = 100;
|
|
788
|
+
function SorceryProgressBar({
|
|
789
|
+
isLoading,
|
|
790
|
+
statusText = "CONJURING...",
|
|
791
|
+
completeText = "COMPLETE",
|
|
792
|
+
onComplete,
|
|
793
|
+
heightClass = "h-10",
|
|
794
|
+
initialProgress = 0,
|
|
795
|
+
onProgressChange,
|
|
796
|
+
estimatedDurationMs
|
|
797
|
+
}) {
|
|
798
|
+
const [progress, setProgress] = useState4(initialProgress);
|
|
799
|
+
const timerRef = useRef3(null);
|
|
800
|
+
const isLoadingRef = useRef3(false);
|
|
801
|
+
const hasStartedRef = useRef3(false);
|
|
802
|
+
const startTimeRef = useRef3(0);
|
|
803
|
+
const onProgressChangeRef = useRef3(onProgressChange);
|
|
804
|
+
const onCompleteRef = useRef3(onComplete);
|
|
805
|
+
onProgressChangeRef.current = onProgressChange;
|
|
806
|
+
onCompleteRef.current = onComplete;
|
|
807
|
+
const initialProgressRef = useRef3(initialProgress);
|
|
808
|
+
initialProgressRef.current = initialProgress;
|
|
809
|
+
const estimatedDurationMsRef = useRef3(estimatedDurationMs);
|
|
810
|
+
estimatedDurationMsRef.current = estimatedDurationMs;
|
|
811
|
+
useEffect3(() => {
|
|
812
|
+
const wasLoading = isLoadingRef.current;
|
|
813
|
+
isLoadingRef.current = isLoading;
|
|
814
|
+
if (isLoading && !wasLoading) {
|
|
815
|
+
hasStartedRef.current = true;
|
|
816
|
+
startTimeRef.current = Date.now();
|
|
817
|
+
const startProgress = initialProgressRef.current > 0 ? initialProgressRef.current : 0;
|
|
818
|
+
setProgress(startProgress);
|
|
819
|
+
const duration = estimatedDurationMsRef.current;
|
|
820
|
+
if (duration && duration > 0) {
|
|
821
|
+
const tick = () => {
|
|
822
|
+
setProgress((prev) => {
|
|
823
|
+
const elapsed = Date.now() - startTimeRef.current;
|
|
824
|
+
const target = calculateTimeBasedTarget(elapsed, duration);
|
|
825
|
+
const jitter = (Math.random() - 0.5) * 1;
|
|
826
|
+
const next = Math.min(Math.max(target + jitter, prev + 0.05), 95);
|
|
827
|
+
onProgressChangeRef.current?.(next);
|
|
828
|
+
timerRef.current = setTimeout(tick, TIME_BASED_TICK_MIN + Math.random() * TIME_BASED_TICK_RANGE);
|
|
829
|
+
return next;
|
|
830
|
+
});
|
|
831
|
+
};
|
|
832
|
+
timerRef.current = setTimeout(tick, TIME_BASED_TICK_MIN);
|
|
833
|
+
} else {
|
|
834
|
+
const tick = () => {
|
|
835
|
+
setProgress((prev) => {
|
|
836
|
+
if (prev >= 95) {
|
|
837
|
+
timerRef.current = setTimeout(tick, 1e3);
|
|
838
|
+
return 95;
|
|
839
|
+
}
|
|
840
|
+
const next = Math.min(calculateNextProgress(prev), 95);
|
|
841
|
+
onProgressChangeRef.current?.(next);
|
|
842
|
+
const interval = calculateNextTickInterval(next);
|
|
843
|
+
timerRef.current = setTimeout(tick, interval);
|
|
844
|
+
return next;
|
|
845
|
+
});
|
|
846
|
+
};
|
|
847
|
+
const firstInterval = calculateNextTickInterval(startProgress);
|
|
848
|
+
timerRef.current = setTimeout(tick, firstInterval);
|
|
849
|
+
}
|
|
850
|
+
} else if (!isLoading && wasLoading && hasStartedRef.current) {
|
|
851
|
+
if (timerRef.current) {
|
|
852
|
+
clearTimeout(timerRef.current);
|
|
853
|
+
timerRef.current = null;
|
|
854
|
+
}
|
|
855
|
+
setProgress(100);
|
|
856
|
+
onProgressChangeRef.current?.(100);
|
|
857
|
+
onCompleteRef.current?.();
|
|
858
|
+
hasStartedRef.current = false;
|
|
859
|
+
}
|
|
860
|
+
return () => {
|
|
861
|
+
if (timerRef.current) {
|
|
862
|
+
clearTimeout(timerRef.current);
|
|
863
|
+
timerRef.current = null;
|
|
864
|
+
}
|
|
865
|
+
};
|
|
866
|
+
}, [isLoading]);
|
|
867
|
+
if (!isLoading && progress === 0) {
|
|
868
|
+
return null;
|
|
869
|
+
}
|
|
870
|
+
const displayProgress = Math.floor(progress);
|
|
871
|
+
const isComplete = !isLoading && progress === 100;
|
|
872
|
+
const transitionDuration = progress < 50 ? "300ms" : progress < 80 ? "500ms" : "700ms";
|
|
873
|
+
return /* @__PURE__ */ jsxs3(
|
|
874
|
+
"div",
|
|
875
|
+
{
|
|
876
|
+
className: `relative w-full ${heightClass} bg-sas-panel-alt border border-sas-border rounded-sm overflow-hidden shadow-inner`,
|
|
877
|
+
children: [
|
|
878
|
+
/* @__PURE__ */ jsx5(
|
|
879
|
+
"div",
|
|
880
|
+
{
|
|
881
|
+
className: `
|
|
882
|
+
h-full
|
|
883
|
+
bg-gradient-to-r from-sas-accent/70 to-sas-accent
|
|
884
|
+
shadow-glow-soft
|
|
885
|
+
sorcery-progress-fill
|
|
886
|
+
animate-progress-stripes
|
|
887
|
+
${progress > 70 ? "animate-progress-pulse" : ""}
|
|
888
|
+
transition-all ease-out
|
|
889
|
+
`,
|
|
890
|
+
style: {
|
|
891
|
+
width: `${progress}%`,
|
|
892
|
+
transitionDuration
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
),
|
|
896
|
+
/* @__PURE__ */ jsx5("div", { className: "absolute inset-0 flex items-center justify-center", children: isLoading && progress < 100 ? /* @__PURE__ */ jsxs3("span", { className: "font-mono text-xs text-sas-accent font-bold drop-shadow-md tracking-wider", children: [
|
|
897
|
+
statusText,
|
|
898
|
+
" ",
|
|
899
|
+
displayProgress,
|
|
900
|
+
"%"
|
|
901
|
+
] }) : isComplete ? /* @__PURE__ */ jsx5("span", { className: "font-mono text-xs text-sas-text font-bold drop-shadow-md tracking-wider", children: completeText }) : null }),
|
|
902
|
+
/* @__PURE__ */ jsx5(
|
|
903
|
+
"div",
|
|
904
|
+
{
|
|
905
|
+
className: "absolute inset-0 pointer-events-none opacity-10",
|
|
906
|
+
style: {
|
|
907
|
+
backgroundImage: `repeating-linear-gradient(
|
|
908
|
+
to bottom,
|
|
909
|
+
transparent,
|
|
910
|
+
transparent 2px,
|
|
911
|
+
rgba(0, 0, 0, 0.3) 2px,
|
|
912
|
+
rgba(0, 0, 0, 0.3) 4px
|
|
913
|
+
)`
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
)
|
|
917
|
+
]
|
|
918
|
+
}
|
|
919
|
+
);
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
// src/components/TrackRow.tsx
|
|
923
|
+
import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
924
|
+
function TrackRow({
|
|
925
|
+
track,
|
|
926
|
+
prompt,
|
|
927
|
+
runtimeState,
|
|
928
|
+
fxDetailState,
|
|
929
|
+
fxDrawerOpen,
|
|
930
|
+
isGenerating = false,
|
|
931
|
+
isAuthenticated = false,
|
|
932
|
+
error,
|
|
933
|
+
hasMidi = false,
|
|
934
|
+
generationProgress = 0,
|
|
935
|
+
estimatedGenerationMs = 15e3,
|
|
936
|
+
onPromptChange,
|
|
937
|
+
onGenerate,
|
|
938
|
+
onShuffle,
|
|
939
|
+
onCopy,
|
|
940
|
+
onDelete,
|
|
941
|
+
contentSlot,
|
|
942
|
+
onMuteToggle,
|
|
943
|
+
onSoloToggle,
|
|
944
|
+
onVolumeChange,
|
|
945
|
+
onPanChange,
|
|
946
|
+
onFxToggle,
|
|
947
|
+
onFxPresetChange,
|
|
948
|
+
onFxDryWetChange,
|
|
949
|
+
onToggleFxDrawer,
|
|
950
|
+
onProgressChange,
|
|
951
|
+
accentColor = "#A78BFA",
|
|
952
|
+
instrumentName,
|
|
953
|
+
instrumentMissing,
|
|
954
|
+
instrumentDrawerOpen,
|
|
955
|
+
onToggleInstrumentDrawer,
|
|
956
|
+
availableInstruments,
|
|
957
|
+
currentInstrumentPluginId,
|
|
958
|
+
onInstrumentSelect,
|
|
959
|
+
instrumentsLoading,
|
|
960
|
+
onRefreshInstruments
|
|
961
|
+
}) {
|
|
962
|
+
const { muted: isMuted, solo: isSoloed, volume: currentVolume, pan: currentPan } = runtimeState;
|
|
963
|
+
const needsGeneration = !!(prompt?.trim() && !hasMidi && !isGenerating);
|
|
964
|
+
const hasFxActive = Object.values(fxDetailState).some(
|
|
965
|
+
(d) => d.enabled
|
|
966
|
+
);
|
|
967
|
+
const handleKeyDown = (e) => {
|
|
968
|
+
if (e.key === "Enter" && !e.shiftKey && onGenerate) {
|
|
969
|
+
e.preventDefault();
|
|
970
|
+
onGenerate();
|
|
971
|
+
}
|
|
972
|
+
};
|
|
973
|
+
const borderColorStyle = needsGeneration ? void 0 : accentColor;
|
|
974
|
+
const borderClass = needsGeneration ? "border-amber-400 animate-pulse" : "border-sas-border";
|
|
975
|
+
return /* @__PURE__ */ jsxs4("div", { "data-testid": "sdk-track-row-wrapper", className: "w-full", children: [
|
|
976
|
+
/* @__PURE__ */ jsxs4(
|
|
977
|
+
"div",
|
|
978
|
+
{
|
|
979
|
+
"data-testid": "sdk-track-row",
|
|
980
|
+
className: `relative flex items-stretch gap-1 p-2 rounded-sm border w-full overflow-hidden ${borderClass} bg-sas-panel-alt`,
|
|
981
|
+
style: {
|
|
982
|
+
borderLeftColor: needsGeneration ? "#f59e0b" : borderColorStyle,
|
|
983
|
+
borderLeftWidth: "3px"
|
|
984
|
+
},
|
|
985
|
+
children: [
|
|
986
|
+
isGenerating && /* @__PURE__ */ jsx6("div", { className: "absolute left-0 top-0 bottom-0 right-44 z-20", children: /* @__PURE__ */ jsx6(
|
|
987
|
+
SorceryProgressBar,
|
|
988
|
+
{
|
|
989
|
+
isLoading: true,
|
|
990
|
+
statusText: "CONJURING MIDI...",
|
|
991
|
+
heightClass: "h-full",
|
|
992
|
+
initialProgress: generationProgress,
|
|
993
|
+
onProgressChange,
|
|
994
|
+
estimatedDurationMs: estimatedGenerationMs
|
|
995
|
+
}
|
|
996
|
+
) }),
|
|
997
|
+
/* @__PURE__ */ jsxs4("div", { className: "flex flex-col flex-1 min-w-0 relative z-10", children: [
|
|
998
|
+
contentSlot ? contentSlot : onPromptChange ? /* @__PURE__ */ jsx6(
|
|
999
|
+
"input",
|
|
1000
|
+
{
|
|
1001
|
+
type: "text",
|
|
1002
|
+
"data-testid": "sdk-prompt-input",
|
|
1003
|
+
value: prompt ?? "",
|
|
1004
|
+
onChange: (e) => onPromptChange(e.target.value),
|
|
1005
|
+
onKeyDown: handleKeyDown,
|
|
1006
|
+
placeholder: "Describe your part...",
|
|
1007
|
+
disabled: isGenerating,
|
|
1008
|
+
className: "sas-input w-full px-2 py-1 text-xs disabled:opacity-50 disabled:cursor-not-allowed"
|
|
1009
|
+
}
|
|
1010
|
+
) : null,
|
|
1011
|
+
/* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-2 mt-1", children: [
|
|
1012
|
+
track.name && /* @__PURE__ */ jsx6("span", { className: "text-[10px] text-sas-muted/60 truncate pl-2 flex-shrink-0 max-w-[80px]", title: track.name, children: track.name }),
|
|
1013
|
+
/* @__PURE__ */ jsx6("span", { className: "text-[9px] text-sas-muted/50 flex-shrink-0", children: "vol:" }),
|
|
1014
|
+
/* @__PURE__ */ jsx6(
|
|
1015
|
+
VolumeSlider,
|
|
1016
|
+
{
|
|
1017
|
+
value: currentVolume,
|
|
1018
|
+
onChange: onVolumeChange,
|
|
1019
|
+
disabled: isGenerating,
|
|
1020
|
+
className: "flex-1 min-w-[40px]"
|
|
1021
|
+
}
|
|
1022
|
+
),
|
|
1023
|
+
/* @__PURE__ */ jsx6("span", { className: "text-[9px] text-sas-muted/50 flex-shrink-0", children: "pan:" }),
|
|
1024
|
+
/* @__PURE__ */ jsx6(
|
|
1025
|
+
PanSlider,
|
|
1026
|
+
{
|
|
1027
|
+
value: currentPan,
|
|
1028
|
+
onChange: onPanChange,
|
|
1029
|
+
disabled: isGenerating,
|
|
1030
|
+
className: "w-10 flex-shrink-0"
|
|
1031
|
+
}
|
|
1032
|
+
)
|
|
1033
|
+
] })
|
|
1034
|
+
] }),
|
|
1035
|
+
error && /* @__PURE__ */ jsx6(
|
|
1036
|
+
"div",
|
|
1037
|
+
{
|
|
1038
|
+
"data-testid": "sdk-error-indicator",
|
|
1039
|
+
className: "flex-shrink-0 relative z-10 self-stretch flex items-center px-1 group cursor-help",
|
|
1040
|
+
title: error,
|
|
1041
|
+
children: /* @__PURE__ */ jsxs4("div", { className: "relative", children: [
|
|
1042
|
+
/* @__PURE__ */ jsx6(
|
|
1043
|
+
AlertCircle,
|
|
1044
|
+
{
|
|
1045
|
+
className: "w-5 h-5 text-red-500 animate-pulse",
|
|
1046
|
+
strokeWidth: 2.5
|
|
1047
|
+
}
|
|
1048
|
+
),
|
|
1049
|
+
/* @__PURE__ */ jsx6("div", { className: "absolute bottom-full left-1/2 -translate-x-1/2 mb-2 px-2 py-1 bg-red-900/95 text-red-100 text-xs rounded shadow-lg whitespace-nowrap opacity-0 group-hover:opacity-100 transition-opacity pointer-events-none z-50 max-w-[200px] truncate", children: error })
|
|
1050
|
+
] })
|
|
1051
|
+
}
|
|
1052
|
+
),
|
|
1053
|
+
/* @__PURE__ */ jsxs4("div", { className: "flex flex-col gap-0.5 flex-shrink-0 relative z-30 justify-center", children: [
|
|
1054
|
+
/* @__PURE__ */ jsxs4("div", { className: "flex gap-1 items-center", children: [
|
|
1055
|
+
onGenerate && /* @__PURE__ */ jsx6(
|
|
1056
|
+
"button",
|
|
1057
|
+
{
|
|
1058
|
+
"data-testid": "sdk-generate-button",
|
|
1059
|
+
onClick: onGenerate,
|
|
1060
|
+
disabled: !isAuthenticated || isGenerating || !prompt?.trim(),
|
|
1061
|
+
className: `w-14 py-0.5 rounded-sm text-xs font-medium transition-colors border ${!isAuthenticated || isGenerating ? "bg-sas-panel border-sas-border text-sas-muted/50 cursor-not-allowed" : needsGeneration ? "bg-amber-500/30 border-amber-500 text-amber-400 hover:bg-amber-500 hover:text-sas-bg animate-pulse" : prompt?.trim() ? "bg-sas-accent/20 border-sas-accent text-sas-accent hover:bg-sas-accent hover:text-sas-bg" : "bg-sas-panel border-sas-border text-sas-muted/50 cursor-not-allowed"}`,
|
|
1062
|
+
title: !isAuthenticated ? "Please log in" : isGenerating ? "Generating..." : "Generate MIDI",
|
|
1063
|
+
children: "Create"
|
|
1064
|
+
}
|
|
1065
|
+
),
|
|
1066
|
+
onCopy && /* @__PURE__ */ jsx6(
|
|
1067
|
+
"button",
|
|
1068
|
+
{
|
|
1069
|
+
"data-testid": "sdk-copy-button",
|
|
1070
|
+
onClick: onCopy,
|
|
1071
|
+
disabled: !hasMidi || isGenerating,
|
|
1072
|
+
className: `w-14 py-0.5 rounded-sm text-xs font-medium transition-colors border ${!hasMidi || isGenerating ? "bg-sas-panel border-sas-border text-sas-muted/30 cursor-not-allowed" : "bg-sas-panel-alt border-sas-border text-sas-muted hover:border-sas-accent hover:text-sas-accent"}`,
|
|
1073
|
+
title: hasMidi ? "Duplicate track with different preset" : "Generate MIDI first",
|
|
1074
|
+
children: "Copy"
|
|
1075
|
+
}
|
|
1076
|
+
),
|
|
1077
|
+
/* @__PURE__ */ jsx6(
|
|
1078
|
+
"button",
|
|
1079
|
+
{
|
|
1080
|
+
"data-testid": "sdk-mute-button",
|
|
1081
|
+
onClick: onMuteToggle,
|
|
1082
|
+
disabled: isGenerating,
|
|
1083
|
+
className: `px-1.5 py-0.5 text-xs font-bold rounded transition-colors ${isGenerating ? "bg-sas-panel text-sas-muted/50 cursor-not-allowed" : isMuted ? "bg-red-600 text-white" : "bg-sas-panel-alt text-sas-muted hover:bg-sas-border"}`,
|
|
1084
|
+
title: isMuted ? "Unmute track" : "Mute track",
|
|
1085
|
+
children: "M"
|
|
1086
|
+
}
|
|
1087
|
+
),
|
|
1088
|
+
/* @__PURE__ */ jsx6(
|
|
1089
|
+
"button",
|
|
1090
|
+
{
|
|
1091
|
+
"data-testid": "sdk-delete-button",
|
|
1092
|
+
onClick: onDelete,
|
|
1093
|
+
className: "text-sas-danger/70 hover:text-sas-danger px-1 py-0.5 transition-colors text-sm",
|
|
1094
|
+
title: "Delete track",
|
|
1095
|
+
children: "x"
|
|
1096
|
+
}
|
|
1097
|
+
)
|
|
1098
|
+
] }),
|
|
1099
|
+
/* @__PURE__ */ jsxs4("div", { className: "flex gap-1 items-center", children: [
|
|
1100
|
+
onShuffle && /* @__PURE__ */ jsx6(
|
|
1101
|
+
"button",
|
|
1102
|
+
{
|
|
1103
|
+
"data-testid": "sdk-shuffle-button",
|
|
1104
|
+
onClick: onShuffle,
|
|
1105
|
+
disabled: !hasMidi || isGenerating,
|
|
1106
|
+
className: `w-14 py-0.5 rounded-sm text-xs font-medium transition-colors border ${!hasMidi || isGenerating ? "bg-sas-panel border-sas-border text-sas-muted/30 cursor-not-allowed" : "bg-sas-panel-alt border-sas-border text-sas-muted hover:border-sas-accent hover:text-sas-accent"}`,
|
|
1107
|
+
title: hasMidi ? "Re-roll sound (keep MIDI)" : "Generate MIDI first",
|
|
1108
|
+
children: "Shuffle"
|
|
1109
|
+
}
|
|
1110
|
+
),
|
|
1111
|
+
onToggleFxDrawer && /* @__PURE__ */ jsx6(
|
|
1112
|
+
"button",
|
|
1113
|
+
{
|
|
1114
|
+
"data-testid": "sdk-fx-button",
|
|
1115
|
+
onClick: onToggleFxDrawer,
|
|
1116
|
+
disabled: isGenerating,
|
|
1117
|
+
className: `w-14 py-0.5 rounded-sm text-xs font-medium transition-colors border ${isGenerating ? "bg-sas-panel border-sas-border text-sas-muted/50 cursor-not-allowed" : fxDrawerOpen ? "bg-sas-accent border-sas-accent text-sas-bg" : hasFxActive ? "bg-sas-accent/20 border-sas-accent text-sas-accent hover:bg-sas-accent hover:text-sas-bg" : "bg-sas-panel-alt border-sas-border text-sas-muted hover:border-sas-accent hover:text-sas-accent"}`,
|
|
1118
|
+
title: fxDrawerOpen ? "Hide FX controls" : "Show FX controls",
|
|
1119
|
+
children: "FX"
|
|
1120
|
+
}
|
|
1121
|
+
),
|
|
1122
|
+
/* @__PURE__ */ jsx6(
|
|
1123
|
+
"button",
|
|
1124
|
+
{
|
|
1125
|
+
"data-testid": "sdk-solo-button",
|
|
1126
|
+
onClick: onSoloToggle,
|
|
1127
|
+
disabled: isGenerating,
|
|
1128
|
+
className: `px-1.5 py-0.5 text-xs font-bold rounded transition-colors ${isGenerating ? "bg-sas-panel text-sas-muted/50 cursor-not-allowed" : isSoloed ? "bg-yellow-500 text-black" : "bg-sas-panel-alt text-sas-muted hover:bg-sas-border"}`,
|
|
1129
|
+
title: isSoloed ? "Unsolo track" : "Solo track",
|
|
1130
|
+
children: "S"
|
|
1131
|
+
}
|
|
1132
|
+
),
|
|
1133
|
+
onToggleInstrumentDrawer && /* @__PURE__ */ jsx6(
|
|
1134
|
+
"button",
|
|
1135
|
+
{
|
|
1136
|
+
"data-testid": "sdk-plugin-button",
|
|
1137
|
+
onClick: onToggleInstrumentDrawer,
|
|
1138
|
+
disabled: isGenerating,
|
|
1139
|
+
className: `px-1.5 py-0.5 text-xs font-bold rounded transition-colors ${isGenerating ? "bg-sas-panel text-sas-muted/50 cursor-not-allowed" : instrumentDrawerOpen ? "bg-sas-accent border-sas-accent text-sas-bg" : instrumentMissing ? "bg-amber-500/20 text-amber-400 hover:bg-amber-500/40" : "bg-sas-panel-alt text-sas-muted hover:bg-sas-border"}`,
|
|
1140
|
+
title: `Plugin: ${instrumentName ?? "Surge XT"}${instrumentMissing ? " (missing)" : ""}`,
|
|
1141
|
+
children: "P"
|
|
1142
|
+
}
|
|
1143
|
+
)
|
|
1144
|
+
] })
|
|
1145
|
+
] })
|
|
1146
|
+
]
|
|
1147
|
+
}
|
|
1148
|
+
),
|
|
1149
|
+
fxDrawerOpen && !instrumentDrawerOpen && /* @__PURE__ */ jsx6("div", { "data-testid": "sdk-fx-drawer", className: "border border-t-0 border-sas-border bg-sas-bg rounded-b-sm px-3 py-2 max-h-[180px] overflow-y-auto", children: /* @__PURE__ */ jsx6(
|
|
1150
|
+
FxToggleBar,
|
|
1151
|
+
{
|
|
1152
|
+
trackId: track.id,
|
|
1153
|
+
fxState: fxDetailState,
|
|
1154
|
+
onToggle: (_trackId, category, enabled) => onFxToggle?.(category, enabled),
|
|
1155
|
+
onPresetChange: (_trackId, category, presetIndex) => onFxPresetChange?.(category, presetIndex),
|
|
1156
|
+
onDryWetChange: (_trackId, category, value) => onFxDryWetChange?.(category, value),
|
|
1157
|
+
disabled: isGenerating
|
|
1158
|
+
}
|
|
1159
|
+
) }),
|
|
1160
|
+
instrumentDrawerOpen && !fxDrawerOpen && availableInstruments && onInstrumentSelect && onRefreshInstruments && /* @__PURE__ */ jsx6("div", { "data-testid": "sdk-instrument-drawer", className: "border border-t-0 border-sas-border bg-sas-bg rounded-b-sm px-3 py-2", children: /* @__PURE__ */ jsx6(
|
|
1161
|
+
InstrumentDrawer,
|
|
1162
|
+
{
|
|
1163
|
+
instruments: availableInstruments,
|
|
1164
|
+
currentPluginId: currentInstrumentPluginId ?? null,
|
|
1165
|
+
isLoading: instrumentsLoading ?? false,
|
|
1166
|
+
onSelect: onInstrumentSelect,
|
|
1167
|
+
onRefresh: onRefreshInstruments
|
|
1168
|
+
}
|
|
1169
|
+
) })
|
|
1170
|
+
] });
|
|
1171
|
+
}
|
|
1172
|
+
|
|
1173
|
+
// src/hooks/useSceneState.ts
|
|
1174
|
+
import { useState as useState5, useCallback as useCallback3, useRef as useRef4 } from "react";
|
|
1175
|
+
function useSceneState(activeSceneId, initialValue) {
|
|
1176
|
+
const [stateMap, setStateMap] = useState5(() => /* @__PURE__ */ new Map());
|
|
1177
|
+
const activeSceneIdRef = useRef4(activeSceneId);
|
|
1178
|
+
activeSceneIdRef.current = activeSceneId;
|
|
1179
|
+
const currentValue = activeSceneId !== null && stateMap.has(activeSceneId) ? stateMap.get(activeSceneId) : initialValue;
|
|
1180
|
+
const setForCurrentScene = useCallback3((value) => {
|
|
1181
|
+
const sid = activeSceneIdRef.current;
|
|
1182
|
+
if (sid === null) return;
|
|
1183
|
+
setStateMap((prev) => {
|
|
1184
|
+
const current = prev.has(sid) ? prev.get(sid) : initialValue;
|
|
1185
|
+
const next = typeof value === "function" ? value(current) : value;
|
|
1186
|
+
const newMap = new Map(prev);
|
|
1187
|
+
newMap.set(sid, next);
|
|
1188
|
+
return newMap;
|
|
1189
|
+
});
|
|
1190
|
+
}, [initialValue]);
|
|
1191
|
+
const setForScene = useCallback3((sceneId, value) => {
|
|
1192
|
+
setStateMap((prev) => {
|
|
1193
|
+
const current = prev.has(sceneId) ? prev.get(sceneId) : initialValue;
|
|
1194
|
+
const next = typeof value === "function" ? value(current) : value;
|
|
1195
|
+
const newMap = new Map(prev);
|
|
1196
|
+
newMap.set(sceneId, next);
|
|
1197
|
+
return newMap;
|
|
1198
|
+
});
|
|
1199
|
+
}, [initialValue]);
|
|
1200
|
+
return [currentValue, setForCurrentScene, setForScene];
|
|
1201
|
+
}
|
|
1202
|
+
|
|
1203
|
+
// src/constants/instrument-roles.ts
|
|
1204
|
+
var VALID_INSTRUMENT_ROLES = [
|
|
1205
|
+
"bass",
|
|
1206
|
+
"kick",
|
|
1207
|
+
"snare",
|
|
1208
|
+
"hat",
|
|
1209
|
+
"808",
|
|
1210
|
+
"percussion",
|
|
1211
|
+
"lead",
|
|
1212
|
+
"pad",
|
|
1213
|
+
"keys",
|
|
1214
|
+
"piano",
|
|
1215
|
+
"organ",
|
|
1216
|
+
"pluck",
|
|
1217
|
+
"strings",
|
|
1218
|
+
"brass",
|
|
1219
|
+
"winds",
|
|
1220
|
+
"bell",
|
|
1221
|
+
"mallet",
|
|
1222
|
+
"guitar",
|
|
1223
|
+
"synth",
|
|
1224
|
+
"atmosphere",
|
|
1225
|
+
"drone",
|
|
1226
|
+
"rhythm",
|
|
1227
|
+
"soundscape",
|
|
1228
|
+
"vocal",
|
|
1229
|
+
"fx"
|
|
1230
|
+
];
|
|
1231
|
+
|
|
1232
|
+
// src/constants/sdk-version.ts
|
|
1233
|
+
var PLUGIN_SDK_VERSION = "1.0.0";
|
|
1234
|
+
export {
|
|
1235
|
+
DB_MAX,
|
|
1236
|
+
DB_MIN,
|
|
1237
|
+
DEFAULT_FX_CATEGORY_DETAIL,
|
|
1238
|
+
DEFAULT_FX_DRY_WET,
|
|
1239
|
+
EMPTY_FX_DETAIL_STATE,
|
|
1240
|
+
EMPTY_FX_STATE,
|
|
1241
|
+
FX_CATEGORIES,
|
|
1242
|
+
FX_CHAIN_ORDER,
|
|
1243
|
+
FX_DISPLAY_LABELS,
|
|
1244
|
+
FX_ENGINE_PLUGIN_NAMES,
|
|
1245
|
+
FX_PRESET_CONFIGS,
|
|
1246
|
+
FxToggleBar,
|
|
1247
|
+
InstrumentDrawer,
|
|
1248
|
+
PLUGIN_SDK_VERSION,
|
|
1249
|
+
PanSlider,
|
|
1250
|
+
PluginError,
|
|
1251
|
+
SLIDER_UNITY,
|
|
1252
|
+
SorceryProgressBar,
|
|
1253
|
+
TrackRow,
|
|
1254
|
+
VALID_INSTRUMENT_ROLES,
|
|
1255
|
+
VolumeSlider,
|
|
1256
|
+
calculateTimeBasedTarget,
|
|
1257
|
+
dbToSlider,
|
|
1258
|
+
sliderToDb,
|
|
1259
|
+
useSceneState
|
|
1260
|
+
};
|
|
1261
|
+
//# sourceMappingURL=index.mjs.map
|