<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>  CreatingPlugins &lt; Cinelerra &lt; TWiki</title>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />

<link rel="alternate" type="application/rss+xml" title="RSS Feed" href="http://www.ftconsult.com/twiki/bin/view/Cinelerra/WebRss?skin=rss&contenttype=text/xml" />
<!-- <base href="CreatingPlugins" /> -->
<style type="text/css" media="all">
	/* Default TWiki layout */
	@import url('../../../pub/TWiki/PatternSkin/layout.css');
	/* Default TWiki style */
	@import url('../../../pub/TWiki/PatternSkin/style.css');
	/* Custom overriding layout per web or per topic */
	@import url('http://www.ftconsult.com/twiki/bin/view/Cinelerra/%USERLAYOUTURL%');
	/* Custom overriding style per web or per topic */
	@import url('http://www.ftconsult.com/twiki/bin/view/Cinelerra/%USERSTYLEURL%');
	.twikiToc li {
		list-style-image:url('../../../pub/TWiki/PatternSkin/i_arrow_down.gif');
	}	        
	.twikiWebIndicator {
		background-color:#D0D0D0;
	}
</style>
<style type="text/css" media="all"></style>
<script type="text/javascript">
<!-- HIDE
	function initPage() { }
-->
</script>
</head>
<body class="twikiViewPage" onload="initPage()"><a name="PageTop"></a>
<div class="twikiHidden"><a href="#Content">Skip to topic</a> | <a href="#PageBottom">Skip to bottom</a><hr /></div><div class="twikiTopBar"><div class="twikiTopBarContents"><form name="top" action="CreatingPlugins"> <div class="twikiLeft">
<a href="http://twiki.org/"><img src="../../../pub/TWiki/TWikiLogos/twikiRobot46x50.gif" border="0" alt="Home"/></a>
</div>
<div class="twikiRight twikiSearchBox">
<table border="0" cellpadding="0" cellspacing="0">
<tr>
<td><label for="go">Jump: </label><input type="text" id="go" name="topic" size="16" /></td>
</tr>
</table>
</div>
</form></div></div><div class="twikiMiddleContainer"><div class="twikiLeftBar"><div class="twikiWebIndicator"><b>Cinelerra</b></div>
<div class="twikiLeftBarContents"><form name="main" action="CreatingPlugins"> 
<ul>
<li> <b>Cinelerra Web</b>
</li>
<li> <a class="twikiLink" href="WebHome">Cinelerra Web Home</a>
</li>
<li> <a class="twikiLink" href="WebChanges">Changes</a> 
</li>
<li> <a class="twikiLink" href="WebIndex">Index</a>
</li>
<li> <a class="twikiLink" href="WebSearch">Search</a>
</li>
</ul>
<hr />
<ul>
<li> <strong>Webs</strong>
<ul>
<li> <a class="twikiLink" href="WebHome">Cinelerra</a>
</li>
<li> <a class="twikiLink" href="../Espanol/WebHome">Espanol</a>
</li>
<li> <a class="twikiLink" href="../Francais/WebHome">Francais</a>
</li>
<li> <a class="twikiLink" href="../Italiano/WebHome">Italiano</a>
</li>
<li> <a class="twikiLink" href="../Main/WebHome">Main</a>
</li>
<li> <a class="twikiLink" href="../Sandbox/WebHome">Sandbox</a>
</li>
<li> <a class="twikiLink" href="../Slovenian/WebHome">Slovenian</a>
</li>
<li> <a class="twikiLink" href="../TWiki/WebHome">TWiki</a>
</li>
</ul>
</li>
</ul>
<div class="twikiLeftBarPersonal">
<p />
<ul>
<li> <strong>My links</strong>
</li>
<li> <a class="twikiLink" href="../Main/AeliotBoswell">My home page</a>
</li>
<li> <a href="http://www.ftconsult.com/twiki/bin/search/Codev/?search=InterestedParties.*AeliotBoswell&regex=on" target="_top"><img src="../../../pub/TWiki/TWikiDocGraphics/stargold.gif" style="width:16px; height:16px; border:0px;" alt="Show me topics of interest" /></a>
</li>
</ul>
<div class="twikiSmall"><a href="http://www.ftconsult.com/twiki/bin/edit/Main/TWikiGuestLeftBar?t=20051021151405">edit</a></div>
<p />
</div>
</form></div></div><div class="twikiMain"><div class="twikiToolBar"><div>
<ul>
<li> <a href="http://www.ftconsult.com/twiki/bin/edit/Cinelerra/CreatingPlugins?t=1129907644"><b>Edit</b></a>
</li>
<li> <a href="http://www.ftconsult.com/twiki/bin/attach/Cinelerra/CreatingPlugins">Attach</a>
</li>
<li> <a href="http://www.ftconsult.com/twiki/bin/view/Cinelerra/CreatingPlugins?skin=print.pattern">Printable</a>
</li>
</ul>
</div><div class="twikiRevInfo"><span class="twikiGrayText"><span class="twikiToolbarElem">Cinelerra.CreatingPlugins</span><span class="twikiToolbarElem">r1.1 - 18 Dec 2003 - 21:43 - <a class="twikiLink" href="../Main/AlexFerrer">AlexFerrer</a></span><span class="twikiToolbarElem"><a href="#TopicEnd">topic&nbsp;end</a></span></span></div></div>
<div class="twikiHidden"><hr /></div><a name="Content"> </a><div class="twikiHidden">Start of topic | <a href="#Actions">Skip to actions</a><hr /></div>
<div class="twikiTopic">
<h3><a name="Creating_Plugins"> </a><a name="_Creating_Plugins_"> </a> <a class="twikiLink" href="CreatingPlugins">Creating Plugins</a> </h3>
<p />
The plugin API in Cinelerra dates back to 1997, before the LADSPA and before VST became popular. It's fundamentally the same as it was in 1997, with minor modifications to handle keyframes and GUI feedback. Unfortunately, the GUI is not abstracted from the programmer. This allows the programmer to use whatever toolkit they want and allows more flexibility in appearance but it costs more.
<p />
There are several types of plugins, each with a common procedure of implementation and specific changes for that particular type. The easiest way to implement a plugin is to take the simplest existing one out of the group and rename the symbols.
<p />
<div class="twikiToc">
<ul>
<li> <a href="#Creating_Plugins">Creating Plugins</a>
<ul>
<li> <a href="#COMMON_PROCEDURES">COMMON PROCEDURES</a>
</li>
<li> <a href="#THE_PROCESSING_OBJECT">THE PROCESSING OBJECT</a>
</li>
<li> <a href="#THE_CONFIGURATION_OBJECT">THE CONFIGURATION OBJECT</a>
</li>
<li> <a href="#NONREALTIME_PLUGINS">NONREALTIME PLUGINS</a>
</li>
<li> <a href="#PLUGIN_QUERIES">PLUGIN QUERIES</a>
</li>
</ul>
</li>
</ul>
</div> 
<p />
<h4><a name="COMMON_PROCEDURES"> </a> COMMON PROCEDURES </h4>
<p />
<p />
All plugins inherit from a derivative of <span class="twikiNewLink" style="background : #FFFFCE;"><font color="#0000FF">PluginClient</font><a href="http://www.ftconsult.com/twiki/bin/edit/Cinelerra/PluginClient?topicparent=Cinelerra.CreatingPlugins"><sup>?</sup></a></span>. This derivative implements most of the required methods in <span class="twikiNewLink" style="background : #FFFFCE;"><font color="#0000FF">PluginClient</font><a href="http://www.ftconsult.com/twiki/bin/edit/Cinelerra/PluginClient?topicparent=Cinelerra.CreatingPlugins"><sup>?</sup></a></span>, but users must still define methods for <span class="twikiNewLink" style="background : #FFFFCE;"><font color="#0000FF">PluginClient</font><a href="http://www.ftconsult.com/twiki/bin/edit/Cinelerra/PluginClient?topicparent=Cinelerra.CreatingPlugins"><sup>?</sup></a></span>. The most commonly used methods are already implemented in macros.
<p />
The files they include depend on the plugin type. Audio plugins include pluginaclient.h and video plugins include pluginvclient.h. They inherit <span class="twikiNewLink" style="background : #FFFFCE;"><font color="#0000FF">PluginAClient</font><a href="http://www.ftconsult.com/twiki/bin/edit/Cinelerra/PluginAClient?topicparent=Cinelerra.CreatingPlugins"><sup>?</sup></a></span> and <span class="twikiNewLink" style="background : #FFFFCE;"><font color="#0000FF">PluginVClient</font><a href="http://www.ftconsult.com/twiki/bin/edit/Cinelerra/PluginVClient?topicparent=Cinelerra.CreatingPlugins"><sup>?</sup></a></span> respectively.
<p />
Another thing all plugins do is define at least three objects:
<p />
    * Processing object - Contains pointers to all the other objects and performs the signal processing. This object contains a number of queries to identify itself and is the object you register to register the plugin.
    * User interface object - This is defined according to the programmer's discretion. It can either use Cinelerra's toolkit or another toolkit. It shows data on the screen and collects parameters from the user.
