1c72fcc34Sopenharmony_ci/*
2c72fcc34Sopenharmony_ci * Copyright (C) 2015 Caleb Crome
3c72fcc34Sopenharmony_ci * Copyright (C) 2013-2015 Intel Corporation
4c72fcc34Sopenharmony_ci *
5c72fcc34Sopenharmony_ci * This program is free software; you can redistribute it and/or modify
6c72fcc34Sopenharmony_ci * it under the terms of the GNU General Public License as published by
7c72fcc34Sopenharmony_ci * the Free Software Foundation; either version 2 of the License, or
8c72fcc34Sopenharmony_ci * (at your option) any later version.
9c72fcc34Sopenharmony_ci *
10c72fcc34Sopenharmony_ci * This program is distributed in the hope that it will be useful,
11c72fcc34Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
12c72fcc34Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13c72fcc34Sopenharmony_ci * GNU General Public License for more details.
14c72fcc34Sopenharmony_ci *
15c72fcc34Sopenharmony_ci */
16c72fcc34Sopenharmony_ci
17c72fcc34Sopenharmony_ci/*
18c72fcc34Sopenharmony_ci * This is a general purpose sine wave generator that will stay stable
19c72fcc34Sopenharmony_ci * for a long time, and with a little renormalization, could stay stay
20c72fcc34Sopenharmony_ci * stable indefinitely
21c72fcc34Sopenharmony_ci */
22c72fcc34Sopenharmony_ci
23c72fcc34Sopenharmony_ci#include "aconfig.h"
24c72fcc34Sopenharmony_ci
25c72fcc34Sopenharmony_ci#include <stdio.h>
26c72fcc34Sopenharmony_ci#include <stddef.h>
27c72fcc34Sopenharmony_ci#include <stdlib.h>
28c72fcc34Sopenharmony_ci#include <string.h>
29c72fcc34Sopenharmony_ci#include <math.h>
30c72fcc34Sopenharmony_ci#include <stdint.h>
31c72fcc34Sopenharmony_ci#include <stdbool.h>
32c72fcc34Sopenharmony_ci#include <errno.h>
33c72fcc34Sopenharmony_ci
34c72fcc34Sopenharmony_ci#include "gettext.h"
35c72fcc34Sopenharmony_ci#include "common.h"
36c72fcc34Sopenharmony_ci#include "signal.h"
37c72fcc34Sopenharmony_ci
38c72fcc34Sopenharmony_ci/*
39c72fcc34Sopenharmony_ci * Initialize the sine wave generator.
40c72fcc34Sopenharmony_ci * sin_generator:  gets initialized by this call.
41c72fcc34Sopenharmony_ci * frequency:      the frequency for the sine wave.  must be < 0.5*sample_rate
42c72fcc34Sopenharmony_ci * sample_rate:    the sample rate...
43c72fcc34Sopenharmony_ci * returns 0 on success, -1 on error.
44c72fcc34Sopenharmony_ci */
45c72fcc34Sopenharmony_ciint sin_generator_init(struct sin_generator *sg, float magnitude,
46c72fcc34Sopenharmony_ci		float frequency, float sample_rate)
47c72fcc34Sopenharmony_ci{
48c72fcc34Sopenharmony_ci	/* angular frequency:  cycles/sec / (samp/sec) * rad/cycle = rad/samp */
49c72fcc34Sopenharmony_ci	float w = frequency / sample_rate * 2 * M_PI;
50c72fcc34Sopenharmony_ci	if (frequency >= sample_rate / 2)
51c72fcc34Sopenharmony_ci		return -1;
52c72fcc34Sopenharmony_ci	sg->phasor_real = cos(w);
53c72fcc34Sopenharmony_ci	sg->phasor_imag = sin(w);
54c72fcc34Sopenharmony_ci	sg->magnitude   = magnitude;
55c72fcc34Sopenharmony_ci	sg->state_real  = 0.0;
56c72fcc34Sopenharmony_ci	sg->state_imag  = magnitude;
57c72fcc34Sopenharmony_ci	sg->frequency = frequency;
58c72fcc34Sopenharmony_ci	sg->sample_rate = sample_rate;
59c72fcc34Sopenharmony_ci	return 0;
60c72fcc34Sopenharmony_ci}
61c72fcc34Sopenharmony_ci
62c72fcc34Sopenharmony_ci/*
63c72fcc34Sopenharmony_ci * Generates the next sample in the sine wave.
64c72fcc34Sopenharmony_ci * should be much faster than calling a sin function
65c72fcc34Sopenharmony_ci * if it's inlined and optimized.
66c72fcc34Sopenharmony_ci *
67c72fcc34Sopenharmony_ci * returns the next value.  no possibility of error.
68c72fcc34Sopenharmony_ci */
69c72fcc34Sopenharmony_cifloat sin_generator_next_sample(struct sin_generator *sg)
70c72fcc34Sopenharmony_ci{
71c72fcc34Sopenharmony_ci	/* get shorthand to pointers */
72c72fcc34Sopenharmony_ci	const double pr = sg->phasor_real;
73c72fcc34Sopenharmony_ci	const double pi = sg->phasor_imag;
74c72fcc34Sopenharmony_ci	const double sr = sg->state_real;
75c72fcc34Sopenharmony_ci	const double si = sg->state_imag;
76c72fcc34Sopenharmony_ci	/* step the phasor -- complex multiply */
77c72fcc34Sopenharmony_ci	sg->state_real = sr * pr - si * pi;
78c72fcc34Sopenharmony_ci	sg->state_imag = sr * pi + pr * si;
79c72fcc34Sopenharmony_ci	/* return the input value so sine wave starts at exactly 0.0 */
80c72fcc34Sopenharmony_ci	return (float)sr;
81c72fcc34Sopenharmony_ci}
82c72fcc34Sopenharmony_ci
83c72fcc34Sopenharmony_ci/* fills a vector with a sine wave */
84c72fcc34Sopenharmony_civoid sin_generator_vfill(struct sin_generator *sg, float *buf, int n)
85c72fcc34Sopenharmony_ci{
86c72fcc34Sopenharmony_ci	int i;
87c72fcc34Sopenharmony_ci	for (i = 0; i < n; i++)
88c72fcc34Sopenharmony_ci		*buf++ = sin_generator_next_sample(sg);
89c72fcc34Sopenharmony_ci}
90c72fcc34Sopenharmony_ci
91c72fcc34Sopenharmony_cistatic int reorder(struct bat *bat, float *val, int frames)
92c72fcc34Sopenharmony_ci{
93c72fcc34Sopenharmony_ci	float *new_buf = NULL;
94c72fcc34Sopenharmony_ci	int i, c, bytes;
95c72fcc34Sopenharmony_ci
96c72fcc34Sopenharmony_ci	bytes = frames * bat->channels * sizeof(float);
97c72fcc34Sopenharmony_ci
98c72fcc34Sopenharmony_ci	new_buf = (float *) malloc(bytes);
99c72fcc34Sopenharmony_ci	if (new_buf == NULL) {
100c72fcc34Sopenharmony_ci		fprintf(bat->err, _("Not enough memory.\n"));
101c72fcc34Sopenharmony_ci		return -ENOMEM;
102c72fcc34Sopenharmony_ci	}
103c72fcc34Sopenharmony_ci
104c72fcc34Sopenharmony_ci	memcpy(new_buf, val, bytes);
105c72fcc34Sopenharmony_ci	for (i = 0; i < frames; i++)
106c72fcc34Sopenharmony_ci		for (c = 0; c < bat->channels; c++)
107c72fcc34Sopenharmony_ci			val[i * bat->channels + c] =
108c72fcc34Sopenharmony_ci				new_buf[c * frames + i];
109c72fcc34Sopenharmony_ci	free(new_buf);
110c72fcc34Sopenharmony_ci
111c72fcc34Sopenharmony_ci	return 0;
112c72fcc34Sopenharmony_ci}
113c72fcc34Sopenharmony_ci
114c72fcc34Sopenharmony_cistatic int adjust_waveform(struct bat *bat, float *val, int frames,
115c72fcc34Sopenharmony_ci		int channels)
116c72fcc34Sopenharmony_ci{
117c72fcc34Sopenharmony_ci	int i, nsamples, max;
118c72fcc34Sopenharmony_ci	float factor, offset = 0.0;
119c72fcc34Sopenharmony_ci
120c72fcc34Sopenharmony_ci	switch (bat->format) {
121c72fcc34Sopenharmony_ci	case BAT_PCM_FORMAT_U8:
122c72fcc34Sopenharmony_ci		max = INT8_MAX;
123c72fcc34Sopenharmony_ci		offset = max;	/* shift for unsigned format */
124c72fcc34Sopenharmony_ci		break;
125c72fcc34Sopenharmony_ci	case BAT_PCM_FORMAT_S16_LE:
126c72fcc34Sopenharmony_ci		max  = INT16_MAX;
127c72fcc34Sopenharmony_ci		break;
128c72fcc34Sopenharmony_ci	case BAT_PCM_FORMAT_S24_3LE:
129c72fcc34Sopenharmony_ci		max = (1 << 23) - 1;
130c72fcc34Sopenharmony_ci		break;
131c72fcc34Sopenharmony_ci	case BAT_PCM_FORMAT_S32_LE:
132c72fcc34Sopenharmony_ci		max = INT32_MAX;
133c72fcc34Sopenharmony_ci		break;
134c72fcc34Sopenharmony_ci	default:
135c72fcc34Sopenharmony_ci		fprintf(bat->err, _("Invalid PCM format: %d\n"), bat->format);
136c72fcc34Sopenharmony_ci		return -EINVAL;
137c72fcc34Sopenharmony_ci	}
138c72fcc34Sopenharmony_ci
139c72fcc34Sopenharmony_ci	factor = max * RANGE_FACTOR;
140c72fcc34Sopenharmony_ci	nsamples = channels * frames;
141c72fcc34Sopenharmony_ci
142c72fcc34Sopenharmony_ci	for (i = 0; i < nsamples; i++)
143c72fcc34Sopenharmony_ci		val[i] = val[i] * factor + offset;
144c72fcc34Sopenharmony_ci
145c72fcc34Sopenharmony_ci	return 0;
146c72fcc34Sopenharmony_ci}
147c72fcc34Sopenharmony_ci
148c72fcc34Sopenharmony_ciint generate_sine_wave(struct bat *bat, int frames, void *buf)
149c72fcc34Sopenharmony_ci{
150c72fcc34Sopenharmony_ci	int err = 0;
151c72fcc34Sopenharmony_ci	int c, nsamples;
152c72fcc34Sopenharmony_ci	float *sinus_f = NULL;
153c72fcc34Sopenharmony_ci	static struct sin_generator sg[MAX_CHANNELS];
154c72fcc34Sopenharmony_ci
155c72fcc34Sopenharmony_ci	nsamples = bat->channels * frames;
156c72fcc34Sopenharmony_ci	sinus_f = (float *) malloc(nsamples * sizeof(float));
157c72fcc34Sopenharmony_ci	if (sinus_f == NULL) {
158c72fcc34Sopenharmony_ci		fprintf(bat->err, _("Not enough memory.\n"));
159c72fcc34Sopenharmony_ci		return -ENOMEM;
160c72fcc34Sopenharmony_ci	}
161c72fcc34Sopenharmony_ci
162c72fcc34Sopenharmony_ci	for (c = 0; c < bat->channels; c++) {
163c72fcc34Sopenharmony_ci		/* initialize static struct at the first time */
164c72fcc34Sopenharmony_ci		if (sg[c].frequency != bat->target_freq[c])
165c72fcc34Sopenharmony_ci			sin_generator_init(&sg[c], 1.0, bat->target_freq[c],
166c72fcc34Sopenharmony_ci					bat->rate);
167c72fcc34Sopenharmony_ci		/* fill buffer for each channel */
168c72fcc34Sopenharmony_ci		sin_generator_vfill(&sg[c], sinus_f + c * frames, frames);
169c72fcc34Sopenharmony_ci	}
170c72fcc34Sopenharmony_ci
171c72fcc34Sopenharmony_ci	/* reorder samples to interleaved mode */
172c72fcc34Sopenharmony_ci	err = reorder(bat, sinus_f, frames);
173c72fcc34Sopenharmony_ci	if (err != 0)
174c72fcc34Sopenharmony_ci		goto exit;
175c72fcc34Sopenharmony_ci
176c72fcc34Sopenharmony_ci	/* adjust amplitude and offset of waveform */
177c72fcc34Sopenharmony_ci	err = adjust_waveform(bat, sinus_f, frames, bat->channels);
178c72fcc34Sopenharmony_ci	if (err != 0)
179c72fcc34Sopenharmony_ci		goto exit;
180c72fcc34Sopenharmony_ci
181c72fcc34Sopenharmony_ci	bat->convert_float_to_sample(sinus_f, buf, frames, bat->channels);
182c72fcc34Sopenharmony_ci
183c72fcc34Sopenharmony_ciexit:
184c72fcc34Sopenharmony_ci	free(sinus_f);
185c72fcc34Sopenharmony_ci
186c72fcc34Sopenharmony_ci	return err;
187c72fcc34Sopenharmony_ci}
188c72fcc34Sopenharmony_ci
189c72fcc34Sopenharmony_ci/* generate single channel sine waveform without sample conversion */
190c72fcc34Sopenharmony_ciint generate_sine_wave_raw_mono(struct bat *bat, float *buf,
191c72fcc34Sopenharmony_ci		float freq, int nsamples)
192c72fcc34Sopenharmony_ci{
193c72fcc34Sopenharmony_ci	int err = 0;
194c72fcc34Sopenharmony_ci	struct sin_generator sg;
195c72fcc34Sopenharmony_ci
196c72fcc34Sopenharmony_ci	err = sin_generator_init(&sg, 1.0, freq, bat->rate);
197c72fcc34Sopenharmony_ci	if (err < 0)
198c72fcc34Sopenharmony_ci		return err;
199c72fcc34Sopenharmony_ci	sin_generator_vfill(&sg, buf, nsamples);
200c72fcc34Sopenharmony_ci
201c72fcc34Sopenharmony_ci	/* adjust amplitude and offset of waveform */
202c72fcc34Sopenharmony_ci	err = adjust_waveform(bat, buf, nsamples, 1);
203c72fcc34Sopenharmony_ci
204c72fcc34Sopenharmony_ci	return err;
205c72fcc34Sopenharmony_ci}
206