@waveform-playlist/ui-components 9.1.1 → 9.2.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 +45 -7
- package/dist/index.d.ts +45 -7
- package/dist/index.js +317 -315
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +268 -265
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -38,9 +38,12 @@ __export(index_exports, {
|
|
|
38
38
|
BaseCheckboxWrapper: () => BaseCheckboxWrapper,
|
|
39
39
|
BaseControlButton: () => BaseControlButton,
|
|
40
40
|
BaseInput: () => BaseInput,
|
|
41
|
+
BaseInputSmall: () => BaseInputSmall,
|
|
41
42
|
BaseLabel: () => BaseLabel,
|
|
42
43
|
BaseSelect: () => BaseSelect,
|
|
44
|
+
BaseSelectSmall: () => BaseSelectSmall,
|
|
43
45
|
BaseSlider: () => BaseSlider,
|
|
46
|
+
BeatsAndBarsProvider: () => BeatsAndBarsProvider,
|
|
44
47
|
Button: () => Button,
|
|
45
48
|
ButtonGroup: () => ButtonGroup,
|
|
46
49
|
CLIP_BOUNDARY_WIDTH: () => CLIP_BOUNDARY_WIDTH,
|
|
@@ -94,14 +97,16 @@ __export(index_exports, {
|
|
|
94
97
|
darkTheme: () => darkTheme,
|
|
95
98
|
defaultTheme: () => defaultTheme,
|
|
96
99
|
formatTime: () => formatTime,
|
|
100
|
+
getScaleInfo: () => getScaleInfo,
|
|
97
101
|
isWaveformGradient: () => isWaveformGradient,
|
|
98
102
|
parseTime: () => parseTime,
|
|
99
103
|
pixelsToSamples: () => pixelsToSamples,
|
|
100
104
|
pixelsToSeconds: () => pixelsToSeconds,
|
|
101
|
-
samplesToPixels: () =>
|
|
105
|
+
samplesToPixels: () => samplesToPixels2,
|
|
102
106
|
samplesToSeconds: () => samplesToSeconds,
|
|
103
|
-
secondsToPixels: () =>
|
|
107
|
+
secondsToPixels: () => secondsToPixels2,
|
|
104
108
|
secondsToSamples: () => secondsToSamples,
|
|
109
|
+
useBeatsAndBars: () => useBeatsAndBars,
|
|
105
110
|
useClipViewportOrigin: () => useClipViewportOrigin,
|
|
106
111
|
useDevicePixelRatio: () => useDevicePixelRatio,
|
|
107
112
|
usePlaylistInfo: () => usePlaylistInfo,
|
|
@@ -890,7 +895,6 @@ var Channel = (props) => {
|
|
|
890
895
|
const clipOriginX = useClipViewportOrigin();
|
|
891
896
|
const visibleChunkIndices = useVisibleChunkIndices(length, import_core.MAX_CANVAS_WIDTH, clipOriginX);
|
|
892
897
|
(0, import_react4.useEffect)(() => {
|
|
893
|
-
const tDraw = performance.now();
|
|
894
898
|
const step = barWidth + barGap;
|
|
895
899
|
for (const [canvasIdx, canvas] of canvasMapRef.current.entries()) {
|
|
896
900
|
const globalPixelOffset = canvasIdx * import_core.MAX_CANVAS_WIDTH;
|
|
@@ -926,9 +930,6 @@ var Channel = (props) => {
|
|
|
926
930
|
}
|
|
927
931
|
}
|
|
928
932
|
}
|
|
929
|
-
console.log(
|
|
930
|
-
`[waveform] draw ch${index}: ${canvasMapRef.current.size} chunks, ${(performance.now() - tDraw).toFixed(1)}ms`
|
|
931
|
-
);
|
|
932
933
|
}, [
|
|
933
934
|
canvasMapRef,
|
|
934
935
|
data,
|
|
@@ -1214,6 +1215,7 @@ var FadeOverlay = ({
|
|
|
1214
1215
|
};
|
|
1215
1216
|
|
|
1216
1217
|
// src/components/Clip.tsx
|
|
1218
|
+
var import_core2 = require("@waveform-playlist/core");
|
|
1217
1219
|
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
1218
1220
|
var ClipContainer = import_styled_components13.default.div.attrs((props) => ({
|
|
1219
1221
|
style: props.$isOverlay ? {} : {
|
|
@@ -1227,13 +1229,8 @@ var ClipContainer = import_styled_components13.default.div.attrs((props) => ({
|
|
|
1227
1229
|
width: ${(props) => props.$isOverlay ? `${props.$width}px` : "auto"};
|
|
1228
1230
|
display: flex;
|
|
1229
1231
|
flex-direction: column;
|
|
1230
|
-
background: rgba(255, 255, 255, 0.05);
|
|
1231
1232
|
z-index: 10; /* Above progress overlay (z-index: 2) but below controls/playhead */
|
|
1232
1233
|
pointer-events: none; /* Let clicks pass through to ClickOverlay for playhead positioning */
|
|
1233
|
-
|
|
1234
|
-
&:hover {
|
|
1235
|
-
background: rgba(255, 255, 255, 0.08);
|
|
1236
|
-
}
|
|
1237
1234
|
`;
|
|
1238
1235
|
var ChannelsWrapper = import_styled_components13.default.div`
|
|
1239
1236
|
flex: 1;
|
|
@@ -1263,8 +1260,7 @@ var Clip = ({
|
|
|
1263
1260
|
touchOptimized = false
|
|
1264
1261
|
}) => {
|
|
1265
1262
|
const left = Math.floor(startSample / samplesPerPixel);
|
|
1266
|
-
const
|
|
1267
|
-
const width = endPixel - left;
|
|
1263
|
+
const width = (0, import_core2.clipPixelWidth)(startSample, durationSamples, samplesPerPixel);
|
|
1268
1264
|
const enableDrag = showHeader && !disableHeaderDrag && !isOverlay;
|
|
1269
1265
|
const draggableId = `clip-${trackIndex}-${clipIndex}`;
|
|
1270
1266
|
const {
|
|
@@ -1273,20 +1269,20 @@ var Clip = ({
|
|
|
1273
1269
|
isDragSource
|
|
1274
1270
|
} = (0, import_react7.useDraggable)({
|
|
1275
1271
|
id: draggableId,
|
|
1276
|
-
data: { clipId, trackIndex, clipIndex },
|
|
1272
|
+
data: { clipId, trackIndex, clipIndex, startSample, durationSamples },
|
|
1277
1273
|
disabled: !enableDrag
|
|
1278
1274
|
});
|
|
1279
1275
|
const leftBoundaryId = `clip-boundary-left-${trackIndex}-${clipIndex}`;
|
|
1280
1276
|
const { ref: leftBoundaryRef, isDragSource: isLeftBoundaryDragging } = (0, import_react7.useDraggable)({
|
|
1281
1277
|
id: leftBoundaryId,
|
|
1282
|
-
data: { clipId, trackIndex, clipIndex, boundary: "left" },
|
|
1278
|
+
data: { clipId, trackIndex, clipIndex, boundary: "left", startSample, durationSamples },
|
|
1283
1279
|
disabled: !enableDrag,
|
|
1284
1280
|
feedback: "none"
|
|
1285
1281
|
});
|
|
1286
1282
|
const rightBoundaryId = `clip-boundary-right-${trackIndex}-${clipIndex}`;
|
|
1287
1283
|
const { ref: rightBoundaryRef, isDragSource: isRightBoundaryDragging } = (0, import_react7.useDraggable)({
|
|
1288
1284
|
id: rightBoundaryId,
|
|
1289
|
-
data: { clipId, trackIndex, clipIndex, boundary: "right" },
|
|
1285
|
+
data: { clipId, trackIndex, clipIndex, boundary: "right", startSample, durationSamples },
|
|
1290
1286
|
disabled: !enableDrag,
|
|
1291
1287
|
feedback: "none"
|
|
1292
1288
|
});
|
|
@@ -1416,7 +1412,7 @@ var MasterVolumeControl = ({
|
|
|
1416
1412
|
// src/components/PianoRollChannel.tsx
|
|
1417
1413
|
var import_react8 = require("react");
|
|
1418
1414
|
var import_styled_components15 = __toESM(require("styled-components"));
|
|
1419
|
-
var
|
|
1415
|
+
var import_core3 = require("@waveform-playlist/core");
|
|
1420
1416
|
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
1421
1417
|
var NoteCanvas = import_styled_components15.default.canvas.attrs((props) => ({
|
|
1422
1418
|
style: {
|
|
@@ -1459,7 +1455,7 @@ var PianoRollChannel = ({
|
|
|
1459
1455
|
}) => {
|
|
1460
1456
|
const { canvasRef, canvasMapRef } = useChunkedCanvasRefs();
|
|
1461
1457
|
const clipOriginX = useClipViewportOrigin();
|
|
1462
|
-
const visibleChunkIndices = useVisibleChunkIndices(length,
|
|
1458
|
+
const visibleChunkIndices = useVisibleChunkIndices(length, import_core3.MAX_CANVAS_WIDTH, clipOriginX);
|
|
1463
1459
|
const { minMidi, maxMidi } = (0, import_react8.useMemo)(() => {
|
|
1464
1460
|
if (midiNotes.length === 0) return { minMidi: 0, maxMidi: 127 };
|
|
1465
1461
|
let min = 127, max = 0;
|
|
@@ -1471,12 +1467,11 @@ var PianoRollChannel = ({
|
|
|
1471
1467
|
}, [midiNotes]);
|
|
1472
1468
|
const color = isSelected ? selectedNoteColor : noteColor;
|
|
1473
1469
|
(0, import_react8.useEffect)(() => {
|
|
1474
|
-
const tDraw = performance.now();
|
|
1475
1470
|
const noteRange = maxMidi - minMidi + 1;
|
|
1476
1471
|
const noteHeight = Math.max(2, waveHeight / noteRange);
|
|
1477
1472
|
const pixelsPerSecond = sampleRate / samplesPerPixel;
|
|
1478
1473
|
for (const [canvasIdx, canvas] of canvasMapRef.current.entries()) {
|
|
1479
|
-
const chunkPixelStart = canvasIdx *
|
|
1474
|
+
const chunkPixelStart = canvasIdx * import_core3.MAX_CANVAS_WIDTH;
|
|
1480
1475
|
const canvasWidth = canvas.width / devicePixelRatio;
|
|
1481
1476
|
const ctx = canvas.getContext("2d");
|
|
1482
1477
|
if (!ctx) continue;
|
|
@@ -1503,9 +1498,6 @@ var PianoRollChannel = ({
|
|
|
1503
1498
|
}
|
|
1504
1499
|
ctx.globalAlpha = 1;
|
|
1505
1500
|
}
|
|
1506
|
-
console.log(
|
|
1507
|
-
`[piano-roll] draw ch${index}: ${canvasMapRef.current.size} chunks, ${midiNotes.length} notes, ${(performance.now() - tDraw).toFixed(1)}ms`
|
|
1508
|
-
);
|
|
1509
1501
|
}, [
|
|
1510
1502
|
canvasMapRef,
|
|
1511
1503
|
midiNotes,
|
|
@@ -1522,8 +1514,8 @@ var PianoRollChannel = ({
|
|
|
1522
1514
|
index
|
|
1523
1515
|
]);
|
|
1524
1516
|
const canvases = visibleChunkIndices.map((i) => {
|
|
1525
|
-
const chunkLeft = i *
|
|
1526
|
-
const currentWidth = Math.min(length - chunkLeft,
|
|
1517
|
+
const chunkLeft = i * import_core3.MAX_CANVAS_WIDTH;
|
|
1518
|
+
const currentWidth = Math.min(length - chunkLeft, import_core3.MAX_CANVAS_WIDTH);
|
|
1527
1519
|
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1528
1520
|
NoteCanvas,
|
|
1529
1521
|
{
|
|
@@ -2145,7 +2137,7 @@ function clockFormat(seconds, decimals) {
|
|
|
2145
2137
|
const hours = Math.floor(seconds / 3600) % 24;
|
|
2146
2138
|
const minutes = Math.floor(seconds / 60) % 60;
|
|
2147
2139
|
const secs = (seconds % 60).toFixed(decimals);
|
|
2148
|
-
return String(hours).padStart(2, "0") + ":" + String(minutes).padStart(2, "0") + ":" + secs.padStart(decimals + 3, "0");
|
|
2140
|
+
return String(hours).padStart(2, "0") + ":" + String(minutes).padStart(2, "0") + ":" + secs.padStart(decimals > 0 ? decimals + 3 : 2, "0");
|
|
2149
2141
|
}
|
|
2150
2142
|
function formatTime(seconds, format) {
|
|
2151
2143
|
switch (format) {
|
|
@@ -2297,15 +2289,45 @@ var SelectionTimeInputs = ({
|
|
|
2297
2289
|
] });
|
|
2298
2290
|
};
|
|
2299
2291
|
|
|
2300
|
-
// src/contexts/
|
|
2292
|
+
// src/contexts/BeatsAndBars.tsx
|
|
2301
2293
|
var import_react14 = require("react");
|
|
2294
|
+
var import_core4 = require("@waveform-playlist/core");
|
|
2302
2295
|
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
2296
|
+
var BeatsAndBarsContext = (0, import_react14.createContext)(null);
|
|
2297
|
+
function BeatsAndBarsProvider({
|
|
2298
|
+
bpm,
|
|
2299
|
+
timeSignature,
|
|
2300
|
+
snapTo,
|
|
2301
|
+
children
|
|
2302
|
+
}) {
|
|
2303
|
+
const [numerator, denominator] = timeSignature;
|
|
2304
|
+
const value = (0, import_react14.useMemo)(() => {
|
|
2305
|
+
const ts = [numerator, denominator];
|
|
2306
|
+
const tpBeat = (0, import_core4.ticksPerBeat)(ts);
|
|
2307
|
+
const tpBar = (0, import_core4.ticksPerBar)(ts);
|
|
2308
|
+
return {
|
|
2309
|
+
bpm,
|
|
2310
|
+
timeSignature: ts,
|
|
2311
|
+
snapTo,
|
|
2312
|
+
ticksPerBeat: tpBeat,
|
|
2313
|
+
ticksPerBar: tpBar
|
|
2314
|
+
};
|
|
2315
|
+
}, [bpm, numerator, denominator, snapTo]);
|
|
2316
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(BeatsAndBarsContext.Provider, { value, children });
|
|
2317
|
+
}
|
|
2318
|
+
function useBeatsAndBars() {
|
|
2319
|
+
return (0, import_react14.useContext)(BeatsAndBarsContext);
|
|
2320
|
+
}
|
|
2321
|
+
|
|
2322
|
+
// src/contexts/DevicePixelRatio.tsx
|
|
2323
|
+
var import_react15 = require("react");
|
|
2324
|
+
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
2303
2325
|
function getScale() {
|
|
2304
2326
|
return window.devicePixelRatio;
|
|
2305
2327
|
}
|
|
2306
|
-
var DevicePixelRatioContext = (0,
|
|
2328
|
+
var DevicePixelRatioContext = (0, import_react15.createContext)(getScale());
|
|
2307
2329
|
var DevicePixelRatioProvider = ({ children }) => {
|
|
2308
|
-
const [scale, setScale] = (0,
|
|
2330
|
+
const [scale, setScale] = (0, import_react15.useState)(getScale());
|
|
2309
2331
|
matchMedia(`(resolution: ${getScale()}dppx)`).addEventListener(
|
|
2310
2332
|
"change",
|
|
2311
2333
|
() => {
|
|
@@ -2313,13 +2335,13 @@ var DevicePixelRatioProvider = ({ children }) => {
|
|
|
2313
2335
|
},
|
|
2314
2336
|
{ once: true }
|
|
2315
2337
|
);
|
|
2316
|
-
return /* @__PURE__ */ (0,
|
|
2338
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(DevicePixelRatioContext.Provider, { value: Math.ceil(scale), children });
|
|
2317
2339
|
};
|
|
2318
|
-
var useDevicePixelRatio = () => (0,
|
|
2340
|
+
var useDevicePixelRatio = () => (0, import_react15.useContext)(DevicePixelRatioContext);
|
|
2319
2341
|
|
|
2320
2342
|
// src/contexts/PlaylistInfo.tsx
|
|
2321
|
-
var
|
|
2322
|
-
var PlaylistInfoContext = (0,
|
|
2343
|
+
var import_react16 = require("react");
|
|
2344
|
+
var PlaylistInfoContext = (0, import_react16.createContext)({
|
|
2323
2345
|
sampleRate: 48e3,
|
|
2324
2346
|
samplesPerPixel: 1e3,
|
|
2325
2347
|
zoomLevels: [1e3, 1500, 2e3, 2500],
|
|
@@ -2333,22 +2355,22 @@ var PlaylistInfoContext = (0, import_react15.createContext)({
|
|
|
2333
2355
|
barWidth: 1,
|
|
2334
2356
|
barGap: 0
|
|
2335
2357
|
});
|
|
2336
|
-
var usePlaylistInfo = () => (0,
|
|
2358
|
+
var usePlaylistInfo = () => (0, import_react16.useContext)(PlaylistInfoContext);
|
|
2337
2359
|
|
|
2338
2360
|
// src/contexts/Theme.tsx
|
|
2339
|
-
var
|
|
2361
|
+
var import_react17 = require("react");
|
|
2340
2362
|
var import_styled_components20 = require("styled-components");
|
|
2341
|
-
var useTheme2 = () => (0,
|
|
2363
|
+
var useTheme2 = () => (0, import_react17.useContext)(import_styled_components20.ThemeContext);
|
|
2342
2364
|
|
|
2343
2365
|
// src/contexts/TrackControls.tsx
|
|
2344
|
-
var import_react17 = require("react");
|
|
2345
|
-
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
2346
|
-
var TrackControlsContext = (0, import_react17.createContext)(/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react17.Fragment, {}));
|
|
2347
|
-
var useTrackControls = () => (0, import_react17.useContext)(TrackControlsContext);
|
|
2348
|
-
|
|
2349
|
-
// src/contexts/Playout.tsx
|
|
2350
2366
|
var import_react18 = require("react");
|
|
2351
2367
|
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
2368
|
+
var TrackControlsContext = (0, import_react18.createContext)(/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react18.Fragment, {}));
|
|
2369
|
+
var useTrackControls = () => (0, import_react18.useContext)(TrackControlsContext);
|
|
2370
|
+
|
|
2371
|
+
// src/contexts/Playout.tsx
|
|
2372
|
+
var import_react19 = require("react");
|
|
2373
|
+
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
2352
2374
|
var defaultProgress = 0;
|
|
2353
2375
|
var defaultIsPlaying = false;
|
|
2354
2376
|
var defaultSelectionStart = 0;
|
|
@@ -2359,8 +2381,8 @@ var defaultPlayout = {
|
|
|
2359
2381
|
selectionStart: defaultSelectionStart,
|
|
2360
2382
|
selectionEnd: defaultSelectionEnd
|
|
2361
2383
|
};
|
|
2362
|
-
var PlayoutStatusContext = (0,
|
|
2363
|
-
var PlayoutStatusUpdateContext = (0,
|
|
2384
|
+
var PlayoutStatusContext = (0, import_react19.createContext)(defaultPlayout);
|
|
2385
|
+
var PlayoutStatusUpdateContext = (0, import_react19.createContext)({
|
|
2364
2386
|
setIsPlaying: () => {
|
|
2365
2387
|
},
|
|
2366
2388
|
setProgress: () => {
|
|
@@ -2369,24 +2391,24 @@ var PlayoutStatusUpdateContext = (0, import_react18.createContext)({
|
|
|
2369
2391
|
}
|
|
2370
2392
|
});
|
|
2371
2393
|
var PlayoutProvider = ({ children }) => {
|
|
2372
|
-
const [isPlaying, setIsPlaying] = (0,
|
|
2373
|
-
const [progress, setProgress] = (0,
|
|
2374
|
-
const [selectionStart, setSelectionStart] = (0,
|
|
2375
|
-
const [selectionEnd, setSelectionEnd] = (0,
|
|
2394
|
+
const [isPlaying, setIsPlaying] = (0, import_react19.useState)(defaultIsPlaying);
|
|
2395
|
+
const [progress, setProgress] = (0, import_react19.useState)(defaultProgress);
|
|
2396
|
+
const [selectionStart, setSelectionStart] = (0, import_react19.useState)(defaultSelectionStart);
|
|
2397
|
+
const [selectionEnd, setSelectionEnd] = (0, import_react19.useState)(defaultSelectionEnd);
|
|
2376
2398
|
const setSelection = (start, end) => {
|
|
2377
2399
|
setSelectionStart(start);
|
|
2378
2400
|
setSelectionEnd(end);
|
|
2379
2401
|
};
|
|
2380
|
-
return /* @__PURE__ */ (0,
|
|
2402
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(PlayoutStatusUpdateContext.Provider, { value: { setIsPlaying, setProgress, setSelection }, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(PlayoutStatusContext.Provider, { value: { isPlaying, progress, selectionStart, selectionEnd }, children }) });
|
|
2381
2403
|
};
|
|
2382
|
-
var usePlayoutStatus = () => (0,
|
|
2383
|
-
var usePlayoutStatusUpdate = () => (0,
|
|
2404
|
+
var usePlayoutStatus = () => (0, import_react19.useContext)(PlayoutStatusContext);
|
|
2405
|
+
var usePlayoutStatusUpdate = () => (0, import_react19.useContext)(PlayoutStatusUpdateContext);
|
|
2384
2406
|
|
|
2385
2407
|
// src/components/SpectrogramChannel.tsx
|
|
2386
|
-
var
|
|
2408
|
+
var import_react20 = require("react");
|
|
2387
2409
|
var import_styled_components21 = __toESM(require("styled-components"));
|
|
2388
|
-
var
|
|
2389
|
-
var
|
|
2410
|
+
var import_core5 = require("@waveform-playlist/core");
|
|
2411
|
+
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
2390
2412
|
var LINEAR_FREQUENCY_SCALE = (f, minF, maxF) => (f - minF) / (maxF - minF);
|
|
2391
2413
|
var Wrapper4 = import_styled_components21.default.div.attrs((props) => ({
|
|
2392
2414
|
style: {
|
|
@@ -2438,24 +2460,24 @@ var SpectrogramChannel = ({
|
|
|
2438
2460
|
}) => {
|
|
2439
2461
|
const channelIndex = channelIndexProp ?? index;
|
|
2440
2462
|
const { canvasRef, canvasMapRef } = useChunkedCanvasRefs();
|
|
2441
|
-
const registeredIdsRef = (0,
|
|
2442
|
-
const transferredCanvasesRef = (0,
|
|
2443
|
-
const workerApiRef = (0,
|
|
2444
|
-
const onCanvasesReadyRef = (0,
|
|
2463
|
+
const registeredIdsRef = (0, import_react20.useRef)([]);
|
|
2464
|
+
const transferredCanvasesRef = (0, import_react20.useRef)(/* @__PURE__ */ new WeakSet());
|
|
2465
|
+
const workerApiRef = (0, import_react20.useRef)(workerApi);
|
|
2466
|
+
const onCanvasesReadyRef = (0, import_react20.useRef)(onCanvasesReady);
|
|
2445
2467
|
const isWorkerMode = !!(workerApi && clipId);
|
|
2446
2468
|
const clipOriginX = useClipViewportOrigin();
|
|
2447
|
-
const visibleChunkIndices = useVisibleChunkIndices(length,
|
|
2469
|
+
const visibleChunkIndices = useVisibleChunkIndices(length, import_core5.MAX_CANVAS_WIDTH, clipOriginX);
|
|
2448
2470
|
const lut = colorLUT ?? DEFAULT_COLOR_LUT;
|
|
2449
2471
|
const maxF = maxFrequency ?? (data ? data.sampleRate / 2 : 22050);
|
|
2450
2472
|
const scaleFn = frequencyScaleFn ?? LINEAR_FREQUENCY_SCALE;
|
|
2451
2473
|
const hasCustomFrequencyScale = Boolean(frequencyScaleFn);
|
|
2452
|
-
(0,
|
|
2474
|
+
(0, import_react20.useEffect)(() => {
|
|
2453
2475
|
workerApiRef.current = workerApi;
|
|
2454
2476
|
}, [workerApi]);
|
|
2455
|
-
(0,
|
|
2477
|
+
(0, import_react20.useEffect)(() => {
|
|
2456
2478
|
onCanvasesReadyRef.current = onCanvasesReady;
|
|
2457
2479
|
}, [onCanvasesReady]);
|
|
2458
|
-
(0,
|
|
2480
|
+
(0, import_react20.useEffect)(() => {
|
|
2459
2481
|
if (!isWorkerMode) return;
|
|
2460
2482
|
const currentWorkerApi = workerApiRef.current;
|
|
2461
2483
|
if (!currentWorkerApi || !clipId) return;
|
|
@@ -2510,15 +2532,15 @@ var SpectrogramChannel = ({
|
|
|
2510
2532
|
const match = id.match(/chunk(\d+)$/);
|
|
2511
2533
|
if (!match) {
|
|
2512
2534
|
console.warn(`[spectrogram] Unexpected canvas ID format: ${id}`);
|
|
2513
|
-
return
|
|
2535
|
+
return import_core5.MAX_CANVAS_WIDTH;
|
|
2514
2536
|
}
|
|
2515
2537
|
const chunkIdx = parseInt(match[1], 10);
|
|
2516
|
-
return Math.min(length - chunkIdx *
|
|
2538
|
+
return Math.min(length - chunkIdx * import_core5.MAX_CANVAS_WIDTH, import_core5.MAX_CANVAS_WIDTH);
|
|
2517
2539
|
});
|
|
2518
2540
|
onCanvasesReadyRef.current?.(allIds, allWidths);
|
|
2519
2541
|
}
|
|
2520
2542
|
}, [canvasMapRef, isWorkerMode, clipId, channelIndex, length, visibleChunkIndices]);
|
|
2521
|
-
(0,
|
|
2543
|
+
(0, import_react20.useEffect)(() => {
|
|
2522
2544
|
return () => {
|
|
2523
2545
|
const api = workerApiRef.current;
|
|
2524
2546
|
if (!api) return;
|
|
@@ -2532,7 +2554,7 @@ var SpectrogramChannel = ({
|
|
|
2532
2554
|
registeredIdsRef.current = [];
|
|
2533
2555
|
};
|
|
2534
2556
|
}, []);
|
|
2535
|
-
(0,
|
|
2557
|
+
(0, import_react20.useEffect)(() => {
|
|
2536
2558
|
if (isWorkerMode || !data) return;
|
|
2537
2559
|
const {
|
|
2538
2560
|
frequencyBinCount,
|
|
@@ -2545,7 +2567,7 @@ var SpectrogramChannel = ({
|
|
|
2545
2567
|
const rangeDb = rawRangeDb === 0 ? 1 : rawRangeDb;
|
|
2546
2568
|
const binToFreq = (bin) => bin / frequencyBinCount * (sampleRate / 2);
|
|
2547
2569
|
for (const [canvasIdx, canvas] of canvasMapRef.current.entries()) {
|
|
2548
|
-
const globalPixelOffset = canvasIdx *
|
|
2570
|
+
const globalPixelOffset = canvasIdx * import_core5.MAX_CANVAS_WIDTH;
|
|
2549
2571
|
const ctx = canvas.getContext("2d");
|
|
2550
2572
|
if (!ctx) continue;
|
|
2551
2573
|
const canvasWidth = canvas.width / devicePixelRatio;
|
|
@@ -2621,9 +2643,9 @@ var SpectrogramChannel = ({
|
|
|
2621
2643
|
visibleChunkIndices
|
|
2622
2644
|
]);
|
|
2623
2645
|
const canvases = visibleChunkIndices.map((i) => {
|
|
2624
|
-
const chunkLeft = i *
|
|
2625
|
-
const currentWidth = Math.min(length - chunkLeft,
|
|
2626
|
-
return /* @__PURE__ */ (0,
|
|
2646
|
+
const chunkLeft = i * import_core5.MAX_CANVAS_WIDTH;
|
|
2647
|
+
const currentWidth = Math.min(length - chunkLeft, import_core5.MAX_CANVAS_WIDTH);
|
|
2648
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
2627
2649
|
SpectrogramCanvas,
|
|
2628
2650
|
{
|
|
2629
2651
|
$cssWidth: currentWidth,
|
|
@@ -2637,11 +2659,11 @@ var SpectrogramChannel = ({
|
|
|
2637
2659
|
`${length}-${i}`
|
|
2638
2660
|
);
|
|
2639
2661
|
});
|
|
2640
|
-
return /* @__PURE__ */ (0,
|
|
2662
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Wrapper4, { $index: index, $cssWidth: length, $waveHeight: waveHeight, children: canvases });
|
|
2641
2663
|
};
|
|
2642
2664
|
|
|
2643
2665
|
// src/components/SmartChannel.tsx
|
|
2644
|
-
var
|
|
2666
|
+
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
2645
2667
|
var SmartChannel = ({
|
|
2646
2668
|
isSelected,
|
|
2647
2669
|
transparentBackground,
|
|
@@ -2675,7 +2697,7 @@ var SmartChannel = ({
|
|
|
2675
2697
|
const drawMode = theme?.waveformDrawMode || "inverted";
|
|
2676
2698
|
const hasSpectrogram = spectrogramData || spectrogramWorkerApi;
|
|
2677
2699
|
if (renderMode === "spectrogram" && hasSpectrogram) {
|
|
2678
|
-
return /* @__PURE__ */ (0,
|
|
2700
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
2679
2701
|
SpectrogramChannel,
|
|
2680
2702
|
{
|
|
2681
2703
|
index: props.index,
|
|
@@ -2696,8 +2718,8 @@ var SmartChannel = ({
|
|
|
2696
2718
|
}
|
|
2697
2719
|
if (renderMode === "both" && hasSpectrogram) {
|
|
2698
2720
|
const halfHeight = Math.floor(waveHeight / 2);
|
|
2699
|
-
return /* @__PURE__ */ (0,
|
|
2700
|
-
/* @__PURE__ */ (0,
|
|
2721
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_jsx_runtime24.Fragment, { children: [
|
|
2722
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
2701
2723
|
SpectrogramChannel,
|
|
2702
2724
|
{
|
|
2703
2725
|
index: props.index * 2,
|
|
@@ -2716,7 +2738,7 @@ var SmartChannel = ({
|
|
|
2716
2738
|
onCanvasesReady: spectrogramOnCanvasesReady
|
|
2717
2739
|
}
|
|
2718
2740
|
),
|
|
2719
|
-
/* @__PURE__ */ (0,
|
|
2741
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
2720
2742
|
"div",
|
|
2721
2743
|
{
|
|
2722
2744
|
style: {
|
|
@@ -2725,7 +2747,7 @@ var SmartChannel = ({
|
|
|
2725
2747
|
width: props.length,
|
|
2726
2748
|
height: halfHeight
|
|
2727
2749
|
},
|
|
2728
|
-
children: /* @__PURE__ */ (0,
|
|
2750
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
2729
2751
|
Channel,
|
|
2730
2752
|
{
|
|
2731
2753
|
...props,
|
|
@@ -2745,7 +2767,7 @@ var SmartChannel = ({
|
|
|
2745
2767
|
] });
|
|
2746
2768
|
}
|
|
2747
2769
|
if (renderMode === "piano-roll") {
|
|
2748
|
-
return /* @__PURE__ */ (0,
|
|
2770
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
2749
2771
|
PianoRollChannel,
|
|
2750
2772
|
{
|
|
2751
2773
|
index: props.index,
|
|
@@ -2764,7 +2786,7 @@ var SmartChannel = ({
|
|
|
2764
2786
|
}
|
|
2765
2787
|
);
|
|
2766
2788
|
}
|
|
2767
|
-
return /* @__PURE__ */ (0,
|
|
2789
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
2768
2790
|
Channel,
|
|
2769
2791
|
{
|
|
2770
2792
|
...props,
|
|
@@ -2781,9 +2803,9 @@ var SmartChannel = ({
|
|
|
2781
2803
|
};
|
|
2782
2804
|
|
|
2783
2805
|
// src/components/SpectrogramLabels.tsx
|
|
2784
|
-
var
|
|
2806
|
+
var import_react21 = require("react");
|
|
2785
2807
|
var import_styled_components22 = __toESM(require("styled-components"));
|
|
2786
|
-
var
|
|
2808
|
+
var import_jsx_runtime25 = require("react/jsx-runtime");
|
|
2787
2809
|
var LABELS_WIDTH = 72;
|
|
2788
2810
|
var LabelsStickyWrapper = import_styled_components22.default.div`
|
|
2789
2811
|
position: sticky;
|
|
@@ -2833,12 +2855,12 @@ var SpectrogramLabels = ({
|
|
|
2833
2855
|
renderMode = "spectrogram",
|
|
2834
2856
|
hasClipHeaders = false
|
|
2835
2857
|
}) => {
|
|
2836
|
-
const canvasRef = (0,
|
|
2858
|
+
const canvasRef = (0, import_react21.useRef)(null);
|
|
2837
2859
|
const devicePixelRatio = useDevicePixelRatio();
|
|
2838
2860
|
const spectrogramHeight = renderMode === "both" ? Math.floor(waveHeight / 2) : waveHeight;
|
|
2839
2861
|
const totalHeight = numChannels * waveHeight;
|
|
2840
2862
|
const clipHeaderOffset = hasClipHeaders ? 22 : 0;
|
|
2841
|
-
(0,
|
|
2863
|
+
(0, import_react21.useLayoutEffect)(() => {
|
|
2842
2864
|
const canvas = canvasRef.current;
|
|
2843
2865
|
if (!canvas) return;
|
|
2844
2866
|
const ctx = canvas.getContext("2d");
|
|
@@ -2876,7 +2898,7 @@ var SpectrogramLabels = ({
|
|
|
2876
2898
|
spectrogramHeight,
|
|
2877
2899
|
clipHeaderOffset
|
|
2878
2900
|
]);
|
|
2879
|
-
return /* @__PURE__ */ (0,
|
|
2901
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(LabelsStickyWrapper, { $height: totalHeight + clipHeaderOffset, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
2880
2902
|
"canvas",
|
|
2881
2903
|
{
|
|
2882
2904
|
ref: canvasRef,
|
|
@@ -2892,41 +2914,14 @@ var SpectrogramLabels = ({
|
|
|
2892
2914
|
};
|
|
2893
2915
|
|
|
2894
2916
|
// src/components/SmartScale.tsx
|
|
2895
|
-
var
|
|
2917
|
+
var import_react23 = __toESM(require("react"));
|
|
2918
|
+
var import_styled_components24 = __toESM(require("styled-components"));
|
|
2896
2919
|
|
|
2897
2920
|
// src/components/TimeScale.tsx
|
|
2898
|
-
var
|
|
2921
|
+
var import_react22 = require("react");
|
|
2899
2922
|
var import_styled_components23 = __toESM(require("styled-components"));
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
function samplesToSeconds(samples, sampleRate) {
|
|
2903
|
-
return samples / sampleRate;
|
|
2904
|
-
}
|
|
2905
|
-
function secondsToSamples(seconds, sampleRate) {
|
|
2906
|
-
return Math.ceil(seconds * sampleRate);
|
|
2907
|
-
}
|
|
2908
|
-
function samplesToPixels(samples, samplesPerPixel) {
|
|
2909
|
-
return Math.floor(samples / samplesPerPixel);
|
|
2910
|
-
}
|
|
2911
|
-
function pixelsToSamples(pixels, samplesPerPixel) {
|
|
2912
|
-
return Math.floor(pixels * samplesPerPixel);
|
|
2913
|
-
}
|
|
2914
|
-
function pixelsToSeconds(pixels, samplesPerPixel, sampleRate) {
|
|
2915
|
-
return pixels * samplesPerPixel / sampleRate;
|
|
2916
|
-
}
|
|
2917
|
-
function secondsToPixels(seconds, samplesPerPixel, sampleRate) {
|
|
2918
|
-
return Math.ceil(seconds * sampleRate / samplesPerPixel);
|
|
2919
|
-
}
|
|
2920
|
-
|
|
2921
|
-
// src/components/TimeScale.tsx
|
|
2922
|
-
var import_core4 = require("@waveform-playlist/core");
|
|
2923
|
-
var import_jsx_runtime25 = require("react/jsx-runtime");
|
|
2924
|
-
function formatTime2(milliseconds) {
|
|
2925
|
-
const seconds = Math.floor(milliseconds / 1e3);
|
|
2926
|
-
const s = seconds % 60;
|
|
2927
|
-
const m = (seconds - s) / 60;
|
|
2928
|
-
return `${m}:${String(s).padStart(2, "0")}`;
|
|
2929
|
-
}
|
|
2923
|
+
var import_core6 = require("@waveform-playlist/core");
|
|
2924
|
+
var import_jsx_runtime26 = require("react/jsx-runtime");
|
|
2930
2925
|
var PlaylistTimeScaleScroll = import_styled_components23.default.div.attrs((props) => ({
|
|
2931
2926
|
style: {
|
|
2932
2927
|
width: `${props.$cssWidth}px`,
|
|
@@ -2948,70 +2943,20 @@ var TimeTickChunk = import_styled_components23.default.canvas.attrs((props) => (
|
|
|
2948
2943
|
position: absolute;
|
|
2949
2944
|
bottom: 0;
|
|
2950
2945
|
`;
|
|
2951
|
-
var TimeStamp = import_styled_components23.default.div.attrs((props) => ({
|
|
2952
|
-
style: {
|
|
2953
|
-
left: `${props.$left + 4}px`
|
|
2954
|
-
// Offset 4px to the right of the tick
|
|
2955
|
-
}
|
|
2956
|
-
}))`
|
|
2957
|
-
position: absolute;
|
|
2958
|
-
font-size: 0.75rem; /* Smaller font to prevent overflow */
|
|
2959
|
-
white-space: nowrap; /* Prevent text wrapping */
|
|
2960
|
-
color: ${(props) => props.theme.timeColor}; /* Use theme color instead of inheriting */
|
|
2961
|
-
`;
|
|
2962
2946
|
var TimeScale = (props) => {
|
|
2963
2947
|
const {
|
|
2964
2948
|
theme: { timeColor },
|
|
2965
|
-
|
|
2966
|
-
marker,
|
|
2967
|
-
bigStep,
|
|
2968
|
-
secondStep,
|
|
2969
|
-
renderTimestamp
|
|
2949
|
+
tickData
|
|
2970
2950
|
} = props;
|
|
2971
2951
|
const { canvasRef, canvasMapRef } = useChunkedCanvasRefs();
|
|
2972
|
-
const {
|
|
2952
|
+
const { timeScaleHeight } = (0, import_react22.useContext)(PlaylistInfoContext);
|
|
2973
2953
|
const devicePixelRatio = useDevicePixelRatio();
|
|
2974
|
-
const { widthX, canvasInfo, timeMarkersWithPositions } =
|
|
2975
|
-
|
|
2976
|
-
const nextMarkers = [];
|
|
2977
|
-
const nextWidthX = secondsToPixels(duration / 1e3, samplesPerPixel, sampleRate);
|
|
2978
|
-
const pixPerSec = sampleRate / samplesPerPixel;
|
|
2979
|
-
let counter = 0;
|
|
2980
|
-
for (let i = 0; i < nextWidthX; i += pixPerSec * secondStep / 1e3) {
|
|
2981
|
-
const pix = Math.floor(i);
|
|
2982
|
-
if (counter % marker === 0) {
|
|
2983
|
-
const timeMs = counter;
|
|
2984
|
-
const timestamp = formatTime2(timeMs);
|
|
2985
|
-
const element = renderTimestamp ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react21.default.Fragment, { children: renderTimestamp(timeMs, pix) }, `timestamp-${counter}`) : /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(TimeStamp, { $left: pix, children: timestamp }, timestamp);
|
|
2986
|
-
nextMarkers.push({ pix, element });
|
|
2987
|
-
nextCanvasInfo.set(pix, timeScaleHeight);
|
|
2988
|
-
} else if (counter % bigStep === 0) {
|
|
2989
|
-
nextCanvasInfo.set(pix, Math.floor(timeScaleHeight / 2));
|
|
2990
|
-
} else if (counter % secondStep === 0) {
|
|
2991
|
-
nextCanvasInfo.set(pix, Math.floor(timeScaleHeight / 5));
|
|
2992
|
-
}
|
|
2993
|
-
counter += secondStep;
|
|
2994
|
-
}
|
|
2995
|
-
return {
|
|
2996
|
-
widthX: nextWidthX,
|
|
2997
|
-
canvasInfo: nextCanvasInfo,
|
|
2998
|
-
timeMarkersWithPositions: nextMarkers
|
|
2999
|
-
};
|
|
3000
|
-
}, [
|
|
3001
|
-
duration,
|
|
3002
|
-
samplesPerPixel,
|
|
3003
|
-
sampleRate,
|
|
3004
|
-
marker,
|
|
3005
|
-
bigStep,
|
|
3006
|
-
secondStep,
|
|
3007
|
-
renderTimestamp,
|
|
3008
|
-
timeScaleHeight
|
|
3009
|
-
]);
|
|
3010
|
-
const visibleChunkIndices = useVisibleChunkIndices(widthX, import_core4.MAX_CANVAS_WIDTH);
|
|
2954
|
+
const { widthX, canvasInfo, timeMarkersWithPositions } = tickData;
|
|
2955
|
+
const visibleChunkIndices = useVisibleChunkIndices(widthX, import_core6.MAX_CANVAS_WIDTH);
|
|
3011
2956
|
const visibleChunks = visibleChunkIndices.map((i) => {
|
|
3012
|
-
const chunkLeft = i *
|
|
3013
|
-
const chunkWidth = Math.min(widthX - chunkLeft,
|
|
3014
|
-
return /* @__PURE__ */ (0,
|
|
2957
|
+
const chunkLeft = i * import_core6.MAX_CANVAS_WIDTH;
|
|
2958
|
+
const chunkWidth = Math.min(widthX - chunkLeft, import_core6.MAX_CANVAS_WIDTH);
|
|
2959
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
3015
2960
|
TimeTickChunk,
|
|
3016
2961
|
{
|
|
3017
2962
|
$cssWidth: chunkWidth,
|
|
@@ -3025,14 +2970,14 @@ var TimeScale = (props) => {
|
|
|
3025
2970
|
`timescale-${i}`
|
|
3026
2971
|
);
|
|
3027
2972
|
});
|
|
3028
|
-
const firstChunkLeft = visibleChunkIndices.length > 0 ? visibleChunkIndices[0] *
|
|
3029
|
-
const lastChunkRight = visibleChunkIndices.length > 0 ? (visibleChunkIndices[visibleChunkIndices.length - 1] + 1) *
|
|
2973
|
+
const firstChunkLeft = visibleChunkIndices.length > 0 ? visibleChunkIndices[0] * import_core6.MAX_CANVAS_WIDTH : 0;
|
|
2974
|
+
const lastChunkRight = visibleChunkIndices.length > 0 ? (visibleChunkIndices[visibleChunkIndices.length - 1] + 1) * import_core6.MAX_CANVAS_WIDTH : Infinity;
|
|
3030
2975
|
const visibleMarkers = visibleChunkIndices.length > 0 ? timeMarkersWithPositions.filter(({ pix }) => pix >= firstChunkLeft && pix < lastChunkRight).map(({ element }) => element) : timeMarkersWithPositions.map(({ element }) => element);
|
|
3031
|
-
(0,
|
|
2976
|
+
(0, import_react22.useLayoutEffect)(() => {
|
|
3032
2977
|
for (const [chunkIdx, canvas] of canvasMapRef.current.entries()) {
|
|
3033
2978
|
const ctx = canvas.getContext("2d");
|
|
3034
2979
|
if (!ctx) continue;
|
|
3035
|
-
const chunkLeft = chunkIdx *
|
|
2980
|
+
const chunkLeft = chunkIdx * import_core6.MAX_CANVAS_WIDTH;
|
|
3036
2981
|
const chunkWidth = canvas.width / devicePixelRatio;
|
|
3037
2982
|
ctx.resetTransform();
|
|
3038
2983
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
@@ -3046,16 +2991,8 @@ var TimeScale = (props) => {
|
|
|
3046
2991
|
ctx.fillRect(localX, scaleY, 1, scaleHeight);
|
|
3047
2992
|
}
|
|
3048
2993
|
}
|
|
3049
|
-
}, [
|
|
3050
|
-
|
|
3051
|
-
duration,
|
|
3052
|
-
devicePixelRatio,
|
|
3053
|
-
timeColor,
|
|
3054
|
-
timeScaleHeight,
|
|
3055
|
-
canvasInfo,
|
|
3056
|
-
visibleChunkIndices
|
|
3057
|
-
]);
|
|
3058
|
-
return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(PlaylistTimeScaleScroll, { $cssWidth: widthX, $timeScaleHeight: timeScaleHeight, children: [
|
|
2994
|
+
}, [canvasMapRef, devicePixelRatio, timeColor, timeScaleHeight, canvasInfo, visibleChunkIndices]);
|
|
2995
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(PlaylistTimeScaleScroll, { $cssWidth: widthX, $timeScaleHeight: timeScaleHeight, children: [
|
|
3059
2996
|
visibleMarkers,
|
|
3060
2997
|
visibleChunks
|
|
3061
2998
|
] });
|
|
@@ -3063,64 +3000,16 @@ var TimeScale = (props) => {
|
|
|
3063
3000
|
var StyledTimeScale = (0, import_styled_components23.withTheme)(TimeScale);
|
|
3064
3001
|
|
|
3065
3002
|
// src/components/SmartScale.tsx
|
|
3066
|
-
var
|
|
3003
|
+
var import_core7 = require("@waveform-playlist/core");
|
|
3004
|
+
var import_jsx_runtime27 = require("react/jsx-runtime");
|
|
3067
3005
|
var timeinfo = /* @__PURE__ */ new Map([
|
|
3068
|
-
[
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
],
|
|
3076
|
-
[
|
|
3077
|
-
1500,
|
|
3078
|
-
{
|
|
3079
|
-
marker: 2e3,
|
|
3080
|
-
bigStep: 1e3,
|
|
3081
|
-
smallStep: 200
|
|
3082
|
-
}
|
|
3083
|
-
],
|
|
3084
|
-
[
|
|
3085
|
-
2500,
|
|
3086
|
-
{
|
|
3087
|
-
marker: 2e3,
|
|
3088
|
-
bigStep: 1e3,
|
|
3089
|
-
smallStep: 500
|
|
3090
|
-
}
|
|
3091
|
-
],
|
|
3092
|
-
[
|
|
3093
|
-
5e3,
|
|
3094
|
-
{
|
|
3095
|
-
marker: 5e3,
|
|
3096
|
-
bigStep: 1e3,
|
|
3097
|
-
smallStep: 500
|
|
3098
|
-
}
|
|
3099
|
-
],
|
|
3100
|
-
[
|
|
3101
|
-
1e4,
|
|
3102
|
-
{
|
|
3103
|
-
marker: 1e4,
|
|
3104
|
-
bigStep: 5e3,
|
|
3105
|
-
smallStep: 1e3
|
|
3106
|
-
}
|
|
3107
|
-
],
|
|
3108
|
-
[
|
|
3109
|
-
12e3,
|
|
3110
|
-
{
|
|
3111
|
-
marker: 15e3,
|
|
3112
|
-
bigStep: 5e3,
|
|
3113
|
-
smallStep: 1e3
|
|
3114
|
-
}
|
|
3115
|
-
],
|
|
3116
|
-
[
|
|
3117
|
-
Infinity,
|
|
3118
|
-
{
|
|
3119
|
-
marker: 3e4,
|
|
3120
|
-
bigStep: 1e4,
|
|
3121
|
-
smallStep: 5e3
|
|
3122
|
-
}
|
|
3123
|
-
]
|
|
3006
|
+
[700, { marker: 1e3, bigStep: 500, smallStep: 100 }],
|
|
3007
|
+
[1500, { marker: 2e3, bigStep: 1e3, smallStep: 200 }],
|
|
3008
|
+
[2500, { marker: 2e3, bigStep: 1e3, smallStep: 500 }],
|
|
3009
|
+
[5e3, { marker: 5e3, bigStep: 1e3, smallStep: 500 }],
|
|
3010
|
+
[1e4, { marker: 1e4, bigStep: 5e3, smallStep: 1e3 }],
|
|
3011
|
+
[12e3, { marker: 15e3, bigStep: 5e3, smallStep: 1e3 }],
|
|
3012
|
+
[Infinity, { marker: 3e4, bigStep: 1e4, smallStep: 5e3 }]
|
|
3124
3013
|
]);
|
|
3125
3014
|
function getScaleInfo(samplesPerPixel) {
|
|
3126
3015
|
const keys = timeinfo.keys();
|
|
@@ -3136,25 +3025,113 @@ function getScaleInfo(samplesPerPixel) {
|
|
|
3136
3025
|
}
|
|
3137
3026
|
return config;
|
|
3138
3027
|
}
|
|
3139
|
-
|
|
3140
|
-
const
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
|
|
3028
|
+
function formatTime2(milliseconds) {
|
|
3029
|
+
const seconds = Math.floor(milliseconds / 1e3);
|
|
3030
|
+
const s = seconds % 60;
|
|
3031
|
+
const m = (seconds - s) / 60;
|
|
3032
|
+
return `${m}:${String(s).padStart(2, "0")}`;
|
|
3033
|
+
}
|
|
3034
|
+
var TimeStamp = import_styled_components24.default.div.attrs((props) => ({
|
|
3035
|
+
style: {
|
|
3036
|
+
left: `${props.$left + 4}px`
|
|
3037
|
+
// Offset 4px to the right of the tick
|
|
3038
|
+
}
|
|
3039
|
+
}))`
|
|
3040
|
+
position: absolute;
|
|
3041
|
+
font-size: 0.75rem; /* Smaller font to prevent overflow */
|
|
3042
|
+
white-space: nowrap; /* Prevent text wrapping */
|
|
3043
|
+
color: ${(props) => props.theme.timeColor}; /* Use theme color instead of inheriting */
|
|
3044
|
+
`;
|
|
3045
|
+
var SmartScale = ({ renderTick }) => {
|
|
3046
|
+
const { samplesPerPixel, sampleRate, duration, timeScaleHeight } = (0, import_react23.useContext)(PlaylistInfoContext);
|
|
3047
|
+
const beatsAndBars = useBeatsAndBars();
|
|
3048
|
+
const tickData = (0, import_react23.useMemo)(() => {
|
|
3049
|
+
const widthX = (0, import_core7.secondsToPixels)(duration / 1e3, samplesPerPixel, sampleRate);
|
|
3050
|
+
if (beatsAndBars) {
|
|
3051
|
+
const { bpm, timeSignature, ticksPerBar: tpBar, ticksPerBeat: tpBeat } = beatsAndBars;
|
|
3052
|
+
const canvasInfo2 = /* @__PURE__ */ new Map();
|
|
3053
|
+
const timeMarkersWithPositions2 = [];
|
|
3054
|
+
const durationSeconds = duration / 1e3;
|
|
3055
|
+
const totalTicks = Math.ceil(durationSeconds * bpm * import_core7.PPQN / 60);
|
|
3056
|
+
const pixelsPerBeat = (0, import_core7.ticksToSamples)(tpBeat, bpm, sampleRate) / samplesPerPixel;
|
|
3057
|
+
const pixelsPerBar = (0, import_core7.ticksToSamples)(tpBar, bpm, sampleRate) / samplesPerPixel;
|
|
3058
|
+
const MIN_TICK_PX = 10;
|
|
3059
|
+
const MIN_LABEL_PX = 30;
|
|
3060
|
+
let tickStep;
|
|
3061
|
+
if (pixelsPerBeat >= MIN_TICK_PX) {
|
|
3062
|
+
tickStep = tpBeat;
|
|
3063
|
+
} else if (pixelsPerBar >= MIN_TICK_PX) {
|
|
3064
|
+
tickStep = tpBar;
|
|
3065
|
+
} else {
|
|
3066
|
+
const barsPerTick = Math.ceil(MIN_TICK_PX / pixelsPerBar);
|
|
3067
|
+
tickStep = tpBar * barsPerTick;
|
|
3068
|
+
}
|
|
3069
|
+
let labelStep;
|
|
3070
|
+
if (pixelsPerBeat >= MIN_LABEL_PX) {
|
|
3071
|
+
labelStep = tpBeat;
|
|
3072
|
+
} else if (pixelsPerBar >= MIN_LABEL_PX) {
|
|
3073
|
+
labelStep = tpBar;
|
|
3074
|
+
} else {
|
|
3075
|
+
const barsPerLabel = Math.ceil(MIN_LABEL_PX / pixelsPerBar);
|
|
3076
|
+
labelStep = tpBar * barsPerLabel;
|
|
3077
|
+
}
|
|
3078
|
+
for (let tick = 0; tick <= totalTicks; tick += tickStep) {
|
|
3079
|
+
const samples = (0, import_core7.ticksToSamples)(tick, bpm, sampleRate);
|
|
3080
|
+
const pix = (0, import_core7.samplesToPixels)(samples, samplesPerPixel);
|
|
3081
|
+
if (pix >= widthX) break;
|
|
3082
|
+
const isBarLine = tick % tpBar === 0;
|
|
3083
|
+
const isLabelTick = tick % labelStep === 0;
|
|
3084
|
+
const tickHeight = isBarLine ? timeScaleHeight : isLabelTick ? Math.floor(timeScaleHeight / 2) : Math.floor(timeScaleHeight / 5);
|
|
3085
|
+
canvasInfo2.set(pix, tickHeight);
|
|
3086
|
+
if (isLabelTick) {
|
|
3087
|
+
const label = (0, import_core7.ticksToBarBeatLabel)(tick, timeSignature);
|
|
3088
|
+
const element = renderTick ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react23.default.Fragment, { children: renderTick(label, pix) }, `bb-${tick}`) : /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3089
|
+
"div",
|
|
3090
|
+
{
|
|
3091
|
+
style: {
|
|
3092
|
+
position: "absolute",
|
|
3093
|
+
left: `${pix + 4}px`,
|
|
3094
|
+
fontSize: "0.75rem",
|
|
3095
|
+
whiteSpace: "nowrap"
|
|
3096
|
+
},
|
|
3097
|
+
children: label
|
|
3098
|
+
},
|
|
3099
|
+
`bb-${tick}`
|
|
3100
|
+
);
|
|
3101
|
+
timeMarkersWithPositions2.push({ pix, element });
|
|
3102
|
+
}
|
|
3103
|
+
}
|
|
3104
|
+
return { widthX, canvasInfo: canvasInfo2, timeMarkersWithPositions: timeMarkersWithPositions2 };
|
|
3150
3105
|
}
|
|
3151
|
-
|
|
3106
|
+
const config = getScaleInfo(samplesPerPixel);
|
|
3107
|
+
const { marker, bigStep, smallStep } = config;
|
|
3108
|
+
const canvasInfo = /* @__PURE__ */ new Map();
|
|
3109
|
+
const timeMarkersWithPositions = [];
|
|
3110
|
+
const pixPerSec = sampleRate / samplesPerPixel;
|
|
3111
|
+
let counter = 0;
|
|
3112
|
+
for (let i = 0; i < widthX; i += pixPerSec * smallStep / 1e3) {
|
|
3113
|
+
const pix = Math.floor(i);
|
|
3114
|
+
if (counter % marker === 0) {
|
|
3115
|
+
const timestamp = formatTime2(counter);
|
|
3116
|
+
const element = renderTick ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react23.default.Fragment, { children: renderTick(timestamp, pix) }, `timestamp-${counter}`) : /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(TimeStamp, { $left: pix, children: timestamp }, timestamp);
|
|
3117
|
+
timeMarkersWithPositions.push({ pix, element });
|
|
3118
|
+
canvasInfo.set(pix, timeScaleHeight);
|
|
3119
|
+
} else if (counter % bigStep === 0) {
|
|
3120
|
+
canvasInfo.set(pix, Math.floor(timeScaleHeight / 2));
|
|
3121
|
+
} else if (counter % smallStep === 0) {
|
|
3122
|
+
canvasInfo.set(pix, Math.floor(timeScaleHeight / 5));
|
|
3123
|
+
}
|
|
3124
|
+
counter += smallStep;
|
|
3125
|
+
}
|
|
3126
|
+
return { widthX, canvasInfo, timeMarkersWithPositions };
|
|
3127
|
+
}, [beatsAndBars, duration, samplesPerPixel, sampleRate, timeScaleHeight, renderTick]);
|
|
3128
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(StyledTimeScale, { tickData });
|
|
3152
3129
|
};
|
|
3153
3130
|
|
|
3154
3131
|
// src/components/TimeFormatSelect.tsx
|
|
3155
|
-
var
|
|
3156
|
-
var
|
|
3157
|
-
var SelectWrapper =
|
|
3132
|
+
var import_styled_components25 = __toESM(require("styled-components"));
|
|
3133
|
+
var import_jsx_runtime28 = require("react/jsx-runtime");
|
|
3134
|
+
var SelectWrapper = import_styled_components25.default.div`
|
|
3158
3135
|
display: inline-flex;
|
|
3159
3136
|
align-items: center;
|
|
3160
3137
|
gap: 0.5rem;
|
|
@@ -3176,7 +3153,7 @@ var TimeFormatSelect = ({
|
|
|
3176
3153
|
const handleChange = (e) => {
|
|
3177
3154
|
onChange(e.target.value);
|
|
3178
3155
|
};
|
|
3179
|
-
return /* @__PURE__ */ (0,
|
|
3156
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(SelectWrapper, { className, children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
3180
3157
|
BaseSelect,
|
|
3181
3158
|
{
|
|
3182
3159
|
className: "time-format",
|
|
@@ -3184,15 +3161,15 @@ var TimeFormatSelect = ({
|
|
|
3184
3161
|
onChange: handleChange,
|
|
3185
3162
|
disabled,
|
|
3186
3163
|
"aria-label": "Time format selection",
|
|
3187
|
-
children: TIME_FORMAT_OPTIONS.map((option) => /* @__PURE__ */ (0,
|
|
3164
|
+
children: TIME_FORMAT_OPTIONS.map((option) => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("option", { value: option.value, children: option.label }, option.value))
|
|
3188
3165
|
}
|
|
3189
3166
|
) });
|
|
3190
3167
|
};
|
|
3191
3168
|
|
|
3192
3169
|
// src/components/Track.tsx
|
|
3193
|
-
var
|
|
3194
|
-
var
|
|
3195
|
-
var Container =
|
|
3170
|
+
var import_styled_components26 = __toESM(require("styled-components"));
|
|
3171
|
+
var import_jsx_runtime29 = require("react/jsx-runtime");
|
|
3172
|
+
var Container = import_styled_components26.default.div.attrs((props) => ({
|
|
3196
3173
|
style: {
|
|
3197
3174
|
height: `${props.$waveHeight * props.$numChannels + (props.$hasClipHeaders ? CLIP_HEADER_HEIGHT : 0)}px`
|
|
3198
3175
|
}
|
|
@@ -3200,7 +3177,7 @@ var Container = import_styled_components25.default.div.attrs((props) => ({
|
|
|
3200
3177
|
position: relative;
|
|
3201
3178
|
${(props) => props.$width !== void 0 && `width: ${props.$width}px;`}
|
|
3202
3179
|
`;
|
|
3203
|
-
var ChannelContainer =
|
|
3180
|
+
var ChannelContainer = import_styled_components26.default.div.attrs((props) => ({
|
|
3204
3181
|
style: {
|
|
3205
3182
|
paddingLeft: `${props.$offset || 0}px`
|
|
3206
3183
|
}
|
|
@@ -3222,7 +3199,7 @@ var Track = ({
|
|
|
3222
3199
|
isSelected: _isSelected = false
|
|
3223
3200
|
}) => {
|
|
3224
3201
|
const { waveHeight } = usePlaylistInfo();
|
|
3225
|
-
return /* @__PURE__ */ (0,
|
|
3202
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
3226
3203
|
Container,
|
|
3227
3204
|
{
|
|
3228
3205
|
$numChannels: numChannels,
|
|
@@ -3230,7 +3207,7 @@ var Track = ({
|
|
|
3230
3207
|
$waveHeight: waveHeight,
|
|
3231
3208
|
$width: width,
|
|
3232
3209
|
$hasClipHeaders: hasClipHeaders,
|
|
3233
|
-
children: /* @__PURE__ */ (0,
|
|
3210
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
3234
3211
|
ChannelContainer,
|
|
3235
3212
|
{
|
|
3236
3213
|
$backgroundColor: backgroundColor,
|
|
@@ -3245,8 +3222,8 @@ var Track = ({
|
|
|
3245
3222
|
};
|
|
3246
3223
|
|
|
3247
3224
|
// src/components/TrackControls/Button.tsx
|
|
3248
|
-
var
|
|
3249
|
-
var Button =
|
|
3225
|
+
var import_styled_components27 = __toESM(require("styled-components"));
|
|
3226
|
+
var Button = import_styled_components27.default.button.attrs({
|
|
3250
3227
|
type: "button"
|
|
3251
3228
|
})`
|
|
3252
3229
|
display: inline-block;
|
|
@@ -3321,8 +3298,8 @@ var Button = import_styled_components26.default.button.attrs({
|
|
|
3321
3298
|
`;
|
|
3322
3299
|
|
|
3323
3300
|
// src/components/TrackControls/ButtonGroup.tsx
|
|
3324
|
-
var
|
|
3325
|
-
var ButtonGroup =
|
|
3301
|
+
var import_styled_components28 = __toESM(require("styled-components"));
|
|
3302
|
+
var ButtonGroup = import_styled_components28.default.div`
|
|
3326
3303
|
margin-bottom: 0.3rem;
|
|
3327
3304
|
|
|
3328
3305
|
button:not(:first-child) {
|
|
@@ -3337,10 +3314,10 @@ var ButtonGroup = import_styled_components27.default.div`
|
|
|
3337
3314
|
`;
|
|
3338
3315
|
|
|
3339
3316
|
// src/components/TrackControls/CloseButton.tsx
|
|
3340
|
-
var
|
|
3341
|
-
var
|
|
3342
|
-
var
|
|
3343
|
-
var StyledCloseButton =
|
|
3317
|
+
var import_styled_components29 = __toESM(require("styled-components"));
|
|
3318
|
+
var import_react24 = require("@phosphor-icons/react");
|
|
3319
|
+
var import_jsx_runtime30 = require("react/jsx-runtime");
|
|
3320
|
+
var StyledCloseButton = import_styled_components29.default.button`
|
|
3344
3321
|
position: absolute;
|
|
3345
3322
|
left: 0;
|
|
3346
3323
|
top: 0;
|
|
@@ -3363,11 +3340,11 @@ var StyledCloseButton = import_styled_components28.default.button`
|
|
|
3363
3340
|
color: #dc3545;
|
|
3364
3341
|
}
|
|
3365
3342
|
`;
|
|
3366
|
-
var CloseButton = ({ onClick, title = "Remove track" }) => /* @__PURE__ */ (0,
|
|
3343
|
+
var CloseButton = ({ onClick, title = "Remove track" }) => /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(StyledCloseButton, { onClick, title, children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_react24.X, { size: 12, weight: "bold" }) });
|
|
3367
3344
|
|
|
3368
3345
|
// src/components/TrackControls/Controls.tsx
|
|
3369
|
-
var
|
|
3370
|
-
var Controls =
|
|
3346
|
+
var import_styled_components30 = __toESM(require("styled-components"));
|
|
3347
|
+
var Controls = import_styled_components30.default.div`
|
|
3371
3348
|
background: transparent;
|
|
3372
3349
|
width: 100%;
|
|
3373
3350
|
height: 100%;
|
|
@@ -3383,8 +3360,8 @@ var Controls = import_styled_components29.default.div`
|
|
|
3383
3360
|
`;
|
|
3384
3361
|
|
|
3385
3362
|
// src/components/TrackControls/Header.tsx
|
|
3386
|
-
var
|
|
3387
|
-
var Header =
|
|
3363
|
+
var import_styled_components31 = __toESM(require("styled-components"));
|
|
3364
|
+
var Header = import_styled_components31.default.header`
|
|
3388
3365
|
overflow: hidden;
|
|
3389
3366
|
height: 26px;
|
|
3390
3367
|
width: 100%;
|
|
@@ -3398,28 +3375,28 @@ var Header = import_styled_components30.default.header`
|
|
|
3398
3375
|
`;
|
|
3399
3376
|
|
|
3400
3377
|
// src/components/TrackControls/VolumeDownIcon.tsx
|
|
3401
|
-
var import_react24 = require("@phosphor-icons/react");
|
|
3402
|
-
var import_jsx_runtime30 = require("react/jsx-runtime");
|
|
3403
|
-
var VolumeDownIcon = (props) => /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_react24.SpeakerLowIcon, { weight: "light", ...props });
|
|
3404
|
-
|
|
3405
|
-
// src/components/TrackControls/VolumeUpIcon.tsx
|
|
3406
3378
|
var import_react25 = require("@phosphor-icons/react");
|
|
3407
3379
|
var import_jsx_runtime31 = require("react/jsx-runtime");
|
|
3408
|
-
var
|
|
3380
|
+
var VolumeDownIcon = (props) => /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_react25.SpeakerLowIcon, { weight: "light", ...props });
|
|
3409
3381
|
|
|
3410
|
-
// src/components/TrackControls/
|
|
3382
|
+
// src/components/TrackControls/VolumeUpIcon.tsx
|
|
3411
3383
|
var import_react26 = require("@phosphor-icons/react");
|
|
3412
3384
|
var import_jsx_runtime32 = require("react/jsx-runtime");
|
|
3413
|
-
var
|
|
3385
|
+
var VolumeUpIcon = (props) => /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_react26.SpeakerHighIcon, { weight: "light", ...props });
|
|
3414
3386
|
|
|
3415
|
-
// src/components/TrackControls/
|
|
3387
|
+
// src/components/TrackControls/TrashIcon.tsx
|
|
3416
3388
|
var import_react27 = require("@phosphor-icons/react");
|
|
3417
3389
|
var import_jsx_runtime33 = require("react/jsx-runtime");
|
|
3418
|
-
var
|
|
3390
|
+
var TrashIcon = (props) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_react27.TrashIcon, { weight: "light", ...props });
|
|
3391
|
+
|
|
3392
|
+
// src/components/TrackControls/DotsIcon.tsx
|
|
3393
|
+
var import_react28 = require("@phosphor-icons/react");
|
|
3394
|
+
var import_jsx_runtime34 = require("react/jsx-runtime");
|
|
3395
|
+
var DotsIcon = (props) => /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_react28.DotsThreeIcon, { weight: "bold", ...props });
|
|
3419
3396
|
|
|
3420
3397
|
// src/components/TrackControls/Slider.tsx
|
|
3421
|
-
var
|
|
3422
|
-
var Slider = (0,
|
|
3398
|
+
var import_styled_components32 = __toESM(require("styled-components"));
|
|
3399
|
+
var Slider = (0, import_styled_components32.default)(BaseSlider)`
|
|
3423
3400
|
width: 75%;
|
|
3424
3401
|
height: 5px;
|
|
3425
3402
|
background: ${(props) => props.theme.sliderTrackColor};
|
|
@@ -3471,8 +3448,8 @@ var Slider = (0, import_styled_components31.default)(BaseSlider)`
|
|
|
3471
3448
|
`;
|
|
3472
3449
|
|
|
3473
3450
|
// src/components/TrackControls/SliderWrapper.tsx
|
|
3474
|
-
var
|
|
3475
|
-
var SliderWrapper =
|
|
3451
|
+
var import_styled_components33 = __toESM(require("styled-components"));
|
|
3452
|
+
var SliderWrapper = import_styled_components33.default.label`
|
|
3476
3453
|
width: 100%;
|
|
3477
3454
|
display: flex;
|
|
3478
3455
|
justify-content: space-between;
|
|
@@ -3483,15 +3460,15 @@ var SliderWrapper = import_styled_components32.default.label`
|
|
|
3483
3460
|
`;
|
|
3484
3461
|
|
|
3485
3462
|
// src/components/TrackMenu.tsx
|
|
3486
|
-
var
|
|
3463
|
+
var import_react29 = __toESM(require("react"));
|
|
3487
3464
|
var import_react_dom = require("react-dom");
|
|
3488
|
-
var
|
|
3489
|
-
var
|
|
3490
|
-
var MenuContainer =
|
|
3465
|
+
var import_styled_components34 = __toESM(require("styled-components"));
|
|
3466
|
+
var import_jsx_runtime35 = require("react/jsx-runtime");
|
|
3467
|
+
var MenuContainer = import_styled_components34.default.div`
|
|
3491
3468
|
position: relative;
|
|
3492
3469
|
display: inline-block;
|
|
3493
3470
|
`;
|
|
3494
|
-
var MenuButton =
|
|
3471
|
+
var MenuButton = import_styled_components34.default.button`
|
|
3495
3472
|
background: none;
|
|
3496
3473
|
border: none;
|
|
3497
3474
|
cursor: pointer;
|
|
@@ -3507,7 +3484,7 @@ var MenuButton = import_styled_components33.default.button`
|
|
|
3507
3484
|
}
|
|
3508
3485
|
`;
|
|
3509
3486
|
var DROPDOWN_MIN_WIDTH = 180;
|
|
3510
|
-
var Dropdown =
|
|
3487
|
+
var Dropdown = import_styled_components34.default.div`
|
|
3511
3488
|
position: fixed;
|
|
3512
3489
|
top: ${(p) => p.$top}px;
|
|
3513
3490
|
left: ${(p) => p.$left}px;
|
|
@@ -3520,19 +3497,19 @@ var Dropdown = import_styled_components33.default.div`
|
|
|
3520
3497
|
min-width: ${DROPDOWN_MIN_WIDTH}px;
|
|
3521
3498
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
|
|
3522
3499
|
`;
|
|
3523
|
-
var Divider =
|
|
3500
|
+
var Divider = import_styled_components34.default.hr`
|
|
3524
3501
|
border: none;
|
|
3525
3502
|
border-top: 1px solid rgba(128, 128, 128, 0.3);
|
|
3526
3503
|
margin: 0.35rem 0;
|
|
3527
3504
|
`;
|
|
3528
3505
|
var TrackMenu = ({ items: itemsProp }) => {
|
|
3529
|
-
const [open, setOpen] = (0,
|
|
3530
|
-
const close = (0,
|
|
3506
|
+
const [open, setOpen] = (0, import_react29.useState)(false);
|
|
3507
|
+
const close = (0, import_react29.useCallback)(() => setOpen(false), []);
|
|
3531
3508
|
const items = typeof itemsProp === "function" ? itemsProp(close) : itemsProp;
|
|
3532
|
-
const [dropdownPos, setDropdownPos] = (0,
|
|
3533
|
-
const buttonRef = (0,
|
|
3534
|
-
const dropdownRef = (0,
|
|
3535
|
-
const updatePosition = (0,
|
|
3509
|
+
const [dropdownPos, setDropdownPos] = (0, import_react29.useState)({ top: 0, left: 0 });
|
|
3510
|
+
const buttonRef = (0, import_react29.useRef)(null);
|
|
3511
|
+
const dropdownRef = (0, import_react29.useRef)(null);
|
|
3512
|
+
const updatePosition = (0, import_react29.useCallback)(() => {
|
|
3536
3513
|
if (!buttonRef.current) return;
|
|
3537
3514
|
const rect = buttonRef.current.getBoundingClientRect();
|
|
3538
3515
|
const vw = window.innerWidth;
|
|
@@ -3549,7 +3526,7 @@ var TrackMenu = ({ items: itemsProp }) => {
|
|
|
3549
3526
|
}
|
|
3550
3527
|
setDropdownPos({ top, left });
|
|
3551
3528
|
}, []);
|
|
3552
|
-
(0,
|
|
3529
|
+
(0, import_react29.useEffect)(() => {
|
|
3553
3530
|
if (!open) return;
|
|
3554
3531
|
updatePosition();
|
|
3555
3532
|
const rafId = requestAnimationFrame(() => updatePosition());
|
|
@@ -3563,7 +3540,7 @@ var TrackMenu = ({ items: itemsProp }) => {
|
|
|
3563
3540
|
window.removeEventListener("resize", onResize);
|
|
3564
3541
|
};
|
|
3565
3542
|
}, [open, updatePosition]);
|
|
3566
|
-
(0,
|
|
3543
|
+
(0, import_react29.useEffect)(() => {
|
|
3567
3544
|
if (!open) return;
|
|
3568
3545
|
const handleClick = (e) => {
|
|
3569
3546
|
const target = e.target;
|
|
@@ -3583,8 +3560,8 @@ var TrackMenu = ({ items: itemsProp }) => {
|
|
|
3583
3560
|
document.removeEventListener("keydown", handleKeyDown);
|
|
3584
3561
|
};
|
|
3585
3562
|
}, [open]);
|
|
3586
|
-
return /* @__PURE__ */ (0,
|
|
3587
|
-
/* @__PURE__ */ (0,
|
|
3563
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(MenuContainer, { children: [
|
|
3564
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
|
|
3588
3565
|
MenuButton,
|
|
3589
3566
|
{
|
|
3590
3567
|
ref: buttonRef,
|
|
@@ -3595,19 +3572,19 @@ var TrackMenu = ({ items: itemsProp }) => {
|
|
|
3595
3572
|
onMouseDown: (e) => e.stopPropagation(),
|
|
3596
3573
|
title: "Track menu",
|
|
3597
3574
|
"aria-label": "Track menu",
|
|
3598
|
-
children: /* @__PURE__ */ (0,
|
|
3575
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(DotsIcon, { size: 16 })
|
|
3599
3576
|
}
|
|
3600
3577
|
),
|
|
3601
3578
|
open && typeof document !== "undefined" && (0, import_react_dom.createPortal)(
|
|
3602
|
-
/* @__PURE__ */ (0,
|
|
3579
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
|
|
3603
3580
|
Dropdown,
|
|
3604
3581
|
{
|
|
3605
3582
|
ref: dropdownRef,
|
|
3606
3583
|
$top: dropdownPos.top,
|
|
3607
3584
|
$left: dropdownPos.left,
|
|
3608
3585
|
onMouseDown: (e) => e.stopPropagation(),
|
|
3609
|
-
children: items.map((item, index) => /* @__PURE__ */ (0,
|
|
3610
|
-
index > 0 && /* @__PURE__ */ (0,
|
|
3586
|
+
children: items.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(import_react29.default.Fragment, { children: [
|
|
3587
|
+
index > 0 && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(Divider, {}),
|
|
3611
3588
|
item.content
|
|
3612
3589
|
] }, item.id))
|
|
3613
3590
|
}
|
|
@@ -3616,6 +3593,26 @@ var TrackMenu = ({ items: itemsProp }) => {
|
|
|
3616
3593
|
)
|
|
3617
3594
|
] });
|
|
3618
3595
|
};
|
|
3596
|
+
|
|
3597
|
+
// src/utils/conversions.ts
|
|
3598
|
+
function samplesToSeconds(samples, sampleRate) {
|
|
3599
|
+
return samples / sampleRate;
|
|
3600
|
+
}
|
|
3601
|
+
function secondsToSamples(seconds, sampleRate) {
|
|
3602
|
+
return Math.ceil(seconds * sampleRate);
|
|
3603
|
+
}
|
|
3604
|
+
function samplesToPixels2(samples, samplesPerPixel) {
|
|
3605
|
+
return Math.floor(samples / samplesPerPixel);
|
|
3606
|
+
}
|
|
3607
|
+
function pixelsToSamples(pixels, samplesPerPixel) {
|
|
3608
|
+
return Math.floor(pixels * samplesPerPixel);
|
|
3609
|
+
}
|
|
3610
|
+
function pixelsToSeconds(pixels, samplesPerPixel, sampleRate) {
|
|
3611
|
+
return pixels * samplesPerPixel / sampleRate;
|
|
3612
|
+
}
|
|
3613
|
+
function secondsToPixels2(seconds, samplesPerPixel, sampleRate) {
|
|
3614
|
+
return Math.ceil(seconds * sampleRate / samplesPerPixel);
|
|
3615
|
+
}
|
|
3619
3616
|
// Annotate the CommonJS export names for ESM import in node:
|
|
3620
3617
|
0 && (module.exports = {
|
|
3621
3618
|
AudioPosition,
|
|
@@ -3626,9 +3623,12 @@ var TrackMenu = ({ items: itemsProp }) => {
|
|
|
3626
3623
|
BaseCheckboxWrapper,
|
|
3627
3624
|
BaseControlButton,
|
|
3628
3625
|
BaseInput,
|
|
3626
|
+
BaseInputSmall,
|
|
3629
3627
|
BaseLabel,
|
|
3630
3628
|
BaseSelect,
|
|
3629
|
+
BaseSelectSmall,
|
|
3631
3630
|
BaseSlider,
|
|
3631
|
+
BeatsAndBarsProvider,
|
|
3632
3632
|
Button,
|
|
3633
3633
|
ButtonGroup,
|
|
3634
3634
|
CLIP_BOUNDARY_WIDTH,
|
|
@@ -3682,6 +3682,7 @@ var TrackMenu = ({ items: itemsProp }) => {
|
|
|
3682
3682
|
darkTheme,
|
|
3683
3683
|
defaultTheme,
|
|
3684
3684
|
formatTime,
|
|
3685
|
+
getScaleInfo,
|
|
3685
3686
|
isWaveformGradient,
|
|
3686
3687
|
parseTime,
|
|
3687
3688
|
pixelsToSamples,
|
|
@@ -3690,6 +3691,7 @@ var TrackMenu = ({ items: itemsProp }) => {
|
|
|
3690
3691
|
samplesToSeconds,
|
|
3691
3692
|
secondsToPixels,
|
|
3692
3693
|
secondsToSamples,
|
|
3694
|
+
useBeatsAndBars,
|
|
3693
3695
|
useClipViewportOrigin,
|
|
3694
3696
|
useDevicePixelRatio,
|
|
3695
3697
|
usePlaylistInfo,
|