Highly desirable: stateful MIDI

Hi, I’m really enjoying using the Metamodule integrated with TouchOSC on my iPad. While the physical knobs on the Metamodule (or potential future expanders) are invaluable for hands-on control—especially during performances—this setup has opened up a whole new world of possibilities. It’s even enabled me to use buttons effectively, which has been a game changer.

I was wondering what the priorities are for improving the MIDI implementation. For me, it’s already highly usable, but introducing the possibility of sending controller values back to an external controller could unlock an entirely new universe of functionality.

Currently, modules like sequencers and quantizers are not as convenient to use within the Metamodule, partly because managing numerous button presses is cumbersome and impractical. This issue could be solved if we could query their state and reflect it on an external controller, making them much easier to handle.

I understand that implementing this with SysEx and unique UUIDs for every module might be complex. However, perhaps an earlier implementation could simply use the learned CCs to send state information back to the controller. This approach might simplify things significantly while still adding powerful new capabilities.

Imagine being able to use all those sequencers and utilities inside the Metamodule with a dedicated, fully synchronized interface—it would be incredible!

yes, +1 to this request. I mean, just look at Melbourne Roto Control. :slight_smile: Or any other MIDI controller!

Yeah, I’ve been asking for bi-directional midi so I can use with the Electra One.

perhaps now that dev/2.0 has midi out, its possible.
in fairness, there aren’t that many controllers that support bi-directional midi, so I do get its not highest priority.

while at it… Id also like to see 14bit midi support :wink:

1 Like

Hi,

Soon after the MetaModule announcement last year, I asked 4MS on this modwiggler thread if it would be possible for a module running on the MM to query and change parameters on other modules in the same patch. The reply was … no (link to modwiggler). Later I asked for some more info on that (link to modwiggler), but never got a reply. It would be really interesting to know from @danngreen if that feature is ever likely to be supported in the MM firmware.

I recently published my beta testing - ready RSBATechModules VCVRack plugin (see VCVRack forum thread) that does provide 2-way parameter control of any mapped VCVRack module. I would love to be able to write a version that uses the same mapping library, but runs on the MetaModule, using Midi In/out to hook up to a TouchOSC or Electra-One smart MIDI controller. For this to be feasible, as well as access to the midi in/out stream, it would also need to be able to query and change state of other modules in a MM patch.

That’s do-able, without even v2.0. I haven’t played with 14-bit MIDI but as I understand it, it’s just combining a CC 0-31 as MSB with the value from the CC number +32 as LSB, right? So it would need a user setting to enable this, and then the patch would ignore maps on CCs 32-63 and update the mapped controls for CCs 0-31 with a 14-bit value whenever it receives either MSB or LSB (resetting LSB to 0 when it receives an MSB)

So, the MIDI controller understands that when it receives a MIDI CC message, it should update its internal representation of that control (e.g. redraw the knob on the screen at a new position or something)? I’m not sure I fully understand the whole system…
If you mapped MIDI controller buttons via CCs to a virtual sequencer’s buttons (running in the MM), then pressing the buttons on the controller would toggle those buttons on the virtual sequencer. This part is already working. But then the MM should query the parameter values from the sequencer and send them back to the MIDI controller? Seems like that would just report back the value already sent… unless we’re talking about loading saved/preset sequencers (like the Fundamental/VCV Quantizer module). Or would it make more sense to query Light values from the virtual modules and send that? But I’m not sure how the MM would know which Light ID is linked to which Param ID…

Yeah… but if there’s a fairly easy way to do it without much special-case stuff, I’d consider it

Sorry about that! I think I missed a lot of messages in that period right before release (still have trouble keeping up)
So, the two things about that need to be figured out is discoverability and concurrency. I.e., how does the controller module know about what modules are in the patch and how does the user pick which one to control? And how does it change the other’s values while the latter is potentially running?
I think the latter problem can be solved easily now that we have a solid way to do patch-level things between audio frames (updating graphic displays, lights, etc). But I’m not sure what the first part looks like? Maybe something similar to the MetaModule Hub where mappings are done in VCV and then exported to a patch file? Then there wouldn’t need to be a special UI within MM just for this sort of intra-patch mappings.

