public void OnReceiveMessage(MidiMessage message) { switch (message.messageType) { case MidiMessageType.NoteOn: OnNoteOn(message.midiNote, message.velocity); OnNoteOnEvent.Invoke(message.midiNote, message.velocity); break; case MidiMessageType.NoteOff: OnNoteOff(message.midiNote, message.velocity); OnNoteOffEvent.Invoke(message.midiNote, message.velocity); break; case MidiMessageType.NoteAftertouch: OnNoteAftertouch(message.midiNote, message.velocity); OnNoteAftertouchEvent.Invoke(message.midiNote, message.velocity); break; } }
void NoteOn(MidiChannel channel, int note, float velocity) { if (!FilterNote(channel, note)) { return; } velocity = Mathf.Lerp(_velocityOffset, 1.0f, velocity); if (_eventType == EventType.Trigger) { _triggerEvent.Invoke(velocity); } else if (_eventType == EventType.Gate) { if (_voiceMode == VoiceMode.Mono && _lastNote != -1 && _lastNote != note) { _noteOffEvent.Invoke(_lastNote); } _noteOnEvent.Invoke(note, velocity); _lastNote = note; } else if (_eventType == EventType.Toggle) { _toggle ^= true; if (_toggle) { _toggleOnEvent.Invoke(); } else { _toggleOffEvent.Invoke(); } } else // EventType.Value { _value.targetValue = _onValue * velocity; } }
/// <summary> /// A MIDI command plus its MIDI data parameters to be called a MIDI message . The minimum size of a MIDI message is 1 byte (one command byte and no parameter bytes). The maximum size of a MIDI message (note considering 0xF0 commands) is three bytes. A MIDI message always starts with a command byte. /// /// Information for MIDI: https://ccrma.stanford.edu/~craig/articles/linuxmidi/misc/essenmidi.html /// The MIDI file format: https://www.csie.ntu.edu.tw/~r92092/ref/midi/ /// /// MIDI commands /// 0x80 Note Off /// 0x90 Note On /// 0xA0 Aftertouch /// 0xB0 Continuous controller /// 0xC0 Patch change /// 0xD0 Channel Pressure /// 0xE0 Pitch bend /// 0xF0 (non-musical commands) /// </summary> /// <param name="events"></param> // Dispatch incoming MIDI events. void DispatchEvents(List <MidiEvent> events) { if (events != null) { List <byte> noteOns = new List <byte>(); foreach (var e in events) { // Midi bytes from 10000000 to 11111111 are command bytes. SmfLite stores them in the status variable // Command bytes are split as well into two parts, The most significant half contains the actual MIDI command, and the second half contains the MIDI channel for which the command is for // If you AND a byte with 0xf0 (11110000), you get just the first half of the message, so here we are getting the actual MIDI command from our status byte // x90 for signifies a Note On message. // // If note On if ((e.status & 0xf0) == 0x90) { // Debug.Log(e.data1); noteOns.Add(e.data1); if (e.data1 == 0x3C) { // Kick.Play(); } if (e.data1 == 0x3E) { // Snare.Play(); } if (e.data1 == 0x40) { // Hat.Play(); } } } m_noteOnEvent.Invoke(noteOns); } }
void DispatchEvents(List <MidiEvent> events) { if (events == null) { return; } foreach (MidiEvent e in events) { int channelIndex; MidiEvent.Type type; e.UnpackStatus(out type, out channelIndex); switch (type) { case MidiEvent.Type.NoteOff: _onMemo[channelIndex, e.data1] = false; _onNoteOffEvent.Invoke(channelIndex, e.data1); break; case MidiEvent.Type.NoteOn: _onMemo[channelIndex, e.data1] = true; _onNoteOnEvent.Invoke(channelIndex, e.data1, e.data2); break; case MidiEvent.Type.Aftertouch: _onAftertouchEvent.Invoke(channelIndex, e.data1, e.data2); break; case MidiEvent.Type.ControlChange: _onControlChangeEvent.Invoke(channelIndex, e.data1, e.data2); break; case MidiEvent.Type.ProgramChange: _onProgramChangeEvent.Invoke(channelIndex, e.data1); break; case MidiEvent.Type.ChannelPressure: _onChannelPressureEvent.Invoke(channelIndex, e.data1); break; case MidiEvent.Type.PitchBend: break; // TODO } } }