C#NAudio渲染没有DMO或ACM的波形ASP.net

时间:2016-09-08 19:19:55

标签: c# naudio n-layer

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

NLayer解压缩器的格式可能是32位浮点数而不是16位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;
    }
}

1 个答案:

答案 0 :(得分:2)

终于明白了。感谢@MarkHeath的意见和建议(以及构建令人惊叹的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;