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.

1098 lines
30KB

  1. /*
  2. ** Copyright (c) 1999-2016, Erik de Castro Lopo <erikd@mega-nerd.com>
  3. ** All rights reserved.
  4. **
  5. ** This code is released under 2-clause BSD license. Please see the
  6. ** file at : https://github.com/erikd/libsamplerate/blob/master/COPYING
  7. */
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11. #include <unistd.h>
  12. #include <config.h>
  13. #include "audio_out.h"
  14. #if HAVE_ALSA_ASOUNDLIB_H
  15. #define ALSA_PCM_NEW_HW_PARAMS_API
  16. #define ALSA_PCM_NEW_SW_PARAMS_API
  17. #include <alsa/asoundlib.h>
  18. #include <sys/time.h>
  19. #endif
  20. #if (HAVE_SNDFILE)
  21. #include <float_cast.h>
  22. #include <sndfile.h>
  23. #define BUFFER_LEN (2048)
  24. #define MAKE_MAGIC(a,b,c,d,e,f,g,h) \
  25. ((a) + ((b) << 1) + ((c) << 2) + ((d) << 3) + ((e) << 4) + ((f) << 5) + ((g) << 6) + ((h) << 7))
  26. typedef struct AUDIO_OUT_s
  27. { int magic ;
  28. } AUDIO_OUT ;
  29. /*------------------------------------------------------------------------------
  30. ** Linux (ALSA and OSS) functions for playing a sound.
  31. */
  32. #if defined (__linux__)
  33. #if HAVE_ALSA_ASOUNDLIB_H
  34. #define ALSA_MAGIC MAKE_MAGIC ('L', 'n', 'x', '-', 'A', 'L', 'S', 'A')
  35. typedef struct
  36. { int magic ;
  37. snd_pcm_t * dev ;
  38. int channels ;
  39. } ALSA_AUDIO_OUT ;
  40. static int alsa_write_float (snd_pcm_t *alsa_dev, float *data, int frames, int channels) ;
  41. static AUDIO_OUT *
  42. alsa_open (int channels, unsigned samplerate)
  43. { ALSA_AUDIO_OUT *alsa_out ;
  44. const char * device = "default" ;
  45. snd_pcm_hw_params_t *hw_params ;
  46. snd_pcm_uframes_t buffer_size ;
  47. snd_pcm_uframes_t alsa_period_size, alsa_buffer_frames ;
  48. snd_pcm_sw_params_t *sw_params ;
  49. int err ;
  50. alsa_period_size = 1024 ;
  51. alsa_buffer_frames = 4 * alsa_period_size ;
  52. if ((alsa_out = calloc (1, sizeof (ALSA_AUDIO_OUT))) == NULL)
  53. { perror ("alsa_open : malloc ") ;
  54. exit (1) ;
  55. } ;
  56. alsa_out->magic = ALSA_MAGIC ;
  57. alsa_out->channels = channels ;
  58. if ((err = snd_pcm_open (&alsa_out->dev, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0)
  59. { fprintf (stderr, "cannot open audio device \"%s\" (%s)\n", device, snd_strerror (err)) ;
  60. goto catch_error ;
  61. } ;
  62. snd_pcm_nonblock (alsa_out->dev, 0) ;
  63. if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0)
  64. { fprintf (stderr, "cannot allocate hardware parameter structure (%s)\n", snd_strerror (err)) ;
  65. goto catch_error ;
  66. } ;
  67. if ((err = snd_pcm_hw_params_any (alsa_out->dev, hw_params)) < 0)
  68. { fprintf (stderr, "cannot initialize hardware parameter structure (%s)\n", snd_strerror (err)) ;
  69. goto catch_error ;
  70. } ;
  71. if ((err = snd_pcm_hw_params_set_access (alsa_out->dev, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
  72. { fprintf (stderr, "cannot set access type (%s)\n", snd_strerror (err)) ;
  73. goto catch_error ;
  74. } ;
  75. if ((err = snd_pcm_hw_params_set_format (alsa_out->dev, hw_params, SND_PCM_FORMAT_FLOAT)) < 0)
  76. { fprintf (stderr, "cannot set sample format (%s)\n", snd_strerror (err)) ;
  77. goto catch_error ;
  78. } ;
  79. if ((err = snd_pcm_hw_params_set_rate_near (alsa_out->dev, hw_params, &samplerate, 0)) < 0)
  80. { fprintf (stderr, "cannot set sample rate (%s)\n", snd_strerror (err)) ;
  81. goto catch_error ;
  82. } ;
  83. if ((err = snd_pcm_hw_params_set_channels (alsa_out->dev, hw_params, channels)) < 0)
  84. { fprintf (stderr, "cannot set channel count (%s)\n", snd_strerror (err)) ;
  85. goto catch_error ;
  86. } ;
  87. if ((err = snd_pcm_hw_params_set_buffer_size_near (alsa_out->dev, hw_params, &alsa_buffer_frames)) < 0)
  88. { fprintf (stderr, "cannot set buffer size (%s)\n", snd_strerror (err)) ;
  89. goto catch_error ;
  90. } ;
  91. if ((err = snd_pcm_hw_params_set_period_size_near (alsa_out->dev, hw_params, &alsa_period_size, 0)) < 0)
  92. { fprintf (stderr, "cannot set period size (%s)\n", snd_strerror (err)) ;
  93. goto catch_error ;
  94. } ;
  95. if ((err = snd_pcm_hw_params (alsa_out->dev, hw_params)) < 0)
  96. { fprintf (stderr, "cannot set parameters (%s)\n", snd_strerror (err)) ;
  97. goto catch_error ;
  98. } ;
  99. /* extra check: if we have only one period, this code won't work */
  100. snd_pcm_hw_params_get_period_size (hw_params, &alsa_period_size, 0) ;
  101. snd_pcm_hw_params_get_buffer_size (hw_params, &buffer_size) ;
  102. if (alsa_period_size == buffer_size)
  103. { fprintf (stderr, "Can't use period equal to buffer size (%lu == %lu)", alsa_period_size, buffer_size) ;
  104. goto catch_error ;
  105. } ;
  106. snd_pcm_hw_params_free (hw_params) ;
  107. if ((err = snd_pcm_sw_params_malloc (&sw_params)) != 0)
  108. { fprintf (stderr, "%s: snd_pcm_sw_params_malloc: %s", __func__, snd_strerror (err)) ;
  109. goto catch_error ;
  110. } ;
  111. if ((err = snd_pcm_sw_params_current (alsa_out->dev, sw_params)) != 0)
  112. { fprintf (stderr, "%s: snd_pcm_sw_params_current: %s", __func__, snd_strerror (err)) ;
  113. goto catch_error ;
  114. } ;
  115. /* note: set start threshold to delay start until the ring buffer is full */
  116. snd_pcm_sw_params_current (alsa_out->dev, sw_params) ;
  117. if ((err = snd_pcm_sw_params_set_start_threshold (alsa_out->dev, sw_params, buffer_size)) < 0)
  118. { fprintf (stderr, "cannot set start threshold (%s)\n", snd_strerror (err)) ;
  119. goto catch_error ;
  120. } ;
  121. if ((err = snd_pcm_sw_params (alsa_out->dev, sw_params)) != 0)
  122. { fprintf (stderr, "%s: snd_pcm_sw_params: %s", __func__, snd_strerror (err)) ;
  123. goto catch_error ;
  124. } ;
  125. snd_pcm_sw_params_free (sw_params) ;
  126. snd_pcm_reset (alsa_out->dev) ;
  127. catch_error :
  128. if (err < 0 && alsa_out->dev != NULL)
  129. { snd_pcm_close (alsa_out->dev) ;
  130. return NULL ;
  131. } ;
  132. return (AUDIO_OUT *) alsa_out ;
  133. } /* alsa_open */
  134. static void
  135. alsa_play (get_audio_callback_t callback, AUDIO_OUT *audio_out, void *callback_data)
  136. { static float buffer [BUFFER_LEN] ;
  137. ALSA_AUDIO_OUT *alsa_out ;
  138. int read_frames ;
  139. if ((alsa_out = (ALSA_AUDIO_OUT*) audio_out) == NULL)
  140. { printf ("alsa_close : AUDIO_OUT is NULL.\n") ;
  141. return ;
  142. } ;
  143. if (alsa_out->magic != ALSA_MAGIC)
  144. { printf ("alsa_close : Bad magic number.\n") ;
  145. return ;
  146. } ;
  147. while ((read_frames = callback (callback_data, buffer, BUFFER_LEN / alsa_out->channels)))
  148. alsa_write_float (alsa_out->dev, buffer, read_frames, alsa_out->channels) ;
  149. return ;
  150. } /* alsa_play */
  151. static int
  152. alsa_write_float (snd_pcm_t *alsa_dev, float *data, int frames, int channels)
  153. { static int epipe_count = 0 ;
  154. int total = 0 ;
  155. int retval ;
  156. if (epipe_count > 0)
  157. epipe_count -- ;
  158. while (total < frames)
  159. { retval = snd_pcm_writei (alsa_dev, data + total * channels, frames - total) ;
  160. if (retval >= 0)
  161. { total += retval ;
  162. if (total == frames)
  163. return total ;
  164. continue ;
  165. } ;
  166. switch (retval)
  167. { case -EAGAIN :
  168. puts ("alsa_write_float: EAGAIN") ;
  169. continue ;
  170. break ;
  171. case -EPIPE :
  172. if (epipe_count > 0)
  173. { printf ("alsa_write_float: EPIPE %d\n", epipe_count) ;
  174. if (epipe_count > 140)
  175. return retval ;
  176. } ;
  177. epipe_count += 100 ;
  178. #if 0
  179. if (0)
  180. { snd_pcm_status_t *status ;
  181. snd_pcm_status_alloca (&status) ;
  182. if ((retval = snd_pcm_status (alsa_dev, status)) < 0)
  183. fprintf (stderr, "alsa_out: xrun. can't determine length\n") ;
  184. else if (snd_pcm_status_get_state (status) == SND_PCM_STATE_XRUN)
  185. { struct timeval now, diff, tstamp ;
  186. gettimeofday (&now, 0) ;
  187. snd_pcm_status_get_trigger_tstamp (status, &tstamp) ;
  188. timersub (&now, &tstamp, &diff) ;
  189. fprintf (stderr, "alsa_write_float xrun: of at least %.3f msecs. resetting stream\n",
  190. diff.tv_sec * 1000 + diff.tv_usec / 1000.0) ;
  191. }
  192. else
  193. fprintf (stderr, "alsa_write_float: xrun. can't determine length\n") ;
  194. } ;
  195. #endif
  196. snd_pcm_prepare (alsa_dev) ;
  197. break ;
  198. case -EBADFD :
  199. fprintf (stderr, "alsa_write_float: Bad PCM state.n") ;
  200. return 0 ;
  201. break ;
  202. case -ESTRPIPE :
  203. fprintf (stderr, "alsa_write_float: Suspend event.n") ;
  204. return 0 ;
  205. break ;
  206. case -EIO :
  207. puts ("alsa_write_float: EIO") ;
  208. return 0 ;
  209. default :
  210. fprintf (stderr, "alsa_write_float: retval = %d\n", retval) ;
  211. return 0 ;
  212. break ;
  213. } ; /* switch */
  214. } ; /* while */
  215. return total ;
  216. } /* alsa_write_float */
  217. static void
  218. alsa_close (AUDIO_OUT *audio_out)
  219. { ALSA_AUDIO_OUT *alsa_out ;
  220. if ((alsa_out = (ALSA_AUDIO_OUT*) audio_out) == NULL)
  221. { printf ("alsa_close : AUDIO_OUT is NULL.\n") ;
  222. return ;
  223. } ;
  224. if (alsa_out->magic != ALSA_MAGIC)
  225. { printf ("alsa_close : Bad magic number.\n") ;
  226. return ;
  227. } ;
  228. memset (alsa_out, 0, sizeof (ALSA_AUDIO_OUT)) ;
  229. free (alsa_out) ;
  230. return ;
  231. } /* alsa_close */
  232. #endif /* HAVE_ALSA_ASOUNDLIB_H */
  233. #include <fcntl.h>
  234. #include <sys/ioctl.h>
  235. #include <sys/soundcard.h>
  236. #define OSS_MAGIC MAKE_MAGIC ('L', 'i', 'n', 'u', 'x', 'O', 'S', 'S')
  237. typedef struct
  238. { int magic ;
  239. int fd ;
  240. int channels ;
  241. } OSS_AUDIO_OUT ;
  242. static AUDIO_OUT *opensoundsys_open (int channels, int samplerate) ;
  243. static void opensoundsys_play (get_audio_callback_t callback, AUDIO_OUT *audio_out, void *callback_data) ;
  244. static void opensoundsys_close (AUDIO_OUT *audio_out) ;
  245. static AUDIO_OUT *
  246. opensoundsys_open (int channels, int samplerate)
  247. { OSS_AUDIO_OUT *opensoundsys_out ;
  248. int stereo, fmt, error ;
  249. if ((opensoundsys_out = calloc (1, sizeof (OSS_AUDIO_OUT))) == NULL)
  250. { perror ("opensoundsys_open : malloc ") ;
  251. exit (1) ;
  252. } ;
  253. opensoundsys_out->magic = OSS_MAGIC ;
  254. opensoundsys_out->channels = channels ;
  255. if ((opensoundsys_out->fd = open ("/dev/dsp", O_WRONLY, 0)) == -1)
  256. { perror ("opensoundsys_open : open ") ;
  257. exit (1) ;
  258. } ;
  259. stereo = 0 ;
  260. if (ioctl (opensoundsys_out->fd, SNDCTL_DSP_STEREO, &stereo) == -1)
  261. { /* Fatal error */
  262. perror ("opensoundsys_open : stereo ") ;
  263. exit (1) ;
  264. } ;
  265. if (ioctl (opensoundsys_out->fd, SNDCTL_DSP_RESET, 0))
  266. { perror ("opensoundsys_open : reset ") ;
  267. exit (1) ;
  268. } ;
  269. fmt = CPU_IS_BIG_ENDIAN ? AFMT_S16_BE : AFMT_S16_LE ;
  270. if (ioctl (opensoundsys_out->fd, SNDCTL_DSP_SETFMT, &fmt) != 0)
  271. { perror ("opensoundsys_open_dsp_device : set format ") ;
  272. exit (1) ;
  273. } ;
  274. if ((error = ioctl (opensoundsys_out->fd, SNDCTL_DSP_CHANNELS, &channels)) != 0)
  275. { perror ("opensoundsys_open : channels ") ;
  276. exit (1) ;
  277. } ;
  278. if ((error = ioctl (opensoundsys_out->fd, SNDCTL_DSP_SPEED, &samplerate)) != 0)
  279. { perror ("opensoundsys_open : sample rate ") ;
  280. exit (1) ;
  281. } ;
  282. if ((error = ioctl (opensoundsys_out->fd, SNDCTL_DSP_SYNC, 0)) != 0)
  283. { perror ("opensoundsys_open : sync ") ;
  284. exit (1) ;
  285. } ;
  286. return (AUDIO_OUT*) opensoundsys_out ;
  287. } /* opensoundsys_open */
  288. static void
  289. opensoundsys_play (get_audio_callback_t callback, AUDIO_OUT *audio_out, void *callback_data)
  290. { OSS_AUDIO_OUT *opensoundsys_out ;
  291. static float float_buffer [BUFFER_LEN] ;
  292. static short buffer [BUFFER_LEN] ;
  293. int k, read_frames ;
  294. if ((opensoundsys_out = (OSS_AUDIO_OUT*) audio_out) == NULL)
  295. { printf ("opensoundsys_play : AUDIO_OUT is NULL.\n") ;
  296. return ;
  297. } ;
  298. if (opensoundsys_out->magic != OSS_MAGIC)
  299. { printf ("opensoundsys_play : Bad magic number.\n") ;
  300. return ;
  301. } ;
  302. while ((read_frames = callback (callback_data, float_buffer, BUFFER_LEN / opensoundsys_out->channels)))
  303. { for (k = 0 ; k < read_frames * opensoundsys_out->channels ; k++)
  304. buffer [k] = lrint (32767.0 * float_buffer [k]) ;
  305. (void) write (opensoundsys_out->fd, buffer, read_frames * opensoundsys_out->channels * sizeof (short)) ;
  306. } ;
  307. return ;
  308. } /* opensoundsys_play */
  309. static void
  310. opensoundsys_close (AUDIO_OUT *audio_out)
  311. { OSS_AUDIO_OUT *opensoundsys_out ;
  312. if ((opensoundsys_out = (OSS_AUDIO_OUT*) audio_out) == NULL)
  313. { printf ("opensoundsys_close : AUDIO_OUT is NULL.\n") ;
  314. return ;
  315. } ;
  316. if (opensoundsys_out->magic != OSS_MAGIC)
  317. { printf ("opensoundsys_close : Bad magic number.\n") ;
  318. return ;
  319. } ;
  320. memset (opensoundsys_out, 0, sizeof (OSS_AUDIO_OUT)) ;
  321. free (opensoundsys_out) ;
  322. return ;
  323. } /* opensoundsys_close */
  324. #endif /* __linux__ */
  325. /*------------------------------------------------------------------------------
  326. ** Mac OS X functions for playing a sound.
  327. */
  328. #if (defined (__MACH__) && defined (__APPLE__)) /* MacOSX */
  329. #include <Carbon.h>
  330. #include <CoreAudio/AudioHardware.h>
  331. #define MACOSX_MAGIC MAKE_MAGIC ('M', 'a', 'c', ' ', 'O', 'S', ' ', 'X')
  332. typedef struct
  333. { int magic ;
  334. AudioStreamBasicDescription format ;
  335. UInt32 buf_size ;
  336. AudioDeviceID device ;
  337. int channels ;
  338. int samplerate ;
  339. int buffer_size ;
  340. int done_playing ;
  341. get_audio_callback_t callback ;
  342. void *callback_data ;
  343. } MACOSX_AUDIO_OUT ;
  344. static AUDIO_OUT *macosx_open (int channels, int samplerate) ;
  345. static void macosx_play (get_audio_callback_t callback, AUDIO_OUT *audio_out, void *callback_data) ;
  346. static void macosx_close (AUDIO_OUT *audio_out) ;
  347. static OSStatus
  348. macosx_audio_out_callback (AudioDeviceID device, const AudioTimeStamp* current_time,
  349. const AudioBufferList* data_in, const AudioTimeStamp* time_in,
  350. AudioBufferList* data_out, const AudioTimeStamp* time_out, void* client_data) ;
  351. static AUDIO_OUT *
  352. macosx_open (int channels, int samplerate)
  353. { MACOSX_AUDIO_OUT *macosx_out ;
  354. OSStatus err ;
  355. size_t count ;
  356. if ((macosx_out = calloc (1, sizeof (MACOSX_AUDIO_OUT))) == NULL)
  357. { perror ("macosx_open : malloc ") ;
  358. exit (1) ;
  359. } ;
  360. macosx_out->magic = MACOSX_MAGIC ;
  361. macosx_out->channels = channels ;
  362. macosx_out->samplerate = samplerate ;
  363. macosx_out->device = kAudioDeviceUnknown ;
  364. /* get the default output device for the HAL */
  365. count = sizeof (AudioDeviceID) ;
  366. if ((err = AudioHardwareGetProperty (kAudioHardwarePropertyDefaultOutputDevice,
  367. &count, (void *) &(macosx_out->device))) != noErr)
  368. { printf ("AudioHardwareGetProperty failed.\n") ;
  369. free (macosx_out) ;
  370. return NULL ;
  371. } ;
  372. /* get the buffersize that the default device uses for IO */
  373. count = sizeof (UInt32) ;
  374. if ((err = AudioDeviceGetProperty (macosx_out->device, 0, false, kAudioDevicePropertyBufferSize,
  375. &count, &(macosx_out->buffer_size))) != noErr)
  376. { printf ("AudioDeviceGetProperty (AudioDeviceGetProperty) failed.\n") ;
  377. free (macosx_out) ;
  378. return NULL ;
  379. } ;
  380. /* get a description of the data format used by the default device */
  381. count = sizeof (AudioStreamBasicDescription) ;
  382. if ((err = AudioDeviceGetProperty (macosx_out->device, 0, false, kAudioDevicePropertyStreamFormat,
  383. &count, &(macosx_out->format))) != noErr)
  384. { printf ("AudioDeviceGetProperty (kAudioDevicePropertyStreamFormat) failed.\n") ;
  385. free (macosx_out) ;
  386. return NULL ;
  387. } ;
  388. macosx_out->format.mSampleRate = samplerate ;
  389. macosx_out->format.mChannelsPerFrame = channels ;
  390. if ((err = AudioDeviceSetProperty (macosx_out->device, NULL, 0, false, kAudioDevicePropertyStreamFormat,
  391. sizeof (AudioStreamBasicDescription), &(macosx_out->format))) != noErr)
  392. { printf ("AudioDeviceSetProperty (kAudioDevicePropertyStreamFormat) failed.\n") ;
  393. free (macosx_out) ;
  394. return NULL ;
  395. } ;
  396. /* we want linear pcm */
  397. if (macosx_out->format.mFormatID != kAudioFormatLinearPCM)
  398. { free (macosx_out) ;
  399. return NULL ;
  400. } ;
  401. macosx_out->done_playing = 0 ;
  402. /* Fire off the device. */
  403. if ((err = AudioDeviceAddIOProc (macosx_out->device, macosx_audio_out_callback,
  404. (void *) macosx_out)) != noErr)
  405. { printf ("AudioDeviceAddIOProc failed.\n") ;
  406. free (macosx_out) ;
  407. return NULL ;
  408. } ;
  409. return (MACOSX_AUDIO_OUT *) macosx_out ;
  410. } /* macosx_open */
  411. static void
  412. macosx_play (get_audio_callback_t callback, AUDIO_OUT *audio_out, void *callback_data)
  413. { MACOSX_AUDIO_OUT *macosx_out ;
  414. OSStatus err ;
  415. if ((macosx_out = (MACOSX_AUDIO_OUT*) audio_out) == NULL)
  416. { printf ("macosx_play : AUDIO_OUT is NULL.\n") ;
  417. return ;
  418. } ;
  419. if (macosx_out->magic != MACOSX_MAGIC)
  420. { printf ("macosx_play : Bad magic number.\n") ;
  421. return ;
  422. } ;
  423. /* Set the callback function and callback data. */
  424. macosx_out->callback = callback ;
  425. macosx_out->callback_data = callback_data ;
  426. err = AudioDeviceStart (macosx_out->device, macosx_audio_out_callback) ;
  427. if (err != noErr)
  428. printf ("AudioDeviceStart failed.\n") ;
  429. while (macosx_out->done_playing == SF_FALSE)
  430. usleep (10 * 1000) ; /* 10 000 milliseconds. */
  431. return ;
  432. } /* macosx_play */
  433. static void
  434. macosx_close (AUDIO_OUT *audio_out)
  435. { MACOSX_AUDIO_OUT *macosx_out ;
  436. OSStatus err ;
  437. if ((macosx_out = (MACOSX_AUDIO_OUT*) audio_out) == NULL)
  438. { printf ("macosx_close : AUDIO_OUT is NULL.\n") ;
  439. return ;
  440. } ;
  441. if (macosx_out->magic != MACOSX_MAGIC)
  442. { printf ("macosx_close : Bad magic number.\n") ;
  443. return ;
  444. } ;
  445. if ((err = AudioDeviceStop (macosx_out->device, macosx_audio_out_callback)) != noErr)
  446. { printf ("AudioDeviceStop failed.\n") ;
  447. return ;
  448. } ;
  449. err = AudioDeviceRemoveIOProc (macosx_out->device, macosx_audio_out_callback) ;
  450. if (err != noErr)
  451. { printf ("AudioDeviceRemoveIOProc failed.\n") ;
  452. return ;
  453. } ;
  454. } /* macosx_close */
  455. static OSStatus
  456. macosx_audio_out_callback (AudioDeviceID device, const AudioTimeStamp* current_time,
  457. const AudioBufferList* data_in, const AudioTimeStamp* time_in,
  458. AudioBufferList* data_out, const AudioTimeStamp* time_out, void* client_data)
  459. { MACOSX_AUDIO_OUT *macosx_out ;
  460. int k, size, frame_count, read_count ;
  461. float *buffer ;
  462. if ((macosx_out = (MACOSX_AUDIO_OUT*) client_data) == NULL)
  463. { printf ("macosx_play : AUDIO_OUT is NULL.\n") ;
  464. return 42 ;
  465. } ;
  466. if (macosx_out->magic != MACOSX_MAGIC)
  467. { printf ("macosx_play : Bad magic number.\n") ;
  468. return 42 ;
  469. } ;
  470. size = data_out->mBuffers [0].mDataByteSize ;
  471. frame_count = size / sizeof (float) / macosx_out->channels ;
  472. buffer = (float*) data_out->mBuffers [0].mData ;
  473. read_count = macosx_out->callback (macosx_out->callback_data, buffer, frame_count) ;
  474. if (read_count < frame_count)
  475. { memset (&(buffer [read_count]), 0, (frame_count - read_count) * sizeof (float)) ;
  476. macosx_out->done_playing = 1 ;
  477. } ;
  478. return noErr ;
  479. } /* macosx_audio_out_callback */
  480. #endif /* MacOSX */
  481. /*------------------------------------------------------------------------------
  482. ** Win32 functions for playing a sound.
  483. **
  484. ** This API sucks. Its needlessly complicated and is *WAY* too loose with
  485. ** passing pointers arounf in integers and and using char* pointers to
  486. ** point to data instead of short*. It plain sucks!
  487. */
  488. #if (defined (_WIN32) || defined (WIN32))
  489. #include <windows.h>
  490. #include <mmsystem.h>
  491. #define WIN32_BUFFER_LEN (1<<15)
  492. #define WIN32_MAGIC MAKE_MAGIC ('W', 'i', 'n', '3', '2', 's', 'u', 'x')
  493. typedef struct
  494. { int magic ;
  495. HWAVEOUT hwave ;
  496. WAVEHDR whdr [2] ;
  497. HANDLE Event ;
  498. short short_buffer [WIN32_BUFFER_LEN / sizeof (short)] ;
  499. float float_buffer [WIN32_BUFFER_LEN / sizeof (short) / 2] ;
  500. int bufferlen, current ;
  501. int channels ;
  502. get_audio_callback_t callback ;
  503. void *callback_data ;
  504. } WIN32_AUDIO_OUT ;
  505. static AUDIO_OUT *win32_open (int channels, int samplerate) ;
  506. static void win32_play (get_audio_callback_t callback, AUDIO_OUT *audio_out, void *callback_data) ;
  507. static void win32_close (AUDIO_OUT *audio_out) ;
  508. static DWORD CALLBACK
  509. win32_audio_out_callback (HWAVEOUT hwave, UINT msg, DWORD data, DWORD param1, DWORD param2) ;
  510. static AUDIO_OUT*
  511. win32_open (int channels, int samplerate)
  512. { WIN32_AUDIO_OUT *win32_out ;
  513. WAVEFORMATEX wf ;
  514. int error ;
  515. if ((win32_out = calloc (1, sizeof (WIN32_AUDIO_OUT))) == NULL)
  516. { perror ("win32_open : malloc ") ;
  517. exit (1) ;
  518. } ;
  519. win32_out->magic = WIN32_MAGIC ;
  520. win32_out->channels = channels ;
  521. win32_out->current = 0 ;
  522. win32_out->Event = CreateEvent (0, FALSE, FALSE, 0) ;
  523. wf.nChannels = channels ;
  524. wf.nSamplesPerSec = samplerate ;
  525. wf.nBlockAlign = channels * sizeof (short) ;
  526. wf.wFormatTag = WAVE_FORMAT_PCM ;
  527. wf.cbSize = 0 ;
  528. wf.wBitsPerSample = 16 ;
  529. wf.nAvgBytesPerSec = wf.nBlockAlign * wf.nSamplesPerSec ;
  530. error = waveOutOpen (&(win32_out->hwave), WAVE_MAPPER, &wf, (DWORD) win32_audio_out_callback,
  531. (DWORD) win32_out, CALLBACK_FUNCTION) ;
  532. if (error)
  533. { puts ("waveOutOpen failed.") ;
  534. free (win32_out) ;
  535. return NULL ;
  536. } ;
  537. waveOutPause (win32_out->hwave) ;
  538. return (WIN32_AUDIO_OUT *) win32_out ;
  539. } /* win32_open */
  540. static void
  541. win32_play (get_audio_callback_t callback, AUDIO_OUT *audio_out, void *callback_data)
  542. { WIN32_AUDIO_OUT *win32_out ;
  543. int error ;
  544. if ((win32_out = (WIN32_AUDIO_OUT*) audio_out) == NULL)
  545. { printf ("win32_play : AUDIO_OUT is NULL.\n") ;
  546. return ;
  547. } ;
  548. if (win32_out->magic != WIN32_MAGIC)
  549. { printf ("win32_play : Bad magic number (%d %d).\n", win32_out->magic, WIN32_MAGIC) ;
  550. return ;
  551. } ;
  552. /* Set the callback function and callback data. */
  553. win32_out->callback = callback ;
  554. win32_out->callback_data = callback_data ;
  555. win32_out->whdr [0].lpData = (char*) win32_out->short_buffer ;
  556. win32_out->whdr [1].lpData = ((char*) win32_out->short_buffer) + sizeof (win32_out->short_buffer) / 2 ;
  557. win32_out->whdr [0].dwBufferLength = sizeof (win32_out->short_buffer) / 2 ;
  558. win32_out->whdr [1].dwBufferLength = sizeof (win32_out->short_buffer) / 2 ;
  559. win32_out->bufferlen = sizeof (win32_out->short_buffer) / 2 / sizeof (short) ;
  560. /* Prepare the WAVEHDRs */
  561. if ((error = waveOutPrepareHeader (win32_out->hwave, &(win32_out->whdr [0]), sizeof (WAVEHDR))))
  562. { printf ("waveOutPrepareHeader [0] failed : %08X\n", error) ;
  563. waveOutClose (win32_out->hwave) ;
  564. return ;
  565. } ;
  566. if ((error = waveOutPrepareHeader (win32_out->hwave, &(win32_out->whdr [1]), sizeof (WAVEHDR))))
  567. { printf ("waveOutPrepareHeader [1] failed : %08X\n", error) ;
  568. waveOutUnprepareHeader (win32_out->hwave, &(win32_out->whdr [0]), sizeof (WAVEHDR)) ;
  569. waveOutClose (win32_out->hwave) ;
  570. return ;
  571. } ;
  572. waveOutRestart (win32_out->hwave) ;
  573. /* Fake 2 calls to the callback function to queue up enough audio. */
  574. win32_audio_out_callback (0, MM_WOM_DONE, (DWORD) win32_out, 0, 0) ;
  575. win32_audio_out_callback (0, MM_WOM_DONE, (DWORD) win32_out, 0, 0) ;
  576. /* Wait for playback to finish. The callback notifies us when all
  577. ** wave data has been played.
  578. */
  579. WaitForSingleObject (win32_out->Event, INFINITE) ;
  580. waveOutPause (win32_out->hwave) ;
  581. waveOutReset (win32_out->hwave) ;
  582. waveOutUnprepareHeader (win32_out->hwave, &(win32_out->whdr [0]), sizeof (WAVEHDR)) ;
  583. waveOutUnprepareHeader (win32_out->hwave, &(win32_out->whdr [1]), sizeof (WAVEHDR)) ;
  584. waveOutClose (win32_out->hwave) ;
  585. win32_out->hwave = 0 ;
  586. return ;
  587. } /* win32_play */
  588. static void
  589. win32_close (AUDIO_OUT *audio_out)
  590. { WIN32_AUDIO_OUT *win32_out ;
  591. if ((win32_out = (WIN32_AUDIO_OUT*) audio_out) == NULL)
  592. { printf ("win32_close : AUDIO_OUT is NULL.\n") ;
  593. return ;
  594. } ;
  595. if (win32_out->magic != WIN32_MAGIC)
  596. { printf ("win32_close : Bad magic number.\n") ;
  597. return ;
  598. } ;
  599. memset (win32_out, 0, sizeof (WIN32_AUDIO_OUT)) ;
  600. free (win32_out) ;
  601. } /* win32_close */
  602. static DWORD CALLBACK
  603. win32_audio_out_callback (HWAVEOUT hwave, UINT msg, DWORD data, DWORD param1, DWORD param2)
  604. { WIN32_AUDIO_OUT *win32_out ;
  605. int read_count, frame_count, k ;
  606. short *sptr ;
  607. /*
  608. ** I consider this technique of passing a pointer via an integer as
  609. ** fundamentally broken but thats the way microsoft has defined the
  610. ** interface.
  611. */
  612. if ((win32_out = (WIN32_AUDIO_OUT*) data) == NULL)
  613. { printf ("win32_audio_out_callback : AUDIO_OUT is NULL.\n") ;
  614. return 1 ;
  615. } ;
  616. if (win32_out->magic != WIN32_MAGIC)
  617. { printf ("win32_audio_out_callback : Bad magic number (%d %d).\n", win32_out->magic, WIN32_MAGIC) ;
  618. return 1 ;
  619. } ;
  620. if (msg != MM_WOM_DONE)
  621. return 0 ;
  622. /* Do the actual audio. */
  623. sample_count = win32_out->bufferlen ;
  624. frame_count = sample_count / win32_out->channels ;
  625. read_count = win32_out->callback (win32_out->callback_data, win32_out->float_buffer, frame_count) ;
  626. sptr = (short*) win32_out->whdr [win32_out->current].lpData ;
  627. for (k = 0 ; k < read_count ; k++)
  628. sptr [k] = lrint (32767.0 * win32_out->float_buffer [k]) ;
  629. if (read_count > 0)
  630. { /* Fix buffer length is only a partial block. */
  631. if (read_count * sizeof (short) < win32_out->bufferlen)
  632. win32_out->whdr [win32_out->current].dwBufferLength = read_count * sizeof (short) ;
  633. /* Queue the WAVEHDR */
  634. waveOutWrite (win32_out->hwave, (LPWAVEHDR) &(win32_out->whdr [win32_out->current]), sizeof (WAVEHDR)) ;
  635. }
  636. else
  637. { /* Stop playback */
  638. waveOutPause (win32_out->hwave) ;
  639. SetEvent (win32_out->Event) ;
  640. } ;
  641. win32_out->current = (win32_out->current + 1) % 2 ;
  642. return 0 ;
  643. } /* win32_audio_out_callback */
  644. #endif /* Win32 */
  645. /*------------------------------------------------------------------------------
  646. ** Solaris.
  647. */
  648. #if (defined (sun) && defined (unix)) /* ie Solaris */
  649. #include <fcntl.h>
  650. #include <sys/ioctl.h>
  651. #include <sys/audioio.h>
  652. #define SOLARIS_MAGIC MAKE_MAGIC ('S', 'o', 'l', 'a', 'r', 'i', 's', ' ')
  653. typedef struct
  654. { int magic ;
  655. int fd ;
  656. int channels ;
  657. int samplerate ;
  658. } SOLARIS_AUDIO_OUT ;
  659. static AUDIO_OUT *solaris_open (int channels, int samplerate) ;
  660. static void solaris_play (get_audio_callback_t callback, AUDIO_OUT *audio_out, void *callback_data) ;
  661. static void solaris_close (AUDIO_OUT *audio_out) ;
  662. static AUDIO_OUT *
  663. solaris_open (int channels, int samplerate)
  664. { SOLARIS_AUDIO_OUT *solaris_out ;
  665. audio_info_t audio_info ;
  666. int error ;
  667. if ((solaris_out = calloc (1, sizeof (SOLARIS_AUDIO_OUT))) == NULL)
  668. { perror ("solaris_open : malloc ") ;
  669. exit (1) ;
  670. } ;
  671. solaris_out->magic = SOLARIS_MAGIC ;
  672. solaris_out->channels = channels ;
  673. solaris_out->samplerate = channels ;
  674. /* open the audio device - write only, non-blocking */
  675. if ((solaris_out->fd = open ("/dev/audio", O_WRONLY | O_NONBLOCK)) < 0)
  676. { perror ("open (/dev/audio) failed") ;
  677. exit (1) ;
  678. } ;
  679. /* Retrive standard values. */
  680. AUDIO_INITINFO (&audio_info) ;
  681. audio_info.play.sample_rate = samplerate ;
  682. audio_info.play.channels = channels ;
  683. audio_info.play.precision = 16 ;
  684. audio_info.play.encoding = AUDIO_ENCODING_LINEAR ;
  685. audio_info.play.gain = AUDIO_MAX_GAIN ;
  686. audio_info.play.balance = AUDIO_MID_BALANCE ;
  687. if ((error = ioctl (solaris_out->fd, AUDIO_SETINFO, &audio_info)))
  688. { perror ("ioctl (AUDIO_SETINFO) failed") ;
  689. exit (1) ;
  690. } ;
  691. return (AUDIO_OUT*) solaris_out ;
  692. } /* solaris_open */
  693. static void
  694. solaris_play (get_audio_callback_t callback, AUDIO_OUT *audio_out, void *callback_data)
  695. { SOLARIS_AUDIO_OUT *solaris_out ;
  696. static float float_buffer [BUFFER_LEN] ;
  697. static short buffer [BUFFER_LEN] ;
  698. int k, read_frames ;
  699. if ((solaris_out = (SOLARIS_AUDIO_OUT*) audio_out) == NULL)
  700. { printf ("solaris_play : AUDIO_OUT is NULL.\n") ;
  701. return ;
  702. } ;
  703. if (solaris_out->magic != SOLARIS_MAGIC)
  704. { printf ("solaris_play : Bad magic number.\n") ;
  705. return ;
  706. } ;
  707. while ((read_frames = callback (callback_data, float_buffer, BUFFER_LEN / solaris_out->channels)))
  708. { for (k = 0 ; k < read_frames * solaris_out->channels ; k++)
  709. buffer [k] = lrint (32767.0 * float_buffer [k]) ;
  710. write (solaris_out->fd, buffer, read_frames * solaris_out->channels * sizeof (short)) ;
  711. } ;
  712. return ;
  713. } /* solaris_play */
  714. static void
  715. solaris_close (AUDIO_OUT *audio_out)
  716. { SOLARIS_AUDIO_OUT *solaris_out ;
  717. if ((solaris_out = (SOLARIS_AUDIO_OUT*) audio_out) == NULL)
  718. { printf ("solaris_close : AUDIO_OUT is NULL.\n") ;
  719. return ;
  720. } ;
  721. if (solaris_out->magic != SOLARIS_MAGIC)
  722. { printf ("solaris_close : Bad magic number.\n") ;
  723. return ;
  724. } ;
  725. memset (solaris_out, 0, sizeof (SOLARIS_AUDIO_OUT)) ;
  726. free (solaris_out) ;
  727. return ;
  728. } /* solaris_close */
  729. #endif /* Solaris */
  730. /*==============================================================================
  731. ** Main function.
  732. */
  733. AUDIO_OUT *
  734. audio_open (int channels, int samplerate)
  735. {
  736. #if defined (__linux__)
  737. #if HAVE_ALSA_ASOUNDLIB_H
  738. if (access ("/proc/asound/cards", R_OK) == 0)
  739. return alsa_open (channels, samplerate) ;
  740. #endif
  741. return opensoundsys_open (channels, samplerate) ;
  742. #elif (defined (__MACH__) && defined (__APPLE__))
  743. return macosx_open (channels, samplerate) ;
  744. #elif (defined (sun) && defined (unix))
  745. return solaris_open (channels, samplerate) ;
  746. #elif (defined (_WIN32) || defined (WIN32))
  747. return win32_open (channels, samplerate) ;
  748. #else
  749. #warning "*** Playing sound not yet supported on this platform."
  750. #warning "*** Please feel free to submit a patch."
  751. printf ("Error : Playing sound not yet supported on this platform.\n") ;
  752. return NULL ;
  753. #endif
  754. return NULL ;
  755. } /* audio_open */
  756. void
  757. audio_play (get_audio_callback_t callback, AUDIO_OUT *audio_out, void *callback_data)
  758. {
  759. if (callback == NULL)
  760. { printf ("Error : bad callback pointer.\n") ;
  761. return ;
  762. } ;
  763. if (audio_out == NULL)
  764. { printf ("Error : bad audio_out pointer.\n") ;
  765. return ;
  766. } ;
  767. if (callback_data == NULL)
  768. { printf ("Error : bad callback_data pointer.\n") ;
  769. return ;
  770. } ;
  771. #if defined (__linux__)
  772. #if HAVE_ALSA_ASOUNDLIB_H
  773. if (audio_out->magic == ALSA_MAGIC)
  774. alsa_play (callback, audio_out, callback_data) ;
  775. #endif
  776. opensoundsys_play (callback, audio_out, callback_data) ;
  777. #elif (defined (__MACH__) && defined (__APPLE__))
  778. macosx_play (callback, audio_out, callback_data) ;
  779. #elif (defined (sun) && defined (unix))
  780. solaris_play (callback, audio_out, callback_data) ;
  781. #elif (defined (_WIN32) || defined (WIN32))
  782. win32_play (callback, audio_out, callback_data) ;
  783. #else
  784. #warning "*** Playing sound not yet supported on this platform."
  785. #warning "*** Please feel free to submit a patch."
  786. printf ("Error : Playing sound not yet supported on this platform.\n") ;
  787. return ;
  788. #endif
  789. return ;
  790. } /* audio_play */
  791. void
  792. audio_close (AUDIO_OUT *audio_out)
  793. {
  794. #if defined (__linux__)
  795. #if HAVE_ALSA_ASOUNDLIB_H
  796. if (audio_out->magic == ALSA_MAGIC)
  797. alsa_close (audio_out) ;
  798. #endif
  799. opensoundsys_close (audio_out) ;
  800. #elif (defined (__MACH__) && defined (__APPLE__))
  801. macosx_close (audio_out) ;
  802. #elif (defined (sun) && defined (unix))
  803. solaris_close (audio_out) ;
  804. #elif (defined (_WIN32) || defined (WIN32))
  805. win32_close (audio_out) ;
  806. #else
  807. #warning "*** Playing sound not yet supported on this platform."
  808. #warning "*** Please feel free to submit a patch."
  809. printf ("Error : Playing sound not yet supported on this platform.\n") ;
  810. return ;
  811. #endif
  812. return ;
  813. } /* audio_close */
  814. #else /* (HAVE_SNDFILE == 0) */
  815. /* Do not have libsndfile installed so just return. */
  816. AUDIO_OUT *
  817. audio_open (int channels, int samplerate)
  818. {
  819. (void) channels ;
  820. (void) samplerate ;
  821. return NULL ;
  822. } /* audio_open */
  823. void
  824. audio_play (get_audio_callback_t callback, AUDIO_OUT *audio_out, void *callback_data)
  825. {
  826. (void) callback ;
  827. (void) audio_out ;
  828. (void) callback_data ;
  829. return ;
  830. } /* audio_play */
  831. void
  832. audio_close (AUDIO_OUT *audio_out)
  833. {
  834. audio_out = audio_out ;
  835. return ;
  836. } /* audio_close */
  837. #endif /* HAVE_SNDFILE */