5
  1. 是否有任何与音频/编程相关的堆栈交换站点?
  2. 我正在尝试在 WinForms中制作波形
  3. 我应该使用什么算法?

例如,如果我每个像素(垂直线)有 200 个样本,我应该从 200 个样本的那部分中抽取最低和最高样本吗?或者我应该绘制低样本和高样本的平均值吗?也许两者都有不同的颜色?

4

5 回答 5

9

这将帮助您在 C# 中使用 nAudio 从音频文件生成波形...

using NAudio.Wave;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

public partial class test : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
    string strPath = Server.MapPath("audio/060.mp3");
    string SongID = "2";
    byte[] bytes = File.ReadAllBytes(strPath);
    WriteToFile(SongID,strPath, bytes);
    Response.Redirect("Main.aspx");
    }

private void WriteToFile(string SongID, string strPath, byte[] Buffer)
{
    try
    {
        int samplesPerPixel = 128;
        long startPosition = 0;
        //FileStream newFile = new FileStream(GeneralUtils.Get_SongFilePath() + "/" + strPath, FileMode.Create);
        float[] data = FloatArrayFromByteArray(Buffer);

        Bitmap bmp = new Bitmap(1170, 200);

        int BORDER_WIDTH = 5;
        int width = bmp.Width - (2 * BORDER_WIDTH);
        int height = bmp.Height - (2 * BORDER_WIDTH);

        NAudio.Wave.Mp3FileReader reader = new NAudio.Wave.Mp3FileReader(strPath, wf => new NAudio.FileFormats.Mp3.DmoMp3FrameDecompressor(wf));
        NAudio.Wave.WaveChannel32 channelStream = new NAudio.Wave.WaveChannel32(reader);

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

        using (Graphics g = Graphics.FromImage(bmp))
        {

            g.Clear(Color.White);
            Pen pen1 = new Pen(Color.Gray);
            int size = data.Length;

            string hexValue1 = "#009adf";
            Color colour1 = System.Drawing.ColorTranslator.FromHtml(hexValue1);
            pen1.Color = colour1;

            Stream wavestream = new NAudio.Wave.Mp3FileReader(strPath, wf => new NAudio.FileFormats.Mp3.DmoMp3FrameDecompressor(wf));

            wavestream.Position = 0;
            int bytesRead1;
            byte[] waveData1 = new byte[samplesPerPixel * bytesPerSample];
            wavestream.Position = startPosition + (width * bytesPerSample * samplesPerPixel);

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

            }
        }

        string filename = Server.MapPath("image/060.png");
        bmp.Save(filename);
        bmp.Dispose();

    }
catch (Exception e)
    {

    }
}
public float[] FloatArrayFromStream(System.IO.MemoryStream stream)
{
    return FloatArrayFromByteArray(stream.GetBuffer());
}

public float[] FloatArrayFromByteArray(byte[] input)
{
    float[] output = new float[input.Length / 4];
    for (int i = 0; i < output.Length; i++)
    {
        output[i] = BitConverter.ToSingle(input, i * 4);
    }
    return output;
}

}
于 2013-11-25T10:48:29.480 回答
6
  1. 试试 dsp.stackexchange.com

  2. 每个像素有 200 个样本,您可以尝试多种方法。无论您做什么,通常最好在 0 上方和下方绘制每条垂直线,即。分别处理正负样本值。可能最简单的方法就是计算 RMS。在如此低的分辨率下,峰值可能会给您带来误导性的波形表示。

于 2012-07-13T08:14:38.583 回答
1

您可以使用代码项目中的AudioControl

看看这个:在 C# 中生成各种音频波形

如果最初实现您的代码,这些项目可能对您有用:

于 2012-07-12T12:26:03.017 回答
1

万一有人遇到这个:

您可以将每个像素的样本视为缩放级别,在更高级别(缩小更多),出于性能原因,您可能希望对其进行二次采样。

您很可能需要一个适合屏幕的固定宽度来绘制并使用虚拟滚动(因此您可能没有几百万像素的绘制区域)。

您可以通过迭代音频数据来计算每个像素的值:跳过(滚动位置 * 每个像素的样本)+(像素 * 每个像素的样本)每个像素获取样本。这允许高性能无限缩放和滚动,因为您只读取和绘制最小量来填充视图。滚动宽度是用音频数据长度/每像素样本数计算的。

音频样本通常以两种方式之一显示,即样本范围的峰值或 rms 值。rms 值是通过对样本范围内所有值的平方求和来计算的,将总和除以样本长度,如果是平方根,则 rms 值(rms 会比平均值高一点,是感知响度的一个很好的度量)

您可以通过多种方式提高性能,例如增加子采样(导致细节丢失)、限制滚动和使绘制请求可取消,以防新的滚动在渲染之前触发。

于 2017-10-18T12:06:44.103 回答
0

只是为了记录它,如果你想让音频文件填充输出图像的宽度

samplesPerPixel = (reader.Length / bytesPerSample) / width ;
于 2019-12-07T16:27:04.693 回答