| 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:
@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
---
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:
@import "devices/my_device.mmd"
[00:00.000]
- device_preset 1.42
Step-by-Step Creation
Step 1: Gather MIDI Implementation
You need:
- MIDI Implementation Chart (from device manual)
- CC numbers for device functions
- PC behavior (how program changes work)
- SysEx messages (if applicable)
- 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:
---
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:
@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:
---
title: "Device Library Test"
ppq: 480
---
@import "devices/my_device.mmd"
[00:00.000]
- device_preset 1.0
- device_volume 1.100
Validate:
mmdc validate test.mmd
mmdc inspect test.mmd
Alias Patterns
Simple Aliases
Map device functions to CC or PC:
@alias device_function cc.{ch}.{cc_number}.{value} "Description"
Examples:
@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:
@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:
@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:
@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:
@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)
# 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)
# 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
# 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:
# ==============================================
# 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:
@alias cortex_preset ... # ✓ Clear
@alias preset ... # ✗ Too generic
Use descriptive names:
@alias amp_gain ... # ✓ Descriptive
@alias ag ... # ✗ Unclear
Group related functions:
@alias stomp_a_on ...
@alias stomp_a_off ...
@alias stomp_a_toggle ...
Parameter Naming
Use meaningful names:
{ch} # Channel
{preset} # Preset number
{value} # Generic value
{percent} # Percentage (0-100)
{state} # On/off state
{mode} # Mode selection
Include ranges in descriptions:
@alias device_tempo {ch} {bpm:40-300} "Set tempo (40-300 BPM)"
Advanced Features
Conditional Aliases
Different behavior based on parameters:
@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:
@alias device_patch_dump "Request patch dump"
- sysex F0 00 01 06 02 F7
@end
Macros for Common Sequences
@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
mmdc validate devices/my_device.mmd
Test Each Alias
Create comprehensive test file:
---
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
# 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:
---
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:
# 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
# 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:
/**
* 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
# 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
# Check parameter count
@alias name {p1}.{p2} "..."
# Usage must match
- name 1.2 # ✓ Correct
- name 1 # ✗ Missing parameter
Value Out of Range
# 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
# 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
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.