sndio.cc 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. /*
  2. * Copyright (c) 2010 Jacob Meuser <jakemsr@sdf.lonestar.org>
  3. *
  4. * Permission to use, copy, modify, and distribute this software for any
  5. * purpose with or without fee is hereby granted, provided that the above
  6. * copyright notice and this permission notice appear in all copies.
  7. *
  8. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  9. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  11. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  13. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  14. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. */
  16. /* Based on voxware.cc which came with the following copyright notice. */
  17. /*************************************************************************/
  18. /* */
  19. /* Centre for Speech Technology Research */
  20. /* University of Edinburgh, UK */
  21. /* Copyright (c) 1997,1998 */
  22. /* All Rights Reserved. */
  23. /* */
  24. /* Permission is hereby granted, free of charge, to use and distribute */
  25. /* this software and its documentation without restriction, including */
  26. /* without limitation the rights to use, copy, modify, merge, publish, */
  27. /* distribute, sublicense, and/or sell copies of this work, and to */
  28. /* permit persons to whom this work is furnished to do so, subject to */
  29. /* the following conditions: */
  30. /* 1. The code must retain the above copyright notice, this list of */
  31. /* conditions and the following disclaimer. */
  32. /* 2. Any modifications must be clearly marked as such. */
  33. /* 3. Original authors' names are not deleted. */
  34. /* 4. The authors' names are not used to endorse or promote products */
  35. /* derived from this software without specific prior written */
  36. /* permission. */
  37. /* */
  38. /* THE UNIVERSITY OF EDINBURGH AND THE CONTRIBUTORS TO THIS WORK */
  39. /* DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING */
  40. /* ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT */
  41. /* SHALL THE UNIVERSITY OF EDINBURGH NOR THE CONTRIBUTORS BE LIABLE */
  42. /* FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES */
  43. /* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN */
  44. /* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, */
  45. /* ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF */
  46. /* THIS SOFTWARE. */
  47. /* */
  48. /*************************************************************************/
  49. /* Author : Alan W Black */
  50. /* Date : July 1997 */
  51. /*-----------------------------------------------------------------------*/
  52. #include <stdio.h>
  53. #include <string.h>
  54. #include <stdlib.h>
  55. #include <ctype.h>
  56. #include <sys/stat.h>
  57. #include "EST_cutils.h"
  58. #include "EST_walloc.h"
  59. #include "EST_Wave.h"
  60. #include "EST_wave_aux.h"
  61. #include "EST_Option.h"
  62. #include "audioP.h"
  63. #include "EST_io_aux.h"
  64. #include "EST_error.h"
  65. #ifdef SUPPORT_SNDIO
  66. #include <sndio.h>
  67. int sndio_supported = TRUE;
  68. static char *aud_sys_name = "sndio";
  69. static int stereo_only = 0;
  70. // Code to block signals while sound is playing.
  71. // Needed inside Java on (at least some) linux systems
  72. // as scheduling interrupts seem to break the writes.
  73. #ifdef THREAD_SAFETY
  74. #include <signal.h>
  75. #include <pthread.h>
  76. #define THREAD_DECS() \
  77. sigset_t oldmask \
  78. #define THREAD_PROTECT() do { \
  79. sigset_t newmask; \
  80. \
  81. sigfillset(&newmask); \
  82. \
  83. pthread_sigmask(SIG_BLOCK, &newmask, &oldmask); \
  84. } while(0)
  85. #define THREAD_UNPROTECT() do { \
  86. pthread_sigmask(SIG_SETMASK, &oldmask, NULL); \
  87. } while (0)
  88. #else
  89. #define THREAD_DECS() //empty
  90. #define THREAD_PROTECT() //empty
  91. #define THREAD_UNPROTECT() //empty
  92. #endif
  93. #define AUDIOBUFFSIZE 256
  94. // #define AUDIOBUFFSIZE 20480
  95. int
  96. play_sndio_wave(EST_Wave &inwave, EST_Option &al)
  97. {
  98. struct sio_hdl *hdl;
  99. struct sio_par par;
  100. int sample_rate;
  101. short *waveform;
  102. short *waveform2 = NULL;
  103. int num_samples;
  104. int i, r, n;
  105. char *audiodevice = NULL;
  106. if (al.present("-audiodevice"))
  107. audiodevice = al.val("-audiodevice");
  108. if ((hdl = sio_open(audiodevice, SIO_PLAY, 0)) == NULL) {
  109. cerr << aud_sys_name << ": error opening device" << endl;
  110. return -1;
  111. }
  112. waveform = inwave.values().memory();
  113. num_samples = inwave.num_samples();
  114. sample_rate = inwave.sample_rate();
  115. sio_initpar(&par);
  116. par.rate = sample_rate;
  117. par.pchan = 1;
  118. par.bits = 16;
  119. par.sig = 1;
  120. par.le = SIO_LE_NATIVE;
  121. if (!sio_setpar(hdl, &par) || !sio_getpar(hdl, &par)) {
  122. cerr << aud_sys_name << ": error configuring parameters" << endl;
  123. return -1;
  124. }
  125. if ((par.pchan != 1 && par.pchan != 2) ||
  126. !((par.bits == 16 && par.sig == 1) ||
  127. (par.bits == 8 && par.sig == 0)) ||
  128. par.rate != sample_rate) {
  129. cerr << aud_sys_name << ": could not set appropriate parameters" << endl;
  130. return -1;
  131. }
  132. if (!sio_start(hdl)) {
  133. cerr << aud_sys_name << ": could not start sudio" << endl;
  134. return -1;
  135. }
  136. if (par.pchan == 2)
  137. stereo_only = 1;
  138. if (stereo_only) {
  139. waveform2 = walloc(short, num_samples * 2);
  140. for (i = 0; i < num_samples; i++) {
  141. waveform2[i * 2] = inwave.a(i);
  142. waveform2[(i * 2) + 1] = inwave.a(i);
  143. }
  144. waveform = waveform2;
  145. num_samples *= 2;
  146. }
  147. THREAD_DECS();
  148. THREAD_PROTECT();
  149. if (par.bits == 8) {
  150. // Its actually 8bit unsigned so convert the buffer;
  151. unsigned char *uchars = walloc(unsigned char,num_samples);
  152. for (i=0; i < num_samples; i++)
  153. uchars[i] = waveform[i] / 256 + 128;
  154. for (i=0; i < num_samples; i += r) {
  155. if (num_samples > i + AUDIOBUFFSIZE)
  156. n = AUDIOBUFFSIZE;
  157. else
  158. n = num_samples - i;
  159. r = sio_write(hdl, &uchars[i], n);
  160. if (r == 0 && sio_eof(hdl)) {
  161. THREAD_UNPROTECT();
  162. cerr << aud_sys_name << ": failed to write to buffer" <<
  163. sample_rate << endl;
  164. sio_close(hdl);
  165. return -1;
  166. }
  167. }
  168. wfree(uchars);
  169. } else {
  170. // 16-bit
  171. int nbuf, c;
  172. short *buf;
  173. nbuf = par.round * par.bps * par.pchan;
  174. buf = new short[nbuf];
  175. for (i = 0; i < num_samples; i += r / 2) {
  176. if (num_samples > i+nbuf)
  177. n = nbuf;
  178. else
  179. n = num_samples-i;
  180. for (c = 0; c < n; c++)
  181. buf[c] = waveform[c + i];
  182. for(; c < nbuf; c++)
  183. buf[c] = waveform[n - 1];
  184. r = sio_write(hdl, buf, nbuf * 2);
  185. if (r == 0 && sio_eof(hdl)) {
  186. THREAD_UNPROTECT();
  187. EST_warning("%s: failed to write to buffer (sr=%d)",
  188. aud_sys_name, sample_rate );
  189. sio_close(hdl);
  190. return -1;
  191. }
  192. }
  193. delete [] buf;
  194. }
  195. sio_close(hdl);
  196. if (waveform2)
  197. wfree(waveform2);
  198. THREAD_UNPROTECT();
  199. return 1;
  200. }
  201. int
  202. record_sndio_wave(EST_Wave &inwave, EST_Option &al)
  203. {
  204. struct sio_hdl *hdl;
  205. struct sio_par par;
  206. int sample_rate = 16000; // egcs needs the initialized for some reason
  207. short *waveform;
  208. short *waveform2 = NULL;
  209. int num_samples;
  210. int i,r,n;
  211. char *audiodevice = NULL;
  212. if (al.present("-audiodevice"))
  213. audiodevice = al.val("-audiodevice");
  214. sample_rate = al.ival("-sample_rate");
  215. if ((hdl = sio_open(audiodevice, SIO_REC, 0)) == NULL) {
  216. cerr << aud_sys_name << ": error opening device" << endl;
  217. return -1;
  218. }
  219. sio_initpar(&par);
  220. par.rate = sample_rate;
  221. par.rchan = 1;
  222. par.bits = 16;
  223. par.sig = 1;
  224. par.le = SIO_LE_NATIVE;
  225. if (!sio_setpar(hdl, &par) || !sio_getpar(hdl, &par)) {
  226. cerr << aud_sys_name << ": error configuring parameters" << endl;
  227. return -1;
  228. }
  229. if ((par.rchan != 1 && par.rchan != 2) ||
  230. !((par.bits == 16 && par.sig == 1) ||
  231. (par.bits == 8 && par.sig == 0)) ||
  232. par.rate != sample_rate) {
  233. cerr << aud_sys_name << ": could not set appropriate parameters" << endl;
  234. return -1;
  235. }
  236. if (!sio_start(hdl)) {
  237. cerr << aud_sys_name << ": could not start sudio" << endl;
  238. return -1;
  239. }
  240. if (par.rchan == 2)
  241. stereo_only = 1;
  242. inwave.resize((int)(sample_rate * al.fval("-time")));
  243. inwave.set_sample_rate(sample_rate);
  244. num_samples = inwave.num_samples();
  245. waveform = inwave.values().memory();
  246. if (par.bits == 16) {
  247. // We assume that the device returns audio in native byte order
  248. // by default
  249. if (stereo_only) {
  250. waveform2 = walloc(short, num_samples * 2);
  251. num_samples *= 2;
  252. } else
  253. waveform2 = waveform;
  254. for (i = 0; i < num_samples; i+= r) {
  255. if (num_samples > i+AUDIOBUFFSIZE)
  256. n = AUDIOBUFFSIZE;
  257. else
  258. n = num_samples-i;
  259. r = sio_read(hdl, &waveform2[i], n * 2);
  260. r /= 2;
  261. if (r == 0 && sio_eof(hdl)) {
  262. cerr << aud_sys_name << ": failed to read from audio device"
  263. << endl;
  264. sio_close(hdl);
  265. return -1;
  266. }
  267. }
  268. } else {
  269. unsigned char *u8wave = walloc(unsigned char, num_samples);
  270. for (i = 0; i < num_samples; i += r) {
  271. if (num_samples > i+AUDIOBUFFSIZE)
  272. n = AUDIOBUFFSIZE;
  273. else
  274. n = num_samples - i;
  275. r = sio_read(hdl, &u8wave[i], n);
  276. if (r == 0 && sio_eof(hdl)) {
  277. cerr << aud_sys_name << ": failed to read from audio device"
  278. << endl;
  279. sio_close(hdl);
  280. wfree(u8wave);
  281. return -1;
  282. }
  283. }
  284. uchar_to_short(u8wave, waveform, num_samples);
  285. wfree(u8wave);
  286. }
  287. if (stereo_only) {
  288. for (i = 0; i < num_samples; i += 2)
  289. waveform[i / 2] = waveform2[i];
  290. wfree(waveform2);
  291. }
  292. sio_close(hdl);
  293. return 0;
  294. }
  295. #else
  296. int sndio_supported = FALSE;
  297. int
  298. play_sndio_wave(EST_Wave &inwave, EST_Option &al)
  299. {
  300. (void)inwave;
  301. (void)al;
  302. cerr << "Audio: sndio not compiled in this version" << endl;
  303. return -1;
  304. }
  305. int
  306. record_sndio_wave(EST_Wave &inwave, EST_Option &al)
  307. {
  308. (void)inwave;
  309. (void)al;
  310. cerr << "Audio: sndio not compiled in this version" << endl;
  311. return -1;
  312. }
  313. #endif