public void Export(string path) { MidiEventCollection mid = new MidiEventCollection(1, DELTA_TICKS_PER_QUARTER); mid.AddTrack(CreateTempoTrack()); mid.AddTrack(CreateTrack()); MidiFile.Export(path, mid); }
private void ExportAtMarker(MidiFile midiFile, string markerName, string midiFilename, long startAbsoluteTime, long endAbsoluteTime) { string exportFileName = CreateFileName(markerName, midiFilename); LogInformation("Exporting Marker {0} to {1}", markerName, exportFileName); // 1. Construct a list of meta-events for track zero List<MidiEvent> trackZeroEvents = new List<MidiEvent>(); trackZeroEvents.Add(new TextEvent(markerName, MetaEventType.SequenceTrackName, startAbsoluteTime)); CreateTrackZeroEvents(trackZeroEvents, midiFile, startAbsoluteTime, endAbsoluteTime, settings.MidiFileType == 0); MidiEventCollection exportEvents = new MidiEventCollection(settings.MidiFileType, midiFile.DeltaTicksPerQuarterNote); exportEvents.AddTrack(trackZeroEvents); if (settings.MidiFileType == 1) { if (midiFile.Tracks == 1) { // this is a special case - we got a type 0 or a strange type 1 with just 1 track // turn it into a type 1 with notes on the second track List<MidiEvent> trackOneEvents = new List<MidiEvent>(); trackOneEvents.Add(new TextEvent(markerName, MetaEventType.SequenceTrackName, startAbsoluteTime)); CreateTrackEvents(trackOneEvents, midiFile.Events[0], startAbsoluteTime, endAbsoluteTime, false); exportEvents.AddTrack(trackOneEvents); } for (int track = 1; track < midiFile.Tracks; track++) { List<MidiEvent> trackEvents = new List<MidiEvent>(); trackEvents.Add(new TextEvent(markerName, MetaEventType.SequenceTrackName, startAbsoluteTime)); CreateTrackEvents(trackEvents, midiFile.Events[track], startAbsoluteTime, endAbsoluteTime, true); exportEvents.AddTrack(trackEvents); } } bool gotNotes = false; foreach(IList<MidiEvent> trackEvents in exportEvents) { foreach(MidiEvent trackEvent in trackEvents) { if (trackEvent.CommandCode == MidiCommandCode.NoteOn) { gotNotes = true; break; } } } if (!gotNotes) { LogInformation("No note events found for this marker {0}", markerName); return; } exportEvents.StartAbsoluteTime = startAbsoluteTime; MidiFile.Export(exportFileName, exportEvents); }
public void ExportMIDI(string fn, CSEQ seq) { string cr = Path.GetFileNameWithoutExtension(fn) + "\r\n\r\n" + Properties.Resources.midi_copyright; MidiEventCollection mc = new MidiEventCollection(1, TPQN); //this is a lazy fix for guitarpro5 bug, 1st track does not import there List <MidiEvent> dummy = new List <MidiEvent>(); dummy.Add(new TextEvent(Path.GetFileNameWithoutExtension(fn), MetaEventType.SequenceTrackName, 0)); dummy.Add(new TextEvent(cr, MetaEventType.Copyright, 0)); dummy.Add(new TempoEvent(MPQN, 0)); mc.AddTrack(dummy); int availablechannel = 1; for (int i = 0; i < tracks.Count; i++) { mc.AddTrack(tracks[i].ToMidiEventList(MPQN, tracks[i].isDrumTrack ? 10 : availablechannel, seq)); if (!tracks[i].isDrumTrack) { availablechannel++; //skip drum track if (availablechannel == 10) { availablechannel++; } //limit channel if overflow if (availablechannel > 16) { availablechannel = 16; } } } mc.PrepareForExport(); try { MidiFile.Export(fn, mc); } catch (Exception ex) { System.Windows.Forms.MessageBox.Show(ex.Message); } }
public void TestAddNamedTrack() { var manualMidi = new MidiEventCollection(1, 200); var noteEvent = new NoteOnEvent(0, 1, 1, 1, 1); const string trackName = "name"; var trackNameEvent = new TextEvent(trackName, MetaEventType.SequenceTrackName, 0); var endTrackEvent = new MetaEvent(MetaEventType.EndTrack, 0, noteEvent.OffEvent.AbsoluteTime); var track = manualMidi.AddTrack(); track.Add(trackNameEvent); track.Add(noteEvent); track.Add(noteEvent.OffEvent); track.Add(endTrackEvent); var extensionMidi = new MidiEventCollection(1, 200); var events = new MidiEvent[] { noteEvent, noteEvent.OffEvent }; extensionMidi.AddNamedTrack(trackName, events); MidiAssert.Equal(manualMidi, extensionMidi); // Assert events (not name / end) are the same objects var manualTrack = manualMidi[0]; var extensionTrack = extensionMidi[0]; for (var e = 1; e < manualTrack.Count - 1; e++) { Assert.That(extensionTrack[e], Is.SameAs(manualTrack[e])); } }
public void TestAddTrackCopyParams() { var manualMidi = new MidiEventCollection(1, 200); var noteEvent = new NoteOnEvent(0, 1, 1, 1, 1); var track = manualMidi.AddTrack(); track.Add(noteEvent); track.Add(noteEvent.OffEvent); var extensionMidi = new MidiEventCollection(1, 200); extensionMidi.AddTrackCopy(noteEvent, noteEvent.OffEvent); MidiAssert.Equal(manualMidi, extensionMidi); // Assert they aren't the same objects var manualTrack = manualMidi[0]; var extensionTrack = extensionMidi[0]; for (var e = 0; e < manualTrack.Count; e++) { Assert.That(extensionTrack[e], Is.Not.SameAs(manualTrack[e])); } // Verify the NoteOnEvent.OffEvent link Assert.AreEqual(extensionMidi[0][1], ((NoteOnEvent)extensionMidi[0][0]).OffEvent); }
public void TestAddNamedTrackCopyWithOwnEnd() { var manualMidi = new MidiEventCollection(1, 200); var noteEvent = new NoteOnEvent(0, 1, 1, 1, 1); const string trackName = "name"; var trackNameEvent = new TextEvent(trackName, MetaEventType.SequenceTrackName, 0); var endTrackEvent = new MetaEvent(MetaEventType.EndTrack, 0, 90); var track = manualMidi.AddTrack(); track.Add(trackNameEvent); track.Add(noteEvent); track.Add(noteEvent.OffEvent); track.Add(endTrackEvent); var extensionMidi = new MidiEventCollection(1, 200); var events = new MidiEvent[] { noteEvent, noteEvent.OffEvent, endTrackEvent }; extensionMidi.AddNamedTrackCopy(trackName, events); MidiAssert.Equal(manualMidi, extensionMidi); // Assert they aren't the same objects var manualTrack = manualMidi[0]; var extensionTrack = extensionMidi[0]; for (var e = 0; e < manualTrack.Count; e++) { Assert.That(extensionTrack[e], Is.Not.SameAs(manualTrack[e])); } // Verify the NoteOnEvent.OffEvent link Assert.AreEqual(extensionMidi[0][2], ((NoteOnEvent)extensionMidi[0][1]).OffEvent); }
private static void MakeSilent(string midifile) { var mf = new MidiFile(midifile, false); MidiEventCollection collection = new MidiEventCollection(mf.FileFormat, mf.DeltaTicksPerQuarterNote); for (int n = 0; n < mf.Tracks; n++) { collection.AddTrack(); foreach (var midiEvent in mf.Events[n]) { if (midiEvent.CommandCode == MidiCommandCode.NoteOn) { var ne = (NoteEvent)midiEvent; ne.Velocity = 1; collection.AddEvent((MidiEvent)ne, n); } else { collection.AddEvent(midiEvent, n); } } } MidiFile.Export(output_dir + "\\" + midifile, collection); Console.WriteLine("Created " + output_dir + "\\" + midifile); }
public static MidiEventCollection ReorderTracks(MidiEventCollection midi) { var newMidi = new MidiEventCollection(midi.MidiFileType, midi.DeltaTicksPerQuarterNote); var tempoMapIndex = midi.FindTrackNumberByName(TrackName.TempoMap.ToString()); newMidi.AddTrack(midi[tempoMapIndex]); for (var t = 0; t < midi.Tracks; t++) { if (t != tempoMapIndex) { newMidi.AddTrack(midi[t]); } } return(newMidi); }
public bool ConvertFile(string sourceFile, string destFile, int fileType) { MidiFile midiFile = new MidiFile(sourceFile, false); if (fileType == -1) { fileType = midiFile.FileFormat; } EventRuleArgs eventRuleArgs = new EventRuleArgs(Path.GetFileNameWithoutExtension(sourceFile)); MidiEventCollection outputFileEvents = new MidiEventCollection(fileType, midiFile.DeltaTicksPerQuarterNote); bool hasNotes = false; for (int track = 0; track < midiFile.Tracks; track++) { IList <MidiEvent> trackEvents = midiFile.Events[track]; IList <MidiEvent> outputEvents; if (fileType == 1 || track == 0) { outputEvents = new List <MidiEvent>(); } else { outputEvents = outputFileEvents[0]; } foreach (MidiEvent midiEvent in InsertEvents) { outputEvents.Add(midiEvent); } foreach (MidiEvent midiEvent in trackEvents) { if (Process(midiEvent, eventRuleArgs)) { outputEvents.Add(midiEvent); NoteOnEvent noteOnEvent = midiEvent as NoteOnEvent; if (noteOnEvent != null) { System.Diagnostics.Debug.Assert(noteOnEvent.OffEvent != null); hasNotes = true; outputEvents.Add(noteOnEvent.OffEvent); } } } if (fileType == 1 || track == 0) { outputFileEvents.AddTrack(outputEvents); } } if (hasNotes) { MidiFile.Export(destFile, outputFileEvents); } return(hasNotes); }
public void TestClone() { var manualMidi = new MidiEventCollection(1, 200); var noteEvent1 = new NoteOnEvent(0, 1, 1, 1, 1); const string trackName1 = "name"; var trackNameEvent1 = new TextEvent(trackName1, MetaEventType.SequenceTrackName, 0); var endTrackEvent1 = new MetaEvent(MetaEventType.EndTrack, 0, noteEvent1.OffEvent.AbsoluteTime); var track1 = manualMidi.AddTrack(); track1.Add(trackNameEvent1); track1.Add(noteEvent1); track1.Add(noteEvent1.OffEvent); track1.Add(endTrackEvent1); var noteEvent2 = new NoteOnEvent(0, 1, 1, 1, 1); const string trackName2 = "name"; var trackNameEvent2 = new TextEvent(trackName2, MetaEventType.SequenceTrackName, 0); var endTrackEvent2 = new MetaEvent(MetaEventType.EndTrack, 0, noteEvent2.OffEvent.AbsoluteTime); var track2 = manualMidi.AddTrack(); track2.Add(trackNameEvent2); track2.Add(noteEvent2); track2.Add(noteEvent2.OffEvent); track2.Add(endTrackEvent2); var clone = manualMidi.Clone(); MidiAssert.Equal(manualMidi, clone); for (var t = 0; t < manualMidi.Tracks; t++) { var manualTrack = manualMidi[t]; var extensionTrack = clone[t]; for (var e = 1; e < manualTrack.Count - 1; e++) { Assert.That(extensionTrack[e], Is.Not.SameAs(manualTrack[e])); } } }
protected void CreateDefaultMid(string midPath) { var mid = new MidiEventCollection(1, 480); // Create basic tempo track var tempoTrack = new List <MidiEvent>(); tempoTrack.Add(new TextEvent("animTempo", MetaEventType.SequenceTrackName, 0)); tempoTrack.Add(new MetaEvent(MetaEventType.EndTrack, 0, 0)); mid.AddTrack(tempoTrack); // Add other tracks foreach (var trackName in DefaultMIDITracks) { var track = new List <MidiEvent>(); track.Add(new TextEvent(trackName, MetaEventType.SequenceTrackName, 0)); track.Add(new MetaEvent(MetaEventType.EndTrack, 0, 0)); mid.AddTrack(track); } MidiFile.Export(midPath, mid); Console.WriteLine("Wrote \"venue.mid\""); }
public static IList <MidiEvent> AddNamedTrack(this MidiEventCollection midiEventCollection, string name, IEnumerable <MidiEvent> initialEvents) { var nameEvent = new TextEvent(name, MetaEventType.SequenceTrackName, 0); var track = midiEventCollection.AddTrack(nameEvent); foreach (var midiEvent in initialEvents) { track.Add(midiEvent); } var endEvent = track.OfType <MetaEvent>().Where(MidiEvent.IsEndTrack).SingleOrDefault(); if (endEvent == null) { var lastEvent = track.OrderBy(e => e.AbsoluteTime).Last(); track.Add(new MetaEvent(MetaEventType.EndTrack, 0, lastEvent.AbsoluteTime)); } return(track); }
public static IList <MidiEvent> AddTrackCopy(this MidiEventCollection midiEventCollection, IEnumerable <MidiEvent> initialEvents) { var initialEventsList = initialEvents.ToList(); if (initialEventsList.GroupBy(e => e).Any(g => g.Count() > 1)) { throw new ArgumentException("Must not contain duplicate events", nameof(initialEventsList)); } var clonedEvents = new MidiEvent[initialEventsList.Count]; for (var e = 0; e < initialEventsList.Count; e++) { var midiEvent = initialEventsList[e]; var clone = midiEvent.Clone(); var noteEvent = midiEvent as NoteEvent; if (noteEvent != null) { var noteOnEvent = noteEvent as NoteOnEvent; // NoteOff events are set at the same time as their NoteOnEvent if (noteOnEvent == null) { continue; } var clonedOff = ((NoteOnEvent)clone).OffEvent; var offEventIndex = initialEventsList.FindIndex(m => m == noteOnEvent.OffEvent); if (offEventIndex != -1) { clonedEvents[offEventIndex] = clonedOff; } } clonedEvents[e] = clone; } var newTrack = midiEventCollection.AddTrack(clonedEvents); return(newTrack); }
private void toolStripButton2_Click(object sender, EventArgs e) { if (MessageBox.Show("Do you want to export all channels?", "Export", MessageBoxButtons.YesNo) == DialogResult.No) { MidiEventCollection events = new MidiEventCollection(1, 48); for (int index = 0; index < this.file.Data.Midi.Tracks; ++index) { if (this.checkedListBox1.GetItemChecked(index)) { events.AddTrack(this.file.Data.Midi[index]); } } if (this.saveFileDialog1.ShowDialog() != DialogResult.OK || this.saveFileDialog1.FileName.Length <= 0) { return; } MidiFile.Export(this.saveFileDialog1.FileName, events); } else if (this.saveFileDialog1.ShowDialog() == DialogResult.OK && this.saveFileDialog1.FileName.Length > 0) { MidiFile.Export(this.saveFileDialog1.FileName, this.file.Data.Midi); } }
public void Export(string path) { MidiEventCollection mid = new MidiEventCollection(1, DELTA_TICKS_PER_QUARTER); _xmks.Sort((x, y) => GetSortNumber(x.Name) - GetSortNumber(y.Name)); int GetSortNumber(string name) { switch (name) { case "touchdrums": return(1); case "touchguitar": return(2); case "guitar_3x2": return(3); case "vocals": return(4); case "control": return(5); default: return(100); } } // Get xmk track to use for tempo map + generating BEAT track // Note: Avoiding "touchdrums" because it was an under-developed feature so it may not consistently be as accurate compared to 6 fret var tempoTrackPreference = new[] { "guitar_3x2", "touchguitar", "vocals", "control" }; Xmk firstXmk = _xmks .Select(x => { var idx = Array.FindIndex(tempoTrackPreference, y => y == x.Name); if (idx == -1) { idx = 100; } return(Xmk: x, Order: idx); }) .OrderBy(x => x.Order) .Select(x => x.Xmk) .First(); mid.AddTrack(CreateTempoTrack(firstXmk.TempoEntries, firstXmk.TimeSignatureEntries)); if (!_exportOptions.Remap) { for (int i = 0; i < _xmks.Count; i++) { mid.AddTrack(CreateTrack(_xmks[i], i)); } } else { var eventsIdx = -1; for (int i = 0; i < _xmks.Count; i++) { Xmk xmk = _xmks[i]; string trackName = !string.IsNullOrEmpty(xmk.Name) ? xmk.Name : $"NOTES {i}"; // Sets remapping and track name switch (trackName.ToLower()) { case "control": // EVENTS mid.AddTrack(ParseEvents(xmk)); eventsIdx = i + 1; continue; case "guitar_3x2": // PART GUITAR GHL mid.AddTrack(ParseGuitar3(xmk)); continue; case "touchdrums": // PART DRUMS mid.AddTrack(ParseDrums(xmk)); continue; case "touchguitar": // PART GUITAR mid.AddTrack(ParseGuitar5(xmk)); continue; case "vocals": // PART VOCALS mid.AddTrack(ParseVocals(xmk)); continue; } // TODO: Refactor to be more elegant if (_voxRegex.IsMatch(trackName)) { mid.AddTrack(ParseVocals(xmk)); continue; } mid.AddTrack(CreateTrack(xmk, i)); } // Updates EVENTS track var firstPlay = mid.SelectMany(x => x) .Where(y => y is TextEvent && ((TextEvent)y).Text == "[play]") .OrderBy(z => z.AbsoluteTime) .FirstOrDefault(); var lastIdle = mid.SelectMany(x => x) .Where(y => y is TextEvent && ((TextEvent)y).Text == "[idle]") .OrderByDescending(z => z.AbsoluteTime) .FirstOrDefault(); if (eventsIdx != -1 && firstPlay != null) { var events = mid[eventsIdx]; var nextEvent = events .OrderBy(y => y.AbsoluteTime) .FirstOrDefault(z => z.AbsoluteTime > firstPlay.AbsoluteTime); // If nextEvent is null, assume no text events exist var nextEventIdx = (nextEvent is null) ? 1 : events.IndexOf(nextEvent); events.Insert(nextEventIdx, new TextEvent("[music_start]", MetaEventType.TextEvent, firstPlay.AbsoluteTime)); } if (eventsIdx != -1 && lastIdle != null) { var events = mid[eventsIdx]; var trackEnd = events.Last(); trackEnd.AbsoluteTime = lastIdle.AbsoluteTime; // Updates end track position events.Remove(trackEnd); events.Add(new TextEvent("[music_end]", MetaEventType.TextEvent, lastIdle.AbsoluteTime)); events.Add(new TextEvent("[end]", MetaEventType.TextEvent, lastIdle.AbsoluteTime)); events.Add(trackEnd); // Adds end track back } // Generates up/down events for BEAT track (Needed for beat markers in CH and OD in RB) mid.AddTrack(GenerateBeatTrack(firstXmk.TimeSignatureEntries, mid)); } MidiFile.Export(path, mid); }
public MidiEventCollection process(int timeSigNum, int timeSigDen, int octaveEst, int avgVel, int bars) { MidiEventCollection m = melody; int noteCount = getNumberOfNotes(); int noteIndex = 0; int initialTrackCount = m.Tracks; m.AddTrack(); int newTrack = m.Tracks - 1; bool bFirst = true; Vector3D noHint = new Vector3D(0, 0, 0); m[newTrack].Add(new PatchChangeEvent(0, 2, 1)); // Loop through each track in the MidiEventCollection for (int track = 0; track < initialTrackCount; track++) { // For every MidiEvent in that track... foreach (MidiEvent e in m[track]) { // This is where we can do some work. // Check the CommandCode. // Here, we are interested in NoteOn messages if (e.CommandCode == MidiCommandCode.NoteOn) { if (e is NoteOnEvent) { NoteOnEvent non = (NoteOnEvent)e; NoteEvent n = (NoteEvent)e; if (non.OffEvent != null) { ++noteIndex; // We want to harmonize this note! Vector3D harmonization = new Vector3D(0, 0, 0); if (!bFirst && noteIndex < noteCount - 1) { harmonization = harmonizeNote(n.NoteNumber, mostRecentChord, noHint); } else { if (noteIndex == noteCount - 1) { harmonization = harmonizeNote(n.NoteNumber, mostRecentChord, chordVectors[getCadenceForNote(n.NoteNumber % 12)]); } else if (noteIndex == noteCount) { harmonization = harmonizeNote(n.NoteNumber, mostRecentChord, chordVectors[0]); } else { bFirst = false; harmonization = mostRecentChord; } } // NoteEvent n1 = new NoteEvent(n.AbsoluteTime, 2, MidiCommandCode.NoteOn, // (int) harmonization.X + 60, n.Velocity); NoteOnEvent n1 = new NoteOnEvent(n.AbsoluteTime, 2, (int)harmonization.X + 60, n.Velocity, non.NoteLength); // NoteEvent n1off = new NoteEvent(non.NoteLength, 2, MidiCommandCode.NoteOff, // (int) harmonization.X + 60, n.Velocity); // NoteEvent n2 = new NoteEvent(n.AbsoluteTime, 2, MidiCommandCode.NoteOn, // (int) harmonization.Y + 60, n.Velocity); NoteOnEvent n2 = new NoteOnEvent(n.AbsoluteTime, 2, (int)harmonization.Y + 60, n.Velocity, non.NoteLength); // NoteEvent n2off = new NoteEvent(non.NoteLength, 2, MidiCommandCode.NoteOff, // (int) harmonization.Y + 60, n.Velocity); // NoteEvent n3 = new NoteEvent(n.AbsoluteTime, 2, MidiCommandCode.NoteOn, // (int) harmonization.Z + 60, n.Velocity); NoteOnEvent n3 = new NoteOnEvent(n.AbsoluteTime, 2, (int)harmonization.Z + 60, n.Velocity, non.NoteLength); // NoteEvent n3off = new NoteEvent(non.NoteLength, 2, MidiCommandCode.NoteOff, // (int) harmonization.Z + 60, n.Velocity); m[newTrack].Add(n1); m[newTrack].Add(n1.OffEvent); // m[newTrack].Add(n1off); m[newTrack].Add(n2); m[newTrack].Add(n2.OffEvent); // m[newTrack].Add(n2off); m[newTrack].Add(n3); m[newTrack].Add(n3.OffEvent); // m[newTrack].Add(n3off); mostRecentChord = harmonization; } } } } } AppendEndMarker(m[0]); AppendEndMarker(m[1]); return(m); }
public void WriteToMidi(string path) { MidiEventCollection events = new MidiEventCollection(1, 480); foreach(Track t in Tracks) { List<MidiEvent> trackEvents = new List<MidiEvent>(); var info = t.GeneratePlaybackInfo(); var keys = new int[info.Messages.Keys.Count]; int i = 0; foreach (var k in info.Messages.Keys) { keys[i++] = k; } for (i = 0; i < keys.Length - 1; i++) { foreach (PlaybackMessage message in info.Messages[keys[i]]) { try { var e = MidiEvent.FromRawMessage(message.GenerateMidiMessage().RawData); int note_dur = (int)Note.ToNoteDuration(keys[i]); int midi_dur = Note.ToMidiLength(note_dur, 240, 60); e.AbsoluteTime = keys[i]; trackEvents.Add(e); } catch { // TODO figure out crash } } int sleep_dur = keys[i + 1] - keys[i]; //Thread.Sleep(sleep_dur); } // Append the end marker to the track if(trackEvents[trackEvents.Count - 1].CommandCode == MidiCommandCode.NoteOn) { var noteOn = trackEvents[trackEvents.Count - 1] as NoteOnEvent; int note = noteOn.NoteNumber; int duration = noteOn.NoteLength; int channel = noteOn.Channel; var offM = MidiMessage.StopNote(note, noteOn.Velocity, channel); var offE = MidiEvent.FromRawMessage(offM.RawData); offE.AbsoluteTime = noteOn.AbsoluteTime; trackEvents.Add(offE); } long absoluteTime = 0; if (trackEvents.Count > 0) absoluteTime = trackEvents[trackEvents.Count - 1].AbsoluteTime+100; trackEvents.Add(new MetaEvent(MetaEventType.EndTrack, 0, absoluteTime)); events.AddTrack(trackEvents); } MidiFile.Export(path, events); }
public void Export(string path, bool remap = false) { MidiEventCollection mid = new MidiEventCollection(1, DELTA_TICKS_PER_QUARTER); _xmks.Sort((x, y) => GetSortNumber(x.Name) - GetSortNumber(y.Name)); int GetSortNumber(string name) { switch (name) { case "touchdrums": return(1); case "touchguitar": return(2); case "guitar_3x2": return(3); case "vocals": return(4); case "control": return(5); default: return(100); } } Xmk firstXmk = _xmks.FirstOrDefault(); mid.AddTrack(CreateTempoTrack(firstXmk.TempoEntries, firstXmk.TimeSignatureEntries)); if (!remap) { for (int i = 0; i < _xmks.Count; i++) { mid.AddTrack(CreateTrack(_xmks[i], i)); } } else { var eventsIdx = -1; for (int i = 0; i < _xmks.Count; i++) { Xmk xmk = _xmks[i]; string trackName = !string.IsNullOrEmpty(xmk.Name) ? xmk.Name : $"NOTES {i}"; // Sets remapping and track name switch (trackName.ToLower()) { case "control": // EVENTS mid.AddTrack(ParseEvents(xmk)); eventsIdx = i + 1; continue; case "guitar_3x2": // PART GUITAR GHL mid.AddTrack(ParseGuitar3(xmk)); continue; case "touchdrums": // PART DRUMS mid.AddTrack(ParseDrums(xmk)); continue; case "touchguitar": // PART GUITAR mid.AddTrack(ParseGuitar6(xmk)); continue; case "vocals": // PART VOCALS mid.AddTrack(ParseVocals(xmk)); continue; } mid.AddTrack(CreateTrack(xmk, i)); } // Updates EVENTS track var firstPlay = mid.SelectMany(x => x) .Where(y => y is TextEvent && ((TextEvent)y).Text == "[play]") .OrderBy(z => z.AbsoluteTime) .FirstOrDefault(); var lastIdle = mid.SelectMany(x => x) .Where(y => y is TextEvent && ((TextEvent)y).Text == "[idle]") .OrderByDescending(z => z.AbsoluteTime) .FirstOrDefault(); if (eventsIdx != -1 && firstPlay != null) { var events = mid[eventsIdx]; var nextEvent = events.OrderBy(x => x.AbsoluteTime).First(y => y.AbsoluteTime > firstPlay.AbsoluteTime); var nextEventIdx = events.IndexOf(nextEvent); events.Insert(nextEventIdx, new TextEvent("[music_start]", MetaEventType.TextEvent, firstPlay.AbsoluteTime)); } if (eventsIdx != -1 && lastIdle != null) { var events = mid[eventsIdx]; var trackEnd = events.Last(); trackEnd.AbsoluteTime = lastIdle.AbsoluteTime; // Updates end track position events.Remove(trackEnd); events.Add(new TextEvent("[music_end]", MetaEventType.TextEvent, lastIdle.AbsoluteTime)); events.Add(new TextEvent("[end]", MetaEventType.TextEvent, lastIdle.AbsoluteTime)); events.Add(trackEnd); // Adds end track back } // Generates up/down events for BEAT track (Needed for beat markers in CH and OD in RB) mid.AddTrack(GenerateBeatTrack(firstXmk.TimeSignatureEntries, mid)); } MidiFile.Export(path, mid); }
public bool ConvertFile(string sourceFile, int fileType, int TrackNum, ICollection<MidiNotes> NoteCollection) { try { //MidiFile midiFile = new MidiFile(sourceFile); MidiFile midiFile = new MidiFile(sourceFile); if (fileType == -1) { fileType = midiFile.FileFormat; } EventRuleArgs eventRuleArgs = new EventRuleArgs(Path.GetFileNameWithoutExtension(sourceFile)); MidiEventCollection outputFileEvents = new MidiEventCollection(fileType, midiFile.DeltaTicksPerQuarterNote); bool hasNotes = false; int track = TrackNum; ; IList<MidiEvent> trackEvents = midiFile.Events[track]; // Notes the use of the Track reference, if invalid track is referenced then causes big issues IList<MidiEvent> outputEvents; if (fileType == 1 || track == 0) { outputEvents = new List<MidiEvent>(); } else { outputEvents = outputFileEvents[0]; } foreach (MidiEvent midiEvent in InsertEvents) { outputEvents.Add(midiEvent); } foreach (MidiEvent midiEvent in trackEvents) { outputEvents.Add(midiEvent); NoteOnEvent noteOnEvent = midiEvent as NoteOnEvent; if (noteOnEvent != null) { // Add to the midi collection if (!MidiEvent.IsNoteOff(noteOnEvent)) { MidiNotes tempnote = new MidiNotes(noteOnEvent); NoteCollection.Add(tempnote); }; //System.Diagnostics.Debug.Assert(noteOnEvent.OffEvent != null); hasNotes = true; outputEvents.Add(noteOnEvent.OffEvent); } //} } // Get the tempo events foreach (MidiEvent midiEvent in trackEvents) { //get the tempo and drop out of that track if (midiEvent is TempoEvent) { //tempo in milliseconds tempo = (midiEvent as TempoEvent).MicrosecondsPerQuarterNote / 1000; break; } //get the tempo and drop out of that track if (midiEvent is TimeSignatureEvent) { //Time sig timesig1 = (midiEvent as TimeSignatureEvent).Numerator; timesig2 = (midiEvent as TimeSignatureEvent).Denominator; break; } } if (fileType == 1 || track == 0) { outputFileEvents.AddTrack(outputEvents); } //} if (hasNotes) { //MidiFile.Export(destFile, outputFileEvents); } return hasNotes; } catch { MessageBox.Show("Invalid File or track number"); return false; } }
public static IList <MidiEvent> AddTrack(this MidiEventCollection midiEventCollection, params MidiEvent[] events) { return(midiEventCollection.AddTrack(events)); }
public void ExportMidi(string exportMidPath) { // Create directory if it doesn't exist var dirPath = Path.GetDirectoryName(exportMidPath); if (!Directory.Exists(dirPath)) { Directory.CreateDirectory(dirPath); } // Create dictionary of tracks to filter events in var midFilteredTracks = TBRBCharacters .Select(x => x.ToUpper()) .Concat(new[] { "VENUE" }) .ToDictionary(x => x, y => new List <MidiEvent>()); var nameFilterRegex = new Regex($"(?i)([_]?)({string.Join("|", TBRBCharacters)})$"); foreach (var group in Anim.DirectorGroups) { // Default event name + track var eventName = group.PropName; var track = midFilteredTracks["VENUE"]; var match = nameFilterRegex.Match(group.PropName); if (match.Success) { // Get last group match (ex: "_ringo" -> "ringo" and "spot_paul" -> "paul") var key = match .Groups .Values .Last() .Value .ToUpper(); // Look for character track if (midFilteredTracks.ContainsKey(key)) { // Remove appended name + assign character track eventName = nameFilterRegex.Replace(eventName, ""); track = midFilteredTracks[key]; } } foreach (var ev in group.Events.OrderBy(x => x.Position)) { var tickPos = MidiHelper.FramePosToTicks((decimal)ev.Position); var evValue = ev switch { DirectedEventFloat evFloat => $"{evFloat.Value}", DirectedEventTextFloat { Value : 0.0f } evTextFloat => $"{evTextFloat.Text}", // postproc events DirectedEventTextFloat evTextFloat => $"{evTextFloat.Text} {evTextFloat.Value}", DirectedEventBoolean evBool => $"{(evBool.Enabled ? "TRUE" : "FALSE")}", DirectedEventVector4 evVector4 => $"{evVector4.Value.X} {evVector4.Value.Y} {evVector4.Value.Z} {evVector4.Value.W}", DirectedEventVector3 evVector3 => $"{evVector3.Value.X} {evVector3.Value.Y} {evVector3.Value.Z}", DirectedEventText evTextFloat => $"{evTextFloat.Text}", _ => throw new NotSupportedException() }; var evText = eventName switch { "body" => $"[{evValue}]", "shot" => $"[{evValue}]", "configuration" => $"[config ({evValue})]", // Use alias "postproc" when evValue.EndsWith(".pp") && !evValue.Contains(' ') => $"[{evValue}]", "lyric_transition" when evValue.EndsWith(".anim") && !evValue.StartsWith('(') => $"[{evValue}]", _ => $"[{eventName} ({evValue})]", }; track.Add(new TextEvent(evText, MetaEventType.TextEvent, tickPos)); } } foreach (var key in midFilteredTracks.Keys) { if (midFilteredTracks[key].Count <= 0) { // Remove empty track midFilteredTracks.Remove(key); } } // Get tracks from mid var midiTracks = MidiHelper.CreateMidiTracksFromBase(); foreach (var kv in midFilteredTracks) { var trackName = kv.Key; var track = kv.Value; var existingTrack = midiTracks .FirstOrDefault(x => x.Any(y => (y is TextEvent te) && te.MetaEventType == MetaEventType.SequenceTrackName && te.Text == trackName)); if ((existingTrack is null)) { // Sort events track.Sort((x, y) => x.AbsoluteTime.CompareTo(y.AbsoluteTime)); // Create new track // Insert track name and add end event track.Insert(0, new TextEvent(trackName, MetaEventType.SequenceTrackName, 0)); track.Add(new MetaEvent(MetaEventType.EndTrack, 0, track.Max(x => x.AbsoluteTime))); midiTracks.Add(track); continue; } // Use existing track // Remove track name event var trackNameEvent = existingTrack .First(x => x is TextEvent me && me.MetaEventType == MetaEventType.SequenceTrackName); existingTrack.Remove(trackNameEvent); // Remove end event if it exists (it probably should) var endEvent = existingTrack .FirstOrDefault(x => x is MetaEvent me && me.MetaEventType == MetaEventType.EndTrack); if (!(endEvent is null)) { existingTrack.Remove(endEvent); } existingTrack.AddRange(track); // Sort events existingTrack.Sort((x, y) => x.AbsoluteTime.CompareTo(y.AbsoluteTime)); // Insert track name existingTrack.Insert(0, new TextEvent(trackName, MetaEventType.SequenceTrackName, 0)); // Add end event existingTrack.Add(new MetaEvent(MetaEventType.EndTrack, 0, existingTrack.Max(x => x.AbsoluteTime))); } // Copy tracks to mid var mid = new MidiEventCollection(1, MidiHelper.GetTicksPerQuarter()); midiTracks.ForEach(x => mid.AddTrack(x)); MidiFile.Export(exportMidPath, mid); } }
private void ConvertMidi(MidiFile midiFile, string target, string[] context) { string fileNameWithoutExtension = context[context.Length - 1]; string name = null; long endTrackTime = -1; if (settings.UseFileName) { name = fileNameWithoutExtension; } if (settings.ApplyNamingRules) { if (ezdFileName.Match(fileNameWithoutExtension).Success) { name = CreateEzdName(context); } } int outputFileType = midiFile.FileFormat; int outputTrackCount; if (settings.OutputMidiType == OutputMidiType.Type0) { outputFileType = 0; } else if (settings.OutputMidiType == OutputMidiType.Type1) { outputFileType = 1; } if (outputFileType == 0) { outputTrackCount = 1; } else { if (midiFile.FileFormat == 0) outputTrackCount = 2; else outputTrackCount = midiFile.Tracks; } MidiEventCollection events = new MidiEventCollection(outputFileType, midiFile.DeltaTicksPerQuarterNote); for (int track = 0; track < outputTrackCount; track++) { events.AddTrack(); } if (name != null) { for (int track = 0; track < outputTrackCount; track++) { events[track].Add(new TextEvent(name, MetaEventType.SequenceTrackName, 0)); } if (settings.AddNameMarker) { events[0].Add(new TextEvent(name, MetaEventType.Marker, 0)); } } foreach (MidiEvent midiEvent in midiFile.Events[0]) { if (settings.OutputChannelNumber != -1) midiEvent.Channel = settings.OutputChannelNumber; MetaEvent metaEvent = midiEvent as MetaEvent; if (metaEvent != null) { bool exclude = false; switch (metaEvent.MetaEventType) { case MetaEventType.SequenceTrackName: if (name != null) { exclude = true; } break; case MetaEventType.SequencerSpecific: exclude = settings.RemoveSequencerSpecific; break; case MetaEventType.EndTrack: exclude = settings.RecreateEndTrackMarkers; endTrackTime = metaEvent.AbsoluteTime; break; case MetaEventType.SetTempo: if (metaEvent.AbsoluteTime != 0 && settings.RemoveExtraTempoEvents) { LogWarning("Removing a tempo event ({0}bpm) at {1} from {2}", ((TempoEvent)metaEvent).Tempo, metaEvent.AbsoluteTime, target); exclude = true; } break; case MetaEventType.TextEvent: if (settings.TrimTextEvents) { TextEvent textEvent = (TextEvent)midiEvent; textEvent.Text = textEvent.Text.Trim(); if (textEvent.Text.Length == 0) { exclude = true; } } break; case MetaEventType.Marker: if (settings.AddNameMarker && midiEvent.AbsoluteTime == 0) { exclude = true; } if (settings.RemoveExtraMarkers && midiEvent.AbsoluteTime > 0) { LogWarning("Removing a marker ({0}) at {1} from {2}", ((TextEvent)metaEvent).Text, metaEvent.AbsoluteTime, target); exclude = true; } break; } if (!exclude) { events[0].Add(midiEvent); } } else { if (outputFileType == 1) events[1].Add(midiEvent); else events[0].Add(midiEvent); } } // now do track 1 (Groove Monkee) for (int inputTrack = 1; inputTrack < midiFile.Tracks; inputTrack++) { int outputTrack; if(outputFileType == 1) outputTrack = inputTrack; else outputTrack = 0; foreach (MidiEvent midiEvent in midiFile.Events[inputTrack]) { if (settings.OutputChannelNumber != -1) midiEvent.Channel = settings.OutputChannelNumber; bool exclude = false; MetaEvent metaEvent = midiEvent as MetaEvent; if (metaEvent != null) { switch (metaEvent.MetaEventType) { case MetaEventType.SequenceTrackName: if (name != null) { exclude = true; } break; case MetaEventType.SequencerSpecific: exclude = settings.RemoveSequencerSpecific; break; case MetaEventType.EndTrack: exclude = settings.RecreateEndTrackMarkers; break; } } if (!exclude) { events[outputTrack].Add(midiEvent); } } if(outputFileType == 1 && settings.RecreateEndTrackMarkers) { AppendEndMarker(events[outputTrack]); } } if (settings.RecreateEndTrackMarkers) { if (outputFileType == 1) { // if we are converting type 0 to type 1 and recreating end markers, if (midiFile.FileFormat == 0) { AppendEndMarker(events[1]); } } // make sure that track zero has an end track marker AppendEndMarker(events[0]); } else { // if we are converting type 0 to type 1 without recreating end markers, // then we still need to add an end marker to track 1 if (midiFile.FileFormat == 0) { // use the time we got from track 0 as the end track time for track 1 if (endTrackTime == -1) { LogError("Error adding track 1 end marker"); // make it a valid MIDI file anyway AppendEndMarker(events[1]); } else { events[1].Add(new MetaEvent(MetaEventType.EndTrack, 0, endTrackTime)); } } } if (settings.VerboseOutput) { LogTrace("Processing {0}: {1}", name, target); } if (settings.RemoveEmptyTracks) { MidiEventCollection newList = new MidiEventCollection(events.MidiFileType, events.DeltaTicksPerQuarterNote); int removed = 0; for (int track = 0; track < events.Tracks; track++) { IList<MidiEvent> trackEvents = events[track]; if (track < 2) { newList.AddTrack(events[track]); } else { if(HasNotes(trackEvents)) { newList.AddTrack(trackEvents); } else { removed++; } } } if (removed > 0) { events = newList; LogWarning("Removed {0} empty tracks from {1} ({2} remain)", removed, target, events.Tracks); } } MidiFile.Export(target, events); }
private void ConvertMidi(MidiFile midiFile, string target, string[] context) { string fileNameWithoutExtension = context[context.Length - 1]; string name = null; long endTrackTime = -1; if (settings.UseFileName) { name = fileNameWithoutExtension; } if (settings.ApplyNamingRules) { if (ezdFileName.Match(fileNameWithoutExtension).Success) { name = CreateEzdName(context); } } int outputFileType = midiFile.FileFormat; int outputTrackCount; if (settings.OutputMidiType == OutputMidiType.Type0) { outputFileType = 0; } else if (settings.OutputMidiType == OutputMidiType.Type1) { outputFileType = 1; } if (outputFileType == 0) { outputTrackCount = 1; } else { if (midiFile.FileFormat == 0) { outputTrackCount = 2; } else { outputTrackCount = Math.Max(midiFile.Tracks, 2); // at least two tracks because we'll move notes onto track 1 always } } MidiEventCollection events = new MidiEventCollection(outputFileType, midiFile.DeltaTicksPerQuarterNote); for (int track = 0; track < outputTrackCount; track++) { events.AddTrack(); } if (name != null) { for (int track = 0; track < outputTrackCount; track++) { events[track].Add(new TextEvent(name, MetaEventType.SequenceTrackName, 0)); } if (settings.AddNameMarker) { events[0].Add(new TextEvent(name, MetaEventType.Marker, 0)); } } foreach (MidiEvent midiEvent in midiFile.Events[0]) { if (settings.OutputChannelNumber != -1) { midiEvent.Channel = settings.OutputChannelNumber; } MetaEvent metaEvent = midiEvent as MetaEvent; if (metaEvent != null) { bool exclude = false; switch (metaEvent.MetaEventType) { case MetaEventType.SequenceTrackName: if (name != null) { exclude = true; } break; case MetaEventType.SequencerSpecific: exclude = settings.RemoveSequencerSpecific; break; case MetaEventType.EndTrack: exclude = settings.RecreateEndTrackMarkers; endTrackTime = metaEvent.AbsoluteTime; break; case MetaEventType.SetTempo: if (metaEvent.AbsoluteTime != 0 && settings.RemoveExtraTempoEvents) { LogWarning("Removing a tempo event ({0}bpm) at {1} from {2}", ((TempoEvent)metaEvent).Tempo, metaEvent.AbsoluteTime, target); exclude = true; } break; case MetaEventType.TextEvent: if (settings.TrimTextEvents) { TextEvent textEvent = (TextEvent)midiEvent; textEvent.Text = textEvent.Text.Trim(); if (textEvent.Text.Length == 0) { exclude = true; } } break; case MetaEventType.Marker: if (settings.AddNameMarker && midiEvent.AbsoluteTime == 0) { exclude = true; } if (settings.RemoveExtraMarkers && midiEvent.AbsoluteTime > 0) { LogWarning("Removing a marker ({0}) at {1} from {2}", ((TextEvent)metaEvent).Text, metaEvent.AbsoluteTime, target); exclude = true; } break; } if (!exclude) { events[0].Add(midiEvent); } } else { if (outputFileType == 1) { events[1].Add(midiEvent); } else { events[0].Add(midiEvent); } } } // now do track 1 (Groove Monkee) for (int inputTrack = 1; inputTrack < midiFile.Tracks; inputTrack++) { int outputTrack; if (outputFileType == 1) { outputTrack = inputTrack; } else { outputTrack = 0; } foreach (MidiEvent midiEvent in midiFile.Events[inputTrack]) { if (settings.OutputChannelNumber != -1) { midiEvent.Channel = settings.OutputChannelNumber; } bool exclude = false; MetaEvent metaEvent = midiEvent as MetaEvent; if (metaEvent != null) { switch (metaEvent.MetaEventType) { case MetaEventType.SequenceTrackName: if (name != null) { exclude = true; } break; case MetaEventType.SequencerSpecific: exclude = settings.RemoveSequencerSpecific; break; case MetaEventType.EndTrack: exclude = settings.RecreateEndTrackMarkers; break; } } if (!exclude) { events[outputTrack].Add(midiEvent); } } if (outputFileType == 1 && settings.RecreateEndTrackMarkers) { AppendEndMarker(events[outputTrack]); } } if (settings.RecreateEndTrackMarkers) { if (outputFileType == 1) { // make sure track 1 has an end track marker AppendEndMarker(events[1]); } // make sure that track zero has an end track marker AppendEndMarker(events[0]); } else { // if we are converting type 0 to type 1 without recreating end markers, // then we still need to add an end marker to track 1 if (midiFile.FileFormat == 0) { // use the time we got from track 0 as the end track time for track 1 if (endTrackTime == -1) { LogError("Error adding track 1 end marker"); // make it a valid MIDI file anyway AppendEndMarker(events[1]); } else { events[1].Add(new MetaEvent(MetaEventType.EndTrack, 0, endTrackTime)); } } } if (settings.VerboseOutput) { LogTrace("Processing {0}: {1}", name, target); } if (settings.RemoveEmptyTracks) { MidiEventCollection newList = new MidiEventCollection(events.MidiFileType, events.DeltaTicksPerQuarterNote); int removed = 0; for (int track = 0; track < events.Tracks; track++) { IList <MidiEvent> trackEvents = events[track]; if (track < 2) { newList.AddTrack(events[track]); } else { if (HasNotes(trackEvents)) { newList.AddTrack(trackEvents); } else { removed++; } } } if (removed > 0) { events = newList; LogWarning("Removed {0} empty tracks from {1} ({2} remain)", removed, target, events.Tracks); } } MidiFile.Export(target, events); }
void LoadMidi(byte[] bytes) { var br = new BinaryReader(new MemoryStream(bytes)); using (br) { string chunkHeader = Encoding.UTF8.GetString(br.ReadBytes(4)); if (chunkHeader != "MThd") { throw new FormatException("Not a MIDI file - header chunk missing"); } uint chunkSize = SwapUInt32(br.ReadUInt32()); if (chunkSize != 6) { throw new FormatException("Unexpected header chunk length"); } // 0 = single track, 1 = multi-track synchronous, 2 = multi-track asynchronous fileFormat = SwapUInt16(br.ReadUInt16()); int tracks = SwapUInt16(br.ReadUInt16()); deltaTicksPerQuarterNote = SwapUInt16(br.ReadUInt16()); events = new MidiEventCollection((fileFormat == 0) ? 0 : 1, deltaTicksPerQuarterNote); for (int n = 0; n < tracks; n++) { events.AddTrack(); } long absoluteTime = 0; for (int track = 0; track < tracks; track++) { if (fileFormat == 1) { absoluteTime = 0; } chunkHeader = Encoding.UTF8.GetString(br.ReadBytes(4)); if (chunkHeader != "MTrk") { throw new FormatException("Invalid chunk header"); } chunkSize = SwapUInt32(br.ReadUInt32()); long startPos = br.BaseStream.Position; MidiEvent me = null; var outstandingNoteOns = new List<NoteOnEvent>(); while (br.BaseStream.Position < startPos + chunkSize) { me = MidiEvent.ReadNextEvent(br, me); absoluteTime += me.DeltaTime; me.AbsoluteTime = absoluteTime; events[track].Add(me); if (me.CommandCode == MidiCommandCode.NoteOn) { NoteEvent ne = (NoteEvent)me; if (ne.Velocity > 0) { outstandingNoteOns.Add((NoteOnEvent)ne); } else { // don't remove the note offs, even though // they are annoying // events[track].Remove(me); FindNoteOn(ne, outstandingNoteOns); } } else if (me.CommandCode == MidiCommandCode.NoteOff) { FindNoteOn((NoteEvent)me, outstandingNoteOns); } else if (me.CommandCode == MidiCommandCode.MetaEvent) { MetaEvent metaEvent = (MetaEvent)me; if (metaEvent.MetaEventType == MetaEventType.EndTrack) { //break; // some dodgy MIDI files have an event after end track if (strictChecking) { if (br.BaseStream.Position < startPos + chunkSize) { throw new FormatException(String.Format("End Track event was not the last MIDI event on track {0}", track)); } } } } } if (outstandingNoteOns.Count > 0) { if (strictChecking) { throw new FormatException(String.Format("Note ons without note offs {0} (file format {1})", outstandingNoteOns.Count, fileFormat)); } } if (br.BaseStream.Position != startPos + chunkSize) { throw new FormatException(String.Format("Read too far {0}+{1}!={2}", chunkSize, startPos, br.BaseStream.Position)); } } } }
public void Export(string path) { MidiEventCollection mid = new MidiEventCollection(1, DELTA_TICKS_PER_QUARTER); Song song = _objects.First(x => x is Song) as Song; var instruments = song.InstrumentPaths.Select(x => _objects.First(y => y.FilePath == x) as Instrument).ToList(); List <ZObject> GetInstrumentTracks(string type, string difficulty) { var insTracks = instruments.FirstOrDefault(x => x.InstrumentType == type && x.Difficulty == difficulty); if (insTracks == null) { return(new List <ZObject>()); } return(insTracks.TrackPaths.Select(x => _objects.First(y => y.FilePath == x)).ToList()); } var master = GetInstrumentTracks("master", ""); var tempo = master.First(x => x is Tempo) as Tempo; var ts = master.First(x => x is TimeSignature) as TimeSignature; var ev = master.First(x => x is Event) as Event; var section = master.First(x => x is Section) as Section; // Tempo track mid.AddTrack(CreateTempoTrack(tempo, ts)); // Bass tracks var track = CreateTabTrack(GetInstrumentTracks("bass", "jam"), "PART BASS_E"); if (track.Count > 2) { mid.AddTrack(track); } track = CreateTabTrack(GetInstrumentTracks("bass", "nov"), "PART BASS_M"); if (track.Count > 2) { mid.AddTrack(track); } track = CreateTabTrack(GetInstrumentTracks("bass", "beg"), "PART BASS_H"); if (track.Count > 2) { mid.AddTrack(track); } track = CreateTabTrack(GetInstrumentTracks("bass", "int"), "PART BASS_X"); if (track.Count > 2) { mid.AddTrack(track); } track = CreateTabTrack(GetInstrumentTracks("bass", "adv"), "PART BASS_R"); if (track.Count > 2) { mid.AddTrack(track); } // Guitar tracks track = CreateTabTrack(GetInstrumentTracks("guitar", "jam"), "PART GUITAR_E"); if (track.Count > 2) { mid.AddTrack(track); } track = CreateTabTrack(GetInstrumentTracks("guitar", "nov"), "PART GUITAR_M"); if (track.Count > 2) { mid.AddTrack(track); } track = CreateTabTrack(GetInstrumentTracks("guitar", "beg"), "PART GUITAR_H"); if (track.Count > 2) { mid.AddTrack(track); } track = CreateTabTrack(GetInstrumentTracks("guitar", "int"), "PART GUITAR_X"); if (track.Count > 2) { mid.AddTrack(track); } track = CreateTabTrack(GetInstrumentTracks("guitar", "adv"), "PART GUITAR_R"); if (track.Count > 2) { mid.AddTrack(track); } track = CreateTabTrack(GetInstrumentTracks("guitar", "rhy"), "PART GUITAR_R_RHYTHM"); if (track.Count > 2) { mid.AddTrack(track); } // Vox track track = CreateVoxTrack(GetInstrumentTracks("vocals", "")); if (track.Count > 2) { mid.AddTrack(track); } // Events track mid.AddTrack(CreateEventsTrack(ev, section)); // Beat track var measure = master.First(x => x is Measure) as Measure; track = CreateBeatTrack(measure); mid.AddTrack(track); MidiFile.Export(path, mid); }