C# 实时声音频率图绘制

作者 : admin 本文共3276个字,预计阅读时间需要9分钟 发布时间: 2024-06-5 共3人阅读

C# 实时声音频率图绘制

C# 实时声音频率图绘制插图

采集PCM音频数据

音频原来自麦克风

音频源来自录音文件

处理PCM音频数据

使用 FftSharp.FFT 将PCM数据进行傅里叶变换

安装FftSharp框架

在Nuget包管理器中搜索FftSharp并安装C# 实时声音频率图绘制插图(1)

傅里叶变换

将采集到的PCM数据进行傅里叶变换

      // 傅里叶变换
      System.Numerics.Complex[] spectrum = FftSharp.FFT.Forward(audio);
      double[] ys = FftSharp.FFT.Magnitude(spectrum);

绘制频率图

采用自定义控件的方式来绘制频率图,核心代码如下:

        protected override void OnRender(DrawingContext drawingContext)
        {
            // 渲染数据
            DrawFrequency(drawingContext, this.ActualWidth, this.ActualHeight);
        }

        private void DrawFrequency(DrawingContext drawingContext, double imageWidth, double imageHeight)
        {
            double width = imageWidth - MarginLeft - 1;
            double height = imageHeight - MarginBottom - 1;

            var itemWidth = width / 4;
            var itemHeight = height / 4;

            drawingContext.DrawRectangle(this.Background, null, new Rect(0, 0, imageWidth, imageHeight));
            // 画方框
            drawingContext.DrawRect(this.Foreground, 1 + MarginLeft, 1, width, height);

            // 画竖线
            for (int i = 1; i < 4; i++)
            {
                var left = i * itemWidth;
                drawingContext.DrawLine(this.Foreground, left + MarginLeft, 0, left + MarginLeft, height);

                // 画文本
                var freq = MaxFrequency * (i * 0.25);
                drawingContext.DrawText(FormatUtil.Frequency(freq), this.TextBrush, left + MarginLeft, height + MarginBottom / 2 + 2, 13);
            }

            drawingContext.DrawText(FormatUtil.Frequency(0), this.TextBrush, MarginLeft + 10, height + MarginBottom / 2 + 2, 13);
            drawingContext.DrawText(FormatUtil.Frequency(MaxFrequency), this.TextBrush, width + MarginLeft - 16, height + MarginBottom / 2 + 2, 13);

            // 画横线
            for (int i = 1; i  0)
            {
                DrawPointPath(drawingContext, width, height);
            }
        }


        private void DrawPointPath(DrawingContext drawingContext, double width, double height)
        {

            var itemHeight = height / 20;
            var itemWidth = width / dataPoints.Count;

            var amplitude = (mMaxVolume - mMinVolume) * 2;


            // 开始绘制路径
            StreamGeometry geometry = new StreamGeometry();
            using (StreamGeometryContext context = geometry.Open())
            {
                // 将路径移动到第一个数据点
                var x = (1 - dataPoints[0] / amplitude) * 20;
                context.BeginFigure(new Point(MarginLeft + 1, x * itemHeight), false, false);

                // 添加线段连接每个数据点
                for (int i = 1; i < dataPoints.Count; i++)
                {
                    x = (1 - dataPoints[i] / amplitude) * 20;
                    context.LineTo(new Point(i * itemWidth + MarginLeft + 1, x * itemHeight), true, false);
                }
            }

            // 绘制路径
            drawingContext.DrawGeometry(null, pen, geometry);
        }



其他拓展类

FormatUtil

internal class FormatUtil
 {
     public static string Frequency(double freq)
     {
         if (freq < 1000)
         {
             return string.Format("{0}Hz", (int)freq);
         }
         else
         {
             var value = Math.Floor(freq / 1000);
             return string.Format("{0}kHz", value);
         }

     }
 }

DrawingContextExt

public static class DrawingContextExt
{
    public static void DrawRect(this DrawingContext drawingContext, Brush color, double x, double y, double w, double h)
    {
        drawingContext.DrawRectangle(null, new Pen(color, 1), new System.Windows.Rect(x, y, w, h));
    }

    public static void DrawLine(this DrawingContext drawingContext, Brush color, double x, double y, double x2, double y2)
    {
        drawingContext.DrawLine(new Pen(color, 1), new Point(x, y), new Point(x2, y2));
    }





    public static void FillEllipse(this DrawingContext drawingContext, Brush brush, double x, double y, double w, double h)
    {
        var radiusX = w / 2;
        var radiusY = h / 2;
        drawingContext.DrawEllipse(brush, null, new Point(x - radiusX, y - radiusY), radiusX, radiusY);
    }



    public static void DrawText(this DrawingContext drawingContext, string data, Brush brush, double x, double y, double emSize = 10)
    {
        // 创建FormattedText对象以设置文字的样式、位置和对齐方式
        FormattedText formattedText = new FormattedText(
            data,
            System.Globalization.CultureInfo.CurrentCulture,
            FlowDirection.LeftToRight,
            new Typeface("Arial"),
            emSize, brush);

        // 设置文字在 (50, 50) 的位置水平和垂直居中

        // 计算绘制点的坐标,使文本居中绘制
        Point drawPoint = new Point(x - formattedText.Width / 2, y - formattedText.Height / 2);

        // 绘制文字
        drawingContext.DrawText(formattedText, drawPoint);

    }
}
本站无任何商业行为
个人在线分享 » C# 实时声音频率图绘制
E-->