EBUG勉強会/20180825_sndio
をテンプレートにして作成
Start:
#topicpath
* OpenBSD発の音声フレームワーク - sndio
RIGHT:EBUG 第66回会合 ~
2018年 8月25日、長岡市 ながおか市民センター ~
川俣吉広、kaw@on.rim.or.jp
**sndioとは
[[sndio(7)>https://man.openbsd.org/sndio.7]]は音声を統一...
現在はFreeBSD/NetBSD/Linuxにも移植されている。
ALSA, JACK, OSS, PulseAudioなどの音声フレームワークと同様...
具体的には、sndioは以下のような機能を持っている。
:音声デバイスを共有する|音声アプリケーションがデバイスに...
sndioを介在させることで複数のアプリケーションが同時に音声...
:音声のフォーマット変換を行う|音声データの形式、サンプル...
:音源の制御を可能にする|sndioは音声データそのもの以外に、...
:信号のルーティングを行う|sndioサウンドサーバでは複数の音...
これらの伝送はネットワークを経由して、他ホストで稼動して...
**構成
以下に、OpenBSDでsndioフレームワークが動作している様子の...
#ref(sndio.png);
***構成要素
:ハードウェア|様々な音声機器は、PC内の音声コーデックに接...
:デバイスドライバ|カーネル内には、コーデックに対応したデ...
上図の例で挙げられているIntelのICH8 I/Oコントローラ・ハブ...
~
コーデックに対応したドライバの上位にはデバイス非依存の[[a...
~
このレイヤーを参照・操作するツールとして[[audioctl(1)>htt...
~
audioctlの実行例
$ audioctl
name=azalia0
mode=play,record
pause=0
active=1
nblks=8
blksz=960
rate=48000
encoding=s16le
play.channels=2
play.bytes=3796930560
play.errors=883200
record.channels=2
record.bytes=3796930560
record.errors=552960
mixerctlの実行例
$ mixerctl -v | sort
inputs.dac-0:1=234,234
inputs.beep=119
inputs.beep_mute=off [ off on ]
inputs.dac-2:3=234,234
inputs.hp_source=sel6,mix6 { sel6 mix6 }
inputs.mic2=0,0
inputs.mic3=0,0
inputs.mic3_source=sel7,mix6 { sel7 mix6 }
inputs.mic=0,0
inputs.mix4_source=sel3,mix6 { sel3 mix6 }
inputs.mix6_mic2=0,0
inputs.mix6_mic=0,0
inputs.mix6_source=mic,mic2 { mic mic2 }
inputs.sel3_source=dac-0:1 [ dac-0:1 dac-2:3 ]
inputs.sel4_source=dac-0:1 [ dac-0:1 dac-2:3 ]
inputs.sel6_source=dac-0:1 [ dac-0:1 dac-2:3 ]
inputs.sel7_source=dac-0:1 [ dac-0:1 dac-2:3 ]
inputs.spkr_source=dac-2:3,mix6 { dac-2:3 mix6 }
outputs.hp_boost=off [ off on ]
outputs.hp_mute=off [ off on ]
outputs.hp_sense=plugged [ unplugged plugged ]
outputs.master.mute=off [ off on ]
outputs.master.slaves=dac-0:1,dac-2:3,hp,spkr { dac-0:1...
outputs.master=255,255
outputs.mic2_dir=input-vr80 [ none input input-vr0 inpu...
outputs.mic3_dir=input-vr80 [ none output input input-v...
outputs.mic3_mute=off [ off on ]
outputs.mic3_sense=unplugged [ unplugged plugged ]
outputs.mic_dir=input-vr80 [ none input input-vr0 input...
outputs.mic_sense=plugged [ unplugged plugged ]
outputs.mix6=0,0
outputs.mix6_mute=off [ off on ]
outputs.spkr_boost=off [ off on ]
outputs.spkr_eapd=on [ off on ]
outputs.spkr_mute=on [ off on ]
outputs.spkr_muters=hp,mic3 { hp mic3 }
record.adc-0:1=200,200
record.adc-0:1_mute=off [ off on ]
record.adc-0:1_source=mic [ mic mic2 ]
record.adc-2:3=200,200
record.adc-2:3_mute=off [ off on ]
record.adc-2:3_source=mic2 [ mic mic2 ]
record.volume.mute=off [ off on ]
record.volume.slaves=adc-2:3,adc-0:1 { adc-2:3 adc-0:1 ...
record.volume=200,200
:音声サーバ - [[sndiod(8)>https://man.openbsd.org/sndiod....
~
sndiodと音声アプリケーションはソケットインターフェースを...
:ユーザコマンド - [[aucat(1)>https://man.openbsd.org/auca...
sndiodがデーモンとしてバックグラウンドで機能を提供するの...
例えば、aucatには処理を行う音声データをファイルから入力し...
~
aucatコマンド自体はOpenBSD 2.0から存在し、sndioフレームワ...
OpenBSD 4.5でsndioフレームワークが登場した時点ではsndiod...
:音声アプリケーション|音声を扱うアプリケーションでsndioを...
--音声アプリケーション自体が、最初からsndioに対応している...
...OpenBSDネイティブのアプリケーション([[cdio(1)>https://...
あるいは外部プロジェクトのアプリケーションであっても、開...
勿論パッチ等の対応なしでそのまま使用できる。~
~
--音声アプリケーション自体は対応していないが、アプリケー...
...例えば音声編集ソフトのAudacityなど。Audacity自体はsndi...
portaudioを使っているportsを数えてみる
$ cd /usr/ports
$ find * -type d -name patches | xargs grep -rils 'porta...
| sort | uniq | wc -l
12
~
--音声アプリケーションにsndio対応のパッチを当てる。~
...次項で説明するsndio APIを用いるように、アプリケーショ...
ports/packagesでは、このケースが最も多いようだ。
sndio対応のパッチを当てているportsを数えてみる
$ cd /usr/ports
$ find * -type d -name patches | xargs fgrep -rls 'sndio...
| sort | uniq | wc -l
41
~
--sndioに対応していない音声アプリケーションとsndioツール...
...音声アプリケーションが再生あるいは収録のみで、リアルタ...
***音声デバイスへのアクセス制御
音声デバイスが無制限に共有されないように、sndioではセッシ...
sndiodに接続時、音声アプリケーションは$HOME/.aucat_cookie...
-他にsndioに接続している音声アプリケーションがない場合ク...
-2番目以降のアプリケーションがクッキーを提出した時、sndi...
-接続しているアプリケーションがなくなった時点で登録されて...
クッキーとして$HOME/.aucat_cookieを使うため、通常は同一の...
sndiodはデフォルトではUNIXドメインソケットでの接続のみ受...
**sndioのAPI
sndio APIを使用するには、libsndioより提供される各種関数を...
-[[sio_open, sio_close, sio_setpar, sio_getpar, sio_getca...
-[[mio_open, mio_close, mio_read, mio_write, mio_nfds, mi...
sio_*が音声ストリーム関連、mio_*がMIDIストリーム関連の関...
処理の流れ:
sio_initpar() /* パラメータの初期化 */
↓
sio_open() /* 音声デバイスや音声サーバに接続 */
↓
sio_setpar() /* パラメータの設定 */ ←←←←
sio_getpar() /* 設定結果の確認 */ ↑
↓ ↑
sio_start() /* 処理の起動 */ ←←←-↑
↓ ↑
sio_read(), sio_write() /* 入出力 */ ↑
↓ ↑
↓→→パラメータを変更する場合→→ sio_stop() →↑
↓ 処理を一時的に中断する場合など
↓
sio_close() /* 接続を閉じる */
MIDI接続の場合も、これに準ずる。
sio_open()では、一番目の引数で、以下の記法によって接続先...
>'''type'''[''@'''''hostname''']['','''''unit''']''/'''''...
:'''type'''|音声デバイスの種類 ... rsnd, rmidi, snd, midi...
:'''hostname'''|リモートに接続するばあいのホスト名
:'''unit'''|接続するサーバの番号
:'''devnum'''|デバイスの番号
:'''option'''|サブデバイス文字列
この記法はsndiodやaucatなどで音源のデバイスやサーバに接続...
例:
>''rsnd/0'' ... /dev/audio0 に直接アクセス (sndiodを介さ...
''snd/0.rear'' ... デフォルトで起動しているsndiodのリアス...
参考:
-sndio - hints on writing & porting audio code ~
http://www.sndio.org/tips.html
-sndioのサンプルコード ~
https://github.com/t6/sndio/tree/master/examples
**sndioの使用例
-ffmpegを使用したscreen castの例 ~
sndiodにサブデバイスとしてmonを追加(''-m play,mon -s mon'...
これにより、音声アプリケーションの出力を他のアプリケーシ...
# rcctl set sndiod flags '-s default -m play,mon -s mon'
# rcctl restart sndiod
この設定を行っておくとffmpeg実行時、''-i snd/0.mon'' を指...
$ ffmpeg -f x11grab -s 800x600 -i :0.0+100,100 -f sndio ...
-sndio非対応のアプリケーションでsndioを使用する例 ~
lameはpkg_addで導入してもsndio非対応であるが、aucatと組合...
以下の例ではリモートマシンの音声入力をaucatで受信し、パイ...
受け渡しするデータはheaderless raw形式なので、lameの入力...
~
リモートホストでの事前設定
remote_host # rcctl set sndiod flags '-L -'
remote_host # rcctl restart sndiod
ローカルでのコマンド実行
local_host $ aucat -f snd@remote_host/0 -o - | lame -r -...
-サンプルプログラム ~
このプログラムはステレオ音声のL (Ch1)に1kHz, R (Ch2)に400...
/* sin_osc ... generates sine waves
* and outputs to sndio default device
*
* Ch. 1: 1kHz, -6dBFS
* Ch. 2: 400Hz, -6dBFS
*
* Duration: 60 secs
*/
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <sndio.h>
/* frequency parameters in Hz */
#define SAMPLE_FREQ 48000.0
#define OUTPUT_FREQ1 1000.0
#define OUTPUT_FREQ2 400.0
/* buffer size of waveform */
#define SAMPLES 480
/* SAMPLES per CYCLE */
#define SPC1 (SAMPLE_FREQ/OUTPUT_FREQ1)
#define SPC2 (SAMPLE_FREQ/OUTPUT_FREQ2)
/* output level of sine wave with:
* sampling point 't',
* samples per cycle 'spc'
*/
#define SINVAL(t, spc) ((int16_t)(INT16_MAX*sin(2.0*M...
void fail_exit(const char *msg) {
fprintf(stderr, "%s failed\n", msg);
exit(1);
}
int main() {
/* waveform buffer */
int16_t wf[2*SAMPLES], /* signed 16bit per sample */
*p_wf;
/* fill buffer */
p_wf = wf;
for (int i = 0; i<SAMPLES; i++) {
*p_wf++ = SINVAL(i, SPC1); /* 1kHz to Ch1 */
*p_wf++ = SINVAL(i, SPC2); /* 400Hz to Ch2 */
}
/* initialization of sndio */
struct sio_par par;
struct sio_hdl *hdl;
ssize_t n;
sio_initpar(&par);
par.sig = 1;
par.bits = 16;
par.pchan = 2;
par.rate = 48000;
hdl = sio_open("snd/0", SIO_PLAY, 0); /* "snd/0" may b...
if (hdl == NULL) /* or "default"....
fail_exit("sio_open()");
if (!sio_setpar(hdl, &par))
fail_exit("sio_setpar()");
if (!sio_getpar(hdl, &par))
fail_exit("sio_getpar()");
if (!sio_start(hdl))
fail_exit("sio_start()");
/* output for 60 secs */
for (int i=0; i<6000; i++) {
n = sio_write(hdl, wf, sizeof(wf));
if (n == 0)
fail_exit("sio_write()");
}
sio_close(hdl);
return 0;
}
実行例
$ LDFLAGS='-lm -lsndio' make sin_osc
cc -O2 -pipe -lm -lsndio -o sin_osc sin_osc.c
$ ./sin_osc ...
実際に出力された音声((実際にはWAV形式の音声ファイルが出力...
**情報源
-OpenBSD FAQ - Multimedia ~
https://www.openbsd.org/faq/faq13.html
-sndio home ~
http://www.sndio.org/
-sndio - OpenBSD audio & MIDI framework for music and des...
http://www.openbsd.org/papers/asiabsdcon2010_sndio_slides...
----
#topicpath
End:
#topicpath
* OpenBSD発の音声フレームワーク - sndio
RIGHT:EBUG 第66回会合 ~
2018年 8月25日、長岡市 ながおか市民センター ~
川俣吉広、kaw@on.rim.or.jp
**sndioとは
[[sndio(7)>https://man.openbsd.org/sndio.7]]は音声を統一...
現在はFreeBSD/NetBSD/Linuxにも移植されている。
ALSA, JACK, OSS, PulseAudioなどの音声フレームワークと同様...
具体的には、sndioは以下のような機能を持っている。
:音声デバイスを共有する|音声アプリケーションがデバイスに...
sndioを介在させることで複数のアプリケーションが同時に音声...
:音声のフォーマット変換を行う|音声データの形式、サンプル...
:音源の制御を可能にする|sndioは音声データそのもの以外に、...
:信号のルーティングを行う|sndioサウンドサーバでは複数の音...
これらの伝送はネットワークを経由して、他ホストで稼動して...
**構成
以下に、OpenBSDでsndioフレームワークが動作している様子の...
#ref(sndio.png);
***構成要素
:ハードウェア|様々な音声機器は、PC内の音声コーデックに接...
:デバイスドライバ|カーネル内には、コーデックに対応したデ...
上図の例で挙げられているIntelのICH8 I/Oコントローラ・ハブ...
~
コーデックに対応したドライバの上位にはデバイス非依存の[[a...
~
このレイヤーを参照・操作するツールとして[[audioctl(1)>htt...
~
audioctlの実行例
$ audioctl
name=azalia0
mode=play,record
pause=0
active=1
nblks=8
blksz=960
rate=48000
encoding=s16le
play.channels=2
play.bytes=3796930560
play.errors=883200
record.channels=2
record.bytes=3796930560
record.errors=552960
mixerctlの実行例
$ mixerctl -v | sort
inputs.dac-0:1=234,234
inputs.beep=119
inputs.beep_mute=off [ off on ]
inputs.dac-2:3=234,234
inputs.hp_source=sel6,mix6 { sel6 mix6 }
inputs.mic2=0,0
inputs.mic3=0,0
inputs.mic3_source=sel7,mix6 { sel7 mix6 }
inputs.mic=0,0
inputs.mix4_source=sel3,mix6 { sel3 mix6 }
inputs.mix6_mic2=0,0
inputs.mix6_mic=0,0
inputs.mix6_source=mic,mic2 { mic mic2 }
inputs.sel3_source=dac-0:1 [ dac-0:1 dac-2:3 ]
inputs.sel4_source=dac-0:1 [ dac-0:1 dac-2:3 ]
inputs.sel6_source=dac-0:1 [ dac-0:1 dac-2:3 ]
inputs.sel7_source=dac-0:1 [ dac-0:1 dac-2:3 ]
inputs.spkr_source=dac-2:3,mix6 { dac-2:3 mix6 }
outputs.hp_boost=off [ off on ]
outputs.hp_mute=off [ off on ]
outputs.hp_sense=plugged [ unplugged plugged ]
outputs.master.mute=off [ off on ]
outputs.master.slaves=dac-0:1,dac-2:3,hp,spkr { dac-0:1...
outputs.master=255,255
outputs.mic2_dir=input-vr80 [ none input input-vr0 inpu...
outputs.mic3_dir=input-vr80 [ none output input input-v...
outputs.mic3_mute=off [ off on ]
outputs.mic3_sense=unplugged [ unplugged plugged ]
outputs.mic_dir=input-vr80 [ none input input-vr0 input...
outputs.mic_sense=plugged [ unplugged plugged ]
outputs.mix6=0,0
outputs.mix6_mute=off [ off on ]
outputs.spkr_boost=off [ off on ]
outputs.spkr_eapd=on [ off on ]
outputs.spkr_mute=on [ off on ]
outputs.spkr_muters=hp,mic3 { hp mic3 }
record.adc-0:1=200,200
record.adc-0:1_mute=off [ off on ]
record.adc-0:1_source=mic [ mic mic2 ]
record.adc-2:3=200,200
record.adc-2:3_mute=off [ off on ]
record.adc-2:3_source=mic2 [ mic mic2 ]
record.volume.mute=off [ off on ]
record.volume.slaves=adc-2:3,adc-0:1 { adc-2:3 adc-0:1 ...
record.volume=200,200
:音声サーバ - [[sndiod(8)>https://man.openbsd.org/sndiod....
~
sndiodと音声アプリケーションはソケットインターフェースを...
:ユーザコマンド - [[aucat(1)>https://man.openbsd.org/auca...
sndiodがデーモンとしてバックグラウンドで機能を提供するの...
例えば、aucatには処理を行う音声データをファイルから入力し...
~
aucatコマンド自体はOpenBSD 2.0から存在し、sndioフレームワ...
OpenBSD 4.5でsndioフレームワークが登場した時点ではsndiod...
:音声アプリケーション|音声を扱うアプリケーションでsndioを...
--音声アプリケーション自体が、最初からsndioに対応している...
...OpenBSDネイティブのアプリケーション([[cdio(1)>https://...
あるいは外部プロジェクトのアプリケーションであっても、開...
勿論パッチ等の対応なしでそのまま使用できる。~
~
--音声アプリケーション自体は対応していないが、アプリケー...
...例えば音声編集ソフトのAudacityなど。Audacity自体はsndi...
portaudioを使っているportsを数えてみる
$ cd /usr/ports
$ find * -type d -name patches | xargs grep -rils 'porta...
| sort | uniq | wc -l
12
~
--音声アプリケーションにsndio対応のパッチを当てる。~
...次項で説明するsndio APIを用いるように、アプリケーショ...
ports/packagesでは、このケースが最も多いようだ。
sndio対応のパッチを当てているportsを数えてみる
$ cd /usr/ports
$ find * -type d -name patches | xargs fgrep -rls 'sndio...
| sort | uniq | wc -l
41
~
--sndioに対応していない音声アプリケーションとsndioツール...
...音声アプリケーションが再生あるいは収録のみで、リアルタ...
***音声デバイスへのアクセス制御
音声デバイスが無制限に共有されないように、sndioではセッシ...
sndiodに接続時、音声アプリケーションは$HOME/.aucat_cookie...
-他にsndioに接続している音声アプリケーションがない場合ク...
-2番目以降のアプリケーションがクッキーを提出した時、sndi...
-接続しているアプリケーションがなくなった時点で登録されて...
クッキーとして$HOME/.aucat_cookieを使うため、通常は同一の...
sndiodはデフォルトではUNIXドメインソケットでの接続のみ受...
**sndioのAPI
sndio APIを使用するには、libsndioより提供される各種関数を...
-[[sio_open, sio_close, sio_setpar, sio_getpar, sio_getca...
-[[mio_open, mio_close, mio_read, mio_write, mio_nfds, mi...
sio_*が音声ストリーム関連、mio_*がMIDIストリーム関連の関...
処理の流れ:
sio_initpar() /* パラメータの初期化 */
↓
sio_open() /* 音声デバイスや音声サーバに接続 */
↓
sio_setpar() /* パラメータの設定 */ ←←←←
sio_getpar() /* 設定結果の確認 */ ↑
↓ ↑
sio_start() /* 処理の起動 */ ←←←-↑
↓ ↑
sio_read(), sio_write() /* 入出力 */ ↑
↓ ↑
↓→→パラメータを変更する場合→→ sio_stop() →↑
↓ 処理を一時的に中断する場合など
↓
sio_close() /* 接続を閉じる */
MIDI接続の場合も、これに準ずる。
sio_open()では、一番目の引数で、以下の記法によって接続先...
>'''type'''[''@'''''hostname''']['','''''unit''']''/'''''...
:'''type'''|音声デバイスの種類 ... rsnd, rmidi, snd, midi...
:'''hostname'''|リモートに接続するばあいのホスト名
:'''unit'''|接続するサーバの番号
:'''devnum'''|デバイスの番号
:'''option'''|サブデバイス文字列
この記法はsndiodやaucatなどで音源のデバイスやサーバに接続...
例:
>''rsnd/0'' ... /dev/audio0 に直接アクセス (sndiodを介さ...
''snd/0.rear'' ... デフォルトで起動しているsndiodのリアス...
参考:
-sndio - hints on writing & porting audio code ~
http://www.sndio.org/tips.html
-sndioのサンプルコード ~
https://github.com/t6/sndio/tree/master/examples
**sndioの使用例
-ffmpegを使用したscreen castの例 ~
sndiodにサブデバイスとしてmonを追加(''-m play,mon -s mon'...
これにより、音声アプリケーションの出力を他のアプリケーシ...
# rcctl set sndiod flags '-s default -m play,mon -s mon'
# rcctl restart sndiod
この設定を行っておくとffmpeg実行時、''-i snd/0.mon'' を指...
$ ffmpeg -f x11grab -s 800x600 -i :0.0+100,100 -f sndio ...
-sndio非対応のアプリケーションでsndioを使用する例 ~
lameはpkg_addで導入してもsndio非対応であるが、aucatと組合...
以下の例ではリモートマシンの音声入力をaucatで受信し、パイ...
受け渡しするデータはheaderless raw形式なので、lameの入力...
~
リモートホストでの事前設定
remote_host # rcctl set sndiod flags '-L -'
remote_host # rcctl restart sndiod
ローカルでのコマンド実行
local_host $ aucat -f snd@remote_host/0 -o - | lame -r -...
-サンプルプログラム ~
このプログラムはステレオ音声のL (Ch1)に1kHz, R (Ch2)に400...
/* sin_osc ... generates sine waves
* and outputs to sndio default device
*
* Ch. 1: 1kHz, -6dBFS
* Ch. 2: 400Hz, -6dBFS
*
* Duration: 60 secs
*/
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <sndio.h>
/* frequency parameters in Hz */
#define SAMPLE_FREQ 48000.0
#define OUTPUT_FREQ1 1000.0
#define OUTPUT_FREQ2 400.0
/* buffer size of waveform */
#define SAMPLES 480
/* SAMPLES per CYCLE */
#define SPC1 (SAMPLE_FREQ/OUTPUT_FREQ1)
#define SPC2 (SAMPLE_FREQ/OUTPUT_FREQ2)
/* output level of sine wave with:
* sampling point 't',
* samples per cycle 'spc'
*/
#define SINVAL(t, spc) ((int16_t)(INT16_MAX*sin(2.0*M...
void fail_exit(const char *msg) {
fprintf(stderr, "%s failed\n", msg);
exit(1);
}
int main() {
/* waveform buffer */
int16_t wf[2*SAMPLES], /* signed 16bit per sample */
*p_wf;
/* fill buffer */
p_wf = wf;
for (int i = 0; i<SAMPLES; i++) {
*p_wf++ = SINVAL(i, SPC1); /* 1kHz to Ch1 */
*p_wf++ = SINVAL(i, SPC2); /* 400Hz to Ch2 */
}
/* initialization of sndio */
struct sio_par par;
struct sio_hdl *hdl;
ssize_t n;
sio_initpar(&par);
par.sig = 1;
par.bits = 16;
par.pchan = 2;
par.rate = 48000;
hdl = sio_open("snd/0", SIO_PLAY, 0); /* "snd/0" may b...
if (hdl == NULL) /* or "default"....
fail_exit("sio_open()");
if (!sio_setpar(hdl, &par))
fail_exit("sio_setpar()");
if (!sio_getpar(hdl, &par))
fail_exit("sio_getpar()");
if (!sio_start(hdl))
fail_exit("sio_start()");
/* output for 60 secs */
for (int i=0; i<6000; i++) {
n = sio_write(hdl, wf, sizeof(wf));
if (n == 0)
fail_exit("sio_write()");
}
sio_close(hdl);
return 0;
}
実行例
$ LDFLAGS='-lm -lsndio' make sin_osc
cc -O2 -pipe -lm -lsndio -o sin_osc sin_osc.c
$ ./sin_osc ...
実際に出力された音声((実際にはWAV形式の音声ファイルが出力...
**情報源
-OpenBSD FAQ - Multimedia ~
https://www.openbsd.org/faq/faq13.html
-sndio home ~
http://www.sndio.org/
-sndio - OpenBSD audio & MIDI framework for music and des...
http://www.openbsd.org/papers/asiabsdcon2010_sndio_slides...
----
#topicpath
Page: