audio
Version:
Audio loading, editing, and rendering for JavaScript
1,431 lines (1,422 loc) • 143 kB
JavaScript
var __defProp = Object.defineProperty;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __esm = (fn3, res) => function __init() {
return fn3 && (res = (0, fn3[__getOwnPropNames(fn3)[0]])(fn3 = 0)), res;
};
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
// node_modules/audio-mic/browser.js
var browser_exports = {};
__export(browser_exports, {
default: () => mic
});
async function mic(opts = {}) {
const channels2 = opts.channels || 1;
const sampleRate2 = opts.sampleRate || 44100;
const bitDepth = opts.bitDepth || 16;
const constraints = {
audio: {
sampleRate: { ideal: sampleRate2 },
channelCount: { ideal: channels2 },
echoCancellation: opts.echoCancellation ?? false,
noiseSuppression: opts.noiseSuppression ?? false,
autoGainControl: opts.autoGainControl ?? false
}
};
const stream = await navigator.mediaDevices.getUserMedia(constraints);
const ownCtx = !opts.context;
const ctx = opts.context || new AudioContext({ sampleRate: sampleRate2 });
const source = ctx.createMediaStreamSource(stream);
let closed = false;
let pending = null;
let node;
if (ctx.audioWorklet) {
const workletCode = `
class MicProcessor extends AudioWorkletProcessor {
process(inputs) {
const input = inputs[0]
if (input && input.length > 0) {
const channels = []
for (let i = 0; i < input.length; i++) channels.push(input[i].slice())
this.port.postMessage(channels)
}
return true
}
}
registerProcessor('mic-processor', MicProcessor)
`;
const blob = new Blob([workletCode], { type: "application/javascript" });
const url = URL.createObjectURL(blob);
await ctx.audioWorklet.addModule(url);
URL.revokeObjectURL(url);
node = new AudioWorkletNode(ctx, "mic-processor", {
numberOfInputs: 1,
numberOfOutputs: 0,
channelCount: channels2
});
source.connect(node);
node.port.onmessage = (e) => {
if (closed || !pending) return;
const cb = pending;
pending = null;
cb(null, float32ToPCM(e.data, bitDepth));
};
} else {
const bufSize = 2048;
node = ctx.createScriptProcessor(bufSize, channels2, 1);
source.connect(node);
node.connect(ctx.destination);
node.onaudioprocess = (e) => {
if (closed || !pending) return;
const cb = pending;
pending = null;
const chans = [];
for (let i = 0; i < channels2; i++) chans.push(e.inputBuffer.getChannelData(i).slice());
cb(null, float32ToPCM(chans, bitDepth));
};
}
read.close = close;
read.end = close;
read.backend = "mediastream";
return read;
function read(cb) {
if (cb == null || closed) {
close();
return;
}
if (ctx.state === "suspended") ctx.resume();
pending = cb;
}
function close() {
if (closed) return;
closed = true;
pending = null;
source.disconnect();
stream.getTracks().forEach((t) => t.stop());
if (ownCtx) ctx.close?.();
}
function float32ToPCM(channelData, bits) {
const ch = channelData.length;
const len = channelData[0].length;
const bps = bits / 8;
const buf = new Uint8Array(len * ch * bps);
const view = new DataView(buf.buffer);
for (let i = 0; i < len; i++) {
for (let c = 0; c < ch; c++) {
const sample = channelData[c][i];
const offset = (i * ch + c) * bps;
if (bits === 16) {
view.setInt16(offset, Math.max(-32768, Math.min(32767, Math.round(sample * 32767))), true);
} else if (bits === 32) {
view.setFloat32(offset, sample, true);
} else if (bits === 8) {
buf[offset] = Math.max(0, Math.min(255, Math.round((sample + 1) * 127.5)));
}
}
}
return buf;
}
}
var init_browser = __esm({
"node_modules/audio-mic/browser.js"() {
}
});
// node_modules/audio-type/audio-type.js
function audioType(buf) {
if (!buf) return;
buf = new Uint8Array(buf.buffer || buf);
if (isWav(buf)) return "wav";
if (isAiff(buf)) return "aiff";
if (isMp3(buf)) return "mp3";
if (isAac(buf)) return "aac";
if (isFlac(buf)) return "flac";
if (isM4a(buf)) return "m4a";
if (isOpus(buf)) return "opus";
if (isOgg(buf)) return "oga";
if (isQoa(buf)) return "qoa";
if (isMidi(buf)) return "mid";
if (isCaf(buf)) return "caf";
if (isWma(buf)) return "wma";
if (isAmr(buf)) return "amr";
if (isWebm(buf)) return "webm";
}
function isMp3(buf) {
if (!buf || buf.length < 3) return;
return buf[0] === 73 && buf[1] === 68 && buf[2] === 51 || // ID3
buf[0] === 255 && (buf[1] & 224) === 224 && (buf[1] & 6) !== 0 || // MPEG sync, layer != 0 (excludes AAC)
buf[0] === 84 && buf[1] === 65 && buf[2] === 71;
}
function isWav(buf) {
if (!buf || buf.length < 12) return;
return buf[0] === 82 && buf[1] === 73 && buf[2] === 70 && buf[3] === 70 && buf[8] === 87 && buf[9] === 65 && buf[10] === 86 && buf[11] === 69;
}
function isOgg(buf) {
if (!buf || buf.length < 4) return;
return buf[0] === 79 && buf[1] === 103 && buf[2] === 103 && buf[3] === 83;
}
function isFlac(buf) {
if (!buf || buf.length < 4) return;
return buf[0] === 102 && buf[1] === 76 && buf[2] === 97 && buf[3] === 67;
}
function isM4a(buf) {
if (!buf || buf.length < 8) return;
return buf[4] === 102 && buf[5] === 116 && buf[6] === 121 && buf[7] === 112 || buf[0] === 77 && buf[1] === 52 && buf[2] === 65 && buf[3] === 32;
}
function isOpus(buf) {
if (!buf || buf.length < 36) return;
return buf[0] === 79 && buf[1] === 103 && buf[2] === 103 && buf[3] === 83 && buf[28] === 79 && buf[29] === 112 && buf[30] === 117 && buf[31] === 115 && buf[32] === 72 && buf[33] === 101 && buf[34] === 97 && buf[35] === 100;
}
function isQoa(buf) {
if (!buf || buf.length < 4) return;
return buf[0] === 113 && buf[1] === 111 && buf[2] === 97 && buf[3] === 102;
}
function isAiff(buf) {
if (!buf || buf.length < 12) return;
return buf[0] === 70 && buf[1] === 79 && buf[2] === 82 && buf[3] === 77 && buf[8] === 65 && buf[9] === 73 && buf[10] === 70 && (buf[11] === 70 || buf[11] === 67);
}
function isAac(buf) {
if (!buf || buf.length < 2) return;
return buf[0] === 255 && (buf[1] & 240) === 240 && (buf[1] & 6) === 0;
}
function isMidi(buf) {
if (!buf || buf.length < 4) return;
return buf[0] === 77 && buf[1] === 84 && buf[2] === 104 && buf[3] === 100;
}
function isCaf(buf) {
if (!buf || buf.length < 4) return;
return buf[0] === 99 && buf[1] === 97 && buf[2] === 102 && buf[3] === 102;
}
function isWma(buf) {
if (!buf || buf.length < 8) return;
return buf[0] === 48 && buf[1] === 38 && buf[2] === 178 && buf[3] === 117 && buf[4] === 142 && buf[5] === 102 && buf[6] === 207 && buf[7] === 17;
}
function isAmr(buf) {
if (!buf || buf.length < 5) return;
return buf[0] === 35 && buf[1] === 33 && buf[2] === 65 && buf[3] === 77 && buf[4] === 82;
}
function isWebm(buf) {
if (!buf || buf.length < 4) return;
return buf[0] === 26 && buf[1] === 69 && buf[2] === 223 && buf[3] === 163;
}
// node_modules/audio-decode/audio-decode.js
var EMPTY = Object.freeze({ channelData: Object.freeze([]), sampleRate: 0 });
function decode(src, format) {
if (format) return decodeChunked(src, format);
return decodeWhole(src);
}
async function decodeWhole(src) {
if (!src || typeof src === "string" || !(src.buffer || src.byteLength || src.length))
throw TypeError("Expected ArrayBuffer or Uint8Array");
let buf = new Uint8Array(src);
let type = audioType(buf);
if (!type) throw Error("Unknown audio format");
if (!decode[type]) throw Error("No decoder for " + type);
let dec = await decode[type]();
try {
let result = await dec(buf);
let flushed = await dec();
return merge(result, flushed);
} catch (e) {
dec.free();
throw e;
}
}
async function* decodeChunked(source, format) {
if (!decode[format]) throw Error("No decoder for " + format);
let dec = await decode[format]();
try {
if (source.getReader) {
let reader = source.getReader();
while (true) {
let { done, value } = await reader.read();
if (done) break;
let result = await dec(value instanceof Uint8Array ? value : new Uint8Array(value));
if (result.channelData.length) yield result;
}
} else {
for await (let chunk of source) {
let result = await dec(chunk instanceof Uint8Array ? chunk : new Uint8Array(chunk));
if (result.channelData.length) yield result;
}
}
let flushed = await dec();
if (flushed.channelData.length) yield flushed;
} finally {
dec.free();
}
}
function reg(name, load) {
decode[name] = fmt(name, async () => {
let mod = await load();
if (mod.decoder) {
let codec2 = await mod.decoder();
return streamDecoder(
(chunk) => codec2.decode(chunk),
codec2.flush ? () => codec2.flush() : null,
codec2.free ? () => codec2.free() : null
);
}
let init2 = mod.default || mod;
let codec = typeof init2 === "function" ? await init2() : init2;
if (codec.ready) await codec.ready;
return streamDecoder(
(chunk) => codec.decode(chunk),
codec.flush ? () => codec.flush() : null,
codec.free ? () => codec.free() : null
);
});
}
function fmt(name, init2) {
let fn3 = (src) => {
if (!src) return init2();
if (src[Symbol.asyncIterator] || src.getReader) return decodeChunked(src, name);
console.warn("decode." + name + "(data) is deprecated, use decode(data)");
return (async () => {
let dec = await init2();
try {
let result = await dec(src instanceof Uint8Array ? src : new Uint8Array(src.buffer || src));
let flushed = await dec();
return merge(result, flushed);
} catch (e) {
dec.free();
throw e;
}
})();
};
return fn3;
}
reg("mp3", () => import("@audio/decode-mp3"));
reg("flac", () => import("@audio/decode-flac"));
reg("opus", () => import("@audio/decode-opus"));
reg("oga", () => import("@audio/decode-vorbis"));
reg("m4a", () => import("@audio/decode-aac"));
reg("wav", () => import("@audio/decode-wav"));
reg("qoa", () => import("@audio/decode-qoa"));
reg("aac", () => import("@audio/decode-aac"));
reg("aiff", () => import("@audio/decode-aiff"));
reg("caf", () => import("@audio/decode-caf"));
reg("webm", () => import("@audio/decode-webm"));
reg("amr", () => import("@audio/decode-amr"));
reg("wma", () => import("@audio/decode-wma"));
function streamDecoder(onDecode, onFlush, onFree) {
let done = false;
let fn3 = async (chunk) => {
if (chunk) {
if (done) throw Error("Decoder already freed");
try {
return norm(await onDecode(chunk instanceof Uint8Array ? chunk : new Uint8Array(chunk)));
} catch (e) {
done = true;
onFree?.();
throw e;
}
}
if (done) return EMPTY;
done = true;
try {
let result = onFlush ? norm(await onFlush()) : EMPTY;
onFree?.();
return result;
} catch (e) {
onFree?.();
throw e;
}
};
fn3.flush = async () => {
if (done) return EMPTY;
return onFlush ? norm(await onFlush()) : EMPTY;
};
fn3.free = () => {
if (done) return;
done = true;
onFree?.();
};
return fn3;
}
function norm(r) {
if (!r?.channelData?.length) return EMPTY;
let { channelData, sampleRate: sampleRate2, samplesDecoded } = r;
if (samplesDecoded != null && samplesDecoded < channelData[0].length)
channelData = channelData.map((ch) => ch.subarray(0, samplesDecoded));
if (!channelData[0]?.length) return EMPTY;
if (channelData.length === 2) {
let a2 = channelData[0], b = channelData[1], same = true;
for (let i = 0; i < a2.length; i += 37) {
if (a2[i] !== b[i]) {
same = false;
break;
}
}
if (same) channelData = [a2];
}
return { channelData, sampleRate: sampleRate2 };
}
function merge(a2, b) {
if (!b?.channelData?.length) return a2;
if (!a2?.channelData?.length) return b;
let ach = a2.channelData.length, bch = b.channelData.length;
let ch = Math.max(ach, bch);
return {
channelData: Array.from({ length: ch }, (_, i) => {
let ac = a2.channelData[i % ach], bc = b.channelData[i % bch];
let merged = new Float32Array(ac.length + bc.length);
merged.set(ac);
merged.set(bc, ac.length);
return merged;
}),
sampleRate: a2.sampleRate
};
}
// node_modules/encode-audio/audio-encode.js
var EMPTY2 = new Uint8Array(0);
var encode = {};
var audio_encode_default = encode;
function reg2(name, load) {
encode[name] = fmt2(async (opts) => {
let init2 = (await load()).default;
let codec = await init2(opts);
return streamEncoder((ch) => codec.encode(ch), () => codec.flush(), () => codec.free());
});
}
reg2("wav", () => import("@audio/encode-wav"));
reg2("aiff", () => import("@audio/encode-aiff"));
reg2("mp3", () => import("@audio/encode-mp3"));
reg2("ogg", () => import("@audio/encode-ogg"));
reg2("flac", () => import("@audio/encode-flac"));
reg2("opus", () => import("@audio/encode-opus"));
function fmt2(init2) {
let fn3 = async (data, opts) => {
if (!opts) return init2(data);
if (!opts.sampleRate) throw Error("sampleRate is required");
let ch = channels(data);
if (!ch.length || !ch[0].length) return EMPTY2;
let enc = await init2({ channels: ch.length, ...opts });
try {
let result = await enc(ch);
let flushed = await enc();
return merge2(result, flushed);
} catch (e) {
enc.free();
throw e;
}
};
fn3.stream = init2;
return fn3;
}
function channels(data) {
if (!data) return [];
if (Array.isArray(data)) {
if (data[0] instanceof Float32Array) return data;
return [];
}
if (data instanceof Float32Array) return [data];
if (data.getChannelData && data.numberOfChannels) {
let ch = [];
for (let i = 0; i < data.numberOfChannels; i++) ch.push(data.getChannelData(i));
return ch;
}
return [];
}
function streamEncoder(onEncode, onFlush, onFree) {
let done = false;
let fn3 = async (data) => {
if (data) {
if (done) throw Error("Encoder already freed");
let ch = channels(data);
try {
return norm2(await onEncode(ch));
} catch (e) {
done = true;
onFree?.();
throw e;
}
}
if (done) return EMPTY2;
done = true;
try {
let result = onFlush ? norm2(await onFlush()) : EMPTY2;
onFree?.();
return result;
} catch (e) {
onFree?.();
throw e;
}
};
fn3.encode = fn3;
fn3.flush = async () => {
if (done) return EMPTY2;
return onFlush ? norm2(await onFlush()) : EMPTY2;
};
fn3.free = () => {
if (done) return;
done = true;
onFree?.();
};
return fn3;
}
function norm2(r) {
if (!r?.length) return EMPTY2;
if (r instanceof Uint8Array) return r;
if (r.buffer) return new Uint8Array(r.buffer, r.byteOffset, r.byteLength);
return new Uint8Array(r);
}
function merge2(a2, b) {
if (!b?.length) return a2 || EMPTY2;
if (!a2?.length) return b || EMPTY2;
let out = new Uint8Array(a2.length + b.length);
out.set(a2);
out.set(b, a2.length);
return out;
}
// node_modules/pcm-convert/index.js
var sampleRate = [8e3, 11025, 16e3, 22050, 44100, 48e3, 88200, 96e3, 176400, 192e3, 352800, 384e3];
var _AudioBuffer = typeof AudioBuffer !== "undefined" ? AudioBuffer : null;
try {
_AudioBuffer ??= (await import("audio-buffer")).default;
} catch {
}
var RATE_SET = new Set(sampleRate);
var DTYPE = {
float32: { C: Float32Array, min: -1, max: 1 },
float64: { C: Float64Array, min: -1, max: 1 },
uint8: { C: Uint8Array, min: 0, max: 255 },
uint16: { C: Uint16Array, min: 0, max: 65535 },
uint32: { C: Uint32Array, min: 0, max: 4294967295 },
int8: { C: Int8Array, min: -128, max: 127 },
int16: { C: Int16Array, min: -32768, max: 32767 },
int32: { C: Int32Array, min: -2147483648, max: 2147483647 }
};
var dtype = (d2) => DTYPE[d2] && d2 || DTYPE[d2 + "32"] && d2 + "32";
var CONTAINER = { array: 1, arraybuffer: 1, buffer: 1, audiobuffer: 1 };
var CHANNELS = { mono: 1, stereo: 2, "2.1": 3, quad: 4, "5.1": 6 };
for (let i = 3; i <= 32; i++) CHANNELS[i + "-channel"] ||= i;
var CHANNEL_NAME = {};
for (let k in CHANNELS) CHANNEL_NAME[CHANNELS[k]] ||= k;
var isTyped = (v) => ArrayBuffer.isView(v) && !(v instanceof DataView);
var isPlanar = (v) => Array.isArray(v) && v.length > 0 && isTyped(v[0]);
var isContainer = (v) => v != null && typeof v !== "string" && !isPlanar(v) && (Array.isArray(v) || isTyped(v) || v instanceof ArrayBuffer);
var isAudioBuffer = (v) => v != null && typeof v.getChannelData === "function" && typeof v.numberOfChannels === "number";
function parse(fmt3) {
if (!fmt3) return {};
if (typeof fmt3 !== "string") {
let r2 = {};
let d2 = fmt3.dtype || fmt3.type;
if (dtype(d2)) r2.dtype = dtype(d2);
if (d2 && CONTAINER[d2]) r2.container = d2;
if (fmt3.channels != null) r2.channels = CHANNELS[fmt3.channels] || +fmt3.channels;
if (fmt3.numberOfChannels != null) r2.channels ??= fmt3.numberOfChannels;
if (fmt3.interleaved != null) r2.interleaved = fmt3.interleaved;
if (fmt3.endianness) r2.endianness = fmt3.endianness;
if (fmt3.sampleRate != null) r2.sampleRate = fmt3.sampleRate;
if (fmt3.rate != null) r2.sampleRate ??= fmt3.rate;
if (fmt3.container) r2.container = fmt3.container;
return r2;
}
let r = {};
for (let t of fmt3.split(/\s*[,;_]\s*|\s+/)) {
let lo = t.toLowerCase();
if (dtype(lo)) r.dtype = dtype(lo);
else if (CONTAINER[lo]) r.container = lo;
else if (CHANNELS[lo]) r.channels = CHANNELS[lo];
else if (lo === "interleaved") r.interleaved = true;
else if (lo === "planar") r.interleaved = false;
else if (lo === "le") r.endianness = "le";
else if (lo === "be") r.endianness = "be";
else if (/^\d+$/.test(lo) && RATE_SET.has(+lo)) r.sampleRate = +lo;
else throw Error("Unknown format token: " + t);
}
return r;
}
function detect(data) {
if (data == null) return {};
if (isAudioBuffer(data))
return { dtype: "float32", channels: data.numberOfChannels, interleaved: false, sampleRate: data.sampleRate };
if (typeof Buffer !== "undefined" && Buffer.isBuffer(data)) return { dtype: "uint8", container: "buffer" };
if (data instanceof Float32Array) return { dtype: "float32" };
if (data instanceof Float64Array) return { dtype: "float64" };
if (data instanceof Int8Array) return { dtype: "int8" };
if (data instanceof Int16Array) return { dtype: "int16" };
if (data instanceof Int32Array) return { dtype: "int32" };
if (data instanceof Uint8Array) return { dtype: "uint8" };
if (data instanceof Uint8ClampedArray) return { dtype: "uint8" };
if (data instanceof Uint16Array) return { dtype: "uint16" };
if (data instanceof Uint32Array) return { dtype: "uint32" };
if (data instanceof ArrayBuffer) return { container: "arraybuffer" };
if (Array.isArray(data)) {
if (isPlanar(data))
return { ...detect(data[0]), channels: data.length, interleaved: false };
return { container: "array" };
}
return {};
}
function range(d2) {
return DTYPE[d2] || { min: -1, max: 1 };
}
function convert(src, from, to, dst) {
if (!src) throw Error("Source data required");
if (from == null) throw Error("Format required");
let srcInfo = detect(src);
if (to === void 0 && dst === void 0) {
if (isContainer(from)) {
dst = from;
to = detect(dst);
from = srcInfo;
} else {
to = parse(from);
from = srcInfo;
}
} else if (dst === void 0) {
if (isContainer(to)) {
dst = to;
to = parse(from);
from = srcInfo;
} else {
from = { ...srcInfo, ...parse(from) };
to = parse(to);
}
} else {
from = { ...srcInfo, ...parse(from) };
to = { ...dst ? detect(dst) : {}, ...parse(to) };
}
if (to.container === "audiobuffer") to.dtype = "float32";
if (!to.dtype) to.dtype = from.dtype;
if (to.channels == null && from.channels != null) to.channels = from.channels;
if (to.interleaved != null && from.interleaved == null) {
from.interleaved = !to.interleaved;
if (!from.channels) from.channels = 2;
}
if (from.interleaved != null && !from.channels) from.channels = 2;
let fromR = from.container === "array" ? { min: -1, max: 1 } : range(from.dtype);
let toR = to.container === "array" ? { min: -1, max: 1 } : range(to.dtype);
let samples;
if (isPlanar(src)) {
let ch2 = src.length, len2 = src[0].length;
samples = new src[0].constructor(len2 * ch2);
for (let c = 0; c < ch2; c++) samples.set(src[c], len2 * c);
} else if (isAudioBuffer(src)) {
let nc = src.numberOfChannels, len2 = src.length;
samples = new Float32Array(len2 * nc);
for (let c = 0; c < nc; c++) samples.set(src.getChannelData(c), len2 * c);
} else if (src instanceof ArrayBuffer) {
samples = new (DTYPE[from.dtype]?.C || Uint8Array)(src);
} else if (typeof Buffer !== "undefined" && Buffer.isBuffer(src)) {
samples = new (DTYPE[from.dtype]?.C || Uint8Array)(
src.buffer.slice(src.byteOffset, src.byteOffset + src.byteLength)
);
} else {
samples = src;
}
let len = samples.length;
let needsMap = fromR.min !== toR.min || fromR.max !== toR.max;
let reinterleave = from.interleaved != null && to.interleaved != null && from.interleaved !== to.interleaved;
let ch = from.channels || 1, seg2 = Math.floor(len / ch);
let Ctor = DTYPE[to.dtype]?.C || Float32Array;
let out;
if (!needsMap && !reinterleave) {
out = to.container === "array" ? Array.from(samples) : new Ctor(samples);
} else {
out = to.container === "array" ? new Array(len) : new Ctor(len);
let fromSpan = fromR.max - fromR.min;
let toIsInt = toR.max > 1;
let toSpan = fromR.min === -1 && fromR.max === 1 && toIsInt ? toR.max - toR.min + 1 : toR.max - toR.min;
let roundInt = fromR.min === -1 && fromR.max === 1 && toIsInt;
if (!reinterleave) {
for (let i = 0; i < len; i++) {
let v = (samples[i] - fromR.min) / fromSpan * toSpan + toR.min;
if (roundInt) v = Math.round(v);
out[i] = v < toR.min ? toR.min : v > toR.max ? toR.max : v;
}
} else {
let deint = from.interleaved;
for (let i = 0; i < len; i++) {
let si = deint ? i % seg2 * ch + ~~(i / seg2) : i % ch * seg2 + ~~(i / ch);
let v = samples[si];
if (needsMap) {
v = (v - fromR.min) / fromSpan * toSpan + toR.min;
if (roundInt) v = Math.round(v);
if (v < toR.min) v = toR.min;
else if (v > toR.max) v = toR.max;
}
out[i] = v;
}
}
}
if (dst) {
if (Array.isArray(dst)) {
for (let i = 0; i < len; i++) dst[i] = out[i];
out = dst;
} else if (dst instanceof ArrayBuffer) {
let tc = new (DTYPE[to.dtype]?.C || Uint8Array)(dst);
tc.set(out);
out = tc;
} else {
dst.set(out);
out = dst;
}
}
let info = DTYPE[to.dtype];
if (info && info.C.BYTES_PER_ELEMENT > 1 && from.endianness && to.endianness && from.endianness !== to.endianness && out.buffer) {
let le = to.endianness === "le";
let view = new DataView(out.buffer);
let step = info.C.BYTES_PER_ELEMENT;
let fn3 = "set" + to.dtype[0].toUpperCase() + to.dtype.slice(1);
for (let i = 0; i < len; i++) view[fn3](i * step, out[i], le);
}
if (to.container === "audiobuffer") {
let ABCtor = typeof AudioBuffer !== "undefined" ? AudioBuffer : _AudioBuffer;
if (!ABCtor) throw Error("AudioBuffer not available. In Node.js: install audio-buffer package or set globalThis.AudioBuffer");
let ch2 = to.channels || 1, segLen = Math.floor(out.length / ch2);
let sr = to.sampleRate || from.sampleRate || 44100;
let ab = new ABCtor({ length: segLen, numberOfChannels: ch2, sampleRate: sr });
let interleaved = reinterleave ? to.interleaved : from.interleaved ?? false;
if (interleaved && ch2 > 1) {
for (let c = 0; c < ch2; c++) {
let data = new Float32Array(segLen);
for (let i = 0; i < segLen; i++) data[i] = out[i * ch2 + c];
ab.copyToChannel(data, c);
}
} else {
for (let c = 0; c < ch2; c++) ab.copyToChannel(out.subarray(c * segLen, (c + 1) * segLen), c);
}
return ab;
}
if (to.container === "arraybuffer" || to.container === "buffer") return out.buffer || out;
return out;
}
// node_modules/parse-duration/locale/en.js
var unit = /* @__PURE__ */ Object.create(null);
var m = 6e4;
var h = m * 60;
var d = h * 24;
var y = d * 365.25;
unit.year = unit.yr = unit.y = y;
unit.month = unit.mo = unit.mth = y / 12;
unit.week = unit.wk = unit.w = d * 7;
unit.day = unit.d = d;
unit.hour = unit.hr = unit.h = h;
unit.minute = unit.min = unit.m = m;
unit.second = unit.sec = unit.s = 1e3;
unit.millisecond = unit.millisec = unit.ms = 1;
unit.microsecond = unit.microsec = unit.us = unit.\u00B5s = 1e-3;
unit.nanosecond = unit.nanosec = unit.ns = 1e-6;
unit.group = ",";
unit.decimal = ".";
unit.placeholder = " _";
var en_default = unit;
// node_modules/parse-duration/index.js
var durationRE = /((?:\d{1,16}(?:\.\d{1,16})?|\.\d{1,16})(?:[eE][-+]?\d{1,4})?)\s?([\p{L}]{0,14})/gu;
parse2.unit = en_default;
function parse2(str = "", format = "ms") {
let result = null, prevUnits;
String(str).replace(new RegExp(`(\\d)[${parse2.unit.placeholder}${parse2.unit.group}](\\d)`, "g"), "$1$2").replace(parse2.unit.decimal, ".").replace(durationRE, (_, n, units) => {
if (!units) {
if (prevUnits) {
for (const u in parse2.unit) if (parse2.unit[u] < prevUnits) {
units = u;
break;
}
} else units = format;
} else units = units.toLowerCase();
prevUnits = units = parse2.unit[units] || parse2.unit[units.replace(/s$/, "")];
if (units) result = (result || 0) + n * units;
});
return result && result / (parse2.unit[format] || 1) * (str[0] === "-" ? -1 : 1);
}
// core.js
audio.version = "2.2.0";
function parseTime(v) {
if (v == null) return v;
if (typeof v === "number") {
if (!Number.isFinite(v)) throw new Error(`Invalid time: ${v}`);
return v;
}
let tc = v.match(/^(\d+):(\d{1,2})(?::(\d{1,2}))?(?:\.(\d+))?$/);
if (tc) {
let [, a2, b, c, frac] = tc;
let s2 = c != null ? +a2 * 3600 + +b * 60 + +c : +a2 * 60 + +b;
if (frac) s2 += +("0." + frac);
return s2;
}
let s = parse2(v, "s");
if (s != null && isFinite(s)) return s;
throw new Error(`Invalid time: ${v}`);
}
function audio(source, opts = {}) {
if (source == null) {
let sr = opts.sampleRate || 44100, ch = opts.channels || 1;
let waiters2 = [];
let notify2 = () => {
for (let w of waiters2.splice(0)) w();
};
let a3 = create([], sr, ch, 0, opts, null);
a3.decoded = false;
a3.recording = false;
a3._.acc = pageAccumulator({ pages: a3.pages, notify: notify2, ondata: (...args) => emit(a3, "data", ...args) });
a3._.waiters = waiters2;
return a3;
}
if (source && typeof source === "object" && !Array.isArray(source) && source.edits) {
if (!source.source) throw new TypeError("audio: cannot restore document without source reference");
let a3 = audio(source.source, opts);
if (a3.run) for (let e of source.edits) a3.run(e);
return a3;
}
if (Array.isArray(source) && source.length && !(source[0] instanceof Float32Array)) {
let instances = source.map((s) => s?.pages ? s : audio(s, opts));
let first = instances[0].clip ? instances[0].clip() : audio.from(instances[0]);
if (!first.insert) throw new Error('audio([...]): concat requires insert plugin \u2014 import "audio" instead of "audio/core.js"');
for (let i = 1; i < instances.length; i++) first.insert(instances[i]);
let loading = instances.filter((s) => !s.decoded);
if (loading.length) {
first.ready = Promise.all(loading.map((s) => s.ready)).then(() => {
delete first.then;
delete first.catch;
return true;
});
first.ready.catch(() => {
});
makeThenable(first);
}
return first;
}
if (source?.getChannelData && source?.numberOfChannels) return audio.from(source, opts);
if (Array.isArray(source) && source[0] instanceof Float32Array || typeof source === "number") {
let a3 = audio.from(source, opts);
if (audio.evict && a3.cache && a3.budget !== Infinity) {
a3.ready = audio.evict(a3).then(() => {
delete a3.then;
delete a3.catch;
return true;
});
a3.ready.catch(() => {
});
makeThenable(a3);
}
return a3;
}
let ref = typeof source === "string" ? source : source instanceof URL ? source.href : null;
let pages = [], waiters = [];
let notify = () => {
for (let w of waiters.splice(0)) w();
};
let a2 = create(pages, 0, 0, 0, { ...opts, source: ref }, null);
a2._.waiters = waiters;
a2.decoded = false;
let readyResolve, readyReject;
a2._.ready = new Promise((r, j) => {
readyResolve = r;
readyReject = j;
});
a2._.ready.catch(() => {
});
a2.ready = (async () => {
try {
if (opts.storage === "persistent") {
if (!audio.opfsCache) throw new Error('Persistent storage requires cache module (import "./cache.js")');
try {
opts = { ...opts, cache: await audio.opfsCache(), budget: opts.budget ?? audio.DEFAULT_BUDGET ?? Infinity };
} catch {
throw new Error('OPFS not available (required by storage: "persistent")');
}
a2.cache = opts.cache;
a2.budget = opts.budget;
}
let result = await decodeSource(source, { pages, notify, ondata: (...args) => emit(a2, "data", ...args) });
a2.sampleRate = result.sampleRate;
a2._.ch = result.channels;
a2._.chV = -1;
if (result.acc) a2._.acc = result.acc;
if (result.estDuration) a2._.estDur = result.estDuration;
emit(a2, "metadata", { sampleRate: result.sampleRate, channels: result.channels, estDuration: result.estDuration });
readyResolve();
let final = await result.decoding;
a2._.len = final.length;
a2._.lenV = -1;
a2.stats = final.stats;
a2.decoded = true;
notify();
audio.evict?.(a2);
delete a2.then;
delete a2.catch;
return true;
} catch (e) {
readyReject(e);
throw e;
}
})();
a2.ready.catch(() => {
});
makeThenable(a2);
return a2;
}
function makeThenable(a2) {
a2.then = function(resolve, reject) {
return a2.ready.then(() => {
delete a2.then;
delete a2.catch;
return a2;
}).then(resolve, reject);
};
a2.catch = function(reject) {
return a2.then(null, reject);
};
}
audio.from = function(source, opts = {}) {
if (Array.isArray(source) && source[0] instanceof Float32Array) return fromChannels(source, opts);
if (typeof source === "number") return fromSilence(source, opts);
if (typeof source === "function") return fromFunction(source, opts);
if (source?.pages) {
return create(
source.pages,
opts.sampleRate ?? source.sampleRate,
opts.channels ?? source._.ch,
source._.len,
{ source: source.source, storage: source.storage, cache: source.cache, budget: opts.budget ?? source.budget },
source.stats
);
}
if (source?.getChannelData) {
let chs = Array.from({ length: source.numberOfChannels }, (_, i) => new Float32Array(source.getChannelData(i)));
return fromChannels(chs, { sampleRate: source.sampleRate, ...opts });
}
if (ArrayBuffer.isView(source) && opts.format) {
let fmt3 = parse(opts.format);
let ch = fmt3.channels || opts.channels || 1;
let sr = fmt3.sampleRate || opts.sampleRate || 44100;
let src = { ...fmt3, channels: ch };
if (ch > 1 && src.interleaved == null) src.interleaved = true;
let pcm = convert(source, src, { dtype: "float32", interleaved: false, channels: ch });
let perCh = pcm.length / ch;
let chs = Array.from({ length: ch }, (_, c) => pcm.subarray(c * perCh, (c + 1) * perCh));
return fromChannels(chs, { sampleRate: sr });
}
throw new TypeError("audio.from: expected Float32Array[], AudioBuffer, audio instance, function, or number");
};
var fn = {};
audio.fn = fn;
audio.BLOCK_SIZE = 1024;
audio.PAGE_SIZE = 1024 * audio.BLOCK_SIZE;
var LOAD = /* @__PURE__ */ Symbol("load");
var READ = /* @__PURE__ */ Symbol("read");
function emit(a2, event, ...args) {
let arr = a2._.ev[event];
if (arr) for (let cb of arr) cb(...args);
}
fn.on = function(event, cb) {
(this._.ev[event] ??= []).push(cb);
return this;
};
fn.off = function(event, cb) {
if (!event) {
this._.ev = {};
return this;
}
if (!cb) {
delete this._.ev[event];
return this;
}
let arr = this._.ev[event];
if (arr) {
let i = arr.indexOf(cb);
if (i >= 0) arr.splice(i, 1);
}
return this;
};
fn.dispose = function() {
this.stop();
this._.ev = {};
this._.pcm = null;
this._.plan = null;
this.pages.length = 0;
this.stats = null;
this._.waiters = null;
this._.acc = null;
};
if (Symbol.dispose) fn[Symbol.dispose] = fn.dispose;
audio.use = function(...plugins) {
for (let p of plugins) p(audio);
};
function create(pages, sampleRate2, ch, length, opts = {}, stats) {
let a2 = Object.create(fn);
a2.pages = pages;
a2.sampleRate = sampleRate2;
a2.source = opts.source ?? null;
a2.storage = opts.storage || "memory";
a2.cache = opts.cache || null;
a2.budget = opts.budget ?? Infinity;
a2.stats = stats;
a2.decoded = true;
a2.ready = Promise.resolve(true);
a2._ = {
ch,
// source channel count
len: length,
// source sample length
waiters: null,
// decode notify queue (null when not streaming)
ev: {},
// instance event listeners
ct: 0,
ctStamp: 0,
// currentTime wall-clock interpolation
vol: 1,
muted: false,
// volume 0..1 linear with change events
rate: 1
// playbackRate
};
a2.edits = [];
a2.version = 0;
a2._.pcm = null;
a2._.pcmV = -1;
a2._.plan = null;
a2._.planV = -1;
a2._.statsV = -1;
a2._.lenC = a2._.len;
a2._.lenV = 0;
a2._.chC = a2._.ch;
a2._.chV = 0;
Object.defineProperties(a2, {
currentTime: {
get() {
if (this.playing && !this.paused) {
let t = this._.ct + (performance.now() - this._.ctStamp) / 1e3 * (this._.rate || 1);
let d2 = this.duration;
return d2 > 0 ? Math.min(t, d2) : t;
}
return this._.ct;
},
set(v) {
this._.ct = v;
this._.ctStamp = performance.now();
},
enumerable: true,
configurable: true
},
volume: {
get() {
return this._.vol;
},
set(v) {
v = Math.max(0, Math.min(1, +v || 0));
if (this._.vol !== v) {
this._.vol = v;
emit(this, "volumechange");
}
},
enumerable: true,
configurable: true
},
muted: {
get() {
return this._.muted;
},
set(v) {
v = !!v;
if (this._.muted !== v) {
this._.muted = v;
emit(this, "volumechange");
}
},
enumerable: true,
configurable: true
},
playbackRate: {
get() {
return this._.rate;
},
set(v) {
v = Math.max(0.0625, Math.min(16, +v || 1));
if (this._.rate !== v) {
this._.rate = v;
emit(this, "ratechange");
}
},
enumerable: true,
configurable: true
}
});
a2.playing = false;
a2.paused = false;
a2.ended = false;
a2.seeking = false;
a2.loop = false;
a2.block = null;
a2._.lru = /* @__PURE__ */ new Set();
return a2;
}
function fromChannels(channelData, opts = {}) {
let sr = opts.sampleRate || 44100;
return create(paginate(channelData), sr, channelData.length, channelData[0].length, opts, audio.statSession?.(sr).page(channelData).done());
}
function fromSilence(seconds, opts = {}) {
let sr = opts.sampleRate || 44100, ch = opts.channels || 1;
return fromChannels(Array.from({ length: ch }, () => new Float32Array(Math.round(seconds * sr))), { ...opts, sampleRate: sr });
}
function fromFunction(fn3, opts = {}) {
let sr = opts.sampleRate || 44100, ch = opts.channels || 1;
let dur = opts.duration;
if (dur == null) throw new TypeError("audio.from(fn): duration required");
let len = Math.round(dur * sr);
let chs = Array.from({ length: ch }, () => new Float32Array(len));
for (let i = 0; i < len; i++) {
let v = fn3(i / sr, i);
if (typeof v === "number") for (let c = 0; c < ch; c++) chs[c][i] = v;
else for (let c = 0; c < ch; c++) chs[c][i] = v[c] ?? 0;
}
return fromChannels(chs, { sampleRate: sr });
}
Object.defineProperties(fn, {
length: { get() {
return this._.len;
}, configurable: true },
duration: { get() {
return this.length / this.sampleRate;
}, configurable: true },
channels: { get() {
return this._.ch;
}, configurable: true }
});
fn[LOAD] = async function() {
if (this._.ready) await this._.ready;
this._.acc?.drain();
};
fn[READ] = function(offset, duration) {
return readPages(this, offset, duration);
};
fn.push = function(data, fmt3) {
let acc = this._.acc;
if (!acc) throw new Error("push: instance is not pushable \u2014 create with audio()");
let ch = this._.ch, sr = this.sampleRate;
let chData;
if (Array.isArray(data) && data[0] instanceof Float32Array) chData = data;
else if (data instanceof Float32Array) chData = [data];
else if (ArrayBuffer.isView(data)) {
let f = fmt3 || {};
let srcFmt = typeof f === "string" ? f : f.format || "int16";
let nch = f.channels || ch;
let src = { dtype: srcFmt, channels: nch };
if (nch > 1) src.interleaved = true;
let pcm = convert(data, src, { dtype: "float32", interleaved: false, channels: nch });
let perCh = pcm.length / nch;
chData = Array.from({ length: nch }, (_, c) => pcm.subarray(c * perCh, (c + 1) * perCh));
} else throw new TypeError("push: expected Float32Array[], Float32Array, or typed array");
if (!this._.ch) {
this._.ch = chData.length;
this._.chV = -1;
} else if (chData.length !== this._.ch) throw new TypeError(`push: expected ${this._.ch} channels, got ${chData.length}`);
acc.push(chData, fmt3 && fmt3.sampleRate || sr);
this._.len = acc.length;
this._.lenV = -1;
return this;
};
fn.stop = function() {
this.playing = false;
this.paused = false;
this.seeking = false;
if (this._._wake) this._._wake();
if (this.recording) {
this.recording = false;
if (this._._mic) {
this._._mic(null);
this._._mic = null;
}
}
if (this._.acc && !this.decoded) {
this._.acc.drain();
this.decoded = true;
if (this._.waiters) for (let w of this._.waiters.splice(0)) w();
}
return this;
};
fn.record = function(opts = {}) {
if (!this._.acc) throw new Error("record: instance is not pushable \u2014 create with audio()");
if (this.recording) return this;
this.recording = true;
this.decoded = false;
let self = this, sr = this.sampleRate, ch = this._.ch;
let _rec = (async () => {
try {
let { default: mic2 } = await Promise.resolve().then(() => (init_browser(), browser_exports));
let read = mic2({ sampleRate: sr, channels: ch, bitDepth: 16, ...opts });
self._._mic = read;
read((err, buf) => {
if (!self.recording) return;
if (err || !buf) return;
self.push(new Int16Array(buf.buffer, buf.byteOffset, buf.byteLength / 2), "int16");
});
} catch (e) {
self.recording = false;
self.decoded = true;
if (self._.waiters) for (let w of self._.waiters.splice(0)) w();
throw e.code === "ERR_MODULE_NOT_FOUND" ? new Error("record: audio-mic not installed \u2014 npm i audio-mic") : e;
}
})();
_rec.catch(() => {
});
return this;
};
fn.seek = function(t) {
t = Math.max(0, t);
this.seeking = true;
this.currentTime = t;
if (this.cache) {
let page = Math.floor(t * this.sampleRate / audio.PAGE_SIZE);
(async () => {
for (let i = Math.max(0, page - 1); i <= Math.min(page + 2, this.pages.length - 1); i++)
if (this.pages[i] === null && await this.cache.has(i)) this.pages[i] = await this.cache.read(i);
})();
}
if (this.playing) {
this._._seekTo = t;
if (this._._wake) this._._wake();
} else this.seeking = false;
return this;
};
fn.read = async function(opts) {
if (typeof opts !== "object" || opts === null) opts = {};
let { at, duration, format, channel, meta } = opts;
at = parseTime(at);
duration = parseTime(duration);
await this[LOAD]();
let pcm = await this[READ](at, duration);
if (channel != null) pcm = [pcm[channel]];
if (!format) return channel != null ? pcm[0] : pcm;
let converted = audio_encode_default[format] ? await audio_encode_default[format](pcm, { sampleRate: this.sampleRate, ...meta }) : pcm.map((ch) => convert(ch, "float32", format));
return channel != null ? Array.isArray(converted) ? converted[0] : converted : converted;
};
function paginate(channelData) {
let len = channelData[0].length, pages = [];
for (let off = 0; off < len; off += audio.PAGE_SIZE)
pages.push(channelData.map((ch) => ch.subarray(off, Math.min(off + audio.PAGE_SIZE, len))));
return pages;
}
function walkPages(a2, c, srcOff, len, visitor) {
let p0 = Math.floor(srcOff / audio.PAGE_SIZE), pos = p0 * audio.PAGE_SIZE;
for (let p = p0; p < a2.pages.length && pos < srcOff + len; p++) {
let pg = a2.pages[p], pLen = pg ? pg[0].length : audio.PAGE_SIZE;
if (pos + pLen > srcOff && pg) {
let s = Math.max(srcOff - pos, 0), e = Math.min(srcOff + len - pos, pLen);
if (a2._.lru) {
a2._.lru.delete(p);
a2._.lru.add(p);
}
visitor(pg, c, s, e, Math.max(pos - srcOff, 0));
}
pos += pLen;
}
}
function copyPages(a2, c, srcOff, len, target, tOff) {
walkPages(a2, c, srcOff, len, (pg, ch, s, e, off) => target.set(pg[ch].subarray(s, e), tOff + off));
}
function readPages(a2, offset, duration) {
let sr = a2.sampleRate, ch = a2._.ch;
let s = offset != null ? Math.min(Math.max(Math.round(offset * sr), 0), a2._.len) : 0;
let len = duration != null ? Math.round(duration * sr) : a2._.len - s;
len = Math.min(Math.max(len, 0), a2._.len - s);
let out = Array.from({ length: ch }, () => new Float32Array(len));
for (let c = 0; c < ch; c++) copyPages(a2, c, s, len, out[c], 0);
return out;
}
async function resolveSource(source) {
if (source instanceof ArrayBuffer) return source;
if (source instanceof Uint8Array) return source.buffer.slice(source.byteOffset, source.byteOffset + source.byteLength);
if (source instanceof URL) return resolveSource(source.href);
if (typeof source === "string") {
if (/^(https?|data|blob):/.test(source) || typeof window !== "undefined")
return (await fetch(source)).arrayBuffer();
if (source.startsWith("file:")) {
let { fileURLToPath } = await import("url");
source = fileURLToPath(source);
}
let { readFile } = await import("fs/promises");
let buf = await readFile(source);
return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
}
throw new TypeError("audio: unsupported source type");
}
async function detectSource(source) {
if (source instanceof ArrayBuffer || source instanceof Uint8Array) {
let bytes2 = source instanceof ArrayBuffer ? new Uint8Array(source) : source.byteOffset || source.byteLength !== source.buffer.byteLength ? new Uint8Array(source.buffer.slice(source.byteOffset, source.byteOffset + source.byteLength)) : new Uint8Array(source.buffer);
return { format: audioType(bytes2), bytes: bytes2 };
}
if (typeof source === "string" && !/^(https?|data|blob):/.test(source) && typeof window === "undefined") {
let path = source;
if (source.startsWith("file:")) {
let { fileURLToPath } = await import("url");
path = fileURLToPath(source);
}
let { open, stat } = await import("fs/promises");
let fh = await open(path, "r");
let hdr = new Uint8Array(12);
await fh.read(hdr, 0, 12, 0);
await fh.close();
let format = audioType(new Uint8Array(hdr));
let fileSize = (await stat(path)).size;
let { createReadStream } = await import("fs");
return { format, reader: createReadStream(path), fileSize };
}
let buf = await resolveSource(source);
let bytes = new Uint8Array(buf);
return { format: audioType(bytes), bytes };
}
function pageAccumulator(opts = {}) {
let { pages = [], notify, ondata } = opts;
let sr = 0, ch = 0, totalLen = 0, pagePos = 0;
let pageBuf = null, session;
function emit2(page) {
pages.push(page);
totalLen += page[0].length;
notify?.();
}
return {
pages,
get sampleRate() {
return sr;
},
get channels() {
return ch;
},
get length() {
return totalLen + pagePos;
},
get partial() {
return pagePos > 0 ? pageBuf.map((c) => c.subarray(0, pagePos)) : null;
},
get partialLen() {
return pagePos;
},
push(chData, sampleRate2) {
if (!pageBuf) {
sr = sampleRate2;
ch = chData.length;
pageBuf = Array.from({ length: ch }, () => new Float32Array(audio.PAGE_SIZE));
session = audio.statSession?.(sr);
}
session?.page(chData);
let srcPos = 0, chunkLen = chData[0].length;
while (srcPos < chunkLen) {
let n = Math.min(chunkLen - srcPos, audio.PAGE_SIZE - pagePos);
for (let c = 0; c < ch; c++) pageBuf[c].set(chData[c].subarray(srcPos, srcPos + n), pagePos);
srcPos += n;
pagePos += n;
if (pagePos === audio.PAGE_SIZE) {
emit2(pageBuf);
pageBuf = Array.from({ length: ch }, () => new Float32Array(audio.PAGE_SIZE));
pagePos = 0;
}
}
if (ondata) {
let delta = session?.delta();
if (delta) ondata({ delta, offset: (totalLen + pagePos) / sr, sampleRate: sr, channels: ch, pages });
}
notify?.();
},
/** Flush partial page into pages array. Non-destructive — accumulator stays open. */
drain() {
if (pagePos > 0) {
emit2(pageBuf.map((c) => c.slice(0, pagePos)));
pageBuf = Array.from({ length: ch }, () => new Float32Array(audio.PAGE_SIZE));
pagePos = 0;
}
},
done() {
if (pagePos > 0) emit2(pageBuf.map((c) => c.slice(0, pagePos)));
session?.flush();
if (ondata && session) {
let delta = session.delta();
if (delta) ondata({ delta, offset: totalLen / sr, sampleRate: sr, channels: ch, pages });
}
return { stats: session?.done(), length: totalLen };
}
};
}
function estimateDuration(fileSize, format, sampleRate2, channels2) {
if (!fileSize || !sampleRate2 || !channels2) return null;
if (format === "wav") return Math.max(0, (fileSize - 44) / (sampleRate2 * channels2 * 2));
if (format === "flac") return fileSize / (sampleRate2 * channels2 * 0.7);
if (format === "mp3") return fileSize / (128e3 / 8);
if (format === "ogg" || format === "opus") return fileSize / (96e3 / 8);
return null;
}
async function decodeSource(source, opts = {}) {
let { format, bytes, reader, fileSize } = await detectSource(source);
if (!format || !decode[format]) {
if (!bytes) bytes = new Uint8Array(await resolveSource(source));
let { channelData, sampleRate: sampleRate2 } = await decode(bytes.buffer || bytes);
let pages = opts.pages || [];
let ps = paginate(channelData);
for (let p of ps) {
pages.push(p);
opts.notify?.();
}
let stats = audio.statSession?.(sampleRate2)?.page(channelData)?.done() ?? null;
return { pages, sampleRate: sampleRate2, channels: channelData.length, decoding: Promise.resolve({ stats, length: channelData[0].length }) };
}
let dec = await decode[format]();
let yieldLoop = () => new Promise((r) => setTimeout(r, 0));
let firstResolve;
let origNotify = opts.notify;
let firstReady = new Promise((r) => {
firstResolve = r;
});
let acc = pageAccumulator({
pages: opts.pages,
ondata: opts.ondata,
notify: () => {
origNotify?.();
if (firstResolve) {
let f = firstResolve;
firstResolve = null;
f();
}
}
});
let decoding = (async () => {
try {
if (reader) {
for await (let chunk of reader) {
let buf = chunk instanceof Uint8Array ? chunk : new Uint8Array(chunk);
let r = await dec(buf);
if (r.channelData.length) acc.push(r.channelData, r.sampleRate);
await yieldLoop();
}
} else {
let FEED = 64 * 1024;
for (let off = 0; off < bytes.length; off += FEED) {
let r = await dec(bytes.subarray(off, Math.min(off + FEED, bytes.length)));
if (r.channelData.length) acc.push(r.channelData, r.sampleRate);
await yieldLoop();
}
}
let flushed = await dec();
if (flushed.channelData.length) acc.push(flushed.channelData, flushed.sampleRate);
let final = acc.done();
return final;
} catch (e) {
if (firstResolve) {
let f = firstResolve;
firstResolve = null;
f();
}
;
throw e;
}
})();
await firstReady;
if (!acc.sampleRate) throw new Error("audio: decoded no audio data");
let estDuration = estimateDuration(fileSize || bytes?.length, format, acc.sampleRate, acc.channels);
return { pages: acc.pages, sampleRate: acc.sampleRate, channels: acc.channels, decoding, acc, estDuration };
}
// plan.js
var fn2 = audio.fn;
var ops = {};
function seg(src, count, dst, rate, ref) {
let s = [src, count, dst];
if (rate != null && rate !== 1) s[3] = rate;
if (ref !== void 0) s[4] = ref;
return s;
}
function planOff