RobinSchmidt / RS-MET

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

parameter modulation system discussion #65

Open RobinSchmidt opened 7 years ago

RobinSchmidt commented 7 years ago

it sort of works now. you can try it in the chainer. plug in some synth (for example AciDevil) set it up to produce a simple saw. put a Ladder after it in the chain and then put in a BreakpointModulator. right-click on the Ladder's cutoff and open the Modulation setup. click "Add" and select BM 1 ("Breakpoint Modulator 1"). a slider appears to control the modulation depth. it should be obvious, how it works form the user's point of view.

currently, only the Ladder supports modulatable parameters, but it will be trivial to add this feature to any AudioModule.

the final challenge, however, is the state recall. i somehow need to generate unique names to identify the parameters (there may be two Ladder filters in the chain so i need to create some kind of "path" like "Slot2/Ladder/Cutoff"). or something like "Slot1/Straightliner/OscSection/Osc3/Tune" (the AudioModule structure is actually a tree - with child-modules. it (roughly) follows the composite design pattern: https://sourcemaking.com/design_patterns/composite). i will work on this tomorrow.

when everything is finished, i'll explain here, how it all works together and how to use it from client code

RobinSchmidt commented 6 years ago

haha - well, ok - but that doesn't necessarily apply to a computer setup

RobinSchmidt commented 6 years ago

you probably have already noticed that i'm not the kind of person who always hunts for the latest and greatest stuff

elanhickler commented 6 years ago

Actually, I'm not that either. I'm more the kind of person that has a strong opinion on what is the correct way of doing things, and there's nothing "latest and greatest" that has caught my attention for a long time now, ever since I realized I hated all synthesizers... but I love the ones I make.

RobinSchmidt commented 6 years ago

ah - apropos latest-and-greatest, i finished reading my c++11 book. some useful stuff there. especially the functional stuff and threading library

elanhickler commented 6 years ago

you are insane. you finished reading a c++ book... to me that sounds like "I just finished reading the dictionary" well I haven't read a book for along time haha.

Good job.

RobinSchmidt commented 6 years ago

...and c++17 will even have some more interesting things: new math functions that may be relevant for dsp - bessel, elliptic, etc. - so far, i had to code some of them myself - although i guess, i will still need my own elliptic functions because i need the version for complex numbers (used in elliptic filters)

RobinSchmidt commented 6 years ago

...i want to read some dsp books again. it's been a long time. i feel like i'm getting out of practice. will probably order printed versions of these 4 soon (i don't like reading on sceen):

https://ccrma.stanford.edu/~jos/

elanhickler commented 6 years ago

speaking of DSP, can I haz a zero-delay 1 to 4 pole filter? even 1 pole would be nice. ZDF is good for audio rate modulation. None of my plugins really make use of that as a core aspect of the DSP at the moment.

RobinSchmidt commented 6 years ago

hmm...within the RSLib codebase, i experimented a bit with a zdf version of my ladder filter and actually found it to respond worse to modulation than my regular udf ladder. ...although that may have to with the fact that my individual stages use only poles (and no zeros). i didn't try a version with zeros then, because the math was a bit unwieldy and i'm actually quite happy with my udf ladder (makes it easy to throw in nonlinearities - in a nonlinear zdf filter, you'll have to do nasty (expensive) things like solving implicit equations with newton iteration and stuff). ...but - the rsStateVariableFilter (in rapt) is actually a zdf filter. maybe you can try this?

elanhickler commented 6 years ago

What is the slope? 1 pole? 2 pole? can't see anywhere to set the number of poles. Should I combine multiple of them to achieve 1 to 4 poles?

edit: wait, what is this about zeros vs poles... probably outside the scope of my understanding.

RobinSchmidt commented 6 years ago

it's a 2-pole. the frequency responses are actually equivalent to the well trodden (i dare to say: classic) rbj cookbook biquads. if you want 4, yes, you can use in series

elanhickler commented 6 years ago

nice, now I can use marketing hype "Zero delay filters"

RobinSchmidt commented 6 years ago

...i think, zdf is a bit overrated

elanhickler commented 6 years ago

well...... is it good for anything? I mean, I don't even use filters in the typical way. I'd never rely on the resonance of traditional digital filter designs, I'd rather use oscillators in feedback to create resonant filters, and then use non-resonant filters just to control that feedback.

RobinSchmidt commented 6 years ago

in the case of the ladder, the unit delay in the feedback path causes the resonance frequency (and also the resonance amount) to detoriate from where it should be - especially when the cutoff/resonance frequency is high. a zdf design solves this. in my ladder, however, i solved this problem in a different way - i derived formulas to adjust the cutoff of the stages and the feedback gain that make the resonance-frequency and amount come out just right (at least in the self-oscillating case - and in other cases, it's close enough).

i don't know, maybe zdf has more advantages regarding modulation response. but in the case of the ladder, i'm not sure about that

I'd rather use oscillators in feedback to create resonant filters, and then use non-resonant filters just to control that feedback.

what? how would that work?

elanhickler commented 6 years ago

I'd rather use oscillators in feedback to create resonant filters, and then use non-resonant filters just to control that feedback.

what? how would that work?

Where have you been! That's the basis of everything I'm doing! That's the basis of Filters of Mass Desctruction and Chaosfly, and it's the only reason I would ever try to start an audio plugin company... or... at least... maybe I still would at some point, but I wouldn't be so serious about it as I am now, and so eager to make it happen.

elanhickler commented 6 years ago

Have two oscillators modulate each other (or even have an oscillator modulate itself) creating a fixed point attractor: https://en.wikipedia.org/wiki/Attractor#Types_of_attractors You know you got a fixed point attractor when your oscillators produce 0s, zero output. That measns they are stable and not resonating/self-oscillating.

once you achieve that, you "stimulate" the chaos with an input signal. Boom. Done. Analog-esque filter. It will scream, growl, ovedrive, distort, sync, pitch-follow, harmonic-lock, or just provide a small bit of resonance like a good old filter.

elanhickler commented 6 years ago

The major advantage is that I've been able to mimic every analog filter I've ever heard and create behaviors I've nevedr heard.

Sawtooth shaped resonance? Easy. Triangle-shaped resonance? Fine. Weirdly shaped resonance with no name? Done. Square? Soft square? Sinusoidal? Asymmetrical? It does everything.

RobinSchmidt commented 6 years ago

yeah - ok, so you generate the resonance separately by some chaotic system that also gets disturbed by the input. i was just a bit confused by the phrase "oscillators in feedback".

yes, that's nice. i think chaotic systems deserve some further exploration. at some point, i want to include a signal generator into my chainer, where the user may enter a differential equation system (such as lorenz or whatever)

elanhickler commented 6 years ago

you can already do that... but spiral generator has nothing to do with these concepts. It only just HAPPENS to have a feedback control, and it's fun to play with, but not very useful in the big scheme of things. There's another one called Radar that implements what the "feedback control" does except tuning is stable, it's much more useful.

Radar is a beast.

Edit: But I couldn't translate it from Max/MSP, there are some confusing things going on in that patch.

elanhickler commented 6 years ago

Torus is similar to radar, but not quite as awesome... but I translated it successfully!!!

Torus, Spiral, Boing, NyquistShannon, are all working. The rest I failed at. There's still few more I will attempt as well, nothing as exciting though.

RobinSchmidt commented 6 years ago

what is this about zeros vs poles

filters are described in terms of their so called "transfer functions". these are rational functions (i.e. a quotient of two polynomials) of a complex variable ("s" in the analog case, "z" in the digital). when the numerator of the rational function becomes zero for some complex argument, you have a zero at that place in the complex plane (the function produces a zero output). when the denominator becomes zero, the function outputs infinity - that's a pole. your filter transfer-function has zero and infinity points in the complex plane. if you evaluate the function at the imaginary axis (for analog filters), you get the frequency response. that's also a complex number for each input frequency (a filter has magnitude and phase response). yeah...the math is quite advanced. (classical dsp textbook) filter design is basically about placing these poles and zeros into the complex plane.

RobinSchmidt commented 6 years ago

intuitively, if you have a pole near the imaginary axis (i.e. the frequency axis) - you get a boost at these frequencies near the pole, a zero at the same place causes a dip

RobinSchmidt commented 6 years ago

if the pole is on the imaginary axis, you have self-oscillation, if a zero is on the axis, you have a total notch there. if the poles/zeros are not directly on the axis but only near, you'll get boosts and dips

elanhickler commented 6 years ago

Could your modular thing (Liberty) be used to prototype? Yes, I think it can. It's going to be quite valuable to get that working. You know Robin, the more you improve your library, the more I think it could be the best thing on the market. You have a few big ticket items to implement, but it's all coming together.

I could imagine using Liberty to then generate a C++ template that uses your library. I don't think it'd be difficult... at least to get a basic thing working, maybe you'd still need a bit of manual work after generating the code but that's fine.

elanhickler commented 6 years ago

I don't think modulation works. rebuild jucer if if get a new commit.

RobinSchmidt commented 6 years ago

ahh - damn - i forgot to include the baseclass constructors in the subclass. i had to add:

using ModulatableParameter::ModulatableParameter; // import baseclass constructors

to ModulatableParameter2. otherwise the subclass has no constructor (they are not inherited like regular member functions). with that "using" directive, i import/inherit the baseclass constructors (new in c++11 - yay - the book helped). pull a library update and try again

elanhickler commented 6 years ago

I think it still doesn't work. No modulation happening.

image

RobinSchmidt commented 6 years ago

hmm? what happens? i tried it here and it worked. i have routed the env to the density parameter and it got modulated

RobinSchmidt commented 6 years ago

uuuh...i trigger a breakpoint when i try to route it it to the gain. wtf?

RobinSchmidt commented 6 years ago

Microsoft C++ exception: std::bad_function_call at memory location 0x0000002F7261E860.

hmm...is there maybe not a correct callback assigned?

elanhickler commented 6 years ago

try tune, yeah there is not a callback for gain, I didn't need one, but I guess for modulation I do. Just try Tune for now.

Nothing happens when I modulate gain, I don't get an exception.

image

RobinSchmidt commented 6 years ago

i meanwhile have set the initial callback (in class Parameter) to an empty function. i think, it was formerly uninitialized which raised the exception. will check tune soon..

elanhickler commented 6 years ago

btw did you see my commit message? I got all the major work done for jerobeam stuff!! I thought I wouldn't be able to do it. I had a few major errors in the code. Radar is awesome (still needs tweaking to run properly).

elanhickler commented 6 years ago

Any luck with the modulation? If push comes to shove I can use non std function if you just show me an example of the syntax.

RobinSchmidt commented 6 years ago

could it be, that you have a bug in the definition of your callback:

parTune.setCallback([this](double v) { spiralGenCore.setPitchOffset(parTune + parOctave*12); });

line 72 SpiralGeneratorModule.cpp. there's no "v" in the inner call.

RobinSchmidt commented 6 years ago

i checked in a little update, so your "AudioPlugins" project can build now SpiralGenerator. you didn't have the source files in the project yet (giving linker erros). and an "amplitude" variable didn't exist. i assume, you want to refer to MonoSynth::outputAmp there. i fixed this. please review my changes because i had to guess your intentions

RobinSchmidt commented 6 years ago

i see, you have adapted my "uncomment the one you want to build" strategy. maintaining a separate project for each product is such a hassle, isn't it? i've been saying this all the time ;-)

RobinSchmidt commented 6 years ago

Could your modular thing (Liberty) be used to prototype? I could imagine using Liberty to then generate a C++ template that uses your library.

i was already thinking about that myself a few years back when i wrote it. it could certainly be done.

You know Robin, the more you improve your library, the more I think it could be the best thing on the market.

whoa! that's a strong statement. thank you! :-)

elanhickler commented 6 years ago

Currently to set Gain with the breakpoint modulator, it seems like:

breakpoint modulator value VS gain value. 1 = 1 0 = 0.5 -1 = 0

Does the modulation system expect things to be bipolar?

RobinSchmidt commented 6 years ago

yes, modulators can be bipolar to admit for typical lfo stuff. but check also the "relative" option in the popup menu. if active, the modulation value gets scaled by the nominal unmodulated value. that often makes sense for frequency parameters

RobinSchmidt commented 6 years ago

what happens is that the output of the modulator gets multipiled by the modulation depth of the connection (and, if relative is active, also by the unmodulated value) and then added to the unmodulated value

RobinSchmidt commented 6 years ago

check also the "relative" option in the popup menu

hmm... i think, i should put a button on the modulation setup popup. perhaps next to the min/max fields

elanhickler commented 6 years ago

relative is not the same as unipolar though...

Also, modulation system doesn't save in the patch. Is there something specific you need to do in the code for that? Did you explain it in the wiki? Seems like you didn't.

elanhickler commented 6 years ago

The more I experiment with C++ the more I feel like I really want Liberty to be working. After you do the metaparameter mapping system, the next big need for me may actually be a prototyping environment. I don't want to use max. I don't want to use this or that. I could imagine some key features, simple features, that would allow easy prototyping in Liberty that would beat max/msp, puredata, reaktor, etc. I all of a sudden really want to use Liberty!

elanhickler commented 6 years ago

come on robin, this was such a smart design choice:

image

no other prototyping environment has this.

the best part is NO OTHER PROTOTYPING ENVIRONMENT RUNS AS A VST!!!!!!!!

RobinSchmidt commented 6 years ago

you mean the tree-view of the patch? yes - i think, it makes a lot of sense to represent a patch like this for easy "browsing"

...i'm just shooting down a couple of bugs in my framework and modules

elanhickler commented 6 years ago

modulation assignments aren't saved in xml patch or plugin state modulation system doesn't respect parameter interval, shouldn't it?

I think we need default modulation settings stored in the modulatable jura parameter, that's how I did the original spiral generator. Going through 4 menus just to setup a single basic modulation is really a hassle, when compared to most synths it's one or two clicks. For your setup it's like 7 clicks.

Min depth, Max depth, Relative/Absolute, for starters.

elanhickler commented 6 years ago

Modulation system needs improvement before I release anything with it. The end of the year is quickly approaching.

Is there a way to change the color of a slider if it has a modulation assignmnt?

I'd like to have remove buttons directly on the modulation page rather the right click menu. You've got to make this more convenient.

Also the right-click bugs need to be fixed. I wanted to have something for sale by the end of the month, but I can't unless these things are solved.

RobinSchmidt commented 6 years ago

modulation assignments aren't saved in xml patch or plugin state

ahh - yes, you need to append xml->addChildElement(modManager.getStateAsXml()); to getStateAsXml and modManager.setStateFromXml(*(xmlState.getChildByName("Modulations"))); to setStateFromXml. look at the code, how i do it in chainer. ...or i could just do that for you. maybe you want to make a baseclass for this that always does this (one that contains a modManager member)

modulation system doesn't respect parameter interval, shouldn't it?

yes, that's why i have introduced separate min/max values for the final modulated value. the min/max values of the underlying parameter may not always be appropriate and they may also be changed later in which case it would break the patch

Going through 4 menus just to setup a single basic modulation is really a hassle, when compared to most synths it's one or two clicks. For your setup it's like 7 clicks.

ok - so how should it be done instead?

Is there a way to change the color of a slider if it has a modulation assignmnt?

hmm...probably. but maybe it would be better to somehow indicate the range of modulation the slider - like having some overlay that shows the modulation limits

the right-click bugs need to be fixed

what bug exactly are you talking about

i've been quite busy recently making all my old modules work correctly in chainer, and also have a tree-view to select modules. not yet finished, but i think, i can take some time off to polish the mod-system

remove buttons directly on the mod page? do you think, that operation is so common that it's worth to allocate screen space for that which could otherwise be used to make the slider bigger? i actually tend to think, adding/removing mod sources is a quite rare operation and setting up the depth much more common - so i was thinking to give more gui space for adjusting depth (making it more convenient) by making it more inconvenient to remove the connection. it's a trade-off