feat: per-colour res and rev in matrix engine
This commit is contained in:
@@ -41,16 +41,19 @@
|
||||
\perc->1260, \acid->700, \arp->3000, \lead->4000, \stab->2200,
|
||||
\pad->1500, \reese->1100, \melody->3500, \chord->2000
|
||||
];
|
||||
// voices whose SynthDef has a resonant filter (res param). rev (reverb send)
|
||||
// is accepted by all lp_/classic synths, so it is not gated by voice.
|
||||
~matResVoices = ~matResVoices ? [\sub, \acid, \arp, \lead, \stab, \pad, \reese, \bells, \melody, \chord];
|
||||
|
||||
// -- default color defs reproduce the historical global variation table --
|
||||
~matDefaultColorDefs = {
|
||||
[ nil,
|
||||
(stretch: 1.0, octave: 0, amp: 1.0, inst: nil, cutoff: nil, pan: nil, steps: Array.fill(16, nil), mod: nil, pose: Array.new),
|
||||
(stretch: 0.5, octave: 0, amp: 1.0, inst: nil, cutoff: nil, pan: nil, steps: Array.fill(16, nil), mod: nil, pose: Array.new),
|
||||
(stretch: 1.0, octave: 1, amp: 1.0, inst: nil, cutoff: nil, pan: nil, steps: Array.fill(16, nil), mod: nil, pose: Array.new),
|
||||
(stretch: 2.0, octave: 0, amp: 1.0, inst: nil, cutoff: nil, pan: nil, steps: Array.fill(16, nil), mod: nil, pose: Array.new),
|
||||
(stretch: 1.0, octave: -1, amp: 1.05, inst: nil, cutoff: nil, pan: nil, steps: Array.fill(16, nil), mod: nil, pose: Array.new),
|
||||
(stretch: 0.5, octave: 0, amp: 1.2, inst: nil, cutoff: nil, pan: nil, steps: Array.fill(16, nil), mod: nil, pose: Array.new) ]
|
||||
(stretch: 1.0, octave: 0, amp: 1.0, inst: nil, cutoff: nil, pan: nil, res: nil, rev: nil, steps: Array.fill(16, nil), mod: nil, pose: Array.new),
|
||||
(stretch: 0.5, octave: 0, amp: 1.0, inst: nil, cutoff: nil, pan: nil, res: nil, rev: nil, steps: Array.fill(16, nil), mod: nil, pose: Array.new),
|
||||
(stretch: 1.0, octave: 1, amp: 1.0, inst: nil, cutoff: nil, pan: nil, res: nil, rev: nil, steps: Array.fill(16, nil), mod: nil, pose: Array.new),
|
||||
(stretch: 2.0, octave: 0, amp: 1.0, inst: nil, cutoff: nil, pan: nil, res: nil, rev: nil, steps: Array.fill(16, nil), mod: nil, pose: Array.new),
|
||||
(stretch: 1.0, octave: -1, amp: 1.05, inst: nil, cutoff: nil, pan: nil, res: nil, rev: nil, steps: Array.fill(16, nil), mod: nil, pose: Array.new),
|
||||
(stretch: 0.5, octave: 0, amp: 1.2, inst: nil, cutoff: nil, pan: nil, res: nil, rev: nil, steps: Array.fill(16, nil), mod: nil, pose: Array.new) ]
|
||||
};
|
||||
~matColorDefs = ~matColorDefs ? Array.fill(~matVoices.size, { ~matDefaultColorDefs.value });
|
||||
|
||||
@@ -241,6 +244,10 @@ File.exists(~matDir).not.if({ ("mkdir -p " ++ ~matDir.quote).systemCmd });
|
||||
cdPairs = cdPairs ++ [\cutoff, spec[\cutoff]] });
|
||||
(spec[\pan].notNil and: { (~matModTargets[name] ? []).includes(\pan) }).if({
|
||||
cdPairs = cdPairs ++ [\pan, spec[\pan]] });
|
||||
(spec[\res].notNil and: { ~matResVoices.includes(name) }).if({
|
||||
cdPairs = cdPairs ++ [\res, spec[\res]] });
|
||||
(spec[\rev].notNil).if({
|
||||
cdPairs = cdPairs ++ [\rev, spec[\rev]] });
|
||||
(~matStepsEmpty.(spec[\steps]).not).if({
|
||||
~matColorStepPattern.(name, vi, color, spec, volOf, instPair, cdPairs)
|
||||
}, {
|
||||
@@ -435,7 +442,7 @@ File.exists(~matDir).not.if({ ("mkdir -p " ++ ~matDir.quote).systemCmd });
|
||||
|
||||
// -- ~matSetColorDef : set one field of one voice/color, validate, re-source, echo --
|
||||
~matSetColorDef = { |vi, color, field, value|
|
||||
var fields = [\stretch, \octave, \amp, \inst, \cutoff, \pan];
|
||||
var fields = [\stretch, \octave, \amp, \inst, \cutoff, \pan, \res, \rev];
|
||||
((vi >= 0 and: { vi < ~matVoices.size }) and: { color >= 1 and: { color <= 6 } }
|
||||
and: { fields.includes(field.asSymbol) }).if({
|
||||
var name = ~matVoices[vi];
|
||||
@@ -449,6 +456,14 @@ File.exists(~matDir).not.if({ ("mkdir -p " ++ ~matDir.quote).systemCmd });
|
||||
ok = (~matModTargets[name] ? []).includes(field.asSymbol);
|
||||
v = value.asFloat;
|
||||
});
|
||||
(field.asSymbol == \res).if({
|
||||
ok = ~matResVoices.includes(name);
|
||||
v = value.asFloat;
|
||||
});
|
||||
(field.asSymbol == \rev).if({
|
||||
v = value.asFloat;
|
||||
// rev accepted for all voices (ungated)
|
||||
});
|
||||
((field.asSymbol == \stretch) or: { field.asSymbol == \octave }
|
||||
or: { field.asSymbol == \amp }).if({
|
||||
v = (field.asSymbol == \octave).if({ value.asInteger }, { value.asFloat });
|
||||
@@ -463,7 +478,8 @@ File.exists(~matDir).not.if({ ("mkdir -p " ++ ~matDir.quote).systemCmd });
|
||||
};
|
||||
|
||||
// -- ~matColorDefPush : send one voice's 6 color defs flattened to surfaces --
|
||||
// flat layout per color (1..6): stretch, octave, amp, inst(str), cutoff(-1=nil), pan(-2=nil)
|
||||
// flat layout per color (1..6) — stride 8:
|
||||
// stretch, octave, amp, inst(str), cutoff(-1=nil), pan(-2=nil), res(-3=nil), rev(-4=nil)
|
||||
// Distinct OUTBOUND address (plural) so it never collides with the 4-arg inbound
|
||||
// /matrix/colordef set (mirrors /matrix/instrument vs /matrix/instruments).
|
||||
~matColorDefPush = { |vi|
|
||||
@@ -471,7 +487,7 @@ File.exists(~matDir).not.if({ ("mkdir -p " ++ ~matDir.quote).systemCmd });
|
||||
var flat = (1..6).collect({ |c|
|
||||
var d = ~matColorDefs[vi][c];
|
||||
[ d[\stretch], d[\octave], d[\amp], (d[\inst] ? \default).asString,
|
||||
d[\cutoff] ? -1, d[\pan] ? -2 ]
|
||||
d[\cutoff] ? -1, d[\pan] ? -2, d[\res] ? -3, d[\rev] ? -4 ]
|
||||
}).flatten;
|
||||
~toscSend.valueArray(["/matrix/colordefs", vi] ++ flat)
|
||||
}
|
||||
@@ -574,7 +590,7 @@ OSCdef(\mat_steps_get, { |msg, time, addr|
|
||||
(voiceDefs.isArray and: { vi < ~matVoices.size }).if({
|
||||
voiceDefs.do { |d, ci|
|
||||
(d.isKindOf(Event)).if({
|
||||
[\stretch, \octave, \amp, \inst, \cutoff, \pan].do { |f|
|
||||
[\stretch, \octave, \amp, \inst, \cutoff, \pan, \res, \rev].do { |f|
|
||||
d[f].notNil.if({ ~matColorDefs[vi][ci + 1][f] = d[f] })
|
||||
}; (d[\steps].notNil and: { d[\steps].isArray }).if({ ~matColorDefs[vi][ci + 1][\steps] = d[\steps] });
|
||||
(d[\mod].notNil).if({ ~matColorDefs[vi][ci + 1][\mod] = d[\mod] });
|
||||
|
||||
@@ -285,16 +285,16 @@ pass = pass and: { ~matSetColorDef.notNil and: { ~matColorDefPush.notNil } };
|
||||
~matSetColorDef.(5, 3, \octave, -2); // acid, color 3
|
||||
pass = pass and: { ~matColorDefs[5][3][\octave] == -2 };
|
||||
pass = pass and: { ~trigLog[0] == "/matrix/colordefs" and: { ~trigLog[1] == 5 } };
|
||||
pass = pass and: { ~trigLog.size == 38 }; // path + vi + 36 values
|
||||
pass = pass and: { ~trigLog.size == 50 }; // path + vi + 48 values (6 colors x 8 fields)
|
||||
|
||||
// direct test of ~matColorDefPush: address, vi, 38 items total, nil pan=-2, nil cutoff=-1
|
||||
// direct test of ~matColorDefPush: address, vi, 50 items total, nil pan=-2, nil cutoff=-1, nil res=-3, nil rev=-4
|
||||
~trigLog = nil;
|
||||
~matColorDefPush.(5);
|
||||
pass = pass and: { ~trigLog[0] == "/matrix/colordefs" };
|
||||
pass = pass and: { ~trigLog[1] == 5 };
|
||||
pass = pass and: { ~trigLog.size == 38 };
|
||||
pass = pass and: { ~trigLog[(2 + ((1-1)*6) + 5)] == -2 }; // color 1 pan nil -> -2
|
||||
pass = pass and: { ~trigLog[(2 + ((1-1)*6) + 4)] == -1 }; // color 1 cutoff nil -> -1
|
||||
pass = pass and: { ~trigLog.size == 50 };
|
||||
pass = pass and: { ~trigLog[(2 + ((1-1)*8) + 5)] == -2 }; // color 1 pan nil -> -2
|
||||
pass = pass and: { ~trigLog[(2 + ((1-1)*8) + 4)] == -1 }; // color 1 cutoff nil -> -1
|
||||
|
||||
// invalid field is rejected (state unchanged)
|
||||
~matSetColorDef.(5, 3, \bogus, 9);
|
||||
@@ -336,6 +336,17 @@ pass = pass and: { ~matColorDefs[6][2][\inst] == \do_strike };
|
||||
|
||||
pass = pass and: { ~matVariation.(\acid, 1, 5).asStream.next(()).notNil };
|
||||
|
||||
// res/rev round-trip through a colour def
|
||||
~matColorDefs[5][1][\res] = 0.7; // acid, colour 1
|
||||
~matColorDefs[5][1][\rev] = 0.3;
|
||||
variation = ~matVariation.(\acid, 1, 5);
|
||||
pass = pass and: { variation.notNil and: { variation.isKindOf(Pattern) } };
|
||||
// stream one event, must not raise
|
||||
try { variation.asStream.next(()) } { |e| pass = false;
|
||||
("EXCEPTION res/rev stream: " ++ e.errorString).postln };
|
||||
~matColorDefs[5][1][\res] = nil; // restore
|
||||
~matColorDefs[5][1][\rev] = nil;
|
||||
|
||||
// --- Step sequencer state (Task 1) ---
|
||||
pass = pass and: { ~matStepsEmpty.notNil and: { ~matSetStep.notNil and: { ~matStepsPush.notNil } } };
|
||||
// default: every color's steps is a 16-slot all-nil array -> empty
|
||||
|
||||
Reference in New Issue
Block a user