MarC’s solution is very thorough and flexible and well worth a look.
I am currently in the process of updating my old plugins, trying to unify them and improve the coding style. In a somewhat similar fashion to MarC I have also created a parameter class, it doesn’t yet deal with non-linear mappings but does have some other advantages. I have nearly completed this procedure for my Tremolo demo app which you might want to take a look at.
It uses juce::Value’s internally so parameters can easily be connected to UI objects. To avoid the Value::Listener callbacks interfering with the audio thread I have created a small parameter-queue type class that gets added to from the message thread and then dispatched from the audio thread. This does use a CriticalSection for adding and removing values to/from the array but I don’t think this will be an issue for a relatively small number of parameters and if they are not being thrashed. The lock is not held for very long. In any case I have thought about changing this to a lock-free, AbstractFifo based queue which would avoid the locking all together.
Because the Value’s are encapsulated by the PluginParameter class, creating and managing a set of parameters is almost entirely automated. There is a config page with a few arrays that specify the parameter’s names, values etc. but after that they are all managed in loops. Adding a parameter is as simple as defining it in the “Common.h” file.
In your editor you can then simply get a reference to the Value object and hook it up to sliders etc. to automatically control the parameters. Changing the parameter will add it to the parameter queue and then you can respond to it properly on the audio thread via the parameterUpdated callback if you need to update internal variables such as phase increments etc. all in a thread safe way. Obviously its not wise to do anything too time consuming in here, the filling of buffers in the Tremolo demo is borderline and could be implemented on another thread.
How you update your UI will depend on your exact needs but generally I use Values (and their internal ChangeBroadcaster/Listener implementations) to update parameters and Timers to update constantly changing things like scopes or meters.
Some improvements will need to be made to the JUCE wrappers and AudioProcessor class to properly represent parameter ranges and values in the hosts and this is discussed here.
Hope this offers some potential ideas.