Track: You Can't Get My

Love this! The glitchy drums are outstanding.

Yeah, Drums are amazing, and dreamy athmosphere or composition remind me some naive idm tunes of late 90s. Thanks for sharing!

1 Like

How do you code drums like that in SC?

I used something I call a “micro-tracker,” where each character corresponds to a different drum hit. For example, I could type k.k.s.hghgkks.hg where k = kick, s = snare, h = hat, g = glitch sound. Sequencing was done manually.

All drum hits are synthesized with standard methods. Glitches were made mostly using FM. Leading up to significant downbeats, random effects like pitch shifting and comb filtering are enabled to add some variety to the sound design.

I’ve thought about using characters or symbols as a way to sequence stuff like this but I gave up. I need to get into SC again.

@nathan Fantasic !!!

I love this a LOT

I don’t expect a full disclosure, but could you point me in the direction of how to accomplish something like that “micro-tracker”?

Either way, great job!

Thanks for listening! It’s a string parser where each character is mapped to a SynthDef using a dictionary. Here’s some example code, SynthDefs not included:

var pattern = "
k.k.s.hghgkks.hg
k.k.s.hghgs.hghg
k.k.s.hghgkks.hg
s.s.hgs.hghgs.hg
";
var map = IdentityDictionary[
    $k -> \kick,
    $s -> \snare,
    $h -> \hat,
    $g -> \glitch
];

Routine {
    var bpm, beat, tatum;
    bpm = 190;
    beat = 60 / bpm;
    tatum = beat / 4;
    pattern.do { |character|
        var synthdef;
        if(map[character].notNil) {
            synthdef = map[character];
            s.makeBundle(s.latency, { Synth(synthdef); });
            tatum.wait;
        } {
            if(character == $.) {
                tatum.wait;
            }
        }
    };
} .play;

Since it’s only a dozen lines, I usually rewrite a micro-tracker from scratch for each new piece, so the syntax and semantics can differ. Some variations include using the digits 0-9 for probabilities or velocities of drum hits, entering melodies with hexadecimal, etc.

7 Likes

Nice song and cool method. How exact do you implement the variations, for example mapping the digits 0-9 to amp? Do you simply create a second string and map the amp to it? Or do you do this in a single string/mapping object?

Have you been working with something similar or do you know a good way for creating either (with your presented ‘micro-tracker’ method):

  1. multiple drum hits at ones (snare + kick) or
  2. adding more variations without coding all notes one by one?
    For the latter I’ve been recently experiencing with Place which gives quick good results. But with a single string its maybe a bit harder to implement.

Also another quick one, why don’t you use patterns?
I’ve tried to implement your method with some minimalstic created drum synths and using ur method of strings but reading them with a Pbind instead:

(
SynthDef(\kick,{
	|amp=0.2|
	var sig, e;
	e = EnvGen.kr(Env.perc(0.01,0.15,1,-4),doneAction:2)**1.2;
	sig = (1*SinOsc.ar(e.linlin(0,1,55,110)))+PinkNoise.ar(1);
	sig = RLPF.ar(sig,e.linlin(0,1,220,1100),5).tanh;
	Out.ar(0,sig * e * amp!2);
}).add;
SynthDef(\snare,{|amp=0.1|
	var sig, e;
	e = EnvGen.kr(Env.new([1,0.15,0],[0.01,0.1],[\sine,-3]),doneAction:2);
	sig = WhiteNoise.ar() + (SinOsc.ar(e.linlin(0,1,110,440)) * e * 2);
	sig = BPeakEQ.ar(sig,e.linlin(0,1,880,1760),10,15).tanh;
	sig = RHPF.ar(sig,220,0.05).lag(0.00015);
	Out.ar(0,sig* amp * e!2);
}).add;
SynthDef(\hat,{|amp=0.1|
	var sig, e;
	e = EnvGen.kr(Env.perc(0.005,0.04),doneAction:2);
	sig = WhiteNoise.ar(1.5).tanh;
	sig = HPF.ar(sig,3520).lag(0.0001);
	Out.ar(0,0.5*sig* amp * e!2);
}).add;
)

(
var ptrn, map;
ptrn = "
k.. h.k 
k.. h.s
ks. .ks
h.h sss
";
//remove spaces and line breaks
ptrn = ptrn.replace(" ","").replace("\n","");
map = IdentityDictionary[
    $k -> \kick,
    $s -> \snare,
	$h -> \hat,
	$. -> \rest
];
p.stop;
p = Pbind(
	\instrument, Pn(Pseries(0,1,ptrn.size)),
	\instrument, Pfunc{|key| map[ptrn[key[\instrument]]]},
	\dur,0.12,
	\amp,0.1*Pn(Pseries(1,-0.1,3)).trace,
).play;
)

