feat(matrix): pitch modulation target
This commit is contained in:
@@ -27,12 +27,12 @@
|
||||
~matInstruments = ~matInstruments ? Array.fill(~matVoices.size, nil);
|
||||
~matModTargets = ~matModTargets ? IdentityDictionary[
|
||||
\kick->[\amp,\pan,\rev], \hats->[\amp,\pan,\rev], \clap->[\amp,\pan,\rev],
|
||||
\perc->[\amp,\cutoff,\pan,\rev],
|
||||
\sub->[\amp,\pan,\rev,\res], \acid->[\amp,\cutoff,\pan,\rev,\res], \arp->[\amp,\cutoff,\pan,\rev,\res],
|
||||
\lead->[\amp,\cutoff,\pan,\rev,\res], \stab->[\amp,\cutoff,\pan,\rev,\res], \pad->[\amp,\cutoff,\pan,\rev,\res],
|
||||
\ride->[\amp,\pan,\rev], \rim->[\amp,\pan,\rev], \tom->[\amp,\pan,\rev],
|
||||
\reese->[\amp,\cutoff,\pan,\rev,\res],
|
||||
\bells->[\amp,\pan,\rev,\res], \sweep->[\amp,\pan,\rev],
|
||||
\perc->[\amp,\cutoff,\pan,\rev,\pitch],
|
||||
\sub->[\amp,\pan,\rev,\res,\pitch], \acid->[\amp,\cutoff,\pan,\rev,\res,\pitch], \arp->[\amp,\cutoff,\pan,\rev,\res,\pitch],
|
||||
\lead->[\amp,\cutoff,\pan,\rev,\res,\pitch], \stab->[\amp,\cutoff,\pan,\rev,\res,\pitch], \pad->[\amp,\cutoff,\pan,\rev,\res,\pitch],
|
||||
\ride->[\amp,\pan,\rev], \rim->[\amp,\pan,\rev], \tom->[\amp,\pan,\rev,\pitch],
|
||||
\reese->[\amp,\cutoff,\pan,\rev,\res,\pitch],
|
||||
\bells->[\amp,\pan,\rev,\res,\pitch], \sweep->[\amp,\pan,\rev],
|
||||
\melody->[\amp,\cutoff,\pan,\rev,\res], \chord->[\amp,\cutoff,\pan,\rev,\res],
|
||||
\fx->[\amp,\pan,\rev], \snare->[\amp,\pan,\rev],
|
||||
\crash->[\amp,\pan,\rev], \shaker->[\amp,\pan,\rev]
|
||||
@@ -158,7 +158,8 @@ File.exists(~matDir).not.if({ ("mkdir -p " ++ ~matDir.quote).systemCmd });
|
||||
var byTarget = IdentityDictionary.new;
|
||||
var pairs = [];
|
||||
((~matVoiceMods[name] ? []).select { |b|
|
||||
b[\source].notNil and: { b[\target].notNil } and: { allowed.includes(b[\target]) }
|
||||
b[\source].notNil and: { b[\target].notNil }
|
||||
and: { b[\target] != \pitch } and: { allowed.includes(b[\target]) }
|
||||
}).do { |b| byTarget[b[\target]] = (byTarget[b[\target]] ? []) ++ [b] };
|
||||
byTarget.keysValuesDo { |tgt, list|
|
||||
(tgt == \cutoff).if({
|
||||
@@ -208,7 +209,7 @@ File.exists(~matDir).not.if({ ("mkdir -p " ++ ~matDir.quote).systemCmd });
|
||||
var pitched = [\sub, \acid, \arp, \lead, \stab, \pad, \reese, \bells, \perc, \tom];
|
||||
var freqRatio = 2 ** (spec[\octave] ? 0);
|
||||
var freqPair = (pitched.includes(name) and: { freqRatio != 1.0 }).if({
|
||||
[\freq, Pfunc({ |e| (e[\freq] ? 440) * freqRatio })]
|
||||
[\freq, Pfunc({ |e| (e[\freq] ? 440) * freqRatio })] // pitch mod step-path only (no degree here)
|
||||
}, { [] });
|
||||
var modPairs = ~matModPairs.(name, spec, volOf);
|
||||
Pchain(
|
||||
@@ -229,7 +230,7 @@ File.exists(~matDir).not.if({ ("mkdir -p " ++ ~matDir.quote).systemCmd });
|
||||
var pitched = [\sub, \acid, \arp, \lead, \stab, \pad, \reese, \bells, \perc, \tom];
|
||||
var modPairs = ~matModPairs.(name, spec, volOf);
|
||||
var freqPair = pitched.includes(name).if({
|
||||
[\freq, Pfunc { |e| (~lpNote.notNil).if({ ~lpNote.(e[\degree], 0).midicps * freqRatio }, { 440 }) }]
|
||||
[\freq, Pfunc { |e| (~lpNote.notNil).if({ ~lpNote.(e[\degree] + ~matPitchOffset.(name), 0).midicps * freqRatio }, { 440 }) }]
|
||||
}, { [] });
|
||||
Pbind(*([
|
||||
\stepIdx, Pseq((0..15), inf),
|
||||
@@ -950,6 +951,17 @@ OSCdef(\mat_audition, { |msg, time, addr|
|
||||
// reader: clamp to 0..1, default 0 when absent
|
||||
~matModSourceVal = { |key| (~matModCache[key] ? 0).clip(0, 1) };
|
||||
|
||||
// +/- scale-degree offset at full deflection (env-tunable; 7 ~= 1 diatonic octave)
|
||||
~matPitchRange = ~matPitchRange ? 7;
|
||||
// bipolar additive sum of \pitch bindings -> integer degree offset applied in the freq Pfunc
|
||||
~matPitchOffset = { |name|
|
||||
var off = 0;
|
||||
((~matVoiceMods[name] ? []).select { |b| b[\target] == \pitch }).do { |b|
|
||||
off = off + (((~matModSourceVal.(b[\source]) * 2 - 1) * b[\depth] * ~matPitchRange).round.asInteger)
|
||||
};
|
||||
off
|
||||
};
|
||||
|
||||
// -- Live modvalues push (~12 Hz) --
|
||||
~matModValuesPush = {
|
||||
~toscSend !? {
|
||||
|
||||
@@ -766,6 +766,43 @@ File.delete(~matDir +/+ "t6_tmp.matrix");
|
||||
~matVoicePoses[\acid] = [];
|
||||
}.value;
|
||||
|
||||
// --- pitch target (cycle 1): bipolar scale-degree offset ---
|
||||
~matPitchRange = 7; // make the assertion deterministic regardless of env
|
||||
// +full deflection: source 1.0, depth 1.0 -> +7
|
||||
~matVoiceMods[\acid] = [ (source: \rHandY, target: \pitch, depth: 1.0) ];
|
||||
~matModCache[\rHandY] = 1.0;
|
||||
pass = pass and: { ~matPitchOffset.(\acid) == 7 };
|
||||
// -full deflection: source 0.0 -> -7
|
||||
~matModCache[\rHandY] = 0.0;
|
||||
pass = pass and: { ~matPitchOffset.(\acid) == -7 };
|
||||
// neutral: source 0.5 -> 0
|
||||
~matModCache[\rHandY] = 0.5;
|
||||
pass = pass and: { ~matPitchOffset.(\acid) == 0 };
|
||||
// additive: two bindings sum (1.0*+7 and 0.5-source*0 -> +7)
|
||||
~matVoiceMods[\acid] = [ (source: \rHandY, target: \pitch, depth: 1.0),
|
||||
(source: \bodyY, target: \pitch, depth: 1.0) ];
|
||||
~matModCache[\rHandY] = 1.0; ~matModCache[\bodyY] = 0.5; // +7 + 0 = +7
|
||||
pass = pass and: { ~matPitchOffset.(\acid) == 7 };
|
||||
~matVoiceMods[\acid] = [];
|
||||
// gating: pitch allowed on acid (melodic) but NOT on kick (percussive)
|
||||
pass = pass and: { (~matModTargets[\acid] ? []).includes(\pitch) };
|
||||
pass = pass and: { (~matModTargets[\kick] ? []).includes(\pitch).not };
|
||||
// pitch is NOT emitted as a ~matModPairs pair (handled in the freq Pfunc)
|
||||
~matVoiceMods[\acid] = [ (source: \rHandY, target: \pitch, depth: 1.0) ];
|
||||
pass = pass and: { ~matModPairs.(\acid, (amp: 1.0), { 1.0 }).includes(\pitch).not };
|
||||
~matVoiceMods[\acid] = [];
|
||||
// freq integration: with ~lpNote stubbed, a +7 offset transposes the played note up
|
||||
~origLpNote = ~lpNote;
|
||||
~lpNote = { |deg, oct| 60 + deg }; // simple midi-note stub
|
||||
~matVoiceMods[\acid] = [ (source: \rHandY, target: \pitch, depth: 1.0) ];
|
||||
~matModCache[\rHandY] = 1.0; // +7
|
||||
~matColorDefs[5][2][\steps] = Array.fill(16, nil).put(0, (degree: 0, vel: 0.8));
|
||||
~pEv = ~matVariation.(\acid, 2, 5).asStream.next(());
|
||||
pass = pass and: { (~pEv[\freq] - ((60 + 0 + 7).midicps * (2 ** (~matColorDefs[5][2][\octave] ? 0)))).abs < 1.0 };
|
||||
~lpNote = ~origLpNote;
|
||||
~matVoiceMods[\acid] = [];
|
||||
~matColorDefs[5][2][\steps] = Array.fill(16, nil);
|
||||
|
||||
pass.if(
|
||||
{ "TEST PASS".postln },
|
||||
{ "TEST FAIL".postln }
|
||||
|
||||
Reference in New Issue
Block a user