public void PlaySong(SongItem songItem, double specificStartTime = 0) { currentSongItem = songItem; songPaused = false; songHasStarted = true; accumulatedPauseTime = 0; dspPausedTime = 0; songPosition = -1; if (audioSource) { audioSource.clip = songItem.clip; } // songItem.ResetNotesState(); currnetNotes = songItem.GetNotes(); secPerBeat = 60f / songItem.bpm; //Starting the audio play back dspStartTime = AudioSettings.dspTime; if (audioSource) { audioSource.PlayScheduled(AudioSettings.dspTime + delay); audioSource.time = (float)specificStartTime; dspStartTime -= specificStartTime; } trackManager.SetupForNewSong(); onSongStartPlay.Invoke(); }
public static void UpdateBpm(MidiFile rawMidi, SongItem midi) { if (rawMidi == null) { Debug.LogError("Cannot find the midi file"); return; } midi.notes.Clear(); if (midi.bpm <= 0) { return; } var tempoMap = TempoMap.Create(Tempo.FromBeatsPerMinute(midi.bpm)); foreach (var note in rawMidi.GetNotes()) { midi.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)) }); } EditorUtility.SetDirty(midi); }
public static void UpdateNotesTime(SongItem songItem) { foreach (var note in songItem.notes) { note.time = 60f / songItem.bpm * note.beatIndex; note.noteLength = 60f / songItem.bpm * note.beatLengthIndex; } }
public static void ShowWindow(SongItem item) { var window = GetWindow <SequenceEditor>(); window.titleContent = new GUIContent("Sequencer"); window.Show(); window.songItem = item; }
public static LiteSongItem FindJsonFile(SongItem target) { var path = AssetDatabase.GetAssetPath((SongItem)target); var selectedMidFilePath = EditorUtility.OpenFilePanelWithFilters("Import sequence from json", Directory.GetParent(path).ToString(), new string[] { "Json File", "json" }); if (string.IsNullOrEmpty(selectedMidFilePath)) { return(null); } var json = File.ReadAllText(selectedMidFilePath); if (string.IsNullOrEmpty(json)) { Debug.LogWarning("Json file empty!"); return(null); } return(LiteSongItem.FromJson(json)); }
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 void PlaySong(SongItem songItem) { songPaused = false; songHasStarted = true; accumulatedPauseTime = 0; dspPausedTime = 0; songPosition = -1; audioSource.clip = songItem.clip; songItem.ResetNotesState(); currnetNotes = songItem.notes; secPerBeat = 60f / songItem.bpm; //Starting the audio play back dspStartTime = AudioSettings.dspTime; audioSource.PlayScheduled(AudioSettings.dspTime + delay); TrackManager.INSTANCE.SetupForNewSong(); }
public static MidiFile FindMidiFile(SongItem target) { var path = AssetDatabase.GetAssetPath((SongItem)target); var selectedMidFilePath = EditorUtility.OpenFilePanelWithFilters("Import sequence from midi", Directory.GetParent(path).ToString(), new string[] { "Midi File", "mid" }); if (!string.IsNullOrEmpty(selectedMidFilePath)) { return(MidiFile.Read(selectedMidFilePath)); } // string filePath = path.Substring(0, path.Length - Path.GetFileName(path).Length); // string[] files = Directory.GetFiles(filePath, "*.mid"); // if (files.Length > 0) // { // // string midiFileName = Path.Combine(filePath, ); // return MidiFile.Read(files[0]); // } return(null); }
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)); }
public abstract List <SongItem.MidiNote> OnGenerateSequence(SongItem songItem);
public LiteSongItem(string name, SongItem songItem) { this.bpm = songItem.bpm; this.notes = songItem.notes; }
public static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths) { foreach (string asset in importedAssets) { if (asset.EndsWith(".mid")) { var detectedBpm = -1; var bpmString = ""; foreach (var item in Path.GetFileNameWithoutExtension(asset).Split(' ')) { if (item.ToLower().Contains("bpm")) { // Debug.Log(item); // Debug.Log(Regex.Match(item, @"\d+").Value); detectedBpm = int.Parse(Regex.Match(item, @"\d+").Value); bpmString = item; break; } } string songName; if (!string.IsNullOrEmpty(bpmString)) { songName = Path.GetFileNameWithoutExtension(asset).Replace(bpmString, "").Trim(); } else { songName = Path.GetFileNameWithoutExtension(asset); } string filePath = asset.Substring(0, asset.Length - Path.GetFileName(asset).Length); string fileWithoutExt = filePath + songName; string newFileName = fileWithoutExt + ".asset"; var rawMidi = MidiFile.Read(asset); SongItem songItem = (SongItem)AssetDatabase.LoadAssetAtPath(newFileName, typeof(SongItem)); AudioClip clipFile; clipFile = (AudioClip)AssetDatabase.LoadAssetAtPath(fileWithoutExt + ".mp3", typeof(AudioClip)); if (!clipFile) { clipFile = (AudioClip)AssetDatabase.LoadAssetAtPath(fileWithoutExt + ".wav", typeof(AudioClip)); } else if (!clipFile) { clipFile = (AudioClip)AssetDatabase.LoadAssetAtPath(fileWithoutExt + ".ogg", typeof(AudioClip)); } var isNew = false; if (!songItem) { songItem = ScriptableObject.CreateInstance <SongItem>(); isNew = true; } if (songItem.bpm == 0 && detectedBpm != -1) { songItem.bpm = detectedBpm; } songItem.clip = clipFile; SongItemEditor.UpdateBpm(rawMidi, songItem); if (isNew) { Debug.Log("SongItem created for " + songName); AssetDatabase.CreateAsset(songItem, newFileName); } AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); } } }