Audacity built-in effects Stereo Amp GUI

前回作ったモノラルアンプをステレオ対応にしてみた。左右のチャンネル毎にGainを調整するエフェクト。SimpleMono.hを継承しているので、その名前からしてもステレオ処理には向かないのだが、標準エフェクトのPhaserなどもこのSimpleMono.hを使って左右別の処理を行なっている。どうもSimpleMono.hは、各トラック及び各チャンネルをひとつずつ処理している。トラックはint mChannelというチャンネル情報を持っている。これはTrack.hに定義されていた。
enum
{
LeftChannel = 0,
RightChannel = 1,
MonoChannel = 2
};
このような整数で管理している。この情報をもとに、処理しているトラックが左右どちらのチャンネルなのか、もしくはモノラルチャンネルなのか判別できる。SimpleMono.h 継承でステレオ処理する場合は、これを利用することで実現する。
今回のプログラムでは、処理のところで、トラックに右チャンネル情報があった場合のみGainRのパラメータを使うようにした。ということでモノラルトラックの場合は左チャンネルの値を使うという仕様。
ここまで出来れば、それなりのエフェクトは実現できる。ただやりたいのは左右チェンネルの音が入り乱れる処理だったりするので、次はEffect.hを使ってみるか。

上記の設定とは違うが、左右別々に処理できるようになった。

ソースコードは例にならって、NamagiAmp.h と NamagiAmp.cpp に分けている。
/* NamagiAmp.h */
#ifndef __AUDACITY_EFFECT_AMP__
#define __AUDACITY_EFFECT_AMP__
class wxString;
#include <wx/dialog.h>
#include <wx/intl.h>
#include "SimpleMono.h"

class wxStaticText;
class WaveTrack;

class EffectNamagiAmp:public EffectSimpleMono{
 public:
   EffectNamagiAmp();
   virtual wxString GetEffectName(){
      return wxString(_("NamagiAmp..."));
   }
   virtual wxString GetEffectIdentifier(){
      return wxString(wxT("NamagiAmp"));
   }
   virtual wxString GetEffectAction(){
      return wxString(_("NamagiAmp..."));
   }
   virtual wxString GetEffectDescription(); 
   virtual bool PromptUser();
   virtual bool TransferParameters( Shuttle & shuttle );

 protected:
   virtual bool ProcessSimpleMono(float *buffer,
                                 sampleCount len);
 private:
   float gainL;
   float gainR;
   float gain;
   
 friend class NamagiAmpDialog;
};
//-------------------------------------------------------
// NamagiAmpDialog
//-------------------------------------------------------
class NamagiAmpDialog:public EffectDialog {
 public:
   NamagiAmpDialog(EffectNamagiAmp * effect,
                               wxWindow * parent);
   void PopulateOrExchange(ShuttleGui & S);
   bool TransferDataToWindow();
   bool TransferDataFromWindow();
 private:
   void OnPreview( wxCommandEvent &event );
 private:
   bool m_bLoopDetect;
   EffectNamagiAmp *m_pEffect;  
   wxTextCtrl *m_pTextCtrl_gainL;
   wxTextCtrl *m_pTextCtrl_gainR; 
 public:
   float gainLDialog;
   float gainRDialog;
 private:
   DECLARE_EVENT_TABLE()
};
#endif