<p />
      Using Cinelerra's toolkit, the only user interface object a developer needs to worry about is the Window. The window has pointers to a number of widgets, a few initialization methods, and a back pointer to the plugin's processing object. The documentation refers to usage of Cinelerra's toolkit.
<p />
      Depending on the user interface toolkit, a user interface thread may be created to run the user interface asynchronous of everything else. Synchronizing the user interface to changes in keyframes is the most complicated aspect of the plugin, so the user interface thread and object are heavily supported by macros if you use Cinelerra's toolkit.
* Configuration object - This stores the user parameters and always needs interpolation, copying, and comparison functions. The plugin client automatically calls configuration methods to interpolate keyframes.
<p />
<ul>
<li> THE PROCESSING OBJECT:
</li>
<li> THE CONFIGURATION OBJECT:
</li>
<li> THE USER INTERFACE OBJECT:
</li>
</ul>
<p />
<h4><a name="THE_PROCESSING_OBJECT"> </a> THE PROCESSING OBJECT </h4>
<p />
The processing object should inherit from the intended <span class="twikiNewLink" style="background : #FFFFCE;"><font color="#0000FF">PluginClient</font><a href="http://www.ftconsult.com/twiki/bin/edit/Cinelerra/PluginClient?topicparent=Cinelerra.CreatingPlugins"><sup>?</sup></a></span> derivative. Its constructor should take a <span class="twikiNewLink" style="background : #FFFFCE;"><font color="#0000FF">PluginServer</font><a href="http://www.ftconsult.com/twiki/bin/edit/Cinelerra/PluginServer?topicparent=Cinelerra.CreatingPlugins"><sup>?</sup></a></span> argument.
<p />
     <span class="twikiNewLink" style="background : #FFFFCE;"><font color="#0000FF">MyPlugin</font><a href="http://www.ftconsult.com/twiki/bin/edit/Cinelerra/MyPlugin?topicparent=Cinelerra.CreatingPlugins"><sup>?</sup></a></span>(<span class="twikiNewLink" style="background : #FFFFCE;"><font color="#0000FF">PluginServer</font><a href="http://www.ftconsult.com/twiki/bin/edit/Cinelerra/PluginServer?topicparent=Cinelerra.CreatingPlugins"><sup>?</sup></a></span> *server);
