[Intel-gfx] [PATCH i-g-t 1/3] lib: Add audio library with dedicated helpers
Lyude Paul
lyude at redhat.com
Fri Aug 18 16:16:18 UTC 2017
One more small formatting change
On Thu, 2017-08-17 at 19:05 +0300, Paul Kocialkowski wrote:
> This introduces an audio library, with dedicated helpers for both
> generating signals and detecting peak frequencies in a signal.
>
> This library paves the way for testing audio going through display
> connectors, such as HDMI.
>
> Signed-off-by: Paul Kocialkowski <paul.kocialkowski at linux.intel.com>
> ---
> .../intel-gpu-tools/intel-gpu-tools-docs.xml | 1 +
> lib/Makefile.am | 2 +
> lib/igt.h | 1 +
> lib/igt_audio.c | 326
> +++++++++++++++++++++
> lib/igt_audio.h | 47 +++
> 5 files changed, 377 insertions(+)
> create mode 100644 lib/igt_audio.c
> create mode 100644 lib/igt_audio.h
>
> diff --git a/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
> b/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
> index f88afd2a..c77159cf 100644
> --- a/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
> +++ b/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
> @@ -16,6 +16,7 @@
> <chapter>
> <title>API Reference</title>
> <xi:include href="xml/drmtest.xml"/>
> + <xi:include href="xml/igt_audio.xml"/>
> <xi:include href="xml/igt_aux.xml"/>
> <xi:include href="xml/igt_chamelium.xml"/>
> <xi:include href="xml/igt_core.xml"/>
> diff --git a/lib/Makefile.am b/lib/Makefile.am
> index 9c932d6f..5ea08314 100644
> --- a/lib/Makefile.am
> +++ b/lib/Makefile.am
> @@ -33,6 +33,8 @@ if HAVE_GSL
> lib_source_list += \
> igt_frame.c \
> igt_frame.h \
> + igt_audio.c \
> + igt_audio.h \
> $(NULL)
> endif
>
> diff --git a/lib/igt.h b/lib/igt.h
> index d16a4991..a75d2db7 100644
> --- a/lib/igt.h
> +++ b/lib/igt.h
> @@ -35,6 +35,7 @@
> #include "igt_dummyload.h"
> #include "igt_fb.h"
> #include "igt_frame.h"
> +#include "igt_audio.h"
> #include "igt_gt.h"
> #include "igt_kms.h"
> #include "igt_pm.h"
> diff --git a/lib/igt_audio.c b/lib/igt_audio.c
> new file mode 100644
> index 00000000..527a4930
> --- /dev/null
> +++ b/lib/igt_audio.c
> @@ -0,0 +1,326 @@
> +/*
> + * Copyright © 2017 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person
> obtaining a
> + * copy of this software and associated documentation files (the
> "Software"),
> + * to deal in the Software without restriction, including without
> limitation
> + * the rights to use, copy, modify, merge, publish, distribute,
> sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom
> the
> + * Software is furnished to do so, subject to the following
> conditions:
> + *
> + * The above copyright notice and this permission notice (including
> the next
> + * paragraph) shall be included in all copies or substantial
> portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
> EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
> OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> OTHER DEALINGS
> + * IN THE SOFTWARE.
> + *
> + * Authors:
> + * Paul Kocialkowski <paul.kocialkowski at linux.intel.com>
> + */
> +
> +#include "config.h"
> +
> +#include <math.h>
> +#include <gsl/gsl_fft_real.h>
> +
> +#include "igt.h"
> +
> +#define FREQS_MAX 8
> +
> +/**
> + * SECTION:igt_audio
> + * @short_description: Library for audio-related tests
> + * @title: Audio
> + * @include: igt_audio.h
> + *
> + * This library contains helpers for audio-related tests. More
> specifically,
> + * it allows generating additions of sine signals as well as
> detecting them.
> + */
> +
> +struct audio_signal_freq {
> + int freq;
> +
> + short *period;
> + int frames;
> + int offset;
> +};
> +
> +struct audio_signal {
> + int channels;
> + int sampling_rate;
> +
> + struct audio_signal_freq freqs[FREQS_MAX];
> + int freqs_count;
> +};
> +
> +/**
> + * audio_signal_init:
> + * @channels: The number of channels to use for the signal
> + * @sampling_rate: The sampling rate to use for the signal
> + *
> + * Allocate and initialize an audio signal structure with the given
> parameters.
> + *
> + * Returns: A newly-allocated audio signal structure
> + */
> +struct audio_signal *audio_signal_init(int channels, int
> sampling_rate)
> +{
> + struct audio_signal *signal;
> +
> + signal = malloc(sizeof(struct audio_signal));
> + memset(signal, 0, sizeof(struct audio_signal));
> +
> + signal->sampling_rate = sampling_rate;
> + signal->channels = channels;
> +
> + return signal;
> +}
> +
> +/**
> + * audio_signal_add_frequency:
> + * @signal: The target signal structure
> + * @frequency: The frequency to add to the signal
> + *
> + * Add a frequency to the signal.
> + *
> + * Returns: An integer equal to zero for success and negative for
> failure
> + */
> +int audio_signal_add_frequency(struct audio_signal *signal, int
> frequency)
> +{
> + int index = signal->freqs_count;
> +
> + if (index == FREQS_MAX)
> + return -1;
> +
> + /* Stay within the Nyquist–Shannon sampling theorem. */
> + if (frequency > signal->sampling_rate / 2)
> + return -1;
> +
> + /* Clip the frequency to an integer multiple of the sampling
> rate.
> + * This to be able to store a full period of it and use that
> for
> + * signal generation, instead of recurrent calls to sin().
> + */
> + frequency = signal->sampling_rate / (signal->sampling_rate /
> frequency);
> +
> + igt_debug("Adding test frequency %d\n", frequency);
> +
> + signal->freqs[index].freq = frequency;
> + signal->freqs[index].frames = 0;
> + signal->freqs[index].offset = 0;
> + signal->freqs_count++;
> +
> + return 0;
> +}
> +
> +/**
> + * audio_signal_synthesize:
> + * @signal: The target signal structure
> + *
> + * Synthesize the data tables for the audio signal, that can later
> be used
> + * to fill audio buffers. The resources allocated by this function
> must be
> + * freed with a call to audio_signal_clean when the signal is no
> longer used.
> + */
> +void audio_signal_synthesize(struct audio_signal *signal)
> +{
> + short *period;
> + double value;
> + int frames;
> + int freq;
> + int i, j;
> +
> + if (signal->freqs_count == 0)
> + return;
> +
> + for (i = 0; i < signal->freqs_count; i++) {
> + freq = signal->freqs[i].freq;
> + frames = signal->sampling_rate / freq;
> +
> + period = calloc(1, frames * sizeof(short));
> +
> + for (j = 0; j < frames; j++) {
> + value = 2.0 * M_PI * freq / signal-
> >sampling_rate * j;
> + value = sin(value) * SHRT_MAX / signal-
> >freqs_count;
> +
> + period[j] = (short) value;
> + }
> +
> + signal->freqs[i].period = period;
> + signal->freqs[i].frames = frames;
> + }
> +}
> +
> +/**
> + * audio_signal_synthesize:
> + * @signal: The target signal structure
> + *
> + * Free the resources allocated by audio_signal_synthesize and
> remove
> + * the previously-added frequencies.
> + */
> +void audio_signal_clean(struct audio_signal *signal)
> +{
> + int i;
> +
> + for (i = 0; i < signal->freqs_count; i++) {
> + if (signal->freqs[i].period)
> + free(signal->freqs[i].period);
> +
> + memset(&signal->freqs[i], 0, sizeof(struct
> audio_signal_freq));
> + }
> +
> + signal->freqs_count = 0;
> +}
> +
> +/**
> + * audio_signal_fill:
> + * @signal: The target signal structure
> + * @buffer: The target buffer to fill
> + * @frames: The number of frames to fill
> + *
> + * Fill the requested number of frames to the target buffer with the
> audio
> + * signal data (in interleaved S16_LE format), at the requested
> sampling rate
> + * and number of channels.
> + */
> +void audio_signal_fill(struct audio_signal *signal, short *buffer,
> int frames)
> +{
> + short *destination;
> + short *source;
> + int total;
> + int freq_frames;
> + int freq_offset;
> + int count;
> + int i, j, k;
> +
> + memset(buffer, 0, sizeof(short) * signal->channels *
> frames);
> +
> + for (i = 0; i < signal->freqs_count; i++) {
> + total = 0;
> +
> + while (total < frames) {
> + freq_frames = signal->freqs[i].frames;
> + freq_offset = signal->freqs[i].offset;
> +
> + source = signal->freqs[i].period +
> freq_offset;
> + destination = buffer + total * signal-
> >channels;
> +
> + count = freq_frames - freq_offset;
> + if (count > (frames - total))
> + count = frames - total;
> +
> + freq_offset += count;
> + freq_offset %= freq_frames;
> +
> + signal->freqs[i].offset = freq_offset;
> +
> + for (j = 0; j < count; j++) {
> + for (k = 0; k < signal->channels;
> k++) {
> + destination[j * signal-
> >channels + k] += source[j];
> + }
> + }
> +
> + total += count;
> + }
> + }
> +}
> +
> +/**
> + * audio_signal_detect:
> + * @signal: The target signal structure
> + * @channels: The input data's number of channels
> + * @sampling_rate: The input data's sampling rate
> + * @buffer: The input data's buffer
> + * @frames: The input data's number of frames
> + *
> + * Detect that the frequencies specified in @signal, and only those,
> are
> + * present in the input data. The input data's format is required to
> be S16_LE.
> + *
> + * Returns: A boolean indicating whether the detection was
> successful
> + */
> +bool audio_signal_detect(struct audio_signal *signal, int channels,
> + int sampling_rate, short *buffer, int
> frames)
> +{
> + double data[frames];
> + int amplitude[frames / 2];
> + bool detected[signal->freqs_count];
> + int threshold;
> + bool above;
> + int error;
> + int freq;
> + int max;
> + int c, i, j;
> +
> + /* Allowed error in Hz due to FFT step. */
> + error = sampling_rate / frames;
> +
> + for (c = 0; c < channels; c++) {
> + for (i = 0; i < frames; i++)
> + data[i] = (double) buffer[i * channels + c];
> +
> + gsl_fft_real_radix2_transform(data, 1, frames);
> +
> + max = 0;
> +
> + for (i = 0; i < frames / 2; i++) {
> + amplitude[i] = sqrt(data[i] * data[i] +
> + data[frames - i] *
> + data[frames - i]);
More indenting fixes? not sure if this one is just a result of it
getting formatted as an email.
> + if (amplitude[i] > max)
> + max = amplitude[i];
> + }
> +
> + for (i = 0; i < signal->freqs_count; i++)
> + detected[i] = false;
> +
> + threshold = max / 2;
> + above = false;
> + max = 0;
> +
> + for (i = 0; i < frames / 2; i++) {
> + if (amplitude[i] > threshold)
> + above = true;
> +
> + if (above) {
> + if (amplitude[i] < threshold) {
> + above = false;
> + max = 0;
> +
> + for (j = 0; j < signal-
> >freqs_count; j++) {
> + if (signal-
> >freqs[j].freq >
> + freq - error &&
> + signal-
> >freqs[j].freq <
> + freq + error) {
> + detected[j]
> = true;
> + break;
> + }
> + }
> +
> + /* Detected frequency was
> not generated. */
> + if (j == signal-
> >freqs_count) {
> + igt_debug("Detected
> additional frequency: %d\n",
> + freq);
> + return false;
> + }
> + }
> +
> + if (amplitude[i] > max) {
> + max = amplitude[i];
> + freq = sampling_rate * i /
> frames;
> + }
> + }
> + }
> +
> + for (i = 0; i < signal->freqs_count; i++) {
> + if (!detected[i]) {
> + igt_debug("Missing frequency: %d\n",
> + signal->freqs[i].freq);
> + return false;
> + }
> + }
> + }
> +
> + return true;
> +}
> diff --git a/lib/igt_audio.h b/lib/igt_audio.h
> new file mode 100644
> index 00000000..507e7ab9
> --- /dev/null
> +++ b/lib/igt_audio.h
> @@ -0,0 +1,47 @@
> +/*
> + * Copyright © 2017 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person
> obtaining a
> + * copy of this software and associated documentation files (the
> "Software"),
> + * to deal in the Software without restriction, including without
> limitation
> + * the rights to use, copy, modify, merge, publish, distribute,
> sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom
> the
> + * Software is furnished to do so, subject to the following
> conditions:
> + *
> + * The above copyright notice and this permission notice (including
> the next
> + * paragraph) shall be included in all copies or substantial
> portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
> EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
> OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> OTHER DEALINGS
> + * IN THE SOFTWARE.
> + *
> + * Authors:
> + * Paul Kocialkowski <paul.kocialkowski at linux.intel.com>
> + */
> +
> +#ifndef IGT_AUDIO_H
> +#define IGT_AUDIO_H
> +
> +#ifdef HAVE_CONFIG_H
> +#include "config.h"
> +#endif
> +
> +#include "igt.h"
> +#include <stdbool.h>
> +
> +struct audio_signal;
> +
> +struct audio_signal *audio_signal_init(int channels, int
> sampling_rate);
> +int audio_signal_add_frequency(struct audio_signal *signal, int
> frequency);
> +void audio_signal_synthesize(struct audio_signal *signal);
> +void audio_signal_clean(struct audio_signal *signal);
> +void audio_signal_fill(struct audio_signal *signal, short *buffer,
> int frames);
> +bool audio_signal_detect(struct audio_signal *signal, int channels,
> + int sampling_rate, short *buffer, int
> frames);
> +
> +#endif
More information about the Intel-gfx
mailing list