/**************** * Constructors * ****************/ #region Public Constructors /// <summary>Initializes a new instance of the MidiSysExEventDialog class.</summary> /// <param name="sysExEvent"> /// MidiSysExEvent object representing the MIDI system exclusive /// (SysEx) message/event to edit, or null to create a new one. /// </param> public MidiSysExEventDialog(MidiSysExEvent sysExEvent) : base(sysExEvent) { int i = this.ControlCount; /* Initialize the "Escape" check box. */ this.EscapeCheckBox = UI.CreateCheckBox(++i, MarginType.Standard, Properties.Resources.Escape, null); /* Initialize the "Data" controls. */ this.DataLabel = UI.CreateLabel(MarginType.Standard, Properties.Resources.Data, true); DockPanel panel = MidiEventDialog.CreateDataPanel(ref this.DataHexTextBox, ref this.DataCommentTextBox, ++i); this.DataHexTextBox.TextChanged += this.DataHexTextBox_TextChanged; this.DataCommentTextBox.IsReadOnly = true; this.DataLabel.Target = this.DataHexTextBox; /* Build out the window and its content. */ this.AddUIElement(this.EscapeCheckBox); this.AddUIElement(this.DataLabel); this.AddUIElement(panel); this.BuildOut(UI.ClientWidth, MidiSysExEventDialog.TitleString); /* The OK button should start out disabled and stay that way until all required input is entered. */ this.OkButton.IsEnabled = false; /* If a MidiSysExEvent object was supplied, use it to set initial values. */ if (this.ForNewItem) { return; } this.DeltaTime = sysExEvent.DeltaTime; this.EscapeCheckBox.IsChecked = sysExEvent.Escape; this.DataHexTextBox.Text = this.Hex = Midi.FormatHex(sysExEvent.Data, 0, sysExEvent.Data.Length); }
/// <summary> /// Writes a variable-length quantity (VLQ) into this file's byte array, resizing the byte array if necessary. /// </summary> /// <param name="offset">Offset into the byte array at which the VLQ is written.</param> /// <param name="vlq">The VLQ to write.</param> /// <param name="length">Length of quantity that the VLQ is replacing (for resizing purposes).</param> public void WriteVLQ(int offset, int vlq, int length) { /* Resize the byte array (if necessary). */ int i, n = Midi.SizeVLQ(vlq) - length; if (n != 0) { this.Resize(n, offset + length, 0); } /* For the simple (and common) case of a single-byte VLQ, take a shortcut. */ if (vlq < 0x80) { this.Bytes[offset] = (byte)vlq; return; } /* The VLQ is stored as 7 bits per byte (most significant byte first). All bytes except the last have the * Most Significant Bit (MSB) set, and the last byte has the MSB clear. The easiest way to accomplish this * is to write the VLQ "backwards" (least significant byte first) to a temporary byte array, then reverse it. */ for (n = 0, i = vlq; i > 0; i >>= 7) { this.Bytes[offset + n] = (byte)((i % 0x100) & 0x7F); if (n > 0) { this.Bytes[offset + n] |= 0x80; } ++n; } Array.Reverse(this.Bytes, offset, n); }
private static string DescribeNumber(int type, byte[] bytes) { int n = MidiMetaEvent.GetDataLength(type); if (bytes.Length < n) { return(null); } return(Midi.ReadNumber(bytes, 0, n).ToString()); }
/*********** * Methods * ***********/ #region Private Methods #region Event Handlers private void DataHexTextBox_TextChanged(object sender, TextChangedEventArgs e) { byte[] bytes = Midi.ParseHex(this.DataHexTextBox.Text); if (bytes == null) { this.DataHexTextBox.Text = this.Hex; return; } this.Hex = this.DataHexTextBox.Text; this._Data = bytes; this.DataCommentTextBox.Text = Midi.ReadText(this.Data, 0, this.Data.Length); }
private static string DescribeTempo(byte[] bytes) { int n = MidiMetaEvent.GetDataLength(MidiMetaEvent.SetTempoType); if (bytes.Length < n) { return(null); } n = Midi.ReadNumber(bytes, 0, n); return(string.Format("{0} {1} ({2} {3})", n, Properties.Resources.MicrosecondsPerQuarterNote, (n == 0) ? double.PositiveInfinity : (60000000 / n), Properties.Resources.BeatsPerMinute)); }
/// <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); }
/// <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>Reads text as a string of ASCII characters from a byte array.</summary> /// <param name="bytes">Array of bytes containing the text.</param> /// <param name="offset">Offset into the byte array at which the text is stored.</param> /// <param name="length">The number of bytes (ASCII characters) to read.</param> /// <returns>The text that is read.</returns> public static string ReadText(byte[] bytes, int offset, int length) { char[] chars = new char[length]; for (int i = 0; i < length; ++i) { chars[i] = (char)bytes[offset + i]; if (!Midi.IsPrintable(chars[i])) { chars[i] = '.'; } } return(new string(chars)); }
private void DataHexTextBox_TextChanged(object sender, TextChangedEventArgs e) { /* If the hex input is not valid, revert to previous hex. */ byte[] bytes = Midi.ParseHex(this.DataHexTextBox.Text); if (bytes == null) { this.NoValidation = true; this.DataHexTextBox.Text = this.Hex; this.NoValidation = false; return; } /* The hex input is valid. */ this.Hex = this.DataHexTextBox.Text; this._Data = bytes; this.UpdateDataComment(); }
private void DataCommentTextBox_TextChanged(object sender, TextChangedEventArgs e) { /* Prevent unnecessary recursion. */ if (this.NoValidation) { return; } this.NoValidation = true; /* Populate hex box based on text/character/string input. */ int i, n = this.DataCommentTextBox.Text.Length; byte[] bytes = new byte[n]; for (i = 0; i < n; ++i) { bytes[i] = (byte)this.DataCommentTextBox.Text[i]; } this.DataHexTextBox.Text = Midi.FormatHex(bytes, 0, n); this.NoValidation = false; }
/**************** * Constructors * ****************/ #region Public Constructors /// <summary>Initializes a new instance of the MidiMetaEventDialog class.</summary> /// <param name="metaEvent"> /// MidiMetaEvent object representing the MIDI meta-event to edit, or null to create a new one. /// </param> public MidiMetaEventDialog(MidiMetaEvent metaEvent) : base(metaEvent) { int i = this.ControlCount; DockPanel typePanel, dataPanel; /* Initialize the "Type" controls. */ this.TypeLabel = UI.CreateLabel(MarginType.Standard, Properties.Resources.Type, true); typePanel = MidiEventDialog.CreateDataBytePanel(ref this.TypeTextBox, ref this.TypeTextBlock, ++i); this.TypeTextBox.TextChanged += this.TypeTextBox_TextChanged; this.TypeLabel.Target = this.TypeTextBox; /* Initialize the "Data" controls. */ Label label = UI.CreateLabel(MarginType.Standard, Properties.Resources.Data, true); dataPanel = MidiEventDialog.CreateDataPanel(ref this.DataHexTextBox, ref this.DataCommentTextBox, ++i); this.DataHexTextBox.TextChanged += this.DataHexTextBox_TextChanged; this.DataCommentTextBox.TextChanged += this.DataCommentTextBox_TextChanged; label.Target = this.DataHexTextBox; /* Build out the window and its content. */ this.AddUIElement(this.TypeLabel); this.AddUIElement(typePanel); this.AddUIElement(label); this.AddUIElement(dataPanel); this.BuildOut(UI.ClientWidth, MidiMetaEventDialog.TitleString); /* The OK button should start out disabled and stay that way until all required input is entered. */ this.OkButton.IsEnabled = false; /* If a MidiMetaEvent object was supplied, use it to set initial values. */ if (this.ForNewItem) { return; } this.DeltaTime = metaEvent.DeltaTime; this.TypeTextBox.Text = metaEvent.Type.ToString(); this.NoValidation = true; this.DataHexTextBox.Text = this.Hex = Midi.FormatHex(metaEvent.Data, 0, metaEvent.Data.Length); this.NoValidation = false; }
/*********** * 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, int dataLength) { return(Midi.SizeVLQ(deltaTime) + 2 + Midi.SizeVLQ(dataLength) + dataLength); }
/// <summary>Represents a portion of this file's byte array in hexadecimal format.</summary> /// <param name="offset">Offset into the byte array at which to start reading.</param> /// <param name="length">The number of bytes to read.</param> /// <returns>Representation of the specified portion of the byte array in hexadecimal format.</returns> public string FormatHex(int offset, int length) { return(Midi.FormatHex(this.Bytes, offset, length)); }
/// <summary>Returns a comment for the data bytes of a meta-event.</summary> /// <param name="type">Meta-event type (always less than 128).</param> /// <param name="bytes">The data bytes of the event.</param> /// <returns>A comment for the data bytes.</returns> public static string GetDataComment(int type, byte[] bytes) { return((MidiMetaEvent.TypeMap.ContainsKey(type) && MidiMetaEvent.TypeMap[type].DescribeData != null) ? MidiMetaEvent.TypeMap[type].DescribeData(bytes) : Midi.ReadText(bytes, 0, bytes.Length)); }
/// <summary>Attempts to convert the data bytes of a meta-event to a MidiKeySignature value.</summary> /// <param name="bytes">The data bytes of the event.</param> /// <returns> /// The data bytes converted to a MidiKeySignature value, or MidiKeySignature.NA if the data could not be converted. /// </returns> public static MidiKeySignature DataToKeySignature(byte[] bytes) { int n = Midi.ReadNumber(bytes, 0, bytes.Length); return(Enum.IsDefined(typeof(MidiKeySignature), n) ? (MidiKeySignature)n : 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)); }
/// <summary>Reads text as a string of ASCII characters from this file's byte array.</summary> /// <param name="offset">Offset into the byte array at which the text is stored.</param> /// <param name="length">The number of bytes (ASCII characters) to read.</param> /// <returns>The text that is read.</returns> public string ReadText(int offset, int length) { return(Midi.ReadText(this.Bytes, offset, length)); }
/// <summary>Reads a number as an integer (in network byte order) from this file's byte array.</summary> /// <param name="offset"> /// Offset into the byte array at which the number is stored (most significant byte first). /// </param> /// <param name="length">The number of bytes to read (should not be greater than 4).</param> /// <returns>The number that is read.</returns> public int ReadNumber(int offset, int length) { return(Midi.ReadNumber(this.Bytes, offset, length)); }