carta1 1.0.16 → 1.0.18
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/codec/core/constants.js +11 -0
- package/codec/pipeline/decoder.js +184 -71
- package/codec/pipeline/encoder.js +145 -53
- package/codec/transforms/fft.js +175 -89
- package/codec/utils.js +40 -0
- 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
package/codec/core/constants.js
CHANGED
|
@@ -244,6 +244,17 @@ export const FFT_SIZE_LOW = 128
|
|
|
244
244
|
export const FFT_SIZE_MID = 128
|
|
245
245
|
export const FFT_SIZE_HIGH = 256
|
|
246
246
|
|
|
247
|
+
// MDCT/IMDCT transform configuration
|
|
248
|
+
export const MDCT_BAND_CONFIGS = [
|
|
249
|
+
{ size: 128, windowStart: 48 }, // Low band (0-5.5kHz)
|
|
250
|
+
{ size: 128, windowStart: 48 }, // Mid band (5.5-11kHz)
|
|
251
|
+
{ size: 256, windowStart: 112 }, // High band (11-22kHz)
|
|
252
|
+
]
|
|
253
|
+
|
|
254
|
+
export const MDCT_SHORT_BLOCK_SIZE = 32
|
|
255
|
+
export const MDCT_OVERLAP_SIZE = 32
|
|
256
|
+
export const MDCT_TAIL_WINDOW_SIZE = 16
|
|
257
|
+
|
|
247
258
|
// Quantization
|
|
248
259
|
export const QUANTIZATION_SIGN_BIT_SHIFT = 1
|
|
249
260
|
|
|
@@ -13,7 +13,12 @@
|
|
|
13
13
|
* containing buffer pools and decoding options.
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
-
import {
|
|
16
|
+
import {
|
|
17
|
+
pipe,
|
|
18
|
+
throwError,
|
|
19
|
+
reverseSpectrum,
|
|
20
|
+
extractBandCoefficients,
|
|
21
|
+
} from '../utils.js'
|
|
17
22
|
import { qmfSynthesis } from '../transforms/qmf.js'
|
|
18
23
|
import { imdct64, imdct256, imdct512, overlapAdd } from '../transforms/mdct.js'
|
|
19
24
|
import { dequantize } from '../coding/quantization.js'
|
|
@@ -25,6 +30,9 @@ import {
|
|
|
25
30
|
WORD_LENGTH_BITS,
|
|
26
31
|
WINDOW_SHORT,
|
|
27
32
|
MDCT_SIZE_LONG,
|
|
33
|
+
MDCT_BAND_CONFIGS,
|
|
34
|
+
MDCT_SHORT_BLOCK_SIZE,
|
|
35
|
+
MDCT_TAIL_WINDOW_SIZE,
|
|
28
36
|
} from '../core/constants.js'
|
|
29
37
|
|
|
30
38
|
/**
|
|
@@ -110,89 +118,194 @@ export function imdctStage(context) {
|
|
|
110
118
|
context?.bufferPool ?? throwError('imdctStage: bufferPool is required')
|
|
111
119
|
const overlapBuffers = bufferPool.imdctOverlap
|
|
112
120
|
|
|
121
|
+
// Transform function mapping for each band
|
|
122
|
+
const TRANSFORM_FUNCS = [imdct256, imdct256, imdct512]
|
|
123
|
+
|
|
113
124
|
/**
|
|
114
|
-
*
|
|
115
|
-
* @param {Array} input - Dequantization results
|
|
116
|
-
* @param {Float32Array} input[0] - MDCT coefficients (512 samples)
|
|
117
|
-
* @param {Array<number>} input[1] - Block mode indices for each band
|
|
118
|
-
* @returns {Array<Float32Array>} Three reconstructed frequency bands [low, mid, high]
|
|
125
|
+
* Inverse transform a single frequency band
|
|
119
126
|
*/
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
if (band > 0) {
|
|
151
|
-
const reversed = bufferPool.reversalBuffers[blockSpecs.length]
|
|
152
|
-
for (let i = 0; i < blockSpecs.length; i++) {
|
|
153
|
-
reversed[i] = blockSpecs[blockSpecs.length - 1 - i]
|
|
154
|
-
}
|
|
155
|
-
blockSpecs = reversed
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
const inv = imdctFunc.transform(blockSpecs, bufferPool.mdctBuffers)
|
|
159
|
-
const invStart = inv.length / 4
|
|
160
|
-
|
|
161
|
-
for (let i = 0; i < blockSize; i++) {
|
|
162
|
-
invBuf[start + i] = inv[invStart + i]
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
const dstPart = overlapAdd(
|
|
166
|
-
prevBuf.slice(0, 16),
|
|
167
|
-
invBuf.slice(start, start + 16),
|
|
168
|
-
WINDOW_SHORT
|
|
169
|
-
)
|
|
127
|
+
function transformBand(
|
|
128
|
+
coeffs,
|
|
129
|
+
bandIndex,
|
|
130
|
+
blockMode,
|
|
131
|
+
overlapBuffer,
|
|
132
|
+
bufferPool,
|
|
133
|
+
config
|
|
134
|
+
) {
|
|
135
|
+
const isLongBlock = blockMode === 0
|
|
136
|
+
const transformFunc = TRANSFORM_FUNCS[bandIndex]
|
|
137
|
+
|
|
138
|
+
if (isLongBlock) {
|
|
139
|
+
return inverseLongBlock(
|
|
140
|
+
coeffs,
|
|
141
|
+
bandIndex,
|
|
142
|
+
overlapBuffer,
|
|
143
|
+
bufferPool,
|
|
144
|
+
config,
|
|
145
|
+
transformFunc
|
|
146
|
+
)
|
|
147
|
+
} else {
|
|
148
|
+
return inverseShortBlocks(
|
|
149
|
+
coeffs,
|
|
150
|
+
bandIndex,
|
|
151
|
+
overlapBuffer,
|
|
152
|
+
bufferPool,
|
|
153
|
+
config
|
|
154
|
+
)
|
|
155
|
+
}
|
|
156
|
+
}
|
|
170
157
|
|
|
171
|
-
|
|
158
|
+
/**
|
|
159
|
+
* Inverse transform using long block
|
|
160
|
+
*/
|
|
161
|
+
function inverseLongBlock(
|
|
162
|
+
coeffs,
|
|
163
|
+
bandIndex,
|
|
164
|
+
overlapBuffer,
|
|
165
|
+
bufferPool,
|
|
166
|
+
config,
|
|
167
|
+
transformFunc
|
|
168
|
+
) {
|
|
169
|
+
// Unreverse spectral reversal for mid/high bands
|
|
170
|
+
let blockSpecs = coeffs
|
|
171
|
+
if (bandIndex > 0) {
|
|
172
|
+
blockSpecs = reverseSpectrum(coeffs, bufferPool.reversalBuffers)
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Apply inverse transform
|
|
176
|
+
const inv = transformFunc.transform(blockSpecs, bufferPool.mdctBuffers)
|
|
177
|
+
const invStart = inv.length / 4
|
|
172
178
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
179
|
+
// Prepare output buffer
|
|
180
|
+
const invBuf = bufferPool.transformBuffers[MDCT_SIZE_LONG]
|
|
181
|
+
invBuf.fill(0)
|
|
182
|
+
|
|
183
|
+
// Copy transformed samples
|
|
184
|
+
for (let i = 0; i < config.size; i++) {
|
|
185
|
+
invBuf[i] = inv[invStart + i]
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Handle overlap-add with previous frame
|
|
189
|
+
const prevBuf = overlapBuffer.slice(
|
|
190
|
+
config.size * 2 - MDCT_TAIL_WINDOW_SIZE,
|
|
191
|
+
config.size * 2
|
|
192
|
+
)
|
|
193
|
+
const dstPart = overlapAdd(
|
|
194
|
+
prevBuf.slice(0, MDCT_TAIL_WINDOW_SIZE),
|
|
195
|
+
invBuf.slice(0, MDCT_TAIL_WINDOW_SIZE),
|
|
196
|
+
WINDOW_SHORT
|
|
197
|
+
)
|
|
176
198
|
|
|
177
|
-
|
|
178
|
-
|
|
199
|
+
overlapBuffer.set(dstPart, 0)
|
|
200
|
+
|
|
201
|
+
// Save tail for next frame
|
|
202
|
+
for (let i = 0; i < MDCT_TAIL_WINDOW_SIZE; i++) {
|
|
203
|
+
prevBuf[i] = invBuf[MDCT_TAIL_WINDOW_SIZE + i]
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Copy main samples
|
|
207
|
+
const copyLen = bandIndex === 2 ? 240 : 112
|
|
208
|
+
for (let i = 0; i < copyLen; i++) {
|
|
209
|
+
overlapBuffer[32 + i] = invBuf[MDCT_TAIL_WINDOW_SIZE + i]
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// Copy final samples
|
|
213
|
+
for (let i = 0; i < MDCT_TAIL_WINDOW_SIZE; i++) {
|
|
214
|
+
overlapBuffer[config.size * 2 - MDCT_TAIL_WINDOW_SIZE + i] =
|
|
215
|
+
invBuf[config.size - MDCT_TAIL_WINDOW_SIZE + i]
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
return overlapBuffer.slice(0, config.size)
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Inverse transform using short blocks
|
|
223
|
+
*/
|
|
224
|
+
function inverseShortBlocks(
|
|
225
|
+
coeffs,
|
|
226
|
+
bandIndex,
|
|
227
|
+
overlapBuffer,
|
|
228
|
+
bufferPool,
|
|
229
|
+
config
|
|
230
|
+
) {
|
|
231
|
+
const numBlocks = 1 << (config.size === 256 ? 3 : 2)
|
|
232
|
+
const invBuf = bufferPool.transformBuffers[MDCT_SIZE_LONG]
|
|
233
|
+
invBuf.fill(0)
|
|
234
|
+
|
|
235
|
+
const prevBuf = overlapBuffer.slice(
|
|
236
|
+
config.size * 2 - MDCT_TAIL_WINDOW_SIZE,
|
|
237
|
+
config.size * 2
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
let start = 0
|
|
241
|
+
let pos = 0
|
|
242
|
+
|
|
243
|
+
for (let block = 0; block < numBlocks; block++) {
|
|
244
|
+
// Extract block coefficients
|
|
245
|
+
let blockSpecs = coeffs.slice(pos, pos + MDCT_SHORT_BLOCK_SIZE)
|
|
246
|
+
|
|
247
|
+
// Unreverse spectral reversal for mid/high bands
|
|
248
|
+
if (bandIndex > 0) {
|
|
249
|
+
blockSpecs = reverseSpectrum(blockSpecs, bufferPool.reversalBuffers)
|
|
179
250
|
}
|
|
180
251
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
252
|
+
// Apply inverse transform
|
|
253
|
+
const inv = imdct64.transform(blockSpecs, bufferPool.mdctBuffers)
|
|
254
|
+
const invStart = inv.length / 4
|
|
255
|
+
|
|
256
|
+
// Copy to intermediate buffer
|
|
257
|
+
for (let i = 0; i < MDCT_SHORT_BLOCK_SIZE; i++) {
|
|
258
|
+
invBuf[start + i] = inv[invStart + i]
|
|
186
259
|
}
|
|
187
260
|
|
|
188
|
-
|
|
189
|
-
|
|
261
|
+
// Overlap-add with previous block
|
|
262
|
+
const dstPart = overlapAdd(
|
|
263
|
+
prevBuf.slice(0, MDCT_TAIL_WINDOW_SIZE),
|
|
264
|
+
invBuf.slice(start, start + MDCT_TAIL_WINDOW_SIZE),
|
|
265
|
+
WINDOW_SHORT
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
overlapBuffer.set(dstPart, start)
|
|
269
|
+
|
|
270
|
+
// Save tail for next block
|
|
271
|
+
for (let i = 0; i < MDCT_TAIL_WINDOW_SIZE; i++) {
|
|
272
|
+
prevBuf[i] = invBuf[start + MDCT_TAIL_WINDOW_SIZE + i]
|
|
190
273
|
}
|
|
191
274
|
|
|
192
|
-
|
|
275
|
+
start += MDCT_SHORT_BLOCK_SIZE
|
|
276
|
+
pos += MDCT_SHORT_BLOCK_SIZE
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// Copy final tail samples
|
|
280
|
+
for (let i = 0; i < MDCT_TAIL_WINDOW_SIZE; i++) {
|
|
281
|
+
overlapBuffer[config.size * 2 - MDCT_TAIL_WINDOW_SIZE + i] =
|
|
282
|
+
invBuf[config.size - MDCT_TAIL_WINDOW_SIZE + i]
|
|
193
283
|
}
|
|
194
284
|
|
|
195
|
-
return
|
|
285
|
+
return overlapBuffer.slice(0, config.size)
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Transform coefficients back to time domain using inverse MDCT
|
|
290
|
+
* @param {Array} input - Dequantization results
|
|
291
|
+
* @param {Float32Array} input[0] - MDCT coefficients (512 samples)
|
|
292
|
+
* @param {Array<number>} input[1] - Block mode indices for each band
|
|
293
|
+
* @returns {Array<Float32Array>} Three reconstructed frequency bands [low, mid, high]
|
|
294
|
+
*/
|
|
295
|
+
return (input) => {
|
|
296
|
+
const [coefficients, blockModes] = input
|
|
297
|
+
|
|
298
|
+
return MDCT_BAND_CONFIGS.map((config, bandIndex) => {
|
|
299
|
+
const bandCoeffs = extractBandCoefficients(coefficients, bandIndex)
|
|
300
|
+
return transformBand(
|
|
301
|
+
bandCoeffs,
|
|
302
|
+
bandIndex,
|
|
303
|
+
blockModes[bandIndex],
|
|
304
|
+
overlapBuffers[bandIndex],
|
|
305
|
+
bufferPool,
|
|
306
|
+
config
|
|
307
|
+
)
|
|
308
|
+
})
|
|
196
309
|
}
|
|
197
310
|
}
|
|
198
311
|
|
|
@@ -14,7 +14,12 @@
|
|
|
14
14
|
* containing buffer pools and encoding options.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
import {
|
|
17
|
+
import {
|
|
18
|
+
pipe,
|
|
19
|
+
throwError,
|
|
20
|
+
reverseSpectrum,
|
|
21
|
+
calculateBandOffset,
|
|
22
|
+
} from '../utils.js'
|
|
18
23
|
import { qmfAnalysis } from '../transforms/qmf.js'
|
|
19
24
|
import { mdct64, mdct256, mdct512 } from '../transforms/mdct.js'
|
|
20
25
|
import {
|
|
@@ -34,6 +39,9 @@ import {
|
|
|
34
39
|
MDCT_SIZE_SHORT,
|
|
35
40
|
MDCT_SIZE_MID,
|
|
36
41
|
MDCT_SIZE_LONG,
|
|
42
|
+
MDCT_BAND_CONFIGS,
|
|
43
|
+
MDCT_SHORT_BLOCK_SIZE,
|
|
44
|
+
MDCT_OVERLAP_SIZE,
|
|
37
45
|
} from '../core/constants.js'
|
|
38
46
|
import { performFFT, detectTransient } from '../analysis/transient.js'
|
|
39
47
|
import { psychoAnalysis } from '../analysis/psychoacoustics.js'
|
|
@@ -180,6 +188,130 @@ export function mdctStage(context) {
|
|
|
180
188
|
context?.bufferPool ?? throwError('mdctStage: bufferPool is required')
|
|
181
189
|
const overlapBuffers = bufferPool.mdctOverlap
|
|
182
190
|
|
|
191
|
+
// Transform function mapping for each band
|
|
192
|
+
const TRANSFORM_FUNCS = [mdct256, mdct256, mdct512]
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Transform a single frequency band using MDCT
|
|
196
|
+
*/
|
|
197
|
+
function transformBand(
|
|
198
|
+
samples,
|
|
199
|
+
bandIndex,
|
|
200
|
+
blockMode,
|
|
201
|
+
overlapBuffer,
|
|
202
|
+
bufferPool
|
|
203
|
+
) {
|
|
204
|
+
const config = MDCT_BAND_CONFIGS[bandIndex]
|
|
205
|
+
const transformFunc = TRANSFORM_FUNCS[bandIndex]
|
|
206
|
+
const isLongBlock = blockMode === 0
|
|
207
|
+
|
|
208
|
+
if (isLongBlock) {
|
|
209
|
+
return transformLongBlock(
|
|
210
|
+
samples,
|
|
211
|
+
bandIndex,
|
|
212
|
+
config,
|
|
213
|
+
transformFunc,
|
|
214
|
+
overlapBuffer,
|
|
215
|
+
bufferPool
|
|
216
|
+
)
|
|
217
|
+
} else {
|
|
218
|
+
return transformShortBlocks(
|
|
219
|
+
samples,
|
|
220
|
+
bandIndex,
|
|
221
|
+
config,
|
|
222
|
+
overlapBuffer,
|
|
223
|
+
bufferPool
|
|
224
|
+
)
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Transform using long block (better frequency resolution)
|
|
230
|
+
*/
|
|
231
|
+
function transformLongBlock(
|
|
232
|
+
samples,
|
|
233
|
+
bandIndex,
|
|
234
|
+
config,
|
|
235
|
+
transformFunc,
|
|
236
|
+
overlapBuffer,
|
|
237
|
+
bufferPool
|
|
238
|
+
) {
|
|
239
|
+
const mdctSize = bandIndex === 2 ? MDCT_SIZE_LONG : MDCT_SIZE_MID
|
|
240
|
+
const mdctInput = bufferPool.transformBuffers[mdctSize]
|
|
241
|
+
mdctInput.fill(0)
|
|
242
|
+
|
|
243
|
+
// Apply overlap from previous frame
|
|
244
|
+
mdctInput.set(overlapBuffer, config.windowStart)
|
|
245
|
+
|
|
246
|
+
// Window and save tail for next frame
|
|
247
|
+
applyTailWindowing(samples, overlapBuffer, config.size)
|
|
248
|
+
|
|
249
|
+
// Add current frame samples
|
|
250
|
+
mdctInput.set(samples, config.windowStart + MDCT_OVERLAP_SIZE)
|
|
251
|
+
|
|
252
|
+
// Transform
|
|
253
|
+
let spectrum = transformFunc.transform(mdctInput, bufferPool.mdctBuffers)
|
|
254
|
+
|
|
255
|
+
// Apply spectral reversal for mid/high bands
|
|
256
|
+
if (bandIndex > 0) {
|
|
257
|
+
spectrum = reverseSpectrum(spectrum, bufferPool.reversalBuffers)
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
return spectrum
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Transform using short blocks (better time resolution for transients)
|
|
265
|
+
*/
|
|
266
|
+
function transformShortBlocks(
|
|
267
|
+
samples,
|
|
268
|
+
bandIndex,
|
|
269
|
+
config,
|
|
270
|
+
overlapBuffer,
|
|
271
|
+
bufferPool
|
|
272
|
+
) {
|
|
273
|
+
const numBlocks = 1 << (config.size === 256 ? 3 : 2) // 8 for band 2, 4 for bands 0-1
|
|
274
|
+
const output = new Float32Array(config.size)
|
|
275
|
+
|
|
276
|
+
for (let block = 0; block < numBlocks; block++) {
|
|
277
|
+
const blockStart = block * MDCT_SHORT_BLOCK_SIZE
|
|
278
|
+
const blockSamples = samples.subarray(
|
|
279
|
+
blockStart,
|
|
280
|
+
blockStart + MDCT_SHORT_BLOCK_SIZE
|
|
281
|
+
)
|
|
282
|
+
|
|
283
|
+
// Prepare MDCT input
|
|
284
|
+
const mdctInput = bufferPool.transformBuffers[MDCT_SIZE_SHORT]
|
|
285
|
+
mdctInput.fill(0)
|
|
286
|
+
mdctInput.set(overlapBuffer, 0)
|
|
287
|
+
|
|
288
|
+
// Window and save tail
|
|
289
|
+
applyTailWindowing(blockSamples, overlapBuffer, MDCT_SHORT_BLOCK_SIZE)
|
|
290
|
+
mdctInput.set(blockSamples, MDCT_OVERLAP_SIZE)
|
|
291
|
+
|
|
292
|
+
// Transform
|
|
293
|
+
let spectrum = mdct64.transform(mdctInput, bufferPool.mdctBuffers)
|
|
294
|
+
|
|
295
|
+
// Apply spectral reversal for mid/high bands
|
|
296
|
+
if (bandIndex > 0) {
|
|
297
|
+
spectrum = reverseSpectrum(spectrum, bufferPool.reversalBuffers)
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
output.set(spectrum, blockStart)
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
return output
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
function applyTailWindowing(samples, overlapBuffer, blockSize) {
|
|
307
|
+
const tailStart = blockSize - MDCT_OVERLAP_SIZE
|
|
308
|
+
for (let i = 0; i < MDCT_OVERLAP_SIZE; i++) {
|
|
309
|
+
const tailValue = samples[tailStart + i]
|
|
310
|
+
overlapBuffer[i] = WINDOW_SHORT[i] * tailValue
|
|
311
|
+
samples[tailStart + i] = tailValue * WINDOW_SHORT[31 - i]
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
183
315
|
/**
|
|
184
316
|
* Transform frequency bands using MDCT
|
|
185
317
|
* @param {Object} input - Block selection results
|
|
@@ -194,60 +326,20 @@ export function mdctStage(context) {
|
|
|
194
326
|
*/
|
|
195
327
|
return (input) => {
|
|
196
328
|
const { bands, blockModes, originalFrame } = input
|
|
197
|
-
|
|
198
329
|
const coefficients = new Float32Array(512)
|
|
199
330
|
|
|
200
|
-
|
|
201
|
-
const
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
: MDCT_SIZE_MID
|
|
213
|
-
: MDCT_SIZE_SHORT
|
|
214
|
-
const windowStart = numBlocks === 1 ? (band === 2 ? 112 : 48) : 0
|
|
215
|
-
|
|
216
|
-
const offset = band === 0 ? 0 : band === 1 ? 128 : 256
|
|
217
|
-
|
|
218
|
-
for (let block = 0; block < numBlocks; block++) {
|
|
219
|
-
const blockStart = block * blockSize
|
|
220
|
-
const mdctInput = bufferPool.transformBuffers[mdctSize]
|
|
221
|
-
mdctInput.fill(0)
|
|
222
|
-
|
|
223
|
-
mdctInput.set(overlapBuffers[band], windowStart)
|
|
224
|
-
|
|
225
|
-
for (let i = 0; i < 32; i++) {
|
|
226
|
-
const tailValue = samples[blockStart + blockSize - 32 + i]
|
|
227
|
-
overlapBuffers[band][i] = WINDOW_SHORT[i] * tailValue
|
|
228
|
-
samples[blockStart + blockSize - 32 + i] =
|
|
229
|
-
tailValue * WINDOW_SHORT[31 - i]
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
mdctInput.set(
|
|
233
|
-
samples.subarray(blockStart, blockStart + blockSize),
|
|
234
|
-
windowStart + 32
|
|
235
|
-
)
|
|
236
|
-
|
|
237
|
-
let spectrum = mdctFunc.transform(mdctInput, bufferPool.mdctBuffers)
|
|
238
|
-
|
|
239
|
-
if (band > 0) {
|
|
240
|
-
const reversed = bufferPool.reversalBuffers[spectrum.length]
|
|
241
|
-
reversed.fill(0)
|
|
242
|
-
for (let i = 0; i < spectrum.length; i++) {
|
|
243
|
-
reversed[i] = spectrum[spectrum.length - 1 - i]
|
|
244
|
-
}
|
|
245
|
-
spectrum = reversed
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
coefficients.set(spectrum, offset + blockStart)
|
|
249
|
-
}
|
|
250
|
-
}
|
|
331
|
+
bands.forEach((bandSamples, bandIndex) => {
|
|
332
|
+
const transformed = transformBand(
|
|
333
|
+
bandSamples,
|
|
334
|
+
bandIndex,
|
|
335
|
+
blockModes[bandIndex],
|
|
336
|
+
overlapBuffers[bandIndex],
|
|
337
|
+
bufferPool
|
|
338
|
+
)
|
|
339
|
+
|
|
340
|
+
const offset = calculateBandOffset(bandIndex)
|
|
341
|
+
coefficients.set(transformed, offset)
|
|
342
|
+
})
|
|
251
343
|
|
|
252
344
|
return { bands, coefficients, blockModes, originalFrame }
|
|
253
345
|
}
|