2015/08/01

LADSPA GUI

Audacity上でLADSPAのGUIでどんなことが出来るのか試してみる。

ボックス&スライダー

基本的にセットで独立はできないようだ。 スライダーはリニアと対数が出来るようだが、Audacity上では対数は無効のようだ。

スライダーでセレクト(ラジオボタン)

3つ以上の選択をしたい場合に使用するのだが、数字で指定することになるので使い勝手は悪い。

チェックボックス

オンオフをするときに使用する。

以上がLADSPAのGUI。かなり限られている。プルダウンメニューもできないし、レイアウトの自由度もない。使い勝手や見栄えでは、残念すぎるLADSPAでNyquistよりも劣っている。

サンプルプログラム

下は以前作ったアンプを元に作った中身のないGUIだけのサンプル。
1段目はスライダーの初期位置を中間にしてみた。
2、3段目はチェックボックス。これは1段当たり1個しか使えない。2個連続させた場合は改行されてしまう。スペースの無駄遣い。
4段目は上限の数値をサンプリング周波数にしたので、サンプリング周波数が違うと違った値が反映されると思ったが、常時44100か? 調査が必要。
5段目は対数スライダーにしたかったが、反映されない。
6段目は4択のスライダー。数値しか使えないので、わかりにくい。ラベル文字で工夫しようにもラベルの自由度がほとんどない。とりあえず改行ぐらいはできるようだ。

利点はシンプルな仕様なので開発が楽なこと。Audacity2.1以降では、リアルタイムプレビューもできるし、設定の保存も可能。

LADSPA GUI ソースコード

/* namagi_gui.c
 * 2015.08.01
 * compile windows
 * gcc -shared -o namagi_gui.dll namagi_gui.c -ID
 * 
 * compile Ubuntu
 * gcc -fPIC -DPIC -shared -nostartfiles
   -o namagi_gui.so namagi_gui.c
*/
/**********************************************************/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include "ladspa.h"
/**********************************************************/
#define AMP_INPUT1   0
#define AMP_OUTPUT1  1
#define MIN_GAIN1    -12.2
#define MAX_GAIN1     12.2
#define AMP_CONTROL1 2
#define AMP_CKBOX1   3
#define AMP_CKBOX2   4
#define AMP_CONTROL2 5
#define AMP_CONTROL3 6
#define AMP_CONTROL4 7
/**********************************************************/
#ifdef WIN32
int bIsFirstTime = 1;
void _init();
#endif

#ifdef WIN32
    #define _WINDOWS_DLL_EXPORT_ __declspec(dllexport)
#else
    #define _WINDOWS_DLL_EXPORT_ 
