July 2009 Archives

整理整頓

| No Comments | No TrackBacks

iXMFに手を出し始めたら、収拾がつかなくなってきた気がするので、この辺でやりたいことをいろいろ整理してみようと思う。

  • portmidiバインディング, MIDIプレイヤー, SMFライブラリ: この辺は期待通り実装することが出来た。ビジュアルプレイヤーに手を出したことで、仮想MIDIマシンを使った状態管理もできるようになった。基本的には、これらは終了したプロジェクトと思っている。ただ、どうリリースするかは未定。
  • mldsp: 機能的には、多少のTODOが残っているものの、大体やりたいことは実現できた。これで完成品としてリリースするわけにはいかないが、アルファ版的なリリースはできる。
  • MIDIコンパイラ: まだサンプルMMLを書いていないし、SysExや曲タイトルその他の細々としたディレクティブも実装しなければならない。サンプルを書き上げたらそれでアルファ版として公開するくらいはできると思う。今sequerとなっている名前は多分githubにインポートする時にmugeneになる。
  • processing: もともと、Javaの実行環境に相当するものを作ろうと思って始めたはずだったのだけど、スクリプトをそのままアプリケーションにするコンバータとして、画面設計の補助になる以上のものには今のところできていない。そして入力を全然処理するようになっていないので、gainerをいじって遊ぶ実行環境として使えないのが今のところの問題だ。ただprocessingにはもうあまり興味が無かったりもする...むしろこっちに深入りするなら、VPLに近いものを実装してみようと思う。この方面で関心があるのはMAX/MSPだ。その関係でRDSのVPLなんかには割と興味があるのだけど(もう少し色気が無いところで言えばWFのxomlとか)、それより先にMMLコンパイラその他を終わらせるべきかなと思って、深入りできていないのが現状だ。
  • iXMF engine: どこまで実装してみるか、実のところまだあまり考えていない。エンジンを実装するだけでは、動作検証ができないので、実データが必要になるのだけど、その実データが存在していないので、iXMFデータのオーサリング環境から作らなければならないのではないかと思っている。そして、そう考えると案外C#のexpression treeからiXMFのexpressionを生成したりできるのではないか(Linq to iXMF?)、と、いろいろ夢らしいものが広がる。実行環境はCLRでportmidiバインディングを巻き込んでもいいし、Moonlight環境ではOgg Vorbisなどのcustom media streamを巻き込むことも出来る。
  • mldsp input addin: まだ構想しか無い。任意の入力メッセージを受け付ける。コレ自体についての構想はこの前書いたばかりなのでここでは繰り返さない。
  • 液晶スペアナモニタ: これはgainerをいじって作ってみたいおもちゃ。液晶モニタをgainerでいじろうというのはやや無理がある気もするが...グラフィック表示用のモニタはあるが、まだ繋げられていない。
  • カスタムMIDIコントローラ: これも電子工作でやってみたいおもちゃ。実はMIDIよりむしろFMシンセサイザのパラメータ調整に使いたい(がそうするとドライバをいじるコードから書かないといけないのでこれは未来形で不確定)。ツマミはジャンクコントローラを買ってきてあってストックがあるのだけど、まだ分解すらしていない状態。先にMMLコンパイラを終わらせてからだろうとは思っている。あと、カスタムコントローラを制作したら、それをMIDIドライバに送信するコードも必要だけど、何かしら便利な共通モジュールを設計すべきかどうかはまだ分からない。
  • 気が向いたらタッチパネルを使ってDexterみたいなものを作ってみたい。まだタッチパネルが安くても10000円くらいするので、しばらく先でもいいかなと思うけど。Dexterを見るとつい買ってしまいたくなるので気を引き締めないと...
  • リモートMIDI再生環境: 出先で自宅のMIDIデバイスにMIDI楽曲を送り込んで、手元で聴きながら楽曲編集できるようにしたい。そのための方法をいろいろ考えたのだけど、結局ストリーミングサーバを自前で用意するのは面倒なので、ustreamにでも接続してそこから聴く感じにするしかないかと思っている。

