2015/11/16

LADSPA Fade In / Out

Audacityにも昔から built-in effects で Fade In/Out はあるのだが、直線的でやや不自然なので、滑らかに音量を変化させたい。 そこで Nyquist Effects の Adjustable Fade が標準装備されるようになり、滑らかな音量変化ができるようになったが、 これは設定ウィンドウが表示されるので、サクサク作業できない。 ということで、インターフェイスなしのLADSPAでコサインカーブを描くフェードイン/アウトにトライ。 以前にAudacity built-in effectsでも作ったのだが、内容的には全く同じ。

今回問題となったのは、インターフェイスなしのLADSPAエフェクトが作れるのか? という点。 調べるのも億劫だったので、いきなり作って試すことにした。 やってみたら難なく動作した。 下は一定音量のサイン波にフェードインを適用したところ。コサインカーブを描いているのがわかる。

下は同じようにフェードアウトを適用したところ。

注意すべき点は、Audacityでは、一度に処理するサンプル数があって、それを超えてしまうと以下のように複数回適用されてしまう。44100Hz、16bitで、約24秒が単位なので、フェードイン/アウトでこんな長い時間やることはないので、実用的には問題ない。


LADSPA Fade In ソースコード

/* namagi_fade.c
2015.11.16
compile
gcc -shared -o namagi_fadein.dll namagi_fadein.c -ID

compile Ubuntu
gcc -fPIC -DPIC -shared -nostartfiles
 -o namagi_fadein.so namagi_fadein.c
*/
/**********************************************************/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include "ladspa.h"
/**********************************************************/
#define INPUT   0
#define OUTPUT  1
/**********************************************************/
#ifdef WIN32
   int bIsFirstTime = 1; 
   void _init();
   #define _WINDOWS_DLL_EXPORT_ __declspec(dllexport)
#else
   #define _WINDOWS_DLL_EXPORT_ 
#endif
/**********************************************************/
typedef struct {
  float *m_pfInput;
  float *m_pfOutput;
} FadeIn;
/**********************************************************/
LADSPA_Handle 
instantiateFadeIn(const LADSPA_Descriptor *Descriptor,
   unsigned long SampleRate){
      return malloc(sizeof(FadeIn));
}
/**********************************************************/
void connectPortToFadeIn(LADSPA_Handle Instance, 
   unsigned long Port,LADSPA_Data *DataLocation){
   FadeIn *psFadeIn;
   psFadeIn = (FadeIn *)Instance;
   switch (Port){ 
      case INPUT:
         psFadeIn -> m_pfInput = DataLocation;
         break;
      case OUTPUT:
         psFadeIn -> m_pfOutput = DataLocation;
         break;
   }
}
/**********************************************************/
void runFadeIn(LADSPA_Handle Instance,unsigned long SampleCount){
   FadeIn *psFadeIn;
   psFadeIn = (FadeIn *)Instance;   
   float *pfInput;
   float *pfOutput;
   pfInput = psFadeIn -> m_pfInput;
   pfOutput = psFadeIn -> m_pfOutput;
   unsigned long i;
   for (i = 0; i < SampleCount; i++){
      *(pfOutput++) = *(pfInput++) * (0.5+0.5*cos((float)((i*M_PI)) /
        (float)(SampleCount)+M_PI));
   }
}
/**********************************************************/
void cleanupFadeIn(LADSPA_Handle Instance){
   free(Instance);
}
/**********************************************************/
LADSPA_Descriptor * g_psDescriptor = NULL;
/**********************************************************/
void _init() {
   char ** pcPortNames;
   LADSPA_PortDescriptor * piPortDescriptors;
   LADSPA_PortRangeHint * psPortRangeHints;
   int ports = 2;
   g_psDescriptor = (LADSPA_Descriptor *)malloc(sizeof(LADSPA_Descriptor));
   if (g_psDescriptor) {    
      g_psDescriptor -> UniqueID = 0; /* プラグインのID 0x1000000以下 */
      g_psDescriptor -> Label = strdup("fade");
      g_psDescriptor -> Properties = LADSPA_PROPERTY_HARD_RT_CAPABLE;
      g_psDescriptor -> Name = strdup("Namagi: FadeIn ver.151116");
      g_psDescriptor -> Maker = strdup("Namagi Products");
      g_psDescriptor -> Copyright = strdup("None");
      g_psDescriptor -> PortCount = ports;
      piPortDescriptors
      = (LADSPA_PortDescriptor *)calloc(ports, sizeof(LADSPA_PortDescriptor));
      g_psDescriptor -> PortDescriptors
      = (const LADSPA_PortDescriptor *)piPortDescriptors;
   piPortDescriptors[INPUT] = LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO;
   piPortDescriptors[OUTPUT] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO;
   pcPortNames  = (char **)calloc(ports, sizeof(char *));
   g_psDescriptor -> PortNames = (const char **)pcPortNames;
   pcPortNames[INPUT] = strdup("Input");
   pcPortNames[OUTPUT] = strdup("Output");
   psPortRangeHints
   = ((LADSPA_PortRangeHint *)calloc(ports, sizeof(LADSPA_PortRangeHint)));
   g_psDescriptor -> PortRangeHints
   = (const LADSPA_PortRangeHint *)psPortRangeHints;
   psPortRangeHints[INPUT].HintDescriptor = 0;
   psPortRangeHints[OUTPUT].HintDescriptor = 0;
   g_psDescriptor -> instantiate = instantiateFadeIn;
   g_psDescriptor -> connect_port = connectPortToFadeIn;
   g_psDescriptor -> activate = NULL;
   g_psDescriptor -> run = runFadeIn;
   g_psDescriptor -> run_adding  = NULL;
   g_psDescriptor -> set_run_adding_gain  = NULL;
   g_psDescriptor -> deactivate  = NULL;
   g_psDescriptor -> cleanup  = cleanupFadeIn;
   }
}
/**********************************************************/
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;
}


