[obsidian] vault backup: 2025-10-13 11:47:55[

This commit is contained in:
2025-10-13 11:47:55 +09:00
parent 5f5201862a
commit 5d6ec74e47
4 changed files with 42 additions and 69 deletions

6
content/FRP.md Normal file
View File

@@ -0,0 +1,6 @@
---
date: 2025-10-13 11:04
---
#alias
[[Functional Reactive Programming]]

7
content/ReactiveBalsa.md Normal file
View File

@@ -0,0 +1,7 @@
---
date: 2025-10-13 11:07
---
[[Haskell]]の[[MIDI]]を[[FRP]]風に扱うライブラリ
[Reactive-balsa - HaskellWiki](https://wiki.haskell.org/Reactive-balsa)

11
content/midiguchi.md Normal file
View File

@@ -0,0 +1,11 @@
---
date: 2025-10-13 11:04
---
#programming
[[MIDI]]を[[FRP]]っぽくバインドするための[[JavaScript]]ライブラリ(古い)
[GitHub - midiguchi/midiguchi: midiguchi - MIDI I/O using Functional Reactive Programming with Bacon.js. Transpose, remap, filter, manipulate arbitrarily, or synthesize MIDI events with ease.](https://github.com/midiguchi/midiguchi)

View File

@@ -118,92 +118,41 @@ fn bind(f1,f2){
### FRPっぽい感じで考えてみる
MIDIのバイトストリームをフィルターして、ートオンオフのストリームを作る
課題4ポリのMIDIボイスアロケーターを考える
最終的にはそれをHoldしてセルにして、セルをsampleして値にすれば良い
アロケーターを実行すると4つのCell(Behavior)が返ってくる
いや、ストリームを返すべき?
なんかJSには[[midiguchi]]というライブラリがあるらしい
```rust
fn alloc_midi_voice_4(channel)->[Stream<Note>;4]
```
状態のフィードバックはSodiumでは次の2つを持って実行できる
- hold: 任意のStreamが発火した時に最後の値をキープしたCellを作る
- snapshot:任意のStreamが発火したとき、Cellをサンプリングして別のStreamとして発火する
状態の保持として必要なのは、`Busymap([Option<Key>;4])`みたいなやつ。
[[Haskell]]には[[Reactive-Banana]]使った[[ReactiveBalsa]]もある
```rust
fn bind_midi_event()->Stream<Byte>
fn bind_note_event()->Stream<(Channel,Note)>{
bind_midi_event
|> filter(|byte| byte |> is_note_event )
|> map(|byte| (byte[0],Note(byte[1],byte[2]) ) )
}
fn overwrite_arr(idx,v){
|arr| {
let mut narr = arr;
narr[idx] = v
narr
}
}
fn get_4_voice(note){
let (last_stream,last_busymap) = self;
if last_busymap |> is_busy{
(last_stream,last_busymap)
}else{
match note{
Note::On(pitch,vel)=>{
let voice_idx = last_busymap|>find_available_voice;
let new_busymap = last_busymap |> overwritearr(voice_idx,pitch);
let new_str = last_stream |> overwritearr(idx,(pitch,vel))
}
Note::Off=>{
}
}
}
fn voice_mono(notes:Stream<Note>){
let cell = notes |> hold({pitch:60,velocity:0})
}
fn alloc_midi_voice_4(channel){
let busymap = Cell<_>([None,None,None,None]);
bind_note_event
|> filter(|(c,_note)| c==channel)
|> merge(busymap |> snapshot, |(note,busycell)| {
busycell.hold
} )
let midiinput = midi_open_port("from Max 1");
let notes = midiinput |> filter_map(_,is_byte_note)
let notes_cell = notes |> voice_mono //ここまでが今のbind_midi_note_monoに相当
fn dsp(){
let {pitch,velocity} = notes_cell |> sample
pitch |> midi2freq |> osc |> _ * velocty/127
}
```
[[Computation Expression]]使ってIOの値を`let!`でバインドしていく、とかの方がわかりやすいかも?
[[Computation Expression]]使ってIOの値を`let!`でバインドしていく、とかの方がわかりやすいかも
---
シンプルに、MIDIにコールバックを渡せるだけなら、どうやって作る
## MIDIディレイとかどうすんの
```rust
fn __midi_note_callback(cb:{pitch:float,vel:float}->void ){
}
fn poly_midi_allocator()->()->[{pitch:float,vel:float}]{
let channels = array_new({pitch=0,vel=0},4)
let busymap = [0,0,0,0]
__midi_note_callback(|pitch,vel| {
})
channels//セルをupvalueとして返す
fn delay<T>(stream:Stream<T>,time:float){
stream@(now+float)
}
```