ヘッダに実装したシンセの発音に関するクラスについて勉強を進めました。
発音の仕組みも色々と考えられているんだね〜
引き続き、Synthの「Build a MIDI synthesiser」のチュートリアルを進めていきます。今回は、最初にヘッダに定義したシンセサイザーの発音に関するクラスの内容などを、チュートリアルに沿って見ていきたいと思います。チュートリアルの項目としては「The SineWaveSound class」の項目からです。
こんな人の役に立つかも
・JUCEプログラミングを勉強している人
・JUCEの「Build a MIDI synthesiser」チュートリアルを進めている人
・JUCEでシンセを作成したい人
The SineWaveSound class
以前、ヘッダーに定義した「SineWaveSound」クラス(構造体)の内容です。
struct SineWaveSound : public juce::SynthesiserSound
{
SineWaveSound() {}
bool appliesToNote(int) override { return true; }
bool appliesToChannel(int) override { return true; }
};
SynthesiserSoundクラスを継承して、「appliesToNote」と「appliesToChannel」関数をオーバーライドしています。この2つの関数は、Synthesiserオブジェクトが発音の際に使う情報になるようです。
チュートリアルの説明だけだといまいちこのクラスがなにをするのか不明ですね。
挙動の検証
このクラスがどのような挙動をするのか、検証してみました。
struct SineWaveSound : public juce::SynthesiserSound
{
SineWaveSound() {}
bool appliesToNote(int n/*ノートナンバー取得*/) override {
DBG("ToNote:" << n);
//ノートナンバー72(A4)のときのみtrueとしました。
if (n == 72) {
return true;
}
else {
return false;
}
}
bool appliesToChannel(int) override { return true; }
};
appliesToNote関数の引数でノートナンバーを取得するようにnを引数としました。A4のキーが押されたときにノートナンバー72が引数として渡されてきますので、72のとき、返り値をtrueとして、それ以外をfalseとしました。
このようにして挙動を確認すると、A4以外の音は発音しなくなりました。
このクラスで鍵盤の発音可能範囲を指定したり、発音可能MIDIチャンネルを指定できるようです。
SineWaveVoiceクラス
SineWaveVoiceクラスが、実際に発音に関係する計算を行うクラスです。
メンバ変数
privateなメンバとして、以下の変数が存在しています。
private:
double currentAngle = 0.0, angleDelta = 0.0, level = 0.0, tailOff = 0.0;
最初の3つの変数は、サイン波の発音に必要な変数になります。以前、サイン波を発音するアプリの記事と同じ変数のラインナップになっています。
新たに追加されたtailOff変数は、発音のリリースに関する変数で、発音をいきなり止めないようにする処理を行うために利用するようです。アンプエンベロープのリリースに該当するような変数となります。音声のサンプルデータを書き込む「renderNextBlock」関数内で利用されます。
canPlaySound関数
SineWaveSoundのcanPlaySound関数は、オーバーライドしなければいけない関数の一つです。
bool canPlaySound(juce::SynthesiserSound* sound) override
{
return dynamic_cast<SineWaveSound*> (sound) != nullptr;
}
C++のダイナミックキャストを使って、渡されるサウンドクラスの型を確認しています。(渡されるサウンドのクラスが適切かどうかを確認しているようです。)
C++のダイナミックキャストについては、次のページを参考にしました。
ダイナミックキャストで型変換ができない場合、nullとなり、返り値がfalseとなります。
プロレスの技みたいなキャストですね。