cheers.

Just for fun, here’s an alternate (and slightly shorter) way to do the same thing, using Psym1 to lookup a sequence of characters (interpreted as symbols) directly in a pattern:

(
var ptrn, map;
ptrn = "
k.. h.k 
k.. h.s
ks. .ks
h.h sss
";
//remove spaces and line breaks
ptrn = ptrn.replace(" ","").replace("\n","");
map = (k: \kick, s: \snare, h: \hat, '.': \rest);
p.stop;
p = Pbind(
	\instrument, Pn(Psym1(Pseq(ptrn), map)),
	\dur,0.12,
	\amp,0.1*Pn(Pseries(1,-0.1,3)).trace,
).play;
)
3 Likes

Separate strings for each drum type. For example 9.....9. for kick, ..9...9. for snare, etc. Alternatively you can use two characters for each time unit, the first character indicating the drum hit type and the second character for velocity. Whatever works best for the piece.

I stopped using them in favor of Routines years ago. It’s much easier to memorize a single class and a small handful of control structures vs. hundreds of poorly documented P* classes. (Not to mention the numerous design flaws in said classes.)

1 Like

I’ve wondered a lot about the difference / advantages of using Routines (or Tdefs?) instead of Patterns for a while now. One thing that I wasn’t yet sure how to implement was a transition over time in the same way a Pseg would offer eg Pseg([1, 10], 30, \sine) - is this possible with any of the control structures you use?

For gradual automations, I tend to use server-side Env mapped to control busses for that so you get smooth movement while notes are playing, but if you want client-side automation in a Routine you can use functions of thisThread.seconds or thisThread.beats I think. That’s what Penv and Pseg do under the hood.

2 Likes

Great method, it inspire me a lot. And i have question that how can i use two characters for each time unit.

Hi and welcome! The string looks something like this: k9 h3 h3 k5 s9 h3 h5 h3. You can parse it by looping through each character, setting a flag if you encounter a valid drum hit, and if that flag is enabled you parse the next character as velocity/probability/effects/etc. I can’t share code at the moment but hopefully that should get you started.

IMO for parsing, CollStream is everyone’s best friend – because then the parser can be a literal state machine, without needing flags in the loop. E.g., this way, it can handle multiple modifier characters seamlessly.

(
~parseOneHit = { |stream, ch|
	var hit = ch;
	var modifiers = "";
	
	while {
		ch = stream.next;
		ch.notNil and: { ch.isSpace.not }
	} {
		modifiers = modifiers ++ ch;
	};
	
	[hit, modifiers, ch]
};

~parseString = { |string|
	var stream = CollStream(string);
	var ch;
	var items;
	var hit, modifiers;
	
	ch = stream.next;
	while {
		ch.notNil
	} {
		case
		{ ch.isAlpha } {
			#hit, modifiers, ch = ~parseOneHit.(stream, ch);
			items = items.add([hit, modifiers]);
		}
		{ ch.isSpace } {
			ch = stream.next
		}
		// ... other cases
		{ Error("Unrecognized hit '%'".format(ch)).throw };
	};
	
	items
};
)

~parseString.("k9 h3 h3 k5 s9 h3877 h5 h3");
-> [ [ k, 9 ], [ h, 3 ], [ h, 3 ], [ k, 5 ], [ s, 9 ], [ h, 3877 ], [ h, 5 ], [ h, 3 ] ]

hjh

1 Like

necrobumping for sure, but I’ve been watching your streams and youtube videos, Nathan, and I want to say that I love this technique. It’s a lot more straightforward than the standard pdef techniques and it’s flexible enough to add logic. Nice one.

2 Likes

this is huge! i love the specificity of trackers and look forward to trying to implement something like this.
your code has been so informative to try and work through, still trying to get comfortable with using routines instead of pbinds but i love how readable it becomes.

Lately I’ve expanded from the micro-tracker to something akin to an actual tracker, where each time unit is on a separate line. It’s less compact on the eyes but allows for stuff like programming different effects on every beat, which is great for IDM drums. You can see me use this technique in the first half of this livestream:

Not my favorite music I’ve made, but the approach has a ton of potential. I’ve programmed pitched melodies with this approach using LilyPond note names.

2 Likes

I watched the first half so far, great stuff and very inspirational, thanks!

had a weird question,
i’ve been working through a bunch of your youtube example videos (they are amazing)
and i was just wondering what you are conceptualizing your variable tatum as?
sorry if this is basic i’m just curious what you are using it for [i can tell it’s a smaller time division], slash also just why is it called tatum. no pressure just thought i’d ask

thanks again for all your excellent videos