carta1 1.1.10 → 1.3.0

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.
Files changed (46) hide show
  1. package/bin/cli.js +8 -4
  2. package/codec/{coding/bitallocation.js → allocation/solve.js} +131 -97
  3. package/codec/allocation/source.js +69 -0
  4. package/codec/allocation/stage.js +38 -0
  5. package/codec/analysis/bands.js +68 -0
  6. package/codec/analysis/{transient.js → blocks.js} +90 -47
  7. package/codec/analysis/spectrum.js +160 -0
  8. package/codec/analysis/stage.js +32 -0
  9. package/codec/{browser/interface.js → boundary/browser.js} +1 -1
  10. package/codec/boundary/container.js +96 -0
  11. package/codec/boundary/pcm.js +193 -0
  12. package/codec/boundary/processor.js +208 -0
  13. package/codec/{io/readers.js → boundary/reader.js} +2 -1
  14. package/codec/boundary/stream.js +361 -0
  15. package/codec/{browser → boundary}/worker.js +45 -42
  16. package/codec/core/constants.js +19 -132
  17. package/codec/core/geometry.js +25 -0
  18. package/codec/core/tables.js +215 -0
  19. package/codec/dequantization.js +54 -0
  20. package/codec/index.js +12 -13
  21. package/codec/pipeline/decoder.js +10 -399
  22. package/codec/pipeline/encoder.js +12 -434
  23. package/codec/quantization/spectrum.js +67 -0
  24. package/codec/quantization/stage.js +49 -0
  25. package/codec/signal/fft.js +68 -0
  26. package/codec/{transforms → signal}/mdct.js +37 -65
  27. package/codec/signal/order.js +16 -0
  28. package/codec/signal/qmf.js +539 -0
  29. package/codec/state.js +112 -0
  30. package/codec/{io → syntax}/bitstream.js +27 -8
  31. package/codec/{io/serialization.js → syntax/frame.js} +5 -101
  32. package/codec/synthesis/bands.js +228 -0
  33. package/codec/synthesis/pcm.js +64 -0
  34. package/codec/synthesis/stage.js +17 -0
  35. package/codec/utils.js +9 -52
  36. package/dist/carta1-worker-interface.min.js.map +1 -1
  37. package/dist/carta1-worker.min.js +1 -1
  38. package/dist/carta1-worker.min.js.map +1 -1
  39. package/dist/carta1.min.js +1 -1
  40. package/dist/carta1.min.js.map +1 -1
  41. package/package.json +1 -1
  42. package/codec/coding/quantization.js +0 -149
  43. package/codec/core/buffers.js +0 -81
  44. package/codec/io/processor.js +0 -671
  45. package/codec/transforms/fft.js +0 -69
  46. package/codec/transforms/qmf.js +0 -105
