音频波浪线

在第一个gameobject上挂在CurveWaveform脚本,设置参数

在第二个gameobject上挂在AudioSampler脚本,和audiosource组件。

CurveWaveform脚本:

using UnityEngine;
using System.Collections;


namespace AudioVisualizer
{
    /// <summary>
    /// Curve waveform, just like LineWaveform, but also uses a user set curve to affect amplitude of the line.
    /// </summary>
 public class CurveWaveform : LineWaveform {

  public AnimationCurve shapeCurve; // control amplitude over distance, multiplied by the audio waveform.
        public float curveAmplitude = 5;
        public Vector3 curveDirection = Vector3.up; // what direction does the audio g


  void Update ()
  {
   DrawLines ();
  }

  //move points in teh lineRendrer accourding to the decibal level of the audio, * the amplitude Curve
        void DrawLines()
        {
            for (int i = 0; i < (points.Count - 1); i++)
            {
                Vector3 start = points[i].position;
                Vector3 end = points[i + 1].position;
                Vector3 toTarget = end - start; // vector from me to my target
                float[] audioSamples;
                int startIndex = 0;
                int endIndex = lineAtt.lineSegments;


                if (frequencyRange == FrequencyRange.Decibal)
                {
                    audioSamples = AudioSampler.instance.GetAudioSamples(audioSource, lineAtt.lineSegments, abs);
                }
                else
                {
                    audioSamples = AudioSampler.instance.GetFrequencyData(audioSource, frequencyRange, lineAtt.lineSegments, abs);
                }
               
                if (snapEndpoints)
                {
                    //set the start and end of the line to draw perfectly at teh start and end
                    lines[i].SetPosition(0, start);
                    lines[i].SetPosition(lineAtt.lineSegments - 1, end);
                    //change our indicies for the forloop to draw the rest of the line
                    startIndex = 1;
                    endIndex = lineAtt.lineSegments - 1;
                }
                //draw the rest of the line, using the waveform and curve
                for (int j = startIndex; j < endIndex; j++) // for each line segment
                {
                    float percent = (float)j / (lineAtt.lineSegments - 1); // percent complete
                    Vector3 position = start + toTarget * percent; // position = myPos + toTarget*percent
                    float yOffset; //add this y offset to the position for this position in the line
                    float sampleHeight = audioSamples[j];
                    if (abs)
                    {
                        sampleHeight = Mathf.Abs(sampleHeight);
                    }

                    if (shapeCurve != null)
                    {
                        yOffset = shapeCurve.Evaluate(percent) * curveAmplitude + sampleHeight * waveformAmplitude;// use amplitude curve
                    }
                    else
                    {
                        Debug.LogWarning("Warning: No Shape Curve set for CurveWaveform.cs on " + this.gameObject.name);
                        yOffset = sampleHeight * waveformAmplitude;
                    }


                    position += points[i].transform.TransformDirection(curveDirection) *yOffset; // add in the y offset
                    lines[i].SetPosition(j, position); // set the position for this line segment
                }
            }
        }
 }
}



11111111111111111111111111111111111111111111111111111111111111111111111111111111

AudioSampler脚本

using UnityEngine;
using System.Collections;
using System.Collections.Generic;



namespace AudioVisualizer
{
    /// <summary>
    /// Samples the audio across multiple audio sources.
    /// All other AudioVisualizer classes rely on this class to sample the audio data.
    /// There should just be 1 instance of this in each scene.
    /// </summary>
    public class AudioSampler : MonoBehaviour
    {


        public static AudioSampler instance; //singleton static instance
        public List<AudioSource> audioSources; // list of audio sources used for audio input.
        public bool debug = false; // if true, show audio data being sampled

        // used for drawing the debug chart.
        private Texture2D drawTexture;
        private Color startColor = Color.magenta;
        private Color endColor = Color.blue;
        private Gradient gradient;
        private float fMax;// = (float)AudioSettings.outputSampleRate/2;
        private List<string> debugLables = new List<string>() { "SubBass", "Bass", "LowMid", "Mid", "UpperMid", "High", "VeryHigh", "Decibal" };
        private int samplesToTake = 1024; // how many audio samples should we take?

        //singleton logic
        void OnEnable()
        {
            if (instance == null)
            {
                instance = this;
            }
        }
        void OnDisable()
        {
            instance = null;
        }

        void Awake()
        {
            drawTexture = Texture2D.whiteTexture; // get an empty white texture
            gradient = PanelWaveform.GetColorGradient(startColor, endColor); // get a color gradient.
            if (audioSources.Count == 0) // if we haven't assigned any audio sources
            {
                if (this.GetComponent<AudioSource>() != null) // try to grab one from this gameobject
                {
                    audioSources.Add(this.GetComponent<AudioSource>());
                }
                else
                {
                    Debug.LogError("Error! no audio sources attached to AudioSampler.css");
                }
            }
        }

