MidiFilter template project


#1

I’ve offered to help out some people who are interested in making MIDI only plugins, and so have started work on a MidiFilter template.

Here 's the project (VC++e)… it’s not been totally tidied up yet and may involve a little tinkering in the paths etc…

In order to simplify things as much as possible (the initial request was ‘which is better for midi fx - SE or SM?’), i’ve made some ‘enhanced’ base filter classes. They may be of interest to some anyway.

[size=150]Automatic ‘Parameter’ system[/size]

First off, there’s a standard ‘Parameter’ type. Any filter parameters can be of type ‘Parameter’, which has several features:

  • Automatic mapping of float (0-1) range onto a custom range
  • Functions to retrieve the value in various forms (bool, int/float in custom range, internal 0-1 range)
  • can register with a ParameterListener to update when its internal value changes

A ‘ParameterHostingFilter’ base class can hold these parameters, and they simply need to be registered in its constructor with the id (parameter index) it will be accessed with.

A ‘ParameterHostingEditor’ will automatically listen to all registered parameters, or components can be subclassed from ParameterControl (i’ve included a Slider and Button). Parameter controls can be registered with a parameter - they’ll automatically get updated if the parameter changes, and they’ll also update the parameter directly if they are adjusted by the user (notifying the host to allow for automation).

Also, the ParameterHostingFilter has a default implementation for storing/loading patches using the registered parameters.

What this means is that if you use this Parameter system, you don’t need to worry about telling the host about your parameters, updating parameter values from host messages, updating the GUI from the filter when a parameter changes, etc… or even storing a patch. It’s all covered.

I’ve also put in program support - changing programs will store the parameters and load those from the selected program. The only problem with this though is that - because the J.A.P framework uses chunks for the preset storage (best IMO), saving an FXB from the host ignores the actual bank made up of your programs, so i’m not sure quite how useful the program feature is.

[size=150]MidiOnlyFilter simplified base[/size]

On top of all this though, there’s a further simplified ‘MidiOnlyFilter’ class, which has a default audio pass-thru implementation, and tries to hide as much of the code as possible. It’s reduced to a few simple functions to implement:

a ‘processMidi (input,output)’ gives two buffers - the input one from the processBlock function, and an output one. Once this function returns, the input is cleared, and the output is copied into it (and then the output is also cleared).

On top of this, a little ‘processMidiBuffer’ function steps thru the provided buffer (specifically the input), and calls ‘midiInputRecieved (midimessage, samplepos)’ for each message found. The default processMidi implementation simply calls this, so if the person only wanted to remap incoming midi, they’d simply need to override ‘midiInputRecieved’. Another function ‘outputMidiMessage()’ can be used to put a message onto the output buffer.

I’m going to make a few examples, and make it as foolproof as possible (along with a guide, and instructions on how to configure the directory structure to get it built right away).

I’d like to hear any comments or suggestions. I’m aware that the simplification of the MidiOnlyFilter is not particularly efficient, but i think it should be acceptable and makes things a whole lot easier for newcomers (specifically, the people i’m making this for are not programmers!)


#2

interesting stuff haydxn.
the overall construction of the classes is really good, clean and easy. from my point of view, after years that i’m trying to deal with Parameter and ParameterManager classes in different ways (remember some other post talking about this?), now i feel more confortable to have my internal structures with primitive datatypes in the plugin itself, and register them with the ParameterHost without having to deal directly with Parameters objects, instead i assume that the ParameterHost will cook them at the right time (from gui or from sequencer), then i’ll use my floats, ints and bools directly in the process loop (not having to call float x = myParameter.getInternalValue() in every processing block, and when you got 100 or 150 parameters…).
anyway if this is suitable for newcomers, you should provide at least some easy classes to do more complex transformations on the midi messages, such as a MidiMessageTranslator class that let you pass which kind of midi messages you want to keep out of the buffer or want to transform, or a MidiMessageStepper class that passed a configuration of messages, will trigger those messages when an incoming midi message is catched up.
i’m about to start an interesting project, mainly focused for linux users that lacks good tools for making music. sure this kind of midi things could be good to have in the package…


#3

Yeah, that’s kinda the plan, to provide some more midi tools. This minute i’m doing a bit to make sync easier (to save having to code calculations to determine the current bar sample position, etc…), which i’ll be following up with a step-sequence type thing. Some good ideas there, thanks.

