0123456789
list icon
list icon

NTS-1 digital kit

SoundCloud

Share

[DOTEC-AUDIO x Nu:Tekt] NTS-1用カスタム・エフェクトの作成方法

logue-SDK カスタム・プラグインを作るのは難しそう? でもご安心を!
DOTEC-AUDIO様ご協力のもと、NTS-1用カスタム・エフェクトの作成方法を全5回の記事で完全解説いたします。

第1回 NTS-1で自作エフェクターを動かそう

皆様こんにちは。DOTEC-AUDIO(ドーテック・オーディオ)というプラグインメーカーの飯島進仁と申します。

普段はこのようなPCやiPhone、iPad向けのオーディオ・プラグインの開発・販売を行っています。
https://dotec-audio.com/

Nu:Tekt NTS-1 digital kit(以下NTS-1)は組み立て式のデジタルシンセサイザーという大変面白い製品なのですが、なぜ普段PC向けのプラグインを開発しているDOTEC-AUDIOがこのシンセサイザーに興味をもったのかといいますと、それは自分でプログラムを書いて開発した音色(オシレーター)やエフェクターをNTS-1にインストールできてしまうからなんです。

またNTS-1のもう一つ面白いところは「ステレオのAUDIO入力(ライン入力)も持っている」というところで、そこに音源や楽器を繋げればシンセサイザーだけでなく独立したコンパクトエフェクターとして機能してしまうんです。

つまり「自由にプログラム可能なシンセサイザー&コンパクトエフェクターが手に入ってしまう」というわけで、そう聞いてみたら是非チャレンジしてみよう、と思う方もいらっしゃるのではないでしょうか?

ということで早速ですがこちらの動画を御覧ください!

こちらは「ビットクラッシャー」と呼ばれる音の粒子を荒くするエフェクターです。

そして
こちらはヴァイナルストップという、レコード(ヴァイナル)を手で抑えて止めたようなエフェクターです。

どちらもDOTEC-AUDIOの製品である「DeeFX」というマルチエフェクターの機能の一部をNTS-1向けに移植したものです。
ご覧のようにNTS-1のオシレーターだけでなく、入力した音声にもエフェクトをかけられてしまうんですから面白いですよね!

さて今回の連載では、これら2つのエフェクターを題材にしてNTS-1のエフェクター開発についてご紹介していきたいと考えています。

本連載の中でこれらのエフェクターはソースコードも公開&解説予定ですが、まずはこれら2つのエフェクターをダウンロードしてNTS-1にインストールをするところを説明いたします。 NTS-1を既にお持ちの方は是非ダウンロードして実際に試してみてくださいね!

インストール手順

  • 1/ NTS-1 Sound Librarianのインストール

    まず NTS-1 Sound Librarian をPCにインストールします(Win/Mac) こちらを説明に従ってインストールしてNTS-1とPCのの接続を確認します。
  • 2/ エフェクターファイルのダウンロード

    次に今回DOTEC-AUDIOが開発したエフェクターファイルをダウンロードします。

    「Bitcrusher」のダウンロードはこちら
    「Stop FX」のダウンロードはこちら

    ファイルを解凍すると「bitcrusher.ntkdigunit」と「stopfx.ntkdigunit」というファイルが出てきます。
  • 3/ Sound Librarianで読み込む

    読み込み方はですが、メニューの「ファイル」の「ユーザー・ユニットのインポート」から解凍したファイルを選択してください。 すると「USER MODULATION FX」というカテゴリに「bitcrusher」というエフェクターが、そして「USER DELAY FX」というカテゴリに「stopfx」というエフェクターが追加されると思います。 あとは「送信・受信」の「ユーザー・データを書き込み」を選べばNTS-1にこれら2つのエフェクターが転送されます。

    無事転送されたら、NTS-1の「Mod」で「bitcrusher」、Delayとして「stopfx」が選択できるようになっていますので、是非遊んでみてください。
それでは次回をお楽しみに!

第2回 NTS-1のエフェクター開発をする準備をしよう

皆様こんにちは。DOTEC-AUDIO(ドーテック・オーディオ)の飯島です。

前回ではNTS-1のエフェクターを実際に作ったものを紹介しましたが、皆さま実際に触ってみて頂けたでしょうか? 今回は「NTS-1のオリジナルエフェクター(&オシレーター)を作るのに必要な開発環境」について解説したいと思います。
といっても基本的にすべてのことは「logue SDK」のページで説明されていますので、今回はその補足的なことを説明していきます。 なお今から説明するものはすべて無料です。 また、Windows、Mac、Linuxそれぞれの環境で開発が可能となっていますので、ほとんどの方が開発可能であることも魅力です。
(インストール手順はそれぞれ違うのでご注意ください)

logue SDK
https://korginc.github.io/logue-sdk/

まず「SDK」というものについてですが、これは「Software Development Kit」の略で、特定のソフトウェアを開発するのに必要なツールなどをセットにしたものです。 例えばWindowsアプリを開発するのにはWindows SDKが、iPhoneアプリを開発するにはiOS SDKというものを使って開発を行いますが、NTS-1に関してはこの「logue SDK」というものを利用して開発することになります。 https://github.com/korginc/logue-sdk

ここで公開されているのはそのlogue SDK本体です。 一番良いのは「Git(ギット)」というツールを使って最新版を取得することですが、Gitの使い方を理解する必要がありますので、上記のページにある「Clone or Download」という緑色のボタンからZIP形式でダウンロードする形でも構いません。 ただ、SDKもバージョンアップをすることがあり、常に最新版を取得しておきたい場合にはGitを使って取得するほうが得策です。

MSYS2 (Windows用)
https://www.msys2.org/

