public void NoteOn(byte idx) { _playedNotes[idx] = new PlayedNote() { Note = Notes[idx], }; if (_freeChannels.Count() == 0) { return; } var newChannel = _freeChannels.Dequeue(); _noteChannelMapping[idx] = newChannel; _channelNoteMapping[newChannel] = _playedNotes[idx]; }
//======Generate other data from known information=== private void AnalyzeMIDI() { long tempo = 500000; //Default tempo in case none is given //Create lists and arrays //-to put PlayedNotes in per track //-to store notes that have been pressed but not released //-To track what event we're checking, per track List<List<PlayedNote>> lists = new List<List<PlayedNote>>(); List<List<PlayedNote>> unfinishednotes = new List<List<PlayedNote>>(); for (int i = 0; i < tracks.Length; i++) { lists.Add(new List<PlayedNote>()); unfinishednotes.Add(new List<PlayedNote>()); } int[] currentevent = new int[lists.Count]; //Tracks the current event # per list long[] currenttime = new long[lists.Count]; for (int i = 0; i < lists.Count; i++) { currentevent[i] = 0; currenttime[i] = 0; } List<TempoChange> tempoChanges = new List<TempoChange>(); this.tempoChanges = new TempoChange[0]; //Start reading all the lists at the same time, in MIDI timing order bool reading = true; while (reading) { //Check which next MIDI event of all tracks has the lowest delta time long lowesttime = long.MaxValue; int lowestlist = -1; for (int i = 0; i < lists.Count; i++) { if (currentevent[i] < tracks[i].events.Length) //Ignore if at end of track { if (tracks[i].events[currentevent[i]].time + currenttime[i] < lowesttime) { lowestlist = i; lowesttime = tracks[i].events[currentevent[i]].time + currenttime[i]; } } } if (lowestlist == -1) { reading = false; } //All tracks at end of track else //You got the current event, parse it { long newtempo = tempo; Event ev = tracks[lowestlist].events[currentevent[lowestlist]]; if (ev.type == EventType.Midi) { ReanalyzeType: //Jumps here if case NoteOn realizes it's actually a NoteOff switch(ev.midiEvent.midiType) { case MidiType.NoteOn: //Note on event { if (ev.midiEvent.note.velocity == 0) { ev.midiEvent.midiType = MidiType.NoteOff; goto ReanalyzeType; //Return to start of switch to fall to NoteOff instead } PlayedNote pn = new PlayedNote(); pn.note = ev.midiEvent.note; pn.time = currenttime[lowestlist] + TicksToMicroSeconds(ev.time, tempo, currenttime[lowestlist]); unfinishednotes[lowestlist].Add(pn); break; } case MidiType.NoteOff: //Note off event { PlayedNote pn = new PlayedNote(); for (int i = 0; i < unfinishednotes[lowestlist].Count; i++) { if (unfinishednotes[lowestlist][i].note.number == ev.midiEvent.note.number) { pn = unfinishednotes[lowestlist][i]; } } unfinishednotes[lowestlist].Remove(pn); //TODO: Improve, causes 33% of CPU usage of entire LoadMIDI(), has to look for IndexOf() which causes slowdown pn.length = (currenttime[lowestlist] + TicksToMicroSeconds(ev.time, tempo, currenttime[lowestlist])) - pn.time; float division = pn.length / tempo; Msg("Division: " + division); if (division > 7.9 && division < 8.1) pn.lengthtype = LengthType.DoubleWhole; else if (division > 3.9 && division < 4.1) pn.lengthtype = LengthType.Whole; else if (division > 1.9 && division < 2.1) pn.lengthtype = LengthType.Half; else if (division > 0.9 && division < 1.1) pn.lengthtype = LengthType.Quarter; else if (division > 0.45 && division < 0.55) pn.lengthtype = LengthType.Eighth; else if (division > 0.20 && division < 0.30) pn.lengthtype = LengthType.Sixteenth; else if (division > 0.1125 && division < 0.1375) pn.lengthtype = LengthType.ThirtySecond; else if (division > 0.0620 && division < 0.0630) pn.lengthtype = LengthType.SixtyFourth; //Why hello there Beethoven! else if (division > 0.03120 && division < 0.03130) pn.lengthtype = LengthType.HundredTwentyEight; else pn.lengthtype = LengthType.Unknown; lists[lowestlist].Add(pn); break; } } } else if (ev.type == EventType.Meta) { switch (ev.metaType) { case MetaType.Tempo: TempoChange tc = new TempoChange(); tc.time = currenttime[lowestlist] + TicksToMicroSeconds(ev.time, tempo, currenttime[lowestlist]); tc.oldTempo = tempo; newtempo = ConvertThreeByteInt(ev.data); if (currenttime[lowestlist] == 0) this.tempo = newtempo; tc.newTempo = newtempo; tempoChanges.Add(tc); this.tempoChanges = tempoChanges.ToArray(); break; } } currenttime[lowestlist] += TicksToMicroSeconds(ev.time, tempo, currenttime[lowestlist]); tempo = newtempo; currentevent[lowestlist]++; } } for (int i = 0; i < tracks.Length; i++) { tracks[i].notes = lists[i].ToArray(); } this.tempoChanges = tempoChanges.ToArray(); }