VST Tips(準備中)


簡単な音源(VSTi)の作成(暫定版)

(2011/4/14更新)
【注意】
本サンプルはSynthesizerの基本的な処理を追いやすくするために書かれたコードです。以下の点が大きなバグとして残っておりますのでご注意ください。(小さなバグも多数あります)

  • ノートOFF時に振幅が急激に変化するため、不快なノイズが入ります。(基本的には問題ないと思いますが大きな音量の場合、耳やスピーカーを痛める可能性があります。)

なお、本サンプル利用を使用したことによって生じたすべての障害・損害・不具合等に関しては、一切の責任を負いません。各自の責任においてご使用ください。

サンプルコード全体

ソースコードのダウンロード→ ここをクリック
(dllファイルも同梱しております。dllファイルのウィルスチェックはしておりませんのでdllファイル利用の前には必ずチェックをお願いいたします。)

MIDIの処理部分についてはこちらの【CMidiMsg.h】と【CMidiMsg.cpp】をご覧ください。

【MySynthSampleVST.h】
  1. // ============================================================================================
  2. // インクルードファイル
  3. // ============================================================================================
  4. #include <stdlib.h>
  5. #include "audioeffectx.h"
  6.  
  7. #include "CMidiMsg.h"
  8. #include "CVoice.h"
  9.  
  10.  
  11. // ============================================================================================
  12. // 設計情報の記入
  13. // ============================================================================================
  14. #define MY_VST_INPUT_NUM 2 //入力数。モノラル入力=1、ステレオ入力=2
  15. #define MY_VST_OUTPUT_NUM 2 //出力数。モノラル出力=1、ステレオ出力=2
  16.  
  17. #define MY_VST_UNIQUE_ID 'SMPL' //ユニークID
  18. //公開する場合は以下URLで発行されたユニークIDを入力する。
  19. //http://ygrabit.steinberg.de/~ygrabit/public_html/index.html
  20.  
  21. #define MY_VST_PRESET_NUM 1 //プリセットプログラムの数
  22. #define MY_VST_PARAMETER_NUM 0 //パラメータの数
  23.  
  24. #define MAX_OSCILLATORS 8 // オシレータの数(最大発音数)
  25. // ============================================================================================
  26. // VSTの基本となるクラス
  27. // ============================================================================================
  28. class MySynthSampleVST : public AudioEffectX , public CMidiMsg
  29. {
  30. protected:
  31. CVoice osc[MAX_OSCILLATORS];
  32. public:
  33. MySynthSampleVST (audioMasterCallback audioMaster);
  34.  
  35. // 音声信号を処理するメンバー関数
  36. virtual void processReplacing (float** inputs, float** outputs, VstInt32 sampleFrames);
  37. virtual void processReplacing2 (float* inL, float* inR, float* outL, float* outR, VstInt32 sampleFrames);
  38.  
  39. // MIDIメッセージをホストアプリケーションから受け取るためのメンバー関数
  40. VstInt32 processEvents (VstEvents* events);
  41.  
  42. virtual void onMidiKeyOn (unsigned char channel, unsigned char noteNo, unsigned char velo);
  43. virtual void onMidiKeyOff (unsigned char channel, unsigned char noteNo, unsigned char velo);
  44. };
  45.  
  46. // ============================================================================================
  47. // このVSTを生成するための関数
  48. // ============================================================================================
  49. AudioEffect* createEffectInstance (audioMasterCallback audioMaster)
  50. {
  51. //newでこのVSTを生成したポインタを返す
  52. return new MySynthSampleVST (audioMaster);
  53. }
  54.  
  55. // ============================================================================================
  56. // このVSTの初期化
  57. // ============================================================================================
  58. MySynthSampleVST::MySynthSampleVST (audioMasterCallback audioMaster)
  59. : AudioEffectX (audioMaster, MY_VST_PRESET_NUM, MY_VST_PARAMETER_NUM)
  60. {
  61. //VSTの初期化を行う。
  62.  
  63. //以下の関数を呼び出して入力数、出力数等の情報を設定する。
  64. //必ず呼び出さなければならない。
  65. setNumInputs (MY_VST_INPUT_NUM); //入力数の設定
  66. setNumOutputs (MY_VST_OUTPUT_NUM); //出力数の設定
  67. setUniqueID (MY_VST_UNIQUE_ID); //ユニークIDの設定
  68.  
  69. isSynth (true); //このVSTがSynthかどうかのフラグを設定。
  70. //Synthの場合…true、Effectorの場合…false
  71.  
  72. canProcessReplacing (); //このVSTが音声処理可能かどうかのフラグを設定。
  73. //音声処理を行わないVSTはないので必ずこの関数を呼び出す。
  74.  
  75. //上記の関数を呼び出した後に初期化を行う
  76. }
  77.  
  78.  
  79. // ============================================================================================
  80. // 音声信号処理部分
  81. // ============================================================================================
  82. void MySynthSampleVST::processReplacing (float** inputs, float** outputs, VstInt32 sampleFrames)
  83. {
  84. //入力、出力は2次元配列で渡される。
  85. //入力は-1.0f~1.0fの間で渡される。
  86. //出力は-1.0f~1.0fの間で書き込む必要がある。
  87. //sampleFramesが処理するバッファのサイズ
  88. float* inL = inputs[0]; //入力 左用
  89. float* inR = inputs[1]; //入力 右用
  90. float* outL = outputs[0]; //出力 左用
  91. float* outR = outputs[1]; //出力 右用
  92.  
  93. // 処理されたフレーム数
  94. VstInt32 processedFrames = 0;
  95.  
  96. while(getMidiMessageNum() > 0)
  97. {
  98. // 処理すべきフレーム数
  99. VstInt32 Frames = getNextDeltaFrames() - processedFrames;
  100. processReplacing2 (inL, inR, outL, outR, Frames);
  101.  
  102. // MIDIメッセージの処理を行う
  103. midiProc();
  104.  
  105. // 処理されたフレーム数を計算
  106. // 同時に音声信号バッファのポインタについても進める。
  107. processedFrames += Frames;
  108. inL += Frames;
  109. inR += Frames;
  110. outL += Frames;
  111. outR += Frames;
  112. }
  113.  
  114. processReplacing2 (inL, inR, outL, outR, sampleFrames - processedFrames);
  115. }
  116.  
  117. void MySynthSampleVST::processReplacing2 (float* inL, float* inR, float* outL, float* outR, VstInt32 sampleFrames)
  118. {
  119. for (int i = 0; i < sampleFrames; i++)
  120. {
  121. //ここで音声処理を行う。
  122. float out = 0.0f;
  123. float volume = 1.0 / (double)MAX_OSCILLATORS;
  124.  
  125. // 各オシレータの振幅を取得し、出力に足し合わせる。
  126. for(int j = 0; j < MAX_OSCILLATORS; j++)
  127. {
  128. // オシレータの振幅を取得。
  129. out += osc[j].amplitude();
  130.  
  131. // オシレータの状態を更新する。
  132. osc[j].update();
  133. }
  134.  
  135. //出力バッファへ書き込む。
  136. outL[i] = out * volume;
  137. outR[i] = out * volume;
  138. }
  139. }
  140.  
  141. // MIDIメッセージをVSTに保存する。
  142. // processReplacing()の前に必ず1度だけ呼び出される。
  143. VstInt32 MySynthSampleVST::processEvents (VstEvents* events)
  144. {
  145. // MIDIのリストを初期化します。
  146. clearMidiMsg();
  147.  
  148. int loops = (events->numEvents);
  149.  
  150. // VSTイベントの回数だけループをまわす。
  151. for (int i = 0;i < loops; i++)
  152. {
  153. // 与えられたイベントがMIDIならばmidimsgbufにストックする
  154. if ((events->events[i])->type == kVstMidiType)
  155. {
  156. VstMidiEvent *midievent = (VstMidiEvent*)(events->events[i]);
  157. if( !addMidiMsg(midievent) )
  158. {
  159. break;
  160. }
  161. }
  162. }
  163.  
  164. // 1を返さなければならない
  165. return 1;
  166. }
  167.  
  168. // ============================================================================================
  169. // MIDIメッセージを処理する
  170. // ============================================================================================
  171. void MySynthSampleVST::onMidiKeyOn (unsigned char channel, unsigned char noteNo, unsigned char velo)
  172. {
  173. // OFF状態のオシレータを探す
  174. for(int i = 0; i < MAX_OSCILLATORS; i++)
  175. {
  176. if(osc[i].getStatus() == VOICE_STATE_OFF)
  177. {
  178. // OFF状態のオシレータをONにして検索終了
  179. osc[i].start(noteNo);
  180. break;
  181. }
  182. }
  183. }
  184.  
  185. void MySynthSampleVST::onMidiKeyOff (unsigned char channel, unsigned char noteNo, unsigned char velo)
  186. {
  187. // ON状態でかつノートNoと一致するオシレータを探す
  188. for(int i = 0; i < MAX_OSCILLATORS; i++)
  189. {
  190. if(osc[i].getStatus() == VOICE_STATE_ON && osc[i].getNoteNo() == noteNo)
  191. {
  192. // ON状態のオシレータをOFFにして検索終了
  193. osc[i].stop();
  194. break;
  195. }
  196. }
  197. }

