moc 데몬의 사운드 재생을 강제로 페이드다운하는 좋은 방법을 찾아야 합니다.
다음과 같은 시나리오가 있습니다.
저는 MOC(musiconconsole) 데몬과 사용자 정의 Ruby 애플리케이션이 포함된 작은 Ubuntu 12.04 서버 상자를 실행하고 있습니다.
Ruby 응용 프로그램은 주기적 또는 이벤트 기반 시나리오에서 때때로 wav 또는 기타 사운드 파일을 재생합니다. 예를 들어 오후 7시에 "store_is_closing.mp3" 또는 이와 유사한 내용이 재생됩니다.
또한 하루 종일 음악을 재생하는 mp3 재생 목록과 함께 실행되는 MOC 데몬도 있습니다.
ALSA를 사용하여 믹싱을 수행하고 있습니다.
모든 것이 잘 작동하지만 한 가지 점이 누락되었습니다.
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
실제 컨트롤 이름을 확인하는데 사용합니다.)