summaryrefslogtreecommitdiffhomepage
path: root/src/lingot-audio-jack.c
diff options
context:
space:
mode:
authorPiotr Pawlow <pp@siedziba.pl>2014-03-13 20:51:31 +0100
committerPiotr Pawlow <pp@siedziba.pl>2014-03-13 20:51:31 +0100
commitc04af18902322cea1bd05b6f01b7860ca7bfa432 (patch)
treed8d3f812112c0cc835fd29e68d92e297e0164b52 /src/lingot-audio-jack.c
- import version 0.9.1 from upstream
Diffstat (limited to 'src/lingot-audio-jack.c')
-rw-r--r--src/lingot-audio-jack.c349
1 files changed, 349 insertions, 0 deletions
diff --git a/src/lingot-audio-jack.c b/src/lingot-audio-jack.c
new file mode 100644
index 0000000..5135c38
--- /dev/null
+++ b/src/lingot-audio-jack.c
@@ -0,0 +1,349 @@
+/*
+ * lingot, a musical instrument tuner.
+ *
+ * Copyright (C) 2004-2011 Ibán Cereijo Graña, Jairo Chapela Martínez.
+ *
+ * This file is part of lingot.
+ *
+ * lingot 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.
+ *
+ * lingot 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 lingot; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+
+#include "lingot-defs.h"
+#include "lingot-audio-jack.h"
+#include "lingot-i18n.h"
+#include "lingot-msg.h"
+
+#ifdef JACK
+#include <jack/jack.h>
+
+// persistent JACK client to obtain hardware parameters
+jack_client_t* client = NULL;
+pthread_mutex_t stop_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+// this array allows us to reconnect the client to the last ports it was
+// connected in a previous session
+#define MAX_LAST_PORTS 10
+char last_ports[MAX_LAST_PORTS][80];
+
+int lingot_audio_jack_process(jack_nframes_t nframes, void* param) {
+ LingotAudioHandler* audio = param;
+ audio->nframes = nframes;
+
+ pthread_mutex_lock(&stop_mutex);
+ if (audio->running) {
+ lingot_audio_jack_read(audio);
+ audio->process_callback(audio->flt_read_buffer,
+ audio->read_buffer_size, audio->process_callback_arg);
+ }
+ pthread_mutex_unlock(&stop_mutex);
+
+ return 0;
+}
+
+// JACK calls this shutdown_callback if the server ever shuts down or
+// decides to disconnect the client.
+void lingot_audio_jack_shutdown(void* param) {
+ LingotAudioHandler* audio = param;
+ lingot_msg_add_error(_("Missing connection with JACK audio server"));
+ pthread_mutex_lock(&stop_mutex);
+ audio->interrupted = 1;
+ pthread_mutex_unlock(&stop_mutex);
+}
+#endif
+
+LingotAudioHandler* lingot_audio_jack_new(char* device, int sample_rate) {
+
+ LingotAudioHandler* audio = NULL;
+
+# ifdef JACK
+ const char* exception;
+ const char **ports = NULL;
+ const char *client_name = "lingot";
+ const char *server_name = NULL;
+
+ jack_options_t options = JackNoStartServer;
+ jack_status_t status;
+
+ audio = malloc(sizeof(LingotAudioHandler));
+ strcpy(audio->device, "");
+
+ audio->audio_system = AUDIO_SYSTEM_JACK;
+ audio->jack_client = jack_client_open(client_name, options, &status,
+ server_name);
+
+ try {
+ if (audio->jack_client == NULL) {
+ throw(_("Unable to connect to JACK server"));
+ }
+
+ if (status & JackServerStarted) {
+ fprintf(stderr, "JACK server started\n");
+ }
+ if (status & JackNameNotUnique) {
+ client_name = jack_get_client_name(audio->jack_client);
+ fprintf(stderr, "unique name `%s' assigned\n", client_name);
+ }
+
+ jack_on_shutdown(audio->jack_client, lingot_audio_jack_shutdown, audio);
+
+ audio->real_sample_rate = jack_get_sample_rate(audio->jack_client);
+ audio->read_buffer_size = jack_get_buffer_size(audio->jack_client);
+
+ // printf("engine sample rate: %" PRIu32 "\n", jack_get_sample_rate(
+ // audio->jack_client));
+ // printf("buffer size: %" PRIu32 "\n", jack_get_buffer_size(
+ // audio->jack_client));
+
+ audio->jack_input_port = jack_port_register(audio->jack_client,
+ "input", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
+
+ if ((audio->jack_input_port == NULL)) {
+ throw(_("No more JACK ports available"));
+ }
+
+ } catch {
+ free(audio);
+ audio = NULL;
+ lingot_msg_add_error(exception);
+ }
+
+ if (ports != NULL)
+ free(ports);
+
+ if (audio != NULL) {
+ client = audio->jack_client;
+ }
+
+# else
+ lingot_msg_add_error(
+ _("The application has not been built with JACK support"));
+# endif
+ return audio;
+}
+
+void lingot_audio_jack_destroy(LingotAudioHandler* audio) {
+# ifdef JACK
+ if (audio != NULL) {
+ //jack_cycle_wait(audio->jack_client);
+ // jack_deactivate(audio->jack_client);
+ jack_client_close(audio->jack_client);
+ client = NULL;
+ }
+# endif
+}
+
+int lingot_audio_jack_read(LingotAudioHandler* audio) {
+# ifdef JACK
+ register int i;
+ float* in = jack_port_get_buffer(audio->jack_input_port, audio->nframes);
+ for (i = 0; i < audio->nframes; i++)
+ audio->flt_read_buffer[i] = in[i] * 32768;
+ return 0;
+# else
+ return -1;
+# endif
+}
+
+LingotAudioSystemProperties* lingot_audio_jack_get_audio_system_properties(
+ audio_system_t audio_system) {
+
+ LingotAudioSystemProperties* properties = NULL;
+# ifdef JACK
+ properties = (LingotAudioSystemProperties*) malloc(1
+ * sizeof(LingotAudioSystemProperties));
+
+ int sample_rate = -1;
+
+ const char *client_name = "lingot-get-sample-rate";
+ const char *server_name = NULL;
+
+ jack_options_t options = JackNoStartServer;
+ jack_status_t status;
+ jack_client_t* jack_client = NULL;
+ const char **ports = NULL;
+ const char* exception;
+
+ unsigned long int flags = JackPortIsOutput;
+
+ try {
+ if (client != NULL) {
+ sample_rate = jack_get_sample_rate(client);
+ ports = jack_get_ports(client, NULL, NULL, flags);
+ } else {
+ jack_client = jack_client_open(client_name, options, &status,
+ server_name);
+ if (jack_client == NULL) {
+ throw(_("Unable to connect to JACK server"));
+ }
+ if (status & JackServerStarted) {
+ fprintf(stderr, "JACK server started\n");
+ }
+ if (status & JackNameNotUnique) {
+ client_name = jack_get_client_name(jack_client);
+ fprintf(stderr, "unique name `%s' assigned\n", client_name);
+ }
+
+ sample_rate = jack_get_sample_rate(jack_client);
+
+ ports = jack_get_ports(jack_client, NULL, NULL, flags);
+ }
+ } catch {
+ // here I throw a warning message because we are only ontaining the
+ // audio properties
+ lingot_msg_add_warning(exception);
+ }
+
+ properties->forced_sample_rate = 1;
+ properties->n_devices = 0;
+ properties->devices = NULL;
+
+ if (ports != NULL) {
+ int i;
+ for (i = 0; ports[i] != NULL; i++) {
+ }
+ properties->n_devices = i;
+
+ if (properties->n_devices != 0) {
+ properties->devices = malloc(properties->n_devices * sizeof(char*));
+ for (i = 0; ports[i] != NULL; i++) {
+ properties->devices[i] = strdup(ports[i]);
+ }
+ }
+
+ }
+
+ if (sample_rate == -1) {
+ properties->n_sample_rates = 0;
+ properties->sample_rates = NULL;
+ } else {
+ properties->n_sample_rates = 1;
+ properties->sample_rates = malloc(properties->n_sample_rates
+ * sizeof(int));
+ properties->sample_rates[0] = sample_rate;
+ }
+
+ if (ports != NULL)
+ free(ports);
+
+ if (jack_client != NULL)
+ jack_client_close(jack_client);
+
+# else
+ lingot_msg_add_error(
+ _("The application has not been built with JACK support"));
+# endif
+
+ return properties;
+}
+
+int lingot_audio_jack_start(LingotAudioHandler* audio) {
+ int result = 0;
+
+# ifdef JACK
+ int index = 0;
+ const char **ports = NULL;
+ const char* exception;
+ jack_set_process_callback(audio->jack_client, lingot_audio_jack_process,
+ audio);
+
+ try {
+ if (jack_activate(audio->jack_client)) {
+ throw(_("Cannot activate client"));
+ }
+
+ ports
+ = jack_get_ports(audio->jack_client, NULL, NULL,
+ JackPortIsOutput);
+ if (ports == NULL) {
+ throw(_("No active capture ports"));
+ }
+
+ // try to connect the client to the ports is was connected before
+ int j = 0;
+ int connections = 0;
+ for (j = 0; j < MAX_LAST_PORTS; j++) {
+ for (index = 0; ports[index]; index++) {
+ if (!strcmp(last_ports[j], ports[index])) {
+ if (jack_connect(audio->jack_client, ports[index],
+ jack_port_name(audio->jack_input_port))) {
+ throw(_("Cannot connect input ports"));
+ } else {
+ connections++;
+ }
+ }
+ }
+ }
+
+ // if there wasn't connections before, we connect the client to the
+ // first physical port
+ if (!connections) {
+ free(ports);
+ ports = jack_get_ports(audio->jack_client, NULL, NULL,
+ JackPortIsPhysical | JackPortIsOutput);
+ if (ports == NULL) {
+ throw(_("No physical capture ports"));
+ }
+
+ if (jack_connect(audio->jack_client, ports[0], jack_port_name(
+ audio->jack_input_port))) {
+ throw(_("Cannot connect input ports"));
+ }
+ }
+
+ } catch {
+ lingot_msg_add_error(exception);
+ result = -1;
+ }
+
+ free(ports);
+# else
+ lingot_msg_add_error(
+ _("The application has not been built with JACK support"));
+# endif
+
+ return result;
+}
+
+void lingot_audio_jack_stop(LingotAudioHandler* audio) {
+# ifdef JACK
+ //jack_cycle_wait(audio->jack_client);
+ const char** ports = jack_get_ports(audio->jack_client, NULL, NULL,
+ JackPortIsOutput);
+
+ if (ports != NULL) {
+ int i, j = 0;
+
+ for (i = 0; i < MAX_LAST_PORTS; i++) {
+ strcpy(last_ports[i], "");
+ }
+
+ for (i = 0; ports[i]; i++) {
+ if (jack_port_connected(jack_port_by_name(audio->jack_client,
+ ports[i]))) {
+ strcpy(last_ports[j++], ports[i]);
+ }
+ }
+ }
+
+ pthread_mutex_lock(&stop_mutex);
+ jack_deactivate(audio->jack_client);
+ pthread_mutex_unlock(&stop_mutex);
+# else
+ lingot_msg_add_error(
+ _("The application has not been built with JACK support"));
+# endif
+}