feat: CC11 expression automation (spec midi_note_cc11_expression)

- MIDINote schema + expression_curve (position_ratio 0..1, value 0..127)
- Piano roll CC lane mode Expression (CC11): draw/move/del anchors
- Offline: _expression_events grid 64 samples -> job.events -> RenderJob.cpp sample-accurate CC
- Realtime: scheduleNoteExpressionCC11 grid 16ms via bridge pushEvent / SonicSF fallback, epoch-guarded, cleared on stop
- tests/test_cc11_expression.py 6/6 (unit interp/grid/clamp + integration energy follows curve)
- rebuild daw_vst_bridge (narrowing fix) + sync binaries/dist, babel rebuild + sync 5 copies
This commit is contained in:
2026-08-26 11:14:56 +07:00
parent c146d3eb14
commit 2c96a223af
11 changed files with 482 additions and 32 deletions
+13 -1
View File
@@ -151,7 +151,19 @@
"start_beat": { "type": "number", "description": "Beat offset relative to the start of the source buffer (bar 0)" },
"duration_beats": { "type": "number" },
"velocity": { "type": "number", "minimum": 0.0, "maximum": 1.0, "default": 0.8 },
"pan": { "type": "number", "minimum": -1.0, "maximum": 1.0, "default": 0.0 }
"pan": { "type": "number", "minimum": -1.0, "maximum": 1.0, "default": 0.0 },
"expression_curve": {
"type": "array",
"description": "CC11 expression automation: normalized position 0..1 in note, value 0..127",
"items": {
"type": "object",
"properties": {
"position_ratio": { "type": "number", "minimum": 0.0, "maximum": 1.0 },
"value": { "type": "integer", "minimum": 0, "maximum": 127 }
},
"required": ["position_ratio", "value"]
}
}
},
"required": ["id", "pitch", "start_beat", "duration_beats", "velocity"]
},