Merge pull request #19 from sthibaul/alsa-volume

Support setting ALSA volume in addition to espeak volume
This commit is contained in:
Alexander Epaneshnikov 2021-06-14 20:09:19 +03:00 committed by GitHub
commit 7159441731
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 94 additions and 1 deletions

View file

@ -6,7 +6,7 @@ DEPFLAGS = -MMD
WARNFLAGS = -Wall
CFLAGS += ${DEPFLAGS} ${WARNFLAGS}
LDLIBS = -lespeak -lpthread
LDLIBS = -lespeak -lpthread -lasound -lm
INSTALL = install
BINMODE = 0755

6
cli.c
View file

@ -30,11 +30,15 @@ extern char *pidPath;
/* default voice */
extern char *defaultVoice;
/* Whether to drive ALSA volume */
extern int alsaVolume;
/* command line options */
const char *shortOptions = "P:V:adhv";
const struct option longOptions[] = {
{"pid-path", required_argument, NULL, 'P'},
{"default-voice", required_argument, NULL, 'V'},
{"alsa-volume", no_argument, &alsaVolume, 1},
{"acsint", no_argument, NULL, 'a'},
{"debug", no_argument, NULL, 'd'},
{"help", no_argument, NULL, 'h'},
@ -48,6 +52,7 @@ static void show_help()
printf("Options are as follows:\n");
printf(" --pid-path=path, -P path\t\tSet path for pid file.\n");
printf(" --default-voice=voice, -V voice\tSet default voice.\n");
printf(" --alsa-volume\t\t\t\tDrive the ALSA volume.\n");
printf(" --debug, -d\t\t\t\tDebug mode (stay in the foreground).\n");
printf(" --help, -h\t\t\t\tShow this help.\n");
printf(" --version, -v\t\t\t\tDisplay the software version.\n");
@ -93,6 +98,7 @@ void process_cli(int argc, char **argv)
show_version();
break;
case -1:
case 0:
break;
default:
show_help();

View file

@ -22,6 +22,8 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <alsa/asoundlib.h>
#include <math.h>
#include "espeakup.h"
@ -32,6 +34,7 @@ const int defaultRange = 5;
const int defaultRate = 2;
const int defaultVolume = 5;
char *defaultVoice = NULL;
int alsaVolume = 0;
/* multipliers and offsets */
const int frequencyMultiplier = 11;
@ -152,6 +155,86 @@ static espeak_ERROR set_voice(struct synth_t *s, char *voice)
return rc;
}
static void set_alsa_volume(int vol)
{
snd_mixer_t *m;
snd_mixer_elem_t *e;
int err;
err = snd_mixer_open(&m, 0);
if (err < 0)
{
fprintf(stderr, "ALSA mixer open error: %s\n", snd_strerror(err));
return;
}
err = snd_mixer_attach(m, "default");
if (err < 0)
{
fprintf(stderr, "ALSA mixer attach error: %s\n", snd_strerror(err));
return;
}
err = snd_mixer_selem_register(m, NULL, NULL);
if (err < 0)
{
fprintf(stderr, "ALSA mixer load error: %s\n", snd_strerror(err));
return;
}
err = snd_mixer_load(m);
if (err < 0)
{
fprintf(stderr, "ALSA mixer load error: %s\n", snd_strerror(err));
return;
}
/* Turn vol value to volume %.
* We do not want to soften that much with ALSA, espeak is already
* doing it. We want the default value (5) to be the usual default
* volume (80%), and make higher values increase ALSA volume, up to
* 100%. */
int volume = (vol+1) * 50 / 10 + 50;
for (e = snd_mixer_first_elem(m); e; e = snd_mixer_elem_next(e))
{
if (snd_mixer_elem_get_type(e) != SND_MIXER_ELEM_SIMPLE)
continue;
if (snd_mixer_selem_is_enumerated(e))
continue;
if (snd_mixer_selem_has_playback_switch(e)) {
snd_mixer_selem_set_playback_switch_all(e, 1);
}
if (snd_mixer_selem_has_playback_volume(e)) {
long min, max, set;
err = snd_mixer_selem_get_playback_dB_range(e, &min, &max);
if (err == 0 && min < max) {
if (max - min < 2400) {
/* 24dB amplitude is too small for using a logscale */
set = min + volume * (max-min) / 100;
} else {
/* Use a logscale */
double volf = volume / 100.;
if (min != SND_CTL_TLV_DB_GAIN_MUTE)
{
double minf = pow(10, (min-max) / 6000.);
volf = volf * (1 - minf) + minf;
}
set = 6000. * log10(volf) + max;
}
snd_mixer_selem_set_playback_dB_all(e, set, 0);
} else {
/* No dB setting, try a linear scale */
snd_mixer_selem_get_playback_volume_range(e, &min, &max);
set = min + volume * (max-min) / 100;
snd_mixer_selem_set_playback_volume_all(e, set);
}
}
}
}
static espeak_ERROR set_volume(struct synth_t *s, int vol,
enum adjust_t adj)
{
@ -164,7 +247,11 @@ static espeak_ERROR set_volume(struct synth_t *s, int vol,
rc = espeak_SetParameter(espeakVOLUME, (vol + 1) * volumeMultiplier,
0);
if (rc == EE_OK)
{
s->volume = vol;
if (alsaVolume)
set_alsa_volume(vol);
}
return rc;
}