I need to encode a WAV file for my web application. I have not yet decided, if the encoding/decoding process will be running in the backend or frontend. However, my main problem right now is actually implementing the encoding (and decoding) of a WAV file to FLAC format. The goal here is to significantly reduce the file size before later storing it in Firebase Storage for archive.
Sadly, there aren't many resources to learn from for beginners, nor options to choose from when it comes to npm FLAC packages other than libflac.js. Despite following the documentation I can't get the code to work.
What I've tried so far...
My approach was to get the data from a Javascript File object and encode it using code like in their GitHub tools folder, since the demo/tutorial in the docs didn't work for me either.
Problem:
- Code stuck at
flac.FLAC__stream_encoder_process_interleavedinside theelseblock for some reason. fdatais still[]afterflac.init_encoder_stream
flacEncoder.ts:
import Flac, { StreamMetadata, CompressionLevel } from 'libflacjs/dist/libflac';
// my api endpoint calls this function and passes the received WAV file to be encoded to FLAC
export async function encodeFLAC(file: File) {
const arrBuf = await file.arrayBuffer()
const buf = Buffer.from(arrBuf)
const bytes = new Int32Array(buf, buf.byteOffset, buf.byteLength / 4)
if (!Flac.isReady()) {
Flac.on('ready', (evt: Flac.ReadyEvent) => {
console.log("Flac is ready now: ", evt.target)
encode(Flac, 44100, 2, 32, 4, bytes, exportCallback, true)
})
} else {
encode(Flac, 44100, 2, 32, 4, bytes, exportCallback, true)
}
}
function encode(flac: any, sampleRate: number, channels: number, bps: number, compressionLevel: CompressionLevel, data: Int32Array, cb: (data: Uint8Array[], metadata: StreamMetadata) => void, encodeInterleaved: boolean): void {
const enc = flac.create_libflac_encoder(sampleRate, channels, bps, compressionLevel, 0, true);
const fdata: Uint8Array[] = [];
let metadata: StreamMetadata | null = null;
flac.init_encoder_stream(enc, (data: Uint8Array) => {
console.log('write data: ', data);
fdata.push(data);
}, (m?: StreamMetadata) => {
if (m) {
metadata = m;
}
});
if (!encodeInterleaved) {
// separate interleaved data into channels
const list: Int32Array[] = deinterleave(data, channels);
flac.FLAC__stream_encoder_process(enc, list, data.length / channels);
} else {
flac.FLAC__stream_encoder_process_interleaved(enc, data, data.length / channels);
}
flac.FLAC__stream_encoder_finish(enc);
flac.FLAC__stream_encoder_delete(enc);
cb(fdata, metadata as unknown as StreamMetadata);
}
function deinterleave(data: Int32Array, channels: number): Int32Array[] {
const len = data.length;
const samples = len / channels;
const list: Int32Array[] = new Array(channels).fill(null).map(() => new Int32Array(samples));
for (var i = 0; i < len; i += channels) {
for (var j = 0; j < channels; ++j) {
list[j][i / channels] = data[i + j];
}
}
return list;
}
In the process I also had to modify my next.config.json, because of some problem with webpack had loading static resources from the package.
Alternatives?
What alternatives are there to encoding/decoding the WAVs using javascript/typescript?
- For example, is running a
FLACbashcommand on the server for every request even scalabale for a realtime application with many users? - Would a
C,C++orPythonimplementation be better for this matter?