[Sound-open-firmware] [PATCH 2/4] This change provides a tone generator component. The purpose is to provide a high quality FW internal test signal generator for objective audio quality measurements for component or system tests. It can also be used as simple beep indication tones generator for users.

Seppo Ingalsuo seppo.ingalsuo at linux.intel.com
Wed Jun 7 13:17:56 CEST 2017


---
 src/audio/Makefile.am              |   1 +
 src/audio/tone.c                   | 576 +++++++++++++++++++++++++++++++++++
 src/audio/tone.h                   |  54 ++++
 src/include/reef/audio/component.h |   2 +
 src/include/reef/math/trig.h       |  44 +++
 src/include/reef/trace.h           |   1 +
 src/include/uapi/ipc.h             |   8 +
 src/math/trig.c                    | 595 +++++++++++++++++++++++++++++++++++++
 src/tasks/audio.c                  |   1 +
 9 files changed, 1282 insertions(+)
 create mode 100644 src/audio/tone.c
 create mode 100644 src/audio/tone.h
 create mode 100644 src/include/reef/math/trig.h
 create mode 100644 src/math/trig.c

diff --git a/src/audio/Makefile.am b/src/audio/Makefile.am
index 235e785..6f0381a 100644
--- a/src/audio/Makefile.am
+++ b/src/audio/Makefile.am
@@ -1,6 +1,7 @@
 noinst_LIBRARIES = libaudio.a
 
 libaudio_a_SOURCES = \
+	tone.c \
 	src.c \
 	src_core.c \
 	mixer.c \