#endif
/**********************************************************/
typedef struct {
  LADSPA_Data *m_pfControlValue1;
  LADSPA_Data *m_pfInputBuffer1;
  LADSPA_Data *m_pfOutputBuffer1;
} Amplifier;
/**********************************************************/
LADSPA_Handle instantiateAmplifier(
         const LADSPA_Descriptor *Descriptor, 
         unsigned long  SampleRate){
               /* メモリ確保 */
               return malloc(sizeof(Amplifier));
}
/**********************************************************/
void connectPortToAmplifier(
               LADSPA_Handle Instance,
         unsigned long Port,
         LADSPA_Data *DataLocation) {
  Amplifier *psAmplifier;
  psAmplifier = (Amplifier *)Instance;

  switch (Port){
  case AMP_CONTROL1:
    psAmplifier -> m_pfControlValue1 = DataLocation;
    break;  
  case AMP_INPUT1:
    psAmplifier -> m_pfInputBuffer1 = DataLocation;
    break;
  case AMP_OUTPUT1:
    psAmplifier -> m_pfOutputBuffer1 = DataLocation;
    break;
  }
}
/**********************************************************/
void runAmplifier(LADSPA_Handle Instance,
              unsigned long SampleCount){
  LADSPA_Data fGain1;  
  LADSPA_Data *pfInput;
  LADSPA_Data *pfOutput;
  Amplifier *psAmplifier;
  unsigned long lSampleIndex;
  psAmplifier = (Amplifier *)Instance;
  fGain1   = *(psAmplifier -> m_pfControlValue1);
  pfInput  = psAmplifier -> m_pfInputBuffer1;
  pfOutput = psAmplifier -> m_pfOutputBuffer1;

  for (lSampleIndex = 0;
      lSampleIndex < SampleCount; lSampleIndex++){
     *(pfOutput++) = *(pfInput++) * pow(10,fGain1/20.0);
  }
}
/**********************************************************/
void cleanupAmplifier(LADSPA_Handle Instance) {
  free(Instance);
}
/**********************************************************/
LADSPA_Descriptor * g_psDescriptor = NULL;
/**********************************************************/
void _init() {
  char ** pcPortNames;
  LADSPA_PortDescriptor * piPortDescriptors;
  /* スライドなど 構造体 */
  LADSPA_PortRangeHint * psPortRangeHints;
  int portsNum = 8; /* ポートの数 */
  /* メモリ確保 */
  g_psDescriptor
     = (LADSPA_Descriptor *)malloc(sizeof(LADSPA_Descriptor));
  /*  */
  if (g_psDescriptor) {
    /* Audacityに表示する情報 */
    g_psDescriptor -> UniqueID = 3;
    g_psDescriptor -> Label= strdup("GUI");
    g_psDescriptor -> Properties = LADSPA_PROPERTY_HARD_RT_CAPABLE;
    g_psDescriptor -> Name  = strdup("Namagi: GUI ver 150801");
    g_psDescriptor -> Maker = strdup("Namagi Products");
    g_psDescriptor -> Copyright = strdup("None");
    g_psDescriptor -> PortCount = portsNum;
    /* メモリ確保 */
    piPortDescriptors
       = (LADSPA_PortDescriptor *)calloc(portsNum,
        sizeof(LADSPA_PortDescriptor));
    /*  */
    g_psDescriptor -> PortDescriptors
       = (const LADSPA_PortDescriptor *)piPortDescriptors;
    /* ポートの関連付け */
    piPortDescriptors[AMP_CONTROL1]
       = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
    piPortDescriptors[AMP_INPUT1]  
       = LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO;
    piPortDescriptors[AMP_OUTPUT1] 
       = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO;
    /* メモリ確保 */
    pcPortNames = (char **)calloc(portsNum, sizeof(char *));
    /*  */
    g_psDescriptor -> PortNames = (const char **)pcPortNames;

    /* ポート名 */
    pcPortNames[AMP_CONTROL1] = strdup("Gain(dB)");
    pcPortNames[AMP_CKBOX1] = strdup("checkbox1");
    pcPortNames[AMP_CKBOX2] = strdup("checkbox2");
    pcPortNames[AMP_CONTROL2] = strdup("freq(Hz)");
    pcPortNames[AMP_CONTROL3] = strdup("log");
    /* 日本語は使えない サンプルはラベル内での改行*/
    pcPortNames[AMP_CONTROL4]
         = strdup("INTEGER\n0-OFF\n1-HPF1\n2-HPF2\n3-LPF2");

    pcPortNames[AMP_INPUT1] = strdup("Input");
    pcPortNames[AMP_OUTPUT1] = strdup("Output");

    /* メモリ確保 ポート数を修正 */
    psPortRangeHints
         = ((LADSPA_PortRangeHint *)calloc(portsNum,
           sizeof(LADSPA_PortRangeHint)));
    /*  */
    g_psDescriptor -> PortRangeHints
         = (const LADSPA_PortRangeHint *)psPortRangeHints;


/* 1段目 スライダーの範囲と初期値 */
    psPortRangeHints[AMP_CONTROL1].HintDescriptor
         = (LADSPA_HINT_BOUNDED_BELOW 
        | LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_DEFAULT_0);
    psPortRangeHints[AMP_CONTROL1].LowerBound
         =(LADSPA_Data)MIN_GAIN1;/* 12dB */
    psPortRangeHints[AMP_CONTROL1].UpperBound
         =(LADSPA_Data)MAX_GAIN1;/* -12dB */

/* 2段目 checkbox1 */
    psPortRangeHints[AMP_CKBOX1].HintDescriptor
         = (LADSPA_HINT_TOGGLED | LADSPA_HINT_DEFAULT_0);

/* 3段目 checkbox2 */
    psPortRangeHints[AMP_CKBOX2].HintDescriptor
         = (LADSPA_HINT_TOGGLED | LADSPA_HINT_DEFAULT_1);

/* 4段目 周波数スライダ  サンプリング周波数を上限に設定 */
    psPortRangeHints[AMP_CONTROL2].HintDescriptor
         = (LADSPA_HINT_LOGARITHMIC | 
         LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE
         | LADSPA_HINT_SAMPLE_RATE);
    psPortRangeHints[AMP_CONTROL2].LowerBound =0;/* */
     /* 0=0, 0.5=22050, 1=44100, 2=88200 */
    psPortRangeHints[AMP_CONTROL2].UpperBound =1;

/* 5段目 対数スライダ 無視されている */
    psPortRangeHints[AMP_CONTROL3].HintDescriptor
         = (LADSPA_HINT_LOGARITHMIC | LADSPA_HINT_BOUNDED_BELOW 
         | LADSPA_HINT_BOUNDED_ABOVE);
    psPortRangeHints[AMP_CONTROL3].LowerBound =0;/* */
    psPortRangeHints[AMP_CONTROL3].UpperBound =1000;/* */

/* 6段目 選択式 ラジオボタンの代わり 0,1,2,3 */
    psPortRangeHints[AMP_CONTROL4].HintDescriptor
         = (LADSPA_HINT_INTEGER | LADSPA_HINT_BOUNDED_BELOW
         | LADSPA_HINT_BOUNDED_ABOVE);
    psPortRangeHints[AMP_CONTROL4].LowerBound =0;/* */
    psPortRangeHints[AMP_CONTROL4].UpperBound =3;/* */
    
    
    
    /* input output */
    psPortRangeHints[AMP_INPUT1].HintDescriptor = 0;
    psPortRangeHints[AMP_OUTPUT1].HintDescriptor = 0;
    
    /* 初期値を入れる 関数の登録 */
    g_psDescriptor -> instantiate   = instantiateAmplifier;
    g_psDescriptor -> connect_port  = connectPortToAmplifier;
    g_psDescriptor -> activate      = NULL;
    g_psDescriptor -> run           = runAmplifier;
    g_psDescriptor -> run_adding    = NULL;
    g_psDescriptor -> set_run_adding_gain  = NULL;
    g_psDescriptor -> deactivate    = NULL;
    g_psDescriptor -> cleanup       = cleanupAmplifier;
  }
}
/**********************************************************/
void deleteDescriptor(LADSPA_Descriptor * psDescriptor){
  unsigned long lIndex;
  if (psDescriptor){
    free((char *)psDescriptor -> Label);
    free((char *)psDescriptor -> Name);
    free((char *)psDescriptor -> Maker);
    free((char *)psDescriptor -> Copyright);
    free((LADSPA_PortDescriptor *)psDescriptor -> PortDescriptors);

    for (lIndex=0; lIndex < psDescriptor -> PortCount; lIndex++){
      free((char *)(psDescriptor -> PortNames[lIndex]));
    }

    free((char **)psDescriptor -> PortNames);
    free((LADSPA_PortRangeHint *)psDescriptor -> PortRangeHints);
    free(psDescriptor);
  }
}
/**********************************************************/
void _fini(){
  deleteDescriptor(g_psDescriptor);
}
/**********************************************************/
_WINDOWS_DLL_EXPORT_
const LADSPA_Descriptor *ladspa_descriptor(unsigned long Index){
   #ifdef WIN32
    if (bIsFirstTime) {
       _init();
       bIsFirstTime = 0;
    }
    #endif
    if (Index == 0)
       return g_psDescriptor;
    else
       return NULL;
}


LADSPAをAudacityで起動したときに表示される領域

下の絵は20個のパラメーターがあるエフェクトだが、起動直後では15個までしか表示されない。 全てを表示させたいときは、マウスでウィンドウサイズを広げてやる必要がある。 現状では15個以内にした方がよさそうだ。

下はウィンドウを広げて全てのパラメーターを表示させた状態。


sound programming 目次はこちら