...ずいぶんいろいろ出てきたもんだ。ざっと洗い出した感じ、やはり先にMMLコンパイラを一段落つかせないといけないような気がしてきた。ただこのソフト、リリースするにはゆるい実装だし(エラーチェックとか真面目に考えだすと面倒なことになる)、かなり自分専用に近いツールだし、それなりに複雑なので、気合いが入らないとなかなか手を入れようという気になれないのがちょっと困る。まあ焦ってなんかやらないといけないものでもないので、気の向くままに進めようと思う。

追記: ちょっと中の人に話を聞いてみたら、iXMFはどうやら仕様が大幅に変わるらしい。それでは今手を出しても意味がないので、ちょっとこれは放置しよう...

IXE

| No Comments | No TrackBacks

週末に少しRewireを調べようと思っていたのだけど、仕様が全くオープンではないことに失望した。それで、何か代わりになるものは無いかと考えたのだった。で、インタラクティブな音源操作言語の実装はほしいかもしれないと思って、ちょっと寄り道?してiXMF engineを作ってみようかと思い立って始めてみた。 http://github.com/atsushieno/ixe/tree/master

先日も書いたけど、仕様書をろくに読んでいなかったので、そこから始めることになった。そうしたら、もう自分が期待していたものとは全然違う。これはオーディオストリームがコンテンツとして既にパッケージされているものが前提だ。インタラクティブと称されているのは、ストリームの再生やDSPの操作にかかる命令が、ファイル内あるいはコールバックで呼び出せるためである(にすぎない)ように見える。

まあでも実装できたら面白いかもしれない。GStreamerなんかでも実装があるといいなぁという程度の計画はsummer of codeであったようだし。

some ideas on MidiPlayer

| No Comments | No TrackBacks

とりあえずビジュアルプレイヤーとしてやりたかったことの多くが基本的には出来ている感じのmldspだけど、今後は多少方向性の違ったおもちゃにしてみようと思っている。

大まかには、ユーザコントロールによる入力をSMF上の演奏命令とマージしてMIDIデバイスに送信できる機能を追加したいと思っている。それによって、演奏中のMIDI楽曲をあれこれいじってパラメータ調整できるというわけだ。TMIDIでは画面上のコントロール値を左クリックや右クリックで加減できるのだけど、それと目的としては同じ事になる。(ただ、あのUIでやる必要は無いだろうと思っている。細かいからいじりにくいし。)

入力をどう受け付けるかについては、いくつか案がある:

  • ソフトウェアMIDIキーボード。Windows Formsレベルでは既に実装があるので、これをMoonlightに移植できれば、入力をブリッジするだけでいける
  • コマンドテキストをコンパイルして送信。今作っているMMLコンパイラを再利用できる。GUIはテキストボックスと送信ボタンのみ。
  • 外部MIDI入力のブリッジ。これを実現するには、portmidiのバインディングの対応を広げなければならない。これができると、ハードウェアMIDIキーボードが使えるようになる。GUIは不要。
  • 外部カスタムデバイスのブリッジ。たとえばgainerの入力を直接解釈して適宜MIDIメッセージを送信できるようにすれば、portmidiのバインディングが無くてもカスタムデバイスが利用できる。実はこれを一番やりたい。これもGUIは不要。

これは、mldspというよりMidiPlayerのフレームワークで対応した方がスマートだろうと思っている。

ちなみに、これらの他にさらにiXMFなどもサポートできたら楽しいのではないかと思っているのだけど、iXMFの実装から始めないといけないので、やや敷居が高い。仕様書も読み進められていないし。そんなわけで、すぐには出来なそうだ。

今週は無駄にchatpadで遊んだりなどしていたこともあって、あまりMMLコンパイラに時間をかけることができなかったのだけど、2つばかり重要な実装を追加した。

ひとつはトラック別マクロ定義で、これがあると特定のトラックに特化したマクロ命令を定義することが出来る。一番典型的な用途はリズムトラックでの使用だ。リズムトラックを記述する際に、ドレミ(cdefgab)で記述する人はまずいない。むしろ b をバスドラム、s をスネアドラム...といった風に記述したいだろう。また、ギターコードの記述の意味をトラック毎に変えたいという人もいるかもしれない。マクロ定義の適用が全トラック共通だと、こういうことができない。

