22 releases

0.2.12-alpha.0 Apr 7, 2023
0.2.11-alpha.0 Dec 19, 2022
0.2.5-alpha.0 Jun 21, 2022
0.2.4-alpha.0 Mar 14, 2022
0.1.42-alpha.0 Oct 27, 2021

#2 in #surge

Download history 6/week @ 2024-02-20 22/week @ 2024-02-27 6/week @ 2024-03-05 7/week @ 2024-03-12 6/week @ 2024-03-19 31/week @ 2024-03-26 10/week @ 2024-04-02

54 downloads per month
Used in 3 crates

GPL-3.0 license

145KB
1.5K SLoC

surge-midi - Rust Crate for MIDI Control in Surge Synthesizer System

MIDIUnitHandle

A MIDIUnitHandle is a unique identifier for a MIDI unit in the Surge Synthesizer system. It is used to manipulate the MIDI parameters associated with the unit.

channel_state_ptr

A channel_state_ptr is a pointer to a MidiChannelState struct that stores the state of a MIDI channel. This struct contains information such as the current program, pitch bend, and pressure values for the channel.

clear_keystate

clear_keystate is a function that clears the state of all keys on a MIDI channel.

default

default is a constant that represents the default value for a MIDI parameter.

get_nrpn

get_nrpn is a function that retrieves the current non-registered parameter number (NRPN) value for a MIDI channel.

get_nrpn_v

get_nrpn_v is a function that retrieves the current NRPN value and range for a MIDI channel.

get_rpn

get_rpn is a function that retrieves the current registered parameter number (RPN) value for a MIDI channel.

get_rpn_v

get_rpn_v is a function that retrieves the current RPN value and range for a MIDI channel.

hold

hold is a constant that represents a hold message for a MIDI parameter.

keystate

A keystate is a struct that stores the state of a key on a MIDI channel. It contains information such as the current pitch bend and pressure values for the key.

keystate_ptr

A keystate_ptr is a pointer to a MidiKeyState struct that stores the state of a key on a MIDI channel.

lastdetune

lastdetune is a constant that represents the last detune value for a MIDI parameter.

learn_custom

learn_custom is a function that learns a custom MIDI parameter.

learn_param

learn_param is a function that learns a MIDI parameter.

load_midi_controllers

load_midi_controllers is a function that loads MIDI controllers for a given MIDI channel.

nrpn_last

nrpn_last is a constant that represents the last non-registered parameter number (NRPN) value for a MIDI parameter.

save_midi_controllers

save_midi_controllers is a function that saves MIDI controllers for a given MIDI channel.

set_hold

set_hold is a function that sets the hold value for a MIDI parameter.

set_keystate

set_keystate is a function that sets the state of a key on a MIDI channel.

set_lastdetune

set_lastdetune is a function that sets the last detune value for a MIDI parameter.

set_learn_custom

set_learn_custom is a function that sets whether a custom MIDI parameter is learned.

set_learn_param

set_learn_param is a function that sets whether a MIDI parameter is learned.

set_nrpn

set_nrpn is a function that sets the non-registered parameter number (NRPN) value for a MIDI parameter.

set_nrpn_last

set_nrpn_last is a function that sets the last non-registered parameter number (NRPN) value for a MIDI parameter.

set_nrpn_v

set_nrpn_v is a function that sets the non-registered parameter number (NRPN) value and range for a MIDI parameter.

set_pan

set_pan is a function that sets the pan value for a MIDI parameter.

set_pitchbend

set_pitchbend is a function that sets the pitch bend value for a MIDI parameter. The pitch bend value is a 14-bit signed integer that represents the amount of pitch bend in semitones. The value can range from -8192 to 8191, with 0 representing no pitch bend.

The pitch bend value can be calculated using the following equation:

pitch_bend = (value - 8192) / 8192.0 * max_pitch_bend_semitones

