the input file of the class is an ai generated song the length will vary, you wrote me a c# class for fading in and out volume but it seems like it's not respecting or understanding the length of each generation or something it sounds like it's being cut short please fix and return fully fixed.

using System;
using System.Diagnostics;
using System.IO;
using System.Threading.Tasks;

public class SoxVolumeFader
{
    /// <summary>
    /// Applies fade in and fade out volume effect to an audio file using SoX.
    /// Automatically calculates a medium fade in and slightly quicker fade out based on audio length.
    /// </summary>
    /// <param name="inputFile">Full path to the input audio file.</param>
    /// <param name="soxExePath">Full path to Sox executable.</param>
    public static async Task ApplyFadeAsync(string inputFile, string soxExePath)
    {
        if (string.IsNullOrWhiteSpace(inputFile))
            throw new ArgumentException("Input file path is required.", nameof(inputFile));
        if (string.IsNullOrWhiteSpace(soxExePath))
            throw new ArgumentException("SoX executable path is required.", nameof(soxExePath));
        if (!File.Exists(inputFile))
            throw new FileNotFoundException("Input file not found.", inputFile);
        if (!File.Exists(soxExePath))
            throw new FileNotFoundException("SoX executable not found.", soxExePath);

        const double minFadeDuration = 0.01; // fades under 10ms considered zero
        const double minStayDuration = 0.001; // 1ms minimal stay duration to avoid overlap errors

        double durationSeconds = await GetAudioDurationAsync(inputFile, soxExePath);

        if (durationSeconds <= 0)
            throw new InvalidOperationException("Audio duration must be positive.");

        // Determine fade length: 10% of the audio length, clamped between 0.5s and 5s (adjustable)
        double fadeDuration = durationSeconds * 0.1;
        fadeDuration = Math.Clamp(fadeDuration, 0.5, 5.0);

        // If audio too short to apply fades properly, reduce fades proportionally
        double totalFade = fadeDuration * 2;
        if (totalFade > durationSeconds)
        {
            // Scale fades to fit duration
            fadeDuration = durationSeconds / 2;
            totalFade = durationSeconds; // Exactly the whole duration
        }

        double stayDuration = durationSeconds - totalFade;

        // Handle SoX overlap error workaround here:
        if (stayDuration < minStayDuration)
        {
            // stayDuration too small or zero
            // If both fades > 0, SoX throws overlap error. Fix by zeroing one fade
            if (fadeDuration > 0)
            {
                // Since fades are symmetrical, set fadeOut to zero here
                stayDuration = 0;
            }
            else
            {
                // fades zero already - safe
                stayDuration = 0;
            }
        }

        // Assign fadeIn and fadeOut durations
        double fadeIn = fadeDuration;
        // Make fadeOut slightly quicker: for example 80% of fadeIn duration
        double fadeOut = (stayDuration < minStayDuration) ? 0 : fadeDuration * 0.8;

        // Adjust total stay duration accordingly
        // total duration = fadeIn + stayDuration + fadeOut
        // So recalculate stayDuration as total - fadeIn - fadeOut:
        stayDuration = durationSeconds - (fadeIn + fadeOut);
        if (stayDuration < 0)
            stayDuration = 0;

        // Final safety clamp to avoid negatives
        fadeIn = Math.Max(0, fadeIn);
        fadeOut = Math.Max(0, fadeOut);
        stayDuration = Math.Max(0, stayDuration);

        string inputDir = Path.GetDirectoryName(inputFile) ?? Directory.GetCurrentDirectory();

        string tempOutputFile = Path.Combine(
            inputDir,
            Path.GetFileNameWithoutExtension(inputFile) + "_fade_temp" + Path.GetExtension(inputFile));

        // Format arguments with two decimals precision
        string args = $"\"{inputFile}\" \"{tempOutputFile}\" fade t {fadeIn:F2} {stayDuration:F2} {fadeOut:F2}";

        var processInfo = new ProcessStartInfo
        {
            FileName = soxExePath,
            Arguments = args,
            CreateNoWindow = true,
            UseShellExecute = false,
            RedirectStandardError = true,
            RedirectStandardOutput = true,
        };

        using (var process = new Process { StartInfo = processInfo })
        {
            var tcs = new TaskCompletionSource<bool>();

            process.EnableRaisingEvents = true;
            process.Exited += (s, e) => tcs.TrySetResult(true);

            process.Start();

            string stdOut = await process.StandardOutput.ReadToEndAsync();
            string stdErr = await process.StandardError.ReadToEndAsync();

            await tcs.Task;

            if (process.ExitCode != 0)
            {
                try
                {
                    if (File.Exists(tempOutputFile)) File.Delete(tempOutputFile);
                }
                catch { /* ignore cleanup failures */ }

                throw new Exception($"SoX process failed with exit code {process.ExitCode}: {stdErr}");
            }
        }

        // Replace original file with faded version
        try
        {
            File.Delete(inputFile);
            File.Move(tempOutputFile, inputFile);
        }
        catch (Exception ex)
        {
            try
            {
                if (File.Exists(tempOutputFile)) File.Delete(tempOutputFile);
            }
            catch { /* ignore cleanup failures */ }

            throw new IOException("Failed to replace original audio file with faded version.", ex);
        }
    }

    /// <summary>
    /// Get audio duration using SoX.
    /// </summary>
    private static async Task<double> GetAudioDurationAsync(string inputFile, string soxExePath)
    {
        var processInfo = new ProcessStartInfo
        {
            FileName = soxExePath,
            Arguments = $"--i -D \"{inputFile}\"",
            CreateNoWindow = true,
            UseShellExecute = false,
            RedirectStandardOutput = true,
            RedirectStandardError = true,
        };

        using (var process = new Process { StartInfo = processInfo })
        {
            var tcs = new TaskCompletionSource<bool>();
            process.EnableRaisingEvents = true;
            process.Exited += (s, e) => tcs.TrySetResult(true);

            process.Start();

            string output = await process.StandardOutput.ReadToEndAsync();
            string error = await process.StandardError.ReadToEndAsync();

            await tcs.Task;

            if (process.ExitCode != 0)
                throw new Exception($"SoX failed to get audio duration: {error}");

            if (double.TryParse(output.Trim(), out double duration))
                return duration;

            throw new Exception("Failed to parse audio duration from SoX output.");
        }
    }
}