Reverbの自作5 Schroederのアルゴリズム

なんとかリバーブらしいものまでこぎつけた。約2日使ってしまった。プログラミングだけなら1日かからないで出来たのだろうけど、Blogにまとめておく作業が半分以上という感じ。まとめる作業って馬鹿に出来ないぐらい時間がかかる。でもこの作業をしておくことが大事。

Schroederによるリバーブアルゴリズム

1960年代の初期デジタルリバーブであるManfred Robert Schroeder(シュレーダー)のアルゴリズムをなぞってみる。内部的にはcomb fileterを4つ並列でつないで、その後にall-pass fileterを2個直列でつないでいる構造が、もっとも基本的なパターンらしい。comb fileterで長めの残響を作り出し、all-pass fileterで密度を上げ補間するような構造になっている。パラーメータを工夫することでリバーブの後部残響を生成することができる。リバーブの初期反射は別の構造なので、そのうち取り上げたいと思う。

上図はリバーブで作り出した音を色分けしたもの。大雑把に青が直接音で、赤が初期反響音、水色が後部残響音となる。

ブロック図

ブロック図の作図手段が悩みどころ。毎回違うソフトを使っているのだが、今回フリーの汎用CADソフトjwwで描いてみた。この手の作業はCADが一番ストレスないわ。簡単に出来そうなソフトほど苦労するので、はじめから本格的なものを使った方が早かったというオチ。


設定値は残響時間を基本に遅延時間、フィードバックゲインを下記計算式を使って調整していく。combの遅延時間は30から45msec程度で、最小値と最大値の比率は約1.5がよいらしい。また遅延時間は相互に重ならないように、サンプル数が素数になるように、うまく組合わせる必要がある。手計算だとパラメーターの設定だけでも面倒なことになる。今回は基本的なしくみを知りたいだけなので、自動計算などはさせずに、ダイレクトに設定できるように作ってみた。設定値でどう音が変化するかを知るのが大きな目的。allpassは遅延時間が短めで、5msec、1.7msecとあったので、ほぼそのまま採用することにした。allpassのフィードバックゲインも推奨値があり0.7。

Tr: 残響時間 60dB減衰する時間
g: フィードバックゲイン
タウ: 遅延時間(ディレイタイム)


Schroeder Reverb Audacity用 LADSPAプラグイン for Windows

Audacityでの利用画面。各comb、all-passのパラメーターを個別で操作できるようにした。またDRYとWETのgainを設けてみた。このプログラムのall-passはcombを通ったものしか扱わないので、all-passだけ通すということはできない。


LADSPAの問題

LADSPAのインターフェイスの問題。スライダーが多くなると全体を表示しきれないので、ウィンドウを広げてやる必要がある。毎回これをやるというのも・・・ スクロールでアクセスするのもスマートでない。やはり一番の問題はパラメーターの数値が保存できないこと。毎回入力する必要がある。それに近似値扱いという歯切れの悪さ。もうLADSPAを使うのはこれでおしまいにしようと思う。LV2もAudacityで使うとなると、似た問題が出そうなので、やっぱり完全自作しかないかも。

デルタ関数に適用してみる インパルス応答

残響1.5秒で設定している。リバーブらしいインパルス応答が得られている。DRYを1.0に設定しているので、0timeにデルタ関数がそのまま残っている。30msec後からがリバーブの波形。


実際に使ってみる

実際いくつかの音にリバーブをかけてみた。下のサンプルは以前録音したエレクトリックギターにリバーブをかけてみたところ。遅延時間はサンプル数で素数が好ましいので、なるべく素数になるようにして設定してみた。計算はMaximaを使っている。本来は素数のチェックなんてやってられないのでプラグインの中で自動計算させるべきだろう。今は実験なのでそこまではやらない。残響時間は1.5秒で計算。all-passに関してはfeedbackは推奨値である0.7に設定している。

設定値
残響 1.5秒
サンプリング周波数 44100Hz
comb1: 39.0msec
feedback1: 0.83560301823125
comb2: 36.7msec
feedback2: 0.84450067298951
comb3: 33.2msec
feedback3: 0.85822270505402
comb4: 29.9msec
feedback4: 0.83214690068679
APF5: 5.05msec
feedback5: 推奨値0.7
APF6: 1.65msec
feedback6: 推奨値0.7


Audacityがver2.1.0になって、LADSPAの設定が pluginsettings.cfg ファイルに保存できるようになった。 ただ不安定で、ちゃんと書き込めないことも多いので、基本設定をここに書いておく。 ファイル場所はWinではここにある。
C:\Documents and Settings\USER\Application Data\Audacity\pluginsettings.cfg

Parameters=APF5="1.000000000000" APF6="1.000000000000" Comb1="1.000000000000" Comb2="1.000000000000" Comb3="1.000000000000" Comb4="1.000000000000" DelayTime1(msec)="39.000000000000" DelayTime2(msec)="36.700000000000" DelayTime3(msec)="33.200000000000" DelayTime4(msec)="29.900000000000" DelayTime5(msec)="5.050000000000" DelayTime6(msec)="1.650000000000" Dry="1.000000000000" Feedback1="0.83560301823125" Feedback2="0.84450067298951" Feedback3="0.85822270505402" Feedback4="0.83214690068679" Feedback5="0.7000000" Feedback6="0.70000" Wet="0.180000007153"

