making better LFOs

DSP, Plugin and Host development discussion.
Post Reply New Topic
RELATED
PRODUCTS

Post

been immensely inspired lately and turned my attention to lfos. couple of days later i've got over thirty algorithms, more to implement, and waiting for them to stew and find which ones are the more musically useful. i thought, i'd share some thoughts here and hopefully inspire others, though, of course, i have no idea how novel this is as i haven't kept up with the latest commercial releases.

part of the fun is the challenge of coding methods that have one "mod" parameter in addition to rate and amount, keeping the user experience from getting too weighted in particulars. many of these ideas swiftly head into the "i'd like four or five shaping params for this algorithm" territory where perhaps offering a very small selection of complex algorithms for "lf.generators" would be more appropriate.

anyway. my perspective - i reuse lfo builds between synths and am on my fifth lfo iteration, so i've been thinking in the "one mod param" frame for a while. my basis for this algorithm (which is of course completely arbitrary, it's best to think through your own) -

mod = range 0 to 1
m = 1 / mod
mi = 1 / (1 - mod)

a basic (-1 to +1) "mod" linear lfo which fades from saw to tri to ramp.. maybe not the best way to do it, you should try to build your own instead of using the reference as it's basic stuff and fun to think through :)

Code: Select all

			case 0:											//	linear
				if (p > 1) p -= 1;
				o = (p + mod) * 0.5;
				if (o >= 1) o -= 1;
				if (o < mod) {o *= m;}
				else {o = 1 - o;	o *= mi;}
				*out1 = (o * 4 - 3) * *in5;
				p += w;
				break;	

the next waveform we want is a sine, and we can reuse the linear code to make a sine by shaping the linear form with an s-curve. to do this, we bring the range to [0,1] and shape n *= n * (3 - n - n).

the s-curve is not quite a sine.. but we can improve the contour by subtracting the third harmonic from it by a small amount.. o -= (o * o * o * .04712); works for me, it's visually approximate to a sine. there are other ways to do a "phase distorted sine".

i explored the morphing linear form for a bit, as simple (non-AA) numeric shaping is kind of the hallmark of efficient coding from the dsp era i cut my chops in. trying simple things like n * n or n * (2 - n) can produce a variety of interesting and pertinent contours. flip things around, know the ranges of contours.

here's a few i thought were interesting..

Code: Select all

				if (p > 1) p -= 1;
				o = p;
				o *= o * (3 - o - o);
				o = (o + mod) * 0.5;
				if (o >= 1) o -= 1;
				if (o < mod) {o *= m;}
				else {o = 1 - o;	o *= mi;}
				*out1 = (o * 4 - 3) * *in5;
				p += w;
one kind of "wave" contour, from an s-curve in one direction to the other, weighted with narrow peaks.

Code: Select all

				if (p > 1) p -= 1;
				o = (1 - p + mod) * 0.5;
				if (o >= 1) o -= 1;
				if (o < mod) {o *= m;}
				else {o = 1 - o;	o *= mi;}
				o = o * 3 - 1;	//	range 0-2	
				o *= (o - 2) * o * o;
				o = o * 1.17647 + 1;
				*out1 = o * *in5;
				p += w;
this one distorts the linear segments to make a dual cycle lfo.

Code: Select all

				if (p > 1) p -= 1;
				o = 1 - p;	o *= 1 + mod * (o * o - 1);	o += o;
				//o = 2 - p - p;	//	range 0-2	
				o *= (2 - o) * (o * mod - .75) * o;
				{
					double t = mod * (1 - mod) * 4;	t *= t;
					o *= 1.12 + t * 1.2;}
				*out1 = o * *in5;
				p += w;