@@ -0,0 +1,215 @@
1
+ /**
2
+ * Stable ATRAC1 geometry, signal, allocation, and quantization tables.
3
+ */
4
+
5
+ import {
6
+ MAX_WORD_LENGTH_INDEX,
7
+ QMF_ANALYSIS_TERMS,
8
+ QMF_BANDS,
9
+ QMF_SYNTHESIS_DELAY_ROWS,
10
+ QMF_SYNTHESIS_TERMS,
11
+ QMF_TAPS,
12
+ } from './constants.js'
13
+
14
+ export const AEA_MAGIC = new Uint8Array([0x00, 0x08, 0x00, 0x00])
15
+
16
+ export const SPECS_PER_BFU = new Int32Array([
17
+ 8, 8, 8, 8, 4, 4, 4, 4, 8, 8, 8, 8, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7,
18
+ 7, 7, 9, 9, 9, 9, 10, 10, 10, 10, 12, 12, 12, 12, 12, 12, 12, 12, 20, 20, 20,
19
+ 20, 20, 20, 20, 20,
20
+ ])
21
+
22
+ export const BFU_AMOUNTS = new Int32Array([20, 28, 32, 36, 40, 44, 48, 52])
23
+ export const BFU_BAND_BOUNDARIES = new Int32Array([20, 36, 52])
24
+
25
+ export const BFU_START_LONG = new Int32Array([
26
+ 0, 8, 16, 24, 32, 36, 40, 44, 48, 56, 64, 72, 80, 86, 92, 98, 104, 110, 116,
27
+ 122, 128, 134, 140, 146, 152, 159, 166, 173, 180, 189, 198, 207, 216, 226,
28
+ 236, 246, 256, 268, 280, 292, 304, 316, 328, 340, 352, 372, 392, 412, 432,
29
+ 452, 472, 492,
30
+ ])
31
+
32
+ export const BFU_START_SHORT = new Int32Array([
33
+ 0, 32, 64, 96, 8, 40, 72, 104, 12, 44, 76, 108, 20, 52, 84, 116, 26, 58, 90,
34
+ 122, 128, 160, 192, 224, 134, 166, 198, 230, 141, 173, 205, 237, 150, 182,
35
+ 214, 246, 256, 288, 320, 352, 384, 416, 448, 480, 268, 300, 332, 364, 396,
36
+ 428, 460, 492,
37
+ ])
38
+
39
+ export const WINDOW_SHORT = (() => {
40
+ const table = new Float64Array(32)
41
+ for (let i = 0; i < 32; i++) {
42
+ table[i] = Math.sin(((i + 0.5) * Math.PI) / 64)
43
+ }
44
+ return table
45
+ })()
46
+
47
+ export const QMF_COEFFS = new Float32Array([
48
+ -0.00001461907, -0.00009205479, -0.000056157569, 0.00030117269, 0.0002422519,
49
+ -0.00085293897, -0.0005205574, 0.0020340169, 0.00078333891, -0.0042153862,
50
+ -0.00075614988, 0.0078402944, -0.000061169922, -0.01344162, 0.0024626821,
51
+ 0.021736089, -0.007801671, -0.034090221, 0.01880949, 0.054326009,
52
+ -0.043596379, -0.099384367, 0.13207909, 0.46424159,
53
+ ])
54
+
55
+ export const QMF_WINDOW = (() => {
56
+ const window = new Float32Array(QMF_TAPS)
57
+ for (let i = 0; i < 24; i++) {
58
+ window[i] = QMF_COEFFS[i] * 2.0
59
+ window[47 - i] = QMF_COEFFS[i] * 2.0
60
+ }
61
+ return window
62
+ })()
63
+
64
+ export const QMF_EVEN = (() => {
65
+ const even = new Float32Array(24)
66
+ for (let i = 0; i < 24; i++) {
67
+ even[i] = QMF_WINDOW[i * 2]
68
+ }
69
+ return even
70
+ })()
71
+
72
+ export const QMF_ODD = (() => {
73
+ const odd = new Float32Array(24)
74
+ for (let i = 0; i < 24; i++) {
75
+ odd[i] = QMF_WINDOW[i * 2 + 1]
76
+ }
77
+ return odd
78
+ })()
79
+
80
+ /** Sample positions read by each component of the configurable QMF analysis. */
81
+ export const QMF_ANALYSIS_SAMPLE_OFFSETS = (() => {
82
+ const offsets = new Uint8Array(QMF_BANDS * QMF_ANALYSIS_TERMS)
83
+ for (let term = 0; term < QMF_ANALYSIS_TERMS; term++) {
84
+ offsets[term] = QMF_TAPS - 1 - term * QMF_BANDS
85
+ offsets[QMF_ANALYSIS_TERMS + term] = QMF_TAPS - QMF_BANDS - term * QMF_BANDS
86
+ }
87
+ return offsets
88
+ })()
89
+
90
+ /** Prototype-filter coefficients in component-major QMF analysis order. */
91
+ export const QMF_ANALYSIS_FILTER_COEFFICIENTS = (() => {
92
+ const coefficients = new Float32Array(QMF_BANDS * QMF_ANALYSIS_TERMS)
93
+ coefficients.set(QMF_EVEN)
94
+ coefficients.set(QMF_ODD, QMF_ANALYSIS_TERMS)
95
+ return coefficients
96
+ })()
97
+
98
+ /** Dense modulation applied after Carta1 QMF analysis filtering. */
99
+ export const QMF_ANALYSIS_MODULATION_COEFFICIENTS = new Float32Array([
100
+ 1, 1, 1, -1,
101
+ ])
102
+
103
+ /* eslint-disable no-loss-of-precision -- Float32Array applies the intended float32 rounding. */
104
+
105
+ /** Reference factors used by the optimized sixteen-band modulation path. */
106
+ export const QMF_ANALYSIS_PI_OVER_8_BUTTERFLY_SCALES = new Float32Array([
107
+ 1.8477590084075928, 0.7653668522834778, 1.8477590084075928,
108
+ 0.7653668522834778,
109
+ ])
110
+
111
+ /** Reference half-angle factors used by sixteen-band modulation. */
112
+ export const QMF_ANALYSIS_HALF_BUTTERFLY_SCALES = new Float32Array([
113
+ 0.7071067690849304, 0.2071067839860916, 1.2071068286895752,
114
+ ])
115
+
116
+ /** Reference odd pi/32 cosines used by sixteen-band modulation. */
117
+ export const QMF_ANALYSIS_ODD_PI_OVER_32_COSINES = new Float32Array([
118
+ 1.990369439125061, 1.913880705833435, 1.7638425827026367, 1.5460208654403687,
119
+ 1.2687865495681763, 0.9427934885025024, 0.5805693864822388,
120
+ 0.1960342824459076,
121
+ ])
122
+
123
+ /** Reference odd pi/16 cosines used by sixteen-band modulation. */
124
+ export const QMF_ANALYSIS_ODD_PI_OVER_16_COSINES = new Float32Array([
125
+ 1.9615705013275146, 1.662939190864563, 1.111140489578247, 0.39018064737319946,
126
+ ])
127
+
128
+ /** Reference odd pi/64 cosines used by sixteen-band modulation. */
129
+ export const QMF_ANALYSIS_ODD_PI_OVER_64_COSINES = new Float32Array([
130
+ 1.9975908994674683, 1.9783530235290527, 1.9400625228881836,
131
+ 1.8830881118774414, 1.807978630065918, 1.7154572010040283, 1.606415033340454,
132
+ 1.4819022417068481, 1.3431179523468018, 1.1913986206054688,
133
+ 1.0282055139541626, 0.8551101684570312, 0.6737797260284424,
134
+ 0.48596036434173584, 0.2934609651565552, 0.09813535213470459,
135
+ ])
136
+
137
+ /* eslint-enable no-loss-of-precision */
138
+
139
+ /** Delay-row offsets read by each sample of configurable QMF synthesis. */
140
+ export const QMF_SYNTHESIS_DELAY_ROW_OFFSETS = (() => {
141
+ const offsets = new Uint8Array(QMF_BANDS * QMF_SYNTHESIS_TERMS)
142
+ for (let sample = 0; sample < QMF_BANDS; sample++) {
143
+ const sampleOffset = sample * QMF_SYNTHESIS_TERMS
144
+ for (let term = 0; term < QMF_SYNTHESIS_TERMS; term++) {
145
+ offsets[sampleOffset + term] = QMF_SYNTHESIS_DELAY_ROWS - 1 - term
146
+ }
147
+ }
148
+ return offsets
149
+ })()
150
+
151
+ /** Delay components read by each sample of configurable QMF synthesis. */
152
+ export const QMF_SYNTHESIS_DELAY_COMPONENTS = (() => {
153
+ const components = new Uint8Array(QMF_BANDS * QMF_SYNTHESIS_TERMS)
154
+ components.fill(1, 0, QMF_SYNTHESIS_TERMS)
155
+ return components
156
+ })()
157
+
158
+ /** Prototype-filter coefficients in output-sample-major QMF synthesis order. */
159
+ export const QMF_SYNTHESIS_FILTER_COEFFICIENTS = (() => {
160
+ const coefficients = new Float64Array(QMF_BANDS * QMF_SYNTHESIS_TERMS)
161
+ coefficients.set(QMF_ODD)
162
+ coefficients.set(QMF_EVEN, QMF_SYNTHESIS_TERMS)
163
+ return coefficients
164
+ })()
165
+
166
+ /** Dense modulation applied before Carta1 QMF synthesis filtering. */
167
+ export const QMF_SYNTHESIS_MODULATION_COEFFICIENTS = new Float64Array([
168
+ 0.5, 0.5, 0.5, -0.5,
169
+ ])
170
+
171
+ export const MDCT_BAND_CONFIGS = [
172
+ { size: 128, windowStart: 48 },
173
+ { size: 128, windowStart: 48 },
174
+ { size: 256, windowStart: 112 },
175
+ ]
176
+
177
+ export const WORD_LENGTH_BITS = new Int32Array([
178
+ 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
179
+ ])
180
+
181
+ export const SCALE_FACTORS = (() => {
182
+ const table = new Float64Array(64)
183
+ for (let i = 0; i < 64; i++) {
184
+ table[i] = Math.pow(2.0, i / 3.0 - 21)
185
+ }
186
+ return table
187
+ })()
188
+
189
+ export const INV_POWER_OF_TWO = (() => {
190
+ const maxBits = WORD_LENGTH_BITS[MAX_WORD_LENGTH_INDEX]
191
+ const table = new Float64Array(maxBits + 1)
192
+ for (let bits = 0; bits <= maxBits; bits++) {
193
+ table[bits] = Math.pow(2, -bits)
194
+ }
195
+ return table
196
+ })()
197
+
198
+ export const WORD_LENGTH_DELTA_BITS = (() => {
199
+ const table = new Int32Array(MAX_WORD_LENGTH_INDEX)
200
+ for (let i = 0; i < MAX_WORD_LENGTH_INDEX; i++) {
201
+ table[i] = (WORD_LENGTH_BITS[i + 1] - WORD_LENGTH_BITS[i]) | 0
202
+ }
203
+ return table
204
+ })()
205
+
206
+ export const DISTORTION_DELTA_FACTORS = (() => {
207
+ const table = new Float64Array(MAX_WORD_LENGTH_INDEX)
208
+ table[0] = 2.0 - INV_POWER_OF_TWO[WORD_LENGTH_BITS[1]]
209
+ for (let i = 1; i < MAX_WORD_LENGTH_INDEX; i++) {
210
+ const bits1 = WORD_LENGTH_BITS[i] | 0
211
+ const bits2 = WORD_LENGTH_BITS[i + 1] | 0
212
+ table[i] = INV_POWER_OF_TWO[bits1] - INV_POWER_OF_TWO[bits2]
213
+ }
214
+ return table
215
+ })()
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Carta1 dequantization stage.
3
+ */
4
+
5
+ import {
6
+ BFU_BAND_BOUNDARIES,
7
+ BFU_START_LONG,
8
+ BFU_START_SHORT,
9
+ WORD_LENGTH_BITS,
10
+ } from './core/tables.js'
11
+ import * as spectrumQuantization from './quantization/spectrum.js'
12
+
13
+ /**
14
+ * Reconstruct the continuous ATRAC1 spectrum.
15
+ *
16
+ * @returns {Function}
17
+ */
18
+ export function dequantize() {
19
+ /**
20
+ * @param {object} frameData
21
+ * @returns {object}
22
+ */
23
+ return (frameData) => {
24
+ const coefficients = new Float32Array(512)
25
+ const {
26
+ nBfu,
27
+ scaleFactorIndices,
28
+ wordLengthIndices,
29
+ quantizedCoefficients,
30
+ blockModes,
31
+ } = frameData
32
+
33
+ for (let bfu = 0; bfu < nBfu; bfu++) {
34
+ const bitsPerSample = WORD_LENGTH_BITS[wordLengthIndices[bfu]]
35
+ let band = 0
36
+ if (bfu >= BFU_BAND_BOUNDARIES[0]) band = 1
37
+ if (bfu >= BFU_BAND_BOUNDARIES[1]) band = 2
38
+
39
+ const position =
40
+ blockModes[band] === 0 ? BFU_START_LONG[bfu] : BFU_START_SHORT[bfu]
41
+
42
+ if (bitsPerSample > 0) {
43
+ const dequantized = spectrumQuantization.dequantize(
44
+ quantizedCoefficients[bfu],
45
+ scaleFactorIndices[bfu],
46
+ bitsPerSample
47
+ )
48
+ coefficients.set(dequantized, position)
49
+ }
50
+ }
51
+
52
+ return { coefficients, blockModes }
53
+ }
54
+ }
package/codec/index.js CHANGED
@@ -4,31 +4,30 @@
4
4
 
