caps库分析笔记

来源:互联网 发布:如何注册淘宝店 编辑:程序博客网 时间:2024/06/18 11:36
  • 接口封装
    caps是一个由C++语言编写,依赖GNU编译器拓展的音频处理算法共享库。这里需要普及一下attribute ((constructor))和attribute ((destructor)) 两个属性。constructor属性指定函数在执行程序main前(共享库则在加载时)自动执行。destructor属性指定函数在执行程序结束后(共享库则在卸载时)自动执行。
    文件interface.cc
static DescriptorStub * descriptors[N+1];......const LADSPA_Descriptor * ladspa_descriptor (unsigned long i) { return i < N ? descriptors[i] : 0; }

上述代码片是caps对外提供对象指针(并非直接访问)和接口。容易注意到对外提供接口的返回对象指针和定义对外提供的对象指针并不一致。这是因为LADSPA_Descriptor是DescriptorStub的基类。对于C++,子类对象可以强制转换成基类对象(不可以反过来)。
DescriptorStub对象对LADSPA_Descriptor进行封装的目的是为了方便对LADSPA_Descriptor对象的管理(仅仅删除)。上文的对象指针指向的内容通过constructor属性创建和通过destructor属性删除。
创建

__attribute__ ((constructor)) void caps_so_init(){    DescriptorStub ** d = descriptors;    /* make sure uninitialised array members are safe to pass to the host */    memset (d, 0, sizeof (descriptors));    *d++ = new Descriptor<Noisegate>(2602);    *d++ = new Descriptor<Compress>(1772);    *d++ = new Descriptor<CompressX2>(2598);    *d++ = new Descriptor<ToneStack>(2589);    *d++ = new Descriptor<AmpVTS>(2592);    #ifdef SUMMER    *d++ = new Descriptor<AmpVI>(1789);    #endif    *d++ = new Descriptor<CabinetIII>(2601);    *d++ = new Descriptor<CabinetIV>(2606);    #ifdef WITH_JVREV    *d++ = new Descriptor<JVRev>(1778);    #endif    *d++ = new Descriptor<Plate>(1779);    *d++ = new Descriptor<PlateX2>(1795);    *d++ = new Descriptor<Saturate>(1771);    *d++ = new Descriptor<Spice>(2603);    *d++ = new Descriptor<SpiceX2>(2607);    *d++ = new Descriptor<ChorusI>(1767);    *d++ = new Descriptor<PhaserII>(2586);    *d++ = new Descriptor<AutoFilter>(2593);    *d++ = new Descriptor<Scape>(2588);    *d++ = new Descriptor<Eq10>(1773);    *d++ = new Descriptor<Eq10X2>(2594);    *d++ = new Descriptor<Eq4p>(2608);    *d++ = new Descriptor<EqFA4p>(2609);    *d++ = new Descriptor<Wider>(1788);    *d++ = new Descriptor<Narrower>(2595);    *d++ = new Descriptor<Sin>(1781);    *d++ = new Descriptor<White>(1785);    *d++ = new Descriptor<Fractal>(1774);    *d++ = new Descriptor<Click>(1769);    *d++ = new Descriptor<CEO>(1770);    assert (d - descriptors <= N);}

删除

__attribute__ ((destructor)) void caps_so_fini(){    DescriptorStub ** d = descriptors;    while (*d) delete *d++;}

从上述两段代码可以证实上面的观点。Descriptor引用模板,访问是需要指定模板类型。程序结束时,libc++是不会知道模板的具体类型的(caps_so_fini没有形参)。但是,真正创建的对象却是Descriptor,不是LADSPA_Descriptor,也不是DescriptorStub。原因后面解释。
其实笔者想要利用的是EQ部分(音频均衡器算法),所以笔者只分析EQ相应部分(其中的Eq10)。

    *d++ = new Descriptor<Eq10>(1773);
  • 对象Descriptor
    继承关系
class Descriptor <= class DescriptorStub <= struct LADSPA_Descriptor

Descriptor引用模板,访问是需要指定模板类型,所以需要DescriptorStub。但是DescriptorStub是Descriptor的基类,无法访问Descriptor的拓展成员,所以需要LADSPA_Descriptor存储数据。同时,为了方便C访问,LADSPA_Descriptor采用struct而不是class。LADSPA_Descriptor存储了最关键的数据和接口,自然而言就是核心。笔者比较单纯,对于如此复杂的关系深恶痛绝。
成员
通过继承关系,可知Descriptor的成员应该包括(关心)自身,DescriptorStub和LADSPA_Descriptor的共有成员。DescriptorStub设计的目的仅仅是为了清理工作。没有值得关心的成员。LADSPA_Descriptor是结构体类型,所有成员都为共有成员。Descriptor的函数成员都会赋值到LADSPA_Descriptor的函数指针成员。这里没有用虚函数,笔者为C++所痛心,caps作者心里还是只有C。既然心里只有C,为何还用C++实现,大抵天下负心人都如此,奉承着一个,心里却是别人。抛却七情六欲,冷眼看待一下LADSPA_Descriptor。

typedef struct _LADSPA_Descriptor {   /* This numeric identifier indicates the plugin type     uniquely. Plugin programmers may reserve ranges of IDs from a     central body to avoid clashes. Hosts may assume that IDs are     below 0x1000000. */  unsigned long UniqueID;  /* This identifier can be used as a unique, case-sensitive     identifier for the plugin type within the plugin file. Plugin     types should be identified by file and label rather than by index     or plugin name, which may be changed in new plugin     versions. Labels must not contain white-space characters. */  const char * Label;  /* This indicates a number of properties of the plugin. */  LADSPA_Properties Properties;  /* This member points to the null-terminated name of the plugin     (e.g. "Sine Oscillator"). */  const char * Name;  /* This member points to the null-terminated string indicating the     maker of the plugin. This can be an empty string but not NULL. */  const char * Maker;  /* This member points to the null-terminated string indicating any     copyright applying to the plugin. If no Copyright applies the     string "None" should be used. */  const char * Copyright;  /* This indicates the number of ports (input AND output) present on     the plugin. */  unsigned long PortCount;  /* This member indicates an array of port descriptors. Valid indices     vary from 0 to PortCount-1. */  const LADSPA_PortDescriptor * PortDescriptors;  /* This member indicates an array of null-terminated strings     describing ports (e.g. "Frequency (Hz)"). Valid indices vary from     0 to PortCount-1. */  const char * const * PortNames;  /* This member indicates an array of range hints for each port (see     above). Valid indices vary from 0 to PortCount-1. */  const LADSPA_PortRangeHint * PortRangeHints;  /* This may be used by the plugin developer to pass any custom     implementation data into an instantiate call. It must not be used     or interpreted by the host. It is expected that most plugin     writers will not use this facility as LADSPA_Handle should be     used to hold instance data. */  void * ImplementationData;  /* This member is a function pointer that instantiates a plugin. A     handle is returned indicating the new plugin instance. The     instantiation function accepts a sample rate as a parameter. The     plugin descriptor from which this instantiate function was found     must also be passed. This function must return NULL if     instantiation fails.      Note that instance initialisation should generally occur in     activate() rather than here. */  LADSPA_Handle (*instantiate)(const struct _LADSPA_Descriptor * Descriptor,                               unsigned long                     SampleRate);  /* This member is a function pointer that connects a port on an     instantiated plugin to a memory location at which a block of data     for the port will be read/written. The data location is expected     to be an array of LADSPA_Data for audio ports or a single     LADSPA_Data value for control ports. Memory issues will be     managed by the host. The plugin must read/write the data at these     locations every time run() or run_adding() is called and the data     present at the time of this connection call should not be     considered meaningful.     connect_port() may be called more than once for a plugin instance     to allow the host to change the buffers that the plugin is     reading or writing. These calls may be made before or after     activate() or deactivate() calls.     connect_port() must be called at least once for each port before     run() or run_adding() is called. When working with blocks of     LADSPA_Data the plugin should pay careful attention to the block     size passed to the run function as the block allocated may only     just be large enough to contain the block of samples.     Plugin writers should be aware that the host may elect to use the     same buffer for more than one port and even use the same buffer     for both input and output (see LADSPA_PROPERTY_INPLACE_BROKEN).     However, overlapped buffers or use of a single buffer for both     audio and control data may result in unexpected behaviour. */   void (*connect_port)(LADSPA_Handle Instance,                        unsigned long Port,                        LADSPA_Data * DataLocation);  /* This member is a function pointer that initialises a plugin     instance and activates it for use. This is separated from     instantiate() to aid real-time support and so that hosts can     reinitialise a plugin instance by calling deactivate() and then     activate(). In this case the plugin instance must reset all state     information dependent on the history of the plugin instance     except for any data locations provided by connect_port() and any     gain set by set_run_adding_gain(). If there is nothing for     activate() to do then the plugin writer may provide a NULL rather     than an empty function.     When present, hosts must call this function once before run() (or     run_adding()) is called for the first time. This call should be     made as close to the run() call as possible and indicates to     real-time plugins that they are now live. Plugins should not rely     on a prompt call to run() after activate(). activate() may not be     called again unless deactivate() is called first. Note that     connect_port() may be called before or after a call to     activate(). */  void (*activate)(LADSPA_Handle Instance);  /* This method is a function pointer that runs an instance of a     plugin for a block. Two parameters are required: the first is a     handle to the particular instance to be run and the second     indicates the block size (in samples) for which the plugin     instance may run.     Note that if an activate() function exists then it must be called     before run() or run_adding(). If deactivate() is called for a     plugin instance then the plugin instance may not be reused until     activate() has been called again.     If the plugin has the property LADSPA_PROPERTY_HARD_RT_CAPABLE     then there are various things that the plugin should not do     within the run() or run_adding() functions (see above). */  void (*run)(LADSPA_Handle Instance,              unsigned long SampleCount);  /* This method is a function pointer that runs an instance of a     plugin for a block. This has identical behaviour to run() except     in the way data is output from the plugin. When run() is used,     values are written directly to the memory areas associated with     the output ports. However when run_adding() is called, values     must be added to the values already present in the memory     areas. Furthermore, output values written must be scaled by the     current gain set by set_run_adding_gain() (see below) before     additioCn.     run_adding() is optional. When it is not provided by a plugin,     this function pointer must be set to NULL. When it is provided,     the function set_run_adding_gain() must be provided also. */  void (*run_adding)(LADSPA_Handle Instance,             unsigned long SampleCount);  /* This method is a function pointer that sets the output gain for     use when run_adding() is called (see above). If this function is     never called the gain is assumed to default to 1. Gain     information should be retained when activate() or deactivate()     are called.     This function should be provided by the plugin if and only if the     run_adding() function is provided. When it is absent this     function pointer must be set to NULL. */  void (*set_run_adding_gain)(LADSPA_Handle Instance,                  LADSPA_Data   Gain);  /* This is the counterpart to activate() (see above). If there is     nothing for deactivate() to do then the plugin writer may provide     a NULL rather than an empty function.     Hosts must deactivate all activated units after they have been     run() (or run_adding()) for the last time. This call should be     made as close to the last run() call as possible and indicates to     real-time plugins that they are no longer live. Plugins should     not rely on prompt deactivation. Note that connect_port() may be     called before or after a call to deactivate().     Deactivation is not similar to pausing as the plugin instance     will be reinitialised when activate() is called to reuse it. */  void (*deactivate)(LADSPA_Handle Instance);  /* Once an instance of a plugin has been finished with it can be     deleted using the following function. The instance handle passed     ceases to be valid after this call.     If activate() was called for a plugin instance then a     corresponding call to deactivate() must be made before cleanup()     is called. */  void (*cleanup)(LADSPA_Handle Instance);} LADSPA_Descriptor;/**********************************************************************//* Accessing a Plugin: *//* The exact mechanism by which plugins are loaded is host-dependent,   however all most hosts will need to know is the name of shared   object file containing the plugin types. To allow multiple hosts to   share plugin types, hosts may wish to check for environment   variable LADSPA_PATH. If present, this should contain a   colon-separated path indicating directories that should be searched   (in order) when loading plugin types.   A plugin programmer must include a function called   "ladspa_descriptor" with the following function prototype within   the shared object file. This function will have C-style linkage (if   you are using C++ this is taken care of by the `extern "C"' clause   at the top of the file).   A host will find the plugin shared object file by one means or   another, find the ladspa_descriptor() function, call it, and   proceed from there.   Plugin types are accessed by index (not ID) using values from 0   upwards. Out of range indexes must result in this function   returning NULL, so the plugin count can be determined by checking   for the least index that results in NULL being returned. */const LADSPA_Descriptor * ladspa_descriptor(unsigned long Index);/* Datatype corresponding to the ladspa_descriptor() function. */typedef const LADSPA_Descriptor * (*LADSPA_Descriptor_Function)(unsigned long Index);/**********************************************************************/#ifdef __cplusplus}
0 0
原创粉丝点击