void Awake() { if (current == null) { current = this; } _beatMapExists = true; _audioClipExists = true; _audio = GetComponent <AudioSource>(); if (_audio.clip == null) { _audioClipExists = false; Debug.LogError("Maestro: No Audio Clip!"); } else { if ("BeatMap_" + _audio.clip.name.Replace(".mp3", "") != beatmapFile.name) { Debug.LogWarning("Maestro: Audio Clip and Beatmap File name mismatch!"); } } _beatIndex = 0; onBeat = OnBeat; lateOnBeat = LateOnBeat; listeners = new List <MusicBehaviour>(); beatmap = BeatMapSerializer.BeatMapReader.ReadBeatMap(beatmapFile); }
/// <summary> /// Writes beatmap to xml file. /// </summary> /// <param name="beats">Raw data from FFT.</param> /// <param name="name">Xml file name.</param> public static void BeatMapToFile(BeatMap beats, string name) { //BeatMap map = new BeatMap(name, beats.songLength); //this is a test using a dummy object //map.AddBeat(1, 3.0f, 5.0f); BeatMapSerializer.BeatMapWriter.WriteBeatMap(beats); }
public static BeatMap ReadBeatMap(TextAsset xmlFile) { XmlSerializer serializer = new XmlSerializer(typeof(BeatMap)); StringReader xml = new StringReader(xmlFile.text); BeatMap newMap = serializer.Deserialize(xml) as BeatMap; return(newMap); }
public static BeatMap ReadBeatMap(string filePath) { XmlSerializer serializer = new XmlSerializer(typeof(BeatMap)); FileStream stream = new FileStream(filePath, FileMode.Open); BeatMap newMap = (BeatMap)serializer.Deserialize(stream); stream.Close(); return(newMap); }
/// <summary> /// Analyzes the song data for beat information /// </summary> /// <returns>A beatmap of the song.</returns> /// <param name="data">Raw data.</param> /// <param name="clip">Audio clip to analyze.</param> /// <param name="thresholdModifier">Threshold value modifier</param> public BeatMap AnalyzeData(double[] data, AudioClip clip, float thresholdModifier) { _beatList = new BeatMap(clip.name, clip.length); int numParts = (int)clip.length; int partitionSize = (data.Length + 1) / numParts; //We only care about the magnitude of our data, so we get the absolute values before doing analysis data = data.ToList().Select(i => (double)Mathf.Abs((float)i)).ToArray(); for (int i = 0; i < data.Length - (int)(partitionSize); i += (int)(partitionSize)) { //finds the average value of the sub-partition starting at index i and of size partitionSize double avg = data.Skip(i).Take(partitionSize).Average(); //finds the highest energy sample in the current partition //int largest = i; //calculate the average energy variance in the partition double variance = 0; for (int j = 0; j < partitionSize; j++) { variance += (data[i + j] - avg) * (data[i + j] - avg); } variance /= partitionSize; //calculate the base threshold using some magic numbers and the variance double thresh = (-0.0025714 * variance) + 1.5142857; thresh *= thresholdModifier; //if the any sample is threshold percent larger than the average, then we mark it as a beat. for (int j = 0; j < partitionSize; j++) { if (data[i + j] > thresh * avg) { _beatList.AddBeat(((float)(i + j) / data.Length) * clip.length, 1f, data[i + j]); } } } //eliminate double positives (the same beat occurring in two overlapping partitions, for example) by removing beats with extremely similar timestamps for (int i = 0; i < _beatList.beats.Count - 1; i++) { if ((_beatList.beats[i + 1].timeStamp - _beatList.beats[i].timeStamp) < .1) { if (_beatList.beats[i + 1].energy > _beatList.beats[i].energy) { _beatList.beats.RemoveAt(i); } else { _beatList.beats.RemoveAt(i + 1); } i--; } } return(_beatList); }
/// <summary> /// Writes a beatmap to xml file from BPM and song length. /// </summary> /// <param name="name">Xml file name.</param> /// <param name="bpm">Beats per minute.</param> /// <param name="numBeats">Number of beats.</param> public static void BeatMapFromBPM(string name, float bpm, int numBeats) { float beatStep = 60f / bpm; float length = (float)numBeats * beatStep; BeatMap beats = new BeatMap(name, length); for (float i = 0f; i < length; i += beatStep) { beats.AddBeat(i, 1f, 1); } BeatMapSerializer.BeatMapWriter.WriteBeatMap(beats); Debug.LogFormat("Coda: Created beatmap {0} with BPM of {1} and running time of {2} seconds ({3} beats long).", name, bpm, length, numBeats); }
/// <summary> /// Analyzes the song data for beat information /// </summary> /// <returns>A beatmap of the song.</returns> /// <param name="data">Raw data.</param> /// <param name="clip">Audio clip to analyze.</param> /// <param name="thresholdModifier">Threshold value modifier</param> public BeatMap AnalyzeData(double[] data, AudioClip clip, float thresholdModifier) { _beatList = new BeatMap(clip.name, clip.length); int numParts = (int)clip.length; int partitionSize = (data.Length+1)/numParts; //We only care about the magnitude of our data, so we get the absolute values before doing analysis data = data.ToList().Select(i => (double)Mathf.Abs((float)i)).ToArray(); for(int i = 0; i < data.Length-(int)(partitionSize); i += (int)(partitionSize)) { //finds the average value of the sub-partition starting at index i and of size partitionSize double avg = data.Skip(i).Take(partitionSize).Average(); //finds the highest energy sample in the current partition //int largest = i; //calculate the average energy variance in the partition double variance = 0; for(int j = 0; j < partitionSize; j++) { variance += (data[i + j] - avg) * (data[i + j] - avg); } variance /= partitionSize; //calculate the base threshold using some magic numbers and the variance double thresh = (-0.0025714 * variance) + 1.5142857; thresh *= thresholdModifier; //if the any sample is threshold percent larger than the average, then we mark it as a beat. for (int j = 0; j < partitionSize; j++) { if (data[i+j] > thresh * avg) { _beatList.AddBeat(((float)(i + j) / data.Length) * clip.length, 1f, data[i + j]); } } } //eliminate double positives (the same beat occurring in two overlapping partitions, for example) by removing beats with extremely similar timestamps for(int i = 0; i < _beatList.beats.Count-1; i++) { if((_beatList.beats[i+1].timeStamp - _beatList.beats[i].timeStamp) < .1) { if(_beatList.beats[i + 1].energy > _beatList.beats[i].energy) { _beatList.beats.RemoveAt(i); } else { _beatList.beats.RemoveAt(i + 1); } i--; } } return _beatList; }
public static void WriteBeatMap(BeatMap map) { // Check if beatmap folder exists if (!Directory.Exists(BeatMapSerializer.filePath)) { Directory.CreateDirectory(BeatMapSerializer.filePath); } XmlSerializer serializer = new XmlSerializer(typeof(BeatMap)); StreamWriter writer = new StreamWriter(BeatMapSerializer.filePath + "/BeatMap_" + map.fileName + ".xml", false, System.Text.Encoding.UTF8); serializer.Serialize(writer, map); writer.Close(); Debug.Log("Wrote beatmap to file"); }
void Awake() { if (current == null) { current = this; } _beatMapExists = true; _audioClipExists = true; _audio = GetComponent<AudioSource>(); if (_audio.clip == null) { _audioClipExists = false; Debug.LogError("Maestro: No Audio Clip!"); } else { if ("BeatMap_" + _audio.clip.name.Replace(".mp3", "") != beatmapFile.name) { Debug.LogWarning("Maestro: Audio Clip and Beatmap File name mismatch!"); } } _beatIndex = 0; onBeat = OnBeat; lateOnBeat = LateOnBeat; listeners = new List<MusicBehaviour>(); beatmap = BeatMapSerializer.BeatMapReader.ReadBeatMap(beatmapFile); }
//UPDATE LOOP FOR UNITY EDITOR void OnGUI() { int waveformWidth = (int)(position.width - _controlsWidth); _controlsPos = new Rect(0, 0, _controlsWidth, 200); _waveformPos = new Rect(_controlsWidth, 0, waveformWidth, 300); HandleWindowInstantiation(); //make sure the UI exists _waveformMarkupWindow.Setup(_waveformPos); //read in xml beatmap file if it exists for the supplied audio file if (_analysisControlWindow.musicToAnalyze != _prevAudioClip) //only load if new //ANALYZER SONG IF ONE IS ASSIGNED IN THE EDITOR GUI { if (_analysisControlWindow.musicToAnalyze != null) { _filePath = WaveformSerializer.filePath + "/Waveform_" + _analysisControlWindow.musicToAnalyze.name + ".xml"; //location of possibly saved Wavefrom if (System.IO.File.Exists(_filePath)) //retrieve the Waveform if we computed one in the past { Waveform newWave = WaveformSerializer.ReadWaveformData(_filePath); _waveformMarkupWindow.waveform = newWave.data; } else { _waveformMarkupWindow.waveform = null; } _filePath = BeatMapSerializer.filePath + "/BeatMap_" + _analysisControlWindow.musicToAnalyze.name + ".xml"; // location of possibly saved Beatmap if (System.IO.File.Exists(_filePath)) //load Beatmap for current song if it could be found { BeatMap newMap = BeatMapSerializer.BeatMapReader.ReadBeatMap(_filePath); _waveformMarkupWindow.beatmap = newMap; } else { _waveformMarkupWindow.beatmap = null; } } //NO SONG WAS ASSIGNED else { _waveformMarkupWindow.waveform = null; _waveformMarkupWindow.beatmap = null; } _prevAudioClip = _analysisControlWindow.musicToAnalyze; //audio clip from previous frame } //DRAW SUBWINDOWS HandleDrawingSubwindow(_analysisControlWindow, _waveformMarkupWindow); /* * //waveformMarkupWindow.DrawWindowDebug();//shows borders of Subwinows * * if (waveformMarkupWindow.IsInSubwindow(Event.current.mousePosition)) {//check if we can click inside a subwindow * //Debug.LogFormat("waveform has it"); * } */ //USER HAS TRIGGERED ANALYSIS VIA ANALYZER CONTROLLER SUBWINDOW if (_analysisControlWindow.triggerAnalysis == true) { _analysisControlWindow.triggerAnalysis = false; //ANALYSIS //feed Analyzer the user-defined audio file to get audio as frequency data double[] waveformData = _analyzer.ProcessAudio(_analysisControlWindow.musicToAnalyze, _analysisControlWindow.numPartitions, _analysisControlWindow.dataAbstractionOverlapPercent); //feed in frequency data to get a Beatmap BeatMap beats = _analyzer.AnalyzeData(waveformData, _analysisControlWindow.musicToAnalyze, _analysisControlWindow.threshold); //SERIALIZATOIN AnalyzerTools.WaveformToFile(waveformData, _analysisControlWindow.musicToAnalyze.name); AnalyzerTools.BeatMapToFile(beats, _analysisControlWindow.musicToAnalyze.name); //DRAWING _waveformMarkupWindow.waveform = waveformData; _waveformMarkupWindow.beatmap = beats; } Repaint(); //force GUI to draw every update even if not clicked on }