Amplitude of Grains in GrainBuf

Hello,

is there a way to control the amplitute of individual grains in GrainBuf?
As far as I understand mul changes the overall amplitute of the Synth but it would
be great if one could have more precise control. I know TGrains can do that.

Probably it could be possible to include this option in a future release?

This was requested once before, but it was decided against being in the general UGens. However, in sc3-plugins in JoshUGens, I did create variants that allowed for this. See GrainBufJ.

Thank you Josh,

I will check out your plugin. It’s very nice that you made these variants But still maybe it would be worth to implement just the grain amp control in the default GrainBuf because it is very essential part of the synthesis itself.

Out of curiosity, and in order to learn how to modify the source code, it would be interesting if there are any tutorials on this that you could reccomend. I assume such a modification should be just an easy task but really don’t know where to start? Is there any Xcode Template?

You can feel free to bring the topic up again, but for the most part I think the concern was backwards compatibility. And that, at the time, only one person had requested it. I think you are (at least vocally) the second, so I think you’d need to present a strong argument for either breaking the UGens for current users or arguing that other versions should be included in the primary distribution. This is something we take into consideration when changes like this are proposed. Bloat vs. convenience vs. common usage, etc. Now, it could be that we deprecate the current UGens in favor of new ones that have this…
As for templates, I think there are a couple of approaches. You can generate the source with Xcode projects using Cmake. Also, Brian Heim has created cookie cutter UGen starter code. But since this is already made… I’m wondering, what do you want to modify beyond this? If the rest of the dev team wanted to integrate these UGens, that would be the logical next step.

Cheers - Josh

Thank you Josh,

I think I am going to find myself from time to time in similar situations and I should have some experience with source code cooking.

As for the GrainBuf I understand the backwards compatibility issue. A big pain but I believe that in a musical level it is very important. OK I can try to bring it up again but how? Where should I present my argument? I think if the mul parameter is reassigned to control each grain’s individual amlitude (instead of the overall synth), even past code that is as usually defaulting to mul=1 will probably not be affected right?

I’d recommend the GitHub issue tracker or the sc-users mail list for making the suggestion. I’ll bring it up at today’s dev meeting as well.

Also - we can’t use mul since the expectation there is that its value is applied sample by sample (at audio rate), so it would break expectations with modulation or enveloping. I think I’m this instance, a set indigene with higher levels of control would make sense (and we can probably think of other things to add to these UGens that would be general use, but more specialized than the current Ugens).

/*
Josh Parmenter

www.realizedsound.net/josh

*/

As a workaround did you consider other strategies of buffer granulation, e.g. pattern-based ? From your question I conclude that you prefer GrainBuf to TGrains, because you want to pass specified envelopes. With pattern-based granulation that would be easy as well as amplitude sequencing.

1 Like

Thank you Daniel, yes the customized enveloping is the reason I need GrainBuf and yes pattern-based granulation is a nice solution which I have started implementing. With Patterns other options like filtering are available but isn’t it safer and more stable to work generally on the server side than bombardizing it with OSC messages?

It depends how many grains you are generating. A few hundred per second are normally no problem, just use OffsetOut for accurate timing.
I’ve been using both strategies of granulation in parallel for more than 10 years now. I still use granulation ugens but to explore variations of granulation itself pattern-based variants offer more possibilities. It’s a tradeoff between practicability and flexibility, with ugen encapsulation you loose a large number of options. It’s more effective, but more grains do not automatically correlate with more interesting results. IMO differentiation is most important and this is easier with patterns, then you can get very interesting sounds already with some dozens of grains per second.
Also consider hybrid strategies: a SynthDef can generate a short granular cloud with dense timing, a sequence of such clouds could be triggered with Patterns. There are many ways, I’ve described some strategies in miSCellanous_lib’s Buffer Granulation Tutorial.
And still I stumble across alternative ways of implementation, this one e.g. is nice, LFPulse as amplitude modulator. If you take kr you get a trapezoid envelope and at the same time a trigger for pulsar granulation with BufRd. On occasion I should add such to the tutorial:

    b = Buffer.read(s, Platform.resourceDir +/+ "sounds/a11wlk01.wav");

    x = { 
            // var trig = K2A.ar(LFPulse.kr(50));
            var trig = K2A.ar(LFPulse.kr(LFDNoise3.kr(1).exprange(3, 150)));
            var frames = BufFrames.ir(b);    
            var phasor = Phasor.ar(trig, 1, 0, frames, LFDNoise3.ar(0.3).range(0, frames));
            BufRd.ar(1, b, phasor) * trig
    }.play

You could layer several of those pulsar streams, as Curtis Roads suggests, etc.

BufRd granulation combined with variable amplitudes and envelopes can be done with DemandEnvGen

// raw envelope variation with DemandEnvGen

x = { 
    var level = SinOsc.ar(0.3).range(0.2, 1);
    var curve = SinOsc.ar(3) * 5;
    DemandEnvGen.ar(Dseq([0, level, 0, 0], inf), 0.002, shape: 5, curve: curve);
}.scope

x.release


// applied to granulation

b = Buffer.read(s, Platform.resourceDir +/+ "sounds/a11wlk01.wav");

x = { 
    var level = SinOsc.ar(0.3).range(0.2, 1);
    var curve = SinOsc.ar(3) * 5;
    var trig = DemandEnvGen.ar(Dseq([0, level, 0, 0], inf), 0.002, shape: 5, curve: curve);
    var frames = BufFrames.ir(b);    
    var phasor = Phasor.ar(trig, 1, 0, frames, LFDNoise3.ar(0.3).range(0, frames));
    BufRd.ar(1, b, phasor) * trig
}.play
2 Likes

Is there any Xcode Template?

Brian Heim’s cookiecutter template builder is great for getting you up and running, with an Xcode template as well.

There is of course also the example-plugins repo. This is slightly more manual in terms of the setup and build process, but still very doable, and has the advantage of showing you some examples as well.

To learn more, there is a “Writing Unit Generators” tutorial in SC help, Chapter 25 of the SuperCollider book, and some outdated but still useful bits floating around the internet.

[Hopefully this isn’t a duplicate… for some reason my original responses were flagged and hidden]

Is there any Xcode Template?

Brian Heim’s cookiecutter template builder is great for getting you up and running, with an Xcode template as well.

There is of course also the example-plugins repo. This is slightly more manual in terms of the setup and build process, but still very doable, and has the advantage of showing you some examples as well.

To learn more, there is a “Writing Unit Generators” tutorial in SC help, Chapter 25 of the SuperCollider book, and some outdated but still useful bits floating around the internet.