[alsa-devel] [PATCH 1/1] alsabat: rename to avoid naming conflict
han.lu at intel.com
han.lu at intel.com
Tue Jan 12 04:06:24 CET 2016
From: "Lu, Han" <han.lu at intel.com>
alsa-utils as well as bareos-bat (as well a some Bacula packages)
all contain a program called /usr/bin/bat, which causes conflicts on
various distributions ("basic audio tester" vs "bareos administration
tool"("bacula administration tool")).
Rename to avoid conflict.
Signed-off-by: Lu, Han <han.lu at intel.com>
diff --git a/.gitignore b/.gitignore
index 59633c9..822be08 100644
--- a/.gitignore
+++ b/.gitignore
@@ -24,6 +24,7 @@ ABOUT-NLS
*~
.deps
+alsabat/alsabat
alsactl/alsactl
alsactl/alsactl_init.7
alsactl/alsa-state.service
@@ -36,7 +37,6 @@ amixer/amixer
aplay/aplay
aplay/arecord
aplay/arecord.1
-bat/bat
iecset/iecset
seq/aconnect/aconnect
seq/aplaymidi/aplaymidi
diff --git a/Makefile.am b/Makefile.am
index 3d24b87..b996b8f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -18,8 +18,8 @@ SUBDIRS += aplay iecset speaker-test
if ALSALOOP
SUBDIRS += alsaloop
endif
-if BAT
-SUBDIRS += bat
+if ALSABAT
+SUBDIRS += alsabat
endif
endif
if HAVE_SEQ
diff --git a/alsabat/Makefile.am b/alsabat/Makefile.am
new file mode 100644
index 0000000..ab56c19
--- /dev/null
+++ b/alsabat/Makefile.am
@@ -0,0 +1,24 @@
+bin_PROGRAMS = alsabat
+man_MANS = alsabat.1
+
+EXTRA_DIST = alsabat.1
+
+alsabat_SOURCES = \
+ alsabat.c \
+ common.c \
+ analyze.c \
+ signal.c \
+ convert.c \
+ alsa.c
+
+noinst_HEADERS = \
+ common.h \
+ bat-signal.h \
+ alsa.h \
+ convert.h \
+ analyze.h
+
+AM_CPPFLAGS = \
+ -Wall -I$(top_srcdir)/include
+
+alsabat_LDADD = @FFTW_LIB@
diff --git a/alsabat/alsa.c b/alsabat/alsa.c
new file mode 100644
index 0000000..5eaa25b
--- /dev/null
+++ b/alsabat/alsa.c
@@ -0,0 +1,604 @@
+/*
+ * Copyright (C) 2013-2015 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdbool.h>
+#include <math.h>
+#include <stdint.h>
+#include <pthread.h>
+
+#include <alsa/asoundlib.h>
+
+#include "aconfig.h"
+#include "gettext.h"
+
+#include "common.h"
+#include "alsa.h"
+#include "bat-signal.h"
+
+struct pcm_container {
+ snd_pcm_t *handle;
+ snd_pcm_uframes_t period_size;
+ snd_pcm_uframes_t buffer_size;
+ snd_pcm_format_t format;
+ unsigned short channels;
+ size_t period_bytes;
+ size_t sample_bits;
+ size_t frame_bits;
+ char *buffer;
+};
+
+static int set_snd_pcm_params(struct bat *bat, struct pcm_container *sndpcm)
+{
+ snd_pcm_hw_params_t *params;
+ unsigned int buffer_time = 0;
+ unsigned int period_time = 0;
+ unsigned int rate;
+ int err;
+ const char *device_name = snd_pcm_name(sndpcm->handle);
+
+ /* Allocate a hardware parameters object. */
+ snd_pcm_hw_params_alloca(¶ms);
+
+ /* Fill it in with default values. */
+ err = snd_pcm_hw_params_any(sndpcm->handle, params);
+ if (err < 0) {
+ fprintf(bat->err, _("Set parameter to device error: "));
+ fprintf(bat->err, _("default params: %s: %s(%d)\n"),
+ device_name, snd_strerror(err), err);
+ return err;
+ }
+
+ /* Set access mode */
+ err = snd_pcm_hw_params_set_access(sndpcm->handle, params,
+ SND_PCM_ACCESS_RW_INTERLEAVED);
+ if (err < 0) {
+ fprintf(bat->err, _("Set parameter to device error: "));
+ fprintf(bat->err, _("access type: %s: %s(%d)\n"),
+ device_name, snd_strerror(err), err);
+ return err;
+ }
+
+ /* Set format */
+ err = snd_pcm_hw_params_set_format(sndpcm->handle, params, bat->format);
+ if (err < 0) {
+ fprintf(bat->err, _("Set parameter to device error: "));
+ fprintf(bat->err, _("PCM format: %d %s: %s(%d)\n"),
+ bat->format,
+ device_name, snd_strerror(err), err);
+ return err;
+ }
+
+ /* Set channels */
+ err = snd_pcm_hw_params_set_channels(sndpcm->handle,
+ params, bat->channels);
+ if (err < 0) {
+ fprintf(bat->err, _("Set parameter to device error: "));
+ fprintf(bat->err, _("channel number: %d %s: %s(%d)\n"),
+ bat->channels,
+ device_name, snd_strerror(err), err);
+ return err;
+ }
+
+ /* Set sampling rate */
+ rate = bat->rate;
+ err = snd_pcm_hw_params_set_rate_near(sndpcm->handle,
+ params, &bat->rate,
+ 0);
+ if (err < 0) {
+ fprintf(bat->err, _("Set parameter to device error: "));
+ fprintf(bat->err, _("sample rate: %d %s: %s(%d)\n"),
+ bat->rate,
+ device_name, snd_strerror(err), err);
+ return err;
+ }
+ if ((float) rate * (1 + RATE_RANGE) < bat->rate
+ || (float) rate * (1 - RATE_RANGE) > bat->rate) {
+ fprintf(bat->err, _("Invalid parameters: sample rate: "));
+ fprintf(bat->err, _("requested %dHz, got %dHz\n"),
+ rate, bat->rate);
+ return -EINVAL;
+ }
+
+ if (snd_pcm_hw_params_get_buffer_time_max(params,
+ &buffer_time, 0) < 0) {
+ fprintf(bat->err, _("Get parameter from device error: "));
+ fprintf(bat->err, _("buffer time: %d %s: %s(%d)\n"),
+ buffer_time,
+ device_name, snd_strerror(err), err);
+ return -EINVAL;
+ }
+
+ if (buffer_time > MAX_BUFFERTIME)
+ buffer_time = MAX_BUFFERTIME;
+
+ period_time = buffer_time / DIV_BUFFERTIME;
+
+ /* Set buffer time and period time */
+ err = snd_pcm_hw_params_set_buffer_time_near(sndpcm->handle, params,
+ &buffer_time, 0);
+ if (err < 0) {
+ fprintf(bat->err, _("Set parameter to device error: "));
+ fprintf(bat->err, _("buffer time: %d %s: %s(%d)\n"),
+ buffer_time,
+ device_name, snd_strerror(err), err);
+ return err;
+ }
+
+ err = snd_pcm_hw_params_set_period_time_near(sndpcm->handle, params,
+ &period_time, 0);
+ if (err < 0) {
+ fprintf(bat->err, _("Set parameter to device error: "));
+ fprintf(bat->err, _("period time: %d %s: %s(%d)\n"),
+ period_time,
+ device_name, snd_strerror(err), err);
+ return err;
+ }
+
+ /* Write the parameters to the driver */
+ if (snd_pcm_hw_params(sndpcm->handle, params) < 0) {
+ fprintf(bat->err, _("Set parameter to device error: "));
+ fprintf(bat->err, _("hw params: %s: %s(%d)\n"),
+ device_name, snd_strerror(err), err);
+ return -EINVAL;
+ }
+
+ err = snd_pcm_hw_params_get_period_size(params,
+ &sndpcm->period_size, 0);
+ if (err < 0) {
+ fprintf(bat->err, _("Get parameter from device error: "));
+ fprintf(bat->err, _("period size: %zd %s: %s(%d)\n"),
+ sndpcm->period_size,
+ device_name, snd_strerror(err), err);
+ return err;
+ }
+
+ err = snd_pcm_hw_params_get_buffer_size(params, &sndpcm->buffer_size);
+ if (err < 0) {
+ fprintf(bat->err, _("Get parameter from device error: "));
+ fprintf(bat->err, _("buffer size: %zd %s: %s(%d)\n"),
+ sndpcm->buffer_size,
+ device_name, snd_strerror(err), err);
+ return err;
+ }
+
+ if (sndpcm->period_size == sndpcm->buffer_size) {
+ fprintf(bat->err, _("Invalid parameters: can't use period "));
+ fprintf(bat->err, _("equal to buffer size (%zd)\n"),
+ sndpcm->period_size);
+ return -EINVAL;
+ }
+
+ err = snd_pcm_format_physical_width(bat->format);
+ if (err < 0) {
+ fprintf(bat->err, _("Invalid parameters: "));
+ fprintf(bat->err, _("snd_pcm_format_physical_width: %d\n"),
+ err);
+ return err;
+ }
+ sndpcm->sample_bits = err;
+
+ sndpcm->frame_bits = sndpcm->sample_bits * bat->channels;
+
+ /* Calculate the period bytes */
+ sndpcm->period_bytes = sndpcm->period_size * sndpcm->frame_bits / 8;
+ sndpcm->buffer = (char *) malloc(sndpcm->period_bytes);
+ if (sndpcm->buffer == NULL) {
+ fprintf(bat->err, _("Not enough memory: size=%zd\n"),
+ sndpcm->period_bytes);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+/*
+ * Generate buffer to be played either from input file or from generated data
+ * Return value
+ * <0 error
+ * 0 ok
+ * >0 break
+ */
+static int generate_input_data(struct pcm_container *sndpcm, int bytes,
+ struct bat *bat)
+{
+ int err;
+ static int load;
+ int frames = bytes * 8 / sndpcm->frame_bits;
+
+ if (bat->playback.file != NULL) {
+ /* From input file */
+ load = 0;
+
+ while (1) {
+ err = fread(sndpcm->buffer + load, 1,
+ bytes - load, bat->fp);
+ if (0 == err) {
+ if (feof(bat->fp)) {
+ fprintf(bat->log,
+ _("End of playing.\n"));
+ return 1;
+ }
+ } else if (err < bytes - load) {
+ if (ferror(bat->fp)) {
+ fprintf(bat->err, _("Read file error"));
+ fprintf(bat->err, _(": %d\n"), err);
+ return -EIO;
+ }
+ load += err;
+ } else {
+ break;
+ }
+ }
+ } else {
+ /* Generate sine wave */
+ if ((bat->sinus_duration) && (load > bat->sinus_duration))
+ return 1;
+
+ err = generate_sine_wave(bat, frames, (void *)sndpcm->buffer);
+ if (err != 0)
+ return err;
+
+ load += frames;
+ }
+
+ return 0;
+}
+
+static int write_to_pcm(const struct pcm_container *sndpcm,
+ int frames, struct bat *bat)
+{
+ int err;
+ int offset = 0;
+ int remain = frames;
+
+ while (remain > 0) {
+ err = snd_pcm_writei(sndpcm->handle, sndpcm->buffer + offset,
+ remain);
+ if (err == -EAGAIN || (err >= 0 && err < frames)) {
+ snd_pcm_wait(sndpcm->handle, 500);
+ } else if (err == -EPIPE) {
+ fprintf(bat->err, _("Underrun: %s(%d)\n"),
+ snd_strerror(err), err);
+ snd_pcm_prepare(sndpcm->handle);
+ } else if (err < 0) {
+ fprintf(bat->err, _("Write PCM device error: %s(%d)\n"),
+ snd_strerror(err), err);
+ return err;
+ }
+
+ if (err > 0) {
+ remain -= err;
+ offset += err * sndpcm->frame_bits / 8;
+ }
+ }
+
+ return 0;
+}
+
+static int write_to_pcm_loop(struct pcm_container *sndpcm, struct bat *bat)
+{
+ int err;
+ int bytes = sndpcm->period_bytes; /* playback buffer size */
+ int frames = bytes * 8 / sndpcm->frame_bits; /* frame count */
+ FILE *fp = NULL;
+ struct wav_container wav;
+ int bytes_total = 0;
+
+ if (bat->debugplay) {
+ fp = fopen(bat->debugplay, "wb");
+ if (fp == NULL) {
+ fprintf(bat->err, _("Cannot open file for capture: "));
+ fprintf(bat->err, _("%s %d\n"), bat->debugplay, -errno);
+ return -errno;
+ }
+ /* leave space for wav header */
+ err = fseek(fp, sizeof(wav), SEEK_SET);
+ if (err != 0) {
+ fprintf(bat->err, _("Seek file error: %d %d\n"),
+ err, -errno);
+ return -errno;
+ }
+ }
+
+ while (1) {
+ err = generate_input_data(sndpcm, bytes, bat);
+ if (err < 0)
+ return err;
+ else if (err > 0)
+ break;
+
+ if (bat->debugplay) {
+ err = fwrite(sndpcm->buffer, 1, bytes, fp);
+ if (err != bytes) {
+ fprintf(bat->err, _("Write file error: "));
+ fprintf(bat->err, _("%s(%d)\n"),
+ snd_strerror(err), err);
+ return -EIO;
+ }
+ bytes_total += bytes;
+ }
+
+ bat->periods_played++;
+ if (bat->period_is_limited
+ && bat->periods_played >= bat->periods_total)
+ break;
+
+ err = write_to_pcm(sndpcm, frames, bat);
+ if (err != 0)
+ return err;
+ }
+
+ if (bat->debugplay) {
+ /* update wav header */
+ prepare_wav_info(&wav, bat);
+ wav.chunk.length = bytes_total;
+ wav.header.length = (wav.chunk.length) + sizeof(wav.chunk)
+ + sizeof(wav.format) + sizeof(wav.header) - 8;
+
+ rewind(fp);
+ err = write_wav_header(fp, &wav, bat);
+ if (err != 0) {
+ fprintf(bat->err, _("Write file error: %s %s(%d)\n"),
+ bat->debugplay, snd_strerror(err), err);
+ return err;
+ }
+ fclose(fp);
+ }
+
+ snd_pcm_drain(sndpcm->handle);
+
+ return 0;
+}
+
+/**
+ * Play
+ */
+void *playback_alsa(struct bat *bat)
+{
+ int err = 0;
+ struct pcm_container sndpcm;
+
+ fprintf(bat->log, _("Entering playback thread (ALSA).\n"));
+
+ retval_play = 0;
+ memset(&sndpcm, 0, sizeof(sndpcm));
+
+ if (bat->playback.device == NULL) {
+ fprintf(bat->err, _("No PCM device for playback: exit\n"));
+ retval_play = 1;
+ goto exit1;
+ }
+
+ err = snd_pcm_open(&sndpcm.handle, bat->playback.device,
+ SND_PCM_STREAM_PLAYBACK, 0);
+ if (err != 0) {
+ fprintf(bat->err, _("Cannot open PCM playback device: "));
+ fprintf(bat->err, _("%s(%d)\n"), snd_strerror(err), err);
+ retval_play = 1;
+ goto exit1;
+ }
+
+ err = set_snd_pcm_params(bat, &sndpcm);
+ if (err != 0) {
+ retval_play = 1;
+ goto exit2;
+ }
+
+ if (bat->playback.file == NULL) {
+ fprintf(bat->log, _("Playing generated audio sine wave"));
+ bat->sinus_duration == 0 ?
+ fprintf(bat->log, _(" endlessly\n")) :
+ fprintf(bat->log, _("\n"));
+ } else {
+ fprintf(bat->log, _("Playing input audio file: %s\n"),
+ bat->playback.file);
+ bat->fp = fopen(bat->playback.file, "rb");
+ if (bat->fp == NULL) {
+ fprintf(bat->err, _("Cannot open file for capture: "));
+ fprintf(bat->err, _("%s %d\n"),
+ bat->playback.file, -errno);
+ retval_play = 1;
+ goto exit3;
+ }
+ /* Skip header */
+ err = read_wav_header(bat, bat->playback.file, bat->fp, true);
+ if (err != 0) {
+ retval_play = 1;
+ goto exit4;
+ }
+ }
+
+ err = write_to_pcm_loop(&sndpcm, bat);
+ if (err != 0) {
+ retval_play = 1;
+ goto exit4;
+ }
+
+exit4:
+ if (bat->playback.file)
+ fclose(bat->fp);
+exit3:
+ free(sndpcm.buffer);
+exit2:
+ snd_pcm_close(sndpcm.handle);
+exit1:
+ pthread_exit(&retval_play);
+}
+
+static int read_from_pcm(struct pcm_container *sndpcm,
+ int frames, struct bat *bat)
+{
+ int err = 0;
+ int offset = 0;
+ int remain = frames;
+
+ while (remain > 0) {
+ err = snd_pcm_readi(sndpcm->handle,
+ sndpcm->buffer + offset, remain);
+ if (err == -EAGAIN || (err >= 0 && err < remain)) {
+ snd_pcm_wait(sndpcm->handle, 500);
+ } else if (err == -EPIPE) {
+ snd_pcm_prepare(sndpcm->handle);
+ fprintf(bat->err, _("Overrun: %s(%d)\n"),
+ snd_strerror(err), err);
+ } else if (err < 0) {
+ fprintf(bat->err, _("Read PCM device error: %s(%d)\n"),
+ snd_strerror(err), err);
+ return err;
+ }
+
+ if (err > 0) {
+ remain -= err;
+ offset += err * sndpcm->frame_bits / 8;
+ }
+ }
+
+ return 0;
+}
+
+static int read_from_pcm_loop(FILE *fp, int count,
+ struct pcm_container *sndpcm, struct bat *bat)
+{
+ int err = 0;
+ int size, frames;
+ int remain = count;
+
+ while (remain > 0) {
+ size = (remain <= sndpcm->period_bytes) ?
+ remain : sndpcm->period_bytes;
+ frames = size * 8 / sndpcm->frame_bits;
+
+ /* read a chunk from pcm device */
+ err = read_from_pcm(sndpcm, frames, bat);
+ if (err != 0)
+ return err;
+
+ /* write the chunk to file */
+ err = fwrite(sndpcm->buffer, 1, size, fp);
+ if (err != size) {
+ fprintf(bat->err, _("Write file error: %s(%d)\n"),
+ snd_strerror(err), err);
+ return -EIO;
+ }
+ remain -= size;
+ bat->periods_played++;
+
+ if (bat->period_is_limited
+ && bat->periods_played >= bat->periods_total)
+ break;
+ }
+
+ return 0;
+}
+
+static void pcm_cleanup(void *p)
+{
+ snd_pcm_close(p);
+}
+
+static void file_cleanup(void *p)
+{
+ fclose(p);
+}
+
+/**
+ * Record
+ */
+void *record_alsa(struct bat *bat)
+{
+ int err = 0;
+ FILE *fp = NULL;
+ struct pcm_container sndpcm;
+ struct wav_container wav;
+ int count;
+
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
+
+ fprintf(bat->log, _("Entering capture thread (ALSA).\n"));
+
+ retval_record = 0;
+ memset(&sndpcm, 0, sizeof(sndpcm));
+
+ if (bat->capture.device == NULL) {
+ fprintf(bat->err, _("No PCM device for capture: exit\n"));
+ retval_record = 1;
+ goto exit1;
+ }
+
+ err = snd_pcm_open(&sndpcm.handle, bat->capture.device,
+ SND_PCM_STREAM_CAPTURE, 0);
+ if (err != 0) {
+ fprintf(bat->err, _("Cannot open PCM capture device: "));
+ fprintf(bat->err, _("%s(%d)\n"), snd_strerror(err), err);
+ retval_record = 1;
+ goto exit1;
+ }
+
+ err = set_snd_pcm_params(bat, &sndpcm);
+ if (err != 0) {
+ retval_record = 1;
+ goto exit2;
+ }
+
+ remove(bat->capture.file);
+ fp = fopen(bat->capture.file, "w+");
+ if (fp == NULL) {
+ fprintf(bat->err, _("Cannot open file for capture: %s %d\n"),
+ bat->capture.file, -errno);
+ retval_record = 1;
+ goto exit3;
+ }
+
+ prepare_wav_info(&wav, bat);
+
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+ pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
+ pthread_cleanup_push(pcm_cleanup, sndpcm.handle);
+ pthread_cleanup_push(free, sndpcm.buffer);
+ pthread_cleanup_push(file_cleanup, fp);
+
+ err = write_wav_header(fp, &wav, bat);
+ if (err != 0) {
+ retval_record = 1;
+ goto exit4;
+ }
+
+ count = wav.chunk.length;
+ fprintf(bat->log, _("Recording ...\n"));
+ err = read_from_pcm_loop(fp, count, &sndpcm, bat);
+ if (err != 0) {
+ retval_record = 1;
+ goto exit4;
+ }
+
+ /* Normally we will never reach this part of code (before fail_exit) as
+ this thread will be cancelled by end of play thread. */
+ pthread_cleanup_pop(0);
+ pthread_cleanup_pop(0);
+ pthread_cleanup_pop(0);
+
+ snd_pcm_drain(sndpcm.handle);
+
+exit4:
+ fclose(fp);
+exit3:
+ free(sndpcm.buffer);
+exit2:
+ snd_pcm_close(sndpcm.handle);
+exit1:
+ pthread_exit(&retval_record);
+}
diff --git a/alsabat/alsa.h b/alsabat/alsa.h
new file mode 100644
index 0000000..d5c9972
--- /dev/null
+++ b/alsabat/alsa.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2013-2015 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+extern int retval_play;
+extern int retval_record;
+
+void *playback_alsa(struct bat *);
+void *record_alsa(struct bat *);
diff --git a/alsabat/alsabat.1 b/alsabat/alsabat.1
new file mode 100644
index 0000000..93df210
--- /dev/null
+++ b/alsabat/alsabat.1
@@ -0,0 +1,159 @@
+.TH ALSABAT 1 "20th October 2015"
+.SH NAME
+alsabat \- command\-line sound tester for ALSA sound card driver
+
+.SH SYNOPSIS
+\fBalsabat\fP [\fIflags\fP]
+
+.SH DESCRIPTION
+\fBALSABAT(ALSA Basic Audio Tester)\fP is a simple command\-line utility
+intended to help automate audio driver and sound server testing with little
+human interaction. ALSABAT can be used to test audio quality, stress test
+features and test audio before and after PM state changes.
+
+ALSABAT's design is relatively simple. ALSABAT plays an audio stream and
+captures the same stream in either a digital or analog loop back. It then
+compares the captured stream using a FFT to the original to determine if
+the test case passes or fails.
+
+ALSABAT can either run wholly on the target machine being tested (standalone
+mode) or can run as a client/server mode where by bat client runs on the
+target and runs as a server on a separate tester machine. The client/server
+mode still requires some manual interaction for synchronization, but this
+is actively being developed for future releases.
+
+The hardware testing configuration may require the use of an analog cable
+connecting target to tester machines or a cable to create an analog
+loopback if no loopback mode is not available on the sound hardware that
+is being tested.
+An analog loopback cable can be used to connect the "line in" to "line out"
+jacks to create a loopback. If only headphone and mic jacks (or combo jack)
+are available then the following simple circuit can be used to create an
+analog loopback :-
+
+https://source.android.com/devices/audio/loopback.html
+
+.SH OPTIONS
+.TP
+\fI\-h, \-\-help\fP
+Help: show syntax.
+.TP
+\fI\-D\fP
+Select sound card to be tested by name.
+.TP
+\fI\-P\fP
+Select the playback PCM device.
+.TP
+\fI\-C\fP
+Select the capture PCM device.
+.TP
+\fI\-f\fP
+Sample format
+.br
+Recognized sample formats are: U8 S16_LE S24_3LE S32_LE
+.br
+Some of these may not be available on selected hardware
+.br
+The available format shortcuts are:
+.nf
+\-f cd (16 bit little endian, 44100, stereo) [\-f S16_LE \-c2 \-r44100]
+\-f dat (16 bit little endian, 48000, stereo) [\-f S16_LE \-c2 \-r48000]
+.fi
+If no format is given S16_LE is used.
+.TP
+\fI\-c\fP
+The number of channels. The default is one channel.
+Valid values at the moment are 1 or 2.
+.TP
+\fI\-r\fP
+Sampling rate in Hertz. The default rate is 44100 Hertz.
+Valid values depends on hardware support.
+.TP
+\fI\-n\fP
+Duration of generated signal.
+The value could be either of the two forms:
+.br
+1. Decimal integer, means number of frames;
+.br
+2. Floating point with suffix 's', means number of seconds.
+.br
+The default is 2 seconds.
+.TP
+\fI\-k\fP
+Sigma k value for analysis.
+.br
+The analysis function reads data from WAV file, run FFT against the data
+to get magnitude of frequency vectors, and then calculates the average
+value and standard deviation of frequency vectors. After that, we define
+a threshold:
+.br
+threshold = k * standard_deviation + mean_value
+.br
+Frequencies with amplitude larger than threshold will be recognized as a
+peak, and the frequency with largest peak value will be recognized as a
+detected frequency.
+.br
+ALSABAT then compares the detected frequency to target frequency, to decide
+if the detecting passes or fails.
+.br
+The default value is 3.0.
+.TP
+\fI\-F\fP
+Target frequency for signal generation and analysis, in Hertz.
+The default is 997.0 Hertz.
+Valid range is (DC_THRESHOLD, 40% * Sampling rate).
+.TP
+\fI\-p\fP
+Total number of periods to play or capture.
+.TP
+\fI\-\-log=#\fP
+Write stderr and stdout output to this log file.
+.TP
+\fI\-\-file=#\fP
+Input WAV file for playback.
+.TP
+\fI\-\-saveplay=#\fP
+Target WAV file to save capture test content.
+.TP
+\fI\-\-local\fP
+Internal loopback mode.
+Playback, capture and analysis internal to ALSABAT only. This is intended for
+developers to test new ALSABAT features as no audio is routed outside of
+ALSABAT.
+
+.SH EXAMPLES
+
+.TP
+\fBbat \-P plughw:0,0 \-C plughw:0,0 \-c 2 \-f S32_LE \-F 250\fR
+Generate and play a sine wave of 250 Hertz with 2 channel and S32_LE format,
+and then capture and analyze.
+
+.TP
+\fBbat \-P plughw:0,0 \-C plughw:0,0 \-\-file 500Hz.wav\fR
+Play the RIFF WAV file "500Hz.wav" which contains 500 Hertz waveform LPCM
+data, and then capture and analyze.
+
+.SH RETURN VALUE
+.br
+On success, returns 0.
+.br
+If no peak be detected, returns -1001;
+.br
+If only DC be detected, returns -1002;
+.br
+If peak frequency does not match with the target frequency, returns -1003.
+
+.SH SEE ALSO
+\fB
+aplay(1)
+\fP
+
+.SH BUGS
+Currently only support RIFF WAV format with PCM data. Please report any bugs to
+the alsa-devel mailing list.
+
+.SH AUTHOR
+\fBbat\fP is by Liam Girdwood <liam.r.girdwood at linux.intel.com>, Bernard Gautier
+<bernard.gautier at intel.com> and Han Lu <han.lu at intel.com>.
+This document is by Liam Girdwood <liam.r.girdwood at linux.intel.com> and Han Lu
+<han.lu at intel.com>.
diff --git a/alsabat/alsabat.c b/alsabat/alsabat.c
new file mode 100644
index 0000000..ddb60b7
--- /dev/null
+++ b/alsabat/alsabat.c
@@ -0,0 +1,610 @@
+/*
+ * Copyright (C) 2013-2015 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <errno.h>
+#include <pthread.h>
+#include <getopt.h>
+#include <math.h>
+#include <limits.h>
+#include <locale.h>
+
+#include "aconfig.h"
+#include "gettext.h"
+#include "version.h"
+
+#include "common.h"
+
+#include "alsa.h"
+#include "convert.h"
+#include "analyze.h"
+
+static int get_duration(struct bat *bat)
+{
+ float duration_f;
+ long duration_i;
+ char *ptrf, *ptri;
+
+ duration_f = strtof(bat->narg, &ptrf);
+ if (duration_f == HUGE_VALF || duration_f == -HUGE_VALF
+ || (duration_f == 0.0 && errno != 0))
+ goto err_exit;
+
+ duration_i = strtol(bat->narg, &ptri, 10);
+ if (duration_i == LONG_MAX || duration_i == LONG_MIN)
+ goto err_exit;
+
+ if (*ptrf == 's')
+ bat->frames = duration_f * bat->rate;
+ else if (*ptri == 0)
+ bat->frames = duration_i;
+ else
+ bat->frames = -1;
+
+ if (bat->frames <= 0 || bat->frames > MAX_FRAMES) {
+ fprintf(bat->err, _("Invalid duration. Range: (0, %d(%fs))\n"),
+ MAX_FRAMES, (double)MAX_FRAMES / bat->rate);
+ return -EINVAL;
+ }
+
+ return 0;
+
+err_exit:
+ fprintf(bat->err, _("Duration overflow/underflow: %d\n"), -errno);
+
+ return -errno;
+}
+
+static void get_sine_frequencies(struct bat *bat, char *freq)
+{
+ char *tmp1;
+
+ tmp1 = strchr(freq, ':');
+ if (tmp1 == NULL) {
+ bat->target_freq[1] = bat->target_freq[0] = atof(optarg);
+ } else {
+ *tmp1 = '\0';
+ bat->target_freq[0] = atof(optarg);
+ bat->target_freq[1] = atof(tmp1 + 1);
+ }
+}
+
+static void get_format(struct bat *bat, char *optarg)
+{
+ if (strcasecmp(optarg, "cd") == 0) {
+ bat->format = SND_PCM_FORMAT_S16_LE;
+ bat->rate = 44100;
+ bat->channels = 2;
+ } else if (strcasecmp(optarg, "dat") == 0) {
+ bat->format = SND_PCM_FORMAT_S16_LE;
+ bat->rate = 48000;
+ bat->channels = 2;
+ } else {
+ bat->format = snd_pcm_format_value(optarg);
+ if (bat->format == SND_PCM_FORMAT_UNKNOWN) {
+ fprintf(bat->err, _("wrong extended format '%s'\n"),
+ optarg);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ switch (bat->format) {
+ case SND_PCM_FORMAT_U8:
+ bat->sample_size = 1;
+ break;
+ case SND_PCM_FORMAT_S16_LE:
+ bat->sample_size = 2;
+ break;
+ case SND_PCM_FORMAT_S24_3LE:
+ bat->sample_size = 3;
+ break;
+ case SND_PCM_FORMAT_S32_LE:
+ bat->sample_size = 4;
+ break;
+ default:
+ fprintf(bat->err, _("unsupported format: %d\n"), bat->format);
+ exit(EXIT_FAILURE);
+ }
+}
+
+static inline int thread_wait_completion(struct bat *bat,
+ pthread_t id, int **val)
+{
+ int err;
+
+ err = pthread_join(id, (void **) val);
+ if (err)
+ pthread_cancel(id);
+
+ return err;
+}
+
+/* loopback test where we play sine wave and capture the same sine wave */
+static void test_loopback(struct bat *bat)
+{
+ pthread_t capture_id, playback_id;
+ int err;
+ int *thread_result_capture, *thread_result_playback;
+
+ /* start playback */
+ err = pthread_create(&playback_id, NULL,
+ (void *) bat->playback.fct, bat);
+ if (err != 0) {
+ fprintf(bat->err, _("Cannot create playback thread: %d\n"),
+ err);
+ exit(EXIT_FAILURE);
+ }
+
+ /* TODO: use a pipe to signal stream start etc - i.e. to sync threads */
+ /* Let some time for playing something before capturing */
+ usleep(CAPTURE_DELAY * 1000);
+
+ /* start capture */
+ err = pthread_create(&capture_id, NULL, (void *) bat->capture.fct, bat);
+ if (err != 0) {
+ fprintf(bat->err, _("Cannot create capture thread: %d\n"), err);
+ pthread_cancel(playback_id);
+ exit(EXIT_FAILURE);
+ }
+
+ /* wait for playback to complete */
+ err = thread_wait_completion(bat, playback_id, &thread_result_playback);
+ if (err != 0) {
+ fprintf(bat->err, _("Cannot join playback thread: %d\n"), err);
+ free(thread_result_playback);
+ pthread_cancel(capture_id);
+ exit(EXIT_FAILURE);
+ }
+
+ /* check playback status */
+ if (*thread_result_playback != 0) {
+ fprintf(bat->err, _("Exit playback thread fail: %d\n"),
+ *thread_result_playback);
+ pthread_cancel(capture_id);
+ exit(EXIT_FAILURE);
+ } else {
+ fprintf(bat->log, _("Playback completed.\n"));
+ }
+
+ /* now stop and wait for capture to finish */
+ pthread_cancel(capture_id);
+ err = thread_wait_completion(bat, capture_id, &thread_result_capture);
+ if (err != 0) {
+ fprintf(bat->err, _("Cannot join capture thread: %d\n"), err);
+ free(thread_result_capture);
+ exit(EXIT_FAILURE);
+ }
+
+ /* check capture status */
+ if (*thread_result_capture != 0) {
+ fprintf(bat->err, _("Exit capture thread fail: %d\n"),
+ *thread_result_capture);
+ exit(EXIT_FAILURE);
+ } else {
+ fprintf(bat->log, _("Capture completed.\n"));
+ }
+}
+
+/* single ended playback only test */
+static void test_playback(struct bat *bat)
+{
+ pthread_t playback_id;
+ int err;
+ int *thread_result;
+
+ /* start playback */
+ err = pthread_create(&playback_id, NULL,
+ (void *) bat->playback.fct, bat);
+ if (err != 0) {
+ fprintf(bat->err, _("Cannot create playback thread: %d\n"),
+ err);
+ exit(EXIT_FAILURE);
+ }
+
+ /* wait for playback to complete */
+ err = thread_wait_completion(bat, playback_id, &thread_result);
+ if (err != 0) {
+ fprintf(bat->err, _("Cannot join playback thread: %d\n"), err);
+ free(thread_result);
+ exit(EXIT_FAILURE);
+ }
+
+ /* check playback status */
+ if (*thread_result != 0) {
+ fprintf(bat->err, _("Exit playback thread fail: %d\n"),
+ *thread_result);
+ exit(EXIT_FAILURE);
+ } else {
+ fprintf(bat->log, _("Playback completed.\n"));
+ }
+}
+
+/* single ended capture only test */
+static void test_capture(struct bat *bat)
+{
+ pthread_t capture_id;
+ int err;
+ int *thread_result;
+
+ /* start capture */
+ err = pthread_create(&capture_id, NULL, (void *) bat->capture.fct, bat);
+ if (err != 0) {
+ fprintf(bat->err, _("Cannot create capture thread: %d\n"), err);
+ exit(EXIT_FAILURE);
+ }
+
+ /* TODO: stop capture */
+
+ /* wait for capture to complete */
+ err = thread_wait_completion(bat, capture_id, &thread_result);
+ if (err != 0) {
+ fprintf(bat->err, _("Cannot join capture thread: %d\n"), err);
+ free(thread_result);
+ exit(EXIT_FAILURE);
+ }
+
+ /* check playback status */
+ if (*thread_result != 0) {
+ fprintf(bat->err, _("Exit capture thread fail: %d\n"),
+ *thread_result);
+ exit(EXIT_FAILURE);
+ } else {
+ fprintf(bat->log, _("Capture completed.\n"));
+ }
+}
+
+static void usage(struct bat *bat)
+{
+ fprintf(bat->log,
+_("Usage: alsabat [-options]...\n"
+"\n"
+" -h, --help this help\n"
+" -D pcm device for both playback and capture\n"
+" -P pcm device for playback\n"
+" -C pcm device for capture\n"
+" -f sample format\n"
+" -c number of channels\n"
+" -r sampling rate\n"
+" -n frames to playback or capture\n"
+" -k parameter for frequency detecting threshold\n"
+" -F target frequency\n"
+" -p total number of periods to play/capture\n"
+" --log=# file that both stdout and strerr redirecting to\n"
+" --file=# file for playback\n"
+" --saveplay=# file that storing playback content, for debug\n"
+" --local internal loop, set to bypass pcm hardware devices\n"
+));
+ fprintf(bat->log, _("Recognized sample formats are: %s %s %s %s\n"),
+ snd_pcm_format_name(SND_PCM_FORMAT_U8),
+ snd_pcm_format_name(SND_PCM_FORMAT_S16_LE),
+ snd_pcm_format_name(SND_PCM_FORMAT_S24_3LE),
+ snd_pcm_format_name(SND_PCM_FORMAT_S32_LE));
+ fprintf(bat->log, _("The available format shotcuts are:\n"));
+ fprintf(bat->log, _("-f cd (16 bit little endian, 44100, stereo)\n"));
+ fprintf(bat->log, _("-f dat (16 bit little endian, 48000, stereo)\n"));
+}
+
+static void set_defaults(struct bat *bat)
+{
+ memset(bat, 0, sizeof(struct bat));
+
+ /* Set default values */
+ bat->rate = 44100;
+ bat->channels = 1;
+ bat->frame_size = 2;
+ bat->sample_size = 2;
+ bat->format = SND_PCM_FORMAT_S16_LE;
+ bat->convert_float_to_sample = convert_float_to_int16;
+ bat->convert_sample_to_double = convert_int16_to_double;
+ bat->frames = bat->rate * 2;
+ bat->target_freq[0] = 997.0;
+ bat->target_freq[1] = 997.0;
+ bat->sigma_k = 3.0;
+ bat->playback.device = NULL;
+ bat->capture.device = NULL;
+ bat->buf = NULL;
+ bat->local = false;
+ bat->playback.fct = &playback_alsa;
+ bat->capture.fct = &record_alsa;
+ bat->playback.mode = MODE_LOOPBACK;
+ bat->capture.mode = MODE_LOOPBACK;
+ bat->period_is_limited = false;
+ bat->log = stdout;
+ bat->err = stderr;
+}
+
+static void parse_arguments(struct bat *bat, int argc, char *argv[])
+{
+ int c, option_index;
+ static const char short_options[] = "D:P:C:f:n:F:c:r:s:k:p:lth";
+ static const struct option long_options[] = {
+ {"help", 0, 0, 'h'},
+ {"log", 1, 0, OPT_LOG},
+ {"file", 1, 0, OPT_READFILE},
+ {"saveplay", 1, 0, OPT_SAVEPLAY},
+ {"local", 0, 0, OPT_LOCAL},
+ {0, 0, 0, 0}
+ };
+
+ while ((c = getopt_long(argc, argv, short_options, long_options,
+ &option_index)) != -1) {
+ switch (c) {
+ case OPT_LOG:
+ bat->logarg = optarg;
+ break;
+ case OPT_READFILE:
+ bat->playback.file = optarg;
+ break;
+ case OPT_SAVEPLAY:
+ bat->debugplay = optarg;
+ break;
+ case OPT_LOCAL:
+ bat->local = true;
+ break;
+ case 'D':
+ if (bat->playback.device == NULL)
+ bat->playback.device = optarg;
+ if (bat->capture.device == NULL)
+ bat->capture.device = optarg;
+ break;
+ case 'P':
+ if (bat->capture.mode == MODE_SINGLE)
+ bat->capture.mode = MODE_LOOPBACK;
+ else
+ bat->playback.mode = MODE_SINGLE;
+ bat->playback.device = optarg;
+ break;
+ case 'C':
+ if (bat->playback.mode == MODE_SINGLE)
+ bat->playback.mode = MODE_LOOPBACK;
+ else
+ bat->capture.mode = MODE_SINGLE;
+ bat->capture.device = optarg;
+ break;
+ case 'n':
+ bat->narg = optarg;
+ break;
+ case 'F':
+ get_sine_frequencies(bat, optarg);
+ break;
+ case 'c':
+ bat->channels = atoi(optarg);
+ break;
+ case 'r':
+ bat->rate = atoi(optarg);
+ break;
+ case 'f':
+ get_format(bat, optarg);
+ break;
+ case 'k':
+ bat->sigma_k = atof(optarg);
+ break;
+ case 'p':
+ bat->periods_total = atoi(optarg);
+ bat->period_is_limited = true;
+ break;
+ case 'h':
+ default:
+ usage(bat);
+ exit(EXIT_SUCCESS);
+ }
+ }
+}
+
+static int validate_options(struct bat *bat)
+{
+ int c;
+ float freq_low, freq_high;
+
+ /* check if we have an input file for local mode */
+ if ((bat->local == true) && (bat->capture.file == NULL)) {
+ fprintf(bat->err, _("no input file for local testing\n"));
+ return -EINVAL;
+ }
+
+ /* check supported channels */
+ if (bat->channels > MAX_CHANNELS || bat->channels < MIN_CHANNELS) {
+ fprintf(bat->err, _("%d channels not supported\n"),
+ bat->channels);
+ return -EINVAL;
+ }
+
+ /* check single ended is in either playback or capture - not both */
+ if ((bat->playback.mode == MODE_SINGLE)
+ && (bat->capture.mode == MODE_SINGLE)) {
+ fprintf(bat->err, _("single ended mode is simplex\n"));
+ return -EINVAL;
+ }
+
+ /* check sine wave frequency range */
+ freq_low = DC_THRESHOLD;
+ freq_high = bat->rate * RATE_FACTOR;
+ for (c = 0; c < bat->channels; c++) {
+ if (bat->target_freq[c] < freq_low
+ || bat->target_freq[c] > freq_high) {
+ fprintf(bat->err, _("sine wave frequency out of"));
+ fprintf(bat->err, _(" range: (%.1f, %.1f)\n"),
+ freq_low, freq_high);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static int bat_init(struct bat *bat)
+{
+ int err = 0;
+ char name[] = TEMP_RECORD_FILE_NAME;
+
+ /* Determine logging to a file or stdout and stderr */
+ if (bat->logarg) {
+ bat->log = NULL;
+ bat->log = fopen(bat->logarg, "wb");
+ if (bat->log == NULL) {
+ fprintf(bat->err, _("Cannot open file for capture:"));
+ fprintf(bat->err, _(" %s %d\n"),
+ bat->logarg, -errno);
+ return -errno;
+ }
+ bat->err = bat->log;
+ }
+
+ /* Determine duration of playback and/or capture */
+ if (bat->narg) {
+ err = get_duration(bat);
+ if (err < 0)
+ return err;
+ }
+
+ /* Determine capture file */
+ if (bat->local) {
+ bat->capture.file = bat->playback.file;
+ } else {
+ /* create temp file for sound record and analysis */
+ err = mkstemp(name);
+ if (err == -1) {
+ fprintf(bat->err, _("Fail to create record file: %d\n"),
+ -errno);
+ return -errno;
+ }
+ /* store file name which is dynamically created */
+ bat->capture.file = strdup(name);
+ if (bat->capture.file == NULL)
+ return -errno;
+ /* close temp file */
+ close(err);
+ }
+
+ /* Initial for playback */
+ if (bat->playback.file == NULL) {
+ /* No input file so we will generate our own sine wave */
+ if (bat->frames) {
+ if (bat->playback.mode == MODE_SINGLE) {
+ /* Play nb of frames given by -n argument */
+ bat->sinus_duration = bat->frames;
+ } else {
+ /* Play CAPTURE_DELAY msec +
+ * 150% of the nb of frames to be analyzed */
+ bat->sinus_duration = bat->rate *
+ CAPTURE_DELAY / 1000;
+ bat->sinus_duration +=
+ (bat->frames + bat->frames / 2);
+ }
+ } else {
+ /* Special case where we want to generate a sine wave
+ * endlessly without capturing */
+ bat->sinus_duration = 0;
+ bat->playback.mode = MODE_SINGLE;
+ }
+ } else {
+ bat->fp = fopen(bat->playback.file, "rb");
+ if (bat->fp == NULL) {
+ fprintf(bat->err, _("Cannot open file for playback:"));
+ fprintf(bat->err, _(" %s %d\n"),
+ bat->playback.file, -errno);
+ return -errno;
+ }
+ err = read_wav_header(bat, bat->playback.file, bat->fp, false);
+ fclose(bat->fp);
+ if (err != 0)
+ return err;
+ }
+
+ bat->frame_size = bat->sample_size * bat->channels;
+
+ /* Set conversion functions */
+ switch (bat->sample_size) {
+ case 1:
+ bat->convert_float_to_sample = convert_float_to_uint8;
+ bat->convert_sample_to_double = convert_uint8_to_double;
+ break;
+ case 2:
+ bat->convert_float_to_sample = convert_float_to_int16;
+ bat->convert_sample_to_double = convert_int16_to_double;
+ break;
+ case 3:
+ bat->convert_float_to_sample = convert_float_to_int24;
+ bat->convert_sample_to_double = convert_int24_to_double;
+ break;
+ case 4:
+ bat->convert_float_to_sample = convert_float_to_int32;
+ bat->convert_sample_to_double = convert_int32_to_double;
+ break;
+ default:
+ fprintf(bat->err, _("Invalid PCM format: size=%d\n"),
+ bat->sample_size);
+ return -EINVAL;
+ }
+
+ return err;
+}
+
+int main(int argc, char *argv[])
+{
+ struct bat bat;
+ int err = 0;
+
+ set_defaults(&bat);
+
+#ifdef ENABLE_NLS
+ setlocale(LC_ALL, "");
+ textdomain(PACKAGE);
+#endif
+
+ fprintf(bat.log, _("%s version %s\n\n"), PACKAGE_NAME, PACKAGE_VERSION);
+
+ parse_arguments(&bat, argc, argv);
+
+ err = bat_init(&bat);
+ if (err < 0)
+ goto out;
+
+ err = validate_options(&bat);
+ if (err < 0)
+ goto out;
+
+ /* single line playback thread: playback only, no capture */
+ if (bat.playback.mode == MODE_SINGLE) {
+ test_playback(&bat);
+ goto out;
+ }
+
+ /* single line capture thread: capture only, no playback */
+ if (bat.capture.mode == MODE_SINGLE) {
+ test_capture(&bat);
+ goto analyze;
+ }
+
+ /* loopback thread: playback and capture in a loop */
+ if (bat.local == false)
+ test_loopback(&bat);
+
+analyze:
+ err = analyze_capture(&bat);
+out:
+ fprintf(bat.log, _("\nReturn value is %d\n"), err);
+
+ if (bat.logarg)
+ fclose(bat.log);
+ if (!bat.local)
+ free(bat.capture.file);
+
+ return err;
+}
diff --git a/alsabat/analyze.c b/alsabat/analyze.c
new file mode 100644
index 0000000..60e2d1c
--- /dev/null
+++ b/alsabat/analyze.c
@@ -0,0 +1,314 @@
+/*
+ * Copyright (C) 2013-2015 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <math.h>
+#include <fftw3.h>
+
+#include "aconfig.h"
+#include "gettext.h"
+
+#include "common.h"
+
+static void check_amplitude(struct bat *bat, double *buf)
+{
+ double sum, average, amplitude;
+ int i, percent;
+
+ /* calculate average value */
+ for (i = 0, sum = 0.0; i < bat->frames; i++)
+ sum += buf[i];
+ average = sum / bat->frames;
+
+ /* calculate peak-to-average amplitude */
+ for (i = 0, sum = 0.0; i < bat->frames; i++)
+ sum += abs(buf[i] - average);
+ amplitude = sum / bat->frames * M_PI / 2.0;
+
+ /* calculate amplitude percentage against full range */
+ percent = amplitude * 100 / ((1 << ((bat->sample_size << 3) - 1)) - 1);
+
+ fprintf(bat->log, _("Amplitude: %.1f; Percentage: [%d]\n"),
+ amplitude, percent);
+ if (percent < 0)
+ fprintf(bat->err, _("ERROR: Amplitude can't be negative!\n"));
+ else if (percent < 1)
+ fprintf(bat->err, _("WARNING: Signal too weak!\n"));
+ else if (percent > 100)
+ fprintf(bat->err, _("WARNING: Signal overflow!\n"));
+}
+
+/**
+ *
+ * @return 0 if peak detected at right frequency,
+ * 1 if peak detected somewhere else
+ * 2 if DC detected
+ */
+int check_peak(struct bat *bat, struct analyze *a, int end, int peak, float hz,
+ float mean, float p, int channel, int start)
+{
+ int err;
+ float hz_peak = (float) (peak) * hz;
+ float delta_rate = DELTA_RATE * bat->target_freq[channel];
+ float delta_HZ = DELTA_HZ;
+ float tolerance = (delta_rate > delta_HZ) ? delta_rate : delta_HZ;
+
+ fprintf(bat->log, _("Detected peak at %2.2f Hz of %2.2f dB\n"), hz_peak,
+ 10.0 * log10(a->mag[peak] / mean));
+ fprintf(bat->log, _(" Total %3.1f dB from %2.2f to %2.2f Hz\n"),
+ 10.0 * log10(p / mean), start * hz, end * hz);
+
+ if (hz_peak < DC_THRESHOLD) {
+ fprintf(bat->err, _(" WARNING: Found low peak %2.2f Hz,"),
+ hz_peak);
+ fprintf(bat->err, _(" very close to DC\n"));
+ err = FOUND_DC;
+ } else if (hz_peak < bat->target_freq[channel] - tolerance) {
+ fprintf(bat->err, _(" FAIL: Peak freq too low %2.2f Hz\n"),
+ hz_peak);
+ err = FOUND_WRONG_PEAK;
+ } else if (hz_peak > bat->target_freq[channel] + tolerance) {
+ fprintf(bat->err, _(" FAIL: Peak freq too high %2.2f Hz\n"),
+ hz_peak);
+ err = FOUND_WRONG_PEAK;
+ } else {
+ fprintf(bat->log, _(" PASS: Peak detected"));
+ fprintf(bat->log, _(" at target frequency\n"));
+ err = 0;
+ }
+
+ return err;
+}
+
+/**
+ * Search for main frequencies in fft results and compare it to target
+ */
+static int check(struct bat *bat, struct analyze *a, int channel)
+{
+ float hz = 1.0 / ((float) bat->frames / (float) bat->rate);
+ float mean = 0.0, t, sigma = 0.0, p = 0.0;
+ int i, start = -1, end = -1, peak = 0, signals = 0;
+ int err = 0, N = bat->frames / 2;
+
+ /* calculate mean */
+ for (i = 0; i < N; i++)
+ mean += a->mag[i];
+ mean /= (float) N;
+
+ /* calculate standard deviation */
+ for (i = 0; i < N; i++) {
+ t = a->mag[i] - mean;
+ t *= t;
+ sigma += t;
+ }
+ sigma /= (float) N;
+ sigma = sqrtf(sigma);
+
+ /* clip any data less than k sigma + mean */
+ for (i = 0; i < N; i++) {
+ if (a->mag[i] > mean + bat->sigma_k * sigma) {
+
+ /* find peak start points */
+ if (start == -1) {
+ start = peak = end = i;
+ signals++;
+ } else {
+ if (a->mag[i] > a->mag[peak])
+ peak = i;
+ end = i;
+ }
+ p += a->mag[i];
+ } else if (start != -1) {
+ /* Check if peak is as expected */
+ err |= check_peak(bat, a, end, peak, hz, mean,
+ p, channel, start);
+ end = start = -1;
+ if (signals == MAX_PEAKS)
+ break;
+ }
+ }
+ if (signals == 0)
+ err = -ENOPEAK; /* No peak detected */
+ else if ((err == FOUND_DC) && (signals == 1))
+ err = -EONLYDC; /* Only DC detected */
+ else if ((err & FOUND_WRONG_PEAK) == FOUND_WRONG_PEAK)
+ err = -EBADPEAK; /* Bad peak detected */
+ else
+ err = 0; /* Correct peak detected */
+
+ fprintf(bat->log, _("Detected at least %d signal(s) in total\n"),
+ signals);
+
+ return err;
+}
+
+static void calc_magnitude(struct bat *bat, struct analyze *a, int N)
+{
+ double r2, i2;
+ int i;
+
+ for (i = 1; i < N / 2; i++) {
+ r2 = a->out[i] * a->out[i];
+ i2 = a->out[N - i] * a->out[N - i];
+
+ a->mag[i] = sqrtf(r2 + i2);
+ }
+ a->mag[0] = 0.0;
+}
+
+static int find_and_check_harmonics(struct bat *bat, struct analyze *a,
+ int channel)
+{
+ fftw_plan p;
+ int err = -ENOMEM, N = bat->frames;
+
+ /* Allocate FFT buffers */
+ a->in = (double *) fftw_malloc(sizeof(double) * bat->frames);
+ if (a->in == NULL)
+ goto out1;
+
+ a->out = (double *) fftw_malloc(sizeof(double) * bat->frames);
+ if (a->out == NULL)
+ goto out2;
+
+ a->mag = (double *) fftw_malloc(sizeof(double) * bat->frames);
+ if (a->mag == NULL)
+ goto out3;
+
+ /* create FFT plan */
+ p = fftw_plan_r2r_1d(N, a->in, a->out, FFTW_R2HC,
+ FFTW_MEASURE | FFTW_PRESERVE_INPUT);
+ if (p == NULL)
+ goto out4;
+
+ /* convert source PCM to doubles */
+ bat->convert_sample_to_double(a->buf, a->in, bat->frames);
+
+ /* check amplitude */
+ check_amplitude(bat, a->in);
+
+ /* run FFT */
+ fftw_execute(p);
+
+ /* FFT out is real and imaginary numbers - calc magnitude for each */
+ calc_magnitude(bat, a, N);
+
+ /* check data */
+ err = check(bat, a, channel);
+
+ fftw_destroy_plan(p);
+
+out4:
+ fftw_free(a->mag);
+out3:
+ fftw_free(a->out);
+out2:
+ fftw_free(a->in);
+out1:
+ return err;
+}
+
+/**
+ * Convert interleaved samples from channels in samples from a single channel
+ */
+static int reorder_data(struct bat *bat)
+{
+ char *p, *new_bat_buf;
+ int ch, i, j;
+
+ if (bat->channels == 1)
+ return 0; /* No need for reordering */
+
+ p = malloc(bat->frames * bat->frame_size);
+ new_bat_buf = p;
+ if (p == NULL)
+ return -ENOMEM;
+
+ for (ch = 0; ch < bat->channels; ch++) {
+ for (j = 0; j < bat->frames; j++) {
+ for (i = 0; i < bat->sample_size; i++) {
+ *p++ = ((char *) (bat->buf))[j * bat->frame_size
+ + ch * bat->sample_size + i];
+ }
+ }
+ }
+
+ free(bat->buf);
+ bat->buf = new_bat_buf;
+
+ return 0;
+}
+
+int analyze_capture(struct bat *bat)
+{
+ int err = 0;
+ size_t items;
+ int c;
+ struct analyze a;
+
+ fprintf(bat->log, _("\nBAT analysis: signal has %d frames at %d Hz,"),
+ bat->frames, bat->rate);
+ fprintf(bat->log, _(" %d channels, %d bytes per sample.\n"),
+ bat->channels, bat->sample_size);
+
+ bat->buf = malloc(bat->frames * bat->frame_size);
+ if (bat->buf == NULL)
+ return -ENOMEM;
+
+ bat->fp = fopen(bat->capture.file, "rb");
+ if (bat->fp == NULL) {
+ fprintf(bat->err, _("Cannot open file for capture: %s %d\n"),
+ bat->capture.file, -errno);
+ err = -errno;
+ goto exit1;
+ }
+
+ /* Skip header */
+ err = read_wav_header(bat, bat->capture.file, bat->fp, true);
+ if (err != 0)
+ goto exit2;
+
+ items = fread(bat->buf, bat->frame_size, bat->frames, bat->fp);
+ if (items != bat->frames) {
+ err = -EIO;
+ goto exit2;
+ }
+
+ err = reorder_data(bat);
+ if (err != 0)
+ goto exit2;
+
+ for (c = 0; c < bat->channels; c++) {
+ fprintf(bat->log, _("\nChannel %i - "), c + 1);
+ fprintf(bat->log, _("Checking for target frequency %2.2f Hz\n"),
+ bat->target_freq[c]);
+ a.buf = bat->buf +
+ c * bat->frames * bat->frame_size
+ / bat->channels;
+ err = find_and_check_harmonics(bat, &a, c);
+ }
+
+exit2:
+ fclose(bat->fp);
+exit1:
+ free(bat->buf);
+
+ return err;
+}
diff --git a/alsabat/analyze.h b/alsabat/analyze.h
new file mode 100644
index 0000000..3fd03d4
--- /dev/null
+++ b/alsabat/analyze.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (C) 2013-2015 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+int analyze_capture(struct bat *);
diff --git a/alsabat/bat-signal.h b/alsabat/bat-signal.h
new file mode 100644
index 0000000..a295517
--- /dev/null
+++ b/alsabat/bat-signal.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2015 Caleb Crome
+ * Copyright (C) 2013-2015 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+/*
+ * Here's a generic sine wave generator that will work indefinitely
+ * for any frequency.
+ *
+ * Note: the state & phasor are stored as doubles (and updated as
+ * doubles) because after a million samples the magnitude drifts a
+ * bit. If we really need floats, it can be done with periodic
+ * renormalization of the state_real+state_imag magnitudes.
+ */
+
+int sin_generator_init(struct sin_generator *, float, float, float);
+float sin_generator_next_sample(struct sin_generator *);
+void sin_generator_vfill(struct sin_generator *, float *, int);
+int generate_sine_wave(struct bat *, int, void *);
diff --git a/alsabat/common.c b/alsabat/common.c
new file mode 100644
index 0000000..798b00b
--- /dev/null
+++ b/alsabat/common.c
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2013-2015 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <errno.h>
+
+#include "aconfig.h"
+#include "gettext.h"
+
+#include "common.h"
+#include "alsa.h"
+
+int retval_play;
+int retval_record;
+
+/* update chunk_fmt data to bat */
+static int update_fmt_to_bat(struct bat *bat, struct chunk_fmt *fmt)
+{
+ bat->channels = fmt->channels;
+ bat->rate = fmt->sample_rate;
+ bat->sample_size = fmt->sample_length / 8;
+ if (bat->sample_size > 4) {
+ fprintf(bat->err, _("Invalid format: sample size=%d\n"),
+ bat->sample_size);
+ return -EINVAL;
+ }
+ bat->frame_size = fmt->blocks_align;
+
+ return 0;
+}
+
+/* calculate frames and update to bat */
+static int update_frames_to_bat(struct bat *bat,
+ struct wav_chunk_header *header, FILE *fp)
+{
+ /* The number of analyzed captured frames is arbitrarily set to half of
+ the number of frames of the wav file or the number of frames of the
+ wav file when doing direct analysis (--local) */
+ bat->frames = header->length / bat->frame_size;
+ if (!bat->local)
+ bat->frames /= 2;
+
+ return 0;
+}
+
+static int read_chunk_fmt(struct bat *bat, char *file, FILE *fp, bool skip,
+ struct wav_chunk_header *header)
+{
+ size_t err;
+ int header_skip;
+ struct chunk_fmt chunk_fmt;
+
+ err = fread(&chunk_fmt, sizeof(chunk_fmt), 1, fp);
+ if (err != 1) {
+ fprintf(bat->err, _("Read chunk fmt error: %s:%zd\n"),
+ file, err);
+ return -EIO;
+ }
+ /* If the format header is larger, skip the rest */
+ header_skip = header->length - sizeof(chunk_fmt);
+ if (header_skip > 0) {
+ err = fseek(fp, header_skip, SEEK_CUR);
+ if (err == -1) {
+ fprintf(bat->err, _("Seek fmt header error: %s:%zd\n"),
+ file, err);
+ return -EINVAL;
+ }
+ }
+ /* If the file is opened for playback, update BAT data;
+ If the file is opened for analysis, no update */
+ if (skip == false) {
+ err = update_fmt_to_bat(bat, &chunk_fmt);
+ if (err != 0)
+ return err;
+ }
+
+ return 0;
+}
+
+int read_wav_header(struct bat *bat, char *file, FILE *fp, bool skip)
+{
+ struct wav_header riff_wave_header;
+ struct wav_chunk_header chunk_header;
+ int more_chunks = 1;
+ size_t err;
+
+ /* Read header of RIFF wav file */
+ err = fread(&riff_wave_header, sizeof(riff_wave_header), 1, fp);
+ if (err != 1) {
+ fprintf(bat->err, _("Read header error: %s:%zd\n"), file, err);
+ return -EIO;
+ }
+ if ((riff_wave_header.magic != WAV_RIFF)
+ || (riff_wave_header.type != WAV_WAVE)) {
+ fprintf(bat->err, _("%s is not a riff/wave file\n"), file);
+ return -EINVAL;
+ }
+
+ /* Read chunks in RIFF wav file */
+ do {
+ err = fread(&chunk_header, sizeof(chunk_header), 1, fp);
+ if (err != 1) {
+ fprintf(bat->err, _("Read chunk header error: "));
+ fprintf(bat->err, _("%s:%zd\n"), file, err);
+ return -EIO;
+ }
+
+ switch (chunk_header.type) {
+ case WAV_FMT:
+ /* WAV_FMT chunk, read and analyze */
+ err = read_chunk_fmt(bat, file, fp, skip,
+ &chunk_header);
+ if (err != 0)
+ return err;
+ break;
+ case WAV_DATA:
+ /* WAV_DATA chunk, break looping */
+ /* If the file is opened for playback, update BAT data;
+ If the file is opened for analysis, no update */
+ if (skip == false) {
+ err = update_frames_to_bat(bat, &chunk_header,
+ fp);
+ if (err != 0)
+ return err;
+ }
+ /* Stop looking for chunks */
+ more_chunks = 0;
+ break;
+ default:
+ /* Unknown chunk, skip bytes */
+ err = fseek(fp, chunk_header.length, SEEK_CUR);
+ if (err == -1) {
+ fprintf(bat->err, _("Fail to skip unknown"));
+ fprintf(bat->err, _(" chunk of %s:%zd\n"),
+ file, err);
+ return -EINVAL;
+ }
+ }
+ } while (more_chunks);
+
+ return 0;
+}
+
+void prepare_wav_info(struct wav_container *wav, struct bat *bat)
+{
+ wav->header.magic = WAV_RIFF;
+ wav->header.type = WAV_WAVE;
+ wav->format.magic = WAV_FMT;
+ wav->format.fmt_size = 16;
+ wav->format.format = WAV_FORMAT_PCM;
+ wav->format.channels = bat->channels;
+ wav->format.sample_rate = bat->rate;
+ wav->format.sample_length = bat->sample_size * 8;
+ wav->format.blocks_align = bat->channels * bat->sample_size;
+ wav->format.bytes_p_second = wav->format.blocks_align * bat->rate;
+ wav->chunk.length = bat->frames * bat->frame_size;
+ wav->chunk.type = WAV_DATA;
+ wav->header.length = (wav->chunk.length) + sizeof(wav->chunk)
+ + sizeof(wav->format) + sizeof(wav->header) - 8;
+}
+
+int write_wav_header(FILE *fp, struct wav_container *wav, struct bat *bat)
+{
+ int err = 0;
+
+ err = fwrite(&wav->header, 1, sizeof(wav->header), fp);
+ if (err != sizeof(wav->header)) {
+ fprintf(bat->err, _("Write file error: header %d\n"), err);
+ return -EIO;
+ }
+ err = fwrite(&wav->format, 1, sizeof(wav->format), fp);
+ if (err != sizeof(wav->format)) {
+ fprintf(bat->err, _("Write file error: format %d\n"), err);
+ return -EIO;
+ }
+ err = fwrite(&wav->chunk, 1, sizeof(wav->chunk), fp);
+ if (err != sizeof(wav->chunk)) {
+ fprintf(bat->err, _("Write file error: chunk %d\n"), err);
+ return -EIO;
+ }
+
+ return 0;
+}
diff --git a/alsabat/common.h b/alsabat/common.h
new file mode 100644
index 0000000..c04452d
--- /dev/null
+++ b/alsabat/common.h
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2013-2015 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <alsa/asoundlib.h>
+
+#define TEMP_RECORD_FILE_NAME "/tmp/bat.wav.XXXXXX"
+
+#define OPT_BASE 300
+#define OPT_LOG (OPT_BASE + 1)
+#define OPT_READFILE (OPT_BASE + 2)
+#define OPT_SAVEPLAY (OPT_BASE + 3)
+#define OPT_LOCAL (OPT_BASE + 4)
+
+#define COMPOSE(a, b, c, d) ((a) | ((b)<<8) | ((c)<<16) | ((d)<<24))
+#define WAV_RIFF COMPOSE('R', 'I', 'F', 'F')
+#define WAV_WAVE COMPOSE('W', 'A', 'V', 'E')
+#define WAV_FMT COMPOSE('f', 'm', 't', ' ')
+#define WAV_DATA COMPOSE('d', 'a', 't', 'a')
+#define WAV_FORMAT_PCM 1 /* PCM WAVE file encoding */
+
+#define MAX_CHANNELS 2
+#define MIN_CHANNELS 1
+#define MAX_PEAKS 10
+#define MAX_FRAMES (10 * 1024 * 1024)
+/* Given in ms */
+#define CAPTURE_DELAY 500
+/* signal frequency should be less than samplerate * RATE_FACTOR */
+#define RATE_FACTOR 0.4
+/* valid range of samplerate: (1 - RATE_RANGE, 1 + RATE_RANGE) * samplerate */
+#define RATE_RANGE 0.05
+/* Given in us */
+#define MAX_BUFFERTIME 500000
+/* devide factor, was 4, changed to 8 to remove reduce capture overrun */
+#define DIV_BUFFERTIME 8
+/* margin to avoid sign inversion when generate sine wav */
+#define RANGE_FACTOR 0.95
+
+#define EBATBASE 1000
+#define ENOPEAK (EBATBASE + 1)
+#define EONLYDC (EBATBASE + 2)
+#define EBADPEAK (EBATBASE + 3)
+
+#define DC_THRESHOLD 7.01
+
+/* tolerance of detected peak = max (DELTA_HZ, DELTA_RATE * target_freq).
+ * If DELTA_RATE is too high, BAT may not be able to recognize negative result;
+ * if too low, BAT may be too sensitive and results in uncecessary failure. */
+#define DELTA_RATE 0.005
+#define DELTA_HZ 1
+
+#define FOUND_DC (1<<1)
+#define FOUND_WRONG_PEAK (1<<0)
+
+struct wav_header {
+ unsigned int magic; /* 'RIFF' */
+ unsigned int length; /* file len */
+ unsigned int type; /* 'WAVE' */
+};
+
+struct wav_chunk_header {
+ unsigned int type; /* 'data' */
+ unsigned int length; /* sample count */
+};
+
+struct wav_fmt {
+ unsigned int magic; /* 'FMT '*/
+ unsigned int fmt_size; /* 16 or 18 */
+ unsigned short format; /* see WAV_FMT_* */
+ unsigned short channels;
+ unsigned int sample_rate; /* Frequency of sample */
+ unsigned int bytes_p_second;
+ unsigned short blocks_align; /* sample size; 1 or 2 bytes */
+ unsigned short sample_length; /* 8, 12 or 16 bit */
+};
+
+struct chunk_fmt {
+ unsigned short format; /* see WAV_FMT_* */
+ unsigned short channels;
+ unsigned int sample_rate; /* Frequency of sample */
+ unsigned int bytes_p_second;
+ unsigned short blocks_align; /* sample size; 1 or 2 bytes */
+ unsigned short sample_length; /* 8, 12 or 16 bit */
+};
+
+struct wav_container {
+ struct wav_header header;
+ struct wav_fmt format;
+ struct wav_chunk_header chunk;
+};
+
+struct bat;
+
+enum _bat_op_mode {
+ MODE_UNKNOWN = -1,
+ MODE_SINGLE = 0,
+ MODE_LOOPBACK,
+ MODE_LAST
+};
+
+struct pcm {
+ char *device;
+ char *file;
+ enum _bat_op_mode mode;
+ void *(*fct)(struct bat *);
+};
+
+struct sin_generator;
+
+struct sin_generator {
+ double state_real;
+ double state_imag;
+ double phasor_real;
+ double phasor_imag;
+ float frequency;
+ float sample_rate;
+ float magnitude;
+};
+
+struct bat {
+ unsigned int rate; /* sampling rate */
+ int channels; /* nb of channels */
+ int frames; /* nb of frames */
+ int frame_size; /* size of frame */
+ int sample_size; /* size of sample */
+ snd_pcm_format_t format; /* PCM format */
+
+ float sigma_k; /* threshold for peak detection */
+ float target_freq[MAX_CHANNELS];
+
+ int sinus_duration; /* number of frames for playback */
+ char *narg; /* argument string of duration */
+ char *logarg; /* path name of log file */
+ char *debugplay; /* path name to store playback signal */
+
+ struct pcm playback;
+ struct pcm capture;
+
+ unsigned int periods_played;
+ unsigned int periods_total;
+ bool period_is_limited;
+
+ FILE *fp;
+
+ FILE *log;
+ FILE *err;
+
+ void (*convert_sample_to_double)(void *, double *, int);
+ void (*convert_float_to_sample)(float *, void *, int, int);
+
+ void *buf; /* PCM Buffer */
+
+ bool local; /* true for internal test */
+};
+
+struct analyze {
+ void *buf;
+ double *in;
+ double *out;
+ double *mag;
+};
+
+void prepare_wav_info(struct wav_container *, struct bat *);
+int read_wav_header(struct bat *, char *, FILE *, bool);
+int write_wav_header(FILE *, struct wav_container *, struct bat *);
diff --git a/alsabat/convert.c b/alsabat/convert.c
new file mode 100644
index 0000000..dcbe912
--- /dev/null
+++ b/alsabat/convert.c
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2013-2015 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+void convert_uint8_to_double(void *buf, double *val, int samples)
+{
+ int i;
+
+ for (i = 0; i < samples; i++)
+ val[i] = ((uint8_t *) buf)[i];
+}
+
+void convert_int16_to_double(void *buf, double *val, int samples)
+{
+ int i;
+
+ for (i = 0; i < samples; i++)
+ val[i] = ((int16_t *) buf)[i];
+}
+
+void convert_int24_to_double(void *buf, double *val, int samples)
+{
+ int i;
+ int32_t tmp;
+
+ for (i = 0; i < samples; i++) {
+ tmp = ((uint8_t *) buf)[i * 3 + 2] << 24;
+ tmp |= ((uint8_t *) buf)[i * 3 + 1] << 16;
+ tmp |= ((uint8_t *) buf)[i * 3] << 8;
+ tmp >>= 8;
+ val[i] = tmp;
+ }
+}
+
+void convert_int32_to_double(void *buf, double *val, int samples)
+{
+ int i;
+
+ for (i = 0; i < samples; i++)
+ val[i] = ((int32_t *) buf)[i];
+}
+
+void convert_float_to_uint8(float *val, void *buf, int samples, int channels)
+{
+ int i, c, idx;
+
+ for (i = 0; i < samples; i++) {
+ for (c = 0; c < channels; c++) {
+ idx = i * channels + c;
+ ((uint8_t *) buf)[idx] = (uint8_t) val[idx];
+ }
+ }
+}
+
+void convert_float_to_int16(float *val, void *buf, int samples, int channels)
+{
+ int i, c, idx;
+
+ for (i = 0; i < samples; i++) {
+ for (c = 0; c < channels; c++) {
+ idx = i * channels + c;
+ ((int16_t *) buf)[idx] = (int16_t) val[idx];
+ }
+ }
+}
+
+void convert_float_to_int24(float *val, void *buf, int samples, int channels)
+{
+ int i, c, idx_f, idx_i;
+ int32_t val_f_i;
+
+ for (i = 0; i < samples; i++) {
+ for (c = 0; c < channels; c++) {
+ idx_f = i * channels + c;
+ idx_i = 3 * idx_f;
+ val_f_i = (int32_t) val[idx_f];
+ ((int8_t *) buf)[idx_i + 0] =
+ (int8_t) (val_f_i & 0xff);
+ ((int8_t *) buf)[idx_i + 1] =
+ (int8_t) ((val_f_i >> 8) & 0xff);
+ ((int8_t *) buf)[idx_i + 2] =
+ (int8_t) ((val_f_i >> 16) & 0xff);
+ }
+ }
+}
+
+void convert_float_to_int32(float *val, void *buf, int samples, int channels)
+{
+ int i, c, idx;
+
+ for (i = 0; i < samples; i++) {
+ for (c = 0; c < channels; c++) {
+ idx = i * channels + c;
+ ((int32_t *) buf)[idx] = (int32_t) val[idx];
+ }
+ }
+}
diff --git a/alsabat/convert.h b/alsabat/convert.h
new file mode 100644
index 0000000..28828ba
--- /dev/null
+++ b/alsabat/convert.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2013-2015 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+void convert_uint8_to_double(void *, double *, int);
+void convert_int16_to_double(void *, double *, int);
+void convert_int24_to_double(void *, double *, int);
+void convert_int32_to_double(void *, double *, int);
+void convert_float_to_uint8(float *, void *, int, int);
+void convert_float_to_int16(float *, void *, int, int);
+void convert_float_to_int24(float *, void *, int, int);
+void convert_float_to_int32(float *, void *, int, int);
diff --git a/alsabat/signal.c b/alsabat/signal.c
new file mode 100644
index 0000000..d342d00
--- /dev/null
+++ b/alsabat/signal.c
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2015 Caleb Crome
+ * Copyright (C) 2013-2015 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+/*
+ * This is a general purpose sine wave generator that will stay stable
+ * for a long time, and with a little renormalization, could stay stay
+ * stable indefinitely
+ */
+
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <math.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "gettext.h"
+#include "common.h"
+#include "signal.h"
+
+/*
+ * Initialize the sine wave generator.
+ * sin_generator: gets initialized by this call.
+ * frequency: the frequency for the sine wave. must be < 0.5*sample_rate
+ * sample_rate: the sample rate...
+ * returns 0 on success, -1 on error.
+ */
+int sin_generator_init(struct sin_generator *sg, float magnitude,
+ float frequency, float sample_rate)
+{
+ /* angular frequency: cycles/sec / (samp/sec) * rad/cycle = rad/samp */
+ float w = frequency / sample_rate * 2 * M_PI;
+
+ if (frequency >= sample_rate / 2)
+ return -1;
+ sg->phasor_real = cos(w);
+ sg->phasor_imag = sin(w);
+ sg->magnitude = magnitude;
+ sg->state_real = 0.0;
+ sg->state_imag = magnitude;
+ sg->frequency = frequency;
+ sg->sample_rate = sample_rate;
+ return 0;
+}
+
+/*
+ * Generates the next sample in the sine wave.
+ * should be much faster than calling a sin function
+ * if it's inlined and optimized.
+ *
+ * returns the next value. no possibility of error.
+ */
+float sin_generator_next_sample(struct sin_generator *sg)
+{
+ /* get shorthand to pointers */
+ const double pr = sg->phasor_real;
+ const double pi = sg->phasor_imag;
+ const double sr = sg->state_real;
+ const double si = sg->state_imag;
+ /* step the phasor -- complex multiply */
+ sg->state_real = sr * pr - si * pi;
+ sg->state_imag = sr * pi + pr * si;
+ /* return the input value so sine wave starts at exactly 0.0 */
+ return sr;
+}
+
+/* fills a vector with a sine wave */
+void sin_generator_vfill(struct sin_generator *sg, float *buf, int n)
+{
+ int i;
+
+ for (i = 0; i < n; i++)
+ *buf++ = sin_generator_next_sample(sg);
+}
+
+static int reorder(struct bat *bat, float *val, int frames)
+{
+ float *new_buf = NULL;
+ int i, c, bytes;
+
+ bytes = frames * bat->channels * sizeof(float);
+
+ new_buf = (float *) malloc(bytes);
+ if (new_buf == NULL) {
+ fprintf(bat->err, _("Not enough memory.\n"));
+ return -ENOMEM;
+ }
+
+ memcpy(new_buf, val, bytes);
+ for (i = 0; i < frames; i++)
+ for (c = 0; c < bat->channels; c++)
+ val[i * bat->channels + c] =
+ new_buf[c * frames + i];
+ free(new_buf);
+
+ return 0;
+}
+
+static int adjust_waveform(struct bat *bat, float *val, int frames)
+{
+ int i, nsamples, max;
+ float factor, offset = 0.0;
+
+ switch (bat->format) {
+ case SND_PCM_FORMAT_U8:
+ max = INT8_MAX;
+ offset = max; /* shift for unsigned format */
+ break;
+ case SND_PCM_FORMAT_S16_LE:
+ max = INT16_MAX;
+ break;
+ case SND_PCM_FORMAT_S24_3LE:
+ max = (1 << 23) - 1;
+ break;
+ case SND_PCM_FORMAT_S32_LE:
+ max = INT32_MAX;
+ break;
+ default:
+ fprintf(bat->err, _("Invalid PCM format: %s\n"),
+ snd_pcm_format_name(bat->format));
+ return -EINVAL;
+ }
+
+ factor = max * RANGE_FACTOR;
+ nsamples = bat->channels * frames;
+
+ for (i = 0; i < nsamples; i++)
+ val[i] = val[i] * factor + offset;
+
+ return 0;
+}
+
+int generate_sine_wave(struct bat *bat, int frames, void *buf)
+{
+ int err = 0;
+ int c, nsamples;
+ float *sinus_f = NULL;
+ static struct sin_generator sg[MAX_CHANNELS];
+
+ nsamples = bat->channels * frames;
+ sinus_f = (float *) malloc(nsamples * sizeof(float));
+ if (sinus_f == NULL) {
+ fprintf(bat->err, _("Not enough memory.\n"));
+ return -ENOMEM;
+ }
+
+ for (c = 0; c < bat->channels; c++) {
+ /* initialize static struct at the first time */
+ if (sg[c].frequency != bat->target_freq[c])
+ sin_generator_init(&sg[c], 1.0, bat->target_freq[c],
+ bat->rate);
+ /* fill buffer for each channel */
+ sin_generator_vfill(&sg[c], sinus_f + c * frames, frames);
+ }
+
+ /* reorder samples to interleaved mode */
+ err = reorder(bat, sinus_f, frames);
+ if (err != 0)
+ return err;
+
+ /* adjust amplitude and offset of waveform */
+ err = adjust_waveform(bat, sinus_f, frames);
+ if (err != 0)
+ return err;
+
+ bat->convert_float_to_sample(sinus_f, buf, frames, bat->channels);
+
+ free(sinus_f);
+
+ return 0;
+}
diff --git a/bat/Makefile.am b/bat/Makefile.am
deleted file mode 100644
index f0dc5ab..0000000
--- a/bat/Makefile.am
+++ /dev/null
@@ -1,24 +0,0 @@
-bin_PROGRAMS = bat
-man_MANS = bat.1
-
-EXTRA_DIST = bat.1
-
-bat_SOURCES = \
- bat.c \
- common.c \
- analyze.c \
- signal.c \
- convert.c \
- alsa.c
-
-noinst_HEADERS = \
- common.h \
- bat-signal.h \
- alsa.h \
- convert.h \
- analyze.h
-
-AM_CPPFLAGS = \
- -Wall -I$(top_srcdir)/include
-
-bat_LDADD = @FFTW_LIB@
diff --git a/bat/alsa.c b/bat/alsa.c
deleted file mode 100644
index 5eaa25b..0000000
--- a/bat/alsa.c
+++ /dev/null
@@ -1,604 +0,0 @@
-/*
- * Copyright (C) 2013-2015 Intel Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <stdbool.h>
-#include <math.h>
-#include <stdint.h>
-#include <pthread.h>
-
-#include <alsa/asoundlib.h>
-
-#include "aconfig.h"
-#include "gettext.h"
-
-#include "common.h"
-#include "alsa.h"
-#include "bat-signal.h"
-
-struct pcm_container {
- snd_pcm_t *handle;
- snd_pcm_uframes_t period_size;
- snd_pcm_uframes_t buffer_size;
- snd_pcm_format_t format;
- unsigned short channels;
- size_t period_bytes;
- size_t sample_bits;
- size_t frame_bits;
- char *buffer;
-};
-
-static int set_snd_pcm_params(struct bat *bat, struct pcm_container *sndpcm)
-{
- snd_pcm_hw_params_t *params;
- unsigned int buffer_time = 0;
- unsigned int period_time = 0;
- unsigned int rate;
- int err;
- const char *device_name = snd_pcm_name(sndpcm->handle);
-
- /* Allocate a hardware parameters object. */
- snd_pcm_hw_params_alloca(¶ms);
-
- /* Fill it in with default values. */
- err = snd_pcm_hw_params_any(sndpcm->handle, params);
- if (err < 0) {
- fprintf(bat->err, _("Set parameter to device error: "));
- fprintf(bat->err, _("default params: %s: %s(%d)\n"),
- device_name, snd_strerror(err), err);
- return err;
- }
-
- /* Set access mode */
- err = snd_pcm_hw_params_set_access(sndpcm->handle, params,
- SND_PCM_ACCESS_RW_INTERLEAVED);
- if (err < 0) {
- fprintf(bat->err, _("Set parameter to device error: "));
- fprintf(bat->err, _("access type: %s: %s(%d)\n"),
- device_name, snd_strerror(err), err);
- return err;
- }
-
- /* Set format */
- err = snd_pcm_hw_params_set_format(sndpcm->handle, params, bat->format);
- if (err < 0) {
- fprintf(bat->err, _("Set parameter to device error: "));
- fprintf(bat->err, _("PCM format: %d %s: %s(%d)\n"),
- bat->format,
- device_name, snd_strerror(err), err);
- return err;
- }
-
- /* Set channels */
- err = snd_pcm_hw_params_set_channels(sndpcm->handle,
- params, bat->channels);
- if (err < 0) {
- fprintf(bat->err, _("Set parameter to device error: "));
- fprintf(bat->err, _("channel number: %d %s: %s(%d)\n"),
- bat->channels,
- device_name, snd_strerror(err), err);
- return err;
- }
-
- /* Set sampling rate */
- rate = bat->rate;
- err = snd_pcm_hw_params_set_rate_near(sndpcm->handle,
- params, &bat->rate,
- 0);
- if (err < 0) {
- fprintf(bat->err, _("Set parameter to device error: "));
- fprintf(bat->err, _("sample rate: %d %s: %s(%d)\n"),
- bat->rate,
- device_name, snd_strerror(err), err);
- return err;
- }
- if ((float) rate * (1 + RATE_RANGE) < bat->rate
- || (float) rate * (1 - RATE_RANGE) > bat->rate) {
- fprintf(bat->err, _("Invalid parameters: sample rate: "));
- fprintf(bat->err, _("requested %dHz, got %dHz\n"),
- rate, bat->rate);
- return -EINVAL;
- }
-
- if (snd_pcm_hw_params_get_buffer_time_max(params,
- &buffer_time, 0) < 0) {
- fprintf(bat->err, _("Get parameter from device error: "));
- fprintf(bat->err, _("buffer time: %d %s: %s(%d)\n"),
- buffer_time,
- device_name, snd_strerror(err), err);
- return -EINVAL;
- }
-
- if (buffer_time > MAX_BUFFERTIME)
- buffer_time = MAX_BUFFERTIME;
-
- period_time = buffer_time / DIV_BUFFERTIME;
-
- /* Set buffer time and period time */
- err = snd_pcm_hw_params_set_buffer_time_near(sndpcm->handle, params,
- &buffer_time, 0);
- if (err < 0) {
- fprintf(bat->err, _("Set parameter to device error: "));
- fprintf(bat->err, _("buffer time: %d %s: %s(%d)\n"),
- buffer_time,
- device_name, snd_strerror(err), err);
- return err;
- }
-
- err = snd_pcm_hw_params_set_period_time_near(sndpcm->handle, params,
- &period_time, 0);
- if (err < 0) {
- fprintf(bat->err, _("Set parameter to device error: "));
- fprintf(bat->err, _("period time: %d %s: %s(%d)\n"),
- period_time,
- device_name, snd_strerror(err), err);
- return err;
- }
-
- /* Write the parameters to the driver */
- if (snd_pcm_hw_params(sndpcm->handle, params) < 0) {
- fprintf(bat->err, _("Set parameter to device error: "));
- fprintf(bat->err, _("hw params: %s: %s(%d)\n"),
- device_name, snd_strerror(err), err);
- return -EINVAL;
- }
-
- err = snd_pcm_hw_params_get_period_size(params,
- &sndpcm->period_size, 0);
- if (err < 0) {
- fprintf(bat->err, _("Get parameter from device error: "));
- fprintf(bat->err, _("period size: %zd %s: %s(%d)\n"),
- sndpcm->period_size,
- device_name, snd_strerror(err), err);
- return err;
- }
-
- err = snd_pcm_hw_params_get_buffer_size(params, &sndpcm->buffer_size);
- if (err < 0) {
- fprintf(bat->err, _("Get parameter from device error: "));
- fprintf(bat->err, _("buffer size: %zd %s: %s(%d)\n"),
- sndpcm->buffer_size,
- device_name, snd_strerror(err), err);
- return err;
- }
-
- if (sndpcm->period_size == sndpcm->buffer_size) {
- fprintf(bat->err, _("Invalid parameters: can't use period "));
- fprintf(bat->err, _("equal to buffer size (%zd)\n"),
- sndpcm->period_size);
- return -EINVAL;
- }
-
- err = snd_pcm_format_physical_width(bat->format);
- if (err < 0) {
- fprintf(bat->err, _("Invalid parameters: "));
- fprintf(bat->err, _("snd_pcm_format_physical_width: %d\n"),
- err);
- return err;
- }
- sndpcm->sample_bits = err;
-
- sndpcm->frame_bits = sndpcm->sample_bits * bat->channels;
-
- /* Calculate the period bytes */
- sndpcm->period_bytes = sndpcm->period_size * sndpcm->frame_bits / 8;
- sndpcm->buffer = (char *) malloc(sndpcm->period_bytes);
- if (sndpcm->buffer == NULL) {
- fprintf(bat->err, _("Not enough memory: size=%zd\n"),
- sndpcm->period_bytes);
- return -ENOMEM;
- }
-
- return 0;
-}
-
-/*
- * Generate buffer to be played either from input file or from generated data
- * Return value
- * <0 error
- * 0 ok
- * >0 break
- */
-static int generate_input_data(struct pcm_container *sndpcm, int bytes,
- struct bat *bat)
-{
- int err;
- static int load;
- int frames = bytes * 8 / sndpcm->frame_bits;
-
- if (bat->playback.file != NULL) {
- /* From input file */
- load = 0;
-
- while (1) {
- err = fread(sndpcm->buffer + load, 1,
- bytes - load, bat->fp);
- if (0 == err) {
- if (feof(bat->fp)) {
- fprintf(bat->log,
- _("End of playing.\n"));
- return 1;
- }
- } else if (err < bytes - load) {
- if (ferror(bat->fp)) {
- fprintf(bat->err, _("Read file error"));
- fprintf(bat->err, _(": %d\n"), err);
- return -EIO;
- }
- load += err;
- } else {
- break;
- }
- }
- } else {
- /* Generate sine wave */
- if ((bat->sinus_duration) && (load > bat->sinus_duration))
- return 1;
-
- err = generate_sine_wave(bat, frames, (void *)sndpcm->buffer);
- if (err != 0)
- return err;
-
- load += frames;
- }
-
- return 0;
-}
-
-static int write_to_pcm(const struct pcm_container *sndpcm,
- int frames, struct bat *bat)
-{
- int err;
- int offset = 0;
- int remain = frames;
-
- while (remain > 0) {
- err = snd_pcm_writei(sndpcm->handle, sndpcm->buffer + offset,
- remain);
- if (err == -EAGAIN || (err >= 0 && err < frames)) {
- snd_pcm_wait(sndpcm->handle, 500);
- } else if (err == -EPIPE) {
- fprintf(bat->err, _("Underrun: %s(%d)\n"),
- snd_strerror(err), err);
- snd_pcm_prepare(sndpcm->handle);
- } else if (err < 0) {
- fprintf(bat->err, _("Write PCM device error: %s(%d)\n"),
- snd_strerror(err), err);
- return err;
- }
-
- if (err > 0) {
- remain -= err;
- offset += err * sndpcm->frame_bits / 8;
- }
- }
-
- return 0;
-}
-
-static int write_to_pcm_loop(struct pcm_container *sndpcm, struct bat *bat)
-{
- int err;
- int bytes = sndpcm->period_bytes; /* playback buffer size */
- int frames = bytes * 8 / sndpcm->frame_bits; /* frame count */
- FILE *fp = NULL;
- struct wav_container wav;
- int bytes_total = 0;
-
- if (bat->debugplay) {
- fp = fopen(bat->debugplay, "wb");
- if (fp == NULL) {
- fprintf(bat->err, _("Cannot open file for capture: "));
- fprintf(bat->err, _("%s %d\n"), bat->debugplay, -errno);
- return -errno;
- }
- /* leave space for wav header */
- err = fseek(fp, sizeof(wav), SEEK_SET);
- if (err != 0) {
- fprintf(bat->err, _("Seek file error: %d %d\n"),
- err, -errno);
- return -errno;
- }
- }
-
- while (1) {
- err = generate_input_data(sndpcm, bytes, bat);
- if (err < 0)
- return err;
- else if (err > 0)
- break;
-
- if (bat->debugplay) {
- err = fwrite(sndpcm->buffer, 1, bytes, fp);
- if (err != bytes) {
- fprintf(bat->err, _("Write file error: "));
- fprintf(bat->err, _("%s(%d)\n"),
- snd_strerror(err), err);
- return -EIO;
- }
- bytes_total += bytes;
- }
-
- bat->periods_played++;
- if (bat->period_is_limited
- && bat->periods_played >= bat->periods_total)
- break;
-
- err = write_to_pcm(sndpcm, frames, bat);
- if (err != 0)
- return err;
- }
-
- if (bat->debugplay) {
- /* update wav header */
- prepare_wav_info(&wav, bat);
- wav.chunk.length = bytes_total;
- wav.header.length = (wav.chunk.length) + sizeof(wav.chunk)
- + sizeof(wav.format) + sizeof(wav.header) - 8;
-
- rewind(fp);
- err = write_wav_header(fp, &wav, bat);
- if (err != 0) {
- fprintf(bat->err, _("Write file error: %s %s(%d)\n"),
- bat->debugplay, snd_strerror(err), err);
- return err;
- }
- fclose(fp);
- }
-
- snd_pcm_drain(sndpcm->handle);
-
- return 0;
-}
-
-/**
- * Play
- */
-void *playback_alsa(struct bat *bat)
-{
- int err = 0;
- struct pcm_container sndpcm;
-
- fprintf(bat->log, _("Entering playback thread (ALSA).\n"));
-
- retval_play = 0;
- memset(&sndpcm, 0, sizeof(sndpcm));
-
- if (bat->playback.device == NULL) {
- fprintf(bat->err, _("No PCM device for playback: exit\n"));
- retval_play = 1;
- goto exit1;
- }
-
- err = snd_pcm_open(&sndpcm.handle, bat->playback.device,
- SND_PCM_STREAM_PLAYBACK, 0);
- if (err != 0) {
- fprintf(bat->err, _("Cannot open PCM playback device: "));
- fprintf(bat->err, _("%s(%d)\n"), snd_strerror(err), err);
- retval_play = 1;
- goto exit1;
- }
-
- err = set_snd_pcm_params(bat, &sndpcm);
- if (err != 0) {
- retval_play = 1;
- goto exit2;
- }
-
- if (bat->playback.file == NULL) {
- fprintf(bat->log, _("Playing generated audio sine wave"));
- bat->sinus_duration == 0 ?
- fprintf(bat->log, _(" endlessly\n")) :
- fprintf(bat->log, _("\n"));
- } else {
- fprintf(bat->log, _("Playing input audio file: %s\n"),
- bat->playback.file);
- bat->fp = fopen(bat->playback.file, "rb");
- if (bat->fp == NULL) {
- fprintf(bat->err, _("Cannot open file for capture: "));
- fprintf(bat->err, _("%s %d\n"),
- bat->playback.file, -errno);
- retval_play = 1;
- goto exit3;
- }
- /* Skip header */
- err = read_wav_header(bat, bat->playback.file, bat->fp, true);
- if (err != 0) {
- retval_play = 1;
- goto exit4;
- }
- }
-
- err = write_to_pcm_loop(&sndpcm, bat);
- if (err != 0) {
- retval_play = 1;
- goto exit4;
- }
-
-exit4:
- if (bat->playback.file)
- fclose(bat->fp);
-exit3:
- free(sndpcm.buffer);
-exit2:
- snd_pcm_close(sndpcm.handle);
-exit1:
- pthread_exit(&retval_play);
-}
-
-static int read_from_pcm(struct pcm_container *sndpcm,
- int frames, struct bat *bat)
-{
- int err = 0;
- int offset = 0;
- int remain = frames;
-
- while (remain > 0) {
- err = snd_pcm_readi(sndpcm->handle,
- sndpcm->buffer + offset, remain);
- if (err == -EAGAIN || (err >= 0 && err < remain)) {
- snd_pcm_wait(sndpcm->handle, 500);
- } else if (err == -EPIPE) {
- snd_pcm_prepare(sndpcm->handle);
- fprintf(bat->err, _("Overrun: %s(%d)\n"),
- snd_strerror(err), err);
- } else if (err < 0) {
- fprintf(bat->err, _("Read PCM device error: %s(%d)\n"),
- snd_strerror(err), err);
- return err;
- }
-
- if (err > 0) {
- remain -= err;
- offset += err * sndpcm->frame_bits / 8;
- }
- }
-
- return 0;
-}
-
-static int read_from_pcm_loop(FILE *fp, int count,
- struct pcm_container *sndpcm, struct bat *bat)
-{
- int err = 0;
- int size, frames;
- int remain = count;
-
- while (remain > 0) {
- size = (remain <= sndpcm->period_bytes) ?
- remain : sndpcm->period_bytes;
- frames = size * 8 / sndpcm->frame_bits;
-
- /* read a chunk from pcm device */
- err = read_from_pcm(sndpcm, frames, bat);
- if (err != 0)
- return err;
-
- /* write the chunk to file */
- err = fwrite(sndpcm->buffer, 1, size, fp);
- if (err != size) {
- fprintf(bat->err, _("Write file error: %s(%d)\n"),
- snd_strerror(err), err);
- return -EIO;
- }
- remain -= size;
- bat->periods_played++;
-
- if (bat->period_is_limited
- && bat->periods_played >= bat->periods_total)
- break;
- }
-
- return 0;
-}
-
-static void pcm_cleanup(void *p)
-{
- snd_pcm_close(p);
-}
-
-static void file_cleanup(void *p)
-{
- fclose(p);
-}
-
-/**
- * Record
- */
-void *record_alsa(struct bat *bat)
-{
- int err = 0;
- FILE *fp = NULL;
- struct pcm_container sndpcm;
- struct wav_container wav;
- int count;
-
- pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
-
- fprintf(bat->log, _("Entering capture thread (ALSA).\n"));
-
- retval_record = 0;
- memset(&sndpcm, 0, sizeof(sndpcm));
-
- if (bat->capture.device == NULL) {
- fprintf(bat->err, _("No PCM device for capture: exit\n"));
- retval_record = 1;
- goto exit1;
- }
-
- err = snd_pcm_open(&sndpcm.handle, bat->capture.device,
- SND_PCM_STREAM_CAPTURE, 0);
- if (err != 0) {
- fprintf(bat->err, _("Cannot open PCM capture device: "));
- fprintf(bat->err, _("%s(%d)\n"), snd_strerror(err), err);
- retval_record = 1;
- goto exit1;
- }
-
- err = set_snd_pcm_params(bat, &sndpcm);
- if (err != 0) {
- retval_record = 1;
- goto exit2;
- }
-
- remove(bat->capture.file);
- fp = fopen(bat->capture.file, "w+");
- if (fp == NULL) {
- fprintf(bat->err, _("Cannot open file for capture: %s %d\n"),
- bat->capture.file, -errno);
- retval_record = 1;
- goto exit3;
- }
-
- prepare_wav_info(&wav, bat);
-
- pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
- pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
- pthread_cleanup_push(pcm_cleanup, sndpcm.handle);
- pthread_cleanup_push(free, sndpcm.buffer);
- pthread_cleanup_push(file_cleanup, fp);
-
- err = write_wav_header(fp, &wav, bat);
- if (err != 0) {
- retval_record = 1;
- goto exit4;
- }
-
- count = wav.chunk.length;
- fprintf(bat->log, _("Recording ...\n"));
- err = read_from_pcm_loop(fp, count, &sndpcm, bat);
- if (err != 0) {
- retval_record = 1;
- goto exit4;
- }
-
- /* Normally we will never reach this part of code (before fail_exit) as
- this thread will be cancelled by end of play thread. */
- pthread_cleanup_pop(0);
- pthread_cleanup_pop(0);
- pthread_cleanup_pop(0);
-
- snd_pcm_drain(sndpcm.handle);
-
-exit4:
- fclose(fp);
-exit3:
- free(sndpcm.buffer);
-exit2:
- snd_pcm_close(sndpcm.handle);
-exit1:
- pthread_exit(&retval_record);
-}
diff --git a/bat/alsa.h b/bat/alsa.h
deleted file mode 100644
index d5c9972..0000000
--- a/bat/alsa.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) 2013-2015 Intel Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-extern int retval_play;
-extern int retval_record;
-
-void *playback_alsa(struct bat *);
-void *record_alsa(struct bat *);
diff --git a/bat/analyze.c b/bat/analyze.c
deleted file mode 100644
index 60e2d1c..0000000
--- a/bat/analyze.c
+++ /dev/null
@@ -1,314 +0,0 @@
-/*
- * Copyright (C) 2013-2015 Intel Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <stdbool.h>
-#include <stdint.h>
-
-#include <math.h>
-#include <fftw3.h>
-
-#include "aconfig.h"
-#include "gettext.h"
-
-#include "common.h"
-
-static void check_amplitude(struct bat *bat, double *buf)
-{
- double sum, average, amplitude;
- int i, percent;
-
- /* calculate average value */
- for (i = 0, sum = 0.0; i < bat->frames; i++)
- sum += buf[i];
- average = sum / bat->frames;
-
- /* calculate peak-to-average amplitude */
- for (i = 0, sum = 0.0; i < bat->frames; i++)
- sum += abs(buf[i] - average);
- amplitude = sum / bat->frames * M_PI / 2.0;
-
- /* calculate amplitude percentage against full range */
- percent = amplitude * 100 / ((1 << ((bat->sample_size << 3) - 1)) - 1);
-
- fprintf(bat->log, _("Amplitude: %.1f; Percentage: [%d]\n"),
- amplitude, percent);
- if (percent < 0)
- fprintf(bat->err, _("ERROR: Amplitude can't be negative!\n"));
- else if (percent < 1)
- fprintf(bat->err, _("WARNING: Signal too weak!\n"));
- else if (percent > 100)
- fprintf(bat->err, _("WARNING: Signal overflow!\n"));
-}
-
-/**
- *
- * @return 0 if peak detected at right frequency,
- * 1 if peak detected somewhere else
- * 2 if DC detected
- */
-int check_peak(struct bat *bat, struct analyze *a, int end, int peak, float hz,
- float mean, float p, int channel, int start)
-{
- int err;
- float hz_peak = (float) (peak) * hz;
- float delta_rate = DELTA_RATE * bat->target_freq[channel];
- float delta_HZ = DELTA_HZ;
- float tolerance = (delta_rate > delta_HZ) ? delta_rate : delta_HZ;
-
- fprintf(bat->log, _("Detected peak at %2.2f Hz of %2.2f dB\n"), hz_peak,
- 10.0 * log10(a->mag[peak] / mean));
- fprintf(bat->log, _(" Total %3.1f dB from %2.2f to %2.2f Hz\n"),
- 10.0 * log10(p / mean), start * hz, end * hz);
-
- if (hz_peak < DC_THRESHOLD) {
- fprintf(bat->err, _(" WARNING: Found low peak %2.2f Hz,"),
- hz_peak);
- fprintf(bat->err, _(" very close to DC\n"));
- err = FOUND_DC;
- } else if (hz_peak < bat->target_freq[channel] - tolerance) {
- fprintf(bat->err, _(" FAIL: Peak freq too low %2.2f Hz\n"),
- hz_peak);
- err = FOUND_WRONG_PEAK;
- } else if (hz_peak > bat->target_freq[channel] + tolerance) {
- fprintf(bat->err, _(" FAIL: Peak freq too high %2.2f Hz\n"),
- hz_peak);
- err = FOUND_WRONG_PEAK;
- } else {
- fprintf(bat->log, _(" PASS: Peak detected"));
- fprintf(bat->log, _(" at target frequency\n"));
- err = 0;
- }
-
- return err;
-}
-
-/**
- * Search for main frequencies in fft results and compare it to target
- */
-static int check(struct bat *bat, struct analyze *a, int channel)
-{
- float hz = 1.0 / ((float) bat->frames / (float) bat->rate);
- float mean = 0.0, t, sigma = 0.0, p = 0.0;
- int i, start = -1, end = -1, peak = 0, signals = 0;
- int err = 0, N = bat->frames / 2;
-
- /* calculate mean */
- for (i = 0; i < N; i++)
- mean += a->mag[i];
- mean /= (float) N;
-
- /* calculate standard deviation */
- for (i = 0; i < N; i++) {
- t = a->mag[i] - mean;
- t *= t;
- sigma += t;
- }
- sigma /= (float) N;
- sigma = sqrtf(sigma);
-
- /* clip any data less than k sigma + mean */
- for (i = 0; i < N; i++) {
- if (a->mag[i] > mean + bat->sigma_k * sigma) {
-
- /* find peak start points */
- if (start == -1) {
- start = peak = end = i;
- signals++;
- } else {
- if (a->mag[i] > a->mag[peak])
- peak = i;
- end = i;
- }
- p += a->mag[i];
- } else if (start != -1) {
- /* Check if peak is as expected */
- err |= check_peak(bat, a, end, peak, hz, mean,
- p, channel, start);
- end = start = -1;
- if (signals == MAX_PEAKS)
- break;
- }
- }
- if (signals == 0)
- err = -ENOPEAK; /* No peak detected */
- else if ((err == FOUND_DC) && (signals == 1))
- err = -EONLYDC; /* Only DC detected */
- else if ((err & FOUND_WRONG_PEAK) == FOUND_WRONG_PEAK)
- err = -EBADPEAK; /* Bad peak detected */
- else
- err = 0; /* Correct peak detected */
-
- fprintf(bat->log, _("Detected at least %d signal(s) in total\n"),
- signals);
-
- return err;
-}
-
-static void calc_magnitude(struct bat *bat, struct analyze *a, int N)
-{
- double r2, i2;
- int i;
-
- for (i = 1; i < N / 2; i++) {
- r2 = a->out[i] * a->out[i];
- i2 = a->out[N - i] * a->out[N - i];
-
- a->mag[i] = sqrtf(r2 + i2);
- }
- a->mag[0] = 0.0;
-}
-
-static int find_and_check_harmonics(struct bat *bat, struct analyze *a,
- int channel)
-{
- fftw_plan p;
- int err = -ENOMEM, N = bat->frames;
-
- /* Allocate FFT buffers */
- a->in = (double *) fftw_malloc(sizeof(double) * bat->frames);
- if (a->in == NULL)
- goto out1;
-
- a->out = (double *) fftw_malloc(sizeof(double) * bat->frames);
- if (a->out == NULL)
- goto out2;
-
- a->mag = (double *) fftw_malloc(sizeof(double) * bat->frames);
- if (a->mag == NULL)
- goto out3;
-
- /* create FFT plan */
- p = fftw_plan_r2r_1d(N, a->in, a->out, FFTW_R2HC,
- FFTW_MEASURE | FFTW_PRESERVE_INPUT);
- if (p == NULL)
- goto out4;
-
- /* convert source PCM to doubles */
- bat->convert_sample_to_double(a->buf, a->in, bat->frames);
-
- /* check amplitude */
- check_amplitude(bat, a->in);
-
- /* run FFT */
- fftw_execute(p);
-
- /* FFT out is real and imaginary numbers - calc magnitude for each */
- calc_magnitude(bat, a, N);
-
- /* check data */
- err = check(bat, a, channel);
-
- fftw_destroy_plan(p);
-
-out4:
- fftw_free(a->mag);
-out3:
- fftw_free(a->out);
-out2:
- fftw_free(a->in);
-out1:
- return err;
-}
-
-/**
- * Convert interleaved samples from channels in samples from a single channel
- */
-static int reorder_data(struct bat *bat)
-{
- char *p, *new_bat_buf;
- int ch, i, j;
-
- if (bat->channels == 1)
- return 0; /* No need for reordering */
-
- p = malloc(bat->frames * bat->frame_size);
- new_bat_buf = p;
- if (p == NULL)
- return -ENOMEM;
-
- for (ch = 0; ch < bat->channels; ch++) {
- for (j = 0; j < bat->frames; j++) {
- for (i = 0; i < bat->sample_size; i++) {
- *p++ = ((char *) (bat->buf))[j * bat->frame_size
- + ch * bat->sample_size + i];
- }
- }
- }
-
- free(bat->buf);
- bat->buf = new_bat_buf;
-
- return 0;
-}
-
-int analyze_capture(struct bat *bat)
-{
- int err = 0;
- size_t items;
- int c;
- struct analyze a;
-
- fprintf(bat->log, _("\nBAT analysis: signal has %d frames at %d Hz,"),
- bat->frames, bat->rate);
- fprintf(bat->log, _(" %d channels, %d bytes per sample.\n"),
- bat->channels, bat->sample_size);
-
- bat->buf = malloc(bat->frames * bat->frame_size);
- if (bat->buf == NULL)
- return -ENOMEM;
-
- bat->fp = fopen(bat->capture.file, "rb");
- if (bat->fp == NULL) {
- fprintf(bat->err, _("Cannot open file for capture: %s %d\n"),
- bat->capture.file, -errno);
- err = -errno;
- goto exit1;
- }
-
- /* Skip header */
- err = read_wav_header(bat, bat->capture.file, bat->fp, true);
- if (err != 0)
- goto exit2;
-
- items = fread(bat->buf, bat->frame_size, bat->frames, bat->fp);
- if (items != bat->frames) {
- err = -EIO;
- goto exit2;
- }
-
- err = reorder_data(bat);
- if (err != 0)
- goto exit2;
-
- for (c = 0; c < bat->channels; c++) {
- fprintf(bat->log, _("\nChannel %i - "), c + 1);
- fprintf(bat->log, _("Checking for target frequency %2.2f Hz\n"),
- bat->target_freq[c]);
- a.buf = bat->buf +
- c * bat->frames * bat->frame_size
- / bat->channels;
- err = find_and_check_harmonics(bat, &a, c);
- }
-
-exit2:
- fclose(bat->fp);
-exit1:
- free(bat->buf);
-
- return err;
-}
diff --git a/bat/analyze.h b/bat/analyze.h
deleted file mode 100644
index 3fd03d4..0000000
--- a/bat/analyze.h
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * Copyright (C) 2013-2015 Intel Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-int analyze_capture(struct bat *);
diff --git a/bat/bat-signal.h b/bat/bat-signal.h
deleted file mode 100644
index a295517..0000000
--- a/bat/bat-signal.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2015 Caleb Crome
- * Copyright (C) 2013-2015 Intel Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-/*
- * Here's a generic sine wave generator that will work indefinitely
- * for any frequency.
- *
- * Note: the state & phasor are stored as doubles (and updated as
- * doubles) because after a million samples the magnitude drifts a
- * bit. If we really need floats, it can be done with periodic
- * renormalization of the state_real+state_imag magnitudes.
- */
-
-int sin_generator_init(struct sin_generator *, float, float, float);
-float sin_generator_next_sample(struct sin_generator *);
-void sin_generator_vfill(struct sin_generator *, float *, int);
-int generate_sine_wave(struct bat *, int, void *);
diff --git a/bat/bat.1 b/bat/bat.1
deleted file mode 100644
index e00fc27..0000000
--- a/bat/bat.1
+++ /dev/null
@@ -1,158 +0,0 @@
-.TH BAT 1 "20th October 2015"
-.SH NAME
-bat \- command\-line sound tester for ALSA sound card driver
-
-.SH SYNOPSIS
-\fBbat\fP [\fIflags\fP]
-
-.SH DESCRIPTION
-\fBBAT(Basic Audio Tester)\fP is a simple command\-line utility intended
-to help automate audio driver and sound server testing with little human
-interaction. BAT can be used to test audio quality, stress test features
-and test audio before and after PM state changes.
-
-BAT's design is relatively simple. BAT plays an audio stream and captures
-the same stream in either a digital or analog loop back. It then compares
-the captured stream using a FFT to the original to determine if the test
-case passes or fails.
-
-BAT can either run wholly on the target machine being tested (standalone
-mode) or can run as a client/server mode where by bat client runs on the
-target and runs as a server on a separate tester machine. The client/server
-mode still requires some manual interaction for synchronization, but this
-is actively being developed for future releases.
-
-The hardware testing configuration may require the use of an analog cable
-connecting target to tester machines or a cable to create an analog
-loopback if no loopback mode is not available on the sound hardware that
-is being tested.
-An analog loopback cable can be used to connect the "line in" to "line out"
-jacks to create a loopback. If only headphone and mic jacks (or combo jack)
-are available then the following simple circuit can be used to create an
-analog loopback :-
-
-https://source.android.com/devices/audio/loopback.html
-
-.SH OPTIONS
-.TP
-\fI\-h, \-\-help\fP
-Help: show syntax.
-.TP
-\fI\-D\fP
-Select sound card to be tested by name.
-.TP
-\fI\-P\fP
-Select the playback PCM device.
-.TP
-\fI\-C\fP
-Select the capture PCM device.
-.TP
-\fI\-f\fP
-Sample format
-.br
-Recognized sample formats are: U8 S16_LE S24_3LE S32_LE
-.br
-Some of these may not be available on selected hardware
-.br
-The available format shortcuts are:
-.nf
-\-f cd (16 bit little endian, 44100, stereo) [\-f S16_LE \-c2 \-r44100]
-\-f dat (16 bit little endian, 48000, stereo) [\-f S16_LE \-c2 \-r48000]
-.fi
-If no format is given S16_LE is used.
-.TP
-\fI\-c\fP
-The number of channels. The default is one channel.
-Valid values at the moment are 1 or 2.
-.TP
-\fI\-r\fP
-Sampling rate in Hertz. The default rate is 44100 Hertz.
-Valid values depends on hardware support.
-.TP
-\fI\-n\fP
-Duration of generated signal.
-The value could be either of the two forms:
-.br
-1. Decimal integer, means number of frames;
-.br
-2. Floating point with suffix 's', means number of seconds.
-.br
-The default is 2 seconds.
-.TP
-\fI\-k\fP
-Sigma k value for analysis.
-.br
-The analysis function reads data from WAV file, run FFT against the data
-to get magnitude of frequency vectors, and then calculates the average
-value and standard deviation of frequency vectors. After that, we define
-a threshold:
-.br
-threshold = k * standard_deviation + mean_value
-.br
-Frequencies with amplitude larger than threshold will be recognized as a
-peak, and the frequency with largest peak value will be recognized as a
-detected frequency.
-.br
-BAT then compares the detected frequency to target frequency, to decide
-if the detecting passes or fails.
-.br
-The default value is 3.0.
-.TP
-\fI\-F\fP
-Target frequency for signal generation and analysis, in Hertz.
-The default is 997.0 Hertz.
-Valid range is (DC_THRESHOLD, 40% * Sampling rate).
-.TP
-\fI\-p\fP
-Total number of periods to play or capture.
-.TP
-\fI\-\-log=#\fP
-Write stderr and stdout output to this log file.
-.TP
-\fI\-\-file=#\fP
-Input WAV file for playback.
-.TP
-\fI\-\-saveplay=#\fP
-Target WAV file to save capture test content.
-.TP
-\fI\-\-local\fP
-Internal loopback mode.
-Playback, capture and analysis internal to BAT only. This is intended for
-developers to test new BAT features as no audio is routed outside of BAT.
-
-.SH EXAMPLES
-
-.TP
-\fBbat \-P plughw:0,0 \-C plughw:0,0 \-c 2 \-f S32_LE \-F 250\fR
-Generate and play a sine wave of 250 Hertz with 2 channel and S32_LE format,
-and then capture and analyze.
-
-.TP
-\fBbat \-P plughw:0,0 \-C plughw:0,0 \-\-file 500Hz.wav\fR
-Play the RIFF WAV file "500Hz.wav" which contains 500 Hertz waveform LPCM
-data, and then capture and analyze.
-
-.SH RETURN VALUE
-.br
-On success, returns 0.
-.br
-If no peak be detected, returns -1001;
-.br
-If only DC be detected, returns -1002;
-.br
-If peak frequency does not match with the target frequency, returns -1003.
-
-.SH SEE ALSO
-\fB
-aplay(1)
-\fP
-
-.SH BUGS
-Currently only support RIFF WAV format with PCM data. Please report any bugs to
-the alsa-devel mailing list.
-
-.SH AUTHOR
-\fBbat\fP is by Liam Girdwood <liam.r.girdwood at linux.intel.com>, Bernard Gautier
-<bernard.gautier at intel.com> and Han Lu <han.lu at intel.com>.
-This document is by Liam Girdwood <liam.r.girdwood at linux.intel.com> and Han Lu
-<han.lu at intel.com>.
diff --git a/bat/bat.c b/bat/bat.c
deleted file mode 100644
index 086b9fa..0000000
--- a/bat/bat.c
+++ /dev/null
@@ -1,610 +0,0 @@
-/*
- * Copyright (C) 2013-2015 Intel Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#include <unistd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdbool.h>
-#include <string.h>
-#include <errno.h>
-#include <pthread.h>
-#include <getopt.h>
-#include <math.h>
-#include <limits.h>
-#include <locale.h>
-
-#include "aconfig.h"
-#include "gettext.h"
-#include "version.h"
-
-#include "common.h"
-
-#include "alsa.h"
-#include "convert.h"
-#include "analyze.h"
-
-static int get_duration(struct bat *bat)
-{
- float duration_f;
- long duration_i;
- char *ptrf, *ptri;
-
- duration_f = strtof(bat->narg, &ptrf);
- if (duration_f == HUGE_VALF || duration_f == -HUGE_VALF
- || (duration_f == 0.0 && errno != 0))
- goto err_exit;
-
- duration_i = strtol(bat->narg, &ptri, 10);
- if (duration_i == LONG_MAX || duration_i == LONG_MIN)
- goto err_exit;
-
- if (*ptrf == 's')
- bat->frames = duration_f * bat->rate;
- else if (*ptri == 0)
- bat->frames = duration_i;
- else
- bat->frames = -1;
-
- if (bat->frames <= 0 || bat->frames > MAX_FRAMES) {
- fprintf(bat->err, _("Invalid duration. Range: (0, %d(%fs))\n"),
- MAX_FRAMES, (double)MAX_FRAMES / bat->rate);
- return -EINVAL;
- }
-
- return 0;
-
-err_exit:
- fprintf(bat->err, _("Duration overflow/underflow: %d\n"), -errno);
-
- return -errno;
-}
-
-static void get_sine_frequencies(struct bat *bat, char *freq)
-{
- char *tmp1;
-
- tmp1 = strchr(freq, ':');
- if (tmp1 == NULL) {
- bat->target_freq[1] = bat->target_freq[0] = atof(optarg);
- } else {
- *tmp1 = '\0';
- bat->target_freq[0] = atof(optarg);
- bat->target_freq[1] = atof(tmp1 + 1);
- }
-}
-
-static void get_format(struct bat *bat, char *optarg)
-{
- if (strcasecmp(optarg, "cd") == 0) {
- bat->format = SND_PCM_FORMAT_S16_LE;
- bat->rate = 44100;
- bat->channels = 2;
- } else if (strcasecmp(optarg, "dat") == 0) {
- bat->format = SND_PCM_FORMAT_S16_LE;
- bat->rate = 48000;
- bat->channels = 2;
- } else {
- bat->format = snd_pcm_format_value(optarg);
- if (bat->format == SND_PCM_FORMAT_UNKNOWN) {
- fprintf(bat->err, _("wrong extended format '%s'\n"),
- optarg);
- exit(EXIT_FAILURE);
- }
- }
-
- switch (bat->format) {
- case SND_PCM_FORMAT_U8:
- bat->sample_size = 1;
- break;
- case SND_PCM_FORMAT_S16_LE:
- bat->sample_size = 2;
- break;
- case SND_PCM_FORMAT_S24_3LE:
- bat->sample_size = 3;
- break;
- case SND_PCM_FORMAT_S32_LE:
- bat->sample_size = 4;
- break;
- default:
- fprintf(bat->err, _("unsupported format: %d\n"), bat->format);
- exit(EXIT_FAILURE);
- }
-}
-
-static inline int thread_wait_completion(struct bat *bat,
- pthread_t id, int **val)
-{
- int err;
-
- err = pthread_join(id, (void **) val);
- if (err)
- pthread_cancel(id);
-
- return err;
-}
-
-/* loopback test where we play sine wave and capture the same sine wave */
-static void test_loopback(struct bat *bat)
-{
- pthread_t capture_id, playback_id;
- int err;
- int *thread_result_capture, *thread_result_playback;
-
- /* start playback */
- err = pthread_create(&playback_id, NULL,
- (void *) bat->playback.fct, bat);
- if (err != 0) {
- fprintf(bat->err, _("Cannot create playback thread: %d\n"),
- err);
- exit(EXIT_FAILURE);
- }
-
- /* TODO: use a pipe to signal stream start etc - i.e. to sync threads */
- /* Let some time for playing something before capturing */
- usleep(CAPTURE_DELAY * 1000);
-
- /* start capture */
- err = pthread_create(&capture_id, NULL, (void *) bat->capture.fct, bat);
- if (err != 0) {
- fprintf(bat->err, _("Cannot create capture thread: %d\n"), err);
- pthread_cancel(playback_id);
- exit(EXIT_FAILURE);
- }
-
- /* wait for playback to complete */
- err = thread_wait_completion(bat, playback_id, &thread_result_playback);
- if (err != 0) {
- fprintf(bat->err, _("Cannot join playback thread: %d\n"), err);
- free(thread_result_playback);
- pthread_cancel(capture_id);
- exit(EXIT_FAILURE);
- }
-
- /* check playback status */
- if (*thread_result_playback != 0) {
- fprintf(bat->err, _("Exit playback thread fail: %d\n"),
- *thread_result_playback);
- pthread_cancel(capture_id);
- exit(EXIT_FAILURE);
- } else {
- fprintf(bat->log, _("Playback completed.\n"));
- }
-
- /* now stop and wait for capture to finish */
- pthread_cancel(capture_id);
- err = thread_wait_completion(bat, capture_id, &thread_result_capture);
- if (err != 0) {
- fprintf(bat->err, _("Cannot join capture thread: %d\n"), err);
- free(thread_result_capture);
- exit(EXIT_FAILURE);
- }
-
- /* check capture status */
- if (*thread_result_capture != 0) {
- fprintf(bat->err, _("Exit capture thread fail: %d\n"),
- *thread_result_capture);
- exit(EXIT_FAILURE);
- } else {
- fprintf(bat->log, _("Capture completed.\n"));
- }
-}
-
-/* single ended playback only test */
-static void test_playback(struct bat *bat)
-{
- pthread_t playback_id;
- int err;
- int *thread_result;
-
- /* start playback */
- err = pthread_create(&playback_id, NULL,
- (void *) bat->playback.fct, bat);
- if (err != 0) {
- fprintf(bat->err, _("Cannot create playback thread: %d\n"),
- err);
- exit(EXIT_FAILURE);
- }
-
- /* wait for playback to complete */
- err = thread_wait_completion(bat, playback_id, &thread_result);
- if (err != 0) {
- fprintf(bat->err, _("Cannot join playback thread: %d\n"), err);
- free(thread_result);
- exit(EXIT_FAILURE);
- }
-
- /* check playback status */
- if (*thread_result != 0) {
- fprintf(bat->err, _("Exit playback thread fail: %d\n"),
- *thread_result);
- exit(EXIT_FAILURE);
- } else {
- fprintf(bat->log, _("Playback completed.\n"));
- }
-}
-
-/* single ended capture only test */
-static void test_capture(struct bat *bat)
-{
- pthread_t capture_id;
- int err;
- int *thread_result;
-
- /* start capture */
- err = pthread_create(&capture_id, NULL, (void *) bat->capture.fct, bat);
- if (err != 0) {
- fprintf(bat->err, _("Cannot create capture thread: %d\n"), err);
- exit(EXIT_FAILURE);
- }
-
- /* TODO: stop capture */
-
- /* wait for capture to complete */
- err = thread_wait_completion(bat, capture_id, &thread_result);
- if (err != 0) {
- fprintf(bat->err, _("Cannot join capture thread: %d\n"), err);
- free(thread_result);
- exit(EXIT_FAILURE);
- }
-
- /* check playback status */
- if (*thread_result != 0) {
- fprintf(bat->err, _("Exit capture thread fail: %d\n"),
- *thread_result);
- exit(EXIT_FAILURE);
- } else {
- fprintf(bat->log, _("Capture completed.\n"));
- }
-}
-
-static void usage(struct bat *bat)
-{
- fprintf(bat->log,
-_("Usage: bat [-options]...\n"
-"\n"
-" -h, --help this help\n"
-" -D pcm device for both playback and capture\n"
-" -P pcm device for playback\n"
-" -C pcm device for capture\n"
-" -f sample format\n"
-" -c number of channels\n"
-" -r sampling rate\n"
-" -n frames to playback or capture\n"
-" -k parameter for frequency detecting threshold\n"
-" -F target frequency\n"
-" -p total number of periods to play/capture\n"
-" --log=# file that both stdout and strerr redirecting to\n"
-" --file=# file for playback\n"
-" --saveplay=# file that storing playback content, for debug\n"
-" --local internal loop, set to bypass pcm hardware devices\n"
-));
- fprintf(bat->log, _("Recognized sample formats are: %s %s %s %s\n"),
- snd_pcm_format_name(SND_PCM_FORMAT_U8),
- snd_pcm_format_name(SND_PCM_FORMAT_S16_LE),
- snd_pcm_format_name(SND_PCM_FORMAT_S24_3LE),
- snd_pcm_format_name(SND_PCM_FORMAT_S32_LE));
- fprintf(bat->log, _("The available format shotcuts are:\n"));
- fprintf(bat->log, _("-f cd (16 bit little endian, 44100, stereo)\n"));
- fprintf(bat->log, _("-f dat (16 bit little endian, 48000, stereo)\n"));
-}
-
-static void set_defaults(struct bat *bat)
-{
- memset(bat, 0, sizeof(struct bat));
-
- /* Set default values */
- bat->rate = 44100;
- bat->channels = 1;
- bat->frame_size = 2;
- bat->sample_size = 2;
- bat->format = SND_PCM_FORMAT_S16_LE;
- bat->convert_float_to_sample = convert_float_to_int16;
- bat->convert_sample_to_double = convert_int16_to_double;
- bat->frames = bat->rate * 2;
- bat->target_freq[0] = 997.0;
- bat->target_freq[1] = 997.0;
- bat->sigma_k = 3.0;
- bat->playback.device = NULL;
- bat->capture.device = NULL;
- bat->buf = NULL;
- bat->local = false;
- bat->playback.fct = &playback_alsa;
- bat->capture.fct = &record_alsa;
- bat->playback.mode = MODE_LOOPBACK;
- bat->capture.mode = MODE_LOOPBACK;
- bat->period_is_limited = false;
- bat->log = stdout;
- bat->err = stderr;
-}
-
-static void parse_arguments(struct bat *bat, int argc, char *argv[])
-{
- int c, option_index;
- static const char short_options[] = "D:P:C:f:n:F:c:r:s:k:p:lth";
- static const struct option long_options[] = {
- {"help", 0, 0, 'h'},
- {"log", 1, 0, OPT_LOG},
- {"file", 1, 0, OPT_READFILE},
- {"saveplay", 1, 0, OPT_SAVEPLAY},
- {"local", 0, 0, OPT_LOCAL},
- {0, 0, 0, 0}
- };
-
- while ((c = getopt_long(argc, argv, short_options, long_options,
- &option_index)) != -1) {
- switch (c) {
- case OPT_LOG:
- bat->logarg = optarg;
- break;
- case OPT_READFILE:
- bat->playback.file = optarg;
- break;
- case OPT_SAVEPLAY:
- bat->debugplay = optarg;
- break;
- case OPT_LOCAL:
- bat->local = true;
- break;
- case 'D':
- if (bat->playback.device == NULL)
- bat->playback.device = optarg;
- if (bat->capture.device == NULL)
- bat->capture.device = optarg;
- break;
- case 'P':
- if (bat->capture.mode == MODE_SINGLE)
- bat->capture.mode = MODE_LOOPBACK;
- else
- bat->playback.mode = MODE_SINGLE;
- bat->playback.device = optarg;
- break;
- case 'C':
- if (bat->playback.mode == MODE_SINGLE)
- bat->playback.mode = MODE_LOOPBACK;
- else
- bat->capture.mode = MODE_SINGLE;
- bat->capture.device = optarg;
- break;
- case 'n':
- bat->narg = optarg;
- break;
- case 'F':
- get_sine_frequencies(bat, optarg);
- break;
- case 'c':
- bat->channels = atoi(optarg);
- break;
- case 'r':
- bat->rate = atoi(optarg);
- break;
- case 'f':
- get_format(bat, optarg);
- break;
- case 'k':
- bat->sigma_k = atof(optarg);
- break;
- case 'p':
- bat->periods_total = atoi(optarg);
- bat->period_is_limited = true;
- break;
- case 'h':
- default:
- usage(bat);
- exit(EXIT_SUCCESS);
- }
- }
-}
-
-static int validate_options(struct bat *bat)
-{
- int c;
- float freq_low, freq_high;
-
- /* check if we have an input file for local mode */
- if ((bat->local == true) && (bat->capture.file == NULL)) {
- fprintf(bat->err, _("no input file for local testing\n"));
- return -EINVAL;
- }
-
- /* check supported channels */
- if (bat->channels > MAX_CHANNELS || bat->channels < MIN_CHANNELS) {
- fprintf(bat->err, _("%d channels not supported\n"),
- bat->channels);
- return -EINVAL;
- }
-
- /* check single ended is in either playback or capture - not both */
- if ((bat->playback.mode == MODE_SINGLE)
- && (bat->capture.mode == MODE_SINGLE)) {
- fprintf(bat->err, _("single ended mode is simplex\n"));
- return -EINVAL;
- }
-
- /* check sine wave frequency range */
- freq_low = DC_THRESHOLD;
- freq_high = bat->rate * RATE_FACTOR;
- for (c = 0; c < bat->channels; c++) {
- if (bat->target_freq[c] < freq_low
- || bat->target_freq[c] > freq_high) {
- fprintf(bat->err, _("sine wave frequency out of"));
- fprintf(bat->err, _(" range: (%.1f, %.1f)\n"),
- freq_low, freq_high);
- return -EINVAL;
- }
- }
-
- return 0;
-}
-
-static int bat_init(struct bat *bat)
-{
- int err = 0;
- char name[] = TEMP_RECORD_FILE_NAME;
-
- /* Determine logging to a file or stdout and stderr */
- if (bat->logarg) {
- bat->log = NULL;
- bat->log = fopen(bat->logarg, "wb");
- if (bat->log == NULL) {
- fprintf(bat->err, _("Cannot open file for capture:"));
- fprintf(bat->err, _(" %s %d\n"),
- bat->logarg, -errno);
- return -errno;
- }
- bat->err = bat->log;
- }
-
- /* Determine duration of playback and/or capture */
- if (bat->narg) {
- err = get_duration(bat);
- if (err < 0)
- return err;
- }
-
- /* Determine capture file */
- if (bat->local) {
- bat->capture.file = bat->playback.file;
- } else {
- /* create temp file for sound record and analysis */
- err = mkstemp(name);
- if (err == -1) {
- fprintf(bat->err, _("Fail to create record file: %d\n"),
- -errno);
- return -errno;
- }
- /* store file name which is dynamically created */
- bat->capture.file = strdup(name);
- if (bat->capture.file == NULL)
- return -errno;
- /* close temp file */
- close(err);
- }
-
- /* Initial for playback */
- if (bat->playback.file == NULL) {
- /* No input file so we will generate our own sine wave */
- if (bat->frames) {
- if (bat->playback.mode == MODE_SINGLE) {
- /* Play nb of frames given by -n argument */
- bat->sinus_duration = bat->frames;
- } else {
- /* Play CAPTURE_DELAY msec +
- * 150% of the nb of frames to be analyzed */
- bat->sinus_duration = bat->rate *
- CAPTURE_DELAY / 1000;
- bat->sinus_duration +=
- (bat->frames + bat->frames / 2);
- }
- } else {
- /* Special case where we want to generate a sine wave
- * endlessly without capturing */
- bat->sinus_duration = 0;
- bat->playback.mode = MODE_SINGLE;
- }
- } else {
- bat->fp = fopen(bat->playback.file, "rb");
- if (bat->fp == NULL) {
- fprintf(bat->err, _("Cannot open file for playback:"));
- fprintf(bat->err, _(" %s %d\n"),
- bat->playback.file, -errno);
- return -errno;
- }
- err = read_wav_header(bat, bat->playback.file, bat->fp, false);
- fclose(bat->fp);
- if (err != 0)
- return err;
- }
-
- bat->frame_size = bat->sample_size * bat->channels;
-
- /* Set conversion functions */
- switch (bat->sample_size) {
- case 1:
- bat->convert_float_to_sample = convert_float_to_uint8;
- bat->convert_sample_to_double = convert_uint8_to_double;
- break;
- case 2:
- bat->convert_float_to_sample = convert_float_to_int16;
- bat->convert_sample_to_double = convert_int16_to_double;
- break;
- case 3:
- bat->convert_float_to_sample = convert_float_to_int24;
- bat->convert_sample_to_double = convert_int24_to_double;
- break;
- case 4:
- bat->convert_float_to_sample = convert_float_to_int32;
- bat->convert_sample_to_double = convert_int32_to_double;
- break;
- default:
- fprintf(bat->err, _("Invalid PCM format: size=%d\n"),
- bat->sample_size);
- return -EINVAL;
- }
-
- return err;
-}
-
-int main(int argc, char *argv[])
-{
- struct bat bat;
- int err = 0;
-
- set_defaults(&bat);
-
-#ifdef ENABLE_NLS
- setlocale(LC_ALL, "");
- textdomain(PACKAGE);
-#endif
-
- fprintf(bat.log, _("%s version %s\n\n"), PACKAGE_NAME, PACKAGE_VERSION);
-
- parse_arguments(&bat, argc, argv);
-
- err = bat_init(&bat);
- if (err < 0)
- goto out;
-
- err = validate_options(&bat);
- if (err < 0)
- goto out;
-
- /* single line playback thread: playback only, no capture */
- if (bat.playback.mode == MODE_SINGLE) {
- test_playback(&bat);
- goto out;
- }
-
- /* single line capture thread: capture only, no playback */
- if (bat.capture.mode == MODE_SINGLE) {
- test_capture(&bat);
- goto analyze;
- }
-
- /* loopback thread: playback and capture in a loop */
- if (bat.local == false)
- test_loopback(&bat);
-
-analyze:
- err = analyze_capture(&bat);
-out:
- fprintf(bat.log, _("\nReturn value is %d\n"), err);
-
- if (bat.logarg)
- fclose(bat.log);
- if (!bat.local)
- free(bat.capture.file);
-
- return err;
-}
diff --git a/bat/common.c b/bat/common.c
deleted file mode 100644
index 798b00b..0000000
--- a/bat/common.c
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * Copyright (C) 2013-2015 Intel Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#include <stdio.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <stdbool.h>
-#include <errno.h>
-
-#include "aconfig.h"
-#include "gettext.h"
-
-#include "common.h"
-#include "alsa.h"
-
-int retval_play;
-int retval_record;
-
-/* update chunk_fmt data to bat */
-static int update_fmt_to_bat(struct bat *bat, struct chunk_fmt *fmt)
-{
- bat->channels = fmt->channels;
- bat->rate = fmt->sample_rate;
- bat->sample_size = fmt->sample_length / 8;
- if (bat->sample_size > 4) {
- fprintf(bat->err, _("Invalid format: sample size=%d\n"),
- bat->sample_size);
- return -EINVAL;
- }
- bat->frame_size = fmt->blocks_align;
-
- return 0;
-}
-
-/* calculate frames and update to bat */
-static int update_frames_to_bat(struct bat *bat,
- struct wav_chunk_header *header, FILE *fp)
-{
- /* The number of analyzed captured frames is arbitrarily set to half of
- the number of frames of the wav file or the number of frames of the
- wav file when doing direct analysis (--local) */
- bat->frames = header->length / bat->frame_size;
- if (!bat->local)
- bat->frames /= 2;
-
- return 0;
-}
-
-static int read_chunk_fmt(struct bat *bat, char *file, FILE *fp, bool skip,
- struct wav_chunk_header *header)
-{
- size_t err;
- int header_skip;
- struct chunk_fmt chunk_fmt;
-
- err = fread(&chunk_fmt, sizeof(chunk_fmt), 1, fp);
- if (err != 1) {
- fprintf(bat->err, _("Read chunk fmt error: %s:%zd\n"),
- file, err);
- return -EIO;
- }
- /* If the format header is larger, skip the rest */
- header_skip = header->length - sizeof(chunk_fmt);
- if (header_skip > 0) {
- err = fseek(fp, header_skip, SEEK_CUR);
- if (err == -1) {
- fprintf(bat->err, _("Seek fmt header error: %s:%zd\n"),
- file, err);
- return -EINVAL;
- }
- }
- /* If the file is opened for playback, update BAT data;
- If the file is opened for analysis, no update */
- if (skip == false) {
- err = update_fmt_to_bat(bat, &chunk_fmt);
- if (err != 0)
- return err;
- }
-
- return 0;
-}
-
-int read_wav_header(struct bat *bat, char *file, FILE *fp, bool skip)
-{
- struct wav_header riff_wave_header;
- struct wav_chunk_header chunk_header;
- int more_chunks = 1;
- size_t err;
-
- /* Read header of RIFF wav file */
- err = fread(&riff_wave_header, sizeof(riff_wave_header), 1, fp);
- if (err != 1) {
- fprintf(bat->err, _("Read header error: %s:%zd\n"), file, err);
- return -EIO;
- }
- if ((riff_wave_header.magic != WAV_RIFF)
- || (riff_wave_header.type != WAV_WAVE)) {
- fprintf(bat->err, _("%s is not a riff/wave file\n"), file);
- return -EINVAL;
- }
-
- /* Read chunks in RIFF wav file */
- do {
- err = fread(&chunk_header, sizeof(chunk_header), 1, fp);
- if (err != 1) {
- fprintf(bat->err, _("Read chunk header error: "));
- fprintf(bat->err, _("%s:%zd\n"), file, err);
- return -EIO;
- }
-
- switch (chunk_header.type) {
- case WAV_FMT:
- /* WAV_FMT chunk, read and analyze */
- err = read_chunk_fmt(bat, file, fp, skip,
- &chunk_header);
- if (err != 0)
- return err;
- break;
- case WAV_DATA:
- /* WAV_DATA chunk, break looping */
- /* If the file is opened for playback, update BAT data;
- If the file is opened for analysis, no update */
- if (skip == false) {
- err = update_frames_to_bat(bat, &chunk_header,
- fp);
- if (err != 0)
- return err;
- }
- /* Stop looking for chunks */
- more_chunks = 0;
- break;
- default:
- /* Unknown chunk, skip bytes */
- err = fseek(fp, chunk_header.length, SEEK_CUR);
- if (err == -1) {
- fprintf(bat->err, _("Fail to skip unknown"));
- fprintf(bat->err, _(" chunk of %s:%zd\n"),
- file, err);
- return -EINVAL;
- }
- }
- } while (more_chunks);
-
- return 0;
-}
-
-void prepare_wav_info(struct wav_container *wav, struct bat *bat)
-{
- wav->header.magic = WAV_RIFF;
- wav->header.type = WAV_WAVE;
- wav->format.magic = WAV_FMT;
- wav->format.fmt_size = 16;
- wav->format.format = WAV_FORMAT_PCM;
- wav->format.channels = bat->channels;
- wav->format.sample_rate = bat->rate;
- wav->format.sample_length = bat->sample_size * 8;
- wav->format.blocks_align = bat->channels * bat->sample_size;
- wav->format.bytes_p_second = wav->format.blocks_align * bat->rate;
- wav->chunk.length = bat->frames * bat->frame_size;
- wav->chunk.type = WAV_DATA;
- wav->header.length = (wav->chunk.length) + sizeof(wav->chunk)
- + sizeof(wav->format) + sizeof(wav->header) - 8;
-}
-
-int write_wav_header(FILE *fp, struct wav_container *wav, struct bat *bat)
-{
- int err = 0;
-
- err = fwrite(&wav->header, 1, sizeof(wav->header), fp);
- if (err != sizeof(wav->header)) {
- fprintf(bat->err, _("Write file error: header %d\n"), err);
- return -EIO;
- }
- err = fwrite(&wav->format, 1, sizeof(wav->format), fp);
- if (err != sizeof(wav->format)) {
- fprintf(bat->err, _("Write file error: format %d\n"), err);
- return -EIO;
- }
- err = fwrite(&wav->chunk, 1, sizeof(wav->chunk), fp);
- if (err != sizeof(wav->chunk)) {
- fprintf(bat->err, _("Write file error: chunk %d\n"), err);
- return -EIO;
- }
-
- return 0;
-}
diff --git a/bat/common.h b/bat/common.h
deleted file mode 100644
index c04452d..0000000
--- a/bat/common.h
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * Copyright (C) 2013-2015 Intel Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#include <alsa/asoundlib.h>
-
-#define TEMP_RECORD_FILE_NAME "/tmp/bat.wav.XXXXXX"
-
-#define OPT_BASE 300
-#define OPT_LOG (OPT_BASE + 1)
-#define OPT_READFILE (OPT_BASE + 2)
-#define OPT_SAVEPLAY (OPT_BASE + 3)
-#define OPT_LOCAL (OPT_BASE + 4)
-
-#define COMPOSE(a, b, c, d) ((a) | ((b)<<8) | ((c)<<16) | ((d)<<24))
-#define WAV_RIFF COMPOSE('R', 'I', 'F', 'F')
-#define WAV_WAVE COMPOSE('W', 'A', 'V', 'E')
-#define WAV_FMT COMPOSE('f', 'm', 't', ' ')
-#define WAV_DATA COMPOSE('d', 'a', 't', 'a')
-#define WAV_FORMAT_PCM 1 /* PCM WAVE file encoding */
-
-#define MAX_CHANNELS 2
-#define MIN_CHANNELS 1
-#define MAX_PEAKS 10
-#define MAX_FRAMES (10 * 1024 * 1024)
-/* Given in ms */
-#define CAPTURE_DELAY 500
-/* signal frequency should be less than samplerate * RATE_FACTOR */
-#define RATE_FACTOR 0.4
-/* valid range of samplerate: (1 - RATE_RANGE, 1 + RATE_RANGE) * samplerate */
-#define RATE_RANGE 0.05
-/* Given in us */
-#define MAX_BUFFERTIME 500000
-/* devide factor, was 4, changed to 8 to remove reduce capture overrun */
-#define DIV_BUFFERTIME 8
-/* margin to avoid sign inversion when generate sine wav */
-#define RANGE_FACTOR 0.95
-
-#define EBATBASE 1000
-#define ENOPEAK (EBATBASE + 1)
-#define EONLYDC (EBATBASE + 2)
-#define EBADPEAK (EBATBASE + 3)
-
-#define DC_THRESHOLD 7.01
-
-/* tolerance of detected peak = max (DELTA_HZ, DELTA_RATE * target_freq).
- * If DELTA_RATE is too high, BAT may not be able to recognize negative result;
- * if too low, BAT may be too sensitive and results in uncecessary failure. */
-#define DELTA_RATE 0.005
-#define DELTA_HZ 1
-
-#define FOUND_DC (1<<1)
-#define FOUND_WRONG_PEAK (1<<0)
-
-struct wav_header {
- unsigned int magic; /* 'RIFF' */
- unsigned int length; /* file len */
- unsigned int type; /* 'WAVE' */
-};
-
-struct wav_chunk_header {
- unsigned int type; /* 'data' */
- unsigned int length; /* sample count */
-};
-
-struct wav_fmt {
- unsigned int magic; /* 'FMT '*/
- unsigned int fmt_size; /* 16 or 18 */
- unsigned short format; /* see WAV_FMT_* */
- unsigned short channels;
- unsigned int sample_rate; /* Frequency of sample */
- unsigned int bytes_p_second;
- unsigned short blocks_align; /* sample size; 1 or 2 bytes */
- unsigned short sample_length; /* 8, 12 or 16 bit */
-};
-
-struct chunk_fmt {
- unsigned short format; /* see WAV_FMT_* */
- unsigned short channels;
- unsigned int sample_rate; /* Frequency of sample */
- unsigned int bytes_p_second;
- unsigned short blocks_align; /* sample size; 1 or 2 bytes */
- unsigned short sample_length; /* 8, 12 or 16 bit */
-};
-
-struct wav_container {
- struct wav_header header;
- struct wav_fmt format;
- struct wav_chunk_header chunk;
-};
-
-struct bat;
-
-enum _bat_op_mode {
- MODE_UNKNOWN = -1,
- MODE_SINGLE = 0,
- MODE_LOOPBACK,
- MODE_LAST
-};
-
-struct pcm {
- char *device;
- char *file;
- enum _bat_op_mode mode;
- void *(*fct)(struct bat *);
-};
-
-struct sin_generator;
-
-struct sin_generator {
- double state_real;
- double state_imag;
- double phasor_real;
- double phasor_imag;
- float frequency;
- float sample_rate;
- float magnitude;
-};
-
-struct bat {
- unsigned int rate; /* sampling rate */
- int channels; /* nb of channels */
- int frames; /* nb of frames */
- int frame_size; /* size of frame */
- int sample_size; /* size of sample */
- snd_pcm_format_t format; /* PCM format */
-
- float sigma_k; /* threshold for peak detection */
- float target_freq[MAX_CHANNELS];
-
- int sinus_duration; /* number of frames for playback */
- char *narg; /* argument string of duration */
- char *logarg; /* path name of log file */
- char *debugplay; /* path name to store playback signal */
-
- struct pcm playback;
- struct pcm capture;
-
- unsigned int periods_played;
- unsigned int periods_total;
- bool period_is_limited;
-
- FILE *fp;
-
- FILE *log;
- FILE *err;
-
- void (*convert_sample_to_double)(void *, double *, int);
- void (*convert_float_to_sample)(float *, void *, int, int);
-
- void *buf; /* PCM Buffer */
-
- bool local; /* true for internal test */
-};
-
-struct analyze {
- void *buf;
- double *in;
- double *out;
- double *mag;
-};
-
-void prepare_wav_info(struct wav_container *, struct bat *);
-int read_wav_header(struct bat *, char *, FILE *, bool);
-int write_wav_header(FILE *, struct wav_container *, struct bat *);
diff --git a/bat/convert.c b/bat/convert.c
deleted file mode 100644
index dcbe912..0000000
--- a/bat/convert.c
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (C) 2013-2015 Intel Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#include <stdio.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <stdint.h>
-
-void convert_uint8_to_double(void *buf, double *val, int samples)
-{
- int i;
-
- for (i = 0; i < samples; i++)
- val[i] = ((uint8_t *) buf)[i];
-}
-
-void convert_int16_to_double(void *buf, double *val, int samples)
-{
- int i;
-
- for (i = 0; i < samples; i++)
- val[i] = ((int16_t *) buf)[i];
-}
-
-void convert_int24_to_double(void *buf, double *val, int samples)
-{
- int i;
- int32_t tmp;
-
- for (i = 0; i < samples; i++) {
- tmp = ((uint8_t *) buf)[i * 3 + 2] << 24;
- tmp |= ((uint8_t *) buf)[i * 3 + 1] << 16;
- tmp |= ((uint8_t *) buf)[i * 3] << 8;
- tmp >>= 8;
- val[i] = tmp;
- }
-}
-
-void convert_int32_to_double(void *buf, double *val, int samples)
-{
- int i;
-
- for (i = 0; i < samples; i++)
- val[i] = ((int32_t *) buf)[i];
-}
-
-void convert_float_to_uint8(float *val, void *buf, int samples, int channels)
-{
- int i, c, idx;
-
- for (i = 0; i < samples; i++) {
- for (c = 0; c < channels; c++) {
- idx = i * channels + c;
- ((uint8_t *) buf)[idx] = (uint8_t) val[idx];
- }
- }
-}
-
-void convert_float_to_int16(float *val, void *buf, int samples, int channels)
-{
- int i, c, idx;
-
- for (i = 0; i < samples; i++) {
- for (c = 0; c < channels; c++) {
- idx = i * channels + c;
- ((int16_t *) buf)[idx] = (int16_t) val[idx];
- }
- }
-}
-
-void convert_float_to_int24(float *val, void *buf, int samples, int channels)
-{
- int i, c, idx_f, idx_i;
- int32_t val_f_i;
-
- for (i = 0; i < samples; i++) {
- for (c = 0; c < channels; c++) {
- idx_f = i * channels + c;
- idx_i = 3 * idx_f;
- val_f_i = (int32_t) val[idx_f];
- ((int8_t *) buf)[idx_i + 0] =
- (int8_t) (val_f_i & 0xff);
- ((int8_t *) buf)[idx_i + 1] =
- (int8_t) ((val_f_i >> 8) & 0xff);
- ((int8_t *) buf)[idx_i + 2] =
- (int8_t) ((val_f_i >> 16) & 0xff);
- }
- }
-}
-
-void convert_float_to_int32(float *val, void *buf, int samples, int channels)
-{
- int i, c, idx;
-
- for (i = 0; i < samples; i++) {
- for (c = 0; c < channels; c++) {
- idx = i * channels + c;
- ((int32_t *) buf)[idx] = (int32_t) val[idx];
- }
- }
-}
diff --git a/bat/convert.h b/bat/convert.h
deleted file mode 100644
index 28828ba..0000000
--- a/bat/convert.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2013-2015 Intel Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-void convert_uint8_to_double(void *, double *, int);
-void convert_int16_to_double(void *, double *, int);
-void convert_int24_to_double(void *, double *, int);
-void convert_int32_to_double(void *, double *, int);
-void convert_float_to_uint8(float *, void *, int, int);
-void convert_float_to_int16(float *, void *, int, int);
-void convert_float_to_int24(float *, void *, int, int);
-void convert_float_to_int32(float *, void *, int, int);
diff --git a/bat/signal.c b/bat/signal.c
deleted file mode 100644
index 8026a35..0000000
--- a/bat/signal.c
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * Copyright (C) 2015 Caleb Crome
- * Copyright (C) 2013-2015 Intel Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-/*
- * This is a general purpose sine wave generator that will stay stable
- * for a long time, and with a little renormalization, could stay stay
- * stable indefinitely
- */
-
-#include <stdio.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <math.h>
-#include <stdint.h>
-#include <stdbool.h>
-
-#include "gettext.h"
-#include "common.h"
-#include "signal.h"
-
-/*
- * Initialize the sine wave generator.
- * sin_generator: gets initialized by this call.
- * frequency: the frequency for the sine wave. must be < 0.5*sample_rate
- * sample_rate: the sample rate...
- * returns 0 on success, -1 on error.
- */
-int sin_generator_init(struct sin_generator *sg, float magnitude,
- float frequency, float sample_rate)
-{
- /* angular frequency: cycles/sec / (samp/sec) * rad/cycle = rad/samp */
- float w = frequency / sample_rate * 2 * M_PI;
- if (frequency >= sample_rate / 2)
- return -1;
- sg->phasor_real = cos(w);
- sg->phasor_imag = sin(w);
- sg->magnitude = magnitude;
- sg->state_real = 0.0;
- sg->state_imag = magnitude;
- sg->frequency = frequency;
- sg->sample_rate = sample_rate;
- return 0;
-}
-
-/*
- * Generates the next sample in the sine wave.
- * should be much faster than calling a sin function
- * if it's inlined and optimized.
- *
- * returns the next value. no possibility of error.
- */
-float sin_generator_next_sample(struct sin_generator *sg)
-{
- /* get shorthand to pointers */
- const double pr = sg->phasor_real;
- const double pi = sg->phasor_imag;
- const double sr = sg->state_real;
- const double si = sg->state_imag;
- /* step the phasor -- complex multiply */
- sg->state_real = sr * pr - si * pi;
- sg->state_imag = sr * pi + pr * si;
- /* return the input value so sine wave starts at exactly 0.0 */
- return sr;
-}
-
-/* fills a vector with a sine wave */
-void sin_generator_vfill(struct sin_generator *sg, float *buf, int n)
-{
- int i;
- for (i = 0; i < n; i++)
- *buf++ = sin_generator_next_sample(sg);
-}
-
-static int reorder(struct bat *bat, float *val, int frames)
-{
- float *new_buf = NULL;
- int i, c, bytes;
-
- bytes = frames * bat->channels * sizeof(float);
-
- new_buf = (float *) malloc(bytes);
- if (new_buf == NULL) {
- fprintf(bat->err, _("Not enough memory.\n"));
- return -ENOMEM;
- }
-
- memcpy(new_buf, val, bytes);
- for (i = 0; i < frames; i++)
- for (c = 0; c < bat->channels; c++)
- val[i * bat->channels + c] =
- new_buf[c * frames + i];
- free(new_buf);
-
- return 0;
-}
-
-static int adjust_waveform(struct bat *bat, float *val, int frames)
-{
- int i, nsamples, max;
- float factor, offset = 0.0;
-
- switch (bat->format) {
- case SND_PCM_FORMAT_U8:
- max = INT8_MAX;
- offset = max; /* shift for unsigned format */
- break;
- case SND_PCM_FORMAT_S16_LE:
- max = INT16_MAX;
- break;
- case SND_PCM_FORMAT_S24_3LE:
- max = (1 << 23) - 1;
- break;
- case SND_PCM_FORMAT_S32_LE:
- max = INT32_MAX;
- break;
- default:
- fprintf(bat->err, _("Invalid PCM format: %s\n"),
- snd_pcm_format_name(bat->format));
- return -EINVAL;
- }
-
- factor = max * RANGE_FACTOR;
- nsamples = bat->channels * frames;
-
- for (i = 0; i < nsamples; i++)
- val[i] = val[i] * factor + offset;
-
- return 0;
-}
-
-int generate_sine_wave(struct bat *bat, int frames, void *buf)
-{
- int err = 0;
- int c, nsamples;
- float *sinus_f = NULL;
- static struct sin_generator sg[MAX_CHANNELS];
-
- nsamples = bat->channels * frames;
- sinus_f = (float *) malloc(nsamples * sizeof(float));
- if (sinus_f == NULL) {
- fprintf(bat->err, _("Not enough memory.\n"));
- return -ENOMEM;
- }
-
- for (c = 0; c < bat->channels; c++) {
- /* initialize static struct at the first time */
- if (sg[c].frequency != bat->target_freq[c])
- sin_generator_init(&sg[c], 1.0, bat->target_freq[c],
- bat->rate);
- /* fill buffer for each channel */
- sin_generator_vfill(&sg[c], sinus_f + c * frames, frames);
- }
-
- /* reorder samples to interleaved mode */
- err = reorder(bat, sinus_f, frames);
- if (err != 0)
- return err;
-
- /* adjust amplitude and offset of waveform */
- err = adjust_waveform(bat, sinus_f, frames);
- if (err != 0)
- return err;
-
- bat->convert_float_to_sample(sinus_f, buf, frames, bat->channels);
-
- free(sinus_f);
-
- return 0;
-}
diff --git a/configure.ac b/configure.ac
index bdb133c..8f3be98 100644
--- a/configure.ac
+++ b/configure.ac
@@ -49,20 +49,20 @@ AM_CONDITIONAL(HAVE_UCM, test "$have_ucm" = "yes")
AM_CONDITIONAL(HAVE_TOPOLOGY, test "$have_topology" = "yes")
AM_CONDITIONAL(HAVE_SAMPLERATE, test "$have_samplerate" = "yes")
-dnl Disable bat
-bat=
+dnl Disable alsabat
+alsabat=
if test "$have_pcm" = "yes"; then
-AC_ARG_ENABLE(bat,
- AS_HELP_STRING([--disable-bat], [Disable bat compilation]),
+AC_ARG_ENABLE(alsabat,
+ AS_HELP_STRING([--disable-alsabat], [Disable alsabat compilation]),
[case "${enableval}" in
- yes) bat=true ;;
- no) bat=false ;;
- *) AC_MSG_ERROR(bad value ${enableval} for --enable-bat) ;;
- esac],[bat=true])
+ yes) alsabat=true ;;
+ no) alsabat=false ;;
+ *) AC_MSG_ERROR(bad value ${enableval} for --enable-alsabat) ;;
+ esac],[alsabat=true])
fi
-AM_CONDITIONAL(BAT, test x$bat = xtrue)
+AM_CONDITIONAL(ALSABAT, test x$alsabat = xtrue)
-if test x$bat = xtrue; then
+if test x$alsabat = xtrue; then
saved_CFLAGS="$CFLAGS"
saved_LDFLAGS="$LDFLAGS"
@@ -382,7 +382,7 @@ AC_OUTPUT(Makefile alsactl/Makefile alsactl/init/Makefile \
m4/Makefile po/Makefile.in \
alsaconf/alsaconf alsaconf/Makefile \
alsaconf/po/Makefile \
- alsaucm/Makefile topology/Makefile bat/Makefile \
+ alsaucm/Makefile topology/Makefile alsabat/Makefile \
aplay/Makefile include/Makefile iecset/Makefile utils/Makefile \
utils/alsa-utils.spec seq/Makefile seq/aconnect/Makefile \
seq/aplaymidi/Makefile seq/aseqdump/Makefile seq/aseqnet/Makefile \
--
2.5.0
More information about the Alsa-devel
mailing list