wavesurfer.js 7.0.0-alpha.19 → 7.0.0-alpha.20
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.ts +15 -1
- package/dist/index.js +8 -0
- package/dist/plugins/envelope.d.ts +56 -0
- package/dist/plugins/envelope.js +279 -0
- package/dist/plugins/multitrack.d.ts +55 -8
- package/dist/plugins/multitrack.js +213 -87
- package/dist/plugins/regions.js +15 -0
- package/dist/renderer.d.ts +1 -0
- package/dist/renderer.js +12 -9
- package/dist/wavesurfer.Minimap.min.js +1 -1
- package/dist/wavesurfer.Multitrack.min.js +1 -1
- package/dist/wavesurfer.Regions.min.js +1 -1
- package/dist/wavesurfer.min.js +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -38,6 +38,15 @@ export type WaveSurferOptions = {
|
|
|
38
38
|
/** Hide scrollbar **/
|
|
39
39
|
noScrollbar?: boolean;
|
|
40
40
|
};
|
|
41
|
+
declare const defaultOptions: {
|
|
42
|
+
height: number;
|
|
43
|
+
waveColor: string;
|
|
44
|
+
progressColor: string;
|
|
45
|
+
cursorWidth: number;
|
|
46
|
+
minPxPerSec: number;
|
|
47
|
+
fillParent: boolean;
|
|
48
|
+
interactive: boolean;
|
|
49
|
+
};
|
|
41
50
|
export type WaveSurferEvents = {
|
|
42
51
|
decode: {
|
|
43
52
|
duration: number;
|
|
@@ -59,6 +68,9 @@ export type WaveSurferEvents = {
|
|
|
59
68
|
seekClick: {
|
|
60
69
|
currentTime: number;
|
|
61
70
|
};
|
|
71
|
+
zoom: {
|
|
72
|
+
minPxPerSec: number;
|
|
73
|
+
};
|
|
62
74
|
destroy: void;
|
|
63
75
|
};
|
|
64
76
|
export type WaveSurferPluginParams = {
|
|
@@ -67,7 +79,7 @@ export type WaveSurferPluginParams = {
|
|
|
67
79
|
wrapper: HTMLElement;
|
|
68
80
|
};
|
|
69
81
|
declare class WaveSurfer extends EventEmitter<WaveSurferEvents> {
|
|
70
|
-
|
|
82
|
+
options: WaveSurferOptions & typeof defaultOptions;
|
|
71
83
|
private fetcher;
|
|
72
84
|
private decoder;
|
|
73
85
|
private renderer;
|
|
@@ -118,6 +130,8 @@ declare class WaveSurfer extends EventEmitter<WaveSurferEvents> {
|
|
|
118
130
|
getDecodedData(): AudioBuffer | null;
|
|
119
131
|
/** Get the raw media element */
|
|
120
132
|
getMediaElement(): HTMLMediaElement | null;
|
|
133
|
+
/** Toggle if the waveform should react to clicks */
|
|
134
|
+
toggleInteractive(isInteractive: boolean): void;
|
|
121
135
|
/** Unmount wavesurfer */
|
|
122
136
|
destroy(): void;
|
|
123
137
|
}
|
package/dist/index.js
CHANGED
|
@@ -149,6 +149,7 @@ class WaveSurfer extends EventEmitter {
|
|
|
149
149
|
throw new Error('No audio loaded');
|
|
150
150
|
}
|
|
151
151
|
this.renderer.zoom(this.decodedData, minPxPerSec);
|
|
152
|
+
this.emit('zoom', { minPxPerSec });
|
|
152
153
|
}
|
|
153
154
|
/** Start playing the audio */
|
|
154
155
|
play() {
|
|
@@ -206,6 +207,9 @@ class WaveSurfer extends EventEmitter {
|
|
|
206
207
|
wrapper: this.renderer.getWrapper(),
|
|
207
208
|
}, options);
|
|
208
209
|
this.plugins.push(plugin);
|
|
210
|
+
plugin.once('destroy', () => {
|
|
211
|
+
this.plugins = this.plugins.filter((p) => p !== plugin);
|
|
212
|
+
});
|
|
209
213
|
return plugin;
|
|
210
214
|
}
|
|
211
215
|
/** Get the decoded audio data */
|
|
@@ -216,6 +220,10 @@ class WaveSurfer extends EventEmitter {
|
|
|
216
220
|
getMediaElement() {
|
|
217
221
|
return this.player.getMediaElement();
|
|
218
222
|
}
|
|
223
|
+
/** Toggle if the waveform should react to clicks */
|
|
224
|
+
toggleInteractive(isInteractive) {
|
|
225
|
+
this.options.interactive = isInteractive;
|
|
226
|
+
}
|
|
219
227
|
/** Unmount wavesurfer */
|
|
220
228
|
destroy() {
|
|
221
229
|
this.emit('destroy');
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import BasePlugin from '../base-plugin.js';
|
|
2
|
+
import type { WaveSurferPluginParams } from '../index.js';
|
|
3
|
+
export type EnvelopePluginOptions = {
|
|
4
|
+
startTime?: number;
|
|
5
|
+
endTime?: number;
|
|
6
|
+
fadeInEnd?: number;
|
|
7
|
+
fadeOutStart?: number;
|
|
8
|
+
volume?: number;
|
|
9
|
+
lineWidth?: string;
|
|
10
|
+
lineColor?: string;
|
|
11
|
+
dragPointSize?: number;
|
|
12
|
+
dragPointFill?: string;
|
|
13
|
+
dragPointStroke?: string;
|
|
14
|
+
};
|
|
15
|
+
declare const defaultOptions: {
|
|
16
|
+
startTime: number;
|
|
17
|
+
endTime: number;
|
|
18
|
+
fadeInEnd: number;
|
|
19
|
+
fadeOutStart: number;
|
|
20
|
+
lineWidth: number;
|
|
21
|
+
lineColor: string;
|
|
22
|
+
dragPointSize: number;
|
|
23
|
+
dragPointFill: string;
|
|
24
|
+
dragPointStroke: string;
|
|
25
|
+
};
|
|
26
|
+
type EnvelopePluginEvents = {
|
|
27
|
+
'fade-in-change': {
|
|
28
|
+
time: number;
|
|
29
|
+
};
|
|
30
|
+
'fade-out-change': {
|
|
31
|
+
time: number;
|
|
32
|
+
};
|
|
33
|
+
'volume-change': {
|
|
34
|
+
volume: number;
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
declare class EnvelopePlugin extends BasePlugin<EnvelopePluginEvents, EnvelopePluginOptions> {
|
|
38
|
+
protected options: EnvelopePluginOptions & typeof defaultOptions;
|
|
39
|
+
private svg;
|
|
40
|
+
private audioContext;
|
|
41
|
+
private gainNode;
|
|
42
|
+
private volume;
|
|
43
|
+
private isFadingIn;
|
|
44
|
+
private isFadingOut;
|
|
45
|
+
constructor(params: WaveSurferPluginParams, options: EnvelopePluginOptions);
|
|
46
|
+
private makeDraggable;
|
|
47
|
+
private renderPolyline;
|
|
48
|
+
private initSvg;
|
|
49
|
+
destroy(): void;
|
|
50
|
+
private initWebAudio;
|
|
51
|
+
private naturalVolume;
|
|
52
|
+
private onVolumeChange;
|
|
53
|
+
private initFadeEffects;
|
|
54
|
+
getCurrentVolume(): number;
|
|
55
|
+
}
|
|
56
|
+
export default EnvelopePlugin;
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
import BasePlugin from '../base-plugin.js';
|
|
2
|
+
const defaultOptions = {
|
|
3
|
+
startTime: 0,
|
|
4
|
+
endTime: 0,
|
|
5
|
+
fadeInEnd: 0,
|
|
6
|
+
fadeOutStart: 0,
|
|
7
|
+
lineWidth: 4,
|
|
8
|
+
lineColor: 'rgba(0, 0, 255, 0.5)',
|
|
9
|
+
dragPointSize: 10,
|
|
10
|
+
dragPointFill: 'rgba(255, 255, 255, 0.8)',
|
|
11
|
+
dragPointStroke: 'rgba(255, 255, 255, 0.8)',
|
|
12
|
+
};
|
|
13
|
+
class EnvelopePlugin extends BasePlugin {
|
|
14
|
+
options;
|
|
15
|
+
svg = null;
|
|
16
|
+
audioContext = null;
|
|
17
|
+
gainNode = null;
|
|
18
|
+
volume = 1;
|
|
19
|
+
isFadingIn = false;
|
|
20
|
+
isFadingOut = false;
|
|
21
|
+
constructor(params, options) {
|
|
22
|
+
super(params, options);
|
|
23
|
+
this.options = Object.assign({}, defaultOptions, options);
|
|
24
|
+
this.options.lineColor = this.options.lineColor || defaultOptions.lineColor;
|
|
25
|
+
this.options.dragPointFill = this.options.dragPointFill || defaultOptions.dragPointFill;
|
|
26
|
+
this.options.dragPointStroke = this.options.dragPointStroke || defaultOptions.dragPointStroke;
|
|
27
|
+
this.volume = this.options.volume ?? 1;
|
|
28
|
+
this.subscriptions.push(this.wavesurfer.once('decode', ({ duration }) => {
|
|
29
|
+
this.options.startTime = this.options.startTime || 0;
|
|
30
|
+
this.options.endTime = this.options.endTime || duration;
|
|
31
|
+
this.options.fadeInEnd = this.options.fadeInEnd || this.options.startTime;
|
|
32
|
+
this.options.fadeOutStart = this.options.fadeOutStart || this.options.endTime;
|
|
33
|
+
this.initWebAudio();
|
|
34
|
+
this.initSvg();
|
|
35
|
+
this.initFadeEffects();
|
|
36
|
+
}));
|
|
37
|
+
let delay;
|
|
38
|
+
this.subscriptions.push(this.wavesurfer.on('zoom', () => {
|
|
39
|
+
if (delay)
|
|
40
|
+
clearTimeout(delay);
|
|
41
|
+
delay = setTimeout(() => {
|
|
42
|
+
this.svg?.remove();
|
|
43
|
+
this.initSvg();
|
|
44
|
+
}, 100);
|
|
45
|
+
}));
|
|
46
|
+
}
|
|
47
|
+
makeDraggable(draggable, onDrag) {
|
|
48
|
+
draggable.addEventListener('mousedown', (e) => {
|
|
49
|
+
let x = e.clientX;
|
|
50
|
+
let y = e.clientY;
|
|
51
|
+
const wasInteractive = this.wavesurfer.options.interactive;
|
|
52
|
+
let delay;
|
|
53
|
+
// Make the wavesurfer ignore clicks when we're dragging
|
|
54
|
+
this.wavesurfer.toggleInteractive(false);
|
|
55
|
+
const move = (e) => {
|
|
56
|
+
const dx = e.clientX - x;
|
|
57
|
+
const dy = e.clientY - y;
|
|
58
|
+
x = e.clientX;
|
|
59
|
+
y = e.clientY;
|
|
60
|
+
onDrag(dx, dy);
|
|
61
|
+
};
|
|
62
|
+
const up = () => {
|
|
63
|
+
document.removeEventListener('mousemove', move);
|
|
64
|
+
document.removeEventListener('mouseup', up);
|
|
65
|
+
// Restore interactive state
|
|
66
|
+
if (delay)
|
|
67
|
+
clearTimeout(delay);
|
|
68
|
+
delay = setTimeout(() => {
|
|
69
|
+
this.wavesurfer.toggleInteractive(wasInteractive);
|
|
70
|
+
}, 100);
|
|
71
|
+
};
|
|
72
|
+
document.addEventListener('mousemove', move);
|
|
73
|
+
document.addEventListener('mouseup', up);
|
|
74
|
+
e.preventDefault();
|
|
75
|
+
e.stopPropagation();
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
renderPolyline() {
|
|
79
|
+
if (!this.svg)
|
|
80
|
+
return;
|
|
81
|
+
const polyline = this.svg.querySelector('polyline');
|
|
82
|
+
const points = polyline.points;
|
|
83
|
+
const top = points.getItem(1).y;
|
|
84
|
+
const line = this.svg.querySelector('line');
|
|
85
|
+
line.setAttribute('x1', points.getItem(1).x.toString());
|
|
86
|
+
line.setAttribute('x2', points.getItem(2).x.toString());
|
|
87
|
+
line.setAttribute('y1', top.toString());
|
|
88
|
+
line.setAttribute('y2', top.toString());
|
|
89
|
+
const circles = this.svg.querySelectorAll('circle');
|
|
90
|
+
for (let i = 0; i < circles.length; i++) {
|
|
91
|
+
const circle = circles[i];
|
|
92
|
+
const point = polyline.points.getItem(i + 1);
|
|
93
|
+
circle.setAttribute('cx', point.x.toString());
|
|
94
|
+
circle.setAttribute('cy', top.toString());
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
initSvg() {
|
|
98
|
+
const width = this.wrapper.clientWidth;
|
|
99
|
+
const height = this.wrapper.clientHeight;
|
|
100
|
+
const duration = this.wavesurfer.getDuration();
|
|
101
|
+
// SVG element
|
|
102
|
+
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
|
103
|
+
svg.setAttribute('width', '100%');
|
|
104
|
+
svg.setAttribute('height', '100%');
|
|
105
|
+
svg.setAttribute('viewBox', `0 0 ${width} ${height}`);
|
|
106
|
+
svg.setAttribute('preserveAspectRatio', 'none');
|
|
107
|
+
svg.setAttribute('style', 'position: absolute; left: 0; top: 0; z-index: 4; pointer-events: none;');
|
|
108
|
+
this.svg = svg;
|
|
109
|
+
// A polyline representing the envelope
|
|
110
|
+
const polyline = document.createElementNS('http://www.w3.org/2000/svg', 'polyline');
|
|
111
|
+
polyline.setAttribute('points', '0,0 0,0 0,0 0,0');
|
|
112
|
+
polyline.setAttribute('stroke', this.options.lineColor);
|
|
113
|
+
polyline.setAttribute('stroke-width', this.options.lineWidth);
|
|
114
|
+
polyline.setAttribute('fill', 'none');
|
|
115
|
+
polyline.setAttribute('style', 'pointer-events: none');
|
|
116
|
+
svg.appendChild(polyline);
|
|
117
|
+
// Draggable top line
|
|
118
|
+
const line = document.createElementNS('http://www.w3.org/2000/svg', 'line');
|
|
119
|
+
line.setAttribute('stroke', 'none');
|
|
120
|
+
line.setAttribute('stroke-width', (this.options.lineWidth * 3).toString());
|
|
121
|
+
line.setAttribute('style', 'cursor: ns-resize; pointer-events: all;');
|
|
122
|
+
svg.appendChild(line);
|
|
123
|
+
const points = polyline.points;
|
|
124
|
+
const offset = this.options.dragPointSize / 2;
|
|
125
|
+
const top = height - this.volume * height + offset;
|
|
126
|
+
points.getItem(0).x = (this.options.startTime / duration) * width;
|
|
127
|
+
points.getItem(0).y = height;
|
|
128
|
+
points.getItem(1).x = (this.options.fadeInEnd / duration) * width;
|
|
129
|
+
points.getItem(1).y = top;
|
|
130
|
+
points.getItem(2).x = (this.options.fadeOutStart / duration) * width;
|
|
131
|
+
points.getItem(2).y = top;
|
|
132
|
+
points.getItem(3).x = (this.options.endTime / duration) * width;
|
|
133
|
+
points.getItem(3).y = height;
|
|
134
|
+
// Drag points
|
|
135
|
+
const dragPoints = [1, 2];
|
|
136
|
+
dragPoints.forEach(() => {
|
|
137
|
+
const circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
|
|
138
|
+
circle.setAttribute('r', (this.options.dragPointSize / 2).toString());
|
|
139
|
+
circle.setAttribute('fill', this.options.dragPointFill);
|
|
140
|
+
circle.setAttribute('stroke', this.options.dragPointStroke || this.options.dragPointFill);
|
|
141
|
+
circle.setAttribute('stroke-width', '2');
|
|
142
|
+
circle.setAttribute('style', 'cursor: ew-resize; pointer-events: all;');
|
|
143
|
+
svg.appendChild(circle);
|
|
144
|
+
});
|
|
145
|
+
this.wrapper.appendChild(svg);
|
|
146
|
+
// Initial polyline
|
|
147
|
+
this.renderPolyline();
|
|
148
|
+
// On top line drag
|
|
149
|
+
const onDragY = (dy) => {
|
|
150
|
+
const newTop = points.getItem(1).y + dy - offset;
|
|
151
|
+
if (newTop < -0.5 || newTop > height)
|
|
152
|
+
return;
|
|
153
|
+
points.getItem(1).y = newTop + offset;
|
|
154
|
+
points.getItem(2).y = newTop + offset;
|
|
155
|
+
this.renderPolyline();
|
|
156
|
+
const newVolume = Math.min(1, Math.max(0, (height - newTop) / height));
|
|
157
|
+
this.onVolumeChange(newVolume);
|
|
158
|
+
this.renderPolyline();
|
|
159
|
+
};
|
|
160
|
+
// On points drag
|
|
161
|
+
const onDragX = (dx, dy, index) => {
|
|
162
|
+
const point = polyline.points.getItem(index);
|
|
163
|
+
const newX = point.x + dx;
|
|
164
|
+
const newTime = (newX / width) * duration;
|
|
165
|
+
if ((index === 1 && newTime > this.options.fadeOutStart) || newTime < this.options.startTime)
|
|
166
|
+
return;
|
|
167
|
+
if ((index === 2 && newTime < this.options.fadeInEnd) || newTime > this.options.endTime)
|
|
168
|
+
return;
|
|
169
|
+
point.x = newX;
|
|
170
|
+
if (index === 1) {
|
|
171
|
+
this.options.fadeInEnd = newTime;
|
|
172
|
+
this.emit('fade-in-change', { time: newTime });
|
|
173
|
+
}
|
|
174
|
+
else if (index === 2) {
|
|
175
|
+
this.options.fadeOutStart = newTime;
|
|
176
|
+
this.emit('fade-out-change', { time: newTime });
|
|
177
|
+
}
|
|
178
|
+
// Also allow dragging points vertically
|
|
179
|
+
if (dy > 1) {
|
|
180
|
+
onDragY(dy);
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
this.renderPolyline();
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
// Draggable top line of the polyline
|
|
187
|
+
this.makeDraggable(line, (_, dy) => onDragY(dy));
|
|
188
|
+
// Make each point draggable
|
|
189
|
+
const draggables = svg.querySelectorAll('circle');
|
|
190
|
+
for (let i = 0; i < draggables.length; i++) {
|
|
191
|
+
const index = i + 1;
|
|
192
|
+
this.makeDraggable(draggables[i], (dx, dy) => onDragX(dx, dy, index));
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
destroy() {
|
|
196
|
+
this.svg?.remove();
|
|
197
|
+
super.destroy();
|
|
198
|
+
}
|
|
199
|
+
initWebAudio() {
|
|
200
|
+
const audio = this.wavesurfer.getMediaElement();
|
|
201
|
+
if (!audio)
|
|
202
|
+
return null;
|
|
203
|
+
this.volume = this.options.volume ?? audio.volume;
|
|
204
|
+
// Create an AudioContext
|
|
205
|
+
const audioContext = new window.AudioContext();
|
|
206
|
+
// Create a GainNode for controlling the volume
|
|
207
|
+
this.gainNode = audioContext.createGain();
|
|
208
|
+
this.gainNode.gain.value = this.volume;
|
|
209
|
+
// Create a MediaElementAudioSourceNode using the audio element
|
|
210
|
+
const source = audioContext.createMediaElementSource(audio);
|
|
211
|
+
// Connect the source to the GainNode, and the GainNode to the destination (speakers)
|
|
212
|
+
source.connect(this.gainNode);
|
|
213
|
+
this.gainNode.connect(audioContext.destination);
|
|
214
|
+
this.audioContext = audioContext;
|
|
215
|
+
}
|
|
216
|
+
naturalVolume(value) {
|
|
217
|
+
const minValue = 0.0001;
|
|
218
|
+
const maxValue = 1;
|
|
219
|
+
const exponent = 3; // Adjust the exponent to change the curve of the volume control
|
|
220
|
+
const interpolatedValue = minValue + (maxValue - minValue) * Math.pow(value, exponent);
|
|
221
|
+
return interpolatedValue;
|
|
222
|
+
}
|
|
223
|
+
onVolumeChange(volume) {
|
|
224
|
+
volume = this.naturalVolume(volume);
|
|
225
|
+
this.volume = volume;
|
|
226
|
+
this.emit('volume-change', { volume });
|
|
227
|
+
if (!this.gainNode)
|
|
228
|
+
return;
|
|
229
|
+
this.gainNode.gain.value = volume;
|
|
230
|
+
}
|
|
231
|
+
initFadeEffects() {
|
|
232
|
+
if (!this.audioContext)
|
|
233
|
+
return;
|
|
234
|
+
const unsub = this.wavesurfer.on('timeupdate', ({ currentTime }) => {
|
|
235
|
+
if (!this.audioContext || !this.gainNode)
|
|
236
|
+
return;
|
|
237
|
+
if (!this.wavesurfer.isPlaying())
|
|
238
|
+
return;
|
|
239
|
+
if (this.audioContext.state === 'suspended') {
|
|
240
|
+
this.audioContext.resume();
|
|
241
|
+
}
|
|
242
|
+
// Fade in
|
|
243
|
+
if (!this.isFadingIn && currentTime >= this.options.startTime && currentTime <= this.options.fadeInEnd) {
|
|
244
|
+
this.isFadingIn = true;
|
|
245
|
+
// Set the initial gain (volume) to 0 (silent)
|
|
246
|
+
this.gainNode.gain.setValueAtTime(0, this.audioContext.currentTime);
|
|
247
|
+
// Set the target gain (volume) to 1 (full volume) over N seconds
|
|
248
|
+
this.gainNode.gain.linearRampToValueAtTime(this.volume, this.audioContext.currentTime + (this.options.fadeInEnd - currentTime));
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
// Fade out
|
|
252
|
+
if (!this.isFadingOut && currentTime >= this.options.fadeOutStart && currentTime <= this.options.endTime) {
|
|
253
|
+
this.isFadingOut = true;
|
|
254
|
+
// Set the target gain (volume) to 0 (silent) over N seconds
|
|
255
|
+
this.gainNode.gain.linearRampToValueAtTime(0, this.audioContext.currentTime + (this.options.endTime - currentTime));
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
// Reset fade in/out
|
|
259
|
+
let cancelRamp = false;
|
|
260
|
+
if (this.isFadingIn && (currentTime < this.options.startTime || currentTime > this.options.fadeInEnd)) {
|
|
261
|
+
this.isFadingIn = false;
|
|
262
|
+
cancelRamp = true;
|
|
263
|
+
}
|
|
264
|
+
if (this.isFadingOut && (currentTime < this.options.fadeOutStart || currentTime >= this.options.endTime)) {
|
|
265
|
+
this.isFadingOut = false;
|
|
266
|
+
cancelRamp = true;
|
|
267
|
+
}
|
|
268
|
+
if (cancelRamp) {
|
|
269
|
+
this.gainNode.gain.cancelScheduledValues(this.audioContext.currentTime);
|
|
270
|
+
this.gainNode.gain.value = this.volume;
|
|
271
|
+
}
|
|
272
|
+
});
|
|
273
|
+
this.subscriptions.push(unsub);
|
|
274
|
+
}
|
|
275
|
+
getCurrentVolume() {
|
|
276
|
+
return this.gainNode ? this.gainNode.gain.value : this.volume;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
export default EnvelopePlugin;
|
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
import { type WaveSurferOptions } from '../index.js';
|
|
2
|
-
type
|
|
3
|
-
|
|
2
|
+
import { type EnvelopePluginOptions } from './envelope.js';
|
|
3
|
+
import EventEmitter from '../event-emitter.js';
|
|
4
|
+
type TrackId = string | number;
|
|
5
|
+
export type TrackOptions = {
|
|
6
|
+
id: TrackId;
|
|
4
7
|
url?: string;
|
|
5
8
|
peaks?: WaveSurferOptions['peaks'];
|
|
6
9
|
draggable?: boolean;
|
|
7
10
|
startPosition: number;
|
|
8
11
|
startCue?: number;
|
|
9
12
|
endCue?: number;
|
|
13
|
+
fadeInEnd?: number;
|
|
14
|
+
fadeOutStart?: number;
|
|
15
|
+
volume?: number;
|
|
10
16
|
markers?: Array<{
|
|
11
17
|
time: number;
|
|
12
18
|
label?: string;
|
|
@@ -19,8 +25,8 @@ type MultitrackTracks = Array<{
|
|
|
19
25
|
color?: string;
|
|
20
26
|
}>;
|
|
21
27
|
options?: WaveSurferOptions;
|
|
22
|
-
}
|
|
23
|
-
type MultitrackOptions = {
|
|
28
|
+
};
|
|
29
|
+
export type MultitrackOptions = {
|
|
24
30
|
container: HTMLElement;
|
|
25
31
|
minPxPerSec?: number;
|
|
26
32
|
cursorColor?: string;
|
|
@@ -28,9 +34,40 @@ type MultitrackOptions = {
|
|
|
28
34
|
trackBackground?: string;
|
|
29
35
|
trackBorderColor?: string;
|
|
30
36
|
rightButtonDrag?: boolean;
|
|
31
|
-
|
|
37
|
+
envelopeOptions?: EnvelopePluginOptions;
|
|
38
|
+
};
|
|
39
|
+
export type MultitrackEvents = {
|
|
40
|
+
canplay: void;
|
|
41
|
+
'start-position-change': {
|
|
42
|
+
id: TrackId;
|
|
43
|
+
startPosition: number;
|
|
44
|
+
};
|
|
45
|
+
'start-cue-change': {
|
|
46
|
+
id: TrackId;
|
|
47
|
+
startCue: number;
|
|
48
|
+
};
|
|
49
|
+
'end-cue-change': {
|
|
50
|
+
id: TrackId;
|
|
51
|
+
endCue: number;
|
|
52
|
+
};
|
|
53
|
+
'fade-in-change': {
|
|
54
|
+
id: TrackId;
|
|
55
|
+
fadeInEnd: number;
|
|
56
|
+
};
|
|
57
|
+
'fade-out-change': {
|
|
58
|
+
id: TrackId;
|
|
59
|
+
fadeOutStart: number;
|
|
60
|
+
};
|
|
61
|
+
'volume-change': {
|
|
62
|
+
id: TrackId;
|
|
63
|
+
volume: number;
|
|
64
|
+
};
|
|
65
|
+
drop: {
|
|
66
|
+
id: TrackId;
|
|
67
|
+
};
|
|
32
68
|
};
|
|
33
|
-
|
|
69
|
+
type MultitrackTracks = Array<TrackOptions>;
|
|
70
|
+
declare class MultiTrack extends EventEmitter<MultitrackEvents> {
|
|
34
71
|
private tracks;
|
|
35
72
|
private options;
|
|
36
73
|
private audios;
|
|
@@ -41,12 +78,19 @@ declare class MultiTrack {
|
|
|
41
78
|
private rendering;
|
|
42
79
|
private isDragging;
|
|
43
80
|
private frameRequest;
|
|
81
|
+
private timer;
|
|
82
|
+
private subscriptions;
|
|
83
|
+
private timeline;
|
|
44
84
|
static create(tracks: MultitrackTracks, options: MultitrackOptions): MultiTrack;
|
|
45
85
|
constructor(tracks: MultitrackTracks, options: MultitrackOptions);
|
|
46
|
-
private
|
|
47
|
-
private
|
|
86
|
+
private initDurations;
|
|
87
|
+
private initAudio;
|
|
88
|
+
private initAllAudios;
|
|
89
|
+
private initWavesurfer;
|
|
90
|
+
private initAllWavesurfers;
|
|
48
91
|
private initTimeline;
|
|
49
92
|
private updatePosition;
|
|
93
|
+
private setIsDragging;
|
|
50
94
|
private onDrag;
|
|
51
95
|
private onMove;
|
|
52
96
|
private findCurrentTracks;
|
|
@@ -54,8 +98,11 @@ declare class MultiTrack {
|
|
|
54
98
|
play(): void;
|
|
55
99
|
pause(): void;
|
|
56
100
|
isPlaying(): boolean;
|
|
101
|
+
getCurrentTime(): number;
|
|
57
102
|
seekTo(time: number): void;
|
|
58
103
|
zoom(pxPerSec: number): void;
|
|
104
|
+
addTrack(track: TrackOptions): void;
|
|
59
105
|
destroy(): void;
|
|
106
|
+
setSinkId(sinkId: string): Promise<void[]>;
|
|
60
107
|
}
|
|
61
108
|
export default MultiTrack;
|