Save Microphone Recording to disk

Ok I have a microphone recorder that I want to save the audio file to a local folder located where the Stand alone app will be located so that the user will be able to find the recording easily, right now it saves it somewhere daffy inside of unity.

public void SaveToDisk ()
        {
        AudioRecorder.Save ("myFile", goAudioSource.clip);
        }

I would like to save the file from the stand alone build into a folder something like:
Audio/Recordings

Can someone please help.

1 Like

First you’ll have to know wat an audiofile consists of. you can see the variables used here:

Basically you’ll have to serialize the bytes into a file in order to save it.
Simply save this array using a for loop

(You could use just use XML to store the data and parse it to the variables when needed, although XML is nutorious for it’s large file size)

And deserialize it in a new AudioClip file when wanting to load it.

If you literally have no idea how to do this, I’m sure there are people willing to help you with the code. Also there’s an assetstore, I’m sure there’s something in there that could help you.

I hope this’ll help!

[EDIT]
After a google search I’ve found this example on Unity Answers

[EDIT2]
If you’re just looking for a simple solution here’s an open source script that handles it for you.

5 Likes

I have seen all of these links, they did not tell me what I wanted to know which was how to save the file into a folder like:
Audio/Recordings relative to where my Stand alone app will be running on the desktop?

http://docs.unity3d.com/ScriptReference/Application-dataPath.html

string filepath = Path.Combine(Application.dataPath, filename);

This is pretty basic, a simple google search would’ve answered this question then.
Also look at my previous post, i edited it again, there’s an existing script to save/load your files:
http://answers.unity3d.com/questions/354401/save-audio-to-a-file.html

2 Likes

Thanks Magiichan,
I think a lot of my issues is how to convert the code as right now in the unity editor it does save the file to something like StreamingAssets/

2452337--168423--Screen Shot 2016-01-06 at 12.09.24 PM.png

But when I build my stand alone player I need it to save to something like:
Audio/Recordings/

Application.dataPath

When you’ve built the standalone version it’ll return something like this:
C:/Program Files/MyGame/MyGame_Data

So all you have to do is this.

var path = Application.dataPath + "/Audio/Recordings/";
if (System.IO.Directory.Exists(path))
{
    var files = System.IO.Directory.GetFiles(path);
    for (var i = 0; i < files.Length; i++)
    {
        if (files[i].ToLower().EndsWith(".wav"))
        {
            //Load files with path files[i]
        }
    }
}

The link I provided actually states this, take a closer look.
http://docs.unity3d.com/ScriptReference/Application-dataPath.html
Unity Editor: <path to project folder>/Assets
Win/Linux player: <path to executablename_Data folder> (note that most Linux installations will be case-sensitive!)

1 Like

I’m not really sure how to use that, I’m on a mac… not that it should matter but my code guy who had done this wrote the save like this:

public void SaveToDisk ()
        {
        AudioRecorder.Save ("myFile", goAudioSource.clip);
        }

Oh, can you show us the AudioRecorder code so we know what it requires in order to save?

2 Likes

Yup, here is the entire code.

using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using System;
using System.IO;
using System.Collections.Generic;

public class AudioRecorder : MonoBehaviour
{
   
    private string absolutePath = "./Audio/Recordings"; // relative path to where the app is running



        public GameObject RecButton;
        public GameObject RecButtonBG;
        public GameObject PausseButton;
        public GameObject PauseButtonBG;
        public GameObject PlayButton;
        public GameObject PlayButtonBG;
        public GameObject ButtonTimeRecordSelect1m;
        public GameObject ButtonTimeRecordSelect5m;
        public GameObject ButtonTimeRecordSelect15m;
        public GameObject ButtonTimeRecordSelect30m;
        public GameObject ButtonTimeRecordSelect60m;
        public GameObject ButtonTimeRecordSelect2h;
        public GameObject ButtonTimeRecordSelect4h;
        public GameObject ButtonTimeRecordSelect8h;
        public bool powerOn;
        private bool recording;
        private bool Playing;
        private bool Paused;
        public Text RecTimeSelect;
        public float tmeleft;
        public float tmerec;
        public float tmestart;
        public float tmeend;
        private bool done;
        public float tmeprdct;
        public float pctleft;
        public float pctcmplt;
        public Color TextColor;
        private bool micRecording = false;
        private int minFreq;
        private int maxFreq;
        private static int HEADER_SIZE ;
        public AudioSource goAudioSource;
       
