2016-06-02 3 views
0

NAudio를 사용하여 현재 재생중인 노래에서 샘플을 가져 와서 노래가 재생 될 때 파형을 그립니다. AudioFileReaderToSampleProvider을 사용하여 모든 샘플을 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과 같은 것을 사용하는 것이 좋습니다. 내 오류는 아마도 샘플을 읽는 방법에 더 많은 영향을 미칩니다. 아마도 일부 바이트가 누락되었거나 일부 바이트를 건너 뛰거나 설정할 필요가없는 일부 속성을 건너 뛰어야 할 수 있습니다.

+1

읽기/재생 ** 및 최소/최대 계산을 처리하는 [WFP 예제] (https://github.com/naudio/NAudio/tree/master/NAudioWpfDemo/AudioPlaybackDemo)의 코드 사용을 진지하게 고려해야합니다. 작업**. 그것은 당신에게 약간의 노력을 필요로하지만, 나는 그것이 그만한 가치가 있다고 약속합니다. 그런 다음 올바른 형식의 데이터 집합을 사용하여 작업하고 도면 부분에 집중할 수 있습니다. 'AudioPlayback.cs'와'SampleAggregator.cs'와의 관계를 자세히 살펴보십시오. –

+0

팁을 고맙게 생각합니다. 그게 유일한 유일한 선택 인 것 같으면 소스 코드를 사용하는 것으로 끝날 것입니다. 조금 더 오디오 프로그래밍에 대해 더 많은 것을 알고 있으므로 실제로 소스 코드를 사용하지 않으려 고 노력하고 있습니다. (실제로는 소스 코드를보고 프로그래머의 자존심을 깨 버렸지 만 이번에는 그와 함께 살 수 있습니다.) – Agustin0987

+0

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

답변

0

읽기/재생을 처리하는 WFP example의 코드 부분과최소/최대 계산 작업을 진지하게 고려해야합니다.

약간의 노력이 필요하지만 그만한 가치가 있다고 약속드립니다.

그런 다음 올바른 양식의 데이터 세트로 작업하게되며 그리기 부분에 집중할 수 있습니다. 자세히 AudioPlayback.cs과 그 관계는 SampleAggregator.cs입니다.

또한 샘플을 읽는 동안 자동 콜백을 얻는 것은 DispatchTimer을 사용하는 것보다 파형 드로잉을 새로 고치는 더 좋은 방법입니다. 또한 웨이브 버퍼를 다시 읽지 못하게 할 수 있습니다. 가능한 경우이를 피하려고합니다.

EDIT :

난 전환 코드를 테스트하고, 결과 값이 올바른 float (-1 내지 1의 범위) 것으로 보인다. 그래서 문제는 WPF에서 파형을 플로팅하는 방식과 관련이 있다고 생각합니다.