/src/espeak-ng/src/libespeak-ng/wavegen.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright (C) 2005 to 2013 by Jonathan Duddington |
3 | | * email: jonsd@users.sourceforge.net |
4 | | * Copyright (C) 2015-2016 Reece H. Dunn |
5 | | * |
6 | | * This program is free software; you can redistribute it and/or modify |
7 | | * it under the terms of the GNU General Public License as published by |
8 | | * the Free Software Foundation; either version 3 of the License, or |
9 | | * (at your option) any later version. |
10 | | * |
11 | | * This program is distributed in the hope that it will be useful, |
12 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | | * GNU General Public License for more details. |
15 | | * |
16 | | * You should have received a copy of the GNU General Public License |
17 | | * along with this program; if not, see: <http://www.gnu.org/licenses/>. |
18 | | */ |
19 | | |
20 | | // this version keeps wavemult window as a constant fraction |
21 | | // of the cycle length - but that spreads out the HF peaks too much |
22 | | |
23 | | #include "config.h" |
24 | | |
25 | | #include <math.h> |
26 | | #include <stdbool.h> |
27 | | #include <stdint.h> |
28 | | #include <stdio.h> |
29 | | #include <stdlib.h> |
30 | | #include <string.h> |
31 | | |
32 | | #include <espeak-ng/espeak_ng.h> |
33 | | #include <espeak-ng/speak_lib.h> |
34 | | |
35 | | #include "wavegen.h" |
36 | | #include "common.h" // for espeak_rand |
37 | | #include "synthesize.h" // for WGEN_DATA, RESONATOR, frame_t |
38 | | #include "mbrola.h" // for MbrolaFill, MbrolaReset, mbrola... |
39 | | |
40 | | #if USE_KLATT |
41 | | #include "klatt.h" |
42 | | #endif |
43 | | |
44 | | #if USE_LIBSONIC |
45 | | #include "sonic.h" |
46 | | #endif |
47 | | |
48 | | #include "sintab.h" |
49 | | #include "speech.h" |
50 | | |
51 | | static void SetSynth(int length, int modn, frame_t *fr1, frame_t *fr2, voice_t *v); |
52 | | |
53 | | static voice_t *wvoice = NULL; |
54 | | |
55 | | static int option_harmonic1 = 10; |
56 | | static int flutter_amp = 64; |
57 | | |
58 | | static int general_amplitude = 60; |
59 | | static int consonant_amp = 26; |
60 | | |
61 | | int embedded_value[N_EMBEDDED_VALUES]; |
62 | | |
63 | | static int PHASE_INC_FACTOR; |
64 | | int samplerate = 0; // this is set by Wavegeninit() |
65 | | |
66 | | static wavegen_peaks_t peaks[N_PEAKS]; |
67 | | static int peak_harmonic[N_PEAKS]; |
68 | | static int peak_height[N_PEAKS]; |
69 | | |
70 | | int echo_head; |
71 | | int echo_tail; |
72 | | int echo_amp = 0; |
73 | | short echo_buf[N_ECHO_BUF]; |
74 | | static int echo_length = 0; // period (in sample\) to ensure completion of echo at the end of speech, set in WavegenSetEcho() |
75 | | |
76 | | static int voicing; |
77 | | static RESONATOR rbreath[N_PEAKS]; |
78 | | |
79 | 35.4G | #define N_LOWHARM 30 |
80 | 81.0M | #define MAX_HARMONIC 400 // 400 * 50Hz = 20 kHz, more than enough |
81 | | static int harm_inc[N_LOWHARM]; // only for these harmonics do we interpolate amplitude between steps |
82 | | static int *harmspect; |
83 | | static int hswitch = 0; |
84 | | static int hspect[2][MAX_HARMONIC]; // 2 copies, we interpolate between then |
85 | | |
86 | | static int nsamples = 0; // number to do |
87 | | static int modulation_type = 0; |
88 | | static int glottal_flag = 0; |
89 | | static int glottal_reduce = 0; |
90 | | |
91 | | static WGEN_DATA wdata; |
92 | | |
93 | | static int amp_ix; |
94 | | static int amp_inc; |
95 | | static unsigned char *amplitude_env = NULL; |
96 | | |
97 | | static int samplecount = 0; // number done |
98 | | static int samplecount_start = 0; // count at start of this segment |
99 | | static int end_wave = 0; // continue to end of wave cycle |
100 | | static int wavephase; |
101 | | static int phaseinc; |
102 | | static int cycle_samples; // number of samples in a cycle at current pitch |
103 | | static int cbytes; |
104 | | static int hf_factor; |
105 | | |
106 | | static double minus_pi_t; |
107 | | static double two_pi_t; |
108 | | |
109 | | unsigned char *out_ptr; |
110 | | unsigned char *out_end; |
111 | | |
112 | | espeak_ng_OUTPUT_HOOKS* output_hooks = NULL; |
113 | | static int const_f0 = 0; |
114 | | |
115 | | // the queue of operations passed to wavegen from sythesize |
116 | | intptr_t wcmdq[N_WCMDQ][4]; |
117 | | int wcmdq_head = 0; |
118 | | int wcmdq_tail = 0; |
119 | | |
120 | | // pitch,speed, |
121 | | const int embedded_default[N_EMBEDDED_VALUES] = { 0, 50, espeakRATE_NORMAL, 100, 50, 0, 0, 0, espeakRATE_NORMAL, 0, 0, 0, 0, 0, 0 }; |
122 | | static const int embedded_max[N_EMBEDDED_VALUES] = { 0, 0x7fff, 2000, 300, 99, 99, 99, 0, 2000, 0, 0, 0, 0, 4, 0 }; |
123 | | |
124 | | #if USE_LIBSONIC |
125 | | static sonicStream sonicSpeedupStream = NULL; |
126 | | static double sonicSpeed = 1.0; |
127 | | #endif |
128 | | |
129 | | // 1st index=roughness |
130 | | // 2nd index=modulation_type |
131 | | // value: bits 0-3 amplitude (16ths), bits 4-7 every n cycles |
132 | 23.2M | #define N_ROUGHNESS 8 |
133 | | static const unsigned char modulation_tab[N_ROUGHNESS][8] = { |
134 | | { 0, 0x00, 0x00, 0x00, 0, 0x46, 0xf2, 0x29 }, |
135 | | { 0, 0x2f, 0x00, 0x2f, 0, 0x45, 0xf2, 0x29 }, |
136 | | { 0, 0x2f, 0x00, 0x2e, 0, 0x45, 0xf2, 0x28 }, |
137 | | { 0, 0x2e, 0x00, 0x2d, 0, 0x34, 0xf2, 0x28 }, |
138 | | { 0, 0x2d, 0x2d, 0x2c, 0, 0x34, 0xf2, 0x28 }, |
139 | | { 0, 0x2b, 0x2b, 0x2b, 0, 0x34, 0xf2, 0x28 }, |
140 | | { 0, 0x2a, 0x2a, 0x2a, 0, 0x34, 0xf2, 0x28 }, |
141 | | { 0, 0x29, 0x29, 0x29, 0, 0x34, 0xf2, 0x28 }, |
142 | | }; |
143 | | |
144 | | // Flutter table, to add natural variations to the pitch |
145 | 78.2M | #define N_FLUTTER 0x170 |
146 | | static int Flutter_inc; |
147 | | static const unsigned char Flutter_tab[N_FLUTTER] = { |
148 | | 0x80, 0x9b, 0xb5, 0xcb, 0xdc, 0xe8, 0xed, 0xec, |
149 | | 0xe6, 0xdc, 0xce, 0xbf, 0xb0, 0xa3, 0x98, 0x90, |
150 | | 0x8c, 0x8b, 0x8c, 0x8f, 0x92, 0x94, 0x95, 0x92, |
151 | | 0x8c, 0x83, 0x78, 0x69, 0x59, 0x49, 0x3c, 0x31, |
152 | | 0x2a, 0x29, 0x2d, 0x36, 0x44, 0x56, 0x69, 0x7d, |
153 | | 0x8f, 0x9f, 0xaa, 0xb1, 0xb2, 0xad, 0xa4, 0x96, |
154 | | 0x87, 0x78, 0x69, 0x5c, 0x53, 0x4f, 0x4f, 0x55, |
155 | | 0x5e, 0x6b, 0x7a, 0x88, 0x96, 0xa2, 0xab, 0xb0, |
156 | | |
157 | | 0xb1, 0xae, 0xa8, 0xa0, 0x98, 0x91, 0x8b, 0x88, |
158 | | 0x89, 0x8d, 0x94, 0x9d, 0xa8, 0xb2, 0xbb, 0xc0, |
159 | | 0xc1, 0xbd, 0xb4, 0xa5, 0x92, 0x7c, 0x63, 0x4a, |
160 | | 0x32, 0x1e, 0x0e, 0x05, 0x02, 0x05, 0x0f, 0x1e, |
161 | | 0x30, 0x44, 0x59, 0x6d, 0x7f, 0x8c, 0x96, 0x9c, |
162 | | 0x9f, 0x9f, 0x9d, 0x9b, 0x99, 0x99, 0x9c, 0xa1, |
163 | | 0xa9, 0xb3, 0xbf, 0xca, 0xd5, 0xdc, 0xe0, 0xde, |
164 | | 0xd8, 0xcc, 0xbb, 0xa6, 0x8f, 0x77, 0x60, 0x4b, |
165 | | |
166 | | 0x3a, 0x2e, 0x28, 0x29, 0x2f, 0x3a, 0x48, 0x59, |
167 | | 0x6a, 0x7a, 0x86, 0x90, 0x94, 0x95, 0x91, 0x89, |
168 | | 0x80, 0x75, 0x6b, 0x62, 0x5c, 0x5a, 0x5c, 0x61, |
169 | | 0x69, 0x74, 0x80, 0x8a, 0x94, 0x9a, 0x9e, 0x9d, |
170 | | 0x98, 0x90, 0x86, 0x7c, 0x71, 0x68, 0x62, 0x60, |
171 | | 0x63, 0x6b, 0x78, 0x88, 0x9b, 0xaf, 0xc2, 0xd2, |
172 | | 0xdf, 0xe6, 0xe7, 0xe2, 0xd7, 0xc6, 0xb2, 0x9c, |
173 | | 0x84, 0x6f, 0x5b, 0x4b, 0x40, 0x39, 0x37, 0x38, |
174 | | |
175 | | 0x3d, 0x43, 0x4a, 0x50, 0x54, 0x56, 0x55, 0x52, |
176 | | 0x4d, 0x48, 0x42, 0x3f, 0x3e, 0x41, 0x49, 0x56, |
177 | | 0x67, 0x7c, 0x93, 0xab, 0xc3, 0xd9, 0xea, 0xf6, |
178 | | 0xfc, 0xfb, 0xf4, 0xe7, 0xd5, 0xc0, 0xaa, 0x94, |
179 | | 0x80, 0x71, 0x64, 0x5d, 0x5a, 0x5c, 0x61, 0x68, |
180 | | 0x70, 0x77, 0x7d, 0x7f, 0x7f, 0x7b, 0x74, 0x6b, |
181 | | 0x61, 0x57, 0x4e, 0x48, 0x46, 0x48, 0x4e, 0x59, |
182 | | 0x66, 0x75, 0x84, 0x93, 0x9f, 0xa7, 0xab, 0xaa, |
183 | | |
184 | | 0xa4, 0x99, 0x8b, 0x7b, 0x6a, 0x5b, 0x4e, 0x46, |
185 | | 0x43, 0x45, 0x4d, 0x5a, 0x6b, 0x7f, 0x92, 0xa6, |
186 | | 0xb8, 0xc5, 0xcf, 0xd3, 0xd2, 0xcd, 0xc4, 0xb9, |
187 | | 0xad, 0xa1, 0x96, 0x8e, 0x89, 0x87, 0x87, 0x8a, |
188 | | 0x8d, 0x91, 0x92, 0x91, 0x8c, 0x84, 0x78, 0x68, |
189 | | 0x55, 0x41, 0x2e, 0x1c, 0x0e, 0x05, 0x01, 0x05, |
190 | | 0x0f, 0x1f, 0x34, 0x4d, 0x68, 0x81, 0x9a, 0xb0, |
191 | | 0xc1, 0xcd, 0xd3, 0xd3, 0xd0, 0xc8, 0xbf, 0xb5, |
192 | | |
193 | | 0xab, 0xa4, 0x9f, 0x9c, 0x9d, 0xa0, 0xa5, 0xaa, |
194 | | 0xae, 0xb1, 0xb0, 0xab, 0xa3, 0x96, 0x87, 0x76, |
195 | | 0x63, 0x51, 0x42, 0x36, 0x2f, 0x2d, 0x31, 0x3a, |
196 | | 0x48, 0x59, 0x6b, 0x7e, 0x8e, 0x9c, 0xa6, 0xaa, |
197 | | 0xa9, 0xa3, 0x98, 0x8a, 0x7b, 0x6c, 0x5d, 0x52, |
198 | | 0x4a, 0x48, 0x4a, 0x50, 0x5a, 0x67, 0x75, 0x82 |
199 | | }; |
200 | | |
201 | | // waveform shape table for HF peaks, formants 6,7,8 |
202 | 1 | #define N_WAVEMULT 128 |
203 | | static int wavemult_offset = 0; |
204 | | static int wavemult_max = 0; |
205 | | |
206 | | // the presets are for 22050 Hz sample rate. |
207 | | // A different rate will need to recalculate the presets in WavegenInit() |
208 | | static unsigned char wavemult[N_WAVEMULT] = { |
209 | | 0, 0, 0, 2, 3, 5, 8, 11, 14, 18, 22, 27, 32, 37, 43, 49, |
210 | | 55, 62, 69, 76, 83, 90, 98, 105, 113, 121, 128, 136, 144, 152, 159, 166, |
211 | | 174, 181, 188, 194, 201, 207, 213, 218, 224, 228, 233, 237, 240, 244, 246, 249, |
212 | | 251, 252, 253, 253, 253, 253, 252, 251, 249, 246, 244, 240, 237, 233, 228, 224, |
213 | | 218, 213, 207, 201, 194, 188, 181, 174, 166, 159, 152, 144, 136, 128, 121, 113, |
214 | | 105, 98, 90, 83, 76, 69, 62, 55, 49, 43, 37, 32, 27, 22, 18, 14, |
215 | | 11, 8, 5, 3, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
216 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 |
217 | | }; |
218 | | |
219 | | // set from y = pow(2,x) * 128, x=-1 to 1 |
220 | 3.28M | #define MAX_PITCH_VALUE 101 |
221 | | static const unsigned char pitch_adjust_tab[MAX_PITCH_VALUE+1] = { |
222 | | 64, 65, 66, 67, 68, 69, 70, 71, |
223 | | 72, 73, 74, 75, 76, 77, 78, 79, |
224 | | 80, 81, 82, 83, 84, 86, 87, 88, |
225 | | 89, 91, 92, 93, 94, 96, 97, 98, |
226 | | 100, 101, 103, 104, 105, 107, 108, 110, |
227 | | 111, 113, 115, 116, 118, 119, 121, 123, |
228 | | 124, 126, 128, 130, 132, 133, 135, 137, |
229 | | 139, 141, 143, 145, 147, 149, 151, 153, |
230 | | 155, 158, 160, 162, 164, 167, 169, 171, |
231 | | 174, 176, 179, 181, 184, 186, 189, 191, |
232 | | 194, 197, 199, 202, 205, 208, 211, 214, |
233 | | 217, 220, 223, 226, 229, 232, 236, 239, |
234 | | 242, 246, 249, 252, 254, 255 |
235 | | }; |
236 | | |
237 | | void WcmdqStop(void) |
238 | 0 | { |
239 | 0 | wcmdq_head = 0; |
240 | 0 | wcmdq_tail = 0; |
241 | |
|
242 | | #if USE_LIBSONIC |
243 | | if (sonicSpeedupStream != NULL) { |
244 | | sonicDestroyStream(sonicSpeedupStream); |
245 | | sonicSpeedupStream = NULL; |
246 | | } |
247 | | #endif |
248 | |
|
249 | | #if USE_MBROLA |
250 | | if (mbrola_name[0] != 0) |
251 | | MbrolaReset(); |
252 | | #endif |
253 | 0 | } |
254 | | |
255 | | int WcmdqFree(void) |
256 | 39.5M | { |
257 | 39.5M | int i; |
258 | 39.5M | i = wcmdq_head - wcmdq_tail; |
259 | 39.5M | if (i <= 0) i += N_WCMDQ; |
260 | 39.5M | return i; |
261 | 39.5M | } |
262 | | |
263 | | int WcmdqUsed(void) |
264 | 28.9M | { |
265 | 28.9M | return N_WCMDQ - WcmdqFree(); |
266 | 28.9M | } |
267 | | |
268 | | void WcmdqInc(void) |
269 | 22.4M | { |
270 | 22.4M | wcmdq_tail++; |
271 | 22.4M | if (wcmdq_tail >= N_WCMDQ) wcmdq_tail = 0; |
272 | 22.4M | } |
273 | | |
274 | | static void WcmdqIncHead(void) |
275 | 22.4M | { |
276 | 22.4M | MAKE_MEM_UNDEFINED(&wcmdq[wcmdq_head], sizeof(wcmdq[wcmdq_head])); |
277 | 22.4M | wcmdq_head++; |
278 | 22.4M | if (wcmdq_head >= N_WCMDQ) wcmdq_head = 0; |
279 | 22.4M | } |
280 | | |
281 | | #define PEAKSHAPEW 256 |
282 | | |
283 | | static const unsigned char pk_shape1[PEAKSHAPEW+1] = { |
284 | | 255, 254, 254, 254, 254, 254, 253, 253, 252, 251, 251, 250, 249, 248, 247, 246, |
285 | | 245, 244, 242, 241, 239, 238, 236, 234, 233, 231, 229, 227, 225, 223, 220, 218, |
286 | | 216, 213, 211, 209, 207, 205, 203, 201, 199, 197, 195, 193, 191, 189, 187, 185, |
287 | | 183, 180, 178, 176, 173, 171, 169, 166, 164, 161, 159, 156, 154, 151, 148, 146, |
288 | | 143, 140, 138, 135, 132, 129, 126, 123, 120, 118, 115, 112, 108, 105, 102, 99, |
289 | | 96, 95, 93, 91, 90, 88, 86, 85, 83, 82, 80, 79, 77, 76, 74, 73, |
290 | | 72, 70, 69, 68, 67, 66, 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, |
291 | | 55, 54, 53, 52, 52, 51, 50, 50, 49, 48, 48, 47, 47, 46, 46, 46, |
292 | | 45, 45, 45, 44, 44, 44, 44, 44, 44, 44, 43, 43, 43, 43, 44, 43, |
293 | | 42, 42, 41, 40, 40, 39, 38, 38, 37, 36, 36, 35, 35, 34, 33, 33, |
294 | | 32, 32, 31, 30, 30, 29, 29, 28, 28, 27, 26, 26, 25, 25, 24, 24, |
295 | | 23, 23, 22, 22, 21, 21, 20, 20, 19, 19, 18, 18, 18, 17, 17, 16, |
296 | | 16, 15, 15, 15, 14, 14, 13, 13, 13, 12, 12, 11, 11, 11, 10, 10, |
297 | | 10, 9, 9, 9, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 5, 5, |
298 | | 5, 5, 4, 4, 4, 4, 4, 3, 3, 3, 3, 2, 2, 2, 2, 2, |
299 | | 2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
300 | | 0 |
301 | | }; |
302 | | |
303 | | static const unsigned char pk_shape2[PEAKSHAPEW+1] = { |
304 | | 255, 254, 254, 254, 254, 254, 254, 254, 254, 254, 253, 253, 253, 253, 252, 252, |
305 | | 252, 251, 251, 251, 250, 250, 249, 249, 248, 248, 247, 247, 246, 245, 245, 244, |
306 | | 243, 243, 242, 241, 239, 237, 235, 233, 231, 229, 227, 225, 223, 221, 218, 216, |
307 | | 213, 211, 208, 205, 203, 200, 197, 194, 191, 187, 184, 181, 178, 174, 171, 167, |
308 | | 163, 160, 156, 152, 148, 144, 140, 136, 132, 127, 123, 119, 114, 110, 105, 100, |
309 | | 96, 94, 91, 88, 86, 83, 81, 78, 76, 74, 71, 69, 66, 64, 62, 60, |
310 | | 57, 55, 53, 51, 49, 47, 44, 42, 40, 38, 36, 34, 32, 30, 29, 27, |
311 | | 25, 23, 21, 19, 18, 16, 14, 12, 11, 9, 7, 6, 4, 3, 1, 0, |
312 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
313 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
314 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
315 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
316 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
317 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
318 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
319 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
320 | | 0 |
321 | | }; |
322 | | |
323 | | static const unsigned char *pk_shape; |
324 | | |
325 | | void WavegenInit(int rate, int wavemult_fact) |
326 | 1 | { |
327 | 1 | int ix; |
328 | 1 | double x; |
329 | | |
330 | 1 | if (wavemult_fact == 0) |
331 | 1 | wavemult_fact = 60; // default |
332 | | |
333 | 1 | wvoice = NULL; |
334 | 1 | samplerate = rate; |
335 | 1 | PHASE_INC_FACTOR = 0x8000000 / samplerate; // assumes pitch is Hz*32 |
336 | 1 | Flutter_inc = (64 * samplerate)/rate; |
337 | 1 | samplecount = 0; |
338 | 1 | nsamples = 0; |
339 | 1 | wavephase = 0x7fffffff; |
340 | | |
341 | 1 | wdata.amplitude = 32; |
342 | 1 | wdata.amplitude_fmt = 100; |
343 | | |
344 | 16 | for (ix = 0; ix < N_EMBEDDED_VALUES; ix++) |
345 | 15 | embedded_value[ix] = embedded_default[ix]; |
346 | | |
347 | | // set up window to generate a spread of harmonics from a |
348 | | // single peak for HF peaks |
349 | 1 | wavemult_max = (samplerate * wavemult_fact)/(256 * 50); |
350 | 1 | if (wavemult_max > N_WAVEMULT) wavemult_max = N_WAVEMULT; |
351 | | |
352 | 1 | wavemult_offset = wavemult_max/2; |
353 | | |
354 | 1 | if (samplerate != 22050) { |
355 | | // wavemult table has preset values for 22050 Hz, we only need to |
356 | | // recalculate them if we have a different sample rate |
357 | 0 | for (ix = 0; ix < wavemult_max; ix++) { |
358 | 0 | x = 127*(1.0 - cos((M_PI*2)*ix/wavemult_max)); |
359 | 0 | wavemult[ix] = (int)x; |
360 | 0 | } |
361 | 0 | } |
362 | | |
363 | 1 | pk_shape = pk_shape2; |
364 | | |
365 | 1 | #if USE_KLATT |
366 | 1 | KlattInit(); |
367 | 1 | #endif |
368 | 1 | } |
369 | | |
370 | | void WavegenFini(void) |
371 | 0 | { |
372 | 0 | #if USE_KLATT |
373 | 0 | KlattFini(); |
374 | 0 | #endif |
375 | 0 | } |
376 | | |
377 | | int GetAmplitude(void) |
378 | 12.7k | { |
379 | 12.7k | int amp; |
380 | | |
381 | | // normal, none, reduced, moderate, strong |
382 | 12.7k | static const unsigned char amp_emphasis[5] = { 16, 16, 10, 16, 22 }; |
383 | | |
384 | 12.7k | amp = (embedded_value[EMBED_A])*55/100; |
385 | 12.7k | general_amplitude = amp * amp_emphasis[embedded_value[EMBED_F]] / 16; |
386 | 12.7k | return general_amplitude; |
387 | 12.7k | } |
388 | | |
389 | | static void WavegenSetEcho(void) |
390 | 10.7k | { |
391 | 10.7k | if (wvoice == NULL) |
392 | 0 | return; |
393 | | |
394 | 10.7k | int delay; |
395 | 10.7k | int amp; |
396 | | |
397 | 10.7k | voicing = wvoice->voicing; |
398 | 10.7k | delay = wvoice->echo_delay; |
399 | 10.7k | amp = wvoice->echo_amp; |
400 | | |
401 | 10.7k | if (delay >= N_ECHO_BUF) |
402 | 0 | delay = N_ECHO_BUF-1; |
403 | 10.7k | if (amp > 100) |
404 | 0 | amp = 100; |
405 | | |
406 | 10.7k | memset(echo_buf, 0, sizeof(echo_buf)); |
407 | 10.7k | echo_tail = 0; |
408 | | |
409 | 10.7k | if (embedded_value[EMBED_H] > 0) { |
410 | | // set echo from an embedded command in the text |
411 | 1.71k | amp = embedded_value[EMBED_H]; |
412 | 1.71k | delay = 130; |
413 | 1.71k | } |
414 | | |
415 | 10.7k | if (delay == 0) |
416 | 9.03k | amp = 0; |
417 | | |
418 | 10.7k | echo_head = (delay * samplerate)/1000; |
419 | 10.7k | echo_length = echo_head; // ensure completion of echo at the end of speech. Use 1 delay period? |
420 | 10.7k | if (amp == 0) |
421 | 9.03k | echo_length = 0; |
422 | 10.7k | if (amp > 20) |
423 | 1.55k | echo_length = echo_head * 2; // perhaps allow 2 echo periods if the echo is loud. |
424 | | |
425 | | // echo_amp units are 1/256ths of the amplitude of the original sound. |
426 | 10.7k | echo_amp = amp; |
427 | | // compensate (partially) for increase in amplitude due to echo |
428 | 10.7k | general_amplitude = GetAmplitude(); |
429 | 10.7k | general_amplitude = ((general_amplitude * (500-amp))/500); |
430 | 10.7k | } |
431 | | |
432 | | int PeaksToHarmspect(wavegen_peaks_t *peaks, int pitch, int *htab, int control) |
433 | 81.0M | { |
434 | 81.0M | if (wvoice == NULL) |
435 | 0 | return 1; |
436 | | |
437 | | // Calculate the amplitude of each harmonics from the formants |
438 | | // Only for formants 0 to 5 |
439 | | |
440 | | // control 0=initial call, 1=every 64 cycles |
441 | | |
442 | | // pitch and freqs are Hz<<16 |
443 | | |
444 | 81.0M | int f; |
445 | 81.0M | wavegen_peaks_t *p; |
446 | 81.0M | int fp; // centre freq of peak |
447 | 81.0M | int fhi; // high freq of peak |
448 | 81.0M | int h; // harmonic number |
449 | 81.0M | int pk; |
450 | 81.0M | int hmax; |
451 | 81.0M | int hmax_samplerate; // highest harmonic allowed for the samplerate |
452 | 81.0M | int x; |
453 | 81.0M | int h1; |
454 | | |
455 | | // initialise as much of *out as we will need |
456 | 81.0M | hmax = (peaks[wvoice->n_harmonic_peaks].freq + peaks[wvoice->n_harmonic_peaks].right)/pitch; |
457 | 81.0M | if (hmax >= MAX_HARMONIC) |
458 | 0 | hmax = MAX_HARMONIC-1; |
459 | | |
460 | | // restrict highest harmonic to half the samplerate |
461 | 81.0M | hmax_samplerate = (((samplerate * 19)/40) << 16)/pitch; // only 95% of Nyquist freq |
462 | | |
463 | 81.0M | if (hmax > hmax_samplerate) |
464 | 0 | hmax = hmax_samplerate; |
465 | | |
466 | 3.82G | for (h = 0; h <= hmax; h++) |
467 | 3.74G | htab[h] = 0; |
468 | | |
469 | 567M | for (pk = 0; pk <= wvoice->n_harmonic_peaks; pk++) { |
470 | 486M | p = &peaks[pk]; |
471 | 486M | if ((p->height == 0) || (fp = p->freq) == 0) |
472 | 4.03M | continue; |
473 | | |
474 | 482M | fhi = p->freq + p->right; |
475 | 482M | h = ((p->freq - p->left) / pitch) + 1; |
476 | 482M | if (h <= 0) h = 1; |
477 | | |
478 | 2.94G | for (f = pitch*h; f < fp; f += pitch) |
479 | 2.46G | htab[h++] += pk_shape[(fp-f)/(p->left>>8)] * p->height; |
480 | 3.51G | for (; f < fhi; f += pitch) |
481 | 3.03G | htab[h++] += pk_shape[(f-fp)/(p->right>>8)] * p->height; |
482 | 482M | } |
483 | | |
484 | 81.0M | int y; |
485 | 81.0M | int h2; |
486 | | // increase bass |
487 | 81.0M | y = peaks[1].height * 10; // addition as a multiple of 1/256s |
488 | 81.0M | h2 = (1000<<16)/pitch; // decrease until 1000Hz |
489 | 81.0M | if (h2 > 0) { |
490 | 81.0M | x = y/h2; |
491 | 81.0M | h = 1; |
492 | 891M | while (y > 0) { |
493 | 810M | htab[h++] += y; |
494 | 810M | y -= x; |
495 | 810M | } |
496 | 81.0M | } |
497 | | |
498 | | // find the nearest harmonic for HF peaks where we don't use shape |
499 | 324M | for (; pk < N_PEAKS; pk++) { |
500 | 243M | x = peaks[pk].height >> 14; |
501 | 243M | peak_height[pk] = (x * x * 5)/2; |
502 | | |
503 | | // find the nearest harmonic for HF peaks where we don't use shape |
504 | 243M | if (control == 0) { |
505 | | // set this initially, but make changes only at the quiet point |
506 | 4.14M | peak_harmonic[pk] = peaks[pk].freq / pitch; |
507 | 4.14M | } |
508 | | // only use harmonics up to half the samplerate |
509 | 243M | if (peak_harmonic[pk] >= hmax_samplerate) |
510 | 22.5k | peak_height[pk] = 0; |
511 | 243M | } |
512 | | |
513 | | // convert from the square-rooted values |
514 | 81.0M | f = 0; |
515 | 3.82G | for (h = 0; h <= hmax; h++, f += pitch) { |
516 | 3.74G | x = htab[h] >> 15; |
517 | 3.74G | htab[h] = (x * x) >> 8; |
518 | | |
519 | 3.74G | int ix; |
520 | 3.74G | if ((ix = (f >> 19)) < N_TONE_ADJUST) |
521 | 3.74G | htab[h] = (htab[h] * wvoice->tone_adjust[ix]) >> 13; // index tone_adjust with Hz/8 |
522 | 3.74G | } |
523 | | |
524 | | // adjust the amplitude of the first harmonic, affects tonal quality |
525 | 81.0M | h1 = htab[1] * option_harmonic1; |
526 | 81.0M | htab[1] = h1/8; |
527 | | |
528 | | // calc intermediate increments of LF harmonics |
529 | 81.0M | if (control & 1) { |
530 | 2.38G | for (h = 1; h < N_LOWHARM; h++) |
531 | 2.30G | harm_inc[h] = (htab[h] - harmspect[h]) >> 3; |
532 | 79.6M | } |
533 | | |
534 | 81.0M | return hmax; // highest harmonic number |
535 | 81.0M | } |
536 | | |
537 | | static void AdvanceParameters(void) |
538 | 78.2M | { |
539 | | // Called every 64 samples to increment the formant freq, height, and widths |
540 | 78.2M | if (wvoice == NULL) |
541 | 0 | return; |
542 | | |
543 | 78.2M | int x = 0; |
544 | 78.2M | int ix; |
545 | 78.2M | static int Flutter_ix = 0; |
546 | | |
547 | | // advance the pitch |
548 | 78.2M | wdata.pitch_ix += wdata.pitch_inc; |
549 | 78.2M | if ((ix = wdata.pitch_ix>>8) > 127) ix = 127; |
550 | 78.2M | if (wdata.pitch_env) x = wdata.pitch_env[ix] * wdata.pitch_range; |
551 | 78.2M | wdata.pitch = (x>>8) + wdata.pitch_base; |
552 | | |
553 | | |
554 | | |
555 | 78.2M | amp_ix += amp_inc; |
556 | | |
557 | | /* add pitch flutter */ |
558 | 78.2M | if (Flutter_ix >= (N_FLUTTER*64)) |
559 | 212k | Flutter_ix = 0; |
560 | 78.2M | x = ((int)(Flutter_tab[Flutter_ix >> 6])-0x80) * flutter_amp; |
561 | 78.2M | Flutter_ix += Flutter_inc; |
562 | 78.2M | wdata.pitch += x; |
563 | | |
564 | 78.2M | if(const_f0) |
565 | 0 | wdata.pitch = (const_f0<<12); |
566 | | |
567 | 78.2M | if (wdata.pitch < 102400) |
568 | 0 | wdata.pitch = 102400; // min pitch, 25 Hz (25 << 12) |
569 | | |
570 | 78.2M | if (samplecount == samplecount_start) |
571 | 9.66M | return; |
572 | | |
573 | 480M | for (ix = 0; ix <= wvoice->n_harmonic_peaks; ix++) { |
574 | 411M | peaks[ix].freq1 += peaks[ix].freq_inc; |
575 | 411M | peaks[ix].freq = (int)peaks[ix].freq1; |
576 | 411M | peaks[ix].height1 += peaks[ix].height_inc; |
577 | 411M | if ((peaks[ix].height = (int)peaks[ix].height1) < 0) |
578 | 1.67M | peaks[ix].height = 0; |
579 | 411M | peaks[ix].left1 += peaks[ix].left_inc; |
580 | 411M | peaks[ix].left = (int)peaks[ix].left1; |
581 | 411M | if (ix < 3) { |
582 | 205M | peaks[ix].right1 += peaks[ix].right_inc; |
583 | 205M | peaks[ix].right = (int)peaks[ix].right1; |
584 | 205M | } else |
585 | 205M | peaks[ix].right = peaks[ix].left; |
586 | 411M | } |
587 | 205M | for (; ix < 8; ix++) { |
588 | | // formants 6,7,8 don't have a width parameter |
589 | 137M | if (ix < 7) { |
590 | 68.6M | peaks[ix].freq1 += peaks[ix].freq_inc; |
591 | 68.6M | peaks[ix].freq = (int)peaks[ix].freq1; |
592 | 68.6M | } |
593 | 137M | peaks[ix].height1 += peaks[ix].height_inc; |
594 | 137M | if ((peaks[ix].height = (int)peaks[ix].height1) < 0) |
595 | 565k | peaks[ix].height = 0; |
596 | 137M | } |
597 | 68.6M | } |
598 | | |
599 | | static double resonator(RESONATOR *r, double input) |
600 | 39.1M | { |
601 | 39.1M | double x; |
602 | | |
603 | 39.1M | x = r->a * input + r->b * r->x1 + r->c * r->x2; |
604 | 39.1M | r->x2 = r->x1; |
605 | 39.1M | r->x1 = x; |
606 | | |
607 | 39.1M | return x; |
608 | 39.1M | } |
609 | | |
610 | | static void setresonator(RESONATOR *rp, int freq, int bwidth, int init) |
611 | 697k | { |
612 | | // freq Frequency of resonator in Hz |
613 | | // bwidth Bandwidth of resonator in Hz |
614 | | // init Initialize internal data |
615 | | |
616 | 697k | double x; |
617 | 697k | double arg; |
618 | | |
619 | 697k | if (init) { |
620 | 83.4k | rp->x1 = 0; |
621 | 83.4k | rp->x2 = 0; |
622 | 83.4k | } |
623 | | |
624 | 697k | arg = minus_pi_t * bwidth; |
625 | 697k | x = exp(arg); |
626 | | |
627 | 697k | rp->c = -(x * x); |
628 | | |
629 | 697k | arg = two_pi_t * freq; |
630 | 697k | rp->b = x * cos(arg) * 2.0; |
631 | | |
632 | 697k | rp->a = 1.0 - rp->b - rp->c; |
633 | 697k | } |
634 | | |
635 | | void InitBreath(void) |
636 | 9.27k | { |
637 | 9.27k | int ix; |
638 | | |
639 | 9.27k | minus_pi_t = -M_PI / samplerate; |
640 | 9.27k | two_pi_t = -2.0 * minus_pi_t; |
641 | | |
642 | 92.7k | for (ix = 0; ix < N_PEAKS; ix++) |
643 | 83.4k | setresonator(&rbreath[ix], 2000, 200, 1); |
644 | 9.27k | } |
645 | | |
646 | | static void SetBreath(void) |
647 | 79.6M | { |
648 | 79.6M | int pk; |
649 | | |
650 | 79.6M | if (wvoice == NULL || wvoice->breath[0] == 0) |
651 | 79.5M | return; |
652 | | |
653 | 921k | for (pk = 1; pk < N_PEAKS; pk++) { |
654 | 819k | if (wvoice->breath[pk] != 0) { |
655 | | // breath[0] indicates that some breath formants are needed |
656 | | // set the freq from the current synthesis formant and the width from the voice data |
657 | 614k | setresonator(&rbreath[pk], peaks[pk].freq >> 16, wvoice->breathw[pk], 0); |
658 | 614k | } |
659 | 819k | } |
660 | 102k | } |
661 | | |
662 | | static int ApplyBreath(void) |
663 | 6.52M | { |
664 | 6.52M | if (wvoice == NULL) |
665 | 0 | return 0; |
666 | | |
667 | 6.52M | int value = 0; |
668 | 6.52M | int noise; |
669 | 6.52M | int ix; |
670 | | |
671 | | // use two random numbers, for alternate formants |
672 | 6.52M | noise = espeak_rand(-0x2000, 0x1fff); |
673 | | |
674 | 58.7M | for (ix = 1; ix < N_PEAKS; ix++) { |
675 | 52.2M | int amp; |
676 | 52.2M | if ((amp = wvoice->breath[ix]) != 0) { |
677 | 39.1M | amp *= (peaks[ix].height >> 14); |
678 | 39.1M | value += (int)resonator(&rbreath[ix], noise) * amp; |
679 | 39.1M | } |
680 | 52.2M | } |
681 | 6.52M | return value; |
682 | 6.52M | } |
683 | | |
684 | | static int Wavegen(int length, int modulation, bool resume, frame_t *fr1, frame_t *fr2, voice_t *wvoice) |
685 | 14.8M | { |
686 | 14.8M | if (resume == false) |
687 | 11.0M | SetSynth(length, modulation, fr1, fr2, wvoice); |
688 | | |
689 | 14.8M | if (wvoice == NULL) |
690 | 0 | return 0; |
691 | | |
692 | 14.8M | unsigned short waveph; |
693 | 14.8M | unsigned short theta; |
694 | 14.8M | int total; |
695 | 14.8M | int h; |
696 | 14.8M | int ix; |
697 | 14.8M | int z, z1, z2; |
698 | 14.8M | int echo; |
699 | 14.8M | int ov; |
700 | 14.8M | static int maxh, maxh2; |
701 | 14.8M | int pk; |
702 | 14.8M | signed char c; |
703 | 14.8M | int sample; |
704 | 14.8M | int amp; |
705 | 14.8M | int modn_amp = 1, modn_period; |
706 | 14.8M | static int agc = 256; |
707 | 14.8M | static int h_switch_sign = 0; |
708 | 14.8M | static int cycle_count = 0; |
709 | 14.8M | static int amplitude2 = 0; // adjusted for pitch |
710 | | |
711 | | // continue until the output buffer is full, or |
712 | | // the required number of samples have been produced |
713 | | |
714 | 5.06G | for (;;) { |
715 | 5.06G | if ((end_wave == 0) && (samplecount == nsamples)) |
716 | 9.66M | return 0; |
717 | | |
718 | 5.05G | if ((samplecount & 0x3f) == 0) { |
719 | | // every 64 samples, adjust the parameters |
720 | 79.6M | if (samplecount == 0) { |
721 | 1.38M | hswitch = 0; |
722 | 1.38M | harmspect = hspect[0]; |
723 | 1.38M | maxh2 = PeaksToHarmspect(peaks, wdata.pitch<<4, hspect[0], 0); |
724 | | |
725 | | // adjust amplitude to compensate for fewer harmonics at higher pitch |
726 | 1.38M | amplitude2 = (wdata.amplitude * (wdata.pitch >> 8) * wdata.amplitude_fmt)/(10000 << 3); |
727 | | |
728 | | // switch sign of harmonics above about 900Hz, to reduce max peak amplitude |
729 | 1.38M | h_switch_sign = 890 / (wdata.pitch >> 12); |
730 | 1.38M | } else |
731 | 78.2M | AdvanceParameters(); |
732 | | |
733 | | // pitch is Hz<<12 |
734 | 79.6M | phaseinc = (wdata.pitch>>7) * PHASE_INC_FACTOR; |
735 | 79.6M | cycle_samples = samplerate/(wdata.pitch >> 12); // sr/(pitch*2) |
736 | 79.6M | hf_factor = wdata.pitch >> 11; |
737 | | |
738 | 79.6M | maxh = maxh2; |
739 | 79.6M | harmspect = hspect[hswitch]; |
740 | 79.6M | hswitch ^= 1; |
741 | 79.6M | maxh2 = PeaksToHarmspect(peaks, wdata.pitch<<4, hspect[hswitch], 1); |
742 | | |
743 | 79.6M | SetBreath(); |
744 | 4.97G | } else if ((samplecount & 0x07) == 0) { |
745 | 16.5G | for (h = 1; h < N_LOWHARM && h <= maxh2 && h <= maxh; h++) |
746 | 15.9G | harmspect[h] += harm_inc[h]; |
747 | | |
748 | | // bring automatic gain control back towards unity |
749 | 552M | if (agc < 256) agc++; |
750 | 552M | } |
751 | | |
752 | 5.05G | samplecount++; |
753 | | |
754 | 5.05G | if (wavephase > 0) { |
755 | 2.52G | wavephase += phaseinc; |
756 | 2.52G | if (wavephase < 0) { |
757 | | // sign has changed, reached a quiet point in the waveform |
758 | 24.6M | cbytes = wavemult_offset - (cycle_samples)/2; |
759 | 24.6M | if (samplecount > nsamples) |
760 | 1.38M | return 0; |
761 | | |
762 | 23.2M | cycle_count++; |
763 | | |
764 | 93.0M | for (pk = wvoice->n_harmonic_peaks+1; pk < N_PEAKS; pk++) { |
765 | | // find the nearest harmonic for HF peaks where we don't use shape |
766 | 69.8M | peak_harmonic[pk] = ((peaks[pk].freq / (wdata.pitch*8)) + 1) / 2; |
767 | 69.8M | } |
768 | | |
769 | | // adjust amplitude to compensate for fewer harmonics at higher pitch |
770 | 23.2M | amplitude2 = (wdata.amplitude * (wdata.pitch >> 8) * wdata.amplitude_fmt)/(10000 << 3); |
771 | | |
772 | 23.2M | if (glottal_flag > 0) { |
773 | 9.21k | if (glottal_flag == 3) { |
774 | 2.74k | if ((nsamples-samplecount) < (cycle_samples*2)) { |
775 | | // Vowel before glottal-stop. |
776 | | // This is the start of the penultimate cycle, reduce its amplitude |
777 | 1.34k | glottal_flag = 2; |
778 | 1.34k | amplitude2 = (amplitude2 * glottal_reduce)/256; |
779 | 1.34k | } |
780 | 6.47k | } else if (glottal_flag == 4) { |
781 | | // Vowel following a glottal-stop. |
782 | | // This is the start of the second cycle, reduce its amplitude |
783 | 2.13k | glottal_flag = 2; |
784 | 2.13k | amplitude2 = (amplitude2 * glottal_reduce)/256; |
785 | 2.13k | } else |
786 | 4.33k | glottal_flag--; |
787 | 9.21k | } |
788 | | |
789 | 23.2M | if (amplitude_env != NULL) { |
790 | | // amplitude envelope is only used for creaky voice effect on certain vowels/tones |
791 | 60.8k | if ((ix = amp_ix>>8) > 127) ix = 127; |
792 | 60.8k | amp = amplitude_env[ix]; |
793 | 60.8k | amplitude2 = (amplitude2 * amp)/128; |
794 | 60.8k | } |
795 | | |
796 | | // introduce roughness into the sound by reducing the amplitude of |
797 | 23.2M | modn_period = 0; |
798 | 23.2M | if (voice->roughness < N_ROUGHNESS) { |
799 | 23.2M | modn_period = modulation_tab[voice->roughness][modulation_type]; |
800 | 23.2M | modn_amp = modn_period & 0xf; |
801 | 23.2M | modn_period = modn_period >> 4; |
802 | 23.2M | } |
803 | | |
804 | 23.2M | if (modn_period != 0) { |
805 | 6.93M | if (modn_period == 0xf) { |
806 | | // just once */ |
807 | 11.8k | amplitude2 = (amplitude2 * modn_amp)/16; |
808 | 11.8k | modulation_type = 0; |
809 | 6.92M | } else { |
810 | | // reduce amplitude every [modn_period} cycles |
811 | 6.92M | if ((cycle_count % modn_period) == 0) |
812 | 3.35M | amplitude2 = (amplitude2 * modn_amp)/16; |
813 | 6.92M | } |
814 | 6.93M | } |
815 | 23.2M | } |
816 | 2.52G | } else |
817 | 2.52G | wavephase += phaseinc; |
818 | 5.04G | waveph = (unsigned short)(wavephase >> 16); |
819 | 5.04G | total = 0; |
820 | | |
821 | | // apply HF peaks, formants 6,7,8 |
822 | | // add a single harmonic and then spread this my multiplying by a |
823 | | // window. This is to reduce the processing power needed to add the |
824 | | // higher frequence harmonics. |
825 | 5.04G | cbytes++; |
826 | 5.04G | if (cbytes >= 0 && cbytes < wavemult_max) { |
827 | 9.63G | for (pk = wvoice->n_harmonic_peaks+1; pk < N_PEAKS; pk++) { |
828 | 7.22G | theta = peak_harmonic[pk] * waveph; |
829 | 7.22G | total += (long)sin_tab[theta >> 5] * peak_height[pk]; |
830 | 7.22G | } |
831 | | |
832 | | // spread the peaks by multiplying by a window |
833 | 2.40G | total = (long)(total / hf_factor) * wavemult[cbytes]; |
834 | 2.40G | } |
835 | | |
836 | | // apply main peaks, formants 0 to 5 |
837 | 5.04G | theta = waveph; |
838 | | |
839 | 47.5G | for (h = 1; h <= h_switch_sign; h++) { |
840 | 42.4G | total += ((int)sin_tab[theta >> 5] * harmspect[h]); |
841 | 42.4G | theta += waveph; |
842 | 42.4G | } |
843 | 190G | while (h <= maxh) { |
844 | 185G | total -= ((int)sin_tab[theta >> 5] * harmspect[h]); |
845 | 185G | theta += waveph; |
846 | 185G | h++; |
847 | 185G | } |
848 | | |
849 | 5.04G | if (voicing != 64) |
850 | 2.71M | total = (total >> 6) * voicing; |
851 | | |
852 | 5.04G | if (wvoice->breath[0]) |
853 | 6.52M | total += ApplyBreath(); |
854 | | |
855 | | // mix with sampled wave if required |
856 | 5.04G | z2 = 0; |
857 | 5.04G | if (wdata.mix_wavefile_ix < wdata.n_mix_wavefile) { |
858 | 434M | if (wdata.mix_wave_scale == 0) { |
859 | | // a 16 bit sample |
860 | 0 | c = wdata.mix_wavefile[wdata.mix_wavefile_ix+wdata.mix_wavefile_offset+1]; |
861 | 0 | sample = wdata.mix_wavefile[wdata.mix_wavefile_ix+wdata.mix_wavefile_offset] + (c * 256); |
862 | 0 | wdata.mix_wavefile_ix += 2; |
863 | 434M | } else { |
864 | | // a 8 bit sample, scaled |
865 | 434M | sample = (signed char)wdata.mix_wavefile[wdata.mix_wavefile_offset+wdata.mix_wavefile_ix++] * wdata.mix_wave_scale; |
866 | 434M | } |
867 | 434M | z2 = (sample * wdata.amplitude_v) >> 10; |
868 | 434M | z2 = (z2 * wdata.mix_wave_amp)/32; |
869 | | |
870 | 434M | if ((wdata.mix_wavefile_ix + wdata.mix_wavefile_offset) >= wdata.mix_wavefile_max) // reached the end of available WAV data |
871 | 77.6k | wdata.mix_wavefile_offset -= (wdata.mix_wavefile_max*3)/4; |
872 | 434M | } |
873 | | |
874 | 5.04G | z1 = z2 + (((total>>8) * amplitude2) >> 13); |
875 | | |
876 | 5.04G | echo = (echo_buf[echo_tail++] * echo_amp); |
877 | 5.04G | z1 += echo >> 8; |
878 | 5.04G | if (echo_tail >= N_ECHO_BUF) |
879 | 915k | echo_tail = 0; |
880 | | |
881 | 5.04G | z = (z1 * agc) >> 8; |
882 | | |
883 | | // check for overflow, 16bit signed samples |
884 | 5.04G | if (z >= 32768) { |
885 | 171k | ov = 8388608/z1 - 1; // 8388608 is 2^23, i.e. max value * 256 |
886 | 171k | if (ov < agc) agc = ov; // set agc to number of 1/256ths to multiply the sample by |
887 | 171k | z = (z1 * agc) >> 8; // reduce sample by agc value to prevent overflow |
888 | 5.04G | } else if (z <= -32768) { |
889 | 71.9k | ov = -8388608/z1 - 1; |
890 | 71.9k | if (ov < agc) agc = ov; |
891 | 71.9k | z = (z1 * agc) >> 8; |
892 | 71.9k | } |
893 | 5.04G | *out_ptr++ = z; |
894 | 5.04G | *out_ptr++ = z >> 8; |
895 | 5.04G | if(output_hooks && output_hooks->outputVoiced) output_hooks->outputVoiced(z); |
896 | | |
897 | 5.04G | echo_buf[echo_head++] = z; |
898 | 5.04G | if (echo_head >= N_ECHO_BUF) |
899 | 915k | echo_head = 0; |
900 | | |
901 | 5.04G | if (out_ptr + 2 > out_end) |
902 | 3.80M | return 1; |
903 | 5.04G | } |
904 | 14.8M | } |
905 | | |
906 | | static int PlaySilence(int length, bool resume) |
907 | 2.89M | { |
908 | 2.89M | static int n_samples; |
909 | | |
910 | 2.89M | nsamples = 0; |
911 | 2.89M | samplecount = 0; |
912 | 2.89M | wavephase = 0x7fffffff; |
913 | | |
914 | 2.89M | if (length == 0) |
915 | 437k | return 0; |
916 | | |
917 | 2.45M | if (resume == false) |
918 | 1.76M | n_samples = length; |
919 | | |
920 | 2.45M | int value = 0; |
921 | 951M | while (n_samples-- > 0) { |
922 | 949M | value = (echo_buf[echo_tail++] * echo_amp) >> 8; |
923 | | |
924 | 949M | if (echo_tail >= N_ECHO_BUF) |
925 | 171k | echo_tail = 0; |
926 | | |
927 | 949M | *out_ptr++ = value; |
928 | 949M | *out_ptr++ = value >> 8; |
929 | 949M | if(output_hooks && output_hooks->outputSilence) output_hooks->outputSilence(value); |
930 | | |
931 | 949M | echo_buf[echo_head++] = value; |
932 | 949M | if (echo_head >= N_ECHO_BUF) |
933 | 171k | echo_head = 0; |
934 | | |
935 | 949M | if (out_ptr + 2 > out_end) |
936 | 699k | return 1; |
937 | 949M | } |
938 | 1.75M | return 0; |
939 | 2.45M | } |
940 | | |
941 | | static int PlayWave(int length, bool resume, unsigned char *data, int scale, int amp) |
942 | 1.93M | { |
943 | 1.93M | static int n_samples; |
944 | 1.93M | static int ix = 0; |
945 | 1.93M | int value; |
946 | 1.93M | signed char c; |
947 | | |
948 | 1.93M | if (resume == false) { |
949 | 1.21M | n_samples = length; |
950 | 1.21M | ix = 0; |
951 | 1.21M | } |
952 | | |
953 | 1.93M | nsamples = 0; |
954 | 1.93M | samplecount = 0; |
955 | | |
956 | 963M | while (n_samples-- > 0) { |
957 | 962M | if (scale == 0) { |
958 | | // 16 bits data |
959 | 0 | c = data[ix+1]; |
960 | 0 | value = data[ix] + (c * 256); |
961 | 0 | ix += 2; |
962 | 962M | } else { |
963 | | // 8 bit data, shift by the specified scale factor |
964 | 962M | value = (signed char)data[ix++] * scale; |
965 | 962M | } |
966 | 962M | value *= (consonant_amp * general_amplitude); // reduce strength of consonant |
967 | 962M | value = value >> 10; |
968 | 962M | value = (value * amp)/32; |
969 | | |
970 | 962M | value += ((echo_buf[echo_tail++] * echo_amp) >> 8); |
971 | | |
972 | 962M | if (value > 32767) |
973 | 0 | value = 32767; |
974 | 962M | else if (value < -32768) |
975 | 3 | value = -32768; |
976 | | |
977 | 962M | if (echo_tail >= N_ECHO_BUF) |
978 | 174k | echo_tail = 0; |
979 | | |
980 | 962M | out_ptr[0] = value; |
981 | 962M | out_ptr[1] = value >> 8; |
982 | 962M | if(output_hooks && output_hooks->outputUnvoiced) output_hooks->outputUnvoiced(value); |
983 | 962M | out_ptr += 2; |
984 | | |
985 | 962M | echo_buf[echo_head++] = (value*3)/4; |
986 | 962M | if (echo_head >= N_ECHO_BUF) |
987 | 174k | echo_head = 0; |
988 | | |
989 | 962M | if (out_ptr + 2 > out_end) |
990 | 721k | return 1; |
991 | 962M | } |
992 | 1.21M | return 0; |
993 | 1.93M | } |
994 | | |
995 | | static int SetWithRange0(int value, int max) |
996 | 31.4k | { |
997 | 31.4k | if (value < 0) |
998 | 857 | return 0; |
999 | 30.5k | if (value > max) |
1000 | 3.34k | return max; |
1001 | 27.2k | return value; |
1002 | 30.5k | } |
1003 | | |
1004 | | static void SetPitchFormants(void) |
1005 | 10.6k | { |
1006 | 10.6k | if (wvoice == NULL) |
1007 | 0 | return; |
1008 | | |
1009 | 10.6k | int ix; |
1010 | 10.6k | int factor = 256; |
1011 | 10.6k | int pitch_value; |
1012 | | |
1013 | | // adjust formants to give better results for a different voice pitch |
1014 | 10.6k | if ((pitch_value = embedded_value[EMBED_P]) > MAX_PITCH_VALUE) |
1015 | 199 | pitch_value = MAX_PITCH_VALUE; |
1016 | | |
1017 | 10.6k | if (pitch_value > 50) { |
1018 | | // only adjust if the pitch is higher than normal |
1019 | 199 | factor = 256 + (25 * (pitch_value - 50))/50; |
1020 | 199 | } |
1021 | | |
1022 | 74.4k | for (ix = 0; ix <= 5; ix++) |
1023 | 63.8k | wvoice->freq[ix] = (wvoice->freq2[ix] * factor)/256; |
1024 | | |
1025 | 10.6k | factor = embedded_value[EMBED_T]*3; |
1026 | 10.6k | wvoice->height[0] = (wvoice->height2[0] * (256 - factor*2))/256; |
1027 | 10.6k | wvoice->height[1] = (wvoice->height2[1] * (256 - factor))/256; |
1028 | 10.6k | } |
1029 | | |
1030 | | void SetEmbedded(int control, int value) |
1031 | 31.4k | { |
1032 | | // there was an embedded command in the text at this point |
1033 | 31.4k | int sign = 0; |
1034 | 31.4k | int command; |
1035 | | |
1036 | 31.4k | command = control & 0x1f; |
1037 | 31.4k | if ((control & 0x60) == 0x60) |
1038 | 4.75k | sign = -1; |
1039 | 26.6k | else if ((control & 0x60) == 0x40) |
1040 | 2.58k | sign = 1; |
1041 | | |
1042 | 31.4k | if (command < N_EMBEDDED_VALUES) { |
1043 | 31.4k | if (sign == 0) |
1044 | 24.0k | embedded_value[command] = value; |
1045 | 7.33k | else |
1046 | 7.33k | embedded_value[command] += (value * sign); |
1047 | 31.4k | embedded_value[command] = SetWithRange0(embedded_value[command], embedded_max[command]); |
1048 | 31.4k | } |
1049 | | |
1050 | 31.4k | switch (command) |
1051 | 31.4k | { |
1052 | 605 | case EMBED_T: |
1053 | 605 | WavegenSetEcho(); // and drop through to case P |
1054 | 1.36k | case EMBED_P: |
1055 | 1.36k | SetPitchFormants(); |
1056 | 1.36k | break; |
1057 | 432 | case EMBED_A: // amplitude |
1058 | 432 | general_amplitude = GetAmplitude(); |
1059 | 432 | break; |
1060 | 1.52k | case EMBED_F: // emphasis |
1061 | 1.52k | general_amplitude = GetAmplitude(); |
1062 | 1.52k | break; |
1063 | 882 | case EMBED_H: |
1064 | 882 | WavegenSetEcho(); |
1065 | 882 | break; |
1066 | 31.4k | } |
1067 | 31.4k | } |
1068 | | |
1069 | | void WavegenSetVoice(voice_t *v) |
1070 | 9.27k | { |
1071 | 9.27k | static voice_t v2; |
1072 | | |
1073 | 9.27k | memcpy(&v2, v, sizeof(v2)); |
1074 | 9.27k | wvoice = &v2; |
1075 | | |
1076 | 9.27k | if (v->peak_shape == 0) |
1077 | 9.27k | pk_shape = pk_shape1; |
1078 | 0 | else |
1079 | 0 | pk_shape = pk_shape2; |
1080 | | |
1081 | 9.27k | consonant_amp = (v->consonant_amp * 26) /100; |
1082 | 9.27k | if (samplerate <= 11000) { |
1083 | 0 | consonant_amp = consonant_amp*2; // emphasize consonants at low sample rates |
1084 | 0 | option_harmonic1 = 6; |
1085 | 0 | } |
1086 | 9.27k | WavegenSetEcho(); |
1087 | 9.27k | SetPitchFormants(); |
1088 | 9.27k | MarkerEvent(espeakEVENT_SAMPLERATE, 0, wvoice->samplerate, 0, out_ptr); |
1089 | 9.27k | } |
1090 | | |
1091 | | static void SetAmplitude(int length, unsigned char *amp_env, int value) |
1092 | 3.16M | { |
1093 | 3.16M | if (wvoice == NULL) |
1094 | 0 | return; |
1095 | | |
1096 | 3.16M | amp_ix = 0; |
1097 | 3.16M | if (length == 0) |
1098 | 285k | amp_inc = 0; |
1099 | 2.87M | else |
1100 | 2.87M | amp_inc = (256 * ENV_LEN * STEPSIZE)/length; |
1101 | | |
1102 | 3.16M | wdata.amplitude = (value * general_amplitude)/16; |
1103 | 3.16M | wdata.amplitude_v = (wdata.amplitude * wvoice->consonant_ampv * 15)/100; // for wave mixed with voiced sounds |
1104 | | |
1105 | 3.16M | amplitude_env = amp_env; |
1106 | 3.16M | } |
1107 | | |
1108 | | void SetPitch2(voice_t *voice, int pitch1, int pitch2, int *pitch_base, int *pitch_range) |
1109 | 3.16M | { |
1110 | 3.16M | int base; |
1111 | 3.16M | int range; |
1112 | 3.16M | int pitch_value; |
1113 | | |
1114 | 3.16M | if (pitch1 > pitch2) { |
1115 | 11.8k | int x; |
1116 | 11.8k | x = pitch1; // swap values |
1117 | 11.8k | pitch1 = pitch2; |
1118 | 11.8k | pitch2 = x; |
1119 | 11.8k | } |
1120 | | |
1121 | 3.16M | if ((pitch_value = embedded_value[EMBED_P]) > MAX_PITCH_VALUE) |
1122 | 101k | pitch_value = MAX_PITCH_VALUE; |
1123 | 3.16M | pitch_value -= embedded_value[EMBED_T]; // adjust tone for announcing punctuation |
1124 | 3.16M | if (pitch_value < 0) |
1125 | 24.7k | pitch_value = 0; |
1126 | | |
1127 | 3.16M | base = (voice->pitch_base * pitch_adjust_tab[pitch_value])/128; |
1128 | 3.16M | range = (voice->pitch_range * embedded_value[EMBED_R])/50; |
1129 | | |
1130 | | // compensate for change in pitch when the range is narrowed or widened |
1131 | 3.16M | base -= (range - voice->pitch_range)*18; |
1132 | | |
1133 | 3.16M | *pitch_base = base + (pitch1 * range)/2; |
1134 | 3.16M | *pitch_range = base + (pitch2 * range)/2 - *pitch_base; |
1135 | 3.16M | } |
1136 | | |
1137 | | static void SetPitch(int length, unsigned char *env, int pitch1, int pitch2) |
1138 | 3.16M | { |
1139 | 3.16M | if (wvoice == NULL) |
1140 | 0 | return; |
1141 | | |
1142 | | // length in samples |
1143 | | |
1144 | 3.16M | if ((wdata.pitch_env = env) == NULL) |
1145 | 0 | wdata.pitch_env = env_fall; // default |
1146 | | |
1147 | 3.16M | wdata.pitch_ix = 0; |
1148 | 3.16M | if (length == 0) |
1149 | 2.39k | wdata.pitch_inc = 0; |
1150 | 3.16M | else |
1151 | 3.16M | wdata.pitch_inc = (256 * ENV_LEN * STEPSIZE)/length; |
1152 | | |
1153 | 3.16M | SetPitch2(wvoice, pitch1, pitch2, &wdata.pitch_base, &wdata.pitch_range); |
1154 | | // set initial pitch |
1155 | 3.16M | wdata.pitch = ((wdata.pitch_env[0] * wdata.pitch_range) >>8) + wdata.pitch_base; // Hz << 12 |
1156 | | |
1157 | 3.16M | flutter_amp = wvoice->flutter; |
1158 | 3.16M | } |
1159 | | |
1160 | | static void SetSynth(int length, int modn, frame_t *fr1, frame_t *fr2, voice_t *v) |
1161 | 11.0M | { |
1162 | 11.0M | if (wvoice == NULL || v == NULL) |
1163 | 0 | return; |
1164 | | |
1165 | 11.0M | int ix; |
1166 | 11.0M | double next; |
1167 | 11.0M | int length2; |
1168 | 11.0M | int length4; |
1169 | 11.0M | int qix; |
1170 | 11.0M | static const int glottal_reduce_tab1[4] = { 0x30, 0x30, 0x40, 0x50 }; // vowel before [?], amp * 1/256 |
1171 | 11.0M | static const int glottal_reduce_tab2[4] = { 0x90, 0xa0, 0xb0, 0xc0 }; // vowel after [?], amp * 1/256 |
1172 | | |
1173 | 11.0M | end_wave = 1; |
1174 | | |
1175 | | // any additional information in the param1 ? |
1176 | 11.0M | modulation_type = modn & 0xff; |
1177 | | |
1178 | 11.0M | glottal_flag = 0; |
1179 | 11.0M | if (modn & 0x400) { |
1180 | 1.46k | glottal_flag = 3; // before a glottal stop |
1181 | 1.46k | glottal_reduce = glottal_reduce_tab1[(modn >> 8) & 3]; |
1182 | 1.46k | } |
1183 | 11.0M | if (modn & 0x800) { |
1184 | 2.13k | glottal_flag = 4; // after a glottal stop |
1185 | 2.13k | glottal_reduce = glottal_reduce_tab2[(modn >> 8) & 3]; |
1186 | 2.13k | } |
1187 | | |
1188 | 16.2M | for (qix = wcmdq_head+1;; qix++) { |
1189 | 16.2M | if (qix >= N_WCMDQ) qix = 0; |
1190 | 16.2M | if (qix == wcmdq_tail) break; |
1191 | | |
1192 | 16.2M | int cmd = wcmdq[qix][0]; |
1193 | 16.2M | if (cmd == WCMD_SPECT) { |
1194 | 9.66M | end_wave = 0; // next wave generation is from another spectrum |
1195 | 9.66M | break; |
1196 | 9.66M | } |
1197 | 6.56M | if ((cmd == WCMD_WAVE) || (cmd == WCMD_PAUSE)) |
1198 | 1.38M | break; // next is not from spectrum, so continue until end of wave cycle |
1199 | 6.56M | } |
1200 | | |
1201 | | // round the length to a multiple of the stepsize |
1202 | 11.0M | length2 = (length + STEPSIZE/2) & ~0x3f; |
1203 | 11.0M | if (length2 == 0) |
1204 | 118k | length2 = STEPSIZE; |
1205 | | |
1206 | | // add this length to any left over from the previous synth |
1207 | 11.0M | samplecount_start = samplecount; |
1208 | 11.0M | nsamples += length2; |
1209 | | |
1210 | 11.0M | length4 = length2/4; |
1211 | | |
1212 | 11.0M | peaks[7].freq = (7800 * v->freq[7] + v->freqadd[7]*256) << 8; |
1213 | 11.0M | peaks[8].freq = (9000 * v->freq[8] + v->freqadd[8]*256) << 8; |
1214 | | |
1215 | 99.4M | for (ix = 0; ix < 8; ix++) { |
1216 | 88.3M | if (ix < 7) { |
1217 | 77.3M | peaks[ix].freq1 = (fr1->ffreq[ix] * v->freq[ix] + v->freqadd[ix]*256) << 8; |
1218 | 77.3M | peaks[ix].freq = (int)peaks[ix].freq1; |
1219 | 77.3M | next = (fr2->ffreq[ix] * v->freq[ix] + v->freqadd[ix]*256) << 8; |
1220 | 77.3M | peaks[ix].freq_inc = ((next - peaks[ix].freq1) * (STEPSIZE/4)) / length4; // lower headroom for fixed point math |
1221 | 77.3M | } |
1222 | | |
1223 | 88.3M | peaks[ix].height1 = (fr1->fheight[ix] * v->height[ix]) << 6; |
1224 | 88.3M | peaks[ix].height = (int)peaks[ix].height1; |
1225 | 88.3M | next = (fr2->fheight[ix] * v->height[ix]) << 6; |
1226 | 88.3M | peaks[ix].height_inc = ((next - peaks[ix].height1) * STEPSIZE) / length2; |
1227 | | |
1228 | 88.3M | if ((ix <= 5) && (ix <= wvoice->n_harmonic_peaks)) { |
1229 | 66.2M | peaks[ix].left1 = (fr1->fwidth[ix] * v->width[ix]) << 10; |
1230 | 66.2M | peaks[ix].left = (int)peaks[ix].left1; |
1231 | 66.2M | next = (fr2->fwidth[ix] * v->width[ix]) << 10; |
1232 | 66.2M | peaks[ix].left_inc = ((next - peaks[ix].left1) * STEPSIZE) / length2; |
1233 | | |
1234 | 66.2M | if (ix < 3) { |
1235 | 33.1M | peaks[ix].right1 = (fr1->fright[ix] * v->width[ix]) << 10; |
1236 | 33.1M | peaks[ix].right = (int)peaks[ix].right1; |
1237 | 33.1M | next = (fr2->fright[ix] * v->width[ix]) << 10; |
1238 | 33.1M | peaks[ix].right_inc = ((next - peaks[ix].right1) * STEPSIZE) / length2; |
1239 | 33.1M | } else |
1240 | 33.1M | peaks[ix].right = peaks[ix].left; |
1241 | 66.2M | } |
1242 | 88.3M | } |
1243 | 11.0M | } |
1244 | | |
1245 | | void Write4Bytes(FILE *f, int value) |
1246 | 0 | { |
1247 | | // Write 4 bytes to a file, least significant first |
1248 | 0 | int ix; |
1249 | |
|
1250 | 0 | for (ix = 0; ix < 4; ix++) { |
1251 | 0 | fputc(value & 0xff, f); |
1252 | 0 | value = value >> 8; |
1253 | 0 | } |
1254 | 0 | } |
1255 | | |
1256 | | static int WavegenFill2(void) |
1257 | 5.29M | { |
1258 | | // Pick up next wavegen commands from the queue |
1259 | | // return: 0 output buffer has been filled |
1260 | | // return: 1 input command queue is now empty |
1261 | 5.29M | intptr_t *q; |
1262 | 5.29M | int length; |
1263 | 5.29M | int result; |
1264 | 5.29M | int marker_type; |
1265 | 5.29M | static bool resume = false; |
1266 | 5.29M | static int echo_complete = 0; |
1267 | | |
1268 | 5.29M | if (wdata.pitch < 102400) |
1269 | 1 | wdata.pitch = 102400; // min pitch, 25 Hz (25 << 12) |
1270 | | |
1271 | 32.9M | while (out_ptr < out_end) { |
1272 | 27.6M | if (WcmdqUsed() <= 0) { |
1273 | 75.8k | if (echo_complete > 0) { |
1274 | | // continue to play silence until echo is completed |
1275 | 9.13k | resume = PlaySilence(echo_complete, resume); |
1276 | 9.13k | if (resume == true) |
1277 | 9.00k | return 0; // not yet finished |
1278 | 9.13k | } |
1279 | 66.8k | return 1; // queue empty, close sound channel |
1280 | 75.8k | } |
1281 | | |
1282 | 27.6M | result = 0; |
1283 | 27.6M | q = wcmdq[wcmdq_head]; |
1284 | 27.6M | length = q[1]; |
1285 | | |
1286 | 27.6M | switch (q[0] & 0xff) |
1287 | 27.6M | { |
1288 | 3.16M | case WCMD_PITCH: |
1289 | 3.16M | SetPitch(length, (unsigned char *)q[2], q[3] >> 16, q[3] & 0xffff); |
1290 | 3.16M | break; |
1291 | 0 | case WCMD_PHONEME_ALIGNMENT: |
1292 | 0 | { |
1293 | 0 | char* data = (char*)q[1]; |
1294 | 0 | output_hooks->outputPhoSymbol(data,q[2]); |
1295 | 0 | free(data); |
1296 | 0 | } |
1297 | 0 | break; |
1298 | 2.88M | case WCMD_PAUSE: |
1299 | 2.88M | if (resume == false) |
1300 | 2.18M | echo_complete -= length; |
1301 | 2.88M | wdata.n_mix_wavefile = 0; |
1302 | 2.88M | wdata.amplitude_fmt = 100; |
1303 | 2.88M | #if USE_KLATT |
1304 | 2.88M | KlattReset(1); |
1305 | 2.88M | #endif |
1306 | 2.88M | result = PlaySilence(length, resume); |
1307 | 2.88M | break; |
1308 | 1.93M | case WCMD_WAVE: |
1309 | 1.93M | echo_complete = echo_length; |
1310 | 1.93M | wdata.n_mix_wavefile = 0; |
1311 | 1.93M | #if USE_KLATT |
1312 | 1.93M | KlattReset(1); |
1313 | 1.93M | #endif |
1314 | 1.93M | result = PlayWave(length, resume, (unsigned char *)q[2], q[3] & 0xff, q[3] >> 8); |
1315 | 1.93M | break; |
1316 | 622k | case WCMD_WAVE2: |
1317 | | // wave file to be played at the same time as synthesis |
1318 | 622k | wdata.mix_wave_amp = q[3] >> 8; |
1319 | 622k | wdata.mix_wave_scale = q[3] & 0xff; |
1320 | 622k | wdata.n_mix_wavefile = (length & 0xffff); |
1321 | 622k | wdata.mix_wavefile_max = (length >> 16) & 0xffff; |
1322 | 622k | if (wdata.mix_wave_scale == 0) { |
1323 | 0 | wdata.n_mix_wavefile *= 2; |
1324 | 0 | wdata.mix_wavefile_max *= 2; |
1325 | 0 | } |
1326 | 622k | wdata.mix_wavefile_ix = 0; |
1327 | 622k | wdata.mix_wavefile_offset = 0; |
1328 | 622k | wdata.mix_wavefile = (unsigned char *)q[2]; |
1329 | 622k | break; |
1330 | 882k | case WCMD_SPECT2: // as WCMD_SPECT but stop any concurrent wave file |
1331 | 882k | wdata.n_mix_wavefile = 0; // ... and drop through to WCMD_SPECT case |
1332 | 14.8M | case WCMD_SPECT: |
1333 | 14.8M | echo_complete = echo_length; |
1334 | 14.8M | result = Wavegen(length & 0xffff, q[1] >> 16, resume, (frame_t *)q[2], (frame_t *)q[3], wvoice); |
1335 | 14.8M | break; |
1336 | 0 | #if USE_KLATT |
1337 | 0 | case WCMD_KLATT2: // as WCMD_SPECT but stop any concurrent wave file |
1338 | 0 | wdata.n_mix_wavefile = 0; // ... and drop through to WCMD_SPECT case |
1339 | 0 | case WCMD_KLATT: |
1340 | 0 | echo_complete = echo_length; |
1341 | 0 | result = Wavegen_Klatt(length & 0xffff, resume, (frame_t *)q[2], (frame_t *)q[3], &wdata, wvoice); |
1342 | 0 | break; |
1343 | 0 | #endif |
1344 | 642k | case WCMD_MARKER: |
1345 | 642k | marker_type = q[0] >> 8; |
1346 | 642k | MarkerEvent(marker_type, q[1], * (int *) & q[2], * ((int *) & q[2] + 1), out_ptr); |
1347 | 642k | break; |
1348 | 3.16M | case WCMD_AMPLITUDE: |
1349 | 3.16M | SetAmplitude(length, (unsigned char *)q[2], q[3]); |
1350 | 3.16M | break; |
1351 | 9.27k | case WCMD_VOICE: |
1352 | 9.27k | WavegenSetVoice((voice_t *)q[2]); |
1353 | 9.27k | free((voice_t *)q[2]); |
1354 | 9.27k | break; |
1355 | 23.6k | case WCMD_EMBEDDED: |
1356 | 23.6k | SetEmbedded(q[1], q[2]); |
1357 | 23.6k | break; |
1358 | | #if USE_MBROLA |
1359 | | case WCMD_MBROLA_DATA: |
1360 | | if (wvoice != NULL) |
1361 | | result = MbrolaFill(length, resume, (general_amplitude * wvoice->voicing)/64); |
1362 | | break; |
1363 | | #endif |
1364 | 320k | case WCMD_FMT_AMPLITUDE: |
1365 | 320k | if ((wdata.amplitude_fmt = q[1]) == 0) |
1366 | 160k | wdata.amplitude_fmt = 100; // percentage, but value=0 means 100% |
1367 | 320k | break; |
1368 | | #if USE_LIBSONIC |
1369 | | case WCMD_SONIC_SPEED: |
1370 | | sonicSpeed = (double)q[1] / 1024; |
1371 | | if (sonicSpeedupStream && (sonicSpeed <= 1.0)) { |
1372 | | sonicFlushStream(sonicSpeedupStream); |
1373 | | int length = (out_end - out_ptr); |
1374 | | length = sonicReadShortFromStream(sonicSpeedupStream, (short*)out_ptr, length/2); |
1375 | | #ifdef ARCH_BIG |
1376 | | { |
1377 | | unsigned i; |
1378 | | for (i = 0; i < length/2; i++) { |
1379 | | unsigned short v = ((unsigned short *) out_ptr)[i]; |
1380 | | out_ptr[i*2] = v & 0xff; |
1381 | | out_ptr[i*2+1] = v >> 8; |
1382 | | } |
1383 | | } |
1384 | | #endif |
1385 | | out_ptr += length * 2; |
1386 | | } |
1387 | | break; |
1388 | | #endif |
1389 | 27.6M | } |
1390 | | |
1391 | 27.6M | if (result == 0) { |
1392 | 22.4M | WcmdqIncHead(); |
1393 | 22.4M | resume = false; |
1394 | 22.4M | } else |
1395 | 5.21M | resume = true; |
1396 | 27.6M | } |
1397 | | |
1398 | 5.21M | return 0; |
1399 | 5.29M | } |
1400 | | |
1401 | | #if USE_LIBSONIC |
1402 | | // Speed up the audio samples with libsonic. |
1403 | | static int SpeedUp(short *outbuf, int length_in, int length_out, int end_of_text) |
1404 | | { |
1405 | | #ifdef ARCH_BIG |
1406 | | unsigned i; |
1407 | | #endif |
1408 | | |
1409 | | if (length_in > 0) { |
1410 | | if (sonicSpeedupStream == NULL) |
1411 | | sonicSpeedupStream = sonicCreateStream(22050, 1); |
1412 | | if (sonicGetSpeed(sonicSpeedupStream) != sonicSpeed) |
1413 | | sonicSetSpeed(sonicSpeedupStream, sonicSpeed); |
1414 | | |
1415 | | #ifdef ARCH_BIG |
1416 | | for (i = 0; i < length_in; i++) { |
1417 | | unsigned short v = ((unsigned char*) outbuf)[i*2] | (((unsigned char *)outbuf)[i*2+1] << 8); |
1418 | | ((unsigned short *) outbuf)[i] = v; |
1419 | | } |
1420 | | #endif |
1421 | | sonicWriteShortToStream(sonicSpeedupStream, outbuf, length_in); |
1422 | | } |
1423 | | |
1424 | | if (sonicSpeedupStream == NULL) |
1425 | | return 0; |
1426 | | |
1427 | | if (end_of_text) |
1428 | | sonicFlushStream(sonicSpeedupStream); |
1429 | | |
1430 | | int ret = sonicReadShortFromStream(sonicSpeedupStream, outbuf, length_out); |
1431 | | #ifdef ARCH_BIG |
1432 | | for (i = 0; i < length_out; i++) { |
1433 | | unsigned short v = ((unsigned short *) outbuf)[i]; |
1434 | | ((unsigned char *)outbuf)[i*2] = v & 0xff; |
1435 | | ((unsigned char *)outbuf)[i*2+1] = v >> 8; |
1436 | | } |
1437 | | #endif |
1438 | | return ret; |
1439 | | } |
1440 | | #endif |
1441 | | |
1442 | | // Call WavegenFill2, and then speed up the output samples. |
1443 | | int WavegenFill(void) |
1444 | 5.29M | { |
1445 | 5.29M | int finished; |
1446 | | #if USE_LIBSONIC |
1447 | | unsigned char *p_start; |
1448 | | |
1449 | | p_start = out_ptr; |
1450 | | #endif |
1451 | | |
1452 | 5.29M | finished = WavegenFill2(); |
1453 | | |
1454 | | #if USE_LIBSONIC |
1455 | | if (sonicSpeed > 1.0) { |
1456 | | int length; |
1457 | | int max_length; |
1458 | | |
1459 | | max_length = (out_end - p_start); |
1460 | | length = 2*SpeedUp((short *)p_start, (out_ptr-p_start)/2, max_length/2, finished); |
1461 | | out_ptr = p_start + length; |
1462 | | |
1463 | | if (length >= max_length) |
1464 | | finished = 0; // there may be more data to flush |
1465 | | } |
1466 | | #endif |
1467 | 5.29M | return finished; |
1468 | 5.29M | } |
1469 | | |
1470 | | #pragma GCC visibility push(default) |
1471 | | |
1472 | | ESPEAK_NG_API espeak_ng_STATUS |
1473 | | espeak_ng_SetOutputHooks(espeak_ng_OUTPUT_HOOKS* hooks) |
1474 | 0 | { |
1475 | 0 | output_hooks = hooks; |
1476 | 0 | return 0; |
1477 | 0 | } |
1478 | | |
1479 | | ESPEAK_NG_API espeak_ng_STATUS |
1480 | | espeak_ng_SetConstF0(int f0) |
1481 | 0 | { |
1482 | 0 | const_f0 = f0; |
1483 | 0 | return ENS_OK; |
1484 | 0 | } |
1485 | | |
1486 | | #pragma GCC visibility pop |