WindowsでNTS-1の開発環境を構築しようと思う際に一番の難関になると思われるのはおそらくこの「MSYS2」だと思われますので、そちらの解説をします。 まずlogue-SDKで使われるGNUのコマンド群はすべてUnixというOSでのコマンド実行を前提としています。そのためUnixそのものであるLinuxや、同じくUnixをベースとするmacOSの場合は最小限のツールのインストールで済むのですが、Windowsの場合はUnixのコマンドを実行するための追加の環境が必要になります。

MSYS2というのは、簡単に言ってしまえば「UnixのコマンドをWindows内で実行するためのプラットフォーム」です。 そのため、Windows & MSYS2で開発を行うためには「MSYS2」のウィンドウ内でコマンドを実行することになります。 「NTS-1 MSYS2」などでネット検索すると具体的な手順を解説されている記事などがヒットしますので是非参考にしてみてください。

GNU Arm Embedded Toolchain
https://github.com/korginc/logue-sdk/tree/master/tools/gcc

そしてプログラムを開発するには人間が書いたプログラムをコンピューターが読める機械語に変換するための「コンパイラー」というものが必要になりますが、logue SDKでは「GNUコンパイラコレクション(通称:GCC)」というものを利用します。 GCCについてはそれだけで分厚い本が1冊書けてしまうほど奥の深いものですので詳しい説明は割愛しますが、このページで説明されている「GNU Arm Embedded Toolchain」というのはそのGCCを含めたプログラミングツール群の名前です。 「Arm Embedded」と付いていますがこれはNTS-1で使っているCPUが「Arm系」と言われる「STM32F4」というチップですので、そのCPUで動くプログラムを開発するためのツールチェーンということになります。 インストールにつきましては、Readmeに記載の通り、用意されているシェルスクリプトを実行すればOKです。

GNU Make
https://github.com/korginc/logue-sdk/tree/master/tools/make

Makeとは「毎回たくさんのコマンドを実行してファイルをコンパイルしたりするの大変なので、それらを設定して1つのコマンドで実行するためのツール」というものです。 (Makeもまた本1冊になるほど奥の深いものです) Mac、Linux、Windows(& MSYS2)では特別追加でインストールする必要はありませんが、そうでない場合のみインストールする必要があることが説明されています。

Info-ZIP
https://github.com/korginc/logue-sdk/tree/master/tools/zip

これはZIPファイルを作成するためのツールですが、こちらもGNU Makeと同じくほとんどの環境では特別インストールする必要はありません。

logue-cli (任意)
https://github.com/korginc/logue-sdk/tree/master/tools/logue-cli

こちらは「任意」となっているとおり、全員が必要なものではありません。
前回ご説明した「Sound Librarian」というツールのコマンドライン版と考えていただければいいでしょう。 ただし、Windows版、Mac版はありますが、Linux版のSoound Librarianはないようですので、Linuxで開発をしようという方はこちらのツールが必要になると思います。

以上のツールが無事インストールできればSDKに含まれるサンプルコードをビルド(プログラムの作成)してみましょう。
https://korginc.github.io/logue-sdk/
の「デモプロジェクトのビルド (Waves)」にある手順でビルドを行います。 

無事これらのコマンドが実行できれば「waves.ntkdigunit」というファイルが出来ますので、これをまたSound Libarianで読み込めば「USER OSCILLATORS」に「waves」という名前で読み込まれるはずです。

ここまでくれば次は実際のプログラミングになりますが、無事動くまでは大変だとおもいます。
しかしながら幸いこれらのツールに関してネット上に情報はたくさんあふれていますので、是非ネット検索等を駆使して環境を作ってくださいね!

それでは次回をお楽しみに!

第3回 オリジナルエフェクターを作ろう その1

こんにちは、DOTEC-AUDIOでサウンドプロデューサーをしているフランク重虎です。
いよいよエフェクターを作っていきますので、今回からDSPの設計をしている僕が担当します。

さて前回までの開発環境は準備できましたでしょうか?
初めてコマンドラインを使ったよとかプログラム環境を作るよって方でも進められるように少しフォローしますね。

MSYS2はマウスではなく「cd フォルダ名」でフォルダを移動しますので、そのときに少し楽になる方法を教えます!
なが~いフォルダ名とかは初めのいくつかの文字をいれて「TAB」キーを押すと前方一致で自動入力してくれます。補完ですね。
そして今いるフォルダ内容の一覧を出したいときは「ls」とコマンドを入れてEnterすれば確認できます。
とりあえずフォルダを移動する「cd」一覧を出す「ls」を覚えておきましょう。
ちなみに一つ上に戻りたいときは「cd ..」とピリオドを二つ打ちましょう。
本当はUNIX上ではフォルダのことをディレクトリと呼ぶんですけど、WindosやMac上での操作もあるのでフォルダの方に統一して呼びます。と、断っておけば怒る人いないよな。。

あとMSYS2のユーザーホームにlogue SDKを入れちゃうと今後の作業が行いやすいですよ。
例:WindowsでCドライブ直下にMSYS2を入れた場合
C:\msys64\home\ユーザー名\korg

では本題。まずは こちらのファイルをダウンロードして
korg\v1.1\platform\nutekt-digital
の中に解凍してください。

Mod(モジュレーター)、Delay、Reverbエフェクトそれぞれを作る時のテンプ
レートが入ってます。
実はlogue SDKにもテンプレートは入っているのですが、今回の勉強が進めやすいようにシンプルにまとめてみました。慣れないとサンプルのフォルダ構成と混同しちゃったり、あれこれコピーに迷ってしまうと難しいですからね。

今回のテンプレートのフォルダ構造について

今回DOTEC-AUDIOで作成したテンプレートですが、それぞれ以下のような構造になっています。

・ld(フォルダ)
・tpl(フォルダ)
・main.c
・Makefile
・manifest.json
・projuect.mk