/* NamagiAmp.cpp */
#include <wx/textctrl.h>
#include <wx/valtext.h>
#include "NamagiAmp.h"
/*************************************************************/
//初期化
EffectNamagiAmp::EffectNamagiAmp()
{
   gainL = float(0.5);
   gainR = float(0.5);
   gain = float(0.5);
}
/*************************************************************/
wxString EffectNamagiAmp::GetEffectDescription(){  
   return wxString::Format(_("effect: %s gainL = %f gainR = %f"),
                           this->GetEffectName().c_str(),
                           gainL,gainR); 
} 
/*************************************************************/
bool EffectNamagiAmp::PromptUser()
{
   NamagiAmpDialog dlog(this, mParent);
   dlog.gainLDialog = gainL;
   dlog.gainRDialog = gainR;
   dlog.CentreOnParent();
   dlog.ShowModal();
   if (dlog.GetReturnCode() == wxID_CANCEL) return false;
   gainL = dlog.gainLDialog;
   gainR = dlog.gainRDialog;
   return true;
}
/*************************************************************/
bool EffectNamagiAmp::TransferParameters( Shuttle & shuttle )
{  
   shuttle.TransferFloat(wxT("gainL"),gainL,0.5);
   shuttle.TransferFloat(wxT("gainR"),gainL,0.5);
   return true;
}
/*************************************************************/
//処理
bool EffectNamagiAmp::ProcessSimpleMono(float *buffer,
                                        sampleCount len)
{
    gain = gainL;
    if (mCurChannel == Track::RightChannel) gain = gainR;
    for(sampleCount i=0; i<len; i++){
        buffer[i] = (float)(buffer[i] * gain);
    }
    return true;
}
//------------------------------------------------------------
// NamagiAmpDialog
//------------------------------------------------------------
BEGIN_EVENT_TABLE(NamagiAmpDialog, EffectDialog)
    EVT_BUTTON(ID_EFFECT_PREVIEW, NamagiAmpDialog::OnPreview)
END_EVENT_TABLE()
/*************************************************************/
NamagiAmpDialog::NamagiAmpDialog(EffectNamagiAmp *effect,
                                       wxWindow *parent)
: EffectDialog(parent, _("NamagiAmp"))
{
   m_bLoopDetect = false;
   m_pEffect = effect;
   m_pTextCtrl_gainL = NULL;
   m_pTextCtrl_gainR = NULL;
   gainLDialog = float(0.5); 
   gainRDialog = float(0.5); 
   Init();
}
/*************************************************************/
//レイアウト
void NamagiAmpDialog::PopulateOrExchange(ShuttleGui & S)
{
   S.AddSpace(0, 5); 
   S.StartMultiColumn(2, wxALIGN_CENTER);
   {
      m_pTextCtrl_gainL = S.AddTextBox(_("GainL:"),
                                       wxT("0.5"),
                                       10);
      m_pTextCtrl_gainL->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
      
      m_pTextCtrl_gainR = S.AddTextBox(_("GainR:"),
                                       wxT("0.5"),
                                       10);
      m_pTextCtrl_gainR->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
   }
   S.EndMultiColumn();
}
/*************************************************************/
bool NamagiAmpDialog::TransferDataToWindow()
{
   m_bLoopDetect = true;
   wxString str;
   if (m_pTextCtrl_gainL) {
      str.Printf(wxT("%g"), gainLDialog);
      m_pTextCtrl_gainL->SetValue(str);
   }
   if (m_pTextCtrl_gainR) {
      str.Printf(wxT("%g"), gainRDialog);
      m_pTextCtrl_gainR->SetValue(str);
   }
   m_bLoopDetect = false;
   return true;
}
/*************************************************************/
bool NamagiAmpDialog::TransferDataFromWindow()
{
   double newValue;
   wxString str;
   if (m_pTextCtrl_gainL) {
      str = m_pTextCtrl_gainL->GetValue();
      str.ToDouble(&newValue);
      gainLDialog = (float)(newValue);
   }
   if (m_pTextCtrl_gainR) {
      str = m_pTextCtrl_gainR->GetValue();
      str.ToDouble(&newValue);
      gainRDialog = (float)(newValue);
   }
   return true;
}
/*************************************************************/
void NamagiAmpDialog::OnPreview(wxCommandEvent & WXUNUSED(event))
{
   TransferDataFromWindow();
   float oldgainL = m_pEffect->gainL;
   float oldgainR = m_pEffect->gainR;
   m_pEffect->gainL = gainLDialog;
   m_pEffect->gainR = gainRDialog;
   m_pEffect->Preview();
   m_pEffect->gainL = oldgainL;
   m_pEffect->gainR = oldgainR;
}


Audacity 関係の記事