Files
quartz-research-note/content/mimiumでのライブコーディングエンジン.md

98 lines
3.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
date: 2025-06-27 16:54
---
#mimium #livecoding
mimiumでも[[ライブコーディング]]がやりたいよね
一般化するとこういうモデルにならんだろうか
![[img/general-livecoding-model.png]]
Tracksの部分の抜き差しだけできるのが[[ChucK]]のShredシステム。
とりあえずはこれをRust実装してもいいけど、最終的にはこのモデル自体をmimium上で実装することもできそう
不要なトラックの削除と空きスロット再利用を実現するためには、普通の配列とは別に単方向リストかSlotmap的なものを作る必要がありそう
Reducerは基本的には全てのチャンネルの加算だけでいいので滅多にいじる必要ないけど、いじりたいケースが出てくるかも
ChucKではエフェクトのテールが更新時にぶちぎれる問題があったので、それを防ぐためのPostFX Chain
各トラックごとのエフェクトのライブ切り替えとかも実現しようと思えばできるかな
...これ、結局[[SuperCollider]]のJITLibと同じことかもな
[jitlib\_basic\_concepts\_01 \| SuperCollider 3.14.0-dev Help](https://doc.sccode.org/Tutorials/JITLib/jitlib_basic_concepts_01.html)
## 信号処理の状態持ち越し
[[Incremental Functional Reactive Programming]]の仕組みを用いることはできるだろうか
```rust
//これが
fn dsp(){
delay(100,100,input)+ delay(200,200,input)
}
//こう更新されるとする
fn dsp(){
delay(300,300,input) + delay(100,100,input)+ delay(200,200,input)
}
```
`delay(100)`にはID(delay_1)が、`delay(200)`にはID(delay_2)がそれぞれつけられる
どう増分検出してID割り振るかの仕組みは置いといて、再コンパイル時に100と200はそのまま、新しく増えたdelay(300)にID`(delay_3)`を挿入する
そうすると、StateStackのためのメモリは完全にリニアにはしないほうが良くて、ツリー状のデータ構造に戻した方が良さそう
[[Red Green Syntax Tree]]のGreen Node→状態メモリのマップだと考えるとわかりやすいのか
```
dsp
| \
delay(1) delay(2)
```
から
```
dsp
/ | \
delay(3)delay(1) delay(2)
```
に更新される
```rust
//PartialEqで中身ではなくサイズを比較するようにする
struct MemoryChunk(Vec<u64>>);
enum StateNode{
Tree(StateTree),
Delay(MemoryChunk),
FeedBack(MemoryChunk),
External(MemoryChunk)
}
struct StateTree{
children: Slotmap<Box<StateNode>>
}
```
途中でchildrenの一部が削除される可能性があって、かつiterateも行うのでSlotmapで良さそう
Delay、feedback、Externalを区別する意味はあるのか→たまたまサイズが同じなDelayとExternalとかはあり得るので区別必要
クロージャの呼び出しの時は→コンパイル時ではなく、Closure命令でクロージャが作られる際にアロケートとIDの振り分けが起きる これは諦めて良さそう(適切にやりたければ[[多段階計算]]でコンパイル時に頑張れ)
あとはIDの振り方問題。dspから順番にnon-closure-callをトレースするのは同じとして
```rust
fn update_state_tree(oldtree:StateTree,newtree)->StateTree{
let state_changed = oldtree.children.iter().zip(newtree.children.iter()).all(|oldc,newc|newc == oldc)
}
```