最初の「ld」フォルダは作るエフェクターの定義ファイルが置かれている場所です。
詳しい説明は割愛しますが、作るエフェクターがMod、Delay、Reverbでこのフォルダの中身が変わると覚えていてください。
「tpl」も同様に各種エフェクターのテンプレートとなるファイルが置かれているフォルダです。
「ld」も「tpl」も作りたいエフェクターの種類によって正しく選択する必要がありますが、皆さんが何か編集する必要はありません。

「Makefile」「manifest.json」「project.mk」はそれぞれ定義ファイルですが、自分が作りたいエフェクターに合わせて書き換える必要があるのは「manifest.json」と「project.mk」です。
この回の最後に編集箇所を解説しています。

そして「main.c」というのがエフェクターのプログラム本体です。

今回はデモにあるbitcrusherをつくります。このエフェクトはDeeFXにあるビットクラッシャーを勉強用にシンプルにしたものです。

何はともあれ先に完成形で遊んでみましょう。
bitcrusherのデモをダウンロードしてテンプレートと同じ場所
korg\v1.1\platform\nutekt-digital
の中に解凍してください。

MSYS2を使って
korg\v1.1\platform\nutekt-digital\bitcrusher
に入ります(移動します)、前述のTABキーをうまく使うと楽ですよ。
cdコマンドを使ってbitcrusherまで入ったら前回のようにmakeしてください。
覚えてますか?makeと打ってEnterキーです。
ズラズラ~と文字が流れて最後に

Packaging to ./bitcrusher.ntkdigunit

Done


と出れば成功です。buildフォルダとbitcrusher.ntkdigunitファイルができてますので、前回のようにNTS-1に転送してみましょう。ツマミAで強くかかります。

ではソースコードを解説していきます!
メモ帳でも秀丸でもなんでも良いですのでテキストエディターでbitcrusherフォルダ内のmain.cを開いてください。

  初めの

#include "usermodfx.h"
#include "float_math.h"


この1行目はmodfxを作る時に必ず必要です。続いて2行目は浮動小数点演算を行うときに必須となります。

デジタルの音声データは数の大きさを表すのに固定小数点と浮動小数点という二つの方法があります。このうち普段生活で見る「1.5倍に増量!」などと同じ使い方ができるのが浮動小数点です。人間が理解しやすいということですね。でもその反面で処理が重くなるという欠点があります。

固定小数点は処理が速いけど人間が理解しづらく、整数と少数の桁数を決める様々なフォーマット(Qフォーマット)があって取り扱いの難易度もあがります。

ですが喜んでください!NTS-1には浮動小数点を専門に扱うプロセッサも内蔵されているのです!
これを活用しない手は無いので、遠慮なく使います。

その次を見てみましょう。

static float rate, lastSampleL,lastSampleR;
static uint32_t count;


これは変数というデータが入る箱にラベルを貼って用意した状態です。
staticでfloat型のrate,lastSampleL,lastSampleRという3つの変数と、staticでuint32_t型のcountという変数を作ってます。
これを「(グローバル)変数の宣言」というのですが、プログラムの基本ですので
「C言語 変数 宣言」
などで調べておきましょう!staticの意味や型についてもわかります。
簡単には処理するたびに中身が消えたら困る変数は、staticをつけると保持されます。
他にも役割がありますが「static 静的な変数」を調べてみましょう。

  さて次は
void MODFX_INIT(uint32_t platform, uint32_t api)
{
 lastSampleL = 0.f;
 lastSampleR = 0.f;
 count = 0;
}

これは関数と呼ばれる一括りです。
プログラム処理を機能ごとに関数名というラベルを付けてまとめたもので、プログラムのあらゆる場所から関数名で呼び出して組み合わせ、連携した結果が一つのソフトウェアになります。自動車の各部品みたいなものです。

  戻り値 関数名(引数)
{
処理内容
}


のフォーマットで書かれます。戻り値というのは関数の処理結果をどのようなデータで呼び出し元に戻すか、引数は呼び出すときに関数に与えるデータと種類のことです。

 今回は初期化処理を書いてます。さきほど用意した変数の内容を0にリセットしているのですが、0.fのfって何?と思いますよね。これは単にfloat型の約束ですので調べてみましょう。
ちなみに戻り値のところのvoidですが、これは結果を何も戻さないという意味で初期化処理は初めの一回実行して終わりだからvoidとなっています。
投げっぱなし上等!

さぁ次はいよいよメイン処理ですが、ちょっと飛ばして先に一番下にある関数を解説します。

  void MODFX_PARAM(uint8_t index, int32_t value)
{
 const float valf = q31_to_f32(value);
  switch (index) {
  case k_user_modfx_param_time:
rate = valf;
break;
  default:
break;
  }
}


  うわー、いきなり難しい!
これは何をしてるかといえば、A,Bのツマミからデータを受け取って変数に入れてるんです。
ツマミを回すとNTS-1のシステムからこの関数が呼ばれます。呼ばれたときにツマミの種類indexとその値valueが引数としてもらえます。
さてこのvalueが先ほど出てきた固定小数点で入ってるので、まずはそれを浮動小数点に変換します。ここではQ31フォーマットの固定小数点を32bit浮動小数点に変換してvalfという変数に入れました。constはデータ内容を変えられたくないときに使いますが、詳しくは検索してみましょう。

  それをswitch case文という文法で処理します。簡単にはswitchで指定した変数がそれぞれのcaseだった場合の処理が並んでます。
今回はツマミAのデータのみ使いますので、k_user_modfx_param_time(ツマミAのindex名)のデータが来た時に変数rateにvalfの内容を入れてます。
このrateを使ってメイン処理をしますので、この関数を先に解説しました。

  つぎこそメインです。

  void MODFX_PROCESS(const float *main_xn, float *main_yn,
                const float *sub_xn,  float *sub_yn,
                uint32_t frames)


  MODFX_PROCESSという関数名で、もらえる引数は

