Announcing: Sapphire Moots module

I’m posting here to announce the release of my VCV Rack plugin called Sapphire. For now it contains a single module called Sapphire Moots. More modules will be added in the near future, and all will be free and open source. Source code and documentation is available on the Sapphire GitHub repo.

The most interesting thing about Sapphire Moots is that, as far as I know, it is the only module that simulates plugging and unplugging cables from a port. It does this using either a push button or a gate voltage.

The implementation details may be interesting to other developers. It simulates unplugging all the cables connected to one of its five output ports by setting the port’s polyphonic channel count to zero. As confirmed in an email conversation with @Vortico, this causes all the connected cables to have a channel count of zero, which VCV Rack considers identical to not being connected at all. When this happens, you can even see all the cables appear thinner on the screen than a monophonic cable.

I created this for cases where I found VCV Mutes did not work as I initially expected; that module mutes by setting all the output channel voltages to zero, but leaving all the channels intact. An example is the Audible Instruments Resonator module’s input jack, which behaves differently when fed a polyphonic zero volt signal, versus not being connected at all.

Here is a video demo of Sapphire Moots in action:

I hope VCV Rackers will find this an interesting addition to their creativity and fun. I’m eagerly interested in any feedback, comments, or questions. Fire away!

22 Likes

This is exactly what I’ve been looking for. Thank you.

1 Like

looks like it’s really working as should, hope to test it soon more deeply, thanks!

1 Like

Great addition! I love the gemstone shape on the panel :heart:

1 Like

Very simple and esoteric, but also a great idea and sometimes just what is needed.

This image shows all 3 possible cable appearances - polyphonic, monophonic, and 0 channel. I wouldn’t say the 0 channel cable is thinner, but rather it has reduced opaqueness. The Nysthi Multivoltimetro graphically shows the difference between a cable with 0V and a cable with 0 channels, and also demonstrates that a 0 channel cable is the same as no cable.

One thing I find particularly interesting is the bottom output - the MOOT 5 is enabled, but because it has no input, the result is a 0 channel cable, the same as the disabled MOOT 4 that does have input. This feature can be really useful for building a patch bay. I frequently create moderately complex patches that emulate some piece of hardware, and I often times create a patch bay to isolate the intended user ports from all the spaghetti of the emulator. Say I have a VCA functioning as volume control, and without any CV input it defaults to 100%. If I patch from a typical patch bay to the VCA CV control, then it defaults to 0V and volume is shut off. But using MOOTS as a patch bay I can patch to the VCA CV input and as long as the user does not patch the patch bay input, then the volume remains at the desired 100%.

The only other module I am aware of that can create a 0 channel cable is the VCV Fundamental MERGE module. With no inputs, it creates a 0 channel output by default. You can also use the context menu to explicitly specify the number of output channels, regardless how many inputs there are.

I do have one enhancement suggestion for MOOTS - it would be nice if an off button glowed a dim red or gray so the UI could be used when the room brightness is 0%.

5 Likes

I immediately thought of you when I saw the MOOTS design!

1 Like

I don’t understand how this works. Looking at the rack port code, calling setChannels for a port with a value of 0 always sets the number of channels to 1.

	/** Sets the number of polyphony channels.
	Also clears voltages of higher channels.
	If disconnected, this does nothing (`channels` remains 0).
	If 0 is given, `channels` is set to 1 but all voltages are cleared.
	*/
	void setChannels(int channels) {
		// If disconnected, keep the number of channels at 0.
		if (this->channels == 0) {
			return;
		}
		// Set higher channel voltages to 0
		for (int c = channels; c < this->channels; c++) {
			voltages[c] = 0.f;
		}
		// Don't allow caller to set port as disconnected
		if (channels == 0) {
			channels = 1;
		}
		this->channels = channels;
	}

Looking at the code in the git repo, it looks like moots is circumnavigating setChannels and setting the channels field directly. Line 110 of moots.cpp. Which admittedly is an “unstable API” but I guess it achieves the desired effect for now and just means it may need to be updated if that part of the API changes.

1 Like

I believe it has always been Andrew’s intent to support this feature. Beyond the fact that MERGE supports 0 channel cables, this passage has been in the documentation since polyphony was first introduced in Rack 1.0

Zero-channel cables are also possible, which make modules think the cable is unpatched. This can be useful if a module has a particular unpatched behavior you want to use but don’t want to actually unpatch the cable. It is even possible for a hypothetical module to automate the number of channels of its outputs, in order to virtually patch/unpatch a cable according to a gate signal. (Email support@vcvrack.com if you know or made a module that does this.)

5 Likes

Yes, that crucial line of code outp.channels = 0 concerned me when I wrote it, because like you say, the setChannels function clamps to a minimum value of 1. Andrew Bolt had this to say in an email reply to me:

Yes, you read correctly that setting the channel count to 0 simulates (and is indistinguishable from) unpatching a cable, allowing modules to automate disconnecting/connecting a cable.

It looks like output.channels = 0 is the only way to do this currently. Setting output.setChannels(0) sets the channels to 1 to preserve backward compatibility with some old modules. In the future we might add another method or modify setChannels() behavior.

So my takeaway is this is a little strange, but the primary VCV Rack developer is aware I’m doing it and is OK with it.

5 Likes

Thanks @DaveVenom for taking the time to experiment and report your observations. That’s a cool demo with Multivoltimetro.

I do have one enhancement suggestion for MOOTS - it would be nice if an off button glowed a dim red or gray so the UI could be used when the room brightness is 0%.

Love that idea! I will do that for my next release. I have added this as the very first issue in the GitHub repo, so I won’t forget about it.

4 Likes

This is fantastic! I was just looking for something like this so I could automate v/oct connection to @martinl1968 's memory sequencer. It’s perfect - thank you!

1 Like

ML Modules.

3 Likes

I think it would be great if gate input would have some slew control, even maybe in context menu to not mess with overall cool design (like Stoermelder or Mindmeld do in their modules for example)

1 Like

I’m interested in understanding your suggestion better. How exactly would the slew work? Would it be a delay before changing plugging/unplugging the cable?

I think Artem wants the output to slew; fade in/out so when you use it with audio in it does not produce clicks. But I could be wrong :man_shrugging: :grinning:

Yes, I’m thinking the same. But that could be tricky. I don’t think there is any way to slew the transition between a normal cable and one that has 0 channels (nothing patched). You would have to complete the slew (fade in/out) while the cable is attached, totally separate from the disabling of the cable.

To fade in the module would have to activate the cable, but start with a 0V value (possibly polyphonic), and then fade in the actual cable voltage(s) until 100% is reached.

To fade out it would be in reverse, fade the voltage to 0, and then disable the cable.

1 Like

@DaveVenom That slew idea makes the most sense to me, and it sounds like a clean and simple option to add. I’d rather not make things too complicated, so I wonder if a fixed 0.1 second linear ramp would be good enough? In other words, you have the option of no slew, or a 0.1 second slew. That should be fast enough to be a snappy response, while eliminating clicks.

Or I could add a small number of time periods to choose from. Any recommendations for reasonable amounts of fade time?

One interesting case is what happens if a toggle happens during the slew. The common sense answer would be, if it’s in the middle of fading out after the gate (or button) goes low for starting the slew for an unplug operation, and the gate goes high again, just reverse direction and start fading back in.

Overall, it should be a simple state machine to implement, and I believe this is a valuable idea.

I think most modules that slew a mute/unmute simply apply a fixed slew, and I suspect it is less than 0.1 second. The Fundamental 4->1 and 1->4 sequential switches have that, but I don’t know what the time frame is.

There definitely should be an option to enable or disable the slew. Typically it would be enabled for audio, and disabled for CV.

1 Like

That info pointed me in a helpful direction. I’m looking here in the sequential switch source code. Its “click filters” fade in/out over 1/400 of a second. The slew limiter code is a simple linear fade with clamping. So I can make the new option work the same way in Moots.

That makes sense, and because Moots works equally well for any kind of voltage signal, it will be up to the user to choose the appropriate option.

I’ll wait a day or two, and if there is a general consensus on this, I will create a tracking issue on the GitHub repo.

1 Like