开源C#代码呈现波形?

有没有开源的C#代码或库提供一个字节数组的graphics波形?

这就像开源一样:

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; } 

这个函数会产生这样的东西:

在这里输入图像说明

这将采用浮点格式的样本数组(其中所有样本值范围从-1到+1)。 如果你的原始数据实际上是一个byte []数组的forms,那么你需要做一些工作来将其转换为float []。 让我知道你是否也需要这个。

更新 :由于问题技术上要求提供一个字节数组,这里有几个辅助方法:

 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; } 

更新2 :我忘了有一个更好的方法来做到这一点:

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

我真的很喜欢循环,我猜。

我修改了MusiGenesis的解决scheme。 这给了我一个更好的结果,特别是与家庭音乐:)

 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; } 

与从robby适应的代码和使用Graphics.Fill / DrawClosedCurve与抗锯齿,我得到一个相当不错的结果。 在这里输入图像说明

这是代码:

 using System; using System.Drawing; using System.Drawing.Drawing2D; namespace Soundfingerprinting.Audio.Services { public static class AudioVisualizationService { public class WaveVisualizationConfiguration { public Nullable<Color> AreaColor { get; set; } public Nullable<Color> EdgeColor { get; set; } public int EdgeSize { get; set; } public Nullable<Rectangle> Bounds { get; set; } public double Overlap { get; set; } public int Step { get; set; } } public static void DrawWave(float[] data, Bitmap bitmap, WaveVisualizationConfiguration config = null) { Color areaColor = Color.FromArgb(0x7F87CEFA);// Color.LightSkyBlue; semi transparent Color edgeColor = Color.DarkSlateBlue; int edgeSize = 2; int step = 2; double overlap = 0.10f; // would better use a windowing function Rectangle bounds = Rectangle.FromLTRB(0, 0, bitmap.Width, bitmap.Height); if (config != null) { edgeSize = config.EdgeSize; if (config.AreaColor.HasValue) areaColor = config.AreaColor.GetValueOrDefault(); if (config.EdgeColor.HasValue) edgeColor = config.EdgeColor.GetValueOrDefault(); if (config.Bounds.HasValue) bounds = config.Bounds.GetValueOrDefault(); step = Math.Max(1, config.Step); overlap = config.Overlap; } float width = bounds.Width; float height = bounds.Height; using (Graphics g = Graphics.FromImage(bitmap)) { Pen edgePen = new Pen(edgeColor); edgePen.LineJoin = LineJoin.Round; edgePen.Width = edgeSize; Brush areaBrush = new SolidBrush(areaColor); float size = data.Length; PointF[] topCurve = new PointF[(int)width / step]; PointF[] bottomCurve = new PointF[(int)width / step]; int idx = 0; for (float iPixel = 0; iPixel < width; iPixel += step) { // determine start and end points within WAV int start = (int)(iPixel * (size / width)); int end = (int)((iPixel + step) * (size / width)); int window = end - start; start -= (int)(overlap * window); end += (int)(overlap * window); if (start < 0) start = 0; if (end > data.Length) end = data.Length; float posAvg, negAvg; averages(data, start, end, out posAvg, out negAvg); float yMax = height - ((posAvg + 1) * .5f * height); float yMin = height - ((negAvg + 1) * .5f * height); float xPos = iPixel + bounds.Left; if (idx >= topCurve.Length) idx = topCurve.Length - 1; topCurve[idx] = new PointF(xPos, yMax); bottomCurve[bottomCurve.Length - idx - 1] = new PointF(xPos, yMin); idx++; } PointF[] curve = new PointF[topCurve.Length * 2]; Array.Copy(topCurve, curve, topCurve.Length); Array.Copy(bottomCurve, 0, curve, topCurve.Length, bottomCurve.Length); g.InterpolationMode = InterpolationMode.HighQualityBicubic; g.SmoothingMode = SmoothingMode.AntiAlias; g.FillClosedCurve(areaBrush, curve, FillMode.Winding, 0.15f); if (edgeSize > 0) g.DrawClosedCurve(edgePen, curve, 0.15f, FillMode.Winding); } } private static void averages(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]; } } if (posCount > 0) posAvg /= posCount; if (negCount > 0) negAvg /= negCount; } } } 

在NAudio中 ,有代码可以在WinForms和WPF中绘制audio波形。 看看演示项目的例子,了解如何使用它。

我一直是ZedGraph的粉丝多年,并用它来显示各种项目中的各种数据。

以下示例代码绘制了在-1和1之间变化的双精度数组:

 void DisplayWaveGraph(ZedGraphControl graphControl, double[] waveData) { var pane = graphControl.GraphPane; pane.Chart.Border.IsVisible = false; pane.Chart.Fill.IsVisible = false; pane.Fill.Color = Color.Black; pane.Margin.All = 0; pane.Title.IsVisible = false; pane.XAxis.IsVisible = false; pane.XAxis.Scale.Max = waveData.Length - 1; pane.XAxis.Scale.Min = 0; pane.YAxis.IsVisible = false; pane.YAxis.Scale.Max = 1; pane.YAxis.Scale.Min = -1; var timeData = Enumerable.Range(0, waveData.Length) .Select(i => (double) i) .ToArray(); pane.AddCurve(null, timeData, waveData, Color.Lime, SymbolType.None); graphControl.AxisChange(); } 

上面的示例通过抑制轴和更改颜色来模仿audio编辑器的样式,以产生以下内容:

ZedGraph音频波