This file is a complement to the Buffer_Granulation tutorial. It contains variants of granulation that are applied to an audio signal directly, without the explicit use of a buffer. As with buffer granulation there exist language-driven and server-driven as well as hybrid variants. Especially pattern-based live granulation raises certain accuracy issues, which are summarized in this tutorial.
You can free buses on occasion if you are sure that nothing is running and you won't need them again. Keep in mind that you can also (re-)start the server with a higher number of audio buses available (Ex.2c)
Another possible source of hangs is careless deep nesting of Patterns where mistakes can easily occur. Starting with clear Pattern structures is recommended - and if more complications are involved: testing without sound first, after saving your patch, might be a good idea.
Even with overlapping grains, sequenced effect processing per grain is possible with GrainIn, but requires more effort, see Buffer_Granulation: Ex.1e in the Buffer Granulation tutorial.
In this example only non-overlapping grains are regarded, for overlapping, as with GrainIn, a multichannel approach as in Ex.1e in the Buffer Granulation tutorial can be applied. In comparison to live granulation example 1a there is hardly an advantage in this basic variant. However intermediate processings can be built into this SynthDef, which aren't possible in the above example, where granulation is encapsulated in a ugen, manipulation of the envelope signal could be one.
The crucial point of this strategy is a kind of incompatibility of In.ar and OffsetOut. Normally we use OffsetOut for exact buffer granulation with patterns, as the start of the synth (the grain) is corrected by a shift (standard Out.ar is only able to start at control block boundaries). However, when In.ar and OffsetOut.ar are used in the same synth the read input signal is also shifted, which results in a correct grain distance but an fluctuating input delay. This can be overcome by a little trick: we can use OffsetOut to send a trigger to a bus, which indicates its correct delay. Then the trigger can be read in the same synth and trigger again a gated envelope for the input signal, the resulting grain can be output with normal Out.ar. So grain distances are correct and input is not fluctuating (see Ex.2d for an accuracy comparison). Nevertheless language-driven sequencing is not sample-exact in realtime, no matter if In.ar is used or not, this is related to hardware control and cannot be overcome. This might be an issue with a strictly periodic input signal and very short grain distances. You can e.g. check out with granulation of a fixed-pitch triangular wave or similar, every few seconds or so there will happen an audible jump due to an irregular time interval, which is necessary for clock calibration; at that point there will, in general, also be a phase shift of the input signal (see last example of Ex.2d). This might not be noticed with an input of spoken voice e.g. Control block length is also a boundary for gated envelopes defined with EnvGen – here envelopes are established with an env buffer used by BufRd and Sweep ugens, a flexible method as Envelopes shape can be defined arbitrarily in language.
At that point I haven't seen a solution to pass the trigger bus as argument, in the example it is hard-wired. As the SynthDef uses a SetResetFF ugen, which relies on two triggers within control block length, grainDelta shouldn't be shorter than that. If shorter grainDeltas are required this would be possible with alternating SynthDefs and buses. For the same reason this SynthDef should only be used once at the same time by a Pbind/EventStreamPlayer. Alternatively – as in Ex.2b – a SynthDef factory can produce a number of structurally equal SynthDefs bound to a number of buses.
As trigger buses have to be hard-wired, a SynthDef factory produces a number of structurally equal SynthDefs bound to a number of buses. In this variant the granulation is combined with a bandpass filter.
This example compares the inaccuracies occuring with "normal" usage of Out.ar and the usage of In.ar + OffsetOut.ar with the strategy recommended in Ex.2a. Run the three examples, the audio output is played and recorded into three files in the recordings directory (you get the path with thisProcess.platform.recordingsDir).