@audio/decode-aiff 1.2.2 → 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.
package/README.md CHANGED
@@ -1,7 +1,6 @@
1
1
  # @audio/decode-aiff
2
2
 
3
- Decode AIFF and AIFF-C audio to PCM float samples.<br>
4
- Part of [decode](https://github.com/audiojs/decode).
3
+ Decode AIFF and AIFF-C audio to PCM float samples.
5
4
 
6
5
  ## Install
7
6
 
@@ -12,42 +11,36 @@ npm i @audio/decode-aiff
12
11
  ## Usage
13
12
 
14
13
  ```js
15
- import decode from '@audio/decode-aiff'
14
+ import decode, { decoder } from '@audio/decode-aiff'
16
15
 
17
- let { channelData, sampleRate } = await decode(aiffBuffer)
18
- // channelData: Float32Array[] (one per channel)
19
- // sampleRate: number
20
- ```
21
-
22
- ### Streaming
16
+ let { channelData, sampleRate } = decode(aiffBytes)
23
17
 
24
- ```js
25
- import { decoder } from '@audio/decode-aiff'
26
-
27
- let dec = await decoder()
18
+ let dec = decoder()
28
19
  let result = dec.decode(chunk)
29
20
  dec.free()
30
21
  ```
31
22
 
23
+ `decode()` and `decoder()` are synchronous.
24
+
32
25
  ## API
33
26
 
34
- ### `decode(src): Promise<AudioData>`
27
+ ### `decode(src): AudioData`
35
28
 
36
- Whole-file decode. Accepts `Uint8Array` or `ArrayBuffer`.
29
+ Decode a complete `Uint8Array` or `ArrayBuffer`.
37
30
 
38
- ### `decoder(): Promise<AIFFDecoder>`
31
+ ### `decoder(): AIFFDecoder`
39
32
 
40
- Creates a decoder instance.
33
+ Create a decoder instance.
41
34
 
42
- - **`dec.decode(data)`** — decode chunk, returns `{ channelData, sampleRate }`
43
- - **`dec.flush()`** — flush (returns empty — AIFF is stateless)
44
- - **`dec.free()`** — release resources
35
+ - `dec.decode(data)`: decode a chunk.
36
+ - `dec.flush()`: decode buffered `ima4` or `GSM` data; otherwise return an empty result.
37
+ - `dec.free()`: release resources.
45
38
 
46
39
  ## Formats
47
40
 
48
- - AIFF — 8, 16, 24, 32-bit signed integer PCM (big-endian)
49
- - AIFF-C — `NONE`/`twos` (BE PCM), `sowt` (LE PCM), `fl32`/`fl64` (float), `alaw`, `ulaw`
41
+ - AIFF: 8, 16, 24, and 32-bit signed big-endian PCM.
42
+ - AIFF-C: `NONE`/`twos`, `sowt`, `fl32`, `fl64`, `alaw`, `ulaw`, `ima4`, and `GSM`.
50
43
 
51
44
  ## License
52
45
 
53
- MIT — [krishnized](https://github.com/krishnized/license)
46
+ [ॐ](https://github.com/krishnized/license/) · [MIT](./LICENSE)
package/decode-aiff.d.ts CHANGED
@@ -1,16 +1,16 @@
1
- interface AudioData {
1
+ export interface AudioData {
2
2
  channelData: Float32Array[];
3
3
  sampleRate: number;
4
4
  }
5
5
 
6
6
  interface AIFFDecoder {
7
- decode(data: Uint8Array): AudioData;
7
+ decode(data: Uint8Array | ArrayBuffer): AudioData;
8
8
  flush(): AudioData;
9
9
  free(): void;
10
10
  }
11
11
 
12
- /** Decode AIFF/AIFF-C audio buffer to PCM samples */
13
- export default function decode(src: ArrayBuffer | Uint8Array): Promise<AudioData>;
12
+ /** Decode a complete AIFF or AIFF-C file synchronously. */
13
+ export default function decode(src: ArrayBuffer | Uint8Array): AudioData;
14
14
 
15
- /** Create decoder instance */
16
- export function decoder(): Promise<AIFFDecoder>;
15
+ /** Create a synchronous decoder. */
16
+ export function decoder(): AIFFDecoder;
package/decode-aiff.js CHANGED
@@ -456,14 +456,10 @@ function gsmRpeDecode(xmaxc, Mc, xMc, erp) {
456
456
  for (let i = 0; i < 13; i++) erp[Mc + 3 * i] = xMp[i]
457
457
  }
458
458
 
459
- /**
460
- * Whole-file decode
461
- * @param {Uint8Array|ArrayBuffer} src
462
- * @returns {Promise<{channelData: Float32Array[], sampleRate: number}>}
463
- */
464
- export default async function decode(src) {
459
+ /** Decode a complete AIFF file synchronously. */
460
+ export default function decode(src) {
465
461
  let buf = src instanceof Uint8Array ? src : src instanceof ArrayBuffer ? new Uint8Array(src) : src
466
- let dec = await decoder()
462
+ let dec = decoder()
467
463
  try {
468
464
  let result = dec.decode(buf)
469
465
  if (!result.channelData.length) result = dec.flush()
@@ -473,27 +469,26 @@ export default async function decode(src) {
473
469
  }
474
470
  }
475
471
 
476
- /**
477
- * Create decoder instance
478
- * @returns {Promise<{decode(chunk: Uint8Array): {channelData, sampleRate}, flush(), free()}>}
479
- */
480
- export async function decoder() {
481
- let hdr = null, left = null, freed = false
472
+ /** Create a synchronous decoder. */
473
+ export function decoder() {
474
+ let hdr = null, left = null, deferredChunks = null, deferredLength = 0, freed = false
482
475
  return {
483
476
  decode(data) {
484
477
  if (freed) throw Error('Decoder already freed')
485
- if (!data?.length) return EMPTY
478
+ if (!data || !data.byteLength) return EMPTY
486
479
  let chunk = data instanceof Uint8Array ? data : new Uint8Array(data)
487
480
  if (left) { chunk = cat(left, chunk); left = null }
488
481
  if (!hdr) {
489
482
  hdr = scanAiffHdr(chunk)
490
483
  if (!hdr) { left = chunk.slice(); return EMPTY }
491
- // IMA4/GSM: buffer all SSND data, decode on flush
492
- if (hdr.comp === 'ima4' || hdr.comp === 'GSM ' || hdr.comp === 'gsm ') {
493
- left = chunk.slice()
494
- return EMPTY
495
- }
496
- chunk = chunk.subarray(hdr.dataStart)
484
+ deferredChunks = hdr.comp === 'ima4' || hdr.comp === 'GSM ' || hdr.comp === 'gsm ' ? [] : null
485
+ if (!deferredChunks) chunk = chunk.subarray(hdr.dataStart)
486
+ }
487
+ // IMA4 and GSM need the complete container.
488
+ if (deferredChunks) {
489
+ deferredChunks.push(new Uint8Array(chunk))
490
+ deferredLength += chunk.length
491
+ return EMPTY
497
492
  }
498
493
  let fb = hdr.frameBytes
499
494
  let complete = Math.floor(chunk.length / fb) * fb
@@ -502,15 +497,16 @@ export async function decoder() {
502
497
  return decodeAiffRaw(chunk.subarray(0, complete), hdr)
503
498
  },
504
499
  flush() {
505
- if (hdr && left && (hdr.comp === 'ima4' || hdr.comp === 'GSM ' || hdr.comp === 'gsm ')) {
506
- let result = parseAiff(left)
507
- left = null
508
- return result
500
+ if (deferredChunks && deferredLength) {
501
+ let input = new Uint8Array(deferredLength), offset = 0
502
+ for (let chunk of deferredChunks) { input.set(chunk, offset); offset += chunk.length }
503
+ deferredChunks = []; deferredLength = 0
504
+ return parseAiff(input)
509
505
  }
510
506
  left = null
511
507
  return EMPTY
512
508
  },
513
- free() { freed = true; left = null; hdr = null },
509
+ free() { freed = true; left = null; hdr = null; deferredChunks = null; deferredLength = 0 },
514
510
  }
515
511
  }
516
512
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@audio/decode-aiff",
3
- "version": "1.2.2",
3
+ "version": "1.3.0",
4
4
  "description": "Decode AIFF/AIFF-C audio to PCM samples",
5
5
  "type": "module",
6
6
  "main": "decode-aiff.js",
@@ -33,16 +33,16 @@
33
33
  },
34
34
  "license": "MIT",
35
35
  "author": "audiojs",
36
- "homepage": "https://github.com/audiojs/decode-aiff#readme",
36
+ "homepage": "https://github.com/audiojs/decode/tree/master/packages/decode-aiff#readme",
37
37
  "repository": {
38
38
  "type": "git",
39
- "url": "git+https://github.com/audiojs/decode-aiff.git",
39
+ "url": "git+https://github.com/audiojs/decode.git",
40
40
  "directory": "packages/decode-aiff"
41
41
  },
42
42
  "engines": {
43
43
  "node": ">=18"
44
44
  },
45
- "bugs": "https://github.com/audiojs/decode-aiff/issues",
45
+ "bugs": "https://github.com/audiojs/decode/issues",
46
46
  "scripts": {
47
47
  "test": "node test.js"
48
48
  },