~ubuntu-branches/debian/squeeze/stella/squeeze

« back to all changes in this revision

Viewing changes to src/emucore/rsynth/phtoelm.c

  • Committer: Bazaar Package Importer
  • Author(s): Stephen Kitt
  • Date: 2010-07-12 23:49:36 UTC
  • mfrom: (1.1.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20100712234936-juawrr3etzhr2qpv
Tags: 3.1.2-1
* New maintainer (closes: #532039).
* New upstream version (closes: #461121):
  - includes launcher (closes: #396058).
* Fix the reference to the X Window System in the description (closes:
  #411815).
* Move to main, DFSG-free ROMs are available (see README.Debian).
* Enhance the package description.
* Drop the libslang2-dev dependency (closes: #560274).
* Remove the Encoding entry from stella.desktop.
* Avoid ignoring errors when cleaning.
* Add ${misc:Depends} to the package dependencies.
* Provide a doc-base file to install the documentation using doc-base.
* Switch to debhelper 7 with a simplified rules file.
* Use autotools-dev to provide updated configuration files.
* Update to Standards-Version 3.9.0:
  - Move to menu section Applications/Emulators.
  - Move the homepage declaration.
* Re-write the manpage.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
    Copyright (c) 1994,2001-2003 Nick Ing-Simmons. All rights reserved.
3
 
 
4
 
    This library is free software; you can redistribute it and/or
5
 
    modify it under the terms of the GNU Library General Public
6
 
    License as published by the Free Software Foundation; either
7
 
    version 2 of the License, or (at your option) any later version.
8
 
 
9
 
    This library is distributed in the hope that it will be useful,
10
 
    but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
 
    Library General Public License for more details.
13
 
 
14
 
    You should have received a copy of the GNU Library General Public
15
 
    License along with this library; if not, write to the Free
16
 
    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
17
 
    MA 02111-1307, USA
18
 
 
19
 
*/
20
 
#include "config.h"
21
 
 
22
 
/* $Id: phtoelm.c,v 1.2 2006/06/12 14:12:52 stephena Exp $
23
 
 */
24
 
char *phtoelm_id = "$Id: phtoelm.c,v 1.2 2006/06/12 14:12:52 stephena Exp $";
25
 
#include <stdio.h>
26
 
#include <ctype.h>
27
 
#include <stdlib.h>
28
 
#include <math.h>
29
 
#include <stdarg.h>
30
 
#include "useconfig.h"
31
 
#include "rsynth.h"
32
 
#include "trie.h"
33
 
#include "phfeat.h"
34
 
 
35
 
 
36
 
trie_ptr phtoelm = NULL;
37
 
 
38
 
static Elm_ptr find_elm(char *s);
39
 
 
40
 
static Elm_ptr
41
 
find_elm(char *s)
42
 
{
43
 
    Elm_ptr e = Elements;
44
 
    while (e < Elements + num_Elements) {
45
 
        if (!strcmp(s, e->name)) {
46
 
            return e;
47
 
        }
48
 
        e++;
49
 
    }
50
 
    return NULL;
51
 
}
52
 
 
53
 
#define COMMENT(s)
54
 
 
55
 
static void
56
 
enter(char *p, ...)
57
 
{
58
 
    va_list ap;
59
 
    char *s;
60
 
    char buf[20];
61
 
    char *x = buf + 1;
62
 
    va_start(ap, p);
63
 
    while ((s = va_arg(ap, char *))) {
64
 
        Elm_ptr e = find_elm(s);
65
 
        if (e)
66
 
            *x++ = (e - Elements);
67
 
        else {
68
 
            fprintf(stderr, "Cannot find %s for [%s]\n", s, p);
69
 
        }
70
 
    }
71
 
    va_end(ap);
72
 
    buf[0] = (x - buf) - 1;
73
 
    x = (char *) malloc(buf[0] + 1);
74
 
    memcpy(x, buf, buf[0] + 1);
75
 
    trie_insert(&phtoelm, p, x);
76
 
}
77
 
 
78
 
static void
79
 
enter_phonemes(void)
80
 
{
81
 
#include "phtoelm.def"
82
 
}
83
 
 
84
 
trie_ptr
85
 
enter_trans(char *trans, int verbose)
86
 
{
87
 
    trie_ptr table = NULL;
88
 
    FILE *f = fopen(trans, "r");
89
 
    if (f) {
90
 
        char buf[1024];
91
 
        char *s;
92
 
        if (verbose)
93
 
            fprintf(stderr, "Reading %s\n", trans);
94
 
        while ((s = fgets(buf, sizeof(buf), f))) {
95
 
            char *p;
96
 
            char *x;
97
 
            while (isspace((unsigned) *s))
98
 
                s++;
99
 
            p = s;
100
 
            while (*s && !isspace((unsigned) *s))
101
 
                s++;
102
 
            while (isspace((unsigned) *s))
103
 
                *s++ = '\0';
104
 
            x = (char *) trie_lookup(&phtoelm, &s);
105
 
            while (isspace(*s))
106
 
                s++;
107
 
            if (*s) {
108
 
                fprintf(stderr, "%s does not map (leaves %s)\n", p, s);
109
 
            }
110
 
            else {
111
 
                trie_insert(&table, p, x);
112
 
            }
113
 
        }
114
 
        fclose(f);
115
 
    }
116
 
    else {
117
 
        perror(trans);
118
 
    }
119
 
    return table;
120
 
}
121
 
 
122
 
 
123
 
#if 1
124
 
#define StressDur(e,s,l) ((e->ud + (e->du - e->ud) * s / 3)*speed)
125
 
#else
126
 
#define StressDur(e,s,l) ((void)(s),(l ? e->du*speed : (e->du + e->ud)/2)*speed)
127
 
#endif
128
 
 
129
 
static float
130
 
decline_f0(float F0Hz, darray_ptr f0, float f, unsigned t)
131
 
{
132
 
    darray_float(f0, t);
133
 
    /* Magic constant - ugh */
134
 
    f -= 0.12 * t;
135
 
    /* Do not drop forever */
136
 
    if (f < 0.7 * F0Hz)
137
 
        f = 0.7 * F0Hz;
138
 
    return darray_float(f0, f);
139
 
}
140
 
 
141
 
static unsigned
142
 
phone_to_elm(rsynth_t * rsynth, int n, char *phone, darray_ptr elm,
143
 
             darray_ptr f0)
144
 
{
145
 
    float F0Hz = rsynth->speaker->F0Hz;
146
 
    float speed = rsynth->speed;
147
 
    int stress = 0;
148
 
    int seen_vowel = 0;
149
 
    int islong = 0;
150
 
    char *s = phone;
151
 
    unsigned t = 0;
152
 
    unsigned f0t = 0;
153
 
    char *limit = s + n;
154
 
    float f = darray_float(f0, F0Hz * 1.1F);
155
 
    if (!phtoelm)
156
 
        enter_phonemes();
157
 
    while (s < limit && *s) {
158
 
        char *e = (char *) trie_lookup(&phtoelm, &s);
159
 
        if (e) {
160
 
            int n = *e++;
161
 
            while (n-- > 0) {
162
 
                int x = *e++;
163
 
                Elm_ptr p = &Elements[x];
164
 
                darray_append(elm, x);
165
 
                /* StressDur works because only vowels have ud != du,
166
 
                   and we set stress just before a vowel
167
 
                 */
168
 
                t += darray_append(elm,
169
 
                                   (int) (StressDur(p, stress, islong)));
170
 
                if (p->feat & vwl) {
171
 
                    seen_vowel = 1;
172
 
                }
173
 
                else if (seen_vowel) {
174
 
                    stress = 0;
175
 
                }
176
 
            }
177
 
        }
178
 
        else {
179
 
            char ch = *s++;
180
 
            switch (ch) {
181
 
            case '\'':          /* Primary stress */
182
 
                stress++;
183
 
            case ',':           /* Secondary stress */
184
 
                stress++;
185
 
            case '+':           /* Tertiary stress */
186
 
                stress++;
187
 
                if (stress > 3)
188
 
                    stress = 3;
189
 
                seen_vowel = 0;
190
 
                /* f0 has been declining since f0t */
191
 
                f = decline_f0(F0Hz, f0, f, t - f0t);
192
 
                f0t = t;
193
 
                /* Now stress pulse pushes f0 up "instantly" */
194
 
                darray_float(f0, 0);
195
 
                darray_float(f0, f + F0Hz * stress * 0.02);
196
 
                break;
197
 
            case '-':           /* hyphen in input */
198
 
                break;
199
 
            case ':':           /* Length mark */
200
 
                islong = 1;
201
 
                break;
202
 
            default:
203
 
                fprintf(stderr, "Ignoring %c in '%.*s'\n", ch, n, phone);
204
 
                break;
205
 
            }
206
 
        }
207
 
    }
208
 
    /* Add final decline to f0 contour */
209
 
    decline_f0(F0Hz, f0, f, t - f0t);
210
 
    return t;
211
 
}
212
 
 
213
 
void
214
 
rsynth_phones(rsynth_t * rsynth, char *phone, int len)
215
 
{
216
 
    darray_t elm;
217
 
    darray_t f0;
218
 
    unsigned frames;
219
 
    darray_init(&elm, sizeof(char), len);
220
 
    darray_init(&f0, sizeof(float), len);
221
 
    if ((frames = phone_to_elm(rsynth, len, phone, &elm, &f0))) {
222
 
        if (rsynth_verbose(rsynth))
223
 
            fprintf(stderr, "[%.*s]\n", len, phone);
224
 
        rsynth_flush(rsynth,
225
 
                     rsynth_interpolate(rsynth,
226
 
                                        (unsigned char *) darray_find(&elm, 0),elm.items,
227
 
                                                (float *) darray_find(&f0,0),
228
 
                                                f0.items));
229
 
    }
230
 
    darray_free(&f0);
231
 
    darray_free(&elm);
232
 
}
233
 
 
234
 
void
235
 
rsynth_pho(rsynth_t * rsynth, const char *path, int dodur, char *trans)
236
 
{
237
 
    int verbose = rsynth_verbose(rsynth);
238
 
    FILE *f = fopen(path, "r");
239
 
    trie_ptr table;
240
 
    if (!phtoelm)
241
 
        enter_phonemes();
242
 
    if (trans && *trans && strcmp(trans, "sampa"))
243
 
        table = enter_trans(trans, verbose);
244
 
    else
245
 
        table = phtoelm;
246
 
    if (f) {
247
 
        char buffer[1024];
248
 
        char *s;
249
 
        darray_t elm;
250
 
        unsigned t = 0;
251
 
        float f0a[1024] = { rsynth->speaker->F0Hz };
252
 
        unsigned nf0 = 0;       /* index of last f0 value */
253
 
        unsigned f0t = 0;       /* time of last f0 value */
254
 
        darray_init(&elm, sizeof(char), 1024);
255
 
        if (verbose) {
256
 
            fprintf(stderr, "Frame is %.3gms\n",
257
 
                    rsynth->samples_frame * 1000.0 / rsynth->sr);
258
 
        }
259
 
        while ((s = fgets(buffer, sizeof(buffer), f))) {
260
 
            /* skip leading space - should not be any but ... */
261
 
            while (isspace((unsigned) *s))
262
 
                s++;
263
 
            if (*s && *s != ';') {
264
 
                /* Not a comment */
265
 
                char *ps = s;
266
 
                char *e = (char *) trie_lookup(&table, &s);
267
 
                if (*s == ':')
268
 
                    s++;
269
 
                if (e && isspace((unsigned) *s)) {
270
 
                    char *pe = s;
271
 
                    unsigned pt = 0;
272
 
                    int n = *e++;
273
 
                    int i;
274
 
                    double ms = strtod(s, &s);
275
 
                    float frames =
276
 
                        ms * (rsynth->sr / rsynth->samples_frame) / 1000;
277
 
                    float edur = 0;
278
 
                    float estp = 0;
279
 
                    int nstp = 0;
280
 
                    float delta = 0;
281
 
                    for (i = 0; i < n; i++) {
282
 
                        int x = e[i];
283
 
                        Elm_ptr p = &Elements[x];
284
 
                        if (!p->du || p->feat & stp)
285
 
                            estp += p->ud;
286
 
                        else {
287
 
                            edur += p->ud;
288
 
                            nstp++;
289
 
                        }
290
 
                    }
291
 
                    /* Stops don't change length */
292
 
                    frames -= estp;
293
 
                    delta = frames - edur;
294
 
#if 0
295
 
                    /* FIXME - revisit the rounding process */
296
 
                    if (verbose)
297
 
                        fprintf(stderr,
298
 
                                "'%.*s' %gms %d elem %g frames vs %g nat d=%g) %d stops\n",
299
 
                                (pe - ps), ps, ms, n, frames, edur, delta,
300
 
                                n - nstp);
301
 
#endif
302
 
                    for (i = 0; i < n; i++) {
303
 
                        int x = e[i];
304
 
                        Elm_ptr p = &Elements[x];
305
 
                        darray_append(&elm, x);
306
 
                        if (!p->du || p->feat & stp)
307
 
                            pt += darray_append(&elm, p->ud);
308
 
                        else {
309
 
                            if (dodur) {
310
 
                                float share =
311
 
                                    (nstp >
312
 
                                     1) ? rint(delta * (p->ud -
313
 
                                                        1) / (edur -
314
 
                                                              nstp)) :
315
 
                                    delta;
316
 
#if 0
317
 
                                fprintf(stderr,
318
 
                                        "%s d=%d vs nstp=%g delta=%g take=%g\n",
319
 
                                        p->name, p->ud, edur, delta,
320
 
                                        share);
321
 
#endif
322
 
                                edur -= p->ud;
323
 
                                delta -= share;
324
 
                                nstp--;
325
 
                                pt +=
326
 
                                    darray_append(&elm,
327
 
                                                  (int) (p->ud + share));
328
 
                            }
329
 
                            else
330
 
                                pt += darray_append(&elm, p->du);
331
 
                        }
332
 
                    }
333
 
                    /* Now have elements entered and duration of phone computed */
334
 
                    if (verbose && dodur) {
335
 
                        float got =
336
 
                            1.0 * pt * rsynth->samples_frame / rsynth->sr *
337
 
                            1000;
338
 
                        if (fabs(got - ms) > 0.5) {
339
 
                            fprintf(stderr,
340
 
                                    "'%.*s' want=%gms got=%.3g (%+3.0f%%)\n",
341
 
                                    (pe - ps), ps, ms, got,
342
 
                                    100 * (got - ms) / ms);
343
 
                        }
344
 
                    }
345
 
                    while (isspace((unsigned) *s))
346
 
                        s++;
347
 
                    while (*s) {
348
 
                        float percent = strtod(s, &s);
349
 
                        float f0 = strtod(s, &s);
350
 
                        unsigned nt =
351
 
                            (unsigned) (t + (percent * pt / 100));
352
 
                        if (nt > f0t) {
353
 
                            /* time has advanced */
354
 
                            f0a[++nf0] = (nt - f0t);
355
 
                            f0a[++nf0] = f0;
356
 
                            f0t = nt;
357
 
                        }
358
 
                        else {
359
 
                            /* same time - change target inplace */
360
 
                            f0a[nf0] = f0;
361
 
                        }
362
 
                        while (isspace((unsigned) *s))
363
 
                            s++;
364
 
                    }
365
 
                    t += pt;
366
 
                }
367
 
                else {
368
 
                    fputs(buffer, stderr);
369
 
                    fprintf(stderr, "Unknown phone:%s", ps);
370
 
                }
371
 
            }
372
 
        }
373
 
        fclose(f);
374
 
        if (t) {
375
 
            float f0 = f0a[nf0++];
376
 
            if (f0t < t) {
377
 
                f0a[nf0++] = t - f0t;
378
 
                f0a[nf0++] = f0;
379
 
            }
380
 
            rsynth_flush(rsynth,
381
 
                rsynth_interpolate(rsynth,
382
 
                            (unsigned char *) darray_find(&elm, 0),
383
 
                            elm.items, f0a, nf0));
384
 
        }
385
 
    }
386
 
    else {
387
 
        perror(path);
388
 
    }
389
 
}
390
 
 
391
 
void
392
 
rsynth_term(rsynth_t * rsynth)
393
 
{
394
 
    if (rsynth) {
395
 
        rsynth_flush(rsynth, 0);
396
 
        trie_free(&phtoelm, &free);
397
 
#ifdef DO_RANGE_CHECKS
398
 
        fprintf(stderr, "Max range %g @ %s:%d\n", range_max, __FILE__,
399
 
                range_ln);
400
 
#endif
401
 
        if (rsynth->voice_file)
402
 
            fclose(rsynth->voice_file);
403
 
        if (rsynth->parm_file)
404
 
            fclose(rsynth->parm_file);
405
 
        free(rsynth->pvt);
406
 
        free(rsynth);
407
 
    }
408
 
}