Announcing: Sapphire Elastika

Another approach on randomization which is trickier. Make output unrandomizable and have a custom randomize handler on input which sets output to the inverse so you don’t get gain blowouts. Bit more code since you need a custom PQ for your input but not impossible.

Moving this from the other thread- have you considered adding a dry/wet control? A master tone/eq might be handy too, the effect tends to generate a lot of low-end mud.

1 Like

Elastika’s Bypass is indeed broken, no signal if I turn it on (well, the light off), silence is emitted

1 Like

Thank you for the great feedback! I have added 3 new issues as a result.

The NAN output issue is a serious bug. I wrestled with this a lot during development. I thought I had this solved, but apparently not. I tried to open your patch but there are a few pre-release Surge XT modules in there.

I’m a little reluctant to mix other people’s pre-release stuff with my own on a development system, just to avoid confounding bugs. Not because I distrust other developers, but because it reduces the surface area of mixed versions or possible instability while I’m debugging. So I will try to repro the NAN issue on my own, based on your description. However, if it’s super easy for you to repro using released modules only, and you feel like doing that, that would be an awesome contribution.

Yes, I will make Elastika sum polyphonic inputs. Elastika is already a CPU-thirsty module, and making it truly polyphonic would be excessive. Summing will be lightweight and will not change the behavior for existing patches that use single-channel cables as input.

Question: should polyphonic summing be applied to audio inputs only, or is it conventional for CV inputs also?

About bypass and dry/wet: these ideas seem related. Dry/wet seems like a continuous version of bypass. Bypass turned on seems the same as 100% dry, and bypass turned off is like 100% wet.

@officialdjglitch : I think I shied away from a dry/wet control, because if I understand correctly, this can be done using an external send/return module. Am I right about this, or am I misunderstanding?

If I am right, the nice thing about a binary bypass switch is when I bypass, I can also turn off the CPU-hungry simulation. Which brings me to another twist: I already have a push-button + gate for turning the simulation on/off. When Elastika is turned off, it mutes the outputs and goes into a nearly 0% CPU usage mode. Bypass could also put Elastika in a low-CPU mode while copying inputs to outputs. This seems half-redundant, and I wonder if it needs more thought. Like, if bypass works, do I really need a silence mode also? Advice would be appreciated.

Another twist: is bypass expected to retain the channel counts of the inputs? It would be weird if I summed polyphonic inputs while not bypassed, and then changed the channel count when bypass is enabled. It seems like I should convert dual polyphonic (L and R) to dual monophonic (L and R stereo, but one channel each) for output whether bypass is enabled or disabled. It seems the least weird thing to do.

Thanks again for the helpful commentary!


Thanks for adding some great topics to the discussion.

Dry/wet is possible, although it would require a lot of work to squeeze in the controls in the panel design (unless I just hide it in the right-click menu). For now, is it possible to use an external send/return module for this?

About a tone/EQ control: I did start out with adjustable LO/HI band-reject filter controls, but I ended up taking them out because I reasoned that someone can always add a filter of their choice on the outputs.

Also, see my response to baconpaul regarding bypass.

I read somewhere that one philosophy of modular synth is to emphasize the “modular” part. The thesis was one should not bundle things in a module that can be added externally, unless there is a strong reason. With the exception of the input/output level controls, all of Elastika’s controls are necessarily part of the module, because they affect the internal state of the simulation and can’t be added from the outside.

Removing the built-in LO/HI filters freed up panel room for adding dual TILT knobs at the top. You may find that playing around with the TILT knobs does give you some control over the resulting frequency spectrum. That and your favorite filters on the output should help a lot.

1 Like

I did consider adding a right-click menu option that would inversely lock the input and output knobs. When you turned one up, it would automatically turn the other one down. But I kept thinking of more and more complications and it gave me a headache.

But I didn’t think about this scoped only to the randomizer, and that’s interesting. I think my only push-back would be that output volume isn’t tied to input level as much as one would think. Sometimes you can get tremendously loud output with no input at all; other times you can hammer the input and get very little out. It all depends on how you tune the controls.

My gut feeling now is that input and output knobs should be completely excluded from randomization. In general, Elastika users need to be careful with their speakers and ears because it’s inherently chaotic. Tame it first, then turn up the volume!

1 Like

Thanks! I have added an issue for bypass and I will fix it in the next release.


Rack has a built in bypass. You can get it through the right mouse button on your module. When that happens your module process isn’t called.

But that built in bypass also has a way to dup inputs to outputs.

So it you literally add the two lines

   configBypass(INPUT_L, OUTPUT_L);
   configBypass(INPUT_R, OUTPUT_R);

to your constructor when you bypass in rack (with the many or shift-alt-b or some such) the CPU drops to zero and you get a clean through pass.


the nan happened when i was changing connections between modules so it was probably at either a calamitous immediate increase or decrease in input. Hope that helps. Fighting nans is hard.

but if you do a if processcount++==1024 { if is_nan(out) reset; process count = 0; } type thing (or at least have a rmb to reset) that may at least help get out of it. The bummer was my only way to restart was to re-initialize which reset all my attenuators and sliders.

I’ve been using the Vult one. Have you considered replacing the bypass control with a dry/wet knob?


OK, that helps. I will definitely add the automatic clearing of internal state if NAN is detected. When that happens, I can easily set all the balls to their original positions and their velocities to zero.

The current defense against model explosions is an upper speed limit for the balls. The speed of each ball is clamped when its velocity vector is updated. I thought this was all I needed. So there must still be a case where a position and/or velocity is going infinite or NAN during a single sample.

In thinking about that out loud just now, I could easily check for non-finite speeds while doing the speed limit clamping. Positions are updated from velocities, so I’m pretty sure the velocity is the root cause. The automatic clearing should be like fire sprinklers… a good backup but I hope it’s never needed!

OK, thanks for the clarification. I get it. I just need to define the pass-through ports to make it work right.

1 Like

Another thought: NAN output could also happen if any of the input voltages (audio or CV) are non-finite. I’m not sure whether this can happen in the first place. Does VCV Rack detect NAN and replace it with zero, or does it just shove the voltages through the network? I would assume the latter because it’s more efficient.

Which brings me to the next question: should I try to filter and ignore non-finite inputs, as another defense against sending them as output? Or is it better to let them pass through and let the user be responsible for debugging the patch to figure out whose fault they are? This one is more a policy question than a technical question.

Rack will flow nans Filtering them is expensive though - is nan is not free Most modules don’t make them (and in my case the modules didn’t send a nan in since I was mixing them with your module)

But my coding practice here is - don’t send nans and assume I don’t get them. But if I might send nans try not to.

Curious what other think tho

I had a follow-up thought about this. Internally there is a pair of low-reject filters, essentially DC blockers, on each of the stereo outputs (L and R). It currently has a fixed corner frequency of 20 Hz. I would consider adding adjustment of the corner frequency in the right-click menu, because it would not affect the panel design and it would not add any extra CPU usage. Maybe that would be a reasonable compromise. What do you think?

1 Like

I made a similar choice for the surge modules where I had things which I wanted adjustable but not necessarily modulatable and it seems folks found it reasonable and idiomatic.

It my experience, many of the problems I have tried to track down in others’ modules have been NaN related. They are very difficult to track down. I typically use Voltmeter as a NaN detector as a NaN will usually register as a gigantic number that goes halfway across my monitor screen. Quite often the output port poly count will also be messed up and I detect that by watching for flickering patch cable width.

It would be cool if someone could create a module that is designed for identifying these types of problems.

Unfortunately, when I see NaN problems, I also see all sorts of modules in the crash log if there is a crash. Without looking at a lot of code, I never know which modules try to screen incoming and/or outgoing NaN’s.

1 Like

That would be a great idea!

Here’s a funny thing. I realized my other module Sapphire Moots doesn’t support bypass either, so I’m fixing it also. But in the process, I found something weird. Moots works by changing the output cable’s channel count to zero when the corresponding gate/button is turned off. It looks like this fools VCV Rack into thinking there is no output cable, which in turn causes the bypass to continue blocking the input signal from reaching the corresponding output signal.

If there were some callback that informed me when bypass is enabled, I could quickly correct the output cables’ channel counts and bypass would then work as expected. I’m not going to worry too much about it right now. I’m just going to map the inputs/outputs using configBypass so it sort-of works.