[Intel-gfx] [PATCH i-g-t 1/3] lib: Add audio library with dedicated helpers

Paul Kocialkowski paul.kocialkowski at linux.intel.com
Mon Aug 21 15:27:34 UTC 2017


Hi,

On Fri, 2017-08-18 at 12:16 -0400, Lyude Paul wrote:
> 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.

This one was a legit mistake, good catch!

> > +			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
-- 
Paul Kocialkowski <paul.kocialkowski at linux.intel.com>
Intel Finland Oy - BIC 0357606-4 - Westendinkatu 7, 02160 Espoo, Finland


More information about the Intel-gfx mailing list