弹来弹去跑马灯!

C# 获取系统声卡音频数据,并绘制波形

//by wgscd
//date:2022/11/7

UI:

 <Path Stroke="Red" Data="{Binding path}" RenderTransformOrigin="0.5,0.5">
            <Path.RenderTransform>
                <TransformGroup>
                    <ScaleTransform/>
                    <SkewTransform/>
                    <RotateTransform Angle="180"/>
                    <TranslateTransform/>
                </TransformGroup>
            </Path.RenderTransform>

        </Path>

  

Code:

using NAudio.CoreAudioApi;
using NAudio.Wave.SampleProviders;
using NAudio.Wave;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;
using NAudio.Wave.Compression;
using System.Runtime.Remoting.Channels;
using System.ComponentModel;
using System.Collections.ObjectModel;
using HandyControl.Collections;
using System.Threading;
using System.Windows.Threading;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Windows;
using System.CodeDom;

namespace DouyuDanmu
{
//by wgscd
//date:2022/11/7
    public  class NAudioHelper
    {
   
        public static SampleData pathData  = new SampleData();
        public static void GetSampleData() {
            // Redefine the capturer instance with a new instance of the LoopbackCapture class
            WasapiLoopbackCapture     _waveIn = new WasapiLoopbackCapture();
            _waveIn.WaveFormat = new WaveFormat(16000, 16, 2);
          

            // Redefine the audio writer instance with the given configuration
            //WaveFileWriter RecordedAudioWriter = new WaveFileWriter(outputFilePath, CaptureInstance.WaveFormat);
            // When the capturer receives audio, start writing the buffer into the mentioned file
            _waveIn.DataAvailable += (s, a) =>
            {
                // Write buffer into the file of the writer instance
                AnalyzeVoice(a.Buffer);

            }; 
            
            _waveIn.StartRecording();


        }

        private static void SampleChannel_PreVolumeMeter(object sender, StreamVolumeEventArgs e)
        {
         Debug.Print(""+ e.MaxSampleValues[0]);

        }

        private static void waveIn_DataAvailable(object sender, NAudio.Wave.WaveInEventArgs e)
        {
            AnalyzeVoice(e.Buffer);
        }

        static bool isbusy = false ;
        /// <summary>
        /// 语音分析
        /// </summary>
        /// <param name="buf"></param>
        private async  static void AnalyzeVoice(byte[] buffer)
        {
            if (isbusy) { return; }

            isbusy = true;
            await  Task.Delay(10);
        
            float[] sts = new float[buffer.Length / 2];
            int outIndex = 0;
            for (int n = 0; n < buffer.Length; n += 2)
            {
                sts[outIndex++] = BitConverter.ToInt16(buffer, n) / 32768f;
            }
            int channels = 20;//值越大提取的越稀疏
            float value = 0;
            List<Point> listPoint = new List<Point>();
            
            float p=0;
            float x = 0;
            for (int n = 0; n < sts.Length; n += channels)
            {
               
                value = sts[n] > 0.0f ? sts[n] *400: 1f;//sts[n] * 400 是为了转化成有用的高度值
                Debug.Print(""+value );//这个就是大概的波形图
                p = value;
                x += 2;
                listPoint.Add(new Point(x,p));
            }
            UpdatePath(listPoint);//listPoint 更新一个类似贝塞尔曲线的效果
            isbusy = false ;
        }


      
        private static  void UpdatePath(List<Point> points)
        { 
            
            StringBuilder data = new StringBuilder("M");
            data.AppendFormat("{0},{1} C", points[0].X, points[0].Y); for (int i = 1; i < points.Count; i++)
            {
                Point pre = new Point((points[i - 1].X + points[i].X) / 2, points[i - 1].Y);  //控制点
                Point next = new Point((points[i - 1].X + points[i].X) / 2, points[i].Y);     //控制点
                data.AppendFormat(" {0},{1} {2},{3} {4},{5}", pre.X, pre.Y, next.X, next.Y, points[i].X, points[i].Y);
            }
           // pathData.path  = new Path { Stroke = Brushes.DodgerBlue, StrokeThickness = 1, Data = Geometry.Parse(data.ToString()) };
            pathData.path =  Geometry.Parse(data.ToString());

        }

    }







    public class SampleData : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        void NotifyPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
        float _value = 0;
        public float value
        {
            get
            {

                return _value;
            }
            set
            {
                _value = value;
                NotifyPropertyChanged(nameof(value));
            }
        }

        Geometry _path ;
        public Geometry path
        {
            get
            {

                return _path;
            }
            set
            {
                _path = value;
                NotifyPropertyChanged(nameof(path));
            }
        }




    }

}

  

posted @ 2022-11-07 15:36  wgscd  阅读(428)  评论(0)    收藏  举报