SVX日記

2004|04|05|06|07|08|09|10|11|12|
2005|01|02|03|04|05|06|07|08|09|10|11|12|
2006|01|02|03|04|05|06|07|08|09|10|11|12|
2007|01|02|03|04|05|06|07|08|09|10|11|12|
2008|01|02|03|04|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|07|08|09|10|11|12|
2010|01|02|03|04|05|06|07|08|09|10|11|12|
2011|01|02|03|04|05|06|07|08|09|10|11|12|
2012|01|02|03|04|05|06|07|08|09|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|05|06|07|08|09|10|11|12|
2015|01|02|03|04|05|06|07|08|09|10|11|12|
2016|01|02|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|05|06|07|08|09|10|11|12|
2018|01|02|03|04|05|06|07|08|09|10|11|12|
2019|01|02|03|04|05|06|07|08|09|10|11|12|
2020|01|02|03|04|05|06|07|08|09|10|11|12|
2021|01|02|03|04|05|06|07|08|09|10|11|12|
2022|01|02|03|04|05|06|07|08|09|10|11|12|
2023|01|02|03|04|05|06|07|08|09|10|11|12|
2024|01|02|03|04|05|06|07|08|09|10|11|12|
2025|01|02|03|

2025-02-17(Mon) シン・チープなDTMアプリ

  Linuxのサウンド機能についておさらいしたところで、だーいぶ以前に作った自作のDTMスイート「CUIck DTM suite」を引っ張り出してみることにした。当時はまだWindozeを使ってたので、Cygwin環境に向けて書いたものだ。何度何度何度かお色直しして使い続けているが、いまでも使えるものだろうか?

  「CUIck DTM suite」には「melod」という発声デーモンがあって「konk」というアプリを組み合わせることで「PCのキーボード」が「楽器のキーボード」と化す。過去にはソレ用にこんな風に塗り分けたりしてた頃もあった。

  画像の説明

  「melod」は「/dev/dsp」にPCM波形を書き込み続けるデーモンで、当時はよく考えずに作ったものなのだが、これはOSS(Open Sound System)アプリだったわけだ。

  まずは、前回まとめたところの、以下の経路で使ってみる。

OSSアプリ → OSSエミュ(PulseAudioの) → PulseAudioエミュ(PipeWireの) → PipeWire → ALSA

  PulseAudioのOSSエミュレータ「padsp」を噛ませて起動するわけだ。

$ padsp ./melod

  通常の環境には/dev/dspは存在しないのだが、padspを噛ませた中の環境には/dev/dspが出現するので、それを経由してPulseAudio……ではなく、PipeWireを経てALSAから鳴るわけだ。実際、アッサリと鳴った。よく考えてみれば、エラく回りクドいことをやってたんだな。

  しかし、別にその経路が唯一というわけではない。OSSエミュレータはALSAからも提供されているのだ。カーネルモジュールの形になっており、通常はロードされていないが、ロードすりゃ使える。

# modprobe snd_pcm_oss

  これにより/dev/dspではないが、/dev/dsp1, /dev/dsp2が出現する。/dev/dsp1がノートPC本体のデバイス、/dev/dsp2はドックのデバイスを指すものだ。これを使えば、以下の経路を使うことになる。

OSSアプリ → OSSエミュ(ALSAの) → ALSA

  melodの/dev/dspを/dev/dsp1に書き換えて起動してみる。

$ ./melod

  んが、動かん。音を鳴らそうとした瞬間に落ちる。どうもfragment(バッファ)のサイズが足りないらしい。なんで?

  fragmentのサイズを調べようと思って、ioctlでSNDCTL_DSP_GETBLKSIZEを発行してみる。どうでもいいけど、ioctlってどこかに仕様がまとめられていたりしないの? カーネルのコード読むほかないのかしらん。

    x = [0].pack('i*')
    p dsp.ioctl(0xc0045004, x)                                  # SNDCTL_DSP_GETBLKSIZE
    printf("%04x\n", x.unpack('i*')[0])

  55hって値が返ってきたが、なんのこっちゃ……って、アレ? なんか音が出るようになっているのだけれど。なんで!?

    x = [0, 0, 0, 0].pack('i*')
    p dsp.ioctl(0x8010500c, x)                                  # SNDCTL_DSP_GETOSPACE
    printf("%04x %04x %04x %04x\n", *(x.unpack('i*')))
0020 0020 0080 1000
 ↓
0020 0020 0300 6000

  事前にSNDCTL_DSP_GETBLKSIZEを実行すると、fragmentサイズとして55hが返ってくるのだが、なぜかその後のfragmentサイズは6倍(80h->300h)になっている……ワケワカラン。まぁ、鳴ったからいいけど。当然ながら、この経路でALSAを使う場合、デバイスは専有されるので複数起動することはできない。

$ ./melod
./melod:26:in `initialize': Device or resource busy @ rb_sysopen - /dev/dsp1 (Errno::EBUSY)

  しかし、なにより驚いたのは、padspの実体がシェルスクリプトになっていたことだ。以前はバイナリだったんだがな。

  結局、この辺りは「いつまでも工事中」ということなんだろうな。ベストを求めて、常に発展途上であり、使う時にはちゃんと最新事情を調べて理解することが重要ということだ。前回と同じ結論だな。以上。解散。