git-svn-id: svn+ssh://jackaudio.org/trunk/jack@3591 0c269be4-1314-0410-8aa9-9f06e86f4224tags/0.117.0
| @@ -1290,6 +1290,7 @@ alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *status, float | |||||
| strerror (errno)); | strerror (errno)); | ||||
| *status = -3; | *status = -3; | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| @@ -1306,9 +1307,8 @@ alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *status, float | |||||
| } | } | ||||
| #ifdef DEBUG_WAKEUP | #ifdef DEBUG_WAKEUP | ||||
| jack_info ("%" PRIu64 ": checked %d fds, %" PRIu64 | |||||
| " usecs since poll entered", poll_ret, nfds, | |||||
| poll_ret - poll_enter); | |||||
| fprintf (stderr, "%" PRIu64 ": checked %d fds, started at %" PRIu64 " %" PRIu64 " usecs since poll entered\n", | |||||
| poll_ret, nfds, poll_enter, poll_ret - poll_enter); | |||||
| #endif | #endif | ||||
| /* check to see if it was the extra FD that caused us | /* check to see if it was the extra FD that caused us | ||||
| @@ -1345,8 +1345,8 @@ alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *status, float | |||||
| if (revents & POLLOUT) { | if (revents & POLLOUT) { | ||||
| need_playback = 0; | need_playback = 0; | ||||
| #ifdef DEBUG_WAKEUP | #ifdef DEBUG_WAKEUP | ||||
| jack_info ("%" PRIu64 | |||||
| " playback stream ready", | |||||
| fprintf (stderr, "%" PRIu64 | |||||
| " playback stream ready\n", | |||||
| poll_ret); | poll_ret); | ||||
| #endif | #endif | ||||
| } | } | ||||
| @@ -1368,8 +1368,8 @@ alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *status, float | |||||
| if (revents & POLLIN) { | if (revents & POLLIN) { | ||||
| need_capture = 0; | need_capture = 0; | ||||
| #ifdef DEBUG_WAKEUP | #ifdef DEBUG_WAKEUP | ||||
| jack_info ("%" PRIu64 | |||||
| " capture stream ready", | |||||
| fprintf (stderr, "%" PRIu64 | |||||
| " capture stream ready\n", | |||||
| poll_ret); | poll_ret); | ||||
| #endif | #endif | ||||
| } | } | ||||
| @@ -1426,8 +1426,8 @@ alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *status, float | |||||
| avail = capture_avail < playback_avail ? capture_avail : playback_avail; | avail = capture_avail < playback_avail ? capture_avail : playback_avail; | ||||
| #ifdef DEBUG_WAKEUP | #ifdef DEBUG_WAKEUP | ||||
| jack_info ("wakeup complete, avail = %lu, pavail = %lu " | |||||
| "cavail = %lu", | |||||
| fprintf (stderr, "wakeup complete, avail = %lu, pavail = %lu " | |||||
| "cavail = %lu\n", | |||||
| avail, playback_avail, capture_avail); | avail, playback_avail, capture_avail); | ||||
| #endif | #endif | ||||
| @@ -1,20 +1,28 @@ | |||||
| MAINTAINERCLEANFILES = Makefile.in | MAINTAINERCLEANFILES = Makefile.in | ||||
| if HAVE_SNDFILE | |||||
| JACKREC = jackrec | |||||
| dist-check-sndfile: | |||||
| else | |||||
| JACKREC = | |||||
| dist-check-sndfile: | |||||
| @echo | |||||
| @echo ' ******' You need sndfile installed to make dist.' ******' | |||||
| @echo | |||||
| @false | |||||
| endif | |||||
| bin_PROGRAMS = jack_simple_client \ | bin_PROGRAMS = jack_simple_client \ | ||||
| jack_transport_client \ | jack_transport_client \ | ||||
| jack_impulse_grabber \ | jack_impulse_grabber \ | ||||
| jack_metro \ | jack_metro \ | ||||
| jack_showtime \ | jack_showtime \ | ||||
| jack_midisine \ | |||||
| jack_midiseq | |||||
| jack_midisine \ | |||||
| jack_midiseq \ | |||||
| $(JACKREC) | |||||
| if HAVE_SNDFILE | |||||
| # note! jackrec_CFLAGS syntax not supported by automake-1.4 | |||||
| sndfile_cflags = @SNDFILE_CFLAGS@ | |||||
| endif | |||||
| AM_CFLAGS = -I.. $(JACK_CFLAGS) $(sndfile_cflags) | |||||
| AM_CXXFLAGS = -I.. $(JACK_CFLAGS) $(sndfile_cflags) | |||||
| AM_CFLAGS = -I.. $(JACK_CFLAGS) | |||||
| AM_CXXFLAGS = -I.. $(JACK_CFLAGS) | |||||
| jack_simple_client_SOURCES = simple_client.c | jack_simple_client_SOURCES = simple_client.c | ||||
| jack_simple_client_LDFLAGS = @OS_LDFLAGS@ | jack_simple_client_LDFLAGS = @OS_LDFLAGS@ | ||||
| @@ -44,6 +52,12 @@ jack_midisine_SOURCES = midisine.c | |||||
| jack_midisine_LDFLAGS = @OS_LDFLAGS@ | jack_midisine_LDFLAGS = @OS_LDFLAGS@ | ||||
| jack_midisine_LDADD = $(top_builddir)/libjack/libjack.la | jack_midisine_LDADD = $(top_builddir)/libjack/libjack.la | ||||
| if HAVE_SNDFILE | |||||
| jackrec_SOURCES = capture_client.c | |||||
| jackrec_LDFLAGS = @SNDFILE_LIBS@ @OS_LDFLAGS@ | |||||
| jackrec_LDADD = $(top_builddir)/libjack/libjack.la | |||||
| endif | |||||
| # | # | ||||
| # sample in-process client(s) | # sample in-process client(s) | ||||
| # | # | ||||
| @@ -508,15 +508,7 @@ int jack_port_unregister (jack_client_t *, jack_port_t *); | |||||
| * zero-filled. if there are multiple inbound connections, the data | * zero-filled. if there are multiple inbound connections, the data | ||||
| * will be mixed appropriately. | * will be mixed appropriately. | ||||
| * | * | ||||
| * FOR OUTPUT PORTS ONLY : WILL BE DEPRECATED in Jack 2.0 !! | |||||
| * --------------------------------------------------------- | |||||
| * You may cache the value returned, but only between calls to | |||||
| * your "blocksize" callback. For this reason alone, you should | |||||
| * either never cache the return value or ensure you have | |||||
| * a "blocksize" callback and be sure to invalidate the cached | |||||
| * address from there. | |||||
| * | |||||
| * Caching output ports is DEPRECATED in Jack 2.0, due to some new optimization (like "pipelining"). | |||||
| * Do not cache the returned address across process() callbacks. | |||||
| * Port buffers have to be retrieved in each callback for proper functionning. | * Port buffers have to be retrieved in each callback for proper functionning. | ||||
| */ | */ | ||||
| void *jack_port_get_buffer (jack_port_t *, jack_nframes_t); | void *jack_port_get_buffer (jack_port_t *, jack_nframes_t); | ||||
| @@ -865,47 +857,57 @@ jack_port_t *jack_port_by_id (jack_client_t *client, | |||||
| /** | /** | ||||
| * @defgroup TimeFunctions Handling time | * @defgroup TimeFunctions Handling time | ||||
| * @{ | * @{ | ||||
| * | |||||
| * JACK time is in units of 'frames', according to the current sample rate. | |||||
| * The absolute value of frame times is meaningless, frame times have meaning | |||||
| * only relative to each other. | |||||
| */ | */ | ||||
| /** | /** | ||||
| * @return the time in frames that has passed since the JACK server | |||||
| * began the current process cycle. | |||||
| * @return the estimated time in frames that has passed since the JACK | |||||
| * server began the current process cycle. | |||||
| */ | */ | ||||
| jack_nframes_t jack_frames_since_cycle_start (const jack_client_t *); | jack_nframes_t jack_frames_since_cycle_start (const jack_client_t *); | ||||
| /** | /** | ||||
| * @return an estimate of the current time in frames. This is a | |||||
| * running counter, no significance should be attached to its value, | |||||
| * but it can be compared to a previously returned value. | |||||
| * @return the estimated current time in frames. | |||||
| * This function is intended for use in other threads (not the process | |||||
| * callback). The return value can be compared with the value of | |||||
| * jack_last_frame_time to relate time in other threads to JACK time. | |||||
| */ | */ | ||||
| jack_nframes_t jack_frame_time (const jack_client_t *); | jack_nframes_t jack_frame_time (const jack_client_t *); | ||||
| /** | /** | ||||
| * @return the frame_time after the last processing of the graph | |||||
| * this is only to be used from the process callback. | |||||
| * | |||||
| * This function can be used to put timestamps generated by | |||||
| * jack_frame_time() in correlation to the current process cycle. | |||||
| * @return the precise time at the start of the current process cycle. | |||||
| * This function may only be used from the process callback, and can | |||||
| * be used to interpret timestamps generated by jack_frame_time() in | |||||
| * other threads with respect to the current process cycle. | |||||
| * | |||||
| * This is the only jack time function that returns exact time: | |||||
| * when used during the process callback it always returns the same | |||||
| * value (until the next process callback, where it will return | |||||
| * that value + nframes, etc). The return value is guaranteed to be | |||||
| * monotonic and linear in this fashion unless an xrun occurs. | |||||
| * If an xrun occurs, clients must check this value again, as time | |||||
| * may have advanced in a non-linear way (e.g. cycles may have been skipped). | |||||
| */ | */ | ||||
| jack_nframes_t jack_last_frame_time (const jack_client_t *client); | jack_nframes_t jack_last_frame_time (const jack_client_t *client); | ||||
| /** | /** | ||||
| * @return estimated time in microseconds of the specified frame time | |||||
| * @return the estimated time in microseconds of the specified frame time | |||||
| */ | */ | ||||
| jack_time_t jack_frames_to_time(const jack_client_t *client, jack_nframes_t); | jack_time_t jack_frames_to_time(const jack_client_t *client, jack_nframes_t); | ||||
| /** | /** | ||||
| * @return estimated time in frames for the specified system time. | |||||
| * @return the estimated time in frames for the specified system time. | |||||
| */ | */ | ||||
| jack_nframes_t jack_time_to_frames(const jack_client_t *client, jack_time_t); | jack_nframes_t jack_time_to_frames(const jack_client_t *client, jack_time_t); | ||||
| /** | /** | ||||
| * @return return JACK's current system time in microseconds, | * @return return JACK's current system time in microseconds, | ||||
| * using JACK clock source. | |||||
| * using the JACK clock source. | |||||
| * | * | ||||
| * The value returned is guaranteed to be monotonic, but not linear. | * The value returned is guaranteed to be monotonic, but not linear. | ||||
| * | |||||
| * This function is a client version of jack_get_microseconds(). | |||||
| */ | */ | ||||
| jack_time_t jack_get_time(); | jack_time_t jack_get_time(); | ||||
| @@ -2270,7 +2270,7 @@ jack_run_cycle (jack_engine_t *engine, jack_nframes_t nframes, | |||||
| timer->current_wakeup = engine->driver->last_wait_ust; | timer->current_wakeup = engine->driver->last_wait_ust; | ||||
| timer->next_wakeup = engine->driver->last_wait_ust + | timer->next_wakeup = engine->driver->last_wait_ust + | ||||
| engine->driver->period_usecs; | engine->driver->period_usecs; | ||||
| timer->reset_pending = 0; | timer->reset_pending = 0; | ||||
| } else { | } else { | ||||
| @@ -248,13 +248,14 @@ jack_time_to_frames(const jack_client_t *client, jack_time_t now) | |||||
| if (time.initialized) { | if (time.initialized) { | ||||
| #if 0 | #if 0 | ||||
| jack_info ("now = %Lu current wakeup = %Lu next = %Lu frames = %lu + %f => %lu", | |||||
| jack_info ("now = %Lu current wakeup = %Lu next = %Lu frames = %lu + %f => %lu FC = %f SOI = %f", | |||||
| now, time.current_wakeup, time.next_wakeup, time.frames, | now, time.current_wakeup, time.next_wakeup, time.frames, | ||||
| (double) (now - time.current_wakeup)/ | |||||
| (time.next_wakeup - time.current_wakeup), | |||||
| (double) (now - time.current_wakeup)/ (time.next_wakeup - time.current_wakeup), | |||||
| time.frames + | time.frames + | ||||
| (long) rint (((double) (now - time.current_wakeup)/ | |||||
| (time.next_wakeup - time.current_wakeup)) * ectl->buffer_size)); | |||||
| (long) rint (((double) ((long long) now - time.current_wakeup)/ | |||||
| (long long) (time.next_wakeup - time.current_wakeup)) * ectl->buffer_size), | |||||
| time.filter_coefficient, | |||||
| time.second_order_integrator); | |||||
| #endif | #endif | ||||
| return time.frames + | return time.frames + | ||||
| @@ -274,9 +275,7 @@ jack_frame_time (const jack_client_t *client) | |||||
| jack_nframes_t | jack_nframes_t | ||||
| jack_last_frame_time (const jack_client_t *client) | jack_last_frame_time (const jack_client_t *client) | ||||
| { | { | ||||
| jack_frame_timer_t current; | |||||
| jack_read_frame_time (client, ¤t); | |||||
| return current.frames; | |||||
| return client->engine->frame_timer.frames; | |||||
| } | } | ||||
| jack_time_t | jack_time_t | ||||
| @@ -1,17 +1,5 @@ | |||||
| MAINTAINERCLEANFILES = Makefile.in | MAINTAINERCLEANFILES = Makefile.in | ||||
| if HAVE_SNDFILE | |||||
| JACKREC = jackrec | |||||
| dist-check-sndfile: | |||||
| else | |||||
| JACKREC = | |||||
| dist-check-sndfile: | |||||
| @echo | |||||
| @echo ' ******' You need sndfile installed to make dist.' ******' | |||||
| @echo | |||||
| @false | |||||
| endif | |||||
| if HAVE_READLINE | if HAVE_READLINE | ||||
| JACK_TRANSPORT = jack_transport | JACK_TRANSPORT = jack_transport | ||||
| dist-check-readline: | dist-check-readline: | ||||
| @@ -48,7 +36,6 @@ bin_PROGRAMS = jack_load \ | |||||
| jack_freewheel \ | jack_freewheel \ | ||||
| jack_evmon \ | jack_evmon \ | ||||
| jack_alias \ | jack_alias \ | ||||
| $(JACKREC) \ | |||||
| $(JACK_TRANSPORT) \ | $(JACK_TRANSPORT) \ | ||||
| $(NETJACK_TOOLS) | $(NETJACK_TOOLS) | ||||
| @@ -94,12 +81,6 @@ jack_freewheel_SOURCES = freewheel.c | |||||
| jack_freewheel_LDFLAGS = @OS_LDFLAGS@ | jack_freewheel_LDFLAGS = @OS_LDFLAGS@ | ||||
| jack_freewheel_LDADD = $(top_builddir)/libjack/libjack.la | jack_freewheel_LDADD = $(top_builddir)/libjack/libjack.la | ||||
| if HAVE_SNDFILE | |||||
| jackrec_SOURCES = capture_client.c | |||||
| jackrec_LDFLAGS = @SNDFILE_LIBS@ @OS_LDFLAGS@ | |||||
| jackrec_LDADD = $(top_builddir)/libjack/libjack.la | |||||
| endif | |||||
| if HAVE_READLINE | if HAVE_READLINE | ||||
| jack_transport_SOURCES = transport.c | jack_transport_SOURCES = transport.c | ||||
| jack_transport_LDFLAGS = -lreadline @READLINE_DEPS@ @OS_LDFLAGS@ | jack_transport_LDFLAGS = -lreadline @READLINE_DEPS@ @OS_LDFLAGS@ | ||||
| @@ -1,344 +0,0 @@ | |||||
| /* | |||||
| Copyright (C) 2001 Paul Davis | |||||
| Copyright (C) 2003 Jack O'Quin | |||||
| This program is free software; you can redistribute it and/or modify | |||||
| it under the terms of the GNU General Public License as published by | |||||
| the Free Software Foundation; either version 2 of the License, or | |||||
| (at your option) any later version. | |||||
| This program is distributed in the hope that it will be useful, | |||||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
| GNU General Public License for more details. | |||||
| You should have received a copy of the GNU General Public License | |||||
| along with this program; if not, write to the Free Software | |||||
| Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||||
| * 2002/08/23 - modify for libsndfile 1.0.0 <andy@alsaplayer.org> | |||||
| * 2003/05/26 - use ringbuffers - joq | |||||
| */ | |||||
| #include <stdio.h> | |||||
| #include <stdlib.h> | |||||
| #include <string.h> | |||||
| #include <errno.h> | |||||
| #include <unistd.h> | |||||
| #include <sndfile.h> | |||||
| #include <pthread.h> | |||||
| #include <getopt.h> | |||||
| #include <jack/jack.h> | |||||
| #include <jack/ringbuffer.h> | |||||
| typedef struct _thread_info { | |||||
| pthread_t thread_id; | |||||
| SNDFILE *sf; | |||||
| jack_nframes_t duration; | |||||
| jack_nframes_t rb_size; | |||||
| jack_client_t *client; | |||||
| unsigned int channels; | |||||
| int bitdepth; | |||||
| char *path; | |||||
| volatile int can_capture; | |||||
| volatile int can_process; | |||||
| volatile int status; | |||||
| } jack_thread_info_t; | |||||
| /* JACK data */ | |||||
| unsigned int nports; | |||||
| jack_port_t **ports; | |||||
| jack_default_audio_sample_t **in; | |||||
| jack_nframes_t nframes; | |||||
| const size_t sample_size = sizeof(jack_default_audio_sample_t); | |||||
| /* Synchronization between process thread and disk thread. */ | |||||
| #define DEFAULT_RB_SIZE 16384 /* ringbuffer size in frames */ | |||||
| jack_ringbuffer_t *rb; | |||||
| pthread_mutex_t disk_thread_lock = PTHREAD_MUTEX_INITIALIZER; | |||||
| pthread_cond_t data_ready = PTHREAD_COND_INITIALIZER; | |||||
| long overruns = 0; | |||||
| void * | |||||
| disk_thread (void *arg) | |||||
| { | |||||
| jack_thread_info_t *info = (jack_thread_info_t *) arg; | |||||
| static jack_nframes_t total_captured = 0; | |||||
| jack_nframes_t samples_per_frame = info->channels; | |||||
| size_t bytes_per_frame = samples_per_frame * sample_size; | |||||
| void *framebuf = malloc (bytes_per_frame); | |||||
| pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL); | |||||
| pthread_mutex_lock (&disk_thread_lock); | |||||
| info->status = 0; | |||||
| while (1) { | |||||
| /* Write the data one frame at a time. This is | |||||
| * inefficient, but makes things simpler. */ | |||||
| while (info->can_capture && | |||||
| (jack_ringbuffer_read_space (rb) >= bytes_per_frame)) { | |||||
| jack_ringbuffer_read (rb, framebuf, bytes_per_frame); | |||||
| if (sf_writef_float (info->sf, framebuf, 1) != 1) { | |||||
| char errstr[256]; | |||||
| sf_error_str (0, errstr, sizeof (errstr) - 1); | |||||
| fprintf (stderr, | |||||
| "cannot write sndfile (%s)\n", | |||||
| errstr); | |||||
| info->status = EIO; /* write failed */ | |||||
| goto done; | |||||
| } | |||||
| if (++total_captured >= info->duration) { | |||||
| printf ("disk thread finished\n"); | |||||
| goto done; | |||||
| } | |||||
| } | |||||
| /* wait until process() signals more data */ | |||||
| pthread_cond_wait (&data_ready, &disk_thread_lock); | |||||
| } | |||||
| done: | |||||
| pthread_mutex_unlock (&disk_thread_lock); | |||||
| free (framebuf); | |||||
| return 0; | |||||
| } | |||||
| int | |||||
| process (jack_nframes_t nframes, void *arg) | |||||
| { | |||||
| int chn; | |||||
| size_t i; | |||||
| jack_thread_info_t *info = (jack_thread_info_t *) arg; | |||||
| /* Do nothing until we're ready to begin. */ | |||||
| if ((!info->can_process) || (!info->can_capture)) | |||||
| return 0; | |||||
| for (chn = 0; chn < nports; chn++) | |||||
| in[chn] = jack_port_get_buffer (ports[chn], nframes); | |||||
| /* Sndfile requires interleaved data. It is simpler here to | |||||
| * just queue interleaved samples to a single ringbuffer. */ | |||||
| for (i = 0; i < nframes; i++) { | |||||
| for (chn = 0; chn < nports; chn++) { | |||||
| if (jack_ringbuffer_write (rb, (void *) (in[chn]+i), | |||||
| sample_size) | |||||
| < sample_size) | |||||
| overruns++; | |||||
| } | |||||
| } | |||||
| /* Tell the disk thread there is work to do. If it is already | |||||
| * running, the lock will not be available. We can't wait | |||||
| * here in the process() thread, but we don't need to signal | |||||
| * in that case, because the disk thread will read all the | |||||
| * data queued before waiting again. */ | |||||
| if (pthread_mutex_trylock (&disk_thread_lock) == 0) { | |||||
| pthread_cond_signal (&data_ready); | |||||
| pthread_mutex_unlock (&disk_thread_lock); | |||||
| } | |||||
| return 0; | |||||
| } | |||||
| void | |||||
| jack_shutdown (void *arg) | |||||
| { | |||||
| fprintf (stderr, "JACK shutdown\n"); | |||||
| // exit (0); | |||||
| abort(); | |||||
| } | |||||
| void | |||||
| setup_disk_thread (jack_thread_info_t *info) | |||||
| { | |||||
| SF_INFO sf_info; | |||||
| int short_mask; | |||||
| sf_info.samplerate = jack_get_sample_rate (info->client); | |||||
| sf_info.channels = info->channels; | |||||
| switch (info->bitdepth) { | |||||
| case 8: short_mask = SF_FORMAT_PCM_U8; | |||||
| break; | |||||
| case 16: short_mask = SF_FORMAT_PCM_16; | |||||
| break; | |||||
| case 24: short_mask = SF_FORMAT_PCM_24; | |||||
| break; | |||||
| case 32: short_mask = SF_FORMAT_PCM_32; | |||||
| break; | |||||
| default: short_mask = SF_FORMAT_PCM_16; | |||||
| break; | |||||
| } | |||||
| sf_info.format = SF_FORMAT_WAV|short_mask; | |||||
| if ((info->sf = sf_open (info->path, SFM_WRITE, &sf_info)) == NULL) { | |||||
| char errstr[256]; | |||||
| sf_error_str (0, errstr, sizeof (errstr) - 1); | |||||
| fprintf (stderr, "cannot open sndfile \"%s\" for output (%s)\n", info->path, errstr); | |||||
| jack_client_close (info->client); | |||||
| exit (1); | |||||
| } | |||||
| if (info->duration == 0) { | |||||
| info->duration = JACK_MAX_FRAMES; | |||||
| } else { | |||||
| info->duration *= sf_info.samplerate; | |||||
| } | |||||
| info->can_capture = 0; | |||||
| pthread_create (&info->thread_id, NULL, disk_thread, info); | |||||
| } | |||||
| void | |||||
| run_disk_thread (jack_thread_info_t *info) | |||||
| { | |||||
| info->can_capture = 1; | |||||
| pthread_join (info->thread_id, NULL); | |||||
| sf_close (info->sf); | |||||
| if (overruns > 0) { | |||||
| fprintf (stderr, | |||||
| "jackrec failed with %ld overruns.\n", overruns); | |||||
| fprintf (stderr, " try a bigger buffer than -B %" | |||||
| PRIu32 ".\n", info->rb_size); | |||||
| info->status = EPIPE; | |||||
| } | |||||
| } | |||||
| void | |||||
| setup_ports (int sources, char *source_names[], jack_thread_info_t *info) | |||||
| { | |||||
| unsigned int i; | |||||
| size_t in_size; | |||||
| /* Allocate data structures that depend on the number of ports. */ | |||||
| nports = sources; | |||||
| ports = (jack_port_t **) malloc (sizeof (jack_port_t *) * nports); | |||||
| in_size = nports * sizeof (jack_default_audio_sample_t *); | |||||
| in = (jack_default_audio_sample_t **) malloc (in_size); | |||||
| rb = jack_ringbuffer_create (nports * sample_size * info->rb_size); | |||||
| /* When JACK is running realtime, jack_activate() will have | |||||
| * called mlockall() to lock our pages into memory. But, we | |||||
| * still need to touch any newly allocated pages before | |||||
| * process() starts using them. Otherwise, a page fault could | |||||
| * create a delay that would force JACK to shut us down. */ | |||||
| memset(in, 0, in_size); | |||||
| memset(rb->buf, 0, rb->size); | |||||
| for (i = 0; i < nports; i++) { | |||||
| char name[64]; | |||||
| sprintf (name, "input%d", i+1); | |||||
| if ((ports[i] = jack_port_register (info->client, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0)) == 0) { | |||||
| fprintf (stderr, "cannot register input port \"%s\"!\n", name); | |||||
| jack_client_close (info->client); | |||||
| exit (1); | |||||
| } | |||||
| } | |||||
| for (i = 0; i < nports; i++) { | |||||
| if (jack_connect (info->client, source_names[i], jack_port_name (ports[i]))) { | |||||
| fprintf (stderr, "cannot connect input port %s to %s\n", jack_port_name (ports[i]), source_names[i]); | |||||
| jack_client_close (info->client); | |||||
| exit (1); | |||||
| } | |||||
| } | |||||
| info->can_process = 1; /* process() can start, now */ | |||||
| } | |||||
| int | |||||
| main (int argc, char *argv[]) | |||||
| { | |||||
| jack_client_t *client; | |||||
| jack_thread_info_t thread_info; | |||||
| int c; | |||||
| int longopt_index = 0; | |||||
| extern int optind, opterr; | |||||
| int show_usage = 0; | |||||
| char *optstring = "d:f:b:B:h"; | |||||
| struct option long_options[] = { | |||||
| { "help", 0, 0, 'h' }, | |||||
| { "duration", 1, 0, 'd' }, | |||||
| { "file", 1, 0, 'f' }, | |||||
| { "bitdepth", 1, 0, 'b' }, | |||||
| { "bufsize", 1, 0, 'B' }, | |||||
| { 0, 0, 0, 0 } | |||||
| }; | |||||
| memset (&thread_info, 0, sizeof (thread_info)); | |||||
| thread_info.rb_size = DEFAULT_RB_SIZE; | |||||
| opterr = 0; | |||||
| while ((c = getopt_long (argc, argv, optstring, long_options, &longopt_index)) != -1) { | |||||
| switch (c) { | |||||
| case 1: | |||||
| /* getopt signals end of '-' options */ | |||||
| break; | |||||
| case 'h': | |||||
| show_usage++; | |||||
| break; | |||||
| case 'd': | |||||
| thread_info.duration = atoi (optarg); | |||||
| break; | |||||
| case 'f': | |||||
| thread_info.path = optarg; | |||||
| break; | |||||
| case 'b': | |||||
| thread_info.bitdepth = atoi (optarg); | |||||
| break; | |||||
| case 'B': | |||||
| thread_info.rb_size = atoi (optarg); | |||||
| break; | |||||
| default: | |||||
| fprintf (stderr, "error\n"); | |||||
| show_usage++; | |||||
| break; | |||||
| } | |||||
| } | |||||
| if (show_usage || thread_info.path == NULL || optind == argc) { | |||||
| fprintf (stderr, "usage: jackrec -f filename [ -d second ] [ -b bitdepth ] [ -B bufsize ] port1 [ port2 ... ]\n"); | |||||
| exit (1); | |||||
| } | |||||
| if ((client = jack_client_new ("jackrec")) == 0) { | |||||
| fprintf (stderr, "jack server not running?\n"); | |||||
| exit (1); | |||||
| } | |||||
| thread_info.client = client; | |||||
| thread_info.channels = argc - optind; | |||||
| thread_info.can_process = 0; | |||||
| setup_disk_thread (&thread_info); | |||||
| jack_set_process_callback (client, process, &thread_info); | |||||
| jack_on_shutdown (client, jack_shutdown, &thread_info); | |||||
| if (jack_activate (client)) { | |||||
| fprintf (stderr, "cannot activate client"); | |||||
| } | |||||
| setup_ports (argc - optind, &argv[optind], &thread_info); | |||||
| run_disk_thread (&thread_info); | |||||
| jack_client_close (client); | |||||
| jack_ringbuffer_free (rb); | |||||
| exit (0); | |||||
| } | |||||