javaandroidwavkotlinokio

Creating WAV file with Okio


My system needs to create a single WAV file using bytes of an array of WAV files. Currently it uses Okio to read and write the data on buffers, and then, write the data on a final file.

I'm following this document and this stack overflow question:

and...

I created this code:

fun mixAudios() {

    try {

        //Create the file used to storage the mixed audio file.
        val file = File(directory, finalFileName)

        //Open the buffer for this file.
        val bufferedSink = Okio.buffer(Okio.appendingSink(file))

        //Data header of the file.
        val header = Buffer()

        //Data of the file.
        val data = Buffer()

        //Do a action for every audio.
        audios.forEach {

            //Try to read the file, if success, return the file.
            Okio.buffer(Okio.source(File(it.address)))?.let { file ->

                //Create a new buffer for every audio address.
                val buffer = Buffer()

                //Read every byte on the buffer.
                file.readAll(buffer)

                //Remove the first 44 items of the buffer.
                buffer.readByteArray(44)

                //Get the buffer and write every byte on the sink.
                data.writeAll(buffer)

                //Close the sink.
                buffer.close()
                file.close()
            }
        }

        //Count of bytes on the data buffer.
        val fileSize = data.size().toInt()

        //The data is ready to be written on the sink.
        data.close()

        val totalFileSize = fileSize + 36
        val byteRate = (SAMPLE_RATE * CHANNELS * BYTES_PER_SAMPLE) / 8

        //Write the header of the final file.
        header.writeUtf8("RIFF")

            //Write the total file size (with the header)
            .writeByte(totalFileSize and 0xff)
            .writeByte((totalFileSize shr 8) and 0xff)
            .writeByte((totalFileSize shr 16) and 0xff)
            .writeByte((totalFileSize shr 24) and 0xff)
    //      .writeIntLe(fileSize) //Inform the size of the chunk, including the header.

            .writeUtf8("WAVE") //Inform the type of file.
            .writeUtf8("fmt ") //Add the "fmt" letters
            .writeIntLe(samplingRate) //fmt chunk

            .writeByte(AUDIO_FORMAT_PCM) //This byte represents the audio format (PCM).
            .writeByte(0)

            .writeByte(CHANNELS) //This byte represents the channels of the audio.
            .writeByte(0)

            //Write the sample rate
            .writeByte(SAMPLE_RATE and 0xff)
            .writeByte((SAMPLE_RATE shr 8) and 0xff)
            .writeByte((SAMPLE_RATE shr 16) and 0xff)
            .writeByte((SAMPLE_RATE shr 24) and 0xff)
    //      .writeIntLe(SAMPLE_RATE) //The sample rate of the audio

            //Write the byte rate
            .writeByte(byteRate and 0xff)
            .writeByte((byteRate shr 8) and 0xff)
            .writeByte((byteRate shr 16) and 0xff)
            .writeByte((byteRate shr 24) and 0xff)
    //      .writeIntLe((SAMPLE_RATE * CHANNELS * BYTES_PER_SAMPLE) / 8) //Byte rate

            .writeByte(CHANNELS * BYTES_PER_SAMPLE / 8) //Block align
            .writeByte(0)

            .writeByte(BYTES_PER_SAMPLE) //Bytes per sample
            .writeByte(0)

            .writeUtf8("data") //File content size

            .writeByte(fileSize and 0xff)
            .writeByte((fileSize shr 8) and 0xff)
            .writeByte((fileSize shr 16) and 0xff)
            .writeByte((fileSize shr 24) and 0xff)
    //      .writeIntLe(fileSize)

            .close()

        with (bufferedSink) {
            writeAll(header)
            writeAll(data)
            close() //Close and write the file on the memory.
        }

        //Do the rest...

        } catch (e: Exception) {
        if (debugEnabled) {
            e.printStackTrace()
        }
      }
    }

The file is generated with success, but when I try to open this audio on any media player, it seems corrupted.

When I try to explore the bytes of this audio file generated, the result is something like this:

bytes

I don't know if I'm writing the header correctly, can you help me to solve this problem?

Thank you!


Solution

  • Where are you getting the value for samplingRate from? You are writing 80 3E 00 00 (ie 16000) but it should actually be 10 00 00 00 (ie 16 for raw PCM format).

    At this point in the header you should write the size of the fmt chunk.

    I hope this solves your problem