RobinSchmidt / RS-MET

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

RS Modular / Liberty / Digital Breadboard discussion #210

Closed elanhickler closed 2 years ago

elanhickler commented 6 years ago

Let's continue the discussion here. I want to help with this project.

For my own purposes I'd like to use Liberty to dive deeper into analog-style filter design where I can recreate Chaosfly/FMD signal flow in Liberty and then attach a bunch of analyzers to the mess of connections so I can see what is going on inside and further fine tune the sound/behavior of the filer and discover even more ways to create crazy and wacky reactive waveshapers/filters.

To make this easy, we need to be able to manipulate the interface of said modules somehow. Looks like controls sometimes appear in here like with Parameter or WhiteNoise (you can select seed) or BiquadDesigner you can select mode.

image

And I'm guessing you mean for the Instrument panel to display the parameters as sliders:

image

RobinSchmidt commented 6 years ago

liberty has just produced the first sound since i put it on the shelf many years ago! it's revived from the grave!

image

i want to stamp out some annoying interface bugs and then we may actually start using it! :-O

RobinSchmidt commented 6 years ago

so, you offer me to include a stripped down version of prettyscope's opengl code into my codebase, so i can gpu-power my own scope? that would be very cool indeed

I'm guessing you mean for the Instrument panel to display the parameters as sliders

yeah, i guess so, too. it's soo long ago - i can't really remember what my plan was. probably to allow the user to put (a subset of) the numeric parameters as sliders on the top-level panel

RobinSchmidt commented 6 years ago

Looks like controls sometimes appear in here like with Parameter or WhiteNoise (you can select seed) or BiquadDesigner you can select mode.

yes, the idea is that each module may have a gui editor associated with it which will appear in that section, when the module is selected. because not all of a module's parameters/variables/state can be given by input signals - for example when dealing with sample-based modules, we will need a gui to load samples, etc. ..but there are also modules for which everything there is, is controlled via the input signals. in this case, it may remain empty...or show some general information...i'm not sure yet what to do with that area when the user selects a simple adder module or something like that

elanhickler commented 6 years ago

To really get a good view of what is going on for my filter designing tasks I need this: (I would want to see many signal analyzers at once, spectrums, meters, oscilloscopes, etc)

image

Is it a big task to implement?

Edit: I spent a long time cleaning up PrettyScope code. It might need to be cleaned up some more before it becomes something you can throw into another project. You should go through the code and if you have suggestions on code cleanup or want to do it yourself let me know.

RobinSchmidt commented 6 years ago

ahh - i see - you want the scope to appear directly on the modular editor. ...hmmm...that's hard to say off the cuff how big or small that task is. i have to look into it

RobinSchmidt commented 6 years ago

oookayyy...i fixed two major showstopper bugs yesterday. there are still a lot of bugs, but - as far as i can see - nothing that should stop us using it already on the developer side for prototyping. i also want to make a couple of architectural changes/refactorings before seriously diving into the process of adding more and more atomic modules (because all of them would then have to changed as well, which would make the task of the overall architecture change even bigger). that said, adding two or three that are of immediate relevance for you right now is no big deal.

RobinSchmidt commented 6 years ago

to get started, you may copy my support folder:

https://github.com/RobinSchmidt/RS-MET-Data

into C:\Users\YourUserName\AppData\Roaming

and rename it to C:\Users\YourUserName\AppData\Roaming\RS-MET

then ToolChain and its submodules will find their presets there, including 3 mini-patches for Liberty that i have thrown together already. ...you have to strip off the "-Data" from the folder manually because i can't give it the proper name (expected by the plugin) here on github because that name is already used by my code repo

elanhickler commented 6 years ago

it is complicated to use that I need a starter patch? I think I can figure it out! 😄

Components I need for Chaosfly/FMD

Crossfader

image

Trisaw Osc

Soft clipper

image

Hard clipper

OH! What about oversampling? Most FMD filters don't sound good at 1x oversmapling. 2x to 4x is usually needed.

That will get me started.

RobinSchmidt commented 6 years ago

