/// <summary> /// Sends a Program Change message to this MIDI output device. /// </summary> /// <param name="channel">The channel.</param> /// <param name="instrument">The instrument.</param> /// <exception cref="ArgumentOutOfRangeException">channel or instrument is out-of-range. /// </exception> /// <exception cref="InvalidOperationException">The device is not open.</exception> /// <exception cref="DeviceException">The message cannot be sent.</exception> /// <remarks> /// A Program Change message is used to switch among instrument settings, generally /// instrument voices. An instrument conforming to General Midi 1 will have the /// instruments described in the <see cref="Instrument"/> enum; other instruments /// may have different instrument sets. /// </remarks> public void SendProgramChange(Channel channel, Instrument instrument) { lock (this) { CheckOpen(); CheckReturnCode(Win32API.midiOutShortMsg(handle, ShortMsg.EncodeProgramChange( channel, instrument))); } }
/// <summary> /// Sends a Control Change message to this MIDI output device. /// </summary> /// <param name="channel">The channel.</param> /// <param name="control">The control.</param> /// <param name="value">The new value 0..127.</param> /// <exception cref="ArgumentOutOfRangeException">channel, control, or value is /// out-of-range.</exception> /// <exception cref="InvalidOperationException">The device is not open.</exception> /// <exception cref="DeviceException">The message cannot be sent.</exception> public void SendControlChange(Channel channel, Control control, int value) { lock (this) { CheckOpen(); CheckReturnCode(Win32API.midiOutShortMsg(handle, ShortMsg.EncodeControlChange( channel, control, value))); } }
/// <summary> /// Sends a Pitch Bend message to this MIDI output device. /// </summary> /// <param name="channel">The channel.</param> /// <param name="value">The pitch bend value, 0..16383, 8192 is centered.</param> /// <exception cref="ArgumentOutOfRangeException">channel or value is out-of-range. /// </exception> /// <exception cref="InvalidOperationException">The device is not open.</exception> /// <exception cref="DeviceException">The message cannot be sent.</exception> public void SendPitchBend(Channel channel, int value) { lock (this) { CheckOpen(); CheckReturnCode(Win32API.midiOutShortMsg(handle, ShortMsg.EncodePitchBend(channel, value))); } }
/// <summary> /// Sends a Note Off message to this MIDI output device. /// </summary> /// <param name="channel">The channel.</param> /// <param name="pitch">The pitch.</param> /// <param name="velocity">The velocity 0..127.</param> /// <exception cref="ArgumentOutOfRangeException">channel, note, or velocity is /// out-of-range.</exception> /// <exception cref="InvalidOperationException">The device is not open.</exception> /// <exception cref="DeviceException">The message cannot be sent.</exception> public void SendNoteOff(Channel channel, Pitch pitch, int velocity) { lock (this) { CheckOpen(); CheckReturnCode(Win32API.midiOutShortMsg(handle, ShortMsg.EncodeNoteOff(channel, pitch, velocity))); } }
/// <summary> /// Sends a Note On message to this MIDI output device. /// </summary> /// <param name="channel">The channel.</param> /// <param name="note">The note.</param> /// <param name="velocity">The velocity 0..127.</param> /// <exception cref="ArgumentOutOfRangeException">channel, note, or velocity is /// out-of-range.</exception> /// <exception cref="InvalidOperationException">The device is not open.</exception> /// <exception cref="DeviceException">The message cannot be sent.</exception> public void SendNoteOn(Channel channel, Note note, int velocity) { lock (this) { CheckOpen(); CheckReturnCode(Win32API.midiOutShortMsg(handle, ShortMsg.EncodeNoteOn(channel, note, velocity))); } }
/// <summary> /// Sends a Note On message to Channel10 of this MIDI output device. /// </summary> /// <param name="percussion">The percussion.</param> /// <param name="velocity">The velocity 0..127.</param> /// <remarks>This is simply shorthand for a Note On message on Channel10 with a /// percussion-specific note, so there is no corresponding message to receive from an input /// device.</remarks> /// <exception cref="ArgumentOutOfRangeException">percussion or velocity is out-of-range. /// </exception> /// <exception cref="InvalidOperationException">The device is not open.</exception> /// <exception cref="DeviceException">The message cannot be sent.</exception> public void SendPercussion(Percussion percussion, int velocity) { lock (this) { CheckOpen(); CheckReturnCode(Win32API.midiOutShortMsg(handle, ShortMsg.EncodeNoteOn( Channel.Channel10, (Pitch)percussion, velocity))); } }
/// <summary> /// The input callback for midiOutOpen. /// </summary> private void InputCallback(Win32API.HMIDIIN hMidiIn, Win32API.MidiInMessage wMsg, UIntPtr dwInstance, UIntPtr dwParam1, UIntPtr dwParam2) { isInsideInputHandler = true; try { if (wMsg == Win32API.MidiInMessage.MIM_DATA) { Channel channel; Pitch pitch; int velocity; int value; UInt32 win32Timestamp; if (ShortMsg.IsNoteOn(dwParam1, dwParam2)) { if (NoteOn != null) { ShortMsg.DecodeNoteOn(dwParam1, dwParam2, out channel, out pitch, out velocity, out win32Timestamp); NoteOn(new NoteOnMessage(this, channel, pitch, velocity, clock == null ? win32Timestamp / 1000f : clock.Time)); } } else if (ShortMsg.IsNoteOff(dwParam1, dwParam2)) { if (NoteOff != null) { ShortMsg.DecodeNoteOff(dwParam1, dwParam2, out channel, out pitch, out velocity, out win32Timestamp); NoteOff(new NoteOffMessage(this, channel, pitch, velocity, clock == null ? win32Timestamp / 1000f : clock.Time)); } } else if (ShortMsg.IsControlChange(dwParam1, dwParam2)) { if (ControlChange != null) { Control control; ShortMsg.DecodeControlChange(dwParam1, dwParam2, out channel, out control, out value, out win32Timestamp); ControlChange(new ControlChangeMessage(this, channel, control, value, clock == null ? win32Timestamp / 1000f : clock.Time)); } } else if (ShortMsg.IsProgramChange(dwParam1, dwParam2)) { if (ProgramChange != null) { Instrument instrument; ShortMsg.DecodeProgramChange(dwParam1, dwParam2, out channel, out instrument, out win32Timestamp); ProgramChange(new ProgramChangeMessage(this, channel, instrument, clock == null ? win32Timestamp / 1000f : clock.Time)); } } else if (ShortMsg.IsPitchBend(dwParam1, dwParam2)) { if (PitchBend != null) { ShortMsg.DecodePitchBend(dwParam1, dwParam2, out channel, out value, out win32Timestamp); PitchBend(new PitchBendMessage(this, channel, value, clock == null ? win32Timestamp / 1000f : clock.Time)); } } else { // Unsupported messages are ignored. } } #region SysEx else if (wMsg == Win32API.MidiInMessage.MIM_LONGDATA) { if (LongMsg.IsSysEx(dwParam1, dwParam2)) { if (SysEx != null) { byte[] data; uint win32Timestamp; LongMsg.DecodeSysEx(dwParam1, dwParam2, out data, out win32Timestamp); if (data.Length != 0) { SysEx(new SysExMessage(this, data, clock == null ? win32Timestamp / 1000f : clock.Time)); } if (isClosing) { //buffers no longer needed DestroyLongMsgBuffer(dwParam1); } else { //prepare the buffer for the next message RecycleLongMsgBuffer(dwParam1); } } } } // The rest of these are just for long message testing else if (wMsg == Win32API.MidiInMessage.MIM_MOREDATA) { SysEx(new SysExMessage(this, new byte[] { 0x13 }, 13)); } else if (wMsg == Win32API.MidiInMessage.MIM_OPEN) { //SysEx(new SysExMessage(this, new byte[] { 0x01 }, 1)); } else if (wMsg == Win32API.MidiInMessage.MIM_CLOSE) { //SysEx(new SysExMessage(this, new byte[] { 0x02 }, 2)); } else if (wMsg == Win32API.MidiInMessage.MIM_ERROR) { SysEx(new SysExMessage(this, new byte[] { 0x03 }, 3)); } else if (wMsg == Win32API.MidiInMessage.MIM_LONGERROR) { SysEx(new SysExMessage(this, new byte[] { 0x04 }, 4)); } else { SysEx(new SysExMessage(this, new byte[] { 0x05 }, 5)); } #endregion } finally { isInsideInputHandler = false; } }
/// <summary> /// The input callback for midiOutOpen. /// </summary> private void InputCallback(Win32API.HMIDIIN hMidiIn, Win32API.MidiInMessage wMsg, UIntPtr dwInstance, UIntPtr dwParam1, UIntPtr dwParam2) { isInsideInputHandler = true; try { if (wMsg == Win32API.MidiInMessage.MIM_DATA) { Channel channel; Pitch pitch; int velocity; Control control; int value; Instrument instrument; UInt32 win32Timestamp; if (ShortMsg.IsNoteOn(dwParam1, dwParam2)) { if (NoteOn != null) { ShortMsg.DecodeNoteOn(dwParam1, dwParam2, out channel, out pitch, out velocity, out win32Timestamp); NoteOn(new NoteOnMessage(this, channel, pitch, velocity, clock == null ? win32Timestamp / 1000f : clock.Time)); } } else if (ShortMsg.IsNoteOff(dwParam1, dwParam2)) { if (NoteOff != null) { ShortMsg.DecodeNoteOff(dwParam1, dwParam2, out channel, out pitch, out velocity, out win32Timestamp); NoteOff(new NoteOffMessage(this, channel, pitch, velocity, clock == null ? win32Timestamp / 1000f : clock.Time)); } } else if (ShortMsg.IsControlChange(dwParam1, dwParam2)) { if (ControlChange != null) { ShortMsg.DecodeControlChange(dwParam1, dwParam2, out channel, out control, out value, out win32Timestamp); ControlChange(new ControlChangeMessage(this, channel, control, value, clock == null ? win32Timestamp / 1000f : clock.Time)); } } else if (ShortMsg.IsProgramChange(dwParam1, dwParam2)) { if (ProgramChange != null) { ShortMsg.DecodeProgramChange(dwParam1, dwParam2, out channel, out instrument, out win32Timestamp); ProgramChange(new ProgramChangeMessage(this, channel, instrument, clock == null ? win32Timestamp / 1000f : clock.Time)); } } else if (ShortMsg.IsPitchBend(dwParam1, dwParam2)) { if (PitchBend != null) { ShortMsg.DecodePitchBend(dwParam1, dwParam2, out channel, out value, out win32Timestamp); PitchBend(new PitchBendMessage(this, channel, value, clock == null ? win32Timestamp / 1000f : clock.Time)); } } else { // Unsupported messages are ignored. } } } finally { isInsideInputHandler = false; } }