これを解決するにあたっては、特に最後に定義されたマクロを適用するように、マクロの解決ロジックを多少変更する必要があった。といっても、この実装で難しかったことはほとんど何もない。

もうひとつはスペクトラムと呼んでいる、時系列に応じて動的に適用されるマクロの実装だ。これは特にピッチベンドやパンポットを緩やかに変化させたい(けどいちいち P32 r48 P36 r48 P40 r48 P44 ...などと書いていられない)という場面で利用するものだ。

しっかりした命令体系をサポートするには、コンパイラレベルでいろいろ対応してやらなければならないのだけど、とりあえずマクロレベルで対応できるように、コンパイラに「マクロを適用する」命令を追加した。これで「4ステップ待機して、値を+4させる命令を適用して...を変化値が64になるまで繰り返して、今度は減算して...」といった動的な変化が実装できるようになった。

ただ、これを実装していてひとつ気付いたのだけど、このスペクトラムを実現するためには、相対的な値の変化を実装できるようにしなければならない。実はこれが出来ていない。とりあえずマクロ定義で P, P+, P- を個別に定義することにして、proof of conceptとしては利用できるようになった。というわけでパンポット以外ではまだ利用できない。

相対的な価の変化が実現できていないというのは、ひとつには引数に相対値指定という概念が存在しないということだ。別の視点で言えば、マクロはあくまで命令リストであって変数ではないので、マクロで指定された引数がそのまま相対値として指定できることにはならない。パンポット命令は単純に引数値をパラメータとするコモンコントロール命令を発行するのみで、現在のパンポット値はどこにも保存されないというわけだ。上記のP+, P-といった命令を実装するにあたって、変数を追加することで、これは保存されることになったのだけど、P以外の命令についてはなお同じことが言える。

この辺りはもう少し柔軟にいろいろ実現できるように、ただし文法が破綻しなくなる程度に、整理しなければならないだろう。

現行方式でのスペクトラムは、割と単純な動的変化しか実現できないので、いずれ本格的なソフトウェアLFOに近いものを実装したいとも思っている。といっても、サイン波などを除けば、MUC MMLの特長だったアクティブ系引数に匹敵する柔軟性は実現できていると思うので、優先度はそれほど高くないかもしれない。ソフトウェアLFOが実装できると、テクノ系の作曲の幅が広がるので、いずれきちんと実装したいとは思っているけど。

なんとも中途半端な実装ではあるけど、mldspに疑似スペアナを追加した。とりあえずキーオンに合わせてボリュームを上げて、周りを比例的に調整して、150msecごとに全体量の10%ずつ減衰するというだけの単純な実装でしかないけど。ひとつには、まずボリュームを保持して画面に反映して一定時間で減衰させるロジックだけでも実装したかったことがある。たぶん減衰のロジックは単純な減衰で問題は無いと思う。スペアナで表示される値の計算はいくらでも改善の余地がある(というかまだ整理して考えていない)。

単純な実装のままにしてある理由のもうひとつは、スペアナ実装のパフォーマンスへの影響がだいぶ大きいので、このまま先に進めるとまずいと思っていることがある。先にアプリケーションの最適化を実現しないと、Silverlight上で実行してもロスが大きいので、Moonlightだとたぶん大変なことになる(今日はMac上で実装を書いていたのでMoonlightでは未確認)。最近はMoonlightのどこかでパフォーマンスが以前より悪化している状態なので、通常の演奏でもだいぶ支障が出てきている(これは旧バージョンでも同じ)。

とりあえず、見てくれだけはスペアナっぽいものが出来たので、スペアナ自体はクリアしたということにしておこうと思う。

パフォーマンス改善のポイントは、とりあえずの推測としては、タイマとStoryboardを減らすと大きいと思っている。Storyboardは(現在の利用方法上)不必要に高い精度で実行されている。タイマはDispatchTimerなので、実行時にはJavascriptへのドメイン越えが必要になる。多分そこでロスが発生しているので、タイマ越しに実行されるコードをなるべくまとめるようにしたい。

