public static void DiscretizeBends(Model midi) { var bendedNotes = midi.EventsOfType <NoteOn>(n => n.Bends != null && n.Bends.Count > 0).ToArray(); // divide note into not-bended ones foreach (var note in bendedNotes) { var tmpNote = note; var pitch = note.NoteNumber; var end = note.End; var bends = note.Bends.OrderBy(b => b.AbsoluteRealTime).ToArray(); note.Bends = new List <PitchBend>(); foreach (var bend in bends) { tmpNote.End = bend.AbsoluteRealTime; tmpNote.RealTimeLength = tmpNote.End - tmpNote.AbsoluteRealTime; var bendedPitch = (byte)(pitch + bend.RealPitchChange + 0.5); if (bendedPitch != tmpNote.NoteNumber) { tmpNote = new NoteOn { AbsoluteRealTime = bend.AbsoluteRealTime, AbsoluteTime = bend.AbsoluteTime, ChannelNumber = note.ChannelNumber, Instrument = note.Instrument, NoteNumber = bendedPitch, Volume = note.Volume, RealVolume = note.RealVolume, Bends = new List <PitchBend>() }; midi.Tracks[0].Channels[tmpNote.ChannelNumber].Events.Add(tmpNote); } } tmpNote.End = end; tmpNote.RealTimeLength = tmpNote.End - tmpNote.AbsoluteRealTime; } // delete all pitch bends var channels = midi.Tracks.SelectMany(t => t.Channels); foreach (var channel in channels) { channel.Events.RemoveAll(e => e is PitchBend); } }
double ControllerValueDuringNote(IEnumerable <Controller>[] changes, NoteOn note, double defaultValue = 96) { var during = changes[note.ChannelNumber] .Where(ch => ch.AbsoluteRealTime < note.AbsoluteRealTime + note.RealTimeLength) .Where(ch => ch.AbsoluteRealTime >= note.AbsoluteRealTime); if (during.Any()) { return(during.Average(d => d.ControllerValue)); } var before = changes[note.ChannelNumber].Where(ch => ch.AbsoluteRealTime <= note.AbsoluteRealTime); if (before.Any()) { // select max according to AbsoluteRealTIme return(before.Aggregate((prev, act) => prev.AbsoluteRealTime < act.AbsoluteRealTime ? act : prev).ControllerValue); } return(defaultValue); }