mocデーモンのサウンド再生を強制的にフェードダウンする良い方法を見つける必要があります
次のようなシナリオがあります。
私は、MOC (musiconconsole) デーモンとカスタム Ruby アプリケーションを搭載した小さな Ubuntu 12.04 サーバー ボックスを実行しています。
Ruby アプリケーションは、定期的またはイベント駆動型のシナリオで、時々 wav またはその他のサウンド ファイルを再生します。たとえば、午後 7 時に「store_is_closing.mp3」などを再生します。
また、MP3 プレイリストで MOC デーモンを実行し、一日中音楽を再生しています。
ミキシングには ALSA を使用しています。
すべて正常に動作していますが、1 点欠けています。
たとえば、MOC が曲を再生していて、Ruby アプリがサウンド ファイルを再生すると、すべてが同じサウンド レベルになります (当然のことですが)。そのため、Ruby アプリによって再生されたサウンド ファイルの音は何も聞き取れません。
MOC デーモンに曲の再生を強制的に定義済みのパーセンテージ (元のサウンド レベルの 10% とします) までフェード ダウンさせる方法を見つける必要があります。Ruby アプリがサウンド ファイルを再生した後、moc を元のサウンド レベルに戻す必要があります。
答え1
MOC デーモンはmocp
クライアントからのみ制御できます。
PulseAudio を使用している場合は、 を使用してpacmd
MOC の音量を変更できます。
MOCをMPDmpc
、 MPD の音量を変更するために使用できます。
本当に ALSA でこれを実行したい場合は、次の内容を に記述します/etc/asound.conf
。
pcm.moc_with_volume {
type softvol
slave.pcm "default" # or whatever you're using in MOC
control {
name "MOC Playback Volume"
count 1
}
}
moc_with_volume
の代わりにALSA デバイス名を使用するように MOC を構成しますdefault
。
ボリューム変更プログラムでミキサー コントロールを設定できない場合は、他のミキサー コントロールを監視し、その値を MOC ミキサー コントロールにコピーする必要があります。これは、次のようなプログラムで実行できます。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <alsa/asoundlib.h>
#define CHECK(fn) check((fn), #fn)
static void check(int err, const char *fn)
{
if (err < 0) {
fprintf(stderr, "%s failed: %s\n", fn, snd_strerror(err));
exit(EXIT_FAILURE);
}
}
int main()
{
snd_ctl_t *ctl;
snd_ctl_event_t *event;
snd_ctl_elem_id_t *id_src, *id_dst;
snd_ctl_elem_value_t *value;
unsigned int mask;
long raw, db;
CHECK(snd_ctl_open(&ctl, "hw:0", 0));
CHECK(snd_ctl_subscribe_events(ctl, 1));
snd_ctl_event_alloca(&event);
snd_ctl_elem_id_alloca(&id_src);
snd_ctl_elem_id_alloca(&id_dst);
snd_ctl_elem_value_alloca(&value);
snd_ctl_elem_id_set_interface(id_dst, SND_CTL_ELEM_IFACE_MIXER);
snd_ctl_elem_id_set_name(id_dst, "MOC Playback Volume");
for (;;) {
CHECK(snd_ctl_read(ctl, event));
if (snd_ctl_event_get_type(event) != SND_CTL_EVENT_ELEM)
continue;
mask = snd_ctl_event_elem_get_mask(event);
if (mask == SND_CTL_EVENT_MASK_REMOVE ||
!(mask & SND_CTL_EVENT_MASK_VALUE) ||
strcmp(snd_ctl_event_elem_get_name(event),
"Some Mic Capture Volume"))
continue;
snd_ctl_event_elem_get_id(event, id_src);
snd_ctl_elem_value_set_id(value, id_src);
CHECK(snd_ctl_elem_read(ctl, value));
raw = snd_ctl_elem_value_get_integer(value, 0);
CHECK(snd_ctl_convert_to_dB(ctl, id_src, raw, &db));
CHECK(snd_ctl_convert_from_dB(ctl, id_dst, db, &raw, 0));
snd_ctl_elem_value_set_id(value, id_dst);
snd_ctl_elem_value_set_integer(value, 0, raw);
snd_ctl_elem_value_set_integer(value, 1, raw);
CHECK(snd_ctl_elem_write(ctl, value));
}
}
(amixer controls
実際のコントロール名を確認するために使用します。)