Files
quartz-research-note/content/mimiumでのライブコーディングエンジン.md
松浦 知也 Matsuura Tomoya f08ff8368c
All checks were successful
Build / build (push) Successful in 12m37s
[obsidian] vault backup: 2025-09-23 01:39:19[
2025-09-23 01:39:19 +09:00

3.6 KiB
Raw Blame History

date
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

信号処理の状態持ち越し

Incremental Functional Reactive Programmingの仕組みを用いることはできるだろうか

//これが
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)

に更新される


struct MemoryChunk(Vec<u64>>);

enum StateNode{
   FnCall(Symbol,StateTree),//非クロージャ関数呼び出し
   Delay(MemoryChunk),
   FeedBack(MemoryChunk),
}
struct StateTree{
  children: SlotMap<Box<StateNode>>
}

関数呼び出しは非クロージャなのでシンボル名は確定できる

途中でchildrenの一部が削除される可能性がある(1,2,3,4の中から2だけが削除されるケースとか)

このchildren同士の構造比較はどうするべきかDelay、Feedbackは

かつiterateも行うのでSlotmapで良さそう Delay、feedback、Externalを区別する意味はあるのか→たまたまサイズが同じなDelayとExternalとかはあり得るので区別必要

クロージャの呼び出しの時は→コンパイル時ではなく、Closure命令でクロージャが作られる際にアロケートとIDの振り分けが起きる これは諦めて良さそう(適切にやりたければ多段階計算でコンパイル時に頑張れ)

あとはIDの振り方問題。dspから順番にnon-closure-callをトレースするのは同じとして

fn update_state_tree(oldtree:StateTree,newtree)->StateTree{
 let state_changed = oldtree.children.iter().zip(newtree.children.iter()).all(|oldc,newc|newc == oldc)
 
}