wavesurfer.js 7.0.0-alpha.9 → 7.0.0-beta.1

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.
Files changed (50) hide show
  1. package/README.md +90 -18
  2. package/dist/base-plugin.d.ts +6 -4
  3. package/dist/base-plugin.js +9 -3
  4. package/dist/decoder.d.ts +8 -7
  5. package/dist/decoder.js +43 -38
  6. package/dist/event-emitter.d.ts +16 -10
  7. package/dist/event-emitter.js +38 -16
  8. package/dist/fetcher.d.ts +4 -3
  9. package/dist/fetcher.js +5 -15
  10. package/dist/player.d.ts +31 -11
  11. package/dist/player.js +58 -31
  12. package/dist/plugins/envelope.d.ts +71 -0
  13. package/dist/plugins/envelope.js +347 -0
  14. package/dist/plugins/envelope.min.js +1 -0
  15. package/dist/plugins/minimap.d.ts +39 -0
  16. package/dist/plugins/minimap.js +117 -0
  17. package/dist/plugins/minimap.min.js +1 -0
  18. package/dist/plugins/multitrack.d.ts +85 -12
  19. package/dist/plugins/multitrack.js +331 -84
  20. package/dist/plugins/multitrack.min.js +1 -0
  21. package/dist/plugins/record.d.ts +26 -0
  22. package/dist/plugins/record.js +126 -0
  23. package/dist/plugins/record.min.js +1 -0
  24. package/dist/plugins/regions.d.ts +83 -43
  25. package/dist/plugins/regions.js +362 -192
  26. package/dist/plugins/regions.min.js +1 -0
  27. package/dist/plugins/spectrogram.d.ts +69 -0
  28. package/dist/plugins/spectrogram.js +340 -0
  29. package/dist/plugins/spectrogram.min.js +1 -0
  30. package/dist/plugins/timeline.d.ts +25 -9
  31. package/dist/plugins/timeline.js +65 -24
  32. package/dist/plugins/timeline.min.js +1 -0
  33. package/dist/renderer.d.ts +29 -13
  34. package/dist/renderer.js +280 -161
  35. package/dist/timer.d.ts +1 -1
  36. package/dist/wavesurfer.d.ts +151 -0
  37. package/dist/wavesurfer.js +241 -0
  38. package/dist/wavesurfer.min.js +1 -1
  39. package/package.json +54 -27
  40. package/dist/index.d.ts +0 -117
  41. package/dist/index.js +0 -227
  42. package/dist/player-webaudio.d.ts +0 -8
  43. package/dist/player-webaudio.js +0 -32
  44. package/dist/plugins/xmultitrack.d.ts +0 -44
  45. package/dist/plugins/xmultitrack.js +0 -260
  46. package/dist/react/useWavesurfer.d.ts +0 -5
  47. package/dist/react/useWavesurfer.js +0 -20
  48. package/dist/wavesurfer.Multitrack.min.js +0 -1
  49. package/dist/wavesurfer.Regions.min.js +0 -1
  50. package/dist/wavesurfer.Timeline.min.js +0 -1
