private void Send(MidiEvent m) { var size = MidiEvent.FixedDataSize(m.StatusByte); buffer[0] = m.StatusByte; buffer[1] = m.Msb; buffer[2] = m.Lsb; _device.Send(buffer, 0, size + 1, 0); }
public void GetFixedSize() { Assert.AreEqual(2, MidiEvent.FixedDataSize(0x90), "NoteOn"); Assert.AreEqual(1, MidiEvent.FixedDataSize(0xC0), "ProgramChange"); Assert.AreEqual(1, MidiEvent.FixedDataSize(0xD0), "CAf"); Assert.AreEqual(2, MidiEvent.FixedDataSize(0xA0), "PAf"); Assert.AreEqual(0, MidiEvent.FixedDataSize(0xF0), "SysEx"); Assert.AreEqual(2, MidiEvent.FixedDataSize(0xF2), "SongPositionPointer"); Assert.AreEqual(1, MidiEvent.FixedDataSize(0xF3), "SongSelect"); Assert.AreEqual(0, MidiEvent.FixedDataSize(0xF8), "MidiClock"); Assert.AreEqual(0, MidiEvent.FixedDataSize(0xFF), "META"); }
private void HandleMidiData(IntPtr dwParam1, IntPtr dwParam2) { if (MidiEventReceived == null) { return; } byte status = (byte)((uint)dwParam1 & 0xFF); byte msb = (byte)(((uint)dwParam1 & 0xFF00) >> 8); byte lsb = (byte)(((uint)dwParam1 & 0xFF0000) >> 16); byte size = MidiEvent.FixedDataSize(status); MidiEventReceived?.Invoke(this, new MidiEventReceivedEventArgs(new MidiEvent(status, msb, lsb, (long)dwParam2))); }
void HandleData(IntPtr param1, IntPtr param2) { var status = (byte)((int)param1 & 0xFF); var msb = (byte)(((int)param1 & 0xFF00) >> 8); var lsb = (byte)(((int)param1 & 0xFF0000) >> 16); var data = MidiEvent.FixedDataSize(status) == 2 ? data3b : data2b; data[0] = status; data[1] = msb; if (data.Length == 3) { data[2] = lsb; } MessageReceived(this, new MidiReceivedEventArgs() { Data = data, Start = 0, Length = data.Length, Timestamp = (long)param2 }); }
// How does it dispatch SYSEX mesasges... void HandleMidiInProc(IntPtr midiIn, uint msg, ref int instance, ref int param1, ref int param2) { if (MessageReceived != null) { var status = (byte)(param1 & 0xFF); var msb = (byte)((param1 & 0xFF00) >> 8); var lsb = (byte)((param1 & 0xFF0000) >> 16); var data = MidiEvent.FixedDataSize(status) == 3 ? data3b : data2b; data[0] = status; data[1] = msb; if (data.Length == 3) { data[2] = lsb; } MessageReceived(this, new MidiReceivedEventArgs() { Data = data, Timestamp = 0 }); } }
/// <remarks> /// This function is not intended to provide complete correctness of MIDI parsing. /// For now the goal is to correctly parse "note start" and "note end" events and correctly delimit all events. /// </remarks> private void readEvent(byte[] data, string senderId, ref int i, out byte eventType, out byte key, out byte velocity) { byte statusType = data[i++]; // continuation messages: // need running status to be interpreted correctly if (statusType <= 0x7F) { if (!runningStatus.ContainsKey(senderId)) { throw new InvalidDataException($"Received running status of sender {senderId}, but no event type was stored"); } eventType = runningStatus[senderId]; key = statusType; velocity = data[i++]; return; } // real-time messages: // 0 additional data bytes always, do not reset running status if (statusType >= 0xF8) { eventType = statusType; key = velocity = 0; return; } // system common messages: // variable number of additional data bytes, reset running status if (statusType >= 0xF0) { eventType = statusType; // system exclusive message // vendor-specific, terminated by 0xF7 // ignoring their whole contents for now since we can't do anything with them anyway if (statusType == 0xF0) { while (data[i - 1] != 0xF7) { i++; } key = velocity = 0; } // other common system messages // fixed size given by MidiEvent.FixedDataSize else { key = MidiEvent.FixedDataSize(statusType) >= 1 ? data[i++] : (byte)0; velocity = MidiEvent.FixedDataSize(statusType) == 2 ? data[i++] : (byte)0; } runningStatus.Remove(senderId); return; } // channel messages // fixed size (varying per event type), set running status eventType = statusType; key = MidiEvent.FixedDataSize(statusType) >= 1 ? data[i++] : (byte)0; velocity = MidiEvent.FixedDataSize(statusType) == 2 ? data[i++] : (byte)0; runningStatus[senderId] = eventType; }
IEnumerable <IMidiMessage> Convert(byte[] mevent, int offset, int length, long timestamp) { int end = offset + length; for (int i = offset; i < end;) { switch (mevent[i] & 0xF0) { case MidiEvent.NoteOn: if (i + 3 < end) { yield return(new MidiNoteOnMessage((byte)(mevent[i] & 0x7F), mevent[i + 1], mevent[i + 2])); } break; case MidiEvent.NoteOff: if (i + 3 < end) { yield return(new MidiNoteOffMessage((byte)(mevent[i] & 0x7F), mevent[i + 1], mevent[i + 2])); } break; case MidiEvent.PAf: if (i + 3 < end) { yield return(new MidiPolyphonicKeyPressureMessage((byte)(mevent[i] & 0x7F), mevent[i + 1], mevent[i + 2])); } break; case MidiEvent.CC: if (i + 3 < end) { yield return(new MidiControlChangeMessage((byte)(mevent[i] & 0x7F), mevent[i + 1], mevent[i + 2])); } break; case MidiEvent.Program: if (i + 2 < end) { yield return(new MidiProgramChangeMessage((byte)(mevent[i] & 0x7F), mevent[i + 1])); } break; case MidiEvent.CAf: if (i + 2 < end) { yield return(new MidiChannelPressureMessage((byte)(mevent[i] & 0x7F), mevent[i + 1])); } break; case MidiEvent.Pitch: if (i + 3 < end) { yield return(new MidiPitchBendChangeMessage((byte)(mevent[i] & 0x7F), (ushort)((mevent[i + 1] << 13) + mevent[i + 2]))); } break; case MidiEvent.SysEx1: int pos = Array.IndexOf(mevent, MidiEvent.EndSysEx, i, length - i); if (pos >= 0) { yield return(new MidiSystemExclusiveMessage(new Buffer(mevent, i, pos - i))); } break; default: throw new NotSupportedException( $"MIDI message byte '{mevent[i].ToString("X02")}' is not supported."); } if (mevent[i] != MidiEvent.SysEx1) { i += MidiEvent.FixedDataSize(mevent[i]); } } }
public override void Send(byte[] mevent, int offset, int length, long timestamp) { int end = offset + length; for (int i = offset; i < end;) { switch (mevent[i] & 0xF0) { case MidiEvent.ActiveSense: break; case MidiEvent.NoteOn: if (i + 2 < end) { _sampler.StartNote(mevent[i + 1], mevent[i + 2], (byte)(mevent[i] & 0x0f)); } break; case MidiEvent.NoteOff: if (i + 2 < end) { _sampler.StopNote(mevent[i + 1], (byte)(mevent[i] & 0x0f)); } break; case MidiEvent.PAf: if (i + 2 < end) { _sampler.SendPressureForKey(mevent[i + 1], mevent[i + 2], (byte)(mevent[i] & 0x0f)); } break; case MidiEvent.CC: if (i + 2 < end) { _sampler.SendController(mevent[i + 1], mevent[i + 2], (byte)(mevent[i] & 0x0f)); } break; case MidiEvent.Program: if (i + 2 < end) { _sampler.SendProgramChange(mevent[i + 1], (byte)(mevent[i] & 0x0f)); } break; case MidiEvent.CAf: if (i + 2 < end) { _sampler.SendPressure(mevent[i + 1], (byte)(mevent[i] & 0x0f)); } break; case MidiEvent.Pitch: if (i + 2 < end) { _sampler.SendPitchBend((ushort)((mevent[i + 1] << 13) + mevent[i + 2]), (byte)(mevent[i] & 0x0f)); } break; case MidiEvent.SysEx1: int pos = Array.IndexOf(mevent, MidiEvent.EndSysEx, i, length - i); if (pos >= 0) { pos++; byte[] message = new byte[pos - i]; Array.Copy(mevent, i, message, 0, pos - i); _sampler.SendMidiSysExEvent(NSData.FromArray(message)); i = pos; } break; default: throw new NotSupportedException($"MIDI message byte '{mevent[i].ToString("X02")}' is not supported."); } if (mevent[i] != MidiEvent.SysEx1) { i += MidiEvent.FixedDataSize(mevent[i]) + 1; } } }