首页 > 解决方案 > Naudio generated audio wave form doesn't match the sound for some .wav file and .m4a file

问题描述

I tried to develop a tool for subtitling of audio and use Naudio to generate wave form for user to identify the sound, each audio is around 1 hour and I find for some audio the wave from doesn't match sound from the middle of audio.

Here is the code

public static class WaveFormRendererTool
    {
        public static void draw(int width, string filename)
        {
            string imagepath = filename+".png";
            var maxPeakProvider = new MaxPeakProvider();
            var rmsPeakProvider = new RmsPeakProvider(200); // e.g. 200
            var samplingPeakProvider = new SamplingPeakProvider(200); // e.g. 200
            var averagePeakProvider = new AveragePeakProvider(4); // e.g. 4

            SolidBrush brush = new SolidBrush(Color.Green);

            var myRendererSettings = new StandardWaveFormRendererSettings();
            //var myRendererSettings = new SoundCloudBlockWaveFormSettings(Color.Red,Color.Green,Color.Yellow,Color.Blue);
            myRendererSettings.Width = width;
            myRendererSettings.TopHeight = 75;
            myRendererSettings.BottomHeight = 75;
            myRendererSettings.BackgroundColor = Color.White;
            myRendererSettings.PixelsPerPeak = 1;
            myRendererSettings.TopPeakPen = new Pen(brush);
            myRendererSettings.BottomPeakPen = new Pen(brush);
            myRendererSettings.TopSpacerPen = new Pen(brush);
            



            
            var renderer = new WaveFormRenderer();
            var audioFilePath = filename;
            var image = renderer.Render(audioFilePath, averagePeakProvider, myRendererSettings);
           /* if (File.Exists(imagepath)) {
                File.Delete(imagepath);
            }*/
            image.Save(imagepath, ImageFormat.Png);
            renderer=null;
        }

the wave form is flat but already speak

Here are code for width:


                MediaFoundationReader wf = new MediaFoundationReader(file.FullName);
                audioLength = wf.TotalTime.TotalSeconds;
                int width = Convert.ToInt32(wf.TotalTime.TotalSeconds*10);
                
                canvas.Width = width * canstf.ScaleX;
                canvaswidth = canvas.Width;
                canvas.Height = 150;
                img.Width = width;
                //img.Height = 100;
                //img.Height = 100

                img.Source = null;
                WaveFormRendererTool.draw(width, file.FullName);
                img.Source = ImageRotation.LoadImageFile(file.FullName + ".png");
                scroller1.ScrollToHorizontalOffset(0);
                initialCanvas(width);

标签: c#naudiowaveform

解决方案


如果无法访问您的特定源文件,我们将无法重现您的问题,特别是因为我不知道有什么价值width,所以这将是一些猜测。根据音频文件,假设您使用的是 Mark 的NAudio.WaveFormRenderer代码,这可能是完全准确的。

老实说,从代码和拉伸的图像来看,我不确定您是否已将图像与时间戳正确同步。如果您PeakProvider在初始化 4 个不同的变体时得到了相似的结果,那么几乎可以肯定您的缩放有问题。

不幸的是,您没有提供实际的显示代码,所以我无法指出错误可能出在哪里。您需要返回并交叉检查将时间映射到渲染波形图像宽度的代码。


我在周末玩了这个文件,我有理由确定主要问题是你的计算和WaveFormRenderer课堂上的计算之间存在脱节,这导致了长时间的漂移。

这是用于WaveFormRenderer确定每个柱将使用多少个样本的代码:

int bytesPerSample = (reader.WaveFormat.BitsPerSample / 8);
var samples = reader.Length / (bytesPerSample);
var samplesPerPixel = (int)(samples / settings.Width);
var stepSize = settings.PixelsPerPeak + settings.SpacerPixels;
peakProvider.Init(reader, samplesPerPixel * stepSize);

使用您的代码调用它,将samplesPerPixel截断为 1599 - 在 1/10 秒内低于样本数的一小部分。因此,不是在渲染图像中获得每像素 0.1 秒,而是每像素获得 0.0999375 秒。在文件中的 00:24:14(您的屏幕截图所在的位置)累积的漂移约为 0.91 秒。

幸运的是,修复很简单,如果所有关于舍入错误的讨论有点违反直觉:在计算宽度时使用截断而不是舍入:

int width = (int)(wf.TotalTime.TotalSeconds*10);

这应该可以保证samplesPerPixel计算结果始终为 1600 而不是 1599,从而使您可以同步播放而不会出现漂移。这肯定比尝试重新调整代码中的所有内容以适应非常轻微的每像素漂移要简单。


推荐阅读