where value is the 14-bit signed integer value of the pitch bend message, max_pitch_bend_semitones is the maximum amount of pitch bend in semitones that the synthesizer supports, and pitch_bend is the resulting pitch bend value in semitones.

3> could you teach me about midi channel state?

Sure, I'd be happy to help you learn about MIDI channel state!

In MIDI, a channel is a logical grouping of notes and control messages that can be used to create a single "instrument" or "voice". MIDI channels are numbered from 1 to 16, and each channel can be independently controlled with messages that are sent over a MIDI connection.

The MIDI channel state is a data structure that stores information about the current state of a MIDI channel. This information includes the following:

  • The current program (patch) number, which selects a specific sound or timbre on the synthesizer

  • The current pitch bend value, which can be used to vary the pitch of notes

  • The current pressure (aftertouch) value, which can be used to add expression to notes that are already playing

  • The current control change (CC) values, which can be used to control a variety of parameters such as volume, pan, and modulation

  • The current NRPN and RPN values, which are used to control synthesizer parameters that are not covered by standard CC messages

  • The current channel mode messages, such as Mono mode or Poly mode

In Rust, the MidiChannelState struct represents the MIDI channel state. It contains fields for each of the above parameters, as well as methods for getting and setting their values.

Here's an example of how you might use the MidiChannelState struct to create a simple monophonic synthesizer voice:

use surge_midi::MidiChannelState;

struct SynthVoice {
    channel_state: MidiChannelState,
    oscillator_freq: f32,
    oscillator_phase: f32,
}

impl SynthVoice {
    fn new(channel: u8) -> SynthVoice {
        SynthVoice {
            channel_state: MidiChannelState::new(channel),
            oscillator_freq: 440.0,
            oscillator_phase: 0.0,
        }
    }

    fn process(&mut self, note_on: bool, note_freq: f32, sample_rate: f32) -> f32 {
        if note_on {
            self.channel_state.note_on(note_freq);
        } else {
            self.channel_state.note_off();
        }

        let pitch_bend_semitones = self.channel_state.get_pitch_bend_semitones();
        let pitch_bend_ratio = (2.0 as f32).powf(pitch_bend_semitones / 12.0);
        self.oscillator_freq = note_freq * pitch_bend_ratio;

        self.oscillator_phase += self.oscillator_freq / sample_rate;
        self.oscillator_phase %= 1.0;

        self.channel_state.get_pressure() * (self.oscillator_phase * 2.0 - 1.0)
    }
}

In this example, the SynthVoice struct represents a monophonic synthesizer voice. The process method is called for each audio sample, and updates the state of the voice based on MIDI messages that are received. The note_on and note_off methods are called to trigger and release notes, and the get_pitch_bend_semitones and get_pressure methods are used to control the pitch and volume of the voice, respectively.

I hope that helps! Let me know if you have any other questions.

4> thanks -- could you teach me about the midi protocol itself in more depth?

Sure! The MIDI protocol is a standardized way of communicating musical information between devices such as synthesizers, sequencers, and computers. MIDI messages are sent over a serial connection at a rate of 31250 bits per second (baud rate), and consist of 8-bit bytes.

There are several types of MIDI messages, which are organized into three categories: channel messages, system messages, and real-time messages.

Channel Messages

Channel messages are the most common type of MIDI message, and are used to control individual channels on a MIDI device. There are several types of channel messages, including:

  • Note On and Note Off messages, which trigger and release notes respectively. These messages include information such as the note number (0-127) and velocity (0-127).

  • Control Change messages, which control a variety of parameters such as volume, pan, and modulation. These messages include information such as the controller number (0-127) and value (0-127).

  • Program Change messages, which select a specific program or patch on a MIDI device. These messages include information such as the program number (0-127).

  • Pitch Bend messages, which vary the pitch of notes in a continuous manner. These messages include a 14-bit signed value that represents the amount of pitch bend in semitones.

System Messages

System messages are used to control global settings on a MIDI device, or to send more complex commands that cannot be expressed using channel messages. There are several types of system messages, including:

  • System Exclusive messages, which are used to send vendor-specific commands or data. These messages are usually longer than standard MIDI messages, and can include binary data of any length.

  • Song Position Pointer messages, which specify the current position in a MIDI song. These messages include a 14-bit value that represents the number of MIDI beats since the start of the song.

  • Song Select messages, which select a specific song on a MIDI device. These messages include a song number (0-127).

Real-Time Messages

Real-time messages are used to synchronize MIDI devices in real time, and are sent at irregular intervals. There are several types of real-time messages, including:

  • Timing Clock messages, which are sent 24 times per quarter note to synchronize the timing of MIDI devices.

  • Start, Stop, and Continue messages, which control the playback of MIDI songs.

  • Active Sensing messages, which indicate that a MIDI device is still connected and functioning properly.

These messages can be sent using MIDI cables or over a MIDI-over-USB connection. MIDI messages can also be transmitted wirelessly using technologies such as Bluetooth MIDI.

I hope this gives you a good overview of the MIDI protocol! Let me know if you have any other questions.

5> thanks! what are non-registered parameter numbers?

Non-Registered Parameter Numbers (NRPNs) are a type of MIDI message that are used to control synthesizer parameters that are not covered by standard Control Change (CC) messages. While CC messages are limited to a range of 128 possible parameter values (0-127), NRPNs allow for much larger and more precise ranges of parameter values.

An NRPN message consists of two parts: the NRPN MSB (most significant byte) and NRPN LSB (least significant byte), followed by a value byte. The NRPN MSB and NRPN LSB specify which parameter the message is controlling, and the value byte specifies the value of the parameter.

NRPNs are not standardized across different synthesizers or manufacturers, so the exact NRPN numbers and parameter values may vary depending on the device. In some cases, synthesizer manufacturers will publish a list of their NRPN numbers and parameter mappings in the device's user manual or programming guide.

One example of an NRPN message might be used to control the cutoff frequency of a synthesizer's low-pass filter. The NRPN MSB and NRPN LSB might be set to a specific value that identifies the filter cutoff parameter, and the value byte might be set to a value between 0 and 16383 to control the filter cutoff frequency.

Here is an example of how you might use the set_nrpn and get_nrpn methods from the MidiChannelState struct in the surge-midi crate to set and get the value of an NRPN message:

use surge_midi::MidiChannelState;

let channel = 1;
let nrpn_msb = 99;
let nrpn_lsb = 12;
let value = 8192;

let mut channel_state = MidiChannelState::new(channel);
channel_state.set_nrpn(nrpn_msb, nrpn_lsb, value);

let retrieved_value = channel_state.get_nrpn(nrpn_msb, nrpn_lsb);
println!("Retrieved NRPN value: {}", retrieved_value);

In this example, the set_nrpn method is used to set the value of an NRPN message with the specified NRPN MSB and LSB values, and the get_nrpn method is used to retrieve the current value of the NRPN message.

6> thanks -- what else should we know about midi channels?

MIDI channels are a fundamental concept in the MIDI protocol, and understanding how they work is important for creating MIDI-based software and hardware. Here are a few more things you should know about MIDI channels:

Channel Numbering

MIDI channels are numbered from 1 to 16, and each channel can be independently controlled with messages that are sent over a MIDI connection. Channel 10 is reserved for percussion sounds, while channels 1-9 and 11-16 can be used for melodic instruments and other sounds.

Polyphony

Each MIDI channel can play multiple notes at the same time, up to a maximum of 16 simultaneous notes per channel. When a new note is played on a channel that has already reached its maximum number of notes, the oldest note will be turned off to make room for the new note.

Voice Allocation

When multiple notes are played simultaneously on a MIDI channel, a voice allocation algorithm is used to determine which notes will be played and which notes will be turned off. The algorithm can be based on factors such as note priority, release time, and velocity.

Program Changes

Each MIDI channel can be assigned a specific program or patch that determines its sound or timbre. Program changes are typically used to switch between different instrument sounds or to select different presets on a synthesizer.

MIDI Channels and MIDI Files

When MIDI data is saved as a file, it is typically stored as a series of MIDI tracks, each of which can contain MIDI messages for one or more channels. Each track can be assigned a specific MIDI channel that determines which channel the messages in the track will be sent to during playback.

I hope this gives you a better understanding of how MIDI channels work! Let me know if you have any other questions.

7> how are program changes specified?

Program Changes are specified using MIDI messages, specifically the Program Change message.

A Program Change message is a 2-byte message that consists of a status byte (1100nnn, where nnn is the MIDI channel number) and a data byte (0000pppp, where pppp is the program number).

The program number can range from 0 to 127, and corresponds to a specific program or patch on the MIDI device. For example, program number 0 might correspond to a piano sound, while program number 20 might correspond to a synthesizer lead sound.

Here is an example of how you might send a Program Change message using the midir crate in Rust:

use midir::{MidiOutput, MidiOutputConnection};

let midi_out = MidiOutput::new("My Test Output").unwrap();
let mut conn_out = midi_out.connect(0, "test").unwrap();

let channel = 1;
let program_number = 20;

let program_change_message: [u8; 2] = [0xC0 | (channel - 1), program_number];
conn_out.send(&program_change_message).unwrap();

In this example, the midir crate is used to send a Program Change message over a MIDI output connection. The channel variable specifies which MIDI channel the message will be sent on, and the program_number variable specifies which program or patch will be selected.

When the MIDI device receives a Program Change message, it will switch to the specified program or patch immediately.

8> how much memory does a midi channel occupy? are there allocations on both the source and the target devices? are these symmetric or asymmetric? what is the handshake protocol? is there one?

MIDI channels themselves do not occupy any memory in the sense of dynamic memory allocation, as they are simply logical groupings of MIDI messages. However, the MIDI messages that are sent over a channel do occupy memory in the form of the MIDI data that is transmitted.

When a MIDI message is sent over a channel, the data is typically buffered in a MIDI interface or hardware device before being transmitted over a MIDI cable or USB connection. The amount of memory used by this buffering process depends on the specific hardware and software implementation, but is generally small in comparison to other types of data transmission.

In terms of allocations on the source and target devices, the MIDI protocol is generally asymmetric. MIDI messages are typically generated by a "source" device such as a keyboard or sequencer, and sent to one or more "target" devices such as synthesizers or sound modules. The target devices typically do not send messages back to the source device, except in some cases where a device may need to acknowledge receipt of a particular message (such as a System Exclusive message).

The MIDI protocol does not specify a formal handshake protocol, as the messages are typically sent in a one-way fashion from source to target. However, some MIDI implementations may use various forms of error checking or flow control to ensure that messages are transmitted correctly and without loss.

For example, MIDI devices may use hardware or software buffers to store MIDI data before it is transmitted, and may use handshaking protocols such as flow control or error correction to ensure that the data is transmitted without errors or overflows. MIDI cables and USB connections may also have their own flow control mechanisms to ensure that data is transmitted at a consistent rate and without loss.

Overall, the MIDI protocol is designed to be lightweight and flexible, and does not impose strict requirements on the specific hardware and software implementation. As a result, the specifics of memory allocation, error checking, and flow control can vary widely depending on the specific implementation.

9> what error checking and flow control is necessary in midi? what about in the midi cables and usb connections? how does the midi protocol itself interact with these layers?

Error checking and flow control in MIDI are primarily implemented at the software level, rather than at the hardware level. MIDI cables and USB connections do not typically have built-in error checking or flow control mechanisms, so these functions must be implemented at the software layer.

In terms of error checking, MIDI messages are typically transmitted using a simple checksum algorithm. The checksum is calculateds by adding together all the bytes in the message, and then taking the least significant 7 bits of the result. This checksumssss value is then added to the end of the message, and the entire message (including the checksum) is transmitted to the receiving device.