<p />
<p />
In the implementation, the plugin must contain a registration line with the name of the processing object like
<p />
     REGISTER_PLUGIN(<span class="twikiNewLink" style="background : #FFFFCE;"><font color="#0000FF">MyPlugin</font><a href="http://www.ftconsult.com/twiki/bin/edit/Cinelerra/MyPlugin?topicparent=Cinelerra.CreatingPlugins"><sup>?</sup></a></span>)
<p />
<p />
The constructor should contain
<p />
     PLUGIN_CONSTRUCTOR_MACRO
<p />
<p />
to initialize the most common variables.
<p />
The processing object should have a destructor containing
<p />
     PLUGIN_DESTRUCTOR_MACRO
<p />
<p />
to delete the most common variables.
<p />
Another function which is useful but not mandatory is
<p />
     int is_multichannel();
<p />
<p />
It should return 1 if one instance of the plugin handles multiple channels simultaneously or 0 if one instance of the plugin only handles one channel. The default is 0 if it is omitted. Multichannel plugins should refer to the value of <span class="twikiNewLink" style="background : #FFFFCE;"><font color="#0000FF">PluginClient</font><a href="http://www.ftconsult.com/twiki/bin/edit/Cinelerra/PluginClient?topicparent=Cinelerra.CreatingPlugins"><sup>?</sup></a></span>::total_in_buffers to determine the number of channels.
<p />
To simplify the implementation of realtime plugins, a macro for commonly used members should be put in the class header, taking the configuration object and user interface thread object as arguments. This is only useful for realtime plugins. Fortunately, nonrealtime plugins are simpler.
<p />
     PLUGIN_CLASS_MEMBERS(config_name, thread_name)
<p />
<p />
Many other members may be defined in the processing object, depending on the plugin type. The commonly used members in PLUGIN_CLASS_MEMBERS are described below. Not all these members are used in nonrealtime plugins.
<p />
    * int load_configuration();
<p />
      Loads the configuration based on surrounding keyframes and current position. The class definition should contain
<p />
          LOAD_CONFIGURATION_MACRO(plugin_class, config_class)
<p />
<p />
      to implement load_configuration. This stores whatever the current configuration is inside the plugin's configuration object. The plugin's configuration object is always called config when using PLUGIN_CLASS_MEMBERS.
    * VFrame* new_picon();
<p />
      Creates a picon for display in the resource window. Use
<p />
          #include "picon_png.h"
          NEW_PICON_MACRO(plugin_class)
<p />
<p />
      to implement new_picon. In addition, the user should create a picon_png.h header file from a PNG image using pngtoh. pngtoh is compiled in the guicast/ARCH directory.
<p />
      The source PNG image should be called picon.png and can be any format supported by PNG.
    * char* plugin_title();
<p />
      Returns a text string identifying the plugin in the resource window. The string has to be unique.
    * void update_gui();
<p />
      Should first load the configuration and then redraw the GUI with the new parameters. All the plugins using <span class="twikiNewLink" style="background : #FFFFCE;"><font color="#0000FF">GuiCast</font><a href="http://www.ftconsult.com/twiki/bin/edit/Cinelerra/GuiCast?topicparent=Cinelerra.CreatingPlugins"><sup>?</sup></a></span> have a format like
<p />
          void <span class="twikiNewLink" style="background : #FFFFCE;"><font color="#0000FF">MyPlugin</font><a href="http://www.ftconsult.com/twiki/bin/edit/Cinelerra/MyPlugin?topicparent=Cinelerra.CreatingPlugins"><sup>?</sup></a></span>::update_gui()
          {
             if(thread)
             {
                load_configuration();
                thread-&gt;window-&gt;lock_window();
          // update widgets here
                thread-&gt;window-&gt;unlock_window();
             }
          }
<p />
<p />
      to handle concurrency and conditions of no GUI.
    * int show_gui();
<p />
      Instantiate the GUI and switch the plugin to GUI mode. This is implemented with
<p />
          SHOW_GUI_MACRO(plugin_class, thread_class)
<p />
<p />
    * int set_string();
<p />
      Changes the title of the GUI window to a certain string. This is implemented with
<p />
          SET_STRING_MACRO(plugin_class)
<p />
<p />
    * void raise_window();
<p />
      Raises the GUI window to the top of the stack. This is implemented with
<p />
          RAISE_WINDOW_MACRO(plugin_class)