As far as the parameters go, i’m still undecided which method i’d prefer for myself. This ‘Parameter’ system i’ve put in does take a LOT of work away from the coder, which i feel is essential for this sort of newbie project template. But also, it does make things easier anyway, in particular by negating the need to ever convert between 0-1 floats and your own preferred range. But stuff like that will always come down to personal preference i guess. I think the fact that it covers so many aspects of it automatically is the biggest benefit [the parameters are named, they are retrieved and set directly by indexing from the arrays so there’s no need for any kind of switch/if tree for set/getParameter, presets are handled totally automatically], so i’m certainly pleased with the result. And i’ll probably continue to use them myself [but then i am ultimately lazy, and like to get the hard stuff done for me by machines, even if that does mean i spend a whole weekend telling them how to do it!]

Many thanks for the comments and suggestions. Basically, i want this to be a totally easy way for newcomers (with no programming experience) to create MIDI plugins with ease. That’s gonna mean a bit more tutorial-writing too!

[and i really need to get some more done on the actual juce tutorial too… :cry: so little time!]


#4

Sounds really cool - I’ll check it out when I’ve a moment! Would you be interested in having it merged into the juce tree?


#5

Well it still needs a little work done before it’s really ready, but that’d be great. I have always felt that it would be good to have a specific parameter type built into the JuceAudioPlugin framework, so i thought i’d go ahead and make one. I hadn’t originally expected it to be quite so useful as it is though!

It’s already been updated a bit since i posted that early version (i decided to just call it ‘SmartFilter’ instead of ‘ParameterHostingFilter’ for a start!), so i’ll post an update later today/tonight. It’s still got the example public ui dimension variables, for example, which i plan on changing to use functions for neatness. I think the best thing about it all is that the user (coder) can let patches be created automatically. Even the programs feature works without any kind of intervention (but storing them would require some extra work as i described earlier… chunks/banks don’t mix unless you just save all the bank data with every patch).

Also, the ParameterControl widget base class means the user just needs to create a widget and attach it to a parameter; it will directly control the parameter’s value, recording automation automatically, and will update itself if the parameter changes. That’s a pretty big enhancement for a newbie to be presented with!

I’d greatly value your thoughts on it once you’ve given it a look. I’ll keep y’all updated with my progress. It’d be cool to have these enhancements present in the plugin framework, and also to have the simplified MidiOnlyFilter base there [which is the main bit that still needs further development - it still has some flaws but i’ll have them ironed out soon i’m sure]


#6

in my way of treating Parameters i have the same benefits too, without add complexity or calling too many functions for getting out the parameters value: it is stored directly as a member of the AudioFilter, and linked with your Parameter. when u deal with complex synths, avoiding excessive functions call inside the processing loop is a must to do, even if the compiler could optimize.


#7

I agree wholeheartedly that you should minimise function calls in the process loop. For complex synths and stuff as you describe, it would be better indeed to use variable values directly.

However, what I’m trying to do is make an easy framework for newcomers to programming (people trying to decide between SM and SE, a little too fearful of coding). When using values directly, you at some stage need to convert between host-friendly 0-1 floats and your own chosen value ranges. Either you have your variables as floats and convert them in your process, or you have your variables as you like and convert them in the set/getParameter functions… both options present a lot for a newcomer to contend with.

The base i’ve designed i’ve called ‘SmartFilter’, which should hopefully imply that it’s doing a little more work than a more streamlined pro-standard plugin, making the coder’s life a little easier.

I’d be interested to see how you’ve designed your parameter system though! :slight_smile: This is, after all, my first attempt. I guess the ‘Parameter’ could be more of a controlling/interfacing object, which could be registered with a pointer to a basic variable (using overloaded registration functions for pointers of different basic types) and then use that object as its data. A fair point indeed, and one I shall investigate.


#8

my parameter system isn’t anything complex, same as yours, lets you create parameters taking into account names, labels, units, type, range, mapping formula. You have to manually register your Parameters, passing its values as you do, but you also pass the pointer to the real memory it will be stored (&myFloatParam, or &myIntParam or whatever) in your range. all is done in the background by the ParameterManager (which you can use to get back your Parameter value in linear 0…1). then you can use directly in the process innerloop the member “myParam”, which have the value you are expecting (already mapped in [min…max] with the formula you specified, exponential, logarithmic, linear, stepped, lookup table, spline…). Also the PresetManager will link to the ParameterManager, taking snapshots of the current parameters states, and storing them into binary blob (if you got some extra binary data to append, like waveforms or the like) or xml. another thing i’m adopting from a previous framework i was using, but still isn’t ported completely to juce, is the possibility to make the ParameterManager morph between 2 states of the PresetManager, with only a few calls.


