package net.heartshield.data;

/**
 * Helper to write PCM data to WAV file format.
 *
 * @author David Madl (git@abanbytes.eu)
 * @date 2017-05-04
 */
public class WavData {
    int channels;
    int bitsPerSample;
    int sampleRate;
    int samples;

    public WavData(int bodySizeBytes, int sampleRate, int channels, int bitsPerSample) {
        int blockAlign = ((channels * bitsPerSample) / 8);
        this.samples = bodySizeBytes / blockAlign;
        this.sampleRate = sampleRate;
        this.channels = channels;
        this.bitsPerSample = bitsPerSample;
    }

    /** WAV file header size in bytes */
    public static final int HEADER_SIZE = 44;

    public byte[] waveHeader() {
        // data format docs: see e.g. http://soundfile.sapp.org/doc/WaveFormat/
        byte[] header = new byte[HEADER_SIZE];

        int blockAlign = ((channels * bitsPerSample) / 8);
        int byteRate = sampleRate * channels * bitsPerSample / 8;

        int subchunk2Size = samples * channels * bitsPerSample / 8;
        int chunkSize = 36 + subchunk2Size;

        header[0] = 'R';  // RIFF/WAVE header
        header[1] = 'I';
        header[2] = 'F';
        header[3] = 'F';
        header[4] = (byte) (chunkSize & 0xff);
        header[5] = (byte) ((chunkSize >> 8) & 0xff);
        header[6] = (byte) ((chunkSize >> 16) & 0xff);
        header[7] = (byte) ((chunkSize >> 24) & 0xff);
        header[8] = 'W';
        header[9] = 'A';
        header[10] = 'V';
        header[11] = 'E';
        header[12] = 'f';  // 'fmt ' chunk
        header[13] = 'm';
        header[14] = 't';
        header[15] = ' ';
        header[16] = 16;  // 4 bytes: size of 'fmt ' chunk
        header[17] = 0;
        header[18] = 0;
        header[19] = 0;
        header[20] = 1;  // format = 1
        header[21] = 0;
        header[22] = (byte) (channels & 0xff);
        header[23] = (byte) ((channels >> 8) & 0xff);
        header[24] = (byte) (sampleRate & 0xff);
        header[25] = (byte) ((sampleRate >> 8) & 0xff);
        header[26] = (byte) ((sampleRate >> 16) & 0xff);
        header[27] = (byte) ((sampleRate >> 24) & 0xff);
        header[28] = (byte) (byteRate & 0xff);
        header[29] = (byte) ((byteRate >> 8) & 0xff);
        header[30] = (byte) ((byteRate >> 16) & 0xff);
        header[31] = (byte) ((byteRate >> 24) & 0xff);
        header[32] = (byte) blockAlign;
        header[33] = 0;
        header[34] = (byte) bitsPerSample;
        header[35] = 0;
        header[36] = 'd';
        header[37] = 'a';
        header[38] = 't';
        header[39] = 'a';
        header[40] = (byte) (subchunk2Size & 0xff);
        header[41] = (byte) ((subchunk2Size >> 8) & 0xff);
        header[42] = (byte) ((subchunk2Size >> 16) & 0xff);
        header[43] = (byte) ((subchunk2Size >> 24) & 0xff);

        return header;
    }
}