メイン入力main_xn
メイン出力main_yn
オシレーターからのサブ入力 sub_xn
オシレーターからのサブ出力 sub_yn
総フレーム数 frames


の6つです。

  変数名についてる*はポインタの参照渡しというもので、この関数で中の値を変更したら呼び出し元の変数も変わることを示します。もらってるデータはコピーじゃなくて原本ですよって意味に近いです。参照渡し、値渡しで調べて勉強してみましょう!

  引数をみてピンと来たかもしれませんが、ようするにmain_xnにフレーム数だけ入ってるデータを色々とエフェクト処理をして、出力としてmain_ynに書き込めば良いんです。
今回サブ入出力は使いません。
その始まりとなるのが

   for(uint32_t i = 0; i < frames; i++){

  これは{}で囲った内容を指定した数だけ繰り返すという意味です。for文と言いましてこれでフレーム数だけ処理を繰り返します。

      //LとRの音を用意する
  const float inL = main_xn[i * 2];
  const float inR = main_xn[i * 2 + 1];


  初めの//はコメントといって、これをつけるとプログラムに影響なくメモを残せます。
さて入力main_xnですが、ステレオの音声(の粒)がLとR交互に入ってます。
それぞれ交互に処理をしても良いですが、わかりやすく毎回inLとinRという変数に入れなおします。
改めてmain_xnの構造を解説しますとLRLRLR…という並びでLRのセットがフレーム数だけ入っています。データ数としてはフレーム数の2倍入っています。配列変数で調べるとわかりますが複数のデータが入る変数を配列変数といいまして、そのデータ数を要素数と呼んでいます。main_xnの要素数はframesに書かれてるフレーム数の倍あるんですね。

  その要素の何番目というのを[]で指定します。ややこしいのが0から始まるのでmain_xn[0]だと1番目なんです。
それでこのfor文では1ループごとに1つ増える変数名iの値が、framesより小さい間だけループします。
iは0から始まりますのでframesより一つ小さい値で終われば回数としてはフレーム数と同じになります。
なんで1からはじめないの?!って思いますよね。その場合はframesと同じ数になったら終わりにすると思います。でも「同じ」ってチャンスとして1回なので、うっかりプログラムミスをして飛び越えちゃったら無限ループが始まっちゃいます。
そうなるとフリーズしちゃったり、その後の処理も0から始まるから便利だったりするんでしょ。それがまさに次の話。

  [i * 2]とか[i * 2 + 1]となってますね。LRが交互に入ってるので0番目はL、1番目はRが入ってます。iが0のときは[0 * 2][0 * 2 + 1]で0と1、iが1,2…と考えると、なるほど~。

  どや顔で解説させて頂いたあとはビットクラッシャーのタネあかし部分です。
先に仕組みを説明すれば、サンプリングデータは細かいほど音質が良くなりますので荒くします。荒くするとはサンプリングデータの更新頻度が低いとか段階(解像度)が大雑把になることです。今回は更新頻度をさげて、何回かに一回だけデータ出力を入れ替える作りにします。12345678と連続した入力データが11335577という感じになります。
これでサンプリングレートが落ちたような音になるのですが、それってビットクラッシャー(量子化を下げる)じゃねぇじゃん!と突っ込みが入るの、よーくわかります。
でもビット演算とかいきなり説明されても辛いですし、世の中でビットクラッシャーとされてる音ってビットを落とす地味な方でなくサンプリングレートを落とした派手な方なので、そっちの方が面白いと思いますので、このまま続けますよ!

    //大きくなるほどサンプルが粗くなる
  uint32_t skip = rate * 64;


  これは先ほどツマミから受け取ったデータを使うところです。やっとでてきた!
受け取ったデータは0~1の範囲で入ってるため、最大(1のとき)を64にしたい場合は64をかけます。
わかりやすいようにskipという変数に入れかえます。

    //countが0の時だけlastSampleを更新する
  if(count == 0){
lastSampleL = inL;
lastSampleR = inR;
  }


  ここの意味は先に進むとわかりますが、先に処理内容だけ解説します。
countという変数が0になった時だけ出力を保持する変数を更新します。つまり0以外はlastSmpleL/Rは前回の値のままです。
前述の初期化でcountは0から始まりますので、いきなりinL/Rの値に更新されます。

    //lastSampleの音を継続する
  main_yn[i * 2] = lastSampleL;
  main_yn[i * 2 + 1] = lastSampleR;
  count++;


入力をLとRに分けた時の逆で出力main_ynにLとRの音を書き込みます。つまりさっき入れたばかりのinL/Rと同じ音が書き込まれます。変化なし!
ところがその後にcount++というのがありまして、これはcountを一つ増やしてます。
つまり0から1になったんですね。この書き方はfor文のときもi++と書いて一周するごとにiを一つ増やしています。別の書き方をすれば count = count + 1 です。
1になったということは、次の周の頭でlastSampleL/Rが更新されません。同じサンプルデータを出力しつづけるのです。ではどこで0に戻るのか?!

    //skipを超えたらcountを0にリセット
  if(count > (int)skip) count = 0;


  はい、ここです。
さきほどツマミから貰って64倍した値をcountが超えたら0にリセットされます。
つまりはskipの数が大きいほどず~~っと同じデータを入力に関係なく出力しますので、サンプリングデータの更新頻度が低く落ちることになるわけです。
完成!

  あと最後の
 }
}

とあります。これが大事で上はfor文の終わり、下は関数の終わりを示します。基本的にいろんな処理を{}で囲みますので、内容が長くなるほど終わりの}を忘れたということが良くあります!たったこれだけでビルドは失敗しますのでよく気を付けてください。
またミスとして見つけにくいため、閉じ括弧一つで長時間悩み続ける話もよくあります。
もちろん僕も経験済みです!見つけた時にパソコンをぶん投げて頭で受けたくなりますね!

  今回のプログラムはModfxですのでテンプレートのtmpModを元に作ることができます。
