Hi I have a Unity Editor Window script that I need you to add the ability to select recording device and press a Record Source button or a Record Reference button to record an audio clip to be used as the Source Audio clip or the Reference Audio clip if desired.

using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using UnityEditor;
using UnityEngine;
using UnityEngine.Networking;

public class SeedVCWindow : EditorWindow
{
    private Texture2D logo;

    // Parameters (matching AudioConverter class)
    private string serverUrl = "http://localhost:8000/convert";
    private int qualityValue = 10;

    // Audio clips for input
    private AudioClip sourceClip;
    private AudioClip referenceClip;

    // Selected folder to save result
    private DefaultAsset saveFolderAsset;
    private string saveFolderPath = "Assets/";

    // Status message
    private string statusMessage;
    private bool isConverting = false;

    // Playback
    private AudioClip convertedClip;
    private bool isPlaying = false;
    private Vector2 scrollPos;

    [MenuItem("Tools/Seed_VC")]
    private static void ShowWindow()
    {
        var window = GetWindow<SeedVCWindow>("Seed_VC");
        window.minSize = new Vector2(400, 500);
    }

    private void OnEnable()
    {
        // Load logo from Resources folder (Assets/Resources/seed_vc_logo.png)
        logo = Resources.Load<Texture2D>("seed_vc_logo");
        EditorApplication.update += EditorUpdate;
    }

    private void OnDisable()
    {
        EditorApplication.update -= EditorUpdate;
        StopPlayback();
    }

    private void EditorUpdate()
    {
        if (isPlaying && !EditorApplication.isPlaying && !Application.isPlaying)
        {
            // Keep inspector repainting if audio is playing
            Repaint();
        }
    }

    private void OnGUI()
    {
        scrollPos = EditorGUILayout.BeginScrollView(scrollPos);

        GUILayout.Space(10);

        if (logo != null)
        {
            var rect = GUILayoutUtility.GetRect(logo.width, logo.height, GUILayout.ExpandWidth(false));
            GUI.DrawTexture(rect, logo, ScaleMode.ScaleToFit);
        }
        else
        {
            EditorGUILayout.HelpBox("Logo not found in Resources as 'seed_vc_logo'. Please add a PNG named 'seed_vc_logo' to Assets/Resources.", MessageType.Warning);
        }

        GUILayout.Space(10);

        EditorGUILayout.LabelField("Server URL:", EditorStyles.boldLabel);
        serverUrl = EditorGUILayout.TextField(serverUrl);

        EditorGUILayout.LabelField("Quality Value (diffusion_steps):", EditorStyles.boldLabel);
        qualityValue = EditorGUILayout.IntSlider(qualityValue, 1, 100);

        GUILayout.Space(10);

        EditorGUILayout.LabelField("Source Audio Clip:", EditorStyles.boldLabel);
        sourceClip = (AudioClip)EditorGUILayout.ObjectField(sourceClip, typeof(AudioClip), false);

        EditorGUILayout.LabelField("Reference Audio Clip:", EditorStyles.boldLabel);
        referenceClip = (AudioClip)EditorGUILayout.ObjectField(referenceClip, typeof(AudioClip), false);

        GUILayout.Space(10);

        EditorGUILayout.LabelField("Save Folder:", EditorStyles.boldLabel);
        EditorGUILayout.BeginHorizontal();

        saveFolderAsset = (DefaultAsset)EditorGUILayout.ObjectField(saveFolderAsset, typeof(DefaultAsset), false);
        if (GUILayout.Button("Select Folder", GUILayout.Width(100)))
        {
            string selectedPath = EditorUtility.OpenFolderPanel("Select Save Folder", Application.dataPath, "");
            if (!string.IsNullOrEmpty(selectedPath))
            {
                // Convert absolute path to relative Unity project path
                if (selectedPath.StartsWith(Application.dataPath))
                {
                    saveFolderPath = "Assets" + selectedPath.Substring(Application.dataPath.Length);
                    saveFolderAsset = AssetDatabase.LoadAssetAtPath<DefaultAsset>(saveFolderPath);
                }
                else
                {
                    EditorUtility.DisplayDialog("Invalid Folder", "Selected folder must be inside the Assets directory.", "OK");
                }
            }
        }
        EditorGUILayout.EndHorizontal();

        GUILayout.Space(15);

        GUI.enabled = !isConverting;
        if (GUILayout.Button("CONVERT", GUILayout.Height(40)))
        {
            if (!ValidateInputs())
                return;

            _ = ConvertAudioFiles(); // Fire & forget async task
        }
        GUI.enabled = true;

        GUILayout.Space(10);

        EditorGUILayout.HelpBox(statusMessage, MessageType.Info);

        GUILayout.Space(10);

        if (convertedClip != null)
        {
            EditorGUILayout.LabelField("Converted Audio Playback:", EditorStyles.boldLabel);

            EditorGUILayout.BeginHorizontal();

            if (!isPlaying)
            {
                if (GUILayout.Button("Play"))
                {
                    PlayConvertedClip();
                }
            }
            else
            {
                if (GUILayout.Button("Stop"))
                {
                    StopPlayback();
                }
            }

            if (GUILayout.Button("Ping Asset", GUILayout.Width(100)))
            {
                string path = AssetDatabase.GetAssetPath(convertedClip);
                if (!string.IsNullOrEmpty(path))
                {
                    UnityEngine.Object obj = AssetDatabase.LoadAssetAtPath<AudioClip>(path);
                    if (obj != null)
                    {
                        EditorGUIUtility.PingObject(obj);
                    }
                }
            }

            EditorGUILayout.EndHorizontal();
        }

        EditorGUILayout.EndScrollView();
    }

