Skip to content

Commit 4a08e0d

Browse files
committed
Add stream entry, simplify API
1 parent feaa262 commit 4a08e0d

5 files changed

Lines changed: 68 additions & 13 deletions

File tree

README.md

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ const flac = await encode.flac(channelData, { sampleRate: 44100 });
3838
const opus = await encode.opus(channelData, { sampleRate: 48000, bitrate: 96 });
3939
```
4040

41-
### Stream encoding
41+
### Chunked encoding
4242

4343
Call with just options (no data) to create a streaming encoder:
4444

@@ -49,11 +49,21 @@ const enc = await encode.mp3({ sampleRate: 44100, bitrate: 128 });
4949

5050
const a = await enc(chunk1); // Uint8Array
5151
const b = await enc(chunk2);
52-
const c = await enc(); // end of stream — flush + free
52+
const c = await enc(null); // end of stream — flush + free
5353

5454
// explicit control: enc.flush(), enc.free()
5555
```
5656

57+
### TransformStream
58+
59+
```js
60+
import encodeStream from 'encode-audio/stream';
61+
62+
audioSource
63+
.pipeThrough(encodeStream('mp3', { sampleRate: 44100, bitrate: 128 }))
64+
.pipeTo(destination);
65+
```
66+
5767
### Options
5868

5969
| Option | Description | Applies to |
@@ -66,17 +76,6 @@ const c = await enc(); // end of stream — flush + free
6676
| `compression` | FLAC compression level 0–8 | flac |
6777
| `application` | `'audio'`, `'voip'`, or `'lowdelay'` | opus |
6878

69-
### Custom encoders
70-
71-
The `encode` registry is extensible:
72-
73-
```js
74-
import encode from 'encode-audio';
75-
encode.myformat = Object.assign(
76-
async (data, opts) => { /* ... */ },
77-
{ stream: async (opts) => ({ encode: chunk => ..., free() {} }) }
78-
);
79-
```
8079

8180
## See also
8281

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,14 @@
1111
"node": "./audio-encode.js",
1212
"default": "./audio-encode.js"
1313
},
14+
"./stream": "./stream.js",
1415
"./package.json": "./package.json"
1516
},
1617
"files": [
1718
"audio-encode.js",
1819
"audio-encode.d.ts",
20+
"stream.js",
21+
"stream.d.ts",
1922
"LICENSE"
2023
],
2124
"workspaces": [

stream.d.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
type AudioInput = Float32Array[] | Float32Array | { numberOfChannels: number; getChannelData(i: number): Float32Array };
2+
3+
/**
4+
* Create a TransformStream that encodes audio chunks to the given format.
5+
* @param format - 'wav', 'mp3', 'ogg', 'opus', 'flac', 'aiff'
6+
* @param opts - encoder options (sampleRate required)
7+
*/
8+
export default function encodeStream(
9+
format: string,
10+
opts: import('./audio-encode.js').EncodeOptions
11+
): TransformStream<AudioInput, Uint8Array>;

stream.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/**
2+
* TransformStream for audio encoding
3+
* @module encode-audio/stream
4+
*
5+
* audioSource.pipeThrough(encodeStream('mp3', { sampleRate: 44100, bitrate: 128 }))
6+
*/
7+
8+
import encode from './audio-encode.js'
9+
10+
/**
11+
* @param {string} format - 'wav', 'mp3', 'ogg', 'opus', 'flac', 'aiff'
12+
* @param {object} opts - encoder options (sampleRate required)
13+
* @returns {TransformStream<Float32Array[]|Float32Array, Uint8Array>}
14+
*/
15+
export default function encodeStream(format, opts) {
16+
if (!encode[format]) throw Error('Unknown format: ' + format)
17+
let enc
18+
return new TransformStream({
19+
async start() { enc = await encode[format](opts) },
20+
async transform(chunk, ctrl) {
21+
let buf = await enc(chunk)
22+
if (buf.length) ctrl.enqueue(buf)
23+
},
24+
async flush(ctrl) {
25+
let buf = await enc()
26+
if (buf.length) ctrl.enqueue(buf)
27+
}
28+
})
29+
}

test.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import t, { is, ok, almost } from 'tst'
22
import encode from './audio-encode.js'
3+
import encodeStream from './stream.js'
34
import decode from 'audio-decode'
45
import AudioBuffer from 'audio-buffer'
56

@@ -96,6 +97,18 @@ t('streaming (deprecated .stream/.encode)', async () => {
9697
ok(c1.length > 0 || c2.length > 0 || final.length > 0)
9798
})
9899

100+
t('TransformStream', async () => {
101+
let chunks = [sine(44100, 440, 0.5), sine(44100, 440, 0.5)]
102+
let source = new ReadableStream({
103+
pull(ctrl) { chunks.length ? ctrl.enqueue(chunks.shift()) : ctrl.close() }
104+
})
105+
let out = []
106+
let dest = new WritableStream({ write(chunk) { out.push(chunk) } })
107+
await source.pipeThrough(encodeStream('wav', { sampleRate: 44100 })).pipeTo(dest)
108+
ok(out.length > 0, 'produced chunks')
109+
ok(out.every(c => c instanceof Uint8Array), 'all Uint8Array')
110+
})
111+
99112
t('AudioBuffer input', async () => {
100113
let ab = new AudioBuffer({ sampleRate: 44100, length: 44100 })
101114
let ch = ab.getChannelData(0)

0 commit comments

Comments
 (0)