【问题标题】:C# NAudio rendering a waveform ASP.net without DMO or ACMC# NAudio 在没有 DMO 或 ACM 的情况下渲染波形 ASP.net
【发布时间】:2016-09-08 19:19:55
【问题描述】:

我正在尝试在 Azure 网站(未安装 ACM 或 DMO 编解码器)上使用 ASP.net 绘制波形,因此我不得不使用 NLayer 来读取 mp3 文件。我下面的代码与常规的 DmoMp3FrameDecompressor 完美配合,但是当我使用 NLayer 解压缩器时,它就不行了。

也许 NLayer 解压器的格式是 32bit Float 而不是 16bit PCM。

byte[] data = new WebClient().DownloadData(URL);

int maxAmplitude = 0;

short[,] dataArray = new short[Width, 2];

//using (Mp3FileReader wavestream = new Mp3FileReader(new MemoryStream(data), wf => new DmoMp3FrameDecompressor(wf)))

using (Mp3FileReader wavestream = new Mp3FileReader(new MemoryStream(data), new Mp3FileReader.FrameDecompressorBuilder(waveFormat => new NLayer.NAudioSupport.Mp3FrameDecompressor(waveFormat))))
{
    WaveChannel32 channelStream = new WaveChannel32(wavestream);

    int bytesPerSample = (wavestream.WaveFormat.BitsPerSample / 8) * channelStream.WaveFormat.Channels;

    wavestream.Position = 0;

    long lenSamples = wavestream.Length / bytesPerSample;

    int samplesPerPixel = (int)(lenSamples / Width);

    int bytesRead1;
    byte[] waveData1 = new byte[samplesPerPixel * bytesPerSample];

    // First get all the data

    for (int x = 0; x < Width; x++)
    {
        short low = 0;
        short high = 0;
        bytesRead1 = wavestream.Read(waveData1, 0, samplesPerPixel * bytesPerSample);
        if (bytesRead1 == 0)
            break;
        for (int n = 0; n < bytesRead1; n += 2)
        {
            short sample = BitConverter.ToInt16(waveData1, n);
            if (sample < low) low = sample;
            if (sample > high) high = sample;
        }

        if (-low > maxAmplitude) maxAmplitude = -low;
        if (high > maxAmplitude) maxAmplitude = high;

        dataArray[x, 0] = low;
        dataArray[x, 1] = high;
    }
}

【问题讨论】:

    标签: c# naudio n-layer


    【解决方案1】:

    终于明白了。感谢 @MarkHeath 的 cmets 和建议(以及构建令人惊叹的 NAudio / NLayer 库)!

    关键是WaveFloatTo16Provider没有Length属性,所以无法计算每个像素的样本数,所以需要有两个循环。一个顺序读取所有单独的样本,然后另一个然后对每个像素的样本进行分组,并计算最大幅度。最后的循环然后将值映射到像素位置并将它们绘制到图像上。如果您不需要AutoFit 代码,那么您可以合并第二个和第三个循环。

    Bitmap bmp = new Bitmap(Width, Height);
    
    using (Graphics g = Graphics.FromImage(bmp))
    {
        g.Clear(Color.White);
        Pen pen1 = new Pen(Color.Gray);
    
        string hexValue = "#" + sColor;
        Color colour1 = System.Drawing.ColorTranslator.FromHtml(hexValue);
        pen1.Color = colour1;
    
        int maxAmplitude = 0;
    
        short[,] dataArray = new short[Width, 2];
    
        using (Mp3FileReader wavestreamFloat = new Mp3FileReader(
               new MemoryStream(new WebClient().DownloadData(URL)), 
               new Mp3FileReader.FrameDecompressorBuilder(
                     waveFormat => new NLayer.NAudioSupport.Mp3FrameDecompressorwaveFormat))))
        {
            IWaveProvider stream16 = new WaveFloatTo16Provider(wavestreamFloat);
    
            int bytesPerSample = (stream16.WaveFormat.BitsPerSample / 8) * stream16.WaveFormat.Channels;
    
            int bytesRead = 0;
            byte[] buffer = new byte[8192];
    
            List<short> rawDataArray = new List<short>();
    
            do
            {
                bytesRead = stream16.Read(buffer, 0, buffer.Length);
    
                for (int n = 0; n < bytesRead; n += bytesPerSample)
                {
                    short sample = BitConverter.ToInt16(buffer, n);
                    rawDataArray.Add(sample);
                }
    
            } while (bytesRead != 0);
    
            // Now that we have all the samples
    
            long lenSamples = rawDataArray.Count;
    
            int samplesPerPixel = (int)(lenSamples / Width);
    
            int nCounter = 0;
    
            for (int x = 0; x < Width; x++)
            {
                short low = 0;
                short high = 0;
    
                for (int n = 0; n < samplesPerPixel; n++)
                {
                    short sample = rawDataArray[nCounter++];
                    if (sample < low) low = sample;
                    if (sample > high) high = sample;
                }
    
                if (-low > maxAmplitude) maxAmplitude = -low;
                if (high > maxAmplitude) maxAmplitude = high;
    
                dataArray[x, 0] = low;
                dataArray[x, 1] = high;
            }
    
            // Now lay it out on the image. This is where we resize it to AutoFit.
    
            for (int x = 0; x < Width; x++)
            {
                short low = dataArray[x, 0];
                short high = dataArray[x, 1];
    
                if (AutoFit)
                {
                    low = (short)((int)low * (int)short.MaxValue / (int)maxAmplitude);
                    high = (short)((int)high * (int)short.MaxValue / (int)maxAmplitude);
                }
    
                float lowPercent = ((((float)low) - short.MinValue) / ushort.MaxValue);
                float highPercent = ((((float)high) - short.MinValue) / ushort.MaxValue);
                float lowValue = Height * lowPercent;
                float highValue = Height * highPercent;
    
                g.DrawLine(pen1, x, lowValue, x, highValue);
            }
            g.Flush();
        }
    }
    
    return bmp;
    

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-10
    • 2018-04-13
    • 1970-01-01
    • 1970-01-01
    • 2019-09-14
    相关资源
    最近更新 更多