NAudio中AudioFileReader.Length与TotalTime的关联及波形图适配问题
嘿,这个问题我刚好碰到过,让我一步步帮你解决!
理清TotalTime和Length的关联
首先得明确AudioFileReader里这两个属性的核心关系:
Length:是解码后PCM音频的总字节数(MP3是压缩格式,AudioFileReader会先把它解码成原始PCM数据,这个值就是解码后的数据大小)TotalTime:是基于PCM参数计算出的实际播放时长,公式是:
反过来,用时长也能反推PCM字节数:TotalTime = TimeSpan.FromSeconds(Length / (SampleRate * Channels * BitsPerSample/8))
这俩是完全匹配的,因为Length = SampleRate * Channels * (BitsPerSample/8) * TotalTime.TotalSecondsTotalTime本质上就是用Length和WaveFormat的参数计算出来的。
解决波形图空白问题:按时间动态计算Bitmap宽度
你想要1秒对应15像素,直接用TotalTime算宽度就刚好匹配音频时长,不会有多余空白:
// 定义每秒对应的像素数 int pixelsPerSecond = 15; // 计算准确的Bitmap宽度:向上取整避免丢帧 int bitmapWidth = (int)Math.Ceiling(reader.TotalTime.TotalSeconds * pixelsPerSecond); // 高度保持你原来的200 Bitmap bim = new Bitmap(bitmapWidth, 200); using (Graphics g = Graphics.FromImage(bim)) { // 后续绘制波形的逻辑 }
采样数与像素的映射(绘制波形的关键)
要让波形准确适配宽度,还得把采样数据对应到每个像素上:
先算总采样帧数(每个帧包含所有通道的采样点,比如立体声就是左右两个采样算一个帧):
// 用时长+采样率计算,更直观 int totalSampleFrames = (int)(reader.TotalTime.TotalSeconds * reader.WaveFormat.SampleRate); // 或者用Length算,结果完全一致 int totalSampleFrames = (int)(reader.Length / reader.WaveFormat.BlockAlign);(
BlockAlign是每个采样帧的字节数,等于Channels * BitsPerSample/8)计算每个像素需要覆盖的采样帧数:
int samplesPerPixel = totalSampleFrames / bitmapWidth; int remainingSamples = totalSampleFrames % bitmapWidth;剩下的
remainingSamples可以分配到前几个像素上,保证所有采样都被覆盖到。绘制时,每个像素对应
samplesPerPixel个采样帧,计算这段采样的峰值(或平均值)来确定波形的高度,这样出来的波形既完整又不会有空白。
为什么之前会有空白?
你固定了12800像素的宽度,但你的音频时长对应的实际宽度(按1秒15像素算)小于12800,所以绘制完波形后剩下的像素自然就是空白啦。现在用动态计算的宽度,刚好匹配音频长度,问题就解决了。
内容的提问来源于stack exchange,提问作者Ben
相关产品推荐
相关产品推荐

