2013/01/26

Reverbの自作3 all-pass filter 直列

今回はリバーブ用のall-pass filterを直列につないでみる。ブロック図はこんな感じ。

LADSPAのインターフェイスの扱いが不慣れで、何ができるのかがよく分かっていない。いろいろやってみてチェックボックスができることが判明したので、それを採用してみた。2つのAPF(all-pass filter)をON/OFFするのに便利だからだ。ただ初期設定の方法が不明。狙い通りの数値をあらかじめ入れておくことは出来ないのか? アバウトならできるのだが・・・ 他のプラグインを見ても1/4単位ぐらいでしか設定できていないから無理なのかな。 LADSPAの拡張規格であるLV2では初期設定ファイルの読込みなどができるようなので、柔軟性はあるのだが、学習負荷が高そうだな。使い勝手で良い方法が見つからなければLV2も考えるとするか。むしろ完全自作へさっさと移行した方が幸せかもしれない。

とりあえず、立ち上げるたびに数値を入力するというスタイル。これぐらいなら入力項目数が少ないので我慢できるが、10を超えるとやってられないよね。

実際このall-pass filterはリバーブの残響密度を上げるために利用するという。そのため5msec以下の短い遅延で使う。実際にホワイトノイズに上記絵の設定を適用してみると、遅延の短さゆえにくし形的な特徴が出てしまっている。combを使うことに比べたら、かなり平坦ではあるのだが、それでも音色としてキンキンした感じは否めない。


ソースは以下の通り。

LADSPA all-pass filter 直列

/* namagi_allpass_w.c 2013.01.26
compile
gcc -shared -o namagi_allpass_w.dll namagi_allpass_w.c -ID
*/
/***********************************************************/
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "ladspa.h"
#define MAX_DELAY       100
#define APF_CHECKBOX1   0
#define APF_DELAY1      1
#define APF_FEEDBACK1   2
#define APF_CHECKBOX2   3
#define APF_DELAY2      4
#define APF_FEEDBACK2   5
#define APF_INPUT       6
#define APF_OUTPUT      7
/***********************************************************/
/* Win用設定 */
#ifdef WIN32
int bIsFirstTime = 1; 
void _init();
#endif
#ifdef WIN32
    #define _WINDOWS_DLL_EXPORT_ __declspec(dllexport)
#else
    #define _WINDOWS_DLL_EXPORT_ 
#endif
/***********************************************************/
#define LIMIT_BETWEEN_0_AND_MAX_DELAY(x)  \
(((x) < 0) ? 0 : (((x) > MAX_DELAY) ? MAX_DELAY : (x)))
/***********************************************************/
typedef struct {
  LADSPA_Data m_fSampleRate; 
  LADSPA_Data *m_pfBuffer1;
  LADSPA_Data *m_pfBuffer2;
  unsigned long m_lBufferSize1;
  unsigned long m_lBufferSize2;
  unsigned long m_lWritePointer1;
  unsigned long m_lWritePointer2;
  LADSPA_Data *m_pfCheckBox1;
  LADSPA_Data *m_pfCheckBox2;
  LADSPA_Data *m_pfDelay1;
  LADSPA_Data *m_pfDelay2;
  LADSPA_Data *m_pfFeedback1;
  LADSPA_Data *m_pfFeedback2;
  LADSPA_Data *m_pfInput;
  LADSPA_Data *m_pfOutput;
} SimpleDelayLine;
/***********************************************************/
LADSPA_Handle 
instantiateSimpleDelayLine(const LADSPA_Descriptor
      * Descriptor, unsigned long SampleRate){
  unsigned long lMinimumBufferSize;
  SimpleDelayLine * psDelayLine;
  psDelayLine =
    (SimpleDelayLine *)malloc(sizeof(SimpleDelayLine));
  if (psDelayLine == NULL) return NULL;
  
  psDelayLine -> m_fSampleRate =
     (LADSPA_Data)SampleRate;
  lMinimumBufferSize = (LADSPA_Data)SampleRate;
  
  psDelayLine -> m_lBufferSize1 = 1;
  while (psDelayLine ->
    m_lBufferSize1 < lMinimumBufferSize)
    psDelayLine -> m_lBufferSize1 <<= 1;
    
  psDelayLine -> m_lBufferSize2 = 1;
  while (psDelayLine ->
    m_lBufferSize2 < lMinimumBufferSize)
    psDelayLine -> m_lBufferSize2 <<= 1;

  psDelayLine -> m_pfBuffer1 = 
    (LADSPA_Data *)calloc(psDelayLine ->
     m_lBufferSize1, sizeof(LADSPA_Data));
  psDelayLine -> m_pfBuffer2 = 
    (LADSPA_Data *)calloc(psDelayLine ->
     m_lBufferSize2, sizeof(LADSPA_Data));

  if (psDelayLine -> m_pfBuffer1 == NULL) {
    free(psDelayLine);
    return NULL;
  }
  if (psDelayLine -> m_pfBuffer2 == NULL) {
    free(psDelayLine);
    return NULL;
  }
  psDelayLine -> m_lWritePointer1 = 0;
  psDelayLine -> m_lWritePointer2 = 0;
  return psDelayLine;
}
/***********************************************************/
void activateSimpleDelayLine(LADSPA_Handle Instance) {
  SimpleDelayLine *psSimpleDelayLine;
  psSimpleDelayLine = (SimpleDelayLine *)Instance;
  memset(psSimpleDelayLine -> m_pfBuffer1, 0, 
      sizeof(LADSPA_Data) *psSimpleDelayLine ->
      m_lBufferSize1);
  memset(psSimpleDelayLine -> m_pfBuffer2, 0, 
      sizeof(LADSPA_Data) *psSimpleDelayLine ->
      m_lBufferSize2);
}
/***********************************************************/
void connectPortToSimpleDelayLine(LADSPA_Handle Instance,
         unsigned long Port,LADSPA_Data * DataLocation){
  SimpleDelayLine * psSimpleDelayLine;
  psSimpleDelayLine = (SimpleDelayLine *)Instance;
  
  switch (Port) {
  case APF_CHECKBOX1:
    psSimpleDelayLine -> m_pfCheckBox1 = DataLocation;
    break;
  case APF_DELAY1:
    psSimpleDelayLine -> m_pfDelay1 = DataLocation;
    break;
  case APF_FEEDBACK1:
    psSimpleDelayLine -> m_pfFeedback1 = DataLocation;
    break;    
  case APF_CHECKBOX2:
    psSimpleDelayLine -> m_pfCheckBox2 = DataLocation;
    break;
  case APF_DELAY2:
    psSimpleDelayLine -> m_pfDelay2 = DataLocation;
    break;  
  case APF_FEEDBACK2:
    psSimpleDelayLine -> m_pfFeedback2 = DataLocation;
    break;
  case APF_INPUT:
    psSimpleDelayLine -> m_pfInput = DataLocation;
    break;
  case APF_OUTPUT:
    psSimpleDelayLine -> m_pfOutput = DataLocation;
    break;
  }
}
/***********************************************************/
void runSimpleDelayLine(LADSPA_Handle Instance, 
                    unsigned long SampleCount){
  LADSPA_Data *pfBuffer1;
  LADSPA_Data *pfBuffer2;
  LADSPA_Data *pfInput;
  LADSPA_Data *pfOutput;
  LADSPA_Data fInputSample;
  LADSPA_Data fOutputSample;
  LADSPA_Data fFeedback1;
  LADSPA_Data fFeedback2;
  LADSPA_Data fCheckBox1;
  LADSPA_Data fCheckBox2;
  SimpleDelayLine *psSimpleDelayLine;
  unsigned long lBufferReadOffset1;
  unsigned long lBufferReadOffset2;
  unsigned long lBufferSizeMinusOne1;
  unsigned long lBufferSizeMinusOne2;
  unsigned long lBufferWriteOffset1;
  unsigned long lBufferWriteOffset2;
  unsigned long lDelay1;
  unsigned long lDelay2;
  unsigned long lSampleIndex;
  psSimpleDelayLine = (SimpleDelayLine*) Instance;
  
  lBufferSizeMinusOne1 =
     psSimpleDelayLine -> m_lBufferSize1 - 1;
  lBufferSizeMinusOne2 =
     psSimpleDelayLine -> m_lBufferSize2 - 1;
  
  lDelay1 = (unsigned long)
  (LIMIT_BETWEEN_0_AND_MAX_DELAY(*(psSimpleDelayLine
      -> m_pfDelay1))
     *psSimpleDelayLine -> m_fSampleRate);
  lDelay2 = (unsigned long)
  (LIMIT_BETWEEN_0_AND_MAX_DELAY(*(psSimpleDelayLine
      -> m_pfDelay2))
     *psSimpleDelayLine -> m_fSampleRate);
  
  pfInput = psSimpleDelayLine -> m_pfInput;
  pfOutput = psSimpleDelayLine -> m_pfOutput;
  
  pfBuffer1 = psSimpleDelayLine -> m_pfBuffer1;
  pfBuffer2 = psSimpleDelayLine -> m_pfBuffer2;
  
  lBufferWriteOffset1 = 
     psSimpleDelayLine -> m_lWritePointer1;
  lBufferWriteOffset2 = 
     psSimpleDelayLine -> m_lWritePointer2;
  
  lBufferReadOffset1 = 
    lBufferWriteOffset1 + psSimpleDelayLine -> 
    m_lBufferSize1 - (float)lDelay1/1000;
  lBufferReadOffset2 = 
    lBufferWriteOffset2 + psSimpleDelayLine -> 
    m_lBufferSize2 - (float)lDelay2/1000;
    
  fFeedback1 = *(psSimpleDelayLine -> m_pfFeedback1);
  fFeedback2 = *(psSimpleDelayLine -> m_pfFeedback2);
  fCheckBox1 = *(psSimpleDelayLine -> m_pfCheckBox1);
  fCheckBox2 = *(psSimpleDelayLine -> m_pfCheckBox2);
  
  for (lSampleIndex = 0; lSampleIndex < SampleCount;
      lSampleIndex++){
      fInputSample = *(pfInput++);

    /* allpass 1 */
    if(fCheckBox1 == 1){
    fOutputSample = 
   -1*fFeedback1 * fInputSample + 
      pfBuffer1[((lSampleIndex + lBufferReadOffset1)
       & lBufferSizeMinusOne1)];
   
    pfBuffer1[((lSampleIndex + lBufferWriteOffset1)
      & lBufferSizeMinusOne1)] = 
      (fInputSample +
      fFeedback1 * pfBuffer1[((lSampleIndex +
      lBufferReadOffset1) & lBufferSizeMinusOne1)]);
     }else{ /* CheckBox == 0 */
     fOutputSample = fInputSample;
     }
     
    /* allpass 2 */
    if(fCheckBox2 == 1){
 *(pfOutput++) = -1*fFeedback2 * fOutputSample + 
     pfBuffer2[((lSampleIndex + lBufferReadOffset2)
     & lBufferSizeMinusOne2)];

    pfBuffer2[((lSampleIndex + lBufferWriteOffset2)
      & lBufferSizeMinusOne2)] = 
      (fOutputSample +
      fFeedback2 * pfBuffer2[((lSampleIndex +
      lBufferReadOffset2) & lBufferSizeMinusOne2)]);
    }else{ /* CheckBox == 0 */
    *(pfOutput++) = fOutputSample;
    }
  }
  psSimpleDelayLine -> m_lWritePointer1
    = ((psSimpleDelayLine -> m_lWritePointer1 +
    SampleCount) & lBufferSizeMinusOne1);
  psSimpleDelayLine -> m_lWritePointer2
    = ((psSimpleDelayLine -> m_lWritePointer2 +
    SampleCount) & lBufferSizeMinusOne2);
}
/***********************************************************/
void cleanupSimpleDelayLine(LADSPA_Handle Instance){
  SimpleDelayLine * psSimpleDelayLine;
  psSimpleDelayLine = (SimpleDelayLine *)Instance;
  free(psSimpleDelayLine -> m_pfBuffer1);
  free(psSimpleDelayLine -> m_pfBuffer2);
  free(psSimpleDelayLine);
}
/***********************************************************/
LADSPA_Descriptor *g_psDescriptor = NULL;
/***********************************************************/
void _init() {
  char ** pcPortNames;
  LADSPA_PortDescriptor * piPortDescriptors;
  LADSPA_PortRangeHint * psPortRangeHints;
  g_psDescriptor = 
    (LADSPA_Descriptor *)malloc(sizeof(LADSPA_Descriptor));
  if (g_psDescriptor) {
    g_psDescriptor->UniqueID = 12;
    g_psDescriptor->Label = 
       strdup("all-pass w");
    g_psDescriptor->Properties = 
       LADSPA_PROPERTY_HARD_RT_CAPABLE;
    g_psDescriptor->Name = 
       strdup("Namagi: all-pass w ver.130126");
    g_psDescriptor->Maker = 
       strdup("Namagi Products");
    g_psDescriptor->Copyright = 
      strdup("None");
      
    g_psDescriptor->PortCount = 8;
    piPortDescriptors = 
      (LADSPA_PortDescriptor *)calloc(8,
       sizeof(LADSPA_PortDescriptor));
    g_psDescriptor -> PortDescriptors = 
      (const LADSPA_PortDescriptor *)piPortDescriptors;

    piPortDescriptors[APF_CHECKBOX1] =
       LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
    piPortDescriptors[APF_DELAY1] =
       LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
    piPortDescriptors[APF_FEEDBACK2] =
       LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
    piPortDescriptors[APF_CHECKBOX2] =
       LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
    piPortDescriptors[APF_DELAY2] =
       LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
    piPortDescriptors[APF_FEEDBACK1] =
       LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
    piPortDescriptors[APF_INPUT] =
       LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO;
    piPortDescriptors[APF_OUTPUT] =
       LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO;
       
    pcPortNames = (char **)calloc(8, sizeof(char *));
    g_psDescriptor->PortNames =
       (const char **)pcPortNames;
    pcPortNames[APF_CHECKBOX1] = strdup("APF1");
    pcPortNames[APF_DELAY1] = strdup("DelayTime1(msec)");
    pcPortNames[APF_FEEDBACK1] = strdup("Feedback1");    
    pcPortNames[APF_CHECKBOX2] = strdup("APF2");
    pcPortNames[APF_DELAY2] = strdup("DelayTime2(msec)");
    pcPortNames[APF_FEEDBACK2] = strdup("Feedback2");
    pcPortNames[APF_INPUT] = strdup("Input");
    pcPortNames[APF_OUTPUT] = strdup("Output");
    psPortRangeHints  =
       ((LADSPA_PortRangeHint *)calloc(8,
        sizeof(LADSPA_PortRangeHint)));
    g_psDescriptor -> PortRangeHints =
       (const LADSPA_PortRangeHint *)psPortRangeHints;

    psPortRangeHints[APF_CHECKBOX1].HintDescriptor =
  (LADSPA_HINT_TOGGLED |
   LADSPA_HINT_DEFAULT_1);
      
    psPortRangeHints[APF_DELAY1].HintDescriptor
      = (LADSPA_HINT_BOUNDED_BELOW | 
      LADSPA_HINT_BOUNDED_ABOVE | 
      LADSPA_HINT_DEFAULT_100);
    psPortRangeHints[APF_DELAY1].LowerBound  = 0;
    psPortRangeHints[APF_DELAY1].UpperBound  =
       (LADSPA_Data)MAX_DELAY; 

    psPortRangeHints[APF_FEEDBACK1].HintDescriptor =
      (LADSPA_HINT_BOUNDED_BELOW |
   LADSPA_HINT_BOUNDED_ABOVE | 
   LADSPA_HINT_DEFAULT_HIGH);
    psPortRangeHints[APF_FEEDBACK1].LowerBound = -1;
    psPortRangeHints[APF_FEEDBACK1].UpperBound = 1;

    psPortRangeHints[APF_CHECKBOX2].HintDescriptor =
  (LADSPA_HINT_TOGGLED |
   LADSPA_HINT_DEFAULT_1);
      
    psPortRangeHints[APF_DELAY2].HintDescriptor
      = (LADSPA_HINT_BOUNDED_BELOW | 
      LADSPA_HINT_BOUNDED_ABOVE | 
      LADSPA_HINT_DEFAULT_100);
    psPortRangeHints[APF_DELAY2].LowerBound  = 0;
    psPortRangeHints[APF_DELAY2].UpperBound  =
     (LADSPA_Data)MAX_DELAY; 

    psPortRangeHints[APF_FEEDBACK2].HintDescriptor =
      (LADSPA_HINT_BOUNDED_BELOW |
   LADSPA_HINT_BOUNDED_ABOVE | 
   LADSPA_HINT_DEFAULT_HIGH);
    psPortRangeHints[APF_FEEDBACK2].LowerBound = -1;
    psPortRangeHints[APF_FEEDBACK2].UpperBound = 1;
    
    psPortRangeHints[APF_INPUT].HintDescriptor = 0;
    psPortRangeHints[APF_OUTPUT].HintDescriptor = 0;

    g_psDescriptor -> instantiate =
       instantiateSimpleDelayLine;
    g_psDescriptor -> connect_port =
       connectPortToSimpleDelayLine;
    g_psDescriptor -> activate =
       activateSimpleDelayLine;
    g_psDescriptor -> run = runSimpleDelayLine;
    g_psDescriptor -> run_adding = NULL;
    g_psDescriptor -> set_run_adding_gain = NULL;
    g_psDescriptor -> deactivate = NULL;
    g_psDescriptor -> cleanup =
       cleanupSimpleDelayLine;
  }
}
/***********************************************************/
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);
  }
}
/***********************************************************/
_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;
}
/***********************************************************/
/* EOF */


sound programming 目次