Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Original dirty compressor #304

Open
yaxu opened this issue Sep 5, 2024 · 9 comments
Open

Original dirty compressor #304

yaxu opened this issue Sep 5, 2024 · 9 comments

Comments

@yaxu
Copy link
Collaborator

yaxu commented Sep 5, 2024

One thing missing from SuperDirt is the original compressor.

https://github.com/tidalcycles/Dirt/blob/071fd88b3e004a11215afd11b718e92d3ab44d18/audio.c#L770-L777

Thankfully Pulu has ported it, code below. It sounds excellent, very useful for from-scratch performance. I think it would be great to incorporate it into superdirt, although probably default off. It needs miSCellaneous_lib as a dependency, perhaps it's better to hard fork Fb1?

// emulation of master compressor from original Dirt
// requires Fb1 from miSCellaeous for single-sample feedback
// https://github.com/dkmayer/miSCellaneous_lib
(
Ndef(\dirtComp, { |amount=1, speed=50|
	var in, max, env;
	in = In.ar(0, ~dirt.numChannels);

	max = Select.ar(ArrayMax.ar(in.abs)[1], in);
	env = Fb1({ |in, out|
		var env, prod;
		env = out[1];
		env = env + (speed / SampleRate.ir);
		prod = (in[0] * env).abs;
		Select.kr(prod > 1, [env, env/prod]);
	}, max, leakDC: false);

	ReplaceOut.ar(0, in * amount.linlin(0, 1, 1, env * 0.2));
}).play(
	group: RootNode(Server.default),
	addAction: \addToTail
);
)

// can also tune the parameters
Ndef(\dirtComp).set(\amount, 1);
Ndef(\dirtComp).set(\speed, 200);
@telephon
Copy link
Contributor

telephon commented Sep 5, 2024

The UGen is a control rate ugen (Select.kr) so it doesn't need Fb1 really.

Can't test it right now, but this should be about what is needed:

(
Ndef(\dirtComp, { |amount=1, speed=50|
	var input, max, env, n, prod;
	var ctrl;
	n =  2; //~dirt.numChannels;
	input = In.ar(0, n);
	ctrl = input[0];// maybe we want to multichannel expand or sum rathen than taking the first channel?

	max = ArrayMax.ar(input.abs);
	env = LocalIn.kr(n);
	env = env + (speed / SampleRate.ir); // needs fix: making it depend on the sample rate and on block size 
	prod = (ctrl * env).abs;
	env = Select.kr(prod > 1, [env, env/prod]);
	LocalOut.kr(env);
	ReplaceOut.ar(0, input * amount.linlin(0, 1, 1, env * 0.2));
}).play(
	group: RootNode(Server.default),
	addAction: \addToTail
);
)

It would be good if we could just add the Fb1 part of the library otherwise, yes!

@ahihi
Copy link
Contributor

ahihi commented Sep 5, 2024

The UGen is a control rate ugen (Select.kr) so it doesn't need Fb1 really.

that is a mistake on my part. the original C code runs this conditional at audio rate, but i am not entirely sure how to achieve that here.

@telephon
Copy link
Contributor

telephon commented Sep 5, 2024

Ah I see, well, all you have to do is to use a Select.ar in the Fb1. But if it sounds good as it is now, maybe that is not necessary? Btw. have you checked the Compander UGen? (here is the source: https://github.com/supercollider/supercollider/blob/71d5d1841bc1b26a59560c6544f3996765f6ff63/server/plugins/FilterUGens.cpp#L3242). It may be similar, but I am not sure. Also there is a CompanderD, a slightly different one.

Just to be sure!

@ahihi
Copy link
Contributor

ahihi commented Sep 5, 2024

as per the Fb1 docs, that does not work:

What cannot / shouldn't be done (ar case considerations):

Writing ar UGens in func that produce a time-varying signal itself (e.g. SinOsc.ar, in contrast to SinOsc.kr and operator UGens like '+', '*' etc.) - instead, if such ar UGens aren't applied to data from inside func, they can be passed via Fb1's and func's 'in' arg. It remains the case of such ar UGens that should process data that is provided by func (e.g. letting the fb out modulate a parameter of a VarSaw.ar). This is currently not possible and I don't have a clear picture if and how it would be possible at all or if it would make much sense.

i do think the current version sounds good, but would like to match the original.

edit: i do also use Compander a lot, but the goal here was to reimplement the algorithm from Dirt ^^

@telephon
Copy link
Contributor

telephon commented Sep 5, 2024

Another idea: What about writing the thing as a ugen plugin? We could add it to sc3plugins.

@ahihi
Copy link
Contributor

ahihi commented Sep 5, 2024

yeah, that could end up being the best option and surely would run the fastest. i have been meaning to learn SC plugin development anyway.. might be a few weeks till i have the time though.

@telephon
Copy link
Contributor

telephon commented Sep 6, 2024

Most people say it is quite easy. You could take Compander as a starting point.

@thgrund
Copy link
Contributor

thgrund commented Sep 27, 2024

I migrated the compressor Ndef from here (https://github.com/alikthename/Musical-Design-in-Supercollider/blob/master/16_compression.sc) and integrated it in the SuperDirtMixer. I am really happy with this implementation. But maybe it's to complex to integrate it directly into SuperDirt? And if someone needs a more flexible compressor they can still use the SuperDirtMixer?! I just wanted to bring this into discussion.

Here is my implementation: https://github.com/thgrund/SuperDirtMixer/blob/mrreason-setup/synths/synth.scd#L24

WDYT?

@telephon
Copy link
Contributor

Ah that may also be a good option (we may need to adjust it a little to match with the logic of global effects).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants