carta1 1.1.2 → 1.1.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.
- package/bin/cli.js +10 -10
- package/codec/analysis/transient.js +13 -13
- package/codec/browser/interface.js +3 -3
- package/codec/browser/worker.js +1 -1
- package/codec/coding/bitallocation.js +3 -3
- package/codec/coding/quantization.js +7 -7
- package/codec/core/buffers.js +32 -32
- package/codec/core/constants.js +4 -15
- package/codec/io/processor.js +22 -30
- package/codec/pipeline/decoder.js +16 -16
- package/codec/pipeline/encoder.js +19 -19
- package/codec/transforms/fft.js +104 -96
- package/codec/transforms/mdct.js +11 -11
- package/codec/transforms/qmf.js +8 -8
- package/codec/utils.js +4 -125
- package/dist/carta1-worker-interface.min.js.map +1 -1
- package/dist/carta1-worker.min.js +1 -1
- package/dist/carta1-worker.min.js.map +1 -1
- package/dist/carta1.min.js +1 -1
- package/dist/carta1.min.js.map +1 -1
- package/package.json +1 -1
|
@@ -59,11 +59,11 @@ export function dequantizationStage() {
|
|
|
59
59
|
* @param {Array<Int32Array>} frameData.quantizedCoefficients - Quantized coefficient data
|
|
60
60
|
* @param {Array<number>} frameData.blockModes - Block modes for each band
|
|
61
61
|
* @returns {Object} Dequantization results
|
|
62
|
-
* @returns {
|
|
62
|
+
* @returns {Float32Array} returns.coefficients - Reconstructed MDCT coefficients (512 samples)
|
|
63
63
|
* @returns {Array<number>} returns.blockModes - Block modes for each band
|
|
64
64
|
*/
|
|
65
65
|
return (frameData) => {
|
|
66
|
-
const coefficients = new
|
|
66
|
+
const coefficients = new Float32Array(512)
|
|
67
67
|
const {
|
|
68
68
|
nBfu,
|
|
69
69
|
scaleFactorIndices,
|
|
@@ -123,13 +123,13 @@ export function imdctStage(context) {
|
|
|
123
123
|
|
|
124
124
|
/**
|
|
125
125
|
* Inverse transform a single frequency band.
|
|
126
|
-
* @param {
|
|
126
|
+
* @param {Float32Array} coeffs
|
|
127
127
|
* @param {number} bandIndex
|
|
128
128
|
* @param {number} blockMode
|
|
129
|
-
* @param {
|
|
129
|
+
* @param {Float32Array} overlapBuffer
|
|
130
130
|
* @param {Object} bufferPool
|
|
131
131
|
* @param {Object} config
|
|
132
|
-
* @returns {
|
|
132
|
+
* @returns {Float32Array}
|
|
133
133
|
*/
|
|
134
134
|
function transformBand(
|
|
135
135
|
coeffs,
|
|
@@ -164,13 +164,13 @@ export function imdctStage(context) {
|
|
|
164
164
|
|
|
165
165
|
/**
|
|
166
166
|
* Inverse transform using long block.
|
|
167
|
-
* @param {
|
|
167
|
+
* @param {Float32Array} coeffs
|
|
168
168
|
* @param {number} bandIndex
|
|
169
|
-
* @param {
|
|
169
|
+
* @param {Float32Array} overlapBuffer
|
|
170
170
|
* @param {Object} bufferPool
|
|
171
171
|
* @param {Object} config
|
|
172
172
|
* @param {Object} transformFunc
|
|
173
|
-
* @returns {
|
|
173
|
+
* @returns {Float32Array}
|
|
174
174
|
*/
|
|
175
175
|
function inverseLongBlock(
|
|
176
176
|
coeffs,
|
|
@@ -234,12 +234,12 @@ export function imdctStage(context) {
|
|
|
234
234
|
|
|
235
235
|
/**
|
|
236
236
|
* Inverse transform using short blocks.
|
|
237
|
-
* @param {
|
|
237
|
+
* @param {Float32Array} coeffs
|
|
238
238
|
* @param {number} bandIndex
|
|
239
|
-
* @param {
|
|
239
|
+
* @param {Float32Array} overlapBuffer
|
|
240
240
|
* @param {Object} bufferPool
|
|
241
241
|
* @param {Object} config
|
|
242
|
-
* @returns {
|
|
242
|
+
* @returns {Float32Array}
|
|
243
243
|
*/
|
|
244
244
|
function inverseShortBlocks(
|
|
245
245
|
coeffs,
|
|
@@ -308,9 +308,9 @@ export function imdctStage(context) {
|
|
|
308
308
|
/**
|
|
309
309
|
* Transform coefficients back to time domain using inverse MDCT
|
|
310
310
|
* @param {Object} input - Dequantization results
|
|
311
|
-
* @param {
|
|
311
|
+
* @param {Float32Array} input.coefficients - MDCT coefficients (512 samples)
|
|
312
312
|
* @param {Array<number>} input.blockModes - Block modes for each band
|
|
313
|
-
* @returns {Array<
|
|
313
|
+
* @returns {Array<Float32Array>} Three reconstructed frequency bands [low, mid, high]
|
|
314
314
|
*/
|
|
315
315
|
return (input) => {
|
|
316
316
|
const { coefficients, blockModes } = input
|
|
@@ -354,14 +354,14 @@ export function qmfSynthesisStage(context) {
|
|
|
354
354
|
|
|
355
355
|
/**
|
|
356
356
|
* Reconstruct full-spectrum PCM samples from frequency bands
|
|
357
|
-
* @param {Array<
|
|
358
|
-
* @returns {
|
|
357
|
+
* @param {Array<Float32Array>} bands - Three frequency bands [low, mid, high]
|
|
358
|
+
* @returns {Float32Array} Reconstructed PCM samples
|
|
359
359
|
*/
|
|
360
360
|
return (bands) => {
|
|
361
361
|
// Apply high band delay compensation
|
|
362
362
|
const delayedHigh = bufferPool.qmfWorkBuffers.highBandDelay[bands[2].length]
|
|
363
363
|
delayedHigh.set(delays.highBand)
|
|
364
|
-
delayedHigh.set(bands[2])
|
|
364
|
+
delayedHigh.set(bands[2], delays.highBand.length)
|
|
365
365
|
|
|
366
366
|
const highBand = delayedHigh.slice(0, bands[0].length * 2)
|
|
367
367
|
delays.highBand = delayedHigh.slice(bands[0].length * 2)
|
|
@@ -62,9 +62,9 @@ export function qmfAnalysisStage(context) {
|
|
|
62
62
|
|
|
63
63
|
/**
|
|
64
64
|
* Process PCM samples through QMF analysis
|
|
65
|
-
* @param {
|
|
65
|
+
* @param {Float32Array} pcmSamples - Input PCM samples
|
|
66
66
|
* @returns {Object} Analysis result containing frequency bands
|
|
67
|
-
* @returns {Array<
|
|
67
|
+
* @returns {Array<Float32Array>} returns.bands - Three frequency bands [low, mid, high]
|
|
68
68
|
*/
|
|
69
69
|
return (pcmSamples) => {
|
|
70
70
|
const stage1 = qmfAnalysis(
|
|
@@ -118,9 +118,9 @@ export function blockSelectorStage(context) {
|
|
|
118
118
|
/**
|
|
119
119
|
* Analyze frequency bands and determine block modes
|
|
120
120
|
* @param {Object} input - QMF analysis results
|
|
121
|
-
* @param {Array<
|
|
121
|
+
* @param {Array<Float32Array>} input.bands - Three frequency bands [low, mid, high]
|
|
122
122
|
* @returns {Object} Block selection results
|
|
123
|
-
* @returns {Array<
|
|
123
|
+
* @returns {Array<Float32Array>} returns.bands - Original frequency bands
|
|
124
124
|
* @returns {Array<number>} returns.blockModes - Block modes for each band
|
|
125
125
|
*/
|
|
126
126
|
return (input) => {
|
|
@@ -170,12 +170,12 @@ export function mdctStage(context) {
|
|
|
170
170
|
|
|
171
171
|
/**
|
|
172
172
|
* Transform a single frequency band using MDCT.
|
|
173
|
-
* @param {
|
|
173
|
+
* @param {Float32Array} samples
|
|
174
174
|
* @param {number} bandIndex
|
|
175
175
|
* @param {number} blockMode
|
|
176
|
-
* @param {
|
|
176
|
+
* @param {Float32Array} overlapBuffer
|
|
177
177
|
* @param {Object} bufferPool
|
|
178
|
-
* @returns {
|
|
178
|
+
* @returns {Float32Array}
|
|
179
179
|
*/
|
|
180
180
|
function transformBand(
|
|
181
181
|
samples,
|
|
@@ -210,13 +210,13 @@ export function mdctStage(context) {
|
|
|
210
210
|
|
|
211
211
|
/**
|
|
212
212
|
* Transform using long block (better frequency resolution).
|
|
213
|
-
* @param {
|
|
213
|
+
* @param {Float32Array} samples
|
|
214
214
|
* @param {number} bandIndex
|
|
215
215
|
* @param {Object} config
|
|
216
216
|
* @param {Object} transformFunc
|
|
217
|
-
* @param {
|
|
217
|
+
* @param {Float32Array} overlapBuffer
|
|
218
218
|
* @param {Object} bufferPool
|
|
219
|
-
* @returns {
|
|
219
|
+
* @returns {Float32Array}
|
|
220
220
|
*/
|
|
221
221
|
function transformLongBlock(
|
|
222
222
|
samples,
|
|
@@ -252,12 +252,12 @@ export function mdctStage(context) {
|
|
|
252
252
|
|
|
253
253
|
/**
|
|
254
254
|
* Transform using short blocks (better time resolution for transients).
|
|
255
|
-
* @param {
|
|
255
|
+
* @param {Float32Array} samples
|
|
256
256
|
* @param {number} bandIndex
|
|
257
257
|
* @param {Object} config
|
|
258
|
-
* @param {
|
|
258
|
+
* @param {Float32Array} overlapBuffer
|
|
259
259
|
* @param {Object} bufferPool
|
|
260
|
-
* @returns {
|
|
260
|
+
* @returns {Float32Array}
|
|
261
261
|
*/
|
|
262
262
|
function transformShortBlocks(
|
|
263
263
|
samples,
|
|
@@ -267,7 +267,7 @@ export function mdctStage(context) {
|
|
|
267
267
|
bufferPool
|
|
268
268
|
) {
|
|
269
269
|
const numBlocks = 1 << (config.size === 256 ? 3 : 2) // 8 for band 2, 4 for bands 0-1
|
|
270
|
-
const output = new
|
|
270
|
+
const output = new Float32Array(config.size)
|
|
271
271
|
|
|
272
272
|
for (let block = 0; block < numBlocks; block++) {
|
|
273
273
|
const blockStart = block * MDCT_SHORT_BLOCK_SIZE
|
|
@@ -311,18 +311,18 @@ export function mdctStage(context) {
|
|
|
311
311
|
/**
|
|
312
312
|
* Transform frequency bands using MDCT
|
|
313
313
|
* @param {Object} input - Block selection results
|
|
314
|
-
* @param {Array<
|
|
314
|
+
* @param {Array<Float32Array>} input.bands - Three frequency bands
|
|
315
315
|
* @param {Array<number>} input.blockModes - Block modes for each band
|
|
316
316
|
* @param {any} input.originalFrame - Original frame data (passed through)
|
|
317
317
|
* @returns {Object} MDCT transform results
|
|
318
|
-
* @returns {Array<
|
|
319
|
-
* @returns {
|
|
318
|
+
* @returns {Array<Float32Array>} returns.bands - Original frequency bands
|
|
319
|
+
* @returns {Float32Array} returns.coefficients - MDCT coefficients (512 samples)
|
|
320
320
|
* @returns {Array<number>} returns.blockModes - Block modes
|
|
321
321
|
* @returns {any} returns.originalFrame - Original frame data
|
|
322
322
|
*/
|
|
323
323
|
return (input) => {
|
|
324
324
|
const { bands, blockModes, originalFrame } = input
|
|
325
|
-
const coefficients = new
|
|
325
|
+
const coefficients = new Float32Array(512)
|
|
326
326
|
|
|
327
327
|
bands.forEach((bandSamples, bandIndex) => {
|
|
328
328
|
const transformed = transformBand(
|
|
@@ -359,7 +359,7 @@ export function quantizationStage() {
|
|
|
359
359
|
/**
|
|
360
360
|
* Perform RDO bit allocation and quantization
|
|
361
361
|
* @param {Object} input - MDCT transform results
|
|
362
|
-
* @param {
|
|
362
|
+
* @param {Float32Array} input.coefficients - MDCT coefficients
|
|
363
363
|
* @param {Array<number>} input.blockModes - Block modes
|
|
364
364
|
* @returns {Object} Quantization results ready for bitstream encoding
|
|
365
365
|
* @returns {number} returns.nBfu - Number of active BFUs
|
package/codec/transforms/fft.js
CHANGED
|
@@ -1,136 +1,144 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Carta1 Audio Codec - Fast Fourier Transform
|
|
3
|
-
*
|
|
3
|
+
*
|
|
4
|
+
* This module implements a radix-2 Cooley-Tukey FFT algorithm for frequency domain
|
|
5
|
+
* analysis used in psychoacoustic modeling and transient detection.
|
|
4
6
|
*/
|
|
5
7
|
export class FFT {
|
|
6
8
|
static _cache = new Map()
|
|
7
9
|
|
|
8
10
|
/**
|
|
9
|
-
* Perform
|
|
10
|
-
* @param {
|
|
11
|
-
* @param {
|
|
11
|
+
* Perform in-place FFT on complex data
|
|
12
|
+
* @param {Float32Array} real - Real part of input/output data
|
|
13
|
+
* @param {Float32Array} imag - Imaginary part of input/output data
|
|
12
14
|
*/
|
|
13
15
|
static fft(real, imag) {
|
|
14
16
|
const n = real.length
|
|
15
|
-
if (n !== imag.length)
|
|
16
|
-
|
|
17
|
+
if (n !== imag.length)
|
|
18
|
+
throw new Error('Real and imaginary arrays must have the same length.')
|
|
19
|
+
if ((n & (n - 1)) !== 0) throw new Error('Input size must be a power of 2.')
|
|
17
20
|
if (n <= 1) return
|
|
18
21
|
|
|
19
22
|
let cache = FFT._cache.get(n)
|
|
20
23
|
if (!cache) {
|
|
21
|
-
|
|
24
|
+
// build plan in Float64 for precision
|
|
25
|
+
const log2n = Math.log2(n)
|
|
26
|
+
|
|
27
|
+
const bitRev = new Uint32Array(n)
|
|
28
|
+
for (let i = 1; i < n; i++) {
|
|
29
|
+
bitRev[i] = (bitRev[i >>> 1] >>> 1) | ((i & 1) << (log2n - 1))
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const cosTbl = new Float64Array(n / 2)
|
|
33
|
+
const sinTbl = new Float64Array(n / 2)
|
|
34
|
+
for (let i = 0; i < n / 2; i++) {
|
|
35
|
+
const angle = (-2 * Math.PI * i) / n
|
|
36
|
+
// compute in f64, then enforce |W| = 1 to remove tiny drift
|
|
37
|
+
let c = Math.cos(angle)
|
|
38
|
+
let s = Math.sin(angle)
|
|
39
|
+
const invm = 1 / Math.hypot(c, s) // ~1, but fixes cos^2+sin^2 drift
|
|
40
|
+
cosTbl[i] = c * invm
|
|
41
|
+
sinTbl[i] = s * invm
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
cache = { bitRev, cos: cosTbl, sin: sinTbl }
|
|
22
45
|
FFT._cache.set(n, cache)
|
|
23
46
|
}
|
|
24
47
|
|
|
25
|
-
const bitRev = cache
|
|
26
|
-
|
|
27
|
-
|
|
48
|
+
const { bitRev, cos: cosTbl, sin: sinTbl } = cache
|
|
49
|
+
|
|
50
|
+
// work in Float64 to avoid per-stage Float32 rounding
|
|
51
|
+
const needCopyBack =
|
|
52
|
+
!(real instanceof Float64Array) || !(imag instanceof Float64Array)
|
|
53
|
+
const r = needCopyBack ? new Float64Array(real) : real
|
|
54
|
+
const im = needCopyBack ? new Float64Array(imag) : imag
|
|
28
55
|
|
|
29
|
-
//
|
|
56
|
+
// bit reversal
|
|
30
57
|
for (let i = 0; i < n; i++) {
|
|
31
58
|
const j = bitRev[i]
|
|
32
59
|
if (j > i) {
|
|
33
|
-
let
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
60
|
+
let t = r[i]
|
|
61
|
+
r[i] = r[j]
|
|
62
|
+
r[j] = t
|
|
63
|
+
t = im[i]
|
|
64
|
+
im[i] = im[j]
|
|
65
|
+
im[j] = t
|
|
39
66
|
}
|
|
40
67
|
}
|
|
41
68
|
|
|
42
|
-
//
|
|
69
|
+
// size-2 butterflies
|
|
43
70
|
for (let i = 0; i < n; i += 2) {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
71
|
+
const i1 = i + 1
|
|
72
|
+
const er = r[i],
|
|
73
|
+
ei = im[i]
|
|
74
|
+
const tr = r[i1],
|
|
75
|
+
ti = im[i1]
|
|
76
|
+
r[i] = er + tr
|
|
77
|
+
im[i] = ei + ti
|
|
78
|
+
r[i1] = er - tr
|
|
79
|
+
im[i1] = ei - ti
|
|
52
80
|
}
|
|
53
81
|
|
|
54
|
-
//
|
|
82
|
+
// size-4 butterflies (uses exact W = -i at k=1)
|
|
55
83
|
if (n >= 4) {
|
|
56
84
|
for (let i = 0; i < n; i += 4) {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
85
|
+
const e0 = i,
|
|
86
|
+
o0 = i + 2
|
|
87
|
+
const er0 = r[e0],
|
|
88
|
+
ei0 = im[e0]
|
|
89
|
+
const tr0 = r[o0],
|
|
90
|
+
ti0 = im[o0]
|
|
91
|
+
r[e0] = er0 + tr0
|
|
92
|
+
im[e0] = ei0 + ti0
|
|
93
|
+
r[o0] = er0 - tr0
|
|
94
|
+
im[o0] = ei0 - ti0
|
|
95
|
+
|
|
96
|
+
const e1 = i + 1,
|
|
97
|
+
o1 = i + 3
|
|
98
|
+
const tr1 = im[o1] // multiply by -i
|
|
99
|
+
const ti1 = -r[o1]
|
|
100
|
+
const er1 = r[e1],
|
|
101
|
+
ei1 = im[e1]
|
|
102
|
+
r[e1] = er1 + tr1
|
|
103
|
+
im[e1] = ei1 + ti1
|
|
104
|
+
r[o1] = er1 - tr1
|
|
105
|
+
im[o1] = ei1 - ti1
|
|
77
106
|
}
|
|
78
107
|
}
|
|
79
108
|
|
|
80
|
-
//
|
|
109
|
+
// size >= 8
|
|
81
110
|
for (let stride = 8; stride <= n; stride <<= 1) {
|
|
82
|
-
const
|
|
83
|
-
const
|
|
84
|
-
for (let
|
|
85
|
-
|
|
86
|
-
let
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
const
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
let ti = r2 * s + i2 * c
|
|
105
|
-
real[base + k] = r1 + tr
|
|
106
|
-
imag[base + k] = i1 + ti
|
|
107
|
-
real[base + k + halfStride] = r1 - tr
|
|
108
|
-
imag[base + k + halfStride] = i1 - ti
|
|
109
|
-
tw += tblStep
|
|
111
|
+
const half = stride >>> 1
|
|
112
|
+
const step = (n / stride) | 0
|
|
113
|
+
for (let i = 0; i < n; i += stride) {
|
|
114
|
+
let k = 0
|
|
115
|
+
for (let j = 0; j < half; j++, k += step) {
|
|
116
|
+
const even = i + j
|
|
117
|
+
const odd = even + half
|
|
118
|
+
|
|
119
|
+
const cr = cosTbl[k],
|
|
120
|
+
sr = sinTbl[k]
|
|
121
|
+
const orr = r[odd],
|
|
122
|
+
oii = im[odd]
|
|
123
|
+
|
|
124
|
+
const tr = orr * cr - oii * sr
|
|
125
|
+
const ti = orr * sr + oii * cr
|
|
126
|
+
|
|
127
|
+
const er = r[even],
|
|
128
|
+
ei = im[even]
|
|
129
|
+
r[even] = er + tr
|
|
130
|
+
im[even] = ei + ti
|
|
131
|
+
r[odd] = er - tr
|
|
132
|
+
im[odd] = ei - ti
|
|
110
133
|
}
|
|
111
134
|
}
|
|
112
135
|
}
|
|
113
|
-
}
|
|
114
136
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
const bitRev = new Uint32Array(n)
|
|
121
|
-
const log2n = Math.log2(n) | 0
|
|
122
|
-
for (let i = 1; i < n; i++) {
|
|
123
|
-
bitRev[i] = (bitRev[i >>> 1] >>> 1) | ((i & 1) << (log2n - 1))
|
|
124
|
-
}
|
|
125
|
-
const halfN = n >>> 1
|
|
126
|
-
const cosTbl = new Float64Array(halfN)
|
|
127
|
-
const sinTbl = new Float64Array(halfN)
|
|
128
|
-
const ang = (-2 * Math.PI) / n
|
|
129
|
-
for (let i = 0; i < halfN; i++) {
|
|
130
|
-
const a = ang * i
|
|
131
|
-
cosTbl[i] = Math.cos(a)
|
|
132
|
-
sinTbl[i] = Math.sin(a)
|
|
137
|
+
if (needCopyBack) {
|
|
138
|
+
for (let i = 0; i < n; i++) {
|
|
139
|
+
real[i] = r[i]
|
|
140
|
+
imag[i] = im[i]
|
|
141
|
+
}
|
|
133
142
|
}
|
|
134
|
-
return { bitRev, cos: cosTbl, sin: sinTbl }
|
|
135
143
|
}
|
|
136
144
|
}
|
package/codec/transforms/mdct.js
CHANGED
|
@@ -47,9 +47,9 @@ export class MDCT extends MDCTBase {
|
|
|
47
47
|
|
|
48
48
|
/**
|
|
49
49
|
* Perform forward MDCT transform
|
|
50
|
-
* @param {
|
|
50
|
+
* @param {Float32Array} input - Time-domain input samples
|
|
51
51
|
* @param {Object} mdctBuffers - Optional work buffers for FFT
|
|
52
|
-
* @returns {
|
|
52
|
+
* @returns {Float32Array} Frequency-domain MDCT coefficients
|
|
53
53
|
*/
|
|
54
54
|
transform(input, mdctBuffers = null) {
|
|
55
55
|
const buffers =
|
|
@@ -107,7 +107,7 @@ export class MDCT extends MDCTBase {
|
|
|
107
107
|
FFT.fft(real, imag)
|
|
108
108
|
|
|
109
109
|
// Post-FFT processing
|
|
110
|
-
const output = new
|
|
110
|
+
const output = new Float32Array(this.halfSize)
|
|
111
111
|
for (let i = 0; i < this.fftSize; i++) {
|
|
112
112
|
const c = this.sinCosTable[i * 2]
|
|
113
113
|
const s = this.sinCosTable[i * 2 + 1]
|
|
@@ -132,9 +132,9 @@ export class IMDCT extends MDCTBase {
|
|
|
132
132
|
|
|
133
133
|
/**
|
|
134
134
|
* Perform inverse MDCT transform
|
|
135
|
-
* @param {
|
|
135
|
+
* @param {Float32Array} input - Frequency-domain MDCT coefficients
|
|
136
136
|
* @param {Object} mdctBuffers - Optional work buffers for FFT
|
|
137
|
-
* @returns {
|
|
137
|
+
* @returns {Float32Array} Time-domain output samples
|
|
138
138
|
*/
|
|
139
139
|
transform(input, mdctBuffers = null) {
|
|
140
140
|
const buffers =
|
|
@@ -172,7 +172,7 @@ export class IMDCT extends MDCTBase {
|
|
|
172
172
|
FFT.fft(real, imag)
|
|
173
173
|
|
|
174
174
|
// Post-FFT butterfly
|
|
175
|
-
const output = new
|
|
175
|
+
const output = new Float32Array(this.size)
|
|
176
176
|
|
|
177
177
|
for (let i = 0; i < this.fftSize / 2; i++) {
|
|
178
178
|
const i2 = i * 2
|
|
@@ -222,14 +222,14 @@ export const imdct512 = new IMDCT(MDCT_SIZE_LONG, MDCT_SIZE_LONG * 4)
|
|
|
222
222
|
|
|
223
223
|
/**
|
|
224
224
|
* Perform overlap-add operation for MDCT reconstruction
|
|
225
|
-
* @param {
|
|
226
|
-
* @param {
|
|
227
|
-
* @param {
|
|
228
|
-
* @returns {
|
|
225
|
+
* @param {Float32Array} prev - Previous block samples
|
|
226
|
+
* @param {Float32Array} curr - Current block samples
|
|
227
|
+
* @param {Float32Array} window - Window function coefficients
|
|
228
|
+
* @returns {Float32Array} Overlap-added output samples
|
|
229
229
|
*/
|
|
230
230
|
export function overlapAdd(prev, curr, window) {
|
|
231
231
|
const size = prev.length
|
|
232
|
-
const output = new
|
|
232
|
+
const output = new Float32Array(size * 2)
|
|
233
233
|
|
|
234
234
|
for (let i = 0; i < size; i++) {
|
|
235
235
|
const w1 = window[i]
|
package/codec/transforms/qmf.js
CHANGED
|
@@ -11,8 +11,8 @@ import { throwError } from '../utils.js'
|
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* Perform QMF analysis filtering to split input into low and high frequency bands
|
|
14
|
-
* @param {
|
|
15
|
-
* @param {
|
|
14
|
+
* @param {Float32Array} input - Input audio samples
|
|
15
|
+
* @param {Float32Array} delayLine - QMF delay line state
|
|
16
16
|
* @param {Object} qmfWorkBuffers - Optional work buffers for processing
|
|
17
17
|
* @returns {Object} Object containing lowBand, highBand, and newDelay
|
|
18
18
|
*/
|
|
@@ -26,8 +26,8 @@ export function qmfAnalysis(input, delayLine, qmfWorkBuffers = null) {
|
|
|
26
26
|
workBuffer.set(delayLine)
|
|
27
27
|
workBuffer.set(input, delayLine.length)
|
|
28
28
|
|
|
29
|
-
const lowBand = new
|
|
30
|
-
const highBand = new
|
|
29
|
+
const lowBand = new Float32Array(outputLength)
|
|
30
|
+
const highBand = new Float32Array(outputLength)
|
|
31
31
|
|
|
32
32
|
for (let i = 0; i < outputLength; i++) {
|
|
33
33
|
let evenSum = 0
|
|
@@ -51,9 +51,9 @@ export function qmfAnalysis(input, delayLine, qmfWorkBuffers = null) {
|
|
|
51
51
|
|
|
52
52
|
/**
|
|
53
53
|
* Perform QMF synthesis filtering to reconstruct audio from low and high frequency bands
|
|
54
|
-
* @param {
|
|
55
|
-
* @param {
|
|
56
|
-
* @param {
|
|
54
|
+
* @param {Float32Array} lowBand - Low frequency band samples
|
|
55
|
+
* @param {Float32Array} highBand - High frequency band samples
|
|
56
|
+
* @param {Float32Array} delayLine - QMF delay line state
|
|
57
57
|
* @param {Object} qmfWorkBuffers - Optional work buffers for processing
|
|
58
58
|
* @returns {Object} Object containing output and newDelay
|
|
59
59
|
*/
|
|
@@ -82,7 +82,7 @@ export function qmfSynthesis(
|
|
|
82
82
|
workBuffer[offset + 1] = 0.5 * (low - high)
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
-
const output = new
|
|
85
|
+
const output = new Float32Array(outputLength)
|
|
86
86
|
|
|
87
87
|
// Convolution
|
|
88
88
|
for (let i = 0; i < subbandLength; i++) {
|