private void MessageTypeComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e) { this.Data2TextBox.IsEnabled = MidiChannelEvent.HasData2(this.MessageType); this.EnableOkButton(); this.UpdateData1Text(); this.UpdateData2Text(); }
/*********** * 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); }
/// <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)); }
/// <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); }
/// <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)); }
/// <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); }
/// <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); }
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); }
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); } }
/**************** * 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(); }
private void UpdateData2Text() { this.Data2TextBlock.Text = (this.MessageType == MidiMessageType.NA || this.Data2 < 0) ? null : MidiChannelEvent.GetData2Comment(this.MessageType, this.Data2); }
private void UpdateData1Text() { this.Data1TextBlock.Text = (this.MessageType == MidiMessageType.NA || this.Data1 < 0) ? null : MidiChannelEvent.GetData1Comment(this.MessageType, this.Data1, this.Channel, MidiKeySignature.NA); }
/*********** * 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)); }