#9

perhaps something like this?

class ParameterInterface
{
public:

	enum paramType
	{
		boolParam,
		intParam,
		floatParam,
		doubleParam
	};

	ParameterInterface ();
	~ParameterInterface ();

	/** Return the parameter's host-friendly value. */
	float getHostValue ();
	/** Set the parameter's host-friendly value. */
	void setHostValue (float newValue);

	// Registering a parameter will set the parameter type...

	/** Register a boolean type parameter. */
	void registerParameter (	bool& param, 
								const String& name, 
								ParameterID paramId	);
	/** Register an integer type parameter, specifying min/max values. */
	void registerParameter (	int& param, 
								const String& name, 
								ParameterID paramId, 
								int min = 0, int max = 127	);
	/** Register a float type parameter, specifying min/max values. */
	void registerParameter (	float& param, 
								const String& name, 
								ParameterID paramId, 
								float min = 0.0f, float max = 1.0f	);
	/** Register a double type parameter, specifying min/max values. */
	void registerParameter (	double& param, 
								const String& name, 
								ParameterID paramId, 
								double min = 0.0, double max = 1.0	);


	// using these 'user get' functions would jassert the parameter
	// type is correct, before casting the variable to the type required
	// and returning it

	bool getBoolValue ();
	int getIntValue ();
	float getFloatValue ();
	double getDoubleValue ();

	void setValue (bool newValue);
	void setValue (int newValue);
	void setValue (float newValue);
	void setValue (double newValue);

private:

	double minimum;
	double maximum;
	double range;

	ParameterID id;
	void* parameter;

};

(this is not tested or anything yet, just trying to flesh out the idea.)


#10

yeah something like, more or less. i’ve got a parameter class, but it’s actually used internally by the parameter manager, in which i register my real variables, and it creates the needed Parameter class in background. it manages those parameters array by itself leaving you to deal with floats and ints and doubles variables you registered. obviously you should treat those values as read only, and if you need to modify those values (but this shouldn’t be done in the innerloops) you could already get back your Parameter object and do whatever you want with it, so your gui/host could be notified of the changes.
another thing you would think on… what to do with a Parameter that a user is tweaking (from gui), but is currently being automated by the host ? eheh


#11

Yeah, i envision this system being hidden from the user. The SmartFilter would have the registerParameter functions which would be called in the constructor for each variable intended as a parameter. This would handle the parameter interface objects itself, so the user doesn’t need to worry about them. Anywhere in the filter class, the user can simply access the variables directly.

The only place the user would actually use features of this interface would be in the editor, but the editor would also have functions to make this more seamless (e.g. getBoolValue (ParameterID id)).

As far as tweaking parameters whilst the host is automating them… i think that’s always an issue regardless of the system chosen; i guess that’s a problem that really only the host can provide solutions for.

Would you be happier with these classes if i used this solution instead? And do you think it would work in the way i’ve outlined above (e.g. bool,float,int,double as the variable types, the functions present etc…)


#12

yes, this seems straightforward. at some point, avoiding to recook back your parameter value to 0…1 format (if for some case you need it), you should also save it as member…

mmmh, i don’t know if the host could be aware if the user is touching something from your gui. A simple locking machanism should be provided
by your parameter, so if you are tweaking from your specialized controls, any other setParameter (called by the host to that parameter) should be trashed. this will provide a better user tweaking experience.

yes i would be happier and would jump here and there in the room… and yes, this should work. what i would lack using your system is the dynamic mapping formula (or lookup table for fixed states), the tweak locking mechanizm, the possibility of attaching midi CCs / midi events to control a Parameter, parameters linking, the possibility to plug the whole system in a generic derived AudioFilterBase (not using classes for midi processing only).


#13

[quote=“kraken”]
yes i would be happier and would jump here and there in the room… and yes, this should work. what i would lack using your system is the dynamic mapping formula (or lookup table for fixed states), the tweak locking mechanizm, the possibility of attaching midi CCs / midi events to control a Parameter, parameters linking, the possibility to plug the whole system in a generic derived AudioFilterBase (not using classes for midi processing only).[/quote]

