#include <sys/queue.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <err.h>
#include <math.h>
#include <sysexits.h>
#include "int.h"
#define REF_FREQ 500
uint32_t voss_ad_last_delay;
uint8_t voss_ad_enabled;
uint8_t voss_ad_output_signal;
uint8_t voss_ad_input_channel;
uint8_t voss_ad_output_channel;
static struct voss_ad {
double *wave;
double *sin_a;
double *cos_a;
double *sin_b;
double *cos_b;
double *buf_a;
double *buf_b;
double sum_sin_a;
double sum_cos_a;
double sum_sin_b;
double sum_cos_b;
uint32_t len_a;
uint32_t len_b;
uint32_t offset_a;
uint32_t offset_b;
} voss_ad;
void
voss_ad_reset(void)
{
uint32_t x;
for (x = 0; x != voss_ad.len_a; x++)
voss_ad.buf_a[x] = 0;
for (x = 0; x != voss_ad.len_b; x++)
voss_ad.buf_b[x] = 0;
voss_ad.sum_sin_a = 0;
voss_ad.sum_cos_a = 0;
voss_ad.sum_sin_b = 0;
voss_ad.sum_cos_b = 0;
voss_ad.offset_a = 0;
voss_ad.offset_b = 0;
voss_ad_last_delay = 0;
}
void
voss_ad_init(uint32_t rate)
{
double freq;
int samples;
int len;
int x;
len = sqrt(rate);
samples = len * len;
voss_ad.wave = malloc(sizeof(voss_ad.wave[0]) * samples);
voss_ad.sin_a = malloc(sizeof(voss_ad.sin_a[0]) * len);
voss_ad.cos_a = malloc(sizeof(voss_ad.cos_a[0]) * len);
voss_ad.buf_a = malloc(sizeof(voss_ad.buf_a[0]) * len);
voss_ad.len_a = len;
voss_ad.sin_b = malloc(sizeof(voss_ad.sin_b[0]) * samples);
voss_ad.cos_b = malloc(sizeof(voss_ad.cos_b[0]) * samples);
voss_ad.buf_b = malloc(sizeof(voss_ad.buf_b[0]) * samples);
voss_ad.len_b = samples;
if (voss_ad.sin_a == NULL || voss_ad.cos_a == NULL ||
voss_ad.sin_b == NULL || voss_ad.cos_b == NULL ||
voss_ad.buf_a == NULL || voss_ad.buf_b == NULL)
errx(EX_SOFTWARE, "Out of memory");
freq = 1.0;
while (1) {
double temp = freq * ((double)rate) / ((double)len);
if (temp >= REF_FREQ)
break;
freq += 1.0;
}
for (x = 0; x != len; x++) {
voss_ad.sin_a[x] = sin(freq * 2.0 * M_PI * ((double)x) / ((double)len));
voss_ad.cos_a[x] = cos(freq * 2.0 * M_PI * ((double)x) / ((double)len));
voss_ad.buf_a[x] = 0;
}
for (x = 0; x != samples; x++) {
voss_ad.wave[x] = sin(freq * 2.0 * M_PI * ((double)x) / ((double)len)) *
(1.0 + sin(2.0 * M_PI * ((double)x) / ((double)samples))) / 2.0;
voss_ad.sin_b[x] = sin(2.0 * M_PI * ((double)x) / ((double)samples));
voss_ad.cos_b[x] = cos(2.0 * M_PI * ((double)x) / ((double)samples));
voss_ad.buf_b[x] = 0;
}
}
static double
voss_add_decode_offset(double x , double y )
{
uint32_t v;
double r;
r = sqrt((x * x) + (y * y));
if (r == 0.0)
return (0);
x /= r;
y /= r;
v = 0;
if (y < 0) {
v |= 1;
y = -y;
}
if (x < 0) {
v |= 2;
x = -x;
}
if (y < x) {
r = acos(y);
} else {
r = asin(x);
}
switch (v) {
case 0:
r = (2.0 * M_PI) - r;
break;
case 1:
r = M_PI + r;
break;
case 3:
r = M_PI - r;
break;
default:
break;
}
return (r);
}
double
voss_ad_getput_sample(double sample)
{
double retval;
double phase;
uint32_t xa;
uint32_t xb;
xa = voss_ad.offset_a;
xb = voss_ad.offset_b;
retval = voss_ad.wave[xb];
sample -= voss_ad.buf_a[xa];
voss_ad.sum_sin_a += voss_ad.sin_a[xa] * sample;
voss_ad.sum_cos_a += voss_ad.cos_a[xa] * sample;
voss_ad.buf_a[xa] += sample;
sample = sqrt((voss_ad.sum_sin_a * voss_ad.sum_sin_a) +
(voss_ad.sum_cos_a * voss_ad.sum_cos_a));
sample -= voss_ad.buf_b[xb];
voss_ad.sum_sin_b += voss_ad.sin_b[xb] * sample;
voss_ad.sum_cos_b += voss_ad.cos_b[xb] * sample;
voss_ad.buf_b[xb] += sample;
if (++xa == voss_ad.len_a)
xa = 0;
if (++xb == voss_ad.len_b) {
xb = 0;
phase = voss_add_decode_offset(
voss_ad.sum_cos_b, voss_ad.sum_sin_b);
voss_ad_last_delay = (uint32_t)(phase * (double)(voss_ad.len_b) / (2.0 * M_PI)) - (voss_ad.len_a / 2);
if (voss_ad_last_delay > voss_ad.len_b)
voss_ad_last_delay = voss_ad.len_b;
}
voss_ad.offset_a = xa;
voss_ad.offset_b = xb;
return (retval * (1LL << voss_ad_output_signal));
}