this one is kind of interesting (see note on next comment) as it shifts from a negative curved pulse to a positive curved pulse (you'll see my naive attempts to maintain a constant gain).

Code: Select all

				if (p > 1) p -= 1;
				o = 1 - p;	o *= 1 + mod * (o * o * o - 1);	o += o;		//	range 0-2	
				o *= (2 - o) * (o - 1) * 2.5;		
				*out1 = o * *in5;
				p += w;
from my years of emulative synthesis i have kind of an obsession with this contour, this one dips a bit but it's like an exponential decay through a lowpass filter (you know.. sinusoid 0-1 up, then a long decay).

Code: Select all

				if (p > 1) p -= 1;
				o = p + (mod * 4.63f - 2.f) * (p * p * p - p);
				o *= o * (3 - o - o);
				o *= (2 - o - o) * (1 - o) * 3.4;		
				*out1 = o * *in5;
				p += w;
this one's kind of "two contours in one" - it fades from (more or less..) the contour i describe forwards to the same backwards, in the middle range (say mod 0.3 to 0.7) then the extremities introduce more multicyclic peaks.

remember i'm all contributionary and ascetic when you're ripping me off here :) i've made like $40 off vst in the last two months. so credit me in your documentation.

Code: Select all

			case 11:										//	phase distortion impulse 1
				if (p > 1) p -= 1;
				o = 1 - p;	o *= o * o;	
				o = sin(p * (1 / (.051 - mod * .048)) * o);
				*out1 = o * (1 - p * (2 - p)) * *in5;
				p += w;
				break;
			case 12:										//	phase distortion impulse 2
				if (p > 1) p -= 1;
				o = 1 - p;	o *= o;	
				o = sin(p * p * (1 / (.051 - mod * .05)) * o);
				*out1 = o * (1 - p * (2 - p)) * *in5;
				p += w;
				break;
here are two similar contours - the idea was to sync them to 0 phase at gate, as modulators equivalent to "percussion transients". more expensive with the sine function but computers are fast and it's time to stop being daunted by using them. very basic idea, decaying rate and amplitude with a simple bit of phase distortion that breaks up the sinusoid motion a bit perceptually, "mod" increases the frequency mod and changes the placement of the flat bit.

in practice, especially with low rates, or if you reverse the algorithm, or double it up to make triangles out of it (two ways, either + to + or + to - which are imo the more musical) these contours serve surprisingly well as both "chaotic and cyclic", eg. to emulate a revolving turntable warp or turntable wibbly scratch pattern. basically, these are musically awesome, because they're like an arbitrary wiggle, where you can introduce more wigglyness. lots of room for exploration here, and with only one shaping param, easy for a nescient to intuit.


some of the more computationally efficient algorithms are "s&h", eg which output a flat value, and computations only occur at phase wrap, eg. to generate a new random value. you can tailor these to create half a dozen variables to make all sorts of wacky events, and then write a big switch statement in the loop to perform any kind of algorithm and make totally spaced out random event generators.

one simple "step" concept is just a sinewave which changes frequency at phase wrap.. at 0 "mod" you get a pure sine, as mod increases it gets a bit warbly, and with extreme mod, you get s&h r2d2 effects. you can butter these up again with modulations so the sine isn't constant, but it is a challenge to design a musically useful and itnuitive algorithm instead of something that "just impresses at first".

s&h/step algorithms have all sorts of choices for how to modify them, eg. i like to slew to the next s&h value. one concept is to have "mod" specify a number of s&h steps, eg. up to 64, so the user can eg. create a pattern of say, 16 arbitrary s&h values which loops. add a procedure in the phase wrap which occasionally modifies a step value (eg. inverts) or switches to another step, or reverses the incrementor, or ???? and basically you have an "lfo" that creates new melodies all day and you can record an entire album with. people love that stuff.

so now you've got an array, and some hidden params that can be created when the phase wraps, you can basically do anything with your lfo generator. keeping it useful is the consideration.

let's proceed to "random" modulation..

..there's eg. chua osc (which i have yet to implement) ... i used to do random with eg. generated values and 2nd order interpolation, or filters, or summing a couple of different methods. there are all sorts of choices for how to mod them, eg. a simple "random" waveform can be crossfaded to n * n * n to make peaks more extreme and modulation more towards the center, or you can reverse that.