5
5
  import { encode } from './pipeline/encoder.js'
6
6
  import { decode } from './pipeline/decoder.js'
7
- import {
8
- serializeFrame,
9
- deserializeFrame,
10
- AeaFile,
11
- } from './io/serialization.js'
12
- import { quantize, dequantize } from './coding/quantization.js'
13
- import { qmfAnalysisStage, mdctStage } from './pipeline/encoder.js'
7
+ import { AeaFile } from './boundary/container.js'
8
+ import { deserializeFrame, serializeFrame } from './syntax/frame.js'
9
+ import { quantize, dequantize } from './quantization/spectrum.js'
10
+ import { analyzeBands } from './analysis/bands.js'
11
+ import { transformSpectrum } from './analysis/spectrum.js'
14
12
  import { pipe } from './utils.js'
15
- import { BufferPool } from './core/buffers.js'
13
+ import { BufferPool } from './state.js'
16
14
  import { EncoderOptions } from './core/options.js'
17
- import { AudioProcessor, decodeAeaPcm, encodeAeaPcm } from './io/processor.js'
18
- import { FFT } from './transforms/fft.js'
15
+ import { AudioProcessor } from './boundary/processor.js'
16
+ import { decodeAeaPcm, encodeAeaPcm } from './boundary/stream.js'
17
+ import { FFT } from './signal/fft.js'
19
18
  import {
20
19
  WORD_LENGTH_BITS,
21
20
  SPECS_PER_BFU,
22
21
  SCALE_FACTORS,
23
22
  BFU_START_LONG,
24
- } from './core/constants.js'
23
+ } from './core/tables.js'
25
24
 
26
25
  export {
27
26
  pipe,
28
27
  encode,
29
28
  decode,
30
- qmfAnalysisStage,
31
- mdctStage,
29
+ analyzeBands as qmfAnalysisStage,
30
+ transformSpectrum as mdctStage,
32
31
  serializeFrame,
33
32
  deserializeFrame,
34
33
  quantize,