Unity音頻採樣器(用於Unity音樂可視化)

主要用於音樂可視化
教程已經很多了,但是沒有拖上來就能用的
直接提供組件,歡迎複製黏貼

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

namespace MusicSampler
{
    public class MusicSampler : MonoBehaviour
    {
        #region Inspector
        /// <summary>
        /// 這個參數用於設置進行採樣的精度
        /// </summary>
        public SpectrumLength SpectrumCount = SpectrumLength.Spectrum256;
        private int spectrumLength => (int)Mathf.Pow(2, ((int)SpectrumCount + 6));
        /// <summary>
        /// 這個屬性返回採樣得到的原始數據
        /// </summary>
        public float[] samples = new float[64];
        private int[] sampleCount = new int[8];
        /// <summary>
        /// 這個參數用於設置將採樣的結果分爲幾組進行討論
        /// </summary>
        public uint BandCount = 8;
        /// <summary>
        /// 這個參數用於設置組別採樣數值減小時使用的平滑策略
        /// </summary>
        public BufferDecreasingType decreasingType = BufferDecreasingType.Jump;
        /// <summary>
        /// 這個參數用於設置在Slide和Falling設置下,組別採樣數值減小時每幀下降的大小。
        /// </summary>
        public float decreasing = 0.003f;
        /// <summary>
        /// 這個參數用於設置在Falling設置下,組別採樣數值減小時每幀下降時加速度的大小。
        /// </summary>
        public float DecreaseAcceleration = 0.2f;
        /// <summary>
        /// 這個參數用於設置組別採樣數值增大時使用的平滑策略
        /// </summary>
        public BufferIncreasingType increasingType = BufferIncreasingType.Jump;
        /// <summary>
        /// 這個參數用於設置在Slide設置下,組別採樣數值增大時每幀增加的大小。
        /// </summary>
        public float increasing = 0.003f;
        /// <summary>
        /// 這個屬性返回經過平滑和平均的幾組數據
        /// </summary>
        public float[] bands = new float[8];
        private float[] freqBands = new float[8];
        private float[] bandBuffers = new float[8];
        private float[] bufferDecrease = new float[8];
        /// <summary>
        /// 這個屬性返回總平均採樣結果
        /// </summary>
        public float average
        {
            get
            {
                float average = 0;
                for(int i = 0; i < BandCount; i++)
                {
                    average += normalizedBands[i];
                }
                average /= BandCount;
                return average;
            }
        }

        private float[] bandHighest = new float[8];
        /// <summary>
        /// 這個屬性返回經過平滑、平均和歸一化的幾組數據
        /// </summary>
        public float[] normalizedBands = new float[8];
        private float[] normalizedBandBuffers = new float[8];
        #endregion

        #region RequiredComponent
        [SerializeField]
        AudioSource AudioSource = null;
        #endregion

        #region LifePeriod
        private void Start()
        {
            GetSampleCount();
        }
        private void OnValidate()
        {
            if (samples.Length != spectrumLength) samples = new float[spectrumLength];
            if (bands.Length != BandCount) bands = new float[BandCount];
            if (freqBands.Length != BandCount) freqBands = new float[BandCount];
            if (bandBuffers.Length != BandCount) bandBuffers = new float[BandCount];
            if (bufferDecrease.Length != BandCount) bufferDecrease = new float[BandCount];
            if (bandHighest.Length != BandCount) bandHighest = new float[BandCount];
            if (normalizedBands.Length != BandCount) normalizedBands = new float[BandCount];
            if (normalizedBandBuffers.Length != BandCount) normalizedBandBuffers = new float[BandCount];
            if (sampleCount.Length != BandCount) sampleCount = new int[BandCount];
        }
        private void Update()
        {
            GetSpectrums();
            GetFrequencyBands();
            GetNormalizedBands();
            GetBandBuffers(increasingType, decreasingType);
            BandNegativeCheck();
        }
        #endregion

        #region Programs
        private void GetSampleCount()
        {
            float acc = (((float)((int)SpectrumCount + 6)) / BandCount);
            int sum = 0;
            int last = 0;
            for (int i = 0; i < BandCount - 1; i++)
            {
                int pow = (int)Mathf.Pow(2, acc * (i));
                sampleCount[i] = pow - sum;
                if (sampleCount[i] < last) sampleCount[i] = last;
                sum += sampleCount[i];
                last = sampleCount[i];
            }
            sampleCount[BandCount - 1] = samples.Length - sum;
        }
        private void GetSpectrums()
        {
            AudioSource.GetSpectrumData(samples, 0, FFTWindow.Blackman);
        }
        private void GetFrequencyBands()
        {
            int counter = 0;
            for (int i = 0; i < BandCount; i++)
            {
                float average = 0;
                for(int j = 0; j < sampleCount[i]; j++)
                {
                    average += samples[counter] * (counter + 1);
                    counter++;
                }
                average /= sampleCount[i];
                freqBands[i] = average * 10;
            }
        }
        private void GetNormalizedBands()
        {
            for (int i = 0; i < BandCount; i++)
            {
                if (freqBands[i] > bandHighest[i])
                {
                    bandHighest[i] = freqBands[i];
                }
            }
        }
        private void GetBandBuffers(BufferIncreasingType increasingType, BufferDecreasingType decreasingType)
        {
            for (int i = 0; i < BandCount; i++)
            {
                if (freqBands[i] > bandBuffers[i])
                {
                    switch(increasingType)
                    {
                        case BufferIncreasingType.Jump:
                            bandBuffers[i] = freqBands[i];
                            bufferDecrease[i] = decreasing;
                            break;
                        case BufferIncreasingType.Slide:
                            bufferDecrease[i] = decreasing;
                            bandBuffers[i] += increasing;
                            break;
                    }
                    if (freqBands[i] < bandBuffers[i]) bandBuffers[i] = freqBands[i];
                }
                if (freqBands[i] < bandBuffers[i])
                {
                    switch(decreasingType)
                    {
                        case BufferDecreasingType.Jump:
                            bandBuffers[i] = freqBands[i];
                            break;
                        case BufferDecreasingType.Falling:
                            bandBuffers[i] -= decreasing;
                            break;
                        case BufferDecreasingType.Slide:
                            bandBuffers[i] -= bufferDecrease[i];
                            bufferDecrease[i] *= 1 + DecreaseAcceleration;
                            break;
                    }
                    if (freqBands[i] > bandBuffers[i]) bandBuffers[i] = freqBands[i]; ;
                }
                bands[i] = bandBuffers[i];
                if (bandHighest[i] == 0) continue;
                normalizedBands[i] = (freqBands[i] / bandHighest[i]);
                normalizedBandBuffers[i] = (bandBuffers[i] / bandHighest[i]);
                if (normalizedBands[i] > normalizedBandBuffers[i])
                {
                    switch (increasingType)
                    {
                        case BufferIncreasingType.Jump:
                            normalizedBandBuffers[i] = normalizedBands[i];
                            bufferDecrease[i] = decreasing;
                            break;
                        case BufferIncreasingType.Slide:
                            bufferDecrease[i] = decreasing;
                            normalizedBandBuffers[i] += increasing;
                            break;
                    }
                    if (normalizedBands[i] < normalizedBandBuffers[i]) normalizedBandBuffers[i] = normalizedBands[i];
                }
                if (normalizedBands[i] < normalizedBandBuffers[i])
                {
                    switch (decreasingType)
                    {
                        case BufferDecreasingType.Jump:
                            normalizedBandBuffers[i] = normalizedBands[i];
                            break;
                        case BufferDecreasingType.Falling:
                            normalizedBandBuffers[i] -= decreasing;
                            break;
                        case BufferDecreasingType.Slide:
                            normalizedBandBuffers[i] -= bufferDecrease[i];
                            bufferDecrease[i] *= 1 + DecreaseAcceleration;
                            break;
                    }
                    if (normalizedBands[i] > normalizedBandBuffers[i]) normalizedBandBuffers[i] = normalizedBands[i];
                }
                normalizedBands[i] = normalizedBandBuffers[i];
            }
        }
        private void BandNegativeCheck()
        {
            for(int i = 0; i < BandCount; i++)
            {
                if (bands[i] < 0)
                {
                    bands[i] = 0;
                }
                if (normalizedBands[i] < 0)
                {
                    normalizedBands[i] = 0;
                }
            }
        }
        #endregion

        /// <summary>
        /// 通過這個函數來生成一個MusicSampler,並初始化其播放的片段爲audioClip
        /// </summary>
        /// <param name="audioClip">播放的片段</param>
        /// <returns></returns>
        public static MusicSampler CreateSampler(AudioClip audioClip)
        {
            GameObject go = new GameObject("MusicPlayer");
            AudioSource asr = go.AddComponent<AudioSource>();
            asr.clip = audioClip;
            asr.loop = false;
            asr.Play();
            MusicSampler ms = go.AddComponent<MusicSampler>();
            return ms;
        }
    }
    public enum SpectrumLength
    {
        Spectrum64, Spectrum128, Spectrum256, Spectrum512, Spectrum1024, Spectrum2048, Spectrum4096, Spectrum8192
    }
    public enum BufferDecreasingType
    {
        Jump, Slide, Falling
    }
    public enum BufferIncreasingType
    {
        Jump, Slide
    }
}

直接掛到物體上然後調參數,可調的參數全部打了備註。使用時從bands或normalizedBands讀取頻段數值就可以了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章