carta1 1.0.18 → 1.0.20

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.
@@ -40,11 +40,11 @@ export class BufferPool {
40
40
  }
41
41
 
42
42
  // Transient detector
43
- this.transientDetection = {
44
- prevLowCoeffs: new Float32Array(64),
45
- prevMidCoeffs: new Float32Array(64),
46
- prevHighCoeffs: new Float32Array(128),
47
- }
43
+ this.transientDetection = [
44
+ new Float32Array(64),
45
+ new Float32Array(64),
46
+ new Float32Array(128),
47
+ ]
48
48
 
49
49
  // MDCT/IMDCT work buffers
50
50
  this.mdctBuffers = {
@@ -130,39 +130,21 @@ export function blockSelectorStage(context) {
130
130
  */
131
131
  return (input) => {
132
132
  const { bands } = input
133
- const [lowBand, midBand, highBand] = bands
134
-
135
- const lowCoeffs = performFFT(lowBand, FFT_SIZE_LOW)
136
- const midCoeffs = performFFT(midBand, FFT_SIZE_MID)
137
- const highCoeffs = performFFT(highBand, FFT_SIZE_HIGH)
138
-
139
- const lowTransient = detectTransient(
140
- lowCoeffs,
141
- bufferPool.transientDetection.prevLowCoeffs,
142
- options.transientThresholdLow
143
- )
144
- const midTransient = detectTransient(
145
- midCoeffs,
146
- bufferPool.transientDetection.prevMidCoeffs,
147
- options.transientThresholdMid
148
- )
149
- const highTransient = detectTransient(
150
- highCoeffs,
151
- bufferPool.transientDetection.prevHighCoeffs,
152
- options.transientThresholdHigh
153
- )
154
-
155
- bufferPool.transientDetection.prevLowCoeffs = lowCoeffs
156
- bufferPool.transientDetection.prevMidCoeffs = midCoeffs
157
- bufferPool.transientDetection.prevHighCoeffs = highCoeffs
133
+ const fftSizes = [FFT_SIZE_LOW, FFT_SIZE_MID, FFT_SIZE_HIGH]
134
+ const blockModes = bands.map((bandSamples, bandIndex) => {
135
+ const coeffs = performFFT(bandSamples, fftSizes[bandIndex])
136
+ const transient = detectTransient(
137
+ coeffs,
138
+ bufferPool.transientDetection[bandIndex],
139
+ options.transientThresholdLow
140
+ )
141
+ bufferPool.transientDetection[bandIndex] = coeffs
142
+ return transient * Math.max(bandIndex + 1, 2)
143
+ })
158
144
 
159
145
  return {
160
146
  bands,
161
- blockModes: [
162
- lowTransient ? 2 : 0,
163
- midTransient ? 2 : 0,
164
- highTransient ? 3 : 0,
165
- ],
147
+ blockModes,
166
148
  }
167
149
  }
168
150
  }
@@ -12,12 +12,8 @@ export class FFT {
12
12
  */
13
13
  static fft(real, imag) {
14
14
  const n = real.length
15
- if (n !== imag.length) {
16
- throw new Error('Real and imaginary arrays must have the same length.')
17
- }
18
- if ((n & (n - 1)) !== 0) {
19
- throw new Error('Input size must be a power of 2.')
20
- }
15
+ if (n !== imag.length) throw new Error('Mismatched array lengths.')
16
+ if ((n & (n - 1)) !== 0) throw new Error('Length must be power of 2.')
21
17
  if (n <= 1) return
22
18
 
23
19
  let cache = FFT._cache.get(n)
@@ -26,168 +22,91 @@ export class FFT {
26
22
  FFT._cache.set(n, cache)
27
23
  }
28
24
 
29
- const { bitRev, cos: cosTbl, sin: sinTbl } = cache
25
+ const bitRev = cache.bitRev
26
+ const cosTbl = cache.cos
27
+ const sinTbl = cache.sin
30
28
 
31
- // Bit-reversal permutation with improved memory access pattern
29
+ // Bit reversal
32
30
  for (let i = 0; i < n; i++) {
33
31
  const j = bitRev[i]
34
32
  if (j > i) {
35
- // Use temporary variables to reduce array access
36
- const tempR = real[i]
37
- const tempI = imag[i]
33
+ let tr = real[i]
34
+ let ti = imag[i]
38
35
  real[i] = real[j]
39
36
  imag[i] = imag[j]
40
- real[j] = tempR
41
- imag[j] = tempI
37
+ real[j] = tr
38
+ imag[j] = ti
42
39
  }
43
40
  }
44
41
 
45
- // Optimized butterfly computations for small strides
46
- // Stride 2 - no twiddle factors needed
42
+ // First stage: stride=2
47
43
  for (let i = 0; i < n; i += 2) {
48
- const evenR = real[i]
49
- const evenI = imag[i]
50
- const oddR = real[i + 1]
51
- const oddI = imag[i + 1]
52
-
53
- real[i] = evenR + oddR
54
- imag[i] = evenI + oddI
55
- real[i + 1] = evenR - oddR
56
- imag[i + 1] = evenI - oddI
44
+ let r0 = real[i],
45
+ i0 = imag[i]
46
+ let r1 = real[i + 1],
47
+ i1 = imag[i + 1]
48
+ real[i] = r0 + r1
49
+ imag[i] = i0 + i1
50
+ real[i + 1] = r0 - r1
51
+ imag[i + 1] = i0 - i1
57
52
  }
58
53
 
59
- // Stride 4 - simple twiddle factors
54
+ // Second stage: stride=4
60
55
  if (n >= 4) {
61
56
  for (let i = 0; i < n; i += 4) {
62
- // First pair (W^0 = 1)
63
- let evenR = real[i]
64
- let evenI = imag[i]
65
- let oddR = real[i + 2]
66
- let oddI = imag[i + 2]
67
-
68
- real[i] = evenR + oddR
69
- imag[i] = evenI + oddI
70
- real[i + 2] = evenR - oddR
71
- imag[i + 2] = evenI - oddI
72
-
73
- // Second pair (W^1 = -i)
74
- evenR = real[i + 1]
75
- evenI = imag[i + 1]
76
- oddR = real[i + 3]
77
- oddI = imag[i + 3]
78
-
79
- const tR = oddI // Multiplication by -i
80
- const tI = -oddR
81
-
82
- real[i + 1] = evenR + tR
83
- imag[i + 1] = evenI + tI
84
- real[i + 3] = evenR - tR
85
- imag[i + 3] = evenI - tI
86
- }
87
- }
88
-
89
- // Stride 8 - unrolled for better performance
90
- if (n >= 8) {
91
- for (let i = 0; i < n; i += 8) {
92
- // W^0 = 1
93
- let idx0 = i
94
- let idx4 = i + 4
95
- let r0 = real[idx0],
96
- i0 = imag[idx0]
97
- let r4 = real[idx4],
98
- i4 = imag[idx4]
99
- real[idx0] = r0 + r4
100
- imag[idx0] = i0 + i4
101
- real[idx4] = r0 - r4
102
- imag[idx4] = i0 - i4
103
-
104
- // W^1 = cos(-π/4) - i*sin(-π/4)
105
- let idx1 = i + 1
106
- let idx5 = i + 5
107
- r0 = real[idx1]
108
- i0 = imag[idx1]
109
- r4 = real[idx5]
110
- i4 = imag[idx5]
111
- const sqrt2_2 = 0.7071067811865476
112
- let tR = sqrt2_2 * (r4 + i4)
113
- let tI = sqrt2_2 * (i4 - r4)
114
- real[idx1] = r0 + tR
115
- imag[idx1] = i0 + tI
116
- real[idx5] = r0 - tR
117
- imag[idx5] = i0 - tI
118
-
119
- // W^2 = -i
120
- let idx2 = i + 2
121
- let idx6 = i + 6
122
- r0 = real[idx2]
123
- i0 = imag[idx2]
124
- r4 = real[idx6]
125
- i4 = imag[idx6]
126
- tR = i4
127
- tI = -r4
128
- real[idx2] = r0 + tR
129
- imag[idx2] = i0 + tI
130
- real[idx6] = r0 - tR
131
- imag[idx6] = i0 - tI
132
-
133
- // W^3 = cos(-3π/4) - i*sin(-3π/4)
134
- let idx3 = i + 3
135
- let idx7 = i + 7
136
- r0 = real[idx3]
137
- i0 = imag[idx3]
138
- r4 = real[idx7]
139
- i4 = imag[idx7]
140
- tR = sqrt2_2 * (-r4 + i4)
141
- tI = sqrt2_2 * (-r4 - i4)
142
- real[idx3] = r0 + tR
143
- imag[idx3] = i0 + tI
144
- real[idx7] = r0 - tR
145
- imag[idx7] = i0 - tI
57
+ let r0 = real[i],
58
+ i0 = imag[i]
59
+ let r2 = real[i + 2],
60
+ i2 = imag[i + 2]
61
+ real[i] = r0 + r2
62
+ imag[i] = i0 + i2
63
+ real[i + 2] = r0 - r2
64
+ imag[i + 2] = i0 - i2
65
+
66
+ r0 = real[i + 1]
67
+ i0 = imag[i + 1]
68
+ r2 = real[i + 3]
69
+ i2 = imag[i + 3]
70
+ // W^1 = -i
71
+ let tR = i2
72
+ let tI = -r2
73
+ real[i + 1] = r0 + tR
74
+ imag[i + 1] = i0 + tI
75
+ real[i + 3] = r0 - tR
76
+ imag[i + 3] = i0 - tI
146
77
  }
147
78
  }
148
79
 
149
- // General Cooley-Tukey butterflies with optimized inner loop
150
- for (let stride = 16; stride <= n; stride <<= 1) {
80
+ // Higher stages
81
+ for (let stride = 8; stride <= n; stride <<= 1) {
151
82
  const halfStride = stride >>> 1
152
- const step = n / stride
153
-
154
- // Process each group
155
- for (let grp = 0; grp < n; grp += stride) {
156
- // First butterfly (W^0 = 1) - no multiplication needed
157
- let evenIdx = grp
158
- let oddIdx = grp + halfStride
159
- const r0 = real[evenIdx]
160
- const i0 = imag[evenIdx]
161
- const r1 = real[oddIdx]
162
- const i1 = imag[oddIdx]
163
- real[evenIdx] = r0 + r1
164
- imag[evenIdx] = i0 + i1
165
- real[oddIdx] = r0 - r1
166
- imag[oddIdx] = i0 - i1
167
-
168
- // Remaining butterflies with twiddle factors
169
- let twiddleIdx = step
83
+ const tblStep = n / stride
84
+ for (let base = 0; base < n; base += stride) {
85
+ // k = 0
86
+ let r0 = real[base],
87
+ i0 = imag[base]
88
+ let r1 = real[base + halfStride],
89
+ i1 = imag[base + halfStride]
90
+ real[base] = r0 + r1
91
+ imag[base] = i0 + i1
92
+ real[base + halfStride] = r0 - r1
93
+ imag[base + halfStride] = i0 - i1
94
+
95
+ let tw = tblStep
170
96
  for (let k = 1; k < halfStride; k++) {
171
- evenIdx = grp + k
172
- oddIdx = evenIdx + halfStride
173
-
174
- const cosW = cosTbl[twiddleIdx]
175
- const sinW = sinTbl[twiddleIdx]
176
-
177
- const oddR = real[oddIdx]
178
- const oddI = imag[oddIdx]
179
- const tR = oddR * cosW - oddI * sinW
180
- const tI = oddR * sinW + oddI * cosW
181
-
182
- const evenR = real[evenIdx]
183
- const evenI = imag[evenIdx]
184
-
185
- real[evenIdx] = evenR + tR
186
- imag[evenIdx] = evenI + tI
187
- real[oddIdx] = evenR - tR
188
- imag[oddIdx] = evenI - tI
189
-
190
- twiddleIdx += step
97
+ const c = cosTbl[tw]
98
+ const s = sinTbl[tw]
99
+ r1 = real[base + k]
100
+ i1 = imag[base + k]
101
+ let r2 = real[base + k + halfStride]
102
+ let i2 = imag[base + k + halfStride]
103
+ let tr = r2 * c - i2 * s
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
191
110
  }
192
111
  }
193
112
  }
@@ -198,27 +117,20 @@ export class FFT {
198
117
  * @private
199
118
  */
200
119
  static _buildCache(n) {
201
- const log2n = Math.log2(n) | 0
202
-
203
- // Optimized bit-reversal using iterative approach
204
120
  const bitRev = new Uint32Array(n)
121
+ const log2n = Math.log2(n) | 0
205
122
  for (let i = 1; i < n; i++) {
206
123
  bitRev[i] = (bitRev[i >>> 1] >>> 1) | ((i & 1) << (log2n - 1))
207
124
  }
208
-
209
- // Pre-compute twiddle factors with better precision
210
125
  const halfN = n >>> 1
211
126
  const cosTbl = new Float32Array(halfN)
212
127
  const sinTbl = new Float32Array(halfN)
213
-
214
- // Use higher precision calculation then cast to Float32
215
- const angleStep = (-2 * Math.PI) / n
128
+ const ang = (-2 * Math.PI) / n
216
129
  for (let i = 0; i < halfN; i++) {
217
- const angle = angleStep * i
218
- cosTbl[i] = Math.fround(Math.cos(angle))
219
- sinTbl[i] = Math.fround(Math.sin(angle))
130
+ const a = ang * i
131
+ cosTbl[i] = Math.cos(a)
132
+ sinTbl[i] = Math.sin(a)
220
133
  }
221
-
222
134
  return { bitRev, cos: cosTbl, sin: sinTbl }
223
135
  }
224
136
  }