コード例 #1
0
 private void MessageTypeComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
 {
     this.Data2TextBox.IsEnabled = MidiChannelEvent.HasData2(this.MessageType);
     this.EnableOkButton();
     this.UpdateData1Text();
     this.UpdateData2Text();
 }
コード例 #2
0
        /***********
        * Methods *
        ***********/

        #region Protected Methods

        protected override bool CheckRequiredInput()
        {
            if (!base.CheckRequiredInput())
            {
                return(false);
            }

            /* If the event does not use running status, message type and channel are required. */
            if (this.RunningStatusCheckBox.IsChecked == false)
            {
                if (this.MessageTypeComboBox.SelectedIndex < 0)
                {
                    return(false);
                }
                if (this.Channel < 0)
                {
                    return(false);
                }
            }

            /* Data byte 1 is always required.  Data byte 2 may or may not be, depending on message type. */
            if (this.Data1 < 0)
            {
                return(false);
            }
            if (MidiChannelEvent.HasData2(this.MessageType) && this.Data2 < 0)
            {
                return(false);
            }

            /* All required input has been provided. */
            return(true);
        }
コード例 #3
0
        /// <summary>Returns a comment for the first data byte of a channel message/event.</summary>
        /// <param name="messageType">Identifies the type of channel message (high nibble of status byte).</param>
        /// <param name="data">The first data byte of the event.</param>
        /// <param name="channel">One of the sixteen logical MIDI channels on which the event is transmitted.</param>
        /// <param name="keySignature">A MidiKeySignature value that applies to the event.</param>
        /// <returns>A comment for the data byte.</returns>
        public static string GetData1Comment(MidiMessageType messageType, int data, int channel, MidiKeySignature keySignature)
        {
            string s = (MidiChannelEvent.TypeMap[messageType].DescribeData1 == null) ? null :
                       MidiChannelEvent.TypeMap[messageType].DescribeData1(data, channel, keySignature);

            return(MidiChannelEvent.BuildDataComment(MidiChannelEvent.TypeMap[messageType].Data1Name, data, s));
        }
コード例 #4
0
        /// <summary>Removes from this file the MidiItem object at the specified index.</summary>
        /// <param name="index">The index in this file's list of the MidiItem object to remove.</param>
        public void RemoveItem(int index)
        {
            /* Determine how many bytes to remove from the array.  If the item is chunk info, the entire
             * chunk will be removed.  If it is a track (MTrk) chunk, decrement the number of tracks.
             */
            MidiItem      item = this.Items[index];
            int           i, n = item.Size;
            MidiChunkInfo chunkInfo = item as MidiChunkInfo;

            if (chunkInfo != null)
            {
                n += chunkInfo.Length;
                i  = this.Bytes.Length - item.Offset;
                if (n > i)
                {
                    n = i;
                }
                if (chunkInfo.Type == MidiChunkInfo.TrackType)
                {
                    --this.Header.NumberOfTracks;
                }
            }

            /* If the item is an MTrk event with a nonzero delta-time, the total time of each subsequent
             * event in the track/chunk will need to be adjusted accordingly (after this item is removed).
             */
            MidiEvent mtrkEvent = item as MidiEvent;
            int       deltaTime = (mtrkEvent == null) ? 0 : mtrkEvent.DeltaTime;

            /* Remove from the list all items whose offsets are within the range of data being removed. */
            for (i = item.Offset + n; index < this.ItemCount && this.Items[index].Offset < i; this.Items.RemoveAt(index))
            {
                item = this.Items[index];

                /* If the item being removed is a channel message/event that does not use running status, there
                 * should be a corresponding entry in the map of running statuses that needs to be removed.
                 */
                MidiChannelEvent channelEvent = item as MidiChannelEvent;
                if (channelEvent != null && !channelEvent.RunningStatus)
                {
                    this.RunningStatusMap.Remove(item.Offset);
                }

                /* If the item being removed is a meta-event representing a key signature, there should
                 * be a corresponding entry in the key signature map that also needs to be removed.
                 */
                MidiMetaEvent metaEvent = MidiFile.ItemToKeySignatureEvent(item);
                if (metaEvent != null)
                {
                    this.KeySignatureMap.Remove(metaEvent.TotalTime);
                }
            }

            /* If applicable, cascade total time changes through all subsequent events in the track. */
            this.AdjustTotalTimes(index, -deltaTime);

            /* Remove the appropriate number of bytes from the array. */
            this.Resize(-n, i, (chunkInfo == null) ? index : -1);
        }