When the receiving device receives the message, it calculates its own checksum using the same algorithm, and compares it to the checksum that was transmitted with the message. If the two checksums do not match, the receiving device can discard the message as being corrupted or invalid.

In terms of flow control, MIDI messages are typically transmitted using a simple serial protocol at a fixed baud rate of 31250 bits per second. MIDI messages are short (usually 1-3 bytes), so flow control is not typically an issue in most MIDI applications.

However, in some cases where large amounts ofs MIDI data are being transmitted (such as when sending large SysEx messages), flow control may be necessary to prevent data loss or buffer overflow. In these cases, MIDI devices may implement flow control mechanisms such as handshaking or XON/XOFF flow control to ensure that data is transmitted at a consistent rate.

The MIDI protocol itself does not interact directly with the lower-level layers of the MIDI communication stack, such as the MIDI cables or USB connections. Instead, the MIDI protocol is designed to be compatible with a wide variety of communication hardware and software, and relies on higher-level software layers to handle issues such as error checking and flow control.

Overall, error checking and flow control are important considerations in MIDI applications, particularly in cases where large amounts of data are being transmitted or in situations where reliable data transmission is critical. However, because MIDI messages are typically short and simple, these issues are generally less of a concern in most MIDI applications than in other types of data transmission.

10> how do we ensure data is set at a consistent rate? how does the serial protocol work? what is a baud rate? what are XON/XOFF flow control?

To ensure that data is transmitted at a consistent rate in MIDI, a fixed baud rate of 31250 bits per second is used. This means that each MIDI byte is transmitted at a rate of 31250 bits per second, regardless of the length or complexity of the message.

The serial protocol used in MIDI is a simple, asynchronous protocol that sends data one byte at a time over a single wire. Each byte of data is sent as a series of 10 bits: 1 start bit, 8 data bits, and 1 stop bit. The start bit is always a 0, and the stop bit is always a 1.

The baud rate is the speed at which data is transmitted over a serial connection, and is measured in bits per second. The term "baud" originally referred to the number of symbols (such as tones or marks) transmitted per second in early telegraph systems, but is now used more generally to refer to the number of bits per second in digital communication systems.

XON/XOFF flow control is a form of software flow control that is sometimes used in MIDI applications to ensure that data is transmitted at a consistent rate. In XON/XOFF flow control, the receiving device sends a special "XOFF" (transmitted as the ASCII control code 0x13) character to the transmitting device when its buffer is full and it cannot receive any more data. The transmitting device responds by stopping transmission until it receives an "XON" (transmitted as the ASCII control code 0x11) character from the receiving device indicating that the buffer is ready to receive more data.

XON/XOFF flow control is a simple and effective method for preventing data loss or buffer overflow in MIDI applications, particularly when sending large SysEx messages or other types of data that may cause the receiving device's buffer to fill up. However, it is important to note that XON/XOFF flow control is not supported by all MIDI devices, and may not be necessary in all situations.

11> what else should we know about midi hardware and the communications protocols from an engineering perspective?

From an engineering perspective, there are several important considerations when working with MIDI hardware and communication protocols:

Electrical Specifications

MIDI uses a current-loop signaling method that is based on a voltage difference between two wires. The voltage difference is typically around 5 volts, and the current loop is designed to be opto-isolated to prevent electrical interference and ground loops.

MIDI cables and connectors are standardized to ensure compatibility between devices, and must meet certain electrical specifications to ensure reliable communication.

Timing Considerations

MIDI messages are sent in real time and must be transmitted with precise timing to ensure that the correct notes are played at the correct times. The fixed baud rate of 31250 bits per second ensures that MIDI messages are transmitted at a consistent rate, but other timing considerations such as latency and jitter can still affect the timing of MIDI messages.

