### Serialization Example Source: https://docs.rs/midi-msg/0.9.0/src/midi_msg/system_exclusive/key_based_instrument_control.rs.html An example demonstrating the serialization of a KeyBasedInstrumentControl message, including handling of disallowed control numbers. ```APIDOC ## Test: serialize_controller_destination This test verifies the correct serialization of a `KeyBasedInstrumentControl` message. It includes a case where a disallowed control number (`0x06`) is provided, which should be automatically converted to `0x01` in the output MIDI bytes, as per the struct's logic. ``` -------------------------------- ### TryFrom Implementation Example Source: https://docs.rs/midi-msg/0.9.0/midi_msg/struct.TimeCodeStatus.html Demonstrates the conversion of a type into TimeCodeStatus using TryFrom. ```rust type Error = Infallible; fn try_from(value: U) -> Result>::Error> ``` -------------------------------- ### TryInto Implementation Example Source: https://docs.rs/midi-msg/0.9.0/midi_msg/struct.TimeCodeStatus.html Demonstrates the conversion of TimeCodeStatus into another type using TryInto. ```rust type Error = >::Error; fn try_into(self) -> Result>::Error> ``` -------------------------------- ### Serialize Time Code Cueing Setup System Stop Source: https://docs.rs/midi-msg/0.9.0/src/midi_msg/time_code.rs.html Serializes a MIDI Time Code Cueing Setup message for System Stop. This is used for non-real-time universal messages. ```rust assert_eq!( MidiMsg::SystemExclusive { msg: SystemExclusiveMsg::UniversalNonRealTime { msg: UniversalNonRealTimeMsg::TimeCodeCueingSetup( TimeCodeCueingSetupMsg::SystemStop ), }, } .to_midi(), vec![0xF0, 0x7E, 0x7f, 0x4, 00, 96, 00, 00, 00, 00, 0x4, 00, 0xF7] ); ``` -------------------------------- ### Example: Playing a Vibraslap Source: https://docs.rs/midi-msg/0.9.0/midi_msg/enum.GMPercussionMap.html Demonstrates how to create a NoteOn message for a Vibraslap using the GMPercussionMap enum on Channel 10. ```rust MidiMsg::ChannelVoice { channel: Channel::Ch10, msg: ChannelVoiceMsg::NoteOn { note: GMPercussionMap::Vibraslap as u8, velocity: 127 } }; ``` -------------------------------- ### Using GMSoundSet for Program Changes Source: https://docs.rs/midi-msg/0.9.0/midi_msg/enum.GMSoundSet.html Example demonstrating how to use the `GMSoundSet` enum to specify an instrument for a `ProgramChange` MIDI message. ```APIDOC ## Usage Example To set an instrument for a MIDI channel using a `ProgramChange` message, cast a `GMSoundSet` variant to `u8` to get its program number. ```rust MidiMsg::ChannelVoice { channel: Channel::Ch1, msg: ChannelVoiceMsg::ProgramChange { program: GMSoundSet::Vibraphone as u8 } }; ``` **Note:** This enum should not be used for channel 10, which is typically reserved for percussion. ``` -------------------------------- ### Serialize and Deserialize Simple Control Change with Running Status Source: https://docs.rs/midi-msg/0.9.0/src/midi_msg/message.rs.html This example shows how to serialize a Control Change message and its running status equivalent into a byte vector. It then prepares for deserialization, demonstrating the setup for reading back messages where running status might be applied. ```rust let cc = MidiMsg::ChannelVoice { channel: Channel::Ch1, msg: ChannelVoiceMsg::ControlChange { control: crate::ControlChange::Volume(0x7F), }, }; let running_cc = MidiMsg::RunningChannelVoice { channel: Channel::Ch1, msg: ChannelVoiceMsg::ControlChange { control: crate::ControlChange::Volume(0x7F), }, }; let simple_cc_msb = MidiMsg::ChannelVoice { channel: Channel::Ch1, msg: ChannelVoiceMsg::ControlChange { control: crate::ControlChange::CC { control: 7, value: 0, }, }, }; let simple_cc_lsb = MidiMsg::ChannelVoice { channel: Channel::Ch1, msg: ChannelVoiceMsg::ControlChange { control: crate::ControlChange::CC { control: 7 + 32, value: 0x7F, }, }, }; // Push two messages let mut midi = vec![]; cc.extend_midi(&mut midi); running_cc.extend_midi(&mut midi); // Read back 4 messages (two are running status messages) let mut offset = 0; let mut ctx = ReceiverContext::new(); ``` -------------------------------- ### General MIDI Sound Set Example Source: https://docs.rs/midi-msg/0.9.0/src/midi_msg/general_midi.rs.html Shows how to use a `GMSoundSet` enum value, like `Vibraphone`, as a program number in a `ChannelVoiceMsg::ProgramChange` message. ```rust MidiMsg::ChannelVoice { channel: Channel::Ch1, msg: ChannelVoiceMsg::ProgramChange { program: GMSoundSet::Vibraphone as u8 } }; ``` -------------------------------- ### Serialize Time Code Cueing Event Start (No Additional Info) Source: https://docs.rs/midi-msg/0.9.0/src/midi_msg/time_code.rs.html Serializes a MIDI Time Code Cueing message for Event Start with no additional information. The event number is 511. ```rust assert_eq!( MidiMsg::SystemExclusive { msg: SystemExclusiveMsg::UniversalRealTime { device: DeviceID::AllCall, msg: UniversalRealTimeMsg::TimeCodeCueing(TimeCodeCueingMsg::EventStart { event_number: 511, additional_information: vec![] }), }, } .to_midi(), vec![0xF0, 0x7F, 0x7f, 0x5, 0x5, 0x7f, 0x03, 0xF7] ); ``` -------------------------------- ### Serialize Time Code Cueing Event Start (With Additional Info) Source: https://docs.rs/midi-msg/0.9.0/src/midi_msg/time_code.rs.html Serializes a MIDI Time Code Cueing message for Event Start with additional information, including a Note On channel voice message. The event number is 511. ```rust assert_eq!( MidiMsg::SystemExclusive { msg: SystemExclusiveMsg::UniversalRealTime { device: DeviceID::AllCall, msg: UniversalRealTimeMsg::TimeCodeCueing(TimeCodeCueingMsg::EventStart { event_number: 511, additional_information: vec![MidiMsg::ChannelVoice { channel: Channel::Ch2, msg: ChannelVoiceMsg::NoteOn { note: 0x55, velocity: 0x67 } }] }), }, } .to_midi(), vec![ 0xF0, 0x7F, 0x7f, 0x5, 0x7, 0x7f, 0x03, // Note on midi msg: 0x91, 0x55, 0x67 0x01, 0x09, 0x05, 0x05, 0x07, 0x06, // End 0xF7 ] ); ``` -------------------------------- ### Serialize and Deserialize Various MIDI Messages Source: https://docs.rs/midi-msg/0.9.0/src/midi_msg/message.rs.html Demonstrates serializing multiple MIDI messages (Note On, Channel Mode, Control Change) into a byte vector and then deserializing them back using a context-aware parser. This example verifies that different message types can be interleaved and correctly parsed. ```rust let noteon = MidiMsg::ChannelVoice { channel: Channel::Ch1, msg: ChannelVoiceMsg::NoteOn { note: 0x60, velocity: 0x7F }, }; let running_noteon = MidiMsg::RunningChannelVoice { channel: Channel::Ch1, msg: ChannelVoiceMsg::NoteOn { note: 0x60, velocity: 0x7F }, }; let reset = MidiMsg::ChannelMode { channel: Channel::Ch1, msg: ChannelModeMsg::ResetAllControllers, }; let running_reset = MidiMsg::RunningChannelMode { channel: Channel::Ch1, msg: ChannelModeMsg::ResetAllControllers, }; let cc = MidiMsg::ChannelVoice { channel: Channel::Ch1, msg: ChannelVoiceMsg::ControlChange { control: crate::ControlChange::Volume(0x7F), }, }; let running_cc = MidiMsg::RunningChannelVoice { channel: Channel::Ch1, msg: ChannelVoiceMsg::ControlChange { control: crate::ControlChange::Volume(0x7F), }, }; // Push 10 messages let mut midi = vec![]; noteon.extend_midi(&mut midi); running_noteon.extend_midi(&mut midi); // Ensure that channel mode messages can follow one another reset.extend_midi(&mut midi); running_reset.extend_midi(&mut midi); // Ensure that control changes can follow one another cc.extend_midi(&mut midi); running_cc.extend_midi(&mut midi); // Ensure that control changes and channel mode messages can follow one another reset.extend_midi(&mut midi); running_cc.extend_midi(&mut midi); cc.extend_midi(&mut midi); running_reset.extend_midi(&mut midi); // Read back ten messages let mut offset = 0; let mut ctx = ReceiverContext::new().complex_cc(); let (msg1, len) = MidiMsg::from_midi_with_context(&midi, &mut ctx).expect("Not an error"); offset += len; let (msg2, len) = MidiMsg::from_midi_with_context(&midi[offset..], &mut ctx).expect("Not an error"); offset += len; let (msg3, len) = MidiMsg::from_midi_with_context(&midi[offset..], &mut ctx).expect("Not an error"); offset += len; let (msg4, len) = MidiMsg::from_midi_with_context(&midi[offset..], &mut ctx).expect("Not an error"); offset += len; let (msg5, len) = MidiMsg::from_midi_with_context(&midi[offset..], &mut ctx).expect("Not an error"); offset += len; let (msg6, len) = MidiMsg::from_midi_with_context(&midi[offset..], &mut ctx).expect("Not an error"); offset += len; let (msg7, len) = MidiMsg::from_midi_with_context(&midi[offset..], &mut ctx).expect("Not an error"); offset += len; let (msg8, len) = MidiMsg::from_midi_with_context(&midi[offset..], &mut ctx).expect("Not an error"); offset += len; let (msg9, len) = MidiMsg::from_midi_with_context(&midi[offset..], &mut ctx).expect("Not an error"); offset += len; let (msg10, _) = MidiMsg::from_midi_with_context(&midi[offset..], &mut ctx).expect("Not an error"); // The expected messages are not running status messages, since we never deserialize into them assert_eq!(msg1, noteon); assert_eq!(msg2, noteon); assert_eq!(msg3, reset); assert_eq!(msg4, reset); assert_eq!(msg5, cc); assert_eq!(msg6, cc); assert_eq!(msg7, reset); assert_eq!(msg8, cc); assert_eq!(msg9, cc); assert_eq!(msg10, reset); } ``` -------------------------------- ### SystemExclusiveMsg Serialization Source: https://docs.rs/midi-msg/0.9.0/src/midi_msg/system_exclusive/mod.rs.html Examples demonstrating how to serialize different types of System Exclusive MIDI messages into their byte representations. ```APIDOC ## SystemExclusiveMsg Serialization Examples This section shows how to convert various `SystemExclusiveMsg` variants into their corresponding MIDI byte sequences using the `to_midi()` method. ### Commercial System Exclusive (Single Manufacturer ID) ```rust MidiMsg::SystemExclusive { msg: SystemExclusiveMsg::Commercial { id: 1.into(), data: vec![0xff, 0x77, 0x00] } }.to_midi() ``` **Expected Output:** ``` [0xF0, 0x01, 0x7F, 0x77, 0x00, 0xF7] ``` ### Commercial System Exclusive (Two-Part Manufacturer ID) ```rust MidiMsg::SystemExclusive { msg: SystemExclusiveMsg::Commercial { id: (1, 3).into(), data: vec![0xff, 0x77, 0x00] } }.to_midi() ``` **Expected Output:** ``` [0xF0, 0x00, 0x01, 0x03, 0x7F, 0x77, 0x00, 0xF7] ``` ### Non-Commercial System Exclusive ```rust MidiMsg::SystemExclusive { msg: SystemExclusiveMsg::NonCommercial { data: vec![0xff, 0x77, 0x00] } }.to_midi() ``` **Expected Output:** ``` [0xF0, 0x7D, 0x7F, 0x77, 0x00, 0xF7] ``` ### Universal Non-Real-Time System Exclusive ```rust MidiMsg::SystemExclusive { msg: SystemExclusiveMsg::UniversalNonRealTime { device: DeviceID::AllCall, msg: UniversalNonRealTimeMsg::EOF } }.to_midi() ``` **Expected Output:** ``` [0xF0, 0x7E, 0x7F, 0x7B, 0x00, 0xF7] ``` ### Universal Real-Time System Exclusive ```rust MidiMsg::SystemExclusive { msg: SystemExclusiveMsg::UniversalRealTime { device: DeviceID::Device(3), msg: UniversalRealTimeMsg::MasterVolume(1000) } }.to_midi() ``` **Expected Output:** ``` [0xF0, 0x7F, 0x03, 0x04, 0x00, 0x32, 0x00, 0xF7] ``` ``` -------------------------------- ### Serialize MIDI Channel Voice Messages Source: https://docs.rs/midi-msg/0.9.0/src/midi_msg/channel_voice.rs.html Demonstrates serialization of various MIDI Channel Voice messages, including HighResNoteOn and different types of ControlChange messages. These examples are useful for testing the encoding of different MIDI events. ```rust test_serialization( MidiMsg::ChannelVoice { channel: Channel::Ch3, msg: ChannelVoiceMsg::HighResNoteOn { note: 77, velocity: 1000, }, }, &mut ctx, ); ``` ```rust test_serialization( MidiMsg::ChannelVoice { channel: Channel::Ch2, msg: ChannelVoiceMsg::ControlChange { control: ControlChange::Parameter(Parameter::FineTuningEntry(-30)), }, }, &mut ctx, ); ``` ```rust test_serialization( MidiMsg::ChannelVoice { channel: Channel::Ch2, msg: ChannelVoiceMsg::ControlChange { control: ControlChange::Parameter(Parameter::Gain3DSoundEntry(1001)), }, }, &mut ctx, ); ``` ```rust test_serialization( MidiMsg::ChannelVoice { channel: Channel::Ch2, msg: ChannelVoiceMsg::ControlChange { control: ControlChange::Parameter(Parameter::PitchBendSensitivityEntry(4, 78)), }, }, &mut ctx, ); ``` ```rust test_serialization( MidiMsg::ChannelVoice { channel: Channel::Ch2, msg: ChannelVoiceMsg::ControlChange { control: ControlChange::GeneralPurpose1(50), }, }, &mut ctx, ); ``` -------------------------------- ### Create and Populate MIDI File Source: https://docs.rs/midi-msg/0.9.0/src/midi_msg/file.rs.html Demonstrates setting the MIDI file header, adding a track, and extending it with various MIDI messages including track name, time signature, note on/off, and end of track. Also shows conversion to bytes and deserialization for verification. ```rust file.header.division = Division::TicksPerQuarterNote(480); file.add_track(Track::default()); file.extend_track( 0, MidiMsg::Meta { msg: Meta::TrackName("Test Track".to_string()), }, 0.0, ); file.extend_track( 0, MidiMsg::Meta { msg: Meta::TimeSignature(FileTimeSignature { numerator: 4, denominator: 4, clocks_per_metronome_tick: 24, thirty_second_notes_per_24_clocks: 8, }), }, 0.0, ); file.extend_track( 0, MidiMsg::ChannelVoice { channel: Channel::Ch1, msg: ChannelVoiceMsg::NoteOn { note: 60, velocity: 64, }, }, 0.0, ); file.extend_track( 0, MidiMsg::ChannelVoice { channel: Channel::Ch1, msg: ChannelVoiceMsg::NoteOff { note: 60, velocity: 64, }, }, 1.0, ); file.extend_track( 0, MidiMsg::Meta { msg: Meta::EndOfTrack, }, 2.0, ); // Convert the file to bytes let bytes = file.to_midi(); // Assert that we've created a valid MIDI file assert!(bytes.starts_with(b"MThd")); assert!(bytes[14..].starts_with(b"MTrk")); let deserialized_file = MidiFile::from_midi(&bytes).unwrap(); assert_eq!(deserialized_file.tracks.len(), 1); assert_eq!(deserialized_file.tracks[0].events().len(), 5); assert_eq!( deserialized_file.header.division, Division::TicksPerQuarterNote(480) ); assert_eq!(deserialized_file, file); ``` -------------------------------- ### Create and Serialize a MidiFile Source: https://docs.rs/midi-msg/0.9.0/src/midi_msg/lib.rs.html Demonstrates creating a MidiFile with a single track, adding Note On, Note Off, and End of Track messages with specified timings, then serializing it to bytes and deserializing it back. ```rust # #[cfg(feature = "file")] # fn main() { 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); # } # # #[cfg(not(feature = "file"))] # fn main() {} ``` -------------------------------- ### Working with Midi Files Source: https://docs.rs/midi-msg Illustrates how to create, serialize, and deserialize Standard MIDI Files (SMF) using the `MidiFile` struct and its associated methods. ```APIDOC ## Midi files We can work with Standard Midi Files (SMF) in much the same way. The `MidiFile` struct represents this data type and it can be serialized into a `Vec` and deserialized from a `Vec`. It holds a header and a list of tracks. Regular `Track::Midi` tracks contains a list of `MidiMsg` events along with the “delta time” that separates subsequent ones. The definition of the delta time is given by the `division` field in the `Header`. Convenience functions are provided for constructing a `MidiFile` based on a series of events and absolute beat or frame timings. For example, the following creates a `MidiFile` with a single track containing a single note. ```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); ``` ``` -------------------------------- ### Creating MIDI Byte Sequences Source: https://docs.rs/midi-msg Demonstrates how to create a `MidiMsg` and serialize it into a `Vec` using the `to_midi()` method. ```APIDOC ## Creating MIDI Byte Sequences `MidiMsg` is the starting point for all MIDI messages. All `MidiMsg`s can be serialized into a valid MIDI sequence. You can create a `MidiMsg` and turn it into a `Vec` like so: ```rust use midi_msg::* MidiMsg::ChannelVoice { channel: Channel::Ch1, msg: ChannelVoiceMsg::NoteOn { note: 60, velocity: 127 } } .to_midi(); ``` ``` -------------------------------- ### Create and Serialize MidiFile Source: https://docs.rs/midi-msg/0.9.0/index.html Construct a `MidiFile` with tracks, notes, and meta-messages, then serialize it into a `Vec` using `to_midi()`. This is useful for creating MIDI files programmatically. ```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); ``` -------------------------------- ### Get TypeId of ManufacturerID Source: https://docs.rs/midi-msg/0.9.0/midi_msg/struct.ManufacturerID.html Retrieves the TypeId of the ManufacturerID. This is part of the Any trait implementation. ```rust fn type_id(&self) -> TypeId; ``` -------------------------------- ### Create ChannelBitMap with All Channels Set Source: https://docs.rs/midi-msg/0.9.0/midi_msg/struct.ChannelBitMap.html Use the `all()` associated function to create a ChannelBitMap where all 16 channels are enabled. ```rust pub fn all() -> Self ``` -------------------------------- ### TimeCodeCueingSetupMsg Enum Source: https://docs.rs/midi-msg/0.9.0/src/midi_msg/time_code.rs.html Represents various non-realtime Time Code Cueing Setup messages. ```APIDOC ## Enum: TimeCodeCueingSetupMsg ### Description Non-realtime Time Code Cueing. Used by [`UniversalNonRealTimeMsg::TimeCodeCueingSetup`](crate::UniversalNonRealTimeMsg::TimeCodeCueingSetup). As defined in the MIDI Time Code spec (MMA0001 / RP004 / RP008) ### Variants - **TimeCodeOffset** { `time_code`: HighResTimeCode } - **EnableEventList** - **DisableEventList** - **ClearEventList** - **SystemStop** - **EventListRequest** { `time_code`: HighResTimeCode } - **PunchIn** { `time_code`: HighResTimeCode, `event_number`: u16 } - **PunchOut** { `time_code`: HighResTimeCode, `event_number`: u16 } - **DeletePunchIn** { `time_code`: HighResTimeCode, `event_number`: u16 } - **DeletePunchOut** { `time_code`: HighResTimeCode, `event_number`: u16 } - **EventStart** { `time_code`: HighResTimeCode, `event_number`: u16, `additional_information`: Vec } - **EventStop** { `time_code`: HighResTimeCode, `event_number`: u16, `additional_information`: Vec } - **DeleteEventStart** { `time_code`: HighResTimeCode, `event_number`: u16 } - **DeleteEventStop** { `time_code`: HighResTimeCode, `event_number`: u16 } - **Cue** { `time_code`: HighResTimeCode, `event_number`: u16, `additional_information`: Vec } - **DeleteCue** { `time_code`: HighResTimeCode, `event_number`: u16 } - **EventName** { `time_code`: HighResTimeCode, `event_number`: u16, `name`: BString } ``` -------------------------------- ### take Source: https://docs.rs/midi-msg/0.9.0/midi_msg/struct.ChannelIter.html Creates an iterator that yields the first `n` elements. ```APIDOC ## fn take(self, n: usize) -> Take ### Description Creates an iterator that yields the first `n` elements, or fewer if the underlying iterator ends sooner. ### Parameters - `n`: The maximum number of elements to yield. ### Returns A new iterator that yields at most `n` elements. ``` -------------------------------- ### Get Track Events Source: https://docs.rs/midi-msg/0.9.0/src/midi_msg/file.rs.html Returns a slice of TrackEvents for a Midi track. Returns an empty slice for an AlienChunk. ```rust pub fn events(&self) -> &[TrackEvent] { match self { Track::Midi(events) => events, Track::AlienChunk(_) => &[], } } ``` -------------------------------- ### Creating and Serializing MIDI Messages Source: https://docs.rs/midi-msg/0.9.0/src/midi_msg/lib.rs.html Demonstrates how to construct a `MidiMsg` and serialize it into a `Vec`. ```APIDOC ## Creating MIDI byte sequences [`MidiMsg`] is the starting point for all MIDI messages. All `MidiMsg`s can be serialized into a valid MIDI sequence. You can create a `MidiMsg` and turn it into a `Vec` like so: ```rust use midi_msg::* MidiMsg::ChannelVoice { channel: Channel::Ch1, msg: ChannelVoiceMsg::NoteOn { note: 60, velocity: 127 } } .to_midi(); ``` ``` -------------------------------- ### Iterator Implementation for GMSoundSetIter Source: https://docs.rs/midi-msg/0.9.0/midi_msg/struct.GMSoundSetIter.html Core iterator functionality, including getting the next item and size hints. ```rust type Item = GMSoundSet ``` ```rust fn next(&mut self) -> Option<::Item> ``` ```rust fn size_hint(&self) -> (usize, Option) ``` ```rust fn nth(&mut self, n: usize) -> Option<::Item> ``` ```rust fn next_chunk( &mut self, ) -> Result<[Self::Item; N], IntoIter> where Self: Sized, ``` ```rust fn count(self) -> usize where Self: Sized, ``` ```rust fn last(self) -> Option where Self: Sized, ``` ```rust fn advance_by(&mut self, n: usize) -> Result<(), NonZero> ``` ```rust fn step_by(self, step: usize) -> StepBy where Self: Sized, ``` ```rust fn chain(self, other: U) -> Chain::IntoIter> where Self: Sized, U: IntoIterator, ``` ```rust fn zip(self, other: U) -> Zip::IntoIter> where Self: Sized, U: IntoIterator, ``` ```rust fn intersperse(self, separator: Self::Item) -> Intersperse where Self: Sized, Self::Item: Clone, ``` ```rust fn intersperse_with(self, separator: G) -> IntersperseWith where Self: Sized, G: FnMut() -> Self::Item, ``` -------------------------------- ### Get Track Length Source: https://docs.rs/midi-msg/0.9.0/midi_msg/enum.Track.html Retrieves the number of events in a MIDI track or the byte length of an alien chunk. ```rust pub fn len(&self) -> usize ``` -------------------------------- ### Implement Default for SoundFileMap Source: https://docs.rs/midi-msg/0.9.0/src/midi_msg/system_exclusive/file_reference.rs.html Provides a default configuration for `SoundFileMap`. ```rust impl Default for SoundFileMap { fn default() -> Self { Self { dst_bank: 0, dst_prog: 0, src_bank: 0, src_prog: 0, src_drum: false, dst_drum: false, volume: 0x7F, } } } ``` -------------------------------- ### from Source: https://docs.rs/midi-msg/0.9.0/midi_msg/enum.UniversalNonRealTimeMsg.html Creates a new instance from the given value. Returns the argument unchanged. ```APIDOC ## fn from(t: T) -> T ### Description Returns the argument unchanged. ### Method `from` ``` -------------------------------- ### ControllerDestination Implementation Source: https://docs.rs/midi-msg/0.9.0/src/midi_msg/system_exclusive/controller_destination.rs.html Provides methods for `ControllerDestination`, including `extend_midi` to serialize the destination into MIDI bytes and a placeholder `from_midi` for deserialization. ```rust impl ControllerDestination { pub(crate) fn extend_midi(&self, v: &mut Vec) { v.push(self.channel as u8); for (p, r) in self.param_ranges.iter() { v.push(*p as u8); push_u7(*r, v); } } #[allow(dead_code)] pub(crate) fn from_midi(_m: &[u8]) -> Result<(Self, usize), ParseError> { Err(ParseError::NotImplemented("ControllerDestination")) } } ``` -------------------------------- ### BarMarker Enum Definition Source: https://docs.rs/midi-msg/0.9.0/midi_msg/enum.BarMarker.html Defines the possible variants for BarMarker, indicating the start of a new measure in MIDI messages. ```APIDOC ## Enum BarMarker ### Summary ``` pub enum BarMarker { NotRunning, CountIn(u16), Number(u16), RunningUnknown, } ``` ### Description Indicates that the next MIDI clock message is the first clock of a new measure. Which bar is optionally indicated by this message. Used by `UniversalRealTimeMsg::BarMarker`. ### Variants #### NotRunning “Actually, we’re not running right now, so there is no bar.” Don’t know why this is used. #### CountIn(u16) The bar is a count-in and are thus negative numbers from 8191-0. #### Number(u16) A regular bar numbered 1-8191. #### RunningUnknown Next clock message will be a new bar, but it’s not known what its number is. ``` -------------------------------- ### Deprecated Cause Method for MidiFileParseError Source: https://docs.rs/midi-msg/0.9.0/midi_msg/struct.MidiFileParseError.html Deprecated method for getting the cause of the error. Use Error::source instead. ```rust fn cause(&self) -> Option<&dyn Error> ``` -------------------------------- ### Implement Default for WAVMap Source: https://docs.rs/midi-msg/0.9.0/src/midi_msg/system_exclusive/file_reference.rs.html Provides a default configuration for `WAVMap`. ```rust impl Default for WAVMap { fn default() -> Self { Self { dst_bank: 0, dst_prog: 0, base: 60, lokey: 0, hikey: 0x7F, fine: 0, volume: 0x7F, } } } ``` -------------------------------- ### Track Methods Source: https://docs.rs/midi-msg/0.9.0/midi_msg/enum.Track.html Provides methods to interact with the Track enum, such as getting the number of events, checking if empty, and retrieving events. ```APIDOC ### impl Track #### pub fn len(&self) -> usize Get the number of events in the track, or the length in bytes of an `AlienChunk`. #### pub fn is_empty(&self) -> bool #### pub fn events(&self) -> &[TrackEvent] Get the `TrackEvent` events in the track. Will be empty for an `AlienChunk`. ``` -------------------------------- ### Deprecated Description Method for MidiFileParseError Source: https://docs.rs/midi-msg/0.9.0/midi_msg/struct.MidiFileParseError.html Deprecated method for getting a string description of the error. Use the Display implementation or to_string() instead. ```rust fn description(&self) -> &str ``` -------------------------------- ### Deserializing with Context (Running Status) Source: https://docs.rs/midi-msg Explains and demonstrates the use of `MidiMsg::from_midi_with_context` for deserializing messages that rely on running status. ```APIDOC ## Deserializing MIDI Byte Sequences with Context Similarly, `MidiMsg::from_midi_with_context` can be used to track the state associated with a MIDI stream, which is necessary to deserialize certain messages: ```rust use midi_msg::* let mut ctx = ReceiverContext::new(); // This is a three-byte MIDI 'note on' message followed by a two-byte "running status" // 'note on' message, which inherits its first ("status") byte from the last `ChannelModeMsg`: let midi_bytes: Vec = vec![ 0x93, 0x66, 0x70, // First msg 0x55, 0x60, // Running status msg ]; 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"); assert_eq!(len2, 2); assert_eq!(msg2, MidiMsg::ChannelVoice { channel: Channel::Ch4, msg: ChannelVoiceMsg::NoteOn { note: 0x55, velocity: 0x60 } }); ``` The previous message would not have been deserializable without the 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(); ``` ``` -------------------------------- ### SystemRealTimeMsg Enum Variants Source: https://docs.rs/midi-msg/0.9.0/midi_msg/enum.SystemRealTimeMsg.html The SystemRealTimeMsg enum includes variants for TimingClock, Start, Continue, Stop, ActiveSensing, and SystemReset, used for device synchronization. ```APIDOC ## Enum SystemRealTimeMsg ### Summary ``` pub enum SystemRealTimeMsg { TimingClock, Start, Continue, Stop, ActiveSensing, SystemReset, } ``` A fairly limited set of messages used for device synchronization. Used in `MidiMsg`. ### Variants #### TimingClock Used to synchronize clocks. Sent at a rate of 24 per quarter note. #### Start Start at the beginning of the song or sequence. #### Continue Continue from the current location in the song or sequence. #### Stop Stop playback. #### ActiveSensing Sent every 300ms or less whenever other MIDI data is not sent. Used to indicate that the given device is still connected. #### SystemReset Request that all devices are reset to their power-up state. This is not a valid message in a MIDI file, since it overlaps with the MIDI file’s Meta messages. If you add this message to a MIDI file, it will be ignored upon serialization. ``` -------------------------------- ### Construct Universal Real-Time Messages Source: https://docs.rs/midi-msg/0.9.0/src/midi_msg/system_exclusive/mod.rs.html Illustrates how to construct different types of Universal Real-Time MIDI messages by extending a byte vector. ```rust v.push(if note_change.tuning_bank_num.is_some() { 0x7 } else { 0x2 }); if let Some(bank_num) = note_change.tuning_bank_num { v.push(to_u7(bank_num)) } note_change.extend_midi(v); ``` ```rust v.push(0x8); v.push(0x8); tuning.extend_midi(v); ``` ```rust v.push(0x8); v.push(0x9); tuning.extend_midi(v); ``` ```rust v.push(0x9); v.push(0x1); d.extend_midi(v); ``` ```rust v.push(0x9); v.push(0x2); d.extend_midi(v); ``` ```rust v.push(0x9); v.push(0x3); d.extend_midi(v); ``` ```rust v.push(0xA); v.push(0x1); control.extend_midi(v); ``` -------------------------------- ### Constructing Global Parameter Messages Source: https://docs.rs/midi-msg/0.9.0/src/midi_msg/system_exclusive/global_parameter.rs.html Demonstrates how to construct a System Exclusive message for global parameter control, specifically setting chorus parameters. This includes specifying chorus type, modulation rate, and reverb send level. ```rust assert_eq!( MidiMsg::SystemExclusive { msg: SystemExclusiveMsg::UniversalRealTime { device: DeviceID::AllCall, msg: UniversalRealTimeMsg::GlobalParameterControl( GlobalParameterControl::chorus( Some(ChorusType::Flanger), Some(1.1), None, None, Some(100.0) ) ), }, } .to_midi(), vec![ 0xF0, 0x7F, 0x7F, // Receiver device 0x4, 0x5, 0x1, // Slot path length 0x1, // Param ID width 0x1, // Value width 0x1, // Slot path 1 MSB 0x2, // Slot path 1 LSB 0x0, // Param number 1: chorus type 0x5, // Param value 1 0x1, // Param number 2: mod rate 0x9, // Param value 2 0x4, // Param number 3: send to reverb 0x7F, // Param value 3 0xF7 ] ); ``` -------------------------------- ### Using GMSoundSet for Program Change Source: https://docs.rs/midi-msg/0.9.0/midi_msg/enum.GMSoundSet.html Demonstrates how to create a ProgramChange message using a GMSoundSet variant. Cast the enum variant to u8 to get the program number. ```rust MidiMsg::ChannelVoice { channel: Channel::Ch1, msg: ChannelVoiceMsg::ProgramChange { program: GMSoundSet::Vibraphone as u8 } }; ``` -------------------------------- ### Channel Conversion TryFrom u8 Source: https://docs.rs/midi-msg/0.9.0/midi_msg/enum.Channel.html Demonstrates the `TryFrom` implementation for converting a `u8` to a `Channel`, which returns a `Result` to handle potential errors. ```APIDOC ## `try_from` (u8) ### Description Attempts to convert a `u8` value into a `Channel` enum variant. This method returns a `Result` to indicate success or failure. ### Trait `impl TryFrom for Channel` ### Method `fn try_from(value: u8) -> Result` ### Parameters - `value` (u8) - The `u8` value to convert. ### Returns A `Result` containing the `Channel` enum variant if the `u8` is valid (0-15), or an error (`&'static str`) if the `u8` is out of range. ### Example ```rust let channel_result = Channel::try_from(12); match channel_result { Ok(channel) => println!("Channel: {:?}", channel), // Channel: Ch13 Err(e) => println!("Error: {}", e), } let invalid_channel_result = Channel::try_from(16); // invalid_channel_result will be an Err ``` ``` -------------------------------- ### ParseCtx Helper Methods Source: https://docs.rs/midi-msg/0.9.0/src/midi_msg/file.rs.html Provides utility methods for the `ParseCtx`, including advancing the offset, getting the remaining data slice, slicing input, and updating the parsing state. ```rust fn advance(&mut self, offset: usize) { self.offset += offset; } fn data(&self) -> &[u8] { &self.input[self.offset..] } fn slice(&self, range: ops::Range) -> &[u8] { &self.input[range.start + self.offset..range.end + self.offset] } fn remaining(&self) -> usize { self.input.len() - self.offset } fn parsing>(&mut self, s: S) { self.parsing = s.into(); } ``` -------------------------------- ### Serialize Universal Real-Time System Exclusive Message Source: https://docs.rs/midi-msg/0.9.0/src/midi_msg/system_exclusive/mod.rs.html Serializes a Universal Real-Time System Exclusive MIDI message. This example demonstrates a Master Volume message for a specific device. ```rust assert_eq!( MidiMsg::SystemExclusive { msg: SystemExclusiveMsg::UniversalRealTime { device: DeviceID::Device(3), msg: UniversalRealTimeMsg::MasterVolume(1000) } } .to_midi(), ``` -------------------------------- ### Test Key Signature Parsing and Serialization Source: https://docs.rs/midi-msg/0.9.0/src/midi_msg/file.rs.html Verifies that `KeySignature::from_midi` correctly parses MIDI data and that `extend_midi` serializes it back to the original data. ```rust #[test] fn test_key_signature() { let midi_data = vec![2, 0]; let key_sig = KeySignature::from_midi(&midi_data).unwrap(); assert_eq!(key_sig.key, 2); assert_eq!(key_sig.scale, 0); let mut output = Vec::new(); key_sig.extend_midi(&mut output); assert_eq!(output, midi_data); } ``` -------------------------------- ### sysex_bytes_from_midi Function Source: https://docs.rs/midi-msg/0.9.0/src/midi_msg/system_exclusive/mod.rs.html Extracts the raw System Exclusive message bytes from a slice of MIDI bytes. It handles the optional F0 start byte and ensures the message is properly terminated with F7. ```APIDOC fn sysex_bytes_from_midi(m: &[u8], first_byte_is_f0: bool) -> Result<&[u8], ParseError> { if first_byte_is_f0 && m.first() != Some(&0xF0) { return Err(ParseError::UndefinedSystemExclusiveMessage( m.first().copied(), )); } let offset = if first_byte_is_f0 { 1 } else { 0 }; for (i, b) in m[offset..].iter().enumerate() { if b == &0xF7 { return Ok(&m[offset..i + offset]); } if b > &127 { return Err(ParseError::ByteOverflow); } } Err(ParseError::NoEndOfSystemExclusiveFlag) } } ``` -------------------------------- ### SystemRealTimeMsg Enum Definition Source: https://docs.rs/midi-msg/0.9.0/src/midi_msg/system_real_time.rs.html Defines the SystemRealTimeMsg enum with variants for timing clock, start, continue, stop, active sensing, and system reset. Includes derive attributes for serialization and debugging. ```rust 1use super::parse_error::*; 2use alloc::vec::Vec; 3 4/// A fairly limited set of messages used for device synchronization. 5/// Used in [`MidiMsg`](crate::MidiMsg). 6#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] 7#[derive(Debug, Clone, Copy, PartialEq, Eq)] 8pub enum SystemRealTimeMsg { 9 /// Used to synchronize clocks. Sent at a rate of 24 per quarter note. 10 TimingClock, 11 /// Start at the beginning of the song or sequence. 12 Start, 13 /// Continue from the current location in the song or sequence. 14 Continue, 15 /// Stop playback. 16 Stop, 17 /// Sent every 300ms or less whenever other MIDI data is not sent. 18 /// Used to indicate that the given device is still connected. 19 ActiveSensing, 20 /// Request that all devices are reset to their power-up state. 21 /// 22 /// This is not a valid message in a MIDI file, since it overlaps 23 /// with the MIDI file's Meta messages. If you add this message to a 24 /// MIDI file, it will be ignored upon serialization. 25 SystemReset, 26} ``` -------------------------------- ### Default MidiFile Source: https://docs.rs/midi-msg/0.9.0/midi_msg/struct.MidiFile.html Creates a MidiFile with default values. ```rust fn default() -> MidiFile ``` -------------------------------- ### PartialEq Implementation for KeySignature Source: https://docs.rs/midi-msg/0.9.0/midi_msg/struct.KeySignature.html Illustrates the `eq` method for comparing two KeySignature instances for equality, as part of the `PartialEq` trait implementation. ```rust fn eq(&self, other: &KeySignature) -> bool ``` -------------------------------- ### Serialize Universal Non-Real-Time System Exclusive Message Source: https://docs.rs/midi-msg/0.9.0/src/midi_msg/system_exclusive/mod.rs.html Serializes a Universal Non-Real-Time System Exclusive MIDI message. This example shows the EOF (End of File) message for a device set to 'AllCall'. ```rust assert_eq!( MidiMsg::SystemExclusive { msg: SystemExclusiveMsg::UniversalNonRealTime { device: DeviceID::AllCall, msg: UniversalNonRealTimeMsg::EOF } } .to_midi(), vec![0xF0, 0x7E, 0x7F, 0x7B, 0x00, 0xF7] ); ```