public static void UpdateBpm(MidiFile rawMidi, SongItem songItem) { if (rawMidi == null) { Debug.LogError("Cannot find the midi file"); return; } songItem.notes.Clear(); var detectedTempoMap = rawMidi.GetTempoMap(); var tempoMap = songItem.useCurrentBpmMidiImport ? TempoMap.Create(detectedTempoMap.TimeDivision, Tempo.FromBeatsPerMinute(songItem.bpm), detectedTempoMap.TimeSignature.AtTime(0)) : detectedTempoMap; if (!songItem.useCurrentBpmMidiImport) { songItem.bpm = (int)rawMidi.GetTempoMap().Tempo.AtTime(0).BeatsPerMinute; } Debug.Log($"Updating Midi Data {tempoMap.TimeDivision}, {songItem.bpm}bpm"); int count = 0; foreach (var note in rawMidi.GetNotes()) { count++; var beat = GetMetricTimeSpanTotal(note.TimeAs <MetricTimeSpan>(tempoMap)) * songItem.bpm / 60; var beatLength = GetMetricTimeSpanTotal(note.LengthAs <MetricTimeSpan>(tempoMap)) * songItem.bpm / 60; // Debug.Log(RoundToNearestBeat(beat)); songItem.notes.Add(new SongItem.MidiNote() { noteName = ParseEnum <SongItem.NoteName>(note.NoteName.ToString()), noteOctave = note.Octave, time = GetMetricTimeSpanTotal(note.TimeAs <MetricTimeSpan>(tempoMap)), noteLength = GetMetricTimeSpanTotal(note.LengthAs <MetricTimeSpan>(tempoMap)), //This two is for recalculating the currect time when the bpm is changed beatIndex = SongItem.RoundToNearestBeat(beat), beatLengthIndex = SongItem.RoundToNearestBeat(beatLength), }); } Debug.Log(count + " Note(s) detected from Midi file"); EditorUtility.SetDirty(songItem); }
public override List <SongItem.MidiNote> OnGenerateSequence(SongItem songItem) { //Safety checks if (!songItem || !songItem.clip) { Debug.LogError("Failed to generate, the clip or the songItem is null"); return(null); } //Seed handling if (reseed) { Random.InitState(System.Environment.TickCount); } else { Random.InitState(seed); } //Calculating the total beat length with quantize to 0.25 var totalBeat = SongItem.RoundToNearestBeat(songItem.bpm * songItem.clip.length / 60f); // Debug.Log(totalBeat); var notes = new List <SongItem.MidiNote>(); ///Begin handling onset notes generations var lastBeatIndex = -1f; if (algorithm == Algorithm.OnsetRandom) { if (songItem.onsetData != null && songItem.onsetData.Length > 0) { for (int i = 0; i < songItem.onsetData.Length; i++) { var onsetTime = AudioAnalysis.getTimeFromIndex(songItem.clip, i); var beatIndex = SongItem.RoundToNearestBeat(onsetTime * songItem.bpm / 60); //Check for close beat distance if (lastBeatIndex == -1 || (beatIndex - lastBeatIndex) > closeBeatDistance) { var fallInRange = false; if (usePercentage) { var onsetPrecentage = (songItem.onsetData[i] / songItem.onsetMax); fallInRange = onsetPrecentage > onsetMinThresholdPercentage && onsetPrecentage <= onsetMaxThresholdPercentage; } else { fallInRange = songItem.onsetData[i] > onsetMinThreshold && songItem.onsetData[i] <= onsetMaxThreshold; } if (fallInRange) { if (!allowHalfStep && (beatIndex % 1) == 0.5f) { continue; } if (!allowQuarterStep && ((beatIndex % 1) == 0.25f || (beatIndex % 1) == 0.75f)) { continue; } notes.Add(new SongItem.MidiNote() { beatIndex = beatIndex, beatLengthIndex = 1f, noteName = SongItem.noteNameMapping[Random.Range(0, targetTrackCount)], noteOctave = 3, //in seconds time = onsetTime, noteLength = 60f / songItem.bpm * 1f, }); lastBeatIndex = beatIndex; } } } return(notes); } else { Debug.LogWarning("Onset data is empty, nothing generated."); return(null); } } //Begin simple random note geneation var maxCountX = 1; var preferredX = -1; var previousX = -1; //First to loop through all beat for (float y = 0; y < totalBeat; y += 1f) { var currentCountX = 0; maxCountX = 1; //Randomize max count x if (UnityEngine.Random.value > 0.9f) { maxCountX = 2; } else if (UnityEngine.Random.value < 0.2f) { maxCountX = 0; } //Randomize preferred X if (maxCountX == 1) { while (previousX == preferredX) { preferredX = UnityEngine.Random.Range(0, 4); } } previousX = preferredX; //Seconds to loop through all track for (int x = 0; x < targetTrackCount; x++) { //Not our targeted track0 if (maxCountX == 1 && preferredX != x) { continue; } //We have more than on quota, try some randomness if (maxCountX > 1) { //Unlucky -> skip if (UnityEngine.Random.value > 0.5f) { continue; } } //We have reached out quota, skip if (currentCountX >= maxCountX) { continue; } //Going to create our note at this beat notes.Add(new SongItem.MidiNote() { beatIndex = y, beatLengthIndex = 1f, noteName = SongItem.noteNameMapping[x], noteOctave = 3, //in seconds time = 60f / songItem.bpm * y, noteLength = 60f / songItem.bpm * 1f, }); currentCountX++; } } return(notes); }
private void OnValidate() { closeBeatDistance = Mathf.Max(0, SongItem.RoundToNearestBeat(closeBeatDistance)); }