Noble Ape
The Central Directories of the Noble Ape Simulation.
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros
speak.c
Go to the documentation of this file.
1 /****************************************************************
2 
3  speak.c
4 
5  =============================================================
6 
7  Copyright 1996-2014 Tom Barbalet. All rights reserved.
8 
9  Permission is hereby granted, free of charge, to any person
10  obtaining a copy of this software and associated documentation
11  files (the "Software"), to deal in the Software without
12  restriction, including without limitation the rights to use,
13  copy, modify, merge, publish, distribute, sublicense, and/or
14  sell copies of the Software, and to permit persons to whom the
15  Software is furnished to do so, subject to the following
16  conditions:
17 
18  The above copyright notice and this permission notice shall be
19  included in all copies or substantial portions of the Software.
20 
21  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
23  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
25  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
26  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
28  OTHER DEALINGS IN THE SOFTWARE.
29 
30  This software and Noble Ape are a continuing work of Tom Barbalet,
31  begun on 13 June 1996. No apes or cats were harmed in the writing
32  of this software.
33 
34  ****************************************************************/
35 
36 #include "entity.h"
37 #include "entity_internal.h"
38 
41 #include <stdio.h>
42 #include <stdlib.h>
43 
53 static n_audio output[AUDIO_FFT_MAX_BUFFER];
54 
55 static n_uint speak_length(n_byte character)
56 {
57  switch (character)
58  {
59  case 'a':
60  case 'e':
61  case 'i':
62  case 'o':
63  return 1;
64  case 'p':
65  case 'b':
66  case 'j':
67  case 't':
68  return 0;
69  default:
70  return 2;
71  }
72 }
73 
74 static n_uint speak_length_total(n_string paragraph)
75 {
76  n_int loop = 0;
77  n_byte character;
78  n_uint length = 0;
79  do
80  {
81  character = paragraph[loop++];
82  if (character != '\n' && character != 0)
83  {
84  length += 1 << speak_length(character);
85  }
86  }
87  while (character != '\n' && character != 0);
88  return length;
89 }
90 
91 static const n_int set_frequencies[24] =
92 {
93  175,178,180,183,
94  185,188,191,193,
95  196,199,202,205,
96  208,211,214,217,
97  220,223,227,229,
98  233,237,240,244
99 };
100 
101 
102 static const n_int vowel_reorder[8] =
103 {
104  4, 7, 0, 2, 1, 6, 3, 5
105 };
106 
107 static const n_int consonant_reorder[16] =
108 {
109  6, 13, 3, 7, 0, 14, 1, 12,
110  9, 11, 2, 15, 4, 10, 5, 8
111 };
112 
113 static const n_int low_freq[13]=
114 {
115  60000, 45000, 30000, 55000,
116  30000, 40000, 35000, 60000,
117  40000, 20000, 65000, 40000,
118  30000
119 };
120 
121 static void speak_freq(n_int * high, n_int * low, n_byte value)
122 {
123  const n_string character_building = "aeiovfstpbjm";
124  n_int loop = 0;
125  do
126  {
127  if (value != character_building[loop])
128  {
129  loop++;
130  }
131  }
132  while ((loop<12) && (value != character_building[loop]));
133 
134  if (loop < 12)
135  {
136  low[1] = low_freq[loop ];
137  low[0] = 1;
138  low[3] = low_freq[loop+1];
139  low[2] = 2;
140 
141  if (loop < 4)
142  {
143  high[0] = set_frequencies[vowel_reorder[loop]];
144  high[1] = 600000;
145  high[2] = set_frequencies[vowel_reorder[loop+1]];
146  high[3] = 300000;
147  high[4] = set_frequencies[vowel_reorder[loop+2]+2];
148  high[5] = 200000;
149  high[6] = set_frequencies[vowel_reorder[loop+4]+3];
150  high[7] = 50000;
151  }
152  else
153  {
154  high[0] = set_frequencies[consonant_reorder[loop-4]];
155  high[1] = 600000;
156  high[2] = set_frequencies[consonant_reorder[loop-2]+3];
157  high[3] = 400000;
158  high[4] = set_frequencies[consonant_reorder[loop+1]+8];
159  high[5] = 100000;
160  high[6] = set_frequencies[consonant_reorder[loop+3]+8];
161  high[7] = 50000;
162  }
163  }
164  else
165  {
166  low[0] = 0;
167  low[1] = 0;
168  low[2] = 0;
169  low[3] = 0;
170  high[0] = 0;
171  high[1] = 0;
172  high[2] = 0;
173  high[3] = 0;
174  high[4] = 0;
175  high[5] = 0;
176  high[6] = 0;
177  high[7] = 0;
178  }
179 
180 }
181 
182 void speak_out(n_string filename, n_string paragraph)
183 {
184  FILE *out_file = 0L;
185  n_uint total_length = AUDIO_FFT_MAX_BUFFER * speak_length_total(paragraph) >> 2;
186  n_int loop = 0;
187  n_byte found_character;
188 
189  if (total_length < 1)
190  {
191  (void)SHOW_ERROR("Speaking length is less than one");
192  return;
193  }
194 
195  out_file = fopen(filename,"w");
196 
197  if (out_file == 0L)
198  {
199  (void)SHOW_ERROR("Failed create speak file!");
200  return;
201  }
202 
203  audio_aiff_header(out_file, total_length);
204  do
205  {
206  n_uint power_sample = (speak_length(found_character = paragraph[loop++]) + AUDIO_FFT_MAX_BITS - 2);
207  n_uint length = 1 << power_sample;
208  n_int division = AUDIO_FFT_MAX_BUFFER / length;
209 
210  audio_clear_buffers(length);
211 
212  if (found_character != '\n' && found_character != 0)
213  {
214  if (found_character !=' ' && found_character != '.')
215  {
216  n_int local_high[8], local_low[4];
217 
218  speak_freq(local_high, local_low,found_character);
219 
220  audio_set_frequency(local_high[0]/division, local_high[1]/division);
221  audio_set_frequency(local_high[2]/division, local_high[3]/division);
222  audio_set_frequency(local_high[4]/division, local_high[5]/division);
223  audio_set_frequency(local_high[6]/division, local_high[7]/division);
224 
225  audio_fft(1, power_sample);
226 
227  audio_equal_output(output, length);
228 
229  audio_clear_buffers(length);
230 
231  audio_set_frequency(local_low[0], local_low[1]/division);
232  audio_set_frequency(local_low[2], local_low[3]/division);
233 
234  audio_fft(1, power_sample);
235 
236  audio_multiply_output(output, length);
237  }
238  else
239  {
240  audio_clear_output(output, length);
241  }
242  audio_aiff_body(out_file, output, length);
243  }
244  }
245  while (found_character != '\n' && found_character != 0);
246 
247  if (fclose(out_file) != 0)
248  {
249  (void)SHOW_ERROR("Failed to close speak file");
250  }
251  return;
252 }
253