@waveform-playlist/playout 9.5.2 → 10.1.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 +5 -37
- package/dist/index.d.ts +5 -37
- package/dist/index.js +97 -170
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +98 -163
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/index.mjs
CHANGED
|
@@ -19,6 +19,15 @@ import {
|
|
|
19
19
|
} from "tone";
|
|
20
20
|
|
|
21
21
|
// src/fades.ts
|
|
22
|
+
import {
|
|
23
|
+
linearCurve,
|
|
24
|
+
exponentialCurve,
|
|
25
|
+
sCurveCurve,
|
|
26
|
+
logarithmicCurve,
|
|
27
|
+
generateCurve,
|
|
28
|
+
applyFadeIn,
|
|
29
|
+
applyFadeOut
|
|
30
|
+
} from "@waveform-playlist/core";
|
|
22
31
|
var hasWarned = false;
|
|
23
32
|
function getUnderlyingAudioParam(signal) {
|
|
24
33
|
const param = signal._param;
|
|
@@ -30,92 +39,6 @@ function getUnderlyingAudioParam(signal) {
|
|
|
30
39
|
}
|
|
31
40
|
return param;
|
|
32
41
|
}
|
|
33
|
-
function linearCurve(length, fadeIn) {
|
|
34
|
-
const curve = new Float32Array(length);
|
|
35
|
-
const scale = length - 1;
|
|
36
|
-
for (let i = 0; i < length; i++) {
|
|
37
|
-
const x = i / scale;
|
|
38
|
-
curve[i] = fadeIn ? x : 1 - x;
|
|
39
|
-
}
|
|
40
|
-
return curve;
|
|
41
|
-
}
|
|
42
|
-
function exponentialCurve(length, fadeIn) {
|
|
43
|
-
const curve = new Float32Array(length);
|
|
44
|
-
const scale = length - 1;
|
|
45
|
-
for (let i = 0; i < length; i++) {
|
|
46
|
-
const x = i / scale;
|
|
47
|
-
const index = fadeIn ? i : length - 1 - i;
|
|
48
|
-
curve[index] = Math.exp(2 * x - 1) / Math.E;
|
|
49
|
-
}
|
|
50
|
-
return curve;
|
|
51
|
-
}
|
|
52
|
-
function sCurveCurve(length, fadeIn) {
|
|
53
|
-
const curve = new Float32Array(length);
|
|
54
|
-
const phase = fadeIn ? Math.PI / 2 : -Math.PI / 2;
|
|
55
|
-
for (let i = 0; i < length; i++) {
|
|
56
|
-
curve[i] = Math.sin(Math.PI * i / length - phase) / 2 + 0.5;
|
|
57
|
-
}
|
|
58
|
-
return curve;
|
|
59
|
-
}
|
|
60
|
-
function logarithmicCurve(length, fadeIn, base = 10) {
|
|
61
|
-
const curve = new Float32Array(length);
|
|
62
|
-
for (let i = 0; i < length; i++) {
|
|
63
|
-
const index = fadeIn ? i : length - 1 - i;
|
|
64
|
-
const x = i / length;
|
|
65
|
-
curve[index] = Math.log(1 + base * x) / Math.log(1 + base);
|
|
66
|
-
}
|
|
67
|
-
return curve;
|
|
68
|
-
}
|
|
69
|
-
function generateCurve(type, length, fadeIn) {
|
|
70
|
-
switch (type) {
|
|
71
|
-
case "linear":
|
|
72
|
-
return linearCurve(length, fadeIn);
|
|
73
|
-
case "exponential":
|
|
74
|
-
return exponentialCurve(length, fadeIn);
|
|
75
|
-
case "sCurve":
|
|
76
|
-
return sCurveCurve(length, fadeIn);
|
|
77
|
-
case "logarithmic":
|
|
78
|
-
return logarithmicCurve(length, fadeIn);
|
|
79
|
-
default:
|
|
80
|
-
return linearCurve(length, fadeIn);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
function applyFadeIn(param, startTime, duration, type = "linear", startValue = 0, endValue = 1) {
|
|
84
|
-
if (duration <= 0) return;
|
|
85
|
-
if (type === "linear") {
|
|
86
|
-
param.setValueAtTime(startValue, startTime);
|
|
87
|
-
param.linearRampToValueAtTime(endValue, startTime + duration);
|
|
88
|
-
} else if (type === "exponential") {
|
|
89
|
-
param.setValueAtTime(Math.max(startValue, 1e-3), startTime);
|
|
90
|
-
param.exponentialRampToValueAtTime(Math.max(endValue, 1e-3), startTime + duration);
|
|
91
|
-
} else {
|
|
92
|
-
const curve = generateCurve(type, 1e4, true);
|
|
93
|
-
const scaledCurve = new Float32Array(curve.length);
|
|
94
|
-
const range = endValue - startValue;
|
|
95
|
-
for (let i = 0; i < curve.length; i++) {
|
|
96
|
-
scaledCurve[i] = startValue + curve[i] * range;
|
|
97
|
-
}
|
|
98
|
-
param.setValueCurveAtTime(scaledCurve, startTime, duration);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
function applyFadeOut(param, startTime, duration, type = "linear", startValue = 1, endValue = 0) {
|
|
102
|
-
if (duration <= 0) return;
|
|
103
|
-
if (type === "linear") {
|
|
104
|
-
param.setValueAtTime(startValue, startTime);
|
|
105
|
-
param.linearRampToValueAtTime(endValue, startTime + duration);
|
|
106
|
-
} else if (type === "exponential") {
|
|
107
|
-
param.setValueAtTime(Math.max(startValue, 1e-3), startTime);
|
|
108
|
-
param.exponentialRampToValueAtTime(Math.max(endValue, 1e-3), startTime + duration);
|
|
109
|
-
} else {
|
|
110
|
-
const curve = generateCurve(type, 1e4, false);
|
|
111
|
-
const scaledCurve = new Float32Array(curve.length);
|
|
112
|
-
const range = startValue - endValue;
|
|
113
|
-
for (let i = 0; i < curve.length; i++) {
|
|
114
|
-
scaledCurve[i] = endValue + curve[i] * range;
|
|
115
|
-
}
|
|
116
|
-
param.setValueCurveAtTime(scaledCurve, startTime, duration);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
42
|
|
|
120
43
|
// src/ToneTrack.ts
|
|
121
44
|
var ToneTrack = class {
|
|
@@ -130,7 +53,7 @@ var ToneTrack = class {
|
|
|
130
53
|
this._scheduleGuardOffset = 0;
|
|
131
54
|
this.track = options.track;
|
|
132
55
|
this.volumeNode = new Volume(this.gainToDb(options.track.gain));
|
|
133
|
-
this.panNode = new Panner(options.track.stereoPan);
|
|
56
|
+
this.panNode = new Panner({ pan: options.track.stereoPan, channelCount: 2 });
|
|
134
57
|
this.muteGain = new Gain(options.track.muted ? 0 : 1);
|
|
135
58
|
this.volumeNode.chain(this.panNode, this.muteGain);
|
|
136
59
|
const destination = options.destination || getDestination();
|
|
@@ -1536,6 +1459,84 @@ function createToneAdapter(options) {
|
|
|
1536
1459
|
let _loopStart = 0;
|
|
1537
1460
|
let _loopEnd = 0;
|
|
1538
1461
|
let _audioInitialized = false;
|
|
1462
|
+
function addTrackToPlayout(p, track) {
|
|
1463
|
+
const audioClips = track.clips.filter((c) => c.audioBuffer && !c.midiNotes);
|
|
1464
|
+
const midiClips = track.clips.filter((c) => c.midiNotes && c.midiNotes.length > 0);
|
|
1465
|
+
if (audioClips.length > 0) {
|
|
1466
|
+
const startTime = Math.min(...audioClips.map(clipStartTime));
|
|
1467
|
+
const endTime = Math.max(...audioClips.map(clipEndTime));
|
|
1468
|
+
const trackObj = {
|
|
1469
|
+
id: track.id,
|
|
1470
|
+
name: track.name,
|
|
1471
|
+
gain: track.volume,
|
|
1472
|
+
muted: track.muted,
|
|
1473
|
+
soloed: track.soloed,
|
|
1474
|
+
stereoPan: track.pan,
|
|
1475
|
+
startTime,
|
|
1476
|
+
endTime
|
|
1477
|
+
};
|
|
1478
|
+
const clipInfos = audioClips.map((clip) => ({
|
|
1479
|
+
buffer: clip.audioBuffer,
|
|
1480
|
+
startTime: clipStartTime(clip) - startTime,
|
|
1481
|
+
duration: clipDurationTime(clip),
|
|
1482
|
+
offset: clipOffsetTime(clip),
|
|
1483
|
+
fadeIn: clip.fadeIn,
|
|
1484
|
+
fadeOut: clip.fadeOut,
|
|
1485
|
+
gain: clip.gain
|
|
1486
|
+
}));
|
|
1487
|
+
p.addTrack({
|
|
1488
|
+
clips: clipInfos,
|
|
1489
|
+
track: trackObj,
|
|
1490
|
+
effects: track.effects
|
|
1491
|
+
});
|
|
1492
|
+
}
|
|
1493
|
+
if (midiClips.length > 0) {
|
|
1494
|
+
const startTime = Math.min(...midiClips.map(clipStartTime));
|
|
1495
|
+
const endTime = Math.max(...midiClips.map(clipEndTime));
|
|
1496
|
+
const trackId = audioClips.length > 0 ? `${track.id}:midi` : track.id;
|
|
1497
|
+
const trackObj = {
|
|
1498
|
+
id: trackId,
|
|
1499
|
+
name: track.name,
|
|
1500
|
+
gain: track.volume,
|
|
1501
|
+
muted: track.muted,
|
|
1502
|
+
soloed: track.soloed,
|
|
1503
|
+
stereoPan: track.pan,
|
|
1504
|
+
startTime,
|
|
1505
|
+
endTime
|
|
1506
|
+
};
|
|
1507
|
+
const midiClipInfos = midiClips.map((clip) => ({
|
|
1508
|
+
notes: clip.midiNotes,
|
|
1509
|
+
startTime: clipStartTime(clip) - startTime,
|
|
1510
|
+
duration: clipDurationTime(clip),
|
|
1511
|
+
offset: clipOffsetTime(clip)
|
|
1512
|
+
}));
|
|
1513
|
+
if (options?.soundFontCache?.isLoaded) {
|
|
1514
|
+
const firstClip = midiClips[0];
|
|
1515
|
+
const midiChannel = firstClip.midiChannel;
|
|
1516
|
+
const isPercussion = midiChannel === 9;
|
|
1517
|
+
const programNumber = firstClip.midiProgram ?? 0;
|
|
1518
|
+
p.addSoundFontTrack({
|
|
1519
|
+
clips: midiClipInfos,
|
|
1520
|
+
track: trackObj,
|
|
1521
|
+
soundFontCache: options.soundFontCache,
|
|
1522
|
+
programNumber,
|
|
1523
|
+
isPercussion,
|
|
1524
|
+
effects: track.effects
|
|
1525
|
+
});
|
|
1526
|
+
} else {
|
|
1527
|
+
if (options?.soundFontCache) {
|
|
1528
|
+
console.warn(
|
|
1529
|
+
`[waveform-playlist] SoundFont not loaded for track "${track.name}" \u2014 falling back to PolySynth.`
|
|
1530
|
+
);
|
|
1531
|
+
}
|
|
1532
|
+
p.addMidiTrack({
|
|
1533
|
+
clips: midiClipInfos,
|
|
1534
|
+
track: trackObj,
|
|
1535
|
+
effects: track.effects
|
|
1536
|
+
});
|
|
1537
|
+
}
|
|
1538
|
+
}
|
|
1539
|
+
}
|
|
1539
1540
|
function buildPlayout(tracks) {
|
|
1540
1541
|
if (playout) {
|
|
1541
1542
|
try {
|
|
@@ -1560,82 +1561,7 @@ function createToneAdapter(options) {
|
|
|
1560
1561
|
});
|
|
1561
1562
|
}
|
|
1562
1563
|
for (const track of tracks) {
|
|
1563
|
-
|
|
1564
|
-
const midiClips = track.clips.filter((c) => c.midiNotes && c.midiNotes.length > 0);
|
|
1565
|
-
if (audioClips.length > 0) {
|
|
1566
|
-
const startTime = Math.min(...audioClips.map(clipStartTime));
|
|
1567
|
-
const endTime = Math.max(...audioClips.map(clipEndTime));
|
|
1568
|
-
const trackObj = {
|
|
1569
|
-
id: track.id,
|
|
1570
|
-
name: track.name,
|
|
1571
|
-
gain: track.volume,
|
|
1572
|
-
muted: track.muted,
|
|
1573
|
-
soloed: track.soloed,
|
|
1574
|
-
stereoPan: track.pan,
|
|
1575
|
-
startTime,
|
|
1576
|
-
endTime
|
|
1577
|
-
};
|
|
1578
|
-
const clipInfos = audioClips.map((clip) => ({
|
|
1579
|
-
buffer: clip.audioBuffer,
|
|
1580
|
-
startTime: clipStartTime(clip) - startTime,
|
|
1581
|
-
duration: clipDurationTime(clip),
|
|
1582
|
-
offset: clipOffsetTime(clip),
|
|
1583
|
-
fadeIn: clip.fadeIn,
|
|
1584
|
-
fadeOut: clip.fadeOut,
|
|
1585
|
-
gain: clip.gain
|
|
1586
|
-
}));
|
|
1587
|
-
playout.addTrack({
|
|
1588
|
-
clips: clipInfos,
|
|
1589
|
-
track: trackObj,
|
|
1590
|
-
effects: track.effects
|
|
1591
|
-
});
|
|
1592
|
-
}
|
|
1593
|
-
if (midiClips.length > 0) {
|
|
1594
|
-
const startTime = Math.min(...midiClips.map(clipStartTime));
|
|
1595
|
-
const endTime = Math.max(...midiClips.map(clipEndTime));
|
|
1596
|
-
const trackId = audioClips.length > 0 ? `${track.id}:midi` : track.id;
|
|
1597
|
-
const trackObj = {
|
|
1598
|
-
id: trackId,
|
|
1599
|
-
name: track.name,
|
|
1600
|
-
gain: track.volume,
|
|
1601
|
-
muted: track.muted,
|
|
1602
|
-
soloed: track.soloed,
|
|
1603
|
-
stereoPan: track.pan,
|
|
1604
|
-
startTime,
|
|
1605
|
-
endTime
|
|
1606
|
-
};
|
|
1607
|
-
const midiClipInfos = midiClips.map((clip) => ({
|
|
1608
|
-
notes: clip.midiNotes,
|
|
1609
|
-
startTime: clipStartTime(clip) - startTime,
|
|
1610
|
-
duration: clipDurationTime(clip),
|
|
1611
|
-
offset: clipOffsetTime(clip)
|
|
1612
|
-
}));
|
|
1613
|
-
if (options?.soundFontCache?.isLoaded) {
|
|
1614
|
-
const firstClip = midiClips[0];
|
|
1615
|
-
const midiChannel = firstClip.midiChannel;
|
|
1616
|
-
const isPercussion = midiChannel === 9;
|
|
1617
|
-
const programNumber = firstClip.midiProgram ?? 0;
|
|
1618
|
-
playout.addSoundFontTrack({
|
|
1619
|
-
clips: midiClipInfos,
|
|
1620
|
-
track: trackObj,
|
|
1621
|
-
soundFontCache: options.soundFontCache,
|
|
1622
|
-
programNumber,
|
|
1623
|
-
isPercussion,
|
|
1624
|
-
effects: track.effects
|
|
1625
|
-
});
|
|
1626
|
-
} else {
|
|
1627
|
-
if (options?.soundFontCache) {
|
|
1628
|
-
console.warn(
|
|
1629
|
-
`[waveform-playlist] SoundFont not loaded for track "${track.name}" \u2014 falling back to PolySynth.`
|
|
1630
|
-
);
|
|
1631
|
-
}
|
|
1632
|
-
playout.addMidiTrack({
|
|
1633
|
-
clips: midiClipInfos,
|
|
1634
|
-
track: trackObj,
|
|
1635
|
-
effects: track.effects
|
|
1636
|
-
});
|
|
1637
|
-
}
|
|
1638
|
-
}
|
|
1564
|
+
addTrackToPlayout(playout, track);
|
|
1639
1565
|
}
|
|
1640
1566
|
playout.applyInitialSoloState();
|
|
1641
1567
|
playout.setLoop(_loopEnabled, _loopStart, _loopEnd);
|
|
@@ -1655,6 +1581,15 @@ function createToneAdapter(options) {
|
|
|
1655
1581
|
setTracks(tracks) {
|
|
1656
1582
|
buildPlayout(tracks);
|
|
1657
1583
|
},
|
|
1584
|
+
addTrack(track) {
|
|
1585
|
+
if (!playout) {
|
|
1586
|
+
throw new Error(
|
|
1587
|
+
"[waveform-playlist] adapter.addTrack() called but no playout exists. Call setTracks() first to initialize the playout."
|
|
1588
|
+
);
|
|
1589
|
+
}
|
|
1590
|
+
addTrackToPlayout(playout, track);
|
|
1591
|
+
playout.applyInitialSoloState();
|
|
1592
|
+
},
|
|
1658
1593
|
play(startTime, endTime) {
|
|
1659
1594
|
if (!playout) {
|
|
1660
1595
|
console.warn(
|