現在再生中の曲からサンプルを取得し、その曲が再生されるときに波形を描画するには、NAudioを使用しています。私はAudioFileReader
とToSampleProvider
を使用して、すべてのサンプルをfloat
としてから、曲が再生されている間にInkCanvas
にプロットします。私の問題は、サンプルがサウンドと一致しないように見えるということです。また、NAudioのソースコードにあるWPFの例でも、この同じ曲を使用して検証しています。この例では、波形はサウンドと一致しますが、アプリケーションでは波形が一致しません。だから私は、誰かが私がやっていること(または読んでいること)が間違っているかどうか、あるいは私の作図ロジックが間違っているかどうかを知る手伝いができるかどうか疑問に思いました私は、この描画アルゴリズムは非常に良いではありません知っているが、私は他を試してみましたが、彼らはまた、オーディオに従わないように見えるNAudioオーディオサンプルを取得
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
}
:
は、ここに私の現在のコードです。
ありがとうございました。
注:同様の質問があることを知っていますが、他の質問ではすでに使用しているAudioFileReader
またはToSampleProvider
などを使用することをおすすめします。私のエラーはおそらく私がサンプルをどのように読んでいるか、おそらく私はいくつかのバイトが欠けているか、バイトをスキップしなければならないかもしれません。
読み取り/再生**と最小/最大計算を処理する[WFPの例](https://github.com/naudio/NAudio/tree/master/NAudioWpfDemo/AudioPlaybackDemo)のコードの使用を真剣に検討する必要があります作業**。それはあなたに少しの努力を要しますが、私はそれがそれに値すると約束します。その後、正しいフォームであることがわかっているデータセットを使用して作業し、描画パートに集中できます。 'AudioPlayback.cs'と' SampleAggregator.cs'との関係をよく見てください。 –
私はこのヒントを高く評価しています。もし私の唯一の選択肢であると思われるなら、おそらくソースコードのいくつかを使用することになりますが、私は実際にソースコードを使用しないようにしています。実際にソースコードを見ればプログラマーの自我を壊してしまいましたが、私はこの時間で暮らすことができます。 – Agustin0987
この例を正しく使用すると、 'DispatchTimer'を使って波形描画の更新を駆り立てようとすることがなくなります。'SampleAggregator'からイベントデリゲートメソッド' OnMaximumCalculated'にコールバックを自動的に受け取るときに、100msecごとに1回(必要に応じてこの間隔を変更するプロパティを設定することができます)、これを行う方がずっと簡単だと思います。 –