wavesurfer.js 7.0.0-alpha.9 → 7.0.0-beta.10
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/LICENSE +29 -0
- package/README.md +137 -20
- package/dist/base-plugin.d.ts +6 -4
- package/dist/base-plugin.js +9 -3
- package/dist/decoder.d.ts +8 -7
- package/dist/decoder.js +43 -38
- package/dist/draggable.d.ts +1 -0
- package/dist/draggable.js +59 -0
- package/dist/event-emitter.d.ts +16 -10
- package/dist/event-emitter.js +38 -16
- package/dist/fetcher.d.ts +6 -3
- package/dist/fetcher.js +9 -15
- package/dist/player.d.ts +31 -11
- package/dist/player.js +58 -31
- package/dist/plugins/envelope.d.ts +71 -0
- package/dist/plugins/envelope.js +326 -0
- package/dist/plugins/envelope.min.cjs +1 -0
- package/dist/plugins/minimap.d.ts +39 -0
- package/dist/plugins/minimap.js +114 -0
- package/dist/plugins/minimap.min.cjs +1 -0
- package/dist/plugins/record.d.ts +28 -0
- package/dist/plugins/record.js +132 -0
- package/dist/plugins/record.min.cjs +1 -0
- package/dist/plugins/regions.d.ts +84 -43
- package/dist/plugins/regions.js +330 -195
- package/dist/plugins/regions.min.cjs +1 -0
- package/dist/plugins/spectrogram-fft.d.ts +9 -0
- package/dist/plugins/spectrogram-fft.js +150 -0
- package/dist/plugins/spectrogram.d.ts +72 -0
- package/dist/plugins/spectrogram.js +341 -0
- package/dist/plugins/spectrogram.min.cjs +1 -0
- package/dist/plugins/timeline.d.ts +25 -9
- package/dist/plugins/timeline.js +65 -24
- package/dist/plugins/timeline.min.cjs +1 -0
- package/dist/renderer.d.ts +32 -26
- package/dist/renderer.js +363 -167
- package/dist/timer.d.ts +1 -1
- package/dist/wavesurfer.d.ts +154 -0
- package/dist/wavesurfer.js +230 -0
- package/dist/wavesurfer.min.cjs +1 -0
- package/package.json +61 -28
- package/dist/index.d.ts +0 -117
- package/dist/index.js +0 -227
- package/dist/player-webaudio.d.ts +0 -8
- package/dist/player-webaudio.js +0 -32
- package/dist/plugins/multitrack.d.ts +0 -44
- package/dist/plugins/multitrack.js +0 -260
- package/dist/plugins/xmultitrack.d.ts +0 -44
- package/dist/plugins/xmultitrack.js +0 -260
- package/dist/react/useWavesurfer.d.ts +0 -5
- package/dist/react/useWavesurfer.js +0 -20
- package/dist/wavesurfer.Multitrack.min.js +0 -1
- package/dist/wavesurfer.Regions.min.js +0 -1
- package/dist/wavesurfer.Timeline.min.js +0 -1
- package/dist/wavesurfer.min.js +0 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2012-2023, katspaugh and contributors
|
|
4
|
+
All rights reserved.
|
|
5
|
+
|
|
6
|
+
Redistribution and use in source and binary forms, with or without
|
|
7
|
+
modification, are permitted provided that the following conditions are met:
|
|
8
|
+
|
|
9
|
+
* Redistributions of source code must retain the above copyright notice, this
|
|
10
|
+
list of conditions and the following disclaimer.
|
|
11
|
+
|
|
12
|
+
* Redistributions in binary form must reproduce the above copyright notice,
|
|
13
|
+
this list of conditions and the following disclaimer in the documentation
|
|
14
|
+
and/or other materials provided with the distribution.
|
|
15
|
+
|
|
16
|
+
* Neither the name of the copyright holder nor the names of its
|
|
17
|
+
contributors may be used to endorse or promote products derived from
|
|
18
|
+
this software without specific prior written permission.
|
|
19
|
+
|
|
20
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
21
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
22
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
23
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
24
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
25
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
26
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
27
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
28
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
29
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
package/README.md
CHANGED
|
@@ -1,48 +1,165 @@
|
|
|
1
|
-
# <img src="https://user-images.githubusercontent.com/381895/226091100-f5567a28-7736-4d37-8f84-e08f297b7e1a.png" alt="logo" height="60" valign="middle" /> wavesurfer.
|
|
1
|
+
# <img src="https://user-images.githubusercontent.com/381895/226091100-f5567a28-7736-4d37-8f84-e08f297b7e1a.png" alt="logo" height="60" valign="middle" /> wavesurfer.js
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/wavesurfer.js)
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## New TypeScript version
|
|
6
|
+
|
|
7
|
+
wavesurfer.js v7 beta is a TypeScript rewrite of wavesurfer.js that brings several improvements:
|
|
8
|
+
|
|
9
|
+
* Typed API for better development experience
|
|
10
|
+
* Enhanced decoding and rendering performance
|
|
11
|
+
* New and improved plugins
|
|
12
|
+
|
|
13
|
+
<img width="626" alt="waveform screenshot" src="https://github.com/katspaugh/wavesurfer.js/assets/381895/05f03bed-800e-4fa1-b09a-82a39a1c62ce">
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
ℹ️ Looking for the old stable version? V6 is here: https://github.com/katspaugh/wavesurfer.js/tree/v6
|
|
18
|
+
|
|
19
|
+
---
|
|
6
20
|
|
|
7
21
|
Try it out:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm install --save wavesurfer.js@beta
|
|
25
|
+
```
|
|
26
|
+
```js
|
|
27
|
+
import WaveSurfer from 'wavesurfer.js'
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Alternatively, import it from a CDN as a ES6 module directly in the browser:
|
|
31
|
+
|
|
32
|
+
```html
|
|
33
|
+
<script type="module">
|
|
34
|
+
import WaveSurfer from 'https://unpkg.com/wavesurfer.js@beta'
|
|
35
|
+
|
|
36
|
+
const wavesurfer = WaveSurfer.create({ ... })
|
|
37
|
+
</script>
|
|
8
38
|
```
|
|
9
|
-
|
|
39
|
+
|
|
40
|
+
Or, as a UMD script tag which exports the library as a global `WaveSurfer` variable:
|
|
41
|
+
```html
|
|
42
|
+
<script src="https://unpkg.com/wavesurfer.js@beta/dist/wavesurfer.min.cjs"></script>
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
To import a plugin, e.g. the Timeline plugin:
|
|
46
|
+
```js
|
|
47
|
+
import Timeline from 'https://unpkg.com/wavesurfer.js@beta/dist/plugins/timeline.js'
|
|
10
48
|
```
|
|
11
49
|
|
|
12
|
-
|
|
50
|
+
TypeScript types are included in the package, so there's no need to install `@types/wavesurfer.js`.
|
|
13
51
|
|
|
14
|
-
|
|
15
|
-
* Better architecture
|
|
16
|
-
* Minimize the available options and provide sensible defaults
|
|
17
|
-
* Improve the decoding and rendering performance
|
|
52
|
+
See more [examples](https://wavesurfer-js.org/examples).
|
|
18
53
|
|
|
19
|
-
##
|
|
54
|
+
## Documentation
|
|
20
55
|
|
|
21
|
-
|
|
56
|
+
See the documentation on wavesurfer.js [methods](http://wavesurfer-js.org/docs/methods), [options](http://wavesurfer-js.org/docs/options) and [events](http://wavesurfer-js.org/docs/events) on our website.
|
|
22
57
|
|
|
23
|
-
##
|
|
58
|
+
## Plugins
|
|
24
59
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
*
|
|
28
|
-
*
|
|
60
|
+
The "official" plugins have been completely rewritten and enhanced:
|
|
61
|
+
|
|
62
|
+
* [Regions](https://wavesurfer-js.org/examples/#regions.js) – visual overlays and markers for regions of audio
|
|
63
|
+
* [Timeline](https://wavesurfer-js.org/examples/#timeline.js) – displays notches and time labels below the waveform
|
|
64
|
+
* [Minimap](https://wavesurfer-js.org/examples/#minimap.js) – a small waveform that serves as a scrollbar for the main waveform
|
|
65
|
+
* [Envelope](https://wavesurfer-js.org/examples/#envelope.js) – a graphical interface to add fade-in and -out effects and control volume
|
|
66
|
+
* [Record](https://wavesurfer-js.org/examples/#record.js) – records audio from the microphone and renders a waveform
|
|
67
|
+
* [Spectrogram](https://wavesurfer-js.org/examples/#spectrogram.js) – visualization of an audio frequency spectrum
|
|
68
|
+
|
|
69
|
+
## CSS styling
|
|
70
|
+
|
|
71
|
+
wavesurfer.js v7 is rendered into a Shadow DOM tree. This isolates its CSS from the rest of the web page.
|
|
72
|
+
However, it's still possible to style various wavesurfer.js elements via CSS using the `::part()` pseudo-selector.
|
|
73
|
+
For example:
|
|
74
|
+
|
|
75
|
+
```css
|
|
76
|
+
#waveform ::part(cursor):before {
|
|
77
|
+
content: '🏄';
|
|
78
|
+
}
|
|
79
|
+
#waveform ::part(region) {
|
|
80
|
+
font-family: fantasy;
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
You can see which elements you can style in the DOM inspector – they will have a `part` attribute.
|
|
85
|
+
See [this example](https://wavesurfer-js.org/examples/#styling.js) for play around with styling.
|
|
86
|
+
|
|
87
|
+
## Upgrading from v6
|
|
88
|
+
|
|
89
|
+
Most options, events, and methods are similar to those in previous versions.
|
|
90
|
+
|
|
91
|
+
### Notable differences
|
|
92
|
+
* The `backend` option is removed – [HTML5 audio (or video) is the only playback mechanism](https://github.com/katspaugh/wavesurfer.js/discussions/2762#discussioncomment-5669347). However, you can still connect wavesurfer to Web Audio via `MediaElementSourceNode`. See this [example](https://wavesurfer-js.org/examples/#webaudio.js).
|
|
93
|
+
* The Markers plugin is removed – use the Regions plugin with just a `startTime`.
|
|
94
|
+
* No Microphone plugn – superseded by the new Record plugin with more features.
|
|
95
|
+
* No Cursor and Playhead plugins yet – to be done.
|
|
96
|
+
|
|
97
|
+
### Removed options
|
|
98
|
+
* `backend`, `audioContext`, `closeAudioContext', 'audioScriptProcessor` – there's no Web Audio backend, so no AudioContext
|
|
99
|
+
* `autoCenterImmediately` – `autoCenter` is now always immediate unless the audio is playing
|
|
100
|
+
* `backgroundColor`, `hideCursor` – this can be easily set via CSS
|
|
101
|
+
* `mediaType`, `mediaControls` – you should instead pass an entire media element in the `media` option. [Example](https://wavesurfer-js.org/examples/#video.js).
|
|
102
|
+
* `partialRender` – done by default
|
|
103
|
+
* `pixelRatio` – `window.devicePixelRatio` is used by default
|
|
104
|
+
* `renderer` – there's just one renderer for now, so no need for this option
|
|
105
|
+
* `responsive` – responsiveness is enabled by default
|
|
106
|
+
* `scrollParent` – the container will scroll if `minPxPerSec` is set to a higher value
|
|
107
|
+
* `skipLength` – there's no `skipForward` and `skipBackward` methods anymore
|
|
108
|
+
* `splitChannelsOptions` – you should now use `splitChannels` to pass the channel options. Pass `height: 0` to hide a channel. See [this example](https://wavesurfer-js.org/examples/#split-channels.js).
|
|
109
|
+
* `xhr`, `drawingContextAttributes`, `maxCanvasWidth`, `forceDecode` – removed to reduce code complexity
|
|
110
|
+
|
|
111
|
+
### Removed methods
|
|
112
|
+
* `getFilters`, `setFilter` – as there's no Web Audio "backend"
|
|
113
|
+
* `drawBuffer` – to redraw the waveform, use `setOptions` instead and pass new rendering options
|
|
114
|
+
* `cancelAjax` – ajax is replaced by `fetch`
|
|
115
|
+
* `loadBlob` – use `URL.createObjectURL()` to convert a blob to a URL and call `load(url)` instead
|
|
116
|
+
* `skipForward`, `skipBackward`, `setPlayEnd` – can be implemented using `setTime(time)`
|
|
117
|
+
* `exportPCM` is renamed to `getDecodedData` and doesn't take any params
|
|
118
|
+
* `toggleMute` is now called `setMuted(true | false)`
|
|
119
|
+
* `setHeight`, `setWaveColor`, `setCursorColor`, etc. – use `setOptions` with the corresponding params instead. E.g., `wavesurfer.setOptions({ height: 300, waveColor: '#abc' })`
|
|
120
|
+
|
|
121
|
+
See the complete [documentation of the new API](http://wavesurfer-js.org/docs/methods).
|
|
122
|
+
|
|
123
|
+
## Questions
|
|
124
|
+
|
|
125
|
+
Have a question about integrating wavesurfer.js on your website? Feel free to ask in our [Discussions forum](https://github.com/wavesurfer-js/wavesurfer.js/discussions/categories/q-a).
|
|
126
|
+
|
|
127
|
+
### FAQ
|
|
128
|
+
|
|
129
|
+
* **Q**: Does wavesurfer support large files?
|
|
130
|
+
* **A**: Since wavesurfer decodes audio entirely in the browser, large files may fail to decode due to memory constraints. We recommend using pre-decoded peaks for large files (see [this example](https://wavesurfer-js.org/examples/#predecoded.js)). You can use a tool like [bbc/audiowaveform](https://github.com/bbc/audiowaveform) to generate peaks.
|
|
29
131
|
|
|
30
132
|
## Development
|
|
31
133
|
|
|
32
|
-
|
|
134
|
+
To get started with development, follow these steps:
|
|
135
|
+
|
|
136
|
+
1. Install dev dependencies:
|
|
33
137
|
|
|
34
138
|
```
|
|
35
139
|
yarn
|
|
36
140
|
```
|
|
37
141
|
|
|
38
|
-
Start the TypeScript compiler in watch mode and an HTTP server:
|
|
142
|
+
2. Start the TypeScript compiler in watch mode and launch an HTTP server:
|
|
39
143
|
|
|
40
144
|
```
|
|
41
145
|
yarn start
|
|
42
146
|
```
|
|
43
147
|
|
|
44
|
-
This will open http://localhost:9090
|
|
148
|
+
This command will open http://localhost:9090 in your browser with live reload, allowing you to see the changes as you develop.
|
|
149
|
+
|
|
150
|
+
## Tests
|
|
151
|
+
|
|
152
|
+
The tests are written in the Cypress framework. They are a mix of e2e and visual regression tests.
|
|
153
|
+
To run the test suite locally:
|
|
154
|
+
|
|
155
|
+
```
|
|
156
|
+
yarn cypress
|
|
157
|
+
```
|
|
45
158
|
|
|
46
159
|
## Feedback
|
|
47
160
|
|
|
48
|
-
|
|
161
|
+
We appreciate your feedback and contributions! Join the conversation and share your thoughts here: https://github.com/wavesurfer-js/wavesurfer.js/discussions/2789
|
|
162
|
+
|
|
163
|
+
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.
|
|
164
|
+
|
|
165
|
+
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,11 +1,13 @@
|
|
|
1
1
|
import EventEmitter, { type GeneralEventTypes } from './event-emitter.js';
|
|
2
|
-
import type
|
|
2
|
+
import type WaveSurfer from './wavesurfer.js';
|
|
3
|
+
export type GenericPlugin = BasePlugin<GeneralEventTypes, unknown>;
|
|
3
4
|
export declare class BasePlugin<EventTypes extends GeneralEventTypes, Options> extends EventEmitter<EventTypes> {
|
|
4
|
-
protected wavesurfer
|
|
5
|
-
protected container: HTMLElement;
|
|
5
|
+
protected wavesurfer?: WaveSurfer;
|
|
6
6
|
protected subscriptions: (() => void)[];
|
|
7
7
|
protected options: Options;
|
|
8
|
-
constructor(
|
|
8
|
+
constructor(options: Options);
|
|
9
|
+
onInit(): void;
|
|
10
|
+
init(wavesurfer: WaveSurfer): void;
|
|
9
11
|
destroy(): void;
|
|
10
12
|
}
|
|
11
13
|
export default BasePlugin;
|
package/dist/base-plugin.js
CHANGED
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
import EventEmitter from './event-emitter.js';
|
|
2
2
|
export class BasePlugin extends EventEmitter {
|
|
3
|
-
constructor(
|
|
3
|
+
constructor(options) {
|
|
4
4
|
super();
|
|
5
5
|
this.subscriptions = [];
|
|
6
|
-
this.wavesurfer = params.wavesurfer;
|
|
7
|
-
this.container = params.container;
|
|
8
6
|
this.options = options;
|
|
9
7
|
}
|
|
8
|
+
onInit() {
|
|
9
|
+
// Overridden in plugin definition
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
init(wavesurfer) {
|
|
13
|
+
this.wavesurfer = wavesurfer;
|
|
14
|
+
this.onInit();
|
|
15
|
+
}
|
|
10
16
|
destroy() {
|
|
11
17
|
this.subscriptions.forEach((unsubscribe) => unsubscribe());
|
|
12
18
|
}
|
package/dist/decoder.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
/** Decode an array buffer into an audio buffer */
|
|
2
|
+
declare function decode(audioData: ArrayBuffer, sampleRate: number): Promise<AudioBuffer>;
|
|
3
|
+
/** Create an audio buffer from pre-decoded audio data */
|
|
4
|
+
declare function createBuffer(channelData: Array<Float32Array | number[]>, duration: number): AudioBuffer;
|
|
5
|
+
declare const Decoder: {
|
|
6
|
+
decode: typeof decode;
|
|
7
|
+
createBuffer: typeof createBuffer;
|
|
8
|
+
};
|
|
8
9
|
export default Decoder;
|
package/dist/decoder.js
CHANGED
|
@@ -1,43 +1,48 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
this.audioCtx = null;
|
|
19
|
-
// Minimum sample rate supported by Web Audio API
|
|
20
|
-
const DEFAULT_SAMPLE_RATE = 3000; // Chrome, Safari
|
|
21
|
-
const FALLBACK_SAMPLE_RATE = 8000; // Firefox
|
|
22
|
-
try {
|
|
23
|
-
this.initAudioContext(DEFAULT_SAMPLE_RATE);
|
|
24
|
-
}
|
|
25
|
-
catch (e) {
|
|
26
|
-
this.initAudioContext(FALLBACK_SAMPLE_RATE);
|
|
1
|
+
/** Decode an array buffer into an audio buffer */
|
|
2
|
+
async function decode(audioData, sampleRate) {
|
|
3
|
+
const audioCtx = new AudioContext({ sampleRate });
|
|
4
|
+
const decode = audioCtx.decodeAudioData(audioData);
|
|
5
|
+
decode.finally(() => audioCtx.close());
|
|
6
|
+
return decode;
|
|
7
|
+
}
|
|
8
|
+
/** Normalize peaks to -1..1 */
|
|
9
|
+
function normalize(channelData) {
|
|
10
|
+
const firstChannel = channelData[0];
|
|
11
|
+
if (firstChannel.some((n) => n > 1 || n < -1)) {
|
|
12
|
+
const length = firstChannel.length;
|
|
13
|
+
let max = 0;
|
|
14
|
+
for (let i = 0; i < length; i++) {
|
|
15
|
+
const absN = Math.abs(firstChannel[i]);
|
|
16
|
+
if (absN > max)
|
|
17
|
+
max = absN;
|
|
27
18
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
if (!this.audioCtx) {
|
|
32
|
-
throw new Error('AudioContext is not initialized');
|
|
19
|
+
for (const channel of channelData) {
|
|
20
|
+
for (let i = 0; i < length; i++) {
|
|
21
|
+
channel[i] /= max;
|
|
33
22
|
}
|
|
34
|
-
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
destroy() {
|
|
38
|
-
var _a;
|
|
39
|
-
(_a = this.audioCtx) === null || _a === void 0 ? void 0 : _a.close();
|
|
40
|
-
this.audioCtx = null;
|
|
23
|
+
}
|
|
41
24
|
}
|
|
25
|
+
return channelData;
|
|
42
26
|
}
|
|
27
|
+
/** Create an audio buffer from pre-decoded audio data */
|
|
28
|
+
function createBuffer(channelData, duration) {
|
|
29
|
+
// If a single array of numbers is passed, make it an array of arrays
|
|
30
|
+
if (typeof channelData[0] === 'number')
|
|
31
|
+
channelData = [channelData];
|
|
32
|
+
// Normalize to -1..1
|
|
33
|
+
normalize(channelData);
|
|
34
|
+
return {
|
|
35
|
+
duration,
|
|
36
|
+
length: channelData[0].length,
|
|
37
|
+
sampleRate: channelData[0].length / duration,
|
|
38
|
+
numberOfChannels: channelData.length,
|
|
39
|
+
getChannelData: (i) => channelData?.[i],
|
|
40
|
+
copyFromChannel: AudioBuffer.prototype.copyFromChannel,
|
|
41
|
+
copyToChannel: AudioBuffer.prototype.copyToChannel,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
const Decoder = {
|
|
45
|
+
decode,
|
|
46
|
+
createBuffer,
|
|
47
|
+
};
|
|
43
48
|
export default Decoder;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function makeDraggable(element: HTMLElement | null, onDrag: (dx: number, dy: number, x: number, y: number) => void, onStart?: (x: number, y: number) => void, onEnd?: () => void, threshold?: number): () => void;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
export function makeDraggable(element, onDrag, onStart, onEnd, threshold = 5) {
|
|
2
|
+
let unsub = () => {
|
|
3
|
+
return;
|
|
4
|
+
};
|
|
5
|
+
if (!element)
|
|
6
|
+
return unsub;
|
|
7
|
+
const down = (e) => {
|
|
8
|
+
e.preventDefault();
|
|
9
|
+
e.stopPropagation();
|
|
10
|
+
let startX = e.clientX;
|
|
11
|
+
let startY = e.clientY;
|
|
12
|
+
let isDragging = false;
|
|
13
|
+
const move = (e) => {
|
|
14
|
+
e.preventDefault();
|
|
15
|
+
e.stopPropagation();
|
|
16
|
+
const x = e.clientX;
|
|
17
|
+
const y = e.clientY;
|
|
18
|
+
if (isDragging || Math.abs(x - startX) >= threshold || Math.abs(y - startY) >= threshold) {
|
|
19
|
+
if (!isDragging) {
|
|
20
|
+
isDragging = true;
|
|
21
|
+
onStart?.(startX, startY);
|
|
22
|
+
}
|
|
23
|
+
const { left, top } = element.getBoundingClientRect();
|
|
24
|
+
onDrag(x - startX, y - startY, x - left, y - top);
|
|
25
|
+
startX = x;
|
|
26
|
+
startY = y;
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
const click = (e) => {
|
|
30
|
+
if (isDragging) {
|
|
31
|
+
e.preventDefault();
|
|
32
|
+
e.stopPropagation();
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
const up = () => {
|
|
36
|
+
if (isDragging) {
|
|
37
|
+
onEnd?.();
|
|
38
|
+
}
|
|
39
|
+
unsub();
|
|
40
|
+
};
|
|
41
|
+
unsub = () => {
|
|
42
|
+
document.removeEventListener('pointermove', move);
|
|
43
|
+
document.removeEventListener('pointerup', up);
|
|
44
|
+
document.removeEventListener('pointerleave', up);
|
|
45
|
+
setTimeout(() => {
|
|
46
|
+
document.removeEventListener('click', click, true);
|
|
47
|
+
}, 10);
|
|
48
|
+
};
|
|
49
|
+
document.addEventListener('pointermove', move);
|
|
50
|
+
document.addEventListener('pointerup', up);
|
|
51
|
+
document.addEventListener('pointerleave', up);
|
|
52
|
+
document.addEventListener('click', click, true);
|
|
53
|
+
};
|
|
54
|
+
element.addEventListener('pointerdown', down);
|
|
55
|
+
return () => {
|
|
56
|
+
unsub();
|
|
57
|
+
element.removeEventListener('pointerdown', down);
|
|
58
|
+
};
|
|
59
|
+
}
|
package/dist/event-emitter.d.ts
CHANGED
|
@@ -1,13 +1,19 @@
|
|
|
1
|
-
export
|
|
2
|
-
[
|
|
3
|
-
}
|
|
1
|
+
export type GeneralEventTypes = {
|
|
2
|
+
[EventName: string]: any[];
|
|
3
|
+
};
|
|
4
|
+
type EventListener<EventTypes extends GeneralEventTypes, EventName extends keyof EventTypes> = (...args: EventTypes[EventName]) => void;
|
|
5
|
+
/** A simple event emitter that can be used to listen to and emit events. */
|
|
4
6
|
declare class EventEmitter<EventTypes extends GeneralEventTypes> {
|
|
5
|
-
private
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
/** Subscribe to an event
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
|
|
7
|
+
private listeners;
|
|
8
|
+
/** Subscribe to an event. Returns an unsubscribe function. */
|
|
9
|
+
on<EventName extends keyof EventTypes>(eventName: EventName, listener: EventListener<EventTypes, EventName>): () => void;
|
|
10
|
+
/** Subscribe to an event only once */
|
|
11
|
+
once<EventName extends keyof EventTypes>(eventName: EventName, listener: EventListener<EventTypes, EventName>): () => void;
|
|
12
|
+
/** Unsubscribe from an event */
|
|
13
|
+
un<EventName extends keyof EventTypes>(eventName: EventName, listener: EventListener<EventTypes, EventName>): void;
|
|
14
|
+
/** Clear all events */
|
|
15
|
+
unAll(): void;
|
|
16
|
+
/** Emit an event */
|
|
17
|
+
protected emit<EventName extends keyof EventTypes>(eventName: EventName, ...args: EventTypes[EventName]): void;
|
|
12
18
|
}
|
|
13
19
|
export default EventEmitter;
|
package/dist/event-emitter.js
CHANGED
|
@@ -1,25 +1,47 @@
|
|
|
1
|
+
/** A simple event emitter that can be used to listen to and emit events. */
|
|
1
2
|
class EventEmitter {
|
|
2
3
|
constructor() {
|
|
3
|
-
this.
|
|
4
|
+
this.listeners = {};
|
|
4
5
|
}
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
this.
|
|
6
|
+
/** Subscribe to an event. Returns an unsubscribe function. */
|
|
7
|
+
on(eventName, listener) {
|
|
8
|
+
if (!this.listeners[eventName]) {
|
|
9
|
+
this.listeners[eventName] = new Set();
|
|
10
|
+
}
|
|
11
|
+
this.listeners[eventName].add(listener);
|
|
12
|
+
return () => this.un(eventName, listener);
|
|
8
13
|
}
|
|
9
|
-
/** Subscribe to an event
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
+
/** Subscribe to an event only once */
|
|
15
|
+
once(eventName, listener) {
|
|
16
|
+
// The actual subscription
|
|
17
|
+
const unsubscribe = this.on(eventName, listener);
|
|
18
|
+
// Another subscription that will unsubscribe the actual subscription and itself after the first event
|
|
19
|
+
const unsubscribeOnce = this.on(eventName, () => {
|
|
20
|
+
unsubscribe();
|
|
21
|
+
unsubscribeOnce();
|
|
22
|
+
});
|
|
23
|
+
return unsubscribe;
|
|
24
|
+
}
|
|
25
|
+
/** Unsubscribe from an event */
|
|
26
|
+
un(eventName, listener) {
|
|
27
|
+
if (this.listeners[eventName]) {
|
|
28
|
+
if (listener) {
|
|
29
|
+
this.listeners[eventName].delete(listener);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
delete this.listeners[eventName];
|
|
14
33
|
}
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/** Clear all events */
|
|
37
|
+
unAll() {
|
|
38
|
+
this.listeners = {};
|
|
19
39
|
}
|
|
20
|
-
/**
|
|
21
|
-
|
|
22
|
-
|
|
40
|
+
/** Emit an event */
|
|
41
|
+
emit(eventName, ...args) {
|
|
42
|
+
if (this.listeners[eventName]) {
|
|
43
|
+
this.listeners[eventName].forEach((listener) => listener(...args));
|
|
44
|
+
}
|
|
23
45
|
}
|
|
24
46
|
}
|
|
25
47
|
export default EventEmitter;
|
package/dist/fetcher.d.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
declare
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
declare function fetchArrayBuffer(url: string): Promise<ArrayBuffer>;
|
|
2
|
+
declare function fetchBlob(url: string): Promise<Blob>;
|
|
3
|
+
declare const Fetcher: {
|
|
4
|
+
fetchArrayBuffer: typeof fetchArrayBuffer;
|
|
5
|
+
fetchBlob: typeof fetchBlob;
|
|
6
|
+
};
|
|
4
7
|
export default Fetcher;
|
package/dist/fetcher.js
CHANGED
|
@@ -1,17 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
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
|
-
class Fetcher {
|
|
11
|
-
load(url) {
|
|
12
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
13
|
-
return fetch(url).then((response) => response.arrayBuffer());
|
|
14
|
-
});
|
|
15
|
-
}
|
|
1
|
+
async function fetchArrayBuffer(url) {
|
|
2
|
+
return fetch(url).then((response) => response.arrayBuffer());
|
|
3
|
+
}
|
|
4
|
+
async function fetchBlob(url) {
|
|
5
|
+
return fetch(url).then((response) => response.blob());
|
|
16
6
|
}
|
|
7
|
+
const Fetcher = {
|
|
8
|
+
fetchArrayBuffer,
|
|
9
|
+
fetchBlob,
|
|
10
|
+
};
|
|
17
11
|
export default Fetcher;
|
package/dist/player.d.ts
CHANGED
|
@@ -1,25 +1,45 @@
|
|
|
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;
|
|
3
9
|
private isExternalMedia;
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
on(event: keyof HTMLMediaElementEventMap, callback: () => void, options?: AddEventListenerOptions): () => void;
|
|
10
|
+
constructor(options: PlayerOptions);
|
|
11
|
+
protected onMediaEvent(event: keyof HTMLMediaElementEventMap, callback: () => void, options?: AddEventListenerOptions): () => void;
|
|
12
|
+
protected onceMediaEvent(event: keyof HTMLMediaElementEventMap, callback: () => void): () => void;
|
|
13
|
+
private revokeSrc;
|
|
14
|
+
protected setSrc(url: string, blob?: Blob): void;
|
|
10
15
|
destroy(): void;
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
16
|
+
/** Start playing the audio */
|
|
17
|
+
play(): Promise<void>;
|
|
18
|
+
/** Pause the audio */
|
|
14
19
|
pause(): void;
|
|
20
|
+
/** Check if the audio is playing */
|
|
15
21
|
isPlaying(): boolean;
|
|
16
|
-
|
|
22
|
+
/** Jumpt to a specific time in the audio (in seconds) */
|
|
23
|
+
setTime(time: number): void;
|
|
24
|
+
/** Get the duration of the audio in seconds */
|
|
17
25
|
getDuration(): number;
|
|
26
|
+
/** Get the current audio position in seconds */
|
|
27
|
+
getCurrentTime(): number;
|
|
28
|
+
/** Get the audio volume */
|
|
18
29
|
getVolume(): number;
|
|
30
|
+
/** Set the audio volume */
|
|
19
31
|
setVolume(volume: number): void;
|
|
32
|
+
/** Get the audio muted state */
|
|
20
33
|
getMuted(): boolean;
|
|
34
|
+
/** Mute or unmute the audio */
|
|
21
35
|
setMuted(muted: boolean): void;
|
|
36
|
+
/** Get the playback speed */
|
|
22
37
|
getPlaybackRate(): number;
|
|
38
|
+
/** Set the playback speed, pass an optional false to NOT preserve the pitch */
|
|
23
39
|
setPlaybackRate(rate: number, preservePitch?: boolean): void;
|
|
40
|
+
/** Get the HTML media element */
|
|
41
|
+
getMediaElement(): HTMLMediaElement;
|
|
42
|
+
/** Set a sink id to change the audio output device */
|
|
43
|
+
setSinkId(sinkId: string): Promise<void>;
|
|
24
44
|
}
|
|
25
45
|
export default Player;
|