>> 古い記事: 対訳: WordForgeプロジェクト概要
<< 新しい記事: 対訳: ドキュメンタリー「RiP: リミックス宣言」の予告編が公開

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

簡単な LADSPAプラグインを作ってみた

とりあえず目を通しておく

LADSPA SDK Documentation

LADSPA Plugin Developers' Documentation

Linux Audio Plug-Ins: A Look Into LADSPA | O'Reilly Media - ここの delay.c と解説をだいぶ参考にしてあります。

あとは最新版の ladspa.h を見るように、とのことでした。

大まかな流れ

プログラム(C または C++)を書く

モノラル(1ch)の元データに対して振幅を 0~1倍するだけの簡単なもの、 foogain.c を書いたことにして進める。 実物は長いので下の方に掲載。

ビルド

$ gcc -fPIC -DPIC -Wall -O2 -c -o foogain.o foogain.c
$ ld -shared -o foogain.so foogain.o

確認・テスト

analyseplugin を使い、作ったプラグインについて詳細を表示する。

$ analyseplugin ./foogain.so

Plugin Name: "Foo Gain"
Plugin Label: "fooGain"
Plugin Unique ID: 831043
Maker: "sonota"
Copyright: "None"
Must Run Real-Time: No
Has activate() Function: Yes
Has deativate() Function: No
Has run_adding() Function: No
Environment: Normal or Hard Real-Time
Ports:  "Gain" input, control, 0 to 1
        "Input" input, audio
        "Output" output, audio

applyplugin を使ってプラグインを CUI で動作させる。とりあえず Usage を見てみる。

$ applyplugin
Usage:  applyplugin [flags] <input Wave file> <output Wave file>

        <LADSPA plugin file name> <plugin label> <Control1> <Control2>...
        [<LADSPA plugin file name> <plugin label> <Control1> <Control2>...]...
Flags:  -s<seconds>     Add seconds of silence after end of input file.

To find out what control values are needed by a plugin, use the
"analyseplugin" program and check for control input ports.

Usage に従って入力ファイル、出力ファイル、プラグイン(共有オブジェクト)ファイル名、プラグインのラベル、コントロールを指定して実行。

$ applyplugin in.wav out.wav ./foogain.so fooGain 0.5
Peak output: 1623

実行すると、音量(振幅)が 0.5倍になった out.wav が得られる。

ちなみにこの foogain.so は 1ch の処理しか想定していないので、 たとえば 2ch(ステレオ)のデータを入力ファイルとして渡すと以下のようにエラーとなる。 ただし、Audacity から使った場合はちゃんとそれぞれのチャンネルに対して作用した。

$ applyplugin in-2ch.wav out.wav ./foogain.so fooGain 0.5
Mismatch between channel count in input file and audio inputs on first plugin in chain.

インストール

自分の環境では /usr/lib/ladspa に共有オブジェクトファイル(foogain.so)をコピー。 シンボリックリンクではダメらしい。 LADSPAから(?)見えているか確認するには

$ listplugins | grep foogain.so

使う

Audacity などの LADSPA に対応したソフトから使えます。 Audacity の場合、メニューの [効果] 以下の [プラグイン * から *] の中に 項目が出ます。

選択すると次のような設定用ダイアログが出ます。 プレビューも可。

foogain.c

/* 
foogain.c
Based on a work at http://www.linuxdevcenter.com/linux/2001/02/02/graphics/delay.c
*/

/*****************************************************************************/

#include <stdlib.h>
#include <string.h>

/*****************************************************************************/

#include "ladspa.h"

/*****************************************************************************/

/* ゲイン最大値 */
#define MAX_GAIN 1

/*****************************************************************************/

/* プラグインに対するポート番号
   0起点で連番(forで回して使うため)
*/

#define SDL_GAIN        0
#define SDL_INPUT       1
#define SDL_OUTPUT      2

/*****************************************************************************/

#define LIMIT_BETWEEN_0_AND_1(x)         \
(((x) < 0) ? 0 : (((x) > 1) ? 1 : (x)))
#define LIMIT_BETWEEN_0_AND_MAX_GAIN(x)  \
(((x) < 0) ? 0 : (((x) > MAX_GAIN) ? MAX_GAIN : (x)))

