1 #include <config.h>
2 /* $Id: holmes.c,v 1.13 1994/11/08 13:30:50 a904209 Exp a904209 $
3  */
4 char *holmes_id = "$Id: holmes.c,v 1.13 1994/11/08 13:30:50 a904209 Exp a904209 $";
5 #include <stdio.h>
6 #include <ctype.h>
7 #include <useconfig.h>
8 #include <math.h>
9 #include "proto.h"
10 #include "nsynth.h"
11 #include "elements.h"
12 #include "darray.h"
13 #include "holmes.h"
14 #include "phfeat.h"
15 #include "getargs.h"
16 
17 #if 1
18 #define AMP_ADJ 14
19 #else
20 #define AMP_ADJ 0
21 #endif
22 
23 FILE *par_file;
24 FILE *jsru_file;
25 int speed = 1;
26 
27 double frac = 1.0;
28 
29 typedef struct
30  {
31   float v;                        /* boundary value */
32   int t;                          /* transition time */
33  }
34 slope_t;
35 
36 typedef struct
37  {
38   slope_t p[nEparm];
39  }
40 trans_t;
41 
42 typedef struct
43  {
44   float a;
45   float b;
46   float v;
47  }
48 filter_t, *filter_ptr;
49 
50 static float filter PROTO((filter_ptr p, Float v));
51 
52 static void jsru_save PROTO((double f0, float *tp));
53 
54 static float
filter(p,v)55 filter(p, v)
56 filter_ptr p;
57 Float v;
58 {
59  return p->v = (p->a * v + p->b * p->v);
60 }
61 
62 /* 'a' is dominant element, 'b' is dominated
63    ext is flag to say to use external times from 'a' rather
64    than internal i.e. ext != 0 if 'a' is NOT current element.
65 
66  */
67 
68 static void set_trans PROTO((slope_t * t, Elm_ptr a, Elm_ptr b, int ext, int e));
69 
70 static void
set_trans(t,a,b,ext,e)71 set_trans(t, a, b, ext, e)
72 slope_t *t;
73 Elm_ptr a;
74 Elm_ptr b;
75 int ext;
76 int e;
77 {
78  int i;
79  for (i = 0; i < nEparm; i++)
80   {
81    t[i].t = ((ext) ? a->p[i].ed : a->p[i].id) * speed;
82    if (t[i].t)
83     t[i].v = a->p[i].fixd + (a->p[i].prop * b->p[i].stdy) * (float) 0.01;
84    else
85     t[i].v = b->p[i].stdy;
86   }
87 }
88 
89 static float linear PROTO((Float a, Float b, int t, int d));
90 
91 /*
92    ______________ b
93    /
94    /
95    /
96    a____________/
97    0   d
98    ---------------t---------------
99  */
100 
101 static float
linear(a,b,t,d)102 linear(a, b, t, d)
103 Float a;
104 Float b;
105 int t;
106 int d;
107 {
108  if (t <= 0)
109   return a;
110  else if (t >= d)
111   return b;
112  else
113   {
114    float f = (float) t / (float) d;
115    return a + (b - a) * f;
116   }
117 }
118 
119 static float interpolate PROTO((char *w, char *p, slope_t * s, slope_t * e, Float mid, int t, int d));
120 
121 static float
interpolate(w,p,s,e,mid,t,d)122 interpolate(w, p, s, e, mid, t, d)
123 char *w;
124 char *p;
125 slope_t *s;
126 slope_t *e;
127 Float mid;
128 int t;
129 int d;
130 {
131  float steady = d - (s->t + e->t);
132 #ifdef DEBUG
133  fprintf(stdout, "%4s %s s=%g,%d e=%g,%d m=%g,%g\n",
134          w, p, s->v, s->t, e->v, e->t, mid, steady);
135 #endif
136  if (steady >= 0)
137   {
138    /* Value reaches stready state somewhere ... */
139    if (t < s->t)
140     return linear(s->v, mid, t, s->t);	/* initial transition */
141    else
142     {
143      t -= s->t;
144      if (t <= steady)
145       return mid;                 /* steady state */
146      else
147       return linear(mid, e->v, (int) (t - steady), e->t);
148      /* final transition */
149     }
150   }
151  else
152   {
153    float f = (float) 1.0 - ((float) t / (float) d);
154    float sp = linear(s->v, mid, t, s->t);
155    float ep = linear(e->v, mid, d - t, e->t);
156    return f * sp + ((float) 1.0 - f) * ep;
157   }
158 }
159 
160 
161 unsigned
holmes(nelm,elm,nsamp,samp_base)162 holmes(nelm, elm, nsamp, samp_base)
163 unsigned nelm;
164 unsigned char *elm;
165 unsigned nsamp;
166 short *samp_base;
167 {
168  filter_t flt[nEparm];
169  klatt_frame_t pars;
170  short *samp = samp_base;
171  Elm_ptr le = &Elements[0];
172  unsigned i = 0;
173  unsigned tstress = 0;
174  unsigned ntstress = 0;
175  slope_t stress_s;
176  slope_t stress_e;
177  float top = 1.1 * def_pars.F0hz10;
178  int j;
179  pars = def_pars;
180  pars.FNPhz = le->p[fn].stdy;
181  pars.B1phz = pars.B1hz = 60;
182  pars.B2phz = pars.B2hz = 90;
183  pars.B3phz = pars.B3hz = 150;
184 #if 0
185  pars.F4hz = 3500;
186 #endif
187  pars.B4phz = def_pars.B4phz;
188 
189  /* flag new utterance */
190  parwave_init(&klatt_global);
191 
192  /* Set stress attack/decay slope */
193  stress_s.t = 40;
194  stress_e.t = 40;
195  stress_e.v = 0.0;
196 
197  for (j = 0; j < nEparm; j++)
198   {
199    flt[j].v = le->p[j].stdy;
200    flt[j].a = frac;
201    flt[j].b = (float) 1.0 - (float) frac;
202   }
203  while (i < nelm)
204   {
205    Elm_ptr ce = &Elements[elm[i++]];
206    unsigned dur = elm[i++];
207    i++; /* skip stress */
208    /* Skip zero length elements which are only there to affect
209       boundary values of adjacent elements
210     */
211    if (dur > 0)
212     {
213      Elm_ptr ne = (i < nelm) ? &Elements[elm[i]] : &Elements[0];
214      slope_t start[nEparm];
215      slope_t end[nEparm];
216      unsigned t;
217 
218      if (ce->rk > le->rk)
219       {
220        if (par_file)
221         fprintf(par_file, "# %s < %s\n", le->name, ce->name);
222        set_trans(start, ce, le, 0, 's');
223        /* we dominate last */
224       }
225      else
226       {
227        if (par_file)
228         fprintf(par_file, "# %s >= %s\n", le->name, ce->name);
229        set_trans(start, le, ce, 1, 's');
230        /* last dominates us */
231       }
232 
233      if (ne->rk > ce->rk)
234       {
235        if (par_file)
236         fprintf(par_file, "# %s < %s\n", ce->name, ne->name);
237        set_trans(end, ne, ce, 1, 'e');
238        /* next dominates us */
239       }
240      else
241       {
242        if (par_file)
243         fprintf(par_file, "# %s >= %s\n", ce->name, ne->name);
244        set_trans(end, ce, ne, 0, 'e');
245        /* we dominate next */
246       }
247 
248      if (par_file)
249       {
250        int j;
251        fprintf(par_file, "# %s\n", ce->name);
252        for (j = 0; j < nEparm; j++)
253         fprintf(par_file, "%c%6s", (j) ? ' ' : '#', Ep_name[j]);
254        fprintf(par_file, "\n");
255        for (j = 0; j < nEparm; j++)
256         fprintf(par_file, "%c%6.4g", (j) ? ' ' : '#', start[j].v);
257        fprintf(par_file, "\n");
258        for (j = 0; j < nEparm; j++)
259         fprintf(par_file, "%c%6d", (j) ? ' ' : '#', start[j].t);
260        fprintf(par_file, "\n");
261       }
262 
263      for (t = 0; t < dur; t++, tstress++)
264       {
265        float base = top * 0.8 /* 3 * top / 5 */;
266        float tp[nEparm];
267        int j;
268 
269        if (tstress == ntstress)
270         {
271          unsigned j = i;
272          stress_s = stress_e;
273          tstress = 0;
274          ntstress = dur;
275 #ifdef DEBUG_STRESS
276          printf("Stress %g -> ", stress_s.v);
277 #endif
278          while (j <= nelm)
279           {
280            Elm_ptr e   = (j < nelm) ? &Elements[elm[j++]] : &Elements[0];
281            unsigned du = (j < nelm) ? elm[j++] : 0;
282            unsigned s  = (j < nelm) ? elm[j++] : 3;
283            if (s || e->feat & vwl)
284             {
285              unsigned d = 0;
286              if (s)
287               stress_e.v = (float) s / 3;
288              else
289               stress_e.v = (float) 0.1;
290              do
291               {
292                d += du;
293 #ifdef DEBUG_STRESS
294                printf("%s", (e && e->dict) ? e->dict : "");
295 #endif
296                e = (j < nelm) ? &Elements[elm[j++]] : &Elements[0];
297                du = elm[j++];
298               }
299              while ((e->feat & vwl) && elm[j++] == s);
300              ntstress += d / 2;
301              break;
302             }
303            ntstress += du;
304           }
305 #ifdef DEBUG_STRESS
306          printf(" %g @ %d\n", stress_e.v, ntstress);
307 #endif
308         }
309 
310        for (j = 0; j < nEparm; j++)
311         tp[j] = filter(flt + j, interpolate(ce->name, Ep_name[j], &start[j], &end[j], (float) ce->p[j].stdy, t, dur));
312 
313        /* Now call the synth for each frame */
314 
315        pars.F0hz10 = base + (top - base) *
316         interpolate("", "f0", &stress_s, &stress_e, (float) 0, tstress, ntstress);
317 
318        pars.AVdb = pars.AVpdb = tp[av];
319        pars.AF = tp[af];
320        pars.FNZhz = tp[fn];
321        pars.ASP = tp[asp];
322        pars.Aturb = tp[avc];
323        pars.B1phz = pars.B1hz = tp[b1];
324        pars.B2phz = pars.B2hz = tp[b2];
325        pars.B3phz = pars.B3hz = tp[b3];
326        pars.F1hz = tp[f1];
327        pars.F2hz = tp[f2];
328        pars.F3hz = tp[f3];
329        /* AMP_ADJ + is a bodge to get amplitudes up to klatt-compatible levels
330           Needs to be fixed properly in tables
331         */
332 /*
333    pars.ANP  = AMP_ADJ + tp[an];
334  */
335        pars.AB = AMP_ADJ + tp[ab];
336        pars.A5 = AMP_ADJ + tp[a5];
337        pars.A6 = AMP_ADJ + tp[a6];
338        pars.A1 = AMP_ADJ + tp[a1];
339        pars.A2 = AMP_ADJ + tp[a2];
340        pars.A3 = AMP_ADJ + tp[a3];
341        pars.A4 = AMP_ADJ + tp[a4];
342 
343        parwave(&klatt_global, &pars, samp);
344 
345        samp += klatt_global.nspfr;
346        if (par_file)
347         {
348          for (j = 0; j < nEparm; j++)
349           fprintf(par_file, " %6.4g", tp[j]);
350          fprintf(par_file, "\n");
351         }
352        if (jsru_file)
353         jsru_save(pars.F0hz10 * 0.1, tp);
354        /* Declination of f0 envelope 0.25Hz / cS */
355        top -= 0.5;
356       }
357      if (par_file)
358       {
359        int j;
360        for (j = 0; j < nEparm; j++)
361         fprintf(par_file, "%c%6.4g", (j) ? ' ' : '#', end[j].v);
362        fprintf(par_file, "\n");
363        for (j = 0; j < nEparm; j++)
364         fprintf(par_file, "%c%6d", (j) ? ' ' : '#', end[j].t);
365        fprintf(par_file, "\n");
366       }
367     }
368    le = ce;
369   }
370  return (samp - samp_base);
371 }
372 
373 int
init_holmes(argc,argv)374 init_holmes(argc, argv)
375 int argc;
376 char *argv[];
377 {
378  char *par_name = NULL;
379  char *jsru_name = NULL;
380  argc = getargs("Holmes",argc, argv,
381                 "p", "", &par_name,  "Parameter file for plot",
382                 "j", "", &jsru_name, "Data for alternate synth (JSRU)",
383                 "S", "%d", &speed,   "Speed (1.0 is 'normal')",
384                 "K", "%lg", &frac,   "Parameter filter 'fraction'",
385                 NULL);
386  if (help_only)
387   return argc;
388  if (par_name)
389   {
390    par_file = fopen(par_name, "w");
391    if (!par_file)
392     perror(par_name);
393   }
394  if (jsru_name)
395   {
396    jsru_file = fopen(jsru_name, "w");
397    if (!jsru_file)
398     perror(jsru_name);
399   }
400  return argc;
401 }
402 
403 void
term_holmes()404 term_holmes()
405 {
406  if (par_file)
407   fclose(par_file);
408  if (jsru_file)
409   fclose(jsru_file);
410 }
411 
412 static int jsru_freq PROTO((Float f, Float base, Float inc));
413 static int
jsru_freq(f,base,inc)414 jsru_freq(f, base, inc)
415 Float f;
416 Float base;
417 Float inc;
418 {
419  int i;
420  f = (f - base) / inc;
421  i = (int) f;
422  if (i >= 64)
423   i = 63;
424  return i;
425 }
426 
427 static int jsru_amp PROTO((Float a));
428 static int
jsru_amp(a)429 jsru_amp(a)
430 Float a;
431 {
432  int i = a;
433  if (i <= 0)
434   i = 1;
435  if (i >= 64)
436   i = 63;
437  return i;
438 }
439 
440 
441 /*          0     1      2      3      4    5
442    F1    F2     F3                 FN
443    flflim 125.0 550.0 1350.0 3500.0 3500.0 95.0
444    fincrm  25.0  50.0   50.0    0.0    0.0  5.0
445  */
446 
447 static void
jsru_save(f0,tp)448 jsru_save(f0, tp)
449 double f0;
450 float *tp;
451 {
452  f0 = 16 * (log(f0 / 25.0) / log(2.0)) - 1;
453 
454  /* fn, alf, f1, a1, f2, a2, f3, a3, ahf, v, f0, m */
455  fputc(jsru_freq(tp[fn], 95.0, 5.0), jsru_file);
456  fputc(jsru_amp(tp[an]), jsru_file);
457  fputc(jsru_freq(tp[f1], 125.0, 25.0), jsru_file);
458  fputc(jsru_amp(tp[a1]), jsru_file);
459  fputc(jsru_freq(tp[f2], 550.0, 50.0), jsru_file);
460  fputc(jsru_amp(tp[a2]), jsru_file);
461  fputc(jsru_freq(tp[f3], 1350.0, 50.0), jsru_file);
462  fputc(jsru_amp(tp[a3]), jsru_file);
463  fputc(jsru_amp(tp[a4]), jsru_file);
464  fputc(jsru_amp(tp[av]), jsru_file);
465  fputc((int) f0, jsru_file);
466  fputc((int) 32, jsru_file);
467 }
468