예제 #1
0
        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();
        }
예제 #2
0
        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);
        }
예제 #3
0
 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;
     }
 }
예제 #4
0
        public static void ShowWindow(SongItem item)
        {
            var window = GetWindow <SequenceEditor>();

            window.titleContent = new GUIContent("Sequencer");
            window.Show();

            window.songItem = item;
        }
예제 #5
0
        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));
        }
예제 #6
0
        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);
        }
예제 #7
0
        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();
        }
예제 #8
0
        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);
        }
예제 #9
0
        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);
        }
예제 #10
0
 private void OnValidate()
 {
     closeBeatDistance = Mathf.Max(0, SongItem.RoundToNearestBeat(closeBeatDistance));
 }
 public abstract List <SongItem.MidiNote> OnGenerateSequence(SongItem songItem);
예제 #12
0
 public LiteSongItem(string name, SongItem songItem)
 {
     this.bpm   = songItem.bpm;
     this.notes = songItem.notes;
 }
예제 #13
0
        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();
                }
            }
        }