使用NAudio的C#实时波形数据图

C# Real time waveform data plot using NAudio
2021-07-22
  •  译文(汉语)
  •  原文(英语)

我是处理wav文件和C#的新手.我的目标是在wavfile波形中实时绘制数据.我的意思是在录制声音(wav)文件时,我想同时绘制其图形.我搜索了一些声音库并决定使用NAudio.(不知道这对我来说是最好的选择.我愿意接受有关选择音频库的任何建议).但是我不知道使用声音进行实时数据绘图的想法.有人建议使用GDI,但正如我所说,我是新手,我认为有效使用GDI会花费太多时间.如果我必须学习GDI,请分享任何可以帮助像我这样的初学者的文章.其实我看起来不知道我应该从哪里开始.需要指导:))我有一个问题.

NAudio的教程之一,他使用字节数组在Chart中绘制波形.如果您知道wav文件的大小,那很好.但是它工作得太慢,对于大于10mb的wav文件,它会给出Out of Memory Exception.下面的代码指的是我的意思.

    OpenFileDialog open = new OpenFileDialog();
    open.Filter = "Wave File (*.wav)|*.wav;";
    if (open.ShowDialog() != DialogResult.OK) return;
    chart1.Series.Add("wave");
    chart1.Series["wave"].ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.FastLine;
    chart1.Series["wave"].ChartArea = "ChartArea1";
    NAudio.Wave.WaveChannel32 wave = new NAudio.Wave.WaveChannel32(new NAudio.Wave.WaveFileReader(open.FileName));

    byte[] buffer = new byte[426565];
    int read;
    while (wave.Position < wave.Length)
    {
        read = wave.Read(buffer, 0, 426565);
        for (int i = 0; i < read / 4; i++)
        {
            chart1.Series["wave"].Points.Add(BitConverter.ToSingle(buffer, i * 4));
        }
    }

有没有一种方法可以更快地执行此操作?

速聊1:
作为Gigasoft的创建者,请参阅我们的DirectX / Direct3D Charting wav数据演示,示例123.该演示显示WinForms,WPF和C ++ / MFC纯本机中的exe.通过垂直线注释实时更新播放位置,显示在播放和拖动视口等过程中没有滞后的12M点连续更新.还显示了一个方便的自定义x轴:Minutes:Seconds.可通过鼠标和鼠标滚轮缩放.显示当前缩放区域的缩放框以及通道的完整波形.它的图表类似于Adobe Audition或Nero wave编辑器,仅包含几行代码.
解决过程1

如果绘制每个样本,由于音频通常每秒包含数千个样本,最终将产生难以管理的大波形.绘制波形的常见方法是选择一段时间内的最大值,然后绘制一条垂直线来表示它.例如,如果您有一首三分钟的歌曲,并且想要一个约600像素宽的波形,那么每个像素将代表大约三分之一的时间.因此,您会在三分之二秒的时间内找到最大的采样值,然后使用该值来绘制波形.

另外,在示例代码中,您正在读取奇数个字节.但是,由于这是浮点音频,因此您应始终以四个字节的倍数读取.

解决过程2

这对我有用

            WaveChannel32 wave = new WaveChannel32(new WaveFileReader(txtWave.Text));
            int sampleSize = 1024;
            var bufferSize = 16384 * sampleSize;
            var buffer = new byte[bufferSize];
            int read = 0;
            chart.Series.Add("wave");
            chart.Series["wave"].ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.FastLine;
            chart.Series["wave"].ChartArea = "ChartArea1";
            while (wave.Position < wave.Length)
            {
                read = wave.Read(buffer, 0, bufferSize);
                for (int i = 0; i < read / sampleSize; i++)
                {
                    var point = BitConverter.ToSingle(buffer, i * sampleSize);

                    chart.Series["wave"].Points.Add(point);
                }
            }
速聊1:
我们如何处理Webm文件?

