问题描述
我尝试开发一个音频字幕工具,并使用 Naudio 生成波形供用户识别声音,每个音频大约 1 小时,我发现某些音频的波形与中间的声音不匹配的音频。
这是代码
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
这里是宽度的代码:
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);
解决方法
如果无法访问您的特定源文件,我们就无法重现您的问题,尤其是因为我不知道 width
有什么价值,所以这将是一些猜测。根据音频文件,并假设您使用的是 Mark 的 NAudio.WaveFormRenderer
代码,这可能是完全准确的。
老实说,从代码和拉伸的图像来看,我不确定您是否已将图像与时间戳正确同步。如果您在初始化 4 个不同的 PeakProvider
变体时得到相似的结果,那么几乎可以肯定您的缩放有问题。
很遗憾您没有提供实际的显示代码,所以我无法指出错误可能在哪里。您需要返回并交叉检查将时间映射到渲染波形图像宽度的代码。
我在周末玩了这个文件,我有理由确定主要问题是您的计算与 WaveFormRenderer
类完成的计算之间存在脱节,这导致了长时间的漂移。
Here's the code 由 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,这样您就可以在没有漂移的情况下同步播放。这肯定比尝试重新调整代码中的所有内容以适应非常轻微的每像素漂移更简单。