wavesurfer.js 6.5.1 → 7.0.0-alpha.0

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 (132) hide show
  1. package/.eslintrc.json +24 -0
  2. package/.prettierrc +8 -0
  3. package/README.md +26 -117
  4. package/dist/base-plugin.d.ts +10 -0
  5. package/dist/base-plugin.js +13 -0
  6. package/dist/decoder.d.ts +10 -0
  7. package/dist/decoder.js +43 -0
  8. package/dist/event-emitter.d.ts +11 -0
  9. package/dist/event-emitter.js +21 -0
  10. package/dist/fetcher.d.ts +4 -0
  11. package/dist/fetcher.js +17 -0
  12. package/dist/index.d.ts +92 -0
  13. package/dist/index.js +166 -0
  14. package/dist/player-webaudio.d.ts +8 -0
  15. package/dist/player-webaudio.js +31 -0
  16. package/dist/player.d.ts +16 -0
  17. package/dist/player.js +40 -0
  18. package/dist/plugins/regions.d.ts +48 -0
  19. package/dist/plugins/regions.js +183 -0
  20. package/dist/renderer.d.ts +34 -0
  21. package/dist/renderer.js +193 -0
  22. package/dist/timer.d.ts +10 -0
  23. package/dist/timer.js +17 -0
  24. package/examples/audio.ogg +0 -0
  25. package/examples/bars.js +19 -0
  26. package/examples/basic.js +8 -0
  27. package/examples/gradient.js +28 -0
  28. package/examples/regions.js +63 -0
  29. package/examples/video.js +19 -0
  30. package/examples/webaudio.js +14 -0
  31. package/package.json +19 -99
  32. package/src/base-plugin.ts +20 -0
  33. package/src/decoder.ts +41 -0
  34. package/src/event-emitter.ts +35 -0
  35. package/src/fetcher.ts +7 -0
  36. package/src/index.ts +252 -0
  37. package/src/player-webaudio.ts +34 -0
  38. package/src/player.ts +50 -0
  39. package/src/plugins/regions.ts +240 -0
  40. package/src/renderer.ts +250 -0
  41. package/src/timer.ts +27 -0
  42. package/tsconfig.json +105 -0
  43. package/tutorial/index.html +47 -0
  44. package/tutorial/src/editor.js +70 -0
  45. package/tutorial/src/init.js +66 -0
  46. package/tutorial/src/url.js +25 -0
  47. package/tutorial/style.css +211 -0
  48. package/yarn-error.log +1049 -0
  49. package/LICENSE +0 -29
  50. package/dist/plugin/wavesurfer.cursor.js +0 -418
  51. package/dist/plugin/wavesurfer.cursor.js.map +0 -1
  52. package/dist/plugin/wavesurfer.cursor.min.js +0 -7
  53. package/dist/plugin/wavesurfer.cursor.min.js.map +0 -1
  54. package/dist/plugin/wavesurfer.elan.js +0 -381
  55. package/dist/plugin/wavesurfer.elan.js.map +0 -1
  56. package/dist/plugin/wavesurfer.elan.min.js +0 -7
  57. package/dist/plugin/wavesurfer.elan.min.js.map +0 -1
  58. package/dist/plugin/wavesurfer.markers.js +0 -520
  59. package/dist/plugin/wavesurfer.markers.js.map +0 -1
  60. package/dist/plugin/wavesurfer.markers.min.js +0 -7
  61. package/dist/plugin/wavesurfer.markers.min.js.map +0 -1
  62. package/dist/plugin/wavesurfer.mediasession.js +0 -181
  63. package/dist/plugin/wavesurfer.mediasession.js.map +0 -1
  64. package/dist/plugin/wavesurfer.mediasession.min.js +0 -7
  65. package/dist/plugin/wavesurfer.mediasession.min.js.map +0 -1
  66. package/dist/plugin/wavesurfer.microphone.js +0 -466
  67. package/dist/plugin/wavesurfer.microphone.js.map +0 -1
  68. package/dist/plugin/wavesurfer.microphone.min.js +0 -7
  69. package/dist/plugin/wavesurfer.microphone.min.js.map +0 -1
  70. package/dist/plugin/wavesurfer.minimap.js +0 -440
  71. package/dist/plugin/wavesurfer.minimap.js.map +0 -1
  72. package/dist/plugin/wavesurfer.minimap.min.js +0 -7
  73. package/dist/plugin/wavesurfer.minimap.min.js.map +0 -1
  74. package/dist/plugin/wavesurfer.playhead.js +0 -300
  75. package/dist/plugin/wavesurfer.playhead.js.map +0 -1
  76. package/dist/plugin/wavesurfer.playhead.min.js +0 -7
  77. package/dist/plugin/wavesurfer.playhead.min.js.map +0 -1
  78. package/dist/plugin/wavesurfer.regions.js +0 -1335
  79. package/dist/plugin/wavesurfer.regions.js.map +0 -1
  80. package/dist/plugin/wavesurfer.regions.min.js +0 -7
  81. package/dist/plugin/wavesurfer.regions.min.js.map +0 -1
  82. package/dist/plugin/wavesurfer.spectrogram.js +0 -736
  83. package/dist/plugin/wavesurfer.spectrogram.js.map +0 -1
  84. package/dist/plugin/wavesurfer.spectrogram.min.js +0 -7
  85. package/dist/plugin/wavesurfer.spectrogram.min.js.map +0 -1
  86. package/dist/plugin/wavesurfer.timeline.js +0 -649
  87. package/dist/plugin/wavesurfer.timeline.js.map +0 -1
  88. package/dist/plugin/wavesurfer.timeline.min.js +0 -7
  89. package/dist/plugin/wavesurfer.timeline.min.js.map +0 -1
  90. package/dist/wavesurfer-html-init.js +0 -381
  91. package/dist/wavesurfer-html-init.js.map +0 -1
  92. package/dist/wavesurfer-html-init.min.js +0 -7
  93. package/dist/wavesurfer-html-init.min.js.map +0 -1
  94. package/dist/wavesurfer.js +0 -6145
  95. package/dist/wavesurfer.js.map +0 -1
  96. package/dist/wavesurfer.min.js +0 -7
  97. package/dist/wavesurfer.min.js.map +0 -1
  98. package/src/drawer.canvasentry.js +0 -427
  99. package/src/drawer.js +0 -413
  100. package/src/drawer.multicanvas.js +0 -617
  101. package/src/html-init.js +0 -241
  102. package/src/mediaelement-webaudio.js +0 -77
  103. package/src/mediaelement.js +0 -443
  104. package/src/peakcache.js +0 -127
  105. package/src/plugin/cursor/index.js +0 -350
  106. package/src/plugin/elan/index.js +0 -307
  107. package/src/plugin/markers/index.js +0 -436
  108. package/src/plugin/mediasession/index.js +0 -94
  109. package/src/plugin/microphone/index.js +0 -415
  110. package/src/plugin/minimap/index.js +0 -403
  111. package/src/plugin/playhead/index.js +0 -226
  112. package/src/plugin/regions/index.js +0 -478
  113. package/src/plugin/regions/region.js +0 -875
  114. package/src/plugin/spectrogram/fft.js +0 -222
  115. package/src/plugin/spectrogram/index.js +0 -522
  116. package/src/plugin/timeline/index.js +0 -600
  117. package/src/util/absMax.js +0 -16
  118. package/src/util/clamp.js +0 -11
  119. package/src/util/fetch.js +0 -222
  120. package/src/util/frame.js +0 -13
  121. package/src/util/get-id.js +0 -22
  122. package/src/util/index.js +0 -14
  123. package/src/util/max.js +0 -16
  124. package/src/util/min.js +0 -16
  125. package/src/util/observer.js +0 -144
  126. package/src/util/orientation.js +0 -98
  127. package/src/util/prevent-click.js +0 -19
  128. package/src/util/request-animation-frame.js +0 -15
  129. package/src/util/silence-mode.js +0 -42
  130. package/src/util/style.js +0 -16
  131. package/src/wavesurfer.js +0 -1797
  132. package/src/webaudio.js +0 -779
