Delexander Algomorph — Now in Beta — FM Algorithm Module

Algomorph, my module for connecting, storing, and morphing between FM algorithms, now has a working display unit installed and so it’s moving from alpha to beta.

If you caught the alpha release announcement, mostly this beta is about is the kickin’ new display. Watching algorithms morph is fun! For those interested in technical details, the 1695 supported algorithms (at least one carrier, no feedback) were enumerated as directed graphs in dot language. These were then rendered by Graphviz to SVG files which were processed by Beautiful Soup in order to create CSV files containing all of the relevant coordinate information extracted (algorithm id, node locations, bezier curves for the edges, and polygons for the arrowheads).

Besides the display there is also one other rather significant change, which is the addition of a trigger input for skipping the “base algorithm” one to the left or right. By patching a clock-synchronized LFO to the Morph CV input and its clock to the Advance trigger input, circular morphing between the three stored algorithms is possible. Here is an example using the ZZC Clock (and a Bogaudio Offset to bring its Phase output down to +/-5v):

Also added since the initial release is a “Ring Morph” option which allows for ring modulation effects when an audio rate signal is patched into the Morph CV input. Polyphony is also supported, however there is no SIMD yet so the performance under heavy load isn’t great. Improved support for polyphony is planned for the first major update after the module exits beta.

If you are totally new to Algomorph, here are the details:

Algomorph is a VCV Rack module for constructing FM algorithms using up to 4 operators.

It is intended for use in conjunction with oscillators capable of linear through-zero FM such as Bogaudio FM-OP, Nysthi µOPERATOR/TZOP, Squinky Labs Kitchen Sink, and Valley Audio Terrorform.

It allows for reconfiguring an algorithm using only button presses rather than having to rewire cables.

More interestingly, it allows for storing up to 3 different algorithms which can be instantly recalled by pressing the buttons labeled 1, 2, and 3.

Further, it features a Morph knob and CV input which allow for cross-fading between the stored algorithms.

Explore the space between your FM algorithms!

Getting started:

  • Connect the output of up to four operators to the Operator Inputs.
  • Connect the same number of Modulation Outputs from Algomorph to the linear through-zero FM inputs of the operators.
  • Connect the Sum output to your audio device or a mixer. This output delivers the sum of all carriers.
  • Press an Operator Button followed by a Modulation Button to connect one operator to another. Repeat until you have built a desired algorithm.
  • Connecting an operator to its own modulation output will disable the operator’s modulation output and remove it from the Sum output for that algorithm.
  • After you have finished building your algorithm, press Algorithm Button 1 or 3 to build new algorithms.
  • The Morph knob allows for cross-fading between the stored algorithms:
    12 o’clock is the currently selected algorithm,
    7 o’clock is one algorithm to the left, and
    5 o’clock is one algorithm to the right.
  • The CV input can also be used instead of (or in addition to) the knob, accepting +/-5V.

Builds for Linux, Mac, and Windows are available. To install one of these, follow these instructions.

I’m very grateful for all testers! Let me know if it makes obscene gestures at you or picks up late-night AM radio broadcasts. I hope to release this module in the library soon.

16 Likes

Since I released the alpha, Terrorform has been unleashed on the world. A new friend for Algomorph! I’ve been exploring some terrorformed textural soundscapes using four Terrorform modules, each with all four of their FM inputs patched and four outputs patched, and four instances of Algomorph:

6 Likes

This is super cool!

1 Like

Thank you! But it doesn’t appear in module browser. It detects one module (1) but doesn’t show a thumbnail. I tried to use stoermelder’s 0.6 browser mod and it detects that but then Rack is crashing. Tried compiled one and compiled by myself from the source. Win10.

1 Like

Woops, that was a last minute filename change. Silly mistake. The builds are now updated with the fix. Sorry about that, and thanks for the heads up!

3 Likes

Thanks, working now! Could you consider add some expander with an additional input for using it as non FM algo modulator…but for Effect chain morphing tool?) I just tried use 1st op input for an oscillator and connect three different effects upper, then do another preset with different connections and leave one for a bypass effects section. And this is what I always want to hear when turning morph knob to the bypass one - delays and reverbs just leave desirable trail without click and so bypassy things. And that’s the reason I’m asking for an expander - the process of connection would be much easier and we can use up to 4 effects in the chain which is pretty cool. What do you think on it?

EDIT - also sequential switch CV input for switching algorithms is pretty cool, but could you also add some anti-click (pop) function into right click menu? I mean some short slewing on that to prevent those audible clicks while switching the algorithms.

4 Likes

This looks absolutely INSANE! Thank you so much! I’m no programmer but I was fascinated by your explanation of all the work and process behind creating the display. Im definitely going to be spending some time with this inspiring module.

1 Like

Seems really cool! Unfortunately the current build seems to consistently crash upon being added to the rack (Win 10), about 90% of the time. It doesn’t seem to happen upon loading a patch where the module is already present. Log seems unhelpful:

1 Like

Thank you! Creating and facilitating inspiration is the dream. I hope that your time with the module proves fruitful!

Anti-click is definitely a must-have for that trigger input, I agree. I’ve started working on implementing this, but it won’t be as simple as the anti-click in a sequential switch. I’m hoping to have a build with this feature included soon.

I’m not sure I understand your expander idea. Do you mean to add another operator input that could be routed to the existing Mod outputs? One thing I could do to help with non-FM usage would be to add an option which would allow for an input to be routed to “its own” output rather than using this as a means of disabling the input.

Yikes! I’ve been building and testing on Windows 7, but thankfully I also have quick access to a PC running Windows 10 and was able to reproduce the crashing. What left me head scratching was when I set up my development environment and started debugging, and the crashing disappeared.

It turns out that when I compile myself on Windows 10 here, everything works fine. Only the build from Azure exhibits the crashing. Maybe some kind of corruption? Strangely, the Azure build is also about 20% larger in file size…

In any case, I replaced the Windows build on GitHub with my own. Hopefully this solves the problem for you too, and hopefully this doesn’t crop back up in future builds or when submitting to the library later.

Thank you for testing!

I would be concerned about that mystery crash. In my experience crashes that get fixed by magic don’t stay fixed.

1 Like

It looks like none of the member variable in your Module are initialized. morph[], for example. Is it initialized somewhere that I’m missing? I guess maybe it is since this builds without warnings. You might try running it under address sanitizer to see if there is any monkey business going on with memory.

btw, very cool using dot language for this!

I’m going to do another build on Azure and see if the results persist in their build. If it does, maybe I can figure out how to reproduce their build configuration locally in order to better debug the issue. Thanks for the tip about address sanitizer; I’ll take a look with that.

When I first started researching to see how I might be able to implement this, I spent some time working with the gtools from the nauty/Traces project in an attempt to have all the relevant graphs generated and rendered to dot language for me. Eventually I realized it wasn’t too difficult skip nauty and instead just generate the dot language myself for exactly the set of graphs I was interested in.

GraphViz and nauty/Traces are some cool projects, and it’s been fun to learn about it all for the first time while making this.

btw, asan is not easy to use at all, unless you have a mac. It’s trivial to use in xcode. afaik it’s impossible to use in windows. I run ubuntu in a VM and do my asan testing in there. .

1 Like

Are you building in your development environment without optimization switches? This might be the cause for different behavior of the Azure build which is usually fully optimized…

I think his makefile had the standard options, although I didn’t inspect in great detail. hmmm. I just tried running and immediately crashed.

crashed on exit this time. memory corruption?

Thread 1 received signal SIGTRAP, Trace/breakpoint trap.
0x00007ffc1adb91b3 in ntdll!RtlIsNonEmptyDirectoryReparsePointAllowed ()
   from C:\windows\SYSTEM32\ntdll.dll
(gdb) bt
#0  0x00007ffc1adb91b3 in ntdll!RtlIsNonEmptyDirectoryReparsePointAllowed ()
   from C:\windows\SYSTEM32\ntdll.dll
#1  0x00007ffc1adc15e2 in ntdll!RtlpNtMakeTemporaryKey ()
   from C:\windows\SYSTEM32\ntdll.dll
#2  0x00007ffc1adc18ea in ntdll!RtlpNtMakeTemporaryKey ()
   from C:\windows\SYSTEM32\ntdll.dll
#3  0x00007ffc1adca8a9 in ntdll!RtlpNtMakeTemporaryKey ()
   from C:\windows\SYSTEM32\ntdll.dll
#4  0x00007ffc1ad0253a in ntdll!RtlGetCurrentServiceSessionId ()
   from C:\windows\SYSTEM32\ntdll.dll
#5  0x00007ffc1ad00790 in ntdll!RtlGetCurrentServiceSessionId ()
   from C:\windows\SYSTEM32\ntdll.dll
#6  0x00007ffc1acffb91 in ntdll!RtlFreeHeap ()
   from C:\windows\SYSTEM32\ntdll.dll
#7  0x00007ffc1adc53c9 in ntdll!RtlpNtMakeTemporaryKey ()
   from C:\windows\SYSTEM32\ntdll.dll
#8  0x00007ffc1ad75670 in ntdll!memset () from C:\windows\SYSTEM32\ntdll.dll
#9  0x00007ffc1ad00790 in ntdll!RtlGetCurrentServiceSessionId ()
   from C:\windows\SYSTEM32\ntdll.dll
#10 0x00007ffc1acffb91 in ntdll!RtlFreeHeap ()
   from C:\windows\SYSTEM32\ntdll.dll
#11 0x00007ffc1a8c9cfc in msvcrt!free () from C:\windows\System32\msvcrt.dll
#12 0x00000000004a25e3 in rack::engine::Module::~Module (this=0x1f5784c0,
    __in_chrg=<optimized out>) at src/engine/Module.cpp:15
#13 0x00000003a6ba66d8 in Algomorph4::~Algomorph4 (this=0x1f5784c0,
    __in_chrg=<optimized out>) at src/Algomorph.cpp:5
#14 Algomorph4::~Algomorph4 (this=0x1f5784c0, __in_chrg=<optimized out>)

1 Like

crashed trying to insert a copy from an empty rack, although nothing interesting on the stack:

Thread 1 received signal SIGSEGV, Segmentation fault.
nvgluDeleteFramebuffer (fb=0x3f80000000000000)
    at dep/include/nanovg_gl_utils.h:137
137             if (fb->fbo != 0)
(gdb) bt
#0  nvgluDeleteFramebuffer (fb=0x3f80000000000000)
    at dep/include/nanovg_gl_utils.h:137
#1  0x00000000004aa1a1 in rack::widget::FramebufferWidget::step (
    this=0x233da340) at src/widget/FramebufferWidget.cpp:67
#2  0x00000000004ab46f in rack::widget::Widget::step (this=0x233da280)
    at src/widget/Widget.cpp:151
#3  0x00000000004ab46f in rack::widget::Widget::step (this=0x233d9320)
    at src/widget/Widget.cpp:151
#4  0x00000000004ab46f in rack::widget::Widget::step (this=0x3c26450)
    at src/widget/Widget.cpp:151
#5  0x00000000004ab46f in rack::widget::Widget::step (this=0x3ba6ee0)
    at src/widget/Widget.cpp:151
#6  0x00000000004ab46f in rack::widget::Widget::step (this=0x3ba6e20)
    at src/widget/Widget.cpp:151
#7  0x00000000004ab46f in rack::widget::Widget::step (this=0x1f63af40)
    at src/widget/Widget.cpp:151
#8  0x00000000004ab46f in rack::widget::Widget::step (
    this=this@entry=0x3bcb4e0) at src/widget/Widget.cpp:151
#9  0x00000000004a77d5 in rack::ui::ScrollWidget::step (
    this=this@entry=0x3bcb4e0) at src/ui/ScrollWidget.cpp:36
#10 0x00000000004969a9 in rack::app::RackScrollWidget::step (this=0x3bcb4e0)
    at src/app/RackScrollWidget.cpp:7```

This build seems to work! Except for the display - it’s empty in this version.

I built it from source and still seem to get segfaults on adding the module. My setup is pretty unusual in dozen of ways so it might be more useful if someone else can reproduce it, I can’t rule out it’s just on my end.

1 Like

See above, happens for me, too every time. I pasted in some stack traces from the debugger. I’m going to guess that some code is writing off the end of an array and corrupting someone else’s memory. I didn’t see anything obvious, but the code is fairly complex.