portmidiというプロジェクトがある。従来ソフトウェアでMIDI音源をいじるときは、プラットフォーム中立なAPIが存在しなかったので、MIDIの再生ソフトウェアはどうしてもプラットフォーム別になりがちだった。VideoLANのフォーラムでも、MIDIはプラットフォーム中立じゃないからサポートできんよ、という話が2008年あたりでもまだ書かれていたりする。これではクロスプラットフォームなMIDIサポートを実現するソフトウェアがなかなか登場しない。
そんな問題を解消できそうなのがこのportmidiだ。これは旧portaudio、現portmediaプロジェクトの一環として開発されている。Cベースの実装と、その各種言語ラッパーからなる。
このportmidiをC#ラッパー経由で叩こうというのが、とりあえずの目標である。そんなのはP/Invokeすれば一発である。というわけでとりあえずラッパーを作った。
PortMidiSharp.cs
しかし...
portmidiは、それなりに長いプロジェクトのはずなのに、現在まだまだ開発中で、まだビルドもちゃんと出来ていない。P/Invokeはsoやdllに対して行われるので、まずこれらをビルドしなければならないのだが、現状ではstaticライブラリしかビルドできないのである。Debianにはこれらの共有ビルドが含まれていて、それはちゃんと本家にbackportしてくれとか思うのだけど、しないなら仕方がない。できればこの辺をどうにかして改善してしまいたい。具体的には、Linux上ではshared libraryのビルドを、Windows上ではgcc/mingwを使ったビルドを、それぞれサポートしたい。
というわけで、本当ならautotoolsを使えばその辺は上手く出来るのだろうけど、まずそれよりgcc/mingwでdllをビルドするところを、とりあえずはやってみた。
portmidiには、porttimeとportmidiという2つのライブラリがある。ようだ。staticライブラリだと最終的にlibportmidi.aに全部含まれるし、一方でlibporttime.aもあるわけで、porttime.dllを別途生成する意味があるかどうかは分からないが、とりあえずportmidi/trunk/porttimeディレクトリで以下を実行:
これでporttime.dllが生成される。次にportmidi/trunk/pm_winディレクトリで以下を実行:
これでportmidi.dllが出来る。
コマンドラインにどれだけ余計なものが含まれているかは未検証だけど、この辺はLinux上でsoを作ってautotoolizeした時に再訪したい。
とりあえず先のPortMidiSharp.csと合わせてサンプルをビルドして実行してみた:
そんな問題を解消できそうなのがこのportmidiだ。これは旧portaudio、現portmediaプロジェクトの一環として開発されている。Cベースの実装と、その各種言語ラッパーからなる。
このportmidiをC#ラッパー経由で叩こうというのが、とりあえずの目標である。そんなのはP/Invokeすれば一発である。というわけでとりあえずラッパーを作った。
PortMidiSharp.cs
しかし...
portmidiは、それなりに長いプロジェクトのはずなのに、現在まだまだ開発中で、まだビルドもちゃんと出来ていない。P/Invokeはsoやdllに対して行われるので、まずこれらをビルドしなければならないのだが、現状ではstaticライブラリしかビルドできないのである。Debianにはこれらの共有ビルドが含まれていて、それはちゃんと本家にbackportしてくれとか思うのだけど、しないなら仕方がない。できればこの辺をどうにかして改善してしまいたい。具体的には、Linux上ではshared libraryのビルドを、Windows上ではgcc/mingwを使ったビルドを、それぞれサポートしたい。
というわけで、本当ならautotoolsを使えばその辺は上手く出来るのだろうけど、まずそれよりgcc/mingwでdllをビルドするところを、とりあえずはやってみた。
portmidiには、porttimeとportmidiという2つのライブラリがある。ようだ。staticライブラリだと最終的にlibportmidi.aに全部含まれるし、一方でlibporttime.aもあるわけで、porttime.dllを別途生成する意味があるかどうかは分からないが、とりあえずportmidi/trunk/porttimeディレクトリで以下を実行:
gcc -mno-cygwin -mwindows -c porttime.c -o porttime.o
gcc -mno-cygwin -mwindows -c ptwinmm.c -o ptwinmm.o
dllwrap --target i386-mingw32 --export-all --output-def porttime.def --implib libporttime.a --driver-name gcc -mno-cygwin -mwindows -o porttime.dll porttime.o ptwinmm.o -lwinmm
これでporttime.dllが生成される。次にportmidi/trunk/pm_winディレクトリで以下を実行:
gcc -mno-cygwin -mwindows -c -o pmwin.o -I ../pm_common -I ../porttime pmwin.c
gcc -mno-cygwin -mwindows -c -o pmwinmm.o -I ../pm_common -I ../porttime pmwinmm.c
gcc -mno-cygwin -mwindows -c -o portmidi.o -I ../pm_common -I ../porttime ../pm_common/portmidi.c
gcc -mno-cygwin -mwindows -c -o pmutil.o -I ../pm_common -I ../porttime ../pm_common/pmutil.c
dllwrap --target i386-mingw32 --export-all --output-def portmidi.def --implib libportmidi.a --driver-name gcc -mno-cygwin -mwindows -I ../pm_common -I ../porttime pmwin.o pmwinmm.o portmidi.o pmutil.o -lwinmm -L../porttime -lporttime -o portmidi.dll
これでportmidi.dllが出来る。
コマンドラインにどれだけ余計なものが含まれているかは未検証だけど、この辺はLinux上でsoを作ってautotoolizeした時に再訪したい。
とりあえず先のPortMidiSharp.csと合わせてサンプルをビルドして実行してみた:
using System;
namespace PortMidiSharp
{
public class Driver
{
public static void Main ()
{
Console.WriteLine (MidiDeviceManager.DeviceCount);
Console.WriteLine (MidiDeviceManager.DefaultInputDeviceID);
Console.WriteLine (MidiDeviceManager.DefaultOutputDeviceID);
foreach (var dev in MidiDeviceManager.AllDevices) {
Console.WriteLine (dev.IsInput);
Console.WriteLine (dev.IsOutput);
Console.WriteLine ("IF: " + dev.Interface);
Console.WriteLine ("Name: " + dev.Name);
}
var o = MidiDeviceManager.OpenOutput (MidiDeviceManager.DefaultOutputDeviceID);
o.Close ();
}
}
}
実行結果:
表示内容がおかしすぎるわけだが、なんとかP/Invokeできてはいるようだ。pm_winmm_termとか呼ばれているようだし。とりあえずめでたしめでたし。
$ mono test.exe 2 -1 0 True False IF: Name: True True IF: Name: !!!NoError pm_winmm_term called pm_winmm_term exiting
Leave a comment