<p />
<p />
<h4><a name="THE_CONFIGURATION_OBJECT"> </a> THE CONFIGURATION OBJECT </h4>
<p />
The configuration object is critical for GUI updates, signal processing, and default settings in realtime plugins. Be aware it is not used in nonrealtime plugins. The configuration object inherits from nothing and has no dependancies. It's merely a class containing three functions and variables specific to the plugin's parameters.
<p />
Usually the configuration object starts with the name of the plugin followed by Config.
<p />
     class <span class="twikiNewLink" style="background : #FFFFCE;"><font color="#0000FF">MyPluginConfig</font><a href="http://www.ftconsult.com/twiki/bin/edit/Cinelerra/MyPluginConfig?topicparent=Cinelerra.CreatingPlugins"><sup>?</sup></a></span>
     {
     public:
        <span class="twikiNewLink" style="background : #FFFFCE;"><font color="#0000FF">MyPluginConfig</font><a href="http://www.ftconsult.com/twiki/bin/edit/Cinelerra/MyPluginConfig?topicparent=Cinelerra.CreatingPlugins"><sup>?</sup></a></span>();
<p />
<p />
Following the name of the configuration class, we put the three required functions and the configuration variables.
<p />
        int equivalent(<span class="twikiNewLink" style="background : #FFFFCE;"><font color="#0000FF">MyPluginConfig</font><a href="http://www.ftconsult.com/twiki/bin/edit/Cinelerra/MyPluginConfig?topicparent=Cinelerra.CreatingPlugins"><sup>?</sup></a></span> &amp;that);
        void copy_from(<span class="twikiNewLink" style="background : #FFFFCE;"><font color="#0000FF">MyPluginConfig</font><a href="http://www.ftconsult.com/twiki/bin/edit/Cinelerra/MyPluginConfig?topicparent=Cinelerra.CreatingPlugins"><sup>?</sup></a></span> &amp;that);
        void interpolate(<span class="twikiNewLink" style="background : #FFFFCE;"><font color="#0000FF">MyPluginConfig</font><a href="http://www.ftconsult.com/twiki/bin/edit/Cinelerra/MyPluginConfig?topicparent=Cinelerra.CreatingPlugins"><sup>?</sup></a></span> &amp;prev,
           <span class="twikiNewLink" style="background : #FFFFCE;"><font color="#0000FF">MyPluginConfig</font><a href="http://www.ftconsult.com/twiki/bin/edit/Cinelerra/MyPluginConfig?topicparent=Cinelerra.CreatingPlugins"><sup>?</sup></a></span> &amp;next,
           int64_t prev_position,
           int64_t next_position,
           int64_t current_position);
<p />
<p />
<p />
        float parameter1;
        float parameter2;
        int parameter3;
     };
<p />
<p />
<p />
Now you must define the three functions. Equivalent is called by LOAD_CONFIGURATION_MACRO to get the return value. That is all it's used for and if you don't care about load_configuration's return value, you can leave this function empty. It normally returns 1 if the argument's variables have the same values as the local variables.
<p />
Then there's copy_from which transfers the configuration values from the argument to the local variables. This is once again used in LOAD_CONFIGURATION_MACRO to store configurations in temporaries. Once LOAD_CONFIGURATION_MACRO has replicated the configuration, it loads a second configuration. Then it interpolates the two configurations to get the current configuration. The interpolation function performs the interpolation and stores the result in the local variables.
<p />
Normally the interpolate function calculates a previous and next fraction, using the arguments.
<p />
     void <span class="twikiNewLink" style="background : #FFFFCE;"><font color="#0000FF">MyPluginConfig</font><a href="http://www.ftconsult.com/twiki/bin/edit/Cinelerra/MyPluginConfig?topicparent=Cinelerra.CreatingPlugins"><sup>?</sup></a></span>::interpolate(<span class="twikiNewLink" style="background : #FFFFCE;"><font color="#0000FF">MyPluginConfig</font><a href="http://www.ftconsult.com/twiki/bin/edit/Cinelerra/MyPluginConfig?topicparent=Cinelerra.CreatingPlugins"><sup>?</sup></a></span> &amp;prev,
           <span class="twikiNewLink" style="background : #FFFFCE;"><font color="#0000FF">MyPluginConfig</font><a href="http://www.ftconsult.com/twiki/bin/edit/Cinelerra/MyPluginConfig?topicparent=Cinelerra.CreatingPlugins"><sup>?</sup></a></span> &amp;next,
           int64_t prev_position,
           int64_t next_position,
           int64_t current_position)
     {
        double next_scale = (double)(current_position - prev_position) / (next_position - prev_position);
        double prev_scale = (double)(next_position - current_position) / (next_position - prev_position);
<p />
<p />
Then the scales are applied to the previous and next configuration object to yield the current values.
<p />
<p />
        this-&gt;parameter1 = (float)(prev.parameter1 * prev_scale + next.parameter1 * next_scale);
        this-&gt;parameter2 = (float)(prev.parameter2 * prev_scale + next.parameter2 * next_scale);
        this-&gt;parameter3 = (int)(prev.parameter3 * prev_scale + next.parameter3 * next_scale);
     }
<p />
<p />
<p />
Alternatively you can copy the values from the previous configuration argument for no interpolation.
<p />
This usage is the same in audio and video plugins. In video playback, the interpolation function is called for every frame, yielding smooth interpolation. In audio playback, the interpolation function is called only once for every console fragment and once every time the insertion point moves. This is good enough for updating the GUI while selecting regions on the timeline but it may not be accurate enough for really smooth rendering of the effect.
<p />
For really smooth rendering of audio, you can still use load_configuration when updating the GUI. For process_realtime; however, ignore load_configuration and write your own interpolation routine which loads all the keyframes in a console fragment and interpolates every sample. This would be really slow and hard to debug, yielding improvement which may not be audible. Then of course, every century has its set of wierdos.
<p />
An easier way to get smoother interpolation is to reduce the console fragment to 1 sample. This would have to be rendered and played back in a separate program of course. The Linux sound driver can't play fragments of 1 sample.
<p />
Node:THE USER INTERFACE OBJECT, Previous:THE CONFIGURATION OBJECT, Up:COMMON PROCEDURES
THE USER INTERFACE OBJECT
<p />
The user interface object at the very least consists of a pointer to a window and pointers to a set of widgets. Using Cinelerra's toolkit, it consists of a BCWindow derivative and a Thread derivative. The Thread derivative is declared in the plugin header using
<p />
     PLUGIN_THREAD_HEADER(plugin_class, thread_class, window_class)
<p />
<p />
Then it is defined using
<p />
     PLUGIN_THREAD_OBJECT(plugin_class, thread_class, window_class)
<p />
<p />
This in combination with the SHOW_GUI macro does all the work in instantiating the Window class. This is used in realtime plugins but not in nonrealtime plugins. Nonrealtime plugins create and destroy their GUI in get_parameters and there's no thread.
<p />
Now the window class must be declared in the plugin header. It's easiest to implement the window by copying an existing plugin and renaming the symbols. The following is an outline of what happens. The plugin header must declare the window's constructor using the appropriate arguments.
<p />
<p />
     #include "guicast.h"