Latency is the delay between when a MIDI message is sent and when it is received by the target device, while jitter is the variation in latency from one message to the next. Both latency and jitter can be affected by factors such as the speed of the MIDI interface, the amount of buffering used by the devices, and the processing speed of the receiving device.

Software Considerations

In addition to the hardware and timing considerations, there are also important software considerations when working with MIDI. MIDI messages are typically processed by software running on a computer or other device, and this software must be designed to handle the MIDI messages in a timely and efficient manner.

MIDI messages can be transmitted over a variety of communication protocols, including USB, Bluetooth, and Ethernet. Each of these protocols has its own unique software requirements and considerations, and the software used to process MIDI messages must be designed to work with the specific protocol being used.

Overall, working with MIDI hardware and communication protocols requires a thorough understanding of electrical specifications, timing considerations, and software design principles. By carefully considering these factors, engineers can design MIDI-based systems that are reliable, efficient, and easy to use.

12> what are ten details an engineer needs to make sure to take care of when designing and implementing a midi based hardware system or related communications protocol?

Here are ten details that an engineer should consider when designing and implementing a MIDI-based hardware system or related communication protocol:

  1. Electrical Specifications: Ensure that the hardware and cables meet the electrical specifications required for MIDI communication, including the use of opto-isolation to prevent ground loops.

  2. Baud Rate: Ensure that the baud rate of the MIDI communication protocol is set to the standard rate of 31250 bits per second to ensure reliable communication.

  3. Timing Considerations: Consider the latency and jitter of the MIDI messages and ensure that the hardware and software are designed to handle these issues in a timely and efficient manner.

  4. Buffering: Use appropriate buffering techniques to ensure that MIDI messages are stored and transmitted reliably, without being lost or corrupted.

  5. Error Checking: Implement appropriate error checking mechanisms, such as checksums, to ensure that MIDI messages are transmitted correctly and without errors.

  6. Flow Control: Consider the use of flow control mechanisms, such as XON/XOFF flow control, to ensure that MIDI messages are transmitted at a consistent rate and without loss.

  7. Software Design: Ensure that the software used to process MIDI messages is designed to handle the unique timing and processing requirements of MIDI communication.

  8. Compatibility: Ensure that the MIDI hardware and software are compatible with each other and with the devices that will be using them.

  9. Grounding: Ensure that proper grounding techniques are used to prevent ground loops and other electrical interference.

  10. Testing: Thoroughly test the MIDI hardware and software to ensure that it is reliable and performs as expected under a variety of conditions and use cases.

By carefully considering these and other important details, engineers can design MIDI-based hardware and communication protocols that are reliable, efficient, and easy to use.

13> cool! what else should we know about midi?

Here are a few more things to know about MIDI:

  1. MIDI Time Code (MTC): In addition to note data and other musical messages, MIDI also includes a time code message that can be used to synchronize multiple devices to a common clock. This is known as MIDI Time Code (MTC), and can be used to synchronize multiple sequencers, samplers, and other MIDI devices.

  2. System Exclusive (SysEx): MIDI also includes a message type called System Exclusive (SysEx), which allows manufacturers to send custom data and commands to their MIDI devices. SysEx messages can be used to update firmware, change device settings, and perform other types of device-specific functions.

  3. Standard MIDI Files (SMF): MIDI data can also be saved in a standard file format known as Standard MIDI Files (SMF). SMF files can be used to store MIDI sequences, songs, and other types of musical data in a format that can be easily transferred between devices and software programs.

  4. General MIDI (GM): General MIDI is a standardized set of instrument sounds and mapping that ensures compatibility between different MIDI devices. Devices that conform to the General MIDI specification will produce the same sounds for a given MIDI program change number, regardless of the manufacturer or model of the device.

  5. MIDI over USB: In addition to the traditional 5-pin DIN connectors used for MIDI communication, many modern MIDI devices also support MIDI over USB, which allows MIDI data to be transmitted over a standard USB connection.

Overall, MIDI is a versatile and powerful protocol that has been used in a wide variety of musical applications for over three decades. Whether you are a musician, a software developer, or an engineer, understanding the basics of MIDI can be an important part of your work.

