[obsidian] vault backup: 2025-07-01 23:06:05[
All checks were successful
Build / build (push) Successful in 11m37s
All checks were successful
Build / build (push) Successful in 11m37s
This commit is contained in:
@ -21,6 +21,7 @@ https://github.com/mimium-org/mimium-rs
|
|||||||
### 理論
|
### 理論
|
||||||
|
|
||||||
- [[mimiumの部分的DSP更新とFaustのondemand]]
|
- [[mimiumの部分的DSP更新とFaustのondemand]]
|
||||||
|
- [[mimiumでのIOパラメーター]]
|
||||||
|
|
||||||
### 中間表現について
|
### 中間表現について
|
||||||
|
|
||||||
|
128
content/mimiumでのIOパラメーター.md
Normal file
128
content/mimiumでのIOパラメーター.md
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
---
|
||||||
|
date: 2025-07-01 18:43
|
||||||
|
---
|
||||||
|
#mimium
|
||||||
|
|
||||||
|
マルチスレッド前提の場合、Shared State全般がRwLockとかで包まれることになってしまう
|
||||||
|
|
||||||
|
しかし、大概の場合グローバルな状態共有はAtomicな単一パラメーターで済む
|
||||||
|
|
||||||
|
あくまで、普通のグローバル変数宣言はスレッドローカルな扱いにして、メインスレッドと協調しないといけない場合は"shared"みたいなキーワードをつけるようにするとか(構文増やしたくないけど)
|
||||||
|
|
||||||
|
だし、これだと結局OSC送るサーバークライアント構成と実質的に変わらないかも
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let hoge = 100;
|
||||||
|
```
|
||||||
|
|
||||||
|
みたいなのの代わりに、別のキーワードを持たせる
|
||||||
|
|
||||||
|
```rust
|
||||||
|
global hoge = 100
|
||||||
|
```
|
||||||
|
|
||||||
|
プリミティブな型であれば、Atomicな書き換えでOK。hogeへの書き込みをオーディオコンテキストの中でやると毎サンプル実行される保証がない、みたいな仕様?
|
||||||
|
|
||||||
|
タプルとか合成型だと、マルチスレッドで書き換えたときに片方のパラメーターが更新されてない時に読み取られる可能性が厳密にはある
|
||||||
|
|
||||||
|
グローバルに宣言された配列型とか、合成型をどうやって扱う?
|
||||||
|
|
||||||
|
単に、グローバルな値への書き込みがいつ行われるか保証はされませんよ、という仕様にするならそれでも十分か
|
||||||
|
|
||||||
|
もしくは、
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let hoge = param(100)
|
||||||
|
```
|
||||||
|
|
||||||
|
みたいなラップの仕方を考える。hogeは`Param<Number>`型をもち、Number型に自動キャストできる。
|
||||||
|
|
||||||
|
パラメトリックフィルタ複製で、個々の周波数を外側からコントロールしたいとするとどうなるか
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn replicate(n,gen){
|
||||||
|
let g = gen(n, n*100)
|
||||||
|
if (n>0.0){
|
||||||
|
let c = replicate(n - 1.0,gen)
|
||||||
|
| | g() + c()
|
||||||
|
}else{
|
||||||
|
| | g()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn mygen(freq){
|
||||||
|
osc(freq)
|
||||||
|
}
|
||||||
|
fn gen(n,init_f){
|
||||||
|
let channel = param("freq_%n",init_f);
|
||||||
|
| | mygen(channel)
|
||||||
|
}
|
||||||
|
let myfilter = replicate(5,gen)
|
||||||
|
fn dsp(){
|
||||||
|
myfilter()
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
まあこうなるか 自動グループ化みたいなのできるか?実行してる関数の深さ的に`global::replicate::gen::(args)`で自動ネーミング自体は不可能ではなさそうだが/自動グループをやりたければ、`Param<T>`の中身をレコード型にすればいいのか
|
||||||
|
|
||||||
|
paramがジェネリックな関数`T->Param<T>`であることが重要になってくる。範囲の制限とかはRanged型みたいなのをmimium側で定義すればよくなる・・・はずまあIO周りは結局命令型になるのかなあ
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let channel = param("freq_%n",init_f);
|
||||||
|
set_param("freq_%n",1000.0)
|
||||||
|
channel = 1000;//
|
||||||
|
```
|
||||||
|
|
||||||
|
最後の行のように、普通にAssign書き込むのもできるようにしておきたい。これできるようにするには、Assignをオーバーロードできるような型システムが必要なのかな`param(コンストラクタ)`と`get_param_name`、`get_param`、`set_param`の4種類があれば十分か
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[mimiumのレコード型]]のデフォルト実装、関数のデフォルト引数の組み合わせに対して自動でパラメーターが作られるようにしたい
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn gen_synthesizer(){
|
||||||
|
let s = |gate = 0,freq=1000,gain = 1.0|{
|
||||||
|
...
|
||||||
|
}
|
||||||
|
s({..})
|
||||||
|
}
|
||||||
|
let mysynth = gen_synthesizer();
|
||||||
|
|
||||||
|
fn dsp(){
|
||||||
|
mysynth()
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
これを実行すると、隠れレコード構造体定義とグローバルなデフォルト引数が作られる
|
||||||
|
|
||||||
|
```rust
|
||||||
|
...
|
||||||
|
type defaultarg = {
|
||||||
|
"gate":number = 0,
|
||||||
|
"freq":number = 1000,
|
||||||
|
"gain":number = 1.0
|
||||||
|
}
|
||||||
|
let default_arg_for_mysynth = param("mysynth",defaultarg::default());
|
||||||
|
fn dsp(){
|
||||||
|
mysynth()
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
dsp内で`mysynth({..})`と実行してしまうと、これがグローバルなコンテキストで作られない可能性がある・・のか?いや、でも基本的に書き換えられる心配はないからいいのかな
|
||||||
|
|
||||||
|
デフォルト引数構造体のインスタンスは必ずグローバル評価で行う、だとパラメトリックな生成はできないし問題起きそう
|
||||||
|
|
||||||
|
```rust
|
||||||
|
//自動キャストとジェネリクスの組み合わせさえうまくいけばこのくらいのことはできそう
|
||||||
|
let p = param({..});
|
||||||
|
fn dsp(){
|
||||||
|
p |>
|
||||||
|
|gate = 0,freq = 1000,gain = 1.0|{
|
||||||
|
...//do something
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
ということは、とりあえず雑にParamを実装して
|
@ -60,128 +60,4 @@ fn repl_001(){
|
|||||||
|
|
||||||
シングルスレッドの場合、REPLで実行されたものは必ずオーディオドライバのブロック頭で消化
|
シングルスレッドの場合、REPLで実行されたものは必ずオーディオドライバのブロック頭で消化
|
||||||
|
|
||||||
マルチスレッド前提の場合、Shared State全般がRwLockとかで包まれることになってしまう
|
[[mimiumでのIOパラメーター]]
|
||||||
|
|
||||||
しかし、大概の場合グローバルな状態共有はAtomicな単一パラメーターで済む
|
|
||||||
|
|
||||||
あくまで、普通のグローバル変数宣言はスレッドローカルな扱いにして、メインスレッドと協調しないといけない場合は"shared"みたいなキーワードをつけるようにするとか(構文増やしたくないけど)
|
|
||||||
|
|
||||||
だし、これだと結局OSC送るサーバークライアント構成と実質的に変わらないかも
|
|
||||||
|
|
||||||
```rust
|
|
||||||
let hoge = 100;
|
|
||||||
```
|
|
||||||
|
|
||||||
みたいなのの代わりに、別のキーワードを持たせる
|
|
||||||
|
|
||||||
```rust
|
|
||||||
global hoge = 100
|
|
||||||
```
|
|
||||||
|
|
||||||
プリミティブな型であれば、Atomicな書き換えでOK。hogeへの書き込みをオーディオコンテキストの中でやると毎サンプル実行される保証がない、みたいな仕様?
|
|
||||||
|
|
||||||
タプルとか合成型だと、マルチスレッドで書き換えたときに片方のパラメーターが更新されてない時に読み取られる可能性が厳密にはある
|
|
||||||
|
|
||||||
グローバルに宣言された配列型とか、合成型をどうやって扱う?
|
|
||||||
|
|
||||||
単に、グローバルな値への書き込みがいつ行われるか保証はされませんよ、という仕様にするならそれでも十分か
|
|
||||||
|
|
||||||
もしくは、
|
|
||||||
|
|
||||||
```rust
|
|
||||||
let hoge = param(100)
|
|
||||||
```
|
|
||||||
|
|
||||||
みたいなラップの仕方を考える。hogeは`Param<Number>`型をもち、Number型に自動キャストできる。
|
|
||||||
|
|
||||||
パラメトリックフィルタ複製で、個々の周波数を外側からコントロールしたいとするとどうなるか
|
|
||||||
|
|
||||||
```rust
|
|
||||||
fn replicate(n,gen){
|
|
||||||
let g = gen(n, n*100)
|
|
||||||
if (n>0.0){
|
|
||||||
let c = replicate(n - 1.0,gen)
|
|
||||||
| | g() + c()
|
|
||||||
}else{
|
|
||||||
| | g()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn mygen(freq){
|
|
||||||
osc(freq)
|
|
||||||
}
|
|
||||||
fn gen(n,init_f){
|
|
||||||
let channel = param("freq_%n",init_f);
|
|
||||||
| | mygen(channel)
|
|
||||||
}
|
|
||||||
let myfilter = replicate(5,gen)
|
|
||||||
fn dsp(){
|
|
||||||
myfilter()
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
まあこうなるか 自動グループ化みたいなのできるか?実行してる関数の深さ的に`global::replicate::gen::(args)`で自動ネーミング自体は不可能ではなさそうだが/自動グループをやりたければ、`Param<T>`の中身をレコード型にすればいいのか
|
|
||||||
|
|
||||||
paramがジェネリックな関数`T->Param<T>`であることが重要になってくる。範囲の制限とかはRanged型みたいなのをmimium側で定義すればよくなる・・・はずまあIO周りは結局命令型になるのかなあ
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
```rust
|
|
||||||
let channel = param("freq_%n",init_f);
|
|
||||||
set_param("freq_%n",1000.0)
|
|
||||||
channel = 1000;//
|
|
||||||
```
|
|
||||||
|
|
||||||
最後の行のように、普通にAssign書き込むのもできるようにしておきたい。これできるようにするには、Assignをオーバーロードできるような型システムが必要なのかな`param(コンストラクタ)`と`get_param_name`、`get_param`、`set_param`の4種類があれば十分か
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[[mimiumのレコード型]]のデフォルト実装、関数のデフォルト引数の組み合わせに対して自動でパラメーターが作られるようにしたい
|
|
||||||
|
|
||||||
```rust
|
|
||||||
fn gen_synthesizer(){
|
|
||||||
let s = |gate = 0,freq=1000,gain = 1.0|{
|
|
||||||
...
|
|
||||||
}
|
|
||||||
s({..})
|
|
||||||
}
|
|
||||||
let mysynth = gen_synthesizer();
|
|
||||||
|
|
||||||
fn dsp(){
|
|
||||||
mysynth()
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
これを実行すると、隠れレコード構造体定義とグローバルなデフォルト引数が作られる
|
|
||||||
|
|
||||||
```rust
|
|
||||||
...
|
|
||||||
type defaultarg = {
|
|
||||||
"gate":number = 0,
|
|
||||||
"freq":number = 1000,
|
|
||||||
"gain":number = 1.0
|
|
||||||
}
|
|
||||||
let default_arg_for_mysynth = param("mysynth",defaultarg::default());
|
|
||||||
fn dsp(){
|
|
||||||
mysynth()
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
dsp内で`mysynth({..})`と実行してしまうと、これがグローバルなコンテキストで作られない可能性がある・・のか?いや、でも基本的に書き換えられる心配はないからいいのかな
|
|
||||||
|
|
||||||
デフォルト引数構造体のインスタンスは必ずグローバル評価で行う、だとパラメトリックな生成はできないし問題起きそう
|
|
||||||
|
|
||||||
```rust
|
|
||||||
//自動キャストとジェネリクスの組み合わせさえうまくいけばこのくらいのことはできそう
|
|
||||||
let p = param({..});
|
|
||||||
fn dsp(){
|
|
||||||
p |>
|
|
||||||
|gate = 0,freq = 1000,gain = 1.0|{
|
|
||||||
...//do something
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ということは、とりあえず雑にParamを実装して
|
|
Reference in New Issue
Block a user