@audio/decode-caf 1.4.0 → 1.4.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/README.md +2 -0
- package/decode-caf.js +23 -29
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -43,6 +43,8 @@ Create a decoder instance.
|
|
|
43
43
|
- `ulaw`: G.711 µ-law.
|
|
44
44
|
- `ima4`: IMA/QuickTime ADPCM.
|
|
45
45
|
|
|
46
|
+
Other formats (AAC and ALAC packets, as in Apple Loops) throw `CAF: unsupported format '<id>'`.
|
|
47
|
+
|
|
46
48
|
## License
|
|
47
49
|
|
|
48
50
|
[ॐ](https://github.com/krishnized/license/) · [MIT](./LICENSE)
|
package/decode-caf.js
CHANGED
|
@@ -6,11 +6,27 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
const EMPTY = Object.freeze({ channelData: [], sampleRate: 0 })
|
|
9
|
+
const FORMATS = new Set(['lpcm', 'alaw', 'ulaw', 'ima4'])
|
|
9
10
|
|
|
10
11
|
// IMA/QuickTime ADPCM tables
|
|
11
12
|
const IMA_STEP = new Int16Array([7,8,9,10,11,12,13,14,16,17,19,21,23,25,28,31,34,37,41,45,50,55,60,66,73,80,88,97,107,118,130,143,157,173,190,209,230,253,279,307,337,371,408,449,494,544,598,658,724,796,876,963,1060,1166,1282,1411,1552,1707,1878,2066,2272,2499,2749,3024,3327,3660,4026,4428,4871,5358,5894,6484,7132,7845,8630,9493,10442,11487,12635,13899,15289,16818,18500,20350,22385,24623,27086,29794,32767])
|
|
12
13
|
const IMA_IDX = new Int8Array([-1,-1,-1,-1,2,4,6,8,-1,-1,-1,-1,2,4,6,8])
|
|
13
14
|
|
|
15
|
+
// G.711 expansion tables (ITU-T), as decode-aiff and decode-wav: int16 PCM per encoded byte
|
|
16
|
+
const ALAW_TBL = new Int16Array(256)
|
|
17
|
+
const ULAW_TBL = new Int16Array(256)
|
|
18
|
+
for (let i = 0; i < 256; i++) {
|
|
19
|
+
let ax = i ^ 0x55, seg = (ax >> 4) & 7, val = ((ax & 0x0F) << 4) + 8
|
|
20
|
+
if (seg) val = (val + 256) << (seg - 1)
|
|
21
|
+
ALAW_TBL[i] = (ax & 0x80) ? val : -val
|
|
22
|
+
|
|
23
|
+
let ux = ~i & 0xFF
|
|
24
|
+
seg = (ux >> 4) & 7
|
|
25
|
+
val = ((ux & 0x0F) << 3) + 132
|
|
26
|
+
val <<= seg
|
|
27
|
+
ULAW_TBL[i] = (ux & 0x80) ? (132 - val) : (val - 132)
|
|
28
|
+
}
|
|
29
|
+
|
|
14
30
|
/** Decode a complete CAF file synchronously. */
|
|
15
31
|
export default function decode(src) {
|
|
16
32
|
let dec = decoder()
|
|
@@ -76,6 +92,8 @@ function scanCafHdr(buf) {
|
|
|
76
92
|
channelsPerFrame: dv.getUint32(off + 24, false),
|
|
77
93
|
bitsPerChannel: dv.getUint32(off + 28, false),
|
|
78
94
|
}
|
|
95
|
+
// compressed formats (aac, alac, ...) carry packets this decoder can't read: say so, don't wait forever
|
|
96
|
+
if (!FORMATS.has(desc.formatID)) throw Error(`CAF: unsupported format '${desc.formatID}'`)
|
|
79
97
|
} else if (type === 'data') {
|
|
80
98
|
if (!desc) return null
|
|
81
99
|
let dataStart = off + 4 // skip editCount
|
|
@@ -88,7 +106,7 @@ function scanCafHdr(buf) {
|
|
|
88
106
|
if (formatID === 'alaw' || formatID === 'ulaw') frameBytes = ch
|
|
89
107
|
else if (formatID === 'ima4') frameBytes = desc.bytesPerPacket || 34 * ch // packet = 34 bytes/channel
|
|
90
108
|
else frameBytes = ch * bytesPerSample
|
|
91
|
-
if (!frameBytes)
|
|
109
|
+
if (!frameBytes) throw Error(`CAF: invalid ${formatID} description (${ch} channels, ${bits} bits)`)
|
|
92
110
|
return { ...desc, dataStart, frameBytes, dataSize }
|
|
93
111
|
}
|
|
94
112
|
if (size < 0) break
|
|
@@ -104,8 +122,8 @@ function decodeCafRaw(raw, hdr) {
|
|
|
104
122
|
if (!frames) return EMPTY
|
|
105
123
|
let samples
|
|
106
124
|
if (formatID === 'lpcm') samples = decodeLPCM(raw, formatFlags, bits, ch)
|
|
107
|
-
else if (formatID === 'alaw') samples =
|
|
108
|
-
else if (formatID === 'ulaw') samples =
|
|
125
|
+
else if (formatID === 'alaw') samples = decodeLaw(raw, ch, ALAW_TBL)
|
|
126
|
+
else if (formatID === 'ulaw') samples = decodeLaw(raw, ch, ULAW_TBL)
|
|
109
127
|
else if (formatID === 'ima4') samples = decodeIma4(raw, hdr)
|
|
110
128
|
else throw Error('CAF: unsupported format ' + formatID)
|
|
111
129
|
return { channelData: samples, sampleRate }
|
|
@@ -203,36 +221,12 @@ function decodeLPCM(data, flags, bits, ch) {
|
|
|
203
221
|
return channelData
|
|
204
222
|
}
|
|
205
223
|
|
|
206
|
-
function
|
|
207
|
-
val ^= 0x55
|
|
208
|
-
let sign = val & 0x80, seg = (val >> 4) & 7, quant = val & 0x0F
|
|
209
|
-
let sample = seg ? ((quant << 1) | 0x21) << (seg - 1) : (quant << 1) | 1
|
|
210
|
-
return (sign ? -sample : sample) / 32768
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
function ulawDecode(val) {
|
|
214
|
-
val = ~val & 0xFF
|
|
215
|
-
let sign = val & 0x80, exp = (val >> 4) & 7, mant = val & 0x0F
|
|
216
|
-
let sample = ((mant << 1) | 0x21) << exp
|
|
217
|
-
return (sign ? -(sample - 33) : (sample - 33)) / 32768
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
function decodeAlaw(data, ch) {
|
|
221
|
-
let framesCount = (data.length / ch) | 0
|
|
222
|
-
if (!framesCount) return []
|
|
223
|
-
let channelData = Array.from({ length: ch }, () => new Float32Array(framesCount))
|
|
224
|
-
for (let i = 0, off = 0; i < framesCount; i++)
|
|
225
|
-
for (let c = 0; c < ch; c++, off++)
|
|
226
|
-
channelData[c][i] = alawDecode(data[off])
|
|
227
|
-
return channelData
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
function decodeUlaw(data, ch) {
|
|
224
|
+
function decodeLaw(data, ch, tbl) {
|
|
231
225
|
let framesCount = (data.length / ch) | 0
|
|
232
226
|
if (!framesCount) return []
|
|
233
227
|
let channelData = Array.from({ length: ch }, () => new Float32Array(framesCount))
|
|
234
228
|
for (let i = 0, off = 0; i < framesCount; i++)
|
|
235
229
|
for (let c = 0; c < ch; c++, off++)
|
|
236
|
-
channelData[c][i] =
|
|
230
|
+
channelData[c][i] = tbl[data[off]] / 32768
|
|
237
231
|
return channelData
|
|
238
232
|
}
|