Blame bat/signal.c

Packit Service a9274b
/*
Packit Service a9274b
 * Copyright (C) 2015 Caleb Crome
Packit Service a9274b
 * Copyright (C) 2013-2015 Intel Corporation
Packit Service a9274b
 *
Packit Service a9274b
 * This program is free software; you can redistribute it and/or modify
Packit Service a9274b
 * it under the terms of the GNU General Public License as published by
Packit Service a9274b
 * the Free Software Foundation; either version 2 of the License, or
Packit Service a9274b
 * (at your option) any later version.
Packit Service a9274b
 *
Packit Service a9274b
 * This program is distributed in the hope that it will be useful,
Packit Service a9274b
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service a9274b
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service a9274b
 * GNU General Public License for more details.
Packit Service a9274b
 *
Packit Service a9274b
 */
Packit Service a9274b
Packit Service a9274b
/*
Packit Service a9274b
 * This is a general purpose sine wave generator that will stay stable
Packit Service a9274b
 * for a long time, and with a little renormalization, could stay stay
Packit Service a9274b
 * stable indefinitely
Packit Service a9274b
 */
Packit Service a9274b
Packit Service a9274b
#include <stdio.h>
Packit Service a9274b
#include <stddef.h>
Packit Service a9274b
#include <stdlib.h>
Packit Service a9274b
#include <string.h>
Packit Service a9274b
#include <math.h>
Packit Service a9274b
#include <stdint.h>
Packit Service a9274b
#include <stdbool.h>
Packit Service a9274b
#include <errno.h>
Packit Service a9274b
Packit Service a9274b
#include "gettext.h"
Packit Service a9274b
#include "common.h"
Packit Service a9274b
#include "signal.h"
Packit Service a9274b
Packit Service a9274b
/*
Packit Service a9274b
 * Initialize the sine wave generator.
Packit Service a9274b
 * sin_generator:  gets initialized by this call.
Packit Service a9274b
 * frequency:      the frequency for the sine wave.  must be < 0.5*sample_rate
Packit Service a9274b
 * sample_rate:    the sample rate...
Packit Service a9274b
 * returns 0 on success, -1 on error.
Packit Service a9274b
 */
Packit Service a9274b
int sin_generator_init(struct sin_generator *sg, float magnitude,
Packit Service a9274b
		float frequency, float sample_rate)