package/dist/index.js DELETED
@@ -1,227 +0,0 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
- import Fetcher from './fetcher.js';
11
- import Decoder from './decoder.js';
12
- import Renderer from './renderer.js';
13
- import Player from './player.js';
14
- import EventEmitter from './event-emitter.js';
15
- import Timer from './timer.js';
16
- const defaultOptions = {
17
- height: 128,
18
- waveColor: '#999',
19
- progressColor: '#555',
20
- minPxPerSec: 0,
21
- fillParent: true,
22
- interactive: true,
23
- };
24
- export class WaveSurfer extends EventEmitter {
25
- /** Create a new WaveSurfer instance */
26
- static create(options) {
27
- return new WaveSurfer(options);
28
- }
29
- /** Create a new WaveSurfer instance */
30
- constructor(options) {
31
- var _a;
32
- super();
33
- this.plugins = [];
34
- this.subscriptions = [];
35
- this.decodedData = null;
36
- this.options = Object.assign({}, defaultOptions, options);
37
- this.fetcher = new Fetcher();
38
- this.decoder = new Decoder();
39
- this.timer = new Timer();
40
- this.player = new Player({
41
- media: this.options.media,
42
- autoplay: this.options.autoplay,
43
- });
44
- this.renderer = new Renderer({
45
- container: this.options.container,
46
- height: this.options.height,
47
- waveColor: this.options.waveColor,
48
- progressColor: this.options.progressColor,
49
- cursorColor: this.options.cursorColor,
50
- minPxPerSec: this.options.minPxPerSec,
51
- fillParent: this.options.fillParent,
52
- barWidth: this.options.barWidth,
53
- barGap: this.options.barGap,
54
- barRadius: this.options.barRadius,
55
- });
56
- this.initPlayerEvents();
57
- this.initRendererEvents();
58
- this.initTimerEvents();
59
- this.initReadyEvent();
60
- const url = this.options.url || ((_a = this.options.media) === null || _a === void 0 ? void 0 : _a.src);
61
- if (url) {
62
- this.load(url, this.options.peaks, this.options.duration);
63
- }
64
- }
65
- initPlayerEvents() {
66
- this.subscriptions.push(this.player.on('timeupdate', () => {
67
- const currentTime = this.getCurrentTime();
68
- this.renderer.renderProgress(currentTime / this.getDuration(), this.isPlaying());
69
- this.emit('timeupdate', { currentTime });
70
- }), this.player.on('play', () => {
71
- this.emit('play');
72
- this.timer.start();
73
- }), this.player.on('pause', () => {
74
- this.emit('pause');
75
- this.timer.stop();
76
- }), this.player.on('canplay', () => {
77
- this.emit('canplay', { duration: this.getDuration() });
78
- }), this.player.on('seeking', () => {
79
- this.emit('seeking', { currentTime: this.getCurrentTime() });
80
- }));
81
- }
82
- initRendererEvents() {
83
- // Seek on click
84
- this.subscriptions.push(this.renderer.on('click', ({ relativeX }) => {
85
- if (this.options.interactive) {
86
- const time = this.getDuration() * relativeX;
87
- this.seekTo(time);
88
- this.emit('seekClick', { currentTime: this.getCurrentTime() });
89
- }
90
- }));
91
- }
92
- initTimerEvents() {
93
- // The timer fires every 16ms for a smooth progress animation
94
- this.subscriptions.push(this.timer.on('tick', () => {
95
- const currentTime = this.getCurrentTime();
96
- this.renderer.renderProgress(currentTime / this.getDuration(), true);
97
- this.emit('timeupdate', { currentTime });
98
- }));
99
- }
100
- initReadyEvent() {
101
- let isDecoded = false;
102
- let isPlayable = false;
103
- const emitReady = () => {
104
- if (isDecoded && isPlayable) {
105
- this.emit('ready', { duration: this.getDuration() });
106
- }
107
- };
108
- this.subscriptions.push(this.on('decode', () => {
109
- isDecoded = true;
110
- emitReady();
111
- }), this.on('canplay', () => {
112
- isPlayable = true;
113
- emitReady();
114
- }), this.player.on('waiting', () => {
115
- isPlayable = false;
116
- isDecoded = false;
117
- }));
118
- }
119
- /** Load an audio file by URL, with optional pre-decoded audio data */
120
- load(url, channelData, duration) {
121
- return __awaiter(this, void 0, void 0, function* () {
122
- this.player.loadUrl(url);
123
- // Fetch and decode the audio of no pre-computed audio data is provided
124
- if (channelData == null) {
125
- const audio = yield this.fetcher.load(url);
126
- const data = yield this.decoder.decode(audio);
127
- this.decodedData = data;
128
- }
129
- else {
130
- if (!duration) {
131
- duration =
132
- (yield new Promise((resolve) => {
133
- this.player.on('canplay', () => resolve(this.getDuration()), { once: true });
134
- })) || 0;
135
- }
136
- this.decodedData = {
137
- duration,
138
- numberOfChannels: channelData.length,
139
- sampleRate: channelData[0].length / duration,
140
- getChannelData: (i) => channelData[i],
141
- };
142
- }
143
- this.renderer.render(this.decodedData);
144
- this.emit('decode', { duration: this.decodedData.duration });
145
- });
146
- }
147
- /** Zoom in or out */
148
- zoom(minPxPerSec) {
149
- if (!this.decodedData) {
150
- throw new Error('No audio loaded');
151
- }
152
- this.renderer.zoom(this.decodedData, minPxPerSec);
153
- }
154
- /** Start playing the audio */
155
- play() {
156
- this.player.play();
157
- }
158
- /** Pause the audio */
159
- pause() {
160
- this.player.pause();
161
- }
162
- /** Skip to a time position in seconds */
163
- seekTo(time) {
164
- this.player.seekTo(time);
165
- }
166
- /** Check if the audio is playing */
167
- isPlaying() {
168
- return this.player.isPlaying();
169
- }
170
- /** Get the duration of the audio in seconds */
171
- getDuration() {
172
- var _a;
173
- return this.player.getDuration() || ((_a = this.decodedData) === null || _a === void 0 ? void 0 : _a.duration) || 0;
174
- }
175
- /** Get the current audio position in seconds */
176
- getCurrentTime() {
177
- return this.player.getCurrentTime();
178
- }
179
- /** Get the audio volume */
180
- getVolume() {
181
- return this.player.getVolume();
182
- }
183
- /** Set the audio volume */
184
- setVolume(volume) {
185
- this.player.setVolume(volume);
186
- }
187
- /** Get the audio muted state */
188
- getMuted() {
189
- return this.player.getMuted();
190
- }
191
- /** Mute or unmute the audio */
192
- setMuted(muted) {
193
- this.player.setMuted(muted);
194
- }
195
- /** Get playback rate */
196
- getPlaybackRate() {
197
- return this.player.getPlaybackRate();
198
- }
199
- /** Set playback rate, with an optional parameter to NOT preserve the pitch if false */
200
- setPlaybackRate(rate, preservePitch) {
201
- this.player.setPlaybackRate(rate, preservePitch);
202
- }
203
- /** Register and initialize a plugin */
204
- registerPlugin(CustomPlugin, options) {
205
- const plugin = new CustomPlugin({
206
- wavesurfer: this,
207
- container: this.renderer.getContainer(),
208
- }, options);
209
- this.plugins.push(plugin);
210
- return plugin;
211
- }
212
- /** Get the decoded audio data */
213
- getDecodedData() {
214
- return this.decodedData;
215
- }
216
- /** Unmount wavesurfer */
217
- destroy() {
218
- this.emit('destroy');
219
- this.subscriptions.forEach((unsubscribe) => unsubscribe());
220
- this.plugins.forEach((plugin) => plugin.destroy());
221
- this.timer.destroy();
222
- this.player.destroy();
223
- this.decoder.destroy();
224
- this.renderer.destroy();
225
- }
226
- }
227
- export default WaveSurfer;
@@ -1,8 +0,0 @@
1
- import Player from './player.js';
2
- declare class WebAudioPlayer extends Player {
3
- audioCtx: AudioContext | null;
4
- sourceNode: MediaElementAudioSourceNode | null;
5
- destroy(): void;
6
- loadUrl(url: string): void;
7
- }
8
- export default WebAudioPlayer;
@@ -1,32 +0,0 @@
1
- import Player from './player.js';
2
- class WebAudioPlayer extends Player {
3
- constructor() {
4
- super(...arguments);
5
- this.audioCtx = null;
6
- this.sourceNode = null;
7
- }
8
- destroy() {
9
- var _a, _b;
10
- (_a = this.sourceNode) === null || _a === void 0 ? void 0 : _a.disconnect();
11
- this.sourceNode = null;
12
- (_b = this.audioCtx) === null || _b === void 0 ? void 0 : _b.close();
13
- this.audioCtx = null;
14
- super.destroy();
15
- }
16
- loadUrl(url) {
17
- super.loadUrl(url);
18
- if (!this.audioCtx) {
19
- this.audioCtx = new AudioContext({
20
- latencyHint: 'playback',
21
- });
22
- }
23
- if (this.sourceNode) {
24
- this.sourceNode.disconnect();
25
- }
26
- if (this.media) {
27
- this.sourceNode = this.audioCtx.createMediaElementSource(this.media);
28
- this.sourceNode.connect(this.audioCtx.destination);
29
- }
30
- }
31
- }
32
- export default WebAudioPlayer;
@@ -1,44 +0,0 @@
1
- import { type WaveSurferOptions } from '../index.js';
2
- type MultitrackTracks = Array<{
3
- id: string | number;
4
- url?: string;
5
- peaks?: WaveSurferOptions['peaks'];
6
- draggable?: boolean;
7
- startPosition: number;
8
- startCue?: number;
9
- endCue?: number;
10
- markers?: Array<{
11
- id: string | number;
12
- time: number;
13
- label?: string;
14
- color?: string;
15
- }>;
16
- }>;
17
- type MultitrackOptions = {
18
- container: HTMLElement;
19
- minPxPerSec: number;
20
- } & WaveSurferOptions;
21
- declare class MultiTrack {
22
- private tracks;
23
- private options;
24
- private audios;
25
- private wavesurfers;
26
- private durations;
27
- private currentTime;
28
- private maxDuration;
29
- private rendering;
30
- private isDragging;
31
- static create(tracks: MultitrackTracks, options: MultitrackOptions): MultiTrack;
32
- constructor(tracks: MultitrackTracks, options: MultitrackOptions);
33
- private initAudios;
34
- private initWavesurfers;
35
- private updatePosition;
36
- private onSeek;
37
- private onDrag;
38
- private findCurrentTracks;
39
- play(): void;
40
- pause(): void;
41
- isPlaying(): boolean;
42
- destroy(): void;
43
- }
44
- export default MultiTrack;
@@ -1,260 +0,0 @@
1
- import WaveSurfer from '../index.js';
2
- import RegionsPlugin from './regions.js';
3
- class MultiTrack {
4
- static create(tracks, options) {
5
- return new MultiTrack(tracks, options);
6
- }
7
- constructor(tracks, options) {
8
- this.audios = [];
9
- this.wavesurfers = [];
10
- this.durations = [];
11
- this.currentTime = 0;
12
- this.maxDuration = 0;
13
- this.isDragging = false;
14
- this.tracks = tracks.map((track) => (Object.assign(Object.assign({}, track), { startPosition: track.startPosition || 0 })));
15
- this.options = options;
16
- this.rendering = initRendering(this.tracks, this.options);
17
- this.initAudios().then((durations) => {
18
- this.durations = durations;
19
- const maxDuration = this.tracks.reduce((max, track, index) => {
20
- return Math.max(max, track.startPosition + durations[index]);
21
- }, 0);
22
- this.rendering.setMainWidth(maxDuration * this.options.minPxPerSec);
23
- this.rendering.addClickHandler((position) => {
24
- this.onSeek(position * maxDuration);
25
- });
26
- this.maxDuration = maxDuration;
27
- });
28
- this.initWavesurfers();
29
- this.rendering.containers.forEach((container, index) => {
30
- const drag = initDragging(container, (delta) => this.onDrag(index, delta));
31
- this.wavesurfers[index].once('destroy', () => {
32
- drag === null || drag === void 0 ? void 0 : drag.destroy();
33
- });
34
- });
35
- }
36
- initAudios() {
37
- const emptyTrackUrl = 'data:audio/wav;base64,UklGRigAAABXQVZFZm10IBIAAAABAAEARKwAAIhYAQACABAAAABkYXRhAgAAAAEA';
38
- this.audios = this.tracks.map((track) => new Audio(track.url || emptyTrackUrl));
39
- return Promise.all(this.audios.map((audio) => {
40
- return new Promise((resolve) => {
41
- audio.addEventListener('canplay', () => {
42
- resolve(audio.duration);
43
- }, { once: true });
44
- });
45
- }));
46
- }
47
- initWavesurfers() {
48
- const wavesurfers = this.tracks.map((track, index) => {
49
- // Create a wavesurfer instance
50
- const ws = WaveSurfer.create(Object.assign(Object.assign({}, this.options), { container: this.rendering.containers[index], media: this.audios[index], peaks: track.peaks, cursorColor: 'transparent', fillParent: false, interactive: false }));
51
- ws.on('timeupdate', ({ currentTime }) => {
52
- if (ws.isPlaying() && currentTime + track.startPosition > this.currentTime) {
53
- this.updatePosition(track.startPosition + currentTime);
54
- }
55
- });
56
- const wsRegions = ws.registerPlugin(RegionsPlugin, {
57
- draggable: false,
58
- resizable: false,
59
- dragSelection: false,
60
- });
61
- ws.once('decode', () => {
62
- // Render start and end cues
63
- if (track.startCue) {
64
- wsRegions.add(track.startCue, track.startCue, 'start');
65
- }
66
- if (track.endCue) {
67
- wsRegions.add(track.endCue, track.endCue, 'end');
68
- }
69
- // Render markers
70
- ;
71
- (track.markers || []).forEach((marker) => {
72
- wsRegions.add(marker.time, marker.time, marker.label, marker.color);
73
- });
74
- });
75
- return ws;
76
- });
77
- this.wavesurfers = wavesurfers;
78
- }
79
- updatePosition(time) {
80
- const precisionSeconds = 0.3;
81
- this.currentTime = time;
82
- this.rendering.updateCursor(time / this.maxDuration);
83
- const isPaused = !this.isPlaying();
84
- // Update the current time of each audio
85
- this.tracks.forEach((track, index) => {
86
- const audio = this.audios[index];
87
- const duration = this.durations[index];
88
- const newTime = time - track.startPosition;
89
- if (Math.abs(audio.currentTime - newTime) > precisionSeconds) {
90
- audio.currentTime = newTime;
91
- }
92
- // If the position is out of the track bounds, pause it
93
- if (isPaused || newTime < 0 || newTime > duration) {
94
- !audio.paused && audio.pause();
95
- }
96
- else if (!isPaused) {
97
- // If the position is in the track bounds, play it
98
- audio.paused && audio.play();
99
- }
100
- // Unmute if cue is reached
101
- const newVolume = newTime >= (track.startCue || 0) && newTime < (track.endCue || Infinity) ? 1 : 0;
102
- if (newVolume !== audio.volume)
103
- audio.volume = newVolume;
104
- });
105
- }
106
- onSeek(time) {
107
- if (this.isDragging)
108
- return;
109
- const wasPlaying = this.isPlaying();
110
- this.updatePosition(time);
111
- if (wasPlaying)
112
- this.play();
113
- }
114
- onDrag(index, delta) {
115
- const track = this.tracks[index];
116
- if (!track.draggable)
117
- return;
118
- this.isDragging = true;
119
- setTimeout(() => (this.isDragging = false), 300);
120
- const newTime = track.startPosition + delta * this.maxDuration;
121
- track.startPosition = newTime;
122
- this.rendering.setContainerOffsets();
123
- }
124
- findCurrentTracks() {
125
- // Find the audios at the current time
126
- const indexes = [];
127
- this.tracks.forEach((track, index) => {
128
- if (track.url &&
129
- this.currentTime >= track.startPosition &&
130
- this.currentTime < track.startPosition + this.durations[index]) {
131
- indexes.push(index);
132
- }
133
- });
134
- if (indexes.length === 0) {
135
- const minStartTime = Math.min(...this.tracks.filter((t) => t.url).map((track) => track.startPosition));
136
- indexes.push(this.tracks.findIndex((track) => track.startPosition === minStartTime));
137
- }
138
- return indexes;
139
- }
140
- play() {
141
- const indexes = this.findCurrentTracks();
142
- indexes.forEach((index) => {
143
- var _a;
144
- (_a = this.audios[index]) === null || _a === void 0 ? void 0 : _a.play();
145
- });
146
- }
147
- pause() {
148
- this.audios.forEach((audio) => audio.pause());
149
- }
150
- isPlaying() {
151
- return this.audios.some((audio) => !audio.paused);
152
- }
153
- destroy() {
154
- this.rendering.destroy();
155
- this.audios.forEach((audio) => {
156
- audio.pause();
157
- audio.src = '';
158
- });
159
- this.wavesurfers.forEach((ws) => {
160
- ws.destroy();
161
- });
162
- }
163
- }
164
- function initRendering(tracks, options) {
165
- // Create a common container for all tracks
166
- let scroll = document.createElement('div');
167
- scroll.setAttribute('style', 'width: 100%; overflow-x: scroll; overflow-y: hidden; user-select: none;');
168
- const wrapper = document.createElement('div');
169
- wrapper.style.position = 'relative';
170
- scroll.appendChild(wrapper);
171
- options.container.appendChild(scroll);
172
- // Create a common cursor
173
- const cursor = document.createElement('div');
174
- cursor.setAttribute('style', 'width: 1px; height: 100%; position: absolute; z-index: 10; top: 0; left: 0');
175
- cursor.style.backgroundColor = options.cursorColor || options.progressColor || '#000';
176
- wrapper.appendChild(cursor);
177
- // Create containers for each track
178
- const containers = tracks.map(() => {
179
- const container = document.createElement('div');
180
- container.style.width = 'fit-content';
181
- wrapper.appendChild(container);
182
- return container;
183
- });
184
- // Set the positions of each container
185
- const setContainerOffsets = () => {
186
- containers.forEach((container, i) => {
187
- const offset = (tracks[i].startPosition * options.minPxPerSec) / devicePixelRatio;
188
- container.style.transform = `translateX(${offset}px)`;
189
- if (tracks[i].draggable)
190
- container.style.cursor = 'ew-resize';
191
- });
192
- };
193
- setContainerOffsets();
194
- return {
195
- containers,
196
- // Set the start offset
197
- setContainerOffsets,
198
- // Set the container width
199
- setMainWidth: (width) => {
200
- wrapper.style.width = `${width / devicePixelRatio}px`;
201
- },
202
- // Update cursor position
203
- updateCursor: (position) => {
204
- cursor.style.left = `${Math.min(100, position * 100)}%`;
205
- },
206
- // Click to seek
207
- addClickHandler: (onClick) => {
208
- wrapper.addEventListener('click', (e) => {
209
- const rect = wrapper.getBoundingClientRect();
210
- const x = e.clientX - rect.left;
211
- const position = x / wrapper.offsetWidth;
212
- onClick(position);
213
- });
214
- },
215
- // Destroy the container
216
- destroy: () => {
217
- scroll.remove();
218
- },
219
- };
220
- }
221
- function initDragging(container, onDrag) {
222
- const wrapper = container.parentElement;
223
- if (!wrapper)
224
- return;
225
- // Dragging tracks to set position
226
- let dragStart = null;
227
- // Drag start
228
- container.addEventListener('mousedown', (e) => {
229
- const rect = wrapper.getBoundingClientRect();
230
- dragStart = e.clientX - rect.left;
231
- });
232
- // Drag end
233
- const onMouseUp = (e) => {
234
- if (dragStart != null) {
235
- e.stopPropagation();
236
- dragStart = null;
237
- }
238
- };
239
- // Drag move
240
- const onMouseMove = (e) => {
241
- if (dragStart == null)
242
- return;
243
- const rect = wrapper.getBoundingClientRect();
244
- const x = e.clientX - rect.left;
245
- const diff = x - dragStart;
246
- if (diff > 1 || diff < -1) {
247
- dragStart = x;
248
- onDrag(diff / wrapper.offsetWidth);
249
- }
250
- };
251
- document.body.addEventListener('mouseup', onMouseUp);
252
- document.body.addEventListener('mousemove', onMouseMove);
253
- return {
254
- destroy: () => {
255
- document.body.removeEventListener('mouseup', onMouseUp);
256
- document.body.removeEventListener('mousemove', onMouseMove);
257
- },
258
- };
259
- }
260
- export default MultiTrack;
@@ -1,5 +0,0 @@
1
- import WaveSurfer, { type WaveSurferOptions } from '../index.js';
2
- export declare const useWavesurfer: (containerRef: {
3
- current: HTMLElement;
4
- }, options: WaveSurferOptions) => WaveSurfer | null;
5
- export default useWavesurfer;
@@ -1,20 +0,0 @@
1
- /// <reference types="react" />
2
- import WaveSurfer from '../index.js';
3
- const { useEffect, useState } = React;
4
- // A React hook to use WaveSurfer
5
- export const useWavesurfer = (containerRef, options) => {
6
- const [wavesurfer, setWavesurfer] = useState(null);
7
- // Initialize wavesurfer when the container mounts
8
- // or any of the props change
9
- useEffect(() => {
10
- if (!containerRef.current)
11
- return;
12
- const ws = WaveSurfer.create(Object.assign(Object.assign({}, options), { container: containerRef.current }));
13
- setWavesurfer(ws);
14
- return () => {
15
- ws.destroy();
16
- };
17
- }, [options, containerRef]);
18
- return wavesurfer;
19
- };
20
- export default useWavesurfer;
@@ -1 +0,0 @@
1
- !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.Multitrack=e():t.Multitrack=e()}(WaveSurfer,(()=>(()=>{"use strict";var t={139:(t,e,i)=>{i.d(e,{Z:()=>s});const s=class{constructor(){this.eventTarget=new EventTarget}emit(t,e){const i=new CustomEvent(String(t),{detail:e});this.eventTarget.dispatchEvent(i)}on(t,e,i){const s=t=>{t instanceof CustomEvent&&e(t.detail)},n=String(t);return this.eventTarget.addEventListener(n,s,{once:i}),()=>this.eventTarget.removeEventListener(n,s)}once(t,e){return this.on(t,e,!0)}}},59:(t,e,i)=>{i.d(e,{default:()=>d});var s=i(139);class n extends s.Z{constructor(t,e){super(),this.subscriptions=[],this.wavesurfer=t.wavesurfer,this.container=t.container,this.options=e}destroy(){this.subscriptions.forEach((t=>t()))}}const o=n,r={dragSelection:!0,draggable:!0,resizable:!0},a=(t,e)=>{for(const i in e)t.style[i]=e[i]||""},h=(t,e)=>{const i=document.createElement(t);return a(i,e),i},d=class extends o{constructor(t,e){super(t,e),this.dragStart=NaN,this.regions=[],this.createdRegion=null,this.modifiedRegion=null,this.isResizingLeft=!1,this.isMoving=!1,this.handleMouseDown=t=>{(this.options.draggable||this.options.resizable||this.options.dragSelection)&&(this.dragStart=t.clientX-this.container.getBoundingClientRect().left)},this.handleMouseMove=t=>{const e=t.clientX-this.container.getBoundingClientRect().left;if(this.options.draggable&&this.modifiedRegion&&this.isMoving)return this.moveRegion(this.modifiedRegion,e-this.dragStart),void(this.dragStart=e);if(this.options.resizable&&this.modifiedRegion)this.updateRegion(this.modifiedRegion,this.isResizingLeft?e:void 0,this.isResizingLeft?void 0:e);else if(this.options.dragSelection&&!isNaN(this.dragStart)){const e=t.clientX-this.wrapper.getBoundingClientRect().left;e-this.dragStart>=10&&(this.createdRegion?this.updateRegion(this.createdRegion,this.dragStart,e):(this.container.style.pointerEvents="none",this.createdRegion=this.createRegion(this.dragStart,e)))}},this.handleMouseUp=()=>{this.createdRegion&&(this.addRegion(this.createdRegion),this.createdRegion=null),this.modifiedRegion=null,this.isMoving=!1,this.dragStart=NaN,this.container.style.pointerEvents=""},this.options=Object.assign({},r,e),this.wrapper=this.initWrapper();const i=this.wavesurfer.once("decode",(()=>{this.container.appendChild(this.wrapper)}));this.subscriptions.push(i),this.container.addEventListener("mousedown",this.handleMouseDown),document.addEventListener("mousemove",this.handleMouseMove),document.addEventListener("mouseup",this.handleMouseUp)}destroy(){this.container.removeEventListener("mousedown",this.handleMouseDown),document.removeEventListener("mousemove",this.handleMouseMove),document.removeEventListener("mouseup",this.handleMouseUp,!0),this.wrapper.remove(),super.destroy()}initWrapper(){return h("div",{position:"absolute",top:"0",left:"0",width:"100%",height:"100%",zIndex:"3",pointerEvents:"none"})}createRegionElement(t,e,i=""){const s=t===e,n=h("div",{position:"absolute",left:`${t}px`,width:e-t+"px",height:"100%",backgroundColor:s?"":"rgba(0, 0, 0, 0.1)",borderRadius:"2px",boxSizing:"border-box",borderLeft:"2px solid rgba(0, 0, 0, 0.5)",borderRight:s?"":"2px solid rgba(0, 0, 0, 0.5)",transition:"background-color 0.2s ease",cursor:this.options.draggable?"move":"",pointerEvents:"all",padding:"0.2em"});n.textContent=i;const o=h("div",{position:"absolute",left:"0",width:"6px",height:"100%",cursor:this.options.resizable?"ew-resize":"",pointerEvents:"all"});n.appendChild(o);const r=o.cloneNode();return a(r,{left:"",right:"0",borderLeft:""}),n.appendChild(r),o.addEventListener("mousedown",(t=>{this.options.resizable&&(t.stopPropagation(),this.modifiedRegion=this.regions.find((t=>t.element===n))||null,this.isResizingLeft=!0,this.isMoving=!1)})),r.addEventListener("mousedown",(t=>{this.options.resizable&&(t.stopPropagation(),this.modifiedRegion=this.regions.find((t=>t.element===n))||null,this.isResizingLeft=!1,this.isMoving=!1)})),n.addEventListener("mousedown",(()=>{this.options.draggable&&(this.modifiedRegion=this.regions.find((t=>t.element===n))||null,this.isMoving=!0)})),n.addEventListener("click",(()=>{const t=this.regions.find((t=>t.element===n));t&&this.emit("region-clicked",{region:t})})),this.wrapper.appendChild(n),n}createRegion(t,e,i=""){const s=this.wavesurfer.getDuration(),n=this.wrapper.clientWidth;return t=Math.max(0,Math.min(t,n-1)),e=Math.max(0,Math.min(e,n-1)),{element:this.createRegionElement(t,e,i),start:t,end:e,startTime:t/n*s,endTime:e/n*s,title:i}}addRegion(t){this.regions.push(t),this.emit("region-created",{region:t})}updateRegion(t,e,i){const s=this.wrapper.clientWidth;null!=e&&(e=Math.max(0,Math.min(e,s)),t.start=e,t.element.style.left=`${t.start}px`,t.startTime=e/this.wrapper.clientWidth*this.wavesurfer.getDuration()),null!=i&&(i=Math.max(0,Math.min(i,s)),t.end=i,t.element.style.width=t.end-t.start+"px",t.endTime=i/this.wrapper.clientWidth*this.wavesurfer.getDuration()),this.emit("region-updated",{region:t})}moveRegion(t,e){this.updateRegion(t,t.start+e,t.end+e)}add(t,e,i="",s=""){const n=this.wavesurfer.getDuration(),o=this.wrapper.clientWidth,r=t/n*o,a=e/n*o,h=this.createRegion(r,a,i);return this.addRegion(h),s&&this.setRegionColor(h,s),h}setRegionColor(t,e){t.element.style[t.startTime===t.endTime?"borderColor":"backgroundColor"]=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:()=>u});var t=i(139);class e extends t.Z{constructor(t){super(),this.timeout=null,this.options=t;let e=null;if("string"==typeof this.options.container?e=document.querySelector(this.options.container):this.options.container instanceof HTMLElement&&(e=this.options.container),!e)throw new Error("Container not found");const i=document.createElement("div"),s=i.attachShadow({mode:"open"});s.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 .wrapper {\n position: relative;\n width: fit-content;\n min-width: 100%;\n z-index: 2;\n }\n :host canvas {\n display: block;\n height: ${this.options.height}px;\n min-width: 100%;\n image-rendering: pixelated;\n }\n :host .progress {\n position: absolute;\n z-index: 2;\n top: 0;\n left: 0;\n pointer-events: none;\n clip-path: inset(100%);\n }\n :host .cursor {\n position: absolute;\n z-index: 3;\n top: 0;\n left: 0;\n height: 100%;\n border-right: 1px solid ${this.options.cursorColor||this.options.progressColor};\n margin-left: -1px;\n }\n </style>\n\n <div class="scroll">\n <div class="wrapper">\n <canvas></canvas>\n <canvas class="progress"></canvas>\n <div class="cursor"></div>\n </div>\n </div>\n `,this.container=i,this.scrollContainer=s.querySelector(".scroll"),this.mainCanvas=s.querySelector("canvas"),this.ctx=this.mainCanvas.getContext("2d",{desynchronized:!0}),this.progressCanvas=s.querySelector(".progress"),this.cursor=s.querySelector(".cursor"),e.appendChild(i),this.mainCanvas.addEventListener("click",(t=>{const e=this.mainCanvas.getBoundingClientRect(),i=(t.clientX-e.left)/e.width;this.emit("click",{relativeX:i})}))}getContainer(){return this.scrollContainer.querySelector(".wrapper")}destroy(){this.container.remove()}delay(t,e=100){return this.timeout&&clearTimeout(this.timeout),new Promise((i=>{this.timeout=setTimeout((()=>{i(t())}),e)}))}renderPeaks(t,e,i){var s,n,o,r,a;return n=this,o=void 0,a=function*(){const{devicePixelRatio:n}=window,{ctx:o}=this,r=null!=this.options.barWidth?this.options.barWidth*n:1,a=null!=this.options.barGap?this.options.barGap*n:this.options.barWidth?r/2:0,h=null!==(s=this.options.barRadius)&&void 0!==s?s:0,d=t[0],l=d.length,c=Math.floor(e/(r+a))/l,u=i/2,p=1===t.length,g=p?d:t[1],m=p&&g.some((t=>t<0)),v=(t,e)=>{let i=0,s=0,n=0;o.beginPath(),o.fillStyle=this.options.waveColor,o.roundRect||(o.roundRect=o.fillRect);for(let l=t;l<e;l++){const t=Math.round(l*c);if(t>i){const e=Math.round(s*u),d=Math.round(n*u);o.roundRect(i*(r+a),u-e,r,e+d||1,h),i=t,s=0,n=0}const e=m?d[l]:Math.abs(d[l]),p=m?g[l]:Math.abs(g[l]);e>s&&(s=e),(m?p<-n:p>n)&&(n=p<0?-p:p)}o.fill(),o.closePath()};o.clearRect(0,0,e,i);const{scrollLeft:f,scrollWidth:y,clientWidth:C}=this.scrollContainer,w=l/y,b=Math.floor(f*w),x=Math.ceil((f+C)*w);v(b,x),this.createProgressMask(),b>0&&(yield this.delay((()=>{v(0,b)}))),x<l&&(yield this.delay((()=>{v(x,l)}))),this.delay((()=>{this.createProgressMask()}))},new((r=void 0)||(r=Promise))((function(t,e){function i(t){try{h(a.next(t))}catch(t){e(t)}}function s(t){try{h(a.throw(t))}catch(t){e(t)}}function h(e){var n;e.done?t(e.value):(n=e.value,n instanceof r?n:new r((function(t){t(n)}))).then(i,s)}h((a=a.apply(n,o||[])).next())}))}createProgressMask(){const t=this.progressCanvas.getContext("2d",{desynchronized:!0});this.progressCanvas.width=this.mainCanvas.width,this.progressCanvas.height=this.mainCanvas.height,this.progressCanvas.style.width=this.mainCanvas.style.width,this.progressCanvas.style.height=this.mainCanvas.style.height,t.drawImage(this.mainCanvas,0,0),t.globalCompositeOperation="source-in",t.fillStyle=this.options.progressColor,t.fillRect(0,0,this.progressCanvas.width,this.progressCanvas.height)}render(t){const{devicePixelRatio:e}=window,i=this.options.fillParent?this.scrollContainer.clientWidth*e:0,s=t.duration*this.options.minPxPerSec,n=s>i,o=Math.max(1,n?s:i),{height:r}=this.options;this.mainCanvas.width=o,this.mainCanvas.height=r,this.mainCanvas.style.width=Math.floor(s/e)+"px";const a=[t.getChannelData(0)];t.numberOfChannels>1&&a.push(t.getChannelData(1)),this.renderPeaks(a,o,r)}zoom(t,e){const i=this.cursor.getBoundingClientRect().left;this.options.minPxPerSec=e,this.render(t);const s=this.cursor.getBoundingClientRect().left;this.scrollContainer.scrollLeft+=s-i}renderProgress(t,e=!1){if(this.progressCanvas.style.clipPath=`inset(0 ${100-100*t}% 0 0)`,this.cursor.style.left=100*t+"%",e){const e=this.container.clientWidth/2,i=this.mainCanvas.clientWidth;i*t>=e&&(this.scrollContainer.scrollLeft=i*t-e)}}}const n=e;class o extends t.Z{constructor(){super(...arguments),this.unsubscribe=()=>{}}start(){this.unsubscribe=this.on("tick",(()=>{requestAnimationFrame((()=>{this.emit("tick")}))})),this.emit("tick")}stop(){this.unsubscribe()}destroy(){this.unsubscribe()}}const r=o;const a={height:128,waveColor:"#999",progressColor:"#555",minPxPerSec:0,fillParent:!0,interactive:!0};class h extends t.Z{static create(t){return new h(t)}constructor(t){var e;super(),this.plugins=[],this.subscriptions=[],this.decodedData=null,this.options=Object.assign({},a,t),this.fetcher=new class{load(t){return e=this,i=void 0,n=function*(){return fetch(t).then((t=>t.arrayBuffer()))},new((s=void 0)||(s=Promise))((function(t,o){function r(t){try{h(n.next(t))}catch(t){o(t)}}function a(t){try{h(n.throw(t))}catch(t){o(t)}}function h(e){var i;e.done?t(e.value):(i=e.value,i instanceof s?i:new s((function(t){t(i)}))).then(r,a)}h((n=n.apply(e,i||[])).next())}));var e,i,s,n}},this.decoder=new class{initAudioContext(t){this.audioCtx=new AudioContext({latencyHint:"playback",sampleRate:t})}constructor(){this.audioCtx=null;try{this.initAudioContext(3e3)}catch(t){this.initAudioContext(8e3)}}decode(t){return e=this,i=void 0,n=function*(){if(!this.audioCtx)throw new Error("AudioContext is not initialized");return this.audioCtx.decodeAudioData(t)},new((s=void 0)||(s=Promise))((function(t,o){function r(t){try{h(n.next(t))}catch(t){o(t)}}function a(t){try{h(n.throw(t))}catch(t){o(t)}}function h(e){var i;e.done?t(e.value):(i=e.value,i instanceof s?i:new s((function(t){t(i)}))).then(r,a)}h((n=n.apply(e,i||[])).next())}));var e,i,s,n}destroy(){var t;null===(t=this.audioCtx)||void 0===t||t.close(),this.audioCtx=null}},this.timer=new r,this.player=new class{constructor({media:t,autoplay:e}){this.isExternalMedia=!1,this.hasPlayedOnce=!1,t?(this.media=t,this.isExternalMedia=!0):this.media=document.createElement("audio");const i=this.on("play",(()=>{this.hasPlayedOnce=!0,i()}));e&&(this.media.autoplay=!0)}on(t,e,i){return this.media.addEventListener(t,e,i),()=>this.media.removeEventListener(t,e)}destroy(){this.media.pause(),this.isExternalMedia||this.media.remove()}loadUrl(t){this.media.src=t}getCurrentTime(){return this.media.currentTime}play(){this.media.play()}pause(){this.media.pause()}isPlaying(){return this.media.currentTime>0&&!this.media.paused&&!this.media.ended}seekTo(t){if(this.media){const{hasPlayedOnce:e}=this;e||this.media.play(),this.media.currentTime=t,e||this.media.pause()}}getDuration(){return this.media.duration}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}}({media:this.options.media,autoplay:this.options.autoplay}),this.renderer=new n({container:this.options.container,height:this.options.height,waveColor:this.options.waveColor,progressColor:this.options.progressColor,cursorColor:this.options.cursorColor,minPxPerSec:this.options.minPxPerSec,fillParent:this.options.fillParent,barWidth:this.options.barWidth,barGap:this.options.barGap,barRadius:this.options.barRadius}),this.initPlayerEvents(),this.initRendererEvents(),this.initTimerEvents(),this.initReadyEvent();const i=this.options.url||(null===(e=this.options.media)||void 0===e?void 0:e.src);i&&this.load(i,this.options.peaks,this.options.duration)}initPlayerEvents(){this.subscriptions.push(this.player.on("timeupdate",(()=>{const t=this.getCurrentTime();this.renderer.renderProgress(t/this.getDuration(),this.isPlaying()),this.emit("timeupdate",{currentTime:t})})),this.player.on("play",(()=>{this.emit("play"),this.timer.start()})),this.player.on("pause",(()=>{this.emit("pause"),this.timer.stop()})),this.player.on("canplay",(()=>{this.emit("canplay",{duration:this.getDuration()})})),this.player.on("seeking",(()=>{this.emit("seeking",{currentTime:this.getCurrentTime()})})))}initRendererEvents(){this.subscriptions.push(this.renderer.on("click",(({relativeX:t})=>{if(this.options.interactive){const e=this.getDuration()*t;this.seekTo(e),this.emit("seekClick",{currentTime:this.getCurrentTime()})}})))}initTimerEvents(){this.subscriptions.push(this.timer.on("tick",(()=>{const t=this.getCurrentTime();this.renderer.renderProgress(t/this.getDuration(),!0),this.emit("timeupdate",{currentTime:t})})))}initReadyEvent(){let t=!1,e=!1;const i=()=>{t&&e&&this.emit("ready",{duration:this.getDuration()})};this.subscriptions.push(this.on("decode",(()=>{t=!0,i()})),this.on("canplay",(()=>{e=!0,i()})),this.player.on("waiting",(()=>{e=!1,t=!1})))}load(t,e,i){return s=this,n=void 0,r=function*(){if(this.player.loadUrl(t),null==e){const e=yield this.fetcher.load(t),i=yield this.decoder.decode(e);this.decodedData=i}else i||(i=(yield new Promise((t=>{this.player.on("canplay",(()=>t(this.getDuration())),{once:!0})})))||0),this.decodedData={duration:i,numberOfChannels:e.length,sampleRate:e[0].length/i,getChannelData:t=>e[t]};this.renderer.render(this.decodedData),this.emit("decode",{duration:this.decodedData.duration})},new((o=void 0)||(o=Promise))((function(t,e){function i(t){try{h(r.next(t))}catch(t){e(t)}}function a(t){try{h(r.throw(t))}catch(t){e(t)}}function h(e){var s;e.done?t(e.value):(s=e.value,s instanceof o?s:new o((function(t){t(s)}))).then(i,a)}h((r=r.apply(s,n||[])).next())}));var s,n,o,r}zoom(t){if(!this.decodedData)throw new Error("No audio loaded");this.renderer.zoom(this.decodedData,t)}play(){this.player.play()}pause(){this.player.pause()}seekTo(t){this.player.seekTo(t)}isPlaying(){return this.player.isPlaying()}getDuration(){var t;return this.player.getDuration()||(null===(t=this.decodedData)||void 0===t?void 0:t.duration)||0}getCurrentTime(){return this.player.getCurrentTime()}getVolume(){return this.player.getVolume()}setVolume(t){this.player.setVolume(t)}getMuted(){return this.player.getMuted()}setMuted(t){this.player.setMuted(t)}getPlaybackRate(){return this.player.getPlaybackRate()}setPlaybackRate(t,e){this.player.setPlaybackRate(t,e)}registerPlugin(t,e){const i=new t({wavesurfer:this,container:this.renderer.getContainer()},e);return this.plugins.push(i),i}getDecodedData(){return this.decodedData}destroy(){this.emit("destroy"),this.subscriptions.forEach((t=>t())),this.plugins.forEach((t=>t.destroy())),this.timer.destroy(),this.player.destroy(),this.decoder.destroy(),this.renderer.destroy()}}const d=h;var l=i(59);class c{static create(t,e){return new c(t,e)}constructor(t,e){this.audios=[],this.wavesurfers=[],this.durations=[],this.currentTime=0,this.maxDuration=0,this.isDragging=!1,this.tracks=t.map((t=>Object.assign(Object.assign({},t),{startPosition:t.startPosition||0}))),this.options=e,this.rendering=function(t,e){let i=document.createElement("div");i.setAttribute("style","width: 100%; overflow-x: scroll; overflow-y: hidden; user-select: none;");const s=document.createElement("div");s.style.position="relative",i.appendChild(s),e.container.appendChild(i);const n=document.createElement("div");n.setAttribute("style","width: 1px; height: 100%; position: absolute; z-index: 10; top: 0; left: 0"),n.style.backgroundColor=e.cursorColor||e.progressColor||"#000",s.appendChild(n);const o=t.map((()=>{const t=document.createElement("div");return t.style.width="fit-content",s.appendChild(t),t})),r=()=>{o.forEach(((i,s)=>{const n=t[s].startPosition*e.minPxPerSec/devicePixelRatio;i.style.transform=`translateX(${n}px)`,t[s].draggable&&(i.style.cursor="ew-resize")}))};return r(),{containers:o,setContainerOffsets:r,setMainWidth:t=>{s.style.width=t/devicePixelRatio+"px"},updateCursor:t=>{n.style.left=`${Math.min(100,100*t)}%`},addClickHandler:t=>{s.addEventListener("click",(e=>{const i=s.getBoundingClientRect(),n=(e.clientX-i.left)/s.offsetWidth;t(n)}))},destroy:()=>{i.remove()}}}(this.tracks,this.options),this.initAudios().then((t=>{this.durations=t;const e=this.tracks.reduce(((e,i,s)=>Math.max(e,i.startPosition+t[s])),0);this.rendering.setMainWidth(e*this.options.minPxPerSec),this.rendering.addClickHandler((t=>{this.onSeek(t*e)})),this.maxDuration=e})),this.initWavesurfers(),this.rendering.containers.forEach(((t,e)=>{const i=function(t,e){const i=t.parentElement;if(!i)return;let s=null;t.addEventListener("mousedown",(t=>{const e=i.getBoundingClientRect();s=t.clientX-e.left}));const n=t=>{null!=s&&(t.stopPropagation(),s=null)},o=t=>{if(null==s)return;const n=i.getBoundingClientRect(),o=t.clientX-n.left,r=o-s;(r>1||r<-1)&&(s=o,e(r/i.offsetWidth))};return document.body.addEventListener("mouseup",n),document.body.addEventListener("mousemove",o),{destroy:()=>{document.body.removeEventListener("mouseup",n),document.body.removeEventListener("mousemove",o)}}}(t,(t=>this.onDrag(e,t)));this.wavesurfers[e].once("destroy",(()=>{null==i||i.destroy()}))}))}initAudios(){return this.audios=this.tracks.map((t=>new Audio(t.url||"data:audio/wav;base64,UklGRigAAABXQVZFZm10IBIAAAABAAEARKwAAIhYAQACABAAAABkYXRhAgAAAAEA"))),Promise.all(this.audios.map((t=>new Promise((e=>{t.addEventListener("canplay",(()=>{e(t.duration)}),{once:!0})})))))}initWavesurfers(){const t=this.tracks.map(((t,e)=>{const i=d.create(Object.assign(Object.assign({},this.options),{container:this.rendering.containers[e],media:this.audios[e],peaks:t.peaks,cursorColor:"transparent",fillParent:!1,interactive:!1}));i.on("timeupdate",(({currentTime:e})=>{i.isPlaying()&&e+t.startPosition>this.currentTime&&this.updatePosition(t.startPosition+e)}));const s=i.registerPlugin(l.default,{draggable:!1,resizable:!1,dragSelection:!1});return i.once("decode",(()=>{t.startCue&&s.add(t.startCue,t.startCue,"start"),t.endCue&&s.add(t.endCue,t.endCue,"end"),(t.markers||[]).forEach((t=>{s.add(t.time,t.time,t.label,t.color)}))})),i}));this.wavesurfers=t}updatePosition(t){this.currentTime=t,this.rendering.updateCursor(t/this.maxDuration);const e=!this.isPlaying();this.tracks.forEach(((i,s)=>{const n=this.audios[s],o=this.durations[s],r=t-i.startPosition;Math.abs(n.currentTime-r)>.3&&(n.currentTime=r),e||r<0||r>o?!n.paused&&n.pause():e||n.paused&&n.play();const a=r>=(i.startCue||0)&&r<(i.endCue||1/0)?1:0;a!==n.volume&&(n.volume=a)}))}onSeek(t){if(this.isDragging)return;const e=this.isPlaying();this.updatePosition(t),e&&this.play()}onDrag(t,e){const i=this.tracks[t];if(!i.draggable)return;this.isDragging=!0,setTimeout((()=>this.isDragging=!1),300);const s=i.startPosition+e*this.maxDuration;i.startPosition=s,this.rendering.setContainerOffsets()}findCurrentTracks(){const t=[];if(this.tracks.forEach(((e,i)=>{e.url&&this.currentTime>=e.startPosition&&this.currentTime<e.startPosition+this.durations[i]&&t.push(i)})),0===t.length){const e=Math.min(...this.tracks.filter((t=>t.url)).map((t=>t.startPosition)));t.push(this.tracks.findIndex((t=>t.startPosition===e)))}return t}play(){this.findCurrentTracks().forEach((t=>{var e;null===(e=this.audios[t])||void 0===e||e.play()}))}pause(){this.audios.forEach((t=>t.pause()))}isPlaying(){return this.audios.some((t=>!t.paused))}destroy(){this.rendering.destroy(),this.audios.forEach((t=>{t.pause(),t.src=""})),this.wavesurfers.forEach((t=>{t.destroy()}))}}const u=c})(),s.default})()));
@@ -1 +0,0 @@
1
- !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.Regions=t():e.Regions=t()}(WaveSurfer,(()=>(()=>{"use strict";var e={139:(e,t,i)=>{i.d(t,{Z:()=>n});const n=class{constructor(){this.eventTarget=new EventTarget}emit(e,t){const i=new CustomEvent(String(e),{detail:t});this.eventTarget.dispatchEvent(i)}on(e,t,i){const n=e=>{e instanceof CustomEvent&&t(e.detail)},s=String(e);return this.eventTarget.addEventListener(s,n,{once:i}),()=>this.eventTarget.removeEventListener(s,n)}once(e,t){return this.on(e,t,!0)}}}},t={};function i(n){var s=t[n];if(void 0!==s)return s.exports;var o=t[n]={exports:{}};return e[n](o,o.exports,i),o.exports}i.d=(e,t)=>{for(var n in t)i.o(t,n)&&!i.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},i.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t);var n={};return(()=>{i.d(n,{default:()=>d});var e=i(139);class t extends e.Z{constructor(e,t){super(),this.subscriptions=[],this.wavesurfer=e.wavesurfer,this.container=e.container,this.options=t}destroy(){this.subscriptions.forEach((e=>e()))}}const s=t,o={dragSelection:!0,draggable:!0,resizable:!0},r=(e,t)=>{for(const i in t)e.style[i]=t[i]||""},a=(e,t)=>{const i=document.createElement(e);return r(i,t),i},d=class extends s{constructor(e,t){super(e,t),this.dragStart=NaN,this.regions=[],this.createdRegion=null,this.modifiedRegion=null,this.isResizingLeft=!1,this.isMoving=!1,this.handleMouseDown=e=>{(this.options.draggable||this.options.resizable||this.options.dragSelection)&&(this.dragStart=e.clientX-this.container.getBoundingClientRect().left)},this.handleMouseMove=e=>{const t=e.clientX-this.container.getBoundingClientRect().left;if(this.options.draggable&&this.modifiedRegion&&this.isMoving)return this.moveRegion(this.modifiedRegion,t-this.dragStart),void(this.dragStart=t);if(this.options.resizable&&this.modifiedRegion)this.updateRegion(this.modifiedRegion,this.isResizingLeft?t:void 0,this.isResizingLeft?void 0:t);else if(this.options.dragSelection&&!isNaN(this.dragStart)){const t=e.clientX-this.wrapper.getBoundingClientRect().left;t-this.dragStart>=10&&(this.createdRegion?this.updateRegion(this.createdRegion,this.dragStart,t):(this.container.style.pointerEvents="none",this.createdRegion=this.createRegion(this.dragStart,t)))}},this.handleMouseUp=()=>{this.createdRegion&&(this.addRegion(this.createdRegion),this.createdRegion=null),this.modifiedRegion=null,this.isMoving=!1,this.dragStart=NaN,this.container.style.pointerEvents=""},this.options=Object.assign({},o,t),this.wrapper=this.initWrapper();const i=this.wavesurfer.once("decode",(()=>{this.container.appendChild(this.wrapper)}));this.subscriptions.push(i),this.container.addEventListener("mousedown",this.handleMouseDown),document.addEventListener("mousemove",this.handleMouseMove),document.addEventListener("mouseup",this.handleMouseUp)}destroy(){this.container.removeEventListener("mousedown",this.handleMouseDown),document.removeEventListener("mousemove",this.handleMouseMove),document.removeEventListener("mouseup",this.handleMouseUp,!0),this.wrapper.remove(),super.destroy()}initWrapper(){return a("div",{position:"absolute",top:"0",left:"0",width:"100%",height:"100%",zIndex:"3",pointerEvents:"none"})}createRegionElement(e,t,i=""){const n=e===t,s=a("div",{position:"absolute",left:`${e}px`,width:t-e+"px",height:"100%",backgroundColor:n?"":"rgba(0, 0, 0, 0.1)",borderRadius:"2px",boxSizing:"border-box",borderLeft:"2px solid rgba(0, 0, 0, 0.5)",borderRight:n?"":"2px solid rgba(0, 0, 0, 0.5)",transition:"background-color 0.2s ease",cursor:this.options.draggable?"move":"",pointerEvents:"all",padding:"0.2em"});s.textContent=i;const o=a("div",{position:"absolute",left:"0",width:"6px",height:"100%",cursor:this.options.resizable?"ew-resize":"",pointerEvents:"all"});s.appendChild(o);const d=o.cloneNode();return r(d,{left:"",right:"0",borderLeft:""}),s.appendChild(d),o.addEventListener("mousedown",(e=>{this.options.resizable&&(e.stopPropagation(),this.modifiedRegion=this.regions.find((e=>e.element===s))||null,this.isResizingLeft=!0,this.isMoving=!1)})),d.addEventListener("mousedown",(e=>{this.options.resizable&&(e.stopPropagation(),this.modifiedRegion=this.regions.find((e=>e.element===s))||null,this.isResizingLeft=!1,this.isMoving=!1)})),s.addEventListener("mousedown",(()=>{this.options.draggable&&(this.modifiedRegion=this.regions.find((e=>e.element===s))||null,this.isMoving=!0)})),s.addEventListener("click",(()=>{const e=this.regions.find((e=>e.element===s));e&&this.emit("region-clicked",{region:e})})),this.wrapper.appendChild(s),s}createRegion(e,t,i=""){const n=this.wavesurfer.getDuration(),s=this.wrapper.clientWidth;return e=Math.max(0,Math.min(e,s-1)),t=Math.max(0,Math.min(t,s-1)),{element:this.createRegionElement(e,t,i),start:e,end:t,startTime:e/s*n,endTime:t/s*n,title:i}}addRegion(e){this.regions.push(e),this.emit("region-created",{region:e})}updateRegion(e,t,i){const n=this.wrapper.clientWidth;null!=t&&(t=Math.max(0,Math.min(t,n)),e.start=t,e.element.style.left=`${e.start}px`,e.startTime=t/this.wrapper.clientWidth*this.wavesurfer.getDuration()),null!=i&&(i=Math.max(0,Math.min(i,n)),e.end=i,e.element.style.width=e.end-e.start+"px",e.endTime=i/this.wrapper.clientWidth*this.wavesurfer.getDuration()),this.emit("region-updated",{region:e})}moveRegion(e,t){this.updateRegion(e,e.start+t,e.end+t)}add(e,t,i="",n=""){const s=this.wavesurfer.getDuration(),o=this.wrapper.clientWidth,r=e/s*o,a=t/s*o,d=this.createRegion(r,a,i);return this.addRegion(d),n&&this.setRegionColor(d,n),d}setRegionColor(e,t){e.element.style[e.startTime===e.endTime?"borderColor":"backgroundColor"]=t}}})(),n.default})()));