diff --git a/src/audio/tone.c b/src/audio/tone.c
new file mode 100644
index 0000000..f305c03
--- /dev/null
+++ b/src/audio/tone.c
@@ -0,0 +1,576 @@
+/*
+ * Copyright (c) 2016, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *   * Neither the name of the Intel Corporation nor the
+ *     names of its contributors may be used to endorse or promote products
+ *     derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: Seppo Ingalsuo <seppo.ingalsuo at linux.intel.com>
+ *         Liam Girdwood <liam.r.girdwood at linux.intel.com>
+ *         Keyon Jie <yang.jie at linux.intel.com>
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+#include <errno.h>
+#include <reef/reef.h>
+#include <reef/lock.h>
+#include <reef/list.h>
+#include <reef/stream.h>
+#include <reef/alloc.h>
+#include <reef/work.h>
+#include <reef/clock.h>
+#include <reef/audio/component.h>
+#include <reef/audio/format.h>
+#include <reef/audio/pipeline.h>
+#include <reef/math/trig.h>
+#include "tone.h"
+
+#ifdef MODULE_TEST
+#include <stdio.h>
+#endif
+
+#define trace_tone(__e) trace_event(TRACE_CLASS_TONE, __e)
+#define tracev_tone(__e) tracev_event(TRACE_CLASS_TONE, __e)
+#define trace_tone_error(__e) trace_error(TRACE_CLASS_TONE, __e)
+
+#define TONE_NUM_FS            13       /* Table size for 8-192 kHz range */
+#define TONE_AMPLITUDE_DEFAULT 2147484  /* -60 dB from full scale */
+#define TONE_FREQUENCY_DEFAULT 16334848 /* 997 in Q18.14 */
+
+static int32_t tonegen(struct tone_state *sg);
+static void tonegen_control(struct tone_state *sg);
+static void tonegen_update_f(struct tone_state *sg, int32_t f);
+
+
+/* 2*pi/Fs lookup tables in Q1.31 for each Fs */
+static const int32_t tone_fs_list[TONE_NUM_FS] = {
+	8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000,
+	64000, 88200, 96000, 176400, 192000
+};
+static const int32_t tone_pi2_div_fs[TONE_NUM_FS] = {
+	1686630, 1223858, 843315, 611929, 562210, 421657, 305965,
+	281105, 210829, 152982, 140552, 76491, 70276
+};
+
+/* tone component private data */
+
+/* TODO: Remove *source when internal endpoint is possible */
+struct comp_data {
+	struct tone_state sg;
+	void (*tone_func)(struct comp_dev *dev, struct comp_buffer *sink,
+		struct comp_buffer *source, uint32_t frames);
+
+};
+
+/* 
+ * Tone generator algorithm code 
+ */
+
+static void tone_s32_default(struct comp_dev *dev, struct comp_buffer *sink,
+	struct comp_buffer *source, uint32_t frames)
+{
+	struct comp_data *cd = comp_get_drvdata(dev);
+	int32_t sine_sample;
+	int32_t *dest = (int32_t*) sink->w_ptr;
+	int i, n, n_wrap_dest;
+	int nch = sink->params.pcm->channels;
+
+	n = frames * nch;
+	while (n > 0) {
+		n_wrap_dest = (int32_t *) sink->end_addr - dest;
+		if (n < n_wrap_dest) {
+			/* No circular wrap need */
+			while (n > 0) {
+				/* Update period count for sweeps, etc. */
+				tonegen_control(&cd->sg);
+				/* Calculate mono sine wave sample and then
+				 * duplicate to channels. 
+				 */
+				sine_sample = tonegen(&cd->sg);
+				n -= nch;
+				for (i = 0; i < nch; i++) {
+					*dest = sine_sample;
+					dest++;
+				}
+			}
+		} else {
+			/* Process until wrap */
+			while (n_wrap_dest > 0) {
+				tonegen_control(&cd->sg);
+				sine_sample = tonegen(&cd->sg);
+				n -= nch;
+				n_wrap_dest -= nch;
+				for (i = 0; i < nch; i++) {
+					*dest = sine_sample;
+					dest++;
+				}
+			}
+			/* No need to check if past end_addr, 
+			 * it is so just subtract buffer size.
+			 */
+			dest = (int32_t *) ((size_t) dest - sink->alloc_size);
+		}
+	}
+	sink->w_ptr = dest;
+	comp_update_sink_free_avail(sink, frames * nch);
+}
+
+static int32_t tonegen(struct tone_state *sg)
+{
+	int64_t sine, w;
+
+	/* sg->w is angle in Q4.28 radians format, sin() returns Q1.31 */
+	/* sg->a is amplitude as Q1.31 */
+	sine = q_mults_32x32(sin_fixed(sg->w), sg->a, 31, 31, 31);
+
+	/* Next point */
+	w = (int64_t) sg->w + sg->w_step;
+	sg->w = (w > PI_MUL2_Q4_28)
+		? (int32_t) (w - PI_MUL2_Q4_28) : (int32_t) w;
+
+	if (sg->mute)
+		return 0;
+	else
+		return(int32_t) sine; /* Q1.31 no saturation need */
+}
+
+static void tonegen_control(struct tone_state *sg)
+{
+	int64_t a, p;
+
+	/* Count samples, 125 us blocks */
+	sg->sample_count++;
+	if (sg->sample_count < sg->samples_in_block)
+		return;
+
+	sg->sample_count = 0;
+	if (sg->block_count < INT32_MAXVALUE)
+		sg->block_count++;
+
+	/* Fadein ramp during tone */
+	if (sg->block_count < sg->tone_length) {
+		if (sg->a == 0)
+			sg->w = 0; /* Reset phase to have less clicky ramp */
+
+		if (sg->a > sg->a_target) {
+			a = (int64_t) sg->a - sg->ramp_step;
+			if (a < sg->a_target)
+				a = sg->a_target;
+
+		} else {
+			a = (int64_t) sg->a + sg->ramp_step;
+			if (a > sg->a_target)
+				a = sg->a_target;
+		}
+		sg->a = (int32_t) a;
+	}
+
+	/* Fadeout ramp after tone*/
+	if (sg->block_count > sg->tone_length) {
+		a = (int64_t) sg->a - sg->ramp_step;
+		if (a < 0)
+			a = 0;
+
+		sg->a = (int32_t) a;
+	}
+
+	/* New repeated tone, update for frequency or amplitude sweep */
+	if ((sg->block_count > sg->tone_period)
+		&& (sg->repeat_count + 1 < sg->repeats)) {
+		sg->block_count = 0;
+		if (sg->ampl_coef > 0) {
+			sg->a_target = sat_int32(q_multsr_32x32(
+				sg->a_target,
+				sg->ampl_coef, 31, 30, 31));
+			sg->a = (sg->ramp_step > sg->a_target)
+				? sg->a_target : sg->ramp_step;
+		}
+		if (sg->freq_coef > 0) {
+			/* f is Q16.16, freq_coef is Q2.30 */
+			p = q_multsr_32x32(sg->f, sg->freq_coef, 16, 30, 16);
+			tonegen_update_f(sg, (int32_t) p); /* No saturation */
+		}
+		sg->repeat_count++;
+	}
+}
+
+static inline void tonegen_set_a(struct tone_state *sg, int32_t a)
+{
+	sg->a_target = a;
+}
+
+static inline void tonegen_set_f(struct tone_state *sg, int32_t f)
+{
+	sg->f = f;
+}
+
+/* Tone sweep parameters description:
+ * fc - Multiplication factor for frequency as Q2.30 for logarithmic change
+ * ac - Multiplication factor for amplitude as Q2.30 for logarithmic change
+ * l - Tone length in samples, this is the active length of tone
+ * p - Tone period in samples, this is the length including the pause after beep
+ * r - Repeated number of beeps
+ */
+
+static void tonegen_set_sweep(struct tone_state *sg, int32_t fc, int32_t ac,
+	uint32_t l, uint32_t p, uint32_t r)
+{
+	sg->repeats = r;
+
+	/* Zeros as defaults make a nicer API without need to remember
+	 * the neutral settings for sweep and repeat parameters. 
+	 */
+	sg->freq_coef = (fc > 0) ? fc : ONE_Q2_30; /* Set freq mult to 1.0 */
+	sg->ampl_coef = (ac > 0) ? ac : ONE_Q2_30; /* Set ampl mult to 1.0 */
+	sg->tone_length = (l > 0) ? l : INT32_MAXVALUE; /* Count rate 125 us */
+	sg->tone_period = (p > 0) ? p : INT32_MAXVALUE; /* Count rate 125 us */
+}
+
+/* Tone ramp parameters:
+ * step - Value that is added or subtracted to amplitude. A zero or negative
+ *        number disables the ramp and amplitude is immediately modified to
+ *        final value.
+ */
+
+static inline void tonegen_set_linramp(struct tone_state *sg, int32_t step)
+{
+	sg->ramp_step = (step > 0) ? step : INT32_MAXVALUE;
+}
+
+static inline int32_t tonegen_get_f(struct tone_state *sg)
+{
+	return sg->f;
+}
+
+static inline int32_t tonegen_get_a(struct tone_state *sg)
+{
+	return sg->a_target;
+}
+
+static inline void tonegen_mute(struct tone_state *sg)
+{
+	sg->mute = 1;
+}
+
+static inline void tonegen_unmute(struct tone_state *sg)
+{
+	sg->mute = 0;
+}
+
+static void tonegen_update_f(struct tone_state *sg, int32_t f)
+{
+	int64_t w_tmp;
+	int64_t f_max;
+
+	/* Calculate Fs/2, fs is Q32.0, f is Q16.16 */
+	f_max = Q_SHIFT_LEFT((int64_t) sg->fs, 0, 16 - 1);
+	f_max = (f_max > INT32_MAXVALUE) ? INT32_MAXVALUE : f_max;
+	sg->f = (f > f_max) ? f_max : f;
+	w_tmp = q_multsr_32x32(sg->f, sg->c, 16, 31, 28); /* Q16 x Q31 -> Q28 */
+	w_tmp = (w_tmp > PI_Q4_28) ? PI_Q4_28 : w_tmp; /* Limit to pi Q4.28 */
+	sg->w_step = (int32_t) w_tmp;
+
+#ifdef MODULE_TEST
+	printf("Fs=%d, f_max=%d, f_new=%.3f\n",
+		sg->fs, (int32_t) (f_max >> 16), sg->f / 65536.0);
+#endif
+}
+
+static void tonegen_reset(struct tone_state *sg)
+{
+	sg->mute = 1;
+	sg->a = 0;
+	sg->a_target = TONE_AMPLITUDE_DEFAULT;
+	sg->c = 0;
+	sg->f = TONE_FREQUENCY_DEFAULT;
+	sg->w = 0;
+	sg->w_step = 0;
+
+	sg->block_count = 0;
+	sg->repeat_count = 0;
+	sg->repeats = 0;
+	sg->sample_count = 0;
+	sg->samples_in_block = 0;
+
+	/* Continuous tone */
+	sg->freq_coef = ONE_Q2_30; /* Set freq multiplier to 1.0 */
+	sg->ampl_coef = ONE_Q2_30; /* Set ampl multiplier to 1.0 */
+	sg->tone_length = INT32_MAXVALUE;
+	sg->tone_period = INT32_MAXVALUE;
+	sg->ramp_step = ONE_Q1_31; /* Set lin ramp modification to max */
+}
+
+static int tonegen_init(struct tone_state *sg, int32_t fs, int32_t f, int32_t a)
+{
+	int idx, i;
+
+	sg->a_target = a;
+	sg->a = (sg->ramp_step > sg->a_target) ? sg->a_target : sg->ramp_step;
+
+	idx = -1;
+	sg->mute = 1;
+	sg->fs = 0;
+
+	/* Find index of current sample rate and then get from lookup table the
+	 * corresponding 2*pi/Fs value. 
+	 */
+	for (i = 0; i < TONE_NUM_FS; i++) {
+		if (fs == tone_fs_list[i])
+			idx = i;
+	}
+
+	if (idx < 0) {
+		sg->w_step = 0;
+		return -EINVAL;
+	}
+
+	sg->fs = fs;
+	sg->c = tone_pi2_div_fs[idx]; /* Store 2*pi/Fs */
+	sg->mute = 0;
+	tonegen_update_f(sg, f);
+
+	/* 125us as Q1.31 is 268435, calculate fs * 125e-6 in Q31.0  */
+	sg->samples_in_block = (int32_t) q_multsr_32x32(fs, 268435, 0, 31, 0);
+
+	return 0;
+}
+
+/* 
+ * End of algorithm code. Next the standard component methods.
+ */
+
+static struct comp_dev *tone_new(struct sof_ipc_comp *comp)
+{
+	struct comp_dev *dev;
+	struct comp_data *cd;
+
+	trace_tone("TNw");
+	dev = rmalloc(RZONE_RUNTIME, RFLAGS_NONE, sizeof(*dev));
+	if (dev == NULL)
+		return NULL;
+
+	//memcpy(&dev->comp, comp, sizeof(struct sof_ipc_comp_tone));
+
+
+	cd = rmalloc(RZONE_RUNTIME, RFLAGS_NONE, sizeof(*cd));
+	if (cd == NULL) {
+		rfree(dev);
+		return NULL;
+	}
+
+	comp_set_drvdata(dev, cd);
+
+
+	tonegen_reset(&cd->sg);
+
+	return dev;
+}
+
+static void tone_free(struct comp_dev *dev)
+{
+	struct tone_data *td = comp_get_drvdata(dev);
+
+	trace_tone("TFr");
+
+	rfree(td);
+	rfree(dev);
+}
+
+/* set component audio stream parameters */
+static int tone_params(struct comp_dev *dev, struct stream_params *params)
+{
+	trace_tone("TPa");
+
+	/* Tone generator supports only S32_LE PCM format */
+	if ((params->type != STREAM_TYPE_PCM)
+		|| (params->pcm->frame_fmt != SOF_IPC_FRAME_S32_LE))
+		return -EINVAL;
+
+	/* Don't do any data transformation */
+	comp_set_sink_params(dev, params);
+
+	return 0;
+}
+
+/* used to pass standard and bespoke commands (with data) to component */
+static int tone_cmd(struct comp_dev *dev, int cmd, void *data)
+{
+	struct comp_data *cd = comp_get_drvdata(dev);
+	struct sof_ipc_comp_tone *cv;
+	trace_tone("TCm");
+
+	switch (cmd) {
+	case COMP_CMD_TONE:
+		trace_tone("Tto");
+		cv = (struct sof_ipc_comp_tone *) data;
+		/* Ignore channels while tone implementation is mono */
+		tonegen_set_f(&cd->sg, cv->frequency);
+		tonegen_set_a(&cd->sg, cv->amplitude);
+		tonegen_set_sweep(&cd->sg, cv->freq_mult, cv->ampl_mult,
+			cv->length, cv->period, cv->repeats);
+		tonegen_set_linramp(&cd->sg, cv->ramp_step);
+		break;
+	case COMP_CMD_VOLUME:
+		trace_tone("TVo");
+		break;
+	case COMP_CMD_MUTE:
+		trace_tone("TMu");
+		tonegen_mute(&cd->sg);
+		break;
+	case COMP_CMD_UNMUTE:
+		trace_tone("TUm");
+		tonegen_unmute(&cd->sg);
+		break;
+	case COMP_CMD_START:
+		trace_tone("TSt");
+		dev->state = COMP_STATE_RUNNING;
+		break;
+	case COMP_CMD_STOP:
+		trace_tone("TSp");
+		if (dev->state == COMP_STATE_RUNNING ||
+			dev->state == COMP_STATE_DRAINING ||
+			dev->state == COMP_STATE_PAUSED) {
+			comp_buffer_reset(dev);
+			dev->state = COMP_STATE_SETUP;
+		}
+		break;
+	case COMP_CMD_PAUSE:
+		trace_tone("TPe");
+		/* only support pausing for running */
+		if (dev->state == COMP_STATE_RUNNING)
+			dev->state = COMP_STATE_PAUSED;
+
+		break;
+	case COMP_CMD_RELEASE:
+		trace_tone("TRl");
+		dev->state = COMP_STATE_RUNNING;
+		break;
+	default:
+		trace_tone("TDf");
+
+		break;
+	}
+
+	return 0;
+}
+
+/* copy and process stream data from source to sink buffers */
+static int tone_copy(struct comp_dev *dev)
+{
+	int need_sink;
+	struct comp_buffer *sink;
+	struct comp_buffer *source = NULL;
+	struct comp_data *cd = comp_get_drvdata(dev);
+	uint32_t cframes;
+
+	trace_comp("Ton");
+
+	/* tone component sink buffer */
+	sink = list_first_item(&dev->bsink_list, struct comp_buffer,
+		source_list);
+	cframes = sink->params.pcm->period_count;
+
+	/* Test that sink has enough free frames. Then run once to maintain
+	 * low latency and steady load for tones. 
+	 */
+	need_sink = cframes * sink->params.pcm->frame_size;
+	if (sink->free >= need_sink) {
+
+		/* create tone */
+		cd->tone_func(dev, sink, source, cframes);
+	}
+
+	return 0;
+}
+
+static int tone_prepare(struct comp_dev *dev)
+{
+	int32_t f, a;
+	struct comp_buffer *sink;
+	struct comp_data *cd = comp_get_drvdata(dev);
+
+	trace_tone("TPp");
+
+	sink = list_first_item(&dev->bsink_list, struct comp_buffer,
+		source_list);
+	trace_value(sink->params.pcm->channels);
+	trace_value(sink->params.pcm->rate);
+
+	cd->tone_func = tone_s32_default;
+	f = tonegen_get_f(&cd->sg);
+	a = tonegen_get_a(&cd->sg);
+	if (tonegen_init(&cd->sg, sink->params.pcm->rate, f, a) < 0)
+		return -EINVAL;
+
+	//dev->preload = PLAT_INT_PERIODS;
+	dev->state = COMP_STATE_PREPARE;
+
+	return 0;
+}
+
+static int tone_preload(struct comp_dev *dev)
+{
+	//int i;
+	trace_tone("TPl");
+
+	//for (i = 0; i < dev->preload; i++)
+	//	tone_copy(dev);
+
+	return 0;
+}
+
+static int tone_reset(struct comp_dev *dev)
+{
+
+	struct comp_data *cd = comp_get_drvdata(dev);
+
+	trace_tone("TRe");
+
+	/* Initialize with the defaults */
+	tonegen_reset(&cd->sg);
+
+	dev->state = COMP_STATE_INIT;
+
+	return 0;
+}
+
+struct comp_driver comp_tone = {
+	.type = SOF_COMP_TONE,
+	.ops =
+	{
+		.new = tone_new,
+		.free = tone_free,
+		.params = tone_params,
+		.cmd = tone_cmd,
+		.copy = tone_copy,
+		.prepare = tone_prepare,
+		.reset = tone_reset,
+		.preload = tone_preload,
+	},
+};
+
+void sys_comp_tone_init(void)
+{
+	comp_register(&comp_tone);
+}
diff --git a/src/audio/tone.h b/src/audio/tone.h
new file mode 100644
index 0000000..37830db
--- /dev/null
+++ b/src/audio/tone.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2016, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *   * Neither the name of the Intel Corporation nor the
+ *     names of its contributors may be used to endorse or promote products
+ *     derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: Seppo Ingalsuo <seppo.ingalsuo at linux.intel.com>
+ *         Liam Girdwood <liam.r.girdwood at linux.intel.com>
+ *         Keyon Jie <yang.jie at linux.intel.com>
+ */
+
+
+struct tone_state {
+	int mute;
+	int32_t a; /* Current amplitude Q1.31 */
+	int32_t a_target; /* Target amplitude Q1.31 */
+	int32_t ampl_coef; /* Amplitude multiplier Q2.30 */
+	int32_t c; /* Coefficient 2*pi/Fs Q1.31 */
+	int32_t f; /* Frequency Q18.14 */
+	int32_t freq_coef; /* Frequency multiplier Q2.30 */
+	int32_t fs; /* Sample rate in Hertz Q32.0 */
+	int32_t ramp_step; /* Amplitude ramp step Q1.31 */
+	int32_t w; /* Angle radians Q4.28 */
+	int32_t w_step; /* Angle step Q4.28 */
+	uint32_t block_count;
+	uint32_t repeat_count;
+	uint32_t repeats; /* Number of repeats for tone (sweep steps) */
+	uint32_t sample_count;
+	uint32_t samples_in_block; /* Samples in 125 us block */
+	uint32_t tone_length; /* Active length in 125 us blocks */
+	uint32_t tone_period; /* Active + idle time in 125 us blocks */
+};
+
diff --git a/src/include/reef/audio/component.h b/src/include/reef/audio/component.h
index a37aa51..e4f4f8f 100644
--- a/src/include/reef/audio/component.h
+++ b/src/include/reef/audio/component.h
@@ -75,6 +75,7 @@
 #define COMP_CMD_SRC		104
 #define COMP_CMD_LOOPBACK	105
 
