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'를 사용하여 파형 드로잉의 업데이트를 구동하는 데 어려움을 겪지 않아도된다는 점을 언급해야합니다.100msec마다 한 번씩 'SampleAggregator'에서 이벤트 위임 메서드 인 'OnMaximumCalculated'로 콜백을 자동 수신 할 때이 작업을 훨씬 쉽게 수행 할 수있을 것입니다. 필요한 경우이 간격을 변경하는 속성을 설정할 수 있습니다. –