wavesurfer.js 7.12.2 → 7.12.3

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 (37) hide show
  1. package/dist/__tests__/regions.test.d.ts +1 -0
  2. package/dist/__tests__/regions.test.js +61 -0
  3. package/dist/__tests__/timeline.test.d.ts +1 -0
  4. package/dist/__tests__/timeline.test.js +46 -0
  5. package/dist/plugins/envelope.js +426 -1
  6. package/dist/plugins/hover.js +131 -1
  7. package/dist/plugins/minimap.js +229 -1
  8. package/dist/plugins/record.js +319 -1
  9. package/dist/plugins/regions.d.ts +2 -0
  10. package/dist/plugins/regions.js +699 -1
  11. package/dist/plugins/spectrogram-windowed.js +967 -1
  12. package/dist/plugins/timeline.cjs +1 -1
  13. package/dist/plugins/timeline.esm.js +1 -1
  14. package/dist/plugins/timeline.js +1 -1
  15. package/dist/plugins/timeline.min.js +1 -1
  16. package/package.json +2 -4
  17. package/dist/plugins/envelope.cjs +0 -1
  18. package/dist/plugins/envelope.esm.js +0 -1
  19. package/dist/plugins/envelope.min.js +0 -1
  20. package/dist/plugins/hover.cjs +0 -1
  21. package/dist/plugins/hover.esm.js +0 -1
  22. package/dist/plugins/hover.min.js +0 -1
  23. package/dist/plugins/minimap.cjs +0 -1
  24. package/dist/plugins/minimap.esm.js +0 -1
  25. package/dist/plugins/minimap.min.js +0 -1
  26. package/dist/plugins/record.cjs +0 -1
  27. package/dist/plugins/record.esm.js +0 -1
  28. package/dist/plugins/record.min.js +0 -1
  29. package/dist/plugins/regions.cjs +0 -1
  30. package/dist/plugins/regions.esm.js +0 -1
  31. package/dist/plugins/regions.min.js +0 -1
  32. package/dist/plugins/spectrogram-windowed.cjs +0 -1
  33. package/dist/plugins/spectrogram-windowed.esm.js +0 -1
  34. package/dist/plugins/spectrogram-windowed.min.js +0 -1
  35. package/dist/plugins/spectrogram.cjs +0 -1
  36. package/dist/plugins/spectrogram.esm.js +0 -1
  37. package/dist/plugins/spectrogram.min.js +0 -1
