Closed elanhickler closed 2 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!
i want to stamp out some annoying interface bugs and then we may actually start using it! :-O
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
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
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)
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.
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
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.
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
it is complicated to use that I need a starter patch? I think I can figure it out! 😄
That will get me started.
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
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
...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
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
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
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!
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.
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
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.
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
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.
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)
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?
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
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)
Would this help? It uses LuaJIT: https://github.com/pac-dev/protoplug
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
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
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
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.
Alright! Good work so far.
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"} );
ok, yes, agreed. avoids this pesky old-school and error-prone vararg mechanism from c. done
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
I need microtuning to eventually tune things that are naturally out of tune like filter resonance. I say make it a module
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?
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
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
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.
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.
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.
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
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)
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)
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).
what is the ADSR envelope module? I haven't seen it, it's not breakpointmodulator I'm guessing
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" });
toolchain just crashes REAPER when I try to start liberty
edit: unless im running debugger? wtf.
And yes, you need gate and/or trigger inputs on your modules like ADSR.
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
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.
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)
Let's continue the discussion here. I want to help with this project.
Firstly, I want to create a PrettyScope / CPU Scope hybrid, so if you have a compatible GPU you can use it, and if you don't, then you get your CPU scope. You can implement PrettyScope for this. Eventually I want to offer a free version of PrettyScope with limited controls anyway.
I can also throw in some FMD filters, maybe 2 or 3 that cover the common analog-style filters.
Of course all the oscilloscope music synth cores can be thrown in for free (unless Liberty becomes a paid product)
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.
And I'm guessing you mean for the Instrument panel to display the parameters as sliders: