C# NAudio获取音频样本
我使用NAudio从当前播放的歌曲中获取样本,并在歌曲播放时绘制波形。我正在使用C# NAudio获取音频样本,c#,wpf,naudio,C#,Wpf,Naudio,我使用NAudio从当前播放的歌曲中获取样本,并在歌曲播放时绘制波形。我正在使用AudioFileReader和ToSampleProvider获取所有样本作为float,然后在播放歌曲时将它们打印到InkCanvas中。我的问题是,样本似乎与声音不匹配。我还通过在NAudio源代码中的WPF示例中使用这首歌来验证这一点。在本例中,波形与声音匹配,但在我的应用程序中,波形与声音不匹配。所以我想知道是否有人能帮我找出我做错了什么(或读错了什么),或者我的绘图逻辑是否错了 这是我目前的代码: pub
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
的关系
您还将发现,在读取(和播放)样本时获得自动回调是刷新波形图的一种比尝试使用调度计时器
好得多的方法。它也会让你