diff --git a/sound_algo/data_only/launchpad.scd b/sound_algo/data_only/launchpad.scd index 7886d97..e6b8505 100644 --- a/sound_algo/data_only/launchpad.scd +++ b/sound_algo/data_only/launchpad.scd @@ -39,6 +39,13 @@ SynthDef(\lp_pluck, { |out=0, freq=220, amp=0.3, cutoff=2500, pan=0| var sig = RLPF.ar(Saw.ar(freq.clip(40,2000) * [1, 1.005]), cutoff.clip(200,8000), 0.4); Out.ar(out, Pan2.ar(Mix(sig) * env, pan.clip(-1,1)) * amp); }).add; +// sustained lead: gated ASR so notes hold for their full \dur (needs \legato). +SynthDef(\lp_lead, { |out=0, freq=220, amp=0.3, cutoff=3000, gate=1, pan=0| + var env = EnvGen.kr(Env.asr(0.01, 1, 0.3), gate, doneAction: 2); + var sig = Mix(Saw.ar(freq.clip(40, 3000) * [0.997, 1.0, 1.005])); + sig = RLPF.ar(sig, (cutoff.clip(300, 9000) * (1 + (env * 0.4))).clip(300, 12000), 0.28); + Out.ar(out, Pan2.ar(sig * env, pan.clip(-1, 1)) * amp * 0.45); +}).add; SynthDef(\lp_pad, { |out=0, freq=220, amp=0.0, cutoff=1500, gate=1| var sig = Mix(Saw.ar(freq.clip(40,1000) * [0.99, 1.0, 1.008, 2.0])); sig = RLPF.ar(sig, cutoff.clip(200,6000), 0.4); @@ -164,10 +171,10 @@ Pdef(\lp_arp, Pbind(\instrument, \lp_pluck, \dur, 0.25, \degree, Pseq([0,2,4,7,4,2], inf), \freq, Pfunc { |e| ~lpNote.(e[\degree], 1).midicps }, \cutoff, 3000, \amp, Pfunc { 0.2 * ~lpVol.(\arp) }, \pan, Pwhite(-0.3,0.3))); -Pdef(\lp_lead, Pbind(\instrument, \lp_pluck, \dur, Pseq([1, 0.5, 0.5, 2], inf), +Pdef(\lp_lead, Pbind(\instrument, \lp_lead, \dur, Pseq([1, 0.5, 0.5, 2], inf), \degree, Pseq([7,5,4,0,2,4], inf), \freq, Pfunc { |e| ~lpNote.(e[\degree], 1).midicps }, - \cutoff, 4000, \amp, Pfunc { 0.24 * ~lpVol.(\lead) })); + \cutoff, 4000, \amp, Pfunc { 0.24 * ~lpVol.(\lead) }, \legato, 1)); Pdef(\lp_stab, Pbind(\instrument, \lp_pluck, \dur, Pseq([Rest(0.5), 0.5], inf), \freq, Pfunc { [0,2,4].collect { |d| ~lpNote.(d, 0).midicps } }, \cutoff, 2200, \amp, Pfunc { 0.2 * ~lpVol.(\stab) })); diff --git a/sound_algo/data_only/matrix.scd b/sound_algo/data_only/matrix.scd index 43f5e8c..59b391e 100644 --- a/sound_algo/data_only/matrix.scd +++ b/sound_algo/data_only/matrix.scd @@ -142,9 +142,10 @@ File.exists(~matDir).not.if({ ("mkdir -p " ++ ~matDir.quote).systemCmd }); // -- ~matVariation : map color 1-6 to a Pchain overlay on the captured base -- // color 1 = base as-is, 2 = double-time, 3 = octave up, 4 = half-time, // 5 = octave down + slight accent, 6 = accent roll (denser + louder). -// \stretch multiplies event duration; \octave shifts degree-based pitch. -// NOTE: voices that compute \freq via Pfunc (ignoring \octave) will not respond -// to the octave variation — acceptable for v1; tune the palette at the live gate. +// \stretch multiplies event duration; octave colors multiply the base \freq +// (x2 up, x0.5 down) over the base event, so they transpose even voices that set +// \freq directly via Pfunc (which bypass SC's \octave). Only pitched voices get +// the \freq multiply — drums keep their pitch (and any instrument override). // Single function so all variation logic lives in one place. ~matVariation = { |name, color, vi = 0| (color == 0).if({ nil }, { @@ -152,18 +153,26 @@ File.exists(~matDir).not.if({ ("mkdir -p " ++ ~matDir.quote).systemCmd }); base.notNil.if({ var spec = [ nil, - (stretch: 1.0, octave: 0, amp: 1.0), - (stretch: 0.5, octave: 0, amp: 1.0), - (stretch: 1.0, octave: 1, amp: 1.0), - (stretch: 2.0, octave: 0, amp: 1.0), - (stretch: 1.0, octave: -1, amp: 1.05), - (stretch: 0.5, octave: 0, amp: 1.2) + (stretch: 1.0, freqRatio: 1.0, amp: 1.0), + (stretch: 0.5, freqRatio: 1.0, amp: 1.0), + (stretch: 1.0, freqRatio: 2.0, amp: 1.0), + (stretch: 2.0, freqRatio: 1.0, amp: 1.0), + (stretch: 1.0, freqRatio: 0.5, amp: 1.05), + (stretch: 0.5, freqRatio: 1.0, amp: 1.2) ][color]; spec.notNil.if({ var inst = ~matInstruments[vi]; // per-voice volume (mixer fix from main): read live, default 0.8 var volOf = { (~lp[\vol].notNil).if({ ~lp[\vol][name.asSymbol] ? 0.8 }, { 0.8 }) }; var instPair = inst.notNil.if({ [\instrument, inst] }, { [] }); + // octave colors: multiply the base \freq, pitched voices only. + // gating avoids forcing a pitch onto drums (incl. drum voices + // remapped to a pitched instrument override). + var pitched = [\sub, \acid, \arp, \lead, \stab, \pad, \reese, \bells, \perc, \tom]; + var freqRatio = spec[\freqRatio] ? 1.0; + var freqPair = (pitched.includes(name) and: { freqRatio != 1.0 }).if({ + [\freq, Pfunc({ |e| (e[\freq] ? 440) * freqRatio })] + }, { [] }); var mod = ~matMod[vi]; var modPairs = mod.isNil.if({ [] }, { var src = mod[\source], tgt = mod[\target], d = mod[\depth]; @@ -186,9 +195,8 @@ File.exists(~matDir).not.if({ ("mkdir -p " ++ ~matDir.quote).systemCmd }); 0 }, \stretch, spec[\stretch], - \octave, spec[\octave], \amp, Pfunc({ (spec[\amp] ? 1.0) * volOf.value }) - ] ++ instPair ++ modPairs)), + ] ++ freqPair ++ instPair ++ modPairs)), base ) }, { base })