defmodule ExMidi do @moduledoc """ Batteries-included Elixir MIDI. `ExMidi` provides a unified API for MIDI message construction, binary encode/decode, Standard MIDI File read/write, SYX file support, and a streaming MIDI parser. ## Message terms All MIDI messages are represented as `{:midi, payload}` tuples: {:midi, {:note_on, [channel: 1, pitch: 60, velocity: 100]}} ## Modules - `ExMidi.MidiMsg` — lightweight message constructors (tuple-based) - `ExMidi.MidiMessage` — frozen message struct with rich API (copy, hex, dict, etc.) - `ExMidi.MidiBin` — binary encode/decode of MIDI messages - `ExMidi.MidiParser` — streaming byte-by-byte MIDI parser - `ExMidi.MidiFile` — Standard MIDI File read/write (Format 0/1/2) - `ExMidi.MidiSyx` — SYX file read/write - `ExMidi.MidiUtil` — utility functions - `ExMidi.MidiLib` — version information ## Quick start # Message constructors ExMidi.MidiMsg.note_on(60, 100) # => {:midi, {:note_on, [pitch: 60, velocity: 100]}} # Binary encode/decode ExMidi.MidiBin.encode(ExMidi.MidiMsg.note_on(1, 60, 100)) # => <<144, 60, 100>> ExMidi.MidiBin.decode(<<144, 60, 100>>) # => {:midi, {:note_on, [channel: 1, pitch: 60, velocity: 100]}} # Frozen message struct msg = ExMidi.MidiMessage.new(:note_on, channel: 1, pitch: 60, velocity: 100) ExMidi.MidiMessage.to_hex(msg) # => "90 3C 64" # Streaming parser parser = ExMidi.MidiParser.new() parser = ExMidi.MidiParser.feed_bytes(parser, [144, 60, 100]) {msg, _} = ExMidi.MidiParser.parse(parser) # MIDI file midi = ExMidi.MidiFile.read("song.mid") for msg <- ExMidi.MidiFile.play(midi), do: IO.inspect(msg) """ @doc "Returns the current library version." def version, do: ExMidi.MidiLib.version() @doc "Returns all version information." def versions, do: ExMidi.MidiLib.versions() end