2016/06/23(Thr)WinampのDSPプラグインをC#から使う

はてブ数 2016/06/23 0:43 プログラミング::C# つーさ

Winamp をしっていますか……。

DSPプラグインの作り方は、WinampのPluginのSDKが公開されてるので、
それとおんなじ様に呼んであげれば、できる? と思ったのと、
Winampのプラグインって関数ポインタを内部の構造体に入れてその構造体へのポインタを返してくるような形してて、
それらのAPIのP/Invoke・マーシャリングの仕方に興味がわいたのでやってみてた。

標準でついてるプラグイン dsp_sps.dll だけは、ロードしたとたんに落ちちゃう。実装を追いかけて調べてみたところ、
Winampには親ウィンドウにWM_USERを投げて関数ポインタの詰まった構造体をもらって、そこからいろんなAPIを呼ぶ機能があることと、
その子には「非対応だぜエラー!」値を返しても、それをそのままポインタとしてメモリアクセスして死んじゃうらしいことがわかった。
このAPI群を実装する気はまったく起こらないので、とりあえずいったんあきらめていつもの SA Stereo Tool を動かしてみた。

インストール済みのプラグインの名前が取得できた。SA Stereo Tool から音が出た。

satoolssharp.png

ソース
https://github.com/ttsuki/ttsuki/blob/e421ad0a3f6e1a51f72aa2d58b231263c7f87d2d/DllPInvoke/WinampDspPlugin.cs
関数ポインタを入れた構造体を返してくるようなAPIはあんまりないけど、マーシャリングしたい場合は、
関数ポインタに戻り値・引数・Calling Conventionもあわせた delegate を宣言して、
それを構造体のメンバとして宣言した状態で、マーシャリングすれば、勝手に関数ポインタからデリゲートを作ってくれる。
が、その方法だと、どうもNULLチェックができないっぽい? ので、今回は構造体のメンバはIntPtrとして受け取った後に、
関数ポインタをラップするデリゲートを手で作っている。

使い道……?
音ゲーとか作ったときに、Winampのプラグインを(VSTがわりに)エフェクターとして使えるかもしれないなとは思う。
SA Toolsなんかは、ヘボいスピーカでもそれなりに映えるような音に変えてくれるし。
レイテンシの問題はあって、それを回避するには、鳴らした場合の音と鳴らしてない場合の音を両方作っとくみたいな手もあるんだけど、
そもそもWinampのDSPは、(DLLファイルを物理的に複製でもしない限り)設計からして複数インスタンス生成できないし、
フィードバックがあるエフェクタは内部状態を再現するのが無理ゲーなので、1インスタンスでちょっと前に戻ることもできなくて、
リアルタイムにミックスする必要のあるゲームアプリケーション*1では、いまいち使えないかも。

他、自作アプリからDSPがドライブできれば、
自分のミュージックライブラリの中の曲を、外出先の自分の携帯電話から好みのDSP通して聴けるのでは、というのは、ちょっと思う。
上で試してるSA Stereo Toolの場合は、パイプで波形処理してくれるコマンドラインツールがあるのでそれを使った方がいいんだけど。
最近コメントがついてた、HSPで作ってたパイプ使ったプロセス間通信のラッパーみたいなのが要る。

余談だけど、コミットと本記事の公開に時差があるのは
ソースコミットの後に記事書こうと思って先のスクリーンショットをブログにあげたらなぜかサムネイルが作れなくて、
調べたらブログを動かしてるサーバのImageMagickのバージョンをあげたときから PNG 読めなくなってたらしく、
ここ2日ばかりあれこれ苦労して、ようやく再インストールできたからである。。
nice make 中に突然再起動しはじめたりとかして、ちょっとこのサーバもなんとかしたい。

あと、最近このブログがページの表示に2秒とかかかる激重状態になってたのは、
サーバが貧弱だからかなーとか思ってたけどいくらなんでもと思って調べたら、
データディレクトリとキャッシュディレクトリのオーナーとパーミッションがおかしいせいだった。
なおしたのでさくさく動くようになった。わーい。

ぐぅ

*1 : いわゆるキー音のある何か