RobinSchmidt / RS-MET

Codebase for RS-MET products (Robin Schmidt's Music Engineering Tools)
Other
56 stars 6 forks source link

waveform morph (saw-up/square/pulse/saw-down/triangle) #276

Closed RobinSchmidt closed 2 years ago

RobinSchmidt commented 5 years ago

i'm trying to figure out, how we can meaningfully morph between the common synthesizer waveforms. the general setting is: we piece the waveform together from two linear segments, like this:

x(t) =
x1(t) = a1*t + b1   for t in 0...h
x2(t) = a2*t + b2   for t in h...1

this allows for sawtooth (up and down), triangle and square waves (h=0.5):

saw-up:    x1(t) = x2(t) =  2*t - 1
saw-down:  x1(t) = x2(t) = -2*t + 1
square:    x1(t) = -1, x2(t) = +1
triangle:  x1(t) = 4*t - 1, x2(t) = -4*t + 3

now the goal is to compute the 5 algo parameters (h,a1,b1,a2,b2) from some musically meaningful user parameters, such that we can reach saw-up/saw-down/square/pulse/triangle in some meaningful way (i.e. with musically useful transitions). i want at least replicate the common pulse-width control. i'm not yet sure, what the best approach to this is. if you have any ideas, feel free to post them. this is (at the moment) supposed to be a brainstorming thread.

the reason why i'm choosing to create the waveform from linear segments like this is that we can anti-alias it nicely by bleps and blamps (we'll have steps and/or corners at 0 and h). ...the "if your tool is a hammer, make the problem look like a nail" approach. this will also play nicely with sync

well, it seems obvious that h may be directly computed from the pulse-width parameter (say: h = 0.5*(pw+1) where pw ins in -1...+1). there are also some other constraints that i want to maintain for all waveshapes: DC-free and normalized energy (or maybe normalized peak-amplitude - not sure yet)

RobinSchmidt commented 5 years ago

there's this old trick of obtaining square-waves by a summing appropriately phase-shifted saw-up and saw-down waveforms: https://www.desmos.com/calculator/78yl7b5nnp tweak "b" to morph between saw-up -> square - saw-down where "d" provides some sort of pulse-width control

RobinSchmidt commented 5 years ago

with d = +-0.5, the b-morph between saw-up -> square -> saw-down seems rather reasonable to me: https://www.desmos.com/calculator/wbot9ibar5, and with b=0.5, d is a nice pulse-width control. but with d=0, the b-morph would morph through an all-zero signal - not nice! also, with b= +-1, d boils down to a mere phase-modulation of the saw - which not very interesting either

elanhickler commented 5 years ago

phase-modulated saw is fine. With anything-to-anything modulation, interesting things will happen.

RobinSchmidt commented 5 years ago

hmm...ok - but i'd like to have some audible change, when the user just turns the knob. also, when d=0 and b=0, the signal is all zero. i don't think, this is a viable control scheme yet

btw. - it seems that having the first transition at time 0 might be too restrictive. maybe we need to be able to move the first transition point, too - the waves with the above control scheme have both transition points anywhere in the interval 0..1 - and it's probably more natural anyway .....but more complicated (and more expensive) to implement

elanhickler commented 5 years ago

If you get all zeros, that's similar to a pulse width of 100% or 0% which is also fine.

RobinSchmidt commented 5 years ago

so - does that mean, you think, this proposed control scheme would be viable and i should implement it? ...but what about triangle? ...but maybe that can come later with a 3rd user parameter

elanhickler commented 5 years ago

Keep in mind what you have here is very similar to simply volume-mixing square and saw (assuming you can mix inverted or non-inverted). I just tested it in my plugin Nyquist Generator.

RobinSchmidt commented 5 years ago

i'm actually currently investigating another approach which would have 3 user parameters and also let us reach the triangle. unfortunately, so far, the formulas are getting a bit unwieldy and may produce singularities. ...more research needed....

edit: the basic idea is: 3 user parameters together with the 2 constraints (no DC, fixed total energy) should uniquely determine the 5 algo parameters. one user parameter is h - that's already a given (and is the pulse-width control in case of square-waves). the only remaining thing to do is the choice of the two others. i'm thinking about the the sum and difference of the two slopes (a1 + a2 and a1 - a2)...maybe suitably normalized by h

RobinSchmidt commented 5 years ago

https://www.desmos.com/calculator/wbot9ibar5, and with b=0.5, d is a nice pulse-width control.

i'm starting to like it. it even allows periodic through zero modulation - the value at d = -1 fits seamlessly with the one at d = +1 (the wraparound at +-1 has the same effect as going through zero). i think, i will implement several control schemes and client code can pick one. or we may even allow the user to select one with a dropdown

RobinSchmidt commented 5 years ago

that: https://www.desmos.com/calculator/qi7tlaopla solves my problem with the first transition point not being at zero. it applies the phase-shift to only one of the saws (instead of +- half of it to both). but it has the disadvantage that now only the saw-down can be phase-modulated by d. saw-up doesn't respond to d anymore. such an asymmetry would be unnatural. so if i implement it, i should indeed allow for two movable transition points in the wave instead of fixing the first at zero