        void Start()
        {
            //get max frequency
            fMax = (float)AudioSettings.outputSampleRate / 2;
        }


  

        //draw the debug chart if enabled.
        void OnGUI()
        {
            if (debug)
            {

                //rms
                // avg
                // 7 Frequency Range volumes
                int heightPerSource = 100;
                for (int s = 0; s < audioSources.Count; s++)
                {
                    int width = (int)(Screen.width * .5f);
                    int height = heightPerSource * (s + 1);
                    int headerFooter = (int)(height * .2f);
                    int spacing = (int)(width / debugLables.Count);
                    int barWidth = 10;
                    int yBottom = height - headerFooter;
                    int yTop = headerFooter;
                    int indent = 40; //left indent

                    GUI.color = Color.white;
                    GUI.Label(new Rect(0, yBottom, 60, 20), "Source: " + s);
                    for (int j = 0; j < debugLables.Count; j++)
                    {
                        float percent = (float)j / (debugLables.Count - 1);
                        int x = indent + spacing + spacing * j;
                        Vector2 start = new Vector2(x, yBottom);
                        float volume = Mathf.Clamp(GetFrequencyVol(s, (FrequencyRange)j) * 10, 0, .5f);
                        float y = yBottom - heightPerSource * volume;
                        //Debug.Log(i + " vol: " + volume + " y: " + y);
                        Vector2 end = new Vector2(x, y);
                        DrawLine(start, end, barWidth, gradient.Evaluate(percent));
                        GUI.Label(new Rect(x, yBottom, 60, 20), debugLables[j]);
                        GUI.Label(new Rect(x, yBottom + 20, 40, 20), volume.ToString("F3"));
                    }
                }

            }
        }
        //draw a line of the debug chart.
        private void DrawLine(Vector2 start, Vector2 end, int width, Color color)
        {
            GUI.color = color;
            Vector2 d = end - start;
            float a = Mathf.Rad2Deg * Mathf.Atan(d.y / d.x);
            if (d.x < 0)
                a += 180;

            int width2 = (int)Mathf.Ceil(width / 2);

            if (Vector2.Distance(start, end) > .1)
            {
                GUIUtility.RotateAroundPivot(a, start);
                GUI.DrawTexture(new Rect(start.x, start.y - width2, d.magnitude, width), drawTexture);
                GUIUtility.RotateAroundPivot(-a, start);
            }
        }


        //get an array of output data (decibals)
        public float[] GetAudioSamples(int audioSourceIndex)
        {
            if (!audioSources[audioSourceIndex].mute) // if not muted
            {
                float[] samples = audioSources[audioSourceIndex].GetOutputData(samplesToTake, 0); // grab samples!
                //normalize the samples
                float[] normSamples = NormalizeArray(samples);
                //multiply by volume.
                for (int i = 0; i < samples.Length; i++)
                {
                    normSamples[i] = normSamples[i] * audioSources[audioSourceIndex].volume;
                }
                return normSamples;
            }

            return new float[samplesToTake];
        }

        //get an array of output data, averaged into 'numBins' bins
        public float[] GetAudioSamples(int audioSourceIndex, int numBins, bool absoluteVal)
        {
            if (!audioSources[audioSourceIndex].mute) // if not muted
            {
                float[] samples = audioSources[audioSourceIndex].GetOutputData(numBins, 0); // grab samples!
                //normalize the samples
                float[] normSamples = NormalizeArray(samples);
                //multiply by volume.
                for (int i = 0; i < samples.Length; i++)
                {
                    if (absoluteVal)
                    {
                        normSamples[i] = Mathf.Abs(samples[i]) * audioSources[audioSourceIndex].volume;
                    }
                    else
                    {
                        normSamples[i] = samples[i] * audioSources[audioSourceIndex].volume;
                    }
                }

                return normSamples;
            }

            return new float[numBins];
        }


        //sample the audio, square each value, and sum them all to get instant energy (the current 'energy' in the audio)
        public float GetInstantEnergy(int audioSourceIndex)
        {
            if (!audioSources[audioSourceIndex].mute)
            {
                float[] audioSamples = GetAudioSamples(audioSourceIndex);
                float sum = 0;
                //sum up the audio samples
                foreach (float f in audioSamples)
                {
                    sum += (f * f);
                }
                return sum * audioSources[audioSourceIndex].volume;
            }

            return 0;
        }