コード例 #5
0
        /// <summary>Returns a comment for the second data byte of a channel message/event.</summary>
        /// <param name="messageType">Identifies the type of channel message (high nibble of status byte).</param>
        /// <param name="data">The second data byte of the event.</param>
        /// <returns>A comment for the data byte.</returns>
        public static string GetData2Comment(MidiMessageType messageType, int data)
        {
            if (!MidiChannelEvent.HasData2(messageType))
            {
                return(null);
            }
            string s = (MidiChannelEvent.TypeMap[messageType].DescribeData2 == null) ? null :
                       MidiChannelEvent.TypeMap[messageType].DescribeData2(data, 0, MidiKeySignature.NA);

            return(MidiChannelEvent.BuildDataComment(MidiChannelEvent.TypeMap[messageType].Data2Name, data, s));
        }
コード例 #6
0
        /// <summary>Inserts a new MIDI channel message/event into this file at the specified index.</summary>
        /// <param name="index">The index in this file's list at which the event should be inserted.</param>
        /// <param name="deltaTime">The amount of time (in ticks) between the previous event in the track and this one.</param>
        /// <param name="status">The status byte of the event, or -1 for running status.</param>
        /// <param name="data1">The first data byte of the event.</param>
        /// <param name="data2">The second data byte of the event (if applicable).</param>
        /// <returns>The new MidiChannelEvent object that is inserted.</returns>
        public MidiChannelEvent InsertChannelEvent(int index, int deltaTime, int status, int data1, int data2)
        {
            int             offset = this.Items[index].Offset, n = (status < 0) ? this.GetRunningStatus(offset) : status;
            MidiMessageType messageType = (MidiMessageType)Midi.GetHighNibble(n);

            n = MidiChannelEvent.SizeItem(0, (status < 0), messageType);
            this.Resize(n, offset, index);
            MidiChannelEvent channelEvent = this.CreateChannelEvent(offset, deltaTime, status, data1, data2);

            this.Items.Insert(index, channelEvent);
            this.SetTotalTime(index);
            return(channelEvent);
        }
コード例 #7
0
        /// <summary>Adds a new MIDI channel message/event to the end of this file.</summary>
        /// <param name="deltaTime">The amount of time (in ticks) between the previous event in the track and this one.</param>
        /// <param name="status">The status byte of the event, or -1 for running status.</param>
        /// <param name="data1">The first data byte of the event.</param>
        /// <param name="data2">The second data byte of the event (if applicable).</param>
        /// <returns>The new MidiChannelEvent object that is added.</returns>
        public MidiChannelEvent AddChannelEvent(int deltaTime, int status, int data1, int data2)
        {
            int             offset = this.Bytes.Length, n = (status < 0) ? this.GetRunningStatus(offset) : status;
            MidiMessageType messageType = (MidiMessageType)Midi.GetHighNibble(n);

            n = MidiChannelEvent.SizeItem(0, (status < 0), messageType);
            this.Resize(n, offset, this.ItemCount);
            MidiChannelEvent channelEvent = this.CreateChannelEvent(offset, deltaTime, status, data1, data2);

            this.Items.Add(channelEvent);
            this.SetTotalTime(this.ItemCount - 1);
            return(channelEvent);
        }
コード例 #8
0
        private MidiChannelEvent CreateChannelEvent(int offset, int deltaTime, int status, int data1, int data2)
        {
            MidiChannelEvent channelEvent = new MidiChannelEvent(this, offset);

            channelEvent.DeltaTime = deltaTime;
            if (status >= 0)
            {
                this.Bytes[channelEvent.StatusOffset] = 0xF0;
                channelEvent.Status = status;
            }
            channelEvent.Data1 = data1;
            channelEvent.Data2 = data2;
            return(channelEvent);
        }
