@readium/navigator 2.4.0-beta.9 → 2.4.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 (122) hide show
  1. package/dist/index.js +597 -451
  2. package/dist/index.umd.cjs +190 -127
  3. package/package.json +2 -2
  4. package/src/audio/AudioNavigator.ts +155 -42
  5. package/src/audio/AudioPoolManager.ts +27 -14
  6. package/src/audio/engine/AudioEngine.ts +4 -3
  7. package/src/audio/engine/PreservePitchProcessor.js +166 -101
  8. package/src/audio/engine/PreservePitchWorklet.ts +2 -17
  9. package/src/audio/engine/WebAudioEngine.ts +138 -160
  10. package/src/audio/engine/index.ts +2 -2
  11. package/src/audio/index.ts +3 -3
  12. package/src/audio/preferences/AudioDefaults.ts +2 -2
  13. package/src/audio/preferences/AudioPreferences.ts +11 -11
  14. package/src/audio/preferences/AudioPreferencesEditor.ts +13 -13
  15. package/src/audio/preferences/AudioSettings.ts +3 -3
  16. package/src/audio/preferences/index.ts +4 -4
  17. package/src/audio/protection/AudioNavigatorProtector.ts +4 -4
  18. package/src/css/index.ts +1 -1
  19. package/src/epub/EpubNavigator.ts +52 -52
  20. package/src/epub/css/Properties.ts +15 -15
  21. package/src/epub/css/ReadiumCSS.ts +43 -43
  22. package/src/epub/css/index.ts +2 -2
  23. package/src/epub/frame/FrameBlobBuilder.ts +10 -11
  24. package/src/epub/frame/FrameComms.ts +1 -1
  25. package/src/epub/frame/FrameManager.ts +9 -9
  26. package/src/epub/frame/FramePoolManager.ts +13 -13
  27. package/src/epub/frame/index.ts +4 -4
  28. package/src/epub/fxl/FXLCoordinator.ts +3 -3
  29. package/src/epub/fxl/FXLFrameManager.ts +8 -8
  30. package/src/epub/fxl/FXLFramePoolManager.ts +13 -13
  31. package/src/epub/fxl/FXLPeripherals.ts +4 -4
  32. package/src/epub/fxl/index.ts +5 -5
  33. package/src/epub/index.ts +5 -5
  34. package/src/epub/preferences/EpubDefaults.ts +23 -23
  35. package/src/epub/preferences/EpubPreferences.ts +16 -16
  36. package/src/epub/preferences/EpubPreferencesEditor.ts +53 -53
  37. package/src/epub/preferences/EpubSettings.ts +101 -101
  38. package/src/epub/preferences/index.ts +4 -4
  39. package/src/helpers/index.ts +2 -2
  40. package/src/index.ts +8 -8
  41. package/src/injection/Injector.ts +42 -42
  42. package/src/injection/epubInjectables.ts +8 -8
  43. package/src/injection/index.ts +2 -2
  44. package/src/injection/webpubInjectables.ts +1 -1
  45. package/src/preferences/Configurable.ts +2 -2
  46. package/src/preferences/PreferencesEditor.ts +2 -2
  47. package/src/preferences/guards.ts +2 -2
  48. package/src/preferences/index.ts +5 -5
  49. package/src/protection/CopyProtector.ts +5 -1
  50. package/src/protection/DevToolsDetector.ts +16 -16
  51. package/src/protection/DragAndDropProtector.ts +14 -1
  52. package/src/protection/NavigatorProtector.ts +6 -6
  53. package/src/webpub/WebPubBlobBuilder.ts +1 -1
  54. package/src/webpub/WebPubFrameManager.ts +8 -8
  55. package/src/webpub/WebPubFramePoolManager.ts +7 -7
  56. package/src/webpub/WebPubNavigator.ts +27 -27
  57. package/src/webpub/css/Properties.ts +3 -3
  58. package/src/webpub/css/WebPubCSS.ts +11 -11
  59. package/src/webpub/css/index.ts +2 -2
  60. package/src/webpub/index.ts +6 -6
  61. package/src/webpub/preferences/WebPubDefaults.ts +12 -12
  62. package/src/webpub/preferences/WebPubPreferences.ts +8 -8
  63. package/src/webpub/preferences/WebPubPreferencesEditor.ts +31 -31
  64. package/src/webpub/preferences/WebPubSettings.ts +45 -45
  65. package/src/webpub/preferences/index.ts +4 -4
  66. package/types/src/audio/AudioNavigator.d.ts +34 -5
  67. package/types/src/audio/AudioPoolManager.d.ts +7 -4
  68. package/types/src/audio/engine/AudioEngine.d.ts +4 -3
  69. package/types/src/audio/engine/PreservePitchWorklet.d.ts +1 -4
  70. package/types/src/audio/engine/WebAudioEngine.d.ts +15 -9
  71. package/types/src/audio/engine/index.d.ts +2 -2
  72. package/types/src/audio/index.d.ts +3 -3
  73. package/types/src/audio/preferences/AudioPreferences.d.ts +9 -9
  74. package/types/src/audio/preferences/AudioPreferencesEditor.d.ts +4 -4
  75. package/types/src/audio/preferences/AudioSettings.d.ts +3 -3
  76. package/types/src/audio/preferences/index.d.ts +4 -4
  77. package/types/src/audio/protection/AudioNavigatorProtector.d.ts +2 -2
  78. package/types/src/css/index.d.ts +1 -1
  79. package/types/src/epub/EpubNavigator.d.ts +11 -11
  80. package/types/src/epub/css/Properties.d.ts +2 -2
  81. package/types/src/epub/css/ReadiumCSS.d.ts +3 -3
  82. package/types/src/epub/css/index.d.ts +2 -2
  83. package/types/src/epub/frame/FrameBlobBuilder.d.ts +1 -1
  84. package/types/src/epub/frame/FrameComms.d.ts +1 -1
  85. package/types/src/epub/frame/FrameManager.d.ts +2 -2
  86. package/types/src/epub/frame/FramePoolManager.d.ts +3 -3
  87. package/types/src/epub/frame/index.d.ts +4 -4
  88. package/types/src/epub/fxl/FXLFrameManager.d.ts +3 -3
  89. package/types/src/epub/fxl/FXLFramePoolManager.d.ts +5 -5
  90. package/types/src/epub/fxl/FXLPeripherals.d.ts +2 -2
  91. package/types/src/epub/fxl/index.d.ts +5 -5
  92. package/types/src/epub/index.d.ts +5 -5
  93. package/types/src/epub/preferences/EpubDefaults.d.ts +1 -1
  94. package/types/src/epub/preferences/EpubPreferences.d.ts +2 -2
  95. package/types/src/epub/preferences/EpubPreferencesEditor.d.ts +5 -5
  96. package/types/src/epub/preferences/EpubSettings.d.ts +4 -4
  97. package/types/src/epub/preferences/index.d.ts +4 -4
  98. package/types/src/helpers/index.d.ts +2 -2
  99. package/types/src/index.d.ts +8 -8
  100. package/types/src/injection/Injector.d.ts +1 -1
  101. package/types/src/injection/epubInjectables.d.ts +1 -1
  102. package/types/src/injection/index.d.ts +2 -2
  103. package/types/src/preferences/Configurable.d.ts +1 -1
  104. package/types/src/preferences/PreferencesEditor.d.ts +1 -1
  105. package/types/src/preferences/guards.d.ts +1 -1
  106. package/types/src/preferences/index.d.ts +5 -5
  107. package/types/src/protection/CopyProtector.d.ts +1 -0
  108. package/types/src/protection/DragAndDropProtector.d.ts +2 -0
  109. package/types/src/protection/NavigatorProtector.d.ts +1 -1
  110. package/types/src/webpub/WebPubBlobBuilder.d.ts +1 -1
  111. package/types/src/webpub/WebPubFrameManager.d.ts +2 -2
  112. package/types/src/webpub/WebPubFramePoolManager.d.ts +3 -3
  113. package/types/src/webpub/WebPubNavigator.d.ts +10 -10
  114. package/types/src/webpub/css/Properties.d.ts +2 -2
  115. package/types/src/webpub/css/WebPubCSS.d.ts +2 -2
  116. package/types/src/webpub/css/index.d.ts +2 -2
  117. package/types/src/webpub/index.d.ts +6 -6
  118. package/types/src/webpub/preferences/WebPubDefaults.d.ts +1 -1
  119. package/types/src/webpub/preferences/WebPubPreferences.d.ts +2 -2
  120. package/types/src/webpub/preferences/WebPubPreferencesEditor.d.ts +5 -5
  121. package/types/src/webpub/preferences/WebPubSettings.d.ts +4 -4
  122. package/types/src/webpub/preferences/index.d.ts +4 -4
