| @@ -0,0 +1,92 @@ | |||
| MAINTAINERCLEANFILES = Makefile.in | |||
| if HAVE_SNDFILE | |||
| JACKREC = jack_rec | |||
| 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 \ | |||
| jack_simple_session_client \ | |||
| jack_transport_client \ | |||
| jack_impulse_grabber \ | |||
| jack_metro \ | |||
| jack_showtime \ | |||
| jack_midisine \ | |||
| jack_midiseq \ | |||
| jack_latent_client \ | |||
| jack_server_control \ | |||
| $(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) | |||
| jack_simple_client_SOURCES = simple_client.c | |||
| jack_simple_client_LDFLAGS = @OS_LDFLAGS@ | |||
| jack_simple_client_LDADD = $(top_builddir)/libjack/libjack.la | |||
| jack_simple_session_client_SOURCES = simple_session_client.c | |||
| jack_simple_session_client_LDFLAGS = @OS_LDFLAGS@ | |||
| jack_simple_session_client_LDADD = $(top_builddir)/libjack/libjack.la | |||
| jack_transport_client_SOURCES = transport_client.c | |||
| jack_transport_client_LDFLAGS = @OS_LDFLAGS@ | |||
| jack_transport_client_LDADD = $(top_builddir)/libjack/libjack.la | |||
| jack_metro_SOURCES = metro.c | |||
| jack_metro_LDFLAGS = @OS_LDFLAGS@ | |||
| jack_metro_LDADD = $(top_builddir)/libjack/libjack.la | |||
| jack_showtime_SOURCES = showtime.c | |||
| jack_showtime_LDFLAGS = @OS_LDFLAGS@ | |||
| jack_showtime_LDADD = $(top_builddir)/libjack/libjack.la | |||
| jack_impulse_grabber_SOURCES = impulse_grabber.c | |||
| jack_impulse_grabber_LDFLAGS = @OS_LDFLAGS@ | |||
| jack_impulse_grabber_LDADD = $(top_builddir)/libjack/libjack.la | |||
| jack_midiseq_SOURCES = midiseq.c | |||
| jack_midiseq_LDFLAGS = @OS_LDFLAGS@ | |||
| jack_midiseq_LDADD = $(top_builddir)/libjack/libjack.la | |||
| jack_midisine_SOURCES = midisine.c | |||
| jack_midisine_LDFLAGS = @OS_LDFLAGS@ | |||
| jack_midisine_LDADD = $(top_builddir)/libjack/libjack.la | |||
| jack_latent_client_SOURCES = latent_client.c | |||
| jack_latent_client_LDFLAGS = @OS_LDFLAGS@ | |||
| jack_latent_client_LDADD = $(top_builddir)/libjack/libjack.la | |||
| jack_server_control_SOURCES = server_control.c | |||
| jack_server_control_LDFLAGS = @OS_LDFLAGS@ | |||
| jack_server_control_LDADD = $(top_builddir)/jackd/libjackserver.la | |||
| if HAVE_SNDFILE | |||
| jack_rec_SOURCES = capture_client.c | |||
| jack_rec_LDFLAGS = @SNDFILE_LIBS@ @OS_LDFLAGS@ | |||
| jack_rec_LDADD = $(top_builddir)/libjack/libjack.la | |||
| endif | |||
| # | |||
| # sample in-process client(s) | |||
| # | |||
| ip_clientdir = $(ADDON_DIR) | |||
| ip_client_LTLIBRARIES = inprocess.la intime.la | |||
| inprocess_la_LDFLAGS = -module -avoid-version @OS_LDFLAGS@ | |||
| inprocess_la_SOURCES = inprocess.c | |||
| intime_la_LDFLAGS = -module -avoid-version @OS_LDFLAGS@ | |||
| intime_la_SOURCES = intime.c | |||
| @@ -0,0 +1,344 @@ | |||
| /* | |||
| 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_open ("jackrec", JackNullOption, NULL)) == 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); | |||
| } | |||
| @@ -0,0 +1,233 @@ | |||
| /* | |||
| * Copyright (C) 2001 Steve Harris | |||
| * | |||
| * 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. | |||
| * | |||
| */ | |||
| #include <stdio.h> | |||
| #include <errno.h> | |||
| #include <unistd.h> | |||
| #include <stdlib.h> | |||
| #include <math.h> | |||
| #include <getopt.h> | |||
| #include <jack/jack.h> | |||
| jack_port_t *input_port; | |||
| jack_port_t *output_port; | |||
| unsigned int impulse_sent = 0; | |||
| float *response; | |||
| unsigned long response_duration; | |||
| unsigned long response_pos; | |||
| int grab_finished = 0; | |||
| int | |||
| process (jack_nframes_t nframes, void *arg) | |||
| { | |||
| jack_default_audio_sample_t *out = (jack_default_audio_sample_t *) jack_port_get_buffer (output_port, nframes); | |||
| jack_default_audio_sample_t *in = (jack_default_audio_sample_t *) jack_port_get_buffer (input_port, nframes); | |||
| unsigned int i; | |||
| if (grab_finished) { | |||
| return 0; | |||
| } else if (impulse_sent) { | |||
| for(i=0; i<nframes && response_pos < response_duration; i++) { | |||
| response[response_pos++] = in[i]; | |||
| } | |||
| if (response_pos >= response_duration) { | |||
| grab_finished = 1; | |||
| } | |||
| for (i=0; i<nframes; i++) { | |||
| out[i] = 0.0f;; | |||
| } | |||
| } else { | |||
| out[0] = 1.0f; | |||
| for (i=1; i<nframes; i++) { | |||
| out[i] = 0.0f; | |||
| } | |||
| impulse_sent = 1; | |||
| } | |||
| return 0; | |||
| } | |||
| void | |||
| jack_shutdown (void *arg) | |||
| { | |||
| exit (1); | |||
| } | |||
| int | |||
| main (int argc, char *argv[]) | |||
| { | |||
| jack_client_t *client; | |||
| const char **ports; | |||
| float fs; // The sample rate | |||
| float peak; | |||
| unsigned long peak_sample; | |||
| unsigned int i; | |||
| float duration = 0.0f; | |||
| unsigned int c_format = 0; | |||
| int longopt_index = 0; | |||
| int c; | |||
| extern int optind, opterr; | |||
| int show_usage = 0; | |||
| char *optstring = "d:f:h"; | |||
| struct option long_options[] = { | |||
| { "help", 1, 0, 'h' }, | |||
| { "duration", 1, 0, 'd' }, | |||
| { "format", 1, 0, 'f' }, | |||
| { 0, 0, 0, 0 } | |||
| }; | |||
| while ((c = getopt_long (argc, argv, optstring, long_options, &longopt_index)) != -1) { | |||
| switch (c) { | |||
| case 1: | |||
| // end of opts, but don't care | |||
| break; | |||
| case 'h': | |||
| show_usage++; | |||
| break; | |||
| case 'd': | |||
| duration = (float)atof(optarg); | |||
| break; | |||
| case 'f': | |||
| if (*optarg == 'c' || *optarg == 'C') { | |||
| c_format = 1; | |||
| } | |||
| break; | |||
| default: | |||
| show_usage++; | |||
| break; | |||
| } | |||
| } | |||
| if (show_usage || duration <= 0.0f) { | |||
| fprintf(stderr, "usage: jack_impulse_grab -d duration [-f (C|gnuplot)]\n"); | |||
| exit(1); | |||
| } | |||
| /* try to become a client of the JACK server */ | |||
| if ((client = jack_client_open("impulse_grabber", JackNullOption, NULL)) == 0) { | |||
| fprintf (stderr, "jack server not running?\n"); | |||
| return 1; | |||
| } | |||
| /* tell the JACK server to call `process()' whenever | |||
| there is work to be done. | |||
| */ | |||
| jack_set_process_callback (client, process, 0); | |||
| /* tell the JACK server to call `jack_shutdown()' if | |||
| it ever shuts down, either entirely, or if it | |||
| just decides to stop calling us. | |||
| */ | |||
| jack_on_shutdown (client, jack_shutdown, 0); | |||
| /* display the current sample rate. once the client is activated | |||
| (see below), you should rely on your own sample rate | |||
| callback (see above) for this value. | |||
| */ | |||
| fs = jack_get_sample_rate(client); | |||
| response_duration = (unsigned long) (fs * duration); | |||
| response = malloc(response_duration * sizeof(float)); | |||
| fprintf(stderr, | |||
| "Grabbing %f seconds (%lu samples) of impulse response\n", | |||
| duration, response_duration); | |||
| /* create two ports */ | |||
| input_port = jack_port_register (client, "input", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0); | |||
| output_port = jack_port_register (client, "output", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); | |||
| /* tell the JACK server that we are ready to roll */ | |||
| if (jack_activate (client)) { | |||
| fprintf (stderr, "cannot activate client"); | |||
| return 1; | |||
| } | |||
| /* connect the ports. Note: you can't do this before | |||
| the client is activated (this may change in the future). | |||
| */ | |||
| if ((ports = jack_get_ports (client, NULL, NULL, JackPortIsPhysical|JackPortIsOutput)) == NULL) { | |||
| fprintf(stderr, "Cannot find any physical capture ports"); | |||
| exit(1); | |||
| } | |||
| if (jack_connect (client, ports[0], jack_port_name (input_port))) { | |||
| fprintf (stderr, "cannot connect input ports\n"); | |||
| } | |||
| free (ports); | |||
| if ((ports = jack_get_ports (client, NULL, NULL, JackPortIsPhysical|JackPortIsInput)) == NULL) { | |||
| fprintf(stderr, "Cannot find any physical playback ports"); | |||
| exit(1); | |||
| } | |||
| if (jack_connect (client, jack_port_name (output_port), ports[0])) { | |||
| fprintf (stderr, "cannot connect output ports\n"); | |||
| } | |||
| free (ports); | |||
| /* Wait for grab to finish */ | |||
| while (!grab_finished) { | |||
| sleep (1); | |||
| } | |||
| jack_client_close (client); | |||
| peak = response[0]; | |||
| peak_sample = 0; | |||
| if (c_format) { | |||
| printf("impulse[%lu] = {", response_duration); | |||
| for (i=0; i<response_duration; i++) { | |||
| if (i % 4 != 0) { | |||
| printf(" "); | |||
| } else { | |||
| printf("\n\t"); | |||
| } | |||
| printf("\"%+1.10f\"", response[i]); | |||
| if (i < response_duration - 1) { | |||
| printf(","); | |||
| } | |||
| if (fabs(response[i]) > peak) { | |||
| peak = fabs(response[i]); | |||
| peak_sample = i; | |||
| } | |||
| } | |||
| printf("\n};\n"); | |||
| } else { | |||
| for (i=0; i<response_duration; i++) { | |||
| printf("%1.12f\n", response[i]); | |||
| if (fabs(response[i]) > peak) { | |||
| peak = fabs(response[i]); | |||
| peak_sample = i; | |||
| } | |||
| } | |||
| } | |||
| fprintf(stderr, "Peak value was %f at sample %lu\n", peak, peak_sample); | |||
| exit (0); | |||
| } | |||
| @@ -0,0 +1,110 @@ | |||
| /** @file inprocess.c | |||
| * | |||
| * @brief This demonstrates the basic concepts for writing a client | |||
| * that runs within the JACK server process. | |||
| * | |||
| * For the sake of example, a port_pair_t is allocated in | |||
| * jack_initialize(), passed to inprocess() as an argument, then freed | |||
| * in jack_finish(). | |||
| */ | |||
| #include <stdlib.h> | |||
| #include <stdio.h> | |||
| #include <memory.h> | |||
| #include <jack/jack.h> | |||
| /** | |||
| * For the sake of example, an instance of this struct is allocated in | |||
| * jack_initialize(), passed to inprocess() as an argument, then freed | |||
| * in jack_finish(). | |||
| */ | |||
| typedef struct { | |||
| jack_port_t *input_port; | |||
| jack_port_t *output_port; | |||
| } port_pair_t; | |||
| /** | |||
| * Called in the realtime thread on every process cycle. The entry | |||
| * point name was passed to jack_set_process_callback() from | |||
| * jack_initialize(). Although this is an internal client, its | |||
| * process() interface is identical to @ref simple_client.c. | |||
| * | |||
| * @return 0 if successful; otherwise jack_finish() will be called and | |||
| * the client terminated immediately. | |||
| */ | |||
| int | |||
| inprocess (jack_nframes_t nframes, void *arg) | |||
| { | |||
| port_pair_t *pp = arg; | |||
| jack_default_audio_sample_t *out = | |||
| jack_port_get_buffer (pp->output_port, nframes); | |||
| jack_default_audio_sample_t *in = | |||
| jack_port_get_buffer (pp->input_port, nframes); | |||
| memcpy (out, in, sizeof (jack_default_audio_sample_t) * nframes); | |||
| return 0; /* continue */ | |||
| } | |||
| /** | |||
| * This required entry point is called after the client is loaded by | |||
| * jack_internal_client_load(). | |||
| * | |||
| * @param client pointer to JACK client structure. | |||
| * @param load_init character string passed to the load operation. | |||
| * | |||
| * @return 0 if successful; otherwise jack_finish() will be called and | |||
| * the client terminated immediately. | |||
| */ | |||
| int | |||
| jack_initialize (jack_client_t *client, const char *load_init) | |||
| { | |||
| port_pair_t *pp = malloc (sizeof (port_pair_t)); | |||
| if (pp == NULL) | |||
| return 1; /* heap exhausted */ | |||
| jack_set_process_callback (client, inprocess, pp); | |||
| /* create a pair of ports */ | |||
| pp->input_port = jack_port_register (client, "input", | |||
| JACK_DEFAULT_AUDIO_TYPE, | |||
| JackPortIsInput, 0); | |||
| pp->output_port = jack_port_register (client, "output", | |||
| JACK_DEFAULT_AUDIO_TYPE, | |||
| JackPortIsOutput, 0); | |||
| /* join the process() cycle */ | |||
| jack_activate (client); | |||
| /* try to connect to the first physical input & output ports */ | |||
| if (jack_connect (client, "system:capture_1", | |||
| jack_port_name (pp->input_port))) { | |||
| fprintf (stderr, "cannot connect input port\n"); | |||
| return 1; /* terminate client */ | |||
| } | |||
| if (jack_connect (client, jack_port_name (pp->output_port), | |||
| "system:playback_1")) { | |||
| fprintf (stderr, "cannot connect output port\n"); | |||
| return 1; /* terminate client */ | |||
| } | |||
| return 0; /* success */ | |||
| } | |||
| /** | |||
| * This required entry point is called immediately before the client | |||
| * is unloaded, which could happen due to a call to | |||
| * jack_internal_client_unload(), or a nonzero return from either | |||
| * jack_initialize() or inprocess(). | |||
| * | |||
| * @param arg the same parameter provided to inprocess(). | |||
| */ | |||
| void | |||
| jack_finish (void *arg) | |||
| { | |||
| if (arg) | |||
| free ((port_pair_t *) arg); | |||
| } | |||
| @@ -0,0 +1,157 @@ | |||
| /* | |||
| * intime.c -- JACK internal timebase master example client. | |||
| * | |||
| * To run: first start `jackd', then `jack_load intime intime 6/8,180bpm'. | |||
| */ | |||
| /* 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. | |||
| */ | |||
| #include <stdio.h> | |||
| #include <string.h> | |||
| #include <jack/jack.h> | |||
| /* Time and tempo variables, global to the entire transport timeline. | |||
| * There is no attempt to keep a true tempo map. The default time | |||
| * signature is "march time": 4/4, 120bpm | |||
| */ | |||
| float time_beats_per_bar = 4.0; | |||
| float time_beat_type = 4.0; | |||
| double time_ticks_per_beat = 1920.0; | |||
| double time_beats_per_minute = 120.0; | |||
| /* BBT timebase callback. | |||
| * | |||
| * Runs in the process thread. Realtime, must not wait. | |||
| */ | |||
| void | |||
| timebbt (jack_transport_state_t state, jack_nframes_t nframes, | |||
| jack_position_t *pos, int new_pos, void *arg) | |||
| { | |||
| double min; /* minutes since frame 0 */ | |||
| long abs_tick; /* ticks since frame 0 */ | |||
| long abs_beat; /* beats since frame 0 */ | |||
| if (new_pos) { | |||
| pos->valid = JackPositionBBT; | |||
| pos->beats_per_bar = time_beats_per_bar; | |||
| pos->beat_type = time_beat_type; | |||
| pos->ticks_per_beat = time_ticks_per_beat; | |||
| pos->beats_per_minute = time_beats_per_minute; | |||
| /* Compute BBT info from frame number. This is | |||
| * relatively simple here, but would become complex if | |||
| * we supported tempo or time signature changes at | |||
| * specific locations in the transport timeline. I | |||
| * make no claims for the numerical accuracy or | |||
| * efficiency of these calculations. */ | |||
| min = pos->frame / ((double) pos->frame_rate * 60.0); | |||
| abs_tick = min * pos->beats_per_minute * pos->ticks_per_beat; | |||
| abs_beat = abs_tick / pos->ticks_per_beat; | |||
| pos->bar = abs_beat / pos->beats_per_bar; | |||
| pos->beat = abs_beat - (pos->bar * pos->beats_per_bar) + 1; | |||
| pos->tick = abs_tick - (abs_beat * pos->ticks_per_beat); | |||
| pos->bar_start_tick = pos->bar * pos->beats_per_bar * | |||
| pos->ticks_per_beat; | |||
| pos->bar++; /* adjust start to bar 1 */ | |||
| /* some debug code... */ | |||
| fprintf(stderr, "\nnew position: %" PRIu32 "\tBBT: %3" | |||
| PRIi32 "|%" PRIi32 "|%04" PRIi32 "\n", | |||
| pos->frame, pos->bar, pos->beat, pos->tick); | |||
| } else { | |||
| /* Compute BBT info based on previous period. */ | |||
| pos->tick += (nframes * pos->ticks_per_beat * | |||
| pos->beats_per_minute / (pos->frame_rate * 60)); | |||
| while (pos->tick >= pos->ticks_per_beat) { | |||
| pos->tick -= pos->ticks_per_beat; | |||
| if (++pos->beat > pos->beats_per_bar) { | |||
| pos->beat = 1; | |||
| ++pos->bar; | |||
| pos->bar_start_tick += (pos->beats_per_bar * | |||
| pos->ticks_per_beat); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| /* experimental timecode callback | |||
| * | |||
| * Fill in extended timecode fields using the trivial assumption that | |||
| * we are running at nominal speed, hence with no drift. | |||
| * | |||
| * It would probably be faster to compute frame_time without the | |||
| * conditional expression. But, this demonstrates the invariant: | |||
| * next_time[i] == frame_time[i+1], unless a reposition occurs. | |||
| * | |||
| * Runs in the process thread. Realtime, must not wait. | |||
| */ | |||
| void | |||
| timecode (jack_transport_state_t state, jack_nframes_t nframes, | |||
| jack_position_t *pos, int new_pos, void *arg) | |||
| { | |||
| /* nominal transport speed */ | |||
| double seconds_per_frame = 1.0 / (double) pos->frame_rate; | |||
| pos->valid = JackPositionTimecode; | |||
| pos->frame_time = (new_pos? | |||
| pos->frame * seconds_per_frame: | |||
| pos->next_time); | |||
| pos->next_time = (pos->frame + nframes) * seconds_per_frame; | |||
| } | |||
| /* after internal client loaded */ | |||
| int | |||
| jack_initialize (jack_client_t *client, const char *load_init) | |||
| { | |||
| JackTimebaseCallback callback = timebbt; | |||
| int rc = sscanf(load_init, " %f/%f, %lf bpm ", &time_beats_per_bar, | |||
| &time_beat_type, &time_beats_per_minute); | |||
| if (rc > 0) { | |||
| fprintf (stderr, "counting %.1f/%.1f at %.2f bpm\n", | |||
| time_beats_per_bar, time_beat_type, | |||
| time_beats_per_minute); | |||
| } else { | |||
| int len = strlen(load_init); | |||
| if ((len > 0) && (strncmp(load_init, "timecode", len) == 0)) | |||
| callback = timecode; | |||
| } | |||
| if (jack_set_timebase_callback(client, 0, callback, NULL) != 0) { | |||
| fprintf (stderr, "Unable to take over timebase.\n"); | |||
| return 1; /* terminate */ | |||
| } | |||
| fprintf (stderr, "Internal timebase master defined.\n"); | |||
| jack_activate (client); | |||
| return 0; /* success */ | |||
| } | |||
| /* before unloading */ | |||
| void | |||
| jack_finish (void *arg) | |||
| { | |||
| fprintf (stderr, "Internal timebase client exiting.\n"); | |||
| } | |||
| @@ -0,0 +1,208 @@ | |||
| /** @file simple_client.c | |||
| * | |||
| * @brief This simple client demonstrates the most basic features of JACK | |||
| * as they would be used by many applications. | |||
| */ | |||
| #include <stdio.h> | |||
| #include <errno.h> | |||
| #include <unistd.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include <jack/jack.h> | |||
| jack_port_t *input_port; | |||
| jack_port_t *output_port; | |||
| jack_client_t *client; | |||
| jack_default_audio_sample_t *delay_line; | |||
| jack_nframes_t delay_index; | |||
| jack_nframes_t latency = 1024; | |||
| /** | |||
| * The process callback for this JACK application is called in a | |||
| * special realtime thread once for each audio cycle. | |||
| * | |||
| * This client does nothing more than copy data from its input | |||
| * port to its output port. It will exit when stopped by | |||
| * the user (e.g. using Ctrl-C on a unix-ish operating system) | |||
| */ | |||
| int | |||
| process (jack_nframes_t nframes, void *arg) | |||
| { | |||
| jack_default_audio_sample_t *in, *out; | |||
| int k; | |||
| in = jack_port_get_buffer (input_port, nframes); | |||
| out = jack_port_get_buffer (output_port, nframes); | |||
| for (k=0; k<nframes; k++) { | |||
| out[k] = delay_line[delay_index]; | |||
| delay_line[delay_index] = in[k]; | |||
| delay_index = (delay_index + 1) % latency; | |||
| } | |||
| return 0; | |||
| } | |||
| void | |||
| latency_cb (jack_latency_callback_mode_t mode, void *arg) | |||
| { | |||
| jack_latency_range_t range; | |||
| if (mode == JackCaptureLatency) { | |||
| jack_port_get_latency_range (input_port, mode, &range); | |||
| range.min += latency; | |||
| range.max += latency; | |||
| jack_port_set_latency_range (output_port, mode, &range); | |||
| } else { | |||
| jack_port_get_latency_range (output_port, mode, &range); | |||
| range.min += latency; | |||
| range.max += latency; | |||
| jack_port_set_latency_range (input_port, mode, &range); | |||
| } | |||
| } | |||
| /** | |||
| * JACK calls this shutdown_callback if the server ever shuts down or | |||
| * decides to disconnect the client. | |||
| */ | |||
| void | |||
| jack_shutdown (void *arg) | |||
| { | |||
| exit (1); | |||
| } | |||
| int | |||
| main (int argc, char *argv[]) | |||
| { | |||
| const char **ports; | |||
| const char *client_name = "latent"; | |||
| const char *server_name = NULL; | |||
| jack_options_t options = JackNullOption; | |||
| jack_status_t status; | |||
| if (argc == 2) | |||
| latency = atoi(argv[1]); | |||
| delay_line = malloc( latency * sizeof(jack_default_audio_sample_t)); | |||
| if (delay_line == NULL) { | |||
| fprintf (stderr, "no memory"); | |||
| exit(1); | |||
| } | |||
| memset (delay_line, 0, latency * sizeof(jack_default_audio_sample_t)); | |||
| /* open a client connection to the JACK server */ | |||
| client = jack_client_open (client_name, options, &status, server_name); | |||
| if (client == NULL) { | |||
| fprintf (stderr, "jack_client_open() failed, " | |||
| "status = 0x%2.0x\n", status); | |||
| if (status & JackServerFailed) { | |||
| fprintf (stderr, "Unable to connect to JACK server\n"); | |||
| } | |||
| exit (1); | |||
| } | |||
| if (status & JackServerStarted) { | |||
| fprintf (stderr, "JACK server started\n"); | |||
| } | |||
| if (status & JackNameNotUnique) { | |||
| client_name = jack_get_client_name(client); | |||
| fprintf (stderr, "unique name `%s' assigned\n", client_name); | |||
| } | |||
| /* tell the JACK server to call `process()' whenever | |||
| there is work to be done. | |||
| */ | |||
| jack_set_process_callback (client, process, 0); | |||
| /* tell the JACK server to call `latency()' whenever | |||
| the latency needs to be recalculated. | |||
| */ | |||
| if (jack_set_latency_callback) | |||
| jack_set_latency_callback (client, latency_cb, 0); | |||
| /* tell the JACK server to call `jack_shutdown()' if | |||
| it ever shuts down, either entirely, or if it | |||
| just decides to stop calling us. | |||
| */ | |||
| jack_on_shutdown (client, jack_shutdown, 0); | |||
| /* display the current sample rate. | |||
| */ | |||
| printf ("engine sample rate: %" PRIu32 "\n", | |||
| jack_get_sample_rate (client)); | |||
| /* create two ports */ | |||
| input_port = jack_port_register (client, "input", | |||
| JACK_DEFAULT_AUDIO_TYPE, | |||
| JackPortIsInput, 0); | |||
| output_port = jack_port_register (client, "output", | |||
| JACK_DEFAULT_AUDIO_TYPE, | |||
| JackPortIsOutput, 0); | |||
| if ((input_port == NULL) || (output_port == NULL)) { | |||
| fprintf(stderr, "no more JACK ports available\n"); | |||
| exit (1); | |||
| } | |||
| /* Tell the JACK server that we are ready to roll. Our | |||
| * process() callback will start running now. */ | |||
| if (jack_activate (client)) { | |||
| fprintf (stderr, "cannot activate client"); | |||
| exit (1); | |||
| } | |||
| /* Connect the ports. You can't do this before the client is | |||
| * activated, because we can't make connections to clients | |||
| * that aren't running. Note the confusing (but necessary) | |||
| * orientation of the driver backend ports: playback ports are | |||
| * "input" to the backend, and capture ports are "output" from | |||
| * it. | |||
| */ | |||
| ports = jack_get_ports (client, NULL, NULL, | |||
| JackPortIsPhysical|JackPortIsOutput); | |||
| if (ports == NULL) { | |||
| fprintf(stderr, "no physical capture ports\n"); | |||
| exit (1); | |||
| } | |||
| if (jack_connect (client, ports[0], jack_port_name (input_port))) { | |||
| fprintf (stderr, "cannot connect input ports\n"); | |||
| } | |||
| free (ports); | |||
| ports = jack_get_ports (client, NULL, NULL, | |||
| JackPortIsPhysical|JackPortIsInput); | |||
| if (ports == NULL) { | |||
| fprintf(stderr, "no physical playback ports\n"); | |||
| exit (1); | |||
| } | |||
| if (jack_connect (client, jack_port_name (output_port), ports[0])) { | |||
| fprintf (stderr, "cannot connect output ports\n"); | |||
| } | |||
| free (ports); | |||
| /* keep running until stopped by the user */ | |||
| sleep (-1); | |||
| /* this is never reached but if the program | |||
| had some other way to exit besides being killed, | |||
| they would be important to call. | |||
| */ | |||
| jack_client_close (client); | |||
| exit (0); | |||
| } | |||
| @@ -0,0 +1,268 @@ | |||
| /* | |||
| Copyright (C) 2002 Anthony Van Groningen | |||
| 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. | |||
| */ | |||
| #include <stdlib.h> | |||
| #include <stdio.h> | |||
| #include <errno.h> | |||
| #include <unistd.h> | |||
| #include <math.h> | |||
| #include <getopt.h> | |||
| #include <string.h> | |||
| #include <jack/jack.h> | |||
| #include <jack/transport.h> | |||
| typedef jack_default_audio_sample_t sample_t; | |||
| const double PI = 3.14; | |||
| jack_client_t *client; | |||
| jack_port_t *output_port; | |||
| unsigned long sr; | |||
| int freq = 880; | |||
| int bpm; | |||
| jack_nframes_t tone_length, wave_length; | |||
| sample_t *wave; | |||
| long offset = 0; | |||
| int transport_aware = 0; | |||
| jack_transport_state_t transport_state; | |||
| void | |||
| usage () | |||
| { | |||
| fprintf (stderr, "\n" | |||
| "usage: jack_metro \n" | |||
| " [ --frequency OR -f frequency (in Hz) ]\n" | |||
| " [ --amplitude OR -A maximum amplitude (between 0 and 1) ]\n" | |||
| " [ --duration OR -D duration (in ms) ]\n" | |||
| " [ --attack OR -a attack (in percent of duration) ]\n" | |||
| " [ --decay OR -d decay (in percent of duration) ]\n" | |||
| " [ --name OR -n jack name for metronome client ]\n" | |||
| " [ --transport OR -t transport aware ]\n" | |||
| " --bpm OR -b beats per minute\n" | |||
| ); | |||
| } | |||
| void | |||
| process_silence (jack_nframes_t nframes) | |||
| { | |||
| sample_t *buffer = (sample_t *) jack_port_get_buffer (output_port, nframes); | |||
| memset (buffer, 0, sizeof (jack_default_audio_sample_t) * nframes); | |||
| } | |||
| void | |||
| process_audio (jack_nframes_t nframes) | |||
| { | |||
| sample_t *buffer = (sample_t *) jack_port_get_buffer (output_port, nframes); | |||
| jack_nframes_t frames_left = nframes; | |||
| while (wave_length - offset < frames_left) { | |||
| memcpy (buffer + (nframes - frames_left), wave + offset, sizeof (sample_t) * (wave_length - offset)); | |||
| frames_left -= wave_length - offset; | |||
| offset = 0; | |||
| } | |||
| if (frames_left > 0) { | |||
| memcpy (buffer + (nframes - frames_left), wave + offset, sizeof (sample_t) * frames_left); | |||
| offset += frames_left; | |||
| } | |||
| } | |||
| int | |||
| process (jack_nframes_t nframes, void *arg) | |||
| { | |||
| if (transport_aware) { | |||
| jack_position_t pos; | |||
| if (jack_transport_query (client, &pos) | |||
| != JackTransportRolling) { | |||
| process_silence (nframes); | |||
| return 0; | |||
| } | |||
| offset = pos.frame % wave_length; | |||
| } | |||
| process_audio (nframes); | |||
| return 0; | |||
| } | |||
| int | |||
| sample_rate_change () { | |||
| printf("Sample rate has changed! Exiting...\n"); | |||
| exit(-1); | |||
| } | |||
| int | |||
| main (int argc, char *argv[]) | |||
| { | |||
| sample_t scale; | |||
| int i, attack_length, decay_length; | |||
| double *amp; | |||
| double max_amp = 0.5; | |||
| int option_index; | |||
| int opt; | |||
| int got_bpm = 0; | |||
| int attack_percent = 1, decay_percent = 10, dur_arg = 100; | |||
| char *client_name = 0; | |||
| char *bpm_string = "bpm"; | |||
| int verbose = 0; | |||
| jack_status_t status; | |||
| const char *options = "f:A:D:a:d:b:n:thv"; | |||
| struct option long_options[] = | |||
| { | |||
| {"frequency", 1, 0, 'f'}, | |||
| {"amplitude", 1, 0, 'A'}, | |||
| {"duration", 1, 0, 'D'}, | |||
| {"attack", 1, 0, 'a'}, | |||
| {"decay", 1, 0, 'd'}, | |||
| {"bpm", 1, 0, 'b'}, | |||
| {"name", 1, 0, 'n'}, | |||
| {"transport", 0, 0, 't'}, | |||
| {"help", 0, 0, 'h'}, | |||
| {"verbose", 0, 0, 'v'}, | |||
| {0, 0, 0, 0} | |||
| }; | |||
| while ((opt = getopt_long (argc, argv, options, long_options, &option_index)) != EOF) { | |||
| switch (opt) { | |||
| case 'f': | |||
| if ((freq = atoi (optarg)) <= 0) { | |||
| fprintf (stderr, "invalid frequency\n"); | |||
| return -1; | |||
| } | |||
| break; | |||
| case 'A': | |||
| if (((max_amp = atof (optarg)) <= 0)|| (max_amp > 1)) { | |||
| fprintf (stderr, "invalid amplitude\n"); | |||
| return -1; | |||
| } | |||
| break; | |||
| case 'D': | |||
| dur_arg = atoi (optarg); | |||
| fprintf (stderr, "durarg = %u\n", dur_arg); | |||
| break; | |||
| case 'a': | |||
| if (((attack_percent = atoi (optarg)) < 0) || (attack_percent > 100)) { | |||
| fprintf (stderr, "invalid attack percent\n"); | |||
| return -1; | |||
| } | |||
| break; | |||
| case 'd': | |||
| if (((decay_percent = atoi (optarg)) < 0) || (decay_percent > 100)) { | |||
| fprintf (stderr, "invalid decay percent\n"); | |||
| return -1; | |||
| } | |||
| break; | |||
| case 'b': | |||
| got_bpm = 1; | |||
| if ((bpm = atoi (optarg)) < 0) { | |||
| fprintf (stderr, "invalid bpm\n"); | |||
| return -1; | |||
| } | |||
| bpm_string = (char *) malloc ((strlen (optarg) + 4) * sizeof (char)); | |||
| strcpy (bpm_string, optarg); | |||
| strcat (bpm_string, "_bpm"); | |||
| break; | |||
| case 'n': | |||
| client_name = (char *) malloc (strlen (optarg) * sizeof (char)); | |||
| strcpy (client_name, optarg); | |||
| break; | |||
| case 'v': | |||
| verbose = 1; | |||
| break; | |||
| case 't': | |||
| transport_aware = 1; | |||
| break; | |||
| default: | |||
| fprintf (stderr, "unknown option %c\n", opt); | |||
| case 'h': | |||
| usage (); | |||
| return -1; | |||
| } | |||
| } | |||
| if (!got_bpm) { | |||
| fprintf (stderr, "bpm not specified\n"); | |||
| usage (); | |||
| return -1; | |||
| } | |||
| /* Initial Jack setup, get sample rate */ | |||
| if (!client_name) { | |||
| client_name = (char *) malloc (9 * sizeof (char)); | |||
| strcpy (client_name, "metro"); | |||
| } | |||
| if ((client = jack_client_open (client_name, JackNoStartServer, &status)) == 0) { | |||
| fprintf (stderr, "jack server not running?\n"); | |||
| return 1; | |||
| } | |||
| jack_set_process_callback (client, process, 0); | |||
| output_port = jack_port_register (client, bpm_string, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); | |||
| sr = jack_get_sample_rate (client); | |||
| /* setup wave table parameters */ | |||
| wave_length = 60 * sr / bpm; | |||
| tone_length = sr * dur_arg / 1000; | |||
| attack_length = tone_length * attack_percent / 100; | |||
| decay_length = tone_length * decay_percent / 100; | |||
| scale = 2 * PI * freq / sr; | |||
| if (tone_length >= wave_length) { | |||
| fprintf (stderr, "invalid duration (tone length = %" PRIu32 | |||
| ", wave length = %" PRIu32 "\n", tone_length, | |||
| wave_length); | |||
| return -1; | |||
| } | |||
| if (attack_length + decay_length > (int)tone_length) { | |||
| fprintf (stderr, "invalid attack/decay\n"); | |||
| return -1; | |||
| } | |||
| /* Build the wave table */ | |||
| wave = (sample_t *) malloc (wave_length * sizeof(sample_t)); | |||
| amp = (double *) malloc (tone_length * sizeof(double)); | |||
| for (i = 0; i < attack_length; i++) { | |||
| amp[i] = max_amp * i / ((double) attack_length); | |||
| } | |||
| for (i = attack_length; i < (int)tone_length - decay_length; i++) { | |||
| amp[i] = max_amp; | |||
| } | |||
| for (i = (int)tone_length - decay_length; i < (int)tone_length; i++) { | |||
| amp[i] = - max_amp * (i - (double) tone_length) / ((double) decay_length); | |||
| } | |||
| for (i = 0; i < (int)tone_length; i++) { | |||
| wave[i] = amp[i] * sin (scale * i); | |||
| } | |||
| for (i = tone_length; i < (int)wave_length; i++) { | |||
| wave[i] = 0; | |||
| } | |||
| if (jack_activate (client)) { | |||
| fprintf (stderr, "cannot activate client"); | |||
| return 1; | |||
| } | |||
| while (1) { | |||
| sleep(1); | |||
| }; | |||
| } | |||
| @@ -0,0 +1,118 @@ | |||
| /* | |||
| Copyright (C) 2004 Ian Esten | |||
| 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. | |||
| */ | |||
| #include <jack/jack.h> | |||
| #include <jack/midiport.h> | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <unistd.h> | |||
| jack_client_t *client; | |||
| jack_port_t *output_port; | |||
| unsigned char* note_frqs; | |||
| jack_nframes_t* note_starts; | |||
| jack_nframes_t* note_lengths; | |||
| jack_nframes_t num_notes; | |||
| jack_nframes_t loop_nsamp; | |||
| jack_nframes_t loop_index; | |||
| void usage() | |||
| { | |||
| fprintf(stderr, "usage: jack_midiseq name nsamp [startindex note nsamp] ...... [startindex note nsamp]\n"); | |||
| fprintf(stderr, "eg: jack_midiseq Sequencer 24000 0 60 8000 12000 63 8000\n"); | |||
| fprintf(stderr, "will play a 1/2 sec loop (if srate is 48khz) with a c4 note at the start of the loop\n"); | |||
| fprintf(stderr, "that lasts for 12000 samples, then a d4# that starts at 1/4 sec that lasts for 800 samples\n"); | |||
| } | |||
| int process(jack_nframes_t nframes, void *arg) | |||
| { | |||
| int i,j; | |||
| void* port_buf = jack_port_get_buffer(output_port, nframes); | |||
| unsigned char* buffer; | |||
| jack_midi_clear_buffer(port_buf); | |||
| /*memset(buffer, 0, nframes*sizeof(jack_default_audio_sample_t));*/ | |||
| for(i=0; i<nframes; i++) | |||
| { | |||
| for(j=0; j<num_notes; j++) | |||
| { | |||
| if(note_starts[j] == loop_index) | |||
| { | |||
| buffer = jack_midi_event_reserve(port_buf, i, 3); | |||
| /* printf("wrote a note on, port buffer = 0x%x, event buffer = 0x%x\n", port_buf, buffer);*/ | |||
| buffer[2] = 64; /* velocity */ | |||
| buffer[1] = note_frqs[j]; | |||
| buffer[0] = 0x90; /* note on */ | |||
| } | |||
| else if(note_starts[j] + note_lengths[j] == loop_index) | |||
| { | |||
| buffer = jack_midi_event_reserve(port_buf, i, 3); | |||
| /* printf("wrote a note off, port buffer = 0x%x, event buffer = 0x%x\n", port_buf, buffer);*/ | |||
| buffer[2] = 64; /* velocity */ | |||
| buffer[1] = note_frqs[j]; | |||
| buffer[0] = 0x80; /* note off */ | |||
| } | |||
| } | |||
| loop_index = loop_index+1 >= loop_nsamp ? 0 : loop_index+1; | |||
| } | |||
| return 0; | |||
| } | |||
| int main(int narg, char **args) | |||
| { | |||
| int i; | |||
| jack_nframes_t nframes; | |||
| if((narg<6) || ((narg-3)%3 !=0)) | |||
| { | |||
| usage(); | |||
| exit(1); | |||
| } | |||
| if((client = jack_client_open (args[1], JackNullOption, NULL)) == 0) | |||
| { | |||
| fprintf (stderr, "jack server not running?\n"); | |||
| return 1; | |||
| } | |||
| jack_set_process_callback (client, process, 0); | |||
| output_port = jack_port_register (client, "out", JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0); | |||
| nframes = jack_get_buffer_size(client); | |||
| loop_index = 0; | |||
| num_notes = (narg - 3)/3; | |||
| note_frqs = malloc(num_notes*sizeof(unsigned char)); | |||
| note_starts = malloc(num_notes*sizeof(unsigned char)); | |||
| note_lengths = malloc(num_notes*sizeof(jack_nframes_t)); | |||
| loop_nsamp = atoi(args[2]); | |||
| for(i=0; i<num_notes; i++) | |||
| { | |||
| note_starts[i] = atoi(args[3 + 3*i]); | |||
| note_frqs[i] = atoi(args[4 + 3*i]); | |||
| note_lengths[i] = atoi(args[5 + 3*i]); | |||
| } | |||
| if (jack_activate(client)) | |||
| { | |||
| fprintf (stderr, "cannot activate client"); | |||
| return 1; | |||
| } | |||
| while (1) | |||
| { | |||
| sleep(1); | |||
| }; | |||
| } | |||
| @@ -0,0 +1,138 @@ | |||
| /* | |||
| Copyright (C) 2004 Ian Esten | |||
| 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. | |||
| */ | |||
| #include <stdio.h> | |||
| #include <errno.h> | |||
| #include <unistd.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include <math.h> | |||
| #include <jack/jack.h> | |||
| #include <jack/midiport.h> | |||
| jack_port_t *input_port; | |||
| jack_port_t *output_port; | |||
| jack_default_audio_sample_t ramp=0.0; | |||
| jack_default_audio_sample_t note_on; | |||
| unsigned char note = 0; | |||
| jack_default_audio_sample_t note_frqs[128]; | |||
| void calc_note_frqs(jack_default_audio_sample_t srate) | |||
| { | |||
| int i; | |||
| for(i=0; i<128; i++) | |||
| { | |||
| note_frqs[i] = (2.0 * 440.0 / 32.0) * pow(2, (((jack_default_audio_sample_t)i - 9.0) / 12.0)) / srate; | |||
| } | |||
| } | |||
| int process(jack_nframes_t nframes, void *arg) | |||
| { | |||
| int i; | |||
| void* port_buf = jack_port_get_buffer(input_port, nframes); | |||
| jack_default_audio_sample_t *out = (jack_default_audio_sample_t *) jack_port_get_buffer (output_port, nframes); | |||
| jack_midi_event_t in_event; | |||
| jack_nframes_t event_index = 0; | |||
| jack_nframes_t event_count = jack_midi_get_event_count(port_buf); | |||
| if(event_count > 1) | |||
| { | |||
| printf(" midisine: have %d events\n", event_count); | |||
| for(i=0; i<event_count; i++) | |||
| { | |||
| jack_midi_event_get(&in_event, port_buf, i); | |||
| printf(" event %d time is %d. 1st byte is 0x%x\n", i, in_event.time, *(in_event.buffer)); | |||
| } | |||
| /* printf("1st byte of 1st event addr is %p\n", in_events[0].buffer);*/ | |||
| } | |||
| jack_midi_event_get(&in_event, port_buf, 0); | |||
| for(i=0; i<nframes; i++) | |||
| { | |||
| if((in_event.time == i) && (event_index < event_count)) | |||
| { | |||
| if( ((*(in_event.buffer) & 0xf0)) == 0x90 ) | |||
| { | |||
| /* note on */ | |||
| note = *(in_event.buffer + 1); | |||
| note_on = 1.0; | |||
| } | |||
| else if( ((*(in_event.buffer)) & 0xf0) == 0x80 ) | |||
| { | |||
| /* note off */ | |||
| note = *(in_event.buffer + 1); | |||
| note_on = 0.0; | |||
| } | |||
| event_index++; | |||
| if(event_index < event_count) | |||
| jack_midi_event_get(&in_event, port_buf, event_index); | |||
| } | |||
| ramp += note_frqs[note]; | |||
| ramp = (ramp > 1.0) ? ramp - 2.0 : ramp; | |||
| out[i] = note_on*sin(2*M_PI*ramp); | |||
| } | |||
| return 0; | |||
| } | |||
| int srate(jack_nframes_t nframes, void *arg) | |||
| { | |||
| printf("the sample rate is now %" PRIu32 "/sec\n", nframes); | |||
| calc_note_frqs((jack_default_audio_sample_t)nframes); | |||
| return 0; | |||
| } | |||
| void jack_shutdown(void *arg) | |||
| { | |||
| exit(1); | |||
| } | |||
| int main(int narg, char **args) | |||
| { | |||
| jack_client_t *client; | |||
| if ((client = jack_client_open ("midisine", JackNullOption, NULL)) == 0) | |||
| { | |||
| fprintf(stderr, "jack server not running?\n"); | |||
| return 1; | |||
| } | |||
| calc_note_frqs(jack_get_sample_rate (client)); | |||
| jack_set_process_callback (client, process, 0); | |||
| jack_set_sample_rate_callback (client, srate, 0); | |||
| jack_on_shutdown (client, jack_shutdown, 0); | |||
| input_port = jack_port_register (client, "midi_in", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0); | |||
| output_port = jack_port_register (client, "audio_out", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); | |||
| if (jack_activate (client)) | |||
| { | |||
| fprintf(stderr, "cannot activate client"); | |||
| return 1; | |||
| } | |||
| /* run until interrupted */ | |||
| while(1) | |||
| { | |||
| sleep(1); | |||
| } | |||
| jack_client_close(client); | |||
| exit (0); | |||
| } | |||
| @@ -0,0 +1,237 @@ | |||
| /* | |||
| Copyright (C) 2008 Grame | |||
| 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. | |||
| */ | |||
| #include <stdio.h> | |||
| #include <errno.h> | |||
| #include <unistd.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include <getopt.h> | |||
| #include <jack/jack.h> | |||
| #include <jack/control.h> | |||
| static jackctl_driver_t * jackctl_server_get_driver(jackctl_server_t *server, const char *driver_name) | |||
| { | |||
| const JSList * node_ptr = jackctl_server_get_drivers_list(server); | |||
| while (node_ptr) { | |||
| if (strcmp(jackctl_driver_get_name((jackctl_driver_t *)node_ptr->data), driver_name) == 0) { | |||
| return (jackctl_driver_t *)node_ptr->data; | |||
| } | |||
| node_ptr = jack_slist_next(node_ptr); | |||
| } | |||
| return NULL; | |||
| } | |||
| static jackctl_internal_t * jackctl_server_get_internal(jackctl_server_t *server, const char *internal_name) | |||
| { | |||
| const JSList * node_ptr = jackctl_server_get_internals_list(server); | |||
| while (node_ptr) { | |||
| if (strcmp(jackctl_internal_get_name((jackctl_internal_t *)node_ptr->data), internal_name) == 0) { | |||
| return (jackctl_internal_t *)node_ptr->data; | |||
| } | |||
| node_ptr = jack_slist_next(node_ptr); | |||
| } | |||
| return NULL; | |||
| } | |||
| static jackctl_parameter_t * | |||
| jackctl_get_parameter( | |||
| const JSList * parameters_list, | |||
| const char * parameter_name) | |||
| { | |||
| while (parameters_list) | |||
| { | |||
| if (strcmp(jackctl_parameter_get_name((jackctl_parameter_t *)parameters_list->data), parameter_name) == 0) | |||
| { | |||
| return (jackctl_parameter_t *)parameters_list->data; | |||
| } | |||
| parameters_list = jack_slist_next(parameters_list); | |||
| } | |||
| return NULL; | |||
| } | |||
| static void print_value(union jackctl_parameter_value value, jackctl_param_type_t type) | |||
| { | |||
| switch (type) { | |||
| case JackParamInt: | |||
| printf("parameter value = %d\n", value.i); | |||
| break; | |||
| case JackParamUInt: | |||
| printf("parameter value = %u\n", value.ui); | |||
| break; | |||
| case JackParamChar: | |||
| printf("parameter value = %c\n", value.c); | |||
| break; | |||
| case JackParamString: | |||
| printf("parameter value = %s\n", value.str); | |||
| break; | |||
| case JackParamBool: | |||
| printf("parameter value = %d\n", value.b); | |||
| break; | |||
| } | |||
| } | |||
| static void print_parameters(const JSList * node_ptr) | |||
| { | |||
| while (node_ptr != NULL) { | |||
| jackctl_parameter_t * parameter = (jackctl_parameter_t *)node_ptr->data; | |||
| printf("\nparameter name = %s\n", jackctl_parameter_get_name(parameter)); | |||
| printf("parameter id = %c\n", jackctl_parameter_get_id(parameter)); | |||
| printf("parameter short decs = %s\n", jackctl_parameter_get_short_description(parameter)); | |||
| printf("parameter long decs = %s\n", jackctl_parameter_get_long_description(parameter)); | |||
| print_value(jackctl_parameter_get_default_value(parameter), jackctl_parameter_get_type(parameter)); | |||
| node_ptr = jack_slist_next(node_ptr); | |||
| } | |||
| } | |||
| static void print_driver(jackctl_driver_t * driver) | |||
| { | |||
| printf("\n--------------------------\n"); | |||
| printf("driver = %s\n", jackctl_driver_get_name(driver)); | |||
| printf("-------------------------- \n"); | |||
| print_parameters(jackctl_driver_get_parameters(driver)); | |||
| } | |||
| static void print_internal(jackctl_internal_t * internal) | |||
| { | |||
| printf("\n-------------------------- \n"); | |||
| printf("internal = %s\n", jackctl_internal_get_name(internal)); | |||
| printf("-------------------------- \n"); | |||
| print_parameters(jackctl_internal_get_parameters(internal)); | |||
| } | |||
| static void usage() | |||
| { | |||
| fprintf (stderr, "\n" | |||
| "usage: jack_server_control \n" | |||
| " [ --driver OR -d driver_name ]\n" | |||
| " [ --client OR -c client_name ]\n" | |||
| ); | |||
| } | |||
| int main(int argc, char *argv[]) | |||
| { | |||
| jackctl_server_t * server; | |||
| const JSList * parameters; | |||
| const JSList * drivers; | |||
| const JSList * internals; | |||
| const JSList * node_ptr; | |||
| sigset_t signals; | |||
| int opt, option_index; | |||
| const char* driver_name = "dummy"; | |||
| const char* client_name = "audioadapter"; | |||
| const char *options = "d:c:"; | |||
| struct option long_options[] = { | |||
| {"driver", 1, 0, 'd'}, | |||
| {"client", 1, 0, 'c'}, | |||
| }; | |||
| while ((opt = getopt_long (argc, argv, options, long_options, &option_index)) != EOF) { | |||
| switch (opt) { | |||
| case 'd': | |||
| driver_name = optarg; | |||
| break; | |||
| case 'c': | |||
| client_name = optarg; | |||
| break; | |||
| default: | |||
| usage(); | |||
| exit(0); | |||
| } | |||
| } | |||
| server = jackctl_server_create(NULL, NULL); | |||
| parameters = jackctl_server_get_parameters(server); | |||
| /* | |||
| jackctl_parameter_t* param; | |||
| union jackctl_parameter_value value; | |||
| param = jackctl_get_parameter(parameters, "verbose"); | |||
| if (param != NULL) { | |||
| value.b = true; | |||
| jackctl_parameter_set_value(param, &value); | |||
| } | |||
| */ | |||
| printf("\n========================== \n"); | |||
| printf("List of server parameters \n"); | |||
| printf("========================== \n"); | |||
| print_parameters(parameters); | |||
| printf("\n========================== \n"); | |||
| printf("List of drivers \n"); | |||
| printf("========================== \n"); | |||
| drivers = jackctl_server_get_drivers_list(server); | |||
| node_ptr = drivers; | |||
| while (node_ptr != NULL) { | |||
| print_driver((jackctl_driver_t *)node_ptr->data); | |||
| node_ptr = jack_slist_next(node_ptr); | |||
| } | |||
| printf("\n========================== \n"); | |||
| printf("List of internal clients \n"); | |||
| printf("========================== \n"); | |||
| internals = jackctl_server_get_internals_list(server); | |||
| node_ptr = internals; | |||
| while (node_ptr != NULL) { | |||
| print_internal((jackctl_internal_t *)node_ptr->data); | |||
| node_ptr = jack_slist_next(node_ptr); | |||
| } | |||
| signals = jackctl_setup_signals(0); | |||
| jackctl_server_start(server, jackctl_server_get_driver(server, driver_name)); | |||
| jackctl_server_load_internal(server, jackctl_server_get_internal(server, client_name)); | |||
| /* | |||
| // Switch master test | |||
| jackctl_driver_t* master; | |||
| usleep(5000000); | |||
| printf("jackctl_server_load_master\n"); | |||
| master = jackctl_server_get_driver(server, "coreaudio"); | |||
| jackctl_server_switch_master(server, master); | |||
| usleep(5000000); | |||
| printf("jackctl_server_load_master\n"); | |||
| master = jackctl_server_get_driver(server, "dummy"); | |||
| jackctl_server_switch_master(server, master); | |||
| */ | |||
| jackctl_wait_signals(signals); | |||
| jackctl_server_destroy(server); | |||
| return 0; | |||
| } | |||
| @@ -0,0 +1,117 @@ | |||
| #include <stdio.h> | |||
| #include <errno.h> | |||
| #include <unistd.h> | |||
| #include <signal.h> | |||
| #include <stdlib.h> | |||
| #include <jack/jack.h> | |||
| #include <jack/transport.h> | |||
| jack_client_t *client; | |||
| void | |||
| showtime () | |||
| { | |||
| jack_position_t current; | |||
| jack_transport_state_t transport_state; | |||
| jack_nframes_t frame_time; | |||
| transport_state = jack_transport_query (client, ¤t); | |||
| frame_time = jack_frame_time (client); | |||
| printf ("frame: %7" PRIu32 " @ %" PRIu32 "\t", current.frame, frame_time); | |||
| switch (transport_state) { | |||
| case JackTransportStopped: | |||
| printf ("state: Stopped"); | |||
| break; | |||
| case JackTransportRolling: | |||
| printf ("state: Rolling"); | |||
| break; | |||
| case JackTransportStarting: | |||
| printf ("state: Starting"); | |||
| break; | |||
| default: | |||
| printf ("state: [unknown]"); | |||
| } | |||
| if (current.valid & JackPositionBBT) | |||
| printf ("\tBBT: %3" PRIi32 "|%" PRIi32 "|%04" | |||
| PRIi32, current.bar, current.beat, current.tick); | |||
| if (current.valid & JackPositionTimecode) | |||
| printf ("\tTC: (%.6f, %.6f)", | |||
| current.frame_time, current.next_time); | |||
| if (current.valid & JackBBTFrameOffset) | |||
| printf ("\tBBT offset: (%" PRIi32 ")", | |||
| current.bbt_offset); | |||
| if (current.valid & JackAudioVideoRatio) | |||
| printf ("\taudio/video: (%f)", | |||
| current.audio_frames_per_video_frame); | |||
| if (current.valid & JackVideoFrameOffset) { | |||
| if (current.video_offset) { | |||
| printf ("\t video@: (%" PRIi32 ")", current.video_offset); | |||
| } else { | |||
| printf ("\t no video"); | |||
| } | |||
| } | |||
| printf ("\n"); | |||
| } | |||
| void | |||
| jack_shutdown (void *arg) | |||
| { | |||
| exit (1); | |||
| } | |||
| void | |||
| signal_handler (int sig) | |||
| { | |||
| jack_client_close (client); | |||
| fprintf (stderr, "signal received, exiting ...\n"); | |||
| exit (0); | |||
| } | |||
| int | |||
| main (int argc, char *argv[]) | |||
| { | |||
| /* try to become a client of the JACK server */ | |||
| if ((client = jack_client_open ("showtime", JackNullOption, NULL)) == 0) { | |||
| fprintf (stderr, "jack server not running?\n"); | |||
| return 1; | |||
| } | |||
| signal (SIGQUIT, signal_handler); | |||
| signal (SIGTERM, signal_handler); | |||
| signal (SIGHUP, signal_handler); | |||
| signal (SIGINT, signal_handler); | |||
| /* tell the JACK server to call `jack_shutdown()' if | |||
| it ever shuts down, either entirely, or if it | |||
| just decides to stop calling us. | |||
| */ | |||
| jack_on_shutdown (client, jack_shutdown, 0); | |||
| /* tell the JACK server that we are ready to roll */ | |||
| if (jack_activate (client)) { | |||
| fprintf (stderr, "cannot activate client"); | |||
| return 1; | |||
| } | |||
| while (1) { | |||
| usleep (20); | |||
| showtime (); | |||
| } | |||
| jack_client_close (client); | |||
| exit (0); | |||
| } | |||
| @@ -0,0 +1,164 @@ | |||
| /** @file simple_client.c | |||
| * | |||
| * @brief This simple client demonstrates the most basic features of JACK | |||
| * as they would be used by many applications. | |||
| */ | |||
| #include <stdio.h> | |||
| #include <errno.h> | |||
| #include <unistd.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include <jack/jack.h> | |||
| jack_port_t *input_port; | |||
| jack_port_t *output_port; | |||
| jack_client_t *client; | |||
| /** | |||
| * The process callback for this JACK application is called in a | |||
| * special realtime thread once for each audio cycle. | |||
| * | |||
| * This client does nothing more than copy data from its input | |||
| * port to its output port. It will exit when stopped by | |||
| * the user (e.g. using Ctrl-C on a unix-ish operating system) | |||
| */ | |||
| int | |||
| process (jack_nframes_t nframes, void *arg) | |||
| { | |||
| jack_default_audio_sample_t *in, *out; | |||
| in = jack_port_get_buffer (input_port, nframes); | |||
| out = jack_port_get_buffer (output_port, nframes); | |||
| memcpy (out, in, | |||
| sizeof (jack_default_audio_sample_t) * nframes); | |||
| return 0; | |||
| } | |||
| /** | |||
| * JACK calls this shutdown_callback if the server ever shuts down or | |||
| * decides to disconnect the client. | |||
| */ | |||
| void | |||
| jack_shutdown (void *arg) | |||
| { | |||
| exit (1); | |||
| } | |||
| int | |||
| main (int argc, char *argv[]) | |||
| { | |||
| const char **ports; | |||
| const char *client_name = "simple"; | |||
| const char *server_name = NULL; | |||
| jack_options_t options = JackNullOption; | |||
| jack_status_t status; | |||
| /* open a client connection to the JACK server */ | |||
| client = jack_client_open (client_name, options, &status, server_name); | |||
| if (client == NULL) { | |||
| fprintf (stderr, "jack_client_open() failed, " | |||
| "status = 0x%2.0x\n", status); | |||
| if (status & JackServerFailed) { | |||
| fprintf (stderr, "Unable to connect to JACK server\n"); | |||
| } | |||
| exit (1); | |||
| } | |||
| if (status & JackServerStarted) { | |||
| fprintf (stderr, "JACK server started\n"); | |||
| } | |||
| if (status & JackNameNotUnique) { | |||
| client_name = jack_get_client_name(client); | |||
| fprintf (stderr, "unique name `%s' assigned\n", client_name); | |||
| } | |||
| /* tell the JACK server to call `process()' whenever | |||
| there is work to be done. | |||
| */ | |||
| jack_set_process_callback (client, process, 0); | |||
| /* tell the JACK server to call `jack_shutdown()' if | |||
| it ever shuts down, either entirely, or if it | |||
| just decides to stop calling us. | |||
| */ | |||
| jack_on_shutdown (client, jack_shutdown, 0); | |||
| /* display the current sample rate. | |||
| */ | |||
| printf ("engine sample rate: %" PRIu32 "\n", | |||
| jack_get_sample_rate (client)); | |||
| /* create two ports */ | |||
| input_port = jack_port_register (client, "input", | |||
| JACK_DEFAULT_AUDIO_TYPE, | |||
| JackPortIsInput, 0); | |||
| output_port = jack_port_register (client, "output", | |||
| JACK_DEFAULT_AUDIO_TYPE, | |||
| JackPortIsOutput, 0); | |||
| if ((input_port == NULL) || (output_port == NULL)) { | |||
| fprintf(stderr, "no more JACK ports available\n"); | |||
| exit (1); | |||
| } | |||
| /* Tell the JACK server that we are ready to roll. Our | |||
| * process() callback will start running now. */ | |||
| if (jack_activate (client)) { | |||
| fprintf (stderr, "cannot activate client"); | |||
| exit (1); | |||
| } | |||
| /* Connect the ports. You can't do this before the client is | |||
| * activated, because we can't make connections to clients | |||
| * that aren't running. Note the confusing (but necessary) | |||
| * orientation of the driver backend ports: playback ports are | |||
| * "input" to the backend, and capture ports are "output" from | |||
| * it. | |||
| */ | |||
| ports = jack_get_ports (client, NULL, NULL, | |||
| JackPortIsPhysical|JackPortIsOutput); | |||
| if (ports == NULL) { | |||
| fprintf(stderr, "no physical capture ports\n"); | |||
| exit (1); | |||
| } | |||
| if (jack_connect (client, ports[0], jack_port_name (input_port))) { | |||
| fprintf (stderr, "cannot connect input ports\n"); | |||
| } | |||
| free (ports); | |||
| ports = jack_get_ports (client, NULL, NULL, | |||
| JackPortIsPhysical|JackPortIsInput); | |||
| if (ports == NULL) { | |||
| fprintf(stderr, "no physical playback ports\n"); | |||
| exit (1); | |||
| } | |||
| if (jack_connect (client, jack_port_name (output_port), ports[0])) { | |||
| fprintf (stderr, "cannot connect output ports\n"); | |||
| } | |||
| free (ports); | |||
| /* keep running until stopped by the user */ | |||
| sleep (-1); | |||
| /* this is never reached but if the program | |||
| had some other way to exit besides being killed, | |||
| they would be important to call. | |||
| */ | |||
| jack_client_close (client); | |||
| exit (0); | |||
| } | |||
| @@ -0,0 +1,201 @@ | |||
| /** @file simple_session_client.c | |||
| * | |||
| * @brief This simple client demonstrates the most basic features of JACK | |||
| * as they would be used by many applications. | |||
| * this version also adds session manager functionality. | |||
| */ | |||
| #include <stdio.h> | |||
| #include <errno.h> | |||
| #include <unistd.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include <jack/jack.h> | |||
| #include <jack/session.h> | |||
| jack_port_t *input_port; | |||
| jack_port_t *output_port; | |||
| jack_client_t *client; | |||
| int simple_quit = 0; | |||
| /** | |||
| * The process callback for this JACK application is called in a | |||
| * special realtime thread once for each audio cycle. | |||
| * | |||
| * This client does nothing more than copy data from its input | |||
| * port to its output port. It will exit when stopped by | |||
| * the user (e.g. using Ctrl-C on a unix-ish operating system) | |||
| */ | |||
| int | |||
| process (jack_nframes_t nframes, void *arg) | |||
| { | |||
| jack_default_audio_sample_t *in, *out; | |||
| in = jack_port_get_buffer (input_port, nframes); | |||
| out = jack_port_get_buffer (output_port, nframes); | |||
| memcpy (out, in, | |||
| sizeof (jack_default_audio_sample_t) * nframes); | |||
| return 0; | |||
| } | |||
| void | |||
| session_callback (jack_session_event_t *event, void *arg) | |||
| { | |||
| char retval[100]; | |||
| printf ("session notification\n"); | |||
| printf ("path %s, uuid %s, type: %s\n", event->session_dir, event->client_uuid, event->type == JackSessionSave ? "save" : "quit"); | |||
| snprintf (retval, 100, "jack_simple_session_client %s", event->client_uuid); | |||
| event->command_line = strdup (retval); | |||
| jack_session_reply( client, event ); | |||
| if (event->type == JackSessionSaveAndQuit) { | |||
| simple_quit = 1; | |||
| } | |||
| jack_session_event_free (event); | |||
| } | |||
| /** | |||
| * JACK calls this shutdown_callback if the server ever shuts down or | |||
| * decides to disconnect the client. | |||
| */ | |||
| void | |||
| jack_shutdown (void *arg) | |||
| { | |||
| exit (1); | |||
| } | |||
| int | |||
| main (int argc, char *argv[]) | |||
| { | |||
| const char **ports; | |||
| const char *client_name = "simple"; | |||
| jack_status_t status; | |||
| /* open a client connection to the JACK server */ | |||
| if( argc == 1 ) | |||
| client = jack_client_open (client_name, JackNullOption, &status ); | |||
| else if( argc == 2 ) | |||
| client = jack_client_open (client_name, JackSessionID, &status, argv[1] ); | |||
| if (client == NULL) { | |||
| fprintf (stderr, "jack_client_open() failed, " | |||
| "status = 0x%2.0x\n", status); | |||
| if (status & JackServerFailed) { | |||
| fprintf (stderr, "Unable to connect to JACK server\n"); | |||
| } | |||
| exit (1); | |||
| } | |||
| if (status & JackServerStarted) { | |||
| fprintf (stderr, "JACK server started\n"); | |||
| } | |||
| if (status & JackNameNotUnique) { | |||
| client_name = jack_get_client_name(client); | |||
| fprintf (stderr, "unique name `%s' assigned\n", client_name); | |||
| } | |||
| /* tell the JACK server to call `process()' whenever | |||
| there is work to be done. | |||
| */ | |||
| jack_set_process_callback (client, process, 0); | |||
| /* tell the JACK server to call `jack_shutdown()' if | |||
| it ever shuts down, either entirely, or if it | |||
| just decides to stop calling us. | |||
| */ | |||
| jack_on_shutdown (client, jack_shutdown, 0); | |||
| /* tell the JACK server to call `session_callback()' if | |||
| the session is saved. | |||
| */ | |||
| jack_set_session_callback (client, session_callback, NULL); | |||
| /* display the current sample rate. | |||
| */ | |||
| printf ("engine sample rate: %" PRIu32 "\n", | |||
| jack_get_sample_rate (client)); | |||
| /* create two ports */ | |||
| input_port = jack_port_register (client, "input", | |||
| JACK_DEFAULT_AUDIO_TYPE, | |||
| JackPortIsInput, 0); | |||
| output_port = jack_port_register (client, "output", | |||
| JACK_DEFAULT_AUDIO_TYPE, | |||
| JackPortIsOutput, 0); | |||
| if ((input_port == NULL) || (output_port == NULL)) { | |||
| fprintf(stderr, "no more JACK ports available\n"); | |||
| exit (1); | |||
| } | |||
| /* Tell the JACK server that we are ready to roll. Our | |||
| * process() callback will start running now. */ | |||
| if (jack_activate (client)) { | |||
| fprintf (stderr, "cannot activate client"); | |||
| exit (1); | |||
| } | |||
| /* Connect the ports. You can't do this before the client is | |||
| * activated, because we can't make connections to clients | |||
| * that aren't running. Note the confusing (but necessary) | |||
| * orientation of the driver backend ports: playback ports are | |||
| * "input" to the backend, and capture ports are "output" from | |||
| * it. | |||
| */ | |||
| /* only do the autoconnect when not reloading from a session. | |||
| * in case of a session reload, the SM will restore our connections | |||
| */ | |||
| if (argc==1) { | |||
| ports = jack_get_ports (client, NULL, NULL, | |||
| JackPortIsPhysical|JackPortIsOutput); | |||
| if (ports == NULL) { | |||
| fprintf(stderr, "no physical capture ports\n"); | |||
| exit (1); | |||
| } | |||
| if (jack_connect (client, ports[0], jack_port_name (input_port))) { | |||
| fprintf (stderr, "cannot connect input ports\n"); | |||
| } | |||
| free (ports); | |||
| ports = jack_get_ports (client, NULL, NULL, | |||
| JackPortIsPhysical|JackPortIsInput); | |||
| if (ports == NULL) { | |||
| fprintf(stderr, "no physical playback ports\n"); | |||
| exit (1); | |||
| } | |||
| if (jack_connect (client, jack_port_name (output_port), ports[0])) { | |||
| fprintf (stderr, "cannot connect output ports\n"); | |||
| } | |||
| free (ports); | |||
| } | |||
| /* keep running until until we get a quit event */ | |||
| while (!simple_quit) | |||
| sleep(1); | |||
| jack_client_close (client); | |||
| exit (0); | |||
| } | |||
| @@ -0,0 +1,197 @@ | |||
| /** @file transport_client.c | |||
| * | |||
| * @brief This client demonstrates very simple use of the JACK | |||
| * transport API. Compare it with the simple_client example, | |||
| * which is even simpler. It also demonstrates taking a client | |||
| * name and optionally server name from the command line, rather | |||
| * than hard-coding either of these names. | |||
| */ | |||
| #include <stdio.h> | |||
| #include <errno.h> | |||
| #include <unistd.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include <jack/jack.h> | |||
| jack_port_t *input_port; | |||
| jack_port_t *output_port; | |||
| jack_client_t *client; | |||
| /* a simple state machine for this client */ | |||
| volatile enum { | |||
| Init, | |||
| Run, | |||
| Exit | |||
| } client_state = Init; | |||
| /** | |||
| * The process callback for this JACK application is called in a | |||
| * special realtime thread once for each audio cycle. | |||
| * | |||
| * This client follows a simple rule: when the JACK transport is | |||
| * running, copy the input port to the output. When it stops, exit. | |||
| */ | |||
| int | |||
| process (jack_nframes_t nframes, void *arg) | |||
| { | |||
| jack_default_audio_sample_t *in, *out; | |||
| jack_transport_state_t ts = jack_transport_query(client, NULL); | |||
| if (ts == JackTransportRolling) { | |||
| if (client_state == Init) | |||
| client_state = Run; | |||
| in = jack_port_get_buffer (input_port, nframes); | |||
| out = jack_port_get_buffer (output_port, nframes); | |||
| memcpy (out, in, | |||
| sizeof (jack_default_audio_sample_t) * nframes); | |||
| } else if (ts == JackTransportStopped) { | |||
| if (client_state == Run) | |||
| client_state = Exit; | |||
| } | |||
| return 0; | |||
| } | |||
| /** | |||
| * JACK calls this shutdown_callback if the server ever shuts down or | |||
| * decides to disconnect the client. | |||
| */ | |||
| void | |||
| jack_shutdown (void *arg) | |||
| { | |||
| exit (1); | |||
| } | |||
| int | |||
| main (int argc, char *argv[]) | |||
| { | |||
| const char **ports; | |||
| const char *client_name; | |||
| const char *server_name = NULL; | |||
| jack_options_t options = JackNullOption; | |||
| jack_status_t status; | |||
| if (argc >= 2) { /* client name specified? */ | |||
| client_name = argv[1]; | |||
| if (argc >= 3) { /* server name specified? */ | |||
| server_name = argv[2]; | |||
| options |= JackServerName; | |||
| } | |||
| } else { /* use basename of argv[0] */ | |||
| client_name = strrchr(argv[0], '/'); | |||
| if (client_name == 0) { | |||
| client_name = argv[0]; | |||
| } else { | |||
| client_name++; | |||
| } | |||
| } | |||
| /* open a client connection to the JACK server */ | |||
| client = jack_client_open (client_name, options, &status, server_name); | |||
| if (client == NULL) { | |||
| fprintf (stderr, "jack_client_open() failed, " | |||
| "status = 0x%2.0x\n", status); | |||
| if (status & JackServerFailed) { | |||
| fprintf (stderr, "Unable to connect to JACK server\n"); | |||
| } | |||
| exit (1); | |||
| } | |||
| if (status & JackServerStarted) { | |||
| fprintf (stderr, "JACK server started\n"); | |||
| } | |||
| if (status & JackNameNotUnique) { | |||
| client_name = jack_get_client_name(client); | |||
| fprintf (stderr, "unique name `%s' assigned\n", client_name); | |||
| } | |||
| /* tell the JACK server to call `process()' whenever | |||
| there is work to be done. | |||
| */ | |||
| jack_set_process_callback (client, process, 0); | |||
| /* tell the JACK server to call `jack_shutdown()' if | |||
| it ever shuts down, either entirely, or if it | |||
| just decides to stop calling us. | |||
| */ | |||
| jack_on_shutdown (client, jack_shutdown, 0); | |||
| /* display the current sample rate. | |||
| */ | |||
| printf ("engine sample rate: %" PRIu32 "\n", | |||
| jack_get_sample_rate (client)); | |||
| /* create two ports */ | |||
| input_port = jack_port_register (client, "input", | |||
| JACK_DEFAULT_AUDIO_TYPE, | |||
| JackPortIsInput, 0); | |||
| output_port = jack_port_register (client, "output", | |||
| JACK_DEFAULT_AUDIO_TYPE, | |||
| JackPortIsOutput, 0); | |||
| if ((input_port == NULL) || (output_port == NULL)) { | |||
| fprintf(stderr, "no more JACK ports available\n"); | |||
| exit (1); | |||
| } | |||
| /* Tell the JACK server that we are ready to roll. Our | |||
| * process() callback will start running now. */ | |||
| if (jack_activate (client)) { | |||
| fprintf (stderr, "cannot activate client"); | |||
| exit (1); | |||
| } | |||
| /* Connect the ports. You can't do this before the client is | |||
| * activated, because we can't make connections to clients | |||
| * that aren't running. Note the confusing (but necessary) | |||
| * orientation of the driver backend ports: playback ports are | |||
| * "input" to the backend, and capture ports are "output" from | |||
| * it. | |||
| */ | |||
| ports = jack_get_ports (client, NULL, NULL, | |||
| JackPortIsPhysical|JackPortIsOutput); | |||
| if (ports == NULL) { | |||
| fprintf(stderr, "no physical capture ports\n"); | |||
| exit (1); | |||
| } | |||
| if (jack_connect (client, ports[0], jack_port_name (input_port))) { | |||
| fprintf (stderr, "cannot connect input ports\n"); | |||
| } | |||
| free (ports); | |||
| ports = jack_get_ports (client, NULL, NULL, | |||
| JackPortIsPhysical|JackPortIsInput); | |||
| if (ports == NULL) { | |||
| fprintf(stderr, "no physical playback ports\n"); | |||
| exit (1); | |||
| } | |||
| if (jack_connect (client, jack_port_name (output_port), ports[0])) { | |||
| fprintf (stderr, "cannot connect output ports\n"); | |||
| } | |||
| free (ports); | |||
| /* keep running until the transport stops */ | |||
| while (client_state != Exit) { | |||
| sleep (1); | |||
| } | |||
| jack_client_close (client); | |||
| exit (0); | |||
| } | |||