コード例 #9
0
        private void ParseEvents(int offset, int length, int trackNumber)
        {
            string        s;
            int           n = offset + length, i, j = 0;
            MidiEvent     mtrkEvent = null;
            MidiMetaEvent metaEvent;

            /* A track chunk is a stream of MIDI (MTrk) events.  Process each such
             * event in this part of the byte array comprising the track chunk.
             */
            for (i = offset; i < n; i += mtrkEvent.Size)
            {
                /* In order to know what kind of event to instantiate, we must read the event's status
                 * byte, which requires skipping past the delta-time (stored as a variable-length quantity).
                 */
                for (j = i; j < this.Bytes.Length && (this.Bytes[j] & 0x80) > 0; ++j)
                {
                    if (j - i > 3)
                    {
                        s = string.Format("{0} (@ {1} {2})", Properties.Resources.InvalidVLQ, Properties.Resources.Byte, i);
                        this.AddErrorText(s, trackNumber);
                        return;
                    }
                }
                if (++j >= this.Bytes.Length)
                {
                    break;
                }

                /* Instantiate an event object of the appropriate type (based on the status byte). */
                switch (this.Bytes[j])
                {
                case 0xFF: mtrkEvent = new MidiMetaEvent(this, i); break;

                case 0xF7: mtrkEvent = new MidiSysExEvent(this, i); break;

                case 0xF0: mtrkEvent = new MidiSysExEvent(this, i); break;

                default: mtrkEvent = new MidiChannelEvent(this, i); break;
                }
                this.Items.Add(mtrkEvent);
                this.SetTotalTime(this.ItemCount - 1);

                /* If the event is a MIDI channel message/event that does not use
                 * running status, use it to set the running status at this byte offset.
                 */
                if (++j >= this.Bytes.Length)
                {
                    break;
                }
                MidiChannelEvent channelEvent = mtrkEvent as MidiChannelEvent;
                if (channelEvent != null && !channelEvent.RunningStatus)
                {
                    this.SetRunningStatus(i, channelEvent.Status);
                }

                /* If the event is a meta-event representing a key signature,
                 * use it to set the key signature at the appropriate time.
                 */
                if (++j >= this.Bytes.Length)
                {
                    break;
                }
                metaEvent = MidiFile.ItemToKeySignatureEvent(mtrkEvent);
                if (metaEvent != null)
                {
                    this.SetKeySignature(metaEvent);
                }
            }

            /* If we ran out of data, add an error message. */
            if (j >= this.Bytes.Length)
            {
                s = string.Format(Properties.Resources.MismatchFormat, Properties.Resources.Byte, length, i - offset);
                this.AddErrorText(s, trackNumber);
            }

            /* The last event in a track chunk should be an End of Track meta-event. */
            metaEvent = mtrkEvent as MidiMetaEvent;
            if (metaEvent == null || (metaEvent != null && metaEvent.Type != MidiMetaEvent.EndOfTrackType))
            {
                this.AddErrorText(Properties.Resources.NoEndOfTrack, trackNumber);
            }
        }
