@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.
- package/dist/index.js +597 -451
- package/dist/index.umd.cjs +190 -127
- package/package.json +2 -2
- package/src/audio/AudioNavigator.ts +155 -42
- package/src/audio/AudioPoolManager.ts +27 -14
- package/src/audio/engine/AudioEngine.ts +4 -3
- package/src/audio/engine/PreservePitchProcessor.js +166 -101
- package/src/audio/engine/PreservePitchWorklet.ts +2 -17
- package/src/audio/engine/WebAudioEngine.ts +138 -160
- package/src/audio/engine/index.ts +2 -2
- package/src/audio/index.ts +3 -3
- package/src/audio/preferences/AudioDefaults.ts +2 -2
- package/src/audio/preferences/AudioPreferences.ts +11 -11
- package/src/audio/preferences/AudioPreferencesEditor.ts +13 -13
- package/src/audio/preferences/AudioSettings.ts +3 -3
- package/src/audio/preferences/index.ts +4 -4
- package/src/audio/protection/AudioNavigatorProtector.ts +4 -4
- package/src/css/index.ts +1 -1
- package/src/epub/EpubNavigator.ts +52 -52
- package/src/epub/css/Properties.ts +15 -15
- package/src/epub/css/ReadiumCSS.ts +43 -43
- package/src/epub/css/index.ts +2 -2
- package/src/epub/frame/FrameBlobBuilder.ts +10 -11
- package/src/epub/frame/FrameComms.ts +1 -1
- package/src/epub/frame/FrameManager.ts +9 -9
- package/src/epub/frame/FramePoolManager.ts +13 -13
- package/src/epub/frame/index.ts +4 -4
- package/src/epub/fxl/FXLCoordinator.ts +3 -3
- package/src/epub/fxl/FXLFrameManager.ts +8 -8
- package/src/epub/fxl/FXLFramePoolManager.ts +13 -13
- package/src/epub/fxl/FXLPeripherals.ts +4 -4
- package/src/epub/fxl/index.ts +5 -5
- package/src/epub/index.ts +5 -5
- package/src/epub/preferences/EpubDefaults.ts +23 -23
- package/src/epub/preferences/EpubPreferences.ts +16 -16
- package/src/epub/preferences/EpubPreferencesEditor.ts +53 -53
- package/src/epub/preferences/EpubSettings.ts +101 -101
- package/src/epub/preferences/index.ts +4 -4
- package/src/helpers/index.ts +2 -2
- package/src/index.ts +8 -8
- package/src/injection/Injector.ts +42 -42
- package/src/injection/epubInjectables.ts +8 -8
- package/src/injection/index.ts +2 -2
- package/src/injection/webpubInjectables.ts +1 -1
- package/src/preferences/Configurable.ts +2 -2
- package/src/preferences/PreferencesEditor.ts +2 -2
- package/src/preferences/guards.ts +2 -2
- package/src/preferences/index.ts +5 -5
- package/src/protection/CopyProtector.ts +5 -1
- package/src/protection/DevToolsDetector.ts +16 -16
- package/src/protection/DragAndDropProtector.ts +14 -1
- package/src/protection/NavigatorProtector.ts +6 -6
- package/src/webpub/WebPubBlobBuilder.ts +1 -1
- package/src/webpub/WebPubFrameManager.ts +8 -8
- package/src/webpub/WebPubFramePoolManager.ts +7 -7
- package/src/webpub/WebPubNavigator.ts +27 -27
- package/src/webpub/css/Properties.ts +3 -3
- package/src/webpub/css/WebPubCSS.ts +11 -11
- package/src/webpub/css/index.ts +2 -2
- package/src/webpub/index.ts +6 -6
- package/src/webpub/preferences/WebPubDefaults.ts +12 -12
- package/src/webpub/preferences/WebPubPreferences.ts +8 -8
- package/src/webpub/preferences/WebPubPreferencesEditor.ts +31 -31
- package/src/webpub/preferences/WebPubSettings.ts +45 -45
- package/src/webpub/preferences/index.ts +4 -4
- package/types/src/audio/AudioNavigator.d.ts +34 -5
- package/types/src/audio/AudioPoolManager.d.ts +7 -4
- package/types/src/audio/engine/AudioEngine.d.ts +4 -3
- package/types/src/audio/engine/PreservePitchWorklet.d.ts +1 -4
- package/types/src/audio/engine/WebAudioEngine.d.ts +15 -9
- package/types/src/audio/engine/index.d.ts +2 -2
- package/types/src/audio/index.d.ts +3 -3
- package/types/src/audio/preferences/AudioPreferences.d.ts +9 -9
- package/types/src/audio/preferences/AudioPreferencesEditor.d.ts +4 -4
- package/types/src/audio/preferences/AudioSettings.d.ts +3 -3
- package/types/src/audio/preferences/index.d.ts +4 -4
- package/types/src/audio/protection/AudioNavigatorProtector.d.ts +2 -2
- package/types/src/css/index.d.ts +1 -1
- package/types/src/epub/EpubNavigator.d.ts +11 -11
- package/types/src/epub/css/Properties.d.ts +2 -2
- package/types/src/epub/css/ReadiumCSS.d.ts +3 -3
- package/types/src/epub/css/index.d.ts +2 -2
- package/types/src/epub/frame/FrameBlobBuilder.d.ts +1 -1
- package/types/src/epub/frame/FrameComms.d.ts +1 -1
- package/types/src/epub/frame/FrameManager.d.ts +2 -2
- package/types/src/epub/frame/FramePoolManager.d.ts +3 -3
- package/types/src/epub/frame/index.d.ts +4 -4
- package/types/src/epub/fxl/FXLFrameManager.d.ts +3 -3
- package/types/src/epub/fxl/FXLFramePoolManager.d.ts +5 -5
- package/types/src/epub/fxl/FXLPeripherals.d.ts +2 -2
- package/types/src/epub/fxl/index.d.ts +5 -5
- package/types/src/epub/index.d.ts +5 -5
- package/types/src/epub/preferences/EpubDefaults.d.ts +1 -1
- package/types/src/epub/preferences/EpubPreferences.d.ts +2 -2
- package/types/src/epub/preferences/EpubPreferencesEditor.d.ts +5 -5
- package/types/src/epub/preferences/EpubSettings.d.ts +4 -4
- package/types/src/epub/preferences/index.d.ts +4 -4
- package/types/src/helpers/index.d.ts +2 -2
- package/types/src/index.d.ts +8 -8
- package/types/src/injection/Injector.d.ts +1 -1
- package/types/src/injection/epubInjectables.d.ts +1 -1
- package/types/src/injection/index.d.ts +2 -2
- package/types/src/preferences/Configurable.d.ts +1 -1
- package/types/src/preferences/PreferencesEditor.d.ts +1 -1
- package/types/src/preferences/guards.d.ts +1 -1
- package/types/src/preferences/index.d.ts +5 -5
- package/types/src/protection/CopyProtector.d.ts +1 -0
- package/types/src/protection/DragAndDropProtector.d.ts +2 -0
- package/types/src/protection/NavigatorProtector.d.ts +1 -1
- package/types/src/webpub/WebPubBlobBuilder.d.ts +1 -1
- package/types/src/webpub/WebPubFrameManager.d.ts +2 -2
- package/types/src/webpub/WebPubFramePoolManager.d.ts +3 -3
- package/types/src/webpub/WebPubNavigator.d.ts +10 -10
- package/types/src/webpub/css/Properties.d.ts +2 -2
- package/types/src/webpub/css/WebPubCSS.d.ts +2 -2
- package/types/src/webpub/css/index.d.ts +2 -2
- package/types/src/webpub/index.d.ts +6 -6
- package/types/src/webpub/preferences/WebPubDefaults.d.ts +1 -1
- package/types/src/webpub/preferences/WebPubPreferences.d.ts +2 -2
- package/types/src/webpub/preferences/WebPubPreferencesEditor.d.ts +5 -5
- package/types/src/webpub/preferences/WebPubSettings.d.ts +4 -4
- 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
|
|
8
|
-
this.hopSize
|
|
9
|
-
this.overlap
|
|
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
|
-
//
|
|
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
|
|
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
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
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
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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
|
-
|
|
70
|
-
|
|
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
|
-
//
|
|
73
|
-
let shifted = this.pitchShift(fftResult, this.pitchFactor);
|
|
137
|
+
this._fft(shiftedRe, shiftedIm, true); // in-place IFFT
|
|
74
138
|
|
|
75
|
-
//
|
|
76
|
-
let
|
|
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
|
-
//
|
|
79
|
-
for (let i = 0; i < this.
|
|
80
|
-
this.
|
|
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
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
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
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
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
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
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,
|
|
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;
|