/*****************************************************************************/

/* Instance data for the foo gain plugin. 
   インスタンスデータ
*/
typedef struct {
  // サンプリングレート
  LADSPA_Data m_fSampleRate;

  // ゲイン。ユーザが指定する値。この場合 0~1
  LADSPA_Data * m_pfGain;

  /* Input audio port data location. 
    入力オーディオポートの場所。
  */
  LADSPA_Data* m_pfInput;

  /* Output audio port data location.
    出力オーディオポートの場所。
  */
  LADSPA_Data* m_pfOutput;
} 
FooGain;

/*****************************************************************************/

/* Construct a new plugin instance. 
   新しいプラグイン・インスタンスを構築。
*/
LADSPA_Handle 
instantiateFooGain(
  const LADSPA_Descriptor* Descriptor,
	unsigned long SampleRate
){
  FooGain* psGain;

  // メモリ確保
  psGain = (FooGain*)malloc( sizeof(FooGain) );
  if(psGain == NULL){ return NULL; }
  
  psGain->m_fSampleRate = (LADSPA_Data)SampleRate;

  return psGain;
}

/*****************************************************************************/

/* Initialise and activate a plugin instance. 
  プラグインのインスタンスを初期化、アクティブ化
*/
void
activateFooGain( LADSPA_Handle Instance ) {
  FooGain* psFooGain;
  psFooGain = (FooGain*)Instance;
}

/*****************************************************************************/

/* Connect a port to a data location. 
   ポートをデータ位置に接続。
*/
void
connectPortToFooGain(
  LADSPA_Handle Instance,
	unsigned long Port,
	LADSPA_Data* DataLocation
){
  FooGain* psFooGain;
  psFooGain = (FooGain*)Instance;
  
  switch (Port){
  case SDL_GAIN:
    psFooGain->m_pfGain = DataLocation;
    break;
  case SDL_INPUT:
    psFooGain->m_pfInput = DataLocation;
    break;
  case SDL_OUTPUT:
    psFooGain->m_pfOutput = DataLocation;
    break;
  }
}

/*****************************************************************************/

// SampleCount で指定された数のサンプルに処理を実行
void 
runFooGain(
  LADSPA_Handle Instance,
	unsigned long SampleCount
) {
  LADSPA_Data* pfInput;
  LADSPA_Data* pfOutput;
  
  FooGain* psFooGain;
  psFooGain = (FooGain*)Instance;
  
  double        lGain;
  unsigned long lSampleIndex;

  // psFooGain からゲインの値を受け取る
  lGain = *( psFooGain->m_pfGain );

  // バッファの対応付け
  pfInput  = psFooGain->m_pfInput;
  pfOutput = psFooGain->m_pfOutput;
  
  // 実際の処理
  for( lSampleIndex = 0; lSampleIndex < SampleCount; lSampleIndex++ ){
    *(pfOutput) = *(pfInput) * lGain;
    pfInput++;
    pfOutput++;
  }
}

/*****************************************************************************/

void 
cleanupFooGain(LADSPA_Handle Instance) {
  FooGain* psFooGain;
  psFooGain = (FooGain*)Instance;

  free( psFooGain );
}

/*****************************************************************************/

LADSPA_Descriptor* g_psDescriptor = NULL;

/*****************************************************************************/

/* _init() is called automatically when the plugin library is first
   loaded. 
   プラグイン・ライブラリが最初に呼ばれた時、_init() が自動的に呼ばれる。
   */
