Is there any open source C# code or library to present a graphical waveform given a byte array?
The C language is not a piece of software but a defined standard, so one wouldn't say that it's open-source, but rather that it's an open standard. There are a gazillion different compilers for C however, and many of those are indeed open-source.
Linux. Linux is also written mostly in C, with some parts in assembly. About 97 percent of the world's 500 most powerful supercomputers run the Linux kernel. It is also used in many personal computers.
There's a good reason the Linux kernel is written in C. Finally, C is easy to get started with, especially if you're running Linux. You can already run C code because Linux systems include the GNU C library ( glibc ). To write and build it, all you need to do is install a compiler, open a text editor, and start coding.
Along with the C programming language comes Linux, an essential operating system used by most computer scientists and developers. Linux powers almost all supercomputers and most of the servers worldwide as well as all android devices and most internet of things devices.
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 function will produce something like this:
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.
I modified MusiGenesis's solution a little bit. This gave me a much better result, especially with house music :)
public static Bitmap DrawNormalizedAudio(List<float> data, Color foreColor, Color backColor, Size imageSize) { Bitmap bmp = new Bitmap(imageSize.Width, imageSize.Height); int BORDER_WIDTH = 0; float width = bmp.Width - (2 * BORDER_WIDTH); float height = bmp.Height - (2 * BORDER_WIDTH); using (Graphics g = Graphics.FromImage(bmp)) { g.Clear(backColor); Pen pen = new Pen(foreColor); float size = data.Count; for (float iPixel = 0; iPixel < width; iPixel += 1) { // determine start and end points within WAV int start = (int)(iPixel * (size / width)); int end = (int)((iPixel + 1) * (size / width)); if (end > data.Count) end = data.Count; float posAvg, negAvg; averages(data, start, end, out posAvg, out negAvg); float yMax = BORDER_WIDTH + height - ((posAvg + 1) * .5f * height); float yMin = BORDER_WIDTH + height - ((negAvg + 1) * .5f * height); g.DrawLine(pen, iPixel + BORDER_WIDTH, yMax, iPixel + BORDER_WIDTH, yMin); } } return bmp; } private static void averages(List<float> data, int startIndex, int endIndex, out float posAvg, out float negAvg) { posAvg = 0.0f; negAvg = 0.0f; int posCount = 0, negCount = 0; for (int i = startIndex; i < endIndex; i++) { if (data[i] > 0) { posCount++; posAvg += data[i]; } else { negCount++; negAvg += data[i]; } } posAvg /= posCount; negAvg /= negCount; }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With