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 ExportMsb(Stream dataStream, string outPath) { var file = MsbFile.Read(dataStream); var midiFile = new MidiFile(); var tempoMap = TempoMap.Create(new TicksPerQuarterNoteTimeDivision(960), Tempo.FromBeatsPerMinute((int)file.BpmEntries[0].Bpm)); foreach (var score in file.ScoreEntries) { var track = new TrackChunk(); var scoreNotes = new List <Note>(); foreach (var bar in score.Bars) { scoreNotes.Add(new Note(new SevenBitNumber((byte)(bar.Note + 24)), bar.Length, bar.Offset)); } track.AddNotes(scoreNotes); midiFile.Chunks.Add(track); } midiFile.ReplaceTempoMap(tempoMap); midiFile.Write(outPath); }
public void Create_TimeSignature() { var expectedTimeSignature = new TimeSignature(3, 8); TestSimpleTempoMap(TempoMap.Create(expectedTimeSignature), new TicksPerQuarterNoteTimeDivision(), Tempo.Default, expectedTimeSignature); }
public void Create_Tempo() { var expectedTempo = new Tempo(123456); TestSimpleTempoMap(TempoMap.Create(expectedTempo), new TicksPerQuarterNoteTimeDivision(), expectedTempo, TimeSignature.Default); }
public void GetTempoAtTime_NonDefaultTempoMap_SingleChangeAtStart_GetAtMiddle() { var microsecondsPerQuarterNote = 100000; var tempoMap = TempoMap.Create(new Tempo(microsecondsPerQuarterNote)); var tempo = tempoMap.GetTempoAtTime(new MetricTimeSpan(0, 0, 1)); Assert.AreEqual(new Tempo(microsecondsPerQuarterNote), tempo, "Tempo is invalid."); }
public void GetBeatLength_ConstantTimeSignature(long bars, int timeSignatureNumerator, int timeSignatureDenominator) { const short ticksPerQuarterNote = 100; var tempoMap = TempoMap.Create(new TicksPerQuarterNoteTimeDivision(ticksPerQuarterNote), new TimeSignature(timeSignatureNumerator, timeSignatureDenominator)); var length = BarBeatUtilities.GetBeatLength(bars, tempoMap); Assert.AreEqual(ticksPerQuarterNote * 4 / timeSignatureDenominator, length, "Beat length is invalid."); }
public void Create_Tempo_TimeSignature() { var expectedTempo = Tempo.FromBeatsPerMinute(123); var expectedTimeSignature = new TimeSignature(3, 8); TestSimpleTempoMap(TempoMap.Create(expectedTempo, expectedTimeSignature), new TicksPerQuarterNoteTimeDivision(), expectedTempo, expectedTimeSignature); }
public void GetTimeSignatureAtTime_NonDefaultTempoMap_SingleChangeAtStart_GetAtMiddle() { var numerator = 1; var denominator = 16; var tempoMap = TempoMap.Create(new TimeSignature(numerator, denominator)); var timeSignature = tempoMap.GetTimeSignatureAtTime(new MetricTimeSpan(0, 0, 1)); Assert.AreEqual(new TimeSignature(numerator, denominator), timeSignature, "Time signature is invalid."); }
public MidiFile Build() { var midiFile = new MidiFile(_trackChunk); //1000 milliseconds in a second so using this should allow for timing with millisecond deltas var tempoMap = TempoMap.Create(new TicksPerQuarterNoteTimeDivision(1000), Tempo.FromBeatsPerMinute(60)); midiFile.ReplaceTempoMap(tempoMap); return(midiFile); }
public void GetTempoChanges_SingleChange_AtStart() { var microsecondsPerQuarterNote = 100000; var tempoMap = TempoMap.Create(new Tempo(microsecondsPerQuarterNote)); var changes = tempoMap.GetTempoChanges(); Assert.AreEqual(1, changes.Count(), "Count of tempo changes is invalid."); var change = changes.First(); Assert.AreEqual(0, change.Time, "Time of change is invalid."); Assert.AreEqual(new Tempo(microsecondsPerQuarterNote), change.Value, "Tempo of change is invalid."); }
public void GetTimeSignatureChanges_SingleChange_AtStart() { var numerator = 2; var denominator = 16; var tempoMap = TempoMap.Create(new TimeSignature(numerator, denominator)); var changes = tempoMap.GetTimeSignatureChanges(); Assert.AreEqual(1, changes.Count(), "Count of time signature changes is invalid."); var change = changes.First(); Assert.AreEqual(0, change.Time, "Time of change is invalid."); Assert.AreEqual(new TimeSignature(numerator, denominator), change.Value, "Time signature of change is invalid."); }
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); }
/// <summary> /// /// </summary> /// <returns></returns> internal static TempoMap GetMsTempoMap() => TempoMap.Create(new TicksPerQuarterNoteTimeDivision(600), Tempo.FromBeatsPerMinute(100));
public static string Generate(string oggPath, string songID, string songName, string artist, double bpm, string songEndEvent, string author, int offset) { HandleCache.CheckSaveFolderValid(); var workFolder = Path.Combine(Application.streamingAssetsPath, "Ogg2Audica"); string audicaTemplate = Path.Combine(workFolder, ".AudicaTemplate/"); Encoding encoding = Encoding.GetEncoding("UTF-8"); //We need to modify the BPM of the song.mid contained in the template audica to match whatever this is. File.Delete(Path.Combine(workFolder, "song.mid")); MidiFile songMidi = MidiFile.Read(Path.Combine(workFolder, "songtemplate.mid")); float oneMinuteInMicroseconds = 60000000f; songMidi.ReplaceTempoMap(TempoMap.Create(new Tempo((long)(oneMinuteInMicroseconds / bpm)))); songMidi.Write(Path.Combine(workFolder, "song.mid"), true, MidiFileFormat.MultiTrack); //Generates the mogg into song.mogg, which is moved to the .AudicaTemplate File.Delete(Path.Combine(workFolder, "song.mogg")); Process ogg2mogg = new Process(); ProcessStartInfo startInfo = new ProcessStartInfo(); startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal; startInfo.FileName = Path.Combine(workFolder, "ogg2mogg.exe"); string args = $"\"{oggPath}\" \"{workFolder}/song.mogg\""; startInfo.Arguments = args; startInfo.UseShellExecute = false; ogg2mogg.StartInfo = startInfo; ogg2mogg.Start(); ogg2mogg.WaitForExit(); //Make the song.desc file; File.Delete(Path.Combine(workFolder, "song.desc")); SongDesc songDesc = JsonUtility.FromJson <SongDesc>(File.ReadAllText(Path.Combine(workFolder, "songtemplate.desc"))); songDesc.songID = songID; songDesc.title = songName; songDesc.artist = artist; songDesc.tempo = (float)bpm; songDesc.songEndEvent = songEndEvent; songDesc.author = author; songDesc.offset = offset; File.WriteAllText(Path.Combine(workFolder, "song.desc"), JsonUtility.ToJson(songDesc, true)); //Create the actual audica file and save it to the /saves/ folder using (ZipArchive archive = ZipArchive.Create()) { archive.AddAllFromDirectory(audicaTemplate); archive.AddEntry("song.desc", Path.Combine(workFolder, "song.desc")); archive.AddEntry("song.mid", Path.Combine(workFolder, "song.mid")); archive.AddEntry("song.mogg", Path.Combine(workFolder, "song.mogg")); archive.SaveTo(Path.Combine(Application.dataPath, "saves", songID + ".audica"), SharpCompress.Common.CompressionType.None); } return(Path.Combine(Application.dataPath, "saves", songID + ".audica")); /* * * HandleCache.CheckSaveFolderValid(); * * System.Diagnostics.Process myProcess = new System.Diagnostics.Process(); * ProcessStartInfo startInfo = new ProcessStartInfo(); * startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal; * startInfo.FileName = Path.Combine(ogg2AudicaFolder, "Ogg2Audica.exe"); * * startInfo.Arguments = System.String.Format("\"{0}\" \"{1}\" \"{2}\" \"{3}\" \"{4}\" \"{5}\" \"{6}\" \"{7}\"", oggPath, songID, songName, artist, bpm, songEndEvent, mapper, offset); * startInfo.UseShellExecute = true; * startInfo.WorkingDirectory = ogg2AudicaFolder; * * myProcess.StartInfo = startInfo; * * myProcess.Start(); * * myProcess.WaitForExit(); * * File.Move(Path.Combine(ogg2AudicaFolder, "out.audica"), Path.Combine(Application.dataPath, "saves", songID + ".audica")); * * * return Path.Combine(Application.dataPath, "saves", songID + ".audica"); */ }