--- name: mmd-device-library description: Create custom MIDI device libraries for MIDI Markdown with aliases, parameters, and documentation. Use when the user wants to create device-specific aliases for hardware (guitar processors, synthesizers, effects units), document MIDI implementations, or build reusable command libraries. --- # Device Library Creation Skill ## Overview This skill guides you through creating custom device libraries for MIDI Markdown. Device libraries provide high-level aliases for MIDI hardware, making automation code more readable and maintainable. ## What is a Device Library? A device library is an MMD file containing: - Device metadata (name, manufacturer, MIDI channel) - Alias definitions for device-specific commands - Documentation for each alias - Optional computed values and conditionals **Example usage**: ```mmd @import "devices/my_device.mmd" [00:00.000] - my_device_preset 1.5 # Instead of: cc 1.32.0; pc 1.5 ``` ## Quick Start ### Minimal Device Library ```mmd --- device: "My Device Name" manufacturer: "Company Name" version: 1.0.0 default_channel: 1 --- @alias device_preset pc.{ch}.{preset} "Load preset (0-127)" ``` Save as `devices/my_device.mmd` and import: ```mmd @import "devices/my_device.mmd" [00:00.000] - device_preset 1.42 ``` ## Step-by-Step Creation ### Step 1: Gather MIDI Implementation You need: 1. **MIDI Implementation Chart** (from device manual) 2. **CC numbers** for device functions 3. **PC behavior** (how program changes work) 4. **SysEx messages** (if applicable) 5. **Channel assignment** (default MIDI channel) **Where to find**: - Device user manual (appendix) - Manufacturer website (downloads section) - MIDI implementation PDF/chart ### Step 2: Create Library File Create `devices/my_device.mmd`: ```mmd --- device: "Device Name" manufacturer: "Company" version: 1.0.0 default_channel: 1 documentation: "https://example.com/midi-docs" midi_channels: [1] capabilities: - program_change - control_change - sysex --- # ============================================== # Device Name MIDI Library # ============================================== # MIDI Implementation Overview: # - Channel: 1 (default) # - Program Change: 0-127 # - Control Change: See sections below # - SysEx: F0 00 01 02 ... F7 # ============================================== # Section 1: Preset Management # ============================================== @alias device_preset pc.{ch}.{preset:0-127} "Load preset (0-127)" # Add more aliases... ``` ### Step 3: Document Your Aliases Each alias needs a description: ```mmd @alias device_volume cc.{ch}.7.{value:0-127} "Set master volume (0-127)" ``` **Description guidelines**: - What it does - Parameter ranges - Special notes (if any) ### Step 4: Test the Library Create test file: ```mmd --- title: "Device Library Test" ppq: 480 --- @import "devices/my_device.mmd" [00:00.000] - device_preset 1.0 - device_volume 1.100 ``` Validate: ```bash mmdc validate test.mmd mmdc inspect test.mmd ``` ## Alias Patterns ### Simple Aliases Map device functions to CC or PC: ```mmd @alias device_function cc.{ch}.{cc_number}.{value} "Description" ``` Examples: ```mmd @alias amp_gain cc.{ch}.1.{value:0-127} "Amp gain (0-127)" @alias delay_time cc.{ch}.12.{value:0-127} "Delay time (0-127)" @alias reverb_mix cc.{ch}.91.{value:0-127} "Reverb mix (0-127)" ``` ### Multi-Command Aliases Combine multiple MIDI commands: ```mmd @alias device_load {ch}.{bank}.{preset} "Load bank and preset" - cc {ch}.32.{bank} # Bank select LSB - cc {ch}.0.0 # Bank select MSB - pc {ch}.{preset} # Program change @end ``` ### Aliases with Defaults Provide default values for optional parameters: ```mmd @alias device_volume {ch}.{value=100} "Set volume (default: 100)" - cc {ch}.7.{value} @end # Usage - device_volume 1 # Uses default 100 - device_volume 1.75 # Uses 75 ``` ### Enum Parameters Named values for parameters: ```mmd @alias device_routing {ch}.{mode=series:0,parallel:1,a_only:2,b_only:3} "Set routing mode" - cc {ch}.85.{mode} @end # Usage - device_routing 1.parallel # Sends value 1 - device_routing 1.a_only # Sends value 2 ``` ### Computed Values Transform parameters before sending: ```mmd @alias device_tempo {ch} {bpm:40-300} "Set tempo (40-300 BPM)" {midi_val = int((${bpm} - 40) * 127 / 260)} - cc {ch}.14.{midi_val} @end # BPM 120 → MIDI value 39 ``` ## Common Device Patterns ### Guitar Processor (Quad Cortex, Helix, Kemper) ```mmd # Preset loading @alias cortex_load {ch}.{setlist}.{scene}.{preset} "Load complete preset" - cc {ch}.32.{setlist} # Setlist - cc {ch}.0.{scene} # Scene/group - pc {ch}.{preset} # Preset @end # Scene switching @alias cortex_scene pc.{ch}.{scene:0-7} "Switch scene (A-H = 0-7)" # Expression pedals @alias cortex_exp1 cc.{ch}.11.{value:0-127} "Expression pedal 1" @alias cortex_exp2 cc.{ch}.12.{value:0-127} "Expression pedal 2" # Stomp switches @alias cortex_stomp_a cc.{ch}.81.{state:0-127} "Stomp A (0=off, 127=on)" @alias cortex_stomp_a_on cc.{ch}.81.127 "Stomp A on" @alias cortex_stomp_a_off cc.{ch}.81.0 "Stomp A off" # Tap tempo @alias cortex_tap_tempo cc.{ch}.80.127 "Tap tempo" # Tuner @alias cortex_tuner cc.{ch}.68.{state:0-127} "Tuner (0=off, 127=on)" ``` ### Multi-FX Unit (Eventide, Strymon) ```mmd # Preset selection @alias h90_preset pc.{ch}.{preset:0-127} "Load preset" # Algorithm selection @alias h90_algo_a cc.{ch}.82.{algo:0-52} "Algorithm for path A" @alias h90_algo_b cc.{ch}.83.{algo:0-52} "Algorithm for path B" # Mix control @alias h90_mix cc.{ch}.84.{percent:0-100} "A/B mix (0=A, 100=B)" # Routing @alias h90_routing cc.{ch}.85.{mode=series:0,parallel:1} "Routing mode" # Performance controls @alias h90_bypass cc.{ch}.102.{state=active:127,bypassed:0} "Bypass" @alias h90_infinity cc.{ch}.90.127 "Infinity (freeze)" @alias h90_hotswitch cc.{ch}.91.127 "HotSwitch" ``` ### Synthesizer ```mmd # Oscillator controls @alias synth_osc1_wave cc.{ch}.70.{wave=saw:0,square:32,tri:64,sine:96} "OSC1 waveform" @alias synth_osc1_detune cc.{ch}.71.{value:0-127} "OSC1 detune" # Filter controls @alias synth_filter_cutoff cc.{ch}.74.{value:0-127} "Filter cutoff" @alias synth_filter_resonance cc.{ch}.71.{value:0-127} "Filter resonance" # Envelope @alias synth_env_attack cc.{ch}.73.{value:0-127} "Envelope attack" @alias synth_env_decay cc.{ch}.75.{value:0-127} "Envelope decay" @alias synth_env_sustain cc.{ch}.76.{value:0-127} "Envelope sustain" @alias synth_env_release cc.{ch}.77.{value:0-127} "Envelope release" # LFO @alias synth_lfo_rate cc.{ch}.78.{value:0-127} "LFO rate" @alias synth_lfo_depth cc.{ch}.79.{value:0-127} "LFO depth" ``` ## Organization Best Practices ### Section Headers Organize aliases by function: ```mmd # ============================================== # Preset Management # ============================================== @alias device_preset ... @alias device_bank ... # ============================================== # Effects Controls # ============================================== @alias device_reverb ... @alias device_delay ... # ============================================== # Expression Pedals # ============================================== @alias device_exp1 ... @alias device_exp2 ... ``` ### Naming Conventions **Prefix with device name**: ```mmd @alias cortex_preset ... # ✓ Clear @alias preset ... # ✗ Too generic ``` **Use descriptive names**: ```mmd @alias amp_gain ... # ✓ Descriptive @alias ag ... # ✗ Unclear ``` **Group related functions**: ```mmd @alias stomp_a_on ... @alias stomp_a_off ... @alias stomp_a_toggle ... ``` ### Parameter Naming **Use meaningful names**: ```mmd {ch} # Channel {preset} # Preset number {value} # Generic value {percent} # Percentage (0-100) {state} # On/off state {mode} # Mode selection ``` **Include ranges in descriptions**: ```mmd @alias device_tempo {ch} {bpm:40-300} "Set tempo (40-300 BPM)" ``` ## Advanced Features ### Conditional Aliases Different behavior based on parameters: ```mmd @alias smart_load {ch}.{preset}.{device_type} "Device-aware preset load" @if {device_type} == "a" - cc {ch}.32.0 - pc {ch}.{preset} @elif {device_type} == "b" - cc {ch}.71.{preset} @end @end ``` ### SysEx Support Include SysEx messages: ```mmd @alias device_patch_dump "Request patch dump" - sysex F0 00 01 06 02 F7 @end ``` ### Macros for Common Sequences ```mmd @alias scene_change_smooth {ch}.{old_scene}.{new_scene} "Smooth scene transition" # Fade out old scene - cc {ch}.7.curve(100, 0, ease-in) # Switch scene [+500ms] - pc {ch}.{new_scene} # Fade in new scene [@] - cc {ch}.7.curve(0, 100, ease-out) @end ``` ## Validation and Testing ### Validate Library Structure ```bash mmdc validate devices/my_device.mmd ``` ### Test Each Alias Create comprehensive test file: ```mmd --- title: "Device Library Test Suite" ppq: 480 --- @import "devices/my_device.mmd" # Test all aliases [00:00.000] - device_preset 1.0 - device_volume 1.100 - device_function1 1.50 # ... test each alias # Test edge cases [00:10.000] - device_preset 1.127 # Max value - device_volume 1.0 # Min value - device_function1 1.127 # Max value ``` ### Verify MIDI Output ```bash # Inspect generated events mmdc inspect test.mmd # Compile and check MIDI mmdc compile test.mmd -o test.mid # Play back to verify mmdc play test.mmd --port 0 ``` ## Documentation Template Complete library template: ```mmd --- device: "Device Full Name" manufacturer: "Company Name" version: 1.0.0 default_channel: 1 documentation: "https://example.com/midi-implementation" midi_channels: [1] date_created: "2025-01-15" date_modified: "2025-01-15" author: "Your Name" capabilities: - program_change - control_change - sysex notes: "Additional notes about this device" --- # ============================================== # Device Name MIDI Library # ============================================== /** * MIDI Implementation Summary * * Channels: 1 (default), supports 1-16 * Program Change: 0-127 (presets) * Control Change: See sections below * SysEx: See SysEx section * * Quick Start: * @import "devices/device_name.mmd" * - device_preset 1.0 * * Documentation: https://example.com/docs */ # ============================================== # Preset Management # ============================================== @alias device_preset pc.{ch}.{preset:0-127} "Load preset (0-127)" @alias device_bank_preset {ch}.{bank:0-7}.{preset:0-127} "Load bank and preset" - cc {ch}.32.{bank} - pc {ch}.{preset} @end # ============================================== # Effects Controls # ============================================== @alias device_reverb cc.{ch}.91.{value:0-127} "Reverb mix (0-127)" @alias device_delay cc.{ch}.92.{value:0-127} "Delay mix (0-127)" # ... Add more sections as needed ``` ## Real-World Examples Study existing device libraries: ```bash # View Quad Cortex implementation cat devices/quad_cortex.mmd # View Eventide H90 implementation cat devices/eventide_h90.mmd # View Helix implementation cat devices/helix.mmd ``` These provide patterns for: - Complex preset loading sequences - Expression pedal mapping - Stomp switch control - Tempo synchronization - Scene management ## Publishing Your Library ### 1. Test Thoroughly ```bash # Validate mmdc validate devices/my_device.mmd # Test all aliases mmdc validate test_suite.mmd # Test with actual device mmdc play test_suite.mmd --port "Device Name" ``` ### 2. Document Usage Add README or examples: ```mmd /** * Usage Examples * * Basic preset load: * - device_preset 1.42 * * Bank select: * - device_bank_preset 1.2.5 * * Effects control: * - device_reverb 1.75 */ ``` ### 3. Share with Community - Add to project `devices/` directory - Create pull request - Include test files - Document MIDI implementation source ## Troubleshooting ### Alias Not Working ```bash # Check import grep "@import" your_file.mmd # Verify alias definition grep "@alias device_name" devices/my_device.mmd # Test with raw MIDI - cc 1.XX.YY # Instead of alias ``` ### Parameter Count Mismatch ```mmd # Check parameter count @alias name {p1}.{p2} "..." # Usage must match - name 1.2 # ✓ Correct - name 1 # ✗ Missing parameter ``` ### Value Out of Range ```mmd # Add range constraints @alias func {ch}.{value:0-100} "..." # Or use computed values {clamped = min(127, max(0, ${value}))} ``` ## Related Skills and Resources **Skills**: - **mmd-writing** - MMD syntax reference - **mmd-debugging** - Troubleshooting aliases - **mmd-cli** - Testing and validation **Resources**: - **devices/** - Existing device libraries (6 examples) - **examples/04_device_libraries/** - Usage examples - **docs/user-guide/alias-system.md** - Alias documentation - **spec.md** - Complete alias syntax reference ## Quick Reference ### Alias Syntax ```mmd # Simple alias @alias name command.{param} "Description" # Multi-command alias @alias name {p1}.{p2} "Description" - command1 - command2 @end # With defaults @alias name {param=default} "Description" # With enums @alias name {param=opt1:val1,opt2:val2} "Description" # With computed values @alias name {param} "Description" {computed = expression} - command ${computed} @end ``` ### Testing Workflow ```bash 1. mmdc validate devices/my_device.mmd 2. mmdc validate test_file.mmd 3. mmdc inspect test_file.mmd 4. mmdc play test_file.mmd --port 0 ``` For complete device library examples, see the `devices/` directory in the project.