2013/01/02

C言語 LADSPA 複数サイン波生成

PADSPAプラグインを作ってみる。前回ひとつのサイン波を生成するプラグインだったので、今回は4つまで同時に生成できるようにした。

複数サイン波生成プラグイン

/* namagi_sine2.c
3013.1.2

compile windows
gcc -shared -o namagi_sine2.dll namagi_sine2.c -ID

compile Ubuntu
gcc -fPIC -DPIC -shared -nostartfiles -o namagi_sine2.so namagi_sine2.c

 */
/**********************************************************/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
/**********************************************************/
#include "ladspa.h"
#define MAX_FREQ 20000
#define MAX_GAIN 1
/**********************************************************/
#define SINE_CONTROL1 0
#define SINE_CONTROL2 1
#define SINE_CONTROL3 2
#define SINE_CONTROL4 3
#define SINE_CONTROL5 4
#define SINE_CONTROL6 5
#define SINE_CONTROL7 6
#define SINE_CONTROL8 7
#define SINE_INPUT1  8
#define SINE_OUTPUT1 9
/**********************************************************/
#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_fSampleRate;
  LADSPA_Data *m_pfControlValue1;
  LADSPA_Data *m_pfControlValue2;
  LADSPA_Data *m_pfControlValue3;
  LADSPA_Data *m_pfControlValue4;
  LADSPA_Data *m_pfControlValue5;
  LADSPA_Data *m_pfControlValue6;
  LADSPA_Data *m_pfControlValue7;
  LADSPA_Data *m_pfControlValue8;
  LADSPA_Data *m_pfInputBuffer1;
  LADSPA_Data *m_pfOutputBuffer1;
} Sine;
/**********************************************************/
LADSPA_Handle instantiateSine(
                        const LADSPA_Descriptor *Descriptor, 
                        unsigned long  SampleRate){
  Sine * psSine;
  psSine = (Sine *)malloc(sizeof(Sine));
  psSine -> m_fSampleRate = (LADSPA_Data)SampleRate;
  return psSine;
}
/**********************************************************/
void connectPortToSine(LADSPA_Handle Instance,
         unsigned long Port,
         LADSPA_Data *DataLocation) {
  Sine *psSine;
  psSine = (Sine *)Instance;

  switch (Port) {
  case SINE_CONTROL1:
    psSine -> m_pfControlValue1 = DataLocation;
    break;  
  case SINE_CONTROL2:
    psSine -> m_pfControlValue2 = DataLocation;
    break;
  case SINE_CONTROL3:
    psSine -> m_pfControlValue3 = DataLocation;
    break;  
  case SINE_CONTROL4:
    psSine -> m_pfControlValue4 = DataLocation;
    break;
  case SINE_CONTROL5:
    psSine -> m_pfControlValue5 = DataLocation;
    break;  
  case SINE_CONTROL6:
    psSine -> m_pfControlValue6 = DataLocation;
    break;
  case SINE_CONTROL7:
    psSine -> m_pfControlValue7 = DataLocation;
    break;  
  case SINE_CONTROL8:
    psSine -> m_pfControlValue8 = DataLocation;
    break;
  case SINE_INPUT1:
    psSine -> m_pfInputBuffer1 = DataLocation;
    break;
  case SINE_OUTPUT1:
    psSine -> m_pfOutputBuffer1 = DataLocation;
    break;
  }
}
/**********************************************************/
void runSine(LADSPA_Handle Instance,
             unsigned long SampleCount){
  LADSPA_Data *pfInput;
  LADSPA_Data *pfOutput;
  LADSPA_Data fSine1;
  LADSPA_Data fGain1;
  LADSPA_Data fSine2;
  LADSPA_Data fGain2;
  LADSPA_Data fSine3;
  LADSPA_Data fGain3;
  LADSPA_Data fSine4;
  LADSPA_Data fGain4; 
  float w = 0; /* 角速度 1Hz */
  Sine *psSine;
  unsigned long lSampleIndex;
  psSine = (Sine *)Instance;
  unsigned long SampleRate;
  float step = 2 * M_PI / psSine -> m_fSampleRate;
  fSine1 = *(psSine -> m_pfControlValue1);
  fGain1 = *(psSine -> m_pfControlValue2);
  fSine2 = *(psSine -> m_pfControlValue3);
  fGain2 = *(psSine -> m_pfControlValue4);
  fSine3 = *(psSine -> m_pfControlValue5);
  fGain3 = *(psSine -> m_pfControlValue6);
  fSine4 = *(psSine -> m_pfControlValue7);
  fGain4 = *(psSine -> m_pfControlValue8);
  pfInput = psSine -> m_pfInputBuffer1;
  pfOutput = psSine -> m_pfOutputBuffer1;
  for (lSampleIndex = 0; 
       lSampleIndex < SampleCount; 
       lSampleIndex++){
    *(pfOutput++) = *(pfInput++)+
                    (fGain1 * sin(w * fSine1))+
                    (fGain2 * sin(w * fSine2))+
                    (fGain3 * sin(w * fSine3))+
                    (fGain4 * sin(w * fSine4));
     w += step;
  }
}
/**********************************************************/
void cleanupSine(LADSPA_Handle Instance) {
  free(Instance);
}
/**********************************************************/
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
      = 2;
    g_psDescriptor -> Label
      = strdup("sine2");
    g_psDescriptor -> Properties
      = LADSPA_PROPERTY_HARD_RT_CAPABLE;
    g_psDescriptor -> Name 
      = strdup("Namagi: Sine2");
    g_psDescriptor -> Maker
      = strdup("Namagi Products");
    g_psDescriptor -> Copyright
      = strdup("None");
    g_psDescriptor -> PortCount
      = 10;
    piPortDescriptors
      = (LADSPA_PortDescriptor *)calloc(10, 
                         sizeof(LADSPA_PortDescriptor));
    g_psDescriptor -> PortDescriptors
      = (const LADSPA_PortDescriptor *)piPortDescriptors;

    piPortDescriptors[SINE_CONTROL1]
      = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
    piPortDescriptors[SINE_CONTROL2]
      = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
    piPortDescriptors[SINE_CONTROL3]
      = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
    piPortDescriptors[SINE_CONTROL4]
      = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
    piPortDescriptors[SINE_CONTROL5]
      = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
    piPortDescriptors[SINE_CONTROL6]
      = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
    piPortDescriptors[SINE_CONTROL7]
      = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
    piPortDescriptors[SINE_CONTROL8]
      = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
    piPortDescriptors[SINE_INPUT1]
      = LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO;
    piPortDescriptors[SINE_OUTPUT1]
      = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO;

    pcPortNames
      = (char **)calloc(8, sizeof(char *));
    g_psDescriptor -> PortNames 
      = (const char **)pcPortNames;

    pcPortNames[SINE_CONTROL1]
      = strdup("Sine1");
    pcPortNames[SINE_CONTROL2]
      = strdup("Gain1");
    pcPortNames[SINE_CONTROL3]
      = strdup("Sine2");
    pcPortNames[SINE_CONTROL4]
      = strdup("Gain2");
    pcPortNames[SINE_CONTROL5]
      = strdup("Sine3");
    pcPortNames[SINE_CONTROL6]
      = strdup("Gain3");
    pcPortNames[SINE_CONTROL7]
      = strdup("Sine4");
    pcPortNames[SINE_CONTROL8]
      = strdup("Gain4");
    pcPortNames[SINE_INPUT1]
      = strdup("Input");
    pcPortNames[SINE_OUTPUT1]
      = strdup("Output");

    psPortRangeHints = ((LADSPA_PortRangeHint *)
        calloc(10, sizeof(LADSPA_PortRangeHint)));

    g_psDescriptor -> PortRangeHints
      = (const LADSPA_PortRangeHint *)psPortRangeHints;

    /* Sine1 */
    psPortRangeHints[SINE_CONTROL1].HintDescriptor
      = (LADSPA_HINT_BOUNDED_BELOW
      | LADSPA_HINT_BOUNDED_ABOVE
      | LADSPA_HINT_DEFAULT_100);
    psPortRangeHints[SINE_CONTROL1].LowerBound = 0;
    psPortRangeHints[SINE_CONTROL1].UpperBound
                               =(LADSPA_Data)MAX_FREQ;
    /* Gain1 */
    psPortRangeHints[SINE_CONTROL2].HintDescriptor
      = (LADSPA_HINT_BOUNDED_BELOW 
      | LADSPA_HINT_BOUNDED_ABOVE
      | LADSPA_HINT_DEFAULT_0);
    psPortRangeHints[SINE_CONTROL2].LowerBound = 0;
    psPortRangeHints[SINE_CONTROL2].UpperBound
                                  =(LADSPA_Data)MAX_GAIN;
    /* Sine2 */
    psPortRangeHints[SINE_CONTROL3].HintDescriptor
      = (LADSPA_HINT_BOUNDED_BELOW
      | LADSPA_HINT_BOUNDED_ABOVE
      | LADSPA_HINT_DEFAULT_0);
    psPortRangeHints[SINE_CONTROL3].LowerBound = 0;
    psPortRangeHints[SINE_CONTROL3].UpperBound
                               =(LADSPA_Data)MAX_FREQ;
    /* Gain2 */
    psPortRangeHints[SINE_CONTROL4].HintDescriptor
      = (LADSPA_HINT_BOUNDED_BELOW 
      | LADSPA_HINT_BOUNDED_ABOVE
      | LADSPA_HINT_DEFAULT_0);
    psPortRangeHints[SINE_CONTROL4].LowerBound = 0;
    psPortRangeHints[SINE_CONTROL4].UpperBound
                                  =(LADSPA_Data)MAX_GAIN;
    /* Sine3 */
    psPortRangeHints[SINE_CONTROL5].HintDescriptor
      = (LADSPA_HINT_BOUNDED_BELOW
      | LADSPA_HINT_BOUNDED_ABOVE
      | LADSPA_HINT_DEFAULT_0);
    psPortRangeHints[SINE_CONTROL5].LowerBound = 0;
    psPortRangeHints[SINE_CONTROL5].UpperBound
                               =(LADSPA_Data)MAX_FREQ;
    /* Gain3 */
    psPortRangeHints[SINE_CONTROL6].HintDescriptor
      = (LADSPA_HINT_BOUNDED_BELOW 
      | LADSPA_HINT_BOUNDED_ABOVE
      | LADSPA_HINT_DEFAULT_0);
    psPortRangeHints[SINE_CONTROL6].LowerBound = 0;
    psPortRangeHints[SINE_CONTROL6].UpperBound
                                  =(LADSPA_Data)MAX_GAIN; 
    /* Sine4 */
    psPortRangeHints[SINE_CONTROL7].HintDescriptor
      = (LADSPA_HINT_BOUNDED_BELOW
      | LADSPA_HINT_BOUNDED_ABOVE
      | LADSPA_HINT_DEFAULT_0);
    psPortRangeHints[SINE_CONTROL7].LowerBound = 0;
    psPortRangeHints[SINE_CONTROL7].UpperBound
                               =(LADSPA_Data)MAX_FREQ;
    /* Gain4 */
    psPortRangeHints[SINE_CONTROL8].HintDescriptor
      = (LADSPA_HINT_BOUNDED_BELOW 
      | LADSPA_HINT_BOUNDED_ABOVE
      | LADSPA_HINT_DEFAULT_0);
    psPortRangeHints[SINE_CONTROL8].LowerBound = 0;
    psPortRangeHints[SINE_CONTROL8].UpperBound
                                  =(LADSPA_Data)MAX_GAIN; 
           
    psPortRangeHints[SINE_INPUT1].HintDescriptor = 0;
    psPortRangeHints[SINE_OUTPUT1].HintDescriptor = 0;

    g_psDescriptor -> instantiate  = instantiateSine;
    g_psDescriptor -> connect_port  = connectPortToSine;
    g_psDescriptor -> activate  = NULL;
    g_psDescriptor -> run   = runSine;
    g_psDescriptor -> run_adding  = NULL;
    g_psDescriptor -> set_run_adding_gain  = NULL;
    g_psDescriptor -> deactivate  = NULL;
    g_psDescriptor -> cleanup  = cleanupSine;
  }
}
/**********************************************************/
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;
}
基本的には前回のプログラムとあまり変わらない。

Windowsでのコンパイル。
gcc -shared -o namagi_sine2.dll namagi_sine2.c -ID

これでnamagi_sine2.dllが同じ階層に作られるので、それをAudacityのPlug-Insフォルダに入れると使えるようになる。

Audacityで実行してみたときの画面。パラメーターはSineの周波数とGainを4つ分同時に扱える。

実際に波形を生成してみた。4和音まで出来るので、実験には便利かも。


sound programming 目次
C言語 ANSI C89 Meadow & MinGW GCC 目次