OwnedArray or ReferenceCountedArray, which should I be using?


#1

Hi JUCE folk, 

I have a bit of a question in regards to OwnedArrays and ReferenceCountedArrays/Objects.

I am trying to abstract the various components of my synth plugin into "module" base classes. So for instance my filters and oscillators will all be a subclass of a SynthAudioModule class and my LFO's and ADSR's will be subclasses of a SynthModModule class. 

The SynthAudioModule and SynthModModule will then be a subclass of SynthModule and my synth is a derived class of the JUCE Synthesizer class and is also derived from a class I am implementing called SynthModuleHost. 

Im trying to get my head around RAII techniques and the best ways of handling a dynamic array of objects. 

Specifically i want the SynthModuleHost class to hold an array of object pointers to SynthModules.

I know the number of indivual modules(oscillators, filters etc.) in my synthesizer but obviously want the SynthModuleHost class to be reuseable for Synth plugins with more or fewer components/modules. 

So to the meat of my question, 

How would I go about adding in modules to the array of SynthModule pointers in my SynthModuleHost class ? 

My idea was to do this with an OwnedArray like so: OwnedArray<SynthModule> synthModules;

And then in the counstructor of my synth call the function addSynthModule(Int index, SynthModule* module) which is declared in the SynthModuleHost class and adds a SynthModule pointer to the OwnedArray at a specified index (defined my a modules enum).

 

The modules will have various functions allowing audio modules to be connected together within the Synthesizer object (oscillator to filter etc.) and modulation modules to be connected to audio module parameters. So I'm unsure as to whether an OwnedArray is the best thing to use as modules within the OwnedArray may need to be accessed during the Synth's processBlock(wondering about speed accessing the array elements). 

Jules has kindly mentioned in this thread that the OwnedArray is capable of returning its elements pretty quickly so its probably not an issue. 

http://www.juce.com/forum/topic/how-effecient-are-arrays/ownedarrays

 

On the other hand would more learned JUCE coders advise to just define an array of SynthModule pointers in my own Synthesizer class as define the size of the array upfront ? 

 

Apologies for the long winded explanation, any help with a bit of a design decision here will be greatly appreciated. 


#2

The basic rule of thumb would be to use reference counted objects when and object is shared and an OwnedArray for a collection of like objects.

In other words, if the same instance of a module was used by multiple clients, a reference counted object would work well. The clients could release the object in any order and the object would self delete.

One of the simplest examples of RAII is ScopedPointer (simple in concept, not so simple in robust implementation - but that is another story).

Instead of:

Obj* ptr = new Obj();
<do stuff>
delete ptr;

It becomes:

ScopedPointer<Obj> ptr = new Obj();
<do stuff>

It doesn't matter if you have multiple paths out of the function, or even if you throw an exception - the Obj will get deleted with the ScopedPointer goes out of scope (hence the name ;-)

OwnedArray is sort of ScopedPointer meets Array. Useful, especially in cases where things are getting added and dropped. But when I read stuff like "from an enum" or "specific index" it sounds like the usage might be forced.

In other words, if you are counting on something being at a specific index the 'array' part really isn't doing much for you. And, if the services are different enough to warrant fixed indexes, maybe they are not really 'like' enough to be put in a container object.

What is not clear to me from your post is what problem you are really trying to solve. If services are loaded and unloaded dynamically, that would be one thing. But if you need all the modules, why not just make them member ScopedPointers in your overarcing synth class?

Good Luck!


#3

Hey jfitzpat, 

 

Many thanks for the well thought out advice. I had a handle on smart pointers and the like and the OwnedArray taking ownership of its objects but I was a little lost on the ReferenceCountedArray and its intended useage. Many thanks for clarifying that a little more for me. 

I think perhaps your right, the modules probably don't need to be held in any kind of container and I'm probably over complicating things by doing this. Your idea of just adding them as straight members within my Synth class is a fair point. 

 I guess really part of my concern was also about having lots of "module" instances. So for each synth voice there is 2 filters, 3 oscillators etc. etc. 

I'm really trying to work out the best way of chaining all my modules together and designing an effective modulation matrix type system (oscillator 1 to filer 1 or 2, lfo to filter 1 cutoff etc.). I haven't done much experimenting with this yet and want to consider cpu useage and to me logically holding the modules within the Synthesizer derived class makes the most logical sense but maybe its not the way to go ? 

I've got all my filters and oscillators etc coded up and sounding decent but thats because my focus for the last 6 months has been DSP, not got a whole lot under my belt in regards to synth/plugin architecture yet. 

 

Thanks again for all your help. 

If anyone else has any comments / advice on this I'd be really interested/grateful to read. 

 

Josh 


#4

Just out of interest from reading through some other threads, Would anyone else suggest that I should be using some sort of audio processor graph to chain together the various modules / processors within my Synth ? 

This is starting to push the limits of my JUCE / C++ abilities


#5

Horaa, 

 

You advice was spot on my friend so thanks very much. 

 

A mixture of your approach and using and audio processor graph seems to have been the best way around dealing with a "modular" structure and its all starting to come together. 

 

Many thanks for the help.