        //Use this for initialization
        void Start ()
        {
                done = false;
                TextColor = RecTimeSelect.color;
                HEADER_SIZE = 44;
       

        }

        void Update ()
        {
                micRecording = Microphone.IsRecording (" ");
           
                if (micRecording) {
                        tmeend = Time.time;
                        tmeleft = tmeprdct - tmeend;
                        done = false;
               
                        pctleft = (int)(tmeleft / tmerec * 100);
                        if (pctleft < 0.5f)
                                pctleft = 0;
                        pctcmplt = 100 - pctleft;
                } else {
                        RecButtonBG.SetActive (true);
                        recording = false;

                        if (!done) {
                                tmeend = Time.time;
                   
                                tmeleft = tmeend - tmestart;
                                done = true;
                        }
                        if (!goAudioSource.isPlaying & !Paused)
                                PlayButtonBG.SetActive (true);

                        tmeend = Time.time;
                        tmeleft = tmeprdct - tmeend;
               
                        pctleft = (int)(tmeleft / tmerec * 100);
                        if (pctleft < 0.5f)
                                pctleft = 0;
                        pctcmplt = 100 - pctleft;
                }
        }

        public void Record ()
        {
                micRecording = true;
                Playing = false;
                Paused = false;
                done = false;
                tmestart = Time.time;   
           
                if (tmerec == 0f) {
                        RecTimeSelect.text = ("TIME REQUIRED");
                        TextColor = RecTimeSelect.color;
                        RecTimeSelect.color = Color.red;
                } else {
                        goAudioSource.clip = Microphone.Start (null, false, (int)tmerec, 44100);
                }
                RecButtonBG.SetActive (false);
                PlayButtonBG.SetActive (true);
                PauseButtonBG.SetActive (true);
           
        }
       
        public void StopRecord ()
        {
                micRecording = false;
                tmeend = Time.time;   
                Microphone.End (null); //Stop the audio recording

        }
       
        public void Play ()
        {
                if (micRecording)
                        StopRecord ();

                Playing = true;
                if (Paused) {
                        Paused = false;
                        PauseButtonBG.SetActive (true);
                }
                goAudioSource.Play (); //Playback the recorded audio
                PlayButtonBG.SetActive (false);
        }
       
        public void StopPlay ()
        {
                Playing = false;
                goAudioSource.Stop (); //Playback the recorded audio
                PlayButtonBG.SetActive (true);
        }
       
        public void Stop ()
        {

                Playing = false;
                Paused = false;
                RecButtonBG.SetActive (true);
                PauseButtonBG.SetActive (true);
                PlayButtonBG.SetActive (true);

                if (micRecording)
                        StopRecord ();
                else {
                        StopPlay ();
                        Playing = false;
                }
        micRecording = false;
        }

        public void Pause ()
        {
                if (!micRecording & Playing) {
                        if (!Paused) {
                                goAudioSource.Pause (); //Pause Playback
                                Paused = true;
                                PauseButtonBG.SetActive (false);

                        } else {
                                goAudioSource.Play (); //Playback the recorded audio
                                Paused = false;
                                PauseButtonBG.SetActive (true);
                        }
                }
                if (micRecording) {
                        Stop ();
                        PauseButtonBG.SetActive (true);
                        Paused = false;
                }
        }

        public void SaveToDisk ()
        {
        AudioRecorder.Save ("myFile", goAudioSource.clip);
        }

        public void RecordTime1m ()
        {
                tmerec = 5;   
                RecTimeSelect.text = ("Time Selected 5 S");
                TimeSelected ();
                ButtonTimeRecordSelect1m.SetActive (false);
        }

        public void RecordTime5m ()
        {
                tmerec = 300;   
                RecTimeSelect.text = ("Time Selected 5 M");
                TimeSelected ();
                ButtonTimeRecordSelect5m.SetActive (false);
       
        }

