C# NAudio获取音频样本

C# NAudio获取音频样本,c#,wpf,naudio,C#,Wpf,Naudio,我使用NAudio从当前播放的歌曲中获取样本,并在歌曲播放时绘制波形。我正在使用AudioFileReader和ToSampleProvider获取所有样本作为float,然后在播放歌曲时将它们打印到InkCanvas中。我的问题是,样本似乎与声音不匹配。我还通过在NAudio源代码中的WPF示例中使用这首歌来验证这一点。在本例中,波形与声音匹配,但在我的应用程序中,波形与声音不匹配。所以我想知道是否有人能帮我找出我做错了什么(或读错了什么),或者我的绘图逻辑是否错了 这是我目前的代码: pub

我使用NAudio从当前播放的歌曲中获取样本,并在歌曲播放时绘制波形。我正在使用
AudioFileReader
ToSampleProvider
获取所有样本作为
float
,然后在播放歌曲时将它们打印到
InkCanvas
中。我的问题是,样本似乎与声音不匹配。我还通过在NAudio源代码中的WPF示例中使用这首歌来验证这一点。在本例中,波形与声音匹配,但在我的应用程序中,波形与声音不匹配。所以我想知道是否有人能帮我找出我做错了什么(或读错了什么),或者我的绘图逻辑是否错了

这是我目前的代码:

public partial class MainWindow : Window, INotifyPropertyChanged
{
    private ISampleProvider provider;
    private DispatcherTimer timer;
    private AudioFileReader reader;

    private WaveOut waveOut;
    private StylusPointCollection topPoints, bottomPoints;
    private DrawingAttributes attr;

    private double canvasHeight, canvasWidth;
    private int samplesGroupSize;
    private double drawPos = 0;

    private StrokeCollection _WaveformLines;
    public StrokeCollection WaveformLines
    {
        get { return _WaveformLines; } 
        set
        {
            _WaveformLines = value;
            OnPropertyChanged("WaveformLines");
        }
    }

    public MainWindow()
    {
        InitializeComponent();
        this.DataContext = this;
    }

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        reader = new AudioFileReader("C:\\Users\\Agustin\\Desktop\\DragonRider.mp3");
        waveOut = new WaveOut();
        waveOut.Init(reader);

        provider = reader.ToSampleProvider(); //Here I get the samples
        reader.Position = 0; //Go to the position 0 after reading the samples

        canvasHeight = Waveform.ActualHeight;
        canvasWidth = Waveform.ActualWidth;

        WaveformLines = new StrokeCollection();
        topPoints = new StylusPointCollection();
        topPoints.Add(new StylusPoint(0, (canvasHeight / 2)));
        topPoints.Changed += topPoints_Changed;
        bottomPoints = new StylusPointCollection();
        bottomPoints.Add(new StylusPoint(0, (canvasHeight / 2)));
        bottomPoints.Changed += topPoints_Changed;
        WaveformLines.Add(new Stroke(topPoints));
        WaveformLines.Add(new Stroke(bottomPoints));

        attr = new DrawingAttributes();
        attr.Color = Colors.Green;
        attr.Width = 1.5;
        attr.Height = 1;

