Trouble encoding WAV to FLAC in web application using libflac.js

66 views Asked by At

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:

  1. Code stuck at flac.FLAC__stream_encoder_process_interleaved inside the else block for some reason.
  2. fdata is still [] after flac.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?

  1. For example, is running a FLAC bash command on the server for every request even scalabale for a realtime application with many users?
  2. Would a C, C++ or Python implementation be better for this matter?
0

There are 0 answers