README from GitHub, GPL-3.0
o303
Ableton Move 用 Schwung の音源(sound generator)です。1 つのチェーンスロットの中で、次の 3 つを 1 台のアシッドベースとしてつないでいます。
TB-3PO シーケンサー → Open303(+ ハードシンク付き VCO2)→ RAT ディストーション → Volume → 出力
- TB-3PO:djphazer の O_C-Phazerville(Hemisphere Suite)にある
TB_3POアプレットを Schwung に移植したものです。303 風のパターンを確率で生成するシーケンサーです。 - Open303:Robin Schmidt による Roland TB-303 のエミュレーションエンジンです。Devilfish 改造の拡張も含みます。
- RAT:ProCo RAT ディストーションペダルの回路モデルで、RAT(LM308)と RAT2(OP07DP)を切り替えられます。
MIDI チャンネルの設定も 2 つ目のスロットも要りません。スロットに読み込むと、Move の再生に合わせて鳴ります。
非公式のエミュレーションで、Roland・ProCo とその関係者とは無関係です。「TB-303」「RAT」は説明のために使っています。ライセンスは GPL-3.0-only です(LICENSE、THIRD_PARTY_LICENSES.md)。
使い方(はじめての操作)
- Schwung のチェーンスロットで、Sound Generator から o303 を選びます。
- スロットの画面を開くと、PAD がシーケンサーの操作面に変わります。
- Move の Play を押すと、パターンが鳴り始めます。
- 下段左の PAD(GEN)を押すたびに、新しいパターンが生成されます。
- ノブ 2〜6(Cutoff / Resonance / Env Mod / Decay / Accent)で 303 らしい音作りをし、ノブ 7・8 で RAT の歪みとトーンを足します。
- 気に入ったパターンは Shift を押しながら 下から 3 段目の PAD をタップすると、バンク 1〜8 に保存できます。
画面を閉じると PAD は Move に戻ります。シーケンサーは Move の再生中ずっと鳴り続けます。
操作方法(詳細)
PAD(この音源の画面を開いている間)
| 段 | 役割 |
|---|---|
| 最上段 | ステップ 1〜8(ステップ窓の前半) |
| 2 段目 | ステップ 9〜16(ステップ窓の後半) |
| 3 段目 | バンク 1〜8 |
| 最下段 | GEN(新規生成)・MUT(変異)・DIR(再生方向)・OUT(音を外へ)・IN(音を内へ)。6〜8 番目は使いません |
- ステップ PAD:タップするたびに、休符 → ノート → アクセント → スライド → 休符…と切り替わります。
- 色は白がノート、赤がアクセント、青がスライド、消灯が休符です。
- 再生中のステップは黄色で光ります。
- バンク PAD:タップで呼び出し、Shift + タップで今のパターンを保存します。
- 呼び出しは、再生中なら次の小節の頭で、停止中ならすぐ切り替わります。
- バンクにはステップの並び・音程・パターンの長さが入ります。
- 色は紫が今のバンク、ティールが保存済み、消灯が空きです。呼び出し待ちのバンクは黄色で点滅し、Shift を押している間は保存先として赤とピンクで点滅します。
- GEN:今の Density / Accent / Slide / Octaves の確率で、新しいパターンを作ります。Length が 8 ステップのときだけ、8 ステップで繰り返して格好よく聴こえるアシッドベース専用の生成方法に切り替わります(下の「8 ステップの GEN」)。16 / 24 / 32 ステップでは TB-3PO 本来の生成方法のままです。
- MUT:今のパターンの約 25% のステップを作り直します。
- DIR:再生方向を 順方向 → 逆方向 → 往復 → ランダム の順に切り替えます。
- OUT(4 番目、緑):フレーズの中で鳴っている音からランダムに 1 つ選び、その音より低い音の方が多ければ 1 つ上のスケール音へ、高い音の方が多ければ 1 つ下のスケール音へ動かします(同じ数ならどちらかにランダム)。つまりフレーズの真ん中(中央値)から離れる向きです。平均を基準にすると、1 つだけ外れた音が平均を引っぱり、その音だけが上がり続けてしまうため、中央値を使っています。押すほどフレーズの音域が外へ広がります。
- IN(5 番目、青):フレーズの一番高い音か一番低い音のうち、平均から遠い方を、平均に近づく向きに 1 つ隣のスケール音へ動かします(同じだけ離れていればどちらかをランダムに選びます)。同じ高さの音が何か所かにあるときは、そのうちの 1 つだけを動かします。押すほど音域が内へまとまり、全部が同じ高さになると何もしなくなります。
- OUT と IN が動かすのは音の高さだけで、ステップの種類(ノート / アクセント / スライド)と位置は変わりません。「フレーズ」は Length の範囲で鳴っているステップのことで、休符は対象外です。動かす量は、半音動かしてから今のスケールに合わせた(クオンタイズした)結果、つまりスケール上の隣の音です。Octaves の範囲は超えません。OUT で選ばれた音が下限(一番下のオクターブのルート)や上限にいて外へ動けないときは、逆向きに 1 つ動かします。選ばれた音が必ず変わるので、ルートの多いフレーズでも毎回いろいろな音が変化します。どちらも Undo で 1 回前に戻せます。
Move が描く PAD の色について:この画面を開いている間も、Move は裏で自分のトラックの PAD を光らせ続けます(Drum Rack の PAD がクリップに合わせて光るなど)。PAD の押下は Move から取り上げていますが、Move の LED までは止められません。そこで、Move が PAD の色を書き換えたら次のフレームでシーケンサーの色に塗り直し、さらに約 0.15 秒ごとに全 PAD を塗り直しています。Move が光らせた直後の 1 フレーム(十数ミリ秒)程度だけ、Move の色が見えることがあります。
8 ステップの GEN
TB-3PO 本来の生成方法は、ステップを 1 つずつ確率で決めます。16〜32 ステップなら偏りがならされますが、8 ステップだと 1 小節の半分を何度も繰り返し聴くことになるので、まとまりの無いフレーズになりがちです。そこで Length が 8 のときの GEN は、アシッドベースの組み立て方に沿って 1 つのループを作ります。操作は今までと同じで、GEN を押すだけです。
- スタイルを、次の 5 つから毎回ランダムに 1 つ選びます。画面には出ず、選ぶ操作もありません。
- HYPNOTIC:ルート音の繰り返しが中心。音程の変化は少なく、アクセントでリズムを作る。スライドは控えめ。
- INDUSTRIAL:ルート音を中心に、すぐ上と下の半音を飾りに使う攻撃的なフレーズ。アクセントが強く、スライドは短い音程差だけ。
- ROLLING:発音が多めで、ルート・5 度・オクターブを行き来する転がるフレーズ。スライドが比較的多い。
- MINIMAL:ほぼ 1 音(8 割以上がルート音)。休符とアクセントで変化をつけ、時々オクターブ上に跳ぶ。
- BROKEN:休符が多く、半音やトライトーンを飾りに使う不穏なフレーズ。アクセントは不規則で、大きな跳躍は少ない。
- リズムを先に決めます。
X-XX-X-XやXX-XX-XXのような 8 ステップのリズムの型から 1 つ選び、発音を 1 つずらすなどして毎回違うノリにしたうえで、Density が求める発音数まで足したり減らしたりします。ステップ 1 は必ず発音し、全部休符や詰まりすぎにはなりません(Density 0 でも 2 音以上)。 - 音程を決めます。スタイルに合った音程(ルート、5 度、短 3 度、オクターブ、半音など)から、Root / Scale / Octaves で使える音だけを使います。今のスケールに無い音(例えば Minor での半音)は使いません。同じ音の繰り返しを多めにし、大きな跳躍は避け、最後の音はステップ 1 のルートへ戻りやすい音にします。
- アクセントは、スタイルが好む拍に置きます。数は Accent の確率で決まり、全部の音には付けません。
- スライドは、発音しているステップから次の発音しているステップへだけ掛けます(8 ステップ目からループ先頭のステップ 1 への接続も含みます)。半音や同じ音へのスライドを優先し、数は Slide の確率で決まります。全部の音には付けず、休符をまたぐことはありません。
- こうした候補を 8 つ作り、ループとして一番まとまっているもの(発音数、ルート音の割合、跳躍の少なさ、ループのつなぎ目、アクセントとスライドの付き方)を採用します。
できたパターンは TB-3PO 本来のデータ(ステップの種類・音階の度数・オクターブ)として書き込まれます。手で編集する・MUT で変異させる・バンクに保存して呼び出す・セットと一緒に保存される、といった扱いはすべて他のパターンと同じです。Undo で GEN の前のパターンに戻せます。MUT は 8 ステップでも TB-3PO 本来の動作のままです。
ボタン(この音源の画面を開いている間)
| ボタン | 動作 |
|---|---|
| + / − | パターン全体を 1 オクターブ上げる / 下げる(±4 オクターブまで) |
| < / > | ステップ窓を移動(24 ステップ・32 ステップのパターンで後半を編集する) |
| Undo | 直前の GEN / MUT / クリアを取り消す |
| X を 2 回 | パターンをクリア(1 回目で確認表示、約 1.5 秒以内にもう一度押すと実行) |
| ジョグを回す | ページ切り替え |
| 選択肢のあるノブを触りながらジョグを押す | そのパラメータの選択肢一覧を開く。ジョグかノブで選び、ジョグを押して決定、Back で取り消し |
| Back | 画面を閉じる(シーケンサーは鳴り続けます) |
これらのボタンは、この画面を表示している間は Move 本体には届きません。画面を閉じると Move の操作に戻ります。
ノブとページ
ジョグでページを切り替えます。画面上部のバーで今のページの位置が分かります。
| ページ | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
|---|---|---|---|---|---|---|---|---|
| Synth | Volume | Cutoff | Resonance | Env Mod | Decay | Accent | RAT Dist | RAT Filter |
| Steps | Density | Accent 確率 | Slide 確率 | Gate | ||||
| Pattern | Density | Accent 確率 | Slide 確率 | Gate | Root | Scale | Length | Octaves |
| Setup | Direction | Transpose | Bank(表示のみ) | |||||
| Tone | Waveform | Tuning | 303 Level | RAT オン/オフ | RAT / RAT2 | RAT Level | Low Cut | Hi Cut |
| VCO | VCO2 Level | Tune | Fine | Wave | Hard Sync | Sync Env | VCO1 Level | |
| Devilfish | Mod オン/オフ | Normal Decay | Accent Decay | Feedback HPF | Soft Attack | Slide Time | Shaper |
さらに、PAD の割り当て図(Pads)とボタン一覧(Keys)のページがあります。
- Steps ページは、ステップを大きく表示するレーンの下に、Pattern ページの 1 段目(Density / Accent 確率 / Slide 確率 / Gate)を並べたものです。
- Density / Accent 確率 / Slide 確率 / Octaves は次の GEN(または MUT)から効きます。Gate は音の長さで、すぐ効きます。
- Root / Scale は音階です。Scale は Minor / Phrygian / HarmMinor / MinPent / Dorian / Major から選べます。Length は 8 / 16 / 24 / 32 ステップです。
- Volume はこの音源の最終段の音量で、RAT の後ろにあります。2 乗カーブで、0 で完全な無音になります。Volume の後に、フルスケールの 0.7 を超えた分だけを丸めるソフトリミッターが入っています。
- 303 Level は 303 から RAT に入る音量(歪みの深さに効きます)、RAT Level はペダル自体の出力音量です。どちらも Volume とは別のつまみです。
- RAT オン/オフ は約 6 ミリ秒のクロスフェードで切り替わります。
VCO2 とハードシンク
Open303 のオシレーター(VCO1)に、2 つ目のオシレーター(VCO2)を足しています。VCO2 は 303 のフィルターの手前で VCO1 と混ざるので、Cutoff・Env Mod・Accent・Decay は VCO2 にも同じようにかかります。スライドすると 2 つとも一緒にグライドします。
- VCO2 Level:VCO2 の音量です。初期値は 0(オフ)です。
- Tune / Fine:VCO1 に対する VCO2 の音程です。Tune は ±24 半音(初期値 +7)、Fine は ±50 セントです。
- Wave:VCO2 の波形を、ノコギリ波か矩形波から選びます。
- Hard Sync:オンにすると、VCO1 が 1 周期を終えるたびに VCO2 の位相を頭に戻します(初期値オン)。VCO2 を VCO1 より高く調律すると、シンク特有の鋭い倍音が出ます。
- Sync Env:303 のメインエンベロープで、VCO2 の音程を最大 +36 半音持ち上げます。アクセントのステップほど強くかかり、ディケイに合わせて下がっていく「シンクスイープ」になります。
- VCO1 Level:303 本来のオシレーターの音量です。下げると VCO2 だけの音になります。
VCO2 は帯域制限した波形(PolyBLEP)で作り、Open303 内部の 4 倍オーバーサンプリングで動かしているので、シンクを強くかけても折り返しノイズを抑えています。VCO2 Level が 0 で VCO1 Level が 1 のときは、元の Open303 と 1 サンプルも違わない出力になります。
TB-3PO(ツール版)と違うところ
| TB-3PO | o303 | 理由 |
|---|---|---|
| 最下段 4・5 番目の PAD が MIDI チャンネル −/+ | OUT / IN(フレーズの音を外へ広げる / 内へまとめる) | 303 が内蔵なので MIDI チャンネルが無く、空いた PAD に割り当てた |
| スロット A / B を Track ボタンで切り替え | シーケンサーは 1 つ | 音源は 1 声。Track ボタンは Schwung のスロット切り替えに使われ、音源からは使えない |
| Step ボタンでページ移動 | ジョグのみ | Step ボタンを押すと Move のシーケンサーにも届いてしまう |
| Shift + X でクリア | X を 2 回 | Shift + Delete は Schwung のスナップショット復帰に使われ、音源には届かない |
| Back で一時停止 | Back で画面を閉じる | チェーンスロットの音源は、Move の再生中ずっと鳴る |
| 状態を 1 つのファイルに保存 | スロットの状態として保存 | セットごと・スロットごとに別々に持つため |
保存
今鳴っているパターン、8 つのバンク、シーケンサーの設定、すべての音色ノブは、スロットの状態として Schwung が自動で保存します。セットを開き直したり Move を再起動したりしても戻ります。新しいスロットに読み込んだときは、初期パターンから始まります。
仕組み
上流の 3 つのソースは vendor/ に無改変のまま置いてあり(vendor/SHA256SUMS でチェック)、外側の薄いラッパーでつないでいます。RAT のファイルの著作者名は「Hiro Ikezawa」と表記しています(コメントとメタデータのみで、コードは取り込んだときのままです)。
| ファイル | 包んでいるもの | 変えていること |
|---|---|---|
dsp/tb_engine.c | TB-3PO の tb3po.c | MIDI の送り先を、別スロットではなく内部の関数にする。チェーン音源の処理はすべてオーディオコールバック上で動くので、メモリ確保・スレッド・状態ファイルを使わない形にする |
dsp/voice303.cpp | Schwung 用 303 プラグインの plugin.cpp(Open303) | 自前のドライブ段を通す前の float 出力を受け取る。エンジンを下の Open303Sync に差し替える |
dsp/open303_sync.h | Open303(派生クラス) | 1 サンプル処理だけを差し替え、VCO2 とハードシンクを足す |
dsp/rat_stage.c | RAT ペダルの rat.c | ステレオのエフェクト用の外枠を外し、モノラル 1 段として動かす |
dsp/acid8.c | — | Length 8 のときの GEN が使う、8 ステップ専用のパターン生成 |
dsp/tr_plugin.c | — | 音源本体:パラメータ、状態の保存、信号経路 |
アクセントとスライドの渡し方:TB-3PO が隣のスロットの 303 に送るのと同じ MIDI を、内部の関数 1 つ(tr_plugin.c の seq_midi())で Open303 に渡しています。ベロシティ 118 がアクセント(Open303 は 100 以上をアクセントとして扱う)、72 が通常のノートです。スライドは前のノートを離す前に次のノートを送る形で、Open303 はこれをレガートとして滑らかにつなぎます。休符はノートオフです。
タイミング:ステップは Move の MIDI クロック(1 拍 24 パルスの 6 パルスごと)で進み、Play を押した最初のパルスでステップ 1 が鳴ります。クロックが来ない場合は内部タイマーで進みます。tests/test_engine.c で、単体の TB-3PO プラグインと内蔵のエンジンを並べて動かし、同じ MIDI が同じオーディオブロックで出ることを確かめています。
ビルドとテスト
scripts/test.sh # ネイティブビルド、全テスト、Move 用ビルドまで
scripts/build.sh arm64 # dist/o303-module.tar.gz を作る
scripts/install.py http://<Move の IP>:7700 # Schwung Manager 経由でインストール
scripts/vendor.sh # 上流のチェックアウトから vendor/ を取り直す
scripts/vendor.sh --verify # vendor/ が無改変かを確認(ビルド時に自動で実行)
- ビルドには aarch64 のクロスコンパイラ(
aarch64-linux-gnu-gcc/g++)が要ります。Schwung のプラグイン API ヘッダーはthird_party/schwung/に同梱しています(Schwung 1.7.3 のもの)。 - UI テストは Schwung のページエンジンと描画ハーネスを使うので、Schwung のチェックアウトが要ります(
SCHWUNG_ROOT、なければこのリポジトリの隣の../schwung)。見つからない場合は UI テストだけ飛ばします。TR_SHAREDに実機のshared/のコピーを指定すると、実機と同じページエンジンでも確かめられます。
| テスト | 確かめていること |
|---|---|
tests/test_engine.c | 内蔵シーケンサーが単体の TB-3PO と同じ MIDI を同じタイミングで出すこと(16 / 24 / 32 ステップの GEN と、8 ステップの MUT を含む)。OUT / IN が 1 音だけを、正しい向きに、スケールの隣の音へ動かすこと、Undo で戻ること、Octaves の範囲を出ないこと。8 ステップの GEN が新しい生成方法で書き込まれること、再生中の GEN で音が残らないこと、8 つのバンクへの保存・呼び出し・状態の保存。状態テキストが壊れていても落ちないこと(ASan / UBSan 付き) |
tests/test_acid8.c | 8 ステップの生成について、4 万通りの設定で約束をすべて守ること(ステップ 1 がルート、スケール外の音を使わない、休符へのスライドが無い、全部にアクセントやスライドが付かない等)。Density / Accent / Slide / Octaves がそれぞれ効くこと、5 つのスタイルの特徴が出ること |
tests/test_vco.cpp | VCO2 が初期値で元の Open303 と 1 サンプルも違わないこと、音量の較正、シンクで VCO1 の周期になること、Sync Env のスイープ、どの設定でも値が暴れないこと |
tests/smoke.py | 実際の dsp.so での再生・停止、テンポ追従、アクセント、スライド、RAT の位置、Volume、極端な設定、状態の保存と復元。8 ステップの GEN とバンク、v0.3.0 で保存した状態(tests/fixtures/state_v030.json)がそのまま読めること |
tests/test_plugin.c | 音源全体をランダムな操作で長時間動かし、メモリ違反や異常値が出ないこと(ASan / UBSan 付き) |
tests/test_ui.mjs | 画面・ノブ・PAD・ボタンの動作と、PAD の操作が TB-3PO 本物の ui.js と同じ結果になること |
制限と注意
- 外部からのノート入力は無視します。303 を鳴らすのは内蔵シーケンサーだけです。
- 再生中に読み込むと、次に来る 16 分音符から走り出します。次に Play を押すと頭がそろいます。
- 画面表示中に使っているボタン(+ − < > Undo X)自体の LED は点けていません。
- この音源の画面には Schwung の「My Presets」ページがありません。名前を付けたプリセットの保存や、別のスロットへのパターンの持ち出しはできません。
- 上流のコードについての注意(
vendor/は変更していません):- Open303 の
MipMappedWaveTable::initPrototypeTable()は、配列の後ろに 4 要素ぶん 0 を書きます。実害はありませんが、最適化で問題にならないよう-fno-aggressive-loop-optimizationsを付けてビルドしています。 - Open303 は生成時と、押さえているノートの一覧でメモリを確保します。
- Open303 の