倍音が付加されると、一気に音に複雑さが増します。
ウェーブテーブルの波形をいろいろといじれるようになるね~
JUCEチュートリアル、「Synth:Wavetable synthesis」の最後の項目、「Selecting the Harmonics」をやっていきたいと思います。今回は、今まで単調たったサイン波に倍音を付けた波形をウェーブテーブルとするような内容となります。
公式ドキュメントからダウンロードできる該当サンプルは、「WavetableSynthTutorial_04.h」となります。
こんな人の役に立つかも
・JUCEでプログラミングの勉強をしている人
・JUCEチュートリアル「Wavetable synthesis」を勉強している人
・ウェーブテーブルのサイン波に倍音を付加したい人
プログラムの実装
プログラムは、前回までのチュートリアルのプログラムを変更する形で実装していきます。
createWavetable関数
createWavetable関数は、コンストラクタで実行され、AudioBufferクラスの音声バッファにサイン波のウェーブテーブルデータを作成する関数でした。今回は、このcreateWavetable関数で作成するサイン波に指定した倍音を付加した波形データをウェーブテーブルに作成するように作り変えています。
void MainComponent::createWavetable()
{
sineTable.setSize(1, (int)tableSize + 1);
//[1]追加しました。
sineTable.clear();
auto* samples = sineTable.getWritePointer(0);
//[2]以下通常のサイン波を作成する処理をコメントアウトしました。
/*auto angleDelta = juce::MathConstants<double>::twoPi / (double)(tableSize - 1);
auto currentAngle = 0.0;
for (unsigned int i = 0; i < tableSize; ++i)
{
auto sample = std::sin(currentAngle);
samples[i] = (float)sample;
currentAngle += angleDelta;
}*/
//[3]↑の処理の代わりに倍音を付加したサイン波を作成します。===
//[3-1]倍音作成の変数を定義します。
int harmonics[] = { 1, 3, 5, 6, 7, 9, 13, 15 };
float harmonicWeights[] = { 0.5f, 0.1f, 0.05f, 0.125f, 0.09f, 0.005f, 0.002f, 0.001f };
jassert(juce::numElementsInArray(harmonics) == juce::numElementsInArray(harmonicWeights));
//[3-2]波形を作成します。
for (auto harmonic = 0; harmonic < juce::numElementsInArray(harmonics); ++harmonic)
{
auto angleDelta = juce::MathConstants<double>::twoPi / (double)(tableSize - 1) * harmonics[harmonic];
auto currentAngle = 0.0;
for (unsigned int i = 0; i < tableSize; ++i)
{
auto sample = std::sin(currentAngle);
samples[i] += (float)sample * harmonicWeights[harmonic];
currentAngle += angleDelta;
}
}
//===
samples[tableSize] = samples[0];
}
[1]では、AudioBufferクラスの「clear」関数でウェーブテーブルとする音声バッファを初期化しています。(なぜ今までこの行がなかったのでしょうか^^;)
[2]は、今までのサイン波を作成する処理です。比較しやすいようにコメントアウトしてみました。
[3]からが、今回の倍音を付け加えた波形を作成する処理になります。
[3-1]では、倍音作成のための変数を準備します。harmonics配列に、何次倍音を付加するかの数値を格納します。チュートリアルでは、奇数倍音とのことでしたが、6がはいっていますね~。harmonicWeights変数として、各倍音のサイン波の音量を設定します。高次倍音になるほど、音量を下げていっていますね。
jassertは、アサーションマクロを表示してくれますので、harmonicsとharmonicWeightsの配列数が一致しないと診断メッセージを表示します。
[3-2]では、波形を作成しています。外側のforで、harmonics配列の数分ループ、内側のループで、ウェーブテーブルのサンプルバッファ数分ループです。harmonics数分のサイン波形を作成して、サンプルに重ねていっている様子がうかがえます。倍音の作成としては、angleDeltaをharmonics倍して進めることで、周期がその倍率になりますので、通常のサイン波に対して周期の早いサイン波が生成できます。
angleDeltaを3倍すると、ラジアンが3倍早く増加するので、sin関数で生成するサイン波も同じサンプル数で3倍の周期が収まることになります。
以下のページの「三角波」をみるとわかるのですが、この配列は三角波を生成しようとしているような気もします。(6次倍音はタイプミス??代わりに11次倍音がないですね。)
prepareToPlay関数
prepareToPlay関数の発音数を200から変更しました。チュートリアルでは10となっているのですが、わかりにくいので、1にして確認しました。
void MainComponent::prepareToPlay (int samplesPerBlockExpected, double sampleRate)
{
auto numberOfOscillators = 1;//発音数を指定します。
//...略...
以前より複雑な音色になっている感じがします。