@@ -1 +1,319 @@
1
- function i(i,t,e,s){return new(e||(e=Promise))((function(r,o){function n(i){try{d(s.next(i))}catch(i){o(i)}}function a(i){try{d(s.throw(i))}catch(i){o(i)}}function d(i){var t;i.done?r(i.value):(t=i.value,t instanceof e?t:new e((function(i){i(t)}))).then(n,a)}d((s=s.apply(i,t||[])).next())}))}"function"==typeof SuppressedError&&SuppressedError;class t{constructor(){this.listeners={}}on(i,t,e){if(this.listeners[i]||(this.listeners[i]=new Set),null==e?void 0:e.once){const e=(...s)=>{this.un(i,e),t(...s)};return this.listeners[i].add(e),()=>this.un(i,e)}return this.listeners[i].add(t),()=>this.un(i,t)}un(i,t){var e;null===(e=this.listeners[i])||void 0===e||e.delete(t)}once(i,t){return this.on(i,t,{once:!0})}unAll(){this.listeners={}}emit(i,...t){this.listeners[i]&&this.listeners[i].forEach((i=>i(...t)))}}class e extends t{constructor(i){super(),this.subscriptions=[],this.isDestroyed=!1,this.options=i}onInit(){}_init(i){this.isDestroyed&&(this.subscriptions=[],this.isDestroyed=!1),this.wavesurfer=i,this.onInit()}destroy(){this.emit("destroy"),this.subscriptions.forEach((i=>i())),this.subscriptions=[],this.isDestroyed=!0,this.wavesurfer=void 0}}class s extends t{constructor(){super(...arguments),this.animationFrameId=null,this.isRunning=!1}start(){if(this.isRunning)return;this.isRunning=!0;const i=()=>{this.isRunning&&(this.emit("tick"),this.animationFrameId=requestAnimationFrame(i))};i()}stop(){this.isRunning=!1,null!==this.animationFrameId&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null)}destroy(){this.stop()}}const r=100,o=["audio/webm","audio/wav","audio/mpeg","audio/mp4","audio/mp3"];class n extends e{constructor(i){var t,e,r,o,n,a;super(Object.assign(Object.assign({},i),{audioBitsPerSecond:null!==(t=i.audioBitsPerSecond)&&void 0!==t?t:128e3,scrollingWaveform:null!==(e=i.scrollingWaveform)&&void 0!==e&&e,scrollingWaveformWindow:null!==(r=i.scrollingWaveformWindow)&&void 0!==r?r:5,continuousWaveform:null!==(o=i.continuousWaveform)&&void 0!==o&&o,renderRecordedAudio:null===(n=i.renderRecordedAudio)||void 0===n||n,mediaRecorderTimeslice:null!==(a=i.mediaRecorderTimeslice)&&void 0!==a?a:void 0})),this.stream=null,this.mediaRecorder=null,this.dataWindow=null,this.isWaveformPaused=!1,this.lastStartTime=0,this.lastDuration=0,this.duration=0,this.micStream=null,this.recordedBlobUrl=null,this.timer=new s,this.subscriptions.push(this.timer.on("tick",(()=>{const i=performance.now()-this.lastStartTime;this.duration=this.isPaused()?this.duration:this.lastDuration+i,this.emit("record-progress",this.duration)})))}static create(i){return new n(i||{})}renderMicStream(i){var t;const e=new AudioContext,s=e.createMediaStreamSource(i),o=e.createAnalyser();s.connect(o),(this.options.continuousWaveform||this.options.scrollingWaveform)&&(o.fftSize=32);const n=o.frequencyBinCount,a=new Float32Array(n);let d=0;this.wavesurfer&&(null!==(t=this.originalOptions)&&void 0!==t||(this.originalOptions=Object.assign({},this.wavesurfer.options)),this.wavesurfer.options.interact=!1,this.options.scrollingWaveform&&(this.wavesurfer.options.cursorWidth=0,this.wavesurfer.options.normalize=!0,this.wavesurfer.options.maxPeak=1));const h=setInterval((()=>{var i,t,e,s;if(!this.isWaveformPaused){if(o.getFloatTimeDomainData(a),this.options.scrollingWaveform){const i=Math.floor((this.options.scrollingWaveformWindow||0)*r);let t=0;for(let i=0;i<n;i++){const e=Math.abs(a[i]);e>t&&(t=e)}this.dataWindow||(this.dataWindow=new Float32Array(i));const e=new Float32Array(i);if(this.dataWindow&&this.dataWindow.length>0){const t=i-1,s=this.dataWindow.slice(-t);e.set(s,0)}e[i-1]=t,this.dataWindow=e}else if(this.options.continuousWaveform){if(!this.dataWindow){const e=this.options.continuousWaveformDuration?Math.round(this.options.continuousWaveformDuration*r):(null!==(t=null===(i=this.wavesurfer)||void 0===i?void 0:i.getWidth())&&void 0!==t?t:0)*window.devicePixelRatio;this.dataWindow=new Float32Array(e)}let e=0;for(let i=0;i<n;i++){const t=Math.abs(a[i]);t>e&&(e=t)}if(d+1>this.dataWindow.length){const i=new Float32Array(2*this.dataWindow.length);i.set(this.dataWindow,0),this.dataWindow=i}this.dataWindow[d]=e,d++}else this.dataWindow=a;if(this.wavesurfer){const i=(null!==(s=null===(e=this.dataWindow)||void 0===e?void 0:e.length)&&void 0!==s?s:0)/r;this.wavesurfer.load("",[this.dataWindow],this.options.scrollingWaveform?this.options.scrollingWaveformWindow:i).then((()=>{this.wavesurfer&&this.options.continuousWaveform&&(this.wavesurfer.setTime(this.getDuration()/1e3),this.wavesurfer.options.minPxPerSec||this.wavesurfer.setOptions({minPxPerSec:this.wavesurfer.getWidth()/this.wavesurfer.getDuration()}))})).catch((i=>{console.error("Error rendering real-time recording data:",i)}))}}}),10);return{onDestroy:()=>{clearInterval(h),null==s||s.disconnect(),null==e||e.close()},onEnd:()=>{this.isWaveformPaused=!0,this.stopMic()}}}startMic(t){return i(this,void 0,void 0,(function*(){let i;this.micStream&&this.stopMic();try{i=yield navigator.mediaDevices.getUserMedia({audio:null==t||t})}catch(i){throw new Error("Error accessing the microphone: "+i.message)}const e=this.renderMicStream(i);return this.micStream=e,this.unsubscribeDestroy=this.once("destroy",e.onDestroy),this.unsubscribeRecordEnd=this.once("record-end",e.onEnd),this.stream=i,i}))}stopMic(){var i,t,e;null===(i=this.micStream)||void 0===i||i.onDestroy(),null===(t=this.unsubscribeDestroy)||void 0===t||t.call(this),null===(e=this.unsubscribeRecordEnd)||void 0===e||e.call(this),this.micStream=null,this.unsubscribeDestroy=void 0,this.unsubscribeRecordEnd=void 0,this.stream&&(this.stream.getTracks().forEach((i=>i.stop())),this.stream=null,this.mediaRecorder=null)}startRecording(t){return i(this,void 0,void 0,(function*(){const i=this.stream||(yield this.startMic(t));this.dataWindow=null;const e=this.mediaRecorder||new MediaRecorder(i,{mimeType:this.options.mimeType||o.find((i=>MediaRecorder.isTypeSupported(i))),audioBitsPerSecond:this.options.audioBitsPerSecond});this.mediaRecorder=e,this.stopRecording();const s=[];e.ondataavailable=i=>{i.data.size>0&&s.push(i.data),this.emit("record-data-available",i.data)};const r=i=>{var t;const r=new Blob(s,{type:e.mimeType});this.emit(i,r),this.options.renderRecordedAudio&&(this.applyOriginalOptionsIfNeeded(),this.recordedBlobUrl&&URL.revokeObjectURL(this.recordedBlobUrl),this.recordedBlobUrl=URL.createObjectURL(r),null===(t=this.wavesurfer)||void 0===t||t.load(this.recordedBlobUrl))};e.onpause=()=>r("record-pause"),e.onstop=()=>r("record-end"),e.start(this.options.mediaRecorderTimeslice),this.lastStartTime=performance.now(),this.lastDuration=0,this.duration=0,this.isWaveformPaused=!1,this.timer.start(),this.emit("record-start")}))}getDuration(){return this.duration}isRecording(){var i;return"recording"===(null===(i=this.mediaRecorder)||void 0===i?void 0:i.state)}isPaused(){var i;return"paused"===(null===(i=this.mediaRecorder)||void 0===i?void 0:i.state)}isActive(){var i;return"inactive"!==(null===(i=this.mediaRecorder)||void 0===i?void 0:i.state)}stopRecording(){var i;this.isActive()&&(null===(i=this.mediaRecorder)||void 0===i||i.stop(),this.timer.stop())}pauseRecording(){var i,t;this.isRecording()&&(this.isWaveformPaused=!0,null===(i=this.mediaRecorder)||void 0===i||i.requestData(),null===(t=this.mediaRecorder)||void 0===t||t.pause(),this.timer.stop(),this.lastDuration=this.duration)}resumeRecording(){var i;this.isPaused()&&(this.isWaveformPaused=!1,null===(i=this.mediaRecorder)||void 0===i||i.resume(),this.timer.start(),this.lastStartTime=performance.now(),this.emit("record-resume"))}static getAvailableAudioDevices(){return i(this,void 0,void 0,(function*(){return navigator.mediaDevices.enumerateDevices().then((i=>i.filter((i=>"audioinput"===i.kind))))}))}destroy(){this.applyOriginalOptionsIfNeeded(),super.destroy(),this.stopRecording(),this.stopMic(),this.recordedBlobUrl&&(URL.revokeObjectURL(this.recordedBlobUrl),this.recordedBlobUrl=null)}applyOriginalOptionsIfNeeded(){this.wavesurfer&&this.originalOptions&&(this.wavesurfer.setOptions(this.originalOptions),delete this.originalOptions)}}export{n as default};
1
+ /**
2
+ * Record audio from the microphone with a real-time waveform preview
3
+ */
4
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
5
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
6
+ return new (P || (P = Promise))(function (resolve, reject) {
7
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
8
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
9
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
10
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
11
+ });
12
+ };
13
+ import BasePlugin from '../base-plugin.js';
14
+ import Timer from '../timer.js';
15
+ const DEFAULT_BITS_PER_SECOND = 128000;
16
+ const DEFAULT_SCROLLING_WAVEFORM_WINDOW = 5;
17
+ const FPS = 100;
18
+ const MIME_TYPES = ['audio/webm', 'audio/wav', 'audio/mpeg', 'audio/mp4', 'audio/mp3'];
19
+ const findSupportedMimeType = () => MIME_TYPES.find((mimeType) => MediaRecorder.isTypeSupported(mimeType));
20
+ class RecordPlugin extends BasePlugin {
21
+ /** Create an instance of the Record plugin */
22
+ constructor(options) {
23
+ var _a, _b, _c, _d, _e, _f;
24
+ super(Object.assign(Object.assign({}, options), { audioBitsPerSecond: (_a = options.audioBitsPerSecond) !== null && _a !== void 0 ? _a : DEFAULT_BITS_PER_SECOND, scrollingWaveform: (_b = options.scrollingWaveform) !== null && _b !== void 0 ? _b : false, scrollingWaveformWindow: (_c = options.scrollingWaveformWindow) !== null && _c !== void 0 ? _c : DEFAULT_SCROLLING_WAVEFORM_WINDOW, continuousWaveform: (_d = options.continuousWaveform) !== null && _d !== void 0 ? _d : false, renderRecordedAudio: (_e = options.renderRecordedAudio) !== null && _e !== void 0 ? _e : true, mediaRecorderTimeslice: (_f = options.mediaRecorderTimeslice) !== null && _f !== void 0 ? _f : undefined }));
25
+ this.stream = null;
26
+ this.mediaRecorder = null;
27
+ this.dataWindow = null;
28
+ this.isWaveformPaused = false;
29
+ this.lastStartTime = 0;
30
+ this.lastDuration = 0;
31
+ this.duration = 0;
32
+ this.micStream = null;
33
+ this.recordedBlobUrl = null;
34
+ this.timer = new Timer();
35
+ this.subscriptions.push(this.timer.on('tick', () => {
36
+ const currentTime = performance.now() - this.lastStartTime;
37
+ this.duration = this.isPaused() ? this.duration : this.lastDuration + currentTime;
38
+ this.emit('record-progress', this.duration);
39
+ }));
40
+ }
41
+ /** Create an instance of the Record plugin */
42
+ static create(options) {
43
+ return new RecordPlugin(options || {});
44
+ }
45
+ renderMicStream(stream) {
46
+ var _a;
47
+ const audioContext = new AudioContext();
48
+ const source = audioContext.createMediaStreamSource(stream);
49
+ const analyser = audioContext.createAnalyser();
50
+ source.connect(analyser);
51
+ // Use smaller FFT size for more responsive peak detection
52
+ if (this.options.continuousWaveform || this.options.scrollingWaveform) {
53
+ analyser.fftSize = 32;
54
+ }
55
+ const bufferLength = analyser.frequencyBinCount;
56
+ const dataArray = new Float32Array(bufferLength);
57
+ let sampleIdx = 0;
58
+ if (this.wavesurfer) {
59
+ (_a = this.originalOptions) !== null && _a !== void 0 ? _a : (this.originalOptions = Object.assign({}, this.wavesurfer.options));
60
+ this.wavesurfer.options.interact = false;
61
+ if (this.options.scrollingWaveform) {
62
+ this.wavesurfer.options.cursorWidth = 0;
63
+ // Use fixed max peak in scrolling mode to prevent "dancing" waveform
64
+ this.wavesurfer.options.normalize = true;
65
+ this.wavesurfer.options.maxPeak = 1;
66
+ }
67
+ }
68
+ const drawWaveform = () => {
69
+ var _a, _b, _c, _d;
70
+ if (this.isWaveformPaused)
71
+ return;
72
+ analyser.getFloatTimeDomainData(dataArray);
73
+ if (this.options.scrollingWaveform) {
74
+ // Scrolling waveform - use peak values for smooth rendering
75
+ const windowSize = Math.floor((this.options.scrollingWaveformWindow || 0) * FPS);
76
+ // Calculate peak value from the current buffer
77
+ let maxValue = 0;
78
+ for (let i = 0; i < bufferLength; i++) {
79
+ const value = Math.abs(dataArray[i]);
80
+ if (value > maxValue) {
81
+ maxValue = value;
82
+ }
83
+ }
84
+ if (!this.dataWindow) {
85
+ this.dataWindow = new Float32Array(windowSize);
86
+ }
87
+ const tempArray = new Float32Array(windowSize);
88
+ if (this.dataWindow && this.dataWindow.length > 0) {
89
+ // Shift old data to the left, dropping the oldest sample
90
+ const keepLength = windowSize - 1;
91
+ const oldData = this.dataWindow.slice(-keepLength);
92
+ tempArray.set(oldData, 0);
93
+ }
94
+ // Add new peak value at the end
95
+ tempArray[windowSize - 1] = maxValue;
96
+ this.dataWindow = tempArray;
97
+ }
98
+ else if (this.options.continuousWaveform) {
99
+ // Continuous waveform
100
+ if (!this.dataWindow) {
101
+ const size = this.options.continuousWaveformDuration
102
+ ? Math.round(this.options.continuousWaveformDuration * FPS)
103
+ : ((_b = (_a = this.wavesurfer) === null || _a === void 0 ? void 0 : _a.getWidth()) !== null && _b !== void 0 ? _b : 0) * window.devicePixelRatio;
104
+ this.dataWindow = new Float32Array(size);
105
+ }
106
+ let maxValue = 0;
107
+ for (let i = 0; i < bufferLength; i++) {
108
+ const value = Math.abs(dataArray[i]);
109
+ if (value > maxValue) {
110
+ maxValue = value;
111
+ }
112
+ }
113
+ if (sampleIdx + 1 > this.dataWindow.length) {
114
+ const tempArray = new Float32Array(this.dataWindow.length * 2);
115
+ tempArray.set(this.dataWindow, 0);
116
+ this.dataWindow = tempArray;
117
+ }
118
+ this.dataWindow[sampleIdx] = maxValue;
119
+ sampleIdx++;
120
+ }
121
+ else {
122
+ this.dataWindow = dataArray;
123
+ }
124
+ // Render the waveform
125
+ if (this.wavesurfer) {
126
+ const totalDuration = ((_d = (_c = this.dataWindow) === null || _c === void 0 ? void 0 : _c.length) !== null && _d !== void 0 ? _d : 0) / FPS;
127
+ this.wavesurfer
128
+ .load('', [this.dataWindow], this.options.scrollingWaveform ? this.options.scrollingWaveformWindow : totalDuration)
129
+ .then(() => {
130
+ if (this.wavesurfer && this.options.continuousWaveform) {
131
+ this.wavesurfer.setTime(this.getDuration() / 1000);
132
+ if (!this.wavesurfer.options.minPxPerSec) {
133
+ this.wavesurfer.setOptions({
134
+ minPxPerSec: this.wavesurfer.getWidth() / this.wavesurfer.getDuration(),
135
+ });
136
+ }
137
+ }
138
+ })
139
+ .catch((err) => {
140
+ console.error('Error rendering real-time recording data:', err);
141
+ });
142
+ }
143
+ };
144
+ const intervalId = setInterval(drawWaveform, 1000 / FPS);
145
+ const cleanup = () => {
146
+ clearInterval(intervalId);
147
+ source === null || source === void 0 ? void 0 : source.disconnect();
148
+ audioContext === null || audioContext === void 0 ? void 0 : audioContext.close();
149
+ };
150
+ return {
151
+ onDestroy: cleanup,
152
+ onEnd: () => {
153
+ this.isWaveformPaused = true;
154
+ this.stopMic();
155
+ },
156
+ };
157
+ }
158
+ /** Request access to the microphone and start monitoring incoming audio */
159
+ startMic(options) {
160
+ return __awaiter(this, void 0, void 0, function* () {
161
+ // Stop previous mic stream if exists to clean up AudioContext
162
+ if (this.micStream) {
163
+ this.stopMic();
164
+ }
165
+ let stream;
166
+ try {
167
+ stream = yield navigator.mediaDevices.getUserMedia({
168
+ audio: options !== null && options !== void 0 ? options : true,
169
+ });
170
+ }
171
+ catch (err) {
172
+ throw new Error('Error accessing the microphone: ' + err.message);
173
+ }
174
+ const micStream = this.renderMicStream(stream);
175
+ this.micStream = micStream;
176
+ this.unsubscribeDestroy = this.once('destroy', micStream.onDestroy);
177
+ this.unsubscribeRecordEnd = this.once('record-end', micStream.onEnd);
178
+ this.stream = stream;
179
+ return stream;
180
+ });
181
+ }
182
+ /** Stop monitoring incoming audio */
183
+ stopMic() {
184
+ var _a, _b, _c;
185
+ (_a = this.micStream) === null || _a === void 0 ? void 0 : _a.onDestroy();
186
+ (_b = this.unsubscribeDestroy) === null || _b === void 0 ? void 0 : _b.call(this);
187
+ (_c = this.unsubscribeRecordEnd) === null || _c === void 0 ? void 0 : _c.call(this);
188
+ this.micStream = null;
189
+ this.unsubscribeDestroy = undefined;
190
+ this.unsubscribeRecordEnd = undefined;
191
+ if (!this.stream)
192
+ return;
193
+ this.stream.getTracks().forEach((track) => track.stop());
194
+ this.stream = null;
195
+ this.mediaRecorder = null;
196
+ }
197
+ /** Start recording audio from the microphone */
198
+ startRecording(options) {
199
+ return __awaiter(this, void 0, void 0, function* () {
200
+ const stream = this.stream || (yield this.startMic(options));
201
+ this.dataWindow = null;
202
+ const mediaRecorder = this.mediaRecorder ||
203
+ new MediaRecorder(stream, {
204
+ mimeType: this.options.mimeType || findSupportedMimeType(),
205
+ audioBitsPerSecond: this.options.audioBitsPerSecond,
206
+ });
207
+ this.mediaRecorder = mediaRecorder;
208
+ this.stopRecording();
209
+ const recordedChunks = [];
210
+ mediaRecorder.ondataavailable = (event) => {
211
+ if (event.data.size > 0) {
212
+ recordedChunks.push(event.data);
213
+ }
214
+ this.emit('record-data-available', event.data);
215
+ };
216
+ const emitWithBlob = (ev) => {
217
+ var _a;
218
+ const blob = new Blob(recordedChunks, { type: mediaRecorder.mimeType });
219
+ this.emit(ev, blob);
220
+ if (this.options.renderRecordedAudio) {
221
+ this.applyOriginalOptionsIfNeeded();
222
+ // Revoke previous blob URL before creating a new one
223
+ if (this.recordedBlobUrl) {
224
+ URL.revokeObjectURL(this.recordedBlobUrl);
225
+ }
226
+ this.recordedBlobUrl = URL.createObjectURL(blob);
227
+ (_a = this.wavesurfer) === null || _a === void 0 ? void 0 : _a.load(this.recordedBlobUrl);
228
+ }
229
+ };
230
+ mediaRecorder.onpause = () => emitWithBlob('record-pause');
231
+ mediaRecorder.onstop = () => emitWithBlob('record-end');
232
+ mediaRecorder.start(this.options.mediaRecorderTimeslice);
233
+ this.lastStartTime = performance.now();
234
+ this.lastDuration = 0;
235
+ this.duration = 0;
236
+ this.isWaveformPaused = false;
237
+ this.timer.start();
238
+ this.emit('record-start');
239
+ });
240
+ }
241
+ /** Get the duration of the recording */
242
+ getDuration() {
243
+ return this.duration;
244
+ }
245
+ /** Check if the audio is being recorded */
246
+ isRecording() {
247
+ var _a;
248
+ return ((_a = this.mediaRecorder) === null || _a === void 0 ? void 0 : _a.state) === 'recording';
249
+ }
250
+ isPaused() {
251
+ var _a;
252
+ return ((_a = this.mediaRecorder) === null || _a === void 0 ? void 0 : _a.state) === 'paused';
253
+ }
254
+ isActive() {
255
+ var _a;
256
+ return ((_a = this.mediaRecorder) === null || _a === void 0 ? void 0 : _a.state) !== 'inactive';
257
+ }
258
+ /** Stop the recording */
259
+ stopRecording() {
260
+ var _a;
261
+ if (this.isActive()) {
262
+ (_a = this.mediaRecorder) === null || _a === void 0 ? void 0 : _a.stop();
263
+ this.timer.stop();
264
+ }
265
+ }
266
+ /** Pause the recording */
267
+ pauseRecording() {
268
+ var _a, _b;
269
+ if (this.isRecording()) {
270
+ this.isWaveformPaused = true;
271
+ (_a = this.mediaRecorder) === null || _a === void 0 ? void 0 : _a.requestData();
272
+ (_b = this.mediaRecorder) === null || _b === void 0 ? void 0 : _b.pause();
273
+ this.timer.stop();
274
+ this.lastDuration = this.duration;
275
+ }
276
+ }
277
+ /** Resume the recording */
278
+ resumeRecording() {
279
+ var _a;
280
+ if (this.isPaused()) {
281
+ this.isWaveformPaused = false;
282
+ (_a = this.mediaRecorder) === null || _a === void 0 ? void 0 : _a.resume();
283
+ this.timer.start();
284
+ this.lastStartTime = performance.now();
285
+ this.emit('record-resume');
286
+ }
287
+ }
288
+ /** Get a list of available audio devices
289
+ * You can use this to get the device ID of the microphone to use with the startMic and startRecording methods
290
+ * Will return an empty array if the browser doesn't support the MediaDevices API or if the user has not granted access to the microphone
291
+ * You can ask for permission to the microphone by calling startMic
292
+ */
293
+ static getAvailableAudioDevices() {
294
+ return __awaiter(this, void 0, void 0, function* () {
295
+ return navigator.mediaDevices
296
+ .enumerateDevices()
297
+ .then((devices) => devices.filter((device) => device.kind === 'audioinput'));
298
+ });
299
+ }
300
+ /** Destroy the plugin */
301
+ destroy() {
302
+ this.applyOriginalOptionsIfNeeded();
303
+ super.destroy();
304
+ this.stopRecording();
305
+ this.stopMic();
306
+ // Revoke blob URL to free memory
307
+ if (this.recordedBlobUrl) {
308
+ URL.revokeObjectURL(this.recordedBlobUrl);
309
+ this.recordedBlobUrl = null;
310
+ }
311
+ }
312
+ applyOriginalOptionsIfNeeded() {
313
+ if (this.wavesurfer && this.originalOptions) {
314
+ this.wavesurfer.setOptions(this.originalOptions);
315
+ delete this.originalOptions;
316
+ }
317
+ }
318
+ }
319
+ export default RecordPlugin;
@@ -36,6 +36,8 @@ export type RegionEvents = {
36
36
  update: [side?: UpdateSide];
37
37
  /** When dragging or resizing is finished */
38
38
  'update-end': [side?: UpdateSide];
39
+ /** When the region needs to be re-rendered */
40
+ render: [];
39
41
  /** On play */
40
42
  play: [end?: number];
41
43
  /** On mouse click */