carta1 1.0.13 → 1.0.14
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/analysis/psychoacoustics.js +119 -147
- package/codec/coding/bitallocation.js +110 -177
- package/codec/core/constants.js +48 -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
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
NUM_BFUS,
|
|
18
18
|
SAMPLE_RATE,
|
|
19
19
|
BFU_FREQUENCIES,
|
|
20
|
+
BFU_AMOUNTS_COUNT,
|
|
20
21
|
PSYMODEL_MIN_POWER_DB,
|
|
21
22
|
PSYMODEL_CB_FREQ_INDICES,
|
|
22
23
|
INTERPOLATION_COMPENSATION_FACTOR,
|
|
@@ -93,7 +94,7 @@ function calculateBfuEnergy(bfuData, bfuSizes, bfuCount) {
|
|
|
93
94
|
energy += data[j] * data[j]
|
|
94
95
|
}
|
|
95
96
|
|
|
96
|
-
// Convert to dB
|
|
97
|
+
// Convert to dB correctly using log10
|
|
97
98
|
energyPerBfu[i] =
|
|
98
99
|
energy > 0 ? 10 * Math.log10(energy / size) : PSYMODEL_MIN_POWER_DB
|
|
99
100
|
}
|
|
@@ -108,36 +109,32 @@ function calculateBfuEnergy(bfuData, bfuSizes, bfuCount) {
|
|
|
108
109
|
*/
|
|
109
110
|
function interpolateCriticalBandsToBfus(criticalBandThresholds) {
|
|
110
111
|
const maskThresholdPerBfu = new Float32Array(NUM_BFUS)
|
|
111
|
-
maskThresholdPerBfu.fill(PSYMODEL_MIN_POWER_DB)
|
|
112
|
-
|
|
113
112
|
const freqPerBin = SAMPLE_RATE / PSYMODEL_FFT_SIZE
|
|
114
113
|
|
|
115
|
-
// Get frequency indices for critical bands (from constants)
|
|
116
|
-
const freqIndices = PSYMODEL_CB_FREQ_INDICES
|
|
117
|
-
|
|
118
114
|
for (let i = 0; i < NUM_BFUS; i++) {
|
|
119
115
|
const bfuFreq = BFU_FREQUENCIES[i]
|
|
120
|
-
// Convert BFU frequency to FFT bin index (rounded like current implementation)
|
|
121
116
|
const fftBinIndex = Math.round(bfuFreq / freqPerBin)
|
|
122
117
|
|
|
123
118
|
// Find which critical bands surround this FFT bin
|
|
124
119
|
let bandIndex = 0
|
|
125
120
|
while (
|
|
126
|
-
bandIndex <
|
|
127
|
-
|
|
121
|
+
bandIndex < PSYMODEL_CB_FREQ_INDICES.length - 1 &&
|
|
122
|
+
PSYMODEL_CB_FREQ_INDICES[bandIndex + 1] < fftBinIndex
|
|
128
123
|
) {
|
|
129
124
|
bandIndex++
|
|
130
125
|
}
|
|
131
126
|
|
|
132
|
-
|
|
133
|
-
if (fftBinIndex <= freqIndices[0]) {
|
|
127
|
+
if (fftBinIndex <= PSYMODEL_CB_FREQ_INDICES[0]) {
|
|
134
128
|
maskThresholdPerBfu[i] = criticalBandThresholds[0]
|
|
135
|
-
} else if (
|
|
129
|
+
} else if (
|
|
130
|
+
fftBinIndex >=
|
|
131
|
+
PSYMODEL_CB_FREQ_INDICES[PSYMODEL_CB_FREQ_INDICES.length - 1]
|
|
132
|
+
) {
|
|
136
133
|
maskThresholdPerBfu[i] =
|
|
137
134
|
criticalBandThresholds[criticalBandThresholds.length - 1]
|
|
138
135
|
} else {
|
|
139
|
-
const x0 =
|
|
140
|
-
const x1 =
|
|
136
|
+
const x0 = PSYMODEL_CB_FREQ_INDICES[bandIndex]
|
|
137
|
+
const x1 = PSYMODEL_CB_FREQ_INDICES[bandIndex + 1]
|
|
141
138
|
const y0 = criticalBandThresholds[bandIndex]
|
|
142
139
|
const y1 = criticalBandThresholds[bandIndex + 1]
|
|
143
140
|
const bandWidth = x1 - x0
|
|
@@ -168,7 +165,6 @@ function calculateSMR(signalEnergyDb, maskThresholdDb, maxBfuCount) {
|
|
|
168
165
|
const smrValues = new Float32Array(maxBfuCount)
|
|
169
166
|
|
|
170
167
|
for (let bfu = 0; bfu < maxBfuCount; bfu++) {
|
|
171
|
-
// BFUs with no signal have undefined SMR
|
|
172
168
|
smrValues[bfu] =
|
|
173
169
|
signalEnergyDb[bfu] <= PSYMODEL_MIN_POWER_DB
|
|
174
170
|
? -Infinity
|
|
@@ -190,111 +186,86 @@ function selectOptimalBfuCount(smrValues, signalEnergyDb, maxBfuCount) {
|
|
|
190
186
|
const hasAudibleContent = smrValues.some((smr) => smr > 0)
|
|
191
187
|
|
|
192
188
|
if (hasAudibleContent) {
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
smrValues
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
)
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
/**
|
|
204
|
-
* Select BFU count when content is above masking threshold
|
|
205
|
-
* Uses diminishing returns approach - find where adding more BFUs
|
|
206
|
-
* provides minimal benefit
|
|
207
|
-
*/
|
|
208
|
-
function selectBfuCountForAudibleContent(smrValues, maxBfuCount) {
|
|
209
|
-
// Create sorted list of BFUs by their contribution (positive SMR only)
|
|
210
|
-
const contributions = []
|
|
211
|
-
for (let i = 0; i < maxBfuCount; i++) {
|
|
212
|
-
if (smrValues[i] > 0) {
|
|
213
|
-
contributions.push({ index: i, smr: smrValues[i] })
|
|
189
|
+
// Create sorted list of BFUs by their contribution (positive SMR only)
|
|
190
|
+
const contributions = []
|
|
191
|
+
for (let i = 0; i < maxBfuCount; i++) {
|
|
192
|
+
if (smrValues[i] > 0) {
|
|
193
|
+
contributions.push({ index: i, smr: smrValues[i] })
|
|
194
|
+
}
|
|
214
195
|
}
|
|
215
|
-
|
|
216
|
-
contributions.sort((a, b) => b.smr - a.smr)
|
|
217
|
-
|
|
218
|
-
if (contributions.length === 0) {
|
|
219
|
-
return BFU_AMOUNTS[BFU_AMOUNTS.length - 1]
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
// Find the natural cutoff using gradient of cumulative SMR
|
|
223
|
-
const cumulativeSMR = []
|
|
224
|
-
let sum = 0
|
|
225
|
-
for (let i = 0; i < contributions.length; i++) {
|
|
226
|
-
sum += contributions[i].smr
|
|
227
|
-
cumulativeSMR.push(sum)
|
|
228
|
-
}
|
|
196
|
+
contributions.sort((a, b) => b.smr - a.smr)
|
|
229
197
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
198
|
+
if (contributions.length === 0) {
|
|
199
|
+
return BFU_AMOUNTS[BFU_AMOUNTS.length - 1]
|
|
200
|
+
}
|
|
233
201
|
|
|
234
|
-
//
|
|
235
|
-
const
|
|
236
|
-
|
|
237
|
-
|
|
202
|
+
// Find the natural cutoff using gradient of cumulative SMR
|
|
203
|
+
const cumulativeSMR = []
|
|
204
|
+
let sum = 0
|
|
205
|
+
for (let i = 0; i < contributions.length; i++) {
|
|
206
|
+
sum += contributions[i].smr
|
|
207
|
+
cumulativeSMR.push(sum)
|
|
208
|
+
}
|
|
238
209
|
|
|
239
|
-
|
|
210
|
+
// Find where the gradient becomes shallow (diminishing returns)
|
|
211
|
+
for (const candidateCount of BFU_AMOUNTS) {
|
|
212
|
+
if (candidateCount > maxBfuCount) continue
|
|
240
213
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
contributions.length - 1
|
|
246
|
-
)
|
|
247
|
-
if (capturedIndex >= contributions.length - 1) {
|
|
248
|
-
return candidateCount
|
|
249
|
-
}
|
|
214
|
+
// Check if all significant contributions fit within this count
|
|
215
|
+
const requiredBfus = contributions
|
|
216
|
+
.slice(0, Math.min(contributions.length, candidateCount))
|
|
217
|
+
.map((c) => c.index)
|
|
250
218
|
|
|
251
|
-
|
|
252
|
-
const currentValue = cumulativeSMR[capturedIndex]
|
|
253
|
-
const totalValue = cumulativeSMR[cumulativeSMR.length - 1]
|
|
254
|
-
const remainingIndices = contributions.length - capturedIndex - 1
|
|
219
|
+
const maxRequiredIndex = Math.max(...requiredBfus, 0)
|
|
255
220
|
|
|
256
|
-
if (
|
|
257
|
-
|
|
258
|
-
const
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
221
|
+
if (maxRequiredIndex < candidateCount) {
|
|
222
|
+
// Check if we've captured the bulk of the contribution
|
|
223
|
+
const capturedIndex = Math.min(
|
|
224
|
+
candidateCount - 1,
|
|
225
|
+
contributions.length - 1
|
|
226
|
+
)
|
|
227
|
+
if (capturedIndex >= contributions.length - 1) {
|
|
262
228
|
return candidateCount
|
|
263
229
|
}
|
|
230
|
+
|
|
231
|
+
// Use gradient to detect diminishing returns
|
|
232
|
+
const remainingIndices = contributions.length - capturedIndex - 1
|
|
233
|
+
if (remainingIndices > 0) {
|
|
234
|
+
const avgRemaining =
|
|
235
|
+
(cumulativeSMR[cumulativeSMR.length - 1] -
|
|
236
|
+
cumulativeSMR[capturedIndex]) /
|
|
237
|
+
remainingIndices
|
|
238
|
+
const avgCaptured = cumulativeSMR[capturedIndex] / (capturedIndex + 1)
|
|
239
|
+
|
|
240
|
+
// If remaining BFUs contribute much less on average, we've found our cutoff
|
|
241
|
+
if (avgRemaining < avgCaptured * 0.1) {
|
|
242
|
+
return candidateCount
|
|
243
|
+
}
|
|
244
|
+
}
|
|
264
245
|
}
|
|
265
246
|
}
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
signalEnergyDb,
|
|
278
|
-
maxBfuCount
|
|
279
|
-
) {
|
|
280
|
-
// Find the highest BFU index that contains actual signal
|
|
281
|
-
let highestSignalBfu = -1
|
|
282
|
-
|
|
283
|
-
for (let i = maxBfuCount - 1; i >= 0; i--) {
|
|
284
|
-
if (signalEnergyDb[i] > PSYMODEL_MIN_POWER_DB && smrValues[i] > -Infinity) {
|
|
285
|
-
highestSignalBfu = i
|
|
286
|
-
break
|
|
247
|
+
} else {
|
|
248
|
+
// Find the highest BFU index that contains actual signal
|
|
249
|
+
let highestSignalBfu = -1
|
|
250
|
+
for (let i = maxBfuCount - 1; i >= 0; i--) {
|
|
251
|
+
if (
|
|
252
|
+
signalEnergyDb[i] > PSYMODEL_MIN_POWER_DB &&
|
|
253
|
+
smrValues[i] > -Infinity
|
|
254
|
+
) {
|
|
255
|
+
highestSignalBfu = i
|
|
256
|
+
break
|
|
257
|
+
}
|
|
287
258
|
}
|
|
288
|
-
}
|
|
289
259
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
260
|
+
// Find smallest BFU count that includes all signal
|
|
261
|
+
for (const candidateCount of BFU_AMOUNTS) {
|
|
262
|
+
if (candidateCount > highestSignalBfu) {
|
|
263
|
+
return candidateCount
|
|
264
|
+
}
|
|
294
265
|
}
|
|
295
266
|
}
|
|
296
267
|
|
|
297
|
-
return BFU_AMOUNTS[
|
|
268
|
+
return BFU_AMOUNTS[BFU_AMOUNTS_COUNT - 1]
|
|
298
269
|
}
|
|
299
270
|
|
|
300
271
|
/**
|
|
@@ -311,36 +282,44 @@ function performBitAllocation(
|
|
|
311
282
|
bfuSizes,
|
|
312
283
|
availableBits
|
|
313
284
|
) {
|
|
314
|
-
const allocation = new Int32Array(actualBfuCount)
|
|
285
|
+
const allocation = new Int32Array(actualBfuCount)
|
|
286
|
+
const heap = []
|
|
315
287
|
|
|
316
|
-
// Initialize
|
|
317
|
-
|
|
288
|
+
// Initialize heap with BFUs that have signal
|
|
289
|
+
for (let i = 0; i < actualBfuCount; i++) {
|
|
290
|
+
if (smrValues[i] > -Infinity) {
|
|
291
|
+
heap.push({ bfu: i, priority: smrValues[i] })
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// Build max heap
|
|
296
|
+
for (let i = Math.floor(heap.length / 2) - 1; i >= 0; i--) {
|
|
297
|
+
heapifyDown(heap, i)
|
|
298
|
+
}
|
|
318
299
|
|
|
319
|
-
// Greedy allocation
|
|
320
|
-
while (
|
|
321
|
-
const bestBfu =
|
|
300
|
+
// Greedy allocation
|
|
301
|
+
while (heap.length > 0 && availableBits > 0) {
|
|
302
|
+
const bestBfu = heap[0]
|
|
322
303
|
const currentWl = allocation[bestBfu.bfu]
|
|
323
304
|
|
|
324
|
-
// Check if BFU is already at maximum word length
|
|
325
305
|
if (currentWl >= MAX_WORD_LENGTH_INDEX) {
|
|
326
|
-
|
|
306
|
+
heap[0] = heap[heap.length - 1]
|
|
307
|
+
heap.pop()
|
|
308
|
+
if (heap.length > 0) heapifyDown(heap, 0)
|
|
327
309
|
continue
|
|
328
310
|
}
|
|
329
311
|
|
|
330
|
-
// Calculate cost to upgrade this BFU
|
|
331
312
|
const upgradeCost = calculateUpgradeCost(bestBfu.bfu, currentWl, bfuSizes)
|
|
332
313
|
|
|
333
314
|
if (upgradeCost <= availableBits) {
|
|
334
|
-
// Perform upgrade
|
|
335
315
|
availableBits -= upgradeCost
|
|
336
316
|
allocation[bestBfu.bfu]++
|
|
337
|
-
|
|
338
|
-
// Update priority based on distortion reduction
|
|
339
317
|
bestBfu.priority += DISTORTION_DELTA_DB[currentWl]
|
|
340
|
-
|
|
318
|
+
heapifyDown(heap, 0)
|
|
341
319
|
} else {
|
|
342
|
-
|
|
343
|
-
|
|
320
|
+
heap[0] = heap[heap.length - 1]
|
|
321
|
+
heap.pop()
|
|
322
|
+
if (heap.length > 0) heapifyDown(heap, 0)
|
|
344
323
|
}
|
|
345
324
|
}
|
|
346
325
|
|
|
@@ -349,6 +328,10 @@ function performBitAllocation(
|
|
|
349
328
|
|
|
350
329
|
/**
|
|
351
330
|
* Calculate bit cost to upgrade a BFU's word length
|
|
331
|
+
* @param {number} bfuIndex - Index of the BFU to upgrade
|
|
332
|
+
* @param {number} currentWl - Current word length of the BFU
|
|
333
|
+
* @param {number[]} bfuSizes - Array of BFU sizes (number of coefficients per BFU)
|
|
334
|
+
* @returns {number} Additional bits required to upgrade word length by 1
|
|
352
335
|
*/
|
|
353
336
|
function calculateUpgradeCost(bfuIndex, currentWl, bfuSizes) {
|
|
354
337
|
const currentBits = WORD_LENGTH_BITS[currentWl] * bfuSizes[bfuIndex]
|
|
@@ -356,52 +339,21 @@ function calculateUpgradeCost(bfuIndex, currentWl, bfuSizes) {
|
|
|
356
339
|
return nextBits - currentBits
|
|
357
340
|
}
|
|
358
341
|
|
|
359
|
-
/**
|
|
360
|
-
* Create a priority queue for BFU allocation
|
|
361
|
-
* @param {Float32Array} smrValues - Initial priorities (SMR values)
|
|
362
|
-
* @param {number} bfuCount - Number of BFUs
|
|
363
|
-
* @returns {Object} Priority queue interface
|
|
364
|
-
*/
|
|
365
|
-
function createPriorityQueue(smrValues, bfuCount) {
|
|
366
|
-
const heap = []
|
|
367
|
-
|
|
368
|
-
// Initialize with BFUs that have signal
|
|
369
|
-
for (let i = 0; i < bfuCount; i++) {
|
|
370
|
-
if (smrValues[i] > -Infinity) {
|
|
371
|
-
heap.push({ bfu: i, priority: smrValues[i] })
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
// Build max heap
|
|
376
|
-
for (let i = Math.floor(heap.length / 2) - 1; i >= 0; i--) {
|
|
377
|
-
heapifyDown(heap, i)
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
return {
|
|
381
|
-
isEmpty: () => heap.length === 0,
|
|
382
|
-
peek: () => heap[0],
|
|
383
|
-
pop: () => popMax(heap),
|
|
384
|
-
updateTop: () => heapifyDown(heap, 0),
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
|
|
388
342
|
/**
|
|
389
343
|
* Maintain max heap property by moving element down
|
|
390
344
|
* @param {Array} heap - Heap array
|
|
391
345
|
* @param {number} startIdx - Starting index
|
|
392
346
|
*/
|
|
393
347
|
function heapifyDown(heap, startIdx) {
|
|
394
|
-
let idx = startIdx
|
|
395
|
-
const element = heap[idx]
|
|
396
348
|
const length = heap.length
|
|
349
|
+
const element = heap[startIdx]
|
|
397
350
|
|
|
398
351
|
while (true) {
|
|
399
|
-
const leftChild = 2 *
|
|
400
|
-
const rightChild = 2 *
|
|
401
|
-
let largest =
|
|
352
|
+
const leftChild = 2 * startIdx + 1
|
|
353
|
+
const rightChild = 2 * startIdx + 2
|
|
354
|
+
let largest = startIdx
|
|
402
355
|
let largestPriority = element.priority
|
|
403
356
|
|
|
404
|
-
// Find largest among parent and children
|
|
405
357
|
if (leftChild < length && heap[leftChild].priority > largestPriority) {
|
|
406
358
|
largest = leftChild
|
|
407
359
|
largestPriority = heap[leftChild].priority
|
|
@@ -411,30 +363,11 @@ function heapifyDown(heap, startIdx) {
|
|
|
411
363
|
largest = rightChild
|
|
412
364
|
}
|
|
413
365
|
|
|
414
|
-
|
|
415
|
-
if (largest === idx) break
|
|
416
|
-
|
|
417
|
-
// Swap and continue
|
|
418
|
-
heap[idx] = heap[largest]
|
|
419
|
-
idx = largest
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
heap[idx] = element
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
/**
|
|
426
|
-
* Remove and return the maximum element from heap
|
|
427
|
-
* @param {Array} heap - Heap array
|
|
428
|
-
* @returns {Object} Maximum element
|
|
429
|
-
*/
|
|
430
|
-
function popMax(heap) {
|
|
431
|
-
const max = heap[0]
|
|
432
|
-
const last = heap.pop()
|
|
366
|
+
if (largest === startIdx) break
|
|
433
367
|
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
heapifyDown(heap, 0)
|
|
368
|
+
heap[startIdx] = heap[largest]
|
|
369
|
+
startIdx = largest
|
|
437
370
|
}
|
|
438
371
|
|
|
439
|
-
|
|
372
|
+
heap[startIdx] = element
|
|
440
373
|
}
|
package/codec/core/constants.js
CHANGED
|
@@ -33,6 +33,7 @@ export const SPECS_PER_BFU = new Int32Array([
|
|
|
33
33
|
20, 20, 20, 20, 20,
|
|
34
34
|
])
|
|
35
35
|
|
|
36
|
+
export const BFU_AMOUNTS_COUNT = 8
|
|
36
37
|
export const BFU_AMOUNTS = new Int32Array([20, 28, 32, 36, 40, 44, 48, 52])
|
|
37
38
|
export const BFU_BAND_BOUNDARIES = new Int32Array([20, 36, 52])
|
|
38
39
|
|
|
@@ -191,6 +192,53 @@ export const SPREADING_MATRIX = (() => {
|
|
|
191
192
|
export const PSYMODEL_MIN_POWER_DB = -200
|
|
192
193
|
export const PSYMODEL_FFT_SIZE = 2048
|
|
193
194
|
|
|
195
|
+
// Pre-computes lookup tables for resampling the MDCT power spectrum into a PSD.
|
|
196
|
+
// For each PSD bin, these tables provide the two source MDCT indices and the
|
|
197
|
+
// linear interpolation weight needed to calculate the final power value.
|
|
198
|
+
export const [
|
|
199
|
+
PSYMODEL_PSD_SOURCE_IDX0,
|
|
200
|
+
PSYMODEL_PSD_SOURCE_IDX1,
|
|
201
|
+
PSYMODEL_PSD_INTERP_WEIGHT,
|
|
202
|
+
] = (() => {
|
|
203
|
+
const half = PSYMODEL_FFT_SIZE >>> 1
|
|
204
|
+
const sizeMinus1 = PSYMODEL_FFT_SIZE - 1
|
|
205
|
+
const halfDiv2 = half / 2
|
|
206
|
+
const scale = sizeMinus1 / half
|
|
207
|
+
|
|
208
|
+
const idx0 = new Uint16Array(half + 1)
|
|
209
|
+
const idx1 = new Uint16Array(half + 1)
|
|
210
|
+
const w1 = new Float32Array(half + 1)
|
|
211
|
+
|
|
212
|
+
for (let i = 0; i <= half; i++) {
|
|
213
|
+
const src = i * scale
|
|
214
|
+
const base = src | 0
|
|
215
|
+
|
|
216
|
+
const j0 = base
|
|
217
|
+
idx0[i] =
|
|
218
|
+
j0 < half
|
|
219
|
+
? j0 < halfDiv2
|
|
220
|
+
? j0
|
|
221
|
+
: half - 1 - (j0 - halfDiv2)
|
|
222
|
+
: sizeMinus1 - (j0 - half)
|
|
223
|
+
|
|
224
|
+
const j1 = base + 1
|
|
225
|
+
if (j1 >= PSYMODEL_FFT_SIZE) {
|
|
226
|
+
idx1[i] = idx0[i]
|
|
227
|
+
} else {
|
|
228
|
+
idx1[i] =
|
|
229
|
+
j1 < half
|
|
230
|
+
? j1 < halfDiv2
|
|
231
|
+
? j1
|
|
232
|
+
: half - 1 - (j1 - halfDiv2)
|
|
233
|
+
: sizeMinus1 - (j1 - half)
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
w1[i] = src - base
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
return [idx0, idx1, w1]
|
|
240
|
+
})()
|
|
241
|
+
|
|
194
242
|
// FFT sizes for transient detection
|
|
195
243
|
export const FFT_SIZE_LOW = 256
|
|
196
244
|
export const FFT_SIZE_MID = 256
|