【COscillator.h】
  1. #pragma once
  2. #include <math.h>
  3.  
  4. #define VOICE_STATE_OFF 0
  5. #define VOICE_STATE_ON 1
  6.  
  7. class CVoice
  8. {
  9. protected:
  10. float elapsedFrames; //オシレータが発音を始めてから経過したフレーム数
  11.  
  12. int status; //オシレータ発音中の場合はTrue
  13. int noteNo; //オシレータの音程
  14.  
  15. float sampleRate; //サンプルレート(デフォルト 44100)
  16.  
  17. public:
  18. inline CVoice(void);
  19. inline ~CVoice(void);
  20.  
  21. // オシレータを初期化するメンバー関数
  22. inline void init();
  23.  
  24. // 現在のオシレータの振幅を返すメンバー関数
  25. inline float amplitude();
  26.  
  27. // オシレータの状態を更新するメンバー関数
  28. inline void update();
  29.  
  30. // オシレータの動作を開始・停止させるメンバー関数
  31. inline void start(int note);
  32. inline void stop();
  33.  
  34. // オシレータのメンバ変数を設定するメンバー関数
  35. inline void setSampleRate(float newSampleRate);
  36.  
  37. // オシレータの状態を取得するメンバー関数
  38. inline int getStatus() { return status; };
  39. inline int getNoteNo() { return noteNo; };
  40.  
  41. };
  42.  
  43. CVoice::CVoice()
  44. {
  45. // 初期化を実施
  46. init();
  47. }
  48.  
  49. CVoice::~CVoice()
  50. {
  51. }
  52.  
  53. void CVoice::init()
  54. {
  55. // メンバ変数を初期化する
  56. elapsedFrames = 0.0;
  57. status = VOICE_STATE_OFF;
  58. noteNo = 0;
  59. sampleRate =44100.0f;
  60. }
  61.  
  62. float CVoice::amplitude()
  63. {
  64. // オシレータの振幅を返す
  65. if(status == VOICE_STATE_ON)
  66. {
  67. // オシレータの状態がONの時
  68. float pi = 3.14159265f;
  69.  
  70. // ノートNoから周波数を計算する
  71. float freq = (float)(440.0 * pow(2.0, ((double)noteNo - 69.0)/12.0));;
  72.  
  73. // 現在の振幅量を返す
  74. return (float)sin(2.0 * pi * freq * elapsedFrames / sampleRate);
  75. }
  76. else
  77. {
  78. // オシレータの状態がOFFの時
  79.  
  80. // 0を返す
  81. return 0.0f;
  82. }
  83. }
  84.  
  85. void CVoice::update()
  86. {
  87. // 経過時間を進める
  88. elapsedFrames += 1.0f;
  89. }
  90.  
  91. void CVoice::start(int note)
  92. {
  93. status = VOICE_STATE_ON;
  94. noteNo = note;
  95. }
  96.  
  97. void CVoice::stop()
  98. {
  99. init();
  100. }
  101.  
  102. void CVoice::setSampleRate(float newSampleRate)
  103. {
  104. sampleRate = newSampleRate;
  105. }





同一カテゴリのTips


項目 No. 概要


javascript plugin Error : このプラグインで利用できない命令または文字列が入っています。
最終更新:2011年04月18日 00:34