オシロに絵を描くシンセサイザをNTS1で作りました


ちょっと時間が経ってしまいましたが、先月ゴールデンウイーク中に開催されたMaker Fair Kyotoのオンラインイベントに下記の作品を出品をしました。(といってもハッシュタグをつけてツイートするだけですが)


このコードは既に下記のリポジトリで公開中なのですが、まだ解説をこのブログに書いていなかったので、忘れないうちに書いておきます。内容は基本的に上のツイートのままなのですが、ツイッターの動画は時間制限もあり、あまり詳しく書けなかったので、詳細版ということになります。

boochow/picture
Picture display for oscilloscopes. Contribute to boochow/picture development by creating an account on GitHub.

今回作ったものはlogue SDKを使ったオシレータなのですが、プロジェクト的には以前作ったLissa Delayの続きになっています。

Korg NTS-1でリサジュー図形生成用ディレイを作ってみた
オシロスコープ・ミュージックというものがあります。英会話の先生とシンセサイザの話をしているときに聞いて知ったのですが、電子工作&シンセサイザ好きの人間にはそそられるものがあります。 オシロスコープをX-Yモードで動かすと、...

Lissa Delayは、入力音声(単音)を1/4波長だけ遅延させ、それをLch、元の入力をRchに出すというものでした。
その制作動機は上記の記事でも書きましたが、オシロスコープミュージックというプロジェクトが面白かったので、その簡易版的なことをやってみたいということです。

オシロスコープに図形を描くには、まず図形を一筆描きで作成し、時間軸に沿って座標のX軸成分の信号とY軸成分の信号を生成し、X-Yモードのオシロスコープに入力します。しかし、NTS-1のオシレータはモノラルですので、2つの音声信号を出力できません。そこで、ステレオ信号を出力できるディレイを使って、原信号と、原信号を1/4波長だけ遅らせた信号をX-Y信号として出力する、というのがLissa Delayのアイデアです。

なぜ1/4波長かというのを直観的に分かるように描いてみたのが下の図です。
サインとコサインは円の上を動く点の座標を、X軸への射影とY軸への射影で考えるというのを、高校のときに習ったと思います。
この図の左の部分はそれを表しています。

ここで、この円の部分が、実はパイプ型のものを斜めに切った切り口を正面から見ていると考えます。(図中央)
そして、このパイプを90度回転させたものが図の右の部分だと考えてください。
このように横方向からパイプを見ているときは、円の上を動く点は単なる往復運動になります。このとき、動く点のX軸への射影とY軸への射影は、どちらもサイン関数になります。

上で説明した流れを、逆に考えてみます。
斜めに切ったパイプを、右の状態から90度回して左の状態にするイメージです。この回転することが90度(1/4波長)遅延させるということに相当します。
つまり、別の言い方をするとコサイン関数はサイン関数を90度遅延させたものということになります。

遅延が90度以外だと、切り口の図形を斜めから見ている具合になります。例えば45度だと、上の図の中央のような状態になりますし、180度だと図の右を左右反転させたような状態になります。もっとも、これはサイン波など振幅方向の対称性(正負を反転させても形状が変わらない)や時間軸方向の対称性(π/4や3π/4で時間軸を反転させても形状が変わらない)がある波形の場合です。非対称な波形の場合は180度や270度でも意味がある図形を表示できる可能性があります。

ここまでの話で切り口の形=信号が描く図形が円になっているのは、元の波形がサイン関数だったからですが、次に任意の波形について考えてみます。


まず、波形の最初の1/4の部分だけを考え、これが切り口の図形のY軸の値だとします。これに対応するX軸の値は、元波形を90度遅らせた波形の最初の1/4の部分、すなわち元波形の最後の1/4の部分となります。この2つの波形の組み合わせから、切り口の図形の1/4が決まります。

次に、波形の次の1/4の部分を考えます。まず先にX軸の値を考えると、90度遅延が入るのでこれは波形の最初の1/4の部分と同じです。これは先ほどの図形ではY軸として使われていました。ですので、先ほどの図形でX軸として使われていた値をうまくY軸の値として使うと、先ほどの図形と同じような図形が描けます。
具体的には、波形の最後の1/4の部分を正負反転させた波形を使うと、先ほどの図形を90度回転した図形になります。

こういった具合に波形を決めていくと、一波長分の信号で同じ図形を90度ずつ回転したものを4回描くことができます。例えば、入力信号が三角波の場合、最初の1/4波長は「/」という直線が描かれます。その次の1/4波長は、これを90度回転させた「\」、その次は「/」、その次は「\」となり、全体としては「◇」という図形になります。矩形波の場合は正方形になり、鋸波の場合は直角二等辺三角形になります。

下の図は波形と図形の関係を表しています。
図の左上、①の象限に表示される図形は、原信号の先頭の1/4波長をY軸、最後の1/4波長をX軸として用いています。その右隣りの象限②は、座標系が①から時計回りに90度回転しています。③、④の象限も同様です。
図の左下の両矢印の点線は、同じ信号であることを表しています。例えばY軸方向の先頭の1/4波長と、X軸方向の2番目の1/4波長は同じ信号(後者は前者をディレイで遅延させた信号)です。

以上で、任意の図形をオシロスコープに表示するオシレータの材料がそろいました。

