carta1 1.1.0 → 1.1.2
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 +23 -72
- package/codec/coding/quantization.js +9 -11
- package/codec/core/buffers.js +33 -44
- package/codec/core/constants.js +13 -84
- package/codec/io/processor.js +18 -18
- package/codec/pipeline/decoder.js +15 -15
- package/codec/pipeline/encoder.js +19 -19
- package/codec/transforms/fft.js +4 -4
- package/codec/transforms/mdct.js +19 -19
- package/codec/transforms/qmf.js +8 -8
- package/codec/utils.js +12 -12
- 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
package/bin/cli.js
CHANGED
|
@@ -156,7 +156,7 @@ class ProgressTracker {
|
|
|
156
156
|
* Provides async iteration over WAV file frames for memory-efficient
|
|
157
157
|
* processing of large audio files. Automatically handles:
|
|
158
158
|
* - Multi-channel deinterleaving
|
|
159
|
-
* - Bit depth conversion to
|
|
159
|
+
* - Bit depth conversion to Float64
|
|
160
160
|
* - Frame padding for the last partial frame
|
|
161
161
|
*
|
|
162
162
|
* @class
|
|
@@ -225,9 +225,9 @@ class WavReader {
|
|
|
225
225
|
* Async iterator for streaming WAV file frames
|
|
226
226
|
*
|
|
227
227
|
* @param {number} [frameSize=SAMPLES_PER_FRAME] - Samples per frame
|
|
228
|
-
* @yields {
|
|
229
|
-
* - Mono:
|
|
230
|
-
* - Stereo: [left, right]
|
|
228
|
+
* @yields {Float64Array|Array<Float64Array>} Audio frame data
|
|
229
|
+
* - Mono: Float64Array of samples
|
|
230
|
+
* - Stereo: [left, right] Float64Arrays
|
|
231
231
|
*/
|
|
232
232
|
async *[Symbol.asyncIterator](frameSize = SAMPLES_PER_FRAME) {
|
|
233
233
|
const fileStream = fs.createReadStream(this.filePath)
|
|
@@ -305,23 +305,23 @@ class WavReader {
|
|
|
305
305
|
}
|
|
306
306
|
|
|
307
307
|
/**
|
|
308
|
-
* Process raw PCM buffer into
|
|
308
|
+
* Process raw PCM buffer into float64 frame data
|
|
309
309
|
*
|
|
310
310
|
* @private
|
|
311
311
|
* @param {Buffer} frameBuffer - Raw PCM data
|
|
312
312
|
* @param {number} frameSize - Number of samples per channel
|
|
313
|
-
* @returns {
|
|
313
|
+
* @returns {Float64Array|Array<Float64Array>} Processed frame data
|
|
314
314
|
*/
|
|
315
315
|
_processFrameBuffer(frameBuffer, frameSize) {
|
|
316
316
|
if (this.channels === 1) {
|
|
317
|
-
const frame = new
|
|
317
|
+
const frame = new Float64Array(frameSize)
|
|
318
318
|
for (let i = 0; i < frameSize; i++) {
|
|
319
319
|
frame[i] = this._sampleToFloat(frameBuffer, i * (this.bitDepth / 8))
|
|
320
320
|
}
|
|
321
321
|
return frame
|
|
322
322
|
} else {
|
|
323
|
-
const left = new
|
|
324
|
-
const right = new
|
|
323
|
+
const left = new Float64Array(frameSize)
|
|
324
|
+
const right = new Float64Array(frameSize)
|
|
325
325
|
for (let i = 0; i < frameSize; i++) {
|
|
326
326
|
const offset = i * this.channels * (this.bitDepth / 8)
|
|
327
327
|
left[i] = this._sampleToFloat(frameBuffer, offset)
|
|
@@ -332,7 +332,7 @@ class WavReader {
|
|
|
332
332
|
}
|
|
333
333
|
|
|
334
334
|
/**
|
|
335
|
-
* Convert PCM sample to normalized
|
|
335
|
+
* Convert PCM sample to normalized Float64 value
|
|
336
336
|
*
|
|
337
337
|
* @private
|
|
338
338
|
* @param {Buffer} buffer - PCM data buffer
|
|
@@ -10,13 +10,13 @@ import { FFT } from '../transforms/fft.js'
|
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Perform FFT on time-domain samples and return magnitude spectrum
|
|
13
|
-
* @param {
|
|
13
|
+
* @param {Float64Array} samples - Time-domain samples
|
|
14
14
|
* @param {number} fftSize - FFT size (must be power of 2)
|
|
15
|
-
* @returns {
|
|
15
|
+
* @returns {Float64Array} Magnitude spectrum (positive frequencies only)
|
|
16
16
|
*/
|
|
17
17
|
export function performFFT(samples, fftSize) {
|
|
18
|
-
const real = new
|
|
19
|
-
const imag = new
|
|
18
|
+
const real = new Float64Array(fftSize)
|
|
19
|
+
const imag = new Float64Array(fftSize)
|
|
20
20
|
|
|
21
21
|
// Copy samples with zero-padding if necessary
|
|
22
22
|
const copyLen = Math.min(samples.length, fftSize)
|
|
@@ -26,7 +26,7 @@ export function performFFT(samples, fftSize) {
|
|
|
26
26
|
FFT.fft(real, imag)
|
|
27
27
|
|
|
28
28
|
// Calculate magnitude spectrum for positive frequencies
|
|
29
|
-
const magnitude = new
|
|
29
|
+
const magnitude = new Float64Array(fftSize / 2)
|
|
30
30
|
for (let i = 0; i < fftSize / 2; i++) {
|
|
31
31
|
magnitude[i] = Math.sqrt(real[i] * real[i] + imag[i] * imag[i])
|
|
32
32
|
}
|
|
@@ -36,8 +36,8 @@ export function performFFT(samples, fftSize) {
|
|
|
36
36
|
|
|
37
37
|
/**
|
|
38
38
|
* Detect transients by analyzing spectral changes between frames
|
|
39
|
-
* @param {
|
|
40
|
-
* @param {
|
|
39
|
+
* @param {Float64Array} currentCoeffs - Current frame coefficients
|
|
40
|
+
* @param {Float64Array} prevCoeffs - Previous frame coefficients
|
|
41
41
|
* @param {number} threshold - Detection threshold
|
|
42
42
|
* @returns {boolean} True if transient detected
|
|
43
43
|
*/
|
|
@@ -56,8 +56,8 @@ export function detectTransient(currentCoeffs, prevCoeffs, threshold) {
|
|
|
56
56
|
|
|
57
57
|
/**
|
|
58
58
|
* Calculate all spectral features for transient detection
|
|
59
|
-
* @param {
|
|
60
|
-
* @param {
|
|
59
|
+
* @param {Float64Array} currentCoeffs - Current frame coefficients
|
|
60
|
+
* @param {Float64Array} prevCoeffs - Previous frame coefficients
|
|
61
61
|
* @returns {Object} Computed spectral features
|
|
62
62
|
*/
|
|
63
63
|
function calculateSpectralFeatures(currentCoeffs, prevCoeffs) {
|
|
@@ -114,7 +114,7 @@ function calculateSpectralFlux(currentCoeffs, prevCoeffs) {
|
|
|
114
114
|
/**
|
|
115
115
|
* Calculate spectral flatness (geometric mean / arithmetic mean)
|
|
116
116
|
* Measures how noise-like vs tonal the spectrum is
|
|
117
|
-
* @param {
|
|
117
|
+
* @param {Float64Array} coeffs - Spectral coefficients
|
|
118
118
|
* @returns {number} Flatness measure (0 = tonal, 1 = noise-like)
|
|
119
119
|
*/
|
|
120
120
|
function calculateSpectralFlatness(coeffs) {
|
|
@@ -143,7 +143,7 @@ function calculateSpectralFlatness(coeffs) {
|
|
|
143
143
|
/**
|
|
144
144
|
* Calculate ratio of high-frequency to total energy
|
|
145
145
|
* High values indicate bright/harsh sounds that are perceptually important
|
|
146
|
-
* @param {
|
|
146
|
+
* @param {Float64Array} coeffs - Spectral coefficients
|
|
147
147
|
* @returns {number} High-frequency energy ratio (0-1)
|
|
148
148
|
*/
|
|
149
149
|
function calculateHighFrequencyRatio(coeffs) {
|
|
@@ -165,8 +165,8 @@ function calculateHighFrequencyRatio(coeffs) {
|
|
|
165
165
|
|
|
166
166
|
/**
|
|
167
167
|
* Calculate energy change between frames in dB
|
|
168
|
-
* @param {
|
|
169
|
-
* @param {
|
|
168
|
+
* @param {Float64Array} currentCoeffs - Current frame coefficients
|
|
169
|
+
* @param {Float64Array} prevCoeffs - Previous frame coefficients
|
|
170
170
|
* @returns {number} Energy change in dB (positive values only)
|
|
171
171
|
*/
|
|
172
172
|
function calculateEnergyChange(currentCoeffs, prevCoeffs) {
|
|
@@ -64,9 +64,9 @@ class Carta1Worker {
|
|
|
64
64
|
/**
|
|
65
65
|
* Encode PCM audio to ATRAC1 format
|
|
66
66
|
*
|
|
67
|
-
* @param {
|
|
68
|
-
* - Mono:
|
|
69
|
-
* - Stereo: [left, right]
|
|
67
|
+
* @param {Float64Array|Array<Float64Array>} pcmData - PCM audio data
|
|
68
|
+
* - Mono: Float64Array
|
|
69
|
+
* - Stereo: [left, right] Float64Arrays
|
|
70
70
|
* @param {Object} [options={}] - Encoder options
|
|
71
71
|
* @param {number} [options.transientThresholdLow] - Low band transient threshold
|
|
72
72
|
* @param {number} [options.transientThresholdMid] - Mid band transient threshold
|
package/codec/browser/worker.js
CHANGED
|
@@ -56,7 +56,7 @@ self.onmessage = async (e) => {
|
|
|
56
56
|
/**
|
|
57
57
|
* Encode PCM audio data to ATRAC1 format
|
|
58
58
|
*
|
|
59
|
-
* @param {Array<
|
|
59
|
+
* @param {Array<Float64Array>} pcmData - PCM audio data [mono] or [left, right]
|
|
60
60
|
* @param {Object} options - Encoder options
|
|
61
61
|
* @returns {Promise<Object>} Encoded AEA blob
|
|
62
62
|
*/
|
|
@@ -29,16 +29,13 @@ import {
|
|
|
29
29
|
BITS_PER_BFU_METADATA,
|
|
30
30
|
MAX_WORD_LENGTH_INDEX,
|
|
31
31
|
WORD_LENGTH_BITS,
|
|
32
|
-
|
|
33
|
-
SF_POW_P,
|
|
34
|
-
POW2_POS_P,
|
|
35
|
-
POW2_NEG_P,
|
|
32
|
+
INV_POWER_OF_TWO,
|
|
36
33
|
SCALE_FACTORS,
|
|
37
34
|
} from '../core/constants.js'
|
|
38
35
|
|
|
39
36
|
/**
|
|
40
37
|
* Allocate bits to BFUs using optimized greedy Lp-RDO
|
|
41
|
-
* @param {Array<
|
|
38
|
+
* @param {Array<Float64Array>} bfuData
|
|
42
39
|
* @param {Int32Array} bfuSizes
|
|
43
40
|
* @param {number} maxBfuCount
|
|
44
41
|
* @returns {{bfuCount:number, allocation:Int32Array, scaleFactorIndices:Int32Array}}
|
|
@@ -64,21 +61,8 @@ export function allocateBits(bfuData, bfuSizes, maxBfuCount) {
|
|
|
64
61
|
* while staying within the bit budget. It uses a priority queue (max-heap) to greedily allocate
|
|
65
62
|
* bits to the BFUs that provide the greatest distortion reduction per bit spent.
|
|
66
63
|
*
|
|
67
|
-
* Mathematical Model:
|
|
68
|
-
* Distortion for b bits is modeled as:
|
|
69
|
-
* D(b) = C * 2^{-p * b} for b >= 1
|
|
70
|
-
* D(0) = C * 2^{ p } (finite large step for "mute" case)
|
|
71
|
-
* where C = N * (sf^p) * k, with N = BFU length, sf = scale factor, p and k constants.
|
|
72
|
-
*
|
|
73
|
-
* Hence, for an upgrade from b1 -> b2 (b2 > b1), ΔD = D(b1) - D(b2) can be computed with 2 table lookups.
|
|
74
|
-
*
|
|
75
|
-
* Precomputed tables:
|
|
76
|
-
* POW2_NEG_P[b] = 2^{-p*b} for b=0..maxBits
|
|
77
|
-
* POW2_POS_P = 2^{ p}
|
|
78
|
-
* SF_POW_P[sfIndex] = (SCALE_FACTORS[sfIndex])^p
|
|
79
|
-
*
|
|
80
64
|
* @param {number} activeBfuCount
|
|
81
|
-
* @param {Array<
|
|
65
|
+
* @param {Array<Float64Array>} bfuData
|
|
82
66
|
* @param {Int32Array} bfuSizes
|
|
83
67
|
* @param {number} remainingBits
|
|
84
68
|
* @returns {{wordLengths: Int32Array, scaleFactorIndices: Int32Array}}
|
|
@@ -87,38 +71,31 @@ function distributeBitsRDO(activeBfuCount, bfuData, bfuSizes, remainingBits) {
|
|
|
87
71
|
const scaleFactorTable = new Int32Array(NUM_BFUS)
|
|
88
72
|
const wordLengths = new Int32Array(activeBfuCount)
|
|
89
73
|
|
|
90
|
-
const baseWeight = new Float64Array(activeBfuCount) // C above
|
|
91
|
-
for (let bfuIndex = 0; bfuIndex < activeBfuCount; bfuIndex++) {
|
|
92
|
-
const sz = bfuSizes[bfuIndex] | 0
|
|
93
|
-
if (sz > 0) {
|
|
94
|
-
const sfi = findScaleFactor(bfuData[bfuIndex].subarray(0, sz))
|
|
95
|
-
scaleFactorTable[bfuIndex] = sfi
|
|
96
|
-
baseWeight[bfuIndex] = sz * SF_POW_P[sfi] * LP_DISTORTION_CONSTANT
|
|
97
|
-
} else {
|
|
98
|
-
scaleFactorTable[bfuIndex] = 0
|
|
99
|
-
baseWeight[bfuIndex] = 0
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
74
|
const heapIndices = []
|
|
104
75
|
const heapPriorities = []
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
76
|
+
|
|
77
|
+
const deltaDistPerCoeff = (bfuIndex, currentWl, nextWl) => {
|
|
78
|
+
const sfi = scaleFactorTable[bfuIndex]
|
|
79
|
+
const scaleFactor = SCALE_FACTORS[sfi]
|
|
80
|
+
if (scaleFactor === 0) return 0
|
|
108
81
|
|
|
109
82
|
const bits1 = WORD_LENGTH_BITS[currentWl] | 0
|
|
110
83
|
const bits2 = WORD_LENGTH_BITS[nextWl] | 0
|
|
111
84
|
|
|
112
|
-
const f1 = bits1 === 0 ?
|
|
113
|
-
const f2 =
|
|
85
|
+
const f1 = bits1 === 0 ? 2.0 : INV_POWER_OF_TWO[bits1]
|
|
86
|
+
const f2 = INV_POWER_OF_TWO[bits2]
|
|
114
87
|
|
|
115
|
-
return
|
|
88
|
+
return scaleFactor * (f1 - f2)
|
|
116
89
|
}
|
|
117
90
|
|
|
118
91
|
for (let bfuIndex = 0; bfuIndex < activeBfuCount; bfuIndex++) {
|
|
119
92
|
const sz = bfuSizes[bfuIndex] | 0
|
|
120
93
|
if (sz === 0) continue
|
|
121
|
-
|
|
94
|
+
|
|
95
|
+
const sfi = findScaleFactor(bfuData[bfuIndex].subarray(0, sz))
|
|
96
|
+
scaleFactorTable[bfuIndex] = sfi
|
|
97
|
+
|
|
98
|
+
if (sfi === 0) continue
|
|
122
99
|
|
|
123
100
|
const currentWl = 0
|
|
124
101
|
const nextWl = 1
|
|
@@ -126,11 +103,9 @@ function distributeBitsRDO(activeBfuCount, bfuData, bfuSizes, remainingBits) {
|
|
|
126
103
|
(WORD_LENGTH_BITS[nextWl] - WORD_LENGTH_BITS[currentWl]) | 0
|
|
127
104
|
if (deltaBits <= 0) continue
|
|
128
105
|
|
|
129
|
-
const
|
|
130
|
-
const dd = deltaDist(bfuIndex, currentWl, nextWl)
|
|
131
|
-
|
|
106
|
+
const ddPerCoeff = deltaDistPerCoeff(bfuIndex, currentWl, nextWl)
|
|
132
107
|
heapIndices.push(bfuIndex)
|
|
133
|
-
heapPriorities.push(
|
|
108
|
+
heapPriorities.push(ddPerCoeff / deltaBits)
|
|
134
109
|
}
|
|
135
110
|
|
|
136
111
|
// Heapify
|
|
@@ -159,7 +134,7 @@ function distributeBitsRDO(activeBfuCount, bfuData, bfuSizes, remainingBits) {
|
|
|
159
134
|
const nxt2 = nxt + 1
|
|
160
135
|
const deltaBits2 = (WORD_LENGTH_BITS[nxt2] - WORD_LENGTH_BITS[nxt]) | 0
|
|
161
136
|
if (deltaBits2 > 0) {
|
|
162
|
-
heapPriorities[0] =
|
|
137
|
+
heapPriorities[0] = deltaDistPerCoeff(bfu, nxt, nxt2) / deltaBits2
|
|
163
138
|
siftDown(heapIndices, heapPriorities, 0)
|
|
164
139
|
} else {
|
|
165
140
|
popRoot(heapIndices, heapPriorities)
|
|
@@ -175,42 +150,18 @@ function distributeBitsRDO(activeBfuCount, bfuData, bfuSizes, remainingBits) {
|
|
|
175
150
|
/**
|
|
176
151
|
* Find the optimal scale factor index for a set of coefficients.
|
|
177
152
|
* Same semantics as the original.
|
|
178
|
-
* @param {
|
|
153
|
+
* @param {Float64Array} coefficients
|
|
179
154
|
* @returns {number}
|
|
180
155
|
*/
|
|
181
156
|
export function findScaleFactor(coefficients) {
|
|
182
157
|
let maxAmplitude = 0.0
|
|
183
|
-
|
|
184
|
-
let i = 0
|
|
185
|
-
const n4 = n & ~3
|
|
186
|
-
for (; i < n4; i += 4) {
|
|
187
|
-
const a0 = Math.abs(coefficients[i])
|
|
188
|
-
const a1 = Math.abs(coefficients[i + 1])
|
|
189
|
-
const a2 = Math.abs(coefficients[i + 2])
|
|
190
|
-
const a3 = Math.abs(coefficients[i + 3])
|
|
191
|
-
if (a0 > maxAmplitude) maxAmplitude = a0
|
|
192
|
-
if (a1 > maxAmplitude) maxAmplitude = a1
|
|
193
|
-
if (a2 > maxAmplitude) maxAmplitude = a2
|
|
194
|
-
if (a3 > maxAmplitude) maxAmplitude = a3
|
|
195
|
-
}
|
|
196
|
-
for (; i < n; i++) {
|
|
158
|
+
for (let i = 0; i < coefficients.length; i++) {
|
|
197
159
|
const a = Math.abs(coefficients[i])
|
|
198
160
|
if (a > maxAmplitude) maxAmplitude = a
|
|
199
161
|
}
|
|
200
162
|
if (maxAmplitude === 0) return 0
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
let low = 0
|
|
204
|
-
let high = SCALE_FACTORS.length - 1
|
|
205
|
-
while (low < high) {
|
|
206
|
-
const mid = (low + high) >> 1
|
|
207
|
-
if (maxAmplitude <= SCALE_FACTORS[mid]) {
|
|
208
|
-
high = mid
|
|
209
|
-
} else {
|
|
210
|
-
low = mid + 1
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
return low
|
|
163
|
+
const index = Math.ceil(3 * (Math.log2(maxAmplitude) + 21))
|
|
164
|
+
return Math.max(0, Math.min(63, index))
|
|
214
165
|
}
|
|
215
166
|
|
|
216
167
|
/**
|
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
28
|
* Quantize coefficients.
|
|
29
|
-
* @param {
|
|
29
|
+
* @param {Float64Array} coefficients
|
|
30
30
|
* @param {number} scaleFactorIndex
|
|
31
31
|
* @param {number} bitsPerSample
|
|
32
32
|
* @returns {Int32Array} out
|
|
@@ -35,7 +35,6 @@ export function quantize(coefficients, scaleFactorIndex, bitsPerSample) {
|
|
|
35
35
|
const length = coefficients.length
|
|
36
36
|
const out = new Int32Array(length)
|
|
37
37
|
if (bitsPerSample === 0 || scaleFactorIndex === 0) {
|
|
38
|
-
// Zero fast path
|
|
39
38
|
out.fill(0, 0, length)
|
|
40
39
|
return out
|
|
41
40
|
}
|
|
@@ -45,7 +44,7 @@ export function quantize(coefficients, scaleFactorIndex, bitsPerSample) {
|
|
|
45
44
|
const normFactor = quantRange / scaleFactor
|
|
46
45
|
|
|
47
46
|
const hi = quantRange
|
|
48
|
-
const lo = -quantRange
|
|
47
|
+
const lo = -quantRange
|
|
49
48
|
|
|
50
49
|
for (let i = 0; i < length; i++) {
|
|
51
50
|
const x = coefficients[i] * normFactor
|
|
@@ -61,20 +60,19 @@ export function quantize(coefficients, scaleFactorIndex, bitsPerSample) {
|
|
|
61
60
|
* @param {Int32Array} quantized
|
|
62
61
|
* @param {number} scaleFactorIndex
|
|
63
62
|
* @param {number} bitsPerSample
|
|
64
|
-
* @returns {
|
|
63
|
+
* @returns {Float64Array}
|
|
65
64
|
*/
|
|
66
65
|
export function dequantize(quantized, scaleFactorIndex, bitsPerSample) {
|
|
67
66
|
if (bitsPerSample === 0 || scaleFactorIndex === 0) {
|
|
68
|
-
return new
|
|
67
|
+
return new Float64Array(quantized.length)
|
|
69
68
|
}
|
|
70
69
|
|
|
71
70
|
const scaleFactor = SCALE_FACTORS[scaleFactorIndex]
|
|
72
71
|
const quantRange = (1 << (bitsPerSample - QUANTIZATION_SIGN_BIT_SHIFT)) - 1
|
|
73
|
-
const denormFactor = scaleFactor / quantRange
|
|
74
72
|
|
|
75
|
-
const deq = new
|
|
73
|
+
const deq = new Float64Array(quantized.length)
|
|
76
74
|
for (let i = 0; i < quantized.length; i++) {
|
|
77
|
-
deq[i] = quantized[i] *
|
|
75
|
+
deq[i] = (quantized[i] * scaleFactor) / quantRange
|
|
78
76
|
}
|
|
79
77
|
return deq
|
|
80
78
|
}
|
|
@@ -101,9 +99,9 @@ export function dequantize(quantized, scaleFactorIndex, bitsPerSample) {
|
|
|
101
99
|
* - Long blocks (mode 0): Higher frequency resolution, fewer temporal segments
|
|
102
100
|
* - Short blocks (mode 1): Lower frequency resolution, more temporal segments
|
|
103
101
|
*
|
|
104
|
-
* @param {
|
|
102
|
+
* @param {Float64Array} coefficients
|
|
105
103
|
* @param {Array<number>} blockModes
|
|
106
|
-
* @returns {{bfuData: Array<
|
|
104
|
+
* @returns {{bfuData: Array<Float64Array>, bfuSizes: Array<number>, bfuCount: number}}
|
|
107
105
|
*/
|
|
108
106
|
export function groupIntoBFUs(coefficients, blockModes) {
|
|
109
107
|
const bfuData = []
|
|
@@ -123,7 +121,7 @@ export function groupIntoBFUs(coefficients, blockModes) {
|
|
|
123
121
|
const size = SPECS_PER_BFU[bfuIndex]
|
|
124
122
|
const startPos = startPositions[bfuIndex] - bandStart
|
|
125
123
|
const endPos = startPos + size
|
|
126
|
-
const bfu = new
|
|
124
|
+
const bfu = new Float64Array(size)
|
|
127
125
|
|
|
128
126
|
if (startPos >= 0 && endPos <= bandSize) {
|
|
129
127
|
bfu.set(coefficients.subarray(bandStart + startPos, bandStart + endPos))
|
package/codec/core/buffers.js
CHANGED
|
@@ -2,91 +2,80 @@
|
|
|
2
2
|
* Carta1 Audio Codec - Buffer Management
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
NUM_BFUS,
|
|
7
|
-
MAX_BFU_SIZE,
|
|
8
|
-
QMF_DELAY,
|
|
9
|
-
QMF_HIGH_BAND_DELAY,
|
|
10
|
-
} from './constants.js'
|
|
5
|
+
import { QMF_DELAY, QMF_HIGH_BAND_DELAY } from './constants.js'
|
|
11
6
|
|
|
12
7
|
export class BufferPool {
|
|
13
8
|
constructor() {
|
|
14
9
|
// Transform buffers
|
|
15
10
|
this.transformBuffers = {
|
|
16
|
-
64: new
|
|
17
|
-
128: new
|
|
18
|
-
256: new
|
|
19
|
-
512: new
|
|
11
|
+
64: new Float64Array(64),
|
|
12
|
+
128: new Float64Array(128),
|
|
13
|
+
256: new Float64Array(256),
|
|
14
|
+
512: new Float64Array(512),
|
|
20
15
|
}
|
|
21
16
|
|
|
22
17
|
// QMF work buffers
|
|
23
18
|
this.qmfWorkBuffers = {
|
|
24
19
|
delay: {
|
|
25
|
-
128: new
|
|
26
|
-
256: new
|
|
27
|
-
512: new
|
|
20
|
+
128: new Float64Array(QMF_DELAY + 128),
|
|
21
|
+
256: new Float64Array(QMF_DELAY + 256),
|
|
22
|
+
512: new Float64Array(QMF_DELAY + 512),
|
|
28
23
|
},
|
|
29
24
|
highBandDelay: {
|
|
30
|
-
128: new
|
|
31
|
-
256: new
|
|
25
|
+
128: new Float64Array(QMF_HIGH_BAND_DELAY + 128),
|
|
26
|
+
256: new Float64Array(QMF_HIGH_BAND_DELAY + 256),
|
|
32
27
|
},
|
|
33
28
|
}
|
|
34
29
|
|
|
35
30
|
// QMF delay lines
|
|
36
31
|
this.qmfDelays = {
|
|
37
|
-
lowBand: new
|
|
38
|
-
midBand: new
|
|
39
|
-
highBand: new
|
|
32
|
+
lowBand: new Float64Array(QMF_DELAY),
|
|
33
|
+
midBand: new Float64Array(QMF_DELAY),
|
|
34
|
+
highBand: new Float64Array(QMF_HIGH_BAND_DELAY),
|
|
40
35
|
}
|
|
41
36
|
|
|
42
37
|
// Transient detector
|
|
43
38
|
this.transientDetection = [
|
|
44
|
-
new
|
|
45
|
-
new
|
|
46
|
-
new
|
|
39
|
+
new Float64Array(64),
|
|
40
|
+
new Float64Array(64),
|
|
41
|
+
new Float64Array(128),
|
|
47
42
|
]
|
|
48
43
|
|
|
49
44
|
// MDCT/IMDCT work buffers
|
|
50
45
|
this.mdctBuffers = {
|
|
51
46
|
16: {
|
|
52
|
-
real: new
|
|
53
|
-
imag: new
|
|
47
|
+
real: new Float64Array(16),
|
|
48
|
+
imag: new Float64Array(16),
|
|
54
49
|
},
|
|
55
50
|
64: {
|
|
56
|
-
real: new
|
|
57
|
-
imag: new
|
|
51
|
+
real: new Float64Array(64),
|
|
52
|
+
imag: new Float64Array(64),
|
|
58
53
|
},
|
|
59
54
|
128: {
|
|
60
|
-
real: new
|
|
61
|
-
imag: new
|
|
55
|
+
real: new Float64Array(128),
|
|
56
|
+
imag: new Float64Array(128),
|
|
62
57
|
},
|
|
63
58
|
}
|
|
64
59
|
|
|
65
|
-
// MDCT overlap buffers
|
|
60
|
+
// MDCT overlap buffers
|
|
66
61
|
this.mdctOverlap = [
|
|
67
|
-
new
|
|
68
|
-
new
|
|
69
|
-
new
|
|
62
|
+
new Float64Array(32),
|
|
63
|
+
new Float64Array(32),
|
|
64
|
+
new Float64Array(32),
|
|
70
65
|
]
|
|
71
66
|
|
|
72
|
-
// IMDCT overlap buffers
|
|
67
|
+
// IMDCT overlap buffers
|
|
73
68
|
this.imdctOverlap = [
|
|
74
|
-
new
|
|
75
|
-
new
|
|
76
|
-
new
|
|
69
|
+
new Float64Array(256),
|
|
70
|
+
new Float64Array(256),
|
|
71
|
+
new Float64Array(512),
|
|
77
72
|
]
|
|
78
73
|
|
|
79
74
|
// Spectrum reversal buffers
|
|
80
75
|
this.reversalBuffers = {
|
|
81
|
-
32: new
|
|
82
|
-
128: new
|
|
83
|
-
256: new
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// Bit allocation buffers
|
|
87
|
-
this.bfuData = new Array(NUM_BFUS)
|
|
88
|
-
for (let i = 0; i < NUM_BFUS; i++) {
|
|
89
|
-
this.bfuData[i] = new Float32Array(MAX_BFU_SIZE)
|
|
76
|
+
32: new Float64Array(32),
|
|
77
|
+
128: new Float64Array(128),
|
|
78
|
+
256: new Float64Array(256),
|
|
90
79
|
}
|
|
91
80
|
}
|
|
92
81
|
}
|