User-free, time-long audio recording using the microphone class in Unity
Master Recording Script AudioRecord.cs
Maxcliplength: Maximum audio length, do not exceed the length of the actual recording, or set the maxcliplength infinite size can also
Using Unityengine;
Using Unityengine.ui;
Using System.Collections;
Using System;
Using System.IO;
Using System.Collections.Generic;
public class Audiorecorder:monobehaviour {public enum audiorecordresultstate {Success,nomicrophone,tooshort}
[serializefield]private int maxcliplength = 300;
[hideininspector]public bool isrecording = false;
Private AudioClip Recordedclip;
private int _samplewindow = 128;
private float Recordtimer = 0.0f;
private void Update () {if (isrecording) {recordtimer + = Time.deltatime;
}}///<summary>///Start recording///</summary> public audiorecordresultstate Startrecord ()
{if (Microphone.devices.Length <= 0) return audiorecordresultstate.nomicrophone;
Recordtimer = 0;
Recordedclip = Microphone.start (null, FALSE, Maxcliplength, 44100);
IsRecording = true;
Debug.Log ("Start record-------------"); return audiorecordresultstate.success; }///<summary>//Get microphone volume///</summary>//<returns></returns> public FL
Oat Getlevelmax () {float Levelmax = 0;
float[] Wavedata = new Float[_samplewindow]; int micposition = microphone.getposition (null)-(_samplewindow + 1);
Null means the first microphone if (Micposition < 0) return 0;
Recordedclip.getdata (Wavedata, micposition); Getting a peak on the last samples for (int i = 0; i < _samplewindow; i++) {float W
Avepeak = wavedata[i] * Wavedata[i];
if (Levelmax < wavepeak) {Levelmax = Wavepeak;
}} return Levelmax; }///<summary>///Stop recording///</summary>//<returns> return audio save Path </returns> pub Lic audiorecordresultstate Stoprecord (out string filePath) {DEBUG.LOG ("Stop record---------------");
Capture the current clip data isrecording = false;
if (Recordtimer < 0.5f) {filePath = null;
return audiorecordresultstate.tooshort;
} int position = microphone.getposition (null);
var sounddata = new float[recordedclip.samples * Recordedclip.channels];
Recordedclip.getdata (sounddata, 0); Create shortened array for the data is used for recording var newdata = new Float[position * Recordedclip.
Channels]; Copy The used samples to a new array for (int i = 0; i < newdata.length; i++) {Newdata[i
] = Sounddata[i];
}//one does not simply shorten an audioclip,//So we do a new one with the appropriate length
Recordedclip = Audioclip.create (recordedclip.name, Position, recordedclip.chAnnels, recordedclip.frequency, false); Recordedclip.setdata (NewData, 0);
Give it the data from the old clip//replace the old clip microphone.end (null);
Save to disk string Recordedaudiopath;
byte[] data = Wavutility.fromaudioclip (Recordedclip, out Recordedaudiopath, true);
FilePath = Recordedaudiopath;
return audiorecordresultstate.success;
}
}
Tool class Script WavUtility.cs, the user handles the conversion between audio files and AudioClip
(source and how to use: HTTPS://GITHUB.COM/DEADLYFINGERS/UNITYWAV)
Using System.Text;
Using System.IO;
Using System;
Using Unityengine;
<summary>//WAV utility for recording and audio playback functions in Unity.
version:1.0 Alpha 1/////////-use "Toaudioclip" method for loading WAV file/bytes.
Loads. WAV (PCM uncompressed) files at 8,16,24 and all bits and converts data to Unity ' s audioclip.
-Use the "Fromaudioclip" method for saving WAV file/bytes.
Converts an AudioClip ' s float data to wav byte array at + bit. </summary>//<remarks>//For documentation and usage examples:https://github.com/deadlyfingers/ Unitywav//</remarks> public class Wavutility {//force Save as 16-bit. wav const int blocksize_16bit =
2; <summary>//Load PCM format *.wav audio file (using Unity ' s Application Data path) and convert to AUDIOCLI P.//</summary>//<returns>the audioclip.</returns>//<param name= "FilePath" >loc Al file path to. wav File</param> public static AudioClip Toaudioclip (string filePath) {if (!filepath.startswith (applicat Ion.persistentdatapath) &&!filepath.startswith (Application.datapath)) {debug.logwarning ("Thi s only supports files that is stored using Unity ' s application Data path. \nto load bundled resources use ' resources.load (\ "Filename\") typeof (AudioClip) ' method.
\nhttps://docs.unity3d.com/scriptreference/resources.load.html ");
return null;
} byte[] Filebytes = file.readallbytes (FilePath);
Return Toaudioclip (filebytes, 0); } public static AudioClip Toaudioclip (byte[] filebytes, int offsetsamples = 0, String name = "wav") {//s
Tring riff = Encoding.ASCII.GetString (filebytes, 0, 4);
String wave = Encoding.ASCII.GetString (Filebytes, 8, 4);
int subchunk1 = Bitconverter.toint32 (filebytes, 16);
UInt16 Audioformat = bitconverter.touint16 (filebytes, 20); NB: Only uncompressed PCM wav files is supported.
String formatcode = Formatcode (Audioformat); Debug.assertformat (Audioformat = = 1 | | audioformat = = 65534, "detected format code ' {0} ' {1}, but only PCM and waveformate
Xtensable uncompressed formats is currently supported. ", Audioformat, Formatcode);
UInt16 channels = Bitconverter.touint16 (Filebytes, 22);
int samplerate = Bitconverter.toint32 (filebytes, 24);
int byterate = Bitconverter.toint32 (filebytes, 28);
UInt16 blockalign = bitconverter.touint16 (filebytes, 32);
UInt16 bitDepth = bitconverter.touint16 (filebytes, 34);
int headeroffset = 4 + Subchunk1 + 4;
int subchunk2 = Bitconverter.toint32 (filebytes, Headeroffset); Debug.logformat ("riff={0} Wave={1} subchunk1={2} format={3} channels={4} samplerate={5} byterate={6} blockAlign={7} BITDEPTH={8} headeroffset={9} subchunk2={10} filesize={11} ", Riff, Wave, Subchunk1, Formatcode, channels, SamplErate, Byterate, Blockalign, BitDepth, Headeroffset, Subchunk2, filebytes.length);
float[] data; Switch (bitDepth) {Case 8:data = Convert8bitbytearraytoaudioclipdata (filebytes, head
Eroffset, SUBCHUNK2);
Break
Case 16:data = Convert16bitbytearraytoaudioclipdata (filebytes, Headeroffset, SUBCHUNK2);
Break
Case 24:data = Convert24bitbytearraytoaudioclipdata (filebytes, Headeroffset, SUBCHUNK2);
Break
Case 32:data = Convert32bitbytearraytoaudioclipdata (filebytes, Headeroffset, SUBCHUNK2);
Break
Default:throw New Exception (bitDepth + "bit depth is not supported."); } AudioClip AudioClip = audioclip.create (name, data.
Length, (int) channels, samplerate, false);
Audioclip.setdata (data, 0);
return audioclip; } #region WAV File bytes to Unity audioclip conversion methods private static float[] Convert8bitbytearraytoaudioclipdata (byte[]
source, int headeroffset, int datasize) {int wavsize = Bitconverter.toint32 (source, headeroffset);
Headeroffset + = sizeof (int); Debug.assertformat (wavsize > 0 && wavsize = = DataSize, "Failed to get valid 8-bit wav Size: {0} from data bytes
: {1} at offset: {2} ", Wavsize, DataSize, Headeroffset);
float[] data = new Float[wavsize]; SByte maxValue = sbyte.
MaxValue;
int i = 0;
while (I < wavsize) {Data[i] = (float) source[i]/maxValue;
++i;
} return data;
} private static float[] Convert16bitbytearraytoaudioclipdata (byte[] source, int headeroffset, int datasize) {
int wavsize = Bitconverter.toint32 (source, headeroffset);
Headeroffset + = sizeof (int); Debug.assertformat (wavsize > 0 && wavsize = = DataSize, "Failed to get valid 16-bit wav Size: {0} from the data bytes: {1} at offset: {2}", Wavsize, DataSize, Headeroffset); int x = sizeof (Int16);
Block size = 2 int convertedsize = wavsize/x;
float[] data = new Float[convertedsize];
Int16 maxValue = Int16.maxvalue;
int offset = 0;
int i = 0;
while (I < convertedsize) {offset = i * x + headeroffset;
Data[i] = (float) bitconverter.toint16 (source, offset)/maxValue;
++i; } debug.assertformat (data. Length = = Convertedsize, "AudioClip. wav data is wrong size: {0} = = {1}", data.
Length, convertedsize);
return data;
} private static float[] Convert24bitbytearraytoaudioclipdata (byte[] source, int headeroffset, int datasize) {
int wavsize = Bitconverter.toint32 (source, headeroffset);
Headeroffset + = sizeof (int); Debug.assertformat (wavsize > 0 && wavsize = = DataSize, "Failed to get valid 24-bit wav Size: {0} from the data bytes: {1} at offset: {2}", Wavsize, DataSize, Headeroffset); int x = 3;
Block size = 3 int convertedsize = wavsize/x;
int maxValue = Int32.MaxValue;
float[] data = new Float[convertedsize]; byte[] block = new byte[sizeof (int)];
Using a 4 byte block for copying 3 bytes, then copy bytes with 1 offset int offset = 0;
int i = 0;
while (I < convertedsize) {offset = i * x + headeroffset;
Buffer.blockcopy (source, offset, block, 1, x);
Data[i] = (float) bitconverter.toint32 (block, 0)/maxValue;
++i; } debug.assertformat (data. Length = = Convertedsize, "AudioClip. wav data is wrong size: {0} = = {1}", data.
Length, convertedsize);
return data;
} private static float[] Convert32bitbytearraytoaudioclipdata (byte[] source, int headeroffset, int datasize) { int Wavsize= Bitconverter.toint32 (source, headeroffset);
Headeroffset + = sizeof (int); Debug.assertformat (wavsize > 0 && wavsize = = DataSize, "Failed to get valid 32-bit wav Size: {0} from data byte
S: {1} at offset: {2} ", Wavsize, DataSize, Headeroffset); int x = sizeof (float);
Block size = 4 int convertedsize = wavsize/x;
Int32 maxValue = Int32.MaxValue;
float[] data = new Float[convertedsize];
int offset = 0;
int i = 0;
while (I < convertedsize) {offset = i * x + headeroffset;
Data[i] = (float) bitconverter.toint32 (source, offset)/maxValue;
++i; } debug.assertformat (data. Length = = Convertedsize, "AudioClip. wav data is wrong size: {0} = = {1}", data.
Length, convertedsize);
return data;
} #endregion public static byte[] Fromaudioclip (AudioClip audioclip) {string file; Return Fromaudioclip (AudioClip, out file, false); } public static byte[] Fromaudioclip (AudioClip audioclip, out string filepath, bool SaveAsFile = True, String dirname
= "Recordings") {MemoryStream stream = new MemoryStream ();
const int headersize = 44; Get bit depth UInt16 bitDepth = 16;
BitDepth (AudioClip); Nb:only supports-bit//debug.assertformat (bitDepth = =, "Only converting-bit is currently supported.
The audio clip data is {0} bit. ", bitDepth);
Total File size = bytes of the header format and audioclip.samples * factor due to float to int16/sbyte conversion int fileSize = audioclip.samples * blocksize_16bit + headersize;
BlockSize (bitDepth)//Chunk Descriptor (RIFF) Writefileheader (ref stream, fileSize);
File header (FMT) Writefileformat (ref stream, Audioclip.channels, audioclip.frequency, bitDepth); Data chunks (data) Writefiledata (ref stream, AudioClip, bitDepth); byte[] bytes = stream.
ToArray (); Validate Total Bytes Debug.assertformat (bytes. Length = = FileSize, "Unexpected audioclip to WAV format byte count: {0} = = {1}", bytes.
Length, fileSize); Save file to persistant storage location if (saveasfile) {filepath = string. Format ("{0}/{1}/{2}.{
3} ", Application.persistentdatapath, DirName, DateTime.UtcNow.ToString (" Yymmdd-hhmmss-fff ")," wav ");
Directory.CreateDirectory (Path.getdirectoryname (filepath));
File.writeallbytes (filepath, bytes);
Debug.Log ("auto-saved. wav file:" + filepath);
} else {filepath = null; } stream.
Dispose ();
return bytes;
} #region write. wav file functions private static int Writefileheader (ref MemoryStream stream, int fileSize)
{int count = 0;
int total = 12; Riff Chunk ID byte[]Riff = Encoding.ASCII.GetBytes ("riff");
Count + = Writebytestomemorystream (ref stream, riff, "ID"); Riff chunk size int chunkSize = fileSize-8; Total Size-8-The other-the the header count + = Writebytestomemorystream (ref stream, Bitconverte
R.getbytes (ChunkSize), "chunk_size");
byte[] wave = Encoding.ASCII.GetBytes ("wave");
Count + = Writebytestomemorystream (ref stream, Wave, "FORMAT"); Validate Header Debug.assertformat (count = = Total, "Unexpected WAV descriptor byte count: {0} = = {1}", Count, T
Otal);
return count;
} private static int Writefileformat (ref MemoryStream stream, int channels, int samplerate, UInt16 bitDepth) {
int count = 0;
int total = 24;
byte[] id = Encoding.ASCII.GetBytes ("FMT");
Count + = Writebytestomemorystream (ref stream, ID, "fmt_id"); int subchunk1size = 16; 24-8 count + = Writebytestomemorystream (Ref stream, Bitconverter.getbytes (subchunk1size), "subchunk_size");
UInt16 Audioformat = 1;
Count + = Writebytestomemorystream (ref stream, Bitconverter.getbytes (Audioformat), "Audio_format");
UInt16 numchannels = convert.touint16 (Channels);
Count + = Writebytestomemorystream (ref stream, Bitconverter.getbytes (numchannels), "CHANNELS");
Count + = Writebytestomemorystream (ref stream, Bitconverter.getbytes (samplerate), "sample_rate");
int byterate = samplerate * Channels * bytespersample (bitDepth);
Count + = Writebytestomemorystream (ref stream, Bitconverter.getbytes (byterate), "byte_rate");
UInt16 blockalign = convert.touint16 (Channels * Bytespersample (bitDepth));
Count + = Writebytestomemorystream (ref stream, Bitconverter.getbytes (blockalign), "block_align"); Count + = Writebytestomemorystream (ref stream, Bitconverter.getbytes (BITD