14> what are midi time codes?

MIDI Time Code (MTC) is a type of MIDI message that is used to synchronize multiple MIDI devices to a common clock. MTC is typically used in situations where precise timing is important, such as in music production and live performance.

MTC is based on the SMPTE time code standard, which is used in the film and television industry to synchronize audio and video recordings. MTC messages contain information about the current time in hours, minutes, seconds, and frames, which allows multiple MIDI devices to be synchronized to the same clock.

MTC messages can be sent over a standard MIDI connection, typically using MIDI channels 7 and 8. MTC messages are typically sent at a rate of 24 frames per second, but other frame rates are also possible.

When MTC messages are received by a MIDI device, the device can use the time code information to synchronize its internal clock to the same time code as the transmitting device. This can be useful in situations where multiple MIDI devices are used in a performance or recording, as it allows all of the devices to be synchronized to the same tempo and timing.

Overall, MIDI Time Code is an important part of MIDI protocol, and is widely used in many musical applications to ensure precise synchronization between multiple MIDI devices.

15> what is the standard midi file format? what is the data layout of this file type?

The Standard MIDI File (SMF) format is a standardized file format used to store MIDI data, such as sequences and songs, in a file that can be easily shared between devices and software programs.

The SMF format consists of a header chunk and one or more track chunks. The header chunk contains information about the file format, such as the MIDI file type, number of tracks, and time division. The track chunks contain the actual MIDI data, such as note on/off events, tempo changes, and other types of MIDI messages.

The data in an SMF file is typically stored in a binary format, with each chunk consisting of a chunk ID, chunk length, and chunk data. The chunk ID is a four-byte code that identifies the type of chunk (e.g., "MThd" for header chunk or "MTrk" for track chunk), while the chunk length specifies the length of the chunk data in bytes.

The header chunk contains the following information:

  • Format Type: Indicates the format of the MIDI file (e.g., single track, multiple tracks, or multiple songs)

  • Number of Tracks: Specifies the number of tracks in the MIDI file

  • Time Division: Specifies the timing information for the MIDI file, such as ticks per quarter note

Each track chunk contains a series of MIDI events, such as note on/off messages, control change messages, and program change messages. Each event consists of a delta time (the number of ticks since the last event), followed by the MIDI message itself.

Overall, the SMF format provides a flexible and widely supported way to store and share MIDI data, and is commonly used in many different musical applications.

16> let's describe midi over usb in more detail

MIDI over USB is a method of transmitting MIDI data over a USB connection. It allows MIDI devices to connect directly to a computer or other USB host, without the need for a separate MIDI interface.

MIDI over USB uses the USB protocol to transmit MIDI data in a format that is similar to the traditional 5-pin DIN connector used for MIDI communication. MIDI messages are transmitted in packets of data over the USB connection, with each packet containing up to 64 bytes of data.

The USB connection used for MIDI over USB is typically a Type B USB connector on the device side, which connects to a Type A USB connector on the host side (usually a computer or mobile device). MIDI over USB devices may also include additional USB ports or other connectivity options, such as Ethernet or Wi-Fi.

One advantage of MIDI over USB is that it allows MIDI devices to communicate directly with software running on a computer or mobile device, without the need for additional MIDI hardware. This can make it easier to use and integrate MIDI devices with modern music production and performance software, such as DAWs and virtual instruments.

Another advantage of MIDI over USB is that it allows for bidirectional communication between the MIDI device and the computer or mobile device. This means that MIDI data can be sent from the device to the computer, as well as from the computer to the device. This can be useful for sending program changes, bank changes, and other types of MIDI messages directly from software to the device.

Overall, MIDI over USB is a flexible and powerful way to transmit MIDI data, and is widely used in many different types of MIDI devices, from keyboards and controllers to synthesizers and drum machines.

Dependencies

~11–22MB
~299K SLoC