### Use GMPercussionMap in NoteOn Message Source: https://docs.rs/midi-msg/latest/midi_msg/enum.GMPercussionMap.html Example of using a GMPercussionMap variant to specify a percussion note on MIDI Channel 10. ```rust MidiMsg::ChannelVoice { channel: Channel::Ch10, msg: ChannelVoiceMsg::NoteOn { note: GMPercussionMap::Vibraslap as u8, velocity: 127 } }; ``` -------------------------------- ### Construct and serialize a MIDI file Source: https://docs.rs/midi-msg/latest/midi_msg/index.html Create a MidiFile, add tracks with events, and serialize the result. ```rust use midi_msg::*; let mut file = MidiFile::default(); // Add a track, updating the header with the number of tracks: file.add_track(Track::default()); // Add a note on message at beat 0: file.extend_track(0, MidiMsg::ChannelVoice { channel: Channel::Ch1, msg: ChannelVoiceMsg::NoteOn { note: 60, velocity: 127 } }, 0.0); // Add a note off message at beat 1: file.extend_track(0, MidiMsg::ChannelVoice { channel: Channel::Ch1, msg: ChannelVoiceMsg::NoteOff { note: 60, velocity: 0 } }, 1.0); // Add an end of track message at beat 4, // which is the only required (by the spec) message in a track: file.extend_track(0, MidiMsg::Meta { msg: Meta::EndOfTrack }, 4.0); // Now we can serialize the track to a Vec: let midi_bytes = file.to_midi(); // And we can deserialize it back to a MidiFile: let file2 = MidiFile::from_midi(&midi_bytes).unwrap(); assert_eq!(file, file2); ``` -------------------------------- ### ChannelBitMap::all() Source: https://docs.rs/midi-msg/latest/midi_msg/struct.ChannelBitMap.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Creates a new ChannelBitMap instance with all 16 channels set to true. ```APIDOC ## pub fn all() -> Self ### Description Returns a ChannelBitMap instance where all channels (1-16) are enabled. ### Returns - **Self** - A ChannelBitMap with all fields set to true. ``` -------------------------------- ### ReceiverContext::new Source: https://docs.rs/midi-msg/latest/midi_msg/struct.ReceiverContext.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Creates a new instance of ReceiverContext with default settings. ```APIDOC ## pub const fn new() -> Self ### Description Creates a new instance of ReceiverContext with default values. ### Returns - **Self** - A new ReceiverContext instance. ``` -------------------------------- ### ChannelBitMap::all Source: https://docs.rs/midi-msg/latest/midi_msg/struct.ChannelBitMap.html?search=u32+-%3E+bool Creates a new ChannelBitMap instance with all 16 channels set to true. ```APIDOC ## pub fn all() -> Self ### Description Returns a new ChannelBitMap instance where all channels (1 through 16) are enabled. ### Returns - **Self** - A ChannelBitMap with all fields set to true. ``` -------------------------------- ### pub fn from_freq(freq: f32) -> Self Source: https://docs.rs/midi-msg/latest/midi_msg/struct.Tuning.html Creates a new Tuning instance from a given frequency value. ```APIDOC ## pub fn from_freq(freq: f32) -> Self ### Description Creates a new Tuning instance based on the provided frequency. ### Parameters - **freq** (f32) - Required - The frequency value to convert into a Tuning representation. ``` -------------------------------- ### ChannelBitMap::none() Source: https://docs.rs/midi-msg/latest/midi_msg/struct.ChannelBitMap.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Creates a new ChannelBitMap instance with all 16 channels set to false. ```APIDOC ## pub fn none() -> Self ### Description Returns a ChannelBitMap instance where no channels are enabled. ### Returns - **Self** - A ChannelBitMap with all fields set to false. ``` -------------------------------- ### ChannelBitMap::none Source: https://docs.rs/midi-msg/latest/midi_msg/struct.ChannelBitMap.html?search=u32+-%3E+bool Creates a new ChannelBitMap instance with all 16 channels set to false. ```APIDOC ## pub fn none() -> Self ### Description Returns a new ChannelBitMap instance where no channels are enabled. ### Returns - **Self** - A ChannelBitMap with all fields set to false. ``` -------------------------------- ### StandardTimeCode Byte Conversion Methods Source: https://docs.rs/midi-msg/latest/midi_msg/struct.StandardTimeCode.html?search= Methods to serialize the StandardTimeCode into byte arrays for MIDI transmission. ```rust pub fn to_bytes(self) -> [u8; 5] ``` ```rust pub fn to_bytes_short(self) -> [u8; 2] ``` -------------------------------- ### Function Signature for freq_to_midi_note_cents Source: https://docs.rs/midi-msg/latest/midi_msg/fn.freq_to_midi_note_cents.html The function signature for converting frequency to MIDI note and cents. ```rust pub fn freq_to_midi_note_cents(freq: f32) -> (u8, f32) ``` -------------------------------- ### GlobalParameterControl Constructors Source: https://docs.rs/midi-msg/latest/midi_msg/struct.GlobalParameterControl.html?search= Convenience constructors for creating GlobalParameterControl instances for GM2 Reverb and Chorus effects. ```rust pub fn reverb(reverb_type: Option, reverb_time: Option) -> Self ``` ```rust pub fn chorus( chorus_type: Option, mod_rate: Option, mod_depth: Option, feedback: Option, send_to_reverb: Option, ) -> Self ``` -------------------------------- ### Constructing GlobalParameterControl for Reverb Source: https://docs.rs/midi-msg/latest/midi_msg/struct.GlobalParameterControl.html Creates a control message specifically for GM2 Reverb slots. ```rust pub fn reverb(reverb_type: Option, reverb_time: Option) -> Self ``` -------------------------------- ### Serialize a MIDI message Source: https://docs.rs/midi-msg/latest/midi_msg/index.html Create a MidiMsg and convert it into a Vec byte sequence. ```rust use midi_msg::*; MidiMsg::ChannelVoice { channel: Channel::Ch1, msg: ChannelVoiceMsg::NoteOn { note: 60, velocity: 127 } } .to_midi(); ``` -------------------------------- ### ControlChange Methods Source: https://docs.rs/midi-msg/latest/midi_msg/enum.ControlChange.html Methods for interacting with ControlChange MIDI messages. ```APIDOC ## pub fn to_complex(&self) -> Self ### Description Converts the control change to a complex representation. ## pub fn to_simple(&self) -> Self ### Description Converts the control change to a simple representation. ## pub fn to_simple_high_res(&self) -> Self ### Description Converts the control change to a simple high-resolution representation. ## pub fn control(&self) -> u8 ### Description Retrieves the control number. ## pub fn value(&self) -> u8 ### Description Retrieves the value of the control change (0-127). Returns 0 for ControlChange::Parameter. ## pub fn value_high_res(&self) -> u16 ### Description Retrieves the 14-bit value of the control change. Non-high-res parameters are scaled to 14 bits. Returns 0 for ControlChange::Parameter. ## pub fn to_midi_running(&self) -> Vec ### Description Converts the control change to a MIDI running status byte sequence. ## pub fn extend_midi_running(&self, v: &mut Vec) ### Description Appends the MIDI running status representation to the provided vector. ``` -------------------------------- ### Function Signature for freq_to_midi_note_float Source: https://docs.rs/midi-msg/latest/midi_msg/fn.freq_to_midi_note_float.html The function signature for converting frequency to a floating-point MIDI note. ```rust pub fn freq_to_midi_note_float(freq: f32) -> f32 ``` -------------------------------- ### pub fn next_message(m: &[u8]) -> Option Source: https://docs.rs/midi-msg/latest/midi_msg/fn.next_message.html Finds the index of the next MIDI message in a byte sequence by searching for a status byte (a byte with the upper bit set). ```APIDOC ## next_message ### Description Find the index of the next message in a MIDI byte sequence. This is useful for being able to skip over messages, which may be necessary when a message is unable to be deserialized. This will skip any running status messages, since it looks for a status byte (a byte with the upper bit set). ### Signature `pub fn next_message(m: &[u8]) -> Option` ### Parameters - **m** (&[u8]) - The MIDI byte sequence to search. ### Returns - **Option** - The index of the next message if found, otherwise None. ``` -------------------------------- ### pub fn next_message(m: &[u8]) -> Option Source: https://docs.rs/midi-msg/latest/midi_msg/fn.next_message.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Finds the index of the next MIDI message in a byte sequence by searching for a status byte (a byte with the upper bit set). ```APIDOC ## next_message ### Description Find the index of the next message in a MIDI byte sequence. This is useful for being able to skip over messages, which may be necessary when a message is unable to be deserialized. This will skip any running status messages, since it looks for a status byte (a byte with the upper bit set). ### Signature `pub fn next_message(m: &[u8]) -> Option` ### Parameters - **m** (&[u8]) - The byte slice representing the MIDI sequence to search. ### Returns - **Option** - The index of the next status byte if found, otherwise None. ``` -------------------------------- ### MidiFile Operations Source: https://docs.rs/midi-msg/latest/midi_msg/index.html Methods for constructing, serializing, and deserializing Standard MIDI Files (SMF). ```APIDOC ## MidiFile Operations ### Description `MidiFile` allows managing MIDI tracks and events. It supports `to_midi()` for serialization and `from_midi()` for deserialization. ### Example ```rust use midi_msg::*; let mut file = MidiFile::default(); file.add_track(Track::default()); file.extend_track(0, MidiMsg::ChannelVoice { ... }, 0.0); let midi_bytes = file.to_midi(); let file2 = MidiFile::from_midi(&midi_bytes).unwrap(); ``` ``` -------------------------------- ### ControlChange Methods Source: https://docs.rs/midi-msg/latest/midi_msg/enum.ControlChange.html?search=u32+-%3E+bool Methods for interacting with ControlChange instances to retrieve values or convert to MIDI formats. ```APIDOC ## ControlChange Methods ### pub fn control(&self) -> u8 Returns the control number. ### pub fn value(&self) -> u8 Returns the value of the control change (0-127). Returns 0 for `ControlChange::Parameter`. ### pub fn value_high_res(&self) -> u16 Returns the 14-bit value of the control change. Non-high-res parameters are scaled to 14 bits. Returns 0 for `ControlChange::Parameter`. ### pub fn to_complex(&self) -> Self Converts the current instance to a complex representation. ### pub fn to_simple(&self) -> Self Converts the current instance to a simple representation. ### pub fn to_simple_high_res(&self) -> Self Converts the current instance to a simple high-resolution representation. ### pub fn to_midi_running(&self) -> Vec Converts the control change to a vector of MIDI bytes. ``` -------------------------------- ### Constructing GlobalParameterControl for Chorus Source: https://docs.rs/midi-msg/latest/midi_msg/struct.GlobalParameterControl.html Creates a control message specifically for GM2 Chorus slots. ```rust pub fn chorus( chorus_type: Option, mod_rate: Option, mod_depth: Option, feedback: Option, send_to_reverb: Option, ) -> Self ``` -------------------------------- ### MidiFile::from_midi Source: https://docs.rs/midi-msg/latest/midi_msg/struct.MidiFile.html Parses a slice of bytes into a MidiFile instance. ```APIDOC ## pub fn from_midi(v: &[u8]) -> Result ### Description Turn a series of bytes into a `MidiFile`. ### Parameters - **v** (&[u8]) - The byte slice representing the MIDI file data. ### Returns - **Result** - Returns the parsed MidiFile or a parsing error. ``` -------------------------------- ### SoundFileMap Struct Definition Source: https://docs.rs/midi-msg/latest/midi_msg/struct.SoundFileMap.html The structure definition for SoundFileMap, containing fields for bank, program, drum status, and volume. ```rust pub struct SoundFileMap { pub dst_bank: u16, pub dst_prog: u8, pub src_bank: u16, pub src_prog: u8, pub src_drum: bool, pub dst_drum: bool, pub volume: u8, } ``` -------------------------------- ### ScaleTuning1Byte Struct Definition Source: https://docs.rs/midi-msg/latest/midi_msg/struct.ScaleTuning1Byte.html The structure definition for ScaleTuning1Byte, containing a channel bitmap and an array of 12 tuning adjustments. ```rust pub struct ScaleTuning1Byte { pub channels: ChannelBitMap, pub tuning: [i8; 12], } ``` -------------------------------- ### MidiFile::add_track Source: https://docs.rs/midi-msg/latest/midi_msg/struct.MidiFile.html Adds a track to the MidiFile and updates the header. ```APIDOC ## pub fn add_track(&mut self, track: Track) ### Description Add a track to the file. Increments the `num_tracks` field in the header. ### Parameters - **track** (Track) - The track to add. ``` -------------------------------- ### GlobalParameterControl::reverb Source: https://docs.rs/midi-msg/latest/midi_msg/struct.GlobalParameterControl.html?search= Constructor for a GlobalParameterControl directed at a GM2 Reverb slot type. ```APIDOC ## fn reverb(reverb_type: Option, reverb_time: Option) -> Self ### Description Constructor for a GlobalParameterControl directed at a GM2 Reverb slot type. ### Parameters - **reverb_type** (Option) - Optional - The type of reverb to apply. - **reverb_time** (Option) - Optional - The time in seconds (0.36 - 9.0) for which the low frequency portion of the original sound declines by 60dB. ``` -------------------------------- ### ScaleTuning2Byte Struct Definition Source: https://docs.rs/midi-msg/latest/midi_msg/struct.ScaleTuning2Byte.html The primary structure for defining channel-specific high-resolution tuning adjustments. ```rust pub struct ScaleTuning2Byte { pub channels: ChannelBitMap, pub tuning: [i16; 12], } ``` -------------------------------- ### Constructing a FileDumpMsg Packet Source: https://docs.rs/midi-msg/latest/midi_msg/enum.FileDumpMsg.html?search=u32+-%3E+bool Use the packet method to construct a FileDumpMsg::Packet variant with a specific packet number and data payload. ```rust pub fn packet(num: u32, data: Vec) -> Self ``` -------------------------------- ### ScaleTuningDump1Byte Struct Definition Source: https://docs.rs/midi-msg/latest/midi_msg/struct.ScaleTuningDump1Byte.html The structure definition for ScaleTuningDump1Byte, containing tuning program and bank numbers, a 16-character name, and 12 semitone tuning adjustments. ```rust pub struct ScaleTuningDump1Byte { pub tuning_program_num: u8, pub tuning_bank_num: u8, pub name: [u8; 16], pub tuning: [i8; 12], } ``` -------------------------------- ### MidiFile::to_midi Source: https://docs.rs/midi-msg/latest/midi_msg/struct.MidiFile.html Serializes a MidiFile instance into a byte vector. ```APIDOC ## pub fn to_midi(&self) -> Vec ### Description Turn a `MidiFile` into a series of bytes. ### Returns - **Vec** - The serialized MIDI file data. ``` -------------------------------- ### MidiMsg Methods Source: https://docs.rs/midi-msg/latest/midi_msg/enum.MidiMsg.html?search=u32+-%3E+bool Methods for serializing, deserializing, and inspecting MIDI messages. ```APIDOC ## MidiMsg Methods ### to_midi Converts a `MidiMsg` into a `Vec` of bytes. ### from_midi Parses a slice of bytes into a `MidiMsg`. Returns a `Result` containing the `MidiMsg` and the number of bytes consumed. ### from_midi_with_context Parses bytes into a `MidiMsg` using a `ReceiverContext` to handle message extensions and state tracking. ### from_midi_with_context_no_extensions Parses bytes into a `MidiMsg` using a `ReceiverContext` without collapsing related consecutive messages. ### messages_to_midi Converts a slice of `MidiMsg` objects into a single `Vec`. ### extend_midi Appends the byte representation of the `MidiMsg` to an existing `Vec`. ### Inspection Methods - `is_channel_voice()`: Returns true if the message is a channel voice message. - `is_note_on()`: Returns true if the message is a note on message. - `is_note_off()`: Returns true if the message is a note off message. - `is_note()`: Returns true if the message is a note (on or off) message. - `is_cc()`: Returns true if the message is a control change message. - `is_channel_mode()`: Returns true if the message is a channel mode message. - `is_system_common()`: Returns true if the message is a system common message. - `is_system_real_time()`: Returns true if the message is a system real-time message. - `is_system_exclusive()`: Returns true if the message is a system exclusive message. - `is_meta()`: Returns true if the message is a meta message. - `is_invalid()`: Returns true if the message is an invalid message. ``` -------------------------------- ### Deserialize MIDI byte sequences Source: https://docs.rs/midi-msg/latest/midi_msg/index.html Convert raw MIDI byte sequences into MidiMsg structures. ```rust use midi_msg::*; // These are two MIDI 'note on' messages: let midi_bytes: Vec = vec![ 0x93, 0x66, 0x70, // First msg 0x93, 0x55, 0x60, // Second msg ]; let (msg, len) = MidiMsg::from_midi(&midi_bytes).expect("Not an error"); assert_eq!(len, 3); assert_eq!(msg, MidiMsg::ChannelVoice { channel: Channel::Ch4, msg: ChannelVoiceMsg::NoteOn { note: 0x66, velocity: 0x70 } }); ``` -------------------------------- ### Define ControllerDestination struct Source: https://docs.rs/midi-msg/latest/midi_msg/struct.ControllerDestination.html The structure definition for ControllerDestination, including the channel and a list of controlled parameter ranges. ```rust pub struct ControllerDestination { pub channel: Channel, pub param_ranges: Vec<(ControlledParameter, u8)>, } ``` -------------------------------- ### pub fn packet(num: u32, data: [u8; 120]) -> Self Source: https://docs.rs/midi-msg/latest/midi_msg/enum.SampleDumpMsg.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Constructs a new SampleDumpMsg packet from a packet number and a 120-byte data array. ```APIDOC ## pub fn packet(num: u32, data: [u8; 120]) -> Self ### Description Constructs a packet of exactly 120 7-bit bytes. The `num` parameter specifies the sequence number of the packet. ### Parameters - **num** (u32) - The packet number. - **data** ([u8; 120]) - The 120-byte data payload. ### Returns - **Self** - A new instance of SampleDumpMsg. ``` -------------------------------- ### ScaleTuningDump2Byte Struct Definition Source: https://docs.rs/midi-msg/latest/midi_msg/struct.ScaleTuningDump2Byte.html The structure definition for ScaleTuningDump2Byte, containing tuning program/bank numbers, a 16-character name, and 12 semitone tuning adjustments. ```rust pub struct ScaleTuningDump2Byte { pub tuning_program_num: u8, pub tuning_bank_num: u8, pub name: [u8; 16], pub tuning: [i16; 12], } ``` -------------------------------- ### WAVMap Struct Definition Source: https://docs.rs/midi-msg/latest/midi_msg/struct.WAVMap.html The structure definition for WAVMap, containing fields for MIDI bank, program, note range, tuning, and volume. ```rust pub struct WAVMap { pub dst_bank: u16, pub dst_prog: u8, pub base: u8, pub lokey: u8, pub hikey: u8, pub fine: i16, pub volume: u8, } ``` -------------------------------- ### Apply Program Change Message Source: https://docs.rs/midi-msg/latest/midi_msg/enum.GMSoundSet.html Use a GMSoundSet variant cast to u8 to construct a ProgramChange message. Note that this should not be used for channel 10, which is reserved for percussion. ```rust MidiMsg::ChannelVoice { channel: Channel::Ch1, msg: ChannelVoiceMsg::ProgramChange { program: GMSoundSet::Vibraphone as u8 } }; ``` -------------------------------- ### StandardTimeCode Methods Source: https://docs.rs/midi-msg/latest/midi_msg/struct.StandardTimeCode.html?search=std%3A%3Avec Methods available on the StandardTimeCode struct for byte serialization. ```APIDOC ## pub fn to_bytes(self) -> [u8; 5] ### Description Returns the five byte representation of the frame: [fractional_frames, frames, seconds, minutes, timecode + hours]. ## pub fn to_bytes_short(self) -> [u8; 2] ### Description Returns the two byte representation of the frame: [fractional_frames, frames]. ``` -------------------------------- ### TuningNoteChange Struct Definition Source: https://docs.rs/midi-msg/latest/midi_msg/struct.TuningNoteChange.html The structure definition for TuningNoteChange, containing the tuning program, bank, and a vector of note-tuning pairs. ```rust pub struct TuningNoteChange { pub tuning_program_num: u8, pub tuning_bank_num: Option, pub tunings: Vec<(u8, Option)>, } ``` -------------------------------- ### midi_note_cents_to_freq function signature Source: https://docs.rs/midi-msg/latest/midi_msg/fn.midi_note_cents_to_freq.html The function signature for calculating frequency from a MIDI note and cents. ```rust pub fn midi_note_cents_to_freq(note: u8, cents: f32) -> f32 ``` -------------------------------- ### Demonstrate failure without context Source: https://docs.rs/midi-msg/latest/midi_msg/index.html Shows that running status messages cannot be deserialized without tracking context. ```rust use midi_msg::*; let midi_bytes: Vec = vec![ 0x93, 0x66, 0x70, // First msg 0x55, 0x60, // Running status msg ]; let (_msg1, len1) = MidiMsg::from_midi(&midi_bytes).expect("Not an error"); MidiMsg::from_midi(&midi_bytes[len1..]).unwrap(); ``` -------------------------------- ### MidiMsg::from_midi_with_context Source: https://docs.rs/midi-msg/latest/midi_msg/index.html Deserializes a MIDI byte sequence using a ReceiverContext to handle stateful messages like running status. ```APIDOC ## MidiMsg::from_midi_with_context ### Description Deserializes a MIDI message while tracking state via `ReceiverContext`, which is required for messages using running status. ### Example ```rust use midi_msg::*; let mut ctx = ReceiverContext::new(); let midi_bytes: Vec = vec![0x93, 0x66, 0x70, 0x55, 0x60]; let (_msg1, len1) = MidiMsg::from_midi_with_context(&midi_bytes, &mut ctx).expect("Not an error"); let (msg2, len2) = MidiMsg::from_midi_with_context(&midi_bytes[len1..], &mut ctx).expect("Not an error"); ``` ``` -------------------------------- ### pub fn to_nibbles(&self) -> [u8; 9] Source: https://docs.rs/midi-msg/latest/midi_msg/struct.UserBits.html Converts the UserBits instance into its 9-nibble representation, which includes the byte data and flag bits. ```APIDOC ## pub fn to_nibbles(&self) -> [u8; 9] ### Description Converts the `UserBits` struct into a 9-nibble array representation. This is used to format the data for MIDI Time Code messages. ### Returns - **[u8; 9]** - An array containing the 9 nibbles: [nibble_1, nibble_2, nibble_3, nibble_4, nibble_5, nibble_6, nibble_7, nibble_8, nibble_9, nibble_flags]. ``` -------------------------------- ### MidiFile::extend_track Source: https://docs.rs/midi-msg/latest/midi_msg/struct.MidiFile.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Adds a MIDI event to a specific track. ```APIDOC ## pub fn extend_track(&mut self, track_num: usize, event: MidiMsg, beat_or_frame: f32) ### Description Adds a MIDI event to a track in the file, given its absolute beat or frame time. The delta time is calculated automatically based on the previous event and file division. ### Parameters - **track_num** (usize) - Required - The index of the track. - **event** (MidiMsg) - Required - The MIDI message to add. - **beat_or_frame** (f32) - Required - The absolute beat or frame time for the event. ``` -------------------------------- ### midi_note_float_to_freq Function Signature Source: https://docs.rs/midi-msg/latest/midi_msg/fn.midi_note_float_to_freq.html The function signature for converting a MIDI note float to a frequency. ```rust pub fn midi_note_float_to_freq(note: f32) -> f32 ``` -------------------------------- ### MidiMsg::from_midi Source: https://docs.rs/midi-msg/latest/midi_msg/index.html Deserializes a MIDI byte sequence into a MidiMsg instance. ```APIDOC ## MidiMsg::from_midi ### Description Deserializes a byte slice into a `MidiMsg` and returns the message along with the number of bytes consumed. ### Example ```rust use midi_msg::*; let midi_bytes: Vec = vec![0x93, 0x66, 0x70]; let (msg, len) = MidiMsg::from_midi(&midi_bytes).expect("Not an error"); ``` ``` -------------------------------- ### Define ControlChangeControllerDestination struct Source: https://docs.rs/midi-msg/latest/midi_msg/struct.ControlChangeControllerDestination.html The structure definition for ControlChangeControllerDestination, including fields for channel, control number, and parameter ranges. ```rust pub struct ControlChangeControllerDestination { pub channel: Channel, pub control_number: u8, pub param_ranges: Vec<(ControlledParameter, u8)>, } ```