代码之家  ›  专栏  ›  技术社区  ›  Michał Ziober

C#声音可视化[关闭]

  •  5
  • Michał Ziober  · 技术社区  · 16 年前

    这可能类似于Winamp应用程序。 例子: alt text http://img44.imageshack.us/img44/9982/examplel.png

    2 回复  |  直到 16 年前
        2
  •  3
  •   Phylliida    9 年前

    下面是一个脚本,它使用WASAPI API计算计算机上播放的任何声音的FFT。它使用CSCore及其 WinformsVisualization

    using CSCore;
    using CSCore.SoundIn;
    using CSCore.Codecs.WAV;
    using WinformsVisualization.Visualization;
    using CSCore.DSP;
    using CSCore.Streams;
    using System;
    
    public class SoundCapture
    {
    
        public int numBars = 30;
    
        public int minFreq = 5;
        public int maxFreq = 4500;
        public int barSpacing = 0;
        public bool logScale = true;
        public bool isAverage = false;
    
        public float highScaleAverage = 2.0f;
        public float highScaleNotAverage = 3.0f;
    
    
    
        LineSpectrum lineSpectrum;
    
        WasapiCapture capture;
        WaveWriter writer;
        FftSize fftSize;
        float[] fftBuffer;
    
        SingleBlockNotificationStream notificationSource;
    
        BasicSpectrumProvider spectrumProvider;
    
        IWaveSource finalSource;
    
        public SoundCapture()
        {
    
            // This uses the wasapi api to get any sound data played by the computer
            capture = new WasapiLoopbackCapture();
    
            capture.Initialize();
    
            // Get our capture as a source
            IWaveSource source = new SoundInSource(capture);
    
    
            // From https://github.com/filoe/cscore/blob/master/Samples/WinformsVisualization/Form1.cs
    
            // This is the typical size, you can change this for higher detail as needed
            fftSize = FftSize.Fft4096;
    
            // Actual fft data
            fftBuffer = new float[(int)fftSize];
    
            // These are the actual classes that give you spectrum data
            // The specific vars of lineSpectrum here aren't that important because they can be changed by the user
            spectrumProvider = new BasicSpectrumProvider(capture.WaveFormat.Channels,
                        capture.WaveFormat.SampleRate, fftSize);
    
            lineSpectrum = new LineSpectrum(fftSize)
            {
                SpectrumProvider = spectrumProvider,
                UseAverage = true,
                BarCount = numBars,
                BarSpacing = 2,
                IsXLogScale = false,
                ScalingStrategy = ScalingStrategy.Linear
            };
    
            // Tells us when data is available to send to our spectrum
            var notificationSource = new SingleBlockNotificationStream(source.ToSampleSource());
    
            notificationSource.SingleBlockRead += NotificationSource_SingleBlockRead;
    
            // We use this to request data so it actualy flows through (figuring this out took forever...)
            finalSource = notificationSource.ToWaveSource();
    
            capture.DataAvailable += Capture_DataAvailable;
            capture.Start();
        }
    
        private void Capture_DataAvailable(object sender, DataAvailableEventArgs e)
        {
            finalSource.Read(e.Data, e.Offset, e.ByteCount);
        }
    
        private void NotificationSource_SingleBlockRead(object sender, SingleBlockReadEventArgs e)
        {
            spectrumProvider.Add(e.Left, e.Right);
        }
    
        ~SoundCapture()
        {
            capture.Stop();
            capture.Dispose();
        }
    
        public float[] barData = new float[20];
    
        public float[] GetFFtData()
        {
            lock (barData)
            {
                lineSpectrum.BarCount = numBars;
                if (numBars != barData.Length)
                {
                    barData = new float[numBars];
                }
            }
    
            if (spectrumProvider.IsNewDataAvailable)
            {
                lineSpectrum.MinimumFrequency = minFreq;
                lineSpectrum.MaximumFrequency = maxFreq;
                lineSpectrum.IsXLogScale = logScale;
                lineSpectrum.BarSpacing = barSpacing;
                lineSpectrum.SpectrumProvider.GetFftData(fftBuffer, this);
                return lineSpectrum.GetSpectrumPoints(100.0f, fftBuffer);
            }
            else
            {
                return null;
            }
        }
    
        public void ComputeData()
        {
    
    
            float[] resData = GetFFtData();
    
            int numBars = barData.Length;
    
            if (resData == null)
            {
                return;
            }
    
            lock (barData)
            {
                for (int i = 0; i < numBars && i < resData.Length; i++)
                {
                    // Make the data between 0.0 and 1.0
                    barData[i] = resData[i] / 100.0f;
                }
    
                for (int i = 0; i < numBars && i < resData.Length; i++)
                {
                    if (lineSpectrum.UseAverage)
                    {
                        // Scale the data because for some reason bass is always loud and treble is soft
                        barData[i] = barData[i] + highScaleAverage * (float)Math.Sqrt(i / (numBars + 0.0f)) * barData[i];
                    }
                    else
                    {
                        barData[i] = barData[i] + highScaleNotAverage * (float)Math.Sqrt(i / (numBars + 0.0f)) * barData[i];
                    }
                }
            }
    
        }
    }
    

    我不确定我从哪里得到的 GetSpectrumPoints 因为它似乎不在 Github Repo

    public float[] GetSpectrumPoints(float height, float[] fftBuffer)
    {
        SpectrumPointData[] dats = CalculateSpectrumPoints(height, fftBuffer);
        float[] res = new float[dats.Length];
        for (int i = 0; i < dats.Length; i++)
        {
            res[i] = (float)dats[i].Value;
        }
    
        return res;
    }
    
    推荐文章