1

I have the following java class that generates WAV audio file from PCM data. I want to implement the same functionality in JavaScript or NodeJS equivalent. Is there any existing library you can recommend?

There's an existing NPM library out there called random-access-file but it is limited.

SampleAudioExport.java

 package com.example.sampleapp;

 import android.util.Log;

 import java.io.File;
 import java.io.IOException;
 import java.io.RandomAccessFile;
 import java.util.concurrent.LinkedBlockingQueue;

 public class SampleAudioExport implements Runnable {
    public final LinkedBlockingQueue<short[]> samples = new
            LinkedBlockingQueue<>();
    public String audioDir;
    private Thread thread;
    public boolean isRunning = false;
    public boolean isDone = false;
    public File wav;
    private final RandomAccessFile randomAccessWriter;
    private int payloadSize;

    public SampleAudioExport(String dir) throws IOException {
        payloadSize = 0;
        audioDir = dir;
        String fileName = "recording.wav";
        wav = new File(audioDir + "/" + fileName);

        int sRate = 44100;
        short nChannels = 2;
        int mBitsPerSample = 16;

        randomAccessWriter = new RandomAccessFile(wav.getAbsoluteFile(), "rw");
        randomAccessWriter.setLength(0); // Set file length to 0, to prevent unexpected behavior in case the file already existed
        randomAccessWriter.writeBytes("RIFF");
        randomAccessWriter.writeInt(0); // Final file size not known yet, write 0
        randomAccessWriter.writeBytes("WAVE");
        randomAccessWriter.writeBytes("fmt ");
        randomAccessWriter.writeInt(Integer.reverseBytes(mBitsPerSample)); // Sub-chunk size, 16 for PCM
        randomAccessWriter.writeShort(Short.reverseBytes((short) 1)); // AudioFormat, 1 for PCM
        randomAccessWriter.writeShort(Short.reverseBytes((short) 2));// Number of channels, 1 for mono, 2 for stereo
        randomAccessWriter.writeInt(Integer.reverseBytes(sRate)); // Sample rate
        randomAccessWriter.writeInt(Integer.reverseBytes(sRate*nChannels*mBitsPerSample/8)); // Byte rate, SampleRate*NumberOfChannels*mBitsPersample/8
        randomAccessWriter.writeShort(Short.reverseBytes((short)(nChannels*mBitsPerSample/8))); // Block align, NumberOfChannels*mBitsPersample/8
        randomAccessWriter.writeShort(Short.reverseBytes((short) mBitsPerSample)); // Bits per sample
        randomAccessWriter.writeBytes("data");
        randomAccessWriter.writeInt(0); // Data chunk size not known yet, write 0
    }

    public void start() {
        this.isRunning = true;
        this.thread = new Thread(this);
        this.thread.start();
    }

    public void stop() {
        this.isRunning = false;
    }

    public void pushAudio(short[] sample) {
        this.samples.add(sample);
    }

    @Override
    public void run() {
        try {
            Log.d("AudioExport", "RUNNING AUDIO EXPORT");
            Log.d("AudioExport", "Samples=" + this.samples.size());

            while (Thread.currentThread() == this.thread && this.samples.size() > 0) {
                short[] sample = this.samples.take();
                byte[] buffer = this.toByteArrayForAudioData(sample);
                randomAccessWriter.write(buffer);
                payloadSize += buffer.length;
            }

            randomAccessWriter.seek(4); // Write size to RIFF header
            randomAccessWriter.writeInt(Integer.reverseBytes(36 + payloadSize));
            randomAccessWriter.seek(40); // Write size to Subchunk2Size field
            randomAccessWriter.writeInt(Integer.reverseBytes(payloadSize));
            randomAccessWriter.close();

            isRunning = false;
            isDone = true;

            Log.d("Audio", "AUDIO EXPORT DONE");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public byte[] toByteArrayForAudioData(short[] shorts) {
        byte[] output = new byte[shorts.length * 2];
        for (int i = 0; i < shorts.length; i++) {
            output[i * 2] = (byte) (shorts[i] & 0xff);
            output[(i * 2) + 1] = (byte) ((shorts[i] >> 8) & 0xff);
        }
        return output;
    }
}
TheMarlinCode
  • 33
  • 1
  • 7

0 Answers0