1 Like

If we think of an external physical MIDI controller that has encoders (say, a Faderfox EC4, which has a screen):

When you load a patch with MIDI CC mappings, the patch should send out the current position of the mapped MIDI CC controls. Why:

  • so that the Faderfox can display the right values on its screen for the mapped controls.
  • When you turn an encoder on the Faderfox, there is no need to do knob pickup – the Faderfox and Metamodule are aligned, both have e.g. cutoff at 20 and turning the encoder clockwise sends 21, not some arbitrary value decided by the Faderfox.

When you adjust MIDI CC mapped values on the Metamodule itself, it should send those MIDI CCs out to stay in sync with the Faderfox. No need to echo the controls the Meta receives.

This gets especially cool with something like the Melbourne Roto-Control that actually has motorized knobs: when you load a MM patch, the Roto knobs that have their MIDI CC numbers mapped on the MM snap to the right position like a motorized mixer desk (by ’numbers’ here I mean something like MIDI CC 0, ’modwheel’, and not an actual MIDI CC control value if that makes sense).

Furthermore, when you ”change pages” on the Roto-Control to display the next 8 controllable MIDI CCs, the Roto again snaps the controls to the right value, since it received the values at patch load.

I hope this clarifies the case for all encoder controllers

yes, 14 bit midi is indeed just 2 CC. LSB and MSB.
there is a ‘minor’ optimisation that means small turns only require you to send the LSB.
this means, you always need to send MSB first, then LSB (and receivers, should only act on the MSB after they get the next LSB!)

bi-directional midi.
yeah, its pretty simple… (Ive implemented on a few systems :))
just send the (same) CC on patch load, and every time the CC is altered.

the one ‘gotcha’ is to ensure you do not send if the cc has not actually changed.
otherwise you can get into a race-condition, due to a CC message being ‘on the wire’, and the controller and module will end up in a loop alternating between two values.
this simple only “send on change” strategy works well enough (assuming both parties adhere to it).

however, , a more thorough way of handling this is to throttle the output . i.e. only send at a certain frequency (and if its changed) - this can be useful to reduce midi IO, as essentially, when you twist a knob you dont get ALL values sent - even more relevant when using 14bit midi !
(but ofc this means you need a connection which is stateful - though not a bad practice for midi given things like running status)

Thanks for your reply, @danngreen! Many MIDI controllers (including TouchOSC) can update their UI when receiving CC messages. This is crucial for keeping everything in sync between an external controller and the Metamodule.

As I mentioned in my initial post, the main challenge is that when a module inside the MM already has a different internal state, the controller doesn’t know about it, which can lead to mismatches. For example, if I have a sequencer running inside the MM and turn on step buttons from my external controller, some of those steps might already be active. Instead of enabling new steps, the controller might actually turn off some of them, leading to unexpected behavior. Similarly, loading a preset doesn’t update the external controller, making it difficult to keep things in sync.

New Considerations

To avoid this, I think the MM should be able to send back the current state of mapped parameters to external controllers. Rather than assuming the controller always starts from a blank state, it should be possible to query or receive updates about actual internal values.

Would it be possible to send updated CC values for any parameter mapped via MIDI Learn whenever its state changes inside the MM? Or should this be handled via a polling mechanism where the controller requests updates? Both approaches could work; automatic feedback would likely be the most seamless. but having a polling function seems necessary to update the initial controller state.

Additionally, it would be useful to have an option in the preferences to enable or disable MIDI feedback. This way, users who need real-time state updates can activate it, while those who prefer to avoid additional MIDI traffic or potential conflicts can keep it disabled. This flexibility would allow different workflows to coexist without forcing a single behavior.

Thanks for the detailed response! That all makes a lot of sense, especially the “send on change” strategy to avoid feedback loops. Throttling updates for 14-bit MIDI is also a great point—definitely helps optimize bandwidth when dealing with high-resolution data.

