Emulating a hardware synth's state, communicating between processing and ui

I’m new to Juce, so this may prove beyond me. This is a slightly general request for advice, largely about communicating between the UI and the process thread.

To give context, I would like to make some tracks using essentially only my Mopho as the sound source. The Mopho is monophonic, so for things like polyphony or unison, I need to record it in multiple passes. Thus I want a VST that essentially functions as a Mopho so far as midi and sound are concerned. The audio it produces doesn’t need to be high quality since it’s audio won’t be used in any final product. Rather, it needs to do just enough that I can work out what I want my Mopho to do before going through the process of recording things in multiple passes.

If I use host automation, I would like the plugin to output MIDI notes and NRPNs that can be recorded so that I have MIDI data that can be played back through the real Mopho. The host I’ll be using is Reaper.

Internally, it’s edit buffer has 256 bytes of data, and the contents of that buffer control the two oscillators, each with a sub oscillator, a lowpass filter, four LFOs and four steppers (IIRC, something like that). So what I want my synth to do is to maintain a 256byte buffer of the config information, receive NRPNs/CCs, and also when changed from the host via automation, to output NRPNs. This will edit buffer will be contained in the audio thread.

The general question is: what is the right way to go about this?

  1. It makes sense for the UI thread to poll the data when it wants it, and to use the value tree state to send updates to the audio thread.
  2. If the plugin state changes via MIDI, the UI only needs to be notified that a change has happened, and then it can poll the data when it can.
  3. So from the point of view of the UI thread, the 256bytes of state are read-only (and written to via the value tree state). And from the point of view of the audio thread, the 256 bytes of state are read-write and it simply notifies the UI when changes occur. There should, I think, be a simple flag which is set when a change occurs, and cleared when the data is polled from the UI thread, so that the notification is only sent once.

Any thoughts welcome. (And I hope you don’t mind some beginner-level questions as to how to do things, or at least what to google for. I generally resort to posting in a forum once I’ve got as far as I can by googling and searching threads, but often I don’t know the right thing to search for, or else the information I find in a post assumes that I know something I don’t, or else assumes I know where to look up some topic.)

I’m not sure what the problem is so don’t take my word for it, but my understanding is that the editor should have no knowledge of the processor data, nor get involved.

Edit: I meant that the processor should not be aware of the editor’s data.

Maybe you could check in the audio thread if there was any change in any parameter of the value tree with getRawParameterValue or if there was any change in any midi message involved, and if so update the 256 buffer.

I guess the general question is about how you communicate from the audio thread to the GUI.

getRawParameterValue() inside the audio thread gets information from the GUI to the processor.

But if e.g. a midi message to change the filter frequency comes in via MIDI, what is the right way for the GUI to be updated? I guess more generally, what is the right way for the audio thread to send messages/information to the GUI? Actually this is common thing, now I think about it, but I’m unclear as to the right way to do it. If, for example you have a waveform view in your GUI, then at some point, data about the audio going through the processor needs to go from the processor to the GUI, and I’m unclear on how this is accomplished.

A good robust way of doing this is to use a lock-free FIFO. You can also use well written lock-free state objects.

Whatever you do, don’t try and craft your own. It’s pretty fraught to get it absolutely right with lots of potential hidden gotchas. I recommend this library for providing robust solutions to pretty much any audio and message thread communication and state access situations.

If you don’t want to use this library then JUCE has some classes for supporting lock-free FIFO although the farbot one is a breeze to use.

1 Like

getRawParameterValue() gets the value of the parameter created in the AudioProcessorValueTreeState, although you may not need it, and you can update the value from the processor with AudioProcessorParameter::setValue. The editor can be notified of the modification by means of an AudioProcessorValueTreeState::Listener in the Component, and add the parameters with processor->apvts.addParameterListener(paramID, this), which can be notified in void AudioProcessorValueTreeState::Listener::parameterChanged.

So unless the calculations are too complex and heavy to be processed in real time, there would be no need for the editor to be involved.