I am new on processing wav file and C#.My goal is to real time data plotting in waveform of wavfile.I mean while recording sound(wav) file,i want to plot its graph simultaneously.I searched some sound libiraries and decide to use NAudio.(Dont know it is the best choice for me.I am open to any suggestions about choosing audio libirary). However i have no idea about real time data plotting using sound. Some people suggest GDI but as i said i am new and i think it will take too much time to use GDI efficiently.If i must learn GDI,pls share any article that can help a beginner like me. Actually i look like dont know where should i start. Need to be guided :)) And i have a question.

One of the tutorial of NAudio,he works with byte array to plot the waveform in Chart.It is fine if you know the size of wav file.However it works too slow and gives Out of Memory Exception for bigger wav files than 10mb.The code below refers to what i mean.

    OpenFileDialog open = new OpenFileDialog();
    open.Filter = "Wave File (*.wav)|*.wav;";
    if (open.ShowDialog() != DialogResult.OK) return;
    chart1.Series.Add("wave");
    chart1.Series["wave"].ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.FastLine;
    chart1.Series["wave"].ChartArea = "ChartArea1";
    NAudio.Wave.WaveChannel32 wave = new NAudio.Wave.WaveChannel32(new NAudio.Wave.WaveFileReader(open.FileName));

    byte[] buffer = new byte[426565];
    int read;
    while (wave.Position < wave.Length)
    {
        read = wave.Read(buffer, 0, 426565);
        for (int i = 0; i < read / 4; i++)
        {
            chart1.Series["wave"].Points.Add(BitConverter.ToSingle(buffer, i * 4));
        }
    }

Is there a way to perform this operation faster?

Talk1:
As Gigasoft founder, see our DirectX /Direct3D Charting wav data demo, example 123 The demo shows exes in WinForms, WPF, and C++/MFC pure native. Real-time updated with play position via vertical line annotation showing 12M points continuously updated with no lag while playing and dragging viewport, etc. Also shows an easy custom x axis of Minutes:Seconds. Zoom-able via mouse and mouse-wheel. Shows zoom-box of current zoomed area along with full waveform of channels. It's charting similar to Adobe Audition or Nero wave editor with just a few lines of code.
Solutions1

If you plot every single sample, you will end up with a waveform that is unmanageably large since audio usually contains many thousands of samples per second. A common way waveforms are drawn is by selecting the maximum value over a period of time, and then drawing a vertical line to represent it. For example, if you had a three minute song, and wanted a waveform around 600 pixels wide, each pixel would represent about a third of a second. So you'd find the largest sample value in that third of a second and use that to plot your waveform.

Also, in your sample code you are reading an odd number of bytes. But since this is floating point audio, you should always read in multiples of four bytes.

Solutions2

This worked for me

            WaveChannel32 wave = new WaveChannel32(new WaveFileReader(txtWave.Text));
            int sampleSize = 1024;
            var bufferSize = 16384 * sampleSize;
            var buffer = new byte[bufferSize];
            int read = 0;
            chart.Series.Add("wave");
            chart.Series["wave"].ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.FastLine;
            chart.Series["wave"].ChartArea = "ChartArea1";
            while (wave.Position < wave.Length)
            {
                read = wave.Read(buffer, 0, bufferSize);
                for (int i = 0; i < read / sampleSize; i++)
                {
                    var point = BitConverter.ToSingle(buffer, i * sampleSize);

                    chart.Series["wave"].Points.Add(point);
                }
            }
Talk1:
How do we do the same with a Webm file ?
转载于:https://stackoverflow.com/questions/17378260/c-sharp-real-time-waveform-data-plot-using-naudio

本人是.net程序员,因为英语不行,使用工具翻译,希望对有需要的人有所帮助
如果本文质量不好,还请谅解,毕竟这些操作还是比较费时的,英语较好的可以看原文

留言回复
我们只提供高质量资源,素材,源码,坚持 下了就能用 原则,让客户花了钱觉得值
上班时间 : 周一至周五9:00-17:30 期待您的加入