是非main.cを見比べて何がどこに追加されているか調べてみてください。
skipのところに色んな値を入れてみて実験してみましょう!

  最後に作ったエフェクター名はmanifest.jsonのnameの項目、project.mkのPROJECTの項目にに記載しておきましょう。テキストエディターで編集できます。

  次回はStopFX
お楽しみに!
長文を読んで頂いてありがとうございました!

第4回 オリジナルエフェクターを作ろう その2

こんにちは、DOTEC-AUDIOでサウンドプロデューサーをしているフランク重虎です。
今回もエフェクターを作っていきますので、引き続きDSPの設計をしている僕が担当します。
第3回と説明がダブるところは省略してますので必ず順番通りに読んでくださいね!

  さて前回よりちょっと高度なエフェクターをつくりますよ。

レコードを止めたような効果が出て面白いですね~。これの作り方を丸ごと教えます!

stopfxのデモをダウンロードして
korg\v1.1\platform\nutekt-digital
の中に解凍してください。


  まずは実際に動いてるのを見るためMSYS2を使って
korg\v1.1\platform\nutekt-digital\stopfx
に入ってmakeします。何言ってんだかさっぱり…となったら前回(第3回)を読んでくださいね。

  動きましたか?ではソースコードを解説していきます!
stopfxフォルダ内のmain.cを開いてください。

初めの

#include "userdelfx.h"
#include "float_math.h"
#include "buffer_ops.h"


1行目はdelfx(ディレイ類)を作る時に必ず必要です。続いて2行目は何か覚えてますか?
はい、前回と同じく浮動小数点演算を使うのに必要な物ですよね。
  でも3行目に新しいのが出てきました。これはNTS-1で沢山の音をメモリに記録するのに必要となります。

だいたい想像がつくと思いますが長い音楽データを記録するには大きなメモリが必要となりますよね。NTS-1のSDKにはメモリ操作(メモリとのやりとり)を行うための機能が用意されていて、それを使うための宣言が3行目の「 #include buffer_ops.h」になります。

  ここで一つ新しい言葉を覚えましょう。「バッファ」です。聞いたことあるかもしれません。
一時的な処理に使うデータを貯めたり保持したりする場所のことで、要は前回でてきた配列を使います。ここに音のデータを沢山貯めたいので、ちょっと大きい配列を作ります。

  さて次は関数に入ります。まずは前回同様に初期化

void DELFX_INIT(uint32_t platform, uint32_t api) { buf_clr_f32(s_delay_ram, BUFFER_LEN); z = 0; z2 = 0; prev = 0; next = 0; p = 0.f; slope = 0.f; isStop = 0; }

delfx専用の関数になってることに注目。名前が違うぐらいですね。
他の変数は0とか初期値を入れればよいのですが、バッファだけbuf_clr_f32()という初期化用の関数があるので利用します。


  一旦ここで先に最後の関数から説明します。

void DELFX_PARAM(uint8_t index, int32_t value)

これも関数の名前が違うだけで前回と同じ使い方をしてますので、忘れてしまったら第3回を読むとわかりますよ!


  いよいよ本題のDSP処理に入ります。

void DELFX_PROCESS(float *xn, uint32_t frames)

DELFX_PROCESSという関数名で、もらえる引数は

メイン入出力main_xn
総フレーム数 frames

の2つです。あぁ6つもあった前回より全然少なくて簡単!

  modfxは入力と出力が分かれてましたが、今回はxnが入出力となってるのがポイントです。
xnに入力データが入ってるので、それを処理して関数の終点で上書きされてたデータが出力データになるという仕組みです。

//サンプリング用バッファにコピー
for(uint32_t i = 0; i < frames * 2; i++){ s_delay_ram[z++] = xn[i]; if(z > BUFFER_LEN - 1) z = 0; }


  用意したバッファに入力を全部入れます。前回も登場した繰り返しを行うfor文と条件を判断するif文ですね。framesは1チャンネル分のフレーム数なので、LRの2チャンネル分をまわすために2倍してます。ややこしいのがzの後に++があるのでバッファのz番目に入力した後でzが増えます。

そして配列は0番目から始まるんでしたよね?!ですからBUFFER_LEN番目を踏んだらクラッシュして大変なので、その前で0にリセットします。前回にもちょっと書きましたが、ここの条件は色んな書き方ができます。今回も上限以上になったらという条件に統一しちゃいますね。ちなみにクラッシュさせてもNTS-1は壊れませんので何度失敗しても大丈夫です。

このように0に戻してバッファを回し続ける(書き続ける)方法をリングバッファや循環バッファと呼んでます。

  次に実際に再生速度をスローダウンさせる値の下準備をします。

