Recording Audio with OnAudioFilterRead, but resulting file doesn't work.

Hello everyone,

I have several audio-sources (different musical instruments) playing at the same time, for a mixing purpose.
And I have my script attached on my AudioListner.

Scipt was originally written by Gregzo (the auther of the plugin G-Audio), but this is an old scipt, however it worked for other users.

I am able to create a wav file, but no player can play the file, and can’t figure out what might be reason.

Here’s the code attached to the AudioListener

	private var bufferSize : int;
	private var numBuffers : int;
	private var outputRate : int = 44100;
	private var fileName : String = "recTest.wav";
	private var headerSize : int = 44; //default for uncompressed wav
	 
	private var recOutput : boolean;
	 
	private var fileStream : FileStream;
 
	function Awake()
	{
	    AudioSettings.outputSampleRate = outputRate;
	}
	 
	function Start()
	{
	    AudioSettings.GetDSPBufferSize(bufferSize,numBuffers);
	}
 
 	public var obj : GameObject ;
 	
	function Update()
	{
	    if(Input.GetKeyDown("r"))
	    { 
		    if(recOutput == false)
			{   				

				StartWriting(fileName);
				recOutput = true;
			}
			else
			{
				
				recOutput = false;
				WriteHeader();     
				print("rec stop");
			}
	    }  
	}
 
	function StartWriting(name : String)
	{
	    fileStream = new FileStream(name, FileMode.Create);
	    var emptyByte : byte = new byte();
	   
	    for(var i : int = 0; i<headerSize; i++) //preparing the header
	    {
	        fileStream.WriteByte(emptyByte);
	    }
	}
 
	function OnAudioFilterRead(data : float[], channels : int)
	{
	    if(recOutput)	    
	        ConvertAndWrite(data); //audio data is interlaced	    
	}
 
	function ConvertAndWrite(dataSource : float[])
	{
	   
	    var intData : Int16[] = new Int16[dataSource.length];
		//converting in 2 steps : float[] to Int16[], //then Int16[] to Byte[]
	   
	    var bytesData : Byte[] = new Byte[dataSource.length*2];
		//bytesData array is twice the size of
		//dataSource array because a float converted in Int16 is 2 bytes.
	   
	    var rescaleFactor : int = 32767; //to convert float to Int16
	   
	    for (var i : int = 0; i<dataSource.length;i++)
	    {
	        intData <em>= dataSource_*rescaleFactor;_</em>

* var byteArr : Byte[] = new Byte[2];*
_ byteArr = BitConverter.GetBytes(intData*);
byteArr.CopyTo(bytesData,i2);

* }*_

* fileStream.Write(bytesData,0,bytesData.length);*
* }*

* function WriteHeader()*
* { *
* // fileStream.Seek(0,Application.dataPath);*

* fileStream.Seek(0,SeekOrigin.Begin);*

* var riff : Byte[] = System.Text.Encoding.UTF8.GetBytes(“RIFF”);*
* fileStream.Write(riff,0,4);*

* var chunkSize : Byte[] = BitConverter.GetBytes(fileStream.Length-8);*
* fileStream.Write(chunkSize,0,4);*

* var wave : Byte[] = System.Text.Encoding.UTF8.GetBytes(“WAVE”);*
* fileStream.Write(wave,0,4);*

* var fmt : Byte[] = System.Text.Encoding.UTF8.GetBytes(“fmt”);*
* fileStream.Write(fmt,0,4);*

* var subChunk1 : Byte[] = BitConverter.GetBytes(16);*
* fileStream.Write(subChunk1,0,4);*

* var two : UInt16 = 2;*
* var one : UInt16 = 1;*

* var audioFormat : Byte[] = BitConverter.GetBytes(one);*
* fileStream.Write(audioFormat,0,2);*

* var numChannels : Byte[] = BitConverter.GetBytes(two);*
* fileStream.Write(numChannels,0,2);*

* var sampleRate : Byte[] = BitConverter.GetBytes(outputRate);*
* fileStream.Write(sampleRate,0,4);*

_ var byteRate : Byte = BitConverter.GetBytes(outputRate4);
// sampleRate * bytesPerSamplenumber of channels, here 4410022_

* fileStream.Write(byteRate,0,4);*

* var four : UInt16 = 4;*
* var blockAlign : Byte[] = BitConverter.GetBytes(four);*
* fileStream.Write(blockAlign,0,2);*

* var sixteen : UInt16 = 16;*
* var bitsPerSample : Byte[] = BitConverter.GetBytes(sixteen);*
* fileStream.Write(bitsPerSample,0,2);*

* var dataString : Byte[] = System.Text.Encoding.UTF8.GetBytes(“data”);*
* fileStream.Write(dataString,0,4);*

* var subChunk2 : Byte[] = BitConverter.GetBytes(fileStream.Length-headerSize);*
* fileStream.Write(subChunk2,0,4);*

* fileStream.Close();*
* }*