<p />
     class <span class="twikiNewLink" style="background : #FFFFCE;"><font color="#0000FF">MyPluginWindow</font><a href="http://www.ftconsult.com/twiki/bin/edit/Cinelerra/MyPluginWindow?topicparent=Cinelerra.CreatingPlugins"><sup>?</sup></a></span> : public BC_Window
     {
     public:
        <span class="twikiNewLink" style="background : #FFFFCE;"><font color="#0000FF">MyPluginWindow</font><a href="http://www.ftconsult.com/twiki/bin/edit/Cinelerra/MyPluginWindow?topicparent=Cinelerra.CreatingPlugins"><sup>?</sup></a></span>(<span class="twikiNewLink" style="background : #FFFFCE;"><font color="#0000FF">MyPluginMain</font><a href="http://www.ftconsult.com/twiki/bin/edit/Cinelerra/MyPluginMain?topicparent=Cinelerra.CreatingPlugins"><sup>?</sup></a></span> *plugin, int x, int y);
<p />
<p />
<p />
This becomes a window on the screen, positioned at x and y.
<p />
It needs two methods
<p />
        int create_objects();
        int close_event();
<p />
<p />
and a back pointer to the plugin
<p />
        <span class="twikiNewLink" style="background : #FFFFCE;"><font color="#0000FF">MyPlugin</font><a href="http://www.ftconsult.com/twiki/bin/edit/Cinelerra/MyPlugin?topicparent=Cinelerra.CreatingPlugins"><sup>?</sup></a></span> *plugin;
<p />
<p />
The constructor's definition should contain extents and flags causing the window to be hidden when first created. The create_objects member puts widgets in the window according to <span class="twikiNewLink" style="background : #FFFFCE;"><font color="#0000FF">GuiCast</font><a href="http://www.ftconsult.com/twiki/bin/edit/Cinelerra/GuiCast?topicparent=Cinelerra.CreatingPlugins"><sup>?</sup></a></span>'s syntax. A pointer to each widget which is to be synchronized to a keyframe is stored in the window class. These are updated in the update_gui function you earlier defined for the plugin. The widgets are usually derivatives of a <span class="twikiNewLink" style="background : #FFFFCE;"><font color="#0000FF">GuiCast</font><a href="http://www.ftconsult.com/twiki/bin/edit/Cinelerra/GuiCast?topicparent=Cinelerra.CreatingPlugins"><sup>?</sup></a></span> widget and they override functions in <span class="twikiNewLink" style="background : #FFFFCE;"><font color="#0000FF">GuiCast</font><a href="http://www.ftconsult.com/twiki/bin/edit/Cinelerra/GuiCast?topicparent=Cinelerra.CreatingPlugins"><sup>?</sup></a></span> to handle events. Finally create_objects calls
<p />
        show_window();
        flush();
<p />
<p />
to make the window appear all at once.
<p />
The close_event member should be implemented using
<p />
     WINDOW_CLOSE_EVENT(window_class)
<p />
<p />
Every widget in the GUI needs to detect when its value changes. In <span class="twikiNewLink" style="background : #FFFFCE;"><font color="#0000FF">GuiCast</font><a href="http://www.ftconsult.com/twiki/bin/edit/Cinelerra/GuiCast?topicparent=Cinelerra.CreatingPlugins"><sup>?</sup></a></span> the handle_event method is called whenever the value changes. In handle_event, the widget then needs to call plugin-&gt;send_configure_change() to propogate the change to rendering.
<p />
Node:REALTIME PLUGINS, Next:NONREALTIME PLUGINS, Previous:COMMON PROCEDURES, Up:PLUGIN AUTHORING
REALTIME PLUGINS
<p />
Realtime plugins should use PLUGIN_CLASS_MEMBERS to define the basic set of members in their headers. All realtime plugins must define an
<p />
     int is_realtime()
<p />
<p />
member returning 1. This causes a number of realtime methods to be called during playback and the plugin to be droppable on the timeline.
<p />
Realtime plugins must define a member called
<p />
     process_realtime
<p />
<p />
to be called during every audio fragment and video frame. It has an input and an output argument and for audio, a size argument. The process_realtime function should start by calling load_configuration. The LOAD_CONFIGURATION_MACRO returns 1 if the configuration changed. Then process_realtime should move the data from the input to the output with processing.
<p />
Additional members are implemented to maintain configuration in realtime plugins. Some of these are also needed in nonrealtime plugins.
<p />
    * void read_data(<a class="twikiLink" href="KeyFrame">KeyFrame</a> *keyframe);
<p />
      Loads data from a keyframe into the plugin's configuration. Inside the keyframe is an XML string. It's most easily parsed by creating a <span class="twikiNewLink" style="background : #FFFFCE;"><font color="#0000FF">FileXML</font><a href="http://www.ftconsult.com/twiki/bin/edit/Cinelerra/FileXML?topicparent=Cinelerra.CreatingPlugins"><sup>?</sup></a></span> object. See an existing plugin to see how the read_data function is implemented.
<p />
      Read data loads data out of the XML object and stores values in the plugin's configuration object.
    * void save_data(<a class="twikiLink" href="KeyFrame">KeyFrame</a> *keyframe);
<p />
      Saves data from the plugin's configuration to a keyframe. Inside the keyframe you'll put an XML string which is normally created by a <span class="twikiNewLink" style="background : #FFFFCE;"><font color="#0000FF">FileXML</font><a href="http://www.ftconsult.com/twiki/bin/edit/Cinelerra/FileXML?topicparent=Cinelerra.CreatingPlugins"><sup>?</sup></a></span> object. See an existing plugin to see how the save_data function is implemented.
<p />
      Save data saves data from the plugin's configuration object into the XML object.
    * int load_defaults();
<p />
      Another way the plugin gets parameters is from a defaults file. The load and save defaults routines use a Defaults object to parse the defaults file. The defaults object is created in load_defaults and destroyed in the plugin's destructor. See an existing plugin to see how the Defaults object is used.
    * int save_defaults();
<p />
Saves the configuration in the defaults object.
<p />
<h4><a name="NONREALTIME_PLUGINS"> </a> NONREALTIME PLUGINS </h4>
<p />
Like realtime plugins, load_defaults and save_defaults must be implemented. In nonrealtime plugins, these are not just used for default parameters but to transfer values from the user interface to the signal processor. There doesn't need to be a configuration class in nonrealtime plugins.
<p />
Unlike realtime plugins, the LOAD_CONFIGURATION_MACRO can't be used in the plugin header. Instead, the following methods must be defined.
<p />
The nonrealtime plugin should contain a pointer to a defaults object.
<p />
<p />
     Defaults *defaults;
<p />
<p />
<p />
It should also have a pointer to a <span class="twikiNewLink" style="background : #FFFFCE;"><font color="#0000FF">MainProgressBar</font><a href="http://www.ftconsult.com/twiki/bin/edit/Cinelerra/MainProgressBar?topicparent=Cinelerra.CreatingPlugins"><sup>?</sup></a></span>.
<p />
<p />
     <span class="twikiNewLink" style="background : #FFFFCE;"><font color="#0000FF">MainProgressBar</font><a href="http://www.ftconsult.com/twiki/bin/edit/Cinelerra/MainProgressBar?topicparent=Cinelerra.CreatingPlugins"><sup>?</sup></a></span> *progress;
<p />
<p />
The progress pointer allows nonrealtime plugins to display their progress in Cinelerra's main window.
<p />
The constructor for a nonrealtime plugin can't use PLUGIN_CONSTRUCTOR_MACRO but must call load_defaults directly.
<p />
The destructor, likewise, must call save_defaults and delete defaults directly instead of PLUGIN_DESTRUCTOR_MACRO.
<p />
    * VFrame* new_picon();
<p />
      char* plugin_title();
<p />
      The usage of these is the same as realtime plugins.
    * int is_realtime();
<p />
      This function must return 0 to indicate a nonrealtime plugin.
    * int get_parameters();
<p />
      Here, the user should create a GUI, wait for the user to hit an OK button or a cancel button, and store the parameters in plugin variables. This routine must return 0 for success and 1 for failure. This way the user can cancel the effect from the GUI.
<p />
      Unlike the realtime plugin, this GUI need not run asynchronously of the plugin. It should block the get_parameters function until the user selects OK or Cancel.
    * int load_defaults();
<p />
      This should create a defaults object and load parameters from the defaults object into plugin variables.
    * int save_defaults();
<p />
      This should save plugin variables to the defaults object.
    * int start_loop();
<p />
      If get_parameters returned 0 for success, this is called once to give the plugin a chance to initialize processing. The plugin should instantiate the progress object with a line like
<p />
<p />
          progress = start_progress("MyPlugin progress...",
             <span class="twikiNewLink" style="background : #FFFFCE;"><font color="#0000FF">PluginClient</font><a href="http://www.ftconsult.com/twiki/bin/edit/Cinelerra/PluginClient?topicparent=Cinelerra.CreatingPlugins"><sup>?</sup></a></span>::end - <span class="twikiNewLink" style="background : #FFFFCE;"><font color="#0000FF">PluginClient</font><a href="http://www.ftconsult.com/twiki/bin/edit/Cinelerra/PluginClient?topicparent=Cinelerra.CreatingPlugins"><sup>?</sup></a></span>::start);
<p />
<p />
<p />
      The usage of start_progress depends on whether the plugin is multichannel or single channel. If it's multichannel you always call start_progress. If it's single channel, you first need to know whether the progress bar has already started in another instance of the plugin.
<p />
      If <span class="twikiNewLink" style="background : #FFFFCE;"><font color="#0000FF">PluginClient</font><a href="http://www.ftconsult.com/twiki/bin/edit/Cinelerra/PluginClient?topicparent=Cinelerra.CreatingPlugins"><sup>?</sup></a></span>::interactive is 1, you need to start the progress bar. If it's 0, the progress bar has already been started.
<p />
      The <span class="twikiNewLink" style="background : #FFFFCE;"><font color="#0000FF">PluginClient</font><a href="http://www.ftconsult.com/twiki/bin/edit/Cinelerra/PluginClient?topicparent=Cinelerra.CreatingPlugins"><sup>?</sup></a></span> defines end and start for the timeline range to be processed. The units are either samples or frames.
    * int process_loop
<p />
      This is called repeatedly until the timeline range is processed. It takes either a samples or frames buffer and a reference to write_length. The arguments are a location and length for the output if it's audio.
<p />
      The plugin must use read_samples or read_frame to read the input. These functions take a buffer and a position relative to the start of the timeline. Then it must process it and put the output in the arguments to process_loop. write_length should contain the number of samples generated if it's audio.
<p />
      Finally, process_loop must test <span class="twikiNewLink" style="background : #FFFFCE;"><font color="#0000FF">PluginClient</font><a href="http://www.ftconsult.com/twiki/bin/edit/Cinelerra/PluginClient?topicparent=Cinelerra.CreatingPlugins"><sup>?</sup></a></span>::interactive and update the progress bar if it's 1.
<p />
          progress-&gt;update(total_written);
<p />
<p />
      returns 1 or 0 if the progress bar was cancelled. If it's 1, process_loop should return 1 to indicate a cancellation. In addition to progress bar cancellation, process_loop should return 1 when the entire timeline range is processed.
    * int stop_loop();
<p />
      This is called after process_loop processes its last buffer.
<p />
If <span class="twikiNewLink" style="background : #FFFFCE;"><font color="#0000FF">PluginClient</font><a href="http://www.ftconsult.com/twiki/bin/edit/Cinelerra/PluginClient?topicparent=Cinelerra.CreatingPlugins"><sup>?</sup></a></span>::is_interactive is 1, this should call stop_progress in the progress bar pointer and delete the pointer. Then it should delete any objects it created for processing in start_loop.
<p />
Node:AUDIO PLUGINS, Next:VIDEO PLUGINS, Previous:NONREALTIME PLUGINS, Up:PLUGIN AUTHORING
AUDIO PLUGINS
<p />
The simplest audio plugin is Gain. The processing object should include pluginaclient.h and inherit from <span class="twikiNewLink" style="background : #FFFFCE;"><font color="#0000FF">PluginAClient</font><a href="http://www.ftconsult.com/twiki/bin/edit/Cinelerra/PluginAClient?topicparent=Cinelerra.CreatingPlugins"><sup>?</sup></a></span>. Realtime audio plugins need to define
<p />
     int process_realtime(int64_t size,
           double **input_ptr,
           double **output_ptr);
<p />
<p />
if it's multichannel or
<p />
     int process_realtime(int64_t size,
           double *input_ptr,
           double *output_ptr);
<p />
<p />
if it's single channel. These should return the number of samples generated. In the future, the number of samples return value will synchronize plugins which delay audio.
<p />
Nonrealtime audio plugins need to define
<p />
     int process_loop(double *buffer, int64_t &amp;write_length);
<p />
<p />
for single channel or
<p />
     int process_loop(double **buffers, int64_t &amp;write_length);
<p />
<p />
for multi channel.
<p />
Node:VIDEO PLUGINS, Next:TRANSITION PLUGINS, Previous:AUDIO PLUGINS, Up:PLUGIN AUTHORING
VIDEO PLUGINS
<p />
The simplest video plugin is Flip. The processing object should include pluginvclient.h and inherit from <span class="twikiNewLink" style="background : #FFFFCE;"><font color="#0000FF">PluginVClient</font><a href="http://www.ftconsult.com/twiki/bin/edit/Cinelerra/PluginVClient?topicparent=Cinelerra.CreatingPlugins"><sup>?</sup></a></span>. Realtime video plugins need to define
<p />
     int process_realtime(VFrame **input,
           VFrame **output);
<p />
<p />
if it's multichannel or
<p />
     int process_realtime(VFrame *input,
           VFrame *output);
<p />
<p />
if it's single channel. They only get one frame per call but should return the number of frames generated anyway. In the future, the number of frames return value will synchronize plugins which delay video.
<p />
The nonrealtime video plugins need to define
<p />
     int process_loop(VFrame *buffer);
<p />
<p />
for single channel or
<p />
     int process_loop(VFrame **buffers);
<p />
<p />
for multi channel. They're always assumed to have a write length of 1 when they return 0.
<p />
Node:TRANSITION PLUGINS, Next:PLUGIN GUI'S WHICH UPDATE DURING PLAYBACK, Previous:VIDEO PLUGINS, Up:PLUGIN AUTHORING
TRANSITION PLUGINS
<p />
The simplest video transition is dissolve and the simplest audio transition is crossfade. These work identical to the single channel, realtime audio and video plugins. The only difference is the addition of an is_transition method to the processing object. is_transition should return 1.
<p />
Routines exist for determining where you are relative to the transition's start and end.
<p />
    * <span class="twikiNewLink" style="background : #FFFFCE;"><font color="#0000FF">PluginClient</font><a href="http://www.ftconsult.com/twiki/bin/edit/Cinelerra/PluginClient?topicparent=Cinelerra.CreatingPlugins"><sup>?</sup></a></span>::get_source_position() - returns an integer position since the start of the transition
* <span class="twikiNewLink" style="background : #FFFFCE;"><font color="#0000FF">PluginClient</font><a href="http://www.ftconsult.com/twiki/bin/edit/Cinelerra/PluginClient?topicparent=Cinelerra.CreatingPlugins"><sup>?</sup></a></span>::get_total_len() - returns the integer length of the transition. The units are either samples or frames.
<p />
Users should divide source position by total length to get the fraction of the transition the current process_realtime function starts at.
<p />
Secondly, the meaning of the input and output arguments to process_realtime is different for transitions than for realtime plugins.
<p />
The first argument to process_realtime is the data for the next edit. The second argument to process_realtime is the data for the previous edit. Eventually the second argument becomes the output.
<p />
Node:PLUGIN GUI'S WHICH UPDATE DURING PLAYBACK, Next:PLUGIN QUERIES, Previous:TRANSITION PLUGINS, Up:PLUGIN AUTHORING
PLUGIN GUI'S WHICH UPDATE DURING PLAYBACK
<p />
Effects like Histogram and <span class="twikiNewLink" style="background : #FFFFCE;"><font color="#0000FF">VideoScope</font><a href="http://www.ftconsult.com/twiki/bin/edit/Cinelerra/VideoScope?topicparent=Cinelerra.CreatingPlugins"><sup>?</sup></a></span> need to update the GUI during playback to display information about the signal. This is achieved with the send_render_gui and render_gui methods. Normally in process_realtime, when the processing object wants to update the GUI it should call send_render_gui. This should only be called in process_realtime. Send_render_gui goes through a search and eventually calls render_gui in the GUI instance of the plugin.
<p />
Render_gui should have a sequence like
<p />
     void <span class="twikiNewLink" style="background : #FFFFCE;"><font color="#0000FF">MyPlugin</font><a href="http://www.ftconsult.com/twiki/bin/edit/Cinelerra/MyPlugin?topicparent=Cinelerra.CreatingPlugins"><sup>?</sup></a></span>::render_gui(void *data)
     {
        if(thread)
        {
           thread-&gt;window-&gt;lock_window();
<p />
     // update GUI here
<p />
           thread-&gt;window-&gt;unlock_window();
        }
     }
<p />
<p />
<p />
The sequence uses one argument, a void pointer to transfer information from the renderer to the GUI. The user should typecast this pointer into something useful.
<p />
<h4><a name="PLUGIN_QUERIES"> </a> PLUGIN QUERIES </h4>
<p />
There are several useful queries in <span class="twikiNewLink" style="background : #FFFFCE;"><font color="#0000FF">PluginClient</font><a href="http://www.ftconsult.com/twiki/bin/edit/Cinelerra/PluginClient?topicparent=Cinelerra.CreatingPlugins"><sup>?</sup></a></span> which can be accessed from the processing object. Some of them have different meaning in realtime and non-realtime mode. They all give information about the operating system or the project.
<p />
    * int <span class="twikiNewLink" style="background : #FFFFCE;"><font color="#0000FF">PluginClient</font><a href="http://www.ftconsult.com/twiki/bin/edit/Cinelerra/PluginClient?topicparent=Cinelerra.CreatingPlugins"><sup>?</sup></a></span>::get_project_smp() Gives the number of CPU's on the system minus 1. If it's a uniprocessor it's 0. If it's a dual processor, it's 1. This number should be used to gain any parallelism.
    * double <span class="twikiNewLink" style="background : #FFFFCE;"><font color="#0000FF">PluginClient</font><a href="http://www.ftconsult.com/twiki/bin/edit/Cinelerra/PluginClient?topicparent=Cinelerra.CreatingPlugins"><sup>?</sup></a></span>::get_project_framerate() Gives the frames per second of the video.
* int <span class="twikiNewLink" style="background : #FFFFCE;"><font color="#0000FF">PluginClient</font><a href="http://www.ftconsult.com/twiki/bin/edit/Cinelerra/PluginClient?topicparent=Cinelerra.CreatingPlugins"><sup>?</sup></a></span>::get_project_samplerate() Gives the samples per second of the audio. 
<p />
-- <a class="twikiLink" href="../Main/AlexFerrer">AlexFerrer</a> - 18 Dec 2003 From <a class="twikiLink" href="SecretsOfCinelerra">SecretsOfCinelerra</a>
<hr />
<br class="twikiClear" />
<a name="TopicEnd"></a>
<span class="twikiRight twikiPageNav twikiGrayText"><a href="#PageTop">to&nbsp;top</a></span><br class="twikiClear" />
</div><div class="twikiHidden"><hr />End of topic<br /><a href="#Actions">Skip to action links</a> | <a href="#PageTop">Back&nbsp;to&nbsp;top</a><hr /></div>
<!---->
<!---->
<a name="Actions"> </a><span class="twikiHidden"><br /></span><div class="twikiTopicAction"><a href="http://www.ftconsult.com/twiki/bin/edit/Cinelerra/CreatingPlugins?t=1129907644"><b>Edit</b></a> <span class="twikiSeparator">|</span> <a href="http://www.ftconsult.com/twiki/bin/attach/Cinelerra/CreatingPlugins">Attach image or document</a> <span class="twikiSeparator">|</span> <a href="http://www.ftconsult.com/twiki/bin/view/Cinelerra/CreatingPlugins?skin=print.pattern">Printable version</a> <span class="twikiSeparator">|</span> <a href="http://www.ftconsult.com/twiki/bin/view/Cinelerra/CreatingPlugins?raw=on">Raw text</a> <span class="twikiSeparator">|</span> <a href="http://www.ftconsult.com/twiki/bin/oops/Cinelerra/CreatingPlugins?template=oopsmore&param1=1.1&param2=1.1">More topic actions</a><br />Revisions:  | r1.1 <span class="twikiSeparator">|</span> <a href="../../rdiff/Cinelerra/CreatingPlugins">Total page history</a> <span class="twikiSeparator">|</span> <a href="http://www.ftconsult.com/twiki/bin/search/Cinelerra/SearchResult?scope=text&regex=on&excludetopic=CreatingPlugins&search=Creating%20*Plugins%5B%5EA-Za-z0-9%5D">Backlinks</a></div>
<div class="twikiTopicInfo twikiRevInfo twikiGrayText twikiMoved"></div>
<div class="twikiTopicFooter"><span class="twikiLeft"><span class="twikiHomePath">You are here: <a class="twikiLink" href="WebHome">Cinelerra</a>  <span class='twikiSeparator'>&gt;</span> CreatingPlugins </span></span><span class="twikiHidden"><br /><br /></span><span class="twikiRight twikiPageNav twikiGrayText"><a href="#PageTop">to&nbsp;top</a></span><br class="twikiClear" /><span class="twikiHidden"><br /></span></div>
<a name="PageBottom"></a> </div></div><div class="twikiBottomBar"><div class="twikiBottomBarContents"><span class="twikiGrayText">Copyright &copy; 1999-2005 by the contributing authors. 
All material on this collaboration platform is the property of the contributing authors. <br /> 
Ideas, requests, problems regarding TWiki? <a href="mailto:alex@ftconsult.com?subject=TWiki&#32;Feedback&#32;on&#32;TWiki.WebBottomBar">Send feedback</a>
</span></div></div>
</body></html>