dbRackFormulaOne preview


i am working on a new script/formula module called FormulaOne.


A pre release can be found at https://github.com/docb/dbRackFormulaOne. I have made a small manual in the Readme which shows how to make Oscillators, Phase controlled Oscillators, Wave folders, Filters, Comb Filters, Stereo Delays, Random and Hold, CV Sequencers, Gate Sequencers, Chord Sequencers, Envelope Generators.

It is based on the exprtk expression library which has very good benchmarks.

Of course it is not intended for replacing native modules because they still will be faster i.e. consume less CPU and provide more usability. It is for experimenting, learning and making special things.

It is only tested for linux so far. Tests on other platforms, opinions, requests are welcome.

On Windows unfortunately the module will be slower as i had to disable optimizations of exprtk which cause that the compiled obj file exceeds the accepted size of the mingw compiler (provided in the rack-plugin-toolchain). Due to the docs of exprtk it should compile fine with the MVSC++ compiler (which i don’t have).


mingw uses the gcc c++ compiler. It’s astounding it has a limit, esp one that you can’t override. Are you sure?

Microsoft’s MSVC comes in a free edition, which I have been using for years. It’s quite good.

it seems to be a known issue, mingw32 seems to have a signed short for the size of the sections in the obj file (2^16) and the option -Wa,-mbig-obj did not work, so may be i need here another version of mingw – i will continue to investigate. I do not have a windows installation either(and don’t want to), and i still would like to be able to compile my modules with the rack-plugin-toolchain on linux.

If someone gives a try - in the Makefile this entry should be commented out.

include $(RACK_DIR)/arch.mk
ifdef ARCH_WIN
# the exprtk cannot compiled on mingw because a too big obj file is generated
# with this option it is under the limit but it is slower
FLAGS += -Dexprtk_disable_enhanced_features

# the option -Wa,-mbig-obj  did not work so far

however the module is still usable but it appears to consume 20-30% more CPU.

Builds and runs just fine on my Mac, great work! I appreciate the thorough documentation on the GitHub page as well.

Is this a fork of Frank Buss Formula:

The script in your example looks different but the name of the module is quite similar.

hi, its not a fork. you could make a diff of the two and tell me which code lines match :wink:. You also could look at the manual and see that almost all examples are not doable with Frank Buss Formula and you could also compare the cpu usage of the two. I have utilized one concept of this module and that is the blinker if the compilation fails.

Thanks!, glad to hear that it works fine on Mac!

1 Like

It’s interesting that you decided to go for the traditional single module solution. It could have been a master & expander (aka player & editor) combo.

I find the manual extremely useful! Very nice description.


Well, i like the compact scripts where all things fit into the window. So i decided to make a single module. The second problem would be, that the module without the editor does not tell you what exactly is present at the moment. But thanks very much for the input, I will consider this option.

Btw. currently there is an expander for editing in the module:

but there is some work to do.


I’m very much looking forward to seeing (and using) this in the library. It appears to be more of a full scripting language, and not just the ability to enter a single formula. So my guess is it could just about replace or substitute for the VCV Prototype module that still is missing from V2.

I see you can have user defined variables. What about user defined functions?

It appears there is implicit iteration of the polyphonic channels. That could be good for a majority of situations - streamlining development of polyphonic applications. But I’m concerned about operations that need to operate on inputs and/or outputs of multiple channels simultaneously. A simplistic example is something like a polyphonic split/merge. Is there a way to take control of the channel iteration?

That script entry window looks like a golden opportunity for additional functionality. It would be great if there were at least two modes for the display:

  1. script display and editing
  2. script defined text output. It could be used to give documentation for knobs/inputs/outputs. It could also give dynamic feedback on input/output values and or computed values.
  3. Maybe a reach - but what about a graphical display option, so it could have its own built in scope and/or frequency plots. It would be cool if that was built in. But if you also had a scripting interface, we could have a platform for user defined visualizations. Maybe a reach, but it sounds cool to me.

hi Dave, thanks for your input: FormulaOne was not intended to be a full scripting interface. May be rather a simple formula evaluator – “x+y” does still work polyphonic :wink: – with some scripting capabilities which provides state and buffers for enabling the implementation of dsp algorithms. For a full scripting interface i would rather make it like the LUA module from Wrong People similar as you pointed out in your third point - with description, scope etc …, Here and also in the VCV Prototype the script is in a file edited with a common editor and there is much space to make such things like descriptions which are displayed when loaded. With the current interface it will get messy. (NB it has already stolen some time to adapt the textfield of the vcvrack api for doing needed stuff).

User defined functions are is not directly provided by the underlying engine. It seems to be possible but this has a bigger effort, as so far i can see it the docs i would have to parse the script by my self first, extract the function and register it in the c++ code before compiling.

The single loop for polyphonic stuff requires a different api which may be not so simple as you would need either variables e.g. w1,…,w16 or a function getW(0) … and same for the outputs. Eventually this leads to a different module or mode, which provides the rack C++ API inside the script (getVoltage(channel), setVoltage(value,channel), getPolyVoltage(channel), getParam(), setChannels(), getChannels(), isConnected(),… and this for each input,output, knob. This could be feasible (may be it is slower) but i am not sure if this is purposeful. Shouldn’t i use simply for these polyphony usecases the LUA Module from Wrong People? Because this module has exactly this interface.

Bottom Line: My intention was to have a reasonably fast and easy interface where i can experiment, learn and do special things i cannot find in other modules. The media discontinuity to have the script in a file and the switch to an external application is eliminated with the drawback that you cannot make scripts with 1000 lines, which anyway would cost too much CPU.

User defined functions are is not directly provided by the underlying engine.

Adding user define functions within the running/execution of an expression is trivial.

The example below defines an is_prime function then subsequently calls it in a loop over the range 1…10^6:


hi Arash, first, very thanks for your great library. So far i have not recognized the exprtk-extras repository. So far understood, you have introduced a syntax for separating function definitions and the main program, by using directives starting with $. The $function directive is parsed (all methods for this are provided) and the resulting function eventually passed to the compositor. I will try to integrate this in the next version. Thanks!

Hi DocB - The $ is something I used for the repl to denote multi-line inputs, as it uses a simple std::cin mechanism.

Given you’ve got a full edit widget you can simply parse as-is. There is code in the repl that parses functions out from a string and using the function compositor generates functions and registers them in the symbol_table.


hi Arash, thanks, it works but here is a problem:

it seems there is some big CPU overhead when using the compositor.

ok the reason was obviously caused using the return statement.

without it is fine.

similar i have already disabled the break and continue statement because of the same issue. so i will go with:

#define exprtk_disable_break_continue
#define exprtk_disable_return_statement

Yeah the mechanism used to perform return in ExprTk is extremely slow when compiled with msvc on windows. Are your perf numbers based on a windows build?

Though it should be fine from a performance POV on linux and macos. Furthermore Section 20 of the readme has a more detailed explanation, with alternatives to return.

Most ppl build with gcc for windows.

this example is on linux built with gcc. nevertheless, i think it is no problem to do without return and break.

Not to forget: limitations can spark up your musical creativity! :crazy_face: