Created
August 21, 2016 04:46
-
-
Save sagarpatel/1f3a645e60d54b7c3e1f9143d12edd14 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
using System.Collections; | |
public class FD_FrequencyDataManager : MonoBehaviour | |
{ | |
const int m_rawFFTDataSize = 1024; //8192; | |
float[] m_currentRawFFTDataArray; | |
const int m_processedFFTDataSize = 128; // separated into 8 sections | |
float[] m_processedFFTDataArray; | |
float[] m_previousProcessedFFTDataArray; | |
// set first to 0 as a quick hack to keep bass ragion clean so it doens't clip through player | |
int[] m_samplesAccumulationPerSectionArray = { 1, 1, 2, 3, 6, 8, 12, 30 }; // for FFT 2048//{ 1, 2, 4, 8, 12, 24, 55, 175 }; //for FFT 8192 // // // for FFT 1024 { 1, 1, 2, 3, 6, 8, 12, 30 }; | |
int m_samplesAccumulationStartIndexOffset = 0; | |
float[] m_sectionsScalerArray = { 1, 1, 1, 1, 1, 1, 1, 1 }; | |
public float m_globalFFTDataScaler = 1.0f; | |
public AnimationCurve m_rValueCurve; | |
public AnimationCurve m_gValueCurve; | |
public AnimationCurve m_bValueCurve; | |
public float d_r; | |
public float d_g; | |
public float d_b; | |
public Color m_currentFFTColor; | |
public float m_currentVolume; | |
float m_rScaler = 1.0f; | |
float m_gScaler = 1.0f; | |
float m_bScaler = 1.0f; | |
public float m_colorScaler = 25.0f; | |
float m_localPeakValueThreashold = 0.15f; | |
float m_localPeakRedistributionRatio = 0.25f; | |
int m_peakValuesSpreadItterations = 3; | |
const int m_outputSamplesCount = 1024; | |
float[] m_outputSamplesArray; | |
int k_volumeRollingAverageCount = 7; | |
int m_volumeRollingAverageIndex = 0; | |
float[] m_volumeRollingAverageArray; | |
float m_volumeRollingAverage = 0; | |
public float m_volumeTemporalMaxima = 0; | |
public float m_volumeTemporalMaximaDecay = 0.421f; | |
void Start() | |
{ | |
m_currentRawFFTDataArray = new float[m_rawFFTDataSize]; | |
m_processedFFTDataArray = new float[m_processedFFTDataSize]; | |
m_previousProcessedFFTDataArray = new float[m_processedFFTDataSize]; | |
m_outputSamplesArray = new float[m_outputSamplesCount]; | |
m_volumeRollingAverageArray = new float[k_volumeRollingAverageCount]; | |
for (int i = 0; i < m_volumeRollingAverageArray.Length; i++) | |
m_volumeRollingAverageArray[i] = 0; | |
} | |
void Update() | |
{ | |
CalculateFreshFFTData(); | |
CalculateFreshRGB(); | |
CalculateFreshVolume(); | |
CalculateVolumeTemporalMaxima(); | |
} | |
void CalculateVolumeTemporalMaxima() | |
{ | |
if (m_volumeRollingAverage > m_volumeTemporalMaxima) | |
m_volumeTemporalMaxima = m_volumeRollingAverage; | |
else | |
m_volumeTemporalMaxima = Mathf.Clamp(m_volumeTemporalMaxima - m_volumeTemporalMaximaDecay * Time.deltaTime, 0, 1); | |
} | |
void ProcessRawFFTData() | |
{ | |
int accumulationIndex = 0; | |
int accumulationInterval = m_processedFFTDataArray.Length / 8; | |
float tempSum = 0; | |
int rawFFTIndex = 0; | |
int currentRawSamplesPerProcessedPoint = 0; | |
for (int i = 0; i < m_processedFFTDataArray.Length; i++) | |
{ | |
if (i % accumulationInterval == 0 && i != 0) | |
accumulationIndex += 1; | |
tempSum = 0; | |
currentRawSamplesPerProcessedPoint = m_samplesAccumulationPerSectionArray[accumulationIndex]; | |
for (int j = 0; j < currentRawSamplesPerProcessedPoint; j++) | |
{ | |
tempSum += m_sectionsScalerArray[accumulationIndex] * m_currentRawFFTDataArray[rawFFTIndex + m_samplesAccumulationStartIndexOffset]; | |
rawFFTIndex += 1; | |
} | |
m_processedFFTDataArray[i] = Mathf.Clamp(m_globalFFTDataScaler * tempSum, 0, 1); ///(float)currentRawSamplesPerProcessedPoint; | |
//Debug.Log("Sum for acuumuator: " + currentRawSamplesPerProcessedPoint + " , " + tempSum); | |
// averageing with previous to smooth out depth axis and hide repeat data | |
m_processedFFTDataArray[i] = (0.75f * m_processedFFTDataArray[i] + 0.25f * m_previousProcessedFFTDataArray[i]); | |
m_previousProcessedFFTDataArray[i] = m_processedFFTDataArray[i]; | |
} | |
SpreadOutPeakValues(); | |
} | |
void SpreadOutPeakValues() | |
{ | |
int spreadCounter = 0; | |
float prevDelta = 0; | |
float postDelta = 0; | |
// Do multiple passes | |
for (int j = 0; j < m_peakValuesSpreadItterations; j++) | |
{ | |
// TODO: handle cases for high values at begining and end of array | |
for (int i = 1; i < m_processedFFTDataArray.Length - 1; i++) | |
{ | |
float amountToRedistributePerSide = 0.5f * m_localPeakRedistributionRatio * m_processedFFTDataArray[i]; | |
prevDelta = m_processedFFTDataArray[i] - m_processedFFTDataArray[i - 1]; | |
postDelta = m_processedFFTDataArray[i] - m_processedFFTDataArray[i + 1]; | |
if (prevDelta > m_localPeakValueThreashold) | |
{ | |
spreadCounter++; | |
m_processedFFTDataArray[i] -= amountToRedistributePerSide; | |
m_processedFFTDataArray[i - 1] += 0.5f * amountToRedistributePerSide; | |
} | |
if (postDelta > m_localPeakValueThreashold) | |
{ | |
spreadCounter++; | |
m_processedFFTDataArray[i] -= amountToRedistributePerSide; | |
m_processedFFTDataArray[i + 1] += 0.5f * amountToRedistributePerSide; | |
} | |
} | |
} | |
//if(spreadCounter > 0) | |
// Debug.LogError("spread: " + spreadCounter ); | |
} | |
Color CalculateFreshRGB() | |
{ | |
int subdivisionIndex = 0; | |
int subdivisionInterval = m_processedFFTDataArray.Length / 8; | |
// goes through subdivisions 0 - 3 | |
float r = 0; | |
int r_SubdivisionStart = 0; | |
int r_SubdivisionEnd = 4; | |
float r_weight = 1.0f / ((r_SubdivisionEnd - r_SubdivisionStart + 1) * (float)subdivisionInterval); | |
// goes through subdivisions 3 - 6 | |
float g = 0; | |
int g_SubdivisionStart = 3; | |
int g_SubdivisionEnd = 6; | |
float g_weight = 1.0f / ((g_SubdivisionEnd - g_SubdivisionStart + 1) * (float)subdivisionInterval); | |
// goes through subdivisions 4 - 7 | |
float b = 0; | |
int b_SubdivisionStart = 4; | |
int b_SubdivisionEnd = 7; | |
float b_weight = 1.0f / ((b_SubdivisionEnd - b_SubdivisionStart + 1) * (float)subdivisionInterval); | |
float progressOnCurve = 0; | |
for (int i = 0; i < m_processedFFTDataArray.Length; i++) | |
{ | |
if (i % subdivisionInterval == 0 && i != 0) | |
subdivisionIndex += 1; | |
if (subdivisionIndex <= r_SubdivisionEnd) | |
{ | |
progressOnCurve = Mathf.InverseLerp(subdivisionInterval * r_SubdivisionStart, subdivisionInterval * r_SubdivisionEnd, i); | |
r += m_rValueCurve.Evaluate(progressOnCurve) * m_processedFFTDataArray[i] * r_weight; | |
} | |
if (subdivisionIndex >= g_SubdivisionStart && subdivisionIndex <= g_SubdivisionEnd) | |
{ | |
progressOnCurve = Mathf.InverseLerp(subdivisionInterval * g_SubdivisionStart, subdivisionInterval * g_SubdivisionEnd, i); | |
g += m_gValueCurve.Evaluate(progressOnCurve) * m_processedFFTDataArray[i] * g_weight; | |
} | |
if (subdivisionIndex >= b_SubdivisionStart) | |
{ | |
progressOnCurve = Mathf.InverseLerp(subdivisionInterval * b_SubdivisionStart, subdivisionInterval * b_SubdivisionEnd, i); | |
b += m_bValueCurve.Evaluate(progressOnCurve) * m_processedFFTDataArray[i] * b_weight; | |
} | |
} | |
Color calculatedColor = m_colorScaler * new Color(r * m_rScaler, g * m_gScaler, b * m_bScaler); | |
m_currentFFTColor = calculatedColor; | |
d_r = calculatedColor.r; | |
d_g = calculatedColor.g; | |
d_b = calculatedColor.b; | |
return calculatedColor; | |
} | |
float[] CalculateFreshFFTData() | |
{ | |
//m_liveAudioDataManager.m_liveAudioSource.GetSpectrumData(m_currentRawFFTDataArray, 0, FFTWindow.BlackmanHarris); | |
AudioListener.GetSpectrumData(m_currentRawFFTDataArray, 0, FFTWindow.BlackmanHarris); | |
ProcessRawFFTData(); | |
return m_processedFFTDataArray; | |
} | |
// ported over from Sagar's VR_VF project | |
// http://answers.unity3d.com/questions/165729/editing-height-relative-to-audio-levels.html | |
float CalculateFreshVolume() | |
{ | |
float vol = 0; | |
AudioListener.GetOutputData(m_outputSamplesArray, 0); | |
float sum = 0; | |
for (int i = 0; i < m_outputSamplesArray.Length; i++) | |
{ | |
sum += m_outputSamplesArray[i] * m_outputSamplesArray[i]; | |
} | |
// vol in RMS | |
vol = Mathf.Sqrt(sum / (float)m_outputSamplesArray.Length); | |
//vol = (sum / (float)m_outputSamplesArray.Length); | |
vol = Mathf.Sqrt(vol); | |
m_currentVolume = vol; | |
m_volumeRollingAverageIndex = (m_volumeRollingAverageIndex + 1) % k_volumeRollingAverageCount; | |
m_volumeRollingAverageArray[m_volumeRollingAverageIndex] = m_currentVolume; | |
sum = 0; | |
for (int i = 0; i < k_volumeRollingAverageCount; i++) | |
{ | |
sum += m_volumeRollingAverageArray[i]; | |
} | |
m_volumeRollingAverage = sum / (float)k_volumeRollingAverageCount; | |
return vol; | |
} | |
int CalculateMaxExtraSamplesCountForSection(int targetSectionIndex) | |
{ | |
int totalSamplesSum = 0 + m_samplesAccumulationStartIndexOffset; | |
int sectionIndexCounter = 0; | |
int sectionInterval = m_processedFFTDataArray.Length / 8; | |
for (int i = 0; i < m_processedFFTDataArray.Length; i++) | |
{ | |
if (i % sectionInterval == 0 && i != 0) | |
sectionIndexCounter += 1; | |
totalSamplesSum += m_samplesAccumulationPerSectionArray[sectionIndexCounter]; | |
} | |
int samplesRemaining = m_currentRawFFTDataArray.Length - totalSamplesSum; | |
int maxSamplesCountForIndex = samplesRemaining / m_samplesAccumulationPerSectionArray[targetSectionIndex]; | |
return maxSamplesCountForIndex; | |
} | |
public void IncrementFrequencyRangeSamplesCount(int sectionIndex, int samplesChangeCount) | |
{ | |
int maxSamplesCount = m_samplesAccumulationPerSectionArray[sectionIndex] + CalculateMaxExtraSamplesCountForSection(sectionIndex); | |
int changedSamplesCountRaw = m_samplesAccumulationPerSectionArray[sectionIndex] + samplesChangeCount; | |
m_samplesAccumulationPerSectionArray[sectionIndex] = (int)Mathf.Clamp(changedSamplesCountRaw, 1, maxSamplesCount); | |
} | |
// public data getters | |
// array is of length m_processedFFTDataSize | |
public float[] GetFreshFFTData() | |
{ | |
return m_processedFFTDataArray; | |
} | |
public Color GetFreshRGB() | |
{ | |
return m_currentFFTColor; | |
} | |
// range is 0 to 1, float | |
public float GetVolumeRollingAverage() | |
{ | |
return m_volumeRollingAverage; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment