Last commit for src/lingot-audio-jack.c: c04af18902322cea1bd05b6f01b7860ca7bfa432

- import version 0.9.1 from upstream

Piotr Pawlow [2014-03-13 19:51:31]
- import version 0.9.1 from upstream
/*
 * 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
}
ViewGit