#region License /* Copyright (c) 2005 Leslie Sanford * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #endregion #region Contact /* * Leslie Sanford * Email: jabberdabber@hotmail.com */ #endregion using System; using System.ComponentModel; using System.Diagnostics; namespace Sanford.Multimedia.Midi { #region Channel Command Types /// /// Defines constants for ChannelMessage types. /// public enum ChannelCommand { /// /// Represents the note-off command type. /// NoteOff = 0x80, /// /// Represents the note-on command type. /// NoteOn = 0x90, /// /// Represents the poly pressure (aftertouch) command type. /// PolyPressure = 0xA0, /// /// Represents the controller command type. /// Controller = 0xB0, /// /// Represents the program change command type. /// ProgramChange = 0xC0, /// /// Represents the channel pressure (aftertouch) command /// type. /// ChannelPressure = 0xD0, /// /// Represents the pitch wheel command type. /// PitchWheel = 0xE0 } #endregion #region Controller Types /// /// Defines constants for controller types. /// public enum ControllerType { /// /// The Bank Select coarse. /// BankSelect, /// /// The Modulation Wheel coarse. /// ModulationWheel, /// /// The Breath Control coarse. /// BreathControl, /// /// The Foot Pedal coarse. /// FootPedal = 4, /// /// The Portamento Time coarse. /// PortamentoTime, /// /// The Data Entry Slider coarse. /// DataEntrySlider, /// /// The Volume coarse. /// Volume, /// /// The Balance coarse. /// Balance, /// /// The Pan position coarse. /// Pan = 10, /// /// The Expression coarse. /// Expression, /// /// The Effect Control 1 coarse. /// EffectControl1, /// /// The Effect Control 2 coarse. /// EffectControl2, /// /// The General Puprose Slider 1 /// GeneralPurposeSlider1 = 16, /// /// The General Puprose Slider 2 /// GeneralPurposeSlider2, /// /// The General Puprose Slider 3 /// GeneralPurposeSlider3, /// /// The General Puprose Slider 4 /// GeneralPurposeSlider4, /// /// The Bank Select fine. /// BankSelectFine = 32, /// /// The Modulation Wheel fine. /// ModulationWheelFine, /// /// The Breath Control fine. /// BreathControlFine, /// /// The Foot Pedal fine. /// FootPedalFine = 36, /// /// The Portamento Time fine. /// PortamentoTimeFine, /// /// The Data Entry Slider fine. /// DataEntrySliderFine, /// /// The Volume fine. /// VolumeFine, /// /// The Balance fine. /// BalanceFine, /// /// The Pan position fine. /// PanFine = 42, /// /// The Expression fine. /// ExpressionFine, /// /// The Effect Control 1 fine. /// EffectControl1Fine, /// /// The Effect Control 2 fine. /// EffectControl2Fine, /// /// The Hold Pedal 1. /// HoldPedal1 = 64, /// /// The Portamento. /// Portamento, /// /// The Sustenuto Pedal. /// SustenutoPedal, /// /// The Soft Pedal. /// SoftPedal, /// /// The Legato Pedal. /// LegatoPedal, /// /// The Hold Pedal 2. /// HoldPedal2, /// /// The Sound Variation. /// SoundVariation, /// /// The Sound Timbre. /// SoundTimbre, /// /// The Sound Release Time. /// SoundReleaseTime, /// /// The Sound Attack Time. /// SoundAttackTime, /// /// The Sound Brightness. /// SoundBrightness, /// /// The Sound Control 6. /// SoundControl6, /// /// The Sound Control 7. /// SoundControl7, /// /// The Sound Control 8. /// SoundControl8, /// /// The Sound Control 9. /// SoundControl9, /// /// The Sound Control 10. /// SoundControl10, /// /// The General Purpose Button 1. /// GeneralPurposeButton1, /// /// The General Purpose Button 2. /// GeneralPurposeButton2, /// /// The General Purpose Button 3. /// GeneralPurposeButton3, /// /// The General Purpose Button 4. /// GeneralPurposeButton4, /// /// The Effects Level. /// EffectsLevel = 91, /// /// The Tremelo Level. /// TremeloLevel, /// /// The Chorus Level. /// ChorusLevel, /// /// The Celeste Level. /// CelesteLevel, /// /// The Phaser Level. /// PhaserLevel, /// /// The Data Button Increment. /// DataButtonIncrement, /// /// The Data Button Decrement. /// DataButtonDecrement, /// /// The NonRegistered Parameter Fine. /// NonRegisteredParameterFine, /// /// The NonRegistered Parameter Coarse. /// NonRegisteredParameterCoarse, /// /// The Registered Parameter Fine. /// RegisteredParameterFine, /// /// The Registered Parameter Coarse. /// RegisteredParameterCoarse, /// /// The All Sound Off. /// AllSoundOff = 120, /// /// The All Controllers Off. /// AllControllersOff, /// /// The Local Keyboard. /// LocalKeyboard, /// /// The All Notes Off. /// AllNotesOff, /// /// The Omni Mode Off. /// OmniModeOff, /// /// The Omni Mode On. /// OmniModeOn, /// /// The Mono Operation. /// MonoOperation, /// /// The Poly Operation. /// PolyOperation } #endregion /// /// Represents MIDI channel messages. /// [ImmutableObject(true)] public sealed class ChannelMessage : ShortMessage { #region ChannelEventArgs Members #region Constants // // Bit manipulation constants. // private const int MidiChannelMask = ~15; private const int CommandMask = ~240; /// /// Maximum value allowed for MIDI channels. /// public const int MidiChannelMaxValue = 15; #endregion #region Construction /// /// Initializes a new instance of the ChannelEventArgs class with the /// specified command, MIDI channel, and data 1 values. /// /// /// The command value. /// /// /// The MIDI channel. /// /// /// The data 1 value. /// /// /// If midiChannel is less than zero or greater than 15. Or if /// data1 is less than zero or greater than 127. /// public ChannelMessage(ChannelCommand command, int midiChannel, int data1) { msg = 0; msg = PackCommand(msg, command); msg = PackMidiChannel(msg, midiChannel); msg = PackData1(msg, data1); #region Ensure Debug.Assert(Command == command); Debug.Assert(MidiChannel == midiChannel); Debug.Assert(Data1 == data1); #endregion } /// /// Initializes a new instance of the ChannelEventArgs class with the /// specified command, MIDI channel, data 1, and data 2 values. /// /// /// The command value. /// /// /// The MIDI channel. /// /// /// The data 1 value. /// /// /// The data 2 value. /// /// /// If midiChannel is less than zero or greater than 15. Or if /// data1 or data 2 is less than zero or greater than 127. /// public ChannelMessage(ChannelCommand command, int midiChannel, int data1, int data2) { msg = 0; msg = PackCommand(msg, command); msg = PackMidiChannel(msg, midiChannel); msg = PackData1(msg, data1); msg = PackData2(msg, data2); #region Ensure Debug.Assert(Command == command); Debug.Assert(MidiChannel == midiChannel); Debug.Assert(Data1 == data1); Debug.Assert(Data2 == data2); #endregion } public ChannelMessage(int message) { this.msg = message; } #endregion #region Methods /// /// Returns a value for the current ChannelEventArgs suitable for use in /// hashing algorithms. /// /// /// A hash code for the current ChannelEventArgs. /// public override int GetHashCode() { return msg; } /// /// Determines whether two ChannelEventArgs instances are equal. /// /// /// The ChannelMessageEventArgs to compare with the current ChannelEventArgs. /// /// /// true if the specified object is equal to the current /// ChannelMessageEventArgs; otherwise, false. /// public override bool Equals(object obj) { #region Guard if(!(obj is ChannelMessage)) { return false; } #endregion ChannelMessage e = (ChannelMessage)obj; return this.msg == e.msg; } /// /// Returns a value indicating how many bytes are used for the /// specified ChannelCommand. /// /// /// The ChannelCommand value to test. /// /// /// The number of bytes used for the specified ChannelCommand. /// internal static int DataBytesPerType(ChannelCommand command) { int result; if(command == ChannelCommand.ChannelPressure || command == ChannelCommand.ProgramChange) { result = 1; } else { result = 2; } return result; } /// /// Unpacks the command value from the specified integer channel /// message. /// /// /// The message to unpack. /// /// /// The command value for the packed message. /// internal static ChannelCommand UnpackCommand(int message) { return (ChannelCommand)(message & DataMask & MidiChannelMask); } /// /// Unpacks the MIDI channel from the specified integer channel /// message. /// /// /// The message to unpack. /// /// /// The MIDI channel for the pack message. /// internal static int UnpackMidiChannel(int message) { return message & DataMask & CommandMask; } /// /// Packs the MIDI channel into the specified integer message. /// /// /// The message into which the MIDI channel is packed. /// /// /// The MIDI channel to pack into the message. /// /// /// An integer message. /// /// /// If midiChannel is less than zero or greater than 15. /// internal static int PackMidiChannel(int message, int midiChannel) { #region Preconditons if(midiChannel < 0 || midiChannel > MidiChannelMaxValue) { throw new ArgumentOutOfRangeException("midiChannel", midiChannel, "MIDI channel out of range."); } #endregion return (message & MidiChannelMask) | midiChannel; } /// /// Packs the command value into an integer message. /// /// /// The message into which the command is packed. /// /// /// The command value to pack into the message. /// /// /// An integer message. /// internal static int PackCommand(int message, ChannelCommand command) { return (message & CommandMask) | (int)command; } #endregion #region Properties /// /// Gets the channel command value. /// public ChannelCommand Command { get { return UnpackCommand(msg); } } /// /// Gets the MIDI channel. /// public int MidiChannel { get { return UnpackMidiChannel(msg); } } /// /// Gets the first data value. /// public int Data1 { get { return UnpackData1(msg); } } /// /// Gets the second data value. /// public int Data2 { get { return UnpackData2(msg); } } /// /// Gets the EventType. /// public override MessageType MessageType { get { return MessageType.Channel; } } #endregion #endregion } }