//ツマミを左に閉じたときにリセット
if(rate < 0.1f){ isStop = 0; rate = 0.f; }else{


これはツマミを左いっぱいに回したときに元の再生速度に戻すための処理です。左いっぱいだからと言って条件をrate== 0.fとすると使い勝手がシビアなので、ちょっと余裕を持たせて0.1f以下としてます。少し指が動いただけで間違って反応させたくないですよね。

  isStopはストップエフェクト中かどうかの判断に使います。C言語では条件判断のtrueとfalseをそれぞれ1と0で代用できますので、ストップエフェクト前として0をセットしています。
エフェクトを切り替えた時にツマミの適当な数値を拾ってしまうので、rateもリセットします。

最後がelseで終わってるのに注目してください。これは「そうではない場合」の処理も付け加えるときに使います。はじめ僕はこれをイレースって読んでたんですよ。バカですよねぇ(笑)

  さてelseに該当する場合はツマミが回っているので、ストップエフェクト処理です。
まずはじめに回し始めた時の初期値をセットします。
ここからちょっと難しい!

//止はじめのポイントを決める。ツマミが回ってる間はisStopが1なので無効。
if(!isStop){ isStop = 1; rate = 0.f; p = (z - frames * 2.f) / 2.f; if(p < 0.f)p = (BUFFER_LEN - 2.f * p) / 2.f; }
//elseではなく、直前のif文の閉じ括弧です


  isStopの前の!は怒ってるわけじゃなくて「違う場合」を示す「not」です。isStopがtrueじゃない場合、つまりfalseの場合にif文の中を処理します。
先ほど0にセットしたので処理しますが、回し始めたら処理して欲しくないので直後でisStopを1にセットしてます。これで左いっぱいに回してリセットされるまで処理が飛ばされるようになりますよね。このような処理をフラグと呼びます。よく言う「〇〇フラグが立った」と同じ意味です。
先ほどと同じくツマミが適当な位置にいる場合があるので、その場合さきほどの条件を抜けていきなりここに入るためrateをリセットします。

pという変数はバッファの再生ポイントを示します。バッファにframesの2倍分を貯めましたから、貯め始めたポイントまで差し引いて戻します。なんでさらに2で割ってるの?と疑問が残りますが、それは後でわかります。最後にif文でもしpがマイナスになっちゃった場合の処理を書きます。例えばバッファがぐるっと一周して書き終わった場合、そのポジションから書き込んだ総数を引いたらマイナスになっちゃいますからね。なので後ろから差分を引きます。

  まぁ今回はキリの良いバッファサイズなので上手いことマイナスにはならないのですが、配列のマイナス番地は考えておく癖をつけましょうね。
バッファが出てくると急に複雑になるけど大丈夫!あなたならわかる!

  ちなみにこのif文は{}を省略してます。直後の一行を処理するだけでしたら省略できますので、ちょっとしたテストでifを加えるときにも便利なので覚えておきましょう!

そしてelseのふしぎな旅はまだ続きます。(つまんねぇギャグ)

for(uint32_t i = 0; i < frames; i++){ uint32_t length_mono = BUFFER_LEN / 2;

  for文が出てきたのでここからエフェクトかけてxnをガンガン上書きしていきます。
なぜ今回はframesを2倍しないかといえば、ステレオで2行づつ処理するからです。
後でちゃんとわかりますので、まだピンと来なくても大丈夫です。

 初めにバッファのモノラル分の長さをわかりやすい名前の変数に置き換えておきます。
何度も半分に計算するの面倒くさいし数式増えて見づらいですからね。
整数なので変数型はuint32_tとします。

//再生ポジションの前後のインデックスと補間する係数を求める
prev = (uint32_t)p; slope = p - prev; next = prev + 1; if(next > length_mono - 1) next = 0;


 ここ大事です!

ゆっくり再生させる仕組みとして、2つのサンプル間の値を算出してゆっくりとサンプルを進めていきます。数をゆっくり数えるときに「い~~ち、に~~ぃ」となるのと同じで、伸ばすところを2点から算出します。

pはfloatなので1.2とか5.4とか半端な数になります。でも配列の1.2番目なんてありません。だから1.2番目にある値は1番目の値から2番目の値に20%近づけた値と仮定します。
そうすると例えば1,2,3と値が並んでたとして1.3,1.6,1.9,2.2,2.5…とゆっくり進んだ風の値を取り出せちゃいます。これが波形の高さだったら伸びた状態ですよね。

 それで解説を進めますと1行目でpを整数に変換してます。この(型)という書き方はキャストと言いまして、型変換をするときに使います。
整数に変換すると、たとえば7.4だったpが7として切り捨てられてprevに入ります。
2行目で元のpから整数化されたprevを引いた分がslopeに入ります。

そう!切り捨て分ですね。先ほどの例だと0.4です。

もうわかっちゃった方もいるでしょう、p番目の値から40%進んだ値を出すのに使います。
どこに進むか?それが3行目で当然p番目の次の配列ですね。これをnextに入れます。

 最後のif文はnextが配列を飛び出ないように。もうおなじみですね。

//再生ポジションの音を求める
float s1L = s_delay_ram[prev * 2]; float s2L = s_delay_ram[next * 2]; float s1R = s_delay_ram[prev * 2 + 1]; float s2R = s_delay_ram[next * 2 + 1];


 いよいよクライマックス!
s1は前述の2点間の初めの音、s2は終わりの音でLとRを用意してます。
prevとnextは先ほど求めた2点の配列の番号です。
2倍したり1足したりしてるのは前回の説明と同じなのですが、バッファにLRが交互に入ってますからLの音は配列の偶数番目、Rは奇数番目を取り出す必要があるからです。

for文のiは0から1づつ増えますので0,1,2,3…をそれぞれで計算してみれば偶数と奇数に分かれますよね。
初めの方でpを出すのに2で割った理由は、ここで2倍にする必要があるからです!
そうだったのかぁ。

float currentL = 0.f,currentR = 0.f; currentL = s1L + (s2L - s1L)*slope; currentR = s1R + (s2R - s1R)*slope;

 初めの変数は一時的に現在の場所の音を入れるために作りました。無音で初期化してます。
次の式が先ほどの中間点の値を出すための計算です。はじめの値に次の値との差分を数%足してるだけです。例えば0,10と続く値だった場合に、0から20%進んだ場所の値は

0+(10-0)*0.2 = 2

となりますね。前述のpが1.2番目だった時の値です。

 そしていきなりですがおめでとうございます!
一番難しい峠を越えました!

//出力として上書きする。
xn[i * 2] = currentL; xn[i * 2 + 1] = currentR;


  めでたく出すべき音の値が計算できたのでxnをLR順番に更新します!
このループの最大数がframesだったのはLRを同じiの値で処理するから半分回せばOKなんです。
はじめもそうできるのですが、特に分ける必要なかったのでぶん回しました。
漢ですから。

//再生ポイントをrateの量に従って進める
p += 1.f - rate; if(p > (float)length_mono - 1.f) p = 0.f;
}//ここがforの終わり
}//ここがelseの終わり


 そして次のループのためにpをrateに従って進めます。