@@ -1,23 +1,51 @@
1
1
  // PreservePitchProcessor.js
2
- // AudioWorklet processor for pitch preservation via pitch shifting
2
+ // AudioWorklet processor for pitch preservation via pitch shifting.
3
+ //
4
+ // Architecture:
5
+ // - Overlap-add (OLA) phase vocoder with an iterative in-place Cooley-Tukey FFT/IFFT.
6
+ // - All intermediate buffers are pre-allocated in the constructor; the hot path
7
+ // (process → _processBuffer → _fft) is allocation-free and GC-safe.
8
+ // - An output ring buffer decouples OLA processing (fires every hopSize input
9
+ // samples) from the Web Audio render quantum (128 frames), so process() always
10
+ // fills outputChannel completely.
3
11
 
4
12
  class PreservePitchProcessor extends AudioWorkletProcessor {
5
13
  constructor() {
6
14
  super();
7
- this.bufferSize = 1024;
8
- this.hopSize = 256;
9
- this.overlap = this.bufferSize - this.hopSize;
10
- this.inputBuffer = new Float32Array(this.bufferSize);
11
- this.outputBuffer = new Float32Array(this.bufferSize);
12
- this.window = new Float32Array(this.bufferSize);
13
- this.bufferIndex = 0;
15
+ this.bufferSize = 1024;
16
+ this.hopSize = 256;
17
+ this.overlap = this.bufferSize - this.hopSize;
14
18
  this.pitchFactor = 1.0;
15
19
 
16
- // Hann window
20
+ // Sliding input window (always holds the last bufferSize samples)
21
+ this.inputBuffer = new Float32Array(this.bufferSize);
22
+ this.inputFill = 0; // samples loaded during startup (saturates at bufferSize)
23
+ this.hopAccum = 0; // new samples since last OLA step; triggers a step at hopSize
24
+
25
+ // OLA output accumulator: overlap-add results accumulate here; hopSize samples
26
+ // are drained to the ring buffer and the remainder shifts down each OLA step.
27
+ this.olaBuffer = new Float32Array(this.bufferSize);
28
+
29
+ // Output FIFO ring buffer — power-of-2 size for allocation-free modulo wrapping.
30
+ this._ringSize = 4096;
31
+ this._ring = new Float32Array(this._ringSize);
32
+ this._ringMask = this._ringSize - 1;
33
+ this._ringWrite = 0;
34
+ this._ringRead = 0;
35
+ this._ringAvail = 0;
36
+
37
+ // Hann window (pre-computed, never mutated)
38
+ this.window = new Float32Array(this.bufferSize);
17
39
  for (let i = 0; i < this.bufferSize; i++) {
18
40
  this.window[i] = 0.5 * (1 - Math.cos(2 * Math.PI * i / this.bufferSize));
19
41
  }
20
42
 
43
+ // Pre-allocated FFT work buffers — never re-created in the hot path
44
+ this._re = new Float64Array(this.bufferSize);
45
+ this._im = new Float64Array(this.bufferSize);
46
+ this._shiftedRe = new Float64Array(this.bufferSize);
47
+ this._shiftedIm = new Float64Array(this.bufferSize);
48
+
21
49
  this.port.onmessage = (event) => {
22
50
  if (event.data.type === 'setPitchFactor') {
23
51
  this.pitchFactor = event.data.factor;
@@ -26,123 +54,160 @@ class PreservePitchProcessor extends AudioWorkletProcessor {
26
54
  }
27
55
 
28
56
  process(inputs, outputs) {
29
- const input = inputs[0];
57
+ const input = inputs[0];
30
58
  const output = outputs[0];
31
-
32
59
  if (!input || !output) return true;
60
+ const inCh = input[0];
61
+ const outCh = output[0];
62
+ if (!inCh || !outCh) return true;
63
+
64
+ const newCount = inCh.length; // always 128 under normal Web Audio conditions
65
+
66
+ // --- 1. Push new samples into the sliding input window ---
67
+ if (this.inputFill < this.bufferSize) {
68
+ // Startup: fill the window until we have a full bufferSize frame.
69
+ // Since bufferSize (1024) is an exact multiple of the render quantum (128)
70
+ // this branch always copies exactly newCount samples.
71
+ this.inputBuffer.set(inCh, this.inputFill);
72
+ this.inputFill += newCount;
73
+ } else {
74
+ // Steady state: slide left by newCount, append the new quantum at the end.
75
+ this.inputBuffer.copyWithin(0, newCount);
76
+ this.inputBuffer.set(inCh, this.bufferSize - newCount);
77
+ }
78
+ this.hopAccum += newCount;
33
79
 
34
- const inputChannel = input[0];
35
- const outputChannel = output[0];
36
-
37
- // Accumulate input
38
- for (let i = 0; i < inputChannel.length; i++) {
39
- this.inputBuffer[this.bufferIndex] = inputChannel[i];
40
- this.bufferIndex++;
80
+ // --- 2. Run OLA step(s) whenever hopAccum reaches hopSize ---
81
+ // During startup we skip processing until a full window is available.
82
+ while (this.inputFill >= this.bufferSize && this.hopAccum >= this.hopSize) {
83
+ this.hopAccum -= this.hopSize;
84
+ this._processBuffer(); // drains hopSize samples into _ring
85
+ }
41
86
 
42
- if (this.bufferIndex >= this.bufferSize) {
43
- // Process buffer
44
- this.processBuffer();
45
- // Output hopSize samples
46
- for (let j = 0; j < this.hopSize; j++) {
47
- outputChannel[j] = this.outputBuffer[j];
48
- }
49
- // Shift buffer
50
- for (let j = 0; j < this.overlap; j++) {
51
- this.inputBuffer[j] = this.inputBuffer[j + this.hopSize];
52
- }
53
- this.bufferIndex = this.overlap;
54
- // Clear output buffer for next
55
- this.outputBuffer.fill(0);
87
+ // --- 3. Drain output ring into outputChannel ---
88
+ // Output silence during the initial buffering latency (bufferSize samples ≈ 23 ms
89
+ // at 44100 Hz). Once the ring has data it stays ahead of demand.
90
+ if (this._ringAvail >= newCount) {
91
+ for (let i = 0; i < newCount; i++) {
92
+ outCh[i] = this._ring[this._ringRead];
93
+ this._ringRead = (this._ringRead + 1) & this._ringMask;
56
94
  }
95
+ this._ringAvail -= newCount;
96
+ } else {
97
+ outCh.fill(0);
57
98
  }
58
99
 
59
100
  return true;
60
101
  }
61
102
 
62
- processBuffer() {
63
- // Apply window
64
- let windowed = new Float32Array(this.bufferSize);
65
- for (let i = 0; i < this.bufferSize; i++) {
66
- windowed[i] = this.inputBuffer[i] * this.window[i];
103
+ _processBuffer() {
104
+ const N = this.bufferSize;
105
+ const re = this._re;
106
+ const im = this._im;
107
+ const shiftedRe = this._shiftedRe;
108
+ const shiftedIm = this._shiftedIm;
109
+ const win = this.window;
110
+
111
+ // Load windowed input into real part; zero imaginary part
112
+ for (let i = 0; i < N; i++) {
113
+ re[i] = this.inputBuffer[i] * win[i];
114
+ im[i] = 0;
67
115
  }
68
116
 
69
- // FFT
70
- let fftResult = this.fft(windowed);
117
+ this._fft(re, im, false);
118
+
119
+ // Spectral pitch shift: map bin k → round(k * factor)
120
+ shiftedRe.fill(0);
121
+ shiftedIm.fill(0);
122
+ const half = N >> 1;
123
+ const factor = this.pitchFactor;
124
+ for (let k = 0; k <= half; k++) {
125
+ const newK = Math.round(k * factor);
126
+ if (newK <= half) {
127
+ shiftedRe[newK] += re[k];
128
+ shiftedIm[newK] += im[k];
129
+ // Restore conjugate symmetry so the IFFT yields a real-valued signal
130
+ if (newK > 0 && newK < half) {
131
+ shiftedRe[N - newK] = shiftedRe[newK];
132
+ shiftedIm[N - newK] = -shiftedIm[newK];
133
+ }
134
+ }
135
+ }
71
136
 
72
- // Pitch shift
73
- let shifted = this.pitchShift(fftResult, this.pitchFactor);
137
+ this._fft(shiftedRe, shiftedIm, true); // in-place IFFT
74
138
 
75
- // IFFT
76
- let ifftResult = this.ifft(shifted);
139
+ // Overlap-add into olaBuffer
140
+ for (let i = 0; i < N; i++) {
141
+ this.olaBuffer[i] += shiftedRe[i] * win[i];
142
+ }
77
143
 
78
- // Overlap-add
79
- for (let i = 0; i < this.bufferSize; i++) {
80
- this.outputBuffer[i] += ifftResult[i] * this.window[i];
144
+ // Push hopSize output samples to the ring buffer
145
+ for (let i = 0; i < this.hopSize; i++) {
146
+ this._ring[this._ringWrite] = this.olaBuffer[i];
147
+ this._ringWrite = (this._ringWrite + 1) & this._ringMask;
81
148
  }
149
+ this._ringAvail += this.hopSize;
150
+
151
+ // Shift the OLA accumulator left by hopSize; clear the vacated tail
152
+ this.olaBuffer.copyWithin(0, this.hopSize);
153
+ this.olaBuffer.fill(0, this.bufferSize - this.hopSize);
82
154
  }
83
155
 
84
- pitchShift(fft, factor) {
85
- let N = fft.length;
86
- let result = new Array(N).fill(null).map(() => ({ real: 0, imag: 0 }));
87
- for (let k = 0; k < N / 2; k++) {
88
- let newK = Math.round(k * factor);
89
- if (newK < N / 2) {
90
- result[newK] = fft[k];
91
- result[N - newK] = fft[N - k]; // symmetric for real input
156
+ /**
157
+ * In-place iterative Cooley-Tukey FFT / IFFT.
158
+ * Operates entirely on the caller-supplied Float64Arrays no allocation.
159
+ *
160
+ * @param {Float64Array} re Real parts (mutated in place)
161
+ * @param {Float64Array} im Imaginary parts (mutated in place)
162
+ * @param {boolean} inverse true → IFFT (divides by N), false → FFT
163
+ */
164
+ _fft(re, im, inverse) {
165
+ const N = re.length;
166
+
167
+ // Bit-reversal permutation
168
+ let j = 0;
169
+ for (let i = 1; i < N; i++) {
170
+ let bit = N >> 1;
171
+ for (; j & bit; bit >>= 1) j ^= bit;
172
+ j ^= bit;
173
+ if (i < j) {
174
+ let tmp;
175
+ tmp = re[i]; re[i] = re[j]; re[j] = tmp;
176
+ tmp = im[i]; im[i] = im[j]; im[j] = tmp;
92
177
  }
93
178
  }
94
- return result;
95
- }
96
179
 
97
- fft(input) {
98
- let N = input.length;
99
- if (N <= 1) return [{ real: input[0] || 0, imag: 0 }];
100
- if ((N & (N - 1)) !== 0) throw new Error('N must be power of 2');
101
-
102
- let even = this.fft(input.filter((_, i) => i % 2 === 0));
103
- let odd = this.fft(input.filter((_, i) => i % 2 === 1));
104
-
105
- let result = new Array(N);
106
- for (let k = 0; k < N / 2; k++) {
107
- let t = odd[k];
108
- let angle = -2 * Math.PI * k / N;
109
- let twiddle = { real: Math.cos(angle), imag: Math.sin(angle) };
110
- let twiddled = {
111
- real: t.real * twiddle.real - t.imag * twiddle.imag,
112
- imag: t.real * twiddle.imag + t.imag * twiddle.real
113
- };
114
- result[k] = {
115
- real: even[k].real + twiddled.real,
116
- imag: even[k].imag + twiddled.imag
117
- };
118
- result[k + N / 2] = {
119
- real: even[k].real - twiddled.real,
120
- imag: even[k].imag - twiddled.imag
121
- };
180
+ // Butterfly stages — O(N log N), no allocation
181
+ const sign = inverse ? 1 : -1;
182
+ for (let len = 2; len <= N; len <<= 1) {
183
+ const halfLen = len >> 1;
184
+ const ang = sign * Math.PI / halfLen;
185
+ const wBaseRe = Math.cos(ang);
186
+ const wBaseIm = Math.sin(ang);
187
+ for (let i = 0; i < N; i += len) {
188
+ let wRe = 1, wIm = 0;
189
+ for (let k = 0; k < halfLen; k++) {
190
+ const uRe = re[i + k];
191
+ const uIm = im[i + k];
192
+ const vRe = re[i + k + halfLen] * wRe - im[i + k + halfLen] * wIm;
193
+ const vIm = re[i + k + halfLen] * wIm + im[i + k + halfLen] * wRe;
194
+ re[i + k] = uRe + vRe;
195
+ im[i + k] = uIm + vIm;
196
+ re[i + k + halfLen] = uRe - vRe;
197
+ im[i + k + halfLen] = uIm - vIm;
198
+ const newWRe = wRe * wBaseRe - wIm * wBaseIm;
199
+ wIm = wRe * wBaseIm + wIm * wBaseRe;
200
+ wRe = newWRe;
201
+ }
202
+ }
122
203
  }
123
- return result;
124
- }
125
204
 
126
- ifft(input) {
127
- let N = input.length;
128
- // Conjugate
129
- let conj = input.map(c => ({ real: c.real, imag: -c.imag }));
130
- // FFT
131
- let fftConj = this.fft(conj.map(c => c.real)); // wait, fft expects real array
132
- // FFT on complex is needed, but simplify
133
- // For simplicity, implement IFFT similarly
134
- let result = new Float32Array(N);
135
- for (let n = 0; n < N; n++) {
136
- let sumReal = 0, sumImag = 0;
137
- for (let k = 0; k < N; k++) {
138
- let angle = 2 * Math.PI * k * n / N;
139
- let c = input[k];
140
- sumReal += c.real * Math.cos(angle) - c.imag * Math.sin(angle);
141
- sumImag += c.real * Math.sin(angle) + c.imag * Math.cos(angle);
205
+ if (inverse) {
206
+ for (let i = 0; i < N; i++) {
207
+ re[i] /= N;
208
+ im[i] /= N;
142
209
  }
143
- result[n] = sumReal / N;
144
210
  }
145
- return result;
146
211
  }
147
212
  }
148
213
 
@@ -1,6 +1,5 @@
1
1
  interface PreservePitchWorkletOptions {
2
2
  ctx: AudioContext;
3
- mediaElement?: HTMLMediaElement;
4
3
  pitchFactor?: number;
5
4
  modulePath?: string;
6
5
  }
@@ -8,14 +7,12 @@ interface PreservePitchWorkletOptions {
8
7
  import processorCode from './PreservePitchProcessor.js?raw';
9
8
 
10
9
  export class PreservePitchWorklet {
11
- mediaElement: HTMLMediaElement | null = null;
12
- source: MediaElementAudioSourceNode | null = null;
13
10
  ctx: AudioContext;
14
11
  workletNode: AudioWorkletNode | null = null;
15
- url: string | null = null;
12
+ private url: string | null = null;
16
13
 
17
14
  static async createWorklet(options: PreservePitchWorkletOptions): Promise<PreservePitchWorklet> {
18
- const { ctx, mediaElement, pitchFactor, modulePath } = options;
15
+ const { ctx, pitchFactor, modulePath } = options;
19
16
  const worklet = new PreservePitchWorklet(ctx);
20
17
 
21
18
  try {
@@ -33,17 +30,9 @@ export class PreservePitchWorklet {
33
30
 
34
31
  try {
35
32
  worklet.workletNode = new AudioWorkletNode(ctx, 'preserve-pitch-processor');
36
-
37
33
  if (pitchFactor) {
38
34
  worklet.updatePitchFactor(pitchFactor);
39
35
  }
40
-
41
- if (mediaElement) {
42
- const source = ctx.createMediaElementSource(mediaElement);
43
- source.connect(worklet.workletNode);
44
- worklet.mediaElement = mediaElement;
45
- worklet.source = source;
46
- }
47
36
  } catch (err) {
48
37
  worklet.destroy();
49
38
  throw new Error(`Error creating worklet node: ${err}`);
@@ -67,10 +56,6 @@ export class PreservePitchWorklet {
67
56
  this.workletNode.disconnect();
68
57
  this.workletNode = null;
69
58
  }
70
- if (this.source) {
71
- this.source.disconnect();
72
- this.source = null;
73
- }
74
59
  if (this.url) {
75
60
  URL.revokeObjectURL(this.url);
76
61
  this.url = null;