tags:

views:

2101

answers:

4

Hi all,

I just wanted to make a quick check,does any of you know of an open source c# code to present wave form (graphically) from a byte array?

Thank you!

+14  A: 

This is as open source as it gets:

public static void DrawNormalizedAudio(ref float[] data, PictureBox pb,
    Color color)
{
    Bitmap bmp;
    if (pb.Image == null)
    {
        bmp = new Bitmap(pb.Width, pb.Height);
    }
    else
    {
        bmp = (Bitmap)pb.Image;
    }

    int BORDER_WIDTH = 5;
    int width = bmp.Width - (2 * BORDER_WIDTH);
    int height = bmp.Height - (2 * BORDER_WIDTH);

    using (Graphics g = Graphics.FromImage(bmp))
    {
        g.Clear(Color.Black);
        Pen pen = new Pen(color);
        int size = data.Length;
        for (int iPixel = 0; iPixel < width; iPixel++)
        {
            // determine start and end points within WAV
            int start = (int)((float)iPixel * ((float)size / (float)width));
            int end = (int)((float)(iPixel + 1) * ((float)size / (float)width));
            float min = float.MaxValue;
            float max = float.MinValue;
            for (int i = start; i < end; i++)
            {
                float val = data[i];
                min = val < min ? val : min;
                max = val > max ? val : max;
            }
            int yMax = BORDER_WIDTH + height - (int)((max + 1) * .5 * height);
            int yMin = BORDER_WIDTH + height - (int)((min + 1) * .5 * height);
            g.DrawLine(pen, iPixel + BORDER_WIDTH, yMax, 
                iPixel + BORDER_WIDTH, yMin);
        }
    }
    pb.Image = bmp;
}

This takes an array of samples in floating-point format (where all sample values range from -1 to +1). If your original data is actually in the form of a byte[] array, you'll have to do a little bit of work to convert it to float[]. Let me know if you need that, too.

Update: since the question technically asked for something to render a byte array, here are a couple of helper methods:

public float[] FloatArrayFromStream(System.IO.MemoryStream stream)
{
    return FloatArrayFromByteArray(stream.GetBuffer());
}

public float[] FloatArrayFromByteArray(byte[] input)
{
    float[] output = new float[input.Length / 4];
    for (int i = 0; i < output.Length; i++)
    {
        output[i] = BitConverter.ToSingle(input, i * 4);
    }
    return output;
}

Update 2: I forgot there's a better way to do this:

public float[] FloatArrayFromByteArray(byte[] input)
{
    float[] output = new float[input.Length / 4];
    Buffer.BlockCopy(input, 0, output, 0, input.Length);
    return output;
}

I'm just so in love with for loops, I guess.

MusiGenesis
Until you license it, and charge the OP $20 per use :)
Martin
@Martin: I charge that just for *looking* at it. Where's my $20? :)
MusiGenesis
Cool algorithm. I was just calculating the closest sample to my pixel and putting a point there, but doing the max and min of the range of that pixel looks much better!
superjoe30
+1  A: 

I've been a fan of ZedGraph for many years and have used it to display all kinds of data in quite a few projects.

The following sample will create a graph that displays an array of doubles that vary between -1 and 1.

void DisplayWaveGraph(ZedGraphControl graphControl, double[] waveData)
{
    var pane = graphControl.GraphPane;
    pane.Title.IsVisible = false;

    var xAxis = pane.XAxis;
    xAxis.Title.IsVisible = false;
    xAxis.Scale.Min = 0;
    xAxis.Scale.Max = waveData.Length - 1;

    var yAxis = pane.YAxis;
    yAxis.Title.IsVisible = false;
    yAxis.Scale.Min = -1;
    yAxis.Scale.Max = 1;

    var timeData = Enumerable.Range(0, waveData.Length)
                             .Select(i => (double) i)
                             .ToArray();
    pane.AddCurve(null, timeData, waveData, Color.Red, SymbolType.None);
    graphControl.AxisChange();
}
Nathan Baulch
+1  A: 

In NAudio, there is code to draw audio waveforms in both WinForms and WPF. Have a look at the demo projects for examples of how to use it.

Mark Heath
+1  A: 

Can someone post code to convert from MemoryStream or Byte[] to float array to create the waveform?

Thanks!

public float[] FloatArrayFromStream(System.IO.MemoryStream stream)
{
    return FloatFromByte(stream.GetBuffer());
}

public float[] FloatArrayFromByteArray(byte[] input)
{
    float[] output = new float[input.Length / 4];
    for (int i = 0; i < output.Length; i++)
    {
        output[i] = BitConverter.ToSingle(input, i * 4);
    }
    return output;
}
Rick