package/.eslintrc.json ADDED
@@ -0,0 +1,24 @@
1
+ {
2
+ "env": {
3
+ "browser": true,
4
+ "es2021": true
5
+ },
6
+ "extends": [
7
+ "eslint:recommended",
8
+ "plugin:@typescript-eslint/recommended",
9
+ "prettier",
10
+ "plugin:prettier/recommended"
11
+ ],
12
+ "overrides": [
13
+ ],
14
+ "parser": "@typescript-eslint/parser",
15
+ "parserOptions": {
16
+ "ecmaVersion": "latest",
17
+ "sourceType": "module"
18
+ },
19
+ "plugins": [
20
+ "@typescript-eslint"
21
+ ],
22
+ "rules": {
23
+ }
24
+ }
package/.prettierrc ADDED
@@ -0,0 +1,8 @@
1
+ {
2
+ "tabWidth": 2,
3
+ "printWidth": 120,
4
+ "trailingComma": "all",
5
+ "singleQuote": true,
6
+ "semi": false,
7
+ "endOfLine": "auto"
8
+ }
package/README.md CHANGED
@@ -1,141 +1,50 @@
1
- # [wavesurfer.js](https://wavesurfer-js.org)
1
+ # wavesurfer.ts
2
2
 
3
- [![npm version](https://img.shields.io/npm/v/wavesurfer.js.svg?style=flat)](https://www.npmjs.com/package/wavesurfer.js)
4
- ![npm](https://img.shields.io/npm/dm/wavesurfer.js.svg) [![Join the chat at https://gitter.im/wavesurfer-js/wavesurfer.js](https://badges.gitter.im/wavesurfer-js/wavesurfer.js.svg)](https://gitter.im/wavesurfer-js/wavesurfer.js?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
5
- [![GitPOAP Badge](https://public-api.gitpoap.io/v1/repo/wavesurfer-js/wavesurfer.js/badge)](https://www.gitpoap.io/gh/wavesurfer-js/wavesurfer.js)
3
+ An experimental rewrite of [wavesufer.js](https://github.com/wavesurfer-js/wavesurfer.js) to play around with new ideas.
6
4
 
7
- Interactive navigable audio visualization using Web Audio and Canvas.
5
+ ## Goals
8
6
 
9
- [![Screenshot](https://raw.githubusercontent.com/wavesurfer-js/wavesurfer.js/gh-pages/example/screenshot.png "Screenshot")](https://wavesurfer-js.org)
7
+ * TypeScript API
8
+ * Better architecture
9
+ * Minimize the available options and provide sensible defaults
10
+ * Improve the decoding and rendering performance
10
11
 
11
- See a [tutorial](https://wavesurfer-js.org/docs) and [examples](https://wavesurfer-js.org/examples) on [wavesurfer-js.org](https://wavesurfer-js.org).
12
+ ## Non-goals
12
13
 
13
- ## Questions
14
- Have a question about integrating wavesurfer.js on your website? Feel free to ask in our forum: https://github.com/wavesurfer-js/wavesurfer.js/discussions/categories/q-a
14
+ Keeping backwards compatibility with earlier versions of wavesurfer.js.
15
15
 
16
- ## Quick start
17
- Install the package:
16
+ ## Architecture
18
17
 
19
- ```
20
- npm install wavesurfer.js --save
21
-
22
- # or
23
-
24
- yarn add wavesurfer.js
25
- ```
26
-
27
- And import it like so:
28
- ```
29
- import WaveSurfer from 'wavesurfer.js'
30
- ```
31
-
32
- If you're not using a package manager, simply insert the script from a CDN:
33
- ```
34
- <script src="https://unpkg.com/wavesurfer.js"></script>
35
- ```
36
-
37
- Create a container in your HTML:
38
- ```html
39
- <div id="waveform"></div>
40
- ```
41
-
42
- Create an instance of wavesufer.js, passing the container selector and a few [options](https://wavesurfer-js.org/docs/options.html):
43
-
44
- ```javascript
45
- var wavesurfer = WaveSurfer.create({
46
- container: '#waveform',
47
- waveColor: 'violet',
48
- progressColor: 'purple'
49
- });
50
- ```
51
-
52
- Subscribe to some [events](https://wavesurfer-js.org/docs/events.html):
53
-
54
- ```javascript
55
- wavesurfer.on('ready', function () {
56
- wavesurfer.play();
57
- });
58
- ```
59
-
60
- Load an audio file from a URL:
61
-
62
- ```javascript
63
- wavesurfer.load('example/media/demo.wav');
64
- ```
65
-
66
- ## Documentation
18
+ Principles:
19
+ * Modular and event-driven
20
+ * Allow swapping the decoding, rendering and playback mechanisms
21
+ * Extensible with plugins
67
22
 
68
- See the documentation on all available [methods](https://wavesurfer-js.org/docs/methods.html), [options](https://wavesurfer-js.org/docs/options.html) and [events](https://wavesurfer-js.org/docs/events.html) on the [homepage](https://wavesurfer-js.org/docs/).
23
+ ![diagram](https://user-images.githubusercontent.com/381895/222349436-38b550e5-24dc-4143-9cdb-efbe00540213.png)
69
24
 
70
- ## Projects using wavesurfer.js
25
+ ## Development
71
26
 
72
- For the list of projects using wavesurfer.js, check out
73
- [the projects page](https://wavesurfer-js.org/projects/).
74
-
75
- ## Contributing
76
-
77
- Have an idea and want to contribute to wavesurfer.js?
78
- Please first start a discussion in the [Ideas section of our forum](https://github.com/wavesurfer-js/wavesurfer.js/discussions/categories/ideas) to coordinate with the maintainers.
79
-
80
- ### Development
81
-
82
- [![Build Status](https://github.com/wavesurfer-js/wavesurfer.js/workflows/wavesurfer.js/badge.svg?branch=master)](https://github.com/wavesurfer-js/wavesurfer.js/actions?workflow=wavesurfer.js)
83
- [![Coverage Status](https://coveralls.io/repos/github/wavesurfer-js/wavesurfer.js/badge.svg)](https://coveralls.io/github/wavesurfer-js/wavesurfer.js)
84
- ![Size](https://img.shields.io/bundlephobia/minzip/wavesurfer.js.svg?style=flat)
85
-
86
- Install development dependencies:
87
-
88
- ```
89
- npm install
90
- ```
91
- Development tasks automatically rebuild certain parts of the library when files are changed (`start` – wavesurfer, `start:plugins` – plugins). Start a dev task and go to `localhost:8080/example/` to test the current build.
92
-
93
- Start development server for core library:
94
-
95
- ```
96
- npm run start
97
- ```
98
-
99
- Start development server for plugins:
27
+ Install dev dependencies:
100
28
 
101
29
  ```
102
- npm run start:plugins
30
+ yarn
103
31
  ```
104
32
 
105
- Build all the files. (generated files are placed in the `dist` directory.)
33
+ Start the TypeScript compiler in watch mode:
106
34
 
107
35
  ```
108
- npm run build
36
+ yarn build -w
109
37
  ```
110
38
 
111
- Running tests only:
112
-
113
- ```
114
- npm run test
115
- ```
39
+ Run an HTTP server to view the examples:
116
40
 
117
- Build documentation with esdoc (generated files are placed in the `doc` directory.)
118
41
  ```
119
- npm run doc
42
+ python3 -m http.server --cgi 8080
120
43
  ```
121
44
 
122
- If you want to use [the VS Code - Debugger for Chrome](https://github.com/Microsoft/vscode-chrome-debug), there is already a [launch.json](.vscode/launch.json) with a properly configured ``sourceMapPathOverrides`` for you.
123
-
124
- ## Editing documentation
125
- The homepage and documentation files are maintained in the [`gh-pages` branch](https://github.com/wavesurfer-js/wavesurfer.js/tree/gh-pages). Contributions to the documentation are especially welcome.
126
-
127
- ## Updating the NPM package
128
- When preparing a new release, update the version in the `package.json` and have it merged to master. The new version of the package will be published to NPM automatically via GitHub Actions.
129
-
130
- ## Credits
131
-
132
- The main maintainer: <img src="https://avatars.githubusercontent.com/u/305679" width="16" height="16" /> [Thijs Triemstra](https://github.com/thijstriemstra)
133
-
134
- Many thanks to [all the awesome contributors](https://github.com/wavesurfer-js/wavesurfer.js/contributors)!
135
-
136
- ## License
45
+ Open http://localhost:8080/examples/basic/ in your browser.
46
+ There's no hot reload yet, so you'll need to reload the page manually on every change.
137
47
 
138
- [![License](https://img.shields.io/badge/License-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause)
48
+ ## Feedback
139
49
 
140
- This work is licensed under a
141
- [BSD 3-Clause License](https://opensource.org/licenses/BSD-3-Clause).
50
+ See https://github.com/wavesurfer-js/wavesurfer.js/discussions/2684
@@ -0,0 +1,10 @@
1
+ import EventEmitter, { type GeneralEventTypes } from './event-emitter.js';
2
+ import type { WaveSurfer, WaveSurferPluginParams } from './index.js';
3
+ export declare class BasePlugin<EventTypes extends GeneralEventTypes> extends EventEmitter<EventTypes> {
4
+ protected wavesurfer: WaveSurfer;
5
+ protected renderer: WaveSurfer['renderer'];
6
+ protected subscriptions: (() => void)[];
7
+ constructor(params: WaveSurferPluginParams);
8
+ destroy(): void;
9
+ }
10
+ export default BasePlugin;
@@ -0,0 +1,13 @@
1
+ import EventEmitter from './event-emitter.js';
2
+ export class BasePlugin extends EventEmitter {
3
+ constructor(params) {
4
+ super();
5
+ this.subscriptions = [];
6
+ this.wavesurfer = params.wavesurfer;
7
+ this.renderer = params.renderer;
8
+ }
9
+ destroy() {
10
+ this.subscriptions.forEach((unsubscribe) => unsubscribe());
11
+ }
12
+ }
13
+ export default BasePlugin;
@@ -0,0 +1,10 @@
1
+ declare class Decoder {
2
+ audioCtx: AudioContext | null;
3
+ constructor();
4
+ decode(audioData: ArrayBuffer): Promise<{
5
+ duration: number;
6
+ channelData: Float32Array[];
7
+ }>;
8
+ destroy(): void;
9
+ }
10
+ export default Decoder;
@@ -0,0 +1,43 @@
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
+ class Decoder {
13
+ constructor() {
14
+ this.audioCtx = null;
15
+ this.audioCtx = new (window.AudioContext ||
16
+ window.webkitAudioContext)({
17
+ latencyHint: 'playback',
18
+ sampleRate: SAMPLE_RATE,
19
+ });
20
+ }
21
+ decode(audioData) {
22
+ return __awaiter(this, void 0, void 0, function* () {
23
+ if (!this.audioCtx) {
24
+ throw new Error('AudioContext is not initialized');
25
+ }
26
+ const buffer = yield this.audioCtx.decodeAudioData(audioData);
27
+ const channelData = [buffer.getChannelData(0)];
28
+ if (buffer.numberOfChannels > 1) {
29
+ channelData.push(buffer.getChannelData(1));
30
+ }
31
+ return {
32
+ duration: buffer.duration,
33
+ channelData,
34
+ };
35
+ });
36
+ }
37
+ destroy() {
38
+ var _a;
39
+ (_a = this.audioCtx) === null || _a === void 0 ? void 0 : _a.close();
40
+ this.audioCtx = null;
41
+ }
42
+ }
43
+ export default Decoder;
@@ -0,0 +1,11 @@
1
+ export interface GeneralEventTypes {
2
+ [eventType: string]: unknown;
3
+ }
4
+ declare class EventEmitter<EventTypes extends GeneralEventTypes> {
5
+ private eventTarget;
6
+ constructor();
7
+ protected emit<T extends keyof EventTypes>(eventType: T, detail?: EventTypes[T]): void;
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;
10
+ }
11
+ export default EventEmitter;
@@ -0,0 +1,21 @@
1
+ class EventEmitter {
2
+ constructor() {
3
+ this.eventTarget = new EventTarget();
4
+ }
5
+ emit(eventType, detail) {
6
+ const e = new CustomEvent(String(eventType), { detail });
7
+ this.eventTarget.dispatchEvent(e);
8
+ }
9
+ /** Subscribe to an event and return a function to unsubscribe */
10
+ on(eventType, callback) {
11
+ const handler = (e) => {
12
+ if (e instanceof CustomEvent) {
13
+ callback(e.detail);
14
+ }
15
+ };
16
+ const eventName = String(eventType);
17
+ this.eventTarget.addEventListener(eventName, handler);
18
+ return () => this.eventTarget.removeEventListener(eventName, handler);
19
+ }
20
+ }
21
+ export default EventEmitter;
@@ -0,0 +1,4 @@
1
+ declare class Fetcher {
2
+ load(url: string): Promise<ArrayBuffer>;
3
+ }
4
+ export default Fetcher;
@@ -0,0 +1,17 @@
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
+ class Fetcher {
11
+ load(url) {
12
+ return __awaiter(this, void 0, void 0, function* () {
13
+ return fetch(url).then((response) => response.arrayBuffer());
14
+ });
15
+ }
16
+ }
17
+ export default Fetcher;
@@ -0,0 +1,92 @@
1
+ import EventEmitter, { type GeneralEventTypes } from './event-emitter.js';
2
+ import BasePlugin from './base-plugin.js';
3
+ export declare enum PlayerType {
4
+ WebAudio = "WebAudio",
5
+ MediaElement = "MediaElement"
6
+ }
7
+ export type WaveSurferOptions = {
8
+ /** HTML element or CSS selector */
9
+ container: HTMLElement | string | null;
10
+ /** Height of the waveform in pixels */
11
+ height?: number;
12
+ /** The color of the waveform */
13
+ waveColor?: string;
14
+ /** The color of the progress mask */
15
+ progressColor?: string;
16
+ /** If set, the waveform will be rendered in bars like so: ▁ ▂ ▇ ▃ ▅ ▂ */
17
+ barWidth?: number;
18
+ /** Spacing between bars in pixels */
19
+ barGap?: number;
20
+ /** Rounded borders for bars */
21
+ barRadius?: number;
22
+ /** Minimum pixels per second of audio (zoom) */
23
+ minPxPerSec?: number;
24
+ /** Audio URL */
25
+ url?: string;
26
+ /** Pre-computed audio data */
27
+ channelData?: Float32Array[];
28
+ /** Pre-computed duration */
29
+ duration?: number;
30
+ /** Player "backend", the default is MediaElement */
31
+ backend?: PlayerType;
32
+ /** Use an existing media element instead of creating one */
33
+ media?: HTMLMediaElement;
34
+ };
35
+ export type WaveSurferEvents = {
36
+ ready: {
37
+ duration: number;
38
+ };
39
+ canplay: void;
40
+ play: void;
41
+ pause: void;
42
+ audioprocess: {
43
+ currentTime: number;
44
+ };
45
+ seek: {
46
+ time: number;
47
+ };
48
+ };
49
+ export type WaveSurferPluginParams = {
50
+ wavesurfer: WaveSurfer;
51
+ renderer: WaveSurfer['renderer'];
52
+ };
53
+ export declare class WaveSurfer extends EventEmitter<WaveSurferEvents> {
54
+ private options;
55
+ private fetcher;
56
+ private decoder;
57
+ private renderer;
58
+ private player;
59
+ private timer;
60
+ private plugins;
61
+ private subscriptions;
62
+ private channelData;
63
+ private duration;
64
+ /** Create a new WaveSurfer instance */
65
+ static create(options: WaveSurferOptions): WaveSurfer;
66
+ /** Create a new WaveSurfer instance */
67
+ constructor(options: WaveSurferOptions);
68
+ private initPlayerEvents;
69
+ private initRendererEvents;
70
+ private initTimerEvents;
71
+ /** Unmount wavesurfer */
72
+ destroy(): void;
73
+ /** Load an audio file by URL */
74
+ load(url: string, channelData?: Float32Array[], duration?: number): Promise<void>;
75
+ /** Zoom in or out */
76
+ zoom(minPxPerSec: number): void;
77
+ /** Start playing the audio */
78
+ play(): void;
79
+ /** Pause the audio */
80
+ pause(): void;
81
+ /** Skip to a time position in seconds */
82
+ seekTo(time: number): void;
83
+ /** Check if the audio is playing */
84
+ isPlaying(): boolean;
85
+ /** Get the duration of the audio in seconds */
86
+ getDuration(): number;
87
+ /** Get the current audio position in seconds */
88
+ getCurrentTime(): number;
89
+ /** Register and initialize a plugin */
90
+ registerPlugin<T extends BasePlugin<GeneralEventTypes>>(CustomPlugin: new (params: WaveSurferPluginParams) => T): T;
91
+ }
92
+ export default WaveSurfer;
package/dist/index.js ADDED
@@ -0,0 +1,166 @@
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 WebAudioPlayer from './player-webaudio.js';
15
+ import EventEmitter from './event-emitter.js';
16
+ import Timer from './timer.js';
17
+ export var PlayerType;
18
+ (function (PlayerType) {
19
+ PlayerType["WebAudio"] = "WebAudio";
20
+ PlayerType["MediaElement"] = "MediaElement";
21
+ })(PlayerType || (PlayerType = {}));
22
+ const defaultOptions = {
23
+ height: 128,
24
+ waveColor: '#999',
25
+ progressColor: '#555',
26
+ minPxPerSec: 0,
27
+ backend: 'MediaElement',
28
+ };
29
+ export class WaveSurfer extends EventEmitter {
30
+ /** Create a new WaveSurfer instance */
31
+ static create(options) {
32
+ return new WaveSurfer(options);
33
+ }
34
+ /** Create a new WaveSurfer instance */
35
+ constructor(options) {
36
+ var _a;
37
+ super();
38
+ this.plugins = [];
39
+ this.subscriptions = [];
40
+ this.channelData = null;
41
+ this.duration = 0;
42
+ this.options = Object.assign({}, defaultOptions, options);
43
+ this.fetcher = new Fetcher();
44
+ this.decoder = new Decoder();
45
+ this.timer = new Timer();
46
+ this.player = new (this.options.backend === PlayerType.WebAudio ? WebAudioPlayer : Player)({
47
+ media: this.options.media,
48
+ });
49
+ this.renderer = new Renderer({
50
+ container: this.options.container,
51
+ height: this.options.height,
52
+ waveColor: this.options.waveColor,
53
+ progressColor: this.options.progressColor,
54
+ minPxPerSec: this.options.minPxPerSec,
55
+ barWidth: this.options.barWidth,
56
+ barGap: this.options.barGap,
57
+ barRadius: this.options.barRadius,
58
+ });
59
+ this.initPlayerEvents();
60
+ this.initRendererEvents();
61
+ this.initTimerEvents();
62
+ const url = this.options.url || ((_a = this.options.media) === null || _a === void 0 ? void 0 : _a.src);
63
+ if (url) {
64
+ this.load(url, this.options.channelData, this.options.duration);
65
+ }
66
+ }
67
+ initPlayerEvents() {
68
+ this.subscriptions.push(this.player.on('timeupdate', () => {
69
+ const currentTime = this.getCurrentTime();
70
+ this.renderer.renderProgress(currentTime / this.duration, this.isPlaying());
71
+ this.emit('audioprocess', { currentTime });
72
+ }), this.player.on('play', () => {
73
+ this.emit('play');
74
+ }), this.player.on('pause', () => {
75
+ this.emit('pause');
76
+ }), this.player.on('canplay', () => {
77
+ this.emit('canplay');
78
+ }), this.player.on('seeking', () => {
79
+ this.emit('seek', { time: this.getCurrentTime() });
80
+ }));
81
+ }
82
+ initRendererEvents() {
83
+ // Seek on click
84
+ this.subscriptions.push(this.renderer.on('click', ({ relativeX }) => {
85
+ const time = this.getDuration() * relativeX;
86
+ this.seekTo(time);
87
+ }));
88
+ }
89
+ initTimerEvents() {
90
+ // The timer fires every 16ms for a smooth progress animation
91
+ this.subscriptions.push(this.timer.on('tick', () => {
92
+ if (this.isPlaying()) {
93
+ const currentTime = this.getCurrentTime();
94
+ this.renderer.renderProgress(currentTime / this.duration, true);
95
+ this.emit('audioprocess', { currentTime });
96
+ }
97
+ }));
98
+ }
99
+ /** Unmount wavesurfer */
100
+ destroy() {
101
+ this.subscriptions.forEach((unsubscribe) => unsubscribe());
102
+ this.plugins.forEach((plugin) => plugin.destroy());
103
+ this.timer.destroy();
104
+ this.player.destroy();
105
+ this.decoder.destroy();
106
+ this.renderer.destroy();
107
+ }
108
+ /** Load an audio file by URL */
109
+ load(url, channelData, duration) {
110
+ return __awaiter(this, void 0, void 0, function* () {
111
+ this.player.loadUrl(url);
112
+ // Fetch and decode the audio of no pre-computed audio data is provided
113
+ if (channelData == null || duration == null) {
114
+ const audio = yield this.fetcher.load(url);
115
+ const data = yield this.decoder.decode(audio);
116
+ channelData = data.channelData;
117
+ duration = data.duration;
118
+ }
119
+ this.channelData = channelData;
120
+ this.duration = duration;
121
+ this.renderer.render(this.channelData, this.duration);
122
+ this.emit('ready', { duration: this.duration });
123
+ });
124
+ }
125
+ /** Zoom in or out */
126
+ zoom(minPxPerSec) {
127
+ if (this.channelData == null || this.duration == null) {
128
+ throw new Error('No audio loaded');
129
+ }
130
+ this.renderer.render(this.channelData, this.duration, minPxPerSec);
131
+ }
132
+ /** Start playing the audio */
133
+ play() {
134
+ this.player.play();
135
+ }
136
+ /** Pause the audio */
137
+ pause() {
138
+ this.player.pause();
139
+ }
140
+ /** Skip to a time position in seconds */
141
+ seekTo(time) {
142
+ this.player.seekTo(time);
143
+ }
144
+ /** Check if the audio is playing */
145
+ isPlaying() {
146
+ return this.player.isPlaying();
147
+ }
148
+ /** Get the duration of the audio in seconds */
149
+ getDuration() {
150
+ return this.duration;
151
+ }
152
+ /** Get the current audio position in seconds */
153
+ getCurrentTime() {
154
+ return this.player.getCurrentTime();
155
+ }
156
+ /** Register and initialize a plugin */
157
+ registerPlugin(CustomPlugin) {
158
+ const plugin = new CustomPlugin({
159
+ wavesurfer: this,
160
+ renderer: this.renderer,
161
+ });
162
+ this.plugins.push(plugin);
163
+ return plugin;
164
+ }
165
+ }
166
+ export default WaveSurfer;
@@ -0,0 +1,8 @@
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;
@@ -0,0 +1,31 @@
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 (window.AudioContext ||
20
+ window.webkitAudioContext)({
21
+ latencyHint: 'playback',
22
+ });
23
+ }
24
+ if (this.sourceNode) {
25
+ this.sourceNode.disconnect();
26
+ }
27
+ this.sourceNode = this.audioCtx.createMediaElementSource(this.media);
28
+ this.sourceNode.connect(this.audioCtx.destination);
29
+ }
30
+ }
31
+ export default WebAudioPlayer;
@@ -0,0 +1,16 @@
1
+ declare class Player {
2
+ protected media: HTMLMediaElement;
3
+ private isExternalMedia;
4
+ constructor({ media }: {
5
+ media?: HTMLMediaElement;
6
+ });
7
+ on(event: keyof HTMLMediaElementEventMap, callback: () => void): () => void;
8
+ destroy(): void;
9
+ loadUrl(src: string): void;
10
+ getCurrentTime(): number;
11
+ play(): void;
12
+ pause(): void;
13
+ isPlaying(): boolean;
14
+ seekTo(time: number): void;
15
+ }
16
+ export default Player;