there's no oversampling in liberty as of yet. i'm not yet sure how to handle that - if i should provide global oversampling for liberty and/or on the module/container level. soo...maybe use the host for oversampling or use an oversampling plugin wrapper

RobinSchmidt commented 6 years ago

a sinusoidal crossfading of two signals with a parameter to move between the two signals.

there is already a SinCos module (which computes sin(2 pi input), cos(...)), i.e. it normalizes already to period 1. using the 1st quarter should give you the sin/cos (constant power) crossfading function, i.e. if your parameter goes from 0 to 1, feed 1/4 of it into SinCos and get the gain factors for both signals as outputs

edit: hardclipper is also already there

RobinSchmidt commented 6 years ago

...together with the phasor module, i've already built a sine-osc (just added it to the support repo)...but there are some bugs related to voice management

RobinSchmidt commented 6 years ago

to see how it can currently be used, i recommend loading the "Whistle" patch (i just updated it in the repo) and click in the tree on the FilterQ parameter and tweak it while playing the keyboard

RobinSchmidt commented 6 years ago

ha! now i know what to do with the top-right gui area for modules that don't have anything to set up via the gui: show a description of the module, explaining what it does, what the inputs and outputs are, etc.

ok - in the case of a simple adder, this certainly won't fill it up, but still better then a totally empty area and more typically, there will be something more to say

elanhickler commented 6 years ago

just read you added TriSaw to Liberty. Is there a soft clipper? It turns out to be one of the most important modules in FMD!

elanhickler commented 6 years ago

Can you make it so that a module (like for example, Chaosfly or Mushroom Generator are modules) can become a liberty module? So there is not a separate way to may liberty modules.

RobinSchmidt commented 6 years ago

unfortunately, that's not easy. using an object of the jura::AudioModule class as romos::Module will require some nontrivial re-routing of signals. they have very different concept of how signals are passed around. a jura::AudioModule uses the same idea as as juce::AudioProcessor or, in fact, any plugin format: your processing callback gets a pointer to a multi-channel buffer of audio samples. a romos::Module uses a different concept. an input-pin receives a pointer to an output pin...and romos uses its own buffersize. but i may think about it...maybe some sort of wrapper/adapter class can be made. something that derives from jura::AudioModule and romos::Module and glues them together, making the required conversions....hmmmm

elanhickler commented 6 years ago

How difficult is it to make a Liberty atmoic romos module? If I just copy/paste one, change the inputs/outputs, and replace the per-sample processing code. Can't be so difficult.

There's no reason to waste time making a wrapper. Instead, I can isolate the important bits which can be inserted into AudioModule or romos Module.

I could perhaps make a class that has the necessary stuff to become an AudioModule or romos module.

RobinSchmidt commented 6 years ago

the main obstacle is probably that a romos::module has all kinds of input and output signals that we would treat as parameters in a jura::AudioModule. and a (monophonic) signal-channel in romos is just a pointer-to-double...whereas a jura::Parameter is.....something entirely different

elanhickler commented 6 years ago

Ok, just carry on. When I need to make my own romos modules I'll learn how. And I'm sure you'll eventually make it easier.

RobinSchmidt commented 6 years ago

yes, i'm currently in a big clean up, also reworking the api to make it easier to add modules (it's currently a mess of having to change the code in at least 4 different places (not counting the .h/.cpp distinction) :-( bad design - but maybe it's good to revisit the code later with now 5 years more programming experience)

software engineering wise, this is the most complex project, i ever did. ...well, maybe together with this little "mixsonic" mini-daw that i did back then for a client (i guess, i should someday include that code into my codebase, too - but it needs to be updated for the new version of juce)

elanhickler commented 6 years ago

You could steal Max/MSP, Reaktor and PureData customers (well puredata is free) with Liberty. Just continue to improve it, you're basically already there. I would help spread the word. Would you ever make a commercial version?

RobinSchmidt commented 6 years ago

hmmm...not sure. i think, business-wise, i'd prefer to focus on b2b exclusively in the future - but who knows - maybe...but it would be difficult to do that with an open-source project (or maybe not?)...and i'd like to keep (all of) my code open source. ...i'm considering to make synthesis tutorial videos with toolchain and maybe liberty. maybe i can acquire some support via patreon for the whole package of tutorial content and open-source software. i think, i'm done with trying to sell plugins myself...it didn't work for me and if i would have serious sales numbers, it would be an accounting nightmare to book all these smallish payments separately. but never say never

RobinSchmidt commented 6 years ago

i think, liberty will not be competetive with reaktor performance wise. i guess they use something like jit-compilation - which i'm not anywhere near to be able to include into liberty anytime soon (i wouldn't even know where to start, tbh - and it would drag soooo much time away from the more fun and creative things)