        //Get the RMS value of the audio (Root means squared) value 0-1
        //An average "noise" value of the audio at this point in time, using samplesToTake audio samples, and the passed in sensitivity.
        public float GetRMS(int audioSourceIndex)
        {
            if (!audioSources[audioSourceIndex].mute)
            {
                //grab output data (decibals)
                float[] audioSamples = audioSources[audioSourceIndex].GetOutputData(samplesToTake, 0); // fill array with samples
                //float[] normSamples = NormalizeArray(audioSamples);
                int i;
                float sum = 0;
                for (i = 0; i < samplesToTake; i++)
                {
                    sum += audioSamples[i] * audioSamples[i]; // sum squared samples
                }
                float rmsValue = Mathf.Sqrt(sum / samplesToTake) * audioSources[audioSourceIndex].volume; // rms = square root of average

                return rmsValue;
            }

            return 0;
        }

        //like GetAvg or GetRMS, but inside a given frequency range
        public float GetFrequencyVol(int audioSourceIndex, FrequencyRange freqRange)
        {
            if (!audioSources[audioSourceIndex].mute) // if not muted
            {
                Vector2 range = GetFreqForRange(freqRange);
                float fLow = range.x;//Mathf.Clamp (range.x, 20, fMax); // limit low...
                float fHigh = range.y;//Mathf.Clamp (range.y, fLow, fMax); // and high frequencies
                // get spectrum
                float[] freqData = new float[samplesToTake];
                audioSources[audioSourceIndex].GetSpectrumData(freqData, 0, FFTWindow.BlackmanHarris);
                int n1 = (int)Mathf.Floor(fLow * samplesToTake / fMax);
                int n2 = (int)Mathf.Floor(fHigh * samplesToTake / fMax);
                float sum = 0;
                // Debug.Log("Smapling freq: " + n1 + "-" + n2);
                // average the volumes of frequencies fLow to fHigh
                for (int i = n1; i <= n2; i++)
                {
                    if(i < freqData.Length)
                        sum += Mathf.Abs(freqData[i]);
                }
                sum = sum * audioSources[audioSourceIndex].volume;
                return sum / (n2 - n1 + 1);
            }

            return 0;
        }

        //return the raw spectrum data i nthe given frequency range.
        public float[] GetFrequencyData(int audioSourceIndex, FrequencyRange freqRange)
        {
            if (!audioSources[audioSourceIndex].mute) // if not muted
            {
                Vector2 range = GetFreqForRange(freqRange);
                float fLow = range.x;//Mathf.Clamp (range.x, 20, fMax); // limit low...
                float fHigh = range.y;//Mathf.Clamp (range.y, fLow, fMax); // and high frequencies
                // get spectrum
                float[] freqData = new float[samplesToTake];
                audioSources[audioSourceIndex].GetSpectrumData(freqData, 0, FFTWindow.BlackmanHarris);
                int n1 = (int)Mathf.Floor(fLow * samplesToTake / fMax);
                int n2 = (int)Mathf.Floor(fHigh * samplesToTake / fMax);
                float sum = 0;
                // Debug.Log("Smapling freq: " + n1 + "-" + n2);
                // average the volumes of frequencies fLow to fHigh

                List<float> validData = new List<float>();
                for (int i = n1; i <= n2; i++)
                {
                    validData.Add(freqData[i] * audioSources[audioSourceIndex].volume);
                }

                float[] normData = NormalizeArray(validData.ToArray());

                return normData;
            }

            Debug.LogWarning("warning: Audio Source: " + audioSourceIndex + " is muted");
            return new float[samplesToTake];
        }

        //return the raw spectrum data i nthe given frequency range, using the specified number of bins
        public float[] GetFrequencyData(int audioSourceIndex, FrequencyRange freqRange, int numBins, bool abs)
        {
            if (!audioSources[audioSourceIndex].mute) // if not muted
            {
                Vector2 range = GetFreqForRange(freqRange);
                float fLow = range.x;//Mathf.Clamp (range.x, 20, fMax); // limit low...
                float fHigh = range.y;//Mathf.Clamp (range.y, fLow, fMax); // and high frequencies
                // get spectrum
                float[] freqData = new float[samplesToTake];
                audioSources[audioSourceIndex].GetSpectrumData(freqData, 0, FFTWindow.BlackmanHarris);
                int n1 = (int)Mathf.Floor(fLow * samplesToTake / fMax);
                int n2 = (int)Mathf.Floor(fHigh * samplesToTake / fMax);
                float sum = 0;
                // Debug.Log("Smapling freq: " + n1 + "-" + n2);
                // average the volumes of frequencies fLow to fHigh

                //Debug.Log("Valid Freq Data: (" + n1 + "-" + n2 + ")/" + samplesToTake);
                List<float> validData = new List<float>();
                for (int i = n1; i <= n2; i++)
                {
                    float frequency = freqData[i];
                    if (abs)
                    {
                        frequency = Mathf.Abs(freqData[i]);
                    }

                    validData.Add(frequency * audioSources[audioSourceIndex].volume);
                }

                float[] binnedArray = GetBinnedArray(validData.ToArray(), numBins);
                float[] normalizedArray = NormalizeArray(binnedArray);
                return normalizedArray;
            }

            Debug.LogWarning("warning: Audio Source: " + audioSourceIndex + " is muted");
            return new float[numBins];
        }

