mirror of
https://github.com/alsa-project/alsa-utils
synced 2024-11-09 17:55:43 +01:00
aplay: try to use 16-bit format to increase capture quality
Recently users reported a bug, I tested it and found it is a common issue on Laptop or Desktop machines. The issue is users plug a headset and use "arecord test.wav" to record a sound with default input volume, the recorded sound has poor quality and nearly can't distinguish it is the sound we want to record. This is because the input volume is low and the default format is U8. The driver records sound with 16bit, because the input volume is low, most of samples are within (-256,+256), when converting 16bit to U8, those samples will be 0x7f. This is called quantization noise and we could only workaround it by increase the input volume or adding -f to arecord. But users want to record a better quality sound with default input volume (after installing a new OS, the volume is the default volume), and they don't want to add parameters to the arecord because most of new linux users just use "arecord test.wav". So this patch tries to change the default format from U8 to S16_LE/BE. If the machine doesn't support S16_LE/BE, it still uses U8 as default format. Signed-off-by: Hui Wang <hui.wang@canonical.com> Signed-off-by: Jaroslav Kysela <perex@perex.cz>
This commit is contained in:
parent
b2ae0b0746
commit
0c5948e98a
1 changed files with 34 additions and 9 deletions
|
@ -32,6 +32,7 @@
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <stdbool.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
@ -94,6 +95,7 @@ enum {
|
||||||
VUMETER_STEREO
|
VUMETER_STEREO
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static snd_pcm_format_t default_format = DEFAULT_FORMAT;
|
||||||
static char *command;
|
static char *command;
|
||||||
static snd_pcm_t *handle;
|
static snd_pcm_t *handle;
|
||||||
static struct {
|
static struct {
|
||||||
|
@ -468,6 +470,24 @@ static long parse_long(const char *str, int *err)
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void try_to_adjust_default_format_16bit(void)
|
||||||
|
{
|
||||||
|
snd_pcm_hw_params_t *params;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
snd_pcm_hw_params_alloca(¶ms);
|
||||||
|
err = snd_pcm_hw_params_any(handle, params);
|
||||||
|
if (err < 0) {
|
||||||
|
error(_("Broken configuration for this PCM: no configurations available"));
|
||||||
|
prg_exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file_type != FORMAT_AU && snd_pcm_hw_params_test_format(handle, params, SND_PCM_FORMAT_S16_LE) == 0)
|
||||||
|
rhwparams.format = default_format = SND_PCM_FORMAT_S16_LE;
|
||||||
|
else if (file_type == FORMAT_AU && snd_pcm_hw_params_test_format(handle, params, SND_PCM_FORMAT_S16_BE) == 0)
|
||||||
|
rhwparams.format = default_format = SND_PCM_FORMAT_S16_BE;
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
int duration_or_sample = 0;
|
int duration_or_sample = 0;
|
||||||
|
@ -528,6 +548,7 @@ int main(int argc, char *argv[])
|
||||||
int do_device_list = 0, do_pcm_list = 0;
|
int do_device_list = 0, do_pcm_list = 0;
|
||||||
snd_pcm_info_t *info;
|
snd_pcm_info_t *info;
|
||||||
FILE *direction;
|
FILE *direction;
|
||||||
|
bool user_set_fmt = false;
|
||||||
|
|
||||||
#ifdef ENABLE_NLS
|
#ifdef ENABLE_NLS
|
||||||
setlocale(LC_ALL, "");
|
setlocale(LC_ALL, "");
|
||||||
|
@ -562,7 +583,7 @@ int main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
|
|
||||||
chunk_size = -1;
|
chunk_size = -1;
|
||||||
rhwparams.format = DEFAULT_FORMAT;
|
rhwparams.format = default_format;
|
||||||
rhwparams.rate = DEFAULT_SPEED;
|
rhwparams.rate = DEFAULT_SPEED;
|
||||||
rhwparams.channels = 1;
|
rhwparams.channels = 1;
|
||||||
|
|
||||||
|
@ -612,6 +633,7 @@ int main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'f':
|
case 'f':
|
||||||
|
user_set_fmt = true;
|
||||||
if (strcasecmp(optarg, "cd") == 0 || strcasecmp(optarg, "cdr") == 0) {
|
if (strcasecmp(optarg, "cd") == 0 || strcasecmp(optarg, "cdr") == 0) {
|
||||||
if (strcasecmp(optarg, "cdr") == 0)
|
if (strcasecmp(optarg, "cdr") == 0)
|
||||||
rhwparams.format = SND_PCM_FORMAT_S16_BE;
|
rhwparams.format = SND_PCM_FORMAT_S16_BE;
|
||||||
|
@ -844,6 +866,9 @@ int main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!user_set_fmt)
|
||||||
|
try_to_adjust_default_format_16bit();
|
||||||
|
|
||||||
chunk_size = 1024;
|
chunk_size = 1024;
|
||||||
hwparams = rhwparams;
|
hwparams = rhwparams;
|
||||||
|
|
||||||
|
@ -1064,7 +1089,7 @@ static ssize_t test_wavefile(int fd, u_char *_buffer, size_t size)
|
||||||
hwparams.channels = channels;
|
hwparams.channels = channels;
|
||||||
switch (TO_CPU_SHORT(f->bit_p_spl, big_endian)) {
|
switch (TO_CPU_SHORT(f->bit_p_spl, big_endian)) {
|
||||||
case 8:
|
case 8:
|
||||||
if (hwparams.format != DEFAULT_FORMAT &&
|
if (hwparams.format != default_format &&
|
||||||
hwparams.format != SND_PCM_FORMAT_U8)
|
hwparams.format != SND_PCM_FORMAT_U8)
|
||||||
fprintf(stderr, _("Warning: format is changed to U8\n"));
|
fprintf(stderr, _("Warning: format is changed to U8\n"));
|
||||||
hwparams.format = SND_PCM_FORMAT_U8;
|
hwparams.format = SND_PCM_FORMAT_U8;
|
||||||
|
@ -1074,7 +1099,7 @@ static ssize_t test_wavefile(int fd, u_char *_buffer, size_t size)
|
||||||
native_format = SND_PCM_FORMAT_S16_BE;
|
native_format = SND_PCM_FORMAT_S16_BE;
|
||||||
else
|
else
|
||||||
native_format = SND_PCM_FORMAT_S16_LE;
|
native_format = SND_PCM_FORMAT_S16_LE;
|
||||||
if (hwparams.format != DEFAULT_FORMAT &&
|
if (hwparams.format != default_format &&
|
||||||
hwparams.format != native_format)
|
hwparams.format != native_format)
|
||||||
fprintf(stderr, _("Warning: format is changed to %s\n"),
|
fprintf(stderr, _("Warning: format is changed to %s\n"),
|
||||||
snd_pcm_format_name(native_format));
|
snd_pcm_format_name(native_format));
|
||||||
|
@ -1087,7 +1112,7 @@ static ssize_t test_wavefile(int fd, u_char *_buffer, size_t size)
|
||||||
native_format = SND_PCM_FORMAT_S24_3BE;
|
native_format = SND_PCM_FORMAT_S24_3BE;
|
||||||
else
|
else
|
||||||
native_format = SND_PCM_FORMAT_S24_3LE;
|
native_format = SND_PCM_FORMAT_S24_3LE;
|
||||||
if (hwparams.format != DEFAULT_FORMAT &&
|
if (hwparams.format != default_format &&
|
||||||
hwparams.format != native_format)
|
hwparams.format != native_format)
|
||||||
fprintf(stderr, _("Warning: format is changed to %s\n"),
|
fprintf(stderr, _("Warning: format is changed to %s\n"),
|
||||||
snd_pcm_format_name(native_format));
|
snd_pcm_format_name(native_format));
|
||||||
|
@ -1098,7 +1123,7 @@ static ssize_t test_wavefile(int fd, u_char *_buffer, size_t size)
|
||||||
native_format = SND_PCM_FORMAT_S24_BE;
|
native_format = SND_PCM_FORMAT_S24_BE;
|
||||||
else
|
else
|
||||||
native_format = SND_PCM_FORMAT_S24_LE;
|
native_format = SND_PCM_FORMAT_S24_LE;
|
||||||
if (hwparams.format != DEFAULT_FORMAT &&
|
if (hwparams.format != default_format &&
|
||||||
hwparams.format != native_format)
|
hwparams.format != native_format)
|
||||||
fprintf(stderr, _("Warning: format is changed to %s\n"),
|
fprintf(stderr, _("Warning: format is changed to %s\n"),
|
||||||
snd_pcm_format_name(native_format));
|
snd_pcm_format_name(native_format));
|
||||||
|
@ -1184,19 +1209,19 @@ static int test_au(int fd, void *buffer)
|
||||||
pbrec_count = BE_INT(ap->data_size);
|
pbrec_count = BE_INT(ap->data_size);
|
||||||
switch (BE_INT(ap->encoding)) {
|
switch (BE_INT(ap->encoding)) {
|
||||||
case AU_FMT_ULAW:
|
case AU_FMT_ULAW:
|
||||||
if (hwparams.format != DEFAULT_FORMAT &&
|
if (hwparams.format != default_format &&
|
||||||
hwparams.format != SND_PCM_FORMAT_MU_LAW)
|
hwparams.format != SND_PCM_FORMAT_MU_LAW)
|
||||||
fprintf(stderr, _("Warning: format is changed to MU_LAW\n"));
|
fprintf(stderr, _("Warning: format is changed to MU_LAW\n"));
|
||||||
hwparams.format = SND_PCM_FORMAT_MU_LAW;
|
hwparams.format = SND_PCM_FORMAT_MU_LAW;
|
||||||
break;
|
break;
|
||||||
case AU_FMT_LIN8:
|
case AU_FMT_LIN8:
|
||||||
if (hwparams.format != DEFAULT_FORMAT &&
|
if (hwparams.format != default_format &&
|
||||||
hwparams.format != SND_PCM_FORMAT_U8)
|
hwparams.format != SND_PCM_FORMAT_U8)
|
||||||
fprintf(stderr, _("Warning: format is changed to U8\n"));
|
fprintf(stderr, _("Warning: format is changed to U8\n"));
|
||||||
hwparams.format = SND_PCM_FORMAT_U8;
|
hwparams.format = SND_PCM_FORMAT_U8;
|
||||||
break;
|
break;
|
||||||
case AU_FMT_LIN16:
|
case AU_FMT_LIN16:
|
||||||
if (hwparams.format != DEFAULT_FORMAT &&
|
if (hwparams.format != default_format &&
|
||||||
hwparams.format != SND_PCM_FORMAT_S16_BE)
|
hwparams.format != SND_PCM_FORMAT_S16_BE)
|
||||||
fprintf(stderr, _("Warning: format is changed to S16_BE\n"));
|
fprintf(stderr, _("Warning: format is changed to S16_BE\n"));
|
||||||
hwparams.format = SND_PCM_FORMAT_S16_BE;
|
hwparams.format = SND_PCM_FORMAT_S16_BE;
|
||||||
|
@ -2315,7 +2340,7 @@ static void voc_play(int fd, int ofs, char *name)
|
||||||
prg_exit(EXIT_FAILURE);
|
prg_exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hwparams.format = DEFAULT_FORMAT;
|
hwparams.format = default_format;
|
||||||
hwparams.channels = 1;
|
hwparams.channels = 1;
|
||||||
hwparams.rate = DEFAULT_SPEED;
|
hwparams.rate = DEFAULT_SPEED;
|
||||||
set_params();
|
set_params();
|
||||||
|
|
Loading…
Reference in a new issue