#include "config.h"
char *holmes_id = "$Id: holmes.c,v 1.2 2006/06/12 14:12:52 stephena Exp $";
#include <stdio.h>
#include <ctype.h>
#include <assert.h>
#include "useconfig.h"
#include <math.h>
#include "rsynth.h"
#include "darray.h"
typedef struct {
float v;
long t;
} slope_t;
typedef struct {
float a;
float b;
float v;
} filter_t, *filter_ptr;
static float
filter(filter_ptr p, float v)
{
return p->v = (p->a * v + p->b * p->v);
}
static void
set_trans(slope_t * t, int i, Elm_ptr a, Elm_ptr b, int ext, int e,
float speed)
{
t[i].t = (long) (((ext) ? a->p[i].ed : a->p[i].id) * speed);
if (t[i].t) {
float afrac = a->p[i].prop * 0.01F;
t[i].v = a->p[i].stdy * (1.0F - afrac) + (afrac * b->p[i].stdy);
}
else
t[i].v = b->p[i].stdy;
}
float
linear(float a, float b, long t, long d)
{
if (t <= 0)
return a;
else if (t >= d)
return b;
else {
float f = (float) t / (float) d;
return a + (b - a) * f;
}
}
float
interpolate(char *w, char *p, slope_t * s, slope_t * e, float mid, long t,
long d)
{
float steady = d - (s->t + e->t);
#ifdef DEBUG
fprintf(stdout, "%4s %s s=%g,%d e=%g,%d m=%g,%g\n",
w, p, s->v, s->t, e->v, e->t, mid, steady);
#endif
if (steady >= 0) {
if (t < s->t)
return linear(s->v, mid, t, s->t);
else {
t -= s->t;
if (t <= steady)
return mid;
else
return linear(mid, e->v, (int) (t - steady), e->t);
}
}
else {
float f = (float) 1.0 - ((float) t / (float) d);
float sp = linear(s->v, mid, t, s->t);
float ep = linear(e->v, mid, d - t, e->t);
return f * sp + ((float) 1.0 - f) * ep;
}
}
#define CHECK_SPACING(a,b) \
do { \
if (a < b + 200) \
fprintf(stdout,"%s=%g < %s=%g+200\n",#a,a,#b,b); \
} while (0)
unsigned
rsynth_interpolate(rsynth_t * rsynth,
unsigned char *elm, unsigned nelm,
float *f0, unsigned nf0)
{
filter_t flt[nEparm];
float ep[nEparm];
Elm_ptr le = &Elements[0];
unsigned i = 0;
unsigned tf0 = 0;
unsigned ntf0 = 0;
unsigned samp = 0;
float contour[3];
float f0s = rsynth->speaker->F0Hz;
float f0e = f0s;
int j;
float speed = rsynth->speed;
float F0Hz;
if (nf0 < 3 || !f0 || (rsynth->flags & RSYNTH_MONOTONE)) {
unsigned i;
f0 = contour;
nf0 = 3;
for (i = 0; i < nelm; i += 2) {
f0[1] += elm[i + 1];
}
if ((rsynth->flags & RSYNTH_MONOTONE)) {
f0[0] = rsynth->speaker->F0Hz;
f0[2] = f0[0];
}
else {
f0[0] = 1.1 * rsynth->speaker->F0Hz;
f0[2] = 0.6 * f0[0];
}
}
#if 0#endif
f0e = f0s = *f0++;
for (j = 0; j < nEparm; j++) {
flt[j].v = le->p[j].stdy;
flt[j].a = rsynth->smooth;
flt[j].b = 1.0F - rsynth->smooth;
}
while (i < nelm) {
Elm_ptr ce = &Elements[elm[i++]];
unsigned dur = elm[i++];
if (rsynth->flags & RSYNTH_ETRACE) {
printf("%s.%ld ", ce->name,
1000 * dur * rsynth->samples_frame / rsynth->sr);
}
if (dur > 0) {
Elm_ptr ne = (i < nelm) ? &Elements[elm[i]] : &Elements[0];
slope_t start[nEparm];
slope_t end[nEparm];
unsigned t;
int i;
for (i = 0; i < nEparm; i++) {
if (ce->p[i].rk > le->p[i].rk) {
if (rsynth->parm_file)
fprintf(rsynth->parm_file,
"# %3s %2s(%2d) < %2s(%2d)\n", Ep_name[i],
le->name, le->p[i].rk, ce->name,
ce->p[i].rk);
set_trans(start, i, ce, le, 0, 's', speed);
}
else {
if (rsynth->parm_file)
fprintf(rsynth->parm_file,
"# %3s %2s(%2d) >= %2s(%2d)\n", Ep_name[i],
le->name, le->p[i].rk, ce->name,
ce->p[i].rk);
set_trans(start, i, le, ce, 1, 's', speed);
}
if (ne->p[i].rk > ce->p[i].rk) {
if (rsynth->parm_file)
fprintf(rsynth->parm_file,
"# %3s %2s(%2d) < %2s(%2d)\n", Ep_name[i],
ce->name, ce->p[i].rk, ne->name,
ne->p[i].rk);
set_trans(end, i, ne, ce, 1, 'e', speed);
}
else {
if (rsynth->parm_file)
fprintf(rsynth->parm_file,
"# %3s %2s(%2d) >= %2s(%2d)\n", Ep_name[i],
ce->name, ce->p[i].rk, ne->name,
ne->p[i].rk);
set_trans(end, i, ce, ne, 0, 'e', speed);
}
}
if (rsynth->parm_file) {
int j;
fprintf(rsynth->parm_file, "# %s\n", ce->name);
fprintf(rsynth->parm_file, "%c%6s %6s", '#', "f0", "ao");
for (j = 0; j < nEparm; j++)
fprintf(rsynth->parm_file, "%c%6s", ' ', Ep_name[j]);
fprintf(rsynth->parm_file, "\n#%6s %6s", "", "");
for (j = 0; j < nEparm; j++)
fprintf(rsynth->parm_file, "%c%6.4g", ' ', start[j].v);
fprintf(rsynth->parm_file, "\n#%6s %6s", "", "");
for (j = 0; j < nEparm; j++)
fprintf(rsynth->parm_file, "%c%6ld", ' ', start[j].t);
fprintf(rsynth->parm_file, "\n");
}
for (t = 0; t < dur; t++, tf0++) {
int j;
float peak = 0.25;
for (j = 0; j < nEparm; j++) {
ep[j] =
filter(flt + j,
interpolate(ce->name, Ep_name[j], &start[j],
&end[j], (float) ce->p[j].stdy,
t, dur));
}
while (tf0 == ntf0) {
tf0 = 0;
f0s = f0e;
ntf0 = (unsigned) *f0++;
f0e = *f0++;
#if 0#endif
}
F0Hz = linear(f0s, f0e, tf0, ntf0);
if (rsynth->flags & RSYNTH_F0TRACE) {
printf(" %5.1fHz", F0Hz);
}
CHECK_SPACING(ep[f2], ep[f1]);
CHECK_SPACING(ep[f3], ep[f2]);
CHECK_SPACING(rsynth->speaker->F4hz, ep[f3]);
samp += rsynth_frame(rsynth, F0Hz, ep, ce->name);
if (rsynth->parm_file) {
fprintf(rsynth->parm_file, " %6.4g %6.4g",
F0Hz, 10 * log10(peak));
for (j = 0; j < nEparm; j++)
fprintf(rsynth->parm_file, " %6.4g", ep[j]);
fprintf(rsynth->parm_file, "\n");
}
}
if (rsynth->parm_file) {
int j;
fprintf(rsynth->parm_file, "#%6s %6s", "", "");
for (j = 0; j < nEparm; j++)
fprintf(rsynth->parm_file, " %6.4g", end[j].v);
fprintf(rsynth->parm_file, "\n");
fprintf(rsynth->parm_file, "#%6s %6s", "", "");
for (j = 0; j < nEparm; j++)
fprintf(rsynth->parm_file, " %6ld", end[j].t);
fprintf(rsynth->parm_file, "\n");
}
}
le = ce;
}
if (rsynth->flags & (RSYNTH_ETRACE | RSYNTH_F0TRACE)) {
printf("\n");
}
return samp;
}