void _MidiInProc(IntPtr handle, int msg, int instance, int lparam, int wparam) { switch (msg) { case MIM_OPEN: Opened?.Invoke(this, EventArgs.Empty); break; case MIM_CLOSE: Closed?.Invoke(this, EventArgs.Empty); break; case MIM_DATA: MidiMessage m; if (0 != _tempoSynchEnabled && 0xF8 == (0xFF & lparam)) { if (0 != _timingTimestamp) { var dif = (_PreciseUtcNowTicks - _timingTimestamp) * 24; var tpm = TimeSpan.TicksPerMillisecond * 60000; var newTempo = (tpm / (double)dif); if (newTempo < _tempoSynchMininumTempo) { Interlocked.Exchange(ref _timingTimestamp, 0); } else { var timeNow = _PreciseUtcNowTicks; if (0L == _tempoSyncTimestamp || 0L == _tempoSyncFrequency || (timeNow - _tempoSyncTimestamp > _tempoSyncFrequency)) { var tmp = Tempo; var ta = (tmp + newTempo) / 2; Tempo = ta; } Interlocked.Exchange(ref _timingTimestamp, timeNow); } } else { var timeNow = _PreciseUtcNowTicks; Interlocked.Exchange(ref _timingTimestamp, timeNow); } } else { m = MidiUtility.UnpackMessage(lparam); _ProcessRecording(m); Input?.Invoke(this, new MidiInputEventArgs(new TimeSpan(0, 0, 0, 0, wparam), m)); } break; case MIM_ERROR: Error?.Invoke(this, new MidiInputEventArgs(new TimeSpan(0, 0, 0, 0, wparam), MidiUtility.UnpackMessage(lparam))); break; case MIM_LONGDATA: case MIM_LONGERROR: // TODO: Semi tested var hdr = (MIDIHDR)Marshal.PtrToStructure(new IntPtr(lparam), typeof(MIDIHDR)); if (0 == hdr.dwBytesRecorded) { return; // no message } // this code assumes it's a sysex message but I should probably check it. var status = Marshal.ReadByte(hdr.lpData, 0); var payload = new byte[hdr.dwBytesRecorded - 1]; Marshal.Copy(new IntPtr((int)hdr.lpData + 1), payload, 0, payload.Length); m = new MidiMessageSysex(payload); var sz = Marshal.SizeOf(typeof(MIDIHDR)); _inHeader.dwBufferLength = _inHeader.dwBytesRecorded = 65536u; _inHeader.lpData = _buffer; _CheckInResult(midiInPrepareHeader(_handle, ref _inHeader, sz)); _CheckInResult(midiInAddBuffer(_handle, ref _inHeader, sz)); _ProcessRecording(m); if (MIM_LONGDATA == msg) { Input?.Invoke(this, new MidiInputEventArgs(new TimeSpan(0, 0, 0, 0, wparam), m)); } else { Error?.Invoke(this, new MidiInputEventArgs(new TimeSpan(0, 0, 0, 0, wparam), m)); } break; case MIM_MOREDATA: break; default: break; } }
internal static MidiSequence ReadFrom(Stream stream) { MidiSequence result = new MidiSequence(); var rs = (byte)0; var delta = _ReadVarlen(stream); if (BitConverter.IsLittleEndian) { delta = _Swap(delta); } var i = stream.ReadByte(); while (-1 != i) { var hasStatus = false; var b = (byte)i; if (0x7F < b) { hasStatus = true; rs = b; i = stream.ReadByte(); if (-1 != i) { b = (byte)i; } else { b = 0; } } var st = hasStatus ? rs : (byte)0; var m = (MidiMessage)null; switch (rs & 0xF0) { case 0x80: if (i == -1) { throw new EndOfStreamException(); } m = new MidiMessageNoteOff(b, (byte)stream.ReadByte(), unchecked ((byte)(st & 0x0F))); break; case 0x90: if (i == -1) { throw new EndOfStreamException(); } m = new MidiMessageNoteOn(b, (byte)stream.ReadByte(), unchecked ((byte)(st & 0x0F))); break; case 0xA0: if (i == -1) { throw new EndOfStreamException(); } m = new MidiMessageKeyPressure(b, (byte)stream.ReadByte(), unchecked ((byte)(st & 0x0F))); break; case 0xB0: if (i == -1) { throw new EndOfStreamException(); } m = new MidiMessageCC(b, (byte)stream.ReadByte(), unchecked ((byte)(st & 0x0F))); break; case 0xC0: if (i == -1) { throw new EndOfStreamException(); } m = new MidiMessagePatchChange(b, unchecked ((byte)(st & 0x0F))); break; case 0xD0: if (i == -1) { throw new EndOfStreamException(); } m = new MidiMessageChannelPressure(b, unchecked ((byte)(st & 0x0F))); break; case 0xE0: if (i == -1) { throw new EndOfStreamException(); } m = new MidiMessageChannelPitch(b, (byte)stream.ReadByte(), unchecked ((byte)(st & 0x0F))); break; case 0xF0: switch (rs & 0xF) { case 0xF: if (i == -1) { throw new EndOfStreamException(); } var l = _ReadVarlen(stream); //if (BitConverter.IsLittleEndian) // l = _Swap(l); var ba = new byte[l]; if (l != stream.Read(ba, 0, ba.Length)) { throw new EndOfStreamException(); } m = new MidiMessageMeta(st, b, ba); break; case 0x0: case 0x7: if (i == -1) { throw new EndOfStreamException(); } l = _ReadVarlen(b, stream); //if (BitConverter.IsLittleEndian) // l = _Swap(l); ba = new byte[l]; if (l != stream.Read(ba, 0, ba.Length)) { throw new EndOfStreamException(); } m = new MidiMessageSysex(st, ba); break; case 0x2: if (i == -1) { throw new EndOfStreamException(); } m = new MidiMessageWord(st, b, (byte)stream.ReadByte()); break; case 0x3: if (i == -1) { throw new EndOfStreamException(); } m = new MidiMessageByte(st, b); break; case 0x6: case 0x8: case 0xA: case 0xB: case 0xC: // status *was* specified if we got here m = new MidiMessage(st); break; default: throw new NotSupportedException("The MIDI message is not recognized."); } break; } result.Events.Add(new MidiEvent(delta, m)); i = _ReadVarlen(stream); if (-1 == i) { break; } delta = i; i = stream.ReadByte(); } return(result); }