protected void ActiveNote(int channel, int note, bool active) { if (note >= 128 || channel >= 16) { return; } if (active) { ActiveNotes[note] |= (ushort)(1 << channel); } else { ActiveNotes[note] &= (ushort)~(1 << channel); } // See if there are hanging notes that we can cancel foreach (var hangingNote in HangingNotes.Reverse()) { if (hangingNote.Channel == channel && hangingNote.Note != 0 && hangingNote.TimeLeft != 0) { hangingNote.TimeLeft = 0; --HangingNotesCount; break; } } }
protected void HangingNote(int channel, int note, int timeLeft, bool recycle = true) { NoteTimer best = null; if (HangingNotesCount >= HangingNotes.Length) { // Console.Error.WriteLine("MidiParser::hangingNote(): Exceeded polyphony"); return; } foreach (var hangingNote in HangingNotes.Reverse()) { if (hangingNote.Channel == channel && hangingNote.Note == note) { if (hangingNote.TimeLeft != 0 && hangingNote.TimeLeft < timeLeft && recycle) { return; } best = hangingNote; if (hangingNote.TimeLeft != 0) { if (recycle) { SendToDriver(0x80 | channel, note, 0); } --HangingNotesCount; } break; } else if (best == null && hangingNote.TimeLeft == 0) { best = hangingNote; } } // Occassionally we might get a zero or negative note // length, if the note should be turned on and off in // the same iteration. For now just set it to 1 and // we'll turn it off in the next cycle. if (timeLeft == 0 || ((timeLeft & 0x80000000) != 0)) { timeLeft = 1; } if (best != null) { best.Channel = channel; best.Note = note; best.TimeLeft = timeLeft; ++HangingNotesCount; } else { // We checked this up top. We should never get here! // Console.Error.WriteLine("MidiParser::hangingNote(): Internal error"); } }