[obsidian] vault backup: 2025-10-13 11:47:55[
This commit is contained in:
2
content/.smart-env/multi/FRP_md.ajson
Normal file
2
content/.smart-env/multi/FRP_md.ajson
Normal file
@@ -0,0 +1,2 @@
|
||||
|
||||
"smart_sources:FRP.md": {"path":"FRP.md","last_embed":{"hash":null},"embeddings":{},"last_read":{"hash":"b65ixq","at":1760321114661},"class_name":"SmartSource","last_import":{"mtime":1760321084909,"size":76,"at":1760321114661,"hash":"b65ixq"},"blocks":{"#---frontmatter---":[1,3],"#alias":[4,7],"#alias#{1}":[6,7]},"outlinks":[{"title":"Functional Reactive Programming","target":"Functional Reactive Programming","line":6}],"metadata":{"date":"2025-10-13 11:04","tags":["#alias"]},"task_lines":[]},
|
2
content/.smart-env/multi/ReactiveBalsa_md.ajson
Normal file
2
content/.smart-env/multi/ReactiveBalsa_md.ajson
Normal file
@@ -0,0 +1,2 @@
|
||||
|
||||
"smart_sources:ReactiveBalsa.md": {"path":"ReactiveBalsa.md","last_embed":{"hash":null},"embeddings":{},"last_read":{"hash":"kbik8l","at":1760321293370},"class_name":"SmartSource","last_import":{"mtime":1760321275315,"size":165,"at":1760321293371,"hash":"kbik8l"},"blocks":{"#---frontmatter---":[1,3],"#":[5,8]},"outlinks":[{"title":"FRP","target":"FRP","line":5},{"title":"Haskell","target":"Haskell","line":5},{"title":"MIDI","target":"MIDI","line":5},{"title":"Reactive-balsa - HaskellWiki","target":"https://wiki.haskell.org/Reactive-balsa","line":7}],"metadata":{"date":"2025-10-13 11:07"},"task_lines":[]},
|
3
content/.smart-env/multi/midiguchi_md.ajson
Normal file
3
content/.smart-env/multi/midiguchi_md.ajson
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
6
content/FRP.md
Normal file
6
content/FRP.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
date: 2025-10-13 11:04
|
||||
---
|
||||
#alias
|
||||
|
||||
[[Functional Reactive Programming]]
|
7
content/ReactiveBalsa.md
Normal file
7
content/ReactiveBalsa.md
Normal 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
11
content/midiguchi.md
Normal 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)
|
||||
|
||||
|
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
```
|
||||
|
||||
|
Reference in New Issue
Block a user