ドライ(リバーブなしのオリジナル)

Schroeder Reverb 残響 1.5sec

金属が反響しているような音になっているが、パラメーターを工夫すれば現状でも使えなくもないという印象。

今後

リバーブの密度が薄いので、これを上げていくためにはall-pass部分の改良が必要。入れ子にして使うとよいみたいだ。 リバーブの後部残響の基礎が少し見えてきたので、今後はオリジナル要素も入れて改良をしていく。また初期反射は別のエフェクターとして考えていくつもり。

Schroeder Reverb ソースコード LADSPA

ダラダラと無駄の多いソースになってしまっているが、実験用なのでいいでしょう。分かりやすさを優先。
/* namagi_schroeder.c 2013.01.27
compile win
gcc -shared -o namagi_schroeder.dll namagi_schroeder.c -ID
compile linux
gcc -fPIC -DPIC -shared -nostartfiles -o 
namagi_schroeder.so namagi_schroeder.c
*/
/***********************************************************/
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "ladspa.h"
#define MAX_DELAY       100

#define COMB_CHECKBOX1   0
#define COMB_DELAY1      1
#define COMB_FEEDBACK1   2

#define COMB_CHECKBOX2   3
#define COMB_DELAY2      4
#define COMB_FEEDBACK2   5

#define COMB_CHECKBOX3   6
#define COMB_DELAY3      7
#define COMB_FEEDBACK3   8

#define COMB_CHECKBOX4   9
#define COMB_DELAY4      10
#define COMB_FEEDBACK4   11

#define APF_CHECKBOX5    12
#define APF_DELAY5       13
#define APF_FEEDBACK5    14

#define APF_CHECKBOX6    15
#define APF_DELAY6       16
#define APF_FEEDBACK6    17

#define DRY              18
#define WET              19

