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