・Lissa Delayを使い、90度遅延した信号をX軸、元信号をY軸としてオシロスコープに入力する
・オシロスコープ上には図形が90度回転しながら4回描画される

という前提の下、図形を表示するオシレータは

・図形のY軸を波形の先頭1/4、図形のX軸を波形の末尾1/4に埋め込む
・図形が重ならないようにするため、波形の先頭1/4は正の値、波形の末尾1/4は負の値とする
・前半1/4~1/2については、波形の末尾1/4を正負反転したものとする
・後半1/2~3/4については、波形の先頭1/4を正負反転したものとする

ことで作成できます。

冒頭でリンクを貼ったリポジトリのコードでは、図形の座標を与えると、初期化時に上記の方法で一波長分のウエーブテーブルを生成しています。波形は複数個利用可能で、Shift-Shape(NTS-1ではALT)で選択できます。

与える図形の座標値はX、Yともに値域が0.0~1.0で、右方向および上方向が正とします。
座標値のデータはfigure.hに格納します。VERTICESが頂点座標の個数、WAVETABLESが波形の個数です。配列figure_xがX座標、配列figure_yがY座標です。

座標データの注意点としては、

(1)個数を概ね30個程度以下にすること
(2)最後の座標値と最初の座標値を同一にすること
(3)前の図形は下方向、次の図形は右方向と意識する
(4)高周波成分をなるべく出さないようにする

があります。

(1)個数を概ね30個程度以下にすること
座標の個数を増やしすぎると絵が崩れます。思ったような絵を表示するには、すべての座標値が波形に反映される必要がありますが、一方で1波長を表現するために使える座標値の個数には、サンプリング周波数による制約があります。

波長のサンプル長は図形の座標の個数の4倍となることに注意が必要です。座標値が30個だと120サンプルになりますが、サンプリングレートが48KHzのとき、1波長が120サンプルとなるのは発音周波数が400Hzのときです。これを超えると、すべての座標を反映しきれず、絵が崩れていきます。Aの音が440Hzですから、それより低い音に表示の限界が来ることになります。(もちろん、発音するのが低音だけでよければもっと座標値を増やすことは可能です。)

(2)最後の座標値と最初の座標値を同一にすること
必須というわけではないのですが、(1)で述べたように座標値の個数には制約があるので、閉じた図形を描きたければあらかじめ計算に入れておく必要があります。

(3)前の図形は下方向、次の図形は右方向と意識する
図形は独立して描画されるのではなく、最初の頂点の前の頂点は下方向(-Yの方向)、最後の頂点の次の頂点は右方向(+Xの方向)にあることを意識しないと、意図しない直線が図形を横切ってしまう場合があります。これを避けるには、図形の開始点をなるべく下方へ、図形の終了点をなるべく右サイドへ持っていくのが良いです。閉じた図形の場合は、図形の中で最も右下にくる点を開始点にします。

(4)高周波成分をなるべく出さないようにする
DA変換でローパスフィルタがかかるので、波形が高周波成分を含んでいると、意図通りの図形が表現できない可能性があります。聴感上のエイリアスノイズはあまり気にしなくてよいと思いますが(エイリアスノイズが気になるのは高音ですが、高温ではそもそも図形が崩れてしまう可能性が大きいため)、波形を生成させてみて図形の頂点の座標が想定と違う場合は、高周波成分のカットを疑ってみるとよいと思います。

こうして作成したオシレータですが、曲を演奏しながら図形を表示させるには、もう一工夫必要です。

Lissa Delayのディレイタイムは波長の正確に1/4である必要がありますが、その計算に必要な入力信号の波長(実際には音高)は、NTS-1ではノブで入力するしかありません。キーを弾くたびにノブを回さないといけないのでは、演奏しながら図形を表示させるのは無理です。

そこで、上の図のようにキーボードのMIDI信号をいったんPCに送り、ノート・ナンバーをディレイタイムのコントローチェンジに変換してNTS-1のMIDI入力に送ります。NTS-1はもともとディレイタイムをノート番号で指定できるようにしています。つまり、ノートナンバーから波長を求め、その1/4をディレイタイムとして用います。

ノートナンバーをコントロールチェンジに変更するには、PizMidiというフリーソフトの中に入っているVSTプラグインを使っています。

最後に、このオシレータで使えるパラメータを紹介しておきます。

(1)Shape(ノブA)
波形の一部を強制的に別の信号に変更します。矩形波のオシレータでPWMを指定するイメージです。

(2)Shift-Shape(ノブB)
表示する図形を選択します。

(3)Type
Shapeで用いる信号を「ゼロフラット、矩形波、三角波、サイン波」から選択します。それぞれ、Shape=100%のとき表示される図形は「一点、四角形、ひし形、円」になります。

(4)Phase
Shapeでの信号変更を図形のどの象限から開始するかを指定します。

(5)Interpolation
これは主に図形データ作成時の補助用に用意したもので、座標データをより見やすくします。オシレータは信号を生成する際に、ウエーブテーブルの2つのサンプルからその途中の値を補完します。このパラメータはその補完アルゴリズムを指定するもので、「線形補間(デフォルト)、コサイン補間、補完なし(より近いほうのサンプルを採用)」の中から指定します。

補完アルゴリズムのイメージは下図のようになります。線形補間もコサイン補間もlogue SDKのライブラリ内で提供されています。

コメント