1 /*
2  * lingot, a musical instrument tuner.
3  *
4  * Copyright (C) 2004-2018  Iban Cereijo.
5  * Copyright (C) 2004-2008  Jairo Chapela.
6 
7  *
8  * This file is part of lingot.
9  *
10  * lingot is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * lingot is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with lingot; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23  */
24 
25 #ifdef JACK
26 
27 #include <stdio.h>
28 
29 #include "lingot-defs.h"
30 #include "lingot-audio-jack.h"
31 #include "lingot-i18n.h"
32 #include "lingot-msg.h"
33 
34 #include <jack/jack.h>
35 
36 // persistent JACK client to obtain hardware parameters
37 jack_client_t* client = NULL;
38 pthread_mutex_t stop_mutex = PTHREAD_MUTEX_INITIALIZER;
39 
40 // this array allows us to reconnect the client to the last ports it was
41 // connected in a previous session
42 #define MAX_LAST_PORTS 10
43 char last_ports[MAX_LAST_PORTS][80];
44 
lingot_audio_jack_process(jack_nframes_t nframes,void * param)45 int lingot_audio_jack_process(jack_nframes_t nframes, void* param) {
46 	LingotAudioHandler* audio = param;
47 	audio->nframes = nframes;
48 
49 	pthread_mutex_lock(&stop_mutex);
50 	if (audio->running) {
51 		lingot_audio_jack_read(audio);
52 		audio->process_callback(audio->flt_read_buffer,
53 				audio->read_buffer_size_samples, audio->process_callback_arg);
54 	}
55 	pthread_mutex_unlock(&stop_mutex);
56 
57 	return 0;
58 }
59 
60 // JACK calls this shutdown_callback if the server ever shuts down or
61 // decides to disconnect the client.
lingot_audio_jack_shutdown(void * param)62 void lingot_audio_jack_shutdown(void* param) {
63 	LingotAudioHandler* audio = param;
64 	lingot_msg_add_error(_("Missing connection with JACK audio server"));
65 	pthread_mutex_lock(&stop_mutex);
66 	audio->interrupted = 1;
67 	pthread_mutex_unlock(&stop_mutex);
68 }
69 
lingot_audio_jack_new(LingotAudioHandler * audio,const char * device)70 void lingot_audio_jack_new(LingotAudioHandler* audio, const char* device) {
71 	const char* exception;
72 //	const char **ports = NULL;
73 	const char *client_name = "lingot";
74 	const char *server_name = NULL;
75 
76 	jack_options_t options = JackNoStartServer;
77 	jack_status_t status;
78 
79 	strcpy(audio->device, "");
80 
81 	audio->bytes_per_sample = -1;
82 	audio->audio_system = AUDIO_SYSTEM_JACK;
83 	audio->jack_client = jack_client_open(client_name, options, &status,
84 			server_name);
85 
86 	try
87 	{
88 		if (audio->jack_client == NULL) {
89 			throw(_("Unable to connect to JACK server"));
90 		}
91 
92 		if (status & JackServerStarted) {
93 			fprintf(stderr, "JACK server started\n");
94 		}
95 		if (status & JackNameNotUnique) {
96 			client_name = jack_get_client_name(audio->jack_client);
97 			fprintf(stderr, "unique name `%s' assigned\n", client_name);
98 		}
99 
100 		jack_on_shutdown(audio->jack_client, lingot_audio_jack_shutdown, audio);
101 
102 		audio->real_sample_rate = jack_get_sample_rate(audio->jack_client);
103 		audio->read_buffer_size_samples = jack_get_buffer_size(
104 				audio->jack_client);
105 
106 		//	printf("engine sample rate: %" PRIu32 "\n", jack_get_sample_rate(
107 		//			audio->jack_client));
108 		//	printf("buffer size: %" PRIu32 "\n", jack_get_buffer_size(
109 		//			audio->jack_client));
110 
111 		audio->jack_input_port = jack_port_register(audio->jack_client, "input",
112 		JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
113 
114 		if ((audio->jack_input_port == NULL)) {
115 			throw(_("No more JACK ports available"));
116 		}
117 
118 		snprintf(audio->device, sizeof(audio->device), "%s", device);
119 
120 	}catch {
121 		audio->audio_system = -1;
122 		lingot_msg_add_error(exception);
123 	}
124 
125 	if (audio->audio_system == AUDIO_SYSTEM_JACK) {
126 		client = audio->jack_client;
127 	}
128 }
129 
lingot_audio_jack_destroy(LingotAudioHandler * audio)130 void lingot_audio_jack_destroy(LingotAudioHandler* audio) {
131 	if (audio->audio_system == AUDIO_SYSTEM_JACK) {
132 		//jack_cycle_wait(audio->jack_client);
133 		//		jack_deactivate(audio->jack_client);
134 		jack_client_close(audio->jack_client);
135 		client = NULL;
136 	}
137 }
138 
lingot_audio_jack_read(LingotAudioHandler * audio)139 int lingot_audio_jack_read(LingotAudioHandler* audio) {
140 	register int i;
141 	float* in = jack_port_get_buffer(audio->jack_input_port, audio->nframes);
142 	for (i = 0; i < audio->nframes; i++)
143 		audio->flt_read_buffer[i] = in[i] * FLT_SAMPLE_SCALE;
144 	return 0;
145 }
146 
lingot_audio_jack_get_audio_system_properties(LingotAudioSystemProperties * properties)147 int lingot_audio_jack_get_audio_system_properties(
148 		LingotAudioSystemProperties* properties) {
149 	int sample_rate = -1;
150 
151 	const char *client_name = "lingot-get-audio-properties";
152 	const char *server_name = NULL;
153 
154 	jack_options_t options = JackNoStartServer;
155 	jack_status_t status;
156 	jack_client_t* jack_client = NULL;
157 	const char **ports = NULL;
158 	const char* exception;
159 
160 	unsigned long int flags = JackPortIsOutput;
161 
162 	properties->forced_sample_rate = 1;
163 	properties->n_devices = 0;
164 	properties->devices = NULL;
165 
166 	try
167 	{
168 		if (client == NULL) {
169 			jack_client = jack_client_open(client_name, options, &status,
170 					server_name);
171 			if (jack_client == NULL) {
172 				throw(_("Unable to connect to JACK server"));
173 			}
174 			if (status & JackServerStarted) {
175 				fprintf(stderr, "JACK server started\n");
176 			}
177 			if (status & JackNameNotUnique) {
178 				client_name = jack_get_client_name(jack_client);
179 				fprintf(stderr, "unique name `%s' assigned\n", client_name);
180 			}
181 		} else {
182 			sample_rate = jack_get_sample_rate(client);
183 			ports = jack_get_ports(client, NULL, NULL, flags);
184 		}
185 
186 	}catch {
187 		// here I throw a warning message because we are only ontaining the
188 		// audio properties
189 //		lingot_msg_add_warning(exception);
190 		fprintf(stderr, "%s", exception);
191 	}
192 
193 	properties->forced_sample_rate = 1;
194 	properties->n_devices = 1;
195 	if (ports != NULL) {
196 		int i;
197 		for (i = 0; ports[i] != NULL; i++) {
198 		}
199 		properties->n_devices = i + 1;
200 	}
201 
202 	properties->devices = (char**) malloc(
203 			properties->n_devices * sizeof(char*));
204 	char buff[512];
205 	snprintf(buff, sizeof(buff), "%s <default>", _("Default Port"));
206 	properties->devices[0] = strdup(buff);
207 
208 	if (ports != NULL) {
209 		if (properties->n_devices != 0) {
210 			int i;
211 			for (i = 0; ports[i] != NULL; i++) {
212 				properties->devices[i + 1] = strdup(ports[i]);
213 			}
214 		}
215 	}
216 
217 	if (sample_rate == -1) {
218 		properties->n_sample_rates = 0;
219 	} else {
220 		properties->n_sample_rates = 1;
221 		properties->sample_rates[0] = sample_rate;
222 	}
223 
224 	if (ports != NULL) {
225 		jack_free(ports);
226 	}
227 
228 	if (jack_client != NULL) {
229 		jack_client_close(jack_client);
230 	}
231 
232 	return 0;
233 }
234 
lingot_audio_jack_start(LingotAudioHandler * audio)235 int lingot_audio_jack_start(LingotAudioHandler* audio) {
236 	int result = 0;
237 	int index = 0;
238 	const char **ports = NULL;
239 	const char* exception;
240 	jack_set_process_callback(audio->jack_client, lingot_audio_jack_process,
241 			audio);
242 
243 	try
244 	{
245 		if (jack_activate(audio->jack_client)) {
246 			throw(_("Cannot activate client"));
247 		}
248 
249 		ports = jack_get_ports(audio->jack_client, NULL, NULL,
250 				JackPortIsOutput);
251 		if (ports == NULL) {
252 			throw(_("No active capture ports"));
253 		}
254 
255 		if (!strcmp(audio->device, "default")) {
256 			// try to connect the client to the ports is was connected before
257 			int j = 0;
258 			int connections = 0;
259 			for (j = 0; j < MAX_LAST_PORTS; j++) {
260 				for (index = 0; ports[index]; index++) {
261 					if (!strcmp(last_ports[j], ports[index])) {
262 						if (jack_connect(audio->jack_client, ports[index],
263 								jack_port_name(audio->jack_input_port))) {
264 							throw(_("Cannot connect input ports"));
265 						} else {
266 							connections++;
267 						}
268 					}
269 				}
270 			}
271 
272 			// if there wasn't connections before, we connect the client to the
273 			// first physical port
274 			if (!connections) {
275 				if (jack_connect(audio->jack_client, ports[0],
276 						jack_port_name(audio->jack_input_port))) {
277 					throw(_("Cannot connect input ports"));
278 				}
279 			}
280 		} else {
281 			if (jack_connect(audio->jack_client, audio->device,
282 					jack_port_name(audio->jack_input_port))) {
283 				char buff[512];
284 				snprintf(buff, sizeof(buff),
285 						_("Cannot connect to requested port '%s'"),
286 						audio->device);
287 				throw(buff);
288 			}
289 		}
290 	}catch {
291 		lingot_msg_add_error(exception);
292 		result = -1;
293 
294 		lingot_audio_jack_stop(audio);
295 	}
296 
297 	if (ports != NULL) {
298 		jack_free(ports);
299 	}
300 
301 	return result;
302 }
303 
lingot_audio_jack_stop(LingotAudioHandler * audio)304 void lingot_audio_jack_stop(LingotAudioHandler* audio) {
305 	//jack_cycle_wait(audio->jack_client);
306 	const char** ports = jack_get_ports(audio->jack_client, NULL, NULL,
307 			JackPortIsOutput);
308 
309 	if (ports != NULL) {
310 		int i, j = 0;
311 
312 		for (i = 0; i < MAX_LAST_PORTS; i++) {
313 			strcpy(last_ports[i], "");
314 		}
315 
316 		for (i = 0; ports[i]; i++) {
317 			if (jack_port_connected(
318 					jack_port_by_name(audio->jack_client, ports[i]))) {
319 				strcpy(last_ports[j++], ports[i]);
320 			}
321 		}
322 	}
323 
324 	pthread_mutex_lock(&stop_mutex);
325 	jack_deactivate(audio->jack_client);
326 	pthread_mutex_unlock(&stop_mutex);
327 }
328 
329 #endif
330