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:
@@ -332,6 +332,26 @@ int run_render_job(const std::string& jobPath, const std::string& outPath) {
|
||||
evs.push_back({endSample, 1, pitch, 0});
|
||||
if (endSample > totalNeeded) totalNeeded = endSample;
|
||||
}
|
||||
// Optional CC events from job.events (e.g. CC11 expression curves emitted
|
||||
// by native_render._expression_events). kind: 2=CC (a=cc, b=value 0..127),
|
||||
// 3=program change (a=program). Sample-accurate like note events.
|
||||
const json_value_s* jev = memberValue(job, "events");
|
||||
if (jev && jev->type == json_type_array) {
|
||||
const json_array_s* evs_arr = static_cast<const json_array_s*>(jev->payload);
|
||||
for (const json_array_element_s* el = evs_arr->start; el; el = el->next) {
|
||||
const json_value_s* v = el->value;
|
||||
if (!v || v->type != json_type_object) continue;
|
||||
const json_object_s* n = static_cast<const json_object_s*>(v->payload);
|
||||
double sampleD = 0.0;
|
||||
memberNumber(n, "sample", sampleD);
|
||||
const uint32_t kind = (uint32_t)(memberInt(n, "kind", 2) & 0x3);
|
||||
const uint32_t a = (uint32_t)(memberInt(n, "a", 0) & 0x7F);
|
||||
const uint32_t b = (uint32_t)(memberInt(n, "b", 0) & 0x7F);
|
||||
const uint64_t sample = (uint64_t)std::llround(sampleD);
|
||||
evs.push_back({sample, (uint8_t)kind, a, b});
|
||||
if (sample + 1 > totalNeeded) totalNeeded = sample + 1;
|
||||
}
|
||||
}
|
||||
std::stable_sort(evs.begin(), evs.end(),
|
||||
[](const Ev& a, const Ev& b) { return a.sample < b.sample; });
|
||||
|
||||
|
||||
Reference in New Issue
Block a user