[obsidian] vault backup: 2025-11-07 12:10:31[
All checks were successful
Build / build (push) Successful in 10m8s
All checks were successful
Build / build (push) Successful in 10m8s
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -42,13 +42,13 @@ Faust[@Orlarey2009]やMaxのGen、のように、サンプル単位レベルで
|
||||
|
||||
## mimium and lambda-mmm
|
||||
|
||||
mimiumは、Rustに近いシンタックスを持った関数型の音楽信号処理をターゲットにしたプログラミング言語である[@matsuura2021]。現在の内部実行モデルとして、値呼び単純型付きラムダ計算を拡張し、最小限の内部状態を持つプリミティブ操作:ディレイとフィードバックを加えたLambda-mmm[@matsuura_lambda-mmm_2024]という計算体系を持っている。
|
||||
mimiumは、Rustに近いシンタックスを持った関数型の音楽信号処理をターゲットドメインにしたプログラミング言語である[@matsuura2021]。現在の内部実行モデルとして、値呼び単純型付きラムダ計算を拡張し、最小限の内部状態を持つプリミティブ操作:ディレイとフィードバックを加えたLambda-mmm[@matsuura_lambda-mmm_2024]という計算体系を持っている。
|
||||
|
||||
mimiumはコードを専用のVMバイトコードへコンパイルし実行する。実行モデルは、一般的なレジスタマシンの命令セットに、内部状態操作用の操作が加わったものとなる。ディレイやフィードバックで用いられる内部状態は、状態ストレージという1次元の配列領域と単一の読み出し位置ポインタを組み合わせたデータ領域に保存される。
|
||||
|
||||
コンパイラは、状態ストレージの読み出し位置ポインタを相対的に前後させる命令を適切に出力することで、VM実行時にはストレージの一部分をディレイ用のリングバッファとして解釈しデータを読み書きする。
|
||||
|
||||
mimiumでは高階関数などを使うことによって任意の数のフィルタバンクのような、パラメトリックなプロセッサを生成することもできるが、こうしたプロセッサは状態ストレージのレイアウトとメモリサイズを決定できない。そのため、グローバルな関数の呼び出しとクロージャ(実行時に高階関数から生成される関数)の呼び出しは区別され、クロージャのインスタンスに個別の状態ストレージを生成し、クロージャ呼び出し時に使用する状態ストレージそのものを切り替えることで対応している。
|
||||
過去のmimiumでは高階関数などを使うことによって任意の数のフィルタバンクのような、パラメトリックなプロセッサを生成することもできたが、こうしたプロセッサは状態ストレージのレイアウトとメモリサイズを決定できなかった。そのため、グローバルな関数の呼び出しとクロージャ(実行時に高階関数から生成される関数)の呼び出しは区別され、クロージャのインスタンスに個別の状態ストレージを生成し、クロージャ呼び出し時に使用する状態ストレージそのものを切り替えることで対応していた。
|
||||
|
||||
今回提案するライブコーディング機能は、2つの機能によって実現される。
|
||||
|
||||
@@ -64,7 +64,6 @@ mimiumでは高階関数などを使うことによって任意の数のフィ
|
||||
|
||||
実用的な例では、Scala 3でのマクロや、関数型組版処理エンジンSaTysFi[@suwa2024]のように、言語内DSLを型安全にライブラリとして実装することを想定しているものがある。
|
||||
|
||||
オーディオ処理においては、こうした計算のステップ分けは、直感に照らし合わせれば、コンパイル時に実行される信号処理のルーティングを決めるメタ操作と、実際の信号を生成するときに実行される処理の2段階に分けることができる。
|
||||
|
||||
### シンタックス
|
||||
|
||||
@@ -120,7 +119,27 @@ fn osc(freq){
|
||||
```
|
||||
|
||||
|
||||
## 問題点
|
||||
## 議論
|
||||
|
||||
|
||||
### 他の言語とのコンパイル時計算のパラダイム比較
|
||||
|
||||
| | Faust | Kronos | mimium |
|
||||
| ---------------- | ------- | ------- | ------------------ |
|
||||
| パラメトリックな信号ルーティング | 項書換えマクロ | 型レベル計算 | ステージ0の計算/グローバル環境評価 |
|
||||
| 実際の信号処理 | BDA | 値レベルの評価 | ステージ1の計算 |
|
||||
|
||||
|
||||
多段階計算の不足している部分
|
||||
|
||||
マクロとしては、型安全な代わりに、型システムの範囲を超えたメタ操作ができない。型システムが充実しない限り、Kronosのようなタプルの要素数をパラメトリックに扱うようなことはできない。代わりに配列を操作する。これはこれで体系がシンプルでいいかも。
|
||||
|
||||
現状、ツリーウォーク型のインタプリタでステージ0を評価し、VMのバイトコードに変換してからステージ1を評価している。これは、リアルタイム実行パフォーマンスの維持しつつ多段階計算の体系を導入するための苦肉の策である。せっかくマクロと実際の計算を同じ意味論で実行できるのに、結局2つの処理系を実装している。
|
||||
|
||||
|
||||
|
||||
|
||||
### ライブ状態更新のエッジケース
|
||||
|
||||
差分処理を実行している間に内部状態が更新されてはいけない。なので、新しいソースコードのパースや内部状態構造導出、VMコード生成、木の比較までは非同期で行えるが、コピー中はオーディオ処理全てを一度中断しなくてはならない。
|
||||
|
||||
@@ -163,6 +182,8 @@ fn dsp(){//dspはFncall[Fncall[FnCall[Feed]],Fncall[Feed]]で変化なし
|
||||
上のサンプルでは、はじめlfoを使って周波数をモジュレーションしている状態から、周波数は固定にして音量をモジュレーションする処理へと切り替えた例である。myfreq()とmyamp()はそれぞれどちらもosc関数を1度だけ呼び出すため、dsp関数の内部状態ツリーの構成は共通しており、再コンパイル時にデータが引き継がれる。
|
||||
この時、myampにはmyfreqの最後の位相が引き継がれることになるが、今回実装しているphasor1はselfに保存される値が0~samplerate/freq、例えば1000Hzなら0~48の値のレンジを取り、これがmyampの中で使われているphasor2のselfのその値の本来のレンジは0~1であるべきにも関わらず引き継がれてしまう。
|
||||
|
||||
ただ、結局phasor2を実行したときには0~1のレンジに丸まるので大きな問題にはならない。ある関数がある範囲に収まることが保証されているということは、仮にそこで使われているselfに不正な値が差し込まれたとしても、その関数が計算し終わったときには元の範囲に収まる可能性が高いからだ。
|
||||
|
||||
|
||||
|
||||
ツリー構築の際に、FnCallはヒントとして関数のラベルを受け取るような変更が考えられる。無名関数はヒントなしで頑張る。
|
||||
|
||||
Reference in New Issue
Block a user