Save a recorded sound to .wav

Hi,
I have made a script that records sound in my Unity game and I want to save the recording to a .wav file
I found a solution regarding this but that is in C language, so can you help me in converting the C script to a C# script.
This is the script I used for recording.
RecordMic.txt (4.2 KB)
solution in C language
Thanks

Hi, @Connor_FMOD
I am facing a major bottleneck can you please help me by providing a solution for how to save a sound to a .wav file. Is it possible to do this using C# language?

Apologies for the delay, we somehow missed this post.The C++ example you’ve linked to is probably a little more low-level than you need- that is for manually creating a wav file whereas you can just use the WAVWRITER output type in a separate system object.
We had a similar question recently where @Connor_FMOD provided a solution in Unity using two system objects; one to record mic input and one to output the wav file. Here is that example again, pared back a bit more just to have the basics of starting and stopping a recording. Use “R” to start the recording and “S” to stop, at which point a file called “fmodoutput.wav” will appear in the root of your Unity project.

RecordMicOutputWav.cs
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using UnityEngine;
using FMOD;

public class RecordMicOutputWav : MonoBehaviour
{
    public float Latency = 0.2f;
    public int RecordingDeviceIndex = 0;
    public string RecordingDeviceName = null;
    public List<string> ConnectedDevices = new List<string>();

    private Sound sound;
    private CREATESOUNDEXINFO exinfo;
    private Channel channel;
    private Channel wavChannel;
    private ChannelGroup channelGroup;

    private FMOD.System micRecordSystem, wavWriterSystem;
    private bool recording = false;
    private int SampleRate = 0;
    private int NumChannels = 0;

    private float time = 0.0f;

    private void Start()
    {
        ERRCHECK( Factory.System_Create(out micRecordSystem) );
        ERRCHECK( Factory.System_Create(out wavWriterSystem) );

        ERRCHECK( micRecordSystem.init(100, INITFLAGS.NORMAL, System.IntPtr.Zero) );
        ERRCHECK( wavWriterSystem.init(100, INITFLAGS.NORMAL, System.IntPtr.Zero) );

        ERRCHECK( wavWriterSystem.setOutput(OUTPUTTYPE.NOSOUND) );

        InitRecordingDevices();
        InitExInfo();
    }

    private void OnDestroy()
    {
        if(recording)
        {
            StopRecording();
        }

        ERRCHECK( micRecordSystem.release() );
        ERRCHECK( wavWriterSystem.release() );
    }

    private void Update()
    { 
        if (recording)
        {
            time += Time.deltaTime;
            if (time >= Latency)
            {
                ERRCHECK( micRecordSystem.update() );
                ERRCHECK( wavWriterSystem.update() );
            }
        }

        if (Input.GetKeyDown(KeyCode.R))
        {
            StartRecording();
        }

        if (Input.GetKeyDown(KeyCode.S))
        {
            StopRecording();
        }
    }

    private void StartRecording()
    {
        recording = true;

        ERRCHECK( micRecordSystem.createSound(exinfo.userdata, MODE.LOOP_NORMAL | MODE.OPENUSER, ref exinfo, out sound) );

        ERRCHECK( micRecordSystem.recordStart(RecordingDeviceIndex, sound, true) );
        ERRCHECK( wavWriterSystem.setOutput(OUTPUTTYPE.WAVWRITER) );

        ERRCHECK( micRecordSystem.playSound(sound, channelGroup, false, out channel) );
        ERRCHECK( wavWriterSystem.playSound(sound, channelGroup, false, out wavChannel) );
    }

    private void StopRecording()
    {
        recording = false;
        time = 0.0f;

        ERRCHECK( micRecordSystem.recordStop(RecordingDeviceIndex) );

        ERRCHECK( wavChannel.stop() );
        ERRCHECK( channel.stop() );
        ERRCHECK( sound.release() );

        ERRCHECK( wavWriterSystem.setOutput(OUTPUTTYPE.NOSOUND) );
    }

    private void InitExInfo()
    {
        exinfo.cbsize = Marshal.SizeOf(typeof(CREATESOUNDEXINFO));
        exinfo.numchannels = NumChannels;
        exinfo.format = SOUND_FORMAT.PCM16;
        exinfo.defaultfrequency = SampleRate;
        exinfo.length = (uint)SampleRate * sizeof(short) * (uint)NumChannels;
    }

    private void InitRecordingDevices()
    {
        ERRCHECK( micRecordSystem.getRecordNumDrivers(out int numdDrivers, out _) );

        for (int i = 0; i < numdDrivers; ++i)
        {
            ERRCHECK( micRecordSystem.getRecordDriverInfo(i, out string name, 64, out _, out int sampleRate, out _, out int numChannels, out _) );

            ConnectedDevices.Add(name);

            if (i == RecordingDeviceIndex)
            {
                RecordingDeviceName = name;
                SampleRate = sampleRate;
                NumChannels = numChannels;
            }
        }
    }

    private void ERRCHECK(RESULT result, [CallerLineNumber] int lineNumber = 0, [CallerMemberName] string failed = null)
    {
        if (result != RESULT.OK)
        {
            UnityEngine.Debug.LogError(lineNumber + "(" + failed + "): " + Error.String(result));
        }
    }
}

Thank you for the solution :+1: @jeff_fmod

Newbie here, but how do you specify a new file path other than the project root to save the file?

Hi,

To set a location you can pass it into the extra driver data: FMOD Engine | Core API Data.

This will also require using a callback handler to assign the extra driver data before the FMOD system has been initialized, we have an example of how to implement that here: Unity integration | Scripting Examples: Callback Handler.

If you have followed the tutorial then you will pass the extra driver data here:

ERRCHECK( wavWriterSystem.init(100, INITFLAGS.NORMAL, /*ExtraDriverData*/) );

Hope this helps!