Music Analyzer Details and Script

**DISCLAIMER : Script has not been commented or structured well. Please evaluate the script as a reference rather than a plug-in play script. I have not found time to organize it but I would rather atleast share what I have in case it can help someone else.

When I was a child my father would tell me to Improvise with what you have. My most valued advice I have received from him. What does that have to do with anything? Well it does. Comprehensive music analyzing does not appear to be possible with the direct built-in library that Unity has. So when something does not appear to be possible, you IMPROVISE. This is a lesson I believe any programming should take to heart. Do what you can with what knowledge you may have.

Typically to get data from a song, all that is required is a few numbers that demonstrate how each segment of a song compares to another segment. This also has to be done in an adequate amount of time. Simply put, the music analyzer takes a general sample of data through the song and averages it out to give me a guestimate of how the song is relatively structured. This may not appear to be accurate at first. But what this does is get rid of any unnecessary data and allows me to filter how much I need to know.

Just Show Me the Script
Play the audio file and store the spectrum data into an array/variable. That’s simply how it is done. The script will prompt the audio to jump forward 5seconds after about one seconds worth of data is recorded.

var audioTrack : AudioClip;

var listener : AudioListener;

var timeSpace : float= 0.05;


static var songTime : float = 0;
static var globalOutput : float;
private var audioPlay : GameObject;
private var samps : float[] = new float[512];
private var dataBlock : int = 0;

static var songData : int[];
private var tempSongData : Array = new Array( 0 );
private var songRound : Array = new Array();
private var  songTimeLength : float;

private var roundCount : int = 0;
private var sampleBlock : int = 5;
private var  dataRound : float = 0.0;
private var dataEveryOther : boolean = false;
private var dataEO : int = 0;
private var roundEO : int = 0;
private var silenceBuffer : int = 5;

function Start() {
	songTime = 0;
	if( audioReader.mySong == null ){
		Debug.Log("missing the song");
	}

	//create audio player game object and position it at the same point as our audio listener
	audioPlay = new GameObject("audioPlay");
	audioPlay.AddComponent("AudioSource");
	audioPlay.transform.position = listener.transform.position;
	
	audioPlay.audio.clip = audioReader.mySong;
	songTimeLength = audioReader.mySong.length;
	audioPlay.audio.Stop();
	listener.volume = 0.0;
	
	audioPlay.audio.Play();
	audioPlay.audio.time = 0;
	tempSongData[0] = 0;
	InvokeRepeating("audioAnalyzer", 0, timeSpace);

}


function audioAnalyzer() {
	
	var average : float = 0;
	audioPlay.audio.GetSpectrumData(samps, 0, FFTWindow.Rectangular);
	var sampleCount : int = Mathf.Pow(2,7)*2;
		
	for ( j=0; j < sampleCount; j++ ) {
		average += samps[j] * ( j+1 );
	}
	
	var newVal : int = average;
	dataRound += average;
	if( ! dataEveryOther ){
		dataEveryOther = true;
		dataEO += average;
	}else{
		dataEveryOther = false;
	}
	roundCount += 1;
	
	if( roundCount == 22 ){
		var roundNum : int = dataRound; //convert data to an int
		tempSongData[dataBlock] = roundNum;
		dataBlock += 1;
		roundEO += 1;
		dataRound = 0;
		roundCount = 0;
		songTime += sampleBlock;
		audioPlay.audio.time = songTime;
		Debug.Log( " the current songtime is " + songTime);
		
		if( roundEO == 2 ){
			// var roundNumEO : int = dataEO; //convert data to an int
			tempSongData[dataBlock] = dataEO;
			dataBlock += 1;
			roundEO += 1;
			tempSongData[dataBlock] = 0;
			roundEO = 0;
			dataEO = 0;
		}
	}
	if( audioPlay.audio.isPlaying == false ){//analyzing finished, now store data
		listener.volume = 1.0;
		silenceBuffer = ( songTimeLength / sampleBlock ) / 6 ;
		for( e = 0; e < silenceBuffer; e++ ){
			tempSongData[dataBlock] = 0;
			dataBlock += 1;
		}
		//Debug.Log("call numbers is " + dataBlock );
		songData = tempSongData.ToBuiltin( int );
		if( songIsWeb >= 1 ){
			storeSongData( songName);
			
		}else if( songIsWeb == 0){
		
			Debug.Log("song is NOT WEB !!");
		}
		
		var debugArray : Array = new Array( songData );
		Debug.Log("Songdata is " + debugArray );
		CancelInvoke();
		// DontDestroyOnLoad( audioPlay.audio.clip );
		Application.LoadLevel("basic_mode");
	}
}

Music Analyzer Limitations and Weaknesses
Unfortunately the results from the audio are never exactly the same. The invoked function does not keep a synchronized pace with the audio playing. Hence the reason why the script records 22 samples every 5 seconds. The 22 samples are averaged into one value giving me a close approximate value each time the same audio is analyzed. Also keep in mind that this script isn’t a true music analyzer script but a simple trick to simulate one.

In my unity game m7Discovery I categorized the averaged samples into categories in the thousandth place. For example lowest frequencies are a 1,000 or less. Here is an example :

function analysisToCalculation(songInt : int){
		var returnValue : int = 0;
		
		if( songInt <= 1000 ){ //low frequencies
			returnValue = 0;
		}else if( songInt <= 2000 ){
			returnValue = 1; //1
		}else if( songInt <= 3000 ){
			returnValue = 3; //3
		}else if( songInt <= 4000 ){
			returnValue = 12;
		}else if( songInt <= 5000 ){
			returnValue = 8;
		}else if( songInt <= 6000 ){
			returnValue = 10;
		}else if( songInt <= 7000 ){
			returnValue = 5;
		}else if( songInt <= 8000 ){
			returnValue = 9;
		}else if( songInt <= 9000 ){//higher frequencies
			returnValue = 6;
		}else{
			returnValue = 0;
		}

TL;DR: Here is my messy code to simulate a music analyzer in order to generate whatever you would like with it. Is not guaranteed to be plug in play because I extracted the script from my game m7Discovery.

If you want any clarifications just ask away

Hi

How come you only loop for 256 when your samps is 512?

var sampleCount : int = Mathf.Pow(2,7)*2; //256

for ( j=0; j < sampleCount; j++ ) {
average += samps[j] * ( j+1 );
}