wavesurfer.js 7.0.0-alpha.9 → 7.0.0-beta.2
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/README.md +90 -18
- package/dist/base-plugin.d.ts +6 -4
- package/dist/base-plugin.js +9 -3
- package/dist/decoder.d.ts +8 -7
- package/dist/decoder.js +43 -38
- package/dist/event-emitter.d.ts +16 -10
- package/dist/event-emitter.js +38 -16
- package/dist/fetcher.d.ts +4 -3
- package/dist/fetcher.js +5 -15
- package/dist/player.d.ts +31 -11
- package/dist/player.js +58 -31
- package/dist/plugins/envelope.d.ts +71 -0
- package/dist/plugins/envelope.js +347 -0
- package/dist/plugins/envelope.min.cjs +1 -0
- package/dist/plugins/envelope.min.js +1 -0
- package/dist/plugins/minimap.d.ts +39 -0
- package/dist/plugins/minimap.js +114 -0
- package/dist/plugins/minimap.min.cjs +1 -0
- package/dist/plugins/minimap.min.js +1 -0
- package/dist/plugins/multitrack.d.ts +85 -12
- package/dist/plugins/multitrack.js +331 -84
- package/dist/plugins/multitrack.min.cjs +1 -0
- package/dist/plugins/multitrack.min.js +1 -0
- package/dist/plugins/record.d.ts +26 -0
- package/dist/plugins/record.js +126 -0
- package/dist/plugins/record.min.cjs +1 -0
- package/dist/plugins/record.min.js +1 -0
- package/dist/plugins/regions.d.ts +83 -43
- package/dist/plugins/regions.js +362 -192
- package/dist/plugins/regions.min.cjs +1 -0
- package/dist/plugins/regions.min.js +1 -0
- package/dist/plugins/spectrogram.d.ts +69 -0
- package/dist/plugins/spectrogram.js +340 -0
- package/dist/plugins/spectrogram.min.cjs +1 -0
- package/dist/plugins/spectrogram.min.js +1 -0
- package/dist/plugins/timeline.d.ts +25 -9
- package/dist/plugins/timeline.js +65 -24
- package/dist/plugins/timeline.min.cjs +1 -0
- package/dist/plugins/timeline.min.js +1 -0
- package/dist/renderer.d.ts +29 -13
- package/dist/renderer.js +280 -161
- package/dist/timer.d.ts +1 -1
- package/dist/wavesurfer.d.ts +151 -0
- package/dist/wavesurfer.js +241 -0
- package/dist/wavesurfer.min.cjs +1 -0
- package/dist/wavesurfer.min.js +1 -1
- package/package.json +55 -28
- package/dist/index.d.ts +0 -117
- package/dist/index.js +0 -227
- package/dist/player-webaudio.d.ts +0 -8
- package/dist/player-webaudio.js +0 -32
- package/dist/plugins/xmultitrack.d.ts +0 -44
- package/dist/plugins/xmultitrack.js +0 -260
- package/dist/react/useWavesurfer.d.ts +0 -5
- package/dist/react/useWavesurfer.js +0 -20
- package/dist/wavesurfer.Multitrack.min.js +0 -1
- package/dist/wavesurfer.Regions.min.js +0 -1
- package/dist/wavesurfer.Timeline.min.js +0 -1
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Envelope is a visual UI for controlling the audio volume and add fade-in and fade-out effects.
|
|
3
|
+
*/
|
|
4
|
+
import BasePlugin from '../base-plugin.js';
|
|
5
|
+
export type EnvelopePluginOptions = {
|
|
6
|
+
fadeInStart?: number;
|
|
7
|
+
fadeInEnd?: number;
|
|
8
|
+
fadeOutStart?: number;
|
|
9
|
+
fadeOutEnd?: number;
|
|
10
|
+
volume?: number;
|
|
11
|
+
lineWidth?: string;
|
|
12
|
+
lineColor?: string;
|
|
13
|
+
dragPointSize?: number;
|
|
14
|
+
dragPointFill?: string;
|
|
15
|
+
dragPointStroke?: string;
|
|
16
|
+
};
|
|
17
|
+
declare const defaultOptions: {
|
|
18
|
+
fadeInStart: number;
|
|
19
|
+
fadeOutEnd: number;
|
|
20
|
+
fadeInEnd: number;
|
|
21
|
+
fadeOutStart: number;
|
|
22
|
+
lineWidth: number;
|
|
23
|
+
lineColor: string;
|
|
24
|
+
dragPointSize: number;
|
|
25
|
+
dragPointFill: string;
|
|
26
|
+
dragPointStroke: string;
|
|
27
|
+
};
|
|
28
|
+
type Options = EnvelopePluginOptions & typeof defaultOptions;
|
|
29
|
+
export type EnvelopePluginEvents = {
|
|
30
|
+
'fade-in-change': [time: number];
|
|
31
|
+
'fade-out-change': [time: number];
|
|
32
|
+
'volume-change': [volume: number];
|
|
33
|
+
};
|
|
34
|
+
declare class EnvelopePlugin extends BasePlugin<EnvelopePluginEvents, EnvelopePluginOptions> {
|
|
35
|
+
protected options: Options;
|
|
36
|
+
private polyline;
|
|
37
|
+
private audioContext;
|
|
38
|
+
private gainNode;
|
|
39
|
+
private volume;
|
|
40
|
+
private isFadingIn;
|
|
41
|
+
private isFadingOut;
|
|
42
|
+
private readonly naturalVolumeExponent;
|
|
43
|
+
constructor(options: EnvelopePluginOptions);
|
|
44
|
+
static create(options: EnvelopePluginOptions): EnvelopePlugin;
|
|
45
|
+
destroy(): void;
|
|
46
|
+
/** Called by wavesurfer, don't call manually */
|
|
47
|
+
onInit(): void;
|
|
48
|
+
private initSvg;
|
|
49
|
+
private renderPolyline;
|
|
50
|
+
private initWebAudio;
|
|
51
|
+
private invertNaturalVolume;
|
|
52
|
+
private naturalVolume;
|
|
53
|
+
private setGainValue;
|
|
54
|
+
private initFadeEffects;
|
|
55
|
+
/** Get the current audio volume */
|
|
56
|
+
getCurrentVolume(): number;
|
|
57
|
+
/**
|
|
58
|
+
* Set the fade-in start time.
|
|
59
|
+
* @param time The time (in seconds) to set the fade-in start time to
|
|
60
|
+
* @param moveFadeInEnd Whether to move the drag point to the new time (default: false)
|
|
61
|
+
*/
|
|
62
|
+
setStartTime(time: number, moveFadeInEnd?: boolean): void;
|
|
63
|
+
/** Set the fade-in end time.
|
|
64
|
+
* @param time The time (in seconds) to set the fade-in end time to
|
|
65
|
+
* @param moveFadeOutStart Whether to move the drag point to the new time (default: false)
|
|
66
|
+
*/
|
|
67
|
+
setEndTime(time: number, moveFadeOutStart?: boolean): void;
|
|
68
|
+
/** Set the volume of the audio */
|
|
69
|
+
setVolume(volume: number): void;
|
|
70
|
+
}
|
|
71
|
+
export default EnvelopePlugin;
|
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Envelope is a visual UI for controlling the audio volume and add fade-in and fade-out effects.
|
|
3
|
+
*/
|
|
4
|
+
import BasePlugin from '../base-plugin.js';
|
|
5
|
+
import EventEmitter from '../event-emitter.js';
|
|
6
|
+
const defaultOptions = {
|
|
7
|
+
fadeInStart: 0,
|
|
8
|
+
fadeOutEnd: 0,
|
|
9
|
+
fadeInEnd: 0,
|
|
10
|
+
fadeOutStart: 0,
|
|
11
|
+
lineWidth: 4,
|
|
12
|
+
lineColor: 'rgba(0, 0, 255, 0.5)',
|
|
13
|
+
dragPointSize: 10,
|
|
14
|
+
dragPointFill: 'rgba(255, 255, 255, 0.8)',
|
|
15
|
+
dragPointStroke: 'rgba(255, 255, 255, 0.8)',
|
|
16
|
+
};
|
|
17
|
+
class Polyline extends EventEmitter {
|
|
18
|
+
constructor(options, wrapper) {
|
|
19
|
+
super();
|
|
20
|
+
this.top = 0;
|
|
21
|
+
// An padding to make the envelope fit into the SVG
|
|
22
|
+
this.padding = options.dragPointSize / 2 + 1;
|
|
23
|
+
// SVG element
|
|
24
|
+
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
|
25
|
+
svg.setAttribute('width', '100%');
|
|
26
|
+
svg.setAttribute('height', '100%');
|
|
27
|
+
svg.setAttribute('viewBox', '0 0 0 0');
|
|
28
|
+
svg.setAttribute('preserveAspectRatio', 'none');
|
|
29
|
+
svg.setAttribute('style', 'position: absolute; left: 0; top: 0; z-index: 4; pointer-events: none;');
|
|
30
|
+
svg.setAttribute('part', 'envelope');
|
|
31
|
+
this.svg = svg;
|
|
32
|
+
// A polyline representing the envelope
|
|
33
|
+
const polyline = document.createElementNS('http://www.w3.org/2000/svg', 'polyline');
|
|
34
|
+
polyline.setAttribute('points', '0,0 0,0 0,0 0,0');
|
|
35
|
+
polyline.setAttribute('stroke', options.lineColor);
|
|
36
|
+
polyline.setAttribute('stroke-width', options.lineWidth);
|
|
37
|
+
polyline.setAttribute('fill', 'none');
|
|
38
|
+
polyline.setAttribute('style', 'pointer-events: none;');
|
|
39
|
+
polyline.setAttribute('part', 'polyline');
|
|
40
|
+
svg.appendChild(polyline);
|
|
41
|
+
// Draggable top line
|
|
42
|
+
const line = document.createElementNS('http://www.w3.org/2000/svg', 'line');
|
|
43
|
+
line.setAttribute('stroke', 'transparent');
|
|
44
|
+
line.setAttribute('stroke-width', (options.lineWidth * 3).toString());
|
|
45
|
+
line.setAttribute('style', 'cursor: ns-resize; pointer-events: all;');
|
|
46
|
+
line.setAttribute('part', 'line');
|
|
47
|
+
svg.appendChild(line);
|
|
48
|
+
[0, 1].forEach(() => {
|
|
49
|
+
const circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
|
|
50
|
+
circle.setAttribute('r', (options.dragPointSize / 2).toString());
|
|
51
|
+
circle.setAttribute('fill', options.dragPointFill);
|
|
52
|
+
circle.setAttribute('stroke', options.dragPointStroke || options.dragPointFill);
|
|
53
|
+
circle.setAttribute('stroke-width', '2');
|
|
54
|
+
circle.setAttribute('style', 'cursor: ew-resize; pointer-events: all;');
|
|
55
|
+
circle.setAttribute('part', 'circle');
|
|
56
|
+
svg.appendChild(circle);
|
|
57
|
+
});
|
|
58
|
+
wrapper.appendChild(svg);
|
|
59
|
+
// Init dtagging
|
|
60
|
+
{
|
|
61
|
+
// On top line drag
|
|
62
|
+
const onDragY = (dy) => {
|
|
63
|
+
const newTop = this.top + dy;
|
|
64
|
+
const { height } = svg.viewBox.baseVal;
|
|
65
|
+
if (newTop < -0.5 || newTop > height)
|
|
66
|
+
return;
|
|
67
|
+
const relativeY = Math.min(1, Math.max(0, (height - newTop) / height));
|
|
68
|
+
this.emit('line-move', relativeY);
|
|
69
|
+
};
|
|
70
|
+
// On points drag
|
|
71
|
+
const onDragX = (index, dx) => {
|
|
72
|
+
const point = polyline.points.getItem(index);
|
|
73
|
+
const newX = point.x + dx;
|
|
74
|
+
const { width } = svg.viewBox.baseVal;
|
|
75
|
+
this.emit('point-move', index, newX / width);
|
|
76
|
+
};
|
|
77
|
+
// Draggable top line of the polyline
|
|
78
|
+
this.makeDraggable(line, (_, dy) => onDragY(dy));
|
|
79
|
+
// Make each point draggable
|
|
80
|
+
const draggables = this.svg.querySelectorAll('circle');
|
|
81
|
+
Array.from(draggables).forEach((draggable, index) => {
|
|
82
|
+
this.makeDraggable(draggable, (dx) => onDragX(index + 1, dx));
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
makeDraggable(draggable, onDrag) {
|
|
87
|
+
draggable.addEventListener('click', (e) => {
|
|
88
|
+
e.preventDefault();
|
|
89
|
+
e.stopPropagation();
|
|
90
|
+
});
|
|
91
|
+
draggable.addEventListener('mousedown', (e) => {
|
|
92
|
+
e.preventDefault();
|
|
93
|
+
e.stopPropagation();
|
|
94
|
+
let x = e.clientX;
|
|
95
|
+
let y = e.clientY;
|
|
96
|
+
const move = (e) => {
|
|
97
|
+
const dx = e.clientX - x;
|
|
98
|
+
const dy = e.clientY - y;
|
|
99
|
+
x = e.clientX;
|
|
100
|
+
y = e.clientY;
|
|
101
|
+
onDrag(dx, dy);
|
|
102
|
+
};
|
|
103
|
+
const up = () => {
|
|
104
|
+
document.removeEventListener('mousemove', move);
|
|
105
|
+
document.removeEventListener('mouseup', up);
|
|
106
|
+
};
|
|
107
|
+
document.addEventListener('mousemove', move);
|
|
108
|
+
document.addEventListener('mouseup', up);
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
update({ x1, x2, x3, x4, y }) {
|
|
112
|
+
const width = this.svg.clientWidth;
|
|
113
|
+
const height = this.svg.clientHeight;
|
|
114
|
+
this.top = height - y * height;
|
|
115
|
+
const paddedTop = Math.max(this.padding, Math.min(this.top, height - this.padding));
|
|
116
|
+
this.svg.setAttribute('viewBox', `0 0 ${width} ${height}`);
|
|
117
|
+
const polyline = this.svg.querySelector('polyline');
|
|
118
|
+
const { points } = polyline;
|
|
119
|
+
points.getItem(0).x = x1 * width;
|
|
120
|
+
points.getItem(0).y = height;
|
|
121
|
+
points.getItem(1).x = x2 * width;
|
|
122
|
+
points.getItem(1).y = paddedTop;
|
|
123
|
+
points.getItem(2).x = x3 * width;
|
|
124
|
+
points.getItem(2).y = paddedTop;
|
|
125
|
+
points.getItem(3).x = x4 * width;
|
|
126
|
+
points.getItem(3).y = height;
|
|
127
|
+
const line = this.svg.querySelector('line');
|
|
128
|
+
line.setAttribute('x1', points.getItem(1).x.toString());
|
|
129
|
+
line.setAttribute('x2', points.getItem(2).x.toString());
|
|
130
|
+
line.setAttribute('y1', paddedTop.toString());
|
|
131
|
+
line.setAttribute('y2', paddedTop.toString());
|
|
132
|
+
const circles = this.svg.querySelectorAll('circle');
|
|
133
|
+
Array.from(circles).forEach((circle, i) => {
|
|
134
|
+
const point = points.getItem(i + 1);
|
|
135
|
+
circle.setAttribute('cx', point.x.toString());
|
|
136
|
+
circle.setAttribute('cy', point.y.toString());
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
destroy() {
|
|
140
|
+
this.svg.remove();
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
class EnvelopePlugin extends BasePlugin {
|
|
144
|
+
constructor(options) {
|
|
145
|
+
super(options);
|
|
146
|
+
this.polyline = null;
|
|
147
|
+
this.audioContext = null;
|
|
148
|
+
this.gainNode = null;
|
|
149
|
+
this.volume = 1;
|
|
150
|
+
this.isFadingIn = false;
|
|
151
|
+
this.isFadingOut = false;
|
|
152
|
+
// Adjust the exponent to change the curve of the volume control
|
|
153
|
+
this.naturalVolumeExponent = 1.5;
|
|
154
|
+
this.options = Object.assign({}, defaultOptions, options);
|
|
155
|
+
this.options.lineColor = this.options.lineColor || defaultOptions.lineColor;
|
|
156
|
+
this.options.dragPointFill = this.options.dragPointFill || defaultOptions.dragPointFill;
|
|
157
|
+
this.options.dragPointStroke = this.options.dragPointStroke || defaultOptions.dragPointStroke;
|
|
158
|
+
this.volume = this.options.volume ?? 1;
|
|
159
|
+
}
|
|
160
|
+
static create(options) {
|
|
161
|
+
return new EnvelopePlugin(options);
|
|
162
|
+
}
|
|
163
|
+
destroy() {
|
|
164
|
+
this.polyline?.destroy();
|
|
165
|
+
super.destroy();
|
|
166
|
+
}
|
|
167
|
+
/** Called by wavesurfer, don't call manually */
|
|
168
|
+
onInit() {
|
|
169
|
+
if (!this.wavesurfer) {
|
|
170
|
+
throw Error('WaveSurfer is not initialized');
|
|
171
|
+
}
|
|
172
|
+
this.initWebAudio();
|
|
173
|
+
this.initSvg();
|
|
174
|
+
this.initFadeEffects();
|
|
175
|
+
this.subscriptions.push(this.wavesurfer.on('redraw', () => {
|
|
176
|
+
const duration = this.wavesurfer?.getDuration();
|
|
177
|
+
if (!duration)
|
|
178
|
+
return;
|
|
179
|
+
this.options.fadeInStart = this.options.fadeInStart || 0;
|
|
180
|
+
this.options.fadeOutEnd = this.options.fadeOutEnd || duration;
|
|
181
|
+
this.options.fadeInEnd = this.options.fadeInEnd || this.options.fadeInStart;
|
|
182
|
+
this.options.fadeOutStart = this.options.fadeOutStart || this.options.fadeOutEnd;
|
|
183
|
+
this.renderPolyline();
|
|
184
|
+
}));
|
|
185
|
+
}
|
|
186
|
+
initSvg() {
|
|
187
|
+
if (!this.wavesurfer)
|
|
188
|
+
return;
|
|
189
|
+
const wrapper = this.wavesurfer.getWrapper();
|
|
190
|
+
this.polyline = new Polyline(this.options, wrapper);
|
|
191
|
+
this.subscriptions.push(this.polyline.on('line-move', (relativeY) => {
|
|
192
|
+
this.setVolume(this.naturalVolume(relativeY));
|
|
193
|
+
}), this.polyline.on('point-move', (index, relativeX) => {
|
|
194
|
+
const duration = this.wavesurfer?.getDuration() || 0;
|
|
195
|
+
const newTime = relativeX * duration;
|
|
196
|
+
// Fade-in end point
|
|
197
|
+
if (index === 1) {
|
|
198
|
+
if (newTime < this.options.fadeInStart || newTime > this.options.fadeOutStart)
|
|
199
|
+
return;
|
|
200
|
+
this.options.fadeInEnd = newTime;
|
|
201
|
+
this.emit('fade-in-change', newTime);
|
|
202
|
+
}
|
|
203
|
+
else if (index === 2) {
|
|
204
|
+
// Fade-out start point
|
|
205
|
+
if (newTime > this.options.fadeOutEnd || newTime < this.options.fadeInEnd)
|
|
206
|
+
return;
|
|
207
|
+
this.options.fadeOutStart = newTime;
|
|
208
|
+
this.emit('fade-out-change', newTime);
|
|
209
|
+
}
|
|
210
|
+
this.renderPolyline();
|
|
211
|
+
}));
|
|
212
|
+
}
|
|
213
|
+
renderPolyline() {
|
|
214
|
+
if (!this.polyline || !this.wavesurfer)
|
|
215
|
+
return;
|
|
216
|
+
const duration = this.wavesurfer.getDuration();
|
|
217
|
+
if (!duration)
|
|
218
|
+
return;
|
|
219
|
+
this.polyline.update({
|
|
220
|
+
x1: this.options.fadeInStart / duration,
|
|
221
|
+
x2: this.options.fadeInEnd / duration,
|
|
222
|
+
x3: this.options.fadeOutStart / duration,
|
|
223
|
+
x4: this.options.fadeOutEnd / duration,
|
|
224
|
+
y: this.invertNaturalVolume(this.volume),
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
initWebAudio() {
|
|
228
|
+
const audio = this.wavesurfer?.getMediaElement();
|
|
229
|
+
if (!audio)
|
|
230
|
+
return null;
|
|
231
|
+
this.volume = this.options.volume ?? audio.volume;
|
|
232
|
+
// Create an AudioContext
|
|
233
|
+
const audioContext = new window.AudioContext();
|
|
234
|
+
// Create a GainNode for controlling the volume
|
|
235
|
+
this.gainNode = audioContext.createGain();
|
|
236
|
+
this.setGainValue();
|
|
237
|
+
// Create a MediaElementAudioSourceNode using the audio element
|
|
238
|
+
const source = audioContext.createMediaElementSource(audio);
|
|
239
|
+
// Connect the source to the GainNode, and the GainNode to the destination (speakers)
|
|
240
|
+
source.connect(this.gainNode);
|
|
241
|
+
this.gainNode.connect(audioContext.destination);
|
|
242
|
+
this.audioContext = audioContext;
|
|
243
|
+
}
|
|
244
|
+
invertNaturalVolume(value) {
|
|
245
|
+
const minValue = 0.0001;
|
|
246
|
+
const maxValue = 1;
|
|
247
|
+
const interpolatedValue = Math.pow((value - minValue) / (maxValue - minValue), 1 / this.naturalVolumeExponent);
|
|
248
|
+
return interpolatedValue;
|
|
249
|
+
}
|
|
250
|
+
naturalVolume(value) {
|
|
251
|
+
const minValue = 0.0001;
|
|
252
|
+
const maxValue = 1;
|
|
253
|
+
const interpolatedValue = minValue + (maxValue - minValue) * Math.pow(value, this.naturalVolumeExponent);
|
|
254
|
+
return interpolatedValue;
|
|
255
|
+
}
|
|
256
|
+
setGainValue() {
|
|
257
|
+
if (this.gainNode) {
|
|
258
|
+
this.gainNode.gain.value = this.volume;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
initFadeEffects() {
|
|
262
|
+
if (!this.audioContext || !this.wavesurfer)
|
|
263
|
+
return;
|
|
264
|
+
const unsub = this.wavesurfer.on('timeupdate', (currentTime) => {
|
|
265
|
+
if (!this.audioContext || !this.gainNode)
|
|
266
|
+
return;
|
|
267
|
+
if (!this.wavesurfer?.isPlaying())
|
|
268
|
+
return;
|
|
269
|
+
if (this.audioContext.state === 'suspended') {
|
|
270
|
+
this.audioContext.resume();
|
|
271
|
+
}
|
|
272
|
+
// Fade in
|
|
273
|
+
if (!this.isFadingIn && currentTime >= this.options.fadeInStart && currentTime <= this.options.fadeInEnd) {
|
|
274
|
+
this.isFadingIn = true;
|
|
275
|
+
// Set the initial gain (volume) to 0 (silent)
|
|
276
|
+
this.gainNode.gain.setValueAtTime(0, this.audioContext.currentTime);
|
|
277
|
+
// Set the target gain (volume) to 1 (full volume) over N seconds
|
|
278
|
+
this.gainNode.gain.linearRampToValueAtTime(this.volume, this.audioContext.currentTime + (this.options.fadeInEnd - currentTime));
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
// Fade out
|
|
282
|
+
if (!this.isFadingOut && currentTime >= this.options.fadeOutStart && currentTime <= this.options.fadeOutEnd) {
|
|
283
|
+
this.isFadingOut = true;
|
|
284
|
+
/**
|
|
285
|
+
* Set the gain at this point in time to the current volume, otherwise
|
|
286
|
+
* the audio will start fading out from the fade-in point.
|
|
287
|
+
*/
|
|
288
|
+
this.gainNode.gain.setValueAtTime(this.volume, this.audioContext.currentTime);
|
|
289
|
+
// Set the target gain (volume) to 0 (silent) over N seconds
|
|
290
|
+
this.gainNode.gain.linearRampToValueAtTime(0, this.audioContext.currentTime + (this.options.fadeOutEnd - currentTime));
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
// Reset fade in/out
|
|
294
|
+
let cancelRamp = false;
|
|
295
|
+
if (this.isFadingIn && (currentTime < this.options.fadeInStart || currentTime > this.options.fadeInEnd)) {
|
|
296
|
+
this.isFadingIn = false;
|
|
297
|
+
cancelRamp = true;
|
|
298
|
+
}
|
|
299
|
+
if (this.isFadingOut && (currentTime < this.options.fadeOutStart || currentTime >= this.options.fadeOutEnd)) {
|
|
300
|
+
this.isFadingOut = false;
|
|
301
|
+
cancelRamp = true;
|
|
302
|
+
}
|
|
303
|
+
if (cancelRamp) {
|
|
304
|
+
this.gainNode.gain.cancelScheduledValues(this.audioContext.currentTime);
|
|
305
|
+
this.setGainValue();
|
|
306
|
+
}
|
|
307
|
+
});
|
|
308
|
+
this.subscriptions.push(unsub);
|
|
309
|
+
}
|
|
310
|
+
/** Get the current audio volume */
|
|
311
|
+
getCurrentVolume() {
|
|
312
|
+
return this.gainNode ? this.gainNode.gain.value : this.volume;
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Set the fade-in start time.
|
|
316
|
+
* @param time The time (in seconds) to set the fade-in start time to
|
|
317
|
+
* @param moveFadeInEnd Whether to move the drag point to the new time (default: false)
|
|
318
|
+
*/
|
|
319
|
+
setStartTime(time, moveFadeInEnd = false) {
|
|
320
|
+
if (moveFadeInEnd) {
|
|
321
|
+
const rampLength = this.options.fadeInEnd - this.options.fadeInStart;
|
|
322
|
+
this.options.fadeInEnd = time + rampLength;
|
|
323
|
+
}
|
|
324
|
+
this.options.fadeInStart = time;
|
|
325
|
+
this.renderPolyline();
|
|
326
|
+
}
|
|
327
|
+
/** Set the fade-in end time.
|
|
328
|
+
* @param time The time (in seconds) to set the fade-in end time to
|
|
329
|
+
* @param moveFadeOutStart Whether to move the drag point to the new time (default: false)
|
|
330
|
+
*/
|
|
331
|
+
setEndTime(time, moveFadeOutStart = false) {
|
|
332
|
+
if (moveFadeOutStart) {
|
|
333
|
+
const rampLength = this.options.fadeOutEnd - this.options.fadeOutStart;
|
|
334
|
+
this.options.fadeOutStart = time - rampLength;
|
|
335
|
+
}
|
|
336
|
+
this.options.fadeOutEnd = time;
|
|
337
|
+
this.renderPolyline();
|
|
338
|
+
}
|
|
339
|
+
/** Set the volume of the audio */
|
|
340
|
+
setVolume(volume) {
|
|
341
|
+
this.volume = volume;
|
|
342
|
+
this.setGainValue();
|
|
343
|
+
this.renderPolyline();
|
|
344
|
+
this.emit('volume-change', volume);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
export default EnvelopePlugin;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.Envelope=e():t.Envelope=e()}(WaveSurfer,(()=>(()=>{"use strict";var t={284:(t,e,i)=>{i.d(e,{Z:()=>o});var s=i(139);class n extends s.Z{constructor(t){super(),this.subscriptions=[],this.options=t}onInit(){}init(t){this.wavesurfer=t,this.onInit()}destroy(){this.subscriptions.forEach((t=>t()))}}const o=n},139:(t,e,i)=>{i.d(e,{Z:()=>s});const s=class{constructor(){this.listeners={}}on(t,e){return this.listeners[t]||(this.listeners[t]=new Set),this.listeners[t].add(e),()=>this.un(t,e)}once(t,e){const i=this.on(t,e),s=this.on(t,(()=>{i(),s()}));return i}un(t,e){this.listeners[t]&&(e?this.listeners[t].delete(e):delete this.listeners[t])}unAll(){this.listeners={}}emit(t,...e){this.listeners[t]&&this.listeners[t].forEach((t=>t(...e)))}}}},e={};function i(s){var n=e[s];if(void 0!==n)return n.exports;var o=e[s]={exports:{}};return t[s](o,o.exports,i),o.exports}i.d=(t,e)=>{for(var s in e)i.o(e,s)&&!i.o(t,s)&&Object.defineProperty(t,s,{enumerable:!0,get:e[s]})},i.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e);var s={};return(()=>{i.d(s,{default:()=>a});var t=i(284),e=i(139);const n={fadeInStart:0,fadeOutEnd:0,fadeInEnd:0,fadeOutStart:0,lineWidth:4,lineColor:"rgba(0, 0, 255, 0.5)",dragPointSize:10,dragPointFill:"rgba(255, 255, 255, 0.8)",dragPointStroke:"rgba(255, 255, 255, 0.8)"};class o extends e.Z{constructor(t,e){super(),this.top=0,this.padding=t.dragPointSize/2+1;const i=document.createElementNS("http://www.w3.org/2000/svg","svg");i.setAttribute("width","100%"),i.setAttribute("height","100%"),i.setAttribute("viewBox","0 0 0 0"),i.setAttribute("preserveAspectRatio","none"),i.setAttribute("style","position: absolute; left: 0; top: 0; z-index: 4; pointer-events: none;"),i.setAttribute("part","envelope"),this.svg=i;const s=document.createElementNS("http://www.w3.org/2000/svg","polyline");s.setAttribute("points","0,0 0,0 0,0 0,0"),s.setAttribute("stroke",t.lineColor),s.setAttribute("stroke-width",t.lineWidth),s.setAttribute("fill","none"),s.setAttribute("style","pointer-events: none;"),s.setAttribute("part","polyline"),i.appendChild(s);const n=document.createElementNS("http://www.w3.org/2000/svg","line");n.setAttribute("stroke","transparent"),n.setAttribute("stroke-width",(3*t.lineWidth).toString()),n.setAttribute("style","cursor: ns-resize; pointer-events: all;"),n.setAttribute("part","line"),i.appendChild(n),[0,1].forEach((()=>{const e=document.createElementNS("http://www.w3.org/2000/svg","circle");e.setAttribute("r",(t.dragPointSize/2).toString()),e.setAttribute("fill",t.dragPointFill),e.setAttribute("stroke",t.dragPointStroke||t.dragPointFill),e.setAttribute("stroke-width","2"),e.setAttribute("style","cursor: ew-resize; pointer-events: all;"),e.setAttribute("part","circle"),i.appendChild(e)})),e.appendChild(i);{const t=t=>{const e=this.top+t,{height:s}=i.viewBox.baseVal;if(e<-.5||e>s)return;const n=Math.min(1,Math.max(0,(s-e)/s));this.emit("line-move",n)},e=(t,e)=>{const n=s.points.getItem(t).x+e,{width:o}=i.viewBox.baseVal;this.emit("point-move",t,n/o)};this.makeDraggable(n,((e,i)=>t(i)));const o=this.svg.querySelectorAll("circle");Array.from(o).forEach(((t,i)=>{this.makeDraggable(t,(t=>e(i+1,t)))}))}}makeDraggable(t,e){t.addEventListener("click",(t=>{t.preventDefault(),t.stopPropagation()})),t.addEventListener("mousedown",(t=>{t.preventDefault(),t.stopPropagation();let i=t.clientX,s=t.clientY;const n=t=>{const n=t.clientX-i,o=t.clientY-s;i=t.clientX,s=t.clientY,e(n,o)},o=()=>{document.removeEventListener("mousemove",n),document.removeEventListener("mouseup",o)};document.addEventListener("mousemove",n),document.addEventListener("mouseup",o)}))}update({x1:t,x2:e,x3:i,x4:s,y:n}){const o=this.svg.clientWidth,r=this.svg.clientHeight;this.top=r-n*r;const a=Math.max(this.padding,Math.min(this.top,r-this.padding));this.svg.setAttribute("viewBox",`0 0 ${o} ${r}`);const u=this.svg.querySelector("polyline"),{points:h}=u;h.getItem(0).x=t*o,h.getItem(0).y=r,h.getItem(1).x=e*o,h.getItem(1).y=a,h.getItem(2).x=i*o,h.getItem(2).y=a,h.getItem(3).x=s*o,h.getItem(3).y=r;const d=this.svg.querySelector("line");d.setAttribute("x1",h.getItem(1).x.toString()),d.setAttribute("x2",h.getItem(2).x.toString()),d.setAttribute("y1",a.toString()),d.setAttribute("y2",a.toString());const l=this.svg.querySelectorAll("circle");Array.from(l).forEach(((t,e)=>{const i=h.getItem(e+1);t.setAttribute("cx",i.x.toString()),t.setAttribute("cy",i.y.toString())}))}destroy(){this.svg.remove()}}class r extends t.Z{constructor(t){super(t),this.polyline=null,this.audioContext=null,this.gainNode=null,this.volume=1,this.isFadingIn=!1,this.isFadingOut=!1,this.naturalVolumeExponent=1.5,this.options=Object.assign({},n,t),this.options.lineColor=this.options.lineColor||n.lineColor,this.options.dragPointFill=this.options.dragPointFill||n.dragPointFill,this.options.dragPointStroke=this.options.dragPointStroke||n.dragPointStroke,this.volume=this.options.volume??1}static create(t){return new r(t)}destroy(){this.polyline?.destroy(),super.destroy()}onInit(){if(!this.wavesurfer)throw Error("WaveSurfer is not initialized");this.initWebAudio(),this.initSvg(),this.initFadeEffects(),this.subscriptions.push(this.wavesurfer.on("redraw",(()=>{const t=this.wavesurfer?.getDuration();t&&(this.options.fadeInStart=this.options.fadeInStart||0,this.options.fadeOutEnd=this.options.fadeOutEnd||t,this.options.fadeInEnd=this.options.fadeInEnd||this.options.fadeInStart,this.options.fadeOutStart=this.options.fadeOutStart||this.options.fadeOutEnd,this.renderPolyline())})))}initSvg(){if(!this.wavesurfer)return;const t=this.wavesurfer.getWrapper();this.polyline=new o(this.options,t),this.subscriptions.push(this.polyline.on("line-move",(t=>{this.setVolume(this.naturalVolume(t))})),this.polyline.on("point-move",((t,e)=>{const i=e*(this.wavesurfer?.getDuration()||0);if(1===t){if(i<this.options.fadeInStart||i>this.options.fadeOutStart)return;this.options.fadeInEnd=i,this.emit("fade-in-change",i)}else if(2===t){if(i>this.options.fadeOutEnd||i<this.options.fadeInEnd)return;this.options.fadeOutStart=i,this.emit("fade-out-change",i)}this.renderPolyline()})))}renderPolyline(){if(!this.polyline||!this.wavesurfer)return;const t=this.wavesurfer.getDuration();t&&this.polyline.update({x1:this.options.fadeInStart/t,x2:this.options.fadeInEnd/t,x3:this.options.fadeOutStart/t,x4:this.options.fadeOutEnd/t,y:this.invertNaturalVolume(this.volume)})}initWebAudio(){const t=this.wavesurfer?.getMediaElement();if(!t)return null;this.volume=this.options.volume??t.volume;const e=new window.AudioContext;this.gainNode=e.createGain(),this.setGainValue(),e.createMediaElementSource(t).connect(this.gainNode),this.gainNode.connect(e.destination),this.audioContext=e}invertNaturalVolume(t){return Math.pow((t-1e-4)/.9999,1/this.naturalVolumeExponent)}naturalVolume(t){return 1e-4+.9999*Math.pow(t,this.naturalVolumeExponent)}setGainValue(){this.gainNode&&(this.gainNode.gain.value=this.volume)}initFadeEffects(){if(!this.audioContext||!this.wavesurfer)return;const t=this.wavesurfer.on("timeupdate",(t=>{if(!this.audioContext||!this.gainNode)return;if(!this.wavesurfer?.isPlaying())return;if("suspended"===this.audioContext.state&&this.audioContext.resume(),!this.isFadingIn&&t>=this.options.fadeInStart&&t<=this.options.fadeInEnd)return this.isFadingIn=!0,this.gainNode.gain.setValueAtTime(0,this.audioContext.currentTime),void this.gainNode.gain.linearRampToValueAtTime(this.volume,this.audioContext.currentTime+(this.options.fadeInEnd-t));if(!this.isFadingOut&&t>=this.options.fadeOutStart&&t<=this.options.fadeOutEnd)return this.isFadingOut=!0,this.gainNode.gain.setValueAtTime(this.volume,this.audioContext.currentTime),void this.gainNode.gain.linearRampToValueAtTime(0,this.audioContext.currentTime+(this.options.fadeOutEnd-t));let e=!1;this.isFadingIn&&(t<this.options.fadeInStart||t>this.options.fadeInEnd)&&(this.isFadingIn=!1,e=!0),this.isFadingOut&&(t<this.options.fadeOutStart||t>=this.options.fadeOutEnd)&&(this.isFadingOut=!1,e=!0),e&&(this.gainNode.gain.cancelScheduledValues(this.audioContext.currentTime),this.setGainValue())}));this.subscriptions.push(t)}getCurrentVolume(){return this.gainNode?this.gainNode.gain.value:this.volume}setStartTime(t,e=!1){if(e){const e=this.options.fadeInEnd-this.options.fadeInStart;this.options.fadeInEnd=t+e}this.options.fadeInStart=t,this.renderPolyline()}setEndTime(t,e=!1){if(e){const e=this.options.fadeOutEnd-this.options.fadeOutStart;this.options.fadeOutStart=t-e}this.options.fadeOutEnd=t,this.renderPolyline()}setVolume(t){this.volume=t,this.setGainValue(),this.renderPolyline(),this.emit("volume-change",t)}}const a=r})(),s.default})()));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.Envelope=e():t.Envelope=e()}(WaveSurfer,(()=>(()=>{"use strict";var t={284:(t,e,i)=>{i.d(e,{Z:()=>o});var s=i(139);class n extends s.Z{constructor(t){super(),this.subscriptions=[],this.options=t}onInit(){}init(t){this.wavesurfer=t,this.onInit()}destroy(){this.subscriptions.forEach((t=>t()))}}const o=n},139:(t,e,i)=>{i.d(e,{Z:()=>s});const s=class{constructor(){this.listeners={}}on(t,e){return this.listeners[t]||(this.listeners[t]=new Set),this.listeners[t].add(e),()=>this.un(t,e)}once(t,e){const i=this.on(t,e),s=this.on(t,(()=>{i(),s()}));return i}un(t,e){this.listeners[t]&&(e?this.listeners[t].delete(e):delete this.listeners[t])}unAll(){this.listeners={}}emit(t,...e){this.listeners[t]&&this.listeners[t].forEach((t=>t(...e)))}}}},e={};function i(s){var n=e[s];if(void 0!==n)return n.exports;var o=e[s]={exports:{}};return t[s](o,o.exports,i),o.exports}i.d=(t,e)=>{for(var s in e)i.o(e,s)&&!i.o(t,s)&&Object.defineProperty(t,s,{enumerable:!0,get:e[s]})},i.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e);var s={};return(()=>{i.d(s,{default:()=>a});var t=i(284),e=i(139);const n={fadeInStart:0,fadeOutEnd:0,fadeInEnd:0,fadeOutStart:0,lineWidth:4,lineColor:"rgba(0, 0, 255, 0.5)",dragPointSize:10,dragPointFill:"rgba(255, 255, 255, 0.8)",dragPointStroke:"rgba(255, 255, 255, 0.8)"};class o extends e.Z{constructor(t,e){super(),this.top=0,this.padding=t.dragPointSize/2+1;const i=document.createElementNS("http://www.w3.org/2000/svg","svg");i.setAttribute("width","100%"),i.setAttribute("height","100%"),i.setAttribute("viewBox","0 0 0 0"),i.setAttribute("preserveAspectRatio","none"),i.setAttribute("style","position: absolute; left: 0; top: 0; z-index: 4; pointer-events: none;"),i.setAttribute("part","envelope"),this.svg=i;const s=document.createElementNS("http://www.w3.org/2000/svg","polyline");s.setAttribute("points","0,0 0,0 0,0 0,0"),s.setAttribute("stroke",t.lineColor),s.setAttribute("stroke-width",t.lineWidth),s.setAttribute("fill","none"),s.setAttribute("style","pointer-events: none;"),s.setAttribute("part","polyline"),i.appendChild(s);const n=document.createElementNS("http://www.w3.org/2000/svg","line");n.setAttribute("stroke","transparent"),n.setAttribute("stroke-width",(3*t.lineWidth).toString()),n.setAttribute("style","cursor: ns-resize; pointer-events: all;"),n.setAttribute("part","line"),i.appendChild(n),[0,1].forEach((()=>{const e=document.createElementNS("http://www.w3.org/2000/svg","circle");e.setAttribute("r",(t.dragPointSize/2).toString()),e.setAttribute("fill",t.dragPointFill),e.setAttribute("stroke",t.dragPointStroke||t.dragPointFill),e.setAttribute("stroke-width","2"),e.setAttribute("style","cursor: ew-resize; pointer-events: all;"),e.setAttribute("part","circle"),i.appendChild(e)})),e.appendChild(i);{const t=t=>{const e=this.top+t,{height:s}=i.viewBox.baseVal;if(e<-.5||e>s)return;const n=Math.min(1,Math.max(0,(s-e)/s));this.emit("line-move",n)},e=(t,e)=>{const n=s.points.getItem(t).x+e,{width:o}=i.viewBox.baseVal;this.emit("point-move",t,n/o)};this.makeDraggable(n,((e,i)=>t(i)));const o=this.svg.querySelectorAll("circle");Array.from(o).forEach(((t,i)=>{this.makeDraggable(t,(t=>e(i+1,t)))}))}}makeDraggable(t,e){t.addEventListener("click",(t=>{t.preventDefault(),t.stopPropagation()})),t.addEventListener("mousedown",(t=>{t.preventDefault(),t.stopPropagation();let i=t.clientX,s=t.clientY;const n=t=>{const n=t.clientX-i,o=t.clientY-s;i=t.clientX,s=t.clientY,e(n,o)},o=()=>{document.removeEventListener("mousemove",n),document.removeEventListener("mouseup",o)};document.addEventListener("mousemove",n),document.addEventListener("mouseup",o)}))}update({x1:t,x2:e,x3:i,x4:s,y:n}){const o=this.svg.clientWidth,r=this.svg.clientHeight;this.top=r-n*r;const a=Math.max(this.padding,Math.min(this.top,r-this.padding));this.svg.setAttribute("viewBox",`0 0 ${o} ${r}`);const u=this.svg.querySelector("polyline"),{points:h}=u;h.getItem(0).x=t*o,h.getItem(0).y=r,h.getItem(1).x=e*o,h.getItem(1).y=a,h.getItem(2).x=i*o,h.getItem(2).y=a,h.getItem(3).x=s*o,h.getItem(3).y=r;const d=this.svg.querySelector("line");d.setAttribute("x1",h.getItem(1).x.toString()),d.setAttribute("x2",h.getItem(2).x.toString()),d.setAttribute("y1",a.toString()),d.setAttribute("y2",a.toString());const l=this.svg.querySelectorAll("circle");Array.from(l).forEach(((t,e)=>{const i=h.getItem(e+1);t.setAttribute("cx",i.x.toString()),t.setAttribute("cy",i.y.toString())}))}destroy(){this.svg.remove()}}class r extends t.Z{constructor(t){super(t),this.polyline=null,this.audioContext=null,this.gainNode=null,this.volume=1,this.isFadingIn=!1,this.isFadingOut=!1,this.naturalVolumeExponent=1.5,this.options=Object.assign({},n,t),this.options.lineColor=this.options.lineColor||n.lineColor,this.options.dragPointFill=this.options.dragPointFill||n.dragPointFill,this.options.dragPointStroke=this.options.dragPointStroke||n.dragPointStroke,this.volume=this.options.volume??1}static create(t){return new r(t)}destroy(){this.polyline?.destroy(),super.destroy()}onInit(){if(!this.wavesurfer)throw Error("WaveSurfer is not initialized");this.initWebAudio(),this.initSvg(),this.initFadeEffects(),this.subscriptions.push(this.wavesurfer.on("redraw",(()=>{const t=this.wavesurfer?.getDuration();t&&(this.options.fadeInStart=this.options.fadeInStart||0,this.options.fadeOutEnd=this.options.fadeOutEnd||t,this.options.fadeInEnd=this.options.fadeInEnd||this.options.fadeInStart,this.options.fadeOutStart=this.options.fadeOutStart||this.options.fadeOutEnd,this.renderPolyline())})))}initSvg(){if(!this.wavesurfer)return;const t=this.wavesurfer.getWrapper();this.polyline=new o(this.options,t),this.subscriptions.push(this.polyline.on("line-move",(t=>{this.setVolume(this.naturalVolume(t))})),this.polyline.on("point-move",((t,e)=>{const i=e*(this.wavesurfer?.getDuration()||0);if(1===t){if(i<this.options.fadeInStart||i>this.options.fadeOutStart)return;this.options.fadeInEnd=i,this.emit("fade-in-change",i)}else if(2===t){if(i>this.options.fadeOutEnd||i<this.options.fadeInEnd)return;this.options.fadeOutStart=i,this.emit("fade-out-change",i)}this.renderPolyline()})))}renderPolyline(){if(!this.polyline||!this.wavesurfer)return;const t=this.wavesurfer.getDuration();t&&this.polyline.update({x1:this.options.fadeInStart/t,x2:this.options.fadeInEnd/t,x3:this.options.fadeOutStart/t,x4:this.options.fadeOutEnd/t,y:this.invertNaturalVolume(this.volume)})}initWebAudio(){const t=this.wavesurfer?.getMediaElement();if(!t)return null;this.volume=this.options.volume??t.volume;const e=new window.AudioContext;this.gainNode=e.createGain(),this.setGainValue(),e.createMediaElementSource(t).connect(this.gainNode),this.gainNode.connect(e.destination),this.audioContext=e}invertNaturalVolume(t){return Math.pow((t-1e-4)/.9999,1/this.naturalVolumeExponent)}naturalVolume(t){return 1e-4+.9999*Math.pow(t,this.naturalVolumeExponent)}setGainValue(){this.gainNode&&(this.gainNode.gain.value=this.volume)}initFadeEffects(){if(!this.audioContext||!this.wavesurfer)return;const t=this.wavesurfer.on("timeupdate",(t=>{if(!this.audioContext||!this.gainNode)return;if(!this.wavesurfer?.isPlaying())return;if("suspended"===this.audioContext.state&&this.audioContext.resume(),!this.isFadingIn&&t>=this.options.fadeInStart&&t<=this.options.fadeInEnd)return this.isFadingIn=!0,this.gainNode.gain.setValueAtTime(0,this.audioContext.currentTime),void this.gainNode.gain.linearRampToValueAtTime(this.volume,this.audioContext.currentTime+(this.options.fadeInEnd-t));if(!this.isFadingOut&&t>=this.options.fadeOutStart&&t<=this.options.fadeOutEnd)return this.isFadingOut=!0,this.gainNode.gain.setValueAtTime(this.volume,this.audioContext.currentTime),void this.gainNode.gain.linearRampToValueAtTime(0,this.audioContext.currentTime+(this.options.fadeOutEnd-t));let e=!1;this.isFadingIn&&(t<this.options.fadeInStart||t>this.options.fadeInEnd)&&(this.isFadingIn=!1,e=!0),this.isFadingOut&&(t<this.options.fadeOutStart||t>=this.options.fadeOutEnd)&&(this.isFadingOut=!1,e=!0),e&&(this.gainNode.gain.cancelScheduledValues(this.audioContext.currentTime),this.setGainValue())}));this.subscriptions.push(t)}getCurrentVolume(){return this.gainNode?this.gainNode.gain.value:this.volume}setStartTime(t,e=!1){if(e){const e=this.options.fadeInEnd-this.options.fadeInStart;this.options.fadeInEnd=t+e}this.options.fadeInStart=t,this.renderPolyline()}setEndTime(t,e=!1){if(e){const e=this.options.fadeOutEnd-this.options.fadeOutStart;this.options.fadeOutStart=t-e}this.options.fadeOutEnd=t,this.renderPolyline()}setVolume(t){this.volume=t,this.setGainValue(),this.renderPolyline(),this.emit("volume-change",t)}}const a=r})(),s.default})()));
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimap is a tiny copy of the main waveform serving as a navigation tool.
|
|
3
|
+
*/
|
|
4
|
+
import BasePlugin from '../base-plugin.js';
|
|
5
|
+
import { type WaveSurferOptions } from '../wavesurfer.js';
|
|
6
|
+
export type MinimapPluginOptions = {
|
|
7
|
+
overlayColor?: string;
|
|
8
|
+
insertPosition?: InsertPosition;
|
|
9
|
+
} & WaveSurferOptions;
|
|
10
|
+
declare const defaultOptions: {
|
|
11
|
+
height: number;
|
|
12
|
+
overlayColor: string;
|
|
13
|
+
insertPosition: string;
|
|
14
|
+
};
|
|
15
|
+
export type MinimapPluginEvents = {
|
|
16
|
+
ready: [];
|
|
17
|
+
interaction: [];
|
|
18
|
+
};
|
|
19
|
+
declare class MinimapPlugin extends BasePlugin<MinimapPluginEvents, MinimapPluginOptions> {
|
|
20
|
+
protected options: MinimapPluginOptions & typeof defaultOptions;
|
|
21
|
+
private minimapWrapper;
|
|
22
|
+
private miniWavesurfer;
|
|
23
|
+
private overlay;
|
|
24
|
+
private container;
|
|
25
|
+
constructor(options: MinimapPluginOptions);
|
|
26
|
+
static create(options: MinimapPluginOptions): MinimapPlugin;
|
|
27
|
+
/** Called by wavesurfer, don't call manually */
|
|
28
|
+
onInit(): void;
|
|
29
|
+
private initMinimapWrapper;
|
|
30
|
+
private initOverlay;
|
|
31
|
+
private initMinimap;
|
|
32
|
+
private getOverlayWidth;
|
|
33
|
+
private onRedraw;
|
|
34
|
+
private onScroll;
|
|
35
|
+
private initWaveSurferEvents;
|
|
36
|
+
/** Unmount */
|
|
37
|
+
destroy(): void;
|
|
38
|
+
}
|
|
39
|
+
export default MinimapPlugin;
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimap is a tiny copy of the main waveform serving as a navigation tool.
|
|
3
|
+
*/
|
|
4
|
+
import BasePlugin from '../base-plugin.js';
|
|
5
|
+
import WaveSurfer from '../wavesurfer.js';
|
|
6
|
+
const defaultOptions = {
|
|
7
|
+
height: 50,
|
|
8
|
+
overlayColor: 'rgba(100, 100, 100, 0.1)',
|
|
9
|
+
insertPosition: 'afterend',
|
|
10
|
+
};
|
|
11
|
+
class MinimapPlugin extends BasePlugin {
|
|
12
|
+
constructor(options) {
|
|
13
|
+
super(options);
|
|
14
|
+
this.miniWavesurfer = null;
|
|
15
|
+
this.container = null;
|
|
16
|
+
this.options = Object.assign({}, defaultOptions, options);
|
|
17
|
+
this.minimapWrapper = this.initMinimapWrapper();
|
|
18
|
+
this.overlay = this.initOverlay();
|
|
19
|
+
}
|
|
20
|
+
static create(options) {
|
|
21
|
+
return new MinimapPlugin(options);
|
|
22
|
+
}
|
|
23
|
+
/** Called by wavesurfer, don't call manually */
|
|
24
|
+
onInit() {
|
|
25
|
+
if (!this.wavesurfer) {
|
|
26
|
+
throw Error('WaveSurfer is not initialized');
|
|
27
|
+
}
|
|
28
|
+
if (this.options.container) {
|
|
29
|
+
if (typeof this.options.container === 'string') {
|
|
30
|
+
this.container = document.querySelector(this.options.container);
|
|
31
|
+
}
|
|
32
|
+
else if (this.options.container instanceof HTMLElement) {
|
|
33
|
+
this.container = this.options.container;
|
|
34
|
+
}
|
|
35
|
+
this.container?.appendChild(this.minimapWrapper);
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
this.container = this.wavesurfer.getWrapper().parentElement;
|
|
39
|
+
this.container?.insertAdjacentElement(this.options.insertPosition, this.minimapWrapper);
|
|
40
|
+
}
|
|
41
|
+
this.initWaveSurferEvents();
|
|
42
|
+
}
|
|
43
|
+
initMinimapWrapper() {
|
|
44
|
+
const div = document.createElement('div');
|
|
45
|
+
div.style.position = 'relative';
|
|
46
|
+
div.setAttribute('part', 'minimap');
|
|
47
|
+
return div;
|
|
48
|
+
}
|
|
49
|
+
initOverlay() {
|
|
50
|
+
const div = document.createElement('div');
|
|
51
|
+
div.setAttribute('style', 'position: absolute; z-index: 2; left: 0; top: 0; bottom: 0; transition: left 100ms ease-out; pointer-events: none;');
|
|
52
|
+
div.style.backgroundColor = this.options.overlayColor;
|
|
53
|
+
this.minimapWrapper.appendChild(div);
|
|
54
|
+
return div;
|
|
55
|
+
}
|
|
56
|
+
initMinimap() {
|
|
57
|
+
if (this.miniWavesurfer) {
|
|
58
|
+
this.miniWavesurfer.destroy();
|
|
59
|
+
this.miniWavesurfer = null;
|
|
60
|
+
}
|
|
61
|
+
if (!this.wavesurfer)
|
|
62
|
+
return;
|
|
63
|
+
const data = this.wavesurfer.getDecodedData();
|
|
64
|
+
const media = this.wavesurfer.getMediaElement();
|
|
65
|
+
if (!data || !media)
|
|
66
|
+
return;
|
|
67
|
+
this.miniWavesurfer = WaveSurfer.create({
|
|
68
|
+
...this.options,
|
|
69
|
+
container: this.minimapWrapper,
|
|
70
|
+
minPxPerSec: 0,
|
|
71
|
+
fillParent: true,
|
|
72
|
+
media,
|
|
73
|
+
peaks: [data.getChannelData(0)],
|
|
74
|
+
duration: data.duration,
|
|
75
|
+
});
|
|
76
|
+
this.subscriptions.push(this.miniWavesurfer.on('ready', () => {
|
|
77
|
+
this.emit('ready');
|
|
78
|
+
}), this.miniWavesurfer.on('interaction', () => {
|
|
79
|
+
this.emit('interaction');
|
|
80
|
+
}));
|
|
81
|
+
}
|
|
82
|
+
getOverlayWidth() {
|
|
83
|
+
const waveformWidth = this.wavesurfer?.getWrapper().clientWidth || 1;
|
|
84
|
+
return Math.round((this.minimapWrapper.clientWidth / waveformWidth) * 100);
|
|
85
|
+
}
|
|
86
|
+
onRedraw() {
|
|
87
|
+
const overlayWidth = this.getOverlayWidth();
|
|
88
|
+
this.overlay.style.width = `${overlayWidth}%`;
|
|
89
|
+
}
|
|
90
|
+
onScroll(startTime) {
|
|
91
|
+
if (!this.wavesurfer)
|
|
92
|
+
return;
|
|
93
|
+
const duration = this.wavesurfer.getDuration();
|
|
94
|
+
this.overlay.style.left = `${(startTime / duration) * 100}%`;
|
|
95
|
+
}
|
|
96
|
+
initWaveSurferEvents() {
|
|
97
|
+
if (!this.wavesurfer)
|
|
98
|
+
return;
|
|
99
|
+
this.subscriptions.push(this.wavesurfer.on('decode', () => {
|
|
100
|
+
this.initMinimap();
|
|
101
|
+
}), this.wavesurfer.on('scroll', (startTime) => {
|
|
102
|
+
this.onScroll(startTime);
|
|
103
|
+
}), this.wavesurfer.on('redraw', () => {
|
|
104
|
+
this.onRedraw();
|
|
105
|
+
}));
|
|
106
|
+
}
|
|
107
|
+
/** Unmount */
|
|
108
|
+
destroy() {
|
|
109
|
+
this.miniWavesurfer?.destroy();
|
|
110
|
+
this.minimapWrapper.remove();
|
|
111
|
+
super.destroy();
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
export default MinimapPlugin;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.Minimap=e():t.Minimap=e()}(WaveSurfer,(()=>(()=>{"use strict";var t={d:(e,i)=>{for(var s in i)t.o(i,s)&&!t.o(e,s)&&Object.defineProperty(e,s,{enumerable:!0,get:i[s]})},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e)},e={};t.d(e,{default:()=>g});const i=class{constructor(){this.listeners={}}on(t,e){return this.listeners[t]||(this.listeners[t]=new Set),this.listeners[t].add(e),()=>this.un(t,e)}once(t,e){const i=this.on(t,e),s=this.on(t,(()=>{i(),s()}));return i}un(t,e){this.listeners[t]&&(e?this.listeners[t].delete(e):delete this.listeners[t])}unAll(){this.listeners={}}emit(t,...e){this.listeners[t]&&this.listeners[t].forEach((t=>t(...e)))}},s=class extends i{constructor(t){super(),this.subscriptions=[],this.options=t}onInit(){}init(t){this.wavesurfer=t,this.onInit()}destroy(){this.subscriptions.forEach((t=>t()))}},r={decode:async function(t,e){const i=new AudioContext({sampleRate:e}),s=i.decodeAudioData(t);return s.finally((()=>i.close())),s},createBuffer:function(t,e){return"number"==typeof t[0]&&(t=[t]),function(t){const e=t[0];if(e.some((t=>t>1||t<-1))){const i=e.length;let s=0;for(let t=0;t<i;t++){const i=Math.abs(e[t]);i>s&&(s=i)}for(const e of t)for(let t=0;t<i;t++)e[t]/=s}}(t),{duration:e,length:t[0].length,sampleRate:t[0].length/e,numberOfChannels:t.length,getChannelData:e=>t?.[e],copyFromChannel:AudioBuffer.prototype.copyFromChannel,copyToChannel:AudioBuffer.prototype.copyToChannel}}},n=async function(t){return fetch(t).then((t=>t.arrayBuffer()))},o=class extends i{constructor(t){super(),this.isExternalMedia=!1,t.media?(this.media=t.media,this.isExternalMedia=!0):this.media=document.createElement("audio"),t.autoplay&&(this.media.autoplay=!0),null!=t.playbackRate&&(this.media.playbackRate=t.playbackRate)}onMediaEvent(t,e,i){return this.media.addEventListener(t,e,i),()=>this.media.removeEventListener(t,e)}onceMediaEvent(t,e){return this.onMediaEvent(t,e,{once:!0})}revokeSrc(){(this.media.currentSrc||this.media.src||"").startsWith("blob:")&&URL.revokeObjectURL(this.media.currentSrc)}setSrc(t,e){if((this.media.currentSrc||this.media.src||"")===t)return;this.revokeSrc();const i=e?URL.createObjectURL(new Blob([e],{type:"audio/wav"})):t;this.media.src=i}destroy(){this.media.pause(),this.revokeSrc(),this.isExternalMedia||this.media.remove()}play(){return this.media.play()}pause(){this.media.pause()}isPlaying(){return this.media.currentTime>0&&!this.media.paused&&!this.media.ended}setTime(t){this.media.currentTime=t}getDuration(){return this.media.duration}getCurrentTime(){return this.media.currentTime}getVolume(){return this.media.volume}setVolume(t){this.media.volume=t}getMuted(){return this.media.muted}setMuted(t){this.media.muted=t}getPlaybackRate(){return this.media.playbackRate}setPlaybackRate(t,e){null!=e&&(this.media.preservesPitch=e),this.media.playbackRate=t}getMediaElement(){return this.media}setSinkId(t){return this.media.setSinkId(t)}};class a extends i{constructor(t,e){if(super(),this.options={height:0},this.timeout=null,this.isScrolling=!1,this.audioData=null,this.resizeObserver=null,this.isDragging=!1,this.options={...e},"string"==typeof t&&(t=document.querySelector(t)),!t)throw new Error("Container not found");const[i,s]=this.initHtml();t.appendChild(i),this.container=i,this.scrollContainer=s.querySelector(".scroll"),this.wrapper=s.querySelector(".wrapper"),this.canvasWrapper=s.querySelector(".canvases"),this.progressWrapper=s.querySelector(".progress"),this.cursor=s.querySelector(".cursor"),this.initEvents()}initEvents(){this.wrapper.addEventListener("click",(t=>{const e=this.wrapper.getBoundingClientRect(),i=(t.clientX-e.left)/e.width;this.emit("click",i)})),this.initDrag(),this.scrollContainer.addEventListener("scroll",(()=>{const{scrollLeft:t,scrollWidth:e,clientWidth:i}=this.scrollContainer,s=t/e,r=(t+i)/e;this.emit("scroll",s,r)})),this.resizeObserver=new ResizeObserver((()=>{this.delay((()=>this.reRender()),100)})),this.resizeObserver.observe(this.scrollContainer)}initDrag(){this.wrapper.addEventListener("mousedown",(t=>{const e=t.clientX,i=t=>{if(Math.abs(t.clientX-e)>=5){this.isDragging=!0;const e=this.wrapper.getBoundingClientRect();this.emit("drag",Math.max(0,Math.min(1,(t.clientX-e.left)/e.width)))}},s=()=>{document.removeEventListener("mousemove",i),document.removeEventListener("mouseup",s),this.isDragging=!1};document.addEventListener("mousemove",i),document.addEventListener("mouseup",s)}))}initHtml(){const t=document.createElement("div"),e=t.attachShadow({mode:"open"});return e.innerHTML=`\n <style>\n :host {\n user-select: none;\n }\n :host .scroll {\n overflow-x: auto;\n overflow-y: hidden;\n width: 100%;\n position: relative;\n }\n :host .noScrollbar {\n scrollbar-color: transparent;\n scrollbar-width: none;\n }\n :host .noScrollbar::-webkit-scrollbar {\n display: none;\n -webkit-appearance: none;\n }\n :host .wrapper {\n position: relative;\n overflow: visible;\n z-index: 2;\n }\n :host .canvases {\n position: relative;\n height: ${this.options.height}px;\n }\n :host canvas {\n display: block;\n position: absolute;\n top: 0;\n image-rendering: pixelated;\n height: ${this.options.height}px;\n }\n :host .progress {\n pointer-events: none;\n position: absolute;\n z-index: 2;\n top: 0;\n left: 0;\n width: 0;\n height: 100%;\n overflow: hidden;\n }\n :host .cursor {\n pointer-events: none;\n position: absolute;\n z-index: 2;\n top: 0;\n left: 0;\n height: 100%;\n border-radius: 2px;\n width: ${this.options.cursorWidth}px;\n background-color: ${this.options.cursorColor||this.options.progressColor};\n }\n </style>\n\n <div class="scroll" part="scroll">\n <div class="wrapper">\n <div class="canvases"></div>\n <div class="progress"></div>\n <div class="cursor" part="cursor"></div>\n </div>\n </div>\n `,[t,e]}setOptions(t){this.options=t,this.reRender()}getWrapper(){return this.wrapper}getScroll(){return this.scrollContainer.scrollLeft}destroy(){this.container.remove(),this.resizeObserver?.disconnect()}delay(t,e=10){return this.timeout&&clearTimeout(this.timeout),new Promise((i=>{this.timeout=setTimeout((()=>{i(t())}),e)}))}async renderPeaks(t,e,i,s){const r=null==this.options.barWidth||isNaN(this.options.barWidth)?1:this.options.barWidth*s,n=null==this.options.barGap||isNaN(this.options.barGap)?this.options.barWidth?r/2:0:this.options.barGap*s,o=this.options.barRadius||0,h=this.options.barHeight||1,l=t.getChannelData(0),c=l.length,d=Math.floor(e/(r+n))/c,p=i/2,u=1===t.numberOfChannels,m=u?l:t.getChannelData(1),g=u&&m.some((t=>t<0)),v=(t,i)=>{let a=0,u=0,v=0;const f=document.createElement("canvas");f.width=Math.round(e*(i-t)/c),f.height=this.options.height,f.style.width=`${Math.floor(f.width/s)}px`,f.style.height=`${this.options.height}px`,f.style.left=`${Math.floor(t*e/s/c)}px`,this.canvasWrapper.appendChild(f);const y=f.getContext("2d",{desynchronized:!0});y.beginPath(),y.fillStyle=this.options.waveColor??"",y.roundRect||(y.roundRect=y.fillRect);for(let e=t;e<i;e++){const i=Math.round((e-t)*d);if(i>a){const t=Math.round(u*p*h),e=Math.round(v*p*h);y.roundRect(a*(r+n),p-t,r,t+(e||1),o),a=i,u=0,v=0}const s=g?l[e]:Math.abs(l[e]),c=g?m[e]:Math.abs(m[e]);s>u&&(u=s),(g?c<-v:c>v)&&(v=c<0?-c:c)}y.fill(),y.closePath();const b=f.cloneNode();this.progressWrapper.appendChild(b);const w=b.getContext("2d",{desynchronized:!0});f.width>0&&f.height>0&&w.drawImage(f,0,0),w.globalCompositeOperation="source-in",w.fillStyle=this.options.progressColor??"",w.fillRect(0,0,f.width,f.height)};this.canvasWrapper.innerHTML="",this.progressWrapper.innerHTML="";const{scrollLeft:f,scrollWidth:y,clientWidth:b}=this.scrollContainer,w=c/y;let W=Math.min(a.MAX_CANVAS_WIDTH,b);W-=W%((r+n)/s);const C=Math.floor(Math.abs(f)*w),E=Math.ceil(C+W*w);v(C,E);const M=E-C;for(let t=E;t<c;t+=M)await this.delay((()=>{v(t,Math.min(c,t+M))}));for(let t=C-1;t>=0;t-=M)await this.delay((()=>{v(Math.max(0,t-M),t)}))}render(t){const e=window.devicePixelRatio||1,i=this.scrollContainer.clientWidth,s=Math.ceil(t.duration*(this.options.minPxPerSec||0));this.isScrolling=s>i;const r=this.options.fillParent&&!this.isScrolling,n=(r?i:s)*e,{height:o}=this.options;this.wrapper.style.width=r?"100%":`${s}px`,this.scrollContainer.style.overflowX=this.isScrolling?"auto":"hidden",this.scrollContainer.classList.toggle("noScrollbar",!!this.options.hideScrollbar),this.cursor.style.backgroundColor=`${this.options.cursorColor||this.options.progressColor}`,this.cursor.style.width=`${this.options.cursorWidth}px`,this.canvasWrapper.style.height=`${this.options.height}px`,this.renderPeaks(t,n,o,e),this.audioData=t,this.emit("render")}reRender(){if(!this.audioData)return;const t=this.progressWrapper.clientWidth;this.render(this.audioData);const e=this.progressWrapper.clientWidth;this.scrollContainer.scrollLeft+=e-t}zoom(t){this.options.minPxPerSec=t,this.reRender()}scrollIntoView(t,e=!1){const{clientWidth:i,scrollLeft:s,scrollWidth:r}=this.scrollContainer,n=r*t,o=i/2;if(n>s+(e&&this.options.autoCenter&&!this.isDragging?o:i)||n<s)if(this.options.autoCenter&&!this.isDragging){const t=o/20;n-(s+o)>=t&&n<s+i?this.scrollContainer.scrollLeft+=t:this.scrollContainer.scrollLeft=n-o}else if(this.isDragging){const t=10;this.scrollContainer.scrollLeft=n<s?n-t:n-i+t}else this.scrollContainer.scrollLeft=n;{const{scrollLeft:t}=this.scrollContainer,e=t/r,s=(t+i)/r;this.emit("scroll",e,s)}}renderProgress(t,e){isNaN(t)||(this.progressWrapper.style.width=100*t+"%",this.cursor.style.left=100*t+"%",this.cursor.style.marginLeft=100===Math.round(100*t)?`-${this.options.cursorWidth}px`:"",this.isScrolling&&this.options.autoScroll&&this.scrollIntoView(t,e))}}a.MAX_CANVAS_WIDTH=4e3;const h=a,l=class extends i{constructor(){super(...arguments),this.unsubscribe=()=>{}}start(){this.unsubscribe=this.on("tick",(()=>{requestAnimationFrame((()=>{this.emit("tick")}))})),this.emit("tick")}stop(){this.unsubscribe()}destroy(){this.unsubscribe()}},c={height:128,waveColor:"#999",progressColor:"#555",cursorWidth:1,minPxPerSec:0,fillParent:!0,interact:!0,autoScroll:!0,autoCenter:!0,sampleRate:8e3};class d extends o{static create(t){return new d(t)}constructor(t){super({media:t.media,autoplay:t.autoplay,playbackRate:t.audioRate}),this.plugins=[],this.decodedData=null,this.canPlay=!1,this.subscriptions=[],this.options=Object.assign({},c,t),this.timer=new l,this.renderer=new h(this.options.container,this.options),this.initPlayerEvents(),this.initRendererEvents(),this.initTimerEvents(),this.initReadyEvent(),this.initPlugins();const e=this.options.url||this.options.media?.currentSrc||this.options.media?.src;e&&this.load(e,this.options.peaks,this.options.duration)}setOptions(t){this.options={...this.options,...t},this.renderer.setOptions(this.options),t.audioRate&&this.setPlaybackRate(t.audioRate)}initPlayerEvents(){this.subscriptions.push(this.onMediaEvent("timeupdate",(()=>{const t=this.getCurrentTime();this.renderer.renderProgress(t/this.getDuration(),this.isPlaying()),this.emit("timeupdate",t)})),this.onMediaEvent("play",(()=>{this.emit("play"),this.timer.start()})),this.onMediaEvent("pause",(()=>{this.emit("pause"),this.timer.stop()})),this.onMediaEvent("ended",(()=>{this.emit("finish")})),this.onMediaEvent("canplay",(()=>{this.canPlay=!0,this.emit("canplay",this.getDuration())})),this.onMediaEvent("seeking",(()=>{this.emit("seeking",this.getCurrentTime())})))}initRendererEvents(){this.subscriptions.push(this.renderer.on("click",(t=>{this.options.interact&&(this.canPlay&&this.seekTo(t),this.emit("interaction"),this.emit("click",t))})),this.renderer.on("scroll",((t,e)=>{const i=this.getDuration();this.emit("scroll",t*i,e*i)})),this.renderer.on("render",(()=>{this.emit("redraw")})));{let t;this.subscriptions.push(this.renderer.on("drag",(e=>{this.options.interact&&(this.canPlay&&(this.renderer.renderProgress(e),clearTimeout(t),t=setTimeout((()=>{this.seekTo(e)}),this.isPlaying()?0:200)),this.emit("interaction"),this.emit("drag",e))})))}}initTimerEvents(){this.subscriptions.push(this.timer.on("tick",(()=>{const t=this.getCurrentTime();this.renderer.renderProgress(t/this.getDuration(),!0),this.emit("timeupdate",t),this.emit("audioprocess",t)})))}initReadyEvent(){const t=()=>{this.decodedData&&this.canPlay&&this.emit("ready",this.getDuration())};this.subscriptions.push(this.on("decode",t),this.on("canplay",t))}initPlugins(){this.options.plugins?.length&&this.options.plugins.forEach((t=>{this.registerPlugin(t)}))}registerPlugin(t){return t.init(this),this.plugins.push(t),t}getWrapper(){return this.renderer.getWrapper()}getScroll(){return this.renderer.getScroll()}getActivePlugins(){return this.plugins}async load(t,e,i){if(this.decodedData=null,this.canPlay=!1,this.emit("load",t),e)this.setSrc(t),i||(i=await new Promise((t=>{this.onceMediaEvent("loadedmetadata",(()=>t(this.getMediaElement().duration)))}))||0),this.decodedData=r.createBuffer(e,i);else{const e=await n(t);this.setSrc(t,e),this.decodedData=await r.decode(e,this.options.sampleRate)}this.emit("decode",this.getDuration()),this.renderer.render(this.decodedData)}zoom(t){if(!this.decodedData)throw new Error("No audio loaded");this.renderer.zoom(t),this.emit("zoom",t)}getDecodedData(){return this.decodedData}getDuration(){const t=super.getDuration();return t>0&&t<1/0?t:this.decodedData?.duration||0}toggleInteraction(t){this.options.interact=t}seekTo(t){const e=this.getDuration()*t;this.setTime(e)}playPause(){return this.isPlaying()?(this.pause(),Promise.resolve()):this.play()}stop(){this.pause(),this.setTime(0)}skip(t){this.setTime(this.getCurrentTime()+t)}empty(){this.load("",[[0]],.001)}destroy(){this.emit("destroy"),this.subscriptions.forEach((t=>t())),this.plugins.forEach((t=>t.destroy())),this.timer.destroy(),this.renderer.destroy(),super.destroy()}}const p=d,u={height:50,overlayColor:"rgba(100, 100, 100, 0.1)",insertPosition:"afterend"};class m extends s{constructor(t){super(t),this.miniWavesurfer=null,this.container=null,this.options=Object.assign({},u,t),this.minimapWrapper=this.initMinimapWrapper(),this.overlay=this.initOverlay()}static create(t){return new m(t)}onInit(){if(!this.wavesurfer)throw Error("WaveSurfer is not initialized");this.options.container?("string"==typeof this.options.container?this.container=document.querySelector(this.options.container):this.options.container instanceof HTMLElement&&(this.container=this.options.container),this.container?.appendChild(this.minimapWrapper)):(this.container=this.wavesurfer.getWrapper().parentElement,this.container?.insertAdjacentElement(this.options.insertPosition,this.minimapWrapper)),this.initWaveSurferEvents()}initMinimapWrapper(){const t=document.createElement("div");return t.style.position="relative",t.setAttribute("part","minimap"),t}initOverlay(){const t=document.createElement("div");return t.setAttribute("style","position: absolute; z-index: 2; left: 0; top: 0; bottom: 0; transition: left 100ms ease-out; pointer-events: none;"),t.style.backgroundColor=this.options.overlayColor,this.minimapWrapper.appendChild(t),t}initMinimap(){if(this.miniWavesurfer&&(this.miniWavesurfer.destroy(),this.miniWavesurfer=null),!this.wavesurfer)return;const t=this.wavesurfer.getDecodedData(),e=this.wavesurfer.getMediaElement();t&&e&&(this.miniWavesurfer=p.create({...this.options,container:this.minimapWrapper,minPxPerSec:0,fillParent:!0,media:e,peaks:[t.getChannelData(0)],duration:t.duration}),this.subscriptions.push(this.miniWavesurfer.on("ready",(()=>{this.emit("ready")})),this.miniWavesurfer.on("interaction",(()=>{this.wavesurfer&&this.miniWavesurfer&&this.wavesurfer.setTime(this.miniWavesurfer.getCurrentTime()),this.emit("interaction")}))))}getOverlayWidth(){const t=this.wavesurfer?.getWrapper().clientWidth||1;return Math.round(this.minimapWrapper.clientWidth/t*100)}onRedraw(){const t=this.getOverlayWidth();this.overlay.style.width=`${t}%`}onScroll(t){if(!this.wavesurfer)return;const e=this.wavesurfer.getDuration();this.overlay.style.left=t/e*100+"%"}initWaveSurferEvents(){this.wavesurfer&&this.subscriptions.push(this.wavesurfer.on("decode",(()=>{this.initMinimap()})),this.wavesurfer.on("scroll",(t=>{this.onScroll(t)})),this.wavesurfer.on("redraw",(()=>{this.onRedraw()})))}destroy(){this.miniWavesurfer?.destroy(),this.minimapWrapper.remove(),super.destroy()}}const g=m;return e.default})()));
|