2013/10/03

Audacity built-in effects GUI

前回作ったアンプにGUIをつけてみた。GUIにするだけで、ソースコードは一気に長く、読みにくくなってしまう。GUIの学習は時間のかかる作業で、個人的には楽しくない作業。ただAudacity内でささっと使える魅力はあるので、Audacityの標準エフェクトを参考に、その範囲内で学習を進めてみようと思う。

作っていて分かったのだが、Audacityのビルトインエフェクトは以下の5つのクラスを継承して作られている。
Effect.h
  • AutoDuck.h
  • ChangeSpeed.h
  • ClickRemoval.h
  • Echo.h
  • Equalization.h
  • FindClipping.h
  • NoiseRemoval.h
  • Normalize.h
  • Repeat.h
  • Reverb.h
  • Reverse.h
SimpleMono.h
  • Amplify.h
  • Fade.h
  • Invert.h
  • Leveller.h
  • Paulstretch.h
  • Phaser.h
  • Repair.h
  • Wahwah.h
TwoPassSimpleMono.h
  • BassTreble.h
  • Compressor.h
SoundTouchEffect.h
  • ChangePitch.h
  • ChangeTempo.h
Generator.h
  • DtmfGen.h
  • Noise.h
  • Silence.h
Generatorは音を生成するもので、それ以外は音を加工したり、音を調べたりするのに使う。選択基準がやや不明なのだが、今回は簡単そうなSimpleMono.hを継承して作ってみた。

ダイアログはシンプルそのもの。GUI部分はwxWidgetsが担っているので、これをちゃんと学習すれば、使い勝手の良いGUIも実現できるが、やる気はない。
/* NamagiAmp.h */
#ifndef __AUDACITY_EFFECT_AMP__
#define __AUDACITY_EFFECT_AMP__
#include <wx/dialog.h>
#include <wx/intl.h>
#include "SimpleMono.h"
class wxString;
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 );
 private:
   float gain;
 protected:
   virtual bool ProcessSimpleMono(float *buffer,
                                 sampleCount len);  
 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_gain;
 public:
   float gainDialog;
 private:
   DECLARE_EVENT_TABLE()
};
#endif

上記がヘッダファイルでクラスの宣言に過ぎない。下記がその中身となる。GUIがつくだけでかなり長くなる。
/* NamagiAmp.h */
#include <wx/textctrl.h>
#include <wx/valtext.h>
#include "NamagiAmp.h"
/*************************************************************/
//初期化
EffectNamagiAmp::EffectNamagiAmp()
{
   gain = float(0.5);
}
/*************************************************************/
wxString EffectNamagiAmp::GetEffectDescription()
{  
   return wxString::Format(_("effect: %s gain = %f"), 
                           this->GetEffectName().c_str(), gain); 
} 
/*************************************************************/
bool EffectNamagiAmp::PromptUser()
{
   NamagiAmpDialog dlog(this, mParent);
   dlog.gainDialog = gain;
   dlog.CentreOnParent();
   dlog.ShowModal();
   if (dlog.GetReturnCode() == wxID_CANCEL) return false;
   gain = dlog.gainDialog;
   return true;
}
/*************************************************************/
bool EffectNamagiAmp::TransferParameters( Shuttle & shuttle )
{  
   shuttle.TransferFloat(wxT("gain"),gain,0.5);
   return true;
}
/*************************************************************/
//処理
bool EffectNamagiAmp::ProcessSimpleMono(float *buffer,
                                       sampleCount len)
{
    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_gain = NULL;
   gainDialog = float(0.5); 
   Init();
}
/*************************************************************/
//レイアウト
void NamagiAmpDialog::PopulateOrExchange(ShuttleGui & S)
{
   S.AddSpace(0, 5); 
   S.StartMultiColumn(2, wxALIGN_CENTER);
   {
      m_pTextCtrl_gain = S.AddTextBox(_("Gain:"),
                                       wxT("0.5"),
                                       10);
      m_pTextCtrl_gain->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
   }
   S.EndMultiColumn();
}
/*************************************************************/
bool NamagiAmpDialog::TransferDataToWindow()
{
   m_bLoopDetect = true;
   wxString str;
   if (m_pTextCtrl_gain) {
      str.Printf(wxT("%g"), gainDialog);
      m_pTextCtrl_gain->SetValue(str);
   }
   m_bLoopDetect = false;
   return true;
}
/*************************************************************/
bool NamagiAmpDialog::TransferDataFromWindow()
{
   double newValue;
   wxString str;
   if (m_pTextCtrl_gain) {
      str = m_pTextCtrl_gain->GetValue();
      str.ToDouble(&newValue);
      gainDialog = (float)(newValue);
   }
   return true;
}
/*************************************************************/
void NamagiAmpDialog::OnPreview(wxCommandEvent & WXUNUSED(event))
{
   TransferDataFromWindow();
   float oldgain = m_pEffect->gain;
   m_pEffect->gain = gainDialog;
   m_pEffect->Preview();
   m_pEffect->gain = oldgain;
}


Audacity 関係の記事