@omnimedia/omnitool
Version:
open source video processing tools
67 lines (53 loc) • 1.72 kB
text/typescript
import {AudioMix} from "./audio-mix.js"
import {ms} from "../../../../units/ms.js"
import {resampleToPlanar} from "./resamplers.js"
import {applyGainToPlanar} from "./audio-gain.js"
import {TimelineFile} from "../../../parts/basics.js"
import {resolveAudioGain} from "../../../parts/audio.js"
import {DecoderSource} from "../../../../driver/fns/schematic.js"
import {createAudioSampler} from "../../parts/samplers/audio/sampler.js"
export function produceAudio({
timeline,
resolveMedia
}: {
timeline: TimelineFile,
resolveMedia: (hash: string) => DecoderSource
}) {
const mixer = new AudioMix()
const audio = streamAudio(timeline, resolveMedia)
const stream = new TransformStream<AudioData, AudioData>()
const writer = stream.writable.getWriter()
async function produce() {
for await (const chunk of mixer.mix(audio)) {
const data = new AudioData({
format: 'f32-planar',
sampleRate: chunk.sampleRate,
numberOfFrames: chunk.frames,
numberOfChannels: chunk.channels,
timestamp: Math.round(
(chunk.startFrame / chunk.sampleRate) * 1_000_000
),
data: new Float32Array(chunk.planar)
})
await writer.write(data)
}
await writer.close()
}
produce()
return stream.readable
}
async function *streamAudio(timeline: TimelineFile, resolveMedia: (hash: string) => DecoderSource) {
const audioSampler = createAudioSampler(resolveMedia)
const masterGain = resolveAudioGain(timeline.audio)
for await (const {sample, timestamp, gain}
of audioSampler.sampleAudio(timeline, ms(0))) {
const {data} = resampleToPlanar(sample, 48000)
applyGainToPlanar(data, gain * masterGain)
yield {
planes: data,
sampleRate: 48000,
timestamp
}
sample.close()
}
}