パフォーマンスの問題は、実のところプロファイラを使えばある程度計測出来るはずなので、いずれそれで見てみようとも思っている。

parenthesized expressions

| No Comments | No TrackBacks

ループの実装は、ソースレベルで展開するように修正することができた。これで ) や ( を使った相対音量指定がループ付きで簡単に展開出来る...と思ってMMLを書いてみて、問題にぶつかってしまった。( と ) は、計算の優先度を操作するために(要するに括弧付きの式)、既に使われてしまっていたのである。間が悪いことに、これらは名前としてはきちんと妥当するよう、パーサは実装されていたので、今の今まで忘れられていた。

どう解決すべきか悩む。とはいっても、parenthesized expressionとして使えなくするのが正しい解決策だろう。問題は、その穴埋めをどうするかだ。

  • ( と ) のそれぞれを、__( と )__ とかに置き換える: 出来なくはないが、MMLが直感的でなくなるので望ましくない。
  • { と } に置き換える: 多少MMLが直感的でなくなる程度なので悪くはないが、マクロ定義にも使用されているトークンなので、MML解析にちょっと工夫が必要になる
  • 優先度指定式が不要になるように、演算式をLISPyに +(3,4) とか -(4,1) といった式にする。やはり直感的ではなくなる(LISPerにとっては直感的か)。

少し冷却期間をおいて考えることにしよう。

ふと、テキスト音楽サクラに ( と ) が命令として存在しないのを思い出した(サクラにはv+, v-という命令が存在する)。おそらく同じような罠にはまって、音量相対指定コマンド(というより有効なマクロ文字)としての ( ) を禁止したのだろうなと思う。難しい問題だ。

...とりあえず、一番実装に影響の少ない { } を使うかたちで文法を変更することにした。

今日はとりあえず表題の課題を2つ片付けたのだけど(あとバグ潰しとか)、どちらもやっつけ対策という感じになってしまった。 ループは√1,3 √2 ... のようなMMLをサポートするようにしているので(文法上は[cd :1,3 ef :2 ga]4 のような表記になる)、これを展開する部分がトリッキーでバグのもとになり、そして現在のところコンパイル結果を繰り返すような実装になってしまっている。つまり [ cde> ]3 と書いてもオクターブは変わらないし、[c)]12 と書いても音量が上がらない。これでは表現の幅が狭まるので(段階的に変化させ「ない」方法はソースレベルのループ展開でも可能だが、段階的に変化「させる」方法が出力レベルのループ展開では不可能だ)、修正しなければならないだろう。ややこしいことになりそうだが...

和音のやっつけ実装については、結局和音を計算するための特殊命令を仕込むことにした。発音と消音がインターバル無しで行われるケースは、通常はあり得ない(発音即消音にする意味が無いのでユーザが書くことも無い)。これをMMLレベルでの発音コマンドで識別して、インターバルが無いものについては、その消音コマンドを蓄積しておき、後でインターバルのある音があった時に、その消音コマンドのタイムライン上の位置を後ろに回して、インターバルを合わせるということをやっている。これで c0e0g4 という命令は、正しく c0,4e0,4g4,4 として処理されるようになる。この「蓄積」やタイムライン位置補正は、特殊な命令をコンパイラが処理することで、既存の仕組みに影響をあまり及ぼさずに行っている。

和音は面倒かなと思っていたのだけど、それなりに簡単に実装出来たので助かった。こんな感じで少しずつほしい機能を実現していきたい。

最低限の機能を実現

| No Comments | No TrackBacks

相変わらずなかなかMMLコンパイラの作業に時間が割けなかったのだけど、今日なんとか時間をとって、かなりいい感じに先に進むことが出来た。マクロの展開で悩んでいた箇所があったのだけど(発音コマンドの引数をc,c-,c=,c+からb,b,b=,b+まで全部書いていられないが、省略したら引数参照がマクロ展開時に解決出来ないという問題)、文字列レベルでのエイリアスを別途プリプロセスすることによって解決させることにした。やっつけではあるけど、これとマクロの都合のいい方を使う文法にすれば、無理なくいろいろ書けるのではないかと思う。

