wavesurfer.js 4.5.0 → 5.1.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.
- package/CHANGES.md +36 -1
- package/README.md +6 -3
- package/dist/plugin/wavesurfer.cursor.js +39 -34
- package/dist/plugin/wavesurfer.cursor.js.map +1 -1
- package/dist/plugin/wavesurfer.cursor.min.js +2 -2
- package/dist/plugin/wavesurfer.cursor.min.js.map +1 -1
- package/dist/plugin/wavesurfer.elan.js +29 -27
- package/dist/plugin/wavesurfer.elan.js.map +1 -1
- package/dist/plugin/wavesurfer.elan.min.js +2 -2
- package/dist/plugin/wavesurfer.elan.min.js.map +1 -1
- package/dist/plugin/wavesurfer.markers.js +381 -0
- package/dist/plugin/wavesurfer.markers.js.map +1 -0
- package/dist/plugin/wavesurfer.markers.min.js +7 -0
- package/dist/plugin/wavesurfer.markers.min.js.map +1 -0
- package/dist/plugin/wavesurfer.mediasession.js +29 -27
- package/dist/plugin/wavesurfer.mediasession.js.map +1 -1
- package/dist/plugin/wavesurfer.mediasession.min.js +2 -2
- package/dist/plugin/wavesurfer.mediasession.min.js.map +1 -1
- package/dist/plugin/wavesurfer.microphone.js +29 -27
- package/dist/plugin/wavesurfer.microphone.js.map +1 -1
- package/dist/plugin/wavesurfer.microphone.min.js +2 -2
- package/dist/plugin/wavesurfer.microphone.min.js.map +1 -1
- package/dist/plugin/wavesurfer.minimap.js +30 -28
- package/dist/plugin/wavesurfer.minimap.js.map +1 -1
- package/dist/plugin/wavesurfer.minimap.min.js +2 -2
- package/dist/plugin/wavesurfer.minimap.min.js.map +1 -1
- package/dist/plugin/wavesurfer.playhead.js +324 -0
- package/dist/plugin/wavesurfer.playhead.js.map +1 -0
- package/dist/plugin/wavesurfer.playhead.min.js +7 -0
- package/dist/plugin/wavesurfer.playhead.min.js.map +1 -0
- package/dist/plugin/wavesurfer.regions.js +152 -126
- package/dist/plugin/wavesurfer.regions.js.map +1 -1
- package/dist/plugin/wavesurfer.regions.min.js +2 -2
- package/dist/plugin/wavesurfer.regions.min.js.map +1 -1
- package/dist/plugin/wavesurfer.spectrogram.js +97 -89
- package/dist/plugin/wavesurfer.spectrogram.js.map +1 -1
- package/dist/plugin/wavesurfer.spectrogram.min.js +2 -2
- package/dist/plugin/wavesurfer.spectrogram.min.js.map +1 -1
- package/dist/plugin/wavesurfer.timeline.js +46 -32
- package/dist/plugin/wavesurfer.timeline.js.map +1 -1
- package/dist/plugin/wavesurfer.timeline.min.js +2 -2
- package/dist/plugin/wavesurfer.timeline.min.js.map +1 -1
- package/dist/wavesurfer-html-init.js +9 -5
- package/dist/wavesurfer-html-init.js.map +1 -1
- package/dist/wavesurfer-html-init.min.js +2 -2
- package/dist/wavesurfer-html-init.min.js.map +1 -1
- package/dist/wavesurfer.js +350 -166
- package/dist/wavesurfer.js.map +1 -1
- package/dist/wavesurfer.min.js +2 -2
- package/dist/wavesurfer.min.js.map +1 -1
- package/package.json +19 -16
- package/src/drawer.canvasentry.js +16 -0
- package/src/drawer.js +30 -21
- package/src/drawer.multicanvas.js +63 -39
- package/src/plugin/cursor/index.js +3 -1
- package/src/plugin/markers/index.js +282 -0
- package/src/plugin/playhead/index.js +226 -0
- package/src/plugin/regions/index.js +28 -11
- package/src/plugin/regions/region.js +83 -70
- package/src/plugin/spectrogram/index.js +65 -61
- package/src/plugin/timeline/index.js +20 -11
- package/src/util/index.js +1 -0
- package/src/util/orientation.js +98 -0
- package/src/wavesurfer.js +18 -9
- package/src/webaudio.js +10 -9
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
|
|
2
|
+
/**
|
|
3
|
+
* The playhead plugin separates the notion of the currently playing position from
|
|
4
|
+
* a 'play-start' position. Having a playhead enables a listening pattern
|
|
5
|
+
* (commonly found in DAWs) that involves listening to a section of a track
|
|
6
|
+
* repeatedly, rather than listening to an entire track in a linear fashion.
|
|
7
|
+
*
|
|
8
|
+
* @implements {PluginClass}
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* import PlayheadPlugin from 'wavesurfer.playhead.js';
|
|
12
|
+
*
|
|
13
|
+
* // if you are using <script> tags
|
|
14
|
+
* var PlayheadPlugin = window.WaveSurfer.playhead;
|
|
15
|
+
*
|
|
16
|
+
* // ... initialising wavesurfer with the plugin
|
|
17
|
+
* var wavesurfer = WaveSurfer.create({
|
|
18
|
+
* // wavesurfer options ...
|
|
19
|
+
* plugins: [
|
|
20
|
+
* PlayheadPlugin.create({
|
|
21
|
+
* movePlayheadOnSeek: true,
|
|
22
|
+
* drawPlayhead: false,
|
|
23
|
+
* movePlayheadOnPause: false
|
|
24
|
+
* })
|
|
25
|
+
* ]
|
|
26
|
+
* });
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
const DEFAULT_FILL_COLOR = '#CF2F00';
|
|
30
|
+
|
|
31
|
+
export default class PlayheadPlugin {
|
|
32
|
+
/**
|
|
33
|
+
* @typedef {Object} PlayheadPluginParams
|
|
34
|
+
* @property {?boolean} draw=true Draw the playhead as a triangle/line
|
|
35
|
+
* @property {?boolean} moveOnSeek=true Seeking (via clicking) while playing moves the playhead
|
|
36
|
+
* @property {?boolean} returnOnPause=true Pausing the track returns the seek position to the playhead
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Playhead plugin definition factory
|
|
41
|
+
*
|
|
42
|
+
* This function must be used to create a plugin definition which can be
|
|
43
|
+
* used by wavesurfer to correctly instantiate the plugin.
|
|
44
|
+
*
|
|
45
|
+
* @param {PlayheadPluginParams} params parameters use to initialise the plugin
|
|
46
|
+
* @since 5.0.0
|
|
47
|
+
* @return {PluginDefinition} an object representing the plugin
|
|
48
|
+
*/
|
|
49
|
+
static create(params) {
|
|
50
|
+
return {
|
|
51
|
+
name: 'playhead',
|
|
52
|
+
deferInit: params && params.deferInit ? params.deferInit : false,
|
|
53
|
+
params: params,
|
|
54
|
+
instance: PlayheadPlugin
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
constructor(params, ws) {
|
|
59
|
+
this.params = params;
|
|
60
|
+
this.options = {};
|
|
61
|
+
|
|
62
|
+
['draw', 'moveOnSeek', 'returnOnPause'].forEach(opt => {
|
|
63
|
+
if (opt in params) {
|
|
64
|
+
this.options[opt] = params[opt];
|
|
65
|
+
} else {
|
|
66
|
+
this.options[opt] = true;
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
this.wavesurfer = ws;
|
|
72
|
+
this.util = ws.util;
|
|
73
|
+
this.style = this.util.style;
|
|
74
|
+
this.markerWidth = 21;
|
|
75
|
+
this.markerHeight = 16;
|
|
76
|
+
this.playheadTime = 0;
|
|
77
|
+
this.unFuns = [];
|
|
78
|
+
|
|
79
|
+
this._onResize = () => {
|
|
80
|
+
this._updatePlayheadPosition();
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
this._onReady = () => {
|
|
84
|
+
this.wrapper = this.wavesurfer.drawer.wrapper;
|
|
85
|
+
this._updatePlayheadPosition();
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
_onBackendCreated() {
|
|
90
|
+
this.wrapper = this.wavesurfer.drawer.wrapper;
|
|
91
|
+
|
|
92
|
+
if (this.options.draw) {
|
|
93
|
+
this._createPlayheadElement();
|
|
94
|
+
window.addEventListener('resize', this._onResize, true);
|
|
95
|
+
window.addEventListener('orientationchange', this._onResize, true);
|
|
96
|
+
|
|
97
|
+
this.wavesurferOn('zoom', this._onResize);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
this.wavesurferOn('pause', () => {
|
|
101
|
+
if ( this.options.returnOnPause ) {
|
|
102
|
+
this.wavesurfer.setCurrentTime(this.playheadTime);
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
this.wavesurferOn('seek', () => {
|
|
107
|
+
if ( this.options.moveOnSeek ) {
|
|
108
|
+
this.playheadTime = this.wavesurfer.getCurrentTime();
|
|
109
|
+
this._updatePlayheadPosition();
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
this.playheadTime = this.wavesurfer.getCurrentTime();
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
wavesurferOn(ev, fn) {
|
|
117
|
+
let ret = this.wavesurfer.on(ev, fn);
|
|
118
|
+
this.unFuns.push(() => {
|
|
119
|
+
this.wavesurfer.un(ev, fn);
|
|
120
|
+
});
|
|
121
|
+
return ret;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
init() {
|
|
125
|
+
if (this.wavesurfer.isReady) {
|
|
126
|
+
this._onBackendCreated();
|
|
127
|
+
this._onReady();
|
|
128
|
+
} else {
|
|
129
|
+
let r;
|
|
130
|
+
|
|
131
|
+
this.wavesurfer.once('ready', () => this._onReady());
|
|
132
|
+
this.wavesurfer.once('backend-created', () => this._onBackendCreated());
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
destroy() {
|
|
137
|
+
this.unFuns.forEach(f => f());
|
|
138
|
+
this.unFuns = [];
|
|
139
|
+
|
|
140
|
+
this.wrapper.removeChild(this.element);
|
|
141
|
+
|
|
142
|
+
window.removeEventListener('resize', this._onResize, true);
|
|
143
|
+
window.removeEventListener('orientationchange', this._onResize, true);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
setPlayheadTime(time) {
|
|
147
|
+
this.playheadTime = time;
|
|
148
|
+
|
|
149
|
+
if (!this.wavesurfer.isPlaying()) {
|
|
150
|
+
this.wavesurfer.setCurrentTime(time);
|
|
151
|
+
}
|
|
152
|
+
this._updatePlayheadPosition();
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
_createPointerSVG() {
|
|
156
|
+
const svgNS = 'http://www.w3.org/2000/svg';
|
|
157
|
+
|
|
158
|
+
const el = document.createElementNS(svgNS, 'svg');
|
|
159
|
+
const path = document.createElementNS(svgNS, 'path');
|
|
160
|
+
|
|
161
|
+
el.setAttribute('viewBox', '0 0 33 30');
|
|
162
|
+
path.setAttribute('d', 'M16.75 31 31.705 5.566A3 3 0 0 0 29.146 1H4.354a3 3 0 0 0-2.56 4.566L16.75 31z');
|
|
163
|
+
path.setAttribute('stroke', '#979797');
|
|
164
|
+
path.setAttribute('fill', DEFAULT_FILL_COLOR);
|
|
165
|
+
|
|
166
|
+
el.appendChild(path);
|
|
167
|
+
|
|
168
|
+
this.style(el, {
|
|
169
|
+
width: this.markerWidth + 'px',
|
|
170
|
+
height: this.markerHeight + 'px',
|
|
171
|
+
cursor: 'pointer',
|
|
172
|
+
'z-index': 5
|
|
173
|
+
});
|
|
174
|
+
return el;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
_createPlayheadElement() {
|
|
178
|
+
const el = document.createElement('playhead');
|
|
179
|
+
el.className = 'wavesurfer-playhead';
|
|
180
|
+
|
|
181
|
+
this.style(el, {
|
|
182
|
+
position: 'absolute',
|
|
183
|
+
height: '100%',
|
|
184
|
+
display: 'flex',
|
|
185
|
+
'flex-direction': 'column'
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
const pointer = this._createPointerSVG();
|
|
189
|
+
el.appendChild(pointer);
|
|
190
|
+
|
|
191
|
+
pointer.addEventListener('click', e => {
|
|
192
|
+
e.stopPropagation();
|
|
193
|
+
this.wavesurfer.setCurrentTime(this.playheadTime);
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
const line = document.createElement('div');
|
|
197
|
+
this.style(line, {
|
|
198
|
+
'flex-grow': 1,
|
|
199
|
+
'margin-left': (this.markerWidth / 2 - 0.5) + 'px',
|
|
200
|
+
background: 'black',
|
|
201
|
+
width: '1px',
|
|
202
|
+
opacity: 0.1
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
el.appendChild(line);
|
|
206
|
+
|
|
207
|
+
this.element = el;
|
|
208
|
+
this.wrapper.appendChild(el);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
_updatePlayheadPosition() {
|
|
212
|
+
if (!this.element) {
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const duration = this.wavesurfer.getDuration();
|
|
217
|
+
const elementWidth =
|
|
218
|
+
this.wavesurfer.drawer.width /
|
|
219
|
+
this.wavesurfer.params.pixelRatio;
|
|
220
|
+
|
|
221
|
+
const positionPct = this.playheadTime / duration;
|
|
222
|
+
this.style(this.element, {
|
|
223
|
+
left: ((elementWidth * positionPct) - (this.markerWidth / 2)) + 'px'
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
}
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
* @property {?number} channelIdx Select channel to draw the region on (if there are multiple channel waveforms).
|
|
31
31
|
* @property {?object} handleStyle A set of CSS properties used to style the left and right handle.
|
|
32
32
|
* @property {?boolean} preventContextMenu=false Determines whether the context menu is prevented from being opened.
|
|
33
|
+
* @property {boolean} showTooltip=true Enable/disable tooltip displaying start and end times when hovering over region.
|
|
33
34
|
*/
|
|
34
35
|
|
|
35
36
|
import {Region} from "./region.js";
|
|
@@ -127,11 +128,16 @@ export default class RegionsPlugin {
|
|
|
127
128
|
});
|
|
128
129
|
this.wavesurfer.Region = Region;
|
|
129
130
|
|
|
131
|
+
// By default, scroll the container if the user drags a region
|
|
132
|
+
// within 5% of its edge
|
|
133
|
+
const scrollWidthProportion = 0.05;
|
|
130
134
|
this._onBackendCreated = () => {
|
|
131
135
|
this.wrapper = this.wavesurfer.drawer.wrapper;
|
|
136
|
+
this.orientation = this.wavesurfer.drawer.orientation;
|
|
132
137
|
if (this.params.regions) {
|
|
133
138
|
this.params.regions.forEach(region => {
|
|
134
|
-
region.edgeScrollWidth = this.params.edgeScrollWidth ||
|
|
139
|
+
region.edgeScrollWidth = this.params.edgeScrollWidth ||
|
|
140
|
+
this.wrapper.clientWidth * scrollWidthProportion;
|
|
135
141
|
this.add(region);
|
|
136
142
|
});
|
|
137
143
|
}
|
|
@@ -141,6 +147,7 @@ export default class RegionsPlugin {
|
|
|
141
147
|
this.list = {};
|
|
142
148
|
this._onReady = () => {
|
|
143
149
|
this.wrapper = this.wavesurfer.drawer.wrapper;
|
|
150
|
+
this.vertical = this.wavesurfer.drawer.params.vertical;
|
|
144
151
|
if (this.params.dragSelection) {
|
|
145
152
|
this.enableDragSelection(this.params);
|
|
146
153
|
}
|
|
@@ -186,7 +193,9 @@ export default class RegionsPlugin {
|
|
|
186
193
|
* @return {Region} The created region
|
|
187
194
|
*/
|
|
188
195
|
add(params) {
|
|
189
|
-
if (this.wouldExceedMaxRegions())
|
|
196
|
+
if (this.wouldExceedMaxRegions()) {
|
|
197
|
+
return null;
|
|
198
|
+
}
|
|
190
199
|
|
|
191
200
|
if (!params.minLength && this.regionsMinLength) {
|
|
192
201
|
params = {...params, minLength: this.regionsMinLength};
|
|
@@ -268,8 +277,12 @@ export default class RegionsPlugin {
|
|
|
268
277
|
touchId = e.targetTouches ? e.targetTouches[0].identifier : null;
|
|
269
278
|
|
|
270
279
|
// Store for scroll calculations
|
|
271
|
-
maxScroll = this.wrapper.scrollWidth -
|
|
272
|
-
|
|
280
|
+
maxScroll = this.wrapper.scrollWidth -
|
|
281
|
+
this.wrapper.clientWidth;
|
|
282
|
+
wrapperRect = this.util.withOrientation(
|
|
283
|
+
this.wrapper.getBoundingClientRect(),
|
|
284
|
+
this.vertical
|
|
285
|
+
);
|
|
273
286
|
|
|
274
287
|
drag = true;
|
|
275
288
|
start = this.wavesurfer.drawer.handleEvent(e, true);
|
|
@@ -314,7 +327,7 @@ export default class RegionsPlugin {
|
|
|
314
327
|
this.wrapper.removeEventListener('mouseleave', eventUp);
|
|
315
328
|
});
|
|
316
329
|
|
|
317
|
-
const eventMove =
|
|
330
|
+
const eventMove = event => {
|
|
318
331
|
if (!drag) {
|
|
319
332
|
return;
|
|
320
333
|
}
|
|
@@ -322,20 +335,22 @@ export default class RegionsPlugin {
|
|
|
322
335
|
return;
|
|
323
336
|
}
|
|
324
337
|
|
|
325
|
-
if (
|
|
338
|
+
if (event.touches && event.touches.length > 1) {
|
|
326
339
|
return;
|
|
327
340
|
}
|
|
328
|
-
if (
|
|
341
|
+
if (event.targetTouches && event.targetTouches[0].identifier != touchId) {
|
|
329
342
|
return;
|
|
330
343
|
}
|
|
331
344
|
|
|
332
345
|
// auto-create a region during mouse drag, unless region-count would exceed "maxRegions"
|
|
333
346
|
if (!region) {
|
|
334
347
|
region = this.add(params || {});
|
|
335
|
-
if (!region)
|
|
348
|
+
if (!region) {
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
336
351
|
}
|
|
337
352
|
|
|
338
|
-
const end = this.wavesurfer.drawer.handleEvent(
|
|
353
|
+
const end = this.wavesurfer.drawer.handleEvent(event);
|
|
339
354
|
const startUpdate = this.wavesurfer.regions.util.getRegionSnapToGridValue(
|
|
340
355
|
start * duration
|
|
341
356
|
);
|
|
@@ -347,10 +362,12 @@ export default class RegionsPlugin {
|
|
|
347
362
|
end: Math.max(endUpdate, startUpdate)
|
|
348
363
|
});
|
|
349
364
|
|
|
365
|
+
let orientedEvent = this.util.withOrientation(event, this.vertical);
|
|
366
|
+
|
|
350
367
|
// If scrolling is enabled
|
|
351
368
|
if (scroll && container.clientWidth < this.wrapper.scrollWidth) {
|
|
352
369
|
// Check threshold based on mouse
|
|
353
|
-
const x =
|
|
370
|
+
const x = orientedEvent.clientX - wrapperRect.left;
|
|
354
371
|
if (x <= scrollThreshold) {
|
|
355
372
|
scrollDirection = -1;
|
|
356
373
|
} else if (x >= wrapperRect.right - scrollThreshold) {
|
|
@@ -358,7 +375,7 @@ export default class RegionsPlugin {
|
|
|
358
375
|
} else {
|
|
359
376
|
scrollDirection = null;
|
|
360
377
|
}
|
|
361
|
-
scrollDirection && edgeScroll(
|
|
378
|
+
scrollDirection && edgeScroll(event);
|
|
362
379
|
}
|
|
363
380
|
};
|
|
364
381
|
this.wrapper.addEventListener('mousemove', eventMove);
|