do i detect a smattering of sarcasm there?

a lot of what you’ve said there i am planning, and some i don’t understand. and some of it is just plain wrong! (SmartFilter is just AudioFilterBase with the Parameter features- the MidiOnlyFilter is a further subclass of SmartFilter, taking the benefits from that, not the other way round).

Parameter linking? Dynamic Mapping Formula/fixed states lookup? Those things don’t immediately have meaning to me, so i’m curious as to what they are. All the other things are easy to implement, and i expect i shall!


#14

ok i was lacking the presence of the SmartFilter… anyway, i’m always a bit sarcastic, i’m hoping my sarcasm will serve for a continuos improvement for people being affected (and hope you don’t get angry for that :D)…
anyway the mapping formula is a is a transfer function that map linear [0…1] to [min…max] with the shape you select for it, especially useful when the parameter shouldn’t be controlled with linear value (i.e. gain or cutoff frequency).


#15

that sounds cool.

one thing i’ve been wondering about this different parameter setup:

  • the members are stored in their useful form (in user range)
  • getParameter/setParameter will handle conversion between that state and the host’s 0…1 range
  • setting a value from the editor will be done in the user range (an important part of this is that the user never has to convert between 0…1 and the user range)

Now, when the user calls an e.g. setParameterValue (ParameterID id, int newValue) function, they’ll be providing a number in their chosen range. It’s then necessary to have the value set with the host’s setParameter function (to notify the host), which involves a conversion to 0…1 (easily done there in the function) - but then the host setting function will convert that back to the original value.

This seems a little wasteful, but i guess it’s the only way of doing it. Just wondering if you’ve done it differently.


#16

i tend to avoid to set parameters in user range directly to avoid these unnecessary calculations. instead, i set parameters the same as the host do, so in 0…1 format. then if i need to visualize the value somewhere in the gui, i query the parameterManager to give me the text representation of that parameter (in user range)…
another problem in storing user range only in the Parameter class is that if you have modulators in your filter (lfo or envelopes), then in the audio process block you should precalculate your new value for the Parameter and so you have to recalculate your user ranged value (especially if you have mapped it to be exponential or logaritmic, but is simpler if you’re doing linear cause less calculations involved).
For that i have created a special type of parameter, the AutomatedParameter, in which you can plug Modulators, and instead of doing directly the mapping in user range when a setParameter is triggered, it waits the processing block, it recalculate the next value (taking into account user/host value in 0…1 format and modulator value in -1…1) and do linear interpolation between its previous and its next value during the block. this involves a lot of calculations, but works very well with fast transitions…


#17

hi,

I’ve look at that thread with great attention, but unfortunately, the link is dead: http://haydxn.net/content/code/MidiFilterTemplate/MidiTemplate.zip

I’ve also designed Yet Another Parameter System to fit my needs. There’s some stuff in it that I’m proud of, and others that just works but are a bit hacky and thus it doesn’t provide a very clean interface. It sort of growed with time, layering the features I needed when necessary instead of trying to solve the general problem upfront.

I have an Atom class to stores paramater values It owns an union of float,bool and int plus a typeid.

Then there is the Param base class which holds the name, unit, min,max,default, currentValue, paramId, midiCC. It knows how to convert values from/to [0;1] and also provide a to/fromString interface for both UI display and text serialization.

There one difference with other systems I’ve seen:
As I usually put all the DSP logic inside a separate class indepent, from the plugin, with a lot of Setter methods, instead of passing direct references to values and/or use an intrusive listener/broadcaster mechanism, I choosed to use Functors to wrap all the Setters methods.

I made special Parameter types by subclassing the base class like

  • EnumParam which is just a special kind of integer parameter

  • PowerMappingParam which has an extra middle member telling which value should be displayed when the control is at the centre position. It’s quite intuitive to appromximate log or exponential mapping like that [20,2000,20000]

however now, I’d do it differently, I think It woluld be more expressive to separate behaviour into small policies, like MappingPolicy, DisplayPolicy…

I don’t have a parameter manager though, rather a SmartPlugin which owns a ParamMap and use it to implement the get/setParameters, get/setProgram…

When I did that, I as using VSTGUI and all the UI communication was done with normalized parameters. It simplifies communication and the normalized range is useful to set the graphical position of control handles on screen.

