# Getting Started ## Requirements - A C99 compiler (gcc, clang, MSVC, arm-none-eabi-gcc) - `make` (optional, for running tests) No external dependencies. Only `stdint.h`, `stdbool.h`, and `string.h` from the C standard library. ## Install The fastest path depends on the build system. See the [Integration Guide](Integration-Guide.md) for the full set of options. | Build flow | Install | |---|---| | Arduino IDE | Library Manager, search `midi2`, click Install | | arduino-cli | `arduino-cli lib install midi2` | | PlatformIO | `lib_deps = sauloverissimo/midi2 @ ^0.9.0` | | ESP-IDF | `sauloverissimo/midi2: ">=0.9.0"` in `idf_component.yml` | | Zephyr | west manifest entry + `CONFIG_MIDI2=y` (see Integration Guide) | | CMake | `FetchContent_Declare(midi2 GIT_TAG v0.9.0)` | | Manual vendor | drop `dist/midi2.{h,c}` from a release into your tree | For local development: ```bash git clone https://github.com/sauloverissimo/midi2.git cd midi2 make test ``` This compiles and runs all 383 tests under `-Wall -Wextra -Wpedantic`. Switch compilers or enable sanitizers as needed: ```bash make CC=clang test # clang make CC="gcc -fsanitize=address,undefined" test # ASan + UBSan make CC="gcc -m32" test # 32-bit verification ``` The CMake build is also exercised by CI: ```bash cmake -S . -B build -DCMAKE_BUILD_TYPE=Release cmake --build build --parallel cmake --install build --prefix /tmp/midi2-install ``` ## First example: build and parse a Note On ```c #include "midi2.h" int main(void) { /* Build a MIDI 2.0 Note On: group 0, channel 0, note 60 (C4), velocity 75% */ uint32_t w[2]; midi2_msg_note_on(w, 0, 0, 60, 0xC000, 0, 0); /* Parse it back */ uint8_t mt = midi2_msg_get_mt(w); /* 0x04 = MIDI 2.0 CV */ uint8_t group = midi2_msg_get_group(w); /* 0 */ uint8_t channel = midi2_msg_get_channel(w); /* 0 */ uint8_t note = midi2_msg_get_note(w); /* 60 */ uint16_t vel = midi2_msg_get_velocity(w); /* 0xC000 */ /* Scale a legacy 7-bit velocity to 16-bit (round-trip safe) */ uint16_t vel16 = midi2_msg_scale_up_7to16(100); uint8_t vel7 = midi2_msg_scale_down_16to7(vel16); return 0; } ``` Compile: `gcc -std=c99 -I src example.c -o example`. `midi2_msg` is header-only, no `.c` to link. ## Second example: typed dispatch ```c #define MIDI2_IMPLEMENTATION #include "midi2.h" void on_note_on(uint8_t group, uint8_t channel, uint8_t note, uint16_t velocity, uint8_t attr_type, uint16_t attr_data, void *ctx) { printf("Note On: ch=%u note=%u vel=%u\n", channel, note, velocity); } void on_cc(uint8_t group, uint8_t channel, uint8_t index, uint32_t value, void *ctx) { printf("CC: ch=%u index=%u value=%u\n", channel, index, value); } int main(void) { midi2_dispatch dp; midi2_dispatch_init(&dp); dp.on_note_on = on_note_on; dp.on_cc = on_cc; uint32_t w[2]; midi2_msg_note_on(w, 0, 0, 60, 0xFFFF, 0, 0); midi2_dispatch_feed(w, 2, &dp); /* fires on_note_on */ return 0; } ``` Compile: `gcc -std=c99 -I src example.c -o example`. `MIDI2_IMPLEMENTATION` pulls the implementations into the translation unit. ## Third example: proc to dispatch chain ```c #include "midi2.h" /* Pipeline: proc (SysEx reassembly + group filter) -> dispatch (typed callbacks) */ midi2_dispatch dp; midi2_proc_state proc; uint8_t sysex7_buf[128]; uint8_t sysex8_buf[256]; void setup(void) { midi2_dispatch_init(&dp); dp.on_note_on = my_note_on_handler; dp.on_cc = my_cc_handler; midi2_proc_init(&proc, sysex7_buf, sizeof(sysex7_buf), sysex8_buf, sizeof(sysex8_buf)); proc.on_ump = midi2_dispatch_feed; proc.context = &dp; } void on_ump_received(const uint32_t *words, uint8_t word_count) { midi2_proc_feed(&proc, words, word_count); } ``` ## What to read next - [Module Reference](Module-Reference.md): detailed API for each module - [Architecture](Architecture.md): how the layers fit together - [Integration Guide](Integration-Guide.md): every install path explained