clap

CLAP Audio Plugin API
Log | Files | Refs | README | LICENSE

commit f117aa85112990bfbc8336af3a7b8840e4da2d91
parent dc166b87ceb9202214fdaaff0d17d524c1d176e3
Author: Alexandre Bique <bique.alexandre@gmail.com>
Date:   Sat,  4 Oct 2014 19:20:37 +0200

Update specification

Diffstat:
Minclude/clap/clap.h | 52++++++++++++++++++++++++++++++----------------------
Mspec.html | 542++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------
Mspec.rst | 210++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
3 files changed, 600 insertions(+), 204 deletions(-)

diff --git a/include/clap/clap.h b/include/clap/clap.h @@ -65,18 +65,19 @@ struct clap_channel /* channel info */ enum clap_channel_type type; enum clap_channel_role role; - const char *name; + char *name; uint32_t stream_id; // used to connect feedback loops + bool repeatable; }; struct clap_channels_config { /* linked list */ - const struct clap_channel_configs *next; + struct clap_channel_configs *next; /* config */ - const struct clap_channel *inputs; - const struct clap_channel *output; + struct clap_channel *inputs; + struct clap_channel *output; }; //////////////// @@ -141,6 +142,21 @@ struct clap_preset // EVENTS // //////////// +enum clap_event_type +{ + CLAP_EVENT_NOTE_ON, // note attribute + CLAP_EVENT_NOTE_MODULATION, // note attribute + CLAP_EVENT_NOTE_OFF, // note attribute + + CLAP_EVENT_PARAM_SET, // param attribute + CLAP_EVENT_PARAM_RAMP, // param attribute + CLAP_EVENT_PITCH_SET, // diapason attribute + CLAP_EVENT_PRESET_SET, // preset attribute + + CLAP_EVENT_GUI_OPENED, // plugin to host + CLAP_EVENT_GUI_CLOSED, // plugin to host +}; + struct clap_event_note { uint16_t division; // 12 for a standard octave @@ -167,18 +183,6 @@ struct clap_event_preset const char *id; }; -enum clap_event_type -{ - CLAP_EVENT_NOTE_ON, // note attribute - CLAP_EVENT_NOTE_MODULATION, // note attribute - CLAP_EVENT_NOTE_OFF, // note attribute - - CLAP_EVENT_PARAM_SET, // param attribute - CLAP_EVENT_PARAM_RAMP, // param attribute - CLAP_EVENT_PITCH_SET, // diapason attribute - CLAP_EVENT_PRESET_SET, // preset attribute -}; - struct clap_event { struct clap_event *next; // linked list, NULL on end @@ -204,6 +208,10 @@ struct clap_process float **output; uint32_t nb_samples; + /* feedback loops */ + void (*feedback)(void *feedback_ctx, uint32_t stream_id, uint32_t nb_samples); + void *feedback_ctx; + /* process info */ bool is_offline; uint32_t tempo_in_samples; @@ -236,7 +244,7 @@ struct clap_host struct clap_event *events); /* future features */ - void *(*extention)(struct clap_plugin *plugin, const char *extention_id); + void *(*extension)(struct clap_plugin *plugin, const char *extention_id); }; //////////// @@ -272,9 +280,9 @@ struct clap_plugin uint32_t plugin_type; /* audio channels */ - const struct clap_channels_config *channel_configs; - void (*set_channels_config)(struct clap_plugin *plugin, - const struct clap_channels_config *config); + struct clap_channels_config *(*get_channels_configs)(struct clap_plugin *plugin); + bool (*set_channels_config)(struct clap_plugin *plugin, + struct clap_channels_config *config); /* parameters */ struct clap_param *(*get_params)(struct clap_plugin *plugin); @@ -290,7 +298,7 @@ struct clap_plugin void (*process)(struct clap_plugin *plugin, struct clap_process *process); /* gui */ - void (*open_gui)(struct clap_plugin *plugin); + bool (*open_gui)(struct clap_plugin *plugin); void (*close_gui)(struct clap_plugin *plugin); /* state */ @@ -298,7 +306,7 @@ struct clap_plugin void (*restore)(struct clap_plugin *plugin, const void *buffer, size_t size); /* future features */ - void *(*extention)(struct clap_plugin *plugin, const char *extention_id); + void *(*extension)(struct clap_plugin *plugin, const char *extention_id); }; /* typedef for dlsym() cast */ diff --git a/spec.html b/spec.html @@ -107,44 +107,69 @@ tt.docutils { <div class="contents topic" id="contents"> <p class="topic-title first">Contents</p> <ul class="simple"> -<li><a class="reference internal" href="#goals" id="id2">Goals</a></li> -<li><a class="reference internal" href="#specification" id="id3">Specification</a><ul> -<li><a class="reference internal" href="#encoding" id="id4">Encoding</a></li> -<li><a class="reference internal" href="#locate-the-plugins" id="id5">Locate the plugins</a><ul> -<li><a class="reference internal" href="#common" id="id6">Common</a></li> -<li><a class="reference internal" href="#linux" id="id7">Linux</a></li> -<li><a class="reference internal" href="#windows" id="id8">Windows</a></li> -<li><a class="reference internal" href="#mac" id="id9">Mac</a></li> +<li><a class="reference internal" href="#goals" id="id2">Goals</a><ul> +<li><a class="reference internal" href="#later-goals" id="id3">Later goals</a></li> </ul> </li> -<li><a class="reference internal" href="#instantiate-a-plugin" id="id10">Instantiate a plugin</a><ul> -<li><a class="reference internal" href="#precautions" id="id11">Precautions</a></li> -<li><a class="reference internal" href="#shell-plugins" id="id12">Shell plugins</a></li> -<li><a class="reference internal" href="#sample" id="id13">Sample</a></li> -<li><a class="reference internal" href="#description" id="id14">Description</a></li> +<li><a class="reference internal" href="#specification" id="id4">Specification</a><ul> +<li><a class="reference internal" href="#encoding" id="id5">Encoding</a></li> +<li><a class="reference internal" href="#plugins-location" id="id6">Plugins location</a><ul> +<li><a class="reference internal" href="#common" id="id7">Common</a></li> +<li><a class="reference internal" href="#linux" id="id8">Linux</a></li> +<li><a class="reference internal" href="#windows" id="id9">Windows</a></li> +<li><a class="reference internal" href="#mac" id="id10">Mac</a></li> </ul> </li> -<li><a class="reference internal" href="#threading" id="id15">Threading</a></li> -<li><a class="reference internal" href="#activation" id="id16">Activation</a></li> -<li><a class="reference internal" href="#processing" id="id17">Processing</a><ul> -<li><a class="reference internal" href="#audio-buffers" id="id18">Audio buffers</a></li> -<li><a class="reference internal" href="#events" id="id19">Events</a><ul> -<li><a class="reference internal" href="#parameters" id="id20">Parameters</a></li> -<li><a class="reference internal" href="#notes" id="id21">Notes</a></li> -<li><a class="reference internal" href="#pitch" id="id22">Pitch</a></li> +<li><a class="reference internal" href="#instantiate-a-plugin" id="id11">Instantiate a plugin</a><ul> +<li><a class="reference internal" href="#precautions" id="id12">Precautions</a></li> +<li><a class="reference internal" href="#shell-plugins" id="id13">Shell plugins</a><ul> +<li><a class="reference internal" href="#sample-plugin-loader" id="id14">Sample plugin loader</a></li> </ul> </li> +<li><a class="reference internal" href="#description" id="id15">Description</a></li> +<li><a class="reference internal" href="#audio-channel-configuration" id="id16">Audio channel configuration</a><ul> +<li><a class="reference internal" href="#pin-layout" id="id17">Pin layout</a></li> +<li><a class="reference internal" href="#available-configurations" id="id18">Available configurations</a></li> +<li><a class="reference internal" href="#selecting-a-configuration" id="id19">Selecting a configuration</a></li> +<li><a class="reference internal" href="#repeatable-channels" id="id20">Repeatable channels</a></li> </ul> </li> -<li><a class="reference internal" href="#id1" id="id23">Parameters</a></li> -<li><a class="reference internal" href="#graphical-user-interface" id="id24">Graphical User Interface</a></li> -<li><a class="reference internal" href="#presets" id="id25">Presets</a></li> -<li><a class="reference internal" href="#save-and-restore-plugin-s-state" id="id26">Save and restore plugin's state</a></li> -<li><a class="reference internal" href="#extension-system" id="id27">Extension system</a></li> </ul> </li> -<li><a class="reference internal" href="#examples" id="id28">Examples</a></li> -<li><a class="reference internal" href="#references" id="id29">References</a></li> +<li><a class="reference internal" href="#threading" id="id21">Threading</a></li> +<li><a class="reference internal" href="#activation" id="id22">Activation</a></li> +<li><a class="reference internal" href="#processing" id="id23">Processing</a><ul> +<li><a class="reference internal" href="#audio-buffers" id="id24">Audio buffers</a></li> +<li><a class="reference internal" href="#events" id="id25">Events</a><ul> +<li><a class="reference internal" href="#notes" id="id26">Notes</a></li> +<li><a class="reference internal" href="#parameters" id="id27">Parameters</a></li> +<li><a class="reference internal" href="#pitch" id="id28">Pitch</a></li> +</ul> +</li> +</ul> +</li> +<li><a class="reference internal" href="#id1" id="id29">Parameters</a></li> +<li><a class="reference internal" href="#graphical-user-interface" id="id30">Graphical User Interface</a><ul> +<li><a class="reference internal" href="#showing-the-gui" id="id31">Showing the GUI</a></li> +<li><a class="reference internal" href="#sending-events-to-the-host" id="id32">Sending events to the host</a></li> +<li><a class="reference internal" href="#hiding-the-gui" id="id33">Hiding the GUI</a></li> +</ul> +</li> +<li><a class="reference internal" href="#presets" id="id34">Presets</a><ul> +<li><a class="reference internal" href="#list-plugin-s-presets" id="id35">List plugin's presets</a></li> +<li><a class="reference internal" href="#load-a-preset" id="id36">Load a preset</a></li> +</ul> +</li> +<li><a class="reference internal" href="#save-and-restore-plugin-s-state" id="id37">Save and restore plugin's state</a></li> +<li><a class="reference internal" href="#extension-system" id="id38">Extension system</a></li> +</ul> +</li> +<li><a class="reference internal" href="#examples" id="id39">Examples</a></li> +<li><a class="reference internal" href="#references" id="id40">References</a><ul> +<li><a class="reference internal" href="#clap-c" id="id41">clap.c</a></li> +<li><a class="reference internal" href="#samples-clap-info-c" id="id42">samples/clap-info.c</a></li> +</ul> +</li> </ul> </div> <div class="section" id="goals"> @@ -153,9 +178,15 @@ tt.docutils { <li>Make a free audio plugin format</li> <li>Be easy to understand and implement</li> <li>Bring new features missed in VST 2.4</li> -<li>Replace old concepts by modern design</li> +<li>Replace old concepts by modern one</li> <li>Designed to work on any operating system</li> <li>Be event oriented</li> +<li>Be extensible without breaking existing plugins</li> +<li>Be easy to bridge</li> +</ul> +<div class="section" id="later-goals"> +<h2><a class="toc-backref" href="#id3">Later goals</a></h2> +<ul class="simple"> <li>Provide a reference host</li> <li>Provide some reference plugins</li> <li>Provide a validation plugin, which should signal anything wrong the host does</li> @@ -163,39 +194,40 @@ tt.docutils { ensure that basic functionnality are working</li> </ul> </div> +</div> <div class="section" id="specification"> -<h1><a class="toc-backref" href="#id3">Specification</a></h1> +<h1><a class="toc-backref" href="#id4">Specification</a></h1> <div class="section" id="encoding"> -<h2><a class="toc-backref" href="#id4">Encoding</a></h2> +<h2><a class="toc-backref" href="#id5">Encoding</a></h2> <p>All the strings exchanged through the CLAP interface must be encoded in UTF-8 and must be valid.</p> </div> -<div class="section" id="locate-the-plugins"> -<h2><a class="toc-backref" href="#id5">Locate the plugins</a></h2> +<div class="section" id="plugins-location"> +<h2><a class="toc-backref" href="#id6">Plugins location</a></h2> <div class="section" id="common"> -<h3><a class="toc-backref" href="#id6">Common</a></h3> +<h3><a class="toc-backref" href="#id7">Common</a></h3> <ul class="simple"> <li>Directories should be scanned recursively</li> </ul> </div> <div class="section" id="linux"> -<h3><a class="toc-backref" href="#id7">Linux</a></h3> +<h3><a class="toc-backref" href="#id8">Linux</a></h3> <ul class="simple"> <li>Plugins distrubuted with packages should be installed to: <tt class="docutils literal">/usr/lib/clap/</tt></li> <li>Plugins installed in the user's home should be installed to: <tt class="docutils literal"><span class="pre">${HOME}/.clap/</span></tt></li> </ul> </div> <div class="section" id="windows"> -<h3><a class="toc-backref" href="#id8">Windows</a></h3> +<h3><a class="toc-backref" href="#id9">Windows</a></h3> <p>TBD</p> </div> <div class="section" id="mac"> -<h3><a class="toc-backref" href="#id9">Mac</a></h3> +<h3><a class="toc-backref" href="#id10">Mac</a></h3> <p>TBD</p> </div> </div> <div class="section" id="instantiate-a-plugin"> -<h2><a class="toc-backref" href="#id10">Instantiate a plugin</a></h2> +<h2><a class="toc-backref" href="#id11">Instantiate a plugin</a></h2> <p>Plugin instanciation can be done in a few steps:</p> <ul class="simple"> <li>load the plugin library</li> @@ -203,7 +235,7 @@ and must be valid.</p> <li>instantiate the plugin by calling <tt class="docutils literal">clap_create</tt></li> </ul> <div class="section" id="precautions"> -<h3><a class="toc-backref" href="#id11">Precautions</a></h3> +<h3><a class="toc-backref" href="#id12">Precautions</a></h3> <ul class="simple"> <li>The function <tt class="docutils literal">clap_create</tt> must be thread-safe.</li> <li>It must not throw exceptions.</li> @@ -211,70 +243,17 @@ and must be valid.</p> </ul> </div> <div class="section" id="shell-plugins"> -<h3><a class="toc-backref" href="#id12">Shell plugins</a></h3> +<h3><a class="toc-backref" href="#id13">Shell plugins</a></h3> <p>A single dynamic library can contains multiple plugins. To list them, you have to call <tt class="docutils literal">clap_create</tt> with an index of 0 and increment the index until <tt class="docutils literal">clap_create</tt> returns <tt class="docutils literal">NULL</tt>.</p> +<div class="section" id="sample-plugin-loader"> +<h4><a class="toc-backref" href="#id14">Sample plugin loader</a></h4> +<p>See <a class="reference internal" href="#samples-clap-info-c">samples/clap-info.c</a></p> </div> -<div class="section" id="sample"> -<h3><a class="toc-backref" href="#id13">Sample</a></h3> -<pre class="code c literal-block"> -<span class="cp">#include &lt;stdio.h&gt; -#include &lt;dlfcn.h&gt; -</span> -<span class="cp">#include &lt;clap/clap.h&gt; -</span> -<span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span> <span class="o">**</span><span class="n">argv</span><span class="p">)</span> -<span class="p">{</span> - <span class="k">struct</span> <span class="n">clap_host</span> <span class="n">host</span><span class="p">;</span> <span class="c1">// XXX initialize host -</span> - <span class="kt">void</span> <span class="o">*</span> <span class="n">handle</span> <span class="o">=</span> <span class="n">dlopen</span><span class="p">(</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">RTLD_NOW</span> <span class="o">|</span> <span class="n">RTLD_LOCAL</span><span class="p">);</span> - <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">handle</span><span class="p">)</span> <span class="p">{</span> - <span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">&quot;failed to load %s: %s</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span> <span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">dlerror</span><span class="p">());</span> - <span class="k">return</span> <span class="mi">1</span><span class="p">;</span> - <span class="p">}</span> - - <span class="k">union</span> <span class="p">{</span> - <span class="kt">void</span> <span class="o">*</span><span class="n">ptr</span><span class="p">;</span> - <span class="n">clap_create_f</span> <span class="n">clap_create</span><span class="p">;</span> - <span class="p">}</span> <span class="n">symbol</span><span class="p">;</span> - - <span class="n">symbol</span><span class="p">.</span><span class="n">ptr</span> <span class="o">=</span> <span class="n">dlsym</span><span class="p">(</span><span class="n">handle</span><span class="p">,</span> <span class="s">&quot;clap_create&quot;</span><span class="p">);</span> - <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">symbol</span><span class="p">.</span><span class="n">ptr</span><span class="p">)</span> <span class="p">{</span> - <span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">&quot;symbol not found: clap_create</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">);</span> - <span class="k">return</span> <span class="mi">1</span><span class="p">;</span> - <span class="p">}</span> - - <span class="k">for</span> <span class="p">(</span><span class="kt">uint32_t</span> <span class="n">index</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">index</span> <span class="o">&lt;</span> <span class="p">(</span><span class="kt">uint32_t</span><span class="p">)</span><span class="o">-</span><span class="mi">1</span><span class="p">;</span> <span class="o">++</span><span class="n">index</span><span class="p">)</span> <span class="p">{</span> - <span class="k">struct</span> <span class="n">clap_plugin</span> <span class="o">*</span><span class="n">plugin</span> <span class="o">=</span> <span class="n">symbold</span><span class="p">.</span><span class="n">clap_create</span><span class="p">(</span><span class="n">index</span><span class="p">,</span> <span class="n">host</span><span class="p">,</span> <span class="mi">48000</span><span class="p">);</span> - <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">plugin</span><span class="p">)</span> - <span class="k">break</span><span class="p">;</span> - - <span class="n">fprintf</span><span class="p">(</span><span class="n">stdio</span><span class="p">,</span> - <span class="s">&quot;found plugin:</span><span class="se">\n</span><span class="s">&quot;</span> - <span class="s">&quot; id: %s</span><span class="se">\n</span><span class="s">&quot;</span> - <span class="s">&quot; name: %s</span><span class="se">\n</span><span class="s">&quot;</span> - <span class="s">&quot; description: %s</span><span class="se">\n</span><span class="s">&quot;</span> - <span class="s">&quot; manufacturer: %s</span><span class="se">\n</span><span class="s">&quot;</span> - <span class="s">&quot; version: %s</span><span class="se">\n</span><span class="s">&quot;</span> - <span class="s">&quot; url: %s</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span> - <span class="n">plugin</span><span class="o">-&gt;</span><span class="n">id</span><span class="p">,</span> - <span class="n">plugin</span><span class="o">-&gt;</span><span class="n">name</span><span class="p">,</span> - <span class="n">plugin</span><span class="o">-&gt;</span><span class="n">description</span><span class="p">,</span> - <span class="n">plugin</span><span class="o">-&gt;</span><span class="n">manufacturer</span><span class="p">,</span> - <span class="n">plugin</span><span class="o">-&gt;</span><span class="n">version</span><span class="p">,</span> - <span class="n">plugin</span><span class="o">-&gt;</span><span class="n">url</span><span class="p">);</span> - - <span class="c1">// destroy the plugin -</span> <span class="n">plugin</span><span class="o">-&gt;</span><span class="n">destroy</span><span class="p">(</span><span class="n">plugin</span><span class="p">);</span> - <span class="p">}</span> - - <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> -<span class="p">}</span> -</pre> </div> <div class="section" id="description"> -<h3><a class="toc-backref" href="#id14">Description</a></h3> +<h3><a class="toc-backref" href="#id15">Description</a></h3> <p>Both the plugin and host have a few attribute giving general plugin description.</p> <table border="1" class="docutils"> <colgroup> @@ -328,12 +307,6 @@ digital, fm, delay, reverb, compressor, ...</td> <td>Bitfield describing what the plugin does. See enum clap_plugin_type.</td> </tr> -<tr><td>inputs_count</td> -<td>The number of input buffers.</td> -</tr> -<tr><td>outputs_count</td> -<td>The number of output buffers.</td> -</tr> <tr><td>host_data</td> <td>Reserved pointer for the host.</td> </tr> @@ -343,19 +316,165 @@ clap_plugin_type.</td> </tbody> </table> </div> +<div class="section" id="audio-channel-configuration"> +<h3><a class="toc-backref" href="#id16">Audio channel configuration</a></h3> +<p>A plugin may have multiple audio channels, and so multiple audio channels +layout or configurations.</p> +<p>An audio channel has a type: mono, stereo, surround and a role: main +input/output, sidechain, feedback.</p> +<div class="section" id="pin-layout"> +<h4><a class="toc-backref" href="#id17">Pin layout</a></h4> +<table border="1" class="docutils"> +<colgroup> +<col width="28%" /> +<col width="14%" /> +<col width="58%" /> +</colgroup> +<thead valign="bottom"> +<tr><th class="head">type</th> +<th class="head">pin</th> +<th class="head">description</th> +</tr> +</thead> +<tbody valign="top"> +<tr><td>mono</td> +<td>0</td> +<td>mono</td> +</tr> +<tr><td rowspan="2">stereo</td> +<td>0</td> +<td>left</td> +</tr> +<tr><td>1</td> +<td>right</td> +</tr> +<tr><td rowspan="8">surround</td> +<td>0</td> +<td>front left</td> +</tr> +<tr><td>1</td> +<td>front right</td> +</tr> +<tr><td>2</td> +<td>center</td> +</tr> +<tr><td>3</td> +<td>low frequency</td> +</tr> +<tr><td>4</td> +<td>surround left</td> +</tr> +<tr><td>5</td> +<td>surround right</td> +</tr> +<tr><td>6</td> +<td>surround back left</td> +</tr> +<tr><td>7</td> +<td>surround back right</td> +</tr> +</tbody> +</table> +<p>So for the following configuration:</p> +<table border="1" class="docutils"> +<colgroup> +<col width="12%" /> +<col width="15%" /> +<col width="18%" /> +<col width="31%" /> +<col width="25%" /> +</colgroup> +<thead valign="bottom"> +<tr><th class="head">in/out</th> +<th class="head">type</th> +<th class="head">role</th> +<th class="head">buffer</th> +<th class="head">desc</th> +</tr> +</thead> +<tbody valign="top"> +<tr><td>input +input</td> +<td>stereo</td> +<td>inout</td> +<td>process-&gt;inputs[0] +process-&gt;inputs[1]</td> +<td>left input +right input</td> +</tr> +<tr><td>input +input</td> +<td>stereo</td> +<td>sidechain</td> +<td>process-&gt;inputs[2] +process-&gt;inputs[3]</td> +<td>left sidechain +right sidechain</td> +</tr> +<tr><td>input +input</td> +<td>stereo</td> +<td>feedback</td> +<td>process-&gt;inputs[4] +process-&gt;inputs[5]</td> +<td>left feedback +right feedback</td> +</tr> +<tr><td>output +output</td> +<td>stereo</td> +<td>inout</td> +<td>process-&gt;outputs[0] +process-&gt;outputs[1]</td> +<td>left input +right input</td> +</tr> +<tr><td>output +output</td> +<td>stereo</td> +<td>feedback</td> +<td>process-&gt;outputs[2] +process-&gt;outputs[3]</td> +<td>left feedback +right feedback</td> +</tr> +</tbody> +</table> +</div> +<div class="section" id="available-configurations"> +<h4><a class="toc-backref" href="#id18">Available configurations</a></h4> +<p>It is possible to discover a plugin's by calling +<tt class="docutils literal"><span class="pre">plugin-&gt;get_channels_configs(plugin);</span></tt>. It returns a newly allocated linked +list of configurations. It is the responsability of the host to free the list.</p> +</div> +<div class="section" id="selecting-a-configuration"> +<h4><a class="toc-backref" href="#id19">Selecting a configuration</a></h4> +<p>Selecting an audio configuration has to be done when the plugin is deactivated. +It is done by calling <tt class="docutils literal"><span class="pre">plugin-&gt;set_channels_config(plugin,</span> config)</tt>.</p> +<p>The host should duplicate the config before passing it to the plugin, and the +plugin is responsible to free the given config.</p> +<p><tt class="docutils literal"><span class="pre">plugin-&gt;set_channels_config(plugin,</span> config)</tt> returns <tt class="docutils literal">true</tt> if the +confiugration is successful, <tt class="docutils literal">false</tt> otherwise.</p> +</div> +<div class="section" id="repeatable-channels"> +<h4><a class="toc-backref" href="#id20">Repeatable channels</a></h4> +<p>Repeatable channels are a special case. A channel can be identified as +repeatable if <tt class="docutils literal"><span class="pre">channel-&gt;is_repeatable</span> == true</tt>.</p> +<p>A usefull case is for an analyzer. Imagine a spectroscope, to which you want to +plug any number of inputs. Each of those inputs can be named and displayed in +the spectrograph, so it is a convinient way analyze many tracks in the same +spectroscope.</p> +<p>To repeat a channel, just duplicate it and insert it between the original and +its next channel. Then call <tt class="docutils literal"><span class="pre">plugin-&gt;set_channels_config(plugin,</span> config);</tt>.</p> +</div> +</div> </div> <div class="section" id="threading"> -<h2><a class="toc-backref" href="#id15">Threading</a></h2> -<p>The plugin is not thread safe, and must not be called concurrently.</p> -<p>Yet, show_gui() and hide_gui() have to be called from an other thread, -and can be called concurrently.</p> -<p>Rational: starting the GUI requires to load resources which may be done -synchronously and can take time. So to avoid blocking the audio -processing, we choose to start the GUI from a different thread that the -audio processing thread.</p> +<h2><a class="toc-backref" href="#id21">Threading</a></h2> +<p>The plugin must be thread safe.</p> </div> <div class="section" id="activation"> -<h2><a class="toc-backref" href="#id16">Activation</a></h2> +<h2><a class="toc-backref" href="#id22">Activation</a></h2> <p>Before doing any processing, the plugin must be activated by calling <tt class="docutils literal">bool succeed = <span class="pre">plugin-&gt;activate(plugin);</span></tt>.</p> <p>If <tt class="docutils literal">succeed == true</tt> then the activation succeed. If the activation failed, @@ -374,54 +493,95 @@ not activated.</p> <p>It is preferable to de-activate the plugin before destroying it.</p> </div> <div class="section" id="processing"> -<h2><a class="toc-backref" href="#id17">Processing</a></h2> +<h2><a class="toc-backref" href="#id23">Processing</a></h2> <p>The processing is done in one call: <tt class="docutils literal"><span class="pre">plugin-&gt;process(plugin,</span> process);</tt>. The data structure process regroup everything needed by the plugin:</p> <ul class="simple"> <li>audio buffers (in, out)</li> +<li>feedback process callback</li> <li>events (in, out)</li> <li>tempo, time, is offline? (in)</li> <li>more processing needed (out)</li> </ul> <div class="section" id="audio-buffers"> -<h3><a class="toc-backref" href="#id18">Audio buffers</a></h3> +<h3><a class="toc-backref" href="#id24">Audio buffers</a></h3> <p>The audio buffers are allocated by the host. They must be aligned by the maximum requirement of the vector instructions currently avalaible.</p> <p>In-place processing is not supported.</p> +<p>There is no minimum number of samples.</p> +<p>See <a class="reference internal" href="#pin-layout">Pin layout</a>.</p> </div> <div class="section" id="events"> -<h3><a class="toc-backref" href="#id19">Events</a></h3> +<h3><a class="toc-backref" href="#id25">Events</a></h3> <p>Events are relative to <tt class="docutils literal"><span class="pre">process-&gt;time_in_samples</span></tt>. -Their time must be positive, and included into <tt class="docutils literal"><span class="pre">[0..process-&gt;nb_samples[</span></tt>.</p> -<div class="section" id="parameters"> -<h4><a class="toc-backref" href="#id20">Parameters</a></h4> -<p>Parameters can be automated by the host using <tt class="docutils literal">CLAP_EVENT_PARAM_SET</tt> or -<tt class="docutils literal">CLAP_EVENT_PARAM_RAMP</tt>.</p> -</div> +Their time must be positive, and included into <tt class="docutils literal"><span class="pre">[0..process-&gt;nb_samples[</span></tt> +or equal to <tt class="docutils literal">0</tt>.</p> <div class="section" id="notes"> -<h4><a class="toc-backref" href="#id21">Notes</a></h4> +<h4><a class="toc-backref" href="#id26">Notes</a></h4> <p>Notes are reprensented as a pair <tt class="docutils literal">note, division</tt>. Division is the number of intervals between one note and an other note with half or the double frequency.</p> </div> +<div class="section" id="parameters"> +<h4><a class="toc-backref" href="#id27">Parameters</a></h4> +<p>Parameters can be automated by the host using <tt class="docutils literal">CLAP_EVENT_PARAM_SET</tt> or +<tt class="docutils literal">CLAP_EVENT_PARAM_RAMP</tt>.</p> +<p>When using <tt class="docutils literal">CLAP_EVENT_PARAM_RAMP</tt>, the value of the parameter has to be +incremented by <tt class="docutils literal"><span class="pre">event-&gt;param.increment</span></tt> each steps until an other event +occur on this parameter.</p> +</div> <div class="section" id="pitch"> -<h4><a class="toc-backref" href="#id22">Pitch</a></h4> -<p>The pitch is the frequency of the note A. Its default value is 440Hz. +<h4><a class="toc-backref" href="#id28">Pitch</a></h4> +<p>The pitch is the frequency of the note A4. Its default value is 440Hz. The pitch can be changed by the host using the <tt class="docutils literal">CLAP_EVENT_PITCH_SET</tt> event.</p> </div> </div> </div> <div class="section" id="id1"> -<h2><a class="toc-backref" href="#id23">Parameters</a></h2> +<h2><a class="toc-backref" href="#id29">Parameters</a></h2> </div> <div class="section" id="graphical-user-interface"> -<h2><a class="toc-backref" href="#id24">Graphical User Interface</a></h2> +<h2><a class="toc-backref" href="#id30">Graphical User Interface</a></h2> +<div class="section" id="showing-the-gui"> +<h3><a class="toc-backref" href="#id31">Showing the GUI</a></h3> +<p>The plugin should show the GUI after a call to <tt class="docutils literal"><span class="pre">plugin-&gt;show_gui(plugin)</span></tt>. +If the plugin could successfully show the GUI, it returns <tt class="docutils literal">true</tt>, <tt class="docutils literal">false</tt> +otherwise.</p> +</div> +<div class="section" id="sending-events-to-the-host"> +<h3><a class="toc-backref" href="#id32">Sending events to the host</a></h3> +<p>The plugin can notify the host of parameter changes by sending events to: +<tt class="docutils literal"><span class="pre">host-&gt;events(host,</span> plugin, events);</tt>.</p> +</div> +<div class="section" id="hiding-the-gui"> +<h3><a class="toc-backref" href="#id33">Hiding the GUI</a></h3> +<p>The plugin should hide the GUI after a call to <tt class="docutils literal"><span class="pre">plugin-&gt;hide_gui(plugin)</span></tt>. +If the plugin window has been closed by the user, then the plugin should +send an event <tt class="docutils literal">CLAP_EVENT_GUI_CLOSED</tt> to the host.</p> +<pre class="code c literal-block"> +<span class="k">struct</span> <span class="n">clap</span> <span class="n">event</span> <span class="n">ev</span><span class="p">;</span> +<span class="n">ev</span><span class="p">.</span><span class="n">next</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span> +<span class="n">ev</span><span class="p">.</span><span class="n">type</span> <span class="o">=</span> <span class="n">CLAP_EVENT_GUI_CLOSED</span><span class="p">;</span> +<span class="n">host</span><span class="o">-&gt;</span><span class="n">events</span><span class="p">(</span><span class="n">host</span><span class="p">,</span> <span class="n">plugin</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">ev</span><span class="p">);</span> +</pre> +</div> </div> <div class="section" id="presets"> -<h2><a class="toc-backref" href="#id25">Presets</a></h2> +<h2><a class="toc-backref" href="#id34">Presets</a></h2> +<div class="section" id="list-plugin-s-presets"> +<h3><a class="toc-backref" href="#id35">List plugin's presets</a></h3> +<p>The host can browse the plugin's preset by callign <tt class="docutils literal"><span class="pre">plugin-&gt;get_presets(plugin);</span></tt>. +This function returns a newly allocated preset linked list. +It is the responsibility of the host to free the linked list.</p> +</div> +<div class="section" id="load-a-preset"> +<h3><a class="toc-backref" href="#id36">Load a preset</a></h3> +<p>To load a preset, the host should send an event <tt class="docutils literal">CLAP_EVENT_PRESET_SET</tt> to +the plugin.</p> +</div> </div> <div class="section" id="save-and-restore-plugin-s-state"> -<h2><a class="toc-backref" href="#id26">Save and restore plugin's state</a></h2> +<h2><a class="toc-backref" href="#id37">Save and restore plugin's state</a></h2> <p>Saving the plugin's state is done by:</p> <pre class="code c literal-block"> <span class="kt">void</span> <span class="o">*</span><span class="n">buffer</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span> @@ -439,14 +599,22 @@ plugin state on a little endian machine and send it through the network to a big endian machine, it should load again successfully.</p> </div> <div class="section" id="extension-system"> -<h2><a class="toc-backref" href="#id27">Extension system</a></h2> +<h2><a class="toc-backref" href="#id38">Extension system</a></h2> +<p>To extend clap's functionnality, there is a pretty simple mechanism:</p> +<pre class="code c literal-block"> +<span class="kt">void</span> <span class="o">*</span><span class="n">plug_ext</span> <span class="o">=</span> <span class="n">plugin</span><span class="o">-&gt;</span><span class="n">extension</span><span class="p">(</span><span class="n">plug</span><span class="p">,</span> <span class="s">&quot;company/ext-name&quot;</span><span class="p">);</span> +<span class="kt">void</span> <span class="o">*</span><span class="n">host_ext</span> <span class="o">=</span> <span class="n">host</span><span class="o">-&gt;</span><span class="n">extension</span><span class="p">(</span><span class="n">host</span><span class="p">,</span> <span class="s">&quot;company/ext-name&quot;</span><span class="p">);</span> +</pre> +<p>If the extension is not supported, the plugin should return <tt class="docutils literal">NULL</tt>.</p> </div> </div> <div class="section" id="examples"> -<h1><a class="toc-backref" href="#id28">Examples</a></h1> +<h1><a class="toc-backref" href="#id39">Examples</a></h1> </div> <div class="section" id="references"> -<h1><a class="toc-backref" href="#id29">References</a></h1> +<h1><a class="toc-backref" href="#id40">References</a></h1> +<div class="section" id="clap-c"> +<h2><a class="toc-backref" href="#id41">clap.c</a></h2> <pre class="code c literal-block"> <span class="cm">/** * CLAP - CLever Audio Plugin (&lt;--- needs to find a marketing ok name) @@ -515,18 +683,19 @@ big endian machine, it should load again successfully.</p> <span class="cm">/* channel info */</span> <span class="k">enum</span> <span class="n">clap_channel_type</span> <span class="n">type</span><span class="p">;</span> <span class="k">enum</span> <span class="n">clap_channel_role</span> <span class="n">role</span><span class="p">;</span> - <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">name</span><span class="p">;</span> + <span class="kt">char</span> <span class="o">*</span><span class="n">name</span><span class="p">;</span> <span class="kt">uint32_t</span> <span class="n">stream_id</span><span class="p">;</span> <span class="c1">// used to connect feedback loops -</span><span class="p">};</span> +</span> <span class="kt">bool</span> <span class="n">repeatable</span><span class="p">;</span> +<span class="p">};</span> <span class="k">struct</span> <span class="n">clap_channels_config</span> <span class="p">{</span> <span class="cm">/* linked list */</span> - <span class="k">const</span> <span class="k">struct</span> <span class="n">clap_channel_configs</span> <span class="o">*</span><span class="n">next</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">clap_channel_configs</span> <span class="o">*</span><span class="n">next</span><span class="p">;</span> <span class="cm">/* config */</span> - <span class="k">const</span> <span class="k">struct</span> <span class="n">clap_channel</span> <span class="o">*</span><span class="n">inputs</span><span class="p">;</span> - <span class="k">const</span> <span class="k">struct</span> <span class="n">clap_channel</span> <span class="o">*</span><span class="n">output</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">clap_channel</span> <span class="o">*</span><span class="n">inputs</span><span class="p">;</span> + <span class="k">struct</span> <span class="n">clap_channel</span> <span class="o">*</span><span class="n">output</span><span class="p">;</span> <span class="p">};</span> <span class="c1">//////////////// @@ -591,6 +760,21 @@ big endian machine, it should load again successfully.</p> // EVENTS // //////////// </span> +<span class="k">enum</span> <span class="n">clap_event_type</span> +<span class="p">{</span> + <span class="n">CLAP_EVENT_NOTE_ON</span><span class="p">,</span> <span class="c1">// note attribute +</span> <span class="n">CLAP_EVENT_NOTE_MODULATION</span><span class="p">,</span> <span class="c1">// note attribute +</span> <span class="n">CLAP_EVENT_NOTE_OFF</span><span class="p">,</span> <span class="c1">// note attribute +</span> + <span class="n">CLAP_EVENT_PARAM_SET</span><span class="p">,</span> <span class="c1">// param attribute +</span> <span class="n">CLAP_EVENT_PARAM_RAMP</span><span class="p">,</span> <span class="c1">// param attribute +</span> <span class="n">CLAP_EVENT_PITCH_SET</span><span class="p">,</span> <span class="c1">// diapason attribute +</span> <span class="n">CLAP_EVENT_PRESET_SET</span><span class="p">,</span> <span class="c1">// preset attribute +</span> + <span class="n">CLAP_EVENT_GUI_OPENED</span><span class="p">,</span> <span class="c1">// plugin to host +</span> <span class="n">CLAP_EVENT_GUI_CLOSED</span><span class="p">,</span> <span class="c1">// plugin to host +</span><span class="p">};</span> + <span class="k">struct</span> <span class="n">clap_event_note</span> <span class="p">{</span> <span class="kt">uint16_t</span> <span class="n">division</span><span class="p">;</span> <span class="c1">// 12 for a standard octave @@ -617,18 +801,6 @@ big endian machine, it should load again successfully.</p> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">id</span><span class="p">;</span> <span class="p">};</span> -<span class="k">enum</span> <span class="n">clap_event_type</span> -<span class="p">{</span> - <span class="n">CLAP_EVENT_NOTE_ON</span><span class="p">,</span> <span class="c1">// note attribute -</span> <span class="n">CLAP_EVENT_NOTE_MODULATION</span><span class="p">,</span> <span class="c1">// note attribute -</span> <span class="n">CLAP_EVENT_NOTE_OFF</span><span class="p">,</span> <span class="c1">// note attribute -</span> - <span class="n">CLAP_EVENT_PARAM_SET</span><span class="p">,</span> <span class="c1">// param attribute -</span> <span class="n">CLAP_EVENT_PARAM_RAMP</span><span class="p">,</span> <span class="c1">// param attribute -</span> <span class="n">CLAP_EVENT_PITCH_SET</span><span class="p">,</span> <span class="c1">// diapason attribute -</span> <span class="n">CLAP_EVENT_PRESET_SET</span><span class="p">,</span> <span class="c1">// preset attribute -</span><span class="p">};</span> - <span class="k">struct</span> <span class="n">clap_event</span> <span class="p">{</span> <span class="k">struct</span> <span class="n">clap_event</span> <span class="o">*</span><span class="n">next</span><span class="p">;</span> <span class="c1">// linked list, NULL on end @@ -654,6 +826,10 @@ big endian machine, it should load again successfully.</p> <span class="kt">float</span> <span class="o">**</span><span class="n">output</span><span class="p">;</span> <span class="kt">uint32_t</span> <span class="n">nb_samples</span><span class="p">;</span> + <span class="cm">/* feedback loops */</span> + <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">feedback</span><span class="p">)(</span><span class="kt">void</span> <span class="o">*</span><span class="n">feedback_ctx</span><span class="p">,</span> <span class="kt">uint32_t</span> <span class="n">stream_id</span><span class="p">,</span> <span class="kt">uint32_t</span> <span class="n">nb_samples</span><span class="p">);</span> + <span class="kt">void</span> <span class="o">*</span><span class="n">feedback_ctx</span><span class="p">;</span> + <span class="cm">/* process info */</span> <span class="kt">bool</span> <span class="n">is_offline</span><span class="p">;</span> <span class="kt">uint32_t</span> <span class="n">tempo_in_samples</span><span class="p">;</span> @@ -686,7 +862,7 @@ big endian machine, it should load again successfully.</p> <span class="k">struct</span> <span class="n">clap_event</span> <span class="o">*</span><span class="n">events</span><span class="p">);</span> <span class="cm">/* future features */</span> - <span class="kt">void</span> <span class="o">*</span><span class="p">(</span><span class="o">*</span><span class="n">extention</span><span class="p">)(</span><span class="k">struct</span> <span class="n">clap_plugin</span> <span class="o">*</span><span class="n">plugin</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">extention_id</span><span class="p">);</span> + <span class="kt">void</span> <span class="o">*</span><span class="p">(</span><span class="o">*</span><span class="n">extension</span><span class="p">)(</span><span class="k">struct</span> <span class="n">clap_plugin</span> <span class="o">*</span><span class="n">plugin</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">extention_id</span><span class="p">);</span> <span class="p">};</span> <span class="c1">//////////// @@ -722,9 +898,9 @@ big endian machine, it should load again successfully.</p> </span> <span class="kt">uint32_t</span> <span class="n">plugin_type</span><span class="p">;</span> <span class="cm">/* audio channels */</span> - <span class="k">const</span> <span class="k">struct</span> <span class="n">clap_channels_config</span> <span class="o">*</span><span class="n">channel_configs</span><span class="p">;</span> - <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">set_channels_config</span><span class="p">)(</span><span class="k">struct</span> <span class="n">clap_plugin</span> <span class="o">*</span><span class="n">plugin</span><span class="p">,</span> - <span class="k">const</span> <span class="k">struct</span> <span class="n">clap_channels_config</span> <span class="o">*</span><span class="n">config</span><span class="p">);</span> + <span class="k">struct</span> <span class="n">clap_channels_config</span> <span class="o">*</span><span class="p">(</span><span class="o">*</span><span class="n">get_channels_configs</span><span class="p">)(</span><span class="k">struct</span> <span class="n">clap_plugin</span> <span class="o">*</span><span class="n">plugin</span><span class="p">);</span> + <span class="kt">bool</span> <span class="p">(</span><span class="o">*</span><span class="n">set_channels_config</span><span class="p">)(</span><span class="k">struct</span> <span class="n">clap_plugin</span> <span class="o">*</span><span class="n">plugin</span><span class="p">,</span> + <span class="k">struct</span> <span class="n">clap_channels_config</span> <span class="o">*</span><span class="n">config</span><span class="p">);</span> <span class="cm">/* parameters */</span> <span class="k">struct</span> <span class="n">clap_param</span> <span class="o">*</span><span class="p">(</span><span class="o">*</span><span class="n">get_params</span><span class="p">)(</span><span class="k">struct</span> <span class="n">clap_plugin</span> <span class="o">*</span><span class="n">plugin</span><span class="p">);</span> @@ -740,7 +916,7 @@ big endian machine, it should load again successfully.</p> <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">process</span><span class="p">)(</span><span class="k">struct</span> <span class="n">clap_plugin</span> <span class="o">*</span><span class="n">plugin</span><span class="p">,</span> <span class="k">struct</span> <span class="n">clap_process</span> <span class="o">*</span><span class="n">process</span><span class="p">);</span> <span class="cm">/* gui */</span> - <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">open_gui</span><span class="p">)(</span><span class="k">struct</span> <span class="n">clap_plugin</span> <span class="o">*</span><span class="n">plugin</span><span class="p">);</span> + <span class="kt">bool</span> <span class="p">(</span><span class="o">*</span><span class="n">open_gui</span><span class="p">)(</span><span class="k">struct</span> <span class="n">clap_plugin</span> <span class="o">*</span><span class="n">plugin</span><span class="p">);</span> <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">close_gui</span><span class="p">)(</span><span class="k">struct</span> <span class="n">clap_plugin</span> <span class="o">*</span><span class="n">plugin</span><span class="p">);</span> <span class="cm">/* state */</span> @@ -748,7 +924,7 @@ big endian machine, it should load again successfully.</p> <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">restore</span><span class="p">)(</span><span class="k">struct</span> <span class="n">clap_plugin</span> <span class="o">*</span><span class="n">plugin</span><span class="p">,</span> <span class="k">const</span> <span class="kt">void</span> <span class="o">*</span><span class="n">buffer</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">size</span><span class="p">);</span> <span class="cm">/* future features */</span> - <span class="kt">void</span> <span class="o">*</span><span class="p">(</span><span class="o">*</span><span class="n">extention</span><span class="p">)(</span><span class="k">struct</span> <span class="n">clap_plugin</span> <span class="o">*</span><span class="n">plugin</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">extention_id</span><span class="p">);</span> + <span class="kt">void</span> <span class="o">*</span><span class="p">(</span><span class="o">*</span><span class="n">extension</span><span class="p">)(</span><span class="k">struct</span> <span class="n">clap_plugin</span> <span class="o">*</span><span class="n">plugin</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">extention_id</span><span class="p">);</span> <span class="p">};</span> <span class="cm">/* typedef for dlsym() cast */</span> @@ -767,6 +943,64 @@ big endian machine, it should load again successfully.</p> <span class="cp">#endif </span><span class="cm">/* !CLAP_H */</span> </pre> </div> +<div class="section" id="samples-clap-info-c"> +<h2><a class="toc-backref" href="#id42">samples/clap-info.c</a></h2> +<pre class="code c literal-block"> +<span class="cp">#include &lt;stdio.h&gt; +#include &lt;dlfcn.h&gt; +</span> +<span class="cp">#include &lt;clap/clap.h&gt; +</span> +<span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span> <span class="o">**</span><span class="n">argv</span><span class="p">)</span> +<span class="p">{</span> + <span class="k">struct</span> <span class="n">clap_host</span> <span class="n">host</span><span class="p">;</span> <span class="c1">// XXX initialize host +</span> + <span class="kt">void</span> <span class="o">*</span> <span class="n">handle</span> <span class="o">=</span> <span class="n">dlopen</span><span class="p">(</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">RTLD_NOW</span> <span class="o">|</span> <span class="n">RTLD_LOCAL</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">handle</span><span class="p">)</span> <span class="p">{</span> + <span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">&quot;failed to load %s: %s</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span> <span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">dlerror</span><span class="p">());</span> + <span class="k">return</span> <span class="mi">1</span><span class="p">;</span> + <span class="p">}</span> + + <span class="k">union</span> <span class="p">{</span> + <span class="kt">void</span> <span class="o">*</span><span class="n">ptr</span><span class="p">;</span> + <span class="n">clap_create_f</span> <span class="n">clap_create</span><span class="p">;</span> + <span class="p">}</span> <span class="n">symbol</span><span class="p">;</span> + + <span class="n">symbol</span><span class="p">.</span><span class="n">ptr</span> <span class="o">=</span> <span class="n">dlsym</span><span class="p">(</span><span class="n">handle</span><span class="p">,</span> <span class="s">&quot;clap_create&quot;</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">symbol</span><span class="p">.</span><span class="n">ptr</span><span class="p">)</span> <span class="p">{</span> + <span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">&quot;symbol not found: clap_create</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">);</span> + <span class="k">return</span> <span class="mi">1</span><span class="p">;</span> + <span class="p">}</span> + + <span class="k">for</span> <span class="p">(</span><span class="kt">uint32_t</span> <span class="n">index</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">index</span> <span class="o">&lt;</span> <span class="p">(</span><span class="kt">uint32_t</span><span class="p">)</span><span class="o">-</span><span class="mi">1</span><span class="p">;</span> <span class="o">++</span><span class="n">index</span><span class="p">)</span> <span class="p">{</span> + <span class="k">struct</span> <span class="n">clap_plugin</span> <span class="o">*</span><span class="n">plugin</span> <span class="o">=</span> <span class="n">symbold</span><span class="p">.</span><span class="n">clap_create</span><span class="p">(</span><span class="n">index</span><span class="p">,</span> <span class="n">host</span><span class="p">,</span> <span class="mi">48000</span><span class="p">);</span> + <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">plugin</span><span class="p">)</span> + <span class="k">break</span><span class="p">;</span> + + <span class="n">fprintf</span><span class="p">(</span><span class="n">stdio</span><span class="p">,</span> + <span class="s">&quot;found plugin:</span><span class="se">\n</span><span class="s">&quot;</span> + <span class="s">&quot; id: %s</span><span class="se">\n</span><span class="s">&quot;</span> + <span class="s">&quot; name: %s</span><span class="se">\n</span><span class="s">&quot;</span> + <span class="s">&quot; description: %s</span><span class="se">\n</span><span class="s">&quot;</span> + <span class="s">&quot; manufacturer: %s</span><span class="se">\n</span><span class="s">&quot;</span> + <span class="s">&quot; version: %s</span><span class="se">\n</span><span class="s">&quot;</span> + <span class="s">&quot; url: %s</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span> + <span class="n">plugin</span><span class="o">-&gt;</span><span class="n">id</span><span class="p">,</span> + <span class="n">plugin</span><span class="o">-&gt;</span><span class="n">name</span><span class="p">,</span> + <span class="n">plugin</span><span class="o">-&gt;</span><span class="n">description</span><span class="p">,</span> + <span class="n">plugin</span><span class="o">-&gt;</span><span class="n">manufacturer</span><span class="p">,</span> + <span class="n">plugin</span><span class="o">-&gt;</span><span class="n">version</span><span class="p">,</span> + <span class="n">plugin</span><span class="o">-&gt;</span><span class="n">url</span><span class="p">);</span> + + <span class="c1">// destroy the plugin +</span> <span class="n">plugin</span><span class="o">-&gt;</span><span class="n">destroy</span><span class="p">(</span><span class="n">plugin</span><span class="p">);</span> + <span class="p">}</span> + + <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> +<span class="p">}</span> +</pre> +</div> +</div> </div> </body> </html> diff --git a/spec.rst b/spec.rst @@ -14,9 +14,15 @@ Goals - Make a free audio plugin format - Be easy to understand and implement - Bring new features missed in VST 2.4 -- Replace old concepts by modern design +- Replace old concepts by modern one - Designed to work on any operating system - Be event oriented +- Be extensible without breaking existing plugins +- Be easy to bridge + +Later goals +----------- + - Provide a reference host - Provide some reference plugins - Provide a validation plugin, which should signal anything wrong the host does @@ -32,8 +38,8 @@ Encoding All the strings exchanged through the CLAP interface must be encoded in UTF-8 and must be valid. -Locate the plugins ------------------- +Plugins location +---------------- Common ~~~~~~ @@ -79,11 +85,10 @@ A single dynamic library can contains multiple plugins. To list them, you have to call ``clap_create`` with an index of 0 and increment the index until ``clap_create`` returns ``NULL``. -Sample -~~~~~~ +Sample plugin loader +```````````````````` -.. include:: samples/clap-info.c - :code: c +See `samples/clap-info.c`_ Description ~~~~~~~~~~~ @@ -123,27 +128,107 @@ Both the plugin and host have a few attribute giving general plugin description. | plugin_type | Bitfield describing what the plugin does. See enum | | | clap_plugin_type. | +--------------+---------------------------------------------------------------+ -| inputs_count | The number of input buffers. | -+--------------+---------------------------------------------------------------+ -| outputs_count| The number of output buffers. | -+--------------+---------------------------------------------------------------+ | host_data | Reserved pointer for the host. | +--------------+---------------------------------------------------------------+ | plugin_data | Reserved pointer for the plugin. | +--------------+---------------------------------------------------------------+ -Threading ---------- +Audio channel configuration +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A plugin may have multiple audio channels, and so multiple audio channels +layout or configurations. + +An audio channel has a type: mono, stereo, surround and a role: main +input/output, sidechain, feedback. + +Pin layout +`````````` -The plugin is not thread safe, and must not be called concurrently. ++----------+-----+---------------------+ +| type | pin | description | ++==========+=====+=====================+ +| mono | 0 | mono | ++----------+-----+---------------------+ +| stereo | 0 | left | +| +-----+---------------------+ +| | 1 | right | ++----------+-----+---------------------+ +| surround | 0 | front left | +| +-----+---------------------+ +| | 1 | front right | +| +-----+---------------------+ +| | 2 | center | +| +-----+---------------------+ +| | 3 | low frequency | +| +-----+---------------------+ +| | 4 | surround left | +| +-----+---------------------+ +| | 5 | surround right | +| +-----+---------------------+ +| | 6 | surround back left | +| +-----+---------------------+ +| | 7 | surround back right | ++----------+-----+---------------------+ + +So for the following configuration: + ++--------+----------+------------+---------------------+-----------------+ +| in/out | type | role | buffer | desc | ++========+==========+============+=====================+=================+ +| input | stereo | inout | process->inputs[0] | left input | +| input | | | process->inputs[1] | right input | ++--------+----------+------------+---------------------+-----------------+ +| input | stereo | sidechain | process->inputs[2] | left sidechain | +| input | | | process->inputs[3] | right sidechain | ++--------+----------+------------+---------------------+-----------------+ +| input | stereo | feedback | process->inputs[4] | left feedback | +| input | | | process->inputs[5] | right feedback | ++--------+----------+------------+---------------------+-----------------+ +| output | stereo | inout | process->outputs[0] | left input | +| output | | | process->outputs[1] | right input | ++--------+----------+------------+---------------------+-----------------+ +| output | stereo | feedback | process->outputs[2] | left feedback | +| output | | | process->outputs[3] | right feedback | ++--------+----------+------------+---------------------+-----------------+ + +Available configurations +```````````````````````` + +It is possible to discover a plugin's by calling +``plugin->get_channels_configs(plugin);``. It returns a newly allocated linked +list of configurations. It is the responsability of the host to free the list. + +Selecting a configuration +````````````````````````` + +Selecting an audio configuration has to be done when the plugin is deactivated. +It is done by calling ``plugin->set_channels_config(plugin, config)``. + +The host should duplicate the config before passing it to the plugin, and the +plugin is responsible to free the given config. + +``plugin->set_channels_config(plugin, config)`` returns ``true`` if the +confiugration is successful, ``false`` otherwise. + +Repeatable channels +``````````````````` + +Repeatable channels are a special case. A channel can be identified as +repeatable if ``channel->is_repeatable == true``. + +A usefull case is for an analyzer. Imagine a spectroscope, to which you want to +plug any number of inputs. Each of those inputs can be named and displayed in +the spectrograph, so it is a convinient way analyze many tracks in the same +spectroscope. + +To repeat a channel, just duplicate it and insert it between the original and +its next channel. Then call ``plugin->set_channels_config(plugin, config);``. -Yet, show_gui() and hide_gui() have to be called from an other thread, -and can be called concurrently. +Threading +--------- -Rational: starting the GUI requires to load resources which may be done -synchronously and can take time. So to avoid blocking the audio -processing, we choose to start the GUI from a different thread that the -audio processing thread. +The plugin must be thread safe. Activation ---------- @@ -178,6 +263,7 @@ The processing is done in one call: ``plugin->process(plugin, process);``. The data structure process regroup everything needed by the plugin: - audio buffers (in, out) +- feedback process callback - events (in, out) - tempo, time, is offline? (in) - more processing needed (out) @@ -190,17 +276,16 @@ maximum requirement of the vector instructions currently avalaible. In-place processing is not supported. +There is no minimum number of samples. + +See `Pin layout`_. + Events ~~~~~~ Events are relative to ``process->time_in_samples``. -Their time must be positive, and included into ``[0..process->nb_samples[``. - -Parameters -`````````` - -Parameters can be automated by the host using ``CLAP_EVENT_PARAM_SET`` or -``CLAP_EVENT_PARAM_RAMP``. +Their time must be positive, and included into ``[0..process->nb_samples[`` +or equal to ``0``. Notes ````` @@ -209,10 +294,20 @@ Notes are reprensented as a pair ``note, division``. Division is the number of intervals between one note and an other note with half or the double frequency. +Parameters +`````````` + +Parameters can be automated by the host using ``CLAP_EVENT_PARAM_SET`` or +``CLAP_EVENT_PARAM_RAMP``. + +When using ``CLAP_EVENT_PARAM_RAMP``, the value of the parameter has to be +incremented by ``event->param.increment`` each steps until an other event +occur on this parameter. + Pitch ````` -The pitch is the frequency of the note A. Its default value is 440Hz. +The pitch is the frequency of the note A4. Its default value is 440Hz. The pitch can be changed by the host using the ``CLAP_EVENT_PITCH_SET`` event. Parameters @@ -221,9 +316,50 @@ Parameters Graphical User Interface ------------------------ +Showing the GUI +~~~~~~~~~~~~~~~ + +The plugin should show the GUI after a call to ``plugin->show_gui(plugin)``. +If the plugin could successfully show the GUI, it returns ``true``, ``false`` +otherwise. + +Sending events to the host +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The plugin can notify the host of parameter changes by sending events to: +``host->events(host, plugin, events);``. + +Hiding the GUI +~~~~~~~~~~~~~~ + +The plugin should hide the GUI after a call to ``plugin->hide_gui(plugin)``. +If the plugin window has been closed by the user, then the plugin should +send an event ``CLAP_EVENT_GUI_CLOSED`` to the host. + +.. code:: c + + struct clap event ev; + ev.next = NULL; + ev.type = CLAP_EVENT_GUI_CLOSED; + host->events(host, plugin, &ev); + + Presets ------- +List plugin's presets +~~~~~~~~~~~~~~~~~~~~~ + +The host can browse the plugin's preset by callign ``plugin->get_presets(plugin);``. +This function returns a newly allocated preset linked list. +It is the responsibility of the host to free the linked list. + +Load a preset +~~~~~~~~~~~~~ + +To load a preset, the host should send an event ``CLAP_EVENT_PRESET_SET`` to +the plugin. + Save and restore plugin's state ------------------------------- @@ -250,11 +386,29 @@ big endian machine, it should load again successfully. Extension system ---------------- +To extend clap's functionnality, there is a pretty simple mechanism: + +.. code:: c + + void *plug_ext = plugin->extension(plug, "company/ext-name"); + void *host_ext = host->extension(host, "company/ext-name"); + +If the extension is not supported, the plugin should return ``NULL``. + Examples ======== References ========== +clap.c +------ + .. include:: include/clap/clap.h :code: c + +samples/clap-info.c +------------------- + +.. include:: samples/clap-info.c + :code: c