quartz-research-note/content/mimiumでMIDIインプットを実装.md
2024-11-04 17:04:35 +09:00

119 lines
2.9 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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: 2024-10-30 15:42
---
#mimium
## 要件
どこまでMIDIインプットをmimiumの世界の外側として捉えるか
### 先行例
[[SuperCollider]]や[[ChucK]]はコールバックを登録するようなイメージ
[Using MIDI | SuperCollider 3.12.2 Help](https://doc.sccode.org/Guides/UsingMIDI.html
```smalltalk
s.boot;
(
var notes, on, off;
MIDIClient.init;
MIDIIn.connectAll;
notes = Array.newClear(128); // array has one slot per possible MIDI note
on = MIDIFunc.noteOn({ |veloc, num, chan, src|
notes[num] = Synth(\default, [\freq, num.midicps,
\amp, veloc * 0.00315]);
});
off = MIDIFunc.noteOff({ |veloc, num, chan, src|
notes[num].release;
});
q = { on.free; off.free; };
)
// when done:
q.value;
```
まあこれはDSPアウトプットの合成が.playで暗黙的に行える加算で合成されるという想定だからできることかな、、、
ChuckもボイスごとにShredを生やす方向で対応してるからちょっと微妙だ
[Chuck - Input & Output](https://chuck.stanford.edu/doc/reference/io.html#MidiIn)
---
現実的には、[[Faust]]のように、ボイスアロケーターは外側で実装してしまい、非同期に更新されうるAtomicな値のセルをートやccのデータとして受け取れるようにすれば当面は十分
が、最終的にはMIDIエフェクトMIDI信号自体のディレイやクォンタイズ、スロットリングとかを[[FUnctional Reactive Programming|FRP]]っぽく書けると嬉しい
---
Noteのバインドの記法
```rust
let cell:()->float = bind_midi_note_mono(channel)
let (note,vel) = cell(); //値の取り出し
```
```rust
//rust
fn bind_midi_note_mono(&mut self ,vm:&mut Machine)->ReturnCode{
let ch = Machine::get_as::<f64>(vm.get_stack(0));
let cell = Arc::new((AtomicF64::new(),AtomicF64::new() ));
self.add_midi_listener(ch,|note,vel|{
let (note_c,vel_c) = cell.clone();
note_c.write(note);
vel_c.write(vel);
});
let cls = |vm:&mut Machine|->ReturnCode{
let (note_c,vel_c) = cell.clone();
vm.set_stack(0,Machine::to_value(note_c));
vm.set_stack(1,Machine::to_value(vel_c));
2
}
vm::set_stack(0, wrap_rust_closure(cls))
1
}
```
あとは頑張って`add_midi_listener`相当の何かを作ろうって感じだな(関数型っぽくはないけども)
---
IOの順序保証とか考える
正格評価だとIOモナドとかはそもそも考える必要がない
[Algebraic Effects入門](https://v2.aintek.xyz/posts/introduction-to-algebraic-effects)
> `type 'a io = unit -> 'a`
> 純粋な値は以下のようなIOモナドにリフトできる。
> `let return x = fun () -> x`
> 計算はバインド演算子によってつなげることができる。
> `let (>>=) c1 c2 = fun () -> c2 (c1 ())`
mimiumだとバインド演算子ってこうか(ジェネリクスが必要だけども)
```rust
fn bind(f1,f2){
| | f1() |> f2
}
```