        timer = new DispatcherTimer();
        timer.Interval = TimeSpan.FromMilliseconds(1);
        timer.Tick += timer_Tick;
        timer.Start();
        samplesGroupSize = (int)(timer.Interval.TotalSeconds * reader.WaveFormat.SampleRate); //The value for this is 44.
    }

    private void PlayButton_Click(object sender, RoutedEventArgs e)
    {
        waveOut.Play();
    }
    private void PauseButton_Click(object sender, RoutedEventArgs e)
    {
        waveOut.Pause();
    }

    private void timer_Tick(object sender, EventArgs e)
    {
        if (waveOut.PlaybackState == PlaybackState.Playing)
        {
            TimeLabel.Content = string.Format("Time: {0}", reader.CurrentTime.ToString(@"mm\:ss\:ff")); //NEED TO KEEP WORKING
            float[] samps = new float[samplesGroupSize];
            provider.Read(samps, 0, samps.Length);
            float max = Max(samps);
            float min = Min(samps);
            topPoints.Add(new StylusPoint(drawPos, (canvasHeight / 2) - ((canvasHeight / 2) * max)));
            bottomPoints.Add(new StylusPoint(drawPos, (canvasHeight / 2) - ((canvasHeight / 2) * min)));
            drawPos += 2;
            if (drawPos > canvasWidth)
            {
                WaveformLines.Clear();
                topPoints = new StylusPointCollection();
                topPoints.Add(new StylusPoint(0, (canvasHeight / 2)));
                bottomPoints = new StylusPointCollection();
                bottomPoints.Add(new StylusPoint(0, (canvasHeight / 2)));
                WaveformLines.Add(new Stroke(topPoints));
                WaveformLines.Add(new Stroke(bottomPoints));
                drawPos = 0;
            }
        }
    }

    private float Min(float[] samps)
    {
        float max = samps[0];
        foreach (float s in samps)
        {
            if (s > max)
                max = s;
        }
        return max;
    }
    private float Max(float[] samps)
    {
        float min = samps[0];
        foreach (float s in samps)
        {
            if (s < min)
                min = s;
        }
        return min;
    }

    //I excluded the INotifyPropertyChanged implementation, but in the
    //actual code is located here
}
public分部类主窗口:窗口,INotifyPropertyChanged
{
私人供应商;
专用调度定时器;
私人音频文件阅读器;
私人退避退避;
私人StylusPointCollection顶部点、底部点;
私人提款属性属性;
私人双画布高度、画布宽度;
私有int-samplesGroupSize;
私人双提款POS=0;
私人中风采集(波阵);;
公共频闪采集波
{
获取{return}
设置
{
_波形图=数值;
不动产变更(“波形图”);
}
}
公共主窗口()
{
初始化组件();
this.DataContext=this;
}
已加载私有无效窗口(对象发送器、路由目标)
{
reader=新的AudioFileReader(“C:\\Users\\Agustin\\Desktop\\DragonRider.mp3”);
waveOut=新的waveOut();
waveOut.Init(读卡器);
provider=reader.ToSampleProvider();//这里是示例
reader.Position=0;//读取样本后转到位置0
画布高度=波形。实际高度;
画布宽度=波形。实际宽度;
WaveformLines=新的StrokeCollection();
topPoints=新StylusPointCollection();
添加(新StylusPoint(0,(画布高度/2));
最高点已更改+=最高点已更改;
bottomPoints=新StylusPointCollection();
添加(新的StylusPoint(0,(画布高度/2));
底部点。更改+=顶部点\u更改;
添加(新冲程(最高点));
添加(新冲程(底部点));
attr=新绘图属性();
属性颜色=颜色。绿色;
属性宽度=1.5;
属性高度=1;
计时器=新调度程序();
timer.Interval=TimeSpan.fromMillimes(1);
timer.Tick+=定时器_Tick;
timer.Start();
samplesGroupSize=(int)(timer.Interval.TotalSeconds*reader.WaveFormat.SampleRate);//此值为44。
}
私有void播放按钮(对象发送者,路由目标e)
{
waveOut.Play();
}
私有无效暂停按钮单击(对象发送器,路由目标)
{
waveOut.暂停();
}
私有无效计时器(对象发送方、事件参数)
{
if(waveOut.PlaybackState==PlaybackState.Playing)
{
TimeLabel.Content=string.Format(“时间:{0}”,reader.CurrentTime.ToString(@“mm\:ss\:ff”);//需要继续工作
float[]samps=新的float[samplesGroupSize];
读取(samps,0,samps.Length);
浮动最大值=最大值(samps);
浮动最小值=最小值(samps);
顶部点。添加(新StylusPoint(drawPos,(canvasHeight/2)-(canvasHeight/2)*最大值));
添加(新的StylusPoint(drawPos,(canvasHeight/2)-(canvasHeight/2)*最小值));
drawPos+=2;
如果(drawPos>画布宽度)
{
波形图。清除();
topPoints=新StylusPointCollection();
添加(新StylusPoint(0,(画布高度/2));
bottomPoints=新StylusPointCollection();
添加(新的StylusPoint(0,(画布高度/2));
添加(新冲程(最高点));
添加(新冲程(底部点));
drawPos=0;
}
}
}
专用浮点最小值(浮点[]采样点)
{
float max=samps[0];
foreach(SAMP中的浮点s)
{
如果(s>最大值)
max=s;
}
返回最大值;
}
专用浮点最大值(浮点[]采样数)
{
浮动最小值=采样点[0];
foreach(SAMP中的浮点s)
{
如果(s
我知道这个绘图算法不是很好,但我也尝试过其他的,他们似乎也不遵循音频

谢谢


注意:我知道有类似的问题,但其他问题建议使用我已经在使用的
AudioFileReader
ToSampleProvider
之类的工具。我的错误可能更多地在于我是如何读取这些样本的,也许我丢失了一些字节或者必须跳过一些字节,或者可能是我没有设置的一些丢失的属性。

你应该认真考虑使用读/播放和<强>最小/最大计算工作的代码部分。p> 这需要你付出一点努力,但我保证这是值得的

然后,您将使用一个您知道格式正确的数据集,并且可以将注意力集中在绘图零件上。仔细查看
AudioPlayback.cs
及其与
SampleAggregator.cs
的关系

您还将发现,在读取(和播放)样本时获得自动回调是刷新波形图的一种比尝试使用
调度计时器
好得多的方法。它也会让你