jackplay.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  1. /*
  2. ** Copyright (C) 2014 Alexander Regueiro <alex@noldorin.com>
  3. ** Copyright (C) 2013 elboulangero <elboulangero@gmail.com>
  4. ** Copyright (C) 2007-2012 Erik de Castro Lopo <erikd@mega-nerd.com>
  5. ** Copyright (C) 2007 Jonatan Liljedahl <lijon@kymatica.com>
  6. **
  7. ** This program is free software ; you can redistribute it and/or modify
  8. ** it under the terms of the GNU General Public License as published by
  9. ** the Free Software Foundation ; either version 2 of the License, or
  10. ** (at your option) any later version.
  11. **
  12. ** This program is distributed in the hope that it will be useful,
  13. ** but WITHOUT ANY WARRANTY ; without even the implied warranty of
  14. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. ** GNU General Public License for more details.
  16. **
  17. ** You should have received a copy of the GNU General Public License
  18. ** along with this program ; if not, write to the Free Software
  19. ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  20. */
  21. /*#include "src/config.h"*/
  22. #include <stdbool.h>
  23. #include <stdio.h>
  24. #include <errno.h>
  25. #include <unistd.h>
  26. #include <getopt.h>
  27. #include <libgen.h>
  28. #include <stdlib.h>
  29. #include <string.h>
  30. #define HAVE_JACK 1
  31. #if HAVE_JACK
  32. #include <math.h>
  33. #include <pthread.h>
  34. #include <jack/jack.h>
  35. #include <jack/ringbuffer.h>
  36. #include <sndfile.h>
  37. #define RB_SIZE (1 << 16)
  38. #define SAMPLE_SIZE (sizeof (jack_default_audio_sample_t))
  39. #define NOT(x) (! (x))
  40. typedef struct
  41. { jack_client_t *client ;
  42. jack_ringbuffer_t *ringbuf ;
  43. jack_nframes_t pos ;
  44. jack_default_audio_sample_t ** outs ;
  45. jack_port_t ** output_port ;
  46. SNDFILE *sndfile ;
  47. unsigned int channels ;
  48. unsigned int samplerate ;
  49. volatile int can_process ;
  50. volatile int read_done ;
  51. volatile int play_done ;
  52. volatile unsigned int loop_count ;
  53. volatile unsigned int current_loop ;
  54. } thread_info_t ;
  55. static pthread_mutex_t disk_thread_lock = PTHREAD_MUTEX_INITIALIZER ;
  56. static pthread_cond_t data_ready = PTHREAD_COND_INITIALIZER ;
  57. static int
  58. process_callback (jack_nframes_t nframes, void * arg)
  59. {
  60. thread_info_t *info = (thread_info_t *) arg ;
  61. jack_default_audio_sample_t buf [info->channels] ;
  62. unsigned i, n ;
  63. if (NOT (info->can_process))
  64. return 0 ;
  65. for (n = 0 ; n < info->channels ; n++)
  66. info->outs [n] = jack_port_get_buffer (info->output_port [n], nframes) ;
  67. for (i = 0 ; i < nframes ; i++)
  68. { size_t read_count ;
  69. /* Read one frame of audio. */
  70. read_count = jack_ringbuffer_read (info->ringbuf, (void *) buf, SAMPLE_SIZE * info->channels) ;
  71. if (read_count == 0 && info->read_done)
  72. { /* File is done, so stop the main loop. */
  73. info->play_done = 1 ;
  74. return 0 ;
  75. } ;
  76. /* Update play-position counter. */
  77. info->pos += read_count / (SAMPLE_SIZE * info->channels) ;
  78. /* Output each channel of the frame. */
  79. for (n = 0 ; n < info->channels ; n++)
  80. info->outs [n][i] = buf [n] ;
  81. } ;
  82. /* Wake up the disk thread to read more data. */
  83. if (pthread_mutex_trylock (&disk_thread_lock) == 0)
  84. { pthread_cond_signal (&data_ready) ;
  85. pthread_mutex_unlock (&disk_thread_lock) ;
  86. } ;
  87. return 0 ;
  88. } /* process_callback */
  89. static void *
  90. disk_thread (void *arg)
  91. { thread_info_t *info = (thread_info_t *) arg ;
  92. sf_count_t buf_avail, read_frames ;
  93. jack_ringbuffer_data_t vec [2] ;
  94. size_t bytes_per_frame = SAMPLE_SIZE * info->channels ;
  95. pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL) ;
  96. pthread_mutex_lock (&disk_thread_lock) ;
  97. while (1)
  98. { jack_ringbuffer_get_write_vector (info->ringbuf, vec) ;
  99. read_frames = 0 ;
  100. if (vec [0].len)
  101. { /* Fill the first part of the ringbuffer. */
  102. buf_avail = vec [0].len / bytes_per_frame ;
  103. read_frames = sf_readf_float (info->sndfile, (float *) vec [0].buf, buf_avail) ;
  104. if (vec [1].len)
  105. { /* Fill the second part of the ringbuffer? */
  106. buf_avail = vec [1].len / bytes_per_frame ;
  107. read_frames += sf_readf_float (info->sndfile, (float *) vec [1].buf, buf_avail) ;
  108. } ;
  109. } ;
  110. if (read_frames == 0)
  111. { info->current_loop ++ ;
  112. if (info->loop_count >= 1 && info->current_loop >= info->loop_count)
  113. break ; /* end of file? */
  114. sf_seek (info->sndfile, 0, SEEK_SET) ;
  115. }
  116. jack_ringbuffer_write_advance (info->ringbuf, read_frames * bytes_per_frame) ;
  117. /* Tell process_callback that we've filled the ringbuffer. */
  118. info->can_process = 1 ;
  119. /* Wait for the process_callback thread to wake us up. */
  120. pthread_cond_wait (&data_ready, &disk_thread_lock) ;
  121. } ;
  122. /* Tell that we're done reading the file. */
  123. info->read_done = 1 ;
  124. pthread_mutex_unlock (&disk_thread_lock) ;
  125. return NULL ;
  126. } /* disk_thread */
  127. static void
  128. jack_shutdown (void *arg)
  129. { (void) arg ;
  130. exit (1) ;
  131. } /* jack_shutdown */
  132. static inline void
  133. print_time (jack_nframes_t pos, int jack_sr)
  134. { float sec = pos / (1.0 * jack_sr) ;
  135. int min = sec / 60.0 ;
  136. fprintf (stderr, "%02d:%05.2f", min, fmod (sec, 60.0)) ;
  137. } /* print_time */
  138. static inline void
  139. print_status (const thread_info_t * info)
  140. {
  141. if (info->loop_count == 0)
  142. fprintf (stderr, "\r-> %6d ", info->current_loop) ;
  143. else if (info->loop_count > 1)
  144. fprintf (stderr, "\r-> %6d/%d ", info->current_loop, info->loop_count) ;
  145. else
  146. fprintf (stderr, "\r-> ") ;
  147. print_time (info->pos, info->samplerate) ;
  148. fflush (stdout) ;
  149. } /* print_status */
  150. static void
  151. usage_exit (char * argv0, int status)
  152. {
  153. printf ("\n"
  154. "Usage : %s [options] <input sound file>\n"
  155. "\n"
  156. " Where [options] is one of:\n"
  157. "\n"
  158. " -w --wait[=<port>] : Wait for input before starting playback; optionally auto-connect to <port> using Jack.\n"
  159. " -l --loop=<count> : Loop the file <count> times (0 for infinite).\n"
  160. " -h --help : Show this help message.\n"
  161. "\n"
  162. "Using %s.\n"
  163. "\n",
  164. basename (argv0), sf_version_string ()) ;
  165. exit (status) ;
  166. } /* usage_exit */
  167. static struct option const long_options [] =
  168. {
  169. { "wait", optional_argument, NULL, 'w' } ,
  170. { "loop", required_argument, NULL, 'l' } ,
  171. { "help", no_argument, NULL, 'h' } ,
  172. { NULL, 0, NULL, 0 }
  173. } ;
  174. int
  175. main (int argc, char * argv [])
  176. { pthread_t thread_id ;
  177. SNDFILE *sndfile ;
  178. SF_INFO sfinfo ;
  179. const char * filename ;
  180. jack_client_t *client ;
  181. jack_status_t status = 0 ;
  182. thread_info_t info ;
  183. char * auto_connect_str = "system:playback_%d" ;
  184. bool wait_before_play = false ;
  185. int i, jack_sr, loop_count = 1 ;
  186. int c ;
  187. /* Parse options */
  188. while ((c = getopt_long (argc, argv,
  189. "w::" /* --wait */
  190. "l:" /* --loop */
  191. "h", /* --help */
  192. long_options, NULL)) != EOF)
  193. { if (optarg != NULL && optarg [0] == '=')
  194. { optarg++ ;
  195. }
  196. switch (c)
  197. { case 'w' :
  198. wait_before_play = true ;
  199. auto_connect_str = optarg ;
  200. break ;
  201. case 'l' :
  202. loop_count = strtol (optarg, NULL, 10) ;
  203. break ;
  204. case 'h' :
  205. usage_exit (argv [0], EXIT_SUCCESS) ;
  206. break ;
  207. default :
  208. usage_exit (argv [0], EXIT_FAILURE) ;
  209. } ;
  210. }
  211. if (argc - optind != 1)
  212. usage_exit (argv [0], EXIT_FAILURE) ;
  213. filename = argv [optind] ;
  214. /* Create jack client */
  215. if ((client = jack_client_open ("jackplay", JackNullOption | JackNoStartServer, &status)) == 0)
  216. { if (status & JackServerFailed)
  217. fprintf (stderr, "Unable to connect to JACK server\n") ;
  218. else
  219. fprintf (stderr, "jack_client_open () failed, status = 0x%2.0x\n", status) ;
  220. exit (1) ;
  221. } ;
  222. if (status & JackServerStarted)
  223. fprintf (stderr, "JACK server started\n") ;
  224. if (status & JackNameNotUnique)
  225. { const char * client_name = jack_get_client_name (client) ;
  226. fprintf (stderr, "Unique name `%s' assigned\n", client_name) ;
  227. } ;
  228. /* Open the soundfile. */
  229. memset (&sfinfo, 0, sizeof (sfinfo)) ;
  230. sndfile = sf_open (filename, SFM_READ, &sfinfo) ;
  231. if (sndfile == NULL)
  232. { fprintf (stderr, "Could not open soundfile '%s'\n", filename) ;
  233. return 1 ;
  234. } ;
  235. fprintf (stderr, "Channels : %d\nSample rate : %d Hz\nDuration : ", sfinfo.channels, sfinfo.samplerate) ;
  236. print_time (loop_count * sfinfo.frames, sfinfo.samplerate) ;
  237. fprintf (stderr, "\n") ;
  238. if (loop_count < 1)
  239. fprintf (stderr, "Loop count : infinite\n") ;
  240. else if (loop_count > 1)
  241. fprintf (stderr, "Loop count : %d\n", loop_count) ;
  242. jack_sr = jack_get_sample_rate (client) ;
  243. if (sfinfo.samplerate != jack_sr)
  244. fprintf (stderr, "Warning: samplerate of soundfile (%d Hz) does not match jack server (%d Hz).\n", sfinfo.samplerate, jack_sr) ;
  245. /* Init the thread info struct. */
  246. memset (&info, 0, sizeof (info)) ;
  247. info.can_process = 0 ;
  248. info.read_done = 0 ;
  249. info.play_done = 0 ;
  250. info.sndfile = sndfile ;
  251. info.channels = sfinfo.channels ;
  252. info.samplerate = jack_sr ;
  253. info.client = client ;
  254. info.pos = 0 ;
  255. info.current_loop = 0 ;
  256. info.loop_count = loop_count ;
  257. /* Allocate output ports. */
  258. info.output_port = calloc (sfinfo.channels, sizeof (jack_port_t *)) ;
  259. info.outs = calloc (sfinfo.channels, sizeof (jack_default_audio_sample_t *)) ;
  260. for (i = 0 ; i < sfinfo.channels ; i++)
  261. { char name [16] ;
  262. snprintf (name, sizeof (name), "out_%d", i + 1) ;
  263. info.output_port [i] = jack_port_register (client, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0) ;
  264. } ;
  265. /* Allocate and clear ringbuffer. */
  266. info.ringbuf = jack_ringbuffer_create (sizeof (jack_default_audio_sample_t) * RB_SIZE) ;
  267. memset (info.ringbuf->buf, 0, info.ringbuf->size) ;
  268. /* Set up callbacks. */
  269. jack_set_process_callback (client, process_callback, &info) ;
  270. jack_on_shutdown (client, jack_shutdown, 0) ;
  271. /* Activate client. */
  272. if (jack_activate (client))
  273. { fprintf (stderr, "Cannot activate client.\n") ;
  274. return 1 ;
  275. } ;
  276. if (auto_connect_str != NULL)
  277. { /* Auto-connect all channels. */
  278. for (i = 0 ; i < sfinfo.channels ; i++)
  279. { char name [64] ;
  280. snprintf (name, sizeof (name), auto_connect_str, i + 1) ;
  281. if (jack_connect (client, jack_port_name (info.output_port [i]), name))
  282. fprintf (stderr, "Cannot connect output port %d (%s).\n", i, name) ;
  283. } ;
  284. }
  285. if (wait_before_play)
  286. { /* Wait for key press before playing. */
  287. printf ("Press <ENTER> key to start playing...") ;
  288. getchar () ;
  289. }
  290. /* Start the disk thread. */
  291. pthread_create (&thread_id, NULL, disk_thread, &info) ;
  292. /* Sit in a loop, displaying the current play position. */
  293. while (NOT (info.play_done))
  294. { print_status (&info) ;
  295. usleep (10000) ;
  296. } ;
  297. pthread_join (thread_id, NULL) ;
  298. print_status (&info) ;
  299. /* Clean up. */
  300. for (i = 0 ; i < sfinfo.channels ; i++)
  301. jack_port_unregister (client, info.output_port [i]) ;
  302. jack_ringbuffer_free (info.ringbuf) ;
  303. jack_client_close (client) ;
  304. free (info.output_port) ;
  305. free (info.outs) ;
  306. sf_close (sndfile) ;
  307. puts ("") ;
  308. return 0 ;
  309. } /* main */
  310. #else
  311. int
  312. main (void)
  313. {
  314. puts (
  315. "Sorry this program was compiled without libjack (which probably\n"
  316. "only exists on Linux and Mac OSX) and hence doesn't work."
  317. ) ;
  318. return 0 ;
  319. } /* main */
  320. #endif