eSpeak NG is an open source speech synthesizer that supports more than hundred languages and accents.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

wave_sada.c 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  1. /*
  2. * Copyright (C) 2008, Sun Microsystems, Inc.
  3. * Copyright (C) 2015 Reece H. Dunn
  4. * eSpeak driver for Solaris Audio Device Architecture (SADA)
  5. * Written by Willie Walker, based on the eSpeak PulseAudio driver
  6. * from Gilles Casse
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation; either version 3 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, see: <http://www.gnu.org/licenses/>.
  20. */
  21. #include "speech.h"
  22. #include <errno.h>
  23. #include <string.h>
  24. #include <stropts.h>
  25. #include <assert.h>
  26. #include <stdlib.h>
  27. #include <unistd.h>
  28. #include <fcntl.h>
  29. #include <sys/audioio.h>
  30. #include "wave.h"
  31. #define SAMPLE_RATE 22050
  32. #define SAMPLE_SIZE 16
  33. #ifdef USE_SADA
  34. static t_wave_callback *my_callback_is_output_enabled = NULL;
  35. static const char *sun_audio_device = "/dev/audio";
  36. static int sun_audio_fd = -1;
  37. // The total number of 16-bit samples sent to be played via the
  38. // wave_write method.
  39. //
  40. static uint32_t total_samples_sent;
  41. // The total number of samples sent to be played via the wave_write
  42. // method, but which were never played because of a call to
  43. // wave_close.
  44. //
  45. static uint32_t total_samples_skipped;
  46. // The last known playing index after a call to wave_close.
  47. //
  48. static uint32_t last_play_position = 0;
  49. static uint32_t wave_samplerate;
  50. // wave_open
  51. //
  52. // DESCRIPTION:
  53. //
  54. // initializes the audio subsytem.
  55. //
  56. // GLOBALS USED/MODIFIED:
  57. //
  58. // sun_audio_fd: modified to hold the file descriptor of the opened
  59. // audio device.
  60. //
  61. void *wave_open(int srate, const char *device)
  62. {
  63. if (device == NULL)
  64. device = sun_audio_device;
  65. audio_info_t ainfo;
  66. wave_samplerate = srate;
  67. if ((sun_audio_fd = open(device, O_WRONLY)) < 0) {
  68. fprintf(stderr, "wave_open() could not open: %s (%d)\n", device, sun_audio_fd);
  69. return NULL;
  70. }
  71. ioctl(sun_audio_fd, AUDIO_GETINFO, &ainfo);
  72. ainfo.play.encoding = AUDIO_ENCODING_LINEAR;
  73. ainfo.play.channels = 1;
  74. ainfo.play.sample_rate = wave_samplerate;
  75. ainfo.play.precision = SAMPLE_SIZE;
  76. if (ioctl(sun_audio_fd, AUDIO_SETINFO, &ainfo) == -1) {
  77. fprintf(stderr, "wave_open() failed to set audio params: %s\n", strerror(errno));
  78. close(sun_audio_fd);
  79. return NULL;
  80. }
  81. return (void *)sun_audio_fd;
  82. }
  83. // wave_write
  84. //
  85. // DESCRIPTION:
  86. //
  87. // Meant to be asynchronous, it supplies the wave sample to the lower
  88. // audio layer and returns. The sample is played later on. [[[WDW -
  89. // we purposely do not open the audio device as non-blocking because
  90. // managing that would be a pain. So, we rely a lot upon fifo.cpp and
  91. // event.cpp to not overload us, allowing us to get away with a
  92. // blocking write. event.cpp:polling_thread in particular appears to
  93. // use get_remaining_time to prevent flooding.]]]
  94. //
  95. // PARAMETERS:
  96. //
  97. // theHandler: the audio device file descriptor
  98. // theMono16BitsWaveBuffer: the audio data
  99. // theSize: the number of bytes (not 16-bit samples)
  100. //
  101. // GLOBALS USED/MODIFIED:
  102. //
  103. // total_samples_sent: modified based upon 16-bit samples sent
  104. //
  105. // RETURNS:
  106. //
  107. // the number of bytes (not 16-bit samples) sent
  108. //
  109. size_t wave_write(void *theHandler,
  110. char *theMono16BitsWaveBuffer,
  111. size_t theSize)
  112. {
  113. size_t num;
  114. if (my_callback_is_output_enabled && (0 == my_callback_is_output_enabled()))
  115. return 0;
  116. #if defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN
  117. // BIG-ENDIAN, swap the order of bytes in each sound sample
  118. int c;
  119. char *out_ptr;
  120. char *out_end;
  121. out_ptr = (char *)theMono16BitsWaveBuffer;
  122. out_end = out_ptr + theSize;
  123. while (out_ptr < out_end) {
  124. c = out_ptr[0];
  125. out_ptr[0] = out_ptr[1];
  126. out_ptr[1] = c;
  127. out_ptr += 2;
  128. }
  129. #endif
  130. num = write((int)theHandler, theMono16BitsWaveBuffer, theSize);
  131. // Keep track of the total number of samples sent -- we use this in
  132. // wave_get_read_position and also use it to help calculate the
  133. // total_samples_skipped in wave_close.
  134. //
  135. total_samples_sent += num / 2;
  136. return num;
  137. }
  138. // wave_close
  139. //
  140. // DESCRIPTION:
  141. //
  142. // Does what SADA normally would call a flush, which means to cease
  143. // all audio production in progress and throw any remaining audio
  144. // away. [[[WDW - see comment in wave_flush.]]]
  145. //
  146. // PARAMETERS:
  147. //
  148. // theHandler: the audio device file descriptor
  149. //
  150. // GLOBALS USED/MODIFIED:
  151. //
  152. // last_play_position: modified to reflect play position the last time
  153. // this method was called
  154. // total_samples_sent: used to help calculate total_samples_skipped
  155. // total_samples_skipped: modified to hold the total number of 16-bit
  156. // samples sent to wave_write, but which were
  157. // never played
  158. // sun_audio_fd: used because some calls to wave_close seem to
  159. // pass a NULL for theHandler for some odd reason
  160. //
  161. // RETURNS:
  162. //
  163. // The result of the ioctl call (non-0 means failure)
  164. //
  165. int wave_close(void *theHandler)
  166. {
  167. int ret;
  168. audio_info_t ainfo;
  169. int audio_fd = (int)theHandler;
  170. if (!audio_fd)
  171. audio_fd = sun_audio_fd;
  172. // [[[WDW: maybe do a pause/resume ioctl???]]]
  173. ret = ioctl(audio_fd, I_FLUSH, FLUSHRW);
  174. ioctl(audio_fd, AUDIO_GETINFO, &ainfo);
  175. // Calculate the number of samples that won't get
  176. // played. We also keep track of the last_play_position
  177. // because wave_close can be called multiple times
  178. // before another call to wave_write.
  179. //
  180. if (last_play_position != ainfo.play.samples) {
  181. last_play_position = ainfo.play.samples;
  182. total_samples_skipped = total_samples_sent - last_play_position;
  183. }
  184. return ret;
  185. }
  186. // wave_is_busy
  187. //
  188. // DESCRIPTION:
  189. //
  190. // Returns a non-0 value if audio is being played.
  191. //
  192. // PARAMETERS:
  193. //
  194. // theHandler: the audio device file descriptor
  195. //
  196. // GLOBALS USED/MODIFIED:
  197. //
  198. // sun_audio_fd: used because some calls to wave_is_busy seem to
  199. // pass a NULL for theHandler for some odd reason
  200. //
  201. // RETURNS:
  202. //
  203. // A non-0 value if audio is being played
  204. //
  205. int wave_is_busy(void *theHandler)
  206. {
  207. (void)theHandler; // unused
  208. uint32_t time;
  209. if (total_samples_sent >= 1)
  210. wave_get_remaining_time(total_samples_sent - 1, &time);
  211. else
  212. time = 0;
  213. return time != 0;
  214. }
  215. // wave_terminate
  216. //
  217. // DESCRIPTION:
  218. //
  219. // Used to end our session with eSpeak.
  220. //
  221. // GLOBALS USED/MODIFIED:
  222. //
  223. // sun_audio_fd: modified - closed and set to -1
  224. //
  225. void wave_terminate()
  226. {
  227. close(sun_audio_fd);
  228. sun_audio_fd = -1;
  229. }
  230. // wave_flush
  231. //
  232. // DESCRIPTION:
  233. //
  234. // Appears to want to tell the audio subsystem to make sure it plays
  235. // the audio. In our case, the system is already doing this, so this
  236. // is basically a no-op. [[[WDW - if you do a drain, you block, so
  237. // don't do that. In addition the typical SADA notion of flush is
  238. // currently handled by wave_close. I think this is most likely just
  239. // terminology conflict between eSpeak and SADA.]]]
  240. //
  241. // PARAMETERS:
  242. //
  243. // theHandler: the audio device file descriptor
  244. //
  245. void wave_flush(void *theHandler)
  246. {
  247. (void)theHandler; // unused
  248. }
  249. // wave_set_callback_is_output_enabled
  250. //
  251. // DESCRIPTION:
  252. //
  253. // Sets the callback to call from wave_write before it sends data to
  254. // be played. It helps wave_write determine if the data should be
  255. // thrown away or not.
  256. //
  257. // PARAMETERS:
  258. //
  259. // cb: the callback to call from wave_write
  260. //
  261. void wave_set_callback_is_output_enabled(t_wave_callback *cb)
  262. {
  263. my_callback_is_output_enabled = cb;
  264. }
  265. // wave_test_get_write_buffer
  266. //
  267. // DESCRIPTION:
  268. //
  269. // Unnecessary and is used for debug output from
  270. // speak_lib.cpp:dispatch_audio.
  271. //
  272. // RETURNS:
  273. //
  274. // NULL
  275. //
  276. void *wave_test_get_write_buffer()
  277. {
  278. return NULL;
  279. }
  280. // wave_get_read_position
  281. //
  282. // DESCRIPTION:
  283. //
  284. // Concerns the sample which is currently played by the audio layer,
  285. // where 'sample' is a small buffer of synthesized wave data,
  286. // identified so that the user callback could be called when the
  287. // 'sample' is really played. The identifier is returned by
  288. // wave_get_write_position. This method is unused.
  289. //
  290. // PARAMETERS:
  291. //
  292. // theHandler: the audio device file descriptor
  293. //
  294. // RETURNS:
  295. //
  296. // The total number of 16-bit samples played by the audio system
  297. // so far.
  298. //
  299. uint32_t wave_get_read_position(void *theHandler)
  300. {
  301. audio_info_t ainfo;
  302. ioctl((int)theHandler, AUDIO_GETINFO, &ainfo);
  303. return ainfo.play.samples;
  304. }
  305. // wave_get_write_position
  306. //
  307. // DESCRIPTION:
  308. //
  309. // Returns an identifier for a new sample, where 'sample' is a small
  310. // buffer of synthesized wave data, identified so that the user
  311. // callback could be called when the 'sample' is really played. This
  312. // implementation views the audio as one long continuous stream of
  313. // 16-bit samples.
  314. //
  315. // PARAMETERS:
  316. //
  317. // theHandler: the audio device file descriptor
  318. //
  319. // GLOBALS USED/MODIFIED:
  320. //
  321. // total_samples_sent: used as the return value
  322. //
  323. // RETURNS:
  324. //
  325. // total_samples_sent, which is the index for the end of this long
  326. // continuous stream. [[[WDW: with a unit32_t managing 16-bit
  327. // samples at 22050Hz, we have about 54 hours of play time before
  328. // the index wraps back to 0. We don't handle that wrapping, so
  329. // the behavior after 54 hours of play time is undefined.]]]
  330. //
  331. uint32_t wave_get_write_position(void *theHandler)
  332. {
  333. (void)theHandler; // unused
  334. return total_samples_sent;
  335. }
  336. // wave_get_remaining_time
  337. //
  338. // DESCRIPTION:
  339. //
  340. // Returns the remaining time (in ms) before the sample is played.
  341. // The sample in this case is a return value from a previous call to
  342. // wave_get_write_position.
  343. //
  344. // PARAMETERS:
  345. //
  346. // sample: an index returned from wave_get_write_position representing
  347. // an index into the long continuous stream of 16-bit samples
  348. // time: a return value representing the delay in milliseconds until
  349. // sample is played. A value of 0 means the sample is either
  350. // currently being played or it has already been played.
  351. //
  352. // GLOBALS USED/MODIFIED:
  353. //
  354. // sun_audio_fd: used to determine total number of samples played by
  355. // the audio system
  356. // total_samples_skipped: used in remaining time calculation
  357. //
  358. // RETURNS:
  359. //
  360. // Time in milliseconds before the sample is played or 0 if the sample
  361. // is currently playing or has already been played.
  362. //
  363. int wave_get_remaining_time(uint32_t sample, uint32_t *time)
  364. {
  365. uint32_t a_time = 0;
  366. uint32_t actual_index;
  367. audio_info_t ainfo;
  368. if (!time)
  369. return -1;
  370. ioctl(sun_audio_fd, AUDIO_GETINFO, &ainfo);
  371. // See if this sample has already been played or is currently
  372. // playing.
  373. //
  374. actual_index = sample - total_samples_skipped;
  375. if ((sample < total_samples_skipped) ||
  376. (actual_index <= ainfo.play.samples))
  377. *time = 0;
  378. else {
  379. a_time = ((actual_index - ainfo.play.samples) * 1000) / wave_samplerate;
  380. *time = (uint32_t)a_time;
  381. }
  382. return 0;
  383. }
  384. #endif