jack1 codebase
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.

390 lines
8.7KB

  1. /*
  2. Copyright (C) 2001 Paul Davis
  3. This program is free software; you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation; either version 2 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  14. * 2002/08/23 - modify for libsndfile 1.0.0 <andy@alsaplayer.org>
  15. $Id$
  16. */
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #include <errno.h>
  21. #include <unistd.h>
  22. #include <sndfile.h>
  23. #include <pthread.h>
  24. #include <getopt.h>
  25. #include <jack/jack.h>
  26. #include <jack/jslist.h>
  27. typedef struct _thread_info {
  28. pthread_t thread_id;
  29. SNDFILE *sf;
  30. jack_nframes_t duration;
  31. jack_client_t *client;
  32. unsigned int channels;
  33. int bitdepth;
  34. int can_capture;
  35. char *path;
  36. int status;
  37. int can_process;
  38. } thread_info_t;
  39. unsigned int nports;
  40. jack_port_t **ports;
  41. pthread_mutex_t buffer_lock = PTHREAD_MUTEX_INITIALIZER;
  42. pthread_cond_t data_ready = PTHREAD_COND_INITIALIZER;
  43. typedef struct _sample_buffer {
  44. jack_nframes_t nframes;
  45. jack_default_audio_sample_t **data;
  46. } sample_buffer_t;
  47. sample_buffer_t *
  48. sample_buffer_new (jack_nframes_t nframes, unsigned int nchans)
  49. {
  50. sample_buffer_t *buf;
  51. unsigned int i;
  52. buf = (sample_buffer_t *) malloc (sizeof (sample_buffer_t));
  53. buf->nframes = nframes;
  54. buf->data = (jack_default_audio_sample_t **) malloc (sizeof (jack_default_audio_sample_t *) * nchans);
  55. for (i = 0; i < nchans; i++) {
  56. buf->data[i] = (jack_default_audio_sample_t *) malloc (sizeof (jack_default_audio_sample_t) * nframes);
  57. }
  58. return buf;
  59. }
  60. JSList *pending_writes = NULL;
  61. JSList *free_buffers = NULL;
  62. sample_buffer_t *
  63. get_free_buffer (jack_nframes_t nframes, unsigned int nchans)
  64. {
  65. sample_buffer_t *buf;
  66. if (free_buffers == NULL) {
  67. buf = sample_buffer_new (nframes, nchans);
  68. } else {
  69. buf = (sample_buffer_t *) free_buffers->data;
  70. free_buffers = jack_slist_next (free_buffers);
  71. }
  72. return buf;
  73. }
  74. sample_buffer_t *
  75. get_write_buffer ()
  76. {
  77. sample_buffer_t *buf;
  78. if (pending_writes == NULL) {
  79. return NULL;
  80. }
  81. buf = (sample_buffer_t *) pending_writes->data;
  82. pending_writes = jack_slist_next (pending_writes);
  83. return buf;
  84. }
  85. void
  86. put_write_buffer (sample_buffer_t *buf)
  87. {
  88. pending_writes = jack_slist_append (pending_writes, buf);
  89. }
  90. void
  91. put_free_buffer (sample_buffer_t *buf)
  92. {
  93. free_buffers = jack_slist_prepend (free_buffers, buf);
  94. }
  95. void *
  96. disk_thread (void *arg)
  97. {
  98. sample_buffer_t *buf;
  99. thread_info_t *info = (thread_info_t *) arg;
  100. int i;
  101. unsigned int chn;
  102. jack_nframes_t total_captured = 0;
  103. int done = 0;
  104. double *fbuf;
  105. pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
  106. pthread_mutex_lock (&buffer_lock);
  107. /* preload the buffer cache */
  108. for (i = 0; i < 8; i++) {
  109. buf = sample_buffer_new (jack_get_buffer_size (info->client), info->channels);
  110. put_free_buffer (buf);
  111. }
  112. info->status = 0;
  113. while (!done) {
  114. pthread_cond_wait (&data_ready, &buffer_lock);
  115. while ((buf = get_write_buffer ()) != 0) {
  116. pthread_mutex_unlock (&buffer_lock);
  117. /* grrr ... libsndfile doesn't do float data yet, only double */
  118. if (info->can_capture) {
  119. fbuf = (double *) malloc (sizeof (double) * buf->nframes * info->channels);
  120. for (chn = 0; chn < info->channels; chn++) {
  121. for (i = 0; i < buf->nframes; i++) {
  122. fbuf[chn+(i*info->channels)] = buf->data[chn][i];
  123. }
  124. }
  125. if (sf_writef_double (info->sf, fbuf, buf->nframes) != buf->nframes) {
  126. char errstr[256];
  127. sf_error_str (0, errstr, sizeof (errstr) - 1);
  128. fprintf (stderr, "cannot write data to sndfile (%s)\n", errstr);
  129. info->status = -1;
  130. done = 1;
  131. break;
  132. }
  133. free (fbuf);
  134. total_captured += buf->nframes;
  135. if (total_captured >= info->duration) {
  136. printf ("disk thread finished\n");
  137. done = 1;
  138. break;
  139. }
  140. }
  141. pthread_mutex_lock (&buffer_lock);
  142. put_free_buffer (buf);
  143. }
  144. }
  145. pthread_mutex_unlock (&buffer_lock);
  146. return 0;
  147. }
  148. int
  149. process (jack_nframes_t nframes, void *arg)
  150. {
  151. thread_info_t *info = (thread_info_t *) arg;
  152. jack_default_audio_sample_t *in;
  153. sample_buffer_t *buf;
  154. unsigned int i;
  155. if (!info->can_process) {
  156. return 0;
  157. }
  158. /* we don't like taking locks, but until we have a lock
  159. free ringbuffer written in C, this is what has to be done
  160. */
  161. pthread_mutex_lock (&buffer_lock);
  162. buf = get_free_buffer (nframes, nports);
  163. for (i = 0; i < nports; i++) {
  164. in = (jack_default_audio_sample_t *) jack_port_get_buffer (ports[i], nframes);
  165. memcpy (buf->data[i], in, sizeof (jack_default_audio_sample_t) * nframes);
  166. }
  167. put_write_buffer (buf);
  168. /* tell the disk thread that there is work to do */
  169. pthread_cond_signal (&data_ready);
  170. pthread_mutex_unlock (&buffer_lock);
  171. return 0;
  172. }
  173. void
  174. jack_shutdown (void *arg)
  175. {
  176. fprintf (stderr, "JACK shutdown\n");
  177. exit (0);
  178. }
  179. void
  180. setup_disk_thread (thread_info_t *info)
  181. {
  182. SF_INFO sf_info;
  183. int short_mask;
  184. sf_info.samplerate = jack_get_sample_rate (info->client);
  185. sf_info.channels = info->channels;
  186. switch (info->bitdepth) {
  187. case 8: short_mask = SF_FORMAT_PCM_U8;
  188. break;
  189. case 16: short_mask = SF_FORMAT_PCM_16;
  190. break;
  191. case 24: short_mask = SF_FORMAT_PCM_24;
  192. break;
  193. case 32: short_mask = SF_FORMAT_PCM_32;
  194. break;
  195. default: short_mask = SF_FORMAT_PCM_16;
  196. break;
  197. }
  198. sf_info.format = SF_FORMAT_WAV|short_mask;
  199. if ((info->sf = sf_open (info->path, SFM_WRITE, &sf_info)) == NULL) {
  200. char errstr[256];
  201. sf_error_str (0, errstr, sizeof (errstr) - 1);
  202. fprintf (stderr, "cannot open sndfile \"%s\" for output (%s)\n", info->path, errstr);
  203. jack_client_close (info->client);
  204. exit (1);
  205. }
  206. info->duration *= sf_info.samplerate;
  207. info->can_capture = 0;
  208. pthread_create (&info->thread_id, NULL, disk_thread, info);
  209. }
  210. void
  211. run_disk_thread (thread_info_t *info)
  212. {
  213. info->can_capture = 1;
  214. pthread_join (info->thread_id, NULL);
  215. sf_close (info->sf);
  216. if (info->status) {
  217. unlink (info->path);
  218. }
  219. }
  220. void
  221. setup_ports (int sources, char *source_names[], thread_info_t *info)
  222. {
  223. int i;
  224. nports = sources;
  225. ports = (jack_port_t **) malloc (sizeof (jack_port_t *) * nports);
  226. for (i = 0; i < nports; i++) {
  227. char name[64];
  228. sprintf (name, "input%d", i+1);
  229. if ((ports[i] = jack_port_register (info->client, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0)) == 0) {
  230. fprintf (stderr, "cannot register input port \"%s\"!\n", name);
  231. jack_client_close (info->client);
  232. exit (1);
  233. }
  234. }
  235. for (i = 0; i < nports; i++) {
  236. if (jack_connect (info->client, source_names[i], jack_port_name (ports[i]))) {
  237. fprintf (stderr, "cannot connect input port %s to %s\n", jack_port_name (ports[i]), source_names[i]);
  238. jack_client_close (info->client);
  239. exit (1);
  240. }
  241. }
  242. info->can_process = 1;
  243. }
  244. int
  245. main (int argc, char *argv[])
  246. {
  247. jack_client_t *client;
  248. thread_info_t thread_info;
  249. int c;
  250. int longopt_index = 0;
  251. extern int optind, opterr;
  252. int show_usage = 0;
  253. char *optstring = "d:f:b:h";
  254. struct option long_options[] = {
  255. { "help", 1, 0, 'h' },
  256. { "duration", 1, 0, 'd' },
  257. { "file", 1, 0, 'f' },
  258. { "bitdepth", 1, 0, 'b' },
  259. { 0, 0, 0, 0 }
  260. };
  261. memset (&thread_info, 0, sizeof (thread_info));
  262. opterr = 0;
  263. while ((c = getopt_long (argc, argv, optstring, long_options, &longopt_index)) != -1) {
  264. switch (c) {
  265. case 1:
  266. /* getopt signals end of '-' options */
  267. break;
  268. case 'h':
  269. show_usage++;
  270. break;
  271. case 'd':
  272. thread_info.duration = atoi (optarg);
  273. break;
  274. case 'f':
  275. thread_info.path = optarg;
  276. break;
  277. case 'b':
  278. thread_info.bitdepth = atoi (optarg);
  279. break;
  280. default:
  281. fprintf (stderr, "error\n");
  282. show_usage++;
  283. break;
  284. }
  285. }
  286. if (show_usage || thread_info.path == NULL || optind == argc) {
  287. fprintf (stderr, "usage: jackrec -f filename [ -d second ] [ -b bitdepth ] port1 [ port2 ... ]\n");
  288. exit (1);
  289. }
  290. if ((client = jack_client_new ("jackrec")) == 0) {
  291. fprintf (stderr, "jack server not running?\n");
  292. exit (1);
  293. }
  294. thread_info.client = client;
  295. thread_info.channels = argc - optind;
  296. thread_info.can_process = 0;
  297. setup_disk_thread (&thread_info);
  298. jack_set_process_callback (client, process, &thread_info);
  299. jack_on_shutdown (client, jack_shutdown, NULL);
  300. if (jack_activate (client)) {
  301. fprintf (stderr, "cannot activate client");
  302. }
  303. setup_ports (argc - optind, &argv[optind], &thread_info);
  304. run_disk_thread (&thread_info);
  305. jack_client_close (client);
  306. exit (0);
  307. }