this time i'm using sort of a "granular synthesis" with several envelope generators based on n * (1 - n) which is a "round peak with a height of 0.25".

at phase wrap, generate a rate and an amplitude for each "grain" and the sum will output a smooth contour suitable for random modulation. if you feed that into n * n * n, with arbitrary gain before the transform (can you visualise it? :) ) the grains will have a variety of contours from soft curves to gaussian peaks. warp for leading and falling contours, mix algorithms for a variety of contours. the lfos will make the music hehe. and good luck explaining the variety of algorithms to your users.

of course there are tons of ways to do things, create waveform tables, limitless methods.

i hope that someday, this practice will be more about sharing and working together synergetically to improve and edify our species rather than selling "amazing" things to the clueless and perpetuating a planet of misery and competition. best of luck to you whether you are kind or selfish.
you come and go, you come and go. amitabha neither a follower nor a leader be tagore "where roads are made i lose my way" where there is certainty, consideration is absent.

Post

tracking down all the procedural oscillators (attractors, "chaos generators" if you prefer) i could find and hit a goldmine in michael hetrick's pdf on drawjong2 for clear, concise notation of method and clarity enough to innovate (as demonstrable by the 3d pickover form). in use, i opted for hermite interpolation for everything but chua and lorenz. cheaper interpolation is great too but intersample peaks help express more spectral variance if you're looking for less constant perceived rate.

audio demo of procedural modulators.. first is the "evolving step sequence" and the periodic sine rate modulators. the procedural methods are an interactive electronic musician's dream as they respond to input. useful and expressive parameterisation (generally scaling coefficients) was relatively easy. do not omit inverted amplification with these oscs :)

audio is pure sine at 0.25 amplitude, monitor at low volume ;)
http://xoxos.net/temp/lfo5.mp3

might not mean much all at once but hopefully conveys there is a rich assortment of behaviours accessible with one parameter.

here's a chua oscillator (3d) basic and modified form
(h = new xyz, g = old, g3 is arbitrary use to double rate)
i found it unstable roughly around 500Hz at 44.1k, the reset fixes that in use to my satisfaction.

Code: Select all

		//		h0 = g0 + w * 15.6 * (g1 - g0 - -.714 * g0 + 0.5 * (-1.143 - -.714) * (abs(g0 + 1) - abs(g0 - 1)));
		//		h1 = g1 + w * (g0 - g1 + g2);
		//		h2 = g2 - w * 28 * g1;
				g3 = w + w;
				h0 = g0 + g3 * 15.6 * (g1 - g0 - (-.714 * g0 + (.4 + mod * .25) * (-1.143 - -.714) * (abs(g0 + 1) - abs(g0 - 1))));
				h1 = g1 + g3 * (g0 - g1 + g2);
				h2 = g2 - g3 * (28 - g0) * g1;
						
				g0 = h0;	g1 = h1;	g2 = h2;	//	x, y, z
				if (g2 > 25 || g2 < -25) {g0 = *in3;	g1 = g2 = 0;}
				*out1 = .5 * g1 * *in5;

here's clifford as an example of the methods from he-trick. of course these methods are stable due to the use of sin/cos and are likely to produce "chaotic" output with any sort of casual modification of the form, because it's just a bunch of "transform to [-1,+1]" which has massive potential for timewasting. as said, i didn't find it difficult to find parameterisation with a wide range of expression.
excuse my impromptu variable names..

Code: Select all

					g0 = f0;
				//	f0 = sin(a * h0) + c * cos(a * f0);			//	x		form
				//	h0 = sin(b * g0) + d * cos(b * h0);			//	y
					g1 = .8205 + mod;	//	orig a = 1.094
					f0 = sin(g1 * h0) + 2.266 * cos(g1 * f0);			//	x		form
					h0 = sin(1.689 * g0) + -.391 * cos(1.689 * h0);		//	y