コード例 #10
0
        /****************
        * Constructors *
        ****************/

        #region Public Constructors

        /// <summary>Initializes a new instance of the MidiEventDialog class.</summary>
        /// <param name="channelEvent">
        /// MidiChannelEvent object representing the MIDI channel message/event to edit, or null to create a new one.
        /// </param>
        public MidiChannelEventDialog(MidiChannelEvent channelEvent)
            : base(channelEvent)
        {
            int       i = this.ControlCount;
            DockPanel panel1, panel2;

            /* Initialize the "Running status" check box. */
            this.RunningStatusCheckBox            = UI.CreateCheckBox(++i, MarginType.Standard, Properties.Resources.RunningStatus, null);
            this.RunningStatusCheckBox.Checked   += this.RunningStatusCheckBox_Checked;
            this.RunningStatusCheckBox.Unchecked += this.RunningStatusCheckBox_Checked;

            /* Initialize the "Message type" label. */
            this.MessageTypeLabel = UI.CreateLabel(MarginType.Standard, Properties.Resources.MessageType, true);

            /* Initialize the "Message type" combo box. */
            this.MessageTypeComboBox          = new ComboBox();
            this.MessageTypeComboBox.TabIndex = ++i;
            this.MessageTypeComboBox.Margin   = new Thickness(UI.TripleSpace, UI.HalfSpace, UI.TripleSpace, UI.UnitSpace);
            foreach (MidiMessageType messageType in MidiChannelEventDialog.MessageTypes)
            {
                string s = MidiChannelEvent.GetTypeComment(messageType);
                this.MessageTypeComboBox.Items.Add(s);
            }
            this.MessageTypeComboBox.SelectionChanged += MessageTypeComboBox_SelectionChanged;
            this.MessageTypeLabel.Target = this.MessageTypeComboBox;

            /* Initialize the "Channel" label. */
            this.ChannelLabel = UI.CreateLabel(MarginType.Standard, Properties.Resources.Channel, true);

            /* Initialize the "Channel" text box. */
            this.ChannelTextBox               = new TextBox();
            this.ChannelTextBox.TabIndex      = ++i;
            this.ChannelTextBox.Margin        = new Thickness(UI.TripleSpace, UI.HalfSpace, UI.TripleSpace, UI.UnitSpace);
            this.ChannelTextBox.TextAlignment = TextAlignment.Right;
            this.ChannelTextBox.GotFocus     += UI.TextBox_GotFocus;
            this.ChannelTextBox.TextChanged  += this.ChannelTextBox_TextChanged;
            this.ChannelLabel.Target          = this.ChannelTextBox;

            /* Initialize the "Data 1" controls. */
            this.Data1Label = UI.CreateLabel(MarginType.Standard, Properties.Resources.Data1, true);
            panel1          = MidiEventDialog.CreateDataBytePanel(ref this.Data1TextBox, ref this.Data1TextBlock, ++i);
            this.Data1TextBox.TextChanged += this.Data1TextBox_TextChanged;
            this.Data1Label.Target         = this.Data1TextBox;

            /* Initialize the "Data 2" controls. */
            this.Data2Label = UI.CreateLabel(MarginType.Standard, Properties.Resources.Data2, true);
            panel2          = MidiEventDialog.CreateDataBytePanel(ref this.Data2TextBox, ref this.Data2TextBlock, ++i);
            this.Data2TextBox.TextChanged += this.Data2TextBox_TextChanged;
            this.Data2Label.Target         = this.Data2TextBox;

            /* Build out the window and its content. */
            this.AddUIElement(this.RunningStatusCheckBox);
            this.AddUIElement(this.MessageTypeLabel);
            this.AddUIElement(this.MessageTypeComboBox);
            this.AddUIElement(this.ChannelLabel);
            this.AddUIElement(this.ChannelTextBox);
            this.AddUIElement(this.Data1Label);
            this.AddUIElement(panel1);
            this.AddUIElement(this.Data2Label);
            this.AddUIElement(panel2);
            this.BuildOut(MidiChannelEventDialog.ClientWidth, MidiChannelEventDialog.TitleString);

            /* The OK button should start out disabled and stay that way until all required input is entered. */
            this.OkButton.IsEnabled = false;

            /* If a MidiChannelEvent object was supplied, use it to set initial values. */
            if (this.ForNewItem)
            {
                return;
            }
            this.DeltaTime = channelEvent.DeltaTime;
            this.RunningStatusCheckBox.IsEnabled  = false;
            this.RunningStatusCheckBox.IsChecked  = channelEvent.RunningStatus;
            this.MessageTypeComboBox.SelectedItem = MidiChannelEvent.GetTypeComment(channelEvent.MessageType);
            this.ChannelTextBox.Text = channelEvent.Channel.ToString();
            this.Data1TextBox.Text   = channelEvent.Data1.ToString();
            if (!MidiChannelEvent.HasData2(channelEvent.MessageType))
            {
                return;
            }
            this.Data2TextBox.Text = channelEvent.Data2.ToString();
        }
コード例 #11
0
 private void UpdateData2Text()
 {
     this.Data2TextBlock.Text = (this.MessageType == MidiMessageType.NA || this.Data2 < 0)
         ? null : MidiChannelEvent.GetData2Comment(this.MessageType, this.Data2);
 }
コード例 #12
0
 private void UpdateData1Text()
 {
     this.Data1TextBlock.Text = (this.MessageType == MidiMessageType.NA || this.Data1 < 0) ? null :
                                MidiChannelEvent.GetData1Comment(this.MessageType, this.Data1, this.Channel, MidiKeySignature.NA);
 }
コード例 #13
0
        /***********
        * Methods *
        ***********/

        #region Public Methods

        /// <summary>Returns the number of bytes required to store an item of this type.</summary>
        public static int SizeItem(int deltaTime, bool runningStatus, MidiMessageType messageType)
        {
            return(Midi.SizeVLQ(deltaTime) + (runningStatus ? 0 : 1) + (MidiChannelEvent.HasData2(messageType) ? 2 : 1));
        }