LADSPA Fade Out ソースコード

/* namagi_fade.c
2015.11.16
compile
gcc -shared -o namagi_fadeout.dll namagi_fadeout.c -ID

compile Ubuntu
gcc -fPIC -DPIC -shared -nostartfiles
 -o namagi_fadeout.so namagi_fadeout.c
*/
/**********************************************************/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include "ladspa.h"
/**********************************************************/
#define INPUT   0
#define OUTPUT  1
/**********************************************************/
#ifdef WIN32
   int bIsFirstTime = 1; 
   void _init();
   #define _WINDOWS_DLL_EXPORT_ __declspec(dllexport)
#else
   #define _WINDOWS_DLL_EXPORT_ 
#endif
/**********************************************************/
typedef struct {
  float *m_pfInput;
  float *m_pfOutput;
} FadeOut;
/**********************************************************/
LADSPA_Handle 
instantiateFadeOut(const LADSPA_Descriptor *Descriptor,
   unsigned long SampleRate){
      return malloc(sizeof(FadeOut));
}
/**********************************************************/
void connectPortToFadeOut(LADSPA_Handle Instance, 
   unsigned long Port,LADSPA_Data *DataLocation){
   FadeOut *psFadeOut;
   psFadeOut = (FadeOut *)Instance;
   switch (Port){ 
      case INPUT:
         psFadeOut -> m_pfInput = DataLocation;
         break;
      case OUTPUT:
         psFadeOut -> m_pfOutput = DataLocation;
         break;
   }
}
/**********************************************************/
void runFadeOut(LADSPA_Handle Instance,unsigned long SampleCount){
   FadeOut *psFadeOut;
   psFadeOut = (FadeOut *)Instance;   
   float *pfInput;
   float *pfOutput;
   pfInput = psFadeOut -> m_pfInput;
   pfOutput = psFadeOut -> m_pfOutput;
   unsigned long i;
   for (i = 0; i < SampleCount; i++){
      *(pfOutput++) = *(pfInput++) * (0.5+0.5*cos((float)((i*M_PI)) /
        (float)(SampleCount)));
   }
}
/**********************************************************/
void cleanupFadeOut(LADSPA_Handle Instance){
   free(Instance);
}
/**********************************************************/
LADSPA_Descriptor * g_psDescriptor = NULL;
/**********************************************************/
void _init() {
   char ** pcPortNames;
   LADSPA_PortDescriptor * piPortDescriptors;
   LADSPA_PortRangeHint * psPortRangeHints;
   int ports = 2;
   g_psDescriptor
   = (LADSPA_Descriptor *)malloc(sizeof(LADSPA_Descriptor));
   if (g_psDescriptor) {    
      g_psDescriptor -> UniqueID = 0;
      g_psDescriptor -> Label = strdup("fade");
      g_psDescriptor -> Properties = LADSPA_PROPERTY_HARD_RT_CAPABLE;
      g_psDescriptor -> Name = strdup("Namagi: FadeOut ver.151116");
      g_psDescriptor -> Maker = strdup("Namagi Products");
      g_psDescriptor -> Copyright = strdup("None");
      g_psDescriptor -> PortCount = ports;
      piPortDescriptors 
      = (LADSPA_PortDescriptor *)calloc(ports, sizeof(LADSPA_PortDescriptor));
      g_psDescriptor -> PortDescriptors
      = (const LADSPA_PortDescriptor *)piPortDescriptors;
   piPortDescriptors[INPUT] = LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO;
   piPortDescriptors[OUTPUT] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO;
   pcPortNames  = (char **)calloc(ports, sizeof(char *));
   g_psDescriptor -> PortNames = (const char **)pcPortNames;
   pcPortNames[INPUT] = strdup("Input");
   pcPortNames[OUTPUT] = strdup("Output");
   psPortRangeHints 
      = ((LADSPA_PortRangeHint *)calloc(ports, sizeof(LADSPA_PortRangeHint)));
   g_psDescriptor -> PortRangeHints
      = (const LADSPA_PortRangeHint *)psPortRangeHints;
   psPortRangeHints[INPUT].HintDescriptor = 0;
   psPortRangeHints[OUTPUT].HintDescriptor = 0;
   g_psDescriptor -> instantiate = instantiateFadeOut;
   g_psDescriptor -> connect_port = connectPortToFadeOut;
   g_psDescriptor -> activate = NULL;
   g_psDescriptor -> run = runFadeOut;
   g_psDescriptor -> run_adding  = NULL;
   g_psDescriptor -> set_run_adding_gain  = NULL;
   g_psDescriptor -> deactivate  = NULL;
   g_psDescriptor -> cleanup  = cleanupFadeOut;
   }
}
/**********************************************************/
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;
}


sound programming 目次