我需要找到一個好方法來強制淡出 moc 守護程式的聲音播放
我有以下場景:
我正在運行一個小型 Ubuntu 12.04 伺服器,其中包含 MOC(musiconconsole)守護程式和自訂 ruby 應用程式。
ruby 應用程式偶爾會在週期性或事件驅動的場景中播放 wav 或其他聲音檔案。例如,晚上 7 點它會播放“store_is_looking.mp3”或類似的內容。
我還有一個 MOC 守護進程,它運行著一個 mp3 播放列表,可以全天播放音樂。
我正在使用 ALSA 進行混合。
一切正常,但我缺少一點。
如果,假設 MOC 正在播放一首歌曲,而 ruby 應用程式播放一個聲音文件,那麼一切都處於相同的聲音等級(顯然)。因此,您無法理解 ruby 應用程式播放的任何聲音檔案。
我需要找到一種方法來強制 MOC 守護程序將歌曲的播放淡入到定義的百分比(比方說原始聲音級別的 10%),並且在 ruby 應用程序播放聲音文件後,應該將 moc 切換回來至原始聲級。
答案1
MOC 守護程式只能透過mocp
客戶端進行控制。
如果您使用 PulseAudio,則可以用來pacmd
變更 MOC 的音量。
如果您將 MOC 替換為MPD,您可以用來mpc
變更 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 配置為使用 ALSA 設備名稱moc_with_volume
而不是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
檢查實際的控制項名稱。)