public static MidiEventCollection ToMidiEventCollection(this List<Quote> quotes, int track) { var events = quotes.ToMidiEvents(); var result = new MidiEventCollection(MIDI_FILE_TYPE, DELTA_TICKS_PER_QUARTER_NOTE); events.ForEach(n => result.AddEvent(n, track)); return result; }
internal ProcessBuffer(uint nframes, AudioBuffer[] audioInBuffers, AudioBuffer[] audioOutBuffers, MidiEventCollection<MidiInEvent>[] midiInEvents, MidiEventCollection<MidiOutEvent>[] midiOutEvents) { Frames = (int)nframes; AudioIn = audioInBuffers; AudioOut = audioOutBuffers; MidiIn = midiInEvents; MidiOut = midiOutEvents; }
internal static MidiEventCollection<MidiInEvent> GetMidiBuffer(this MidiInPort port, uint nframes) { MidiEventCollection<MidiInEvent> eventCollection = new MidiEventCollection<MidiInEvent> (port); foreach (MidiInEvent midiEvent in port.GetMidiEvents(nframes)) { eventCollection.AddEvent (midiEvent); } return eventCollection; }
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, header.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(header.MPQN, 0)); mc.AddTrack(dummy); int availablechannel = 1; for (int i = 0; i < tracks.Count; i++) { mc.AddTrack(tracks[i].ToMidiEventList(header, 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 Skip3Beats() { var midiEvents = new MidiEventCollection(); midiEvents.Add(new NoteOn(0, 1, "C4", 100)); midiEvents.Add(new NoteOn(120, 1, "C4", 0)); var midiImporter = new GuitarMidiImporter(midiEvents, 120, 3); var firstScoreNote = midiImporter.ScoreNotes.ElementAt(0).Value; Assert.AreEqual(1 + 3, firstScoreNote.Beat); Assert.AreEqual(0, firstScoreNote.Tick); }
//private static string MIDI_for_whom_the_bell_tolls = TestConfig.AudioPath + "metallica-for_whom_the_bell_tolls.mid"; private void TestFirstNotePosition(NoteValue pNoteValue, string pNoteId, int pString, int pPosition) { var midiEvents = new MidiEventCollection(); midiEvents.Add(new NoteOn(0, 1, pNoteId, 100)); midiEvents.Add(new NoteOn(120, 1, pNoteId, 0)); var midiImporter = new GuitarMidiImporter(midiEvents, 120); var firstScoreNote = midiImporter.ScoreNotes.ElementAt(0).Value; Assert.AreEqual(pNoteValue, firstScoreNote.Note.Value, firstScoreNote.NoteId); Assert.AreEqual(pString, firstScoreNote.NotePositions.ElementAt(0).Value.String, firstScoreNote.NoteId); Assert.AreEqual(pPosition, firstScoreNote.NotePositions.ElementAt(0).Value.Fret, firstScoreNote.NoteId); }
private void AddEventIfItDoesNotExist(MidiEventCollection midi, string eventName, long time) { var eventsTrack = midi.GetTrackByName(TrackName.Events.ToString()); var existingEvent = eventsTrack.FindFirstTextEvent(eventName); if (existingEvent != null) { return; } var newEvent = new TextEvent(eventName, MetaEventType.TextEvent, time); AddInfo($"Adding {eventName} event at {GetBarInfo(midi, newEvent)}"); eventsTrack.Add(newEvent); }
public void CapDrumTrackDurations(MidiEventCollection midi) { var drumPart = midi.GetTrackByName(TrackName.Drums.ToString()); // Don't shorten the special notes because they are supposed to // overlap the regular notes var regularDrumNotes = drumPart. OfType <NoteOnEvent>(). Where(note => !SpecialNoteNumbers.Contains(note.NoteNumber)); foreach (var noteOn in regularDrumNotes) { noteOn.OffEvent.AbsoluteTime = noteOn.AbsoluteTime + 1; } }
private List <MidiEvent> GenerateBeatTrack(List <XmkTimeSignature> timeSigs, MidiEventCollection mid) { List <MidiEvent> track = new List <MidiEvent>(); track.Add(new NAudio.Midi.TextEvent("BEAT", MetaEventType.SequenceTrackName, 0)); long lastEventOffset = mid.SelectMany(x => x).Select(y => y.AbsoluteTime).Max(); long offset = 0; var tsEndOffsets = timeSigs.Skip(1).Select(x => (long)(x.Ticks / 2)).ToList(); tsEndOffsets.Add(lastEventOffset); int tsIdx = 0, currentBeat = 1; while (offset < lastEventOffset) { if (offset >= tsEndOffsets[tsIdx]) { // New time signature currentBeat = 1; tsIdx++; offset = timeSigs[tsIdx].Ticks / 2; } var ts = timeSigs[tsIdx]; int beatSize = DELTA_TICKS_PER_MEASURE / ts.Denominator; int eventSize = beatSize / 4; if (currentBeat > ts.Numerator) { currentBeat = 1; } int pitch = currentBeat == 1 ? 12 : 13; // 12 = down, 13 = up // Adds beat event track.Add(new NoteEvent(offset, 1, MidiCommandCode.NoteOn, pitch, 1)); track.Add(new NoteEvent(offset + eventSize, 1, MidiCommandCode.NoteOff, pitch, 1)); currentBeat++; offset += beatSize; } // Adds end track track.Add(new MetaEvent(MetaEventType.EndTrack, 0, track.Last().AbsoluteTime)); return(track); }
public static IList <MidiEvent> AddNamedTrackCopy(this MidiEventCollection midiEventCollection, string name, IEnumerable <MidiEvent> initialEvents) { var nameEvent = new TextEvent(name, MetaEventType.SequenceTrackName, 0); var track = AddTrackCopy(midiEventCollection, new [] { nameEvent }.Concat(initialEvents)); 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); }
private List <MidiEvent> GetNoteOnList(MidiEventCollection mec) { List <MidiEvent> ret = new List <MidiEvent>(); foreach (IList <MidiEvent> mel in mec) { foreach (MidiEvent mEv in mel) { ret.Add(mEv); } } return(ret); }
public static void SaveToFile(string fileName, int[] bankNumbers, int[] patchNumbers, int[] noteNumbers, double[] durations, int[] velocities) { const int MidiFileType = 0; const int MicrosecondsPerQuaterNote = 1000000; const int TicksPerQuarterNote = 120; const int TrackNumber = 0; const long Time = 0; var collection = new MidiEventCollection(MidiFileType, TicksPerQuarterNote); collection.AddEvent(new TextEvent("Note Stream", MetaEventType.TextEvent, Time), TrackNumber); collection.AddEvent(new TempoEvent(MicrosecondsPerQuaterNote, Time), TrackNumber); var channels = new List <Tuple <int, int> >(); int notesAdded = 0; for (int i = 0; i < noteNumbers.Length; i++) { var channelIndex = FindChannel(channels, bankNumbers[i], patchNumbers[i]); if (channelIndex == -1) { channels.Add(new Tuple <int, int>(bankNumbers[i], patchNumbers[i])); channelIndex = channels.Count; collection.AddEvent(new ControlChangeEvent(Time, channelIndex, MidiController.BankSelect, bankNumbers[i] >> 8 << 8), TrackNumber); collection.AddEvent(new ControlChangeEvent(Time, channelIndex, MidiController.BankSelectLsb, (byte)bankNumbers[i]), TrackNumber); collection.AddEvent(new PatchChangeEvent(Time, channelIndex, patchNumbers[i]), TrackNumber); } var tickDuration = (int)(durations[i] * 1000 / MicrosecondsPerQuaterNote * TicksPerQuarterNote); collection.AddEvent(new NoteOnEvent(Time, channelIndex, noteNumbers[i], velocities[i], tickDuration), TrackNumber); collection.AddEvent(new NoteEvent(Time + tickDuration, channelIndex, MidiCommandCode.NoteOff, noteNumbers[i], 0), TrackNumber); notesAdded++; } if (notesAdded == 0) { return; } collection.PrepareForExport(); MidiFile.Export(fileName, collection); }
public void TestType0() { MidiEventCollection collection = new MidiEventCollection(0, 120); collection.AddEvent(new TextEvent("Test", MetaEventType.TextEvent, 0), 0); collection.AddEvent(new NoteOnEvent(0, 1, 30, 100, 15), 1); collection.AddEvent(new NoteOnEvent(15, 1, 30, 100, 15), 1); collection.AddEvent(new NoteOnEvent(30, 1, 30, 100, 15), 1); collection.AddEvent(new NoteOnEvent(0, 10, 60, 100, 15), 10); collection.AddEvent(new NoteOnEvent(15, 10, 60, 100, 15), 10); collection.AddEvent(new NoteOnEvent(30, 10, 60, 100, 15), 10); Assert.AreEqual(collection.Tracks, 1); collection.PrepareForExport(); Assert.AreEqual(collection.Tracks, 1); IList<MidiEvent> track0 = collection.GetTrackEvents(0); Assert.AreEqual(track0.Count, 8); Assert.IsTrue(MidiEvent.IsEndTrack(track0[track0.Count - 1])); }
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 List <TempoData> ReadTempoEvents(MidiEventCollection events) { var tempList = new List <TempoData>(); foreach (var eventList in events) { foreach (var e in eventList) { if (e is TempoEvent) { TempoEvent tempo = (e as TempoEvent); tempList.Add(new TempoData((int)tempo.AbsoluteTime, (ulong)tempo.MicrosecondsPerQuarterNote)); } } } return(tempList); }
private void FilterEventNotes(MidiEventCollection midi, int track, List <MidiEvent> targetEvents) { var noteEvents = midi[track]. OfType <NoteEvent>(). GroupBy(e => !AllowedEventNotes.Contains(e.NoteNumber)). ToList(); var invalidNotes = noteEvents.Where(kvp => !kvp.Key).ToList(); if (invalidNotes.Any()) { AddWarning($"Ignoring {invalidNotes.Count} note(s) on track {TrackName.Events} (#{track})"); } var validNotes = noteEvents.Where(kvp => kvp.Key).SelectMany(e => e); targetEvents.AddRange(validNotes); }
public void ValidateBeatTrack(MidiEventCollection midi) { var beatTrack = midi.GetTrackByName(TrackName.Beat.ToString()); var invalidBeats = beatTrack. OfType <NoteOnEvent>(). Where(e => e.NoteNumber != DownBeat && e.NoteNumber != UpBeat). ToList(); foreach (var beat in invalidBeats) { AddError($"Invalid note: {beat.NoteName} ({beat.NoteNumber}) at {GetBarInfo(midi, beat)}"); } if (invalidBeats.Count > 0) { throw new InvalidBeatTrackException("Invalid beats detected."); } }
public static MidiEventCollection transpose(MidiEventCollection m, int i) { // Loop through each track in the MidiEventCollection);) for (int track = 0; track < m.Tracks; 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) { // We found one. Let's cast to the subclass. NoteOnEvent n = (NoteOnEvent)e; // As long as there is a corresponding off event... if (n.OffEvent != null) { // This is a valid note-on! // Transpose by incrementing by i n.NoteNumber += i; } } else { if (e is NoteEvent) { NoteEvent ne = (NoteEvent)e; ne.NoteNumber += i; } } } } } // Return the transposed data. return(m); }
public void NoteDuration_AdmitTheSameNote() { var midiEvents = new MidiEventCollection(); midiEvents.Add(new NoteOn(0, 1, "C4", 100)); midiEvents.Add(new NoteOn(0, 1, "C4", 100)); midiEvents.Add(new NoteOn(120, 1, "C4", 0)); midiEvents.Add(new NoteOn(120, 1, "C4", 0)); var midiImporter = new GuitarMidiImporter(midiEvents, 120); Assert.AreEqual(2, midiImporter.ScoreNotes.Count); var firstChord = midiImporter.ScoreNotes.Where(p => (p.Value.Beat == 1) && (p.Value.Tick == 0)).ToList(); Assert.AreEqual(2, firstChord.Count); }
public void TestType0() { MidiEventCollection collection = new MidiEventCollection(0, 120); collection.AddEvent(new TextEvent("Test", MetaEventType.TextEvent, 0), 0); collection.AddEvent(new NoteOnEvent(0, 1, 30, 100, 15), 1); collection.AddEvent(new NoteOnEvent(15, 1, 30, 100, 15), 1); collection.AddEvent(new NoteOnEvent(30, 1, 30, 100, 15), 1); collection.AddEvent(new NoteOnEvent(0, 10, 60, 100, 15), 10); collection.AddEvent(new NoteOnEvent(15, 10, 60, 100, 15), 10); collection.AddEvent(new NoteOnEvent(30, 10, 60, 100, 15), 10); Assert.AreEqual(collection.Tracks, 1); collection.PrepareForExport(); Assert.AreEqual(collection.Tracks, 1); IList <MidiEvent> track0 = collection.GetTrackEvents(0); Assert.AreEqual(track0.Count, 8); Assert.IsTrue(MidiEvent.IsEndTrack(track0[track0.Count - 1])); }
private List <IList <IMessage> > parseMidiEvents(MidiEventCollection events) { int currentTrack = 0; List <IList <IMessage> > overallMessages; foreach (IList <MidiEvent> track in events) { IList <IMessage> trackMessages = new List <IMessage>(); foreach (MidiEvent midiEvent in track) { IMessage message = getMessage(midiEvent); if (message != null) { trackMessages.add(message); } } overallMessages.Add(trackMessages); } }
public void CanCloneForSameTrack() { var collection = new MidiEventCollection(0, 120); collection.AddEvent(new NoteOnEvent(0, 1, 30, 100, 15), 0); var clone = (NoteOnEvent)collection[0][0].Clone(); clone.AbsoluteTime += 15; clone.NoteNumber++; collection.AddEvent(clone, 0); collection.PrepareForExport(); Assert.That(collection[0][0].AbsoluteTime, Is.EqualTo(0)); Assert.That(collection[0][1].AbsoluteTime, Is.EqualTo(15)); Assert.That(((NoteOnEvent)collection[0][0]).NoteNumber, Is.EqualTo(30)); Assert.That(((NoteOnEvent)collection[0][1]).NoteNumber, Is.EqualTo(31)); }
public void TestType0ToType1() { MidiEventCollection collection = new MidiEventCollection(0, 120); collection.AddEvent(new TextEvent("Test", MetaEventType.TextEvent, 0), 0); collection.AddEvent(new NoteOnEvent(0, 1, 30, 100, 15), 1); collection.AddEvent(new NoteOnEvent(15, 1, 30, 100, 15), 1); collection.AddEvent(new NoteOnEvent(30, 1, 30, 100, 15), 1); collection.AddEvent(new NoteOnEvent(0, 10, 60, 100, 15), 10); collection.AddEvent(new NoteOnEvent(15, 10, 60, 100, 15), 10); collection.AddEvent(new NoteOnEvent(30, 10, 60, 100, 15), 10); Assert.AreEqual(collection.Tracks, 1); collection.MidiFileType = 1; collection.PrepareForExport(); Assert.AreEqual(3, collection.Tracks, "Wrong number of tracks"); IList<MidiEvent> track0 = collection.GetTrackEvents(0); Assert.AreEqual(track0.Count, 2); Assert.AreEqual(collection.GetTrackEvents(1).Count, 4); Assert.AreEqual(collection.GetTrackEvents(2).Count, 4); Assert.IsTrue(MidiEvent.IsEndTrack(track0[track0.Count - 1])); }
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); }
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])); } } }
public void AddDrumMixEvents(MidiEventCollection midi) { var drumTrack = midi.GetTrackByName(TrackName.Drums.ToString()); var existingMixEvents = drumTrack. OfType <TextEvent>(). Where(e => e.AbsoluteTime == 0 && e.MetaEventType == MetaEventType.TextEvent). Select(e => e.AsDrumMixEvent()). Where(e => e != null). ToList(); for (var difficulty = 0; difficulty < 4; difficulty++) { if (existingMixEvents.Any(e => e.Difficulty == difficulty)) { continue; } // Try to keep them in order drumTrack.Insert(difficulty + 1, DrumMixEvent.DefaultFor(difficulty)); } }
public void OneNote() { var midiEvents = new MidiEventCollection(); midiEvents.Add(new NoteOn(480, 1, "C#4", 100)); //480 = 4 x 120 (4 beats) midiEvents.Add(new NoteOn(120, 1, "C#4", 0)); var midiImporter = new MidiImporter(midiEvents, 120); Assert.AreEqual(1, midiImporter.ScoreNotes.Count); var firstScoreNote = midiImporter.ScoreNotes.ElementAt(0).Value; //Time is 5:0 (beat:tick) Assert.AreEqual(5, firstScoreNote.Beat); Assert.AreEqual(0, firstScoreNote.Tick); //Note is C#4 Assert.AreEqual(NoteValue.Db, firstScoreNote.Note.Value); Assert.AreEqual(4, firstScoreNote.Note.Number); }
public void NoteDuration_OneNote_TwoChords() { var midiEvents = new MidiEventCollection(); midiEvents.Add(new NoteOn(480, 1, "C4", 100)); midiEvents.Add(new NoteOn(0, 1, "G4", 100)); midiEvents.Add(new NoteOn(0, 1, "C5", 100)); midiEvents.Add(new NoteOn(30, 1, "C4", 0)); midiEvents.Add(new NoteOn(0, 1, "G4", 0)); midiEvents.Add(new NoteOn(0, 1, "C5", 0)); midiEvents.Add(new NoteOn(30, 1, "G3", 100)); midiEvents.Add(new NoteOn(0, 1, "D4", 100)); midiEvents.Add(new NoteOn(0, 1, "G4", 100)); midiEvents.Add(new NoteOn(180, 1, "G3", 0)); midiEvents.Add(new NoteOn(0, 1, "D4", 0)); midiEvents.Add(new NoteOn(0, 1, "G4", 0)); var midiImporter = new MidiImporter(midiEvents, 120); Assert.AreEqual(6, midiImporter.ScoreNotes.Count); //Get the first chord (and test the position/duration) var firstChord = midiImporter.ScoreNotes.Where( p => (p.Value.Beat == 5) && (p.Value.Tick == 0) && (p.Value.DurationInTicks == 120)).ToList(); Assert.AreEqual(3, firstChord.Count); //Get the second chord (and test the position/duration) var secondChord = midiImporter.ScoreNotes.Where( p => (p.Value.Beat == 5) && (p.Value.Tick == 240) && (p.Value.DurationInTicks == 480 + 240)).ToList(); Assert.AreEqual(3, secondChord.Count); }
private void toolStripButton1_Click(object sender, EventArgs e) { MidiEventCollection midi = this.file.Data.Midi; if (this.first) { midi.PrepareForExport(); this.midi = Path.GetTempFileName(); MidiFile.Export(this.midi, midi); } if (this.first && this.dls != null) { this.dlss = Path.GetTempFileName(); File.WriteAllBytes(this.dlss, this.dls); } this.m.SetMidi(this.midi); if (this.first && this.dls != null) { this.m.SetDLS(this.dlss); } if (this.file.Data.GetLoopStart() != -1 && this.file.Data.GetLoopEnd() != -1 && this.first) { int length = this.m.GetLength(); int Start = this.file.Data.GetLoopStart() * 16; int End = this.file.Data.GetLoopEnd() * 16; if (Start <= length && End <= length && End >= Start) { this.m.SetLoop(Start, End, this.file.Data.GetNrLoop()); } } if (this.file.Data.GetLoopStart() == -1 || this.file.Data.GetLoopEnd() == -1) { ; } if (this.first) { this.first = false; } this.m.Play(); }
public void SaveToFile(string fileName, List <NoteOnEvent> NoteOnList) { const int MidiFileType = 0; const int BeatsPerMinute = 60; const int TicksPerQuarterNote = 120; const int TrackNumber = 0; const int ChannelNumber = 1; long absoluteTime = 0; var collection = new MidiEventCollection(MidiFileType, TicksPerQuarterNote); collection.AddEvent(new TextEvent("Note Stream", MetaEventType.TextEvent, absoluteTime), TrackNumber); ++absoluteTime; collection.AddEvent(new TempoEvent(CalculateMicrosecondsPerQuaterNote(BeatsPerMinute), absoluteTime), TrackNumber); // var patchParser = new PatchParser(); int patchNumber = 25; collection.AddEvent(new PatchChangeEvent(0, ChannelNumber, patchNumber), TrackNumber); // const int NoteVelocity = 100; // const int NoteDuration = 3 * TicksPerQuarterNote / 4; // i need this to reflect the actual time const long SpaceBetweenNotes = TicksPerQuarterNote; // currently irrelevant if (NoteOnList != null) { foreach (var note in NoteOnList) { collection.AddEvent(new NoteOnEvent(note.AbsoluteTime, ChannelNumber, note.NoteNumber, note.Velocity, note.NoteLength), TrackNumber); collection.AddEvent(new NoteEvent(note.AbsoluteTime + note.NoteLength, ChannelNumber, MidiCommandCode.NoteOff, note.NoteNumber, 0), TrackNumber); absoluteTime += SpaceBetweenNotes; } collection.PrepareForExport(); MidiFile.Export(fileName, collection); } }
public void RemoveDuplicateNotes(MidiEventCollection midi) { for (var t = 0; t < midi.Tracks; t++) { var track = midi[t]; var existingElements = new HashSet <NoteOnEvent>(new NoteEventEqualityComparer()); var notesToRemove = new List <NoteOnEvent>(); foreach (var noteOnEvent in track.OfType <NoteOnEvent>()) { if (!existingElements.Add(noteOnEvent)) { notesToRemove.Add(noteOnEvent); } } foreach (var note in notesToRemove) { track.Remove(note.OffEvent); track.Remove(note); } } }
public void TestType0ToType1() { MidiEventCollection collection = new MidiEventCollection(0, 120); collection.AddEvent(new TextEvent("Test", MetaEventType.TextEvent, 0), 0); collection.AddEvent(new NoteOnEvent(0, 1, 30, 100, 15), 1); collection.AddEvent(new NoteOnEvent(15, 1, 30, 100, 15), 1); collection.AddEvent(new NoteOnEvent(30, 1, 30, 100, 15), 1); collection.AddEvent(new NoteOnEvent(0, 10, 60, 100, 15), 10); collection.AddEvent(new NoteOnEvent(15, 10, 60, 100, 15), 10); collection.AddEvent(new NoteOnEvent(30, 10, 60, 100, 15), 10); Assert.AreEqual(collection.Tracks, 1); collection.MidiFileType = 1; collection.PrepareForExport(); Assert.AreEqual(3, collection.Tracks, "Wrong number of tracks"); IList <MidiEvent> track0 = collection.GetTrackEvents(0); Assert.AreEqual(track0.Count, 2); Assert.AreEqual(collection.GetTrackEvents(1).Count, 4); Assert.AreEqual(collection.GetTrackEvents(2).Count, 4); Assert.IsTrue(MidiEvent.IsEndTrack(track0[track0.Count - 1])); }
public static int FindTrackNumberByName(this MidiEventCollection midiEventCollection, string name) { var trackNumber = -1; for (var t = 0; t < midiEventCollection.Tracks; t++) { var isMatch = midiEventCollection[t].OfType <TextEvent>().Any(e => e.IsSequenceTrackName() && e.Text == name); if (!isMatch) { continue; } if (trackNumber != -1) { throw new InvalidOperationException("Multiple tracks named: " + name); } trackNumber = t; } return(trackNumber); }
public void ConvertLastBeatToEnd(MidiEventCollection midi) { var beatTrack = midi.GetTrackByName(TrackName.Beat.ToString()); var lastBeatOn = beatTrack.OfType <NoteOnEvent>().OrderBy(e => e.AbsoluteTime).LastOrDefault(MidiEvent.IsNoteOn); if (lastBeatOn == null) { throw new InvalidBeatTrackException($"No notes were found on the {TrackName.Beat} track"); } var eventsTrack = midi.FindTrackByName(TrackName.Events.ToString()); if (eventsTrack != null) { var existingEvent = eventsTrack.FindFirstTextEvent(EventName.End.ToString()); if (existingEvent != null) { AddInfo($"{EventName.End} event already exists at {GetBarInfo(midi, existingEvent)}, left last beat in place."); return; } } else { eventsTrack = midi.AddNamedTrack(TrackName.Events.ToString()); } beatTrack.Remove(lastBeatOn); beatTrack.Remove(lastBeatOn.OffEvent); // Fix beat track end var newLastEvent = beatTrack.OfType <NoteEvent>().OrderBy(e => e.AbsoluteTime).Last(); UpdateTrackEnd(beatTrack, newLastEvent.AbsoluteTime); eventsTrack.Add(new TextEvent(EventName.End.ToString(), MetaEventType.TextEvent, lastBeatOn.AbsoluteTime)); UpdateTrackEnd(eventsTrack, lastBeatOn.AbsoluteTime); }
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 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); }
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)); } } } }
/// <summary> /// Exports a MIDI file /// </summary> /// <param name="filename">Filename to export to</param> /// <param name="events">Events to export</param> public static void Export(string filename, MidiEventCollection events) { if (events.MidiFileType == 0 && events.Tracks > 1) { throw new ArgumentException("Can't export more than one track to a type 0 file"); } using (var writer = new BinaryWriter(File.Create(filename))) { writer.Write(Encoding.UTF8.GetBytes("MThd")); writer.Write(SwapUInt32((uint)6)); // chunk size writer.Write(SwapUInt16((ushort)events.MidiFileType)); writer.Write(SwapUInt16((ushort)events.Tracks)); writer.Write(SwapUInt16((ushort)events.DeltaTicksPerQuarterNote)); for (int track = 0; track < events.Tracks; track++ ) { IList<MidiEvent> eventList = events[track]; writer.Write(Encoding.UTF8.GetBytes("MTrk")); long trackSizePosition = writer.BaseStream.Position; writer.Write(SwapUInt32((uint)0)); long absoluteTime = events.StartAbsoluteTime; // use a stable sort to preserve ordering of MIDI events whose // absolute times are the same MergeSort.Sort(eventList, new MidiEventComparer()); if (eventList.Count > 0) { System.Diagnostics.Debug.Assert(MidiEvent.IsEndTrack(eventList[eventList.Count - 1]), "Exporting a track with a missing end track"); } foreach (MidiEvent midiEvent in eventList) { midiEvent.Export(ref absoluteTime, writer); } uint trackChunkLength = (uint)(writer.BaseStream.Position - trackSizePosition) - 4; writer.BaseStream.Position = trackSizePosition; writer.Write(SwapUInt32(trackChunkLength)); writer.BaseStream.Position += trackChunkLength; } } }
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); }
/// <summary> /// /// </summary> /// <param name="filename"></param> /// <param name="selectedChannel"></param> public void Refresh(string filename, int selectedChannel) { GetTitle(filename); midiEventCollection = new MidiFile(filename).Events; i_NumMusicChannels = midiEventCollection.Tracks - 1; // one of the tracks is used for metadata GetAllTimingInformation(); GetUsedChannels(); GetChannelInstruments(); Duration = 0; GetNotesForAllChannels(); l_Metadata.Clear(); for (int i = 0; i < midiEventCollection[0].Count; i++) { l_Metadata.Add(midiEventCollection[0][i]); } }
internal MidiEventCollection<MidiOutEvent> GetMidiBuffer() { MidiEventCollection<MidiOutEvent> eventCollection = new MidiEventCollection<MidiOutEvent> (this); return eventCollection; }
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; } }