+#define COMP_CMD_TONE           106     /* Tone generator amplitude and frequency */
 
 /* MMAP IPC status */
 #define COMP_CMD_IPC_MMAP_RPOS	200	/* host read position */
@@ -259,6 +260,7 @@ void sys_comp_mux_init(void);
 void sys_comp_switch_init(void);
 void sys_comp_volume_init(void);
 void sys_comp_src_init(void);
+void sys_comp_tone_init(void);
 
 
 
diff --git a/src/include/reef/math/trig.h b/src/include/reef/math/trig.h
new file mode 100644
index 0000000..b75f229
--- /dev/null
+++ b/src/include/reef/math/trig.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2016, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *   * Neither the name of the Intel Corporation nor the
+ *     names of its contributors may be used to endorse or promote products
+ *     derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: Seppo Ingalsuo <seppo.ingalsuo at linux.intel.com>
+ *         Liam Girdwood <liam.r.girdwood at linux.intel.com>
+ *         Keyon Jie <yang.jie at linux.intel.com>
+ */
+
+#ifndef TRIG_H
+#define TRIG_H
+
+#define PI_DIV2_Q4_28 421657428
+#define PI_Q4_28      843314857
+#define PI_MUL2_Q4_28     1686629713
+
+int32_t sin_fixed(int32_t w); /* Input is Q4.28, output is Q1.31 */
+
+#endif
+
+
diff --git a/src/include/reef/trace.h b/src/include/reef/trace.h
index eb3fdd2..04b8d5d 100644
--- a/src/include/reef/trace.h
+++ b/src/include/reef/trace.h
@@ -83,6 +83,7 @@
 #define TRACE_CLASS_SWITCH	(15 << 24)
 #define TRACE_CLASS_MUX		(16 << 24)
 #define TRACE_CLASS_SRC         (17 << 24)
