@thi.ng/dsp-io-wav
Version:
WAV file format generation
81 lines (80 loc) • 2.12 kB
JavaScript
import { f32u16, f32u24, f32u32, f32u8 } from "@thi.ng/binary/float";
import { assert } from "@thi.ng/errors/assert";
import {
asBytes,
bytes,
u16,
u24,
u32,
u8
} from "@thi.ng/transducers-binary/bytes";
import { comp } from "@thi.ng/transducers/comp";
import { concat } from "@thi.ng/transducers/concat";
import { iterator } from "@thi.ng/transducers/iterator";
import { map } from "@thi.ng/transducers/map";
import { reduce } from "@thi.ng/transducers/reduce";
import { take } from "@thi.ng/transducers/take";
const HEADER_SIZE = 44;
const CONVERTERS = {
8: (x) => u8(f32u8(x)),
16: (x) => u16(f32u16(x), true),
24: (x) => u24(f32u24(x), true),
32: (x) => u32(f32u32(x), true)
};
const wavHeader = (spec) => {
const bytesPerSample = spec.bits >> 3;
const blockAlign = spec.channels * bytesPerSample;
const dataLength = spec.length * blockAlign;
return [
u32(1380533830, false),
// 'RIFF'
u32(dataLength + HEADER_SIZE - 8, true),
// riff len
u32(1463899717, false),
// 'WAVE'
u32(1718449184, false),
// 'fmt '
u32(16, true),
// fmt len,
u16(1, true),
// audio format id
u16(spec.channels, true),
u32(spec.sampleRate, true),
u32(spec.sampleRate * blockAlign, true),
// byte rate
u16(blockAlign, true),
u16(spec.bits, true),
u32(1684108385, false),
// 'data'
u32(dataLength, true)
];
};
const wavByteArray = (spec, src) => {
const convert = CONVERTERS[spec.bits];
assert(!!convert, `unsupported bits/sample: ${spec.bits}`);
return reduce(
bytes(),
new Uint8Array(
HEADER_SIZE + spec.length * spec.channels * (spec.bits >> 3)
),
concat(
wavHeader(spec),
iterator(comp(take(spec.length * spec.channels), map(convert)), src)
)
);
};
const wavBytes = (spec, src) => {
const convert = CONVERTERS[spec.bits];
assert(!!convert, `unsupported bits/sample: ${spec.bits}`);
return asBytes(
concat(
wavHeader(spec),
iterator(comp(take(spec.length * spec.channels), map(convert)), src)
)
);
};
export {
wavByteArray,
wavBytes,
wavHeader
};