Packit Service a9274b
{
Packit Service a9274b
	/* angular frequency:  cycles/sec / (samp/sec) * rad/cycle = rad/samp */
Packit Service a9274b
	float w = frequency / sample_rate * 2 * M_PI;
Packit Service a9274b
	if (frequency >= sample_rate / 2)
Packit Service a9274b
		return -1;
Packit Service a9274b
	sg->phasor_real = cos(w);
Packit Service a9274b
	sg->phasor_imag = sin(w);
Packit Service a9274b
	sg->magnitude   = magnitude;
Packit Service a9274b
	sg->state_real  = 0.0;
Packit Service a9274b
	sg->state_imag  = magnitude;
Packit Service a9274b
	sg->frequency = frequency;
Packit Service a9274b
	sg->sample_rate = sample_rate;
Packit Service a9274b
	return 0;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
/*
Packit Service a9274b
 * Generates the next sample in the sine wave.
Packit Service a9274b
 * should be much faster than calling a sin function
Packit Service a9274b
 * if it's inlined and optimized.
Packit Service a9274b
 *
Packit Service a9274b
 * returns the next value.  no possibility of error.
Packit Service a9274b
 */
Packit Service a9274b
float sin_generator_next_sample(struct sin_generator *sg)
Packit Service a9274b
{
Packit Service a9274b
	/* get shorthand to pointers */
Packit Service a9274b
	const double pr = sg->phasor_real;
Packit Service a9274b
	const double pi = sg->phasor_imag;
Packit Service a9274b
	const double sr = sg->state_real;
Packit Service a9274b
	const double si = sg->state_imag;
Packit Service a9274b
	/* step the phasor -- complex multiply */
Packit Service a9274b
	sg->state_real = sr * pr - si * pi;
Packit Service a9274b
	sg->state_imag = sr * pi + pr * si;
Packit Service a9274b
	/* return the input value so sine wave starts at exactly 0.0 */
Packit Service a9274b
	return (float)sr;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
/* fills a vector with a sine wave */
Packit Service a9274b
void sin_generator_vfill(struct sin_generator *sg, float *buf, int n)
Packit Service a9274b
{
Packit Service a9274b
	int i;
Packit Service a9274b
	for (i = 0; i < n; i++)
Packit Service a9274b
		*buf++ = sin_generator_next_sample(sg);
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static int reorder(struct bat *bat, float *val, int frames)
Packit Service a9274b
{
Packit Service a9274b
	float *new_buf = NULL;
Packit Service a9274b
	int i, c, bytes;
Packit Service a9274b
Packit Service a9274b
	bytes = frames * bat->channels * sizeof(float);
Packit Service a9274b
Packit Service a9274b
	new_buf = (float *) malloc(bytes);
Packit Service a9274b
	if (new_buf == NULL) {
Packit Service a9274b
		fprintf(bat->err, _("Not enough memory.\n"));
Packit Service a9274b
		return -ENOMEM;
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
	memcpy(new_buf, val, bytes);
Packit Service a9274b
	for (i = 0; i < frames; i++)
Packit Service a9274b
		for (c = 0; c < bat->channels; c++)
Packit Service a9274b
			val[i * bat->channels + c] =
Packit Service a9274b
				new_buf[c * frames + i];
Packit Service a9274b
	free(new_buf);
Packit Service a9274b
Packit Service a9274b
	return 0;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static int adjust_waveform(struct bat *bat, float *val, int frames,
Packit Service a9274b
		int channels)
Packit Service a9274b
{
Packit Service a9274b
	int i, nsamples, max;
Packit Service a9274b
	float factor, offset = 0.0;
Packit Service a9274b
Packit Service a9274b
	switch (bat->format) {
Packit Service a9274b
	case BAT_PCM_FORMAT_U8:
Packit Service a9274b
		max = INT8_MAX;
Packit Service a9274b
		offset = max;	/* shift for unsigned format */
Packit Service a9274b
		break;
Packit Service a9274b
	case BAT_PCM_FORMAT_S16_LE:
Packit Service a9274b
		max  = INT16_MAX;
Packit Service a9274b
		break;
Packit Service a9274b
	case BAT_PCM_FORMAT_S24_3LE:
Packit Service a9274b
		max = (1 << 23) - 1;
Packit Service a9274b
		break;
Packit Service a9274b
	case BAT_PCM_FORMAT_S32_LE:
Packit Service a9274b
		max = INT32_MAX;
Packit Service a9274b
		break;
Packit Service a9274b
	default:
Packit Service a9274b
		fprintf(bat->err, _("Invalid PCM format: %d\n"), bat->format);
Packit Service a9274b
		return -EINVAL;
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
	factor = max * RANGE_FACTOR;
Packit Service a9274b
	nsamples = channels * frames;
Packit Service a9274b
Packit Service a9274b
	for (i = 0; i < nsamples; i++)
Packit Service a9274b
		val[i] = val[i] * factor + offset;
Packit Service a9274b
Packit Service a9274b
	return 0;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
int generate_sine_wave(struct bat *bat, int frames, void *buf)
Packit Service a9274b
{
Packit Service a9274b
	int err = 0;
Packit Service a9274b
	int c, nsamples;
Packit Service a9274b
	float *sinus_f = NULL;
Packit Service a9274b
	static struct sin_generator sg[MAX_CHANNELS];
Packit Service a9274b
Packit Service a9274b
	nsamples = bat->channels * frames;
Packit Service a9274b
	sinus_f = (float *) malloc(nsamples * sizeof(float));
Packit Service a9274b
	if (sinus_f == NULL) {
Packit Service a9274b
		fprintf(bat->err, _("Not enough memory.\n"));
Packit Service a9274b
		return -ENOMEM;
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
	for (c = 0; c < bat->channels; c++) {
Packit Service a9274b
		/* initialize static struct at the first time */
Packit Service a9274b
		if (sg[c].frequency != bat->target_freq[c])
Packit Service a9274b
			sin_generator_init(&sg[c], 1.0, bat->target_freq[c],
Packit Service a9274b
					bat->rate);
Packit Service a9274b
		/* fill buffer for each channel */
Packit Service a9274b
		sin_generator_vfill(&sg[c], sinus_f + c * frames, frames);
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
	/* reorder samples to interleaved mode */
Packit Service a9274b
	err = reorder(bat, sinus_f, frames);
Packit Service a9274b
	if (err != 0)
Packit Service a9274b
		goto exit;
Packit Service a9274b
Packit Service a9274b
	/* adjust amplitude and offset of waveform */
Packit Service a9274b
	err = adjust_waveform(bat, sinus_f, frames, bat->channels);
Packit Service a9274b
	if (err != 0)
Packit Service a9274b
		goto exit;
Packit Service a9274b
Packit Service a9274b
	bat->convert_float_to_sample(sinus_f, buf, frames, bat->channels);
Packit Service a9274b
Packit Service a9274b
exit:
Packit Service a9274b
	free(sinus_f);
Packit Service a9274b
Packit Service a9274b
	return err;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
/* generate single channel sine waveform without sample conversion */
Packit Service a9274b
int generate_sine_wave_raw_mono(struct bat *bat, float *buf,
Packit Service a9274b
		float freq, int nsamples)
Packit Service a9274b
{
Packit Service a9274b
	int err = 0;
Packit Service a9274b
	struct sin_generator sg;
Packit Service a9274b
Packit Service a9274b
	err = sin_generator_init(&sg, 1.0, freq, bat->rate);
Packit Service a9274b
	if (err < 0)
Packit Service a9274b
		return err;
Packit Service a9274b
	sin_generator_vfill(&sg, buf, nsamples);
Packit Service a9274b
Packit Service a9274b
	/* adjust amplitude and offset of waveform */
Packit Service a9274b
	err = adjust_waveform(bat, buf, nsamples, 1);
Packit Service a9274b
Packit Service a9274b
	return err;
Packit Service a9274b
}