        //take an array, and bin the values.
        // if numBins is > intput.Length, duplicate input values
        // if numBins is < input.Length, average input values
        float[] GetBinnedArray(float[] input, int numBins)
        {
            float[] output = new float[numBins];

            if(numBins == input.Length)
            {
                return input;
            }
            // if numBins is > intput.Length, duplicate input values
            if(numBins > input.Length)
            {
                int binsPerInput = numBins/input.Length;
                for(int b = 0; b < numBins; b++)
                {
                    int inputIndex = (b+1)%binsPerInput;
                    output[b] = input[inputIndex];
                }
            }

            // if numBins is < input.Length, average input values
            if (numBins < input.Length)
            {
                int inputsPerBin = input.Length/numBins;
                for (int b = 0; b < numBins; b++)
                {
                    float avg = 0;
                    for (int i = 0; i < inputsPerBin; i++)
                    {
                        int index = b * inputsPerBin + i;
                        avg += input[index];
                    }
                    avg = avg / inputsPerBin;

                    output[b] = avg;
                }
            }

            return output;
        }

        //normalize array values to be in the range 0-1
        float[] NormalizeArray(float[] input)
        {
            float[] output = new float[input.Length];
            float max = -Mathf.Infinity;
            //get the max value in the array
            for (int i = 0; i < input.Length; i++)
            {
                max = Mathf.Max(max, Mathf.Abs(input[i]));
            }

            //divide everything by the max value
            for (int i = 0; i < input.Length; i++)
            {
                output[i] = input[i] / max;
            }

            return output;
        }

        public static Vector2 GetFreqForRange(FrequencyRange freqRange)
        {
            switch (freqRange)
            {
                case FrequencyRange.SubBase:
                    return new Vector2(20, 60);
                    break;
                case FrequencyRange.Bass:
                    return new Vector2(60, 250);
                    break;
                case FrequencyRange.LowMidrange:
                    return new Vector2(250, 500);
                    break;
                case FrequencyRange.Midrange:
                    return new Vector2(500, 2000);
                    break;
                case FrequencyRange.UpperMidrange:
                    return new Vector2(2000, 4000);
                    break;
                case FrequencyRange.High:
                    return new Vector2(4000, 6000);
                    break;
                case FrequencyRange.VeryHigh:
                    return new Vector2(6000, 20000);
                    break;
                case FrequencyRange.Decibal:
                    return new Vector2(0, 20000);
                default:
                    break;
            }

            return Vector2.zero;
        }
    }

    public enum FrequencyRange
    {
        SubBase, // 20-60 Hz
        Bass, // 60-250 Hz
        LowMidrange, //250-500 Hz
        Midrange, //500-2,000 Hz
        UpperMidrange, //2,000-4,000 Hz
        High, //4,000-6000 Hz
        VeryHigh, //6,000-20,000 Hz
        Decibal // use output data instead of frequency data
    };



}



通过音频文件播放,产生波形,如果音频不播放就没有波形。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android音频波形控件是一种可以显示音频波形图的控件。它通常用于音频播放器或录音应用中,可以显示音频文件或实时音频流的波形图形,使用户能够更直观地了解音频的声波变化。 在实现Android音频波形控件时,可以使用Android的绘图功能,通过获取音频数据并将其转换为波形图的形式进行绘制。一般来说,可以通过以下步骤来实现: 1. 获取音频数据:可以通过Android的MediaRecorder类录制音频或使用MediaPlayer类播放音频文件时获取音频数据。也可以使用AudioRecord类从设备的麦克风获取实时音频数据。 2. 转换为波形数据:获取音频数据后,可以将其转换为波形数据,一般是通过将音频数据进行采样和缩放处理得到一系列的波形点。 3. 绘制波形图:使用Android的绘图功能,可以将波形数据绘制成波形图。可以使用Canvas类进行绘制,通过绘制线条或样式化的音频波浪形图等形式展示音频波形。 4. 更新和交互:如果需要实时更新波形图,可以使用定时器或回调函数来获取和绘制最新的音频数据。还可以添加交互功能,如缩放、滚动等,以便用户能够更好地查看和操作音频波形。 总之,Android音频波形控件是一种用于显示音频波形图的控件,通过获取音频数据并将其转换为波形数据来进行绘制。它可以应用于多种音频应用中,提供更直观、美观的音频展示效果,提升用户体验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值