Effects after Reverb?

Thanks. I was under the impression that FX get ordered in the way that we write them in Tidal, except for delay and reverb which are on sends. I could definitely be wrong.

And I’d love to know more about the possibility for making the reverb act like the other effectsIn the local chain if anyone knows if that’s possible.

ordered in the way that we write them

I don't think so. These give identical output:

s "superpiano" # room 1 # delay 1                                                  
s "superpiano"  # delay 1 # room 1

(0>1)|delay: 1.0f, room: 1.0f, s: "superpiano"

The semantics of # is to merge the maps, and the keys "delay", "room" are distinct so the result is identical.

Also, sometimes there is no order in the source:

s "superpiano" # stack [ room 1, delay 1 ]

actually I can't really explain what I am hearing, I guess it is

stack [ s "superpiano" # room 1    , s "superpiano" # delay 1  ]

two events each with their effect settings, and it's a race for who wins.

Does the order in this list play a role? https://github.com/tidalcycles/Tidal/blob/af4871b41d1190960171131390ff1d6b386c3cf3/src/Sound/Tidal/Stream.hs#L106

But this list has no room. Because that is a "local" effect?

Oh sorry, I thought you were asking about all of the other effect besides delay and reverb.

all effects, yes. I'm sure my understanding of effects is lacking.
E.g., this page https://tidalcycles.org/index.php/Advanced_workshop_topics mentions
"global effects and routing". I think "routing" is what we are after here. But what exactly is the distinction between global and non-global (local)? How do I find out that property, for any given effect?

My understanding (which could be wrong) is that 'global' is the same idea as a 'send effect', so the default configuration is that delay and reverb are on sends and 'local effects' will be everything else, and I do know that order matters with the local effects. They stack up. You can hear it pretty well with something like this:
d1 $ s "cp" # freeze 1 # squiz 0.3 # waveloss 98

But if you now place a reverb in the chain it gets sent off to the send bus (orbit) and does not get eaten up by the waveless effect. It sends the sound to the reverb at the end of the chain (so after the waveloss in this case):
d1 $ s "cp" # freeze 1 # squiz 0.3 # waveloss 98 # room 0.5 # size 0.8

And I've seen the documentation for making reverb and delay have their own sends (or orbits), but I haven't seen anything about having delay or reverb act locally, which would be great to play with.

Thanks. I do feel that documentation is lacking in this area. There was a related thread at Default samples list? - #2 by kit-christopher It was suggested to look at "ground truth" by s.queryAllNodes. Well, I really should.

1 Like

I actually thought that all effects were assigned to a specific orbit the moment you call d1, d2 etc?
It could also be that I've never understood correctly.

1 Like

One more thing: are you talking about global sends, i.e. the same way Ableton Live has two main sends for all channels?

If the delay send was global, how would I be able to have two delay effects with two distinct parameter settings such as

d1
    $ s "bd*2"
    # delay 0.8
    # delayt "s"
    # delayfb "0.4"

d2
    $ s "snare*2"
    # delayt "q"
    # delay 0.4

without the streams (d1, d2) constantly overriding each other parameters?


If you take this example instead:

d1
    $ s "bd*2"
    # delay 0.8
    # delayt "s"
    # delayfb "0.4"
    # orbit 1

d2
    $ s "snare*2"
    # delayt "q"
    # delay 0.4
    # orbit 1

delay on d2 will override the parameter of delay in d1 - you will basically hear the same delay applied on both kick and snare. But I have to explicitely route (I do not know if the term is correct here) both streams to the same orbit.

1 Like

I agree with @jwaldmann that order seems not important in the effect chain:

tidal> s "cp" # freeze 1 # squiz 0.3 # waveloss 98
(0>1)|freeze: 1.0f, s: "cp", squiz: 0.3f, waveloss: 98.0f
tidal> s "cp" # freeze 1 # waveloss 98 # squiz 0.3
(0>1)|freeze: 1.0f, s: "cp", squiz: 0.3f, waveloss: 98.0f

Can you provide an example? I can't really hear the difference trying out the two snippets above.

In the sclang shell, write s.queryAllNodes(1) (the 1 increases verbosity) to view the tree (of synth nodes etc.)

and s.sendMsg("/dumpOSC",1) to see what tidal sends but it still needs some guesswork.

perhaps https://github.com/musikinformatik/SuperDirt/issues/59

It seems that mot much changes even when you change the order of the effects:

[ "#bundle", 16322086467671128169, 
  [ 12, 1004, 1 ],
  [ 15, 1004, "resumed", 1 ],
  [ 12, 1003, 1 ],
  [ 15, 1003, "resumed", 1 ],
  [ 12, 1001, 1 ],
  [ 15, 1001, "resumed", 1 ],
  [ 12, 1000, 1 ],
  [ 15, 1000, "resumed", 1 ],
  [ "/g_new", 1789, 1, 2 ],
  [ "/s_new", "dirt_sample_1_2", -1, 1, 1789, "bufnum", 517, "sustain", 0.445122, "speed", 1, "freq", 261.626, "endSpeed", 1, "begin", 0, "end", 1, "loop", 1, "pan", 0, "out", 36 ],
  [ "/s_new", "waveloss2", -1, 1, 1789, "drop", 98, "out", 36 ],
  [ "/s_new", "squiz2", -1, 1, 1789, "pitchratio", 0.3, "out", 36 ],
  [ "/s_new", "spectral-freeze2", -1, 1, 1789, "freeze", 1, "out", 36 ],
  [ "/s_new", "dirt_gate2", -1, 1, 1789, "in", 36, "out", 38, "amp", 0.4, "sample", -1066824580, "sustain", 0.445122, "fadeInTime", 0, "fadeTime", 0.001 ]
]
[ "#bundle", 16322086612745563538, 
  [ 12, 1004, 1 ],
  [ 15, 1004, "resumed", 1 ],
  [ 12, 1003, 1 ],
  [ 15, 1003, "resumed", 1 ],
  [ 12, 1001, 1 ],
  [ 15, 1001, "resumed", 1 ],
  [ 12, 1000, 1 ],
  [ 15, 1000, "resumed", 1 ],
  [ "/g_new", 1790, 1, 2 ],
  [ "/s_new", "dirt_sample_1_2", -1, 1, 1790, "bufnum", 517, "sustain", 0.445122, "speed", 1, "freq", 261.626, "endSpeed", 1, "begin", 0, "end", 1, "loop", 1, "pan", 0, "out", 36 ],
  [ "/s_new", "waveloss2", -1, 1, 1790, "drop", 98, "out", 36 ],
  [ "/s_new", "squiz2", -1, 1, 1790, "pitchratio", 0.3, "out", 36 ],
  [ "/s_new", "spectral-freeze2", -1, 1, 1790, "freeze", 1, "out", 36 ],
  [ "/s_new", "dirt_gate2", -1, 1, 1790, "in", 36, "out", 38, "amp", 0.4, "sample", -1066824580, "sustain", 0.445122, "fadeInTime", 0, "fadeTime", 0.001 ]
]

What changes is this /g_new, it seems sort of incremental counter.

This is what the different orbits are for. @yaxu talks about that in one of his early videos for the class. The one on FX I believe?

It's very hard to tell without some time based effects in the chain, like reverb (which is my goal anyway lol).

I feel like I've gone as far as I can just by listening. We might need to wait for some official word?

EDIT: I think you're both right. I realized that I could set the resonance really high on a filter to ping it to get some decay. It doesn't matter if the waveloss is before or after the filter. I would expect to hear the filter pinging on the grains from the waveloss if it indeed came after. Now I'm really confused, right along with you.

d1 $ s "alex:0" # waveloss 99 # lpf 350 # lpq 1

Indeed it's not currently possible to change the order of the effects chain from Tidal. You can do it from SuperDirt/SuperCollider though.

You can find a lot of info about SuperDirt in the 'hacks' folder, e.g. I found the following info here: https://github.com/musikinformatik/SuperDirt/blob/develop/hacks/adding-effects.scd

~dirt.modules should list the effect chain in order. For me though, it gets truncated.

However I know you can change the order of two or more modules relative to each other like this:
~dirt.orderModules(['bpf', 'coarse']);

Actually if you run it with a single value nothing gets changed and it still prints the list of effects, e.g. from ~dirt.orderModules(['bpf']);, I get:

[ sound, out_to, map_from, vowel, shape, hpf, bpf, crush, coarse, lpf, pshift, envelope, tremolo, phaser, waveloss, squiz, fshift, triode, krush, octer, ring, distort, spectral-delay, spectral-freeze, spectral-comb, spectral-smear, spectral-scram, spectral-binshift, spectral-hbrick, spectral-lbrick, spectral-conformer, spectral-enhance, dj-filter ]

Note that the room and size of reverb aren't there. They're global effects, so necessarily have to come later. It looks like the global effects don't have helper functions for manipulating them yet, but go delay > reverb > leslie .

6 Likes

Thanks @yaxu. Great to be able to see and change the order.

And from this it seems like I could make (or find) my own reverb so that I could place it in the chain how I wanted. Very cool.

2 Likes

@ben perhaps this could be interesting to you?
(Audio signal processing in SuperCollider)

1 Like

I got something going pretty quickly. I ran into one issue that I can't figure out though: the reverb gets cut off at the end of each cycle and restarts. It's like it gets killed at the end of each cycle (or the start of the new one).

I placed the order of the effect after 'envelope' thinking that might be it but it didn't do it. Does anyone have any ideas?

The reverb I used sounds pretty terrible but it's just for test purposes. I followed along with the doc yaxu posted and this is what I did:

Added these params to my BootTidal.hs:

lmix = pF "lmix"
lroom = pF "lroom"
ldamp = pF "ldamp"

Then evaluated these three blocks of code is SC:

(
~dirt.addModule('lverb', { |dirtEvent|
	dirtEvent.sendSynth('lverb' ++ ~dirt.numChannels,
		// OPTIONAL
		// passing this array of parameters could be left out,
		// but it makes it clear what happens
		[
			lmix: ~lmix,
			lroom: ~lroom,
			ldamp: ~ldamp,
			out: ~out
		]
	)
}, { ~lmix.notNil or: { ~lroom.notNil } }); // play synth only if at least one of the two was given
)


~dirt.orderModules(['bpf', 'crush', 'coarse', 'pshift', 'shape', 'envelope', 'lverb', 'tremolo', 'phaser', 'squiz', 'fshift', 'triode', 'krush', 'octer', 'ring', 'distort', 'spectral-delay', 'spectral-freeze', 'spectral-comb', 'spectral-smear', 'spectral-scram', 'spectral-binshift', 'spectral-hbrick', 'spectral-lbrick', 'spectral-conformer', 'spectral-enhance', 'dj-filter', 'vowel', 'waveloss', 'lpf', 'hpf']);

(
var numChannels =  ~dirt.numChannels;

SynthDef(\lverb ++ numChannels, { |out, lmix = 0.25, lroom = 0.3, ldamp = 0.5, amp = 1.0|
	
    var signal;

    signal = In.ar(out, numChannels);

    ReplaceOut.ar(out,
        FreeVerb2.ar( // FreeVerb2 - true stereo UGen
            signal[0], // Left channel
            signal[1], // Right Channel
            lmix, lroom, ldamp, amp
        )
    ); // same params as FreeVerb 1 chn version

}).add;
)

And ran this in Tidal to test:
d1 $ sound "cp!3" # lmix 0.9 # lroom 0.9 # ldamp 0.1 # waveloss 95

Let me know if anyone wants to play around with it, or has ideas re: the restarting of the reverb every cycle.

Hm, I suppose it'll be stopping at the end of each sound? As these effect units are local to each sound, they start and stop with the sound.

Ah, I was afraid of that. I suppose legato 2, etc should work though.

But that leads me to another question that I hadn't thought of until now: effects in SuperDirt must be polyphonic yes? In other words, I'm not treating the overlapping sounds (if using legato) together in the reverb, but I'm treating each sound separately and then SuperDirt is mixing them back together. Is that correct?

In the case of your local reverb effect yes, it's local to each event. For the standard/built-in superdirt reverb, it's 'global', so all the sounds (per orbit) go in there.

1 Like

More talk of orbits in Alex's new video here:

2 Likes