SuperDirt icon indicating copy to clipboard operation
SuperDirt copied to clipboard

Mutating events -- beyond the trigger message

Open yaxu opened this issue 5 years ago • 11 comments

With upcoming changes, Tidal can now represent effect changes beyond trigger messages.

For example sound "bev" # crush "1 2" used to result in the second value of crush being discarded, but now (in the master branch but not released) it's preserved as applying to the second half of the event:

(0>½)-1|crush: 1.0f, s: "bev"
0-(½>1)|crush: 2.0f, s: "bev"

I'm still not sure how to reliably attach an identifier to an event, but if it could be done, how hard would it be to change an effect value on a running sample or synth?

yaxu avatar Jul 10 '19 21:07 yaxu

Well I guess we could simply identify events with a combination of start time, end time, sound, and note/sample number - adding a note/sample number delta control for pitch bend / sample mashing

yaxu avatar Jul 10 '19 22:07 yaxu

I think on the SC end, if you can identify which synth to send the message to it's fairly straightforward to update a parameter. But Tidal would have to send an identifier - I don't think even begin/end/s/n are enough to distinguish synths, you might have superimpose (# shape 0.4) $ s "sn". I think ideally Tidal would send a unique ID with each OSC bundle. Then the tricky part for SC is keeping a dictionary of Tidal ID -> Synth and maybe checking if things are still playing or not.

bgold-cosmos avatar Jul 10 '19 22:07 bgold-cosmos

Yes I think begin/end/s/n only take us 80-90% of the way to identifying individual notes, but is better than nothing, and already better than MIDI. I think a truly unique ID would not be possible with the current representation, but it makes my head hurt to think about it.

yaxu avatar Jul 11 '19 09:07 yaxu

Maybe @telephon has ideas about how this can work on the SC side, I remember we've discussed this sort of thing before.

yaxu avatar Jul 11 '19 09:07 yaxu

Tidal master will now send an alphanumeric 'id' parameter with every message, if the cSendParts config is set true. I have a proof of concept for this working in classic dirt pretty well, e.g. this creates a nice vocal burbling: d1 $ sound "arpy" # vowel "[a e i o]*16" # speed 0.1 The only problem is that the part is sent every frame (20Hz by default) or more, even if no value changes. With a lot of sounds being sent, this will result in quite a lot of string comparison..

yaxu avatar Jul 14 '19 09:07 yaxu

The main issue I see is that tidal doesn't (need to) tell sclang when a note is released, does it? If we need to keep track of ids, we also need to get rid of them, as @bgold-cosmos said.

telephon avatar Jul 14 '19 19:07 telephon

There is a trick similar to the one in cutgroups, which allows us to make the reception of a parameter depend on a key-lock match. So you can send the change to all the synths at once (that is to the group), but only the one with a matching locks will respond.

But this means that we have to wrap every parameter into such a behavior, which may be a bit unwieldy for those who a used to the common syntax:

// instead of a function ~lockParam we'd have a class like `LockParam(…)`.
~lockParam = { |name, defaultValue|
	Latch.kr(name.kr(defaultValue), BinaryOpUGen('==', \paramLock.ir, \paramKey.tr));
};

SynthDef("dirt_hpf" ++ numChannels, { |out|
	var signal = In.ar(out, numChannels);
	var hcutoff = ~lockParam.(hcutoff, 440);
	var hresonance = ~lockParam.(hresonance, 0);
	signal = RHPF.ar(signal, hcutoff.abs, hresonance.linexp(0, 1, 1, 0.001));
	ReplaceOut.ar(out, signal)
}, [\ir, \ir, \ir]).add;

The trick is this:

(
(
SynthDef(\lockTest, { |param|
	var value = Latch.kr(param, BinaryOpUGen('==', \paramLock.ir, \paramKey.tr));
	value.poll(2);
	
}).add
)

x = Synth(\lockTest, [\param, 77, \paramLock, 1999, \paramKey, 1999]);

x.set(\param, 100, \paramKey, 7); // wrong key, no change 
x.set(\param, 100, \paramKey, 1999); // correct key, this changes
x.set(\param, 20, \paramKey, 199); // wrong key, no change 

Would this whole thing maybe be a way to get rid of global effects altogether?

telephon avatar Jul 14 '19 19:07 telephon

The main issue I see is that tidal doesn't (need to) tell sclang when a note is released, does it? If we need to keep track of ids, we also need to get rid of them, as @bgold-cosmos said.

In classic dirt, I just ignored control (triggerless) messages that didn't match with any running sound.

yaxu avatar Jul 14 '19 20:07 yaxu

yes, but you kept track of running sound processes which superdirt doesn't ...

telephon avatar Jul 15 '19 21:07 telephon

This seems good to me @telephon, if you don't mind an experiment..

Currently I'm sending quite a long string for 'id' that is basically the identifying characteristics of an event separated by dashes. I can send a bool value to indicate whether it's an event onset or not as an additional parameter?

yaxu avatar Jul 15 '19 21:07 yaxu

all we'd need is a number that tells us which synth is addressed. For each synth that is started, we also need this number.

telephon avatar Jul 18 '19 06:07 telephon