+#define TRACE_CLASS_TONE        (18 << 24)
 
 /* move to config.h */
 #define TRACE	1
diff --git a/src/include/uapi/ipc.h b/src/include/uapi/ipc.h
index fc5a88b..7b0fd96 100644
--- a/src/include/uapi/ipc.h
+++ b/src/include/uapi/ipc.h
@@ -505,6 +505,14 @@ struct sof_ipc_comp_mux {
 struct sof_ipc_comp_tone {
 	struct sof_ipc_comp comp;
 	struct sof_ipc_pcm_comp pcm;
+	int32_t frequency;
+	int32_t amplitude;
+	int32_t freq_mult;
+	int32_t ampl_mult;
+	int32_t length;
+	int32_t period;
+	int32_t repeats;
+	int32_t ramp_step;
 } __attribute__((packed));
 
 /* frees components, buffers and pipelines
diff --git a/src/math/trig.c b/src/math/trig.c
new file mode 100644
index 0000000..a58e1f4
--- /dev/null
+++ b/src/math/trig.c
@@ -0,0 +1,595 @@
+/*
+ * Copyright (c) 2016, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *   * Neither the name of the Intel Corporation nor the
+ *     names of its contributors may be used to endorse or promote products
+ *     derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: Seppo Ingalsuo <seppo.ingalsuo at linux.intel.com>
+ *         Liam Girdwood <liam.r.girdwood at linux.intel.com>
+ *         Keyon Jie <yang.jie at linux.intel.com>
+ */
+
+#include <stdint.h>
+#include <reef/audio/format.h>
+
+
+#define SINE_C_Q20 341782638 /* 2*SINE_NQUART/pi in Q12.20 */
+#define SINE_NQUART 512 /* Must be 2^N */
+#define SINE_TABLE_SIZE (SINE_NQUART+1)
+
+/* An 1/4 period of sine wave as Q1.31 */
+const int32_t sine_table[SINE_TABLE_SIZE] = {
+    0,
+    6588387,
+    13176712,
+    19764913,
+    26352928,
+    32940695,
+    39528151,
+    46115236,
+    52701887,
+    59288042,
+    65873638,
+    72458615,
+    79042909,
+    85626460,
+    92209205,
+    98791081,
+    105372028,
+    111951983,
+    118530885,
+    125108670,
+    131685278,
+    138260647,
+    144834714,
+    151407418,
+    157978697,
+    164548489,
+    171116732,
+    177683365,
+    184248325,
+    190811551,
+    197372981,
+    203932553,
+    210490206,
+    217045877,
+    223599506,
+    230151030,
+    236700388,
+    243247517,
+    249792358,
+    256334847,
+    262874923,
+    269412525,
+    275947592,
+    282480061,
+    289009871,
+    295536961,
+    302061269,
+    308582734,
+    315101294,
+    321616889,
+    328129457,
+    334638936,
+    341145265,
+    347648383,
+    354148229,
+    360644742,
+    367137860,
+    373627523,
+    380113669,
+    386596237,
+    393075166,
+    399550396,
+    406021864,
+    412489512,
+    418953276,
+    425413098,
+    431868915,
+    438320667,
+    444768293,
+    451211734,
+    457650927,
+    464085813,
+    470516330,
+    476942419,
+    483364019,
+    489781069,
+    496193509,
+    502601279,
+    509004318,
+    515402566,
+    521795963,
+    528184448,
+    534567963,
+    540946445,
+    547319836,
+    553688076,
+    560051103,
+    566408860,
+    572761285,
+    579108319,
+    585449903,
+    591785976,
+    598116478,
+    604441351,
+    610760535,
+    617073970,
+    623381597,
+    629683357,
+    635979190,
+    642269036,
+    648552837,
+    654830534,
+    661102068,
+    667367379,
+    673626408,
+    679879097,
+    686125386,
+    692365218,
+    698598533,
+    704825272,
+    711045377,
+    717258790,
+    723465451,
+    729665303,
+    735858287,
+    742044345,
+    748223418,
+    754395449,
+    760560379,
+    766718151,
+    772868706,
+    779011986,
+    785147934,
+    791276492,
+    797397602,
+    803511207,
+    809617248,
+    815715670,
+    821806413,
+    827889421,
+    833964637,
+    840032003,
+    846091463,
+    852142959,
+    858186434,
+    864221832,
+    870249095,
+    876268167,
+    882278991,
+    888281511,
+    894275670,
+    900261412,
+    906238681,
+    912207419,
+    918167571,
+    924119082,
+    930061894,
+    935995952,
+    941921200,
+    947837582,
+    953745043,
+    959643527,
+    965532978,
+    971413341,
+    977284561,
+    983146583,
+    988999351,
+    994842809,
+    1000676905,
+    1006501581,
+    1012316784,
+    1018122458,
+    1023918549,
+    1029705003,
+    1035481765,
+    1041248781,
+    1047005996,
+    1052753356,
+    1058490807,
+    1064218296,
+    1069935767,
+    1075643168,
+    1081340445,
+    1087027543,
+    1092704410,
+    1098370992,
+    1104027236,
+    1109673088,
+    1115308496,
+    1120933406,
+    1126547765,
+    1132151521,
+    1137744620,
+    1143327011,
+    1148898640,
+    1154459455,
+    1160009404,
+    1165548435,
+    1171076495,
+    1176593532,
+    1182099495,
+    1187594332,
+    1193077990,
+    1198550419,
+    1204011566,
+    1209461381,
+    1214899812,
+    1220326808,
+    1225742318,
+    1231146290,
+    1236538675,
+    1241919421,
+    1247288477,
+    1252645793,
+    1257991319,
+    1263325005,
+    1268646799,
+    1273956652,
+    1279254515,
+    1284540337,
+    1289814068,
+    1295075658,
+    1300325059,
+    1305562221,
+    1310787095,
+    1315999631,
+    1321199780,
+    1326387493,
+    1331562722,
+    1336725418,
+    1341875532,
+    1347013016,
+    1352137822,
+    1357249900,
+    1362349204,
+    1367435684,
+    1372509294,
+    1377569985,
+    1382617710,
+    1387652421,
+    1392674071,
+    1397682613,
+    1402677999,
+    1407660183,
+    1412629117,
+    1417584755,
+    1422527050,
+    1427455956,
+    1432371426,
+    1437273414,
+    1442161874,
+    1447036759,
+    1451898025,
+    1456745625,
+    1461579513,
+    1466399644,
+    1471205973,
+    1475998455,
+    1480777044,
+    1485541695,
+    1490292364,
+    1495029005,
+    1499751575,
+    1504460029,
+    1509154322,
+    1513834410,
+    1518500249,
+    1523151796,
+    1527789006,
+    1532411836,
+    1537020243,
+    1541614182,
+    1546193612,
+    1550758488,
+    1555308767,
+    1559844407,
+    1564365366,
+    1568871600,
+    1573363067,
+    1577839726,
+    1582301533,
+    1586748446,
+    1591180425,
+    1595597427,
+    1599999410,
+    1604386334,
+    1608758157,
+    1613114837,
+    1617456334,
+    1621782607,
+    1626093615,
+    1630389318,
+    1634669675,
+    1638934646,
+    1643184190,
+    1647418268,
+    1651636840,
+    1655839867,
+    1660027308,
+    1664199124,
+    1668355276,
+    1672495724,
+    1676620431,
+    1680729357,
+    1684822463,
+    1688899710,
+    1692961061,
+    1697006478,
+    1701035921,
+    1705049354,
+    1709046738,
+    1713028036,
+    1716993211,
+    1720942224,
+    1724875039,
+    1728791619,
+    1732691927,
+    1736575926,
+    1740443580,
+    1744294852,
+    1748129706,
+    1751948106,
+    1755750016,
+    1759535401,
+    1763304223,
+    1767056449,
+    1770792043,
+    1774510970,
+    1778213194,
+    1781898680,
+    1785567395,
+    1789219304,
+    1792854372,
+    1796472564,
+    1800073848,
+    1803658188,
+    1807225552,
+    1810775906,
+    1814309215,
+    1817825448,
+    1821324571,
+    1824806551,
+    1828271355,
+    1831718951,
+    1835149305,
+    1838562387,
+    1841958164,
+    1845336603,
+    1848697673,
+    1852041343,
+    1855367580,
+    1858676354,
+    1861967633,
+    1865241387,
+    1868497585,
+    1871736195,
+    1874957188,
+    1878160534,
+    1881346201,
+    1884514160,
+    1887664382,
+    1890796836,
+    1893911493,
+    1897008324,
+    1900087300,
+    1903148391,
+    1906191569,
+    1909216806,
+    1912224072,
+    1915213339,
+    1918184580,
+    1921137766,
+    1924072870,
+    1926989863,
+    1929888719,
+    1932769410,
+    1935631909,
+    1938476189,
+    1941302224,
+    1944109986,
+    1946899450,
+    1949670588,
+    1952423376,
+    1955157787,
+    1957873795,
+    1960571374,
+    1963250500,
+    1965911147,
+    1968553291,
+    1971176905,
+    1973781966,
+    1976368449,
+    1978936330,
+    1981485584,
+    1984016188,
+    1986528117,
+    1989021349,
+    1991495859,
+    1993951624,
+    1996388621,
+    1998806828,
+    2001206221,
+    2003586778,
+    2005948477,
+    2008291295,
+    2010615209,
+    2012920200,
+    2015206244,
+    2017473320,
+    2019721407,
+    2021950483,
+    2024160528,
+    2026351521,
+    2028523441,
+    2030676268,
+    2032809981,
+    2034924561,
+    2037019987,
+    2039096240,
+    2041153301,
+    2043191149,
+    2045209766,
+    2047209132,
+    2049189230,
+    2051150040,
+    2053091543,
+    2055013722,
+    2056916559,
+    2058800035,
+    2060664132,
+    2062508835,
+    2064334123,
+    2066139982,
+    2067926393,
+    2069693341,
+    2071440807,
+    2073168776,
+    2074877232,
+    2076566159,
+    2078235539,
+    2079885359,
+    2081515602,
+    2083126253,
+    2084717297,
+    2086288719,
+    2087840504,
+    2089372637,
+    2090885104,
+    2092377891,
+    2093850984,
+    2095304369,
+    2096738031,
+    2098151959,
+    2099546138,
+    2100920555,
+    2102275198,
+    2103610053,
+    2104925108,
+    2106220351,
+    2107495769,
+    2108751351,
+    2109987084,
+    2111202958,
+    2112398959,
+    2113575079,
+    2114731304,
+    2115867625,
+    2116984030,
+    2118080510,
+    2119157053,
+    2120213650,
+    2121250291,
+    2122266966,
+    2123263665,
+    2124240379,
+    2125197099,
+    2126133816,
+    2127050521,
+    2127947205,
+    2128823861,
+    2129680479,
+    2130517051,
+    2131333571,
+    2132130029,
+    2132906419,
+    2133662733,
+    2134398965,
+    2135115106,
+    2135811152,
+    2136487094,
+    2137142926,
+    2137778643,
+    2138394239,
+    2138989707,
+    2139565042,
+    2140120239,
+    2140655292,
+    2141170196,
+    2141664947,
+    2142139540,
+    2142593970,
+    2143028233,
+    2143442325,
+    2143836243,
+    2144209981,
+    2144563538,
+    2144896909,
+    2145210091,
+    2145503082,
+    2145775879,
+    2146028479,
+    2146260880,
+    2146473079,
+    2146665075,
+    2146836865,
+    2146988449,
+    2147119824,
+    2147230990,
+    2147321945,
+    2147392689,
+    2147443221,
+    2147473541,
+    2147483647
+};
+
+/* Sine lookup table read */
+static inline int32_t sine_lookup(int idx) {
+    int32_t s;
+    int i1;
+
+    i1 = idx & (2 * SINE_NQUART - 1);
+    if (i1 > SINE_NQUART)
+        i1 = 2 * SINE_NQUART - i1;
+
+    if (idx > 2 * SINE_NQUART)
+        s = -sine_table[i1];
+    else
+        s = sine_table[i1];
+
+    return (s);
+}
+
+/* Compute fixed point sine with table lookup and interpolation */
+int32_t sin_fixed(int32_t w) {
+    int idx;
+    int32_t frac, s0, s1, delta;
+    int64_t sine, idx_tmp;
+
+    /* Q4.28 x Q12.20 -> Q16.48 */
+    idx_tmp = (int64_t) w * SINE_C_Q20;
+    idx = (int) (idx_tmp >> 48); /* Shift to Q0 */
+    idx_tmp = idx_tmp >> 17; /* Shift to Q16.31 */
+    idx_tmp = idx_tmp - (idx << 31); /* Get fraction */
+    frac = (int32_t) idx_tmp; /* Q1.31 */
+    s0 = sine_lookup(idx); /* Q1.31 */
+    s1 = sine_lookup(idx + 1); /* Q1.31 */
+    delta = s1 - s0; /* Q1.31 */
+    //sine = (int64_t) frac*delta; /* Q1.31 x Q1.31 -> Q2.62 */
+    //sine = (sine >> 31) + s0; /* Q2.31 */
+    sine = s0 + q_mults_32x32(frac, delta, 31, 31, 31); /* All Q1.31 */
+    return (int32_t) sine;
+}
+
diff --git a/src/tasks/audio.c b/src/tasks/audio.c
index ed99806..8dc42ce 100644
--- a/src/tasks/audio.c
+++ b/src/tasks/audio.c
@@ -64,6 +64,7 @@ int do_task(struct reef *reef)
 	sys_comp_switch_init();
 	sys_comp_volume_init();
         sys_comp_src_init();
+        sys_comp_tone_init();
 
 #if 0
 	/* init static pipeline */
-- 
2.11.0



More information about the Sound-open-firmware mailing list