// ============================================================================================
// インクルードファイル
// ============================================================================================
#include <stdlib.h>
#include "audioeffectx.h"
#include "CMidiMsg.h"
#include "CVoice.h"
// ============================================================================================
// 設計情報の記入
// ============================================================================================
#define MY_VST_INPUT_NUM 2 //入力数。モノラル入力=1、ステレオ入力=2
#define MY_VST_OUTPUT_NUM 2 //出力数。モノラル出力=1、ステレオ出力=2
#define MY_VST_UNIQUE_ID 'SMPL' //ユニークID
//公開する場合は以下URLで発行されたユニークIDを入力する。
//http://ygrabit.steinberg.de/~ygrabit/public_html/index.html
#define MY_VST_PRESET_NUM 1 //プリセットプログラムの数
#define MY_VST_PARAMETER_NUM 0 //パラメータの数
#define MAX_OSCILLATORS 8 // オシレータの数(最大発音数)
// ============================================================================================
// VSTの基本となるクラス
// ============================================================================================
class MySynthSampleVST : public AudioEffectX , public CMidiMsg
{
protected:
CVoice osc[MAX_OSCILLATORS];
public:
MySynthSampleVST (audioMasterCallback audioMaster);
// 音声信号を処理するメンバー関数
virtual void processReplacing (float** inputs, float** outputs, VstInt32 sampleFrames);
virtual void processReplacing2 (float* inL, float* inR, float* outL, float* outR, VstInt32 sampleFrames);
// MIDIメッセージをホストアプリケーションから受け取るためのメンバー関数
VstInt32 processEvents (VstEvents* events);
virtual void onMidiKeyOn (unsigned char channel, unsigned char noteNo, unsigned char velo);
virtual void onMidiKeyOff (unsigned char channel, unsigned char noteNo, unsigned char velo);
};
// ============================================================================================
// このVSTを生成するための関数
// ============================================================================================
AudioEffect* createEffectInstance (audioMasterCallback audioMaster)
{
//newでこのVSTを生成したポインタを返す
return new MySynthSampleVST (audioMaster);
}
// ============================================================================================
// このVSTの初期化
// ============================================================================================
MySynthSampleVST::MySynthSampleVST (audioMasterCallback audioMaster)
: AudioEffectX (audioMaster, MY_VST_PRESET_NUM, MY_VST_PARAMETER_NUM)
{
//VSTの初期化を行う。
//以下の関数を呼び出して入力数、出力数等の情報を設定する。
//必ず呼び出さなければならない。
setNumInputs (MY_VST_INPUT_NUM); //入力数の設定
setNumOutputs (MY_VST_OUTPUT_NUM); //出力数の設定
setUniqueID (MY_VST_UNIQUE_ID); //ユニークIDの設定
isSynth (true); //このVSTがSynthかどうかのフラグを設定。
//Synthの場合…true、Effectorの場合…false
canProcessReplacing (); //このVSTが音声処理可能かどうかのフラグを設定。
//音声処理を行わないVSTはないので必ずこの関数を呼び出す。
//上記の関数を呼び出した後に初期化を行う
}
// ============================================================================================
// 音声信号処理部分
// ============================================================================================
void MySynthSampleVST::processReplacing (float** inputs, float** outputs, VstInt32 sampleFrames)
{
//入力、出力は2次元配列で渡される。
//入力は-1.0f~1.0fの間で渡される。
//出力は-1.0f~1.0fの間で書き込む必要がある。
//sampleFramesが処理するバッファのサイズ
float* inL = inputs[0]; //入力 左用
float* inR = inputs[1]; //入力 右用
float* outL = outputs[0]; //出力 左用
float* outR = outputs[1]; //出力 右用
// 処理されたフレーム数
VstInt32 processedFrames = 0;
while(getMidiMessageNum() > 0)
{
// 処理すべきフレーム数
VstInt32 Frames = getNextDeltaFrames() - processedFrames;
processReplacing2 (inL, inR, outL, outR, Frames);
// MIDIメッセージの処理を行う
midiProc();
// 処理されたフレーム数を計算
// 同時に音声信号バッファのポインタについても進める。
processedFrames += Frames;
inL += Frames;
inR += Frames;
outL += Frames;
outR += Frames;
}
processReplacing2 (inL, inR, outL, outR, sampleFrames - processedFrames);
}
void MySynthSampleVST::processReplacing2 (float* inL, float* inR, float* outL, float* outR, VstInt32 sampleFrames)
{
for (int i = 0; i < sampleFrames; i++)
{
//ここで音声処理を行う。
float out = 0.0f;
float volume = 1.0 / (double)MAX_OSCILLATORS;
// 各オシレータの振幅を取得し、出力に足し合わせる。
for(int j = 0; j < MAX_OSCILLATORS; j++)
{
// オシレータの振幅を取得。
out += osc[j].amplitude();
// オシレータの状態を更新する。
osc[j].update();
}
//出力バッファへ書き込む。
outL[i] = out * volume;
outR[i] = out * volume;
}
}
// MIDIメッセージをVSTに保存する。
// processReplacing()の前に必ず1度だけ呼び出される。
VstInt32 MySynthSampleVST::processEvents (VstEvents* events)
{
// MIDIのリストを初期化します。
clearMidiMsg();
int loops = (events->numEvents);
// VSTイベントの回数だけループをまわす。
for (int i = 0;i < loops; i++)
{
// 与えられたイベントがMIDIならばmidimsgbufにストックする
if ((events->events[i])->type == kVstMidiType)
{
VstMidiEvent *midievent = (VstMidiEvent*)(events->events[i]);
if( !addMidiMsg(midievent) )
{
break;
}
}
}
// 1を返さなければならない
return 1;
}
// ============================================================================================
// MIDIメッセージを処理する
// ============================================================================================
void MySynthSampleVST::onMidiKeyOn (unsigned char channel, unsigned char noteNo, unsigned char velo)
{
// OFF状態のオシレータを探す
for(int i = 0; i < MAX_OSCILLATORS; i++)
{
if(osc[i].getStatus() == VOICE_STATE_OFF)
{
// OFF状態のオシレータをONにして検索終了
osc[i].start(noteNo);
break;
}
}
}
void MySynthSampleVST::onMidiKeyOff (unsigned char channel, unsigned char noteNo, unsigned char velo)
{
// ON状態でかつノートNoと一致するオシレータを探す
for(int i = 0; i < MAX_OSCILLATORS; i++)
{
if(osc[i].getStatus() == VOICE_STATE_ON && osc[i].getNoteNo() == noteNo)
{
// ON状態のオシレータをOFFにして検索終了
osc[i].stop();
break;
}
}
}