// util functions private static bool TrackIsOmitable(MidiTrack tr) { foreach (MidiEvent ev in tr.midiEvents) { if (ev is MetaMidiEvent) { MetaMidiEvent mev = ev as MetaMidiEvent; if (mev.getMetaType() == MetaType.TempoSetting) { return(false); } else if (mev.getMetaType() == MetaType.TimeSignature) { return(false); } else if (mev.getMetaType() == MetaType.MarkerText) { return(false); } } else if (ev is MessageMidiEvent) { MessageMidiEvent mev = ev as MessageMidiEvent; if (mev.type == NormalType.NoteON) { return(false); } if (mev.type == NormalType.NoteOFF) { return(false); } } } return(true); }
public static void Trim(MidiFile midi) { /****************** * removes empty tracks and redundant controller/voice events */ midi.midiTracks.RemoveAll(TrackIsOmitable); foreach (MidiTrack tr in midi.midiTracks) { // int array for storing the last set values of the controller values int[] controllerValues = new int[128]; for (int i = 0; i < controllerValues.Length; i++) { controllerValues[i] = -1; } int lastVoice = -1; int lastPitchBendA = -1; int lastPitchBendB = -1; int lastTempo = -1; for (int i = 0; i < tr.midiEvents.Count;) { if (tr.midiEvents[i] is MessageMidiEvent) { MessageMidiEvent mev = tr.midiEvents[i] as MessageMidiEvent; if (mev.type == NormalType.Program) { if (mev.parameter1 == lastVoice) { tr.midiEvents.RemoveAt(i); continue; } lastVoice = mev.parameter1; } else if (mev.type == NormalType.PitchBend) { if (mev.parameter1 == lastPitchBendA && mev.parameter2 == lastPitchBendB) { tr.midiEvents.RemoveAt(i); continue; } lastPitchBendA = mev.parameter1; lastPitchBendB = mev.parameter2; } else if (mev.type == NormalType.Controller) { if (controllerValues[mev.parameter1] == mev.parameter2) { tr.midiEvents.RemoveAt(i); continue; } controllerValues[mev.parameter1] = mev.parameter2; } } else if (tr.midiEvents[i] is MetaMidiEvent) { MetaMidiEvent mev = tr.midiEvents[i] as MetaMidiEvent; if (mev.getMetaType() == MetaType.TempoSetting) { byte[] tempoBytes = mev.getEventData(); Debug.Assert(tempoBytes.Length == 6); int us = (tempoBytes[3] << 16) | (tempoBytes[4] << 8) | tempoBytes[5]; if (lastTempo == us) { tr.midiEvents.RemoveAt(i); continue; } lastTempo = us; } } // only count up if the current event didn't get deleted i++; } } }
public static void InstrMap(MidiFile midi, string mapping) { /****************** * maps instruments and drums using a map */ byte[] instrMap = new byte[128]; for (int i = 0; i < instrMap.Length; i++) { instrMap[i] = (byte)i; } sbyte[] transposeMap = new sbyte[128]; byte[] drumMap = new byte[128]; for (int i = 0; i < drumMap.Length; i++) { drumMap[i] = (byte)i; } bool[] isDrum = new bool[128]; // parse mapping string // // format: // drum=127,imap=53:70,imap=30:25,dmap=40:50,trans=50:-12 string[] cfg = mapping.Split(','); for (int i = 0; i < cfg.Length; i++) { string[] parts = cfg[i].Split('='); if (parts.Length != 2) { throw new Exception("Invalid mapping option: " + String.Join("=", parts)); } switch (parts[0]) { case "drum": { int drum = Convert.ToInt32(parts[1]); if (drum < 0 || drum > 127) { throw new Exception("drum instrument number out of range: " + drum.ToString()); } isDrum[drum] = true; } break; case "imap": { string[] fromTo = parts[1].Split(':'); if (fromTo.Length != 2) { throw new Exception("Invalid instrument map: " + String.Join(":", fromTo)); } int from = Convert.ToInt32(fromTo[0]); if (from < 0 || from > 127) { throw new Exception("instrument 'from' out of range: " + from.ToString()); } int to = Convert.ToInt32(fromTo[1]); if (to < 0 || to > 127) { throw new Exception("instrument 'to' out of range: " + to.ToString()); } instrMap[from] = (byte)to; } break; case "dmap": { string[] fromTo = parts[1].Split(':'); if (fromTo.Length != 2) { throw new Exception("Invalid drum map: " + String.Join(":", fromTo)); } int from = Convert.ToInt32(fromTo[0]); if (from < 0 || from > 127) { throw new Exception("drum 'from' out of range: " + from.ToString()); } int to = Convert.ToInt32(fromTo[1]); if (to < 0 || to > 127) { throw new Exception("drum 'to' out of range: " + to.ToString()); } drumMap[from] = (byte)to; } break; case "trans": { string[] trans = parts[1].Split(':'); if (trans.Length != 2) { throw new Exception("Invalid Transpose: " + String.Join(":", trans)); } int instr = Convert.ToInt32(trans[0]); if (instr < 0 || instr > 127) { throw new Exception("Transpose instrument out of range: " + instr.ToString()); } int shift = Convert.ToInt32(trans[1]); if (shift < -128 || shift > 127) { throw new Exception("Transpose shift out of range: " + shift.ToString()); } transposeMap[instr] = (sbyte)shift; } break; default: throw new Exception("Invalid mapping type: " + parts[0]); } } // update events foreach (MidiTrack trk in midi.midiTracks) { int curProg = -1; foreach (MidiEvent ev in trk.midiEvents) { if (ev is MessageMidiEvent) { MessageMidiEvent mev = ev as MessageMidiEvent; if (mev.type == NormalType.Program) { curProg = mev.parameter1; mev.parameter1 = instrMap[mev.parameter1]; } else if (mev.type == NormalType.NoteON || mev.type == NormalType.NoteOFF) { if (curProg != 0) { if (isDrum[curProg]) { mev.parameter1 = drumMap[mev.parameter1]; } else { mev.parameter1 = (byte)(mev.parameter1 + transposeMap[curProg]); } } } } } } }
public static void FullMaximize(MidiFile midi) { /****************** * maximizes expression to peak level */ // get expression multipliers int[] expPeak = new int[midi.midiTracks.Count]; int[] volPeak = new int[midi.midiTracks.Count]; int[] velPeak = new int[midi.midiTracks.Count]; for (int i = 0; i < midi.midiTracks.Count; i++) { expPeak[i] = -1; volPeak[i] = -1; velPeak[i] = -1; } int itrk = 0; foreach (MidiTrack trk in midi.midiTracks) { foreach (MidiEvent ev in trk.midiEvents) { if (ev is MessageMidiEvent) { MessageMidiEvent mev = ev as MessageMidiEvent; if (mev.type == NormalType.Controller && mev.parameter1 == 11 && mev.parameter2 > 0) { expPeak[itrk] = Math.Max(expPeak[itrk], mev.parameter2); } else if (mev.type == NormalType.Controller && mev.parameter1 == 7 && mev.parameter2 > 0) { volPeak[itrk] = Math.Max(volPeak[itrk], mev.parameter2); } else if (mev.type == NormalType.NoteON && mev.parameter2 > 0) { velPeak[itrk] = Math.Max(velPeak[itrk], mev.parameter2); } } } itrk++; } // update levels itrk = 0; foreach (MidiTrack trk in midi.midiTracks) { foreach (MidiEvent ev in trk.midiEvents) { if (ev is MessageMidiEvent) { MessageMidiEvent mev = ev as MessageMidiEvent; if (mev.type == NormalType.Controller && mev.parameter1 == 11) { double newval = 127.0 / expPeak[itrk] * mev.parameter2; newval = Math.Round(newval, MidpointRounding.AwayFromZero); newval = Math.Min(127.0, newval); newval = Math.Max(0.0, newval); mev.parameter2 = (byte)newval; } else if (mev.type == NormalType.Controller && mev.parameter1 == 7) { double newval = 127.0 / volPeak[itrk] * mev.parameter2; newval = Math.Round(newval, MidpointRounding.AwayFromZero); newval = Math.Min(127.0, newval); newval = Math.Max(0.0, newval); mev.parameter2 = (byte)newval; } else if (mev.type == NormalType.NoteON && mev.parameter2 > 0) { double newval = 127.0 / velPeak[itrk] * mev.parameter2; newval = Math.Round(newval, MidpointRounding.AwayFromZero); newval = Math.Min(127.0, newval); newval = Math.Max(0.0, newval); mev.parameter2 = (byte)newval; } } } itrk++; } }
public static void Maximize(MidiFile midi) { /****************** * maximizes expression to peak level */ // get expression multipliers int expPeak = -1; int volPeak = -1; int velPeak = -1; foreach (MidiTrack trk in midi.midiTracks) { foreach (MidiEvent ev in trk.midiEvents) { if (ev is MessageMidiEvent) { MessageMidiEvent mev = ev as MessageMidiEvent; if (mev.type == NormalType.Controller && mev.parameter1 == 11 && mev.parameter2 > 0) { expPeak = Math.Max(expPeak, mev.parameter2); } else if (mev.type == NormalType.Controller && mev.parameter1 == 7 && mev.parameter2 > 0) { volPeak = Math.Max(volPeak, mev.parameter2); } else if (mev.type == NormalType.NoteON && mev.parameter2 > 0) { velPeak = Math.Max(velPeak, mev.parameter2); } } } } // update levels foreach (MidiTrack trk in midi.midiTracks) { foreach (MidiEvent ev in trk.midiEvents) { if (ev is MessageMidiEvent) { MessageMidiEvent mev = ev as MessageMidiEvent; if (mev.type == NormalType.Controller && mev.parameter1 == 11) { double newval = 127.0 / expPeak * mev.parameter2; newval = Math.Round(newval, MidpointRounding.AwayFromZero); newval = Math.Min(127.0, newval); newval = Math.Max(0.0, newval); mev.parameter2 = (byte)newval; } else if (mev.type == NormalType.Controller && mev.parameter1 == 7) { double newval = 127.0 / volPeak * mev.parameter2; newval = Math.Round(newval, MidpointRounding.AwayFromZero); newval = Math.Min(127.0, newval); newval = Math.Max(0.0, newval); mev.parameter2 = (byte)newval; } else if (mev.type == NormalType.NoteON && mev.parameter2 > 0) { double newval = 127.0 / velPeak * mev.parameter2; newval = Math.Round(newval, MidpointRounding.AwayFromZero); newval = Math.Min(127.0, newval); newval = Math.Max(0.0, newval); mev.parameter2 = (byte)newval; } } } } }