C# sound visualisation

21,496

Solution 1

You can try these links

OpenVP (is a free and open-source platform for developing music visualizations, written in C#), see the OpenVP Screenshots.

Sound visualizer in C#

Play and Visualize WAV Files using Managed Direct Sound

Bye.

Solution 2

Here's a script that computes the FFT of any sound played on the computer using the WASAPI API. It uses CSCore and its WinformsVisualization example:

using CSCore;
using CSCore.SoundIn;
using CSCore.Codecs.WAV;
using WinformsVisualization.Visualization;
using CSCore.DSP;
using CSCore.Streams;
using System;

public class SoundCapture
{

    public int numBars = 30;

    public int minFreq = 5;
    public int maxFreq = 4500;
    public int barSpacing = 0;
    public bool logScale = true;
    public bool isAverage = false;

    public float highScaleAverage = 2.0f;
    public float highScaleNotAverage = 3.0f;



    LineSpectrum lineSpectrum;

    WasapiCapture capture;
    WaveWriter writer;
    FftSize fftSize;
    float[] fftBuffer;

    SingleBlockNotificationStream notificationSource;

    BasicSpectrumProvider spectrumProvider;

    IWaveSource finalSource;

    public SoundCapture()
    {

        // This uses the wasapi api to get any sound data played by the computer
        capture = new WasapiLoopbackCapture();

        capture.Initialize();

        // Get our capture as a source
        IWaveSource source = new SoundInSource(capture);


        // From https://github.com/filoe/cscore/blob/master/Samples/WinformsVisualization/Form1.cs

        // This is the typical size, you can change this for higher detail as needed
        fftSize = FftSize.Fft4096;

        // Actual fft data
        fftBuffer = new float[(int)fftSize];

        // These are the actual classes that give you spectrum data
        // The specific vars of lineSpectrum here aren't that important because they can be changed by the user
        spectrumProvider = new BasicSpectrumProvider(capture.WaveFormat.Channels,
                    capture.WaveFormat.SampleRate, fftSize);

        lineSpectrum = new LineSpectrum(fftSize)
        {
            SpectrumProvider = spectrumProvider,
            UseAverage = true,
            BarCount = numBars,
            BarSpacing = 2,
            IsXLogScale = false,
            ScalingStrategy = ScalingStrategy.Linear
        };

        // Tells us when data is available to send to our spectrum
        var notificationSource = new SingleBlockNotificationStream(source.ToSampleSource());

        notificationSource.SingleBlockRead += NotificationSource_SingleBlockRead;

        // We use this to request data so it actualy flows through (figuring this out took forever...)
        finalSource = notificationSource.ToWaveSource();

        capture.DataAvailable += Capture_DataAvailable;
        capture.Start();
    }

    private void Capture_DataAvailable(object sender, DataAvailableEventArgs e)
    {
        finalSource.Read(e.Data, e.Offset, e.ByteCount);
    }

    private void NotificationSource_SingleBlockRead(object sender, SingleBlockReadEventArgs e)
    {
        spectrumProvider.Add(e.Left, e.Right);
    }

    ~SoundCapture()
    {
        capture.Stop();
        capture.Dispose();
    }

    public float[] barData = new float[20];

    public float[] GetFFtData()
    {
        lock (barData)
        {
            lineSpectrum.BarCount = numBars;
            if (numBars != barData.Length)
            {
                barData = new float[numBars];
            }
        }

        if (spectrumProvider.IsNewDataAvailable)
        {
            lineSpectrum.MinimumFrequency = minFreq;
            lineSpectrum.MaximumFrequency = maxFreq;
            lineSpectrum.IsXLogScale = logScale;
            lineSpectrum.BarSpacing = barSpacing;
            lineSpectrum.SpectrumProvider.GetFftData(fftBuffer, this);
            return lineSpectrum.GetSpectrumPoints(100.0f, fftBuffer);
        }
        else
        {
            return null;
        }
    }

    public void ComputeData()
    {


        float[] resData = GetFFtData();

        int numBars = barData.Length;

        if (resData == null)
        {
            return;
        }

        lock (barData)
        {
            for (int i = 0; i < numBars && i < resData.Length; i++)
            {
                // Make the data between 0.0 and 1.0
                barData[i] = resData[i] / 100.0f;
            }

            for (int i = 0; i < numBars && i < resData.Length; i++)
            {
                if (lineSpectrum.UseAverage)
                {
                    // Scale the data because for some reason bass is always loud and treble is soft
                    barData[i] = barData[i] + highScaleAverage * (float)Math.Sqrt(i / (numBars + 0.0f)) * barData[i];
                }
                else
                {
                    barData[i] = barData[i] + highScaleNotAverage * (float)Math.Sqrt(i / (numBars + 0.0f)) * barData[i];
                }
            }
        }

    }
}

Then when retrieving the barData from a different script it's recommended to lock it first since this is modified on a separate thread.

I'm not sure where I got GetSpectrumPoints since it doesn't seem to be in the Github Repo, but here it is. Just paste this into that file and my code should work.

public float[] GetSpectrumPoints(float height, float[] fftBuffer)
{
    SpectrumPointData[] dats = CalculateSpectrumPoints(height, fftBuffer);
    float[] res = new float[dats.Length];
    for (int i = 0; i < dats.Length; i++)
    {
        res[i] = (float)dats[i].Value;
    }

    return res;
}
Share:
21,496
Michał Ziober
Author by

Michał Ziober

Contact me: ziobermichal (at gmail) SO: How does accepting an answer work? What have you tried? If you think, my answers were helpful consider to support me in what I am doing by sending some "satoshi", BTC Address 1Q99xbr6vgKptnFu7RfUkHo37NoiVHawVR

Updated on December 06, 2020

Comments

  • Michał Ziober
    Michał Ziober over 3 years

    I would like to create a sound visualisation system using C# language and .NET Framework. This could look like in Winamp application. Maybe exist free library or some interesting articles which describe how to do it? Example: alt text http://img44.imageshack.us/img44/9982/examplel.png

  • Shane S.
    Shane S. over 7 years
    I've tried to make use of your example code, but it doesn't seem like GetSpectrumPoints() is a function anymore, and checking the git repository history doesn't show it, either. Would you mind clarifying/updating your answer? (I'm trying to integrate audio capture/processing on Windows with a cross-platform console application that drives LED lights; the 0.0 to 1.0 bar frequency data values are all it needs)
  • Phylliida
    Phylliida over 7 years
    @Shane Sorry! I added that code now, hope that helps