        public void RecordTime15m ()
        {
                tmerec = 900;   
                RecTimeSelect.text = ("Time Selected 15 M");
                TimeSelected ();
                ButtonTimeRecordSelect15m.SetActive (false);
        }
       
        public void RecordTime30m ()
        {
                tmerec = 1800;   
                RecTimeSelect.text = ("Time Selected 30 M");
                TimeSelected ();
                ButtonTimeRecordSelect30m.SetActive (false);
        }
       
        public void RecordTime60m ()
        {
                tmerec = 3600;   
                RecTimeSelect.text = ("Time Selected 60 M");
                TimeSelected ();
                ButtonTimeRecordSelect60m.SetActive (false);
        }
       
        public void RecordTime2h ()
        {
                tmerec = 7200;   
                RecTimeSelect.text = ("Time Selected 2 H");
                TimeSelected ();
                ButtonTimeRecordSelect2h.SetActive (false);
        }
       
        public void RecordTime4h ()
        {
                tmerec = 14400;   
                RecTimeSelect.text = ("Time Selected 4 H");
                TimeSelected ();
                ButtonTimeRecordSelect4h.SetActive (false);
        }
       
        public void RecordTime8h ()
        {
                tmerec = 28800;   
                RecTimeSelect.text = ("Time Selected 8 H");
                TimeSelected ();
                ButtonTimeRecordSelect8h.SetActive (false);
        }

        public void TimeSelected ()
        {
                RecTimeSelect.color = TextColor;
        }

        public static bool Save (string filename, AudioClip clip)
        {
       
                if (!filename.ToLower ().EndsWith (".wav")) {
           
                        filename += ".wav";
           
                }
       
       
       
                var filepath = Path.Combine (Application.streamingAssetsPath, 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<float> (samples), min, clip.channels, clip.frequency);
       
        }
   
        public static AudioClip TrimSilence (List<float> samples, float min, int channels, int hz)
        {
       
                return TrimSilence (samples, min, channels, hz, false, false);
       
        }
   
        public static AudioClip TrimSilence (List<float> 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, _3D, stream);
       
       
       
                clip.SetData (samples.ToArray (), 0);
       
       
       
                return clip;
       
        }
   
        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;
       
        }
   
        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);
       
        }
   
        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();
       
        }

}
1 Like

So your problem is that you don’t know how to save a file at a certain location on a mac using c#? I think the save method (System.IO) is only available on windows platforms. =/

4 Likes

Try to replace the save function with this:

    public static bool Save(string filename, AudioClip clip) {
        if (!filename.ToLower().EndsWith(".wav")) {
            filename += ".wav";
        }

        var filepath = Path.Combine(Application.dataPath, 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
    }

Maybe it’ll work, let me know what errors you get, if any.

3 Likes

Yup, I got one it returned this error:

Assets/AudioRecorder.cs(289,36): error CS0111: A member `AudioRecorder.Save(string, UnityEngine.AudioClip)' is already defined. Rename this member or use different parameter types

Find the function in the code and replace it with what i gave you.
You added it instead of replacing it, so there are 2 with the same name, that gives the error.

1 Like

Figures I’d mess it up in the wrong place.
OK error gone but where will this save the file too?

Build the game as standalone, and it should save it to
<path to player app bundle>/Contents

1 Like

I have no idea where to even find that, can it not be made to save to a folder that would be on the desktop beside the app called Audio/Recordings?
A “Recordings” folder nested inside of a folder called “Audio” ?

Honestly, I don’t know where it is either, mac is so confusing. Any mac user here that can help?

1 Like

Basically I need this so that when the stand alone player is built it will be located on the desktop with a folder beside it called “Audio” inside of the Audio folder are two other folders one for “music” and one for “Recordings.” The microphone recorded audio I would like saved out to the “Recordings” folder.

Build the stand alone player and see where it saves the .wav file. It should be in the same folder I think. if it isn’t try to find where it is instead.

1 Like

Nope I tried a build and it did not even save it to the desktop much less in the directory I wanted?