elanhickler commented 6 years ago

Would this help? It uses LuaJIT: https://github.com/pac-dev/protoplug

RobinSchmidt commented 6 years ago

this is a really cool project - and indeed, to get started, one would probably look into existing jit-compilation engines just as the one for LuaJIT. nevertheless, i think, it would be a gargantuan task to implement one for liberty. perhaps it would be a better idea to convert the module structure to a Lua script and then pass that to the existing LuaJIT engine. this would boil the task down to converting (or "compiling") the module tree to a Lua script as intermediate format. anyway .... given that that protoplug is MIT licensed (which is very cool), it might be a cool thing to turn it into a scripting module for ToolChain (as jura::AudioModule) and/or Liberty (as romos::Module)....although, i actually think, that i'd prefer AngelScript over Lua for a prototyping-scripting-language, because the syntax is so close to C++ which would make it easier to port the scripted code to actual C++ later

RobinSchmidt commented 6 years ago

ok - i think, i'm more or less done with my framework/api rework. and i added this ScaledAndShiftedSigmoid. the module's name is Saturator and it's under Functions. the code for it is just:

in romos_FunctionModules.h

class SaturatorModule : public ModuleAtomic
{
  CREATE_COMMON_DECLARATIONS_3(SaturatorModule);
  double (*sigmoid)(double) = tanh;  // (normalized) prototype sigmoid function
};
class SaturatorTypeInfo : public ModuleTypeInfo
{
public:
  SaturatorTypeInfo() {
    shortName    = "Saturator";
    fullName     = "Saturator";
    description  = "Saturation with adjustable width and center";
    category     = "Functions";
    createModule =  []()->Module* { return new SaturatorModule; };
    hasHeader    = true;
  }
};

in romos_FunctionModules.cpp:

void SaturatorModule::initialize()
{
  initInputPins(3, "In", "Width", "Center");
  initOutputPins(1, "Out");
  inputPins[1].setDefaultValue(2); // Width is 2 by default
}
INLINE void SaturatorModule::process(Module *module, double *In, double *Width, double *Center,
  double *out, int voiceIndex)
{
  SaturatorModule* sat = static_cast<SaturatorModule*> (module);
  double scaleX =  2 / *Width;
  double shiftX = -1 - (scaleX * (*Center - 0.5 * *Width));
  double scaleY =  1 / scaleX; 
  double shiftY = -shiftX * scaleY;
  *out = shiftY + scaleY * sat->sigmoid(scaleX * *In + shiftX);
}
CREATE_AND_ASSIGN_PROCESSING_FUNCTIONS_3(SaturatorModule);

and to make it available, i had to add: registerModuleType(new SaturatorTypeInfo); // a+b*tanh(c*x+d), a,b,c,d adjusted by width/center to ModuleFactoryNew::registerStandardModules

RobinSchmidt commented 6 years ago

try the new ToolChain preset SaturaSynth.xml to check it out. it's just a (polyphonic) TriSaw going monophonically into the Saturator - so be sure to play some fifths to get some nice intermodulation distortion

RobinSchmidt commented 6 years ago

the next thing would be to make a gui editor for it where the user can at least switch between various prototype saturation shapes (currently there's only tanh). ...but i'm on a little short vacation from tomorrow to monday and i have to pack my bag now, so i guess that will have to wait a little.

elanhickler commented 6 years ago

Alright! Good work so far.

elanhickler commented 6 years ago

Suggestions for API:

initInputPins(3, "In", "Width", "Center");
initOutputPins(1, "Out");

It would be better to do this so I could pass that information in another way and the number of pins is automatic based on the size of the initializer list.

initInputPins( {"In","Width","Center"} );
initOutputPins( {"Out"} );
RobinSchmidt commented 6 years ago

ok, yes, agreed. avoids this pesky old-school and error-prone vararg mechanism from c. done

RobinSchmidt commented 6 years ago

a (polyphonic) TriSaw going monophonically into the Saturator

play a midrange major chord and tweak Asymmetry! i love such sounds!

edit! fuck yeah! now i need microtuning (maybe globally for the whole ToolChain) for tweaking the intermodulation frequencies! the third is rather far off in 12 TET, making the sound a bit too muddy

elanhickler commented 6 years ago

I need microtuning to eventually tune things that are naturally out of tune like filter resonance. I say make it a module

RobinSchmidt commented 6 years ago

hmm...a tuning module? what should be the inputs and outputs? frequencies? or pitches? couldn't that be subsumed under a general quantizing function?

i was just thinking about giving the phasor module a second output for sync triggers. it should be 0 most of the time and 1, whenever a phase reset occurred. maybe not exactly , but 1.f where the fractional part can be used for subsample precision information for when exactly within the sample the reset occurred. is there a convention for such things in other modular systems? i mean, how to interpret f? should f itself or 1-f be the delay for the event? has the reset event occurred at n-f or n-1+f when our current sample is n?

RobinSchmidt commented 6 years ago

i think, considering n-f as time-instant of the event would be more natural. it actually doesn't really matter as long as all sync inputs and outputs agree on which convention to use. ...then we can make a subsample-precision zero-crossing detector module that outputs sync triggers, so we can sync oscillators to an incoming audio input signal with subsample precision

RobinSchmidt commented 6 years ago

i actually have a reaktor 5 license. purchased it back then when it was on sale for 99€ but never used it for anything more than a bit of noodling around just for fun. installing it now for inspiration

elanhickler commented 6 years ago

The caveat is that if I'm tuning something like a filter, it needs to be detected once, then set that in stone, like Silent Way. If I was to change the resonance or other parameters the tuning would of course have to be re-detected, that's fine. You could make a constant re-tuner, but it would be glitchy... which might be musically interesting.

RobinSchmidt commented 6 years ago

hmm...maybe put a pitch detector after the filter, then take a difference of the target frequency with the detector's output and add it to the frequency input of the filter. a little feedback control loop - like in a thermostat

error = target - detected freqInput = target + k*error

where k is some kind of time constant.

elanhickler commented 6 years ago

btw, I can make a musically glitchy pitch detector with Chaosfly/FMD, essentially something like PLL: https://www.youtube.com/watch?v=62zargS-5RQ

You'd have to extract the current pitch by measuring the square waves produced, I think... because the square waves produced is a result of chaotic interactions... unless there's a frequency parameter that is actually being modulated to the target frequency. I need to dig it up from my old Chaosfly experiments.

RobinSchmidt commented 6 years ago

i'm trying to understand, what these so called "phase comparators" do: http://www.doepfer.de/a100_man/A196_man.pdf i mean, they can't actually compare phases because their input signal is not a phase (and reconstructing a phase from a signal is only possible, if you know the shape - and that doesn't even work for all shapes). they say, one of the "phase-comparator" algorithms is a simple xor. i don't really understand how xoring two signal relates to comparison of their phases. and i have no idea what an rs-flipflop is (i certainly didn't invent it ;-)). ...but it seems, they care only about square waves in this context?

...but i think, i will need logic modules as well. i recently looked into some math for doing logic with continuous inputs and outputs. operations that boil down to the usual logic operations when their inputs are 0s and 1s but smoothly generalize to continuous inputs - in which case the ins/outs can be interpreted as probabilities

RobinSchmidt commented 6 years ago

operations that boil down to the usual logic operations when their inputs are 0s and 1s but smoothly generalize to continuous inputs - in which case the ins/outs can be interpreted as probabilities

for example, if pA is the probability for event A to occur and pB is the probability for event B to occur, then pA pB is the probability for both events to occur, i.e. the probability for event (A and B) (assuming their non/occurences are independent from each other). pA + pB - pApB is the probability for the event (A or B). plug in 0 or 1 for the probabilities pA, pB and you'll see how this boils down to the usual and and or operations. if you have formulas for and and or and not (the probability for (not A) is simple 1-pA), you can use them to derive formulas for xor and anything else. p(A xor B) = pA + pB - pA pB (3-pA-pB+pA * pB)

edit: actually not and and are sufficient to derive anything else, because or is: or(a,b) = not(and(not(a),not(b))). i.e. (either or both events occur) is the same as (not both events don't occur)

RobinSchmidt commented 6 years ago

that all assumes that A and B are independent. i've been trying to derive generalized formulas that take a correlation between A and B as parameter and which will boil down to the formulas above in case of zero correlation...but that's still under construction.

i guess, it would be cool to have such "continuous logic" modules which can be used as regular logic modules when their inputs are restricted to 0 or 1 but generalize somehow "naturally" to any input (or at least to any input in the range 0..1)

RobinSchmidt commented 6 years ago

i have just revisited my ADSR envelope module and changed the interpretation of the shape inputs. their range is now -1..+1 to make it consistent with our trisaw shape parameters and those in the meta-mapping editor (formerly, it was 0..inf - that's how the "raw" parameter appears in the formula - but that's inconvenient for a user-parameter and parameter-signals). now i wonder, what would be the best way to trigger the envelope. currently, it gets triggered and released "under-the-hood" by the midi signals. i just looked at how reaktor does it - they use an additional "Gate" input. i wonder if should do it like that, too. doepfer envelope modules also use a gate input, so it seems to be the standard way to go. ...and/or if i should provide a trigger input that works like the sync-inputs, i explained above (with this subsample-precision sync feature).

elanhickler commented 6 years ago

what is the ADSR envelope module? I haven't seen it, it's not breakpointmodulator I'm guessing

RobinSchmidt commented 6 years ago

in romos_ModulationModules.h/cpp

class EnvelopeADSR : public AtomicModule
{
  //...

no - it's not the breakpoint modulator. just a plain and simple bread-and-butter ADSR. but with separately adjustable (and modulatable (!)) shape for each stage (between linear and exponentially bent down or up). i'm also not yet sure about the ordering of the input signals. if i should first have ADSR and then the 3 shapes or the shape inputs "interleaved" with the time inputs (as it is now).

initInputPins({ "Att", "AtSh", "Dec", "DcSh", "Sus", "Rel", "RlSh" }); or initInputPins({ "Att", "Dec", "Sus", "Rel", "AtSh", "DcSh", "RlSh" });

elanhickler commented 6 years ago

toolchain just crashes REAPER when I try to start liberty

edit: unless im running debugger? wtf.

elanhickler commented 6 years ago

And yes, you need gate and/or trigger inputs on your modules like ADSR.

RobinSchmidt commented 6 years ago

hmm..i can't reproduce the crash here (edit: oh - you edited it. i didn't check in reaper - just in the juce host). do you think, it's useful to sync envelope generators with sub-sample-precision? because, i think, for this i would need an additional sync/trigger input in addition to the gate. otherwise the gate alone would suffice

elanhickler commented 6 years ago

The point of TriSaw Modulator was to provide sub-sample-precision loopable envelope generator. I don't know of any synth that has sub-sample-precision modulatable/triggerable envelope generator, so if you solved this, that would be amazing, and get us closer to a true analog simulation. Envelope generators could be a great source of atonal sound and chaos if you solve that frequency locking issue. But, maybe not crucial right now.

I notice my FMD filters also have frequency locking problems in certain situations, I dunno what's up with that. I think it happens when I involve heavy clipping (using soft clipper) and high modulation, very strange. I'll have to look into this more in depth and maybe using better filter designs / more appropriate digital components, I can bypass this issue.

elanhickler commented 6 years ago

oh the crash could be related to an old preferences file that I need to delete/refresh, and that preferences file is not accessed with the debugger(because it uses a different file perhaps)