please fix my script I want the user to be able to set the max recording time and to clip the audio clip to it's actual recording length before setting it, the ui must not be the max recording time but instead be the clipped time, you can do this by keeping track with how many seconds have passed while recording to determine it's real length. provide full script fixed. Save tokens by not talking.

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;

    // Additional UI parameters
    private float lengthAdjust = 1.0f;
    private float inferenceCfgRate = 0.7f;
    private bool autoF0Adjust = true;
    private int pitchShift = 0;

    // 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;

    // Hidden AudioSource for playback control in EditorWindow
    private AudioSource editorAudioSource;

    // --- Recording ---
    private string[] micDevices;
    private int selectedMicIndex = 0;

    private bool isRecordingSource = false;
    private bool isRecordingReference = false;

    private AudioClip recordingClipSource;
    private AudioClip recordingClipReference;

    private const int maxRecordingLength = 30;
    private const int defaultSampleRate = 44100;

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

    private void OnEnable()
    {
        logo = Resources.Load<Texture2D>("seed_vc_logo");
        EditorApplication.update += EditorUpdate;

        micDevices = Microphone.devices;
        if (micDevices == null || micDevices.Length == 0)
        {
            micDevices = new string[] { "No Microphone Devices Found" };
            selectedMicIndex = 0;
        }
        else
            selectedMicIndex = 0;
    }

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

        if (editorAudioSource != null && editorAudioSource.gameObject != null)
            DestroyImmediate(editorAudioSource.gameObject);
    }

    private void EditorUpdate()
    {
        if (isPlaying && editorAudioSource != null)
        {
            if (!editorAudioSource.isPlaying)
            {
                isPlaying = false;
                Repaint();
            }
            else
            {
                Repaint();
            }
        }
    }

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

        GUILayout.Space(10);

        if (logo != null)
        {
            float maxWidth = position.width;
            float aspectRatio = (float)logo.height / logo.width;
            float drawWidth = Mathf.Min(logo.width, maxWidth);
            float drawHeight = drawWidth * aspectRatio;

            float posX = (position.width - drawWidth) / 2f;
            Rect rect = GUILayoutUtility.GetRect(drawWidth, drawHeight);
            rect.x = posX;

            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("Additional Conversion Parameters:", EditorStyles.boldLabel);
        lengthAdjust = EditorGUILayout.Slider("Length Adjust", lengthAdjust, 0.1f, 3f);
        inferenceCfgRate = EditorGUILayout.Slider("Inference CFG Rate", inferenceCfgRate, 0f, 1f);
        autoF0Adjust = EditorGUILayout.Toggle("Auto F0 Adjust", autoF0Adjust);
        pitchShift = EditorGUILayout.IntSlider("Pitch Shift", pitchShift, -12, 12);

        GUILayout.Space(10);

        EditorGUILayout.LabelField("Select Recording Device (Microphone):", EditorStyles.boldLabel);

        if (micDevices.Length == 0 || micDevices[0] == "No Microphone Devices Found")
        {
            EditorGUILayout.HelpBox("No microphone devices found on this machine.", MessageType.Warning);
        }
        else
        {
            int newSelectedIndex = EditorGUILayout.Popup(selectedMicIndex, micDevices);
            if (newSelectedIndex != selectedMicIndex)
            {
                selectedMicIndex = newSelectedIndex;
                if (isRecordingSource) StopRecordingSource();
                if (isRecordingReference) StopRecordingReference();
            }
        }

        GUILayout.Space(10);

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

        if (micDevices.Length > 0 && micDevices[0] != "No Microphone Devices Found")
        {
            if (!isRecordingSource)
            {
                if (GUILayout.Button("Record Source", GUILayout.Width(120)))
                {
                    StartRecordingSource();
                }
            }
            else
            {
                if (GUILayout.Button("Stop Recording", GUILayout.Width(120)))
                {
                    StopRecordingSource();
                }
            }
        }
        EditorGUILayout.EndHorizontal();

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

        if (micDevices.Length > 0 && micDevices[0] != "No Microphone Devices Found")
        {
            if (!isRecordingReference)
            {
                if (GUILayout.Button("Record Reference", GUILayout.Width(120)))
                {
                    StartRecordingReference();
                }
            }
            else
            {
                if (GUILayout.Button("Stop Recording", GUILayout.Width(120)))
                {
                    StopRecordingReference();
                }
            }
        }
        EditorGUILayout.EndHorizontal();

        GUILayout.Space(10);

        EditorGUILayout.LabelField("Save Folder (Drag & Drop a Folder from Project Window):", EditorStyles.boldLabel);

        EditorGUI.BeginChangeCheck();
        saveFolderAsset = (DefaultAsset)EditorGUILayout.ObjectField(saveFolderAsset, typeof(DefaultAsset), false, GUILayout.Height(EditorGUIUtility.singleLineHeight));
        if (EditorGUI.EndChangeCheck())
        {
            if (saveFolderAsset != null)
            {
                string path = AssetDatabase.GetAssetPath(saveFolderAsset);
                if (!string.IsNullOrEmpty(path) && AssetDatabase.IsValidFolder(path))
                {
                    saveFolderPath = path;
                    statusMessage = $"Save folder set to '{saveFolderPath}'.";
                }
                else
                {
                    statusMessage = "Please drag and drop a folder (not a file).";
                    saveFolderAsset = null;
                    saveFolderPath = null;
                }
            }
            else
            {
                saveFolderPath = null;
            }
        }

        GUILayout.Space(15);

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

            _ = ConvertAudioFiles();
        }
        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 drag and drop 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
        {
            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 _);

                if (!saved)
                {
                    statusMessage = "Failed to save the converted file.";
                }
            }
            else
            {
                // statusMessage already set on failure
            }
        }
        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"),
            new MultipartFormDataSection("diffusion_steps", qualityValue.ToString()),
            new MultipartFormDataSection("length_adjust", lengthAdjust.ToString("F2")),
            new MultipartFormDataSection("inference_cfg_rate", inferenceCfgRate.ToString("F2")),
            new MultipartFormDataSection("auto_f0_adjust", autoF0Adjust.ToString().ToLower()),
            new MultipartFormDataSection("pitch_shift", pitchShift.ToString())
        };

        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;
                }

                if (!File.Exists(filePath))
                {
                    statusMessage = $"Returned file does not exist on disk: {filePath}";
                    return null;
                }

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

                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 relativeFolderPath = saveFolderPath.TrimEnd('\\', '/');
            string assetPath = $"{relativeFolderPath}/{fileName}";

            string projectRoot = Directory.GetParent(Application.dataPath).FullName;
            string absoluteSavePath = Path.Combine(projectRoot, assetPath.Replace('/', Path.DirectorySeparatorChar));

            string directoryPath = Path.GetDirectoryName(absoluteSavePath);
            if (!Directory.Exists(directoryPath))
                Directory.CreateDirectory(directoryPath);

            File.WriteAllBytes(absoluteSavePath, fileBytes);

            AssetDatabase.ImportAsset(assetPath, ImportAssetOptions.ForceUpdate);
            AssetDatabase.Refresh();

            AudioImporter importer = AssetImporter.GetAtPath(assetPath) as AudioImporter;
            if (importer != null)
            {
                AudioImporterSampleSettings sampleSettings = importer.defaultSampleSettings;
                sampleSettings.loadType = AudioClipLoadType.DecompressOnLoad;
                sampleSettings.compressionFormat = AudioCompressionFormat.PCM;
                importer.defaultSampleSettings = sampleSettings;
                importer.SaveAndReimport();
            }

            EditorApplication.delayCall += () =>
            {
                AudioClip clip = AssetDatabase.LoadAssetAtPath<AudioClip>(assetPath);
                if (clip == null)
                {
                    Debug.LogWarning($"Failed to load AudioClip at path: {assetPath}");
                    statusMessage = "Failed to load converted audio clip after import.";
                }
                else
                {
                    convertedClip = clip;
                    statusMessage = "File saved successfully. You can play it back below.";
                    EditorGUIUtility.PingObject(convertedClip);
                    Repaint();
                }
            };

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

    private AudioSource GetEditorAudioSource()
    {
        const string objName = "SeedVCEditorAudioSource";
        GameObject go = GameObject.Find(objName);
        if (go == null)
        {
            go = new GameObject(objName);
            go.hideFlags = HideFlags.HideAndDontSave;
            editorAudioSource = go.AddComponent<AudioSource>();
            editorAudioSource.playOnAwake = false;
        }
        else
        {
            editorAudioSource = go.GetComponent<AudioSource>();
            if (editorAudioSource == null)
                editorAudioSource = go.AddComponent<AudioSource>();
        }
        return editorAudioSource;
    }

    private void PlayConvertedClip()
    {
        if (convertedClip == null)
        {
            statusMessage = "Converted clip is not ready to play yet.";
            Debug.LogWarning(statusMessage);
            return;
        }

        AudioSource source = GetEditorAudioSource();

        if (source.isPlaying)
            source.Stop();

        source.clip = convertedClip;
        source.time = 0f;
        source.Play();

        isPlaying = true;
    }

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

        AudioSource source = GetEditorAudioSource();
        source.Stop();
        isPlaying = false;
    }


    #region AudioClip to WAV conversion

    private byte[] AudioClipToWav(AudioClip clip)
    {
        if (clip == null)
            return null;

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

        return ConvertAudioClipDataToWav(samples, clip.channels, clip.frequency);
    }

    private byte[] ConvertAudioClipDataToWav(float[] samples, int channels, int sampleRate)
    {
        MemoryStream stream = new MemoryStream();
        BinaryWriter writer = new BinaryWriter(stream);

        int sampleCount = samples.Length;

        writer.Write(System.Text.Encoding.UTF8.GetBytes("RIFF"));
        writer.Write(36 + sampleCount * 2);
        writer.Write(System.Text.Encoding.UTF8.GetBytes("WAVE"));

        writer.Write(System.Text.Encoding.UTF8.GetBytes("fmt "));
        writer.Write(16);
        writer.Write((short)1);
        writer.Write((short)channels);
        writer.Write(sampleRate);
        writer.Write(sampleRate * channels * 2);
        writer.Write((short)(channels * 2));
        writer.Write((short)16);

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

        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();
    }

    #endregion

    #region Recording Methods

    private void StartRecordingSource()
    {
        if (micDevices == null || micDevices.Length == 0 || micDevices[0] == "No Microphone Devices Found")
        {
            statusMessage = "No microphone device available.";
            return;
        }

        if (isRecordingSource)
            return;

        if (Microphone.IsRecording(micDevices[selectedMicIndex]))
            Microphone.End(micDevices[selectedMicIndex]);

        int minFreq, maxFreq;
        Microphone.GetDeviceCaps(micDevices[selectedMicIndex], out minFreq, out maxFreq);

        int sampleRateToUse = defaultSampleRate;
        if (minFreq != 0 && maxFreq != 0)
        {
            if (defaultSampleRate < minFreq || defaultSampleRate > maxFreq)
            {
                if (minFreq <= 16000 && maxFreq >= 16000)
                    sampleRateToUse = 16000;
                else
                    sampleRateToUse = minFreq;
            }
        }

        try
        {
            recordingClipSource = Microphone.Start(micDevices[selectedMicIndex], false, maxRecordingLength, sampleRateToUse);
            isRecordingSource = true;
            statusMessage = $"Recording Source Audio @ {sampleRateToUse} Hz...";
        }
        catch (Exception ex)
        {
            statusMessage = "Failed to start recording: " + ex.Message;
        }
    }

    private void StopRecordingSource()
    {
        if (!isRecordingSource)
            return;

        Microphone.End(micDevices[selectedMicIndex]);

        int samplePos = Microphone.GetPosition(micDevices[selectedMicIndex]);
        if (samplePos < 100 && recordingClipSource != null)
            samplePos = recordingClipSource.samples;

        if (samplePos > 0 && recordingClipSource != null)
        {
            AudioClip newClip = AudioClip.Create("RecordedSource", samplePos, recordingClipSource.channels, recordingClipSource.frequency, false);
            float[] samples = new float[samplePos * recordingClipSource.channels];
            recordingClipSource.GetData(samples, 0);
            newClip.SetData(samples, 0);

            recordingClipSource = null;
            sourceClip = newClip;
            statusMessage = $"Source recording stopped. Length: {samplePos / (float)newClip.frequency:F2} seconds.";
        }
        else
        {
            statusMessage = "Source recording stopped but no audio data was captured.";
        }

        isRecordingSource = false;
    }

    private void StartRecordingReference()
    {
        if (micDevices == null || micDevices.Length == 0 || micDevices[0] == "No Microphone Devices Found")
        {
            statusMessage = "No microphone device available.";
            return;
        }

        if (isRecordingReference)
            return;

        if (Microphone.IsRecording(micDevices[selectedMicIndex]))
            Microphone.End(micDevices[selectedMicIndex]);

        int minFreq, maxFreq;
        Microphone.GetDeviceCaps(micDevices[selectedMicIndex], out minFreq, out maxFreq);

        int sampleRateToUse = defaultSampleRate;
        if (minFreq != 0 && maxFreq != 0)
        {
            if (defaultSampleRate < minFreq || defaultSampleRate > maxFreq)
            {
                if (minFreq <= 16000 && maxFreq >= 16000)
                    sampleRateToUse = 16000;
                else
                    sampleRateToUse = minFreq;
            }
        }

        try
        {
            recordingClipReference = Microphone.Start(micDevices[selectedMicIndex], false, maxRecordingLength, sampleRateToUse);
            isRecordingReference = true;
            statusMessage = $"Recording Reference Audio @ {sampleRateToUse} Hz...";
        }
        catch (Exception ex)
        {
            statusMessage = "Failed to start recording: " + ex.Message;
        }
    }

    private void StopRecordingReference()
    {
        if (!isRecordingReference)
            return;

        Microphone.End(micDevices[selectedMicIndex]);

        int samplePos = Microphone.GetPosition(micDevices[selectedMicIndex]);
        if (samplePos < 100 && recordingClipReference != null)
            samplePos = recordingClipReference.samples;

        if (samplePos > 0 && recordingClipReference != null)
        {
            AudioClip newClip = AudioClip.Create("RecordedReference", samplePos, recordingClipReference.channels, recordingClipReference.frequency, false);
            float[] samples = new float[samplePos * recordingClipReference.channels];
            recordingClipReference.GetData(samples, 0);
            newClip.SetData(samples, 0);

            recordingClipReference = null;
            referenceClip = newClip;
            statusMessage = $"Reference recording stopped. Length: {samplePos / (float)newClip.frequency:F2} seconds.";
        }
        else
        {
            statusMessage = "Reference recording stopped but no audio data was captured.";
        }

        isRecordingReference = false;
    }

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