wavesurfer.js 7.0.0-alpha.3 → 7.0.0-alpha.31
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 +58 -26
- package/dist/base-plugin.d.ts +9 -5
- package/dist/base-plugin.js +11 -3
- package/dist/decoder.d.ts +2 -4
- package/dist/decoder.js +20 -31
- package/dist/event-emitter.d.ts +1 -1
- package/dist/event-emitter.js +4 -7
- package/dist/fetcher.js +2 -13
- package/dist/legacy-adapter.d.ts +7 -0
- package/dist/legacy-adapter.js +15 -0
- package/dist/player.d.ts +39 -9
- package/dist/player.js +90 -15
- package/dist/plugin/wavesurfer.envelope.min.js +1 -0
- package/dist/plugin/wavesurfer.minimap.min.js +1 -0
- package/dist/plugin/wavesurfer.multitrack.min.js +1 -0
- package/dist/plugin/wavesurfer.regions.min.js +1 -0
- package/dist/plugin/wavesurfer.timeline.min.js +1 -0
- package/dist/plugins/envelope.d.ts +60 -0
- package/dist/plugins/envelope.js +302 -0
- package/dist/plugins/envelope.min.js +1 -0
- package/dist/plugins/minimap.d.ts +27 -0
- package/dist/plugins/minimap.js +83 -0
- package/dist/plugins/minimap.min.js +1 -0
- package/dist/plugins/multitrack.d.ts +113 -0
- package/dist/plugins/multitrack.js +504 -0
- package/dist/plugins/multitrack.min.js +1 -0
- package/dist/plugins/record.d.ts +23 -0
- package/dist/plugins/record.js +119 -0
- package/dist/plugins/record.min.js +1 -0
- package/dist/plugins/regions.d.ts +68 -32
- package/dist/plugins/regions.js +291 -158
- package/dist/plugins/regions.min.js +1 -0
- package/dist/plugins/spectrogram.d.ts +24 -0
- package/dist/plugins/spectrogram.js +165 -0
- package/dist/plugins/timeline.d.ts +38 -0
- package/dist/plugins/timeline.js +134 -0
- package/dist/plugins/timeline.min.js +1 -0
- package/dist/renderer.d.ts +27 -12
- package/dist/renderer.js +223 -137
- package/dist/timer.d.ts +2 -1
- package/dist/timer.js +5 -3
- package/dist/wavesurfer.d.ts +132 -0
- package/dist/wavesurfer.js +220 -0
- package/dist/wavesurfer.min.js +1 -1
- package/package.json +51 -20
- package/dist/index.d.ts +0 -92
- package/dist/index.js +0 -166
- package/dist/player-webaudio.d.ts +0 -8
- package/dist/player-webaudio.js +0 -30
- package/dist/wavesurfer.Regions.min.js +0 -1
package/README.md
CHANGED
|
@@ -1,50 +1,82 @@
|
|
|
1
|
-
# wavesurfer.ts
|
|
1
|
+
# <img src="https://user-images.githubusercontent.com/381895/226091100-f5567a28-7736-4d37-8f84-e08f297b7e1a.png" alt="logo" height="60" valign="middle" /> wavesurfer.ts
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A rewrite of [wavesufer.js](https://github.com/wavesurfer-js/wavesurfer.js) in TypeScript with better performance.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
<img alt="screenshot" src="https://user-images.githubusercontent.com/381895/225539680-fc724acd-8657-458e-a558-ff1c6758ba30.png" width="800" />
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
Try it out:
|
|
8
|
+
```
|
|
9
|
+
npm install --save wavesurfer.js@alpha
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Import like this:
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
import WaveSurfer from 'wavesurfer.js'
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
TypeScript types are included in the package, so there's no need to install `@types/wavesurfer.js`.
|
|
19
|
+
|
|
20
|
+
## Why upgrade to wavesurfer.ts?
|
|
21
|
+
|
|
22
|
+
wavesurfer.js v7 (aka wavesurfer.ts) brings several improvements:
|
|
11
23
|
|
|
12
|
-
|
|
24
|
+
* Typed API for better development experience
|
|
25
|
+
* Enhanced decoding and rendering performance
|
|
26
|
+
* New and improved plugins
|
|
13
27
|
|
|
14
|
-
|
|
28
|
+
## Plugins
|
|
29
|
+
The "official" plugins have been completely rewritten and enhanced:
|
|
15
30
|
|
|
16
|
-
|
|
31
|
+
* [Regions](https://wavesurfer-ts.pages.dev/tutorial/#/examples/regions.js) – now also replaces the old Markers plugin
|
|
32
|
+
* [Timeline](https://wavesurfer-ts.pages.dev/tutorial/#/examples/timeline.js) – displays notches and time labels below the waveform
|
|
33
|
+
* [Minimap](https://wavesurfer-ts.pages.dev/tutorial/#/examples/minimap.js) – a small waveform that serves as a scrollbar for the main waveform
|
|
34
|
+
* [Envelope](https://wavesurfer-ts.pages.dev/tutorial/#/examples/envelope.js) – a graphical interface to add fade-in and -out effects and control volume
|
|
35
|
+
* [Record](https://wavesurfer-ts.pages.dev/tutorial/#/examples/record.js) – records audio from the microphone and renders a waveform
|
|
17
36
|
|
|
18
|
-
|
|
19
|
-
* Modular and event-driven
|
|
20
|
-
* Allow swapping the decoding, rendering and playback mechanisms
|
|
21
|
-
* Extensible with plugins
|
|
37
|
+
## Migrating from v6 and lower
|
|
22
38
|
|
|
23
|
-
|
|
39
|
+
Most options, events, and methods are similar to those in previous versions.
|
|
40
|
+
|
|
41
|
+
### Notable differences
|
|
42
|
+
* The `backend` option is removed – HTML5 audio (or video) is the only playback mechanism. However, you can still connect wavesurfer to Web Audio via `MediaElementSourceNode`. See this [example](https://wavesurfer-ts.pages.dev/tutorial/#/examples/webaudio.js).
|
|
43
|
+
* The Markers plugin is removed – use the Regions plugin with `startTime` equal to `endTime`
|
|
44
|
+
* Plugins now have different APIs
|
|
45
|
+
|
|
46
|
+
### Removed methods
|
|
47
|
+
* `getFilters`, `setFilter` – as there's no Web Audio "backend"
|
|
48
|
+
* `cancelAjax` – ajax is replaced by `fetch`
|
|
49
|
+
* `loadBlob` – use `URL.createObjectURL()` to convert a blob to a URL and call `load(url)` instead
|
|
50
|
+
* `un`, `unAll` – the `on` method now returns an unsubscribe function. E.g., `const unsubscribe = wavesurfer.on('ready', () => ...)`
|
|
51
|
+
* `skipForward`, `skipBackward`, `setPlayEnd` – can be implemented using `setTime(time)`
|
|
52
|
+
* `exportPCM` is renamed to `getDecodedData` and doesn't take any params
|
|
53
|
+
* `toggleMute` is now called `setMute(true | false)`
|
|
54
|
+
* `setHeight`, `setWaveColor`, `setCursorColor`, etc. – use `setOptions` with the corresponding params instead. E.g., `wavesurfer.setOptions({ height: 300, waveColor: '#abc' })`
|
|
55
|
+
|
|
56
|
+
See the complete [documentation of the new API](https://wavesurfer-ts.pages.dev/docs/classes/wavesurfer.WaveSurfer).
|
|
24
57
|
|
|
25
58
|
## Development
|
|
26
59
|
|
|
27
|
-
|
|
60
|
+
To get started with development, follow these steps:
|
|
61
|
+
|
|
62
|
+
1. Install dev dependencies:
|
|
28
63
|
|
|
29
64
|
```
|
|
30
65
|
yarn
|
|
31
66
|
```
|
|
32
67
|
|
|
33
|
-
Start the TypeScript compiler in watch mode:
|
|
68
|
+
2. Start the TypeScript compiler in watch mode and launch an HTTP server:
|
|
34
69
|
|
|
35
70
|
```
|
|
36
|
-
yarn
|
|
71
|
+
yarn start
|
|
37
72
|
```
|
|
38
73
|
|
|
39
|
-
|
|
74
|
+
This command will open http://localhost:9090/tutorial in your browser with live reload, allowing you to see the changes as you develop.
|
|
40
75
|
|
|
41
|
-
|
|
42
|
-
python3 -m http.server --cgi 8080
|
|
43
|
-
```
|
|
76
|
+
## Feedback
|
|
44
77
|
|
|
45
|
-
|
|
46
|
-
There's no hot reload yet, so you'll need to reload the page manually on every change.
|
|
78
|
+
We appreciate your feedback and contributions! Join the conversation and share your thoughts here: https://github.com/wavesurfer-js/wavesurfer.js/discussions/2684
|
|
47
79
|
|
|
48
|
-
|
|
80
|
+
If you encounter any issues or have suggestions for improvements, please don't hesitate to open an issue or submit a pull request on the GitHub repository.
|
|
49
81
|
|
|
50
|
-
|
|
82
|
+
We hope you enjoy using wavesurfer.ts and look forward to hearing about your experiences with the library!
|
package/dist/base-plugin.d.ts
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import EventEmitter, { type GeneralEventTypes } from './event-emitter.js';
|
|
2
|
-
import
|
|
3
|
-
export
|
|
4
|
-
|
|
5
|
-
protected
|
|
2
|
+
import WaveSurfer, { type WaveSurferPluginParams } from './wavesurfer.js';
|
|
3
|
+
export type GenericPlugin = BasePlugin<GeneralEventTypes, unknown>;
|
|
4
|
+
export declare class BasePlugin<EventTypes extends GeneralEventTypes, Options> extends EventEmitter<EventTypes> {
|
|
5
|
+
protected wavesurfer?: WaveSurfer;
|
|
6
|
+
protected container?: HTMLElement;
|
|
7
|
+
protected wrapper?: HTMLElement;
|
|
6
8
|
protected subscriptions: (() => void)[];
|
|
7
|
-
|
|
9
|
+
protected options: Options;
|
|
10
|
+
constructor(options: Options);
|
|
11
|
+
init(params: WaveSurferPluginParams): void;
|
|
8
12
|
destroy(): void;
|
|
9
13
|
}
|
|
10
14
|
export default BasePlugin;
|
package/dist/base-plugin.js
CHANGED
|
@@ -1,10 +1,18 @@
|
|
|
1
1
|
import EventEmitter from './event-emitter.js';
|
|
2
2
|
export class BasePlugin extends EventEmitter {
|
|
3
|
-
|
|
3
|
+
wavesurfer;
|
|
4
|
+
container;
|
|
5
|
+
wrapper;
|
|
6
|
+
subscriptions = [];
|
|
7
|
+
options;
|
|
8
|
+
constructor(options) {
|
|
4
9
|
super();
|
|
5
|
-
this.
|
|
10
|
+
this.options = options;
|
|
11
|
+
}
|
|
12
|
+
init(params) {
|
|
6
13
|
this.wavesurfer = params.wavesurfer;
|
|
7
|
-
this.
|
|
14
|
+
this.container = params.container;
|
|
15
|
+
this.wrapper = params.wrapper;
|
|
8
16
|
}
|
|
9
17
|
destroy() {
|
|
10
18
|
this.subscriptions.forEach((unsubscribe) => unsubscribe());
|
package/dist/decoder.d.ts
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
declare class Decoder {
|
|
2
2
|
audioCtx: AudioContext | null;
|
|
3
|
+
private initAudioContext;
|
|
3
4
|
constructor();
|
|
4
|
-
decode(audioData: ArrayBuffer): Promise<
|
|
5
|
-
duration: number;
|
|
6
|
-
channelData: Float32Array[];
|
|
7
|
-
}>;
|
|
5
|
+
decode(audioData: ArrayBuffer): Promise<AudioBuffer>;
|
|
8
6
|
destroy(): void;
|
|
9
7
|
}
|
|
10
8
|
export default Decoder;
|
package/dist/decoder.js
CHANGED
|
@@ -1,41 +1,30 @@
|
|
|
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
|
-
// Web Audio decodeAudioData with a minimum allowed sample rate
|
|
11
|
-
const SAMPLE_RATE = 3000;
|
|
12
1
|
class Decoder {
|
|
13
|
-
|
|
14
|
-
|
|
2
|
+
audioCtx = null;
|
|
3
|
+
initAudioContext(sampleRate) {
|
|
15
4
|
this.audioCtx = new AudioContext({
|
|
16
5
|
latencyHint: 'playback',
|
|
17
|
-
sampleRate
|
|
6
|
+
sampleRate,
|
|
18
7
|
});
|
|
19
8
|
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
}
|
|
9
|
+
constructor() {
|
|
10
|
+
// Minimum sample rate supported by Web Audio API
|
|
11
|
+
const DEFAULT_SAMPLE_RATE = 3000; // Chrome, Safari
|
|
12
|
+
const FALLBACK_SAMPLE_RATE = 8000; // Firefox
|
|
13
|
+
try {
|
|
14
|
+
this.initAudioContext(DEFAULT_SAMPLE_RATE);
|
|
15
|
+
}
|
|
16
|
+
catch (e) {
|
|
17
|
+
this.initAudioContext(FALLBACK_SAMPLE_RATE);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
async decode(audioData) {
|
|
21
|
+
if (!this.audioCtx) {
|
|
22
|
+
throw new Error('AudioContext is not initialized');
|
|
23
|
+
}
|
|
24
|
+
return this.audioCtx.decodeAudioData(audioData);
|
|
35
25
|
}
|
|
36
26
|
destroy() {
|
|
37
|
-
|
|
38
|
-
(_a = this.audioCtx) === null || _a === void 0 ? void 0 : _a.close();
|
|
27
|
+
this.audioCtx?.close();
|
|
39
28
|
this.audioCtx = null;
|
|
40
29
|
}
|
|
41
30
|
}
|
package/dist/event-emitter.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ declare class EventEmitter<EventTypes extends GeneralEventTypes> {
|
|
|
6
6
|
constructor();
|
|
7
7
|
protected emit<T extends keyof EventTypes>(eventType: T, detail?: EventTypes[T]): void;
|
|
8
8
|
/** Subscribe to an event and return a function to unsubscribe */
|
|
9
|
-
on<T extends keyof EventTypes>(eventType: T, callback: (detail: EventTypes[T]) => void): () => void;
|
|
9
|
+
on<T extends keyof EventTypes>(eventType: T, callback: (detail: EventTypes[T]) => void, once?: boolean): () => void;
|
|
10
10
|
/** Subscribe to an event once and return a function to unsubscribe */
|
|
11
11
|
once<T extends keyof EventTypes>(eventType: T, callback: (detail: EventTypes[T]) => void): () => void;
|
|
12
12
|
}
|
package/dist/event-emitter.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
class EventEmitter {
|
|
2
|
+
eventTarget;
|
|
2
3
|
constructor() {
|
|
3
4
|
this.eventTarget = new EventTarget();
|
|
4
5
|
}
|
|
@@ -7,23 +8,19 @@ class EventEmitter {
|
|
|
7
8
|
this.eventTarget.dispatchEvent(e);
|
|
8
9
|
}
|
|
9
10
|
/** Subscribe to an event and return a function to unsubscribe */
|
|
10
|
-
on(eventType, callback) {
|
|
11
|
+
on(eventType, callback, once) {
|
|
11
12
|
const handler = (e) => {
|
|
12
13
|
if (e instanceof CustomEvent) {
|
|
13
14
|
callback(e.detail);
|
|
14
15
|
}
|
|
15
16
|
};
|
|
16
17
|
const eventName = String(eventType);
|
|
17
|
-
this.eventTarget.addEventListener(eventName, handler);
|
|
18
|
+
this.eventTarget.addEventListener(eventName, handler, { once });
|
|
18
19
|
return () => this.eventTarget.removeEventListener(eventName, handler);
|
|
19
20
|
}
|
|
20
21
|
/** Subscribe to an event once and return a function to unsubscribe */
|
|
21
22
|
once(eventType, callback) {
|
|
22
|
-
|
|
23
|
-
unsubscribe();
|
|
24
|
-
callback(...args);
|
|
25
|
-
});
|
|
26
|
-
return unsubscribe;
|
|
23
|
+
return this.on(eventType, callback, true);
|
|
27
24
|
}
|
|
28
25
|
}
|
|
29
26
|
export default EventEmitter;
|
package/dist/fetcher.js
CHANGED
|
@@ -1,17 +1,6 @@
|
|
|
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
1
|
class Fetcher {
|
|
11
|
-
load(url) {
|
|
12
|
-
return
|
|
13
|
-
return fetch(url).then((response) => response.arrayBuffer());
|
|
14
|
-
});
|
|
2
|
+
async load(url) {
|
|
3
|
+
return fetch(url).then((response) => response.arrayBuffer());
|
|
15
4
|
}
|
|
16
5
|
}
|
|
17
6
|
export default Fetcher;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
const LegacyWavesurferMethods = {
|
|
2
|
+
/** Skip a number of seconds from the current position (use a negative value to go backwards) */
|
|
3
|
+
skip(seconds) {
|
|
4
|
+
console.warn('Deprecated, please use `wavesurfer.setTime(wavesurfer.getCurrentTime() + seconds)` instead');
|
|
5
|
+
const time = this.getCurrentTime() + seconds;
|
|
6
|
+
this.setTime(time);
|
|
7
|
+
},
|
|
8
|
+
/** Stop the audio and go to the beginning */
|
|
9
|
+
stop() {
|
|
10
|
+
console.warn('Deprecated, please use `wavesurfer.pause(); wavesurfer.setTime(0)` instead');
|
|
11
|
+
this.pause();
|
|
12
|
+
this.setTime(0);
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
export default LegacyWavesurferMethods;
|
package/dist/player.d.ts
CHANGED
|
@@ -1,16 +1,46 @@
|
|
|
1
|
-
|
|
1
|
+
import EventEmitter, { type GeneralEventTypes } from './event-emitter.js';
|
|
2
|
+
type PlayerOptions = {
|
|
3
|
+
media?: HTMLMediaElement;
|
|
4
|
+
autoplay?: boolean;
|
|
5
|
+
playbackRate?: number;
|
|
6
|
+
};
|
|
7
|
+
declare class Player<T extends GeneralEventTypes> extends EventEmitter<T> {
|
|
2
8
|
protected media: HTMLMediaElement;
|
|
9
|
+
protected subscriptions: Array<() => void>;
|
|
3
10
|
private isExternalMedia;
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
11
|
+
private hasPlayedOnce;
|
|
12
|
+
constructor(options: PlayerOptions);
|
|
13
|
+
protected onMediaEvent(event: keyof HTMLMediaElementEventMap, callback: () => void, options?: AddEventListenerOptions): () => void;
|
|
14
|
+
protected onceMediaEvent(event: keyof HTMLMediaElementEventMap, callback: () => void): () => void;
|
|
15
|
+
protected loadUrl(src: string): void;
|
|
8
16
|
destroy(): void;
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
17
|
+
/** Start playing the audio */
|
|
18
|
+
play(): Promise<void>;
|
|
19
|
+
/** Pause the audio */
|
|
12
20
|
pause(): void;
|
|
21
|
+
/** Check if the audio is playing */
|
|
13
22
|
isPlaying(): boolean;
|
|
14
|
-
|
|
23
|
+
/** Jumpt to a specific time in the audio (in seconds) */
|
|
24
|
+
setTime(time: number): void;
|
|
25
|
+
/** Get the duration of the audio in seconds */
|
|
26
|
+
getDuration(): number;
|
|
27
|
+
/** Get the current audio position in seconds */
|
|
28
|
+
getCurrentTime(): number;
|
|
29
|
+
/** Get the audio volume */
|
|
30
|
+
getVolume(): number;
|
|
31
|
+
/** Set the audio volume */
|
|
32
|
+
setVolume(volume: number): void;
|
|
33
|
+
/** Get the audio muted state */
|
|
34
|
+
getMuted(): boolean;
|
|
35
|
+
/** Mute or unmute the audio */
|
|
36
|
+
setMuted(muted: boolean): void;
|
|
37
|
+
/** Get the playback speed */
|
|
38
|
+
getPlaybackRate(): number;
|
|
39
|
+
/** Set the playback speed, pass an optional false to NOT preserve the pitch */
|
|
40
|
+
setPlaybackRate(rate: number, preservePitch?: boolean): void;
|
|
41
|
+
/** Get the HTML media element */
|
|
42
|
+
getMediaElement(): HTMLMediaElement;
|
|
43
|
+
/** Set a sink id to change the audio output device */
|
|
44
|
+
setSinkId(sinkId: string): Promise<void>;
|
|
15
45
|
}
|
|
16
46
|
export default Player;
|
package/dist/player.js
CHANGED
|
@@ -1,40 +1,115 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import EventEmitter from './event-emitter.js';
|
|
2
|
+
class Player extends EventEmitter {
|
|
3
|
+
media;
|
|
4
|
+
subscriptions = [];
|
|
5
|
+
isExternalMedia = false;
|
|
6
|
+
hasPlayedOnce = false;
|
|
7
|
+
constructor(options) {
|
|
8
|
+
super();
|
|
9
|
+
if (options.media) {
|
|
10
|
+
this.media = options.media;
|
|
6
11
|
this.isExternalMedia = true;
|
|
7
12
|
}
|
|
8
13
|
else {
|
|
9
14
|
this.media = document.createElement('audio');
|
|
10
15
|
}
|
|
16
|
+
this.subscriptions.push(
|
|
17
|
+
// Track the first play() call
|
|
18
|
+
this.onceMediaEvent('play', () => {
|
|
19
|
+
this.hasPlayedOnce = true;
|
|
20
|
+
}));
|
|
21
|
+
// Autoplay
|
|
22
|
+
if (options.autoplay) {
|
|
23
|
+
this.media.autoplay = true;
|
|
24
|
+
}
|
|
25
|
+
// Speed
|
|
26
|
+
if (options.playbackRate != null) {
|
|
27
|
+
this.media.playbackRate = options.playbackRate;
|
|
28
|
+
}
|
|
11
29
|
}
|
|
12
|
-
|
|
13
|
-
this.media.addEventListener(event, callback);
|
|
30
|
+
onMediaEvent(event, callback, options) {
|
|
31
|
+
this.media.addEventListener(event, callback, options);
|
|
14
32
|
return () => this.media.removeEventListener(event, callback);
|
|
15
33
|
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
this.media.remove();
|
|
19
|
-
}
|
|
34
|
+
onceMediaEvent(event, callback) {
|
|
35
|
+
return this.onMediaEvent(event, callback, { once: true });
|
|
20
36
|
}
|
|
21
37
|
loadUrl(src) {
|
|
22
38
|
this.media.src = src;
|
|
23
39
|
}
|
|
24
|
-
|
|
25
|
-
|
|
40
|
+
destroy() {
|
|
41
|
+
this.media.pause();
|
|
42
|
+
this.subscriptions.forEach((unsubscribe) => unsubscribe());
|
|
43
|
+
if (!this.isExternalMedia) {
|
|
44
|
+
this.media.remove();
|
|
45
|
+
}
|
|
26
46
|
}
|
|
47
|
+
/** Start playing the audio */
|
|
27
48
|
play() {
|
|
28
|
-
this.media.play();
|
|
49
|
+
return this.media.play();
|
|
29
50
|
}
|
|
51
|
+
/** Pause the audio */
|
|
30
52
|
pause() {
|
|
31
53
|
this.media.pause();
|
|
32
54
|
}
|
|
55
|
+
/** Check if the audio is playing */
|
|
33
56
|
isPlaying() {
|
|
34
57
|
return this.media.currentTime > 0 && !this.media.paused && !this.media.ended;
|
|
35
58
|
}
|
|
36
|
-
|
|
59
|
+
/** Jumpt to a specific time in the audio (in seconds) */
|
|
60
|
+
setTime(time) {
|
|
61
|
+
if (!this.hasPlayedOnce) {
|
|
62
|
+
this.media.play()?.then?.(() => {
|
|
63
|
+
setTimeout(() => this.media.pause(), 10);
|
|
64
|
+
});
|
|
65
|
+
}
|
|
37
66
|
this.media.currentTime = time;
|
|
38
67
|
}
|
|
68
|
+
/** Get the duration of the audio in seconds */
|
|
69
|
+
getDuration() {
|
|
70
|
+
return this.media.duration;
|
|
71
|
+
}
|
|
72
|
+
/** Get the current audio position in seconds */
|
|
73
|
+
getCurrentTime() {
|
|
74
|
+
return this.media.currentTime;
|
|
75
|
+
}
|
|
76
|
+
/** Get the audio volume */
|
|
77
|
+
getVolume() {
|
|
78
|
+
return this.media.volume;
|
|
79
|
+
}
|
|
80
|
+
/** Set the audio volume */
|
|
81
|
+
setVolume(volume) {
|
|
82
|
+
this.media.volume = volume;
|
|
83
|
+
}
|
|
84
|
+
/** Get the audio muted state */
|
|
85
|
+
getMuted() {
|
|
86
|
+
return this.media.muted;
|
|
87
|
+
}
|
|
88
|
+
/** Mute or unmute the audio */
|
|
89
|
+
setMuted(muted) {
|
|
90
|
+
this.media.muted = muted;
|
|
91
|
+
}
|
|
92
|
+
/** Get the playback speed */
|
|
93
|
+
getPlaybackRate() {
|
|
94
|
+
return this.media.playbackRate;
|
|
95
|
+
}
|
|
96
|
+
/** Set the playback speed, pass an optional false to NOT preserve the pitch */
|
|
97
|
+
setPlaybackRate(rate, preservePitch) {
|
|
98
|
+
// preservePitch is true by default in most browsers
|
|
99
|
+
if (preservePitch != null) {
|
|
100
|
+
this.media.preservesPitch = preservePitch;
|
|
101
|
+
}
|
|
102
|
+
this.media.playbackRate = rate;
|
|
103
|
+
}
|
|
104
|
+
/** Get the HTML media element */
|
|
105
|
+
getMediaElement() {
|
|
106
|
+
return this.media;
|
|
107
|
+
}
|
|
108
|
+
/** Set a sink id to change the audio output device */
|
|
109
|
+
setSinkId(sinkId) {
|
|
110
|
+
// See https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/setSinkId
|
|
111
|
+
const media = this.media;
|
|
112
|
+
return media.setSinkId(sinkId);
|
|
113
|
+
}
|
|
39
114
|
}
|
|
40
115
|
export default Player;
|
|
@@ -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{wavesurfer;container;wrapper;subscriptions=[];options;constructor(t){super(),this.options=t}init(t){this.wavesurfer=t.wavesurfer,this.container=t.container,this.wrapper=t.wrapper}destroy(){this.subscriptions.forEach((t=>t()))}}const o=n},139:(t,e,i)=>{i.d(e,{Z:()=>s});const s=class{eventTarget;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)}}}},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:()=>o});var t=i(284);const e={startTime:0,endTime: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 n extends t.Z{options;svg=null;audioContext=null;gainNode=null;volume=1;isFadingIn=!1;isFadingOut=!1;constructor(t){super(t),this.options=Object.assign({},e,t),this.options.lineColor=this.options.lineColor||e.lineColor,this.options.dragPointFill=this.options.dragPointFill||e.dragPointFill,this.options.dragPointStroke=this.options.dragPointStroke||e.dragPointStroke,this.volume=this.options.volume??1}static create(t){return new n(t)}init(t){if(super.init(t),!this.wavesurfer)throw Error("WaveSurfer is not initialized");let e;this.subscriptions.push(this.wavesurfer.once("decode",(({duration:t})=>{this.options.startTime=this.options.startTime||0,this.options.endTime=this.options.endTime||t,this.options.fadeInEnd=this.options.fadeInEnd||this.options.startTime,this.options.fadeOutStart=this.options.fadeOutStart||this.options.endTime,this.initWebAudio(),this.initSvg(),this.initFadeEffects()}))),this.subscriptions.push(this.wavesurfer.on("zoom",(()=>{e&&clearTimeout(e),e=setTimeout((()=>{this.svg?.remove(),this.initSvg()}),100)})))}makeDraggable(t,e){t.addEventListener("mousedown",(t=>{let i=t.clientX,s=t.clientY;const n=this.wavesurfer?.options.interact||!0;let o;this.wavesurfer?.toggleInteractive(!1);const r=t=>{const n=t.clientX-i,o=t.clientY-s;i=t.clientX,s=t.clientY,e(n,o)},a=()=>{document.removeEventListener("mousemove",r),document.removeEventListener("mouseup",a),o&&clearTimeout(o),o=setTimeout((()=>{this.wavesurfer?.toggleInteractive(n)}),100)};document.addEventListener("mousemove",r),document.addEventListener("mouseup",a),t.preventDefault(),t.stopPropagation()}))}renderPolyline(){if(!this.svg||!this.wrapper||!this.wavesurfer)return;const t=this.svg.querySelector("polyline"),e=t.points,i=e.getItem(1).y,s=this.wrapper.clientWidth,n=this.wavesurfer.getDuration();e.getItem(0).x=this.options.startTime/n*s,e.getItem(3).x=this.options.endTime/n*s;const o=this.svg.querySelector("line");o.setAttribute("x1",e.getItem(1).x.toString()),o.setAttribute("x2",e.getItem(2).x.toString()),o.setAttribute("y1",i.toString()),o.setAttribute("y2",i.toString());const r=this.svg.querySelectorAll("circle");for(let e=0;e<r.length;e++){const s=r[e],n=t.points.getItem(e+1);s.setAttribute("cx",n.x.toString()),s.setAttribute("cy",i.toString())}}initSvg(){if(!this.wrapper||!this.wavesurfer)return;const t=this.wrapper.clientWidth,e=this.wrapper.clientHeight,i=this.wavesurfer.getDuration(),s=document.createElementNS("http://www.w3.org/2000/svg","svg");s.setAttribute("width","100%"),s.setAttribute("height","100%"),s.setAttribute("viewBox",`0 0 ${t} ${e}`),s.setAttribute("preserveAspectRatio","none"),s.setAttribute("style","position: absolute; left: 0; top: 0; z-index: 4; pointer-events: none;"),this.svg=s;const n=document.createElementNS("http://www.w3.org/2000/svg","polyline");n.setAttribute("points","0,0 0,0 0,0 0,0"),n.setAttribute("stroke",this.options.lineColor),n.setAttribute("stroke-width",this.options.lineWidth),n.setAttribute("fill","none"),n.setAttribute("style","pointer-events: none"),s.appendChild(n);const o=document.createElementNS("http://www.w3.org/2000/svg","line");o.setAttribute("stroke","none"),o.setAttribute("stroke-width",(3*this.options.lineWidth).toString()),o.setAttribute("style","cursor: ns-resize; pointer-events: all;"),s.appendChild(o);const r=n.points,a=this.options.dragPointSize/2,u=e-this.volume*e+a;r.getItem(0).x=this.options.startTime/i*t,r.getItem(0).y=e,r.getItem(1).x=this.options.fadeInEnd/i*t,r.getItem(1).y=u,r.getItem(2).x=this.options.fadeOutStart/i*t,r.getItem(2).y=u,r.getItem(3).x=this.options.endTime/i*t,r.getItem(3).y=e,[1,2].forEach((()=>{const t=document.createElementNS("http://www.w3.org/2000/svg","circle");t.setAttribute("r",(this.options.dragPointSize/2).toString()),t.setAttribute("fill",this.options.dragPointFill),t.setAttribute("stroke",this.options.dragPointStroke||this.options.dragPointFill),t.setAttribute("stroke-width","2"),t.setAttribute("style","cursor: ew-resize; pointer-events: all;"),s.appendChild(t)})),this.wrapper.appendChild(s),this.renderPolyline();const h=t=>{const i=r.getItem(1).y+t-a;if(i<-.5||i>e)return;r.getItem(1).y=i+a,r.getItem(2).y=i+a,this.renderPolyline();const s=Math.min(1,Math.max(0,(e-i)/e));this.onVolumeChange(s),this.renderPolyline()},d=(e,s,o)=>{const r=n.points.getItem(o),a=r.x+e,u=a/t*i;1===o&&u>this.options.fadeOutStart||u<this.options.startTime||2===o&&u<this.options.fadeInEnd||u>this.options.endTime||(r.x=a,1===o?(this.options.fadeInEnd=u,this.emit("fade-in-change",{time:u})):2===o&&(this.options.fadeOutStart=u,this.emit("fade-out-change",{time:u})),s>1||s<-1?h(s):this.renderPolyline())};this.makeDraggable(o,((t,e)=>h(e)));const l=s.querySelectorAll("circle");for(let t=0;t<l.length;t++){const e=t+1;this.makeDraggable(l[t],((t,i)=>d(t,i,e)))}}destroy(){this.svg?.remove(),super.destroy()}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.gainNode.gain.value=this.volume,e.createMediaElementSource(t).connect(this.gainNode),this.gainNode.connect(e.destination),this.audioContext=e}naturalVolume(t){return 1e-4+.9999*Math.pow(t,3)}onVolumeChange(t){t=this.naturalVolume(t),this.volume=t,this.emit("volume-change",{volume:t}),this.gainNode&&(this.gainNode.gain.value=t)}initFadeEffects(){if(!this.audioContext||!this.wavesurfer)return;const t=this.wavesurfer.on("timeupdate",(({currentTime: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.startTime&&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.endTime)return this.isFadingOut=!0,void this.gainNode.gain.linearRampToValueAtTime(0,this.audioContext.currentTime+(this.options.endTime-t));let e=!1;this.isFadingIn&&(t<this.options.startTime||t>this.options.fadeInEnd)&&(this.isFadingIn=!1,e=!0),this.isFadingOut&&(t<this.options.fadeOutStart||t>=this.options.endTime)&&(this.isFadingOut=!1,e=!0),e&&(this.gainNode.gain.cancelScheduledValues(this.audioContext.currentTime),this.gainNode.gain.value=this.volume)}));this.subscriptions.push(t)}getCurrentVolume(){return this.gainNode?this.gainNode.gain.value:this.volume}setStartTime(t){this.options.startTime=t,this.renderPolyline()}setEndTime(t){this.options.endTime=t,this.renderPolyline()}}const o=n})(),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.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:()=>p});const i=class{eventTarget;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)},r=String(t);return this.eventTarget.addEventListener(r,s,{once:i}),()=>this.eventTarget.removeEventListener(r,s)}once(t,e){return this.on(t,e,!0)}},s=class extends i{wavesurfer;container;wrapper;subscriptions=[];options;constructor(t){super(),this.options=t}init(t){this.wavesurfer=t.wavesurfer,this.container=t.container,this.wrapper=t.wrapper}destroy(){this.subscriptions.forEach((t=>t()))}},r=class extends i{options;container;scrollContainer;wrapper;canvasWrapper;progressWrapper;timeout=null;isScrolling=!1;audioData=null;resizeObserver=null;constructor(t){super(),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 ${this.options.hideScrollbar?"scrollbar-color: transparent;":""}\n }\n :host ::-webkit-scrollbar {\n display: ${this.options.hideScrollbar?"none":"auto"};\n }\n :host .wrapper {\n position: relative;\n min-width: 100%;\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 height: ${this.options.height}px;\n image-rendering: pixelated;\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: ${this.options.height}px;\n overflow: hidden;\n box-sizing: border-box;\n border-right-style: solid;\n border-right-width: ${this.options.cursorWidth}px;\n border-right-color: ${this.options.cursorColor||this.options.progressColor};\n }\n </style>\n\n <div class="scroll">\n <div class="wrapper">\n <div class="canvases"></div>\n <div class="progress"></div>\n </div>\n </div>\n `,this.container=i,this.scrollContainer=s.querySelector(".scroll"),this.wrapper=s.querySelector(".wrapper"),this.canvasWrapper=s.querySelector(".canvases"),this.progressWrapper=s.querySelector(".progress"),e.appendChild(i),this.wrapper.addEventListener("click",(t=>{const e=this.wrapper.getBoundingClientRect(),i=(t.clientX-e.left)/e.width;this.emit("click",{relativeX:i})})),this.resizeObserver=new ResizeObserver((()=>{this.delay((()=>this.audioData&&this.zoom(this.audioData,this.options.minPxPerSec)),100)})),this.resizeObserver.observe(this.scrollContainer)}getContainer(){return this.scrollContainer}getWrapper(){return this.wrapper}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?this.options.barWidth*s:1,n=null!=this.options.barGap?this.options.barGap*s:this.options.barWidth?r/2:0,o=this.options.barRadius??0,a=t[0],h=a.length,d=Math.floor(e/(r+n))/h,l=i/2,c=1===t.length,p=c?a:t[1],u=c&&p.some((t=>t<0)),m=(t,i)=>{let c=0,m=0,g=0;const v=document.createElement("canvas");v.width=Math.round(e*(i-t)/h),v.height=this.options.height,v.style.width=`${Math.floor(v.width/s)}px`,v.style.left=`${Math.floor(t*e/s/h)}px`,this.canvasWrapper.appendChild(v);const y=v.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>c){const t=Math.round(m*l),e=Math.round(g*l);y.roundRect(c*(r+n),l-t,r,t+e||1,o),c=i,m=0,g=0}const s=u?a[e]:Math.abs(a[e]),h=u?p[e]:Math.abs(p[e]);s>m&&(m=s),(u?h<-g:h>g)&&(g=h<0?-h:h)}y.fill(),y.closePath();const f=v.cloneNode();this.progressWrapper.appendChild(f);const b=f.getContext("2d",{desynchronized:!0});b.drawImage(v,0,0),b.globalCompositeOperation="source-in",b.fillStyle=this.options.progressColor,b.fillRect(0,0,v.width,v.height)};this.canvasWrapper.innerHTML="",this.progressWrapper.innerHTML="";const{scrollLeft:g,scrollWidth:v,clientWidth:y}=this.scrollContainer,f=h/v,b=Math.floor(g*f),w=Math.ceil(Math.min(v,g+y)*f);m(b,w);const C=w-b;for(let t=w;t<h;t+=C)await this.delay((()=>{m(t,Math.min(h,t+C))}));for(let t=b-1;t>=0;t-=C)await this.delay((()=>{m(Math.max(0,t-C),t)}))}render(t){const e=window.devicePixelRatio||1,i=this.options.fillParent?this.scrollContainer.clientWidth*e:0,s=Math.max(1,t.duration*this.options.minPxPerSec),r=s>i?s:i,{height:n}=this.options;this.isScrolling=r>i,this.scrollContainer.style.overflowX=this.isScrolling?"auto":"hidden",this.wrapper.style.width=`${Math.floor(r/e)}px`;const o=[t.getChannelData(0)];t.numberOfChannels>1&&o.push(t.getChannelData(1)),this.renderPeaks(o,r,n,e),this.audioData=t}zoom(t,e){const i=this.progressWrapper.clientWidth;this.options.minPxPerSec=e,this.render(t);const s=this.progressWrapper.clientWidth;this.scrollContainer.scrollLeft+=s-i}renderProgress(t,e=!1){if(this.progressWrapper.style.width=100*t+"%",this.isScrolling){const t=this.scrollContainer.clientWidth,i=t/2,s=this.progressWrapper.clientWidth,r=e?i:t;s>this.scrollContainer.scrollLeft+r&&(this.scrollContainer.scrollLeft=s-i)}}},n=class extends i{media;subscriptions=[];isExternalMedia=!1;hasPlayedOnce=!1;constructor(t){super(),t.media?(this.media=t.media,this.isExternalMedia=!0):this.media=document.createElement("audio"),this.subscriptions.push(this.onceMediaEvent("play",(()=>{this.hasPlayedOnce=!0}))),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})}loadUrl(t){this.media.src=t}destroy(){this.media.pause(),this.subscriptions.forEach((t=>t())),this.isExternalMedia||this.media.remove()}play(){this.media.play()}pause(){this.media.pause()}isPlaying(){return this.media.currentTime>0&&!this.media.paused&&!this.media.ended}seekTo(t){!this.hasPlayedOnce&&navigator.userAgent.match(/(iPad|iPhone|iPod)/g)&&this.media.play()?.then?.((()=>{setTimeout((()=>this.media.pause()),10)})),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}},o=class extends i{unsubscribe=()=>{};start(){this.unsubscribe=this.on("tick",(()=>{requestAnimationFrame((()=>{this.emit("tick")}))})),this.emit("tick")}stop(){this.unsubscribe()}destroy(){this.unsubscribe()}},a={height:128,waveColor:"#999",progressColor:"#555",cursorWidth:1,minPxPerSec:0,fillParent:!0,interact:!0,autoCenter:!0};class h extends n{options;fetcher;decoder;renderer;timer;plugins=[];decodedData=null;canPlay=!1;static create(t){return new h(t)}constructor(t){super({media:t.media,autoplay:t.autoplay,playbackRate:t.audioRate}),this.options=Object.assign({},a,t),this.fetcher=new class{async load(t){return fetch(t).then((t=>t.arrayBuffer()))}},this.decoder=new class{audioCtx=null;initAudioContext(t){this.audioCtx=new AudioContext({latencyHint:"playback",sampleRate:t})}constructor(){try{this.initAudioContext(3e3)}catch(t){this.initAudioContext(8e3)}}async decode(t){if(!this.audioCtx)throw new Error("AudioContext is not initialized");return this.audioCtx.decodeAudioData(t)}destroy(){this.audioCtx?.close(),this.audioCtx=null}},this.timer=new o,this.renderer=new r({container:this.options.container,height:this.options.height,waveColor:this.options.waveColor,progressColor:this.options.progressColor,cursorColor:this.options.cursorColor,cursorWidth:this.options.cursorWidth,minPxPerSec:this.options.minPxPerSec,fillParent:this.options.fillParent,barWidth:this.options.barWidth,barGap:this.options.barGap,barRadius:this.options.barRadius,hideScrollbar:this.options.hideScrollbar}),this.initPlayerEvents(),this.initRendererEvents(),this.initTimerEvents(),this.initReadyEvent(),this.initPlugins();const e=this.options.url||this.options.media?.src;e&&this.load(e,this.options.peaks,this.options.duration)}initPlayerEvents(){this.subscriptions.push(this.onMediaEvent("timeupdate",(()=>{const t=this.getCurrentTime();this.renderer.renderProgress(t/this.getDuration(),this.options.autoCenter&&this.isPlaying()),this.emit("timeupdate",{currentTime:t})})),this.onMediaEvent("play",(()=>{this.emit("play"),this.timer.start()})),this.onMediaEvent("pause",(()=>{this.emit("pause"),this.timer.stop()})),this.onMediaEvent("canplay",(()=>{this.canPlay=!0,this.emit("canplay",{duration:this.getDuration()})})),this.onMediaEvent("seeking",(()=>{this.emit("seeking",{currentTime:this.getCurrentTime()})})))}initRendererEvents(){this.subscriptions.push(this.renderer.on("click",(({relativeX:t})=>{if(this.options.interact){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(){const t=()=>{this.decodedData&&this.canPlay&&this.emit("ready",{duration: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({wavesurfer:this,container:this.renderer.getContainer(),wrapper:this.renderer.getWrapper()}),this.plugins.push(t),t.once("destroy",(()=>{this.plugins=this.plugins.filter((e=>e!==t))})),t}async load(t,e,i){if(this.decodedData=null,this.canPlay=!1,this.loadUrl(t),null==e){const e=await this.fetcher.load(t),i=await this.decoder.decode(e);this.decodedData=i}else i||(i=await new Promise((t=>{this.onceMediaEvent("loadedmetadata",(()=>t(this.getDuration())))}))||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})}zoom(t){if(!this.decodedData)throw new Error("No audio loaded");this.renderer.zoom(this.decodedData,t),this.emit("zoom",{minPxPerSec:t})}getDecodedData(){return this.decodedData}getDuration(){return this.decodedData?.duration||this.getMediaElement()?.duration||0}toggleInteractive(t){this.options.interact=t}destroy(){this.emit("destroy"),this.plugins.forEach((t=>t.destroy())),this.timer.destroy(),this.decoder.destroy(),this.renderer.destroy(),super.destroy()}}const d=h,l={height:50,overlayColor:"rgba(100, 100, 100, 0.1)"};class c extends s{options;minimapWrapper;miniWavesurfer=null;overlay;constructor(t){super(t),this.options=Object.assign({},l,t),this.minimapWrapper=this.initMinimapWrapper(),this.overlay=this.initOverlay()}static create(t){return new c(t)}init(t){if(super.init(t),!this.wavesurfer)throw Error("WaveSurfer is not initialized");this.container?.insertAdjacentElement("afterend",this.minimapWrapper),this.subscriptions.push(this.wavesurfer.on("decode",(()=>{this.initMinimap()})))}initMinimapWrapper(){const t=document.createElement("div");return t.style.position="relative",t}initOverlay(){const t=document.createElement("div");return t.setAttribute("style","position: absolute; z-index: 2; left: 0; top: 0; bottom: 0;"),t.style.backgroundColor=this.options.overlayColor,this.minimapWrapper.appendChild(t),t}initMinimap(){if(!this.wavesurfer||!this.wrapper)return;const t=this.wavesurfer.getDecodedData(),e=this.wavesurfer.getMediaElement();if(!t||!e)return;this.miniWavesurfer=d.create({...this.options,container:this.minimapWrapper,minPxPerSec:1,fillParent:!0,media:e,url:e.src,peaks:[t.getChannelData(0)],duration:t.duration});const i=Math.round(this.minimapWrapper.clientWidth/this.wrapper.clientWidth*100);this.overlay.style.width=`${i}%`,this.wavesurfer.on("timeupdate",(({currentTime:e})=>{const s=Math.max(0,Math.min(e/t.duration*100-i/2,100-i)).toFixed(2);this.overlay.style.left=`${s}%`}))}destroy(){this.miniWavesurfer?.destroy(),this.minimapWrapper.remove(),super.destroy()}}const p=c;return e.default})()));
|