This project has moved and is read-only. For the latest updates, please go here.

How to create waveform of full audio

Jan 12, 2016 at 8:07 AM
I spent some time playing with the project and finally figured out how to create a waveform visualization in WPF using NAudio (it is mostly already done in the WPF demo project if you download this solution).

The problem I'm facing now is that the visualization is created upon actual playback and renders only part of the playing audio at a time. I need to get the waveform of the entire audio without actually playing it. Can anyone help me with this?

Best Regards,
Shujaat
Jan 16, 2016 at 11:48 PM
In winforms NAudio provides a WaveViewer control that displays a Wavestream.
Jan 17, 2016 at 5:34 AM
Thanks a bunch Freefall. I was able to use WaveStream.ToSampleProvider() with a Read() loop to compute the waveform points and then use my custom WPF control (with a Polygon in it) to draw the entire audio waveform in the control.
Jul 4, 2016 at 8:28 AM
@Shujee, could you provide a small piece of code which you used to generate the waveform?

Thanks
Jul 4, 2016 at 8:56 AM
Edited Jul 4, 2016 at 9:03 AM
Has been quite some time since I worked on that project. I just spent some time and tried to gather the pieces. It is part of a large project, so I can't provide a working solution off hand, but the following will hopefully take you a long way.
  private WaveOut playbackDevice = new WaveOut() { DesiredLatency = 100, NumberOfBuffers=2};

  public void Load(string fileName)
  {
        var fileStream = new WaveFileReader(fileName);

        var fileProvider = new WaveFileReader(fileStream);
        playbackDevice.Init(fileProvider);

        var SampleProvider = fileStream.ToSampleProvider();
        var Values = GetWaveForm(SampleProvider, fileStream.WaveFormat, fileStream.Length, fileStream.WaveFormat.SampleRate / 10);

        //Now you can do whatever you want (e.g. plot them) with the Values.
  }

  private List<MinMax> GetWaveForm(ISampleProvider provider, WaveFormat format, long length, int notificationCount)
    {
      int bufferSize = format.ConvertLatencyToByteSize((((WaveOut)playbackDevice).DesiredLatency + ((WaveOut)playbackDevice).NumberOfBuffers - 1) / ((WaveOut)playbackDevice).NumberOfBuffers);
      var buf = new float[bufferSize];
      int samplesRead = 0;
      int count = 0;

      List<MinMax> Values = new List<MinMax>((int)(length / notificationCount));

      float maxValue = 0, minValue = 0;
      while ((samplesRead = provider.Read(buf, 0, buf.Length)) > 0)
      {
        for (int n = 0; n < samplesRead; n += format.Channels)
        {
          maxValue = Math.Max(maxValue, buf[n]);
          minValue = Math.Min(minValue, buf[n]);
          count++;
          if (count >= notificationCount && notificationCount > 0)
          {
            Values.Add(new MinMax(minValue, maxValue));
            minValue = maxValue = count = 0;
          }
        }
      }

      return Values;
    }
You'll need to import NAudio.Wave and System.Collections.Generic namespaces into the module. Also this may have some compilation errors since I haven't tested, but fixing them should be trivial.
Jul 4, 2016 at 9:15 AM
Thanks for the quick response @Shujee. I was able to get rid of the compilation errors

I was wondering if you could guide me as to how would I plot the obtained values. Meaning the Min, Max value pairs that your function returns, how would I plot it on a graph? Should i take their averages or something like that?

I really don't have any theoretical knowledge as to how the audio is managed.
Jul 4, 2016 at 11:57 AM
The values returned by the function are Y-axis averages of left and right channels. The X-axis values would be the playback time itself. You could even use the loop counter as the X-axis value when you plot the graph.

Plotting itself is merely the process of placing a dot at each X,Y pair and then interconnecting all the points; much the same way as we do in manual (hand-drawn) charting. How you do this in code depends upon the platform/language you're using. In WinForms, you would use Graphics class methods such as DrawLine to plot it. In my case I was using WPF, so I used a PolyLine control and set its Points collection in a loop. The key here is that plotting these values has nothing whatsoever to do with NAudio. You need to know how to do basic drawing in the language/platform you're using.

Hope that gets you going.
Aug 4, 2016 at 9:09 AM
Can the above process be executed on a video file or is it necessary to first convert the video file to audio?
Aug 25, 2016 at 4:02 PM
you can use MediaFoundationReader to access the audio from a video file
Aug 25, 2016 at 4:43 PM
@markheath, could you share some piece of code as a reference point for me? Thanks
Aug 25, 2016 at 4:45 PM
MediaFoundationReader is an ISampleProvider so you can just pass it into a method like GetWaveForm as shown above