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.