2025-01-12
昨日もらった野菜の土を落としたりトリミングしてラップやポリ袋に小分けにして野菜室にしまうなどをした
晩ご飯は白菜、春菊、にんじん、あとスーパーで買い足した玉ねぎとか昨日の白菜スープに良い感じに追い煮込みをしてラーメンをいれて野菜煮込みラーメンにした。
https://www.youtube.com/watch?v=bQ7RIHONhnw
シーケンサの実装を整えてた。
プログラム全体の構造としてはmain.rbとsequencer.rbがいる。main.rbは今のところオシレーター(波形を生成する係)とLPFやHPFなどのフィルターをかける係を担っている。sequencer.rbはその名の通りシーケンサーの役割を持っている
ファイルが分かれているということはこの二つは独立したRubyのプロセスで動いていて、その間の通信はどのようにしているかというろdrbを使っている
オシレーターが欲しいのは「16ステップあるうちのどこのタイミングで音を鳴らすのか」という情報が欲しいので、Sequencerというクラスにstepsというattributesを生やしておいてそのままRubyのオブジェクトをオシレーター側が持ってくればよい、という発想になっている。今のところsequencer.rbがDrbのサーバーでmain.rbがクライアント、という構造
もともとはThreadを使えばいいんだろう、とか思っていたんだけど、想像以上にThreadのが難しくて、stepのデータのやりとりの仕方に難儀してた。システムプログラミングむずかしい...。Webアプリケーションは流れが追いやすくて簡単...。
んで、プロセスを分けてやるとして、jsonとかでファイルに書き出してやる...?とか思ってたけど、drbの存在をふと思い出して実装してみたら簡単にできた。
あと、drbって DRbObject.new_with_uri(SERVER_URI) したタイミングでつくったインスタンスの状態しかもってないと思っていて、sequencer.rb側でstepが更新されるたびに都度main.rb側で更新(new_with_uri)しなきゃならないと思っていたけど、そんなことはなかった。
まさにドキュメントに書いてある通りだった
リモートプロセスにあるオブジェクトはローカルには DRb::DRbObject のインスタンスとして表現されます。このオブジェクトはリモートオブジェクトの proxy のように振舞います。つまり、このオブジェクトのメソッドを呼び出すとリモートオブジェクトに転送されます。
もう少し整理が必要で今の考えを整理しておく
main.rbは分解する
今になっている役割は以下
オシレーター
フィルター
アンプ(プレイヤー)
実際にはportaudioを使ってデバイスの音声出力にオシレーターからフィルターを通した波形を再生させているだけ
ざっくり以下のファイル
oscillator.rb
modules/{lpf,hpf}.rb
などmodules/に色々生やしていく。呼び出し方は以下みたいなインターフェースにするとよさそうかな
code:ruby
oscillator = Oscillator.new
oscillator
.then { LPF.new(it).call }
.then { HPF.new(it).call }
.then { Envelope.new(it).call }
oscillatorは再生の機構は持たないのがよい、と思ってるので上記の用に各種モジュールを追加できるだけにするといいかもしれない
oscillator.rbもdrbサーバーとして立ち上げておく
sequencer.rb
今ある実装をそのまま流用
drbサーバーとして立ち上げる
vca.rb(名称は考える)
プレイヤーとかアンプに相当する実装
drbのクライアントとして、oscillatorとsequencerのインスタンスを取得して再生をする
分解したとしてMIDIデバイスの扱いはどのようにするかはちょっと考える必要がある
プロセスをまたいでMIDIのストリームは複数開ける...?
複数のプロセスからリッスンできるならmodules系のフィルターのノブをアサインして設定できるようにする
vca.rbは再生と停止ができるようにする
とかいいつつ今の実装を公開した。
コードの整理は必要なんだけど、まずはプロポーザルをしたためることにしよう。プロポーザルを書いていく内にまたやることが思い浮かびそう