Here we provide the code for recording unity3d sound into WAV file. The following script should be attached to audio source. We use onAudioFilterRead()
function which gets called every time audio buffer is updated. We convert the buffer to WAV raw data and write the date to the prepared beforehand WAV file.
There are two public API function of the script: StartRecording()
and FinishRecording()
. The wav file name is rec.wav
and is hardcoded. Feel free to modify the script to fit your needs.
Note for Android users
The rec.wav
is located at Application.persistentDataPath
which resolves to /storage/emulated/0/Android/data/<packagename>/files
. This folder is unreadable by external applications. To test the WAV created is not corrupted, you need to copy rec.wav
to some readable location like Download
folder from inside android using native API. This inconvience is caused by Unity3d which provides access only to application files folder and not to public folders on Android.
using System; // for BitConverter
using System.IO; // for FileStream
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class AudioRec : MonoBehaviour
{
// Sample at standard 44.1 kHz
private int outputSampleRate = 44100;
private int headerSize = 44;
private int bufferSize;
private int numBuffers;
private FileStream fileStream;
private bool recording = false;
// The function is called after writing the wav file.
// Format ref: http://soundfile.sapp.org/doc/WaveFormat/
private void WriteHeader()
{
fileStream.Seek(0, SeekOrigin.Begin);
Byte[] riff = System.Text.Encoding.UTF8.GetBytes("RIFF");
fileStream.Write(riff, 0, 4);
Byte[] chunkSize = BitConverter.GetBytes(fileStream.Length - 8);
fileStream.Write(chunkSize, 0, 4);
Byte[] wave = System.Text.Encoding.UTF8.GetBytes("WAVE");
fileStream.Write(wave, 0, 4);
Byte[] fmt = System.Text.Encoding.UTF8.GetBytes("fmt ");
fileStream.Write(fmt, 0, 4);
// 16 for PCM; size of the following subchunk
Byte[] subChunk1 = BitConverter.GetBytes(16);
fileStream.Write(subChunk1, 0, 4);
UInt16 one = 1;
// PCM = 1
Byte[] audioFormat = BitConverter.GetBytes(one);
fileStream.Write(audioFormat, 0, 2);
UInt16 two = 2;
// Stereo
Byte[] numChannels = BitConverter.GetBytes(two);
fileStream.Write(numChannels, 0, 2);
// Sample rate 44.1 kHz
Byte[] sampleRate = BitConverter.GetBytes(outputSampleRate);
fileStream.Write(sampleRate, 0, 4);
Byte[] byteRate = BitConverter.GetBytes(outputSampleRate * 4);
fileStream.Write(byteRate, 0, 4);
UInt16 four = 4;
Byte[] blockAlign = BitConverter.GetBytes(four);
fileStream.Write(blockAlign, 0, 2);
UInt16 sixteen = 16;
Byte[] bitsPerSample = BitConverter.GetBytes(sixteen);
fileStream.Write(bitsPerSample, 0, 2);
Byte[] dataString = System.Text.Encoding.UTF8.GetBytes("data");
fileStream.Write(dataString, 0, 4);
Byte[] subChunk2 = BitConverter.GetBytes(fileStream.Length - headerSize);
fileStream.Write(subChunk2, 0, 4);
fileStream.Flush();
fileStream.Close();
}
private void PrepareWriting()
{
string wavFilename = Application.persistentDataPath + "/rec.wav";
AudioSettings.GetDSPBufferSize(out bufferSize, out numBuffers);
fileStream = new FileStream(wavFilename, FileMode.Create);
byte emptyByte = new byte();
for (int i=0; i<headerSize; i++)
{
fileStream.WriteByte(emptyByte);
}
}
public void StartRecording()
{
PrepareWriting();
recording = true;
}
public void FinishRecording()
{
recording = false;
WriteHeader();
}
void OnAudioFilterRead(float[] data, int channels)
{
if (recording == true) {
Int16[] intData = new Int16[data.Length];
byte[] bytesData = new byte[data.Length * 2];
int rescaleFactor = 32767;
for (int i = 0; i < data.Length; i++)
{
intData[i] = (short)(data[i] * rescaleFactor);
byte[] byteArr = new byte[2];
byteArr = BitConverter.GetBytes(intData[i]);
byteArr.CopyTo(bytesData, i * 2);
}
fileStream.Write(bytesData, 0, bytesData.Length);
}
}
}
See also
- AndroidJNIHelper.GetSignature - using Byte parameters is obsolete, use SByte parameters instead. Solution
- Rider editor - no analysis has been performed. Solution
- Android codecs with supported color formats on Sumsung Galaxy A53 5G
- Unity3d onAudioFilterRead call frequency
- Android storage. A list of folders available for application.