Thank You for your time

Hello,

I managed to read this file with Audacity (import raw data)

If you want to use another player you might need some extra plugin or codec using FFmpeg library

This blog post included adding a header to the *.wav file: Evan X. Merz

Here’s a full copy of the code on that page, just in case it goes down:

using UnityEngine;
using System;
using System.IO;

public class AudioRenderer : MonoBehaviour
{
    #region Fields, Properties, and Inner Classes
    // constants for the wave file header
    private const int HEADER_SIZE = 44;
    private const short BITS_PER_SAMPLE = 16;
    private const int SAMPLE_RATE = 44100;

    // the number of audio channels in the output file
    private int channels = 2;

    // the audio stream instance
    private MemoryStream outputStream;
    private BinaryWriter outputWriter;

    // should this object be rendering to the output stream?
    public bool Rendering = false;

    /// The status of a render
    public enum Status
    {
        UNKNOWN,
        SUCCESS,
        FAIL,
        ASYNC
    }

    /// The result of a render.
    public class Result
    {
        public Status State;
        public string Message;

        public Result(Status newState = Status.UNKNOWN, string newMessage = "")
        {
            this.State = newState;
            this.Message = newMessage;
        }
    }
    #endregion

    public AudioRenderer()
    {
        this.Clear();
    }

    // reset the renderer
    public void Clear()
    {
        this.outputStream = new MemoryStream();
        this.outputWriter = new BinaryWriter(outputStream);
    }

    /// Write a chunk of data to the output stream.
    public void Write(float[] audioData)
    {
        // Convert numeric audio data to bytes
        for (int i = 0; i < audioData.Length; i++)
        {
            // write the short to the stream
            this.outputWriter.Write((short)(audioData _* (float)Int16.MaxValue));_

}
}

// write the incoming audio to the output string
void OnAudioFilterRead(float[] data, int channels)
{
if( this.Rendering )
{
// store the number of channels we are rendering
this.channels = channels;

// store the data stream
this.Write(data);
}

}

#region File I/O
public AudioRenderer.Result Save(string filename)
{
Result result = new AudioRenderer.Result();

if (outputStream.Length > 0)
{
// add a header to the file so we can send it to the SoundPlayer
this.AddHeader();

// if a filename was passed in
if (filename.Length > 0)
{
// Save to a file. Print a warning if overwriting a file.
if (File.Exists(filename))
Debug.LogWarning("Overwriting " + filename + “…”);

// reset the stream pointer to the beginning of the stream
outputStream.Position = 0;

// write the stream to a file
FileStream fs = File.OpenWrite(filename);

this.outputStream.WriteTo(fs);

fs.Close();

// for debugging only
Debug.Log("Finished saving to " + filename + “.”);
}

result.State = Status.SUCCESS;
}
else
{
Debug.LogWarning(“There is no audio data to save!”);

result.State = Status.FAIL;
result.Message = “There is no audio data to save!”;
}

return result;
}

/// This generates a simple header for a canonical wave file,
/// which is the simplest practical audio file format. It
/// writes the header and the audio file to a new stream, then
/// moves the reference to that stream.
///
/// See this page for details on canonical wave files:
/// Canonical WAVE File Format
private void AddHeader()
{
// reset the output stream
outputStream.Position = 0;

// calculate the number of samples in the data chunk
long numberOfSamples = outputStream.Length / (BITS_PER_SAMPLE / 8);

// create a new MemoryStream that will have both the audio data AND the header
MemoryStream newOutputStream = new MemoryStream();
BinaryWriter writer = new BinaryWriter(newOutputStream);

writer.Write(0x46464952); // “RIFF” in ASCII

// write the number of bytes in the entire file
writer.Write((int)(HEADER_SIZE + (numberOfSamples * BITS_PER_SAMPLE * channels / 8)) - 8);

writer.Write(0x45564157); // “WAVE” in ASCII
writer.Write(0x20746d66); // "fmt " in ASCII
writer.Write(16);

// write the format tag. 1 = PCM
writer.Write((short)1);

// write the number of channels.
writer.Write((short)channels);

// write the sample rate. 44100 in this case. The number of audio samples per second
writer.Write(SAMPLE_RATE);

writer.Write(SAMPLE_RATE * channels * (BITS_PER_SAMPLE / 8));
writer.Write((short)(channels * (BITS_PER_SAMPLE / 8)));

// 16 bits per sample
writer.Write(BITS_PER_SAMPLE);

// “data” in ASCII. Start the data chunk.
writer.Write(0x61746164);

// write the number of bytes in the data portion
writer.Write((int)(numberOfSamples * BITS_PER_SAMPLE * channels / 8));

// copy over the actual audio data
this.outputStream.WriteTo(newOutputStream);

// move the reference to the new stream
this.outputStream = newOutputStream;
}
#endregion
}