#define SCH_INPUT        20
#define SCH_OUTPUT       21
/***********************************************************/
/* 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;
  LADSPA_Data *m_pfBuffer3;
  LADSPA_Data *m_pfBuffer4;
  LADSPA_Data *m_pfBuffer5;
  LADSPA_Data *m_pfBuffer6;  
  unsigned long m_lBufferSize1;
  unsigned long m_lBufferSize2;
  unsigned long m_lBufferSize3;
  unsigned long m_lBufferSize4;
  unsigned long m_lBufferSize5;
  unsigned long m_lBufferSize6;
  unsigned long m_lWritePointer1;
  unsigned long m_lWritePointer2;
  unsigned long m_lWritePointer3;
  unsigned long m_lWritePointer4;
  unsigned long m_lWritePointer5;
  unsigned long m_lWritePointer6;
  LADSPA_Data *m_pfCheckBox1;
  LADSPA_Data *m_pfCheckBox2;
  LADSPA_Data *m_pfCheckBox3;
  LADSPA_Data *m_pfCheckBox4;
  LADSPA_Data *m_pfCheckBox5;
  LADSPA_Data *m_pfCheckBox6;
  LADSPA_Data *m_pfDelay1;
  LADSPA_Data *m_pfDelay2;
  LADSPA_Data *m_pfDelay3;
  LADSPA_Data *m_pfDelay4;
  LADSPA_Data *m_pfDelay5;
  LADSPA_Data *m_pfDelay6;
  LADSPA_Data *m_pfFeedback1;
  LADSPA_Data *m_pfFeedback2;
  LADSPA_Data *m_pfFeedback3;
  LADSPA_Data *m_pfFeedback4;
  LADSPA_Data *m_pfFeedback5;
  LADSPA_Data *m_pfFeedback6;
  LADSPA_Data *m_pfDry;
  LADSPA_Data *m_pfWet;
  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_lBufferSize3 = 1;
  while (psDelayLine ->
    m_lBufferSize3 < lMinimumBufferSize)
    psDelayLine -> m_lBufferSize3 <<= 1;
  psDelayLine -> m_lBufferSize4 = 1;
  while (psDelayLine ->
    m_lBufferSize4 < lMinimumBufferSize)
    psDelayLine -> m_lBufferSize4 <<= 1;
  psDelayLine -> m_lBufferSize5 = 1;
  while (psDelayLine ->
    m_lBufferSize5 < lMinimumBufferSize)
    psDelayLine -> m_lBufferSize5 <<= 1;
  psDelayLine -> m_lBufferSize6 = 1;
  while (psDelayLine ->
    m_lBufferSize6 < lMinimumBufferSize)
    psDelayLine -> m_lBufferSize6 <<= 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));
  psDelayLine -> m_pfBuffer3 = 
    (LADSPA_Data *)calloc(psDelayLine ->
     m_lBufferSize3, sizeof(LADSPA_Data));
  psDelayLine -> m_pfBuffer4 = 
    (LADSPA_Data *)calloc(psDelayLine ->
     m_lBufferSize4, sizeof(LADSPA_Data));
  psDelayLine -> m_pfBuffer5 = 
    (LADSPA_Data *)calloc(psDelayLine ->
     m_lBufferSize5, sizeof(LADSPA_Data));
  psDelayLine -> m_pfBuffer6 = 
    (LADSPA_Data *)calloc(psDelayLine ->
     m_lBufferSize6, sizeof(LADSPA_Data));

  if (psDelayLine -> m_pfBuffer1 == NULL) {
    free(psDelayLine);
    return NULL;
  }
  if (psDelayLine -> m_pfBuffer2 == NULL) {
    free(psDelayLine);
    return NULL;
  }
  if (psDelayLine -> m_pfBuffer3 == NULL) {
    free(psDelayLine);
    return NULL;
  }
  if (psDelayLine -> m_pfBuffer4 == NULL) {
    free(psDelayLine);
    return NULL;
  }
  if (psDelayLine -> m_pfBuffer5 == NULL) {
    free(psDelayLine);
    return NULL;
  }
  if (psDelayLine -> m_pfBuffer6 == NULL) {
    free(psDelayLine);
    return NULL;
  }

  psDelayLine -> m_lWritePointer1 = 0;
  psDelayLine -> m_lWritePointer2 = 0;
  psDelayLine -> m_lWritePointer3 = 0;
  psDelayLine -> m_lWritePointer4 = 0;
  psDelayLine -> m_lWritePointer5 = 0;
  psDelayLine -> m_lWritePointer6 = 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);
  memset(psSimpleDelayLine -> m_pfBuffer3, 0, 
      sizeof(LADSPA_Data) *psSimpleDelayLine ->
      m_lBufferSize3);
  memset(psSimpleDelayLine -> m_pfBuffer4, 0, 
      sizeof(LADSPA_Data) *psSimpleDelayLine ->
      m_lBufferSize4);
  memset(psSimpleDelayLine -> m_pfBuffer5, 0, 
      sizeof(LADSPA_Data) *psSimpleDelayLine ->
      m_lBufferSize5);
  memset(psSimpleDelayLine -> m_pfBuffer6, 0, 
      sizeof(LADSPA_Data) *psSimpleDelayLine ->
      m_lBufferSize6);
}
/***********************************************************/
void connectPortToSimpleDelayLine(LADSPA_Handle Instance,
         unsigned long Port,LADSPA_Data * DataLocation){
  SimpleDelayLine * psSimpleDelayLine;
  psSimpleDelayLine = (SimpleDelayLine *)Instance;
  
  switch (Port) {
  case COMB_CHECKBOX1:
    psSimpleDelayLine -> m_pfCheckBox1 = DataLocation;
    break;
  case COMB_DELAY1:
    psSimpleDelayLine -> m_pfDelay1 = DataLocation;
    break;
  case COMB_FEEDBACK1:
    psSimpleDelayLine -> m_pfFeedback1 = DataLocation;
    break;    
  case COMB_CHECKBOX2:
    psSimpleDelayLine -> m_pfCheckBox2 = DataLocation;
    break;
  case COMB_DELAY2:
    psSimpleDelayLine -> m_pfDelay2 = DataLocation;
    break;  
  case COMB_FEEDBACK2:
    psSimpleDelayLine -> m_pfFeedback2 = DataLocation;
    break;
  case COMB_CHECKBOX3:
    psSimpleDelayLine -> m_pfCheckBox3 = DataLocation;
    break;
  case COMB_DELAY3:
    psSimpleDelayLine -> m_pfDelay3 = DataLocation;
    break;  
  case COMB_FEEDBACK3:
    psSimpleDelayLine -> m_pfFeedback3 = DataLocation;
    break;
  case COMB_CHECKBOX4:
    psSimpleDelayLine -> m_pfCheckBox4 = DataLocation;
    break;
  case COMB_DELAY4:
    psSimpleDelayLine -> m_pfDelay4 = DataLocation;
    break;  
  case COMB_FEEDBACK4:
    psSimpleDelayLine -> m_pfFeedback4 = DataLocation;
    break;
  case APF_CHECKBOX5:
    psSimpleDelayLine -> m_pfCheckBox5 = DataLocation;
    break;
  case APF_DELAY5:
    psSimpleDelayLine -> m_pfDelay5 = DataLocation;
    break;  
  case APF_FEEDBACK5:
    psSimpleDelayLine -> m_pfFeedback5 = DataLocation;
    break;
  case APF_CHECKBOX6:
    psSimpleDelayLine -> m_pfCheckBox6 = DataLocation;
    break;
  case APF_DELAY6:
    psSimpleDelayLine -> m_pfDelay6 = DataLocation;
    break;  
  case APF_FEEDBACK6:
    psSimpleDelayLine -> m_pfFeedback6 = DataLocation;
    break;
  case DRY:
    psSimpleDelayLine -> m_pfDry = DataLocation;
    break;
  case WET:
    psSimpleDelayLine -> m_pfWet = DataLocation;
    break;
  case SCH_INPUT:
    psSimpleDelayLine -> m_pfInput = DataLocation;
    break;
  case SCH_OUTPUT:
    psSimpleDelayLine -> m_pfOutput = DataLocation;
    break;
  }
}
/***********************************************************/
void runSimpleDelayLine(LADSPA_Handle Instance, 
                    unsigned long SampleCount){
  LADSPA_Data *pfBuffer1;
  LADSPA_Data *pfBuffer2;
  LADSPA_Data *pfBuffer3;
  LADSPA_Data *pfBuffer4;
  LADSPA_Data *pfBuffer5;
  LADSPA_Data *pfBuffer6;
  LADSPA_Data *pfInput;
  LADSPA_Data *pfOutput;
  LADSPA_Data fInputSample;
  LADSPA_Data fOutputSample;
  LADSPA_Data fOutputSample1;
  LADSPA_Data fOutputSample2;
  LADSPA_Data fOutputSample3;
  LADSPA_Data fOutputSample4;
  LADSPA_Data fOutputSample5;
  LADSPA_Data fFeedback1;
  LADSPA_Data fFeedback2;
  LADSPA_Data fFeedback3;
  LADSPA_Data fFeedback4;
  LADSPA_Data fFeedback5;
  LADSPA_Data fFeedback6;
  LADSPA_Data fCheckBox1;
  LADSPA_Data fCheckBox2;
  LADSPA_Data fCheckBox3;
  LADSPA_Data fCheckBox4;
  LADSPA_Data fCheckBox5;
  LADSPA_Data fCheckBox6;
  LADSPA_Data fWet;
  LADSPA_Data fDry;
  SimpleDelayLine *psSimpleDelayLine;
  unsigned long lBufferReadOffset1;
  unsigned long lBufferReadOffset2;
  unsigned long lBufferReadOffset3;
  unsigned long lBufferReadOffset4;
  unsigned long lBufferReadOffset5;
  unsigned long lBufferReadOffset6;
  unsigned long lBufferSizeMinusOne1;
  unsigned long lBufferSizeMinusOne2;
  unsigned long lBufferSizeMinusOne3;
  unsigned long lBufferSizeMinusOne4;
  unsigned long lBufferSizeMinusOne5;
  unsigned long lBufferSizeMinusOne6;
  unsigned long lBufferWriteOffset1;
  unsigned long lBufferWriteOffset2;
  unsigned long lBufferWriteOffset3;
  unsigned long lBufferWriteOffset4;
  unsigned long lBufferWriteOffset5;
  unsigned long lBufferWriteOffset6;
  unsigned long lDelay1;
  unsigned long lDelay2;
  unsigned long lDelay3;
  unsigned long lDelay4;
  unsigned long lDelay5;
  unsigned long lDelay6;
  unsigned long lSampleIndex;
  psSimpleDelayLine = (SimpleDelayLine*) Instance;
  
  lBufferSizeMinusOne1 =
     psSimpleDelayLine -> m_lBufferSize1 - 1;
  lBufferSizeMinusOne2 =
     psSimpleDelayLine -> m_lBufferSize2 - 1;
  lBufferSizeMinusOne3 =
     psSimpleDelayLine -> m_lBufferSize3 - 1;
  lBufferSizeMinusOne4 =
     psSimpleDelayLine -> m_lBufferSize4 - 1;
  lBufferSizeMinusOne5 =
     psSimpleDelayLine -> m_lBufferSize5 - 1;
  lBufferSizeMinusOne6 =
     psSimpleDelayLine -> m_lBufferSize6 - 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);
  lDelay3 = (unsigned long)
  (LIMIT_BETWEEN_0_AND_MAX_DELAY(*(psSimpleDelayLine
      -> m_pfDelay3))
     *psSimpleDelayLine -> m_fSampleRate);
  lDelay4 = (unsigned long)
  (LIMIT_BETWEEN_0_AND_MAX_DELAY(*(psSimpleDelayLine
      -> m_pfDelay4))
     *psSimpleDelayLine -> m_fSampleRate);
  lDelay5 = (unsigned long)
  (LIMIT_BETWEEN_0_AND_MAX_DELAY(*(psSimpleDelayLine
      -> m_pfDelay5))
     *psSimpleDelayLine -> m_fSampleRate);
  lDelay6 = (unsigned long)
  (LIMIT_BETWEEN_0_AND_MAX_DELAY(*(psSimpleDelayLine
      -> m_pfDelay6))
     *psSimpleDelayLine -> m_fSampleRate);

  pfInput = psSimpleDelayLine -> m_pfInput;
  pfOutput = psSimpleDelayLine -> m_pfOutput;
  
  pfBuffer1 = psSimpleDelayLine -> m_pfBuffer1;
  pfBuffer2 = psSimpleDelayLine -> m_pfBuffer2;
  pfBuffer3 = psSimpleDelayLine -> m_pfBuffer3;
  pfBuffer4 = psSimpleDelayLine -> m_pfBuffer4;
  pfBuffer5 = psSimpleDelayLine -> m_pfBuffer5;
  pfBuffer6 = psSimpleDelayLine -> m_pfBuffer6;

  lBufferWriteOffset1 = 
     psSimpleDelayLine -> m_lWritePointer1;
  lBufferWriteOffset2 = 
     psSimpleDelayLine -> m_lWritePointer2;
  lBufferWriteOffset3 = 
     psSimpleDelayLine -> m_lWritePointer3;
  lBufferWriteOffset4 = 
     psSimpleDelayLine -> m_lWritePointer4;
  lBufferWriteOffset5 = 
     psSimpleDelayLine -> m_lWritePointer5;
  lBufferWriteOffset6 = 
     psSimpleDelayLine -> m_lWritePointer6;

  lBufferReadOffset1 = 
    lBufferWriteOffset1 + psSimpleDelayLine -> 
    m_lBufferSize1 - (float)lDelay1/1000;
  lBufferReadOffset2 = 
    lBufferWriteOffset2 + psSimpleDelayLine -> 
    m_lBufferSize2 - (float)lDelay2/1000;
  lBufferReadOffset3 = 
    lBufferWriteOffset3 + psSimpleDelayLine -> 
    m_lBufferSize3 - (float)lDelay3/1000;
  lBufferReadOffset4 = 
    lBufferWriteOffset4 + psSimpleDelayLine -> 
    m_lBufferSize4 - (float)lDelay4/1000;
  lBufferReadOffset5 = 
    lBufferWriteOffset5 + psSimpleDelayLine -> 
    m_lBufferSize5 - (float)lDelay5/1000;
  lBufferReadOffset6 = 
    lBufferWriteOffset6 + psSimpleDelayLine -> 
    m_lBufferSize6 - (float)lDelay6/1000;

  fFeedback1 = *(psSimpleDelayLine -> m_pfFeedback1);
  fFeedback2 = *(psSimpleDelayLine -> m_pfFeedback2);
  fFeedback3 = *(psSimpleDelayLine -> m_pfFeedback3);
  fFeedback4 = *(psSimpleDelayLine -> m_pfFeedback4);
  fFeedback5 = *(psSimpleDelayLine -> m_pfFeedback5);
  fFeedback6 = *(psSimpleDelayLine -> m_pfFeedback6);

  fDry = *(psSimpleDelayLine -> m_pfDry);
  fWet = *(psSimpleDelayLine -> m_pfWet);
  
  fCheckBox1 = *(psSimpleDelayLine -> m_pfCheckBox1);
  fCheckBox2 = *(psSimpleDelayLine -> m_pfCheckBox2);
  fCheckBox3 = *(psSimpleDelayLine -> m_pfCheckBox3);
  fCheckBox4 = *(psSimpleDelayLine -> m_pfCheckBox4); 
  fCheckBox5 = *(psSimpleDelayLine -> m_pfCheckBox5);
  fCheckBox6 = *(psSimpleDelayLine -> m_pfCheckBox6); 

  for (lSampleIndex = 0; lSampleIndex < SampleCount;
      lSampleIndex++){
      fInputSample = *(pfInput++);

/* comb 1 */
    if(fCheckBox1 == 1){
    fOutputSample1 = 
   pfBuffer1[((lSampleIndex + lBufferReadOffset1)
      & lBufferSizeMinusOne1)];
   
    pfBuffer1[((lSampleIndex + lBufferWriteOffset1)
      & lBufferSizeMinusOne1)] = 
      (fInputSample +
      fFeedback1 * pfBuffer1[((lSampleIndex +
      lBufferReadOffset1) & lBufferSizeMinusOne1)]);
     }
/* comb 2 */
    if(fCheckBox2 == 1){
    fOutputSample2 = 
   pfBuffer2[((lSampleIndex + lBufferReadOffset2)
      & lBufferSizeMinusOne2)];
   
    pfBuffer2[((lSampleIndex + lBufferWriteOffset2)
      & lBufferSizeMinusOne2)] = 
      (fInputSample +
      fFeedback2 * pfBuffer2[((lSampleIndex +
      lBufferReadOffset2) & lBufferSizeMinusOne2)]);
     }
/* comb 3 */
    if(fCheckBox3 == 1){
    fOutputSample3 = 
   pfBuffer3[((lSampleIndex + lBufferReadOffset3)
      & lBufferSizeMinusOne3)];
   
    pfBuffer3[((lSampleIndex + lBufferWriteOffset3)
      & lBufferSizeMinusOne3)] = 
      (fInputSample +
      fFeedback2 * pfBuffer3[((lSampleIndex +
      lBufferReadOffset3) & lBufferSizeMinusOne3)]);
     }
/* comb 4 */
    if(fCheckBox4 == 1){
    fOutputSample4 = 
   pfBuffer4[((lSampleIndex + lBufferReadOffset4)
      & lBufferSizeMinusOne2)];
   
    pfBuffer4[((lSampleIndex + lBufferWriteOffset4)
      & lBufferSizeMinusOne4)] = 
      (fInputSample +
      fFeedback4 * pfBuffer4[((lSampleIndex +
      lBufferReadOffset4) & lBufferSizeMinusOne4)]);
     }
/* comb mix   */
    fOutputSample = fOutputSample1 + fOutputSample2 + 
                    fOutputSample3 + fOutputSample4;
/* allpass 1 */
    if(fCheckBox5 == 1){
    fOutputSample5 = 
   -1*fFeedback5 * fOutputSample + 
      pfBuffer5[((lSampleIndex + lBufferReadOffset5)
       & lBufferSizeMinusOne5)];
   
    pfBuffer5[((lSampleIndex + lBufferWriteOffset5)
      & lBufferSizeMinusOne5)] = (fOutputSample +
      fFeedback5 * pfBuffer5[((lSampleIndex +
      lBufferReadOffset5) & lBufferSizeMinusOne5)]);
     }else{ /* CheckBox == 0 */
     fOutputSample5 = fOutputSample;
     }
/* allpass 2 */
    if(fCheckBox6 == 1){
 *(pfOutput++) = fWet * (-1*fFeedback6 * fOutputSample5 + 
     pfBuffer6[((lSampleIndex + lBufferReadOffset6)
     & lBufferSizeMinusOne6)])+ fDry * fInputSample;

    pfBuffer6[((lSampleIndex + lBufferWriteOffset6)
      & lBufferSizeMinusOne6)] = 
      (fOutputSample5 +
      fFeedback6 * pfBuffer6[((lSampleIndex +
      lBufferReadOffset6) & lBufferSizeMinusOne6)]);
    }else{ /* CheckBox == 0 */
    *(pfOutput++) = fWet * fOutputSample5 + fDry * fInputSample;
    }
  }
  psSimpleDelayLine -> m_lWritePointer1
    = ((psSimpleDelayLine -> m_lWritePointer1 + SampleCount)
    & lBufferSizeMinusOne1);
  psSimpleDelayLine -> m_lWritePointer2
    = ((psSimpleDelayLine -> m_lWritePointer2 + SampleCount)
    & lBufferSizeMinusOne2);
  psSimpleDelayLine -> m_lWritePointer3
    = ((psSimpleDelayLine -> m_lWritePointer3 + SampleCount)
    & lBufferSizeMinusOne3);
  psSimpleDelayLine -> m_lWritePointer4
    = ((psSimpleDelayLine -> m_lWritePointer4 + SampleCount)
    & lBufferSizeMinusOne4);
  psSimpleDelayLine -> m_lWritePointer5
    = ((psSimpleDelayLine -> m_lWritePointer5 + SampleCount)
    & lBufferSizeMinusOne5);
  psSimpleDelayLine -> m_lWritePointer6
    = ((psSimpleDelayLine -> m_lWritePointer6 + SampleCount)
    & lBufferSizeMinusOne6);
}
/***********************************************************/
void cleanupSimpleDelayLine(LADSPA_Handle Instance){
  SimpleDelayLine * psSimpleDelayLine;
  psSimpleDelayLine = (SimpleDelayLine *)Instance;
  free(psSimpleDelayLine -> m_pfBuffer1);
  free(psSimpleDelayLine -> m_pfBuffer2);
  free(psSimpleDelayLine -> m_pfBuffer3);
  free(psSimpleDelayLine -> m_pfBuffer4);
  free(psSimpleDelayLine -> m_pfBuffer5);
  free(psSimpleDelayLine -> m_pfBuffer6);
  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 = 14;
    g_psDescriptor->Label = 
       strdup("Schroeder");
    g_psDescriptor->Properties = 
       LADSPA_PROPERTY_HARD_RT_CAPABLE;
    g_psDescriptor->Name = 
       strdup("Namagi: Schroeder ver.130127");
    g_psDescriptor->Maker = 
       strdup("Namagi Products");
    g_psDescriptor->Copyright = 
      strdup("None");
      
    g_psDescriptor->PortCount = 22;
    piPortDescriptors = 
      (LADSPA_PortDescriptor *)calloc(22,
       sizeof(LADSPA_PortDescriptor));
    g_psDescriptor -> PortDescriptors = 
      (const LADSPA_PortDescriptor *)piPortDescriptors;
/*comb1*/
    piPortDescriptors[COMB_CHECKBOX1] =
       LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
    piPortDescriptors[COMB_DELAY1] =
       LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
    piPortDescriptors[COMB_FEEDBACK2] =
       LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
/*comb2*/
    piPortDescriptors[COMB_CHECKBOX2] =
       LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
    piPortDescriptors[COMB_DELAY2] =
       LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
    piPortDescriptors[COMB_FEEDBACK1] =
       LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
/*comb3*/
    piPortDescriptors[COMB_CHECKBOX3] =
       LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
    piPortDescriptors[COMB_DELAY3] =
       LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
    piPortDescriptors[COMB_FEEDBACK3] =
       LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
/*comb4*/
    piPortDescriptors[COMB_CHECKBOX4] =
       LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
    piPortDescriptors[COMB_DELAY4] =
       LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
    piPortDescriptors[COMB_FEEDBACK4] =
       LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
/*apf5*/
    piPortDescriptors[APF_CHECKBOX5] =
       LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
    piPortDescriptors[APF_DELAY5] =
       LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
    piPortDescriptors[APF_FEEDBACK5] =
       LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
/*apf6*/
    piPortDescriptors[APF_CHECKBOX6] =
       LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
    piPortDescriptors[APF_DELAY6] =
       LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
    piPortDescriptors[APF_FEEDBACK6] =
       LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
/*GAIN*/
    piPortDescriptors[DRY] =
       LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
    piPortDescriptors[WET] =
       LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
/*IO*/
    piPortDescriptors[SCH_INPUT] =
       LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO;
    piPortDescriptors[SCH_OUTPUT] =
       LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO;
       
    pcPortNames = (char **)calloc(22, sizeof(char *));
    g_psDescriptor->PortNames =
       (const char **)pcPortNames;

    pcPortNames[COMB_CHECKBOX1] = strdup("Comb1");
    pcPortNames[COMB_DELAY1] = strdup("DelayTime1(msec)");
    pcPortNames[COMB_FEEDBACK1] = strdup("Feedback1");

    pcPortNames[COMB_CHECKBOX2] = strdup("Comb2");
    pcPortNames[COMB_DELAY2] = strdup("DelayTime2(msec)");
    pcPortNames[COMB_FEEDBACK2] = strdup("Feedback2");

    pcPortNames[COMB_CHECKBOX3] = strdup("Comb3");
    pcPortNames[COMB_DELAY3] = strdup("DelayTime3(msec)");
    pcPortNames[COMB_FEEDBACK3] = strdup("Feedback3");

    pcPortNames[COMB_CHECKBOX4] = strdup("Comb4");
    pcPortNames[COMB_DELAY4] = strdup("DelayTime4(msec)");
    pcPortNames[COMB_FEEDBACK4] = strdup("Feedback4");

    pcPortNames[APF_CHECKBOX5] = strdup("APF5");
    pcPortNames[APF_DELAY5] = strdup("DelayTime5(msec)");
    pcPortNames[APF_FEEDBACK5] = strdup("Feedback5");

    pcPortNames[APF_CHECKBOX6] = strdup("APF6");
    pcPortNames[APF_DELAY6] = strdup("DelayTime6(msec)");
    pcPortNames[APF_FEEDBACK6] = strdup("Feedback6");

    pcPortNames[WET] = strdup("Wet");
    pcPortNames[DRY] = strdup("Dry");
    
    pcPortNames[SCH_INPUT] = strdup("Input");
    pcPortNames[SCH_OUTPUT] = strdup("Output");
    psPortRangeHints  =
       ((LADSPA_PortRangeHint *)calloc(22,
        sizeof(LADSPA_PortRangeHint)));
    g_psDescriptor -> PortRangeHints =
       (const LADSPA_PortRangeHint *)psPortRangeHints;
/* comb1 */
    psPortRangeHints[COMB_CHECKBOX1].HintDescriptor =
  (LADSPA_HINT_TOGGLED |
   LADSPA_HINT_DEFAULT_1);
      
    psPortRangeHints[COMB_DELAY1].HintDescriptor
      = (LADSPA_HINT_BOUNDED_BELOW | 
      LADSPA_HINT_BOUNDED_ABOVE | 
      LADSPA_HINT_DEFAULT_100);
    psPortRangeHints[COMB_DELAY1].LowerBound  = 0;
    psPortRangeHints[COMB_DELAY1].UpperBound  =
       (LADSPA_Data)MAX_DELAY; 

    psPortRangeHints[COMB_FEEDBACK1].HintDescriptor =
      (LADSPA_HINT_BOUNDED_BELOW |
   LADSPA_HINT_BOUNDED_ABOVE | 
   LADSPA_HINT_DEFAULT_HIGH);
    psPortRangeHints[COMB_FEEDBACK1].LowerBound = -1;
    psPortRangeHints[COMB_FEEDBACK1].UpperBound = 1;
/* comb2 */
    psPortRangeHints[COMB_CHECKBOX2].HintDescriptor =
  (LADSPA_HINT_TOGGLED |
   LADSPA_HINT_DEFAULT_1);
      
    psPortRangeHints[COMB_DELAY2].HintDescriptor
      = (LADSPA_HINT_BOUNDED_BELOW | 
      LADSPA_HINT_BOUNDED_ABOVE | 
      LADSPA_HINT_DEFAULT_100);
    psPortRangeHints[COMB_DELAY2].LowerBound  = 0;
    psPortRangeHints[COMB_DELAY2].UpperBound  =
     (LADSPA_Data)MAX_DELAY; 

    psPortRangeHints[COMB_FEEDBACK2].HintDescriptor =
      (LADSPA_HINT_BOUNDED_BELOW |
   LADSPA_HINT_BOUNDED_ABOVE | 
   LADSPA_HINT_DEFAULT_HIGH);
    psPortRangeHints[COMB_FEEDBACK2].LowerBound = -1;
    psPortRangeHints[COMB_FEEDBACK2].UpperBound = 1;
/* comb3 */
    psPortRangeHints[COMB_CHECKBOX3].HintDescriptor =
  (LADSPA_HINT_TOGGLED |
   LADSPA_HINT_DEFAULT_1);
      
    psPortRangeHints[COMB_DELAY3].HintDescriptor
      = (LADSPA_HINT_BOUNDED_BELOW | 
      LADSPA_HINT_BOUNDED_ABOVE | 
      LADSPA_HINT_DEFAULT_100);
    psPortRangeHints[COMB_DELAY3].LowerBound  = 0;
    psPortRangeHints[COMB_DELAY3].UpperBound  =
     (LADSPA_Data)MAX_DELAY; 

    psPortRangeHints[COMB_FEEDBACK3].HintDescriptor =
      (LADSPA_HINT_BOUNDED_BELOW |
   LADSPA_HINT_BOUNDED_ABOVE | 
   LADSPA_HINT_DEFAULT_HIGH);
    psPortRangeHints[COMB_FEEDBACK3].LowerBound = -1;
    psPortRangeHints[COMB_FEEDBACK3].UpperBound = 1;
/* comb4 */
    psPortRangeHints[COMB_CHECKBOX4].HintDescriptor =
  (LADSPA_HINT_TOGGLED |
   LADSPA_HINT_DEFAULT_1);
      
    psPortRangeHints[COMB_DELAY4].HintDescriptor
      = (LADSPA_HINT_BOUNDED_BELOW | 
      LADSPA_HINT_BOUNDED_ABOVE | 
      LADSPA_HINT_DEFAULT_100);
    psPortRangeHints[COMB_DELAY4].LowerBound  = 0;
    psPortRangeHints[COMB_DELAY4].UpperBound  =
     (LADSPA_Data)MAX_DELAY; 

    psPortRangeHints[COMB_FEEDBACK4].HintDescriptor =
      (LADSPA_HINT_BOUNDED_BELOW |
   LADSPA_HINT_BOUNDED_ABOVE | 
   LADSPA_HINT_DEFAULT_HIGH);
    psPortRangeHints[COMB_FEEDBACK4].LowerBound = -1;
    psPortRangeHints[COMB_FEEDBACK4].UpperBound = 1;
/* apf5 */
    psPortRangeHints[APF_CHECKBOX5].HintDescriptor =
  (LADSPA_HINT_TOGGLED |
   LADSPA_HINT_DEFAULT_1);
      
    psPortRangeHints[APF_DELAY5].HintDescriptor
      = (LADSPA_HINT_BOUNDED_BELOW | 
      LADSPA_HINT_BOUNDED_ABOVE | 
      LADSPA_HINT_DEFAULT_1);
    psPortRangeHints[APF_DELAY5].LowerBound  = 0;
    psPortRangeHints[APF_DELAY5].UpperBound  = 50;

    psPortRangeHints[APF_FEEDBACK5].HintDescriptor =
      (LADSPA_HINT_BOUNDED_BELOW |
   LADSPA_HINT_BOUNDED_ABOVE | 
   LADSPA_HINT_DEFAULT_HIGH);
    psPortRangeHints[APF_FEEDBACK5].LowerBound = -1;
    psPortRangeHints[APF_FEEDBACK5].UpperBound = 1;
/* apf6 */
    psPortRangeHints[APF_CHECKBOX6].HintDescriptor =
  (LADSPA_HINT_TOGGLED |
   LADSPA_HINT_DEFAULT_1);
      
    psPortRangeHints[APF_DELAY6].HintDescriptor
      = (LADSPA_HINT_BOUNDED_BELOW | 
      LADSPA_HINT_BOUNDED_ABOVE | 
      LADSPA_HINT_DEFAULT_1);
    psPortRangeHints[APF_DELAY6].LowerBound  = 0;
    psPortRangeHints[APF_DELAY6].UpperBound  = 50;

    psPortRangeHints[APF_FEEDBACK6].HintDescriptor =
      (LADSPA_HINT_BOUNDED_BELOW |
   LADSPA_HINT_BOUNDED_ABOVE | 
   LADSPA_HINT_DEFAULT_HIGH);
    psPortRangeHints[APF_FEEDBACK6].LowerBound = -1;
    psPortRangeHints[APF_FEEDBACK6].UpperBound = 1;
/* Gain */
    psPortRangeHints[WET].HintDescriptor =
      (LADSPA_HINT_BOUNDED_BELOW |
   LADSPA_HINT_BOUNDED_ABOVE | 
   LADSPA_HINT_DEFAULT_LOW);
    psPortRangeHints[WET].LowerBound = 0;
    psPortRangeHints[WET].UpperBound = 1;

    psPortRangeHints[DRY].HintDescriptor =
      (LADSPA_HINT_BOUNDED_BELOW |
   LADSPA_HINT_BOUNDED_ABOVE | 
   LADSPA_HINT_DEFAULT_1);
    psPortRangeHints[DRY].LowerBound = 0;
    psPortRangeHints[DRY].UpperBound = 1;

/* IO */
    psPortRangeHints[SCH_INPUT].HintDescriptor = 0;
    psPortRangeHints[SCH_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 目次