Friday, January 19, 2007

RFC: MetaFFRend / FF meta-plugin authoring

Request for Comments

OK, now that FFRend 1.3 is out the door, it's time to get serious about MetaFFRend. I hope to spark a bit of pre-coding discussion here, so that once the coding starts we can get it mostly right the first time. Here are some issues that have been bumping around in my head.


This is a Request For Comments regarding the VJ Forums proposal to turn FFRend into a plugin-authoring tool, somewhat similar to Pete Warden's FreeChain application. The idea is basically to export a FFRend project as a Freeframe plugin. This "meta-plugin" could be loaded into a Freeframe host software, and would behave just as if you were running the equivalent project in FFRend.

The meta-plugin may contain links to the plugins it requires, or alternatively, the plugins may be "bundled" into the meta-plugin. In the latter case, it's easier to distribute the meta-plugin, because there's no dependence on external files. Specifically, a meta-plugin will consist of FFRend's rendering engine, links to (or compressed copies of) the necessary plugins, and the project data (parameter settings, automations, etc).

Linked plugins and bundling

A meta-plugin contains links to other plugins. This works fine as long as the meta-plugin stays on the PC where it was created, but as soon as you distribute it, you have problems. There's very little chance that the absolute paths will happen to be correct on someone else's PC. IMO the solution has two parts. The first part is, the meta-plugin should search for its plugins in an intelligent way, e.g. the following steps, in order:

1) Try the absolute paths from the project data first.
2) Then look for an INI file, e.g. My Documents\FFRend\MetaFFRend.ini, which could contain a plugin path, e.g. PluginPath=C:\whatever;C:\foo;
3) Next, try My Documents\FFRend\Plugins.
4) Finally, look in the same folder the meta-plugin was loaded from.
5) If none of the above works, add an error message to a log file, e.g. My Documents\FFRend\MetaFFRend.log

The second part of the solution is, there should be an option to bundle all the plugins that the meta-plugin requires into the meta-plugin. This could make the meta-plugin quite large, so it probably makes sense to compress the plugins, e.g. using zlib which is open-source. The first time you load a bundled meta-plugin, it will unpack itself to the folder specified in MetaFFRend.ini, or if that fails, to My Documents\FFRend\Plugins. On subsequent loads it will detect that the plugins are already there, and skip the unpack. This means the meta-plugin could be slow to load the first time, but subsequent loads will be fast.


Like any other FF plugin, a meta-plugin can expose parameters to the host. These parameters are referred to as "meta-parameters". The consensus on this forum was that each meta-parameter should be able to control multiple things. When I say "things" I mean control targets; the potential targets in FFRend are not only FF parameters, but also modulator settings (frequency, waveform, etc.), bypass, and other properties. The reason why this is such an important capability, is that many hosts severely limit the number of FF parameters a plugin can expose. By allowing "grouping", the meta-plugin can make better use of a limited number of parameters.

Anatomy of a Meta-Plugin

The base MetaFFRend DLL (i.e. without any project data embedded in it) lives in the same folder as FFRend. It has a tag at the end of the DLL file, consisting of 16 characters: BASEMETAFFREND01

When FFRend creates a new meta-plugin, it starts with the base plugin. It removes the end-of-DLL tag and replaces it with the project data, followed by a different tag, also 16 bytes, like so:

char Id[10]; // must contain characters MetaFFRend
WORD Version; // version number
DWORD DataOfs; // offset of project data from end of DLL file

What's nice about this scheme is it's easy to read the project data from the DLL: you just read the last 16 bytes, and now you know whether it's a valid meta-plugin, and if so, where to find the project data. Project data is a CArchive, and starts with a CMetaPlugin header:

CString m_PluginName; // plugin name, 16 characters maximum
CString m_Description; // a description of the plugin
CString m_AboutText; // author and license information
int m_BitDepthMask; // mask of supported bit depths
int m_PluginMajorVersion; // number before decimal point
int m_PluginMinorVersion; // number after decimal point
int m_NumInputFrames; // number of input frames plugin expects
CDWordArray m_InpTargetIdx; // for each input frame, index of target sub-plugin, or -1 for default
bool m_IsBundled; // true if sub-plugins are bundled into meta-plugin
bool m_IsCompressed; // true if bundled sub-plugins are compressed
CMetaParamArray m_Param; // information about each meta-parameter

class CMetaParam:

CString m_ParamName; // parameter name, 16 characters maximum
float m_Val; // parameter's initial value
CMetaParamTargetArray m_Target; // array of parameter targets

class CMetaParamTarget:

int m_PlugIdx; // index of destination plugin, or -1 for misc. property
int m_ParamIdx; // index of destination parameter, or -1 for plugin property
int m_PropIdx; // index of property
float m_RangeStart; // start of parameter range
float m_RangeEnd; // end of parameter range

No comments: