Can't figure out how to grab files for use in NAudio in a Blazor setup

110 Views Asked by At

For the last several days I have been struggling with the very starting points of a web-app I've been trying to build.

The intention is for it to grab audio files that are already on the server, do some stuff to them (concatenating, mixing, etcetera) based on the user's requirements, and post an output.mp3 file that the user can then download.

However, it's the first part that I've been struggling with. No matter what I do, I just can't figure out how to grab a .wav or any other audio format file from the server.

I have tried grabbing it via an Http.GetAsyncStream("path/to/file.wav"); call, but that gets me stuck with a garbage stream data I can't convert into anything else, because NAudio is missing mfplat.dll on the Github Pages server.

I have tried other Http GetAsync methods, but that left me with even less to work with.

I have tried just trying to read the file straight up via var first = new AudioFileReader("path/to/file.wav"); and that consistently errors out with System.IO.DirectoryNotFoundException: IO_PathNotFound_Path, /sounds/testing/switch.wav, even though it absolutely is in the root folder of the server, and the javascript side of Blazor can actually read it.

After several days of Googling and trying to figure it out myself, I'm stuck. I'm clearly missing something baseline to how Blazor functions, but I have no idea what.

Any help? Please?

EDIT: As requested, here are a few of my attempts.

public void ConcatAudio()
{
    audioTest = new WaveFileReader("sounds/testing/switch.wav");
}

This was what I started with. I expected this to set the audioTest variable to the grabbed .wav file, for future use with NAudio.

Instead it error out with an System.IO.DirectoryNotFoundException: IO_PathNotFound_Path, /sounds/testing/switch.wav error.

I also tried several variants of this.

protected override async Task OnInitializedAsync()
{
    audioTest = (WaveFormatConversionStream) await Http.GetStreamAsync("sounds/testing/switch.wav");
}

I expect it to do the same, give me a variable with the .wav file in it for future use with NAudio.

These either error out with an invalid cast error, or, as the only one where I somewhat succeeded, gave me a System.IO.Stream that I couldn't really do anything with, as I needed it specifically in a format that NAudio would accept.

If required, here's a link to the full code repo, though 99% of it is the starting Blazor project. https://github.com/DestinyPlayer/Project-Biovocoder

1

There are 1 best solutions below

8
SMSTJ On

I will be honest with you this isnt all that pretty and I dont know if the AudioFileReader object we get out of it is going to be "undamaged". If there still are issues with this id recomend taking a look at some source code of NAudio and to try to "recosntruct" some of the constructors that are giving you an issue, like are are doing with AudioFileReader.

@code{
    public AudioFileReader? audioTest;

    protected override async Task OnInitializedAsync()
    {
        //this is to get around getting a HttpResponseStream without length
        var cont = await Http.GetAsync("sounds/testing/switch.wav");
        var firstStream = await cont.Content.ReadAsStreamAsync();
        audioTest = Extensions.GetAudioFileReaderFromStream(firstStream, ".wav");

    await base.OnInitializedAsync();
    }
}

This is not my own Idea the credit belongs to the GithubUser: https://github.com/EitanRa who posted a really good solution in this issue: https://github.com/naudio/NAudio/issues/826

public static class Extensions
{
    public static AudioFileReader? GetAudioFileReaderFromStream(Stream stream, string fileExt)
    {
        try
        {
            AudioFileReader reader = (AudioFileReader)FormatterServices.GetUninitializedObject(typeof(AudioFileReader));

            Type type = reader.GetType();
            type.GetField("lockObject", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(reader, new object());
            var readerStream = GetWaveStream(stream, fileExt);
            type.GetField("readerStream", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(reader, readerStream);
            var sbps = readerStream.WaveFormat.BitsPerSample / 8 * readerStream.WaveFormat.Channels;
            type.GetField("sourceBytesPerSample", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(reader, sbps);
            var sampleChannel = new SampleChannel(readerStream, forceStereo: false);
            type.GetField("sampleChannel", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(reader, sampleChannel);
            var dbps = 4 * sampleChannel.WaveFormat.Channels;
            type.GetField("destBytesPerSample", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(reader, dbps);
            var std = dbps * (readerStream.Length / sbps);
            type.GetField("length", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(reader, std);

            return reader;
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
            return null;
        }
    }

    private static WaveStream GetWaveStream(Stream stream, string fileExt)
    {
        WaveStream readerStream = null;
        if (fileExt.Equals(".wav", StringComparison.OrdinalIgnoreCase))
        {
            readerStream = new WaveFileReader(stream);
            if (readerStream.WaveFormat.Encoding != WaveFormatEncoding.Pcm && readerStream.WaveFormat.Encoding != WaveFormatEncoding.IeeeFloat)
            {
                readerStream = WaveFormatConversionStream.CreatePcmStream(readerStream);
                readerStream = new BlockAlignReductionStream(readerStream);
            }
        }
        else if (fileExt.Equals(".mp3", StringComparison.OrdinalIgnoreCase))
        {
            if (Environment.OSVersion.Version.Major < 6)
            {
                readerStream = new Mp3FileReader(stream);
            }
            else
            {
                readerStream = new StreamMediaFoundationReader(stream);
            }
        }
        else if (fileExt.Equals(".aiff", StringComparison.OrdinalIgnoreCase) || fileExt.Equals(".aif", StringComparison.OrdinalIgnoreCase))
        {
            readerStream = new AiffFileReader(stream);
        }
        else
        {
            readerStream = new StreamMediaFoundationReader(stream);
        }
        return readerStream;
    }
}