But I think it’s also silly not to be able to use natural values inside the UI. However I still have to find a proper way to tell the UI Controls not only about the min,max and value, but also about the Parameter mapping and string conversion…
It feels like UI Controls could act like Parameters proxies, but I’d like to hear some comments about clean and elegant ways to do that.

that was a long post!

best

remy


#18

my idea is to have the Atom class as you, but instead of holding internally a value, it just “points” to a real variable defined elsewhere: this way i can have proxies over that float/double/int/… value defined as member of your synth, obviously for saving a lot of function calls in processing blocks (which also kills your plugin in debug mode) and using your values directly.

i found very useful the idea of having a parameter split in Policies (if i’ve understood correctly your idea) cause for me a parameter is some value that i use in dsp code, and usually doesn’t mean to be equal to the value the frontend would like to display, and could be different to the value the host will give me.
so in a tipical environment i’ll have to deal with 3 “languages”: normalised language (0…1) spoken with the host, denormalised language (-2pi…2pi) tipically used inside dsp code, and display language (“0.000 %”) used in UI.
a good idea would be to split this 3 layers, or policies…
the problem of UI reflecting current parameter values is a special case: i think the best approach is to have a bidirectional communication in normalised range, and if you need to display some value, just ask the underlying layer to give the representation of that value.

i would like to understand better your usage of dsp classes with functors, cause i’m just curious…


#19

well, I usually write my classes so that internal parameters are not visible. For example biquad coeffs. And most of the time I need to not only set a variable, but do some conversions to lowlevel parameters so I really need a function call and not only a variable to be set.
I’ve tried polling for dirty parameters at the beginning of each audio block, but with a growing number of params it easily gets unmanageable, I find an on-demand push message mechanism more scalable, and I think it favours code localization.

let’s say I have a Multimode filter implemented somewhere, written by me or maybe from an libary which I can’t modify.

class MultiModeFilter
{
public:
    ...
    enum Mode{Lowpass,Highpass,Bandpass};
    
    void SetCutoff(float v); 
    void SetResonance(float v); 
    void SetMode(long i);
    ...
};

I could wrap it like that:


class Wrapper
{
     ParamMap pmap;
     PowerMappingParam cutoff,
     Param resonance,
     EnumParam mode;
public:

private:
    void PublishParameters()
   {
      pmap.add(cutoff.middle(2000.f).range(20.f,20000.f)
          .name("Cutoff").unit("Hz")          
          .id(0).cc(74)
          .functor( newfun( bind1st( mem_fun(&MultiModeFilter::SetCutoff) ,&filter) )
      );
      pmap.add(resonance.name("Resonance").unit("%")
          .range(0.f,100.f)
          .functor( newfun( bind1st( mem_fun(&MultiModeFilter::SetResonance) ,&filter) )
      ); 
      pmap.add(mode
          .AddEntry("Lowpass")
          .AddEntry("Highpass")
          .AddEntry("Bandpass")
          .name("Mode")
          .functor( newfun( bind1st( mem_fun(&MultiModeFilter::SetMode) ,&filter) )
      );
   }
};

the functor syntax is a bit verbose, but it add some extra flexibility, like being able to bind parameters to function arguments. like the this pointer in most cases, but it can also be and index for a function having a (long index,float v) signature.

newfun act as polymorphic template factory
I think a simpler syntax is possible but each time I tried I ended with lots of linking errors, so for now I live with it. It’s a little tricky as there’s a mix of templates and inheritance.

I got my inspiration from boost::any boost::function and boost::signals but as I am not a template meta programing expert, It doesn’t go very far.

I’ve thought about using boost in the first place but I though it was a bit overkill for my needs.

There are many things that could be improved. Most of them are about modularizing the usage of the Param class in order to favour parametrization with small policies or structures over inheritance.

For example It would be cleaner to pass a ParamDescription structure to initialise the parameters, have a separate Mapping Policy, have multiple callback slots…


#20

yeah modifying more than one internal value (per set method call) when a single parameter is changed is something useful. the idea of having setters for all the internal values seems reasonable, and the functor method as you used here is pretty straightforward.
i would like to ask people here to expose their thoughts about this, cause it’s a very interesting point in an audio application in my opinion, and would like to see some sort of draft of parameter system to be really integrated with juce, its widgets and the juce plugin… maybe we can propose something to jules (if he really accepts idea from outside) ?