using System; using System.IO; using UnityEngine; using System.Collections.Generic; using NAudio.Wave; using NAudio.Lame; public static class SaveAudio { public enum Savetype { wav, mp3 } //static int normalBitrate = 128; //static int GoodBitrate = 320; static int HEADER_SIZE = 44; //static int outputRate = 44100; static int outputRate = 48000; public static bool Save(string filename, AudioClip clip) { if (!filename.ToLower().EndsWith(".wav")) { filename += ".wav"; } var filepath = Path.Combine(Application.persistentDataPath, filename); Debug.Log(filepath); // Make sure directory exists if user is saving to sub dir. Directory.CreateDirectory(Path.GetDirectoryName(filepath)); using (var fileStream = CreateEmpty(filepath)) { ConvertAndWrite(fileStream, clip); WriteHeader(fileStream, clip); } return true; // TODO: return false if there's a failure saving the file } public static AudioClip TrimSilence(AudioClip clip, float min) { var samples = new float[clip.samples]; clip.GetData(samples, 0); return TrimSilence(new List(samples), min, clip.channels, clip.frequency); } public static AudioClip TrimSilence(List samples, float min, int channels, int hz) { return TrimSilence(samples, min, channels, hz, false, false); } public static AudioClip TrimSilence(List samples, float min, int channels, int hz, bool _3D, bool stream) { int i; for (i = 0; i < samples.Count; i++) { if (Mathf.Abs(samples[i]) > min) { break; } } samples.RemoveRange(0, i); for (i = samples.Count - 1; i > 0; i--) { if (Mathf.Abs(samples[i]) > min) { break; } } samples.RemoveRange(i, samples.Count - i); var clip = AudioClip.Create("TempClip", samples.Count, channels, hz, stream); clip.SetData(samples.ToArray(), 0); return clip; } public static FileStream CreateEmpty(string filepath) { var fileStream = new FileStream(filepath, FileMode.Create); byte emptyByte = new byte(); for (int i = 0; i < HEADER_SIZE; i++) //preparing the header { fileStream.WriteByte(emptyByte); } return fileStream; } public static void ConvertAndWrite(FileStream fileStream, AudioClip clip) { var samples = new float[clip.samples]; clip.GetData(samples, 0); Int16[] intData = new Int16[samples.Length]; //converting in 2 float[] steps to Int16[], //then Int16[] to Byte[] Byte[] bytesData = new Byte[samples.Length * 2]; //bytesData array is twice the size of //dataSource array because a float converted in Int16 is 2 bytes. int rescaleFactor = 32767; //to convert float to Int16 for (int i = 0; i < samples.Length; i++) { intData[i] = (short)(samples[i] * rescaleFactor); Byte[] byteArr = new Byte[2]; byteArr = BitConverter.GetBytes(intData[i]); byteArr.CopyTo(bytesData, i * 2); } fileStream.Write(bytesData, 0, bytesData.Length); } public static void ConvertAndWrite(FileStream fileStream,float[] dataSource ,Savetype type) { Int16[] intData = new Int16[dataSource.Length]; Byte[] bytesData = new Byte[dataSource.Length * 2]; int rescaleFactor = 32767; for (int i = 0; i < dataSource.Length; i++) { intData[i] = (short)(dataSource[i] * rescaleFactor); Byte[] byteArr = new Byte[2]; byteArr = BitConverter.GetBytes(intData[i]); byteArr.CopyTo(bytesData, i * 2); } switch(type) { case Savetype.wav: fileStream.Write(bytesData, 0, bytesData.Length); break; case Savetype.mp3: if (lameMP3temp == null) lameMP3temp = new LameMP3FileWriter(fileStream, new WaveFormat(), 128); if (lameMP3temp !=null) lameMP3temp.Write(bytesData, 0, bytesData.Length); break; default: //fileStream.Write(bytesData, 0, bytesData.Length); break; } } private static LameMP3FileWriter lameMP3temp; public static void WriteHeader(FileStream fileStream, AudioClip clip) { var hz = clip.frequency; var channels = clip.channels; var samples = clip.samples; 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); Byte[] subChunk1 = BitConverter.GetBytes(16); fileStream.Write(subChunk1, 0, 4); //UInt16 two = 2; UInt16 one = 1; Byte[] audioFormat = BitConverter.GetBytes(one); fileStream.Write(audioFormat, 0, 2); Byte[] numChannels = BitConverter.GetBytes(channels); fileStream.Write(numChannels, 0, 2); Byte[] sampleRate = BitConverter.GetBytes(hz); fileStream.Write(sampleRate, 0, 4); Byte[] byteRate = BitConverter.GetBytes(hz * channels * 2); // sampleRate * bytesPerSample*number of channels, here 44100*2*2 fileStream.Write(byteRate, 0, 4); UInt16 blockAlign = (ushort)(channels * 2); fileStream.Write(BitConverter.GetBytes(blockAlign), 0, 2); UInt16 bps = 16; Byte[] bitsPerSample = BitConverter.GetBytes(bps); fileStream.Write(bitsPerSample, 0, 2); Byte[] datastring = System.Text.Encoding.UTF8.GetBytes("data"); fileStream.Write(datastring, 0, 4); Byte[] subChunk2 = BitConverter.GetBytes(samples * channels * 2); fileStream.Write(subChunk2, 0, 4); // fileStream.Close(); } public static void WriteHeader(FileStream fileStream, Savetype audiotype) { if(audiotype == Savetype.mp3) { lameMP3temp.Flush(); lameMP3temp.Dispose(); lameMP3temp.Close(); fileStream.Close(); lameMP3temp = null; return; } 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); Byte[] subChunk1 = BitConverter.GetBytes(16); fileStream.Write(subChunk1, 0, 4); UInt16 two = 2; UInt16 one = 1; Byte[] audioFormat = BitConverter.GetBytes(one); fileStream.Write(audioFormat, 0, 2); Byte[] numChannels = BitConverter.GetBytes(two); fileStream.Write(numChannels, 0, 2); outputRate = AudioSettings.GetConfiguration().sampleRate; Byte[] sampleRate = BitConverter.GetBytes(outputRate); fileStream.Write(sampleRate, 0, 4); Byte[] byteRate = BitConverter.GetBytes(outputRate * 4); // sampleRate * bytesPerSample*number of channels, here 44100*2*2 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 - HEADER_SIZE); fileStream.Write(subChunk2, 0, 4); fileStream.Close(); } /* private static void ConvertAndWrite (AudioClip clip, string path, int bitRate, FileStream fileStream) { var samples = new float[fileStream.Length - HEADER_SIZE]; Int16[] intData = new Int16[samples.Length]; //converting in 2 float[] steps to Int16[], //then Int16[] to Byte[] Byte[] bytesData = new Byte[samples.Length * 2]; //bytesData array is twice the size of //dataSource array because a float converted in Int16 is 2 bytes. float rescaleFactor = 32767; //to convert float to Int16 for (int i = 0; i < samples.Length; i++) { intData [i] = (short)(samples [i] * rescaleFactor); Byte[] byteArr = new Byte[2]; byteArr = BitConverter.GetBytes (intData [i]); byteArr.CopyTo (bytesData, i * 2); } File.WriteAllBytes (path, ConvertWavToMp3 (bytesData,bitRate)); } */ }