private string ToMBT(MidiEvent midiEvent, int ticksPerBeat, List<TimeSignatureChange> timeSignatures) { TimeSignatureChange latestTimeSig = FindLatestTimeSig(midiEvent.AbsoluteTime,timeSignatures); long relativeTime = midiEvent.AbsoluteTime - latestTimeSig.AbsoluteTime; long measure = (relativeTime / (ticksPerBeat * latestTimeSig.BeatsPerMeasure)) + latestTimeSig.StartMeasureNumber; long beat = ((relativeTime / ticksPerBeat) % latestTimeSig.BeatsPerMeasure) + 1; long tick = relativeTime % ticksPerBeat; return String.Format("{0}:{1}:{2}", measure, beat, tick); }
/// <summary> /// Create a new MIDI In Message EventArgs /// </summary> /// <param name="message"></param> /// <param name="timestamp"></param> public MidiInMessageEventArgs(int message, int timestamp) { this.message = message; this.timestamp = timestamp; try { midiEvent = MidiEvent.FromRawMessage(message); } catch (Exception) { // don't worry too much - might be an invalid message } }
private void SendMidiOutMessage(MidiEvent eventToSend) { midiOut.Send(eventToSend.GetAsShortMessage()); progressLog1.LogMessage(Color.Green, String.Format("Sent {0}", eventToSend)); }
private bool IsEndTrack(MidiEvent midiEvent) { var meta = midiEvent as MetaEvent; return meta?.MetaEventType == MetaEventType.EndTrack; }
/// <summary> /// Whether this is a note off event /// </summary> public static bool IsNoteOff(MidiEvent midiEvent) { if (midiEvent != null) { if (midiEvent.CommandCode == MidiCommandCode.NoteOn) { var ne = (NoteEvent) midiEvent; return (ne.Velocity == 0); } return (midiEvent.CommandCode == MidiCommandCode.NoteOff); } return false; }
public static MetaEvent ReadMetaEvent(BinaryReader br) { MetaEventType metaEventType = (MetaEventType)br.ReadByte(); int num = MidiEvent.ReadVarInt(br); MetaEvent metaEvent = new MetaEvent(); MetaEventType metaEventType2 = metaEventType; if (metaEventType2 <= MetaEventType.SetTempo) { switch (metaEventType2) { case MetaEventType.TrackSequenceNumber: metaEvent = new TrackSequenceNumberEvent(br, num); goto IL_E9; case MetaEventType.TextEvent: case MetaEventType.Copyright: case MetaEventType.SequenceTrackName: case MetaEventType.TrackInstrumentName: case MetaEventType.Lyric: case MetaEventType.Marker: case MetaEventType.CuePoint: case MetaEventType.ProgramName: case MetaEventType.DeviceName: metaEvent = new TextEvent(br, num); goto IL_E9; default: if (metaEventType2 != MetaEventType.EndTrack) { if (metaEventType2 == MetaEventType.SetTempo) { metaEvent = new TempoEvent(br, num); goto IL_E9; } } else { if (num != 0) { throw new FormatException("End track length"); } goto IL_E9; } break; } } else { if (metaEventType2 == MetaEventType.SmpteOffset) { metaEvent = new SmpteOffsetEvent(br, num); goto IL_E9; } switch (metaEventType2) { case MetaEventType.TimeSignature: metaEvent = new TimeSignatureEvent(br, num); goto IL_E9; case MetaEventType.KeySignature: metaEvent = new KeySignatureEvent(br, num); goto IL_E9; default: if (metaEventType2 == MetaEventType.SequencerSpecific) { metaEvent = new SequencerSpecificEvent(br, num); goto IL_E9; } break; } } metaEvent.data = br.ReadBytes(num); if (metaEvent.data.Length != num) { throw new FormatException("Failed to read metaevent's data fully"); } IL_E9: metaEvent.metaEvent = metaEventType; metaEvent.metaDataLength = num; return(metaEvent); }
/// <summary> /// Constructs a MidiEvent from a BinaryStream /// </summary> /// <param name="br">The binary stream of MIDI data</param> /// <param name="previous">The previous MIDI event (pass null for first event)</param> /// <returns>A new MidiEvent</returns> public static MidiEvent ReadNextEvent(BinaryReader br, MidiEvent previous) { int deltaTime = MidiEvent.ReadVarInt(br); MidiCommandCode commandCode; int channel = 1; byte b = br.ReadByte(); if ((b & 0x80) == 0) { // a running command - command & channel are same as previous commandCode = previous.CommandCode; channel = previous.Channel; br.BaseStream.Position--; // need to push this back } else { if ((b & 0xF0) == 0xF0) { // both bytes are used for command code in this case commandCode = (MidiCommandCode)b; } else { commandCode = (MidiCommandCode)(b & 0xF0); channel = (b & 0x0F) + 1; } } MidiEvent me; switch (commandCode) { case MidiCommandCode.NoteOn: me = new NoteOnEvent(br); break; case MidiCommandCode.NoteOff: case MidiCommandCode.KeyAfterTouch: me = new NoteEvent(br); break; case MidiCommandCode.TimingClock: case MidiCommandCode.StartSequence: case MidiCommandCode.ContinueSequence: case MidiCommandCode.StopSequence: me = new MidiEvent(); break; case MidiCommandCode.Sysex: me = SysexEvent.ReadSysexEvent(br); break; case MidiCommandCode.MetaEvent: me = MetaEvent.ReadMetaEvent(br); break; default: throw new FormatException(String.Format("Unsupported MIDI Command Code {0:X2}", (byte)commandCode)); } me.channel = channel; me.deltaTime = deltaTime; me.commandCode = commandCode; return(me); }
/// <summary> /// Whether this is a note on event /// </summary> public static bool IsNoteOn(MidiEvent midiEvent) { if (midiEvent != null) { if (midiEvent.CommandCode == MidiCommandCode.NoteOn) { NoteEvent ne = (NoteEvent)midiEvent; return (ne.Velocity > 0); } } return false; }
/// <summary> /// Creates a MidiEvent from a raw message received using /// the MME MIDI In APIs /// </summary> /// <param name="rawMessage">The short MIDI message</param> /// <returns>A new MIDI Event</returns> public static MidiEvent FromRawMessage(int rawMessage) { long absoluteTime = 0; int b = rawMessage & 0xFF; int data1 = (rawMessage >> 8) & 0xFF; int data2 = (rawMessage >> 16) & 0xFF; MidiCommandCode commandCode; int channel = 1; if ((b & 0xF0) == 0xF0) { // both bytes are used for command code in this case commandCode = (MidiCommandCode)b; } else { commandCode = (MidiCommandCode)(b & 0xF0); channel = (b & 0x0F) + 1; } MidiEvent me; switch (commandCode) { case MidiCommandCode.NoteOn: case MidiCommandCode.NoteOff: case MidiCommandCode.KeyAfterTouch: if (data2 > 0 && commandCode == MidiCommandCode.NoteOn) { me = new NoteOnEvent(absoluteTime, channel, data1, data2, 0); } else { me = new NoteEvent(absoluteTime, channel, commandCode, data1, data2); } break; case MidiCommandCode.ControlChange: me = new ControlChangeEvent(absoluteTime, channel, (MidiController)data1, data2); break; case MidiCommandCode.PatchChange: me = new PatchChangeEvent(absoluteTime, channel, data1); break; case MidiCommandCode.ChannelAfterTouch: me = new ChannelAfterTouchEvent(absoluteTime, channel, data1); break; case MidiCommandCode.PitchWheelChange: me = new PitchWheelChangeEvent(absoluteTime, channel, data1 + (data2 << 7)); break; case MidiCommandCode.TimingClock: case MidiCommandCode.StartSequence: case MidiCommandCode.ContinueSequence: case MidiCommandCode.StopSequence: case MidiCommandCode.AutoSensing: me = new MidiEvent(absoluteTime, channel, commandCode); break; case MidiCommandCode.MetaEvent: case MidiCommandCode.Sysex: default: throw new FormatException(String.Format("Unsupported MIDI Command Code for Raw Message {0}", commandCode)); } return(me); }
/// <summary> /// Opens a MIDI file for reading /// </summary> /// <param name="filename">Name of MIDI file</param> /// <param name="strictChecking">If true will error on non-paired note events</param> // Token: 0x0600050B RID: 1291 RVA: 0x00010D64 File Offset: 0x0000EF64 public MidiFile(string filename, bool strictChecking) { this.strictChecking = strictChecking; BinaryReader binaryReader = new BinaryReader(File.OpenRead(filename)); using (binaryReader) { string @string = Encoding.UTF8.GetString(binaryReader.ReadBytes(4)); if (@string != "MThd") { throw new FormatException("Not a MIDI file - header chunk missing"); } uint num = MidiFile.SwapUInt32(binaryReader.ReadUInt32()); if (num != 6u) { throw new FormatException("Unexpected header chunk length"); } this.fileFormat = MidiFile.SwapUInt16(binaryReader.ReadUInt16()); int num2 = (int)MidiFile.SwapUInt16(binaryReader.ReadUInt16()); this.deltaTicksPerQuarterNote = MidiFile.SwapUInt16(binaryReader.ReadUInt16()); this.events = new MidiEventCollection((this.fileFormat == 0) ? 0 : 1, (int)this.deltaTicksPerQuarterNote); for (int i = 0; i < num2; i++) { this.events.AddTrack(); } long num3 = 0L; for (int j = 0; j < num2; j++) { if (this.fileFormat == 1) { num3 = 0L; } @string = Encoding.UTF8.GetString(binaryReader.ReadBytes(4)); if (@string != "MTrk") { throw new FormatException("Invalid chunk header"); } num = MidiFile.SwapUInt32(binaryReader.ReadUInt32()); long position = binaryReader.BaseStream.Position; MidiEvent midiEvent = null; List <NoteOnEvent> list = new List <NoteOnEvent>(); while (binaryReader.BaseStream.Position < position + (long)((ulong)num)) { midiEvent = MidiEvent.ReadNextEvent(binaryReader, midiEvent); num3 += (long)midiEvent.DeltaTime; midiEvent.AbsoluteTime = num3; this.events[j].Add(midiEvent); if (midiEvent.CommandCode == MidiCommandCode.NoteOn) { NoteEvent noteEvent = (NoteEvent)midiEvent; if (noteEvent.Velocity > 0) { list.Add((NoteOnEvent)noteEvent); } else { this.FindNoteOn(noteEvent, list); } } else if (midiEvent.CommandCode == MidiCommandCode.NoteOff) { this.FindNoteOn((NoteEvent)midiEvent, list); } else if (midiEvent.CommandCode == MidiCommandCode.MetaEvent) { MetaEvent metaEvent = (MetaEvent)midiEvent; if (metaEvent.MetaEventType == MetaEventType.EndTrack && strictChecking && binaryReader.BaseStream.Position < position + (long)((ulong)num)) { throw new FormatException(string.Format("End Track event was not the last MIDI event on track {0}", j)); } } } if (list.Count > 0 && strictChecking) { throw new FormatException(string.Format("Note ons without note offs {0} (file format {1})", list.Count, this.fileFormat)); } if (binaryReader.BaseStream.Position != position + (long)((ulong)num)) { throw new FormatException(string.Format("Read too far {0}+{1}!={2}", num, position, binaryReader.BaseStream.Position)); } } } }
private void MidiBinaryReader(BinaryReader br, bool strictChecking) { 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; //UnityEngine.Debug.Log(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)); } } }
private static void GetIntervals(ref NAudio.Midi.MidiFile myMidi, TempoMap tempoMap) //main function to print the dominant channel on each interval { //File.WriteAllText(@"output.txt", string.Empty); //empty file //var ourStream = File.CreateText(@"output.txt"); //start writing var ourStream = new List <string>(); //for the Excel output string output = @"C:\Users\Yoni\Desktop\ThirdStringQuartet.xlsx"; if (File.Exists(output)) { File.Delete(output); } Excel.Application oApp; Excel.Worksheet oSheet; Excel.Workbook oBook; oApp = new Excel.Application(); oBook = oApp.Workbooks.Add(); oSheet = (Excel.Worksheet)oBook.Worksheets.Item[1]; oSheet.Cells[1, 1].EntireRow.Font.Bold = true; oSheet.Cells[1, 1] = "Start Time"; int lastDominantChannel = 0; //in case of same dominant channel as before and tie between two channels now we will choose not to change var currentTempoEvent = new TempoEvent(0, 0); long windowSize = 0; //length of time interval var startEvent = new MidiEvent(myMidi.Events[0][0].AbsoluteTime, myMidi.Events[0][0].Channel, myMidi.Events[0][0].CommandCode); //first event in each interval IDictionary <int, string> patchToChannel = new Dictionary <int, string>(); //to handle patches IDictionary <int, int> mainVolumeToChannel = new Dictionary <int, int>(); //to handle main volume in each channel int k = 0; List <NoteOnEvent> noteOnCollection2 = new List <NoteOnEvent>(); while (myMidi.Events[0][k].AbsoluteTime == 0) //move all noteOns to the end of the 0 absolute time series { if (myMidi.Events[0][k].CommandCode.ToString() == "NoteOn") { var noteOnEvent = (NoteOnEvent)myMidi.Events[0][k]; noteOnCollection2.Add(noteOnEvent); myMidi.Events[0].RemoveAt(k); k--; } k++; } int s = 0; foreach (var noteOnEvent in noteOnCollection2) { myMidi.Events[0].Insert(k + s, noteOnEvent); s++; } /*for excel!*/ int counterForExcel = 2; var i = 0; var endOfFile = false; while (true) //main loop to move between time intervals. ends when endTrack event occours { var j = i; var exitLoop = false; IDictionary <int, int> sumVelocityToChannel = new Dictionary <int, int>(); //to handle sum of velocities per channel IDictionary <int, double> meanVelocityToChannel = new Dictionary <int, double>(); //to handle average velocity per channel IDictionary <int, int> numOfNoteOnsToChannel = new Dictionary <int, int>(); //to handle number of notes on each channel IDictionary <int, double> dominantValue = new Dictionary <int, double>(); //to handle dominant value on each channel IDictionary <int, List <NoteOnEvent> > noteOnsToChannel = new Dictionary <int, List <NoteOnEvent> >(); //to handle list of notes on each channel List <NoteOnEvent> noteOnCollection = new List <NoteOnEvent>(); // list of all noteOn events //inner loop to go through events inside an interval. Handle each relevant event with its own unique way while ((myMidi.Events[0][j].AbsoluteTime - startEvent.AbsoluteTime < windowSize) || windowSize == 0) { switch (myMidi.Events[0][j].CommandCode.ToString()) { case @"MetaEvent": var metaEvent = (MetaEvent)myMidi.Events[0][j]; switch (metaEvent.MetaEventType.ToString()) { case @"TimeSignature": var timeSignatureEvent = (TimeSignatureEvent)metaEvent; //change window size - change from 8 to 16 or 32 if too fast shifting (from 2 bars window to 4 or 8 bars) windowSize = (long)Math.Round(myMidi.DeltaTicksPerQuarterNote * ((double)timeSignatureEvent.Numerator / (Math.Pow(2, timeSignatureEvent.Denominator))) * 4); exitLoop = true; //exit interval -> interval size changes break; case @"EndTrack": endOfFile = true; //reached end of midi file break; default: break; } break; case @"PatchChange": var patchChangeEvent = (PatchChangeEvent)myMidi.Events[0][j]; if (!patchToChannel.ContainsKey(patchChangeEvent.Channel)) { patchToChannel.Add(patchChangeEvent.Channel, GetPatchName(patchChangeEvent.Patch)); } else { patchToChannel[patchChangeEvent.Channel] = GetPatchName(patchChangeEvent.Patch); } break; case @"ControlChange": var controlChangeEvent = (ControlChangeEvent)myMidi.Events[0][j]; if (controlChangeEvent.Controller == MidiController.MainVolume) { if (!mainVolumeToChannel.ContainsKey(controlChangeEvent.Channel)) //if key does not exist - create it { mainVolumeToChannel.Add(controlChangeEvent.Channel, controlChangeEvent.ControllerValue); } else { mainVolumeToChannel[controlChangeEvent.Channel] = controlChangeEvent.ControllerValue; exitLoop = true; } } break; case @"NoteOn": var noteOnEvent = (NoteOnEvent)myMidi.Events[0][j]; if (noteOnEvent.Velocity != 0) { if (!noteOnsToChannel.TryGetValue(noteOnEvent.Channel, out noteOnCollection)) { noteOnCollection = new List <NoteOnEvent>(); noteOnsToChannel[noteOnEvent.Channel] = noteOnCollection; dominantValue[noteOnEvent.Channel] = 0D; } noteOnCollection.Add(noteOnEvent); noteOnsToChannel[noteOnEvent.Channel] = noteOnCollection; numOfNoteOnsToChannel[noteOnEvent.Channel] = noteOnCollection.Count; if (!sumVelocityToChannel.ContainsKey(noteOnEvent.Channel)) //if key does not exist - create it { sumVelocityToChannel.Add(noteOnEvent.Channel, noteOnEvent.Velocity); } else { sumVelocityToChannel[noteOnEvent.Channel] += noteOnEvent.Velocity; } } break; default: break; } if (endOfFile) { break; } j++; if (exitLoop) { break; } } //end of inner loop foreach (KeyValuePair <int, int> pair in sumVelocityToChannel) { meanVelocityToChannel[pair.Key] = (double)pair.Value / (noteOnsToChannel[pair.Key].Count); //calculate avg velocity on each channel } var endEvent = new MidiEvent(1, 1, 0); //the end event on the current interval. If reached end of file stop! if (endOfFile) { endEvent = new MidiEvent(myMidi.Events[0][j].AbsoluteTime, myMidi.Events[0][j].Channel, myMidi.Events[0][j].CommandCode); } else { endEvent = new MidiEvent(myMidi.Events[0][j - 1].AbsoluteTime, myMidi.Events[0][j - 1].Channel, myMidi.Events[0][j - 1].CommandCode); } string value = ""; //neccessery for default patch and main volume int value1 = 100; foreach (KeyValuePair <int, double> pair in meanVelocityToChannel) { if (!endOfFile) { if (!dominantValue.ContainsKey(pair.Key)) { dominantValue[pair.Key] = 0D; } if (!noteOnsToChannel.ContainsKey(pair.Key)) { noteOnsToChannel[pair.Key] = null; } if (!numOfNoteOnsToChannel.ContainsKey(pair.Key)) { numOfNoteOnsToChannel[pair.Key] = 0; } if (!mainVolumeToChannel.ContainsKey(pair.Key)) { mainVolumeToChannel[pair.Key] = 0; } } } foreach (KeyValuePair <int, int> pair in mainVolumeToChannel) { if (!endOfFile) { if (!dominantValue.ContainsKey(pair.Key)) { dominantValue[pair.Key] = 0D; } if (!noteOnsToChannel.ContainsKey(pair.Key)) { noteOnsToChannel[pair.Key] = null; } if (!numOfNoteOnsToChannel.ContainsKey(pair.Key)) { numOfNoteOnsToChannel[pair.Key] = 0; } if (!meanVelocityToChannel.ContainsKey(pair.Key)) { meanVelocityToChannel[pair.Key] = 0D; } } } foreach (KeyValuePair <int, double> pair in dominantValue) //default patch and channel volume in case not given in the midi file { if (!patchToChannel.TryGetValue(pair.Key, out value)) { patchToChannel[pair.Key] = GetPatchName(0); } if (!mainVolumeToChannel.TryGetValue(pair.Key, out value1)) { mainVolumeToChannel[pair.Key] = value1; } } var orderdNumOfNoteOnsToChannel = OrderIDictionary <int>(numOfNoteOnsToChannel); //sort num of note Ons bool isEmpty; bool hasNotEmptyValues = false; using (var dictionaryEnum = noteOnsToChannel.GetEnumerator()) { isEmpty = !dictionaryEnum.MoveNext(); } hasNotEmptyValues = noteOnsToChannel .Any(pair => pair.Value != null && pair.Value.Any()); if (!isEmpty && hasNotEmptyValues) //make sure there is at least one noteOn on what we print { IDictionary <int, double> dominant = new Dictionary <int, double>(); foreach (KeyValuePair <int, double> pair in dominantValue) //The formula to change to adapt to different genres { try { if (orderdNumOfNoteOnsToChannel.First().Value - orderdNumOfNoteOnsToChannel.Last().Value != 0) { dominant[pair.Key] = (0.45) * meanVelocityToChannel[pair.Key] + (0.2) * (double)mainVolumeToChannel[pair.Key] + (0.35) * (double)(((127 * (double)(numOfNoteOnsToChannel[pair.Key] - orderdNumOfNoteOnsToChannel.Last().Value)) / (orderdNumOfNoteOnsToChannel.First().Value - orderdNumOfNoteOnsToChannel.Last().Value))); //calculate dominant value for each channel } else //all channels have same number of noteOns. Go only by two other values { dominant[pair.Key] = (0.5) * meanVelocityToChannel[pair.Key] + (0.5) * (double)mainVolumeToChannel[pair.Key]; } } catch (Exception e) { Console.WriteLine(e); throw; } } dominantValue = dominant; var orderdDominantValue = OrderIDictionary <double>(dominantValue); //sort the dominance if (orderdDominantValue.First().Key != lastDominantChannel) //different dominant channels with the last interval { ourStream.Add( $"from time {CalcFactor(startEvent.AbsoluteTime, tempoMap)}: Channel {orderdDominantValue.First().Key} ({patchToChannel[orderdDominantValue.First().Key]})"); //excel oSheet.Cells[counterForExcel, 1] = CalcFactor(startEvent.AbsoluteTime, tempoMap); oSheet.Cells[counterForExcel, 1].Font.Bold = true; oSheet.Cells[counterForExcel, 2] = orderdDominantValue.First().Key; int v = 2; foreach (KeyValuePair <int, string> pair in patchToChannel) { string str = ""; if (!patchToChannel.TryGetValue(pair.Key, out str)) { oSheet.Cells[counterForExcel, v] = 0; } else if (pair.Key.Equals(orderdDominantValue.First().Key)) { oSheet.Cells[counterForExcel, v] = 1; } else { oSheet.Cells[counterForExcel, v] = 0; } v++; } counterForExcel++; lastDominantChannel = orderdDominantValue.First().Key; } } startEvent = myMidi.Events[0][j]; //change to j if need big time interval... define start event for next time interval i = j; //include this if need the big time interval if (endOfFile) { ourStream.Add($"Ending: {CalcFactor(endEvent.AbsoluteTime, tempoMap)}"); oSheet.Cells[counterForExcel, 1].Font.Bold = true; oSheet.Cells[counterForExcel, 1] = CalcFactor(endEvent.AbsoluteTime, tempoMap); oSheet.Cells[counterForExcel, 2] = "Ending"; break; } } //ourStream.Close(); File.WriteAllLines(@"output.txt", ourStream); //for excel int q = 2; foreach (KeyValuePair <int, string> pair in patchToChannel) { oSheet.Cells[1, q] = $"{pair.Key.ToString()}_({pair.Value})"; oSheet.Cells[1, q].Font.Bold = true; q++; } oBook.SaveAs(output); oBook.Close(); oApp.Quit(); }
public static MidiEvent ReadNextEvent(BinaryReader br, MidiEvent previous) { int num = MidiEvent.ReadVarInt(br); int num2 = 1; byte b = br.ReadByte(); MidiCommandCode midiCommandCode; if ((b & 128) == 0) { midiCommandCode = previous.CommandCode; num2 = previous.Channel; br.BaseStream.Position -= 1L; } else if ((b & 240) == 240) { midiCommandCode = (MidiCommandCode)b; } else { midiCommandCode = (MidiCommandCode)(b & 240); num2 = (int)((b & 15) + 1); } MidiCommandCode midiCommandCode2 = midiCommandCode; MidiEvent midiEvent; if (midiCommandCode2 <= MidiCommandCode.ControlChange) { if (midiCommandCode2 <= MidiCommandCode.NoteOn) { if (midiCommandCode2 != MidiCommandCode.NoteOff) { if (midiCommandCode2 != MidiCommandCode.NoteOn) { goto IL_15F; } midiEvent = new NoteOnEvent(br); goto IL_175; } } else if (midiCommandCode2 != MidiCommandCode.KeyAfterTouch) { if (midiCommandCode2 != MidiCommandCode.ControlChange) { goto IL_15F; } midiEvent = new ControlChangeEvent(br); goto IL_175; } midiEvent = new NoteEvent(br); goto IL_175; } if (midiCommandCode2 <= MidiCommandCode.ChannelAfterTouch) { if (midiCommandCode2 == MidiCommandCode.PatchChange) { midiEvent = new PatchChangeEvent(br); goto IL_175; } if (midiCommandCode2 == MidiCommandCode.ChannelAfterTouch) { midiEvent = new ChannelAfterTouchEvent(br); goto IL_175; } } else { if (midiCommandCode2 == MidiCommandCode.PitchWheelChange) { midiEvent = new PitchWheelChangeEvent(br); goto IL_175; } if (midiCommandCode2 == MidiCommandCode.Sysex) { midiEvent = SysexEvent.ReadSysexEvent(br); goto IL_175; } switch (midiCommandCode2) { case MidiCommandCode.TimingClock: case MidiCommandCode.StartSequence: case MidiCommandCode.ContinueSequence: case MidiCommandCode.StopSequence: midiEvent = new MidiEvent(); goto IL_175; case MidiCommandCode.MetaEvent: midiEvent = MetaEvent.ReadMetaEvent(br); goto IL_175; } } IL_15F: throw new FormatException(string.Format("Unsupported MIDI Command Code {0:X2}", (byte)midiCommandCode)); IL_175: midiEvent.channel = num2; midiEvent.deltaTime = num; midiEvent.commandCode = midiCommandCode; return(midiEvent); }
/// <summary> /// Creates a MidiEvent from a raw message received using /// the MME MIDI In APIs /// </summary> /// <param name="rawMessage">The short MIDI message</param> /// <returns>A new MIDI Event</returns> public static MidiEvent FromRawMessage(int rawMessage) { long absoluteTime = 0; int b = rawMessage & 0xFF; int data1 = (rawMessage >> 8) & 0xFF; int data2 = (rawMessage >> 16) & 0xFF; MidiCommandCode commandCode; int channel = 1; if ((b & 0xF0) == 0xF0) { // both bytes are used for command code in this case commandCode = (MidiCommandCode)b; } else { commandCode = (MidiCommandCode)(b & 0xF0); channel = (b & 0x0F) + 1; } MidiEvent me; switch (commandCode) { case MidiCommandCode.NoteOn: case MidiCommandCode.NoteOff: case MidiCommandCode.KeyAfterTouch: if (data2 > 0 && commandCode == MidiCommandCode.NoteOn) { me = new NoteOnEvent(absoluteTime, channel, data1, data2, 0); } else { me = new NoteEvent(absoluteTime, channel, commandCode, data1, data2); } break; //case MidiCommandCode.ControlChange: // me = new ControlChangeEvent(absoluteTime,channel,(MidiController)data1,data2); // break; case MidiCommandCode.PatchChange: me = new PatchChangeEvent(absoluteTime,channel,data1); break; case MidiCommandCode.ChannelAfterTouch: me = new ChannelAfterTouchEvent(absoluteTime,channel,data1); break; case MidiCommandCode.PitchWheelChange: me = new PitchWheelChangeEvent(absoluteTime, channel, data1 + (data2 << 7)); break; case MidiCommandCode.TimingClock: case MidiCommandCode.StartSequence: case MidiCommandCode.ContinueSequence: case MidiCommandCode.StopSequence: case MidiCommandCode.AutoSensing: me = new MidiEvent(absoluteTime,channel,commandCode); break; case MidiCommandCode.MetaEvent: case MidiCommandCode.Sysex: default: throw new FormatException(String.Format("Unsupported MIDI Command Code for Raw Message {0}", commandCode)); } return me; }
public bool Process(MidiEvent inEvent, EventRuleArgs args) { NoteOnEvent noteEvent = inEvent as NoteOnEvent; // filter note offs - they will be added by their note-on if (MidiEvent.IsNoteOff(inEvent)) { return false; } // if it is a note event, special processing if (noteEvent != null) { foreach (IEventRule rule in noteRules) { if (rule.Apply(inEvent, args)) return true; } // an unmatched note event // TODO: configure to have an option to retain these return false; } // now see if we need to exclude this event foreach (IEventRule rule in excludeRules) { if (rule.Apply(inEvent, args)) { return false; } } bool updatedEvent = false; foreach (IEventRule rule in eventRules) { updatedEvent |= rule.Apply(inEvent, args); } return true; // updatedEvent; }
/// <summary> /// Determines if this is an end track event /// </summary> public static bool IsEndTrack(MidiEvent midiEvent) { if (midiEvent != null) { MetaEvent me = midiEvent as MetaEvent; if (me != null) { return me.MetaEventType == MetaEventType.EndTrack; } } return false; }
private MidiFile(Stream inputStream, bool strictChecking, bool ownInputStream) { this.strictChecking = strictChecking; var br = new BinaryReader(inputStream); try { 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) { try { me = MidiEvent.ReadNextEvent(br, me); } catch (InvalidDataException) { if (strictChecking) { throw; } continue; } catch (FormatException) { if (strictChecking) { throw; } continue; } absoluteTime += me.DeltaTime; me.AbsoluteTime = absoluteTime; events[track].Add(me); if (me.CommandCode == MidiCommandCode.NoteOn) { var 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( $"End Track event was not the last MIDI event on track {track}"); } } } } } if (outstandingNoteOns.Count > 0) { if (strictChecking) { throw new FormatException( $"Note ons without note offs {outstandingNoteOns.Count} (file format {fileFormat})"); } } if (br.BaseStream.Position != startPos + chunkSize) { throw new FormatException($"Read too far {chunkSize}+{startPos}!={br.BaseStream.Position}"); } } } finally { if (ownInputStream) { br.Close(); } } }
/// <summary> /// Constructs a MidiEvent from a BinaryStream /// </summary> /// <param name="br">The binary stream of MIDI data</param> /// <param name="previous">The previous MIDI event (pass null for first event)</param> /// <returns>A new MidiEvent</returns> public static MidiEvent ReadNextEvent(BinaryReader br, MidiEvent previous) { int deltaTime = MidiEvent.ReadVarInt(br); MidiCommandCode commandCode; int channel = 1; byte b = br.ReadByte(); if((b & 0x80) == 0) { // a running command - command & channel are same as previous commandCode = previous.CommandCode; channel = previous.Channel; br.BaseStream.Position--; // need to push this back } else { if((b & 0xF0) == 0xF0) { // both bytes are used for command code in this case commandCode = (MidiCommandCode) b; } else { commandCode = (MidiCommandCode) (b & 0xF0); channel = (b & 0x0F) + 1; } } MidiEvent me; switch(commandCode) { case MidiCommandCode.NoteOn: me = new NoteOnEvent(br); break; case MidiCommandCode.NoteOff: case MidiCommandCode.KeyAfterTouch: me = new NoteEvent(br); break; //case MidiCommandCode.ControlChange: // me = new ControlChangeEvent(br); // break; case MidiCommandCode.PatchChange: me = new PatchChangeEvent(br); break; case MidiCommandCode.ChannelAfterTouch: me = new ChannelAfterTouchEvent(br); break; case MidiCommandCode.PitchWheelChange: me = new PitchWheelChangeEvent(br); break; case MidiCommandCode.TimingClock: case MidiCommandCode.StartSequence: case MidiCommandCode.ContinueSequence: case MidiCommandCode.StopSequence: me = new MidiEvent(); break; case MidiCommandCode.Sysex: me = SysexEvent.ReadSysexEvent(br); break; case MidiCommandCode.MetaEvent: try { me = MetaEvent.ReadMetaEvent(br); } catch(FormatException) { me = new MidiEvent(); } break; default: me = new MidiEvent(); break; //throw new FormatException(String.Format("Unsupported MIDI Command Code {0:X2}",(byte) commandCode)); } me.channel = channel; me.deltaTime = deltaTime; me.commandCode = commandCode; return me; }
public TriggerMessage(MidiEvent aEv, int aRaw) { stEvent = aEv.ToString(); stRawMessage = aRaw; }