void 
_init() {
  char** pcPortNames;
  LADSPA_PortDescriptor* piPortDescriptors;
  LADSPA_PortRangeHint* psPortRangeHints;

  g_psDescriptor = (LADSPA_Descriptor*)malloc( sizeof(LADSPA_Descriptor) );
  
  if (g_psDescriptor) {
    g_psDescriptor->UniqueID   = 831043;
    g_psDescriptor->Label      = strdup("fooGain");
    g_psDescriptor->Properties = LADSPA_PROPERTY_HARD_RT_CAPABLE;
    g_psDescriptor->Name       = strdup("Foo Gain");
    g_psDescriptor->Maker      = strdup("sonota");
    g_psDescriptor->Copyright  = strdup("None");
    g_psDescriptor->PortCount  = 3; // ポート数
    
    piPortDescriptors = (LADSPA_PortDescriptor*)calloc( 
      g_psDescriptor->PortCount
    , sizeof(LADSPA_PortDescriptor) 
    );
    
    g_psDescriptor->PortDescriptors = (const LADSPA_PortDescriptor*)piPortDescriptors;
    
    // ポートの関連付け
    piPortDescriptors[SDL_GAIN]   = LADSPA_PORT_INPUT  | LADSPA_PORT_CONTROL;
    piPortDescriptors[SDL_INPUT]  = LADSPA_PORT_INPUT  | LADSPA_PORT_AUDIO;
    piPortDescriptors[SDL_OUTPUT] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO;
    
    pcPortNames = (char**)calloc( 
      g_psDescriptor->PortCount
    , sizeof(char*) 
    );
    
    g_psDescriptor->PortNames = (const char**)pcPortNames;
    
    // ポートの関連付け。ポート名?
    pcPortNames[SDL_GAIN]   = strdup("Gain");
    pcPortNames[SDL_INPUT]  = strdup("Input");
    pcPortNames[SDL_OUTPUT] = strdup("Output");
    
    // ポート数を修正
    psPortRangeHints
    = ((LADSPA_PortRangeHint*)calloc(
      g_psDescriptor->PortCount
    , sizeof(LADSPA_PortRangeHint)
    ));
    
    g_psDescriptor->PortRangeHints
      = (const LADSPA_PortRangeHint*)psPortRangeHints;
    
    // ユーザ指定値のタイプ、上限、下限など
    psPortRangeHints[SDL_GAIN].HintDescriptor   = LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE;
    psPortRangeHints[SDL_GAIN].LowerBound       = 0;
    psPortRangeHints[SDL_GAIN].UpperBound       = (LADSPA_Data)MAX_GAIN;
    psPortRangeHints[SDL_INPUT].HintDescriptor  = 0;
    psPortRangeHints[SDL_OUTPUT].HintDescriptor = 0;
    
    // 関数の登録
    g_psDescriptor->instantiate         = instantiateFooGain;
    g_psDescriptor->connect_port        = connectPortToFooGain;
    g_psDescriptor->activate            = activateFooGain;
    g_psDescriptor->run                 = runFooGain;
    g_psDescriptor->run_adding          = NULL;
    g_psDescriptor->set_run_adding_gain = NULL;
    g_psDescriptor->deactivate          = NULL;
    g_psDescriptor->cleanup             = cleanupFooGain;
  }
}

/*****************************************************************************/

/* _fini() is called automatically when the library is unloaded. 
    ライブラリがアンロードされた時に自動的に呼ばれる。
*/
void 
_fini() {
  long lIndex;
  if (g_psDescriptor) {
    free( (char*)g_psDescriptor->Label );
    free( (char*)g_psDescriptor->Name );
    free( (char*)g_psDescriptor->Maker );
    free( (char*)g_psDescriptor->Copyright );
    free( (LADSPA_PortDescriptor*)g_psDescriptor->PortDescriptors );
    for ( lIndex = 0; lIndex < g_psDescriptor->PortCount; lIndex++ ){
      free( (char*)(g_psDescriptor->PortNames[lIndex]) );
    }
    free( (char**)g_psDescriptor->PortNames);
    free( (LADSPA_PortRangeHint *)g_psDescriptor->PortRangeHints);
    free( g_psDescriptor);
  }
}

/*****************************************************************************/

/* Return a descriptor of the requested plugin type. Only one plugin
   type is available in this library. 
   要求されたプラグインタイプのディスクリプタを返す。
   type はこのライブラリ内で利用可能。
*/
const LADSPA_Descriptor* 
ladspa_descriptor(unsigned long Index) {
  if (Index == 0){
    return g_psDescriptor;
  }else{
    return NULL;
  }
}

/*****************************************************************************/

/* EOF */

参考(外部リンク)

>> 古い記事: 対訳: WordForgeプロジェクト概要
<< 新しい記事: 対訳: ドキュメンタリー「RiP: リミックス宣言」の予告編が公開
** ホームに戻る

コメント

コメントの投稿

管理者にだけ表示を許可する

|
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。