    private bool ValidateInputs()
    {
        if (string.IsNullOrWhiteSpace(serverUrl))
        {
            statusMessage = "Server URL cannot be empty.";
            return false;
        }

        if (qualityValue < 1)
        {
            statusMessage = "Quality value must be greater than 0.";
            return false;
        }

        if (sourceClip == null)
        {
            statusMessage = "Please assign a Source Audio Clip.";
            return false;
        }

        if (referenceClip == null)
        {
            statusMessage = "Please assign a Reference Audio Clip.";
            return false;
        }

        if (saveFolderAsset == null || string.IsNullOrEmpty(saveFolderPath))
        {
            statusMessage = "Please select a save folder inside the Assets directory.";
            return false;
        }

        return true;
    }

    private async Task ConvertAudioFiles()
    {
        isConverting = true;
        statusMessage = "Reading audio clips and preparing data...";
        Repaint();

        convertedClip = null;
        StopPlayback();

        try
        {
            // Convert AudioClips to WAV byte arrays
            byte[] sourceWavData = AudioClipToWav(sourceClip);
            byte[] referenceWavData = AudioClipToWav(referenceClip);

            if (sourceWavData == null || referenceWavData == null)
            {
                statusMessage = "Failed to convert AudioClips to WAV bytes.";
                isConverting = false;
                Repaint();
                return;
            }

            statusMessage = "Sending data to server...";
            Repaint();

            var base64FileData = await UploadAudioAndConvert(sourceWavData, referenceWavData);

            if (!string.IsNullOrEmpty(base64FileData))
            {
                statusMessage = $"Conversion succeeded, saving the file...";
                Repaint();

                bool saved = SaveFileToAssetFolder(base64FileData, out AudioClip loadedClip);

                if (saved)
                {
                    convertedClip = loadedClip;
                    statusMessage = "File saved successfully. You can play it back below.";
                    // Ping the asset automatically after saving
                    EditorGUIUtility.PingObject(convertedClip);
                }
                else
                {
                    statusMessage = "Failed to save the file as an asset.";
                }
            }
            else
            {
                statusMessage = "Conversion failed or no file returned.";
            }
        }
        catch (Exception ex)
        {
            Debug.LogException(ex);
            statusMessage = $"An error occurred: {ex.Message}";
        }
        finally
        {
            isConverting = false;
            Repaint();
        }
    }

    private async Task<string> UploadAudioAndConvert(byte[] sourceAudioBytes, byte[] referenceAudioBytes)
    {
        List<IMultipartFormSection> formData = new List<IMultipartFormSection>
        {
            new MultipartFormFileSection("source_file", sourceAudioBytes, "source.wav", "audio/wav"),
            new MultipartFormFileSection("reference_file", referenceAudioBytes, "reference.wav", "audio/wav"),

            // Server parameters:
            new MultipartFormDataSection("diffusion_steps", qualityValue.ToString()),
            new MultipartFormDataSection("length_adjust", "1.0"),
            new MultipartFormDataSection("inference_cfg_rate", "0.7"),
            new MultipartFormDataSection("auto_f0_adjust", "true"),
            new MultipartFormDataSection("pitch_shift", "0")
        };

        using (UnityWebRequest request = UnityWebRequest.Post(serverUrl, formData))
        {
            var operation = request.SendWebRequest();

            while (!operation.isDone)
                await Task.Yield();

#if UNITY_2020_1_OR_NEWER
            if (request.result != UnityWebRequest.Result.Success)
#else
            if (request.isNetworkError || request.isHttpError)
#endif
            {
                statusMessage = $"Server error: {request.error}";
                return null;
            }

            var textResult = request.downloadHandler.text;
            if (string.IsNullOrWhiteSpace(textResult))
            {
                statusMessage = "Server returned an empty response.";
                return null;
            }

            try
            {
                ConversionResponse response = JsonUtility.FromJson<ConversionResponse>(textResult);
                string filePath = response.windows_path ?? response.file_path;

                if (string.IsNullOrEmpty(filePath))
                {
                    statusMessage = "Server response does not contain a valid file path.";
                    return null;
                }

                // Read the returned file bytes, assuming server returns a path accessible on local machine or network
                if (!File.Exists(filePath))
                {
                    statusMessage = $"Returned file does not exist on disk: {filePath}";
                    return null;
                }

                byte[] convertedFileBytes = File.ReadAllBytes(filePath);

                // Return this byte array as Base64 string for saving later
                return Convert.ToBase64String(convertedFileBytes);
            }
            catch (Exception ex)
            {
                statusMessage = "Failed to parse server response: " + ex.Message;
                return null;
            }
        }
    }

    private bool SaveFileToAssetFolder(string base64FileData, out AudioClip loadedClip)
    {
        loadedClip = null;
        try
        {
            byte[] fileBytes = Convert.FromBase64String(base64FileData);

            string fileName = $"converted_{DateTime.Now:yyyyMMdd_HHmmss}.wav";

            string fullPath = Path.Combine(saveFolderPath, fileName);

            // Convert to absolute path for writing file
            string absolutePath = Path.Combine(Application.dataPath.Substring(0, Application.dataPath.Length - 6), fullPath);

            File.WriteAllBytes(absolutePath, fileBytes);

            // Refresh AssetDatabase so the file shows up
            AssetDatabase.ImportAsset(fullPath, ImportAssetOptions.ForceUpdate);

            // Load the imported AudioClip asset
            loadedClip = AssetDatabase.LoadAssetAtPath<AudioClip>(fullPath);

            if (loadedClip == null)
            {
                Debug.LogWarning("Saved file but failed to load the AudioClip asset after import.");
            }

            return true;
        }
        catch (Exception ex)
        {
            Debug.LogError("Failed to save file: " + ex);
            return false;
        }
    }

    private void PlayConvertedClip()
    {
        if (convertedClip == null)
            return;

        if (isPlaying)
            StopPlayback();

        isPlaying = true;

        // Play clip using EditorUtility or EditorAPI for preview playback
        // Note: AudioUtil is internal but this is the easiest way without external libs:
        PlayClip(convertedClip);
    }

    private void StopPlayback()
    {
        if (!isPlaying)
            return;

        isPlaying = false;

        StopClip(convertedClip);
    }

    // Utility methods to play/stop preview audio clips in the Editor.
    // These use reflection because AudioUtil is internal in UnityEditor.
    private static readonly System.Type audioUtilType = typeof(AudioImporter).Assembly.GetType("UnityEditor.AudioUtil");
    private static readonly System.Reflection.MethodInfo playClipMethod = audioUtilType?.GetMethod("PlayClip", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public, null, new Type[] { typeof(AudioClip) }, null);
    private static readonly System.Reflection.MethodInfo stopClipMethod = audioUtilType?.GetMethod("StopClip", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public, null, new Type[] { typeof(AudioClip) }, null);

    private static void PlayClip(AudioClip clip)
    {
        if (clip == null)
            return;

        playClipMethod?.Invoke(null, new object[] { clip });
    }

    private static void StopClip(AudioClip clip)
    {
        if (clip == null)
            return;

        stopClipMethod?.Invoke(null, new object[] { clip });
    }

    /// <summary>
    /// Converts an AudioClip to WAV format byte array.
    /// Only supports PCM 16-bit samples.
    /// This method uses the Unity Wav utility approach.
    /// </summary>
    private byte[] AudioClipToWav(AudioClip clip)
    {
        if (clip == null)
            return null;

        float[] samples = new float[clip.samples * clip.channels];
        clip.GetData(samples, 0);

        byte[] wavData = ConvertAudioClipDataToWav(samples, clip.channels, clip.frequency);
        return wavData;
    }

    /// <summary>
    /// Converts float samples to WAV byte array (PCM 16-bit)
    /// Adapted from https://gist.github.com/darktable/2317063
    /// </summary>
    private byte[] ConvertAudioClipDataToWav(float[] samples, int channels, int sampleRate)
    {
        MemoryStream stream = new MemoryStream();
        BinaryWriter writer = new BinaryWriter(stream);

        int sampleCount = samples.Length;

        // RIFF header
        writer.Write(System.Text.Encoding.UTF8.GetBytes("RIFF"));
        writer.Write(36 + sampleCount * 2); // file size minus 8 bytes
        writer.Write(System.Text.Encoding.UTF8.GetBytes("WAVE"));

        // fmt chunk
        writer.Write(System.Text.Encoding.UTF8.GetBytes("fmt "));
        writer.Write(16); // Sub-chunk size
        writer.Write((short)1); // Audio format = PCM
        writer.Write((short)channels);
        writer.Write(sampleRate);
        writer.Write(sampleRate * channels * 2); // Byte rate
        writer.Write((short)(channels * 2)); // Block align
        writer.Write((short)16); // Bits per sample

        // data chunk
        writer.Write(System.Text.Encoding.UTF8.GetBytes("data"));
        writer.Write(sampleCount * 2); // Subchunk2Size

        // Write sample data
        short[] intData = new short[sampleCount];
        for (int i = 0; i < sampleCount; i++)
        {
            float sample = Mathf.Clamp(samples[i], -1f, 1f);
            intData[i] = (short)(sample * short.MaxValue);
        }

        for (int i = 0; i < intData.Length; i++)
        {
            writer.Write(intData[i]);
        }

        writer.Flush();
        writer.Close();

        return stream.ToArray();
    }

    [Serializable]
    private class ConversionResponse
    {
        public string windows_path;
        public string file_path;
    }
}