ともあれ、これで発音コマンドやプリミティブなMIDIメッセージの作成は実現できたと思う。あとは正常系の機能追加としては、メタイベントやSysExイベントのサポート、ループの展開、和音の処理方法の検討、そして動的パラメータのサポートが課題になるだろう。

異常系の対応は少々難しい。数値の範囲チェックなどを行うには「正しい値の範囲」が必要だけど、かなりメタな文法になっているので、変数値に制限をもうけるなどしない限り無理だ。そしてそのために新しく文法要素を追加するのが面倒だ。とはいえ、MMLの難しいところは異常値を簡単に導入出来てしまって、そのデバッグが難しいというところにあるので、これはなるべく対応したい。

ちなみに今回のMML文法には、現在のステップ数をassertするというデバッグ用命令が含まれている。トラックごとにステップ数が合わないというのは、MMLを書いていると非常によくあることなので、これで改善しようというわけだ。assertionは、実際にはステップに限定することはなく、ループ中のオクターブなど、いろいろなハマりどころで使えるのではないかと思っている。

動的パラメータは、mucで言えばアクティブ系引数だけど、もう少しソフトウェアLFO的な実装にした方が、実装も利用も簡単になるのではないかと思っている。アクティブ系引数は反復的なものではないし。ちなみに、サイン波のようなものを導入する支障にならないよう、数値計算はdoubleで行うようにしている。多少面倒だったけど。

mldspに比べるとかなり難産だったけど、とりあえずひとつのブレイクスルーを迎えることが出来たので、今日は枕を高くして寝られそうだ。

いま実装しているMMLの文法では、ユーザー定義マクロに型付き引数を指定することができて、その引数型は整数であったり音長であったりする。cdefgabもマクロで定義していて、これはキーを引数に取るnコマンドにキーをアサインしただけのものになっている。cdefgabを実装するには、その最初の引数 = 音長は、音長として解釈されなければならない。"c4"は、ドを4ステップではなく、ドを4分音符で発声、の意になる。

音長を引数として渡すことが出来るというのは、トークン解析のレベルでは実装したけど、音長と数値はかなり融通させなければならない(要するにキャストしなければならない)場面が多々ある。そして困ったことに、音長は大抵の場合は数値としてトークナイズされている("c4"の"4"が数値になるか音長になるかは、マクロを展開した時に初めて分かる。引数の型調整をぼやかしていたおかげで、音長から数値に変換してさらに音長に変換するようなマクロ展開処理があると、4(分音符)→192/4 = 48(ステップ)→(数値の)48→48分音符として解釈(!) のような事態が生じる。

どう整理したものやら...過去に存在していたMML文法で、それほどマクロ展開をメタに定義した文法が存在していなかったのも頷けようというものだ。ややこしいもの。

音長の関係でもうひとつややこしい要素を発見した。和音だ。FM音源などモノフォニック音源を対象にしていたMMLには、そもそも和音の概念が無いが、たとえばmucではc0d0e4のように記述できる。cとdの発音長はどこから拾っているのだろうか? これはe4までMMLを解釈しないと知り得ない。これは、cとdとeを別々の命令として解釈していて、命令のつながりから意味を再構築するようなステップが無いうちは、決して実現出来ない。そしてその意味論的再構築のステップを用意するとしても、その再構築ルールを定義する文法が必要になるということでもある(!)。これは現実的には不可能で、せいぜいコンパイラの拡張モジュールというかたちでinjectさせるくらいしかできない。

ここまで実装が進めばようやく先に進められるだろうと思っていたところに困った問題がたくさん。ホントどうしたもんだろ。

About this Archive

This page is an archive of entries from July 2009 listed from newest to oldest.

June 2009 is the previous archive.

August 2009 is the next archive.

Find recent content on the main index or look in the archives to find all content.

Categories

Pages

OpenID accepted here Learn more about OpenID
Powered by Movable Type 4.23-en