メモ:Electro-Smith DaisyでKarplus-Strongを鳴らしてみる

ずっと積み基板になってるけどそろそろ気合を入れて物理モデリングシンセつくるかー!!、と重い腰を上げようとしたら、基本のKarplus-Strongは標準のライブラリ(DaisySP)に普通に用意されていたので笑、軽く使ってみたメモ。

DaisySPにはCsoundからポーティングしてきたというPluckクラスと、それをいい感じにラップしたPolyPluckが用意されている、PolyPluckの方はDaisyExamplesにも例があったけど、今回は、より基礎的っぽいPluckを使ってみた。

コード

#include "daisy_seed.h"
#include "daisysp.h"

using namespace daisy;
using namespace daisysp;

#define BUFSIZE 256

static DaisySeed seed;
Pluck synth;
float plkbuff[BUFSIZE];

Switch button1;

static void AudioCallback(float *in, float *out, size_t size)
{
    float sig;
    float trig; // Pluck Vars

    button1.Debounce();

    if (button1.RisingEdge())
    {
        trig = 1.0f;
    } else {
        trig = 0.0f;
    }

    synth.SetDecay(seed.adc.GetFloat(0));

    for (size_t i = 0; i < size; i += 2)
    {
        synth.SetFreq(mtof(seed.adc.GetFloat(0) * 127));
        sig = synth.Process(trig);

        // left out
        out[i] = sig;

        // right out
        out[i + 1] = sig;
    }
}

int main(void)
{
    seed.Configure();
    seed.Init();

    float samplerate = seed.AudioSampleRate();

    // Use pin 16 to read the voltage of the knob
    AdcChannelConfig adcConfig;
    adcConfig.InitSingle(seed.GetPin(16));
    seed.adc.Init(&adcConfig, 1);

    synth.Init(samplerate, plkbuff, BUFSIZE, PLUCK_MODE_RECURSIVE);

    // Use pin 15 to read button to trigger the synth
    button1.Init(seed.GetPin(15), samplerate / 48.f);

    seed.adc.Start();
    seed.StartAudio(AudioCallback);

    for (;;)
    {
    }
}

ピン15にボタンが、ピン16に可変抵抗がつながっていて、可変抵抗でdecayと音程を両方コントロールしている。

ボタン

ボタン、というかトリガ・あるいはゲートを出すタイプの入力を扱うにはSwitchクラスを使う。main()

    button1.Init(seed.GetPin(15), samplerate / 48.f);

と、どのピンの入力かとupdate rateを指定(48という数字で割っているのはなぜなのか理解していない...)して初期化する。

AudioCallback()の中では

    button1.Debounce();

    if (button1.RisingEdge())
    {
        trig = 1.0f;
    }

とするとボタンを押したタイミングが取れる。同様にbutton1.FallingEdge()とするとボタンを離したタイミングが取れる。 button1.Debounce()は、前回の変化からあまりにも短時間で状態が変化していれば無視する、みたいな処理らしい。要はチャタリングを防ぐために呼んでいる。

可変抵抗

連続的な電圧の入力を扱うには、DaisySeed.adcを使う。まずmain()

    AdcChannelConfig adcConfig;
    adcConfig.InitSingle(seed.GetPin(16));
    seed.adc.Init(&adcConfig, 1);

    seed.adc.Start();

と、どのピンの入力かを指定して初期化する。ちなみにInitSingle()じゃなくてInitMux()を使うとマルチプレクサIC(CD405X)を勝手に制御してくれるらしい。便利そう...

AudioCallback()の中では、

    seed.adc.GetFloat(0)

とすれば0〜1の値が取れる(0はチャンネル名。マルチプレクサを使ってない場合は常に0

Pluck

肝心の Pluck は、まずは初期化には

synth.Init(<サンプリングレート>, <Pluck内部で使うバッファ>, <バッファのサイズ>, <モード>);

が指定できる。バッファの長さを増やすとより金属っぽい音?になる気がするけど理論がよくわからない。モードもPLUCK_MODE_RECURSIVE, PLUCK_MODE_WEIGHTED_AVERAGE, PLUCK_LASTの3種類があるけどどういう意味なのかよくわからない。とりあえずPLUCK_MODE_RECURSIVEを選んでおく。

あとはそんな特殊なところはなくて、decayや音程は以下のように指定できる(ちなみにmtof()MIDIのノート番号から周波数に変換する関数)。

synth.SetDecay(seed.adc.GetFloat(0));
synth.SetFreq(mtof(seed.adc.GetFloat(0) * 127));

あとSetDamp()で減衰率?を指定できるのでそこも適切に指定する方がよさそうだけど、とりあえず今回は無視。

結果

なんか低音が謎のローファイさだけど、おおむね弦っぽい音が鳴ってる気がする。