I'm using AudioRecord to record an audio. What I need is to save the recorded audio as one Array/Variable in a playable format (wav). I need to use AudioRecord because parallel to getting the audio I run a speech recognizer. So MediaRecorder is no option. I actually got a working solution. The only problem is the audio is written to a file. Also my function for adding the wav header to the pcm needs a file and stores it again in a file.
What I am looking for: do all this without saving the audio to a file. In the end I would like to have the audio in an array or something similar to send this audio to Flutter and use it there.
My working solution (with saving audio to file):
private fun record() {
val sampleRate = 16000
val frameLength = 512
val bufferSize = (sampleRate / 2).coerceAtLeast(minBufferSize)
var audioRecord: AudioRecord? = null
var buffer = ShortArray(frameLength)
var bufferByte: ByteArray
var fileName = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).absolutePath + "/audio" + ".pcm"
audioRecord = AudioRecord(
MediaRecorder.AudioSource.MIC,
sampleRate,
AudioFormat.CHANNEL_IN_MONO,
AudioFormat.ENCODING_PCM_16BIT,
bufferSize)
audioRecord.startRecording()
var outputStream: FileOutputStream?
try {
outputStream = FileOutputStream(fileName)
} catch (e: FileNotFoundException) {
return
}
while (!stop.get()) {
var readBufferShortLength = audioRecord.read(buffer, 0, buffer.size)
bufferByte = getBytes(buffer)
try {
outputStream!!.write(bufferByte, 0, bufferByte.size)
// clean up file writing operations
} catch (e: IOException) {
e.printStackTrace()
}
}
outputStream.flush()
outputStream.close()
}
For the Voice Recognition it needs a ShortArray. For adding the wav header it needs ByteArray. For converting the ShortArray to ByteArray:
fun shortToByte(shortArray: ShortArray): ByteArray {
val buffer = ByteBuffer.allocate(shortArray.size * 2)
buffer.order(ByteOrder.LITTLE_ENDIAN)
buffer.asShortBuffer().put(shortArray)
val bytes = buffer.array()
return bytes
}
Converting adding wav header:
@Throws(IOException::class)
private fun rawToWave(rawFile: File, waveFile: File, sampleRate: Int) {
val rawData = ByteArray(rawFile.length().toInt())
var input: DataInputStream? = null
try {
input = DataInputStream(FileInputStream(rawFile))
input.read(rawData)
} finally {
input?.close()
}
var output: DataOutputStream? = null
try {
output = DataOutputStream(FileOutputStream(waveFile))
// WAVE header
// see http://ccrma.stanford.edu/courses/422/projects/WaveFormat/
writeString(output, "RIFF") // chunk id
writeInt(output, 36 + rawData.size) // chunk size
writeString(output, "WAVE") // format
writeString(output, "fmt ") // subchunk 1 id
writeInt(output, 16) // subchunk 1 size
writeShort(output, 1.toShort()) // audio format (1 = PCM)
writeShort(output, 1.toShort()) // number of channels
writeInt(output, sampleRate) // sample rate
writeInt(output, sampleRate * 2) // byte rate --------- Here changen maybe
writeShort(output, 2.toShort()) // block align
writeShort(output, 16.toShort()) // bits per sample
writeString(output, "data") // subchunk 2 id
writeInt(output, rawData.size) // subchunk 2 size
// Audio data (conversion big endian -> little endian)
val shorts = ShortArray(rawData.size / 2)
ByteBuffer.wrap(rawData).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(shorts)
val bytes: ByteBuffer = ByteBuffer.allocate(shorts.size * 2)
for (s in shorts) {
bytes.putShort(s)
}
output.write(fullyReadFileToBytes(rawFile))
} finally {
output?.close()
}
}
@Throws(IOException::class)
fun fullyReadFileToBytes(f: File): ByteArray? {
val size = f.length().toInt()
val bytes = ByteArray(size)
val tmpBuff = ByteArray(size)
val fis = FileInputStream(f)
try {
var read = fis.read(bytes, 0, size)
if (read < size) {
var remain = size - read
while (remain > 0) {
read = fis.read(tmpBuff, 0, remain)
System.arraycopy(tmpBuff, 0, bytes, size - remain, read)
remain -= read
}
}
} catch (e: IOException) {
throw e
} finally {
fis.close()
}
return bytes
}
@Throws(IOException::class)
private fun writeInt(output: DataOutputStream, value: Int) {
output.write(value shr 0)
output.write(value shr 8)
output.write(value shr 16)
output.write(value shr 24)
}
@Throws(IOException::class)
private fun writeShort(output: DataOutputStream, value: Short) {
var v = value.toInt()
output.write(v shr 0)
output.write(v shr 8)
}
@Throws(IOException::class)
private fun writeString(output: DataOutputStream, value: String) {
for (i in 0 until value.length) {
output.write(value[i].code) // ------ Here changen maybe
}
}
I really appreciate your support.