+=というのは左辺に右辺を足すという意味です。逆数にしてる理由はツマミを絞ってrateが0の時に最も早く進み、1で止めたいからです。0の時は1個づつ配列が進む=標準の再生速度となりますね。それが0.3個づつなどツマミを右に回すほど遅くなります。
次のif文はpが片チャンネル分進んだ後に0へ戻すためですね。
最後にforとelseの閉じ括弧で終わります。
 旅のおわり。

 このプログラムはDelfxですのでテンプレートのtmpDeleyを元に作ることができます。
main.cを見比べてるとプログラムを書くべき場所がわかりますよ。

 前回同様に最後に作ったエフェクター名はmanifest.jsonのnameの項目、project.mkのPROJECTの項目に記載しておきましょう。

 このエフェクトはDOTEC-AUDIOのDeeFXに搭載されたストップエフェクトをシンプルに変えたものですが、基本的な考え方は同じですので結構見ごたえあったかと思います!

 次回はいよいよ最終回の総まとめ!

 それでは僕からのDSP講座は終わります!長文を読んで頂いてありがとうございました!

第5回(最終回) ボコーダーを作ってみました

皆様こんにちは、DOTEC-AUDIOの飯島進仁です。
前回、前々回とフランク重虎による具体的なDSPの中身の講座となりましたがいかがでしたでしょうか?
正直かなり難しかったのではないかな?と思うのですが、デジタルエフェクターのプログラムの基本はどんなものでも「入力されたデジタルデータを加工して出力する、ということを繰り返す」ということにつきます。

そして今回のサンプルプログラムはどちらも100行に満たないサイズに抑えてありますから、ネット検索などを駆使して是非じっくり理解して頂き、NTS-1のエフェクター開発や今回残念ながら解説できなかったオシレーター(シンセサイザー)の開発までご興味を持って頂くきっかけになればと思っています。

そんなわけでこの連載は今回をもって最終回となってしまうのですが、今回は残念ながらプログラムの解説はございません。

ただ 「我々DOTEC-AUDIOが全力でNTS-1で動く16バンドのボコーダーと専用オシレーターを作りました」ので、そちらの解説と更にDOTEC-AUDIOでリリースしているPC用のプラグインを簡単にご紹介していきたいと思います!

今回私たちが開発したボコーダーですが、こちらは16バンドの本格的なボコーダーとなっています。
NTS-1にモジュレーターとなるマイクを繋いで、言葉を話しながらオシレーターを鳴らせばカッコいいロボットボイスになります。

いかがでしょう?このコンパクトなデジタルシンセサイザーで16バンドのボコーダーが動くってすごくないですか!?

実はNTS-1の仕様上いくつか「裏ワザ」的なことをやって実現していますので、ちょっとややこしいですがこれからそちらの説明をしていきたいと思います。

まずNTS-1は「AUDIO IN」の端子を搭載しています。

こちらにラインレベルで音声入力をすることで、その音声にエフェクトをかけたりオシレーターの音と混ぜたりすることができる機能を持っているのですが(大変素晴らしい仕様です)、この「ライン入力が前提であること」と「入力音声とオシレーターの音が混ざってしまうこと」がボコーダーを実現するのにハードルとなってしまっていますので、そこに使い方の工夫が必要です。
 

・ライン入力について(音声の入力レベルについて)
NTS-1の入力は「ライン入力」を前提としていますので本来であればマイクを繋ぐ場合には必ずマイクアンプかミキサーでの増幅が必要になります。

またライン入力を前提としてレベルを減衰させるアッテネーター(減衰抵抗)が設定されています。

しかし幸いなことにNTS-1では「グローバル・パラメーター」という設定項目があり、本体の様々な動作を変えることができます。 詳しくはNTS-1付属の取扱説明書の「グローバル・パラメーター」の項(P16 右下)を参照していただきたいのですが、その中で「インプット・トリム」という項目があります。

もしお手元の説明書に記載ない場合は最新版を こちらからダウンロードしてご覧ください。PCと接続してNTS-1のファームアップデートが必要な場合もありますので、ご注意ください。

工場出荷状態では「6:-6DB」になっていますが、こちらを「0:0DB」に設定することで減衰を解除できます。もしアンプ無しでダイナミックマイクなどを接続したい場合はこちらを設定してください。 (ライン入力の場合は不要です)

なお「それでも入力音量が小さい」という問題に関しては、ボコーダーのパラメーターAに「ゲイン」を設定していますので、こちらのツマミを調整することで最大100倍の音量に増幅できるようになっています。

・入力音声とオシレーターの音について
ボコーダーというのは「シンセサイザーの音(キャリア)をマイク入力の音声(モジュレータ)で加工する」というものですから、それぞれ別入力を必要としますがNTS-1ではそういった機能はありません。
試して頂ければお分かりの通り、シンセと外部入力がミックスされた後にエフェクトがかかるようになっています。

そこで弊社で無理やり思いついたのが「ステレオ音声の差分で音を分離する」という方法です。 例えば左右どちらにも同じシンセサイザーの音が入っていて、それに加えて片方だけにマイクの音声が加わっていた場合、両方の信号の差分でマイクの音声を抜き出すことができる…、という理屈はご理解頂けるでしょうか?

つまりこういう式になります。

(マイク音声+シンセの音)― シンセの音 = マイク音声

これによりNTS-1でも「マイク音声」と「オシレーター」の音を分離して処理が行えるため、今回のボコーダーが実現できたのです!
しかしながら、これを実現するにはちょっとマイクの繋ぎ方を工夫する必要がありまして、例えば以下のような方法が考えられます。

モノラル端子のダイナミックマイクなどを接続する
・最初から Lのみに声を入れた音源(Rは無音)を用意してステレオでNTS-1にライン入力する
・ミキサーでマイクの音を完全に LのみにしたステレオをNTS-1にライン入力する
・Y字ケーブルで Lにだけマイクを接続する
・(その他ステレオ入力の場合)Y字ケーブルで Lにだけ接続する

  • ダイナミックマイク接続例

  • Y字ケーブルを使った接続例

Y字ケーブルの参考URL: https://www.amazon.co.jp/gp/product/B000068O5H


最後の方法が一番トリッキーと言えますが、理屈が分かってしまえば一番シンプルと言えます。なんといっても電源が不要なのが一番の魅力です。
いずれの方法も、ちょっと面倒ですがぜひ挑戦してみて下さい!

Vocoder for NTS-1

ということで、こちらのボコーダーですがデモ版をオシレーターとセットでDOTEC-AUDIOのサイトから無料ダウンロードできます。

https://dotec-audio.com/nts1.html

デモ版は3分でボコーダーが無効になってしまいますが、「1000円(税別)」で販売させて頂くことになりました。デモ版で試して面白い!と思って頂けましたら是非よろしくお願いします!
NTS-1がボコーダーとして動くのはハッキリ言って感動します!

そして最後にDOTEC-AUDIOの自己紹介と本来の製品も少し紹介させて頂ければと思います。

DOTEC-AUDIO(ドーテック・オーディオ)はミュージシャン・エンジニアであるフランク重虎と株式会社ふむふむソフトが共同で運営しているソフトウェアブランドです。 普段はWindows、Mac、iOSで動作するDAW等の音楽用ソフトウェア用のオーディオ・プラグインを開発・販売しています。

KORG Gadget2にも「DeeMax(ディーマックス)」というDOTEC-AUDIO製マキシマイザーが搭載されておりますので、そちらでご存知の方もいらっしゃると思います。

DOTEC-AUDIOを始めてかれこれ6年ほどになり製品もかなり増えましたので、PCで音楽制作などをされている方や配信向けの製品もありますので、ご興味のある方は是非サイトをご覧頂きたいのですが、その中でも今回の連載に縁の深い製品を2つほど紹介したいと思います。

・DeeFX(ディーエフエックス) マルチエフェクター

日本語ページ: https://www.dotec-audio.com/deefx_jp.html

第1回でも軽く触れておりますが、この製品はエフェクターの定番である「ディストーション」「フィルター」「ディレイ」を徹底的に使いやすくチューニングしたマルチエフェクターです。
3つのエフェクターを合体したようなデザインになっていますが、それぞれON/OFF出来るようになっていますので、単独で利用できるようにもなっています。

さらに加えて、今回の連載でNTS-1用に簡易版を移植した「ビットクラッシャー」「バイナルストップ」の機能も備えています。プロのミュージシャンでも多くの方が利用されている、人気製品の一つです。

・DeeVocoder(ディーボコーダー) ボコーダー

日本語ページ: https://www.dotec-audio.com/deevocoder_jp.html

この製品はその名の通り、「DOTEC-AUDIO製ボコーダー」です。

近年ユーロラックなどで人気が再燃しているフィルターバンク型のボコーダーで8,16,32バンドの切り替えとフォルマントシフトを備えています。
FFTタイプと違って遅延がなく演奏性にすぐれ、なによりアナログボコーダーの図太いロボットボイスが作れます。
さらにエフェクターとしての位置づけを重視し、使い慣れたシンセプラグインをサイドチェイン入力としてキャリアに使うため音作りの幅が無限に広がります。もちろんサイドチェインに入力した音は何でもキャリアとして使えるため、シンセに限らずギターやベース、ドラムなど思いつきで新しいサウンドを楽しめるプラグインエフェクトです。
このようにDAW用プラグインのため、NTS-1で動くボコーダーとは違った自由度を持ちます。

DOTEC-AUDIO製品はいずれも無料でデモ版が試せますので(登録等も不要です)、VSTやAudioUnitといったプラグインに対応したソフトをお使いの方は是非これらの製品もお試しください!

・最後に
今回の連載は弊社からKORGさんにご提案させて頂いた企画なのですが、その理由はただ一つ、「NTS-1がプログラミングのプラットフォームとして大変魅力的だったから」です。

NTS-1の魅力は何と言ってもそのコンパクトなハードウェアとプログラミングが可能であるという自由度の高さです。
加えて音声入力も持っており、シンセサイザーにもエフェクターにもなる、こんな面白いものがお手軽価格で手に入ってしまうんですから、オーディオプログラミングのプロとして私たちの気持ちも熱くなり、より多くの方に面白さをご紹介できればと思い今回の企画を提案しました。

何度か書いています通り、オーディオプログラミングの基本はNTS-1であってもDAW用プラグインであっても変わりません。
実現する方法は無限に存在しますが、基本は「どちらも入力と出力の間でどう求める音のデジタルデータを作り上げるか?」ということにつきます。
今回の連載をきっかけにして、そしてNTS-1を触りながら、少しでも多くの方に「あの音楽アプリもこのシンセアプリもこんな風に出来ているのかな~」といったようにご興味を持って頂ければ幸いです。

ここまでお読み頂きました皆様、本当にありがとうございました! そしてこの企画をご承諾頂きましたKORG 関係者各位にもお礼を申し上げます!

それではまたどこかでお会いしましょう!

DOTEC-AUDIOフランク重虎、飯島進仁