MP3 Audio Spectrogram?

3.1k views Asked by At

Been looking for a way to do this all day with no hope. I'm creating a project with MP3 playback functionality and I'm trying to include a spectrogram (or spectrum analyser.. not sure what the proper name for it is) similar to this http://puu.sh/4lkMn.png (Winamp) (though if it's not in bars, that's fine too)

I've currently been using WMP for the audio playback but WMP doesn't have any methods for plotting a spectrogram.

I looked into using NAudio which seems promising: http://naudio.codeplex.com/ They have a demo for the Spectrum Analyser but they do not provide a source for that demo.

I also looked into this http://wpfsvl.codeplex.com/ which uses NAudio but it uses WPF instead of WinForms (my project is using WinForms) and I'm not sure how I would convert it to WinForms.

Google doesn't seem to have too much information on this for .Net The only thing I really need is an actual example of the source with NAudio implementation, but all I could find was other people pointing out the fact that the example source isn't actually made available.

..And I just noticed that their demo has 'wpf' in the name, so even if the source was available it'd be similar to the WPFSVL implementation which I'm incapable of. :(

2

There are 2 answers

0
Sakuya On BEST ANSWER

I found the example I converted from, it was AudioVSTToolbox

Here is my result from all this: http://puu.sh/4mWU8.png

(I'm copying my Winamp theme :) )

The minimum required to get Spectrum Analyzer working from that Toolbox are the following:

  • All contents of the folder 'NAudio-Visualizing' (except the Waveform stuff unless you want it).
  • CommonUtils\ColorUtils.cs
  • CommonUtils\ExtendedGraphics.cs
  • CommonUtils\MathUtils.cs
  • CommonUtils\MidiUtils.cs
  • CommonUtils\Audio\NAudio\AudioUtilsNAudio.cs
  • CommonUtils\Audio\NAudio\NAudio.dll
  • CommonUtils\FFT\AudioAnalyzer.cs
  • CommonUtils\FFT\FFTWindows.cs
  • CommonUtils\FFT\LomontFFT.cs
  • CommonUtils\FFT\ExocortexDSP\Complex.cs
  • CommonUtils\FFT\ExocortexDSP\ComplexF.cs
  • CommonUtils\FFT\ExocortexDSP\Fourier.cs
  • CommonUtils\FFT\ExocortexDSP\FourierDirection.cs

If converting to VB .Net, I used the converter here. It doesn't convert everything correctly though, the following are notable fixes required: (I can't remember all the changes I did unfortunately, it's not too difficult and you can search around for any conversion problems you may have)

  • In the MathUtils class Removed return from any Yield return ... statements and add Iterator to the method.
  • Change the MathUtils class to a module to fix error with extensions.
  • Fix Case statements with ...,Else.
  • Remove var from For Each statements.
  • In the ExtendedGraphics class, rename the Namespace System.Drawing.Extended to AudioSystem.Drawing.Extended as it conflicts with the System Namespace.

A few changes I made personally:

  • In the NAudioEngine class I changed the value of the DesiredLatency property to 200 as the default causes static.

  • In the NAudioEngine class I changed the Pause functionality to use fading because without fading there seems to be a bug which produces static when resuming. Do the following changes to add fading (and additionally volume control):

Add the Fields:

    Private m_Volume As Single = 0.2F 'Desired default volume
    Private audioFileReader As AudioFileReader
    Private fadeInOut As FadeInOutSampleProvider
    Private m_fadeDuration As Integer = 250 'Desired fading duration

In the OpenFile Method, change all in the Try statement to:

    waveOutDevice = New WaveOutEvent() With { _
        .DesiredLatency = definedLatency _
    }
    audioFileReader = New AudioFileReader(path)
    ActiveStream = DirectCast(audioFileReader, WaveStream)
    inputStream = New WaveChannel32(ActiveStream)

    fadeInOut = New FadeInOutSampleProvider(New WaveToSampleProvider(inputStream))
    audioFileReader.Volume = Volume()

    sampleAggregator = New SampleAggregator(m_fftDataSize)
    AddHandler inputStream.Sample, AddressOf inputStream_Sample
    waveOutDevice.Init(New SampleToWaveProvider(fadeInOut))

    ChannelLength = inputStream.TotalTime.TotalSeconds
    FileTag = TagLib.File.Create(path)
    GenerateWaveformData(path)
    CanPlay = True

In the Pause() Method change waveOutDevice.Pause() to fadeInOut.BeginFadeOut(fadeDuration())

In the Play() Method, In CanPlay statement:

    fadeInOut.BeginFadeIn(fadeDuration())
    waveOutDevice.Play()

To change the style of the graphic to bars, in the code of the custom Spectrum Analyzer control, change the default value of Public DoSpectrumGraph As Boolean = True to False. Then you can change the fields above that to style the bars however you wish.

In the Event Overrides region, you can change the colours/drawing methods.

6
Bjorn Roche On

There isn't enough space to answer your question fully, and I'm afraid I don't know of a place with source-code. The best I can do is put you on the right path. Maybe someone else knows a more complete answer.

This isn't really a spectrogram, though spectrum analyzer might be correct. It's sometimes called simply a "real-time analyzer" or RTA.

The first step is divide the signal into frequency bands. You could do this with an FFT (This will give you an idea of how to use an FFT) as I'm sure many people do, but this is not the correct approach for a variety of reasons.

Since there are so few bands, you should be able to use a bank of 2nd order filters to accomplish this goal. Use a lowpass for the bottom frequency, a highpass for the top frequency and bandpass filters for the intermediate frequencies. Select the center frequencies of the filters so that the frequencies are logarithmic. There are standard frequencies for these things you can look up if you care.

Once you've divided your signal into bands, follow up with a peak meter for each band.