One thing I’m still thinking about is how to handle initial state mismatches when mapping controls. If a sequencer inside the MM already has steps enabled before a controller is mapped, the external controller assumes they’re off, which can lead to unintentional toggles. Similarly, when loading a preset, the controller has no way to sync unless an update is sent.

Would you recommend:

  1. Always sending a full state update when mapping a control or loading a preset?
  2. Making this a manual sync option (e.g., the controller requests an update)?

I also like the idea of stateful connections, though I’m curious how that would work in a more open-ended modular environment like the Metamodule. Have you found a good way to manage state persistence across different controllers?

hmm, good question…
so the underlying issue here is you are introducing a new controller after patch is loaded, I’ll say this is very much an ‘corner case’ , as most of the time users will already have the controller attached.

the simple solution would be for the MM to broadcast a full update when it sees a new controller being attached - given this infrequent, its not a big deal.

and yes

  • when patches are loaded/updated they need to send a full update.
  • when you map a control it should send its initial value.

as for manual sync… I would do this slightly different :slight_smile:

I would support the ability to switch patches using program changes !
thus, if you wanted to do a ‘manual sync’ you could send a program change to switch patches.

the advantage, now controllers have the ability to switch patches on the MM :slight_smile:

not quite sure what you mean, I usually just store state per connection - e.g. the connection knows what (last) value a CC is. this is not much memory as there are a limited number of CC (127) and are 7bit, so not much memory.
I’ll admit this does not work, if you started supporting RPN/NRPN, you’d have to use a different model for these.

anyway these are all thing dan can work thru when he gets to them… I figured most of it out as I was actually coding it up (and testing it :wink: )

Thanks @TheTechnobear. I don’t think this is a corner case. Imagine loading a patch into the Metamodule; this patch could have different settings for knobs and buttons. Even if your controller is already connected, it still needs to receive the current patch state to be usable.

While knobs can somewhat work with catch or jump behavior, buttons need to be fully synchronized to avoid inconsistent states. This is especially critical for step sequencers, where an unsynced controller could completely misrepresent the active steps.

Even beyond sequencers, modules like the Plaits clone have multiple selectable algorithms, and without state updates, the controller would never reflect the actual selection. Having a way to push full-state updates when needed (whether on patch load or as a manual sync option) would make the interaction between the MM and external controllers much smoother.

I agree that Dan can address these as he implements it (if this whole feature gets ever prioritized), but it’s interesting to explore how different systems handle this. Thanks for sharing your experience!

no, I said from first post, that if the patch was changed you have to send all values.

the corner case is a new controller being connected, which would also need the all values to be sent , but this is much less likely, as most users tend to connect before powering on/loading patches.

Ok, thanks. That makes more sense.

Given all this info, I think we can do it like this:
The MM sends MIDI when a parameter value changes via the knobs, or the manual Adjust button, or if the module adjusts its own parameters (loading a preset for example). I already have parameter value changes being checked in order to update the MM’s GUI, so probably I can just have it push those updates to a MIDI queue if the user enabled the feature in settings.
Throttling it back is a good idea, too (the connection already has state – i.e. for keeping track of what notes are down for doing polyphony), we’ll see how much it needs.

For manual sync, the patch can send all params when you press Play (not just on initial load). You could fall back to that if you need to sync or re-sync with a controller. Or we could watch for the midi_connected flag going from false to true, and send a full dump on that.

That example might not be possible for any kind of MIDI connection, nothing to do with the MetaModule. I believe the Plaits keeps its algorithm selection as an internal state variable – that is, it’s not available to the audio engine. (Well technically, the MM can request that the Plaits module dump its state into a json string, and then parse the string, but that’s not going to work without special-case coding for every type of module.)
So basically, this MIDI feedback system will only work for synchronizing parameters that a module chooses to expose – if a module keeps its state private and hidden, then there’s no way to have that display on a MIDI controller screen.

2 Likes