the dejong form (which i found to be notably prolific in expression) removes the scalars, subtracts instead of adds, and just uses four coefficients intead of reusing a and b.
you come and go, you come and go. amitabha neither a follower nor a leader be tagore "where roads are made i lose my way" where there is certainty, consideration is absent.

Post

the thing about procedural LFOs is it's all cycle o' jiggle.
you come and go, you come and go. amitabha neither a follower nor a leader be tagore "where roads are made i lose my way" where there is certainty, consideration is absent.

Post

tough crowd :p

atm going on 50 contours, which becomes cumbersome in use. usually when i produce many instances of something, i later begin to unify the model and compartmentalise options.

eg. from my pov, a divers lfo implementation would include (pre +/- amplification) a "+ only" option (i used to use a "bias" control to select the dc offset) and i am now thinking, whatabout another toggle option for flipping the wave between + and - periods..

eg. consider the "linear" lfo form above, which crossfades from saw to ramp with triangle at halfway - a "flip" function would render one period above dc 0, and the next below dc 0, so that eg. for a saw, we have a linear slope from +Nv to 0v, at which point it switches to -Nv then fades to 0v, like a "convergent" waveform. i don't believe i've seen existant architecture to option the basic contours like this. of course, for a "really unified" model, add another parameter to fade from linear to curved contour, and another to option curvature for the rising and falling segment contours.. and in the end you have 50 parameters :) i guess every implementation is best treated as selective preference...


on the "chaos attractors," as mentioned i did find the dejong form to exhibit about the most aperiodic novelty (usually with modulation applied to the b or c coefficient) and being immediately gratifying to modify. (the pickover 3d form is of course prolific, and suggests further dimensionality) if you are not brave or endowed with ample time, searching for visualisations of the attractors gives good indications of the suitability of coefficients for modulation.. paulbourke and povray sites providing a number of examples. there are many people who have kindly already spent countless hours searching for intriguing coefficient sets.

here's a dejong set from paulbourke (worth a visit..) that seemed to convey character to me (being less wholly circular). while the oscillator is simple to implement, encouraging endusers to see the value of using it without listening to hours of jiggly audio may require a visualisation. there goes the cpu efficiency.

Image

for contrast, here's the defacto set of dejong coefficients
Image

the clifford that inspired the invid shock trooper
Image


stick something like this on your gui and i suspect hapless punters adhere like flies in molasses
Image

and i expect many users will spend hours watching the points render "using" your synth. i've been previewing this with lfo > pitch, which weights perception obviously as higher pitch extremities register the most. really, i find that the various behaviours of chatter these forms produce are as numerous as people on the earth, and while the diversity and differences are fascinating, it is prudent to quickly limit to a few suitable choices before you are inundated with microscopic discretisations.
you come and go, you come and go. amitabha neither a follower nor a leader be tagore "where roads are made i lose my way" where there is certainty, consideration is absent.

Post

Since plots. Some day I intend to make simpler ones using gnuplot that shows what your lfo's are doing.
~stratum~

Post

xoxos wrote:good luck explaining the variety of algorithms to your users.
not only explanation, but eg. they all need names at some point.
Image
several images are placeholders as they convey little about the performance. even with only one additional parameter, thinking of lfos as generators instead of oscillators has an immense potential to build in function. the "melodic phrase" step sequences are fascinating. the last contour here responds to modulation and otherwise settles into a sequence of about ~2 cycles with arbitrary values, producing sequences like the analog "raygun" toys from the 1980s. differentiation can extract the rate of modulation to use as an expression parameter. you get one wiggly line out of it, but what's behind that can be complex and multidimensional.
you come and go, you come and go. amitabha neither a follower nor a leader be tagore "where roads are made i lose my way" where there is certainty, consideration is absent.

Post

Thanks, that's much clearer. I didn't know that usage of irregular LFO shapes was a common practice. I had seen one in a synthmaster preset and was baffled for a moment thinking wtf? :-)
~stratum~

Post Reply

Return to “DSP and Plugin Development”