1 /*
2  * lingot, a musical instrument tuner.
3  *
4  * Copyright (C) 2004-2018  Iban Cereijo.
5  * Copyright (C) 2004-2008  Jairo Chapela.
6  *
7  * This file is part of lingot.
8  *
9  * lingot is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * lingot is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with lingot; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  */
23 
24 #include <assert.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <sys/time.h>
29 #include <time.h>
30 #include <errno.h>
31 
32 #include "lingot-defs.h"
33 #include "lingot-audio.h"
34 
35 #include "lingot-core.h"
36 #include "lingot-audio-oss.h"
37 #include "lingot-audio-alsa.h"
38 #include "lingot-audio-jack.h"
39 #include "lingot-audio-pulseaudio.h"
40 #include "lingot-i18n.h"
41 #include "lingot-msg.h"
42 
lingot_audio_new(LingotAudioHandler * result,audio_system_t audio_system,const char * device,int sample_rate,LingotAudioProcessCallback process_callback,void * process_callback_arg)43 void lingot_audio_new(LingotAudioHandler* result, audio_system_t audio_system, const char* device,
44 		int sample_rate, LingotAudioProcessCallback process_callback,
45 		void *process_callback_arg) {
46 
47 #	if !defined(OSS) && !defined(ALSA) && !defined(JACK) && !defined(PULSEAUDIO)
48 #	error "No audio system has been defined"
49 #	endif
50 
51 	switch (audio_system) {
52 #	ifdef OSS
53 	case AUDIO_SYSTEM_OSS:
54 		lingot_audio_oss_new(result, device, sample_rate);
55 #	else
56 		lingot_msg_add_error(
57 			_("The application has not been built with OSS support"));
58 		result->audio_system = -1;
59 #	endif
60 		break;
61 	case AUDIO_SYSTEM_ALSA:
62 #	ifdef ALSA
63 		lingot_audio_alsa_new(result, device, sample_rate);
64 #	else
65 		lingot_msg_add_error(
66 			_("The application has not been built with ALSA support"));
67 		result->audio_system = -1;
68 #	endif
69 		break;
70 	case AUDIO_SYSTEM_JACK:
71 #	ifdef JACK
72 		lingot_audio_jack_new(result, device);
73 #	else
74 		lingot_msg_add_error(
75 			_("The application has not been built with JACK support"));
76 		result->audio_system = -1;
77 #	endif
78 		break;
79 #	ifdef PULSEAUDIO
80 	case AUDIO_SYSTEM_PULSEAUDIO:
81 		lingot_audio_pulseaudio_new(result, device, sample_rate);
82 #	else
83 		lingot_msg_add_error(
84 			_("The application has not been built with PULSEAUDIO support"));
85 		result->audio_system = -1;
86 #	endif
87 		break;
88 	default:
89 		assert (0);
90 	}
91 
92 	if (result->audio_system != -1 ) {
93 		// audio source read in floating point format.
94 		result->flt_read_buffer = malloc(
95 				result->read_buffer_size_samples * sizeof(FLT));
96 		memset(result->flt_read_buffer, 0,
97 				result->read_buffer_size_samples * sizeof(FLT));
98 		result->process_callback = process_callback;
99 		result->process_callback_arg = process_callback_arg;
100 		result->interrupted = 0;
101 		result->running = 0;
102 	}
103 }
104 
lingot_audio_destroy(LingotAudioHandler * audio)105 void lingot_audio_destroy(LingotAudioHandler* audio) {
106 		switch (audio->audio_system) {
107 #	ifdef OSS
108 		case AUDIO_SYSTEM_OSS:
109 			lingot_audio_oss_destroy(audio);
110 			break;
111 #	endif
112 #	ifdef ALSA
113 		case AUDIO_SYSTEM_ALSA:
114 			lingot_audio_alsa_destroy(audio);
115 			break;
116 #	endif
117 #	ifdef JACK
118 		case AUDIO_SYSTEM_JACK:
119 			lingot_audio_jack_destroy(audio);
120 			break;
121 #	endif
122 #	ifdef PULSEAUDIO
123 		case AUDIO_SYSTEM_PULSEAUDIO:
124 			lingot_audio_pulseaudio_destroy(audio);
125 			break;
126 #	endif
127 		default:
128 			assert (0);
129 		}
130 		if (audio->flt_read_buffer != 0x0) {
131 			free(audio->flt_read_buffer);
132 			audio->flt_read_buffer = 0x0;
133 		}
134 		audio->audio_system = -1;
135 }
136 
lingot_audio_read(LingotAudioHandler * audio)137 int lingot_audio_read(LingotAudioHandler* audio) {
138 	int samples_read = -1;
139 
140 		switch (audio->audio_system) {
141 #		ifdef OSS
142 		case AUDIO_SYSTEM_OSS:
143 			samples_read = lingot_audio_oss_read(audio);
144 			break;
145 #		endif
146 #		ifdef ALSA
147 		case AUDIO_SYSTEM_ALSA:
148 			samples_read = lingot_audio_alsa_read(audio);
149 			break;
150 #		endif
151 #		ifdef PULSEAUDIO
152 		case AUDIO_SYSTEM_PULSEAUDIO:
153 			samples_read = lingot_audio_pulseaudio_read(audio);
154 			break;
155 #		endif
156 		default:
157 			assert (0);
158 		}
159 
160 //#		define RATE_ESTIMATOR
161 
162 #		ifdef RATE_ESTIMATOR
163 		static double samplerate_estimator = 0.0;
164 		static unsigned long read_samples = 0;
165 		static double elapsed_time = 0.0;
166 
167 		struct timeval tdiff, t_abs;
168 		static struct timeval t_abs_old = { .tv_sec = 0, .tv_usec = 0 };
169 		static FILE* fid = 0x0;
170 
171 		if (fid == 0x0) {
172 			fid = fopen("/tmp/dump.txt", "w");
173 		}
174 
175 		gettimeofday(&t_abs, NULL );
176 
177 		if ((t_abs_old.tv_sec != 0) || (t_abs_old.tv_usec != 0)) {
178 
179 			int i;
180 			for (i = 0; i < samples_read; i++) {
181 				fprintf(fid, "%f ", audio->flt_read_buffer[i]);
182 //				printf("%f ", audio->flt_read_buffer[i]);
183 			}
184 //			printf("\n");
185 			timersub(&t_abs, &t_abs_old, &tdiff);
186 			read_samples = samples_read;
187 			elapsed_time = tdiff.tv_sec + 1e-6 * tdiff.tv_usec;
188 			static const double c = 0.9;
189 			samplerate_estimator = c * samplerate_estimator
190 					+ (1 - c) * (read_samples / elapsed_time);
191 //			printf("estimated sample rate %f (read %i samples in %f seconds)\n",
192 //					samplerate_estimator, read_samples, elapsed_time);
193 
194 		}
195 		t_abs_old = t_abs;
196 #		endif
197 
198 	return samples_read;
199 }
200 
lingot_audio_get_audio_system_properties(LingotAudioSystemProperties * properties,audio_system_t audio_system)201 int lingot_audio_get_audio_system_properties(
202 		LingotAudioSystemProperties* properties,
203 		audio_system_t audio_system) {
204 
205 	switch (audio_system) {
206 #	ifdef OSS
207 	case AUDIO_SYSTEM_OSS:
208 		return lingot_audio_oss_get_audio_system_properties(properties);
209 #	endif
210 #	ifdef ALSA
211 	case AUDIO_SYSTEM_ALSA:
212 		return lingot_audio_alsa_get_audio_system_properties(properties);
213 #	endif
214 #	ifdef JACK
215 	case AUDIO_SYSTEM_JACK:
216 		return lingot_audio_jack_get_audio_system_properties(properties);
217 #	endif
218 #	ifdef PULSEAUDIO
219 	case AUDIO_SYSTEM_PULSEAUDIO:
220 		return lingot_audio_pulseaudio_get_audio_system_properties(properties);
221 #	endif
222 	default:
223 		assert (0);
224 	}
225 
226 	return -1;
227 }
228 
lingot_audio_audio_system_properties_destroy(LingotAudioSystemProperties * properties)229 void lingot_audio_audio_system_properties_destroy(
230 		LingotAudioSystemProperties* properties) {
231 
232 	int i;
233 	if (properties->devices != NULL) {
234 		for (i = 0; i < properties->n_devices; i++) {
235 			if (properties->devices[i] != NULL ) {
236 				free(properties->devices[i]);
237 			}
238 		}
239 		free(properties->devices);
240 	}
241 }
242 
lingot_audio_run_reading_thread(LingotAudioHandler * audio)243 void lingot_audio_run_reading_thread(LingotAudioHandler* audio) {
244 
245 	int samples_read = 0;
246 
247 	while (audio->running) {
248 		// process new data block.
249 		samples_read = lingot_audio_read(audio);
250 
251 		if (samples_read < 0) {
252 			audio->running = 0;
253 			audio->interrupted = 1;
254 		} else {
255 			audio->process_callback(audio->flt_read_buffer, samples_read,
256 					audio->process_callback_arg);
257 		}
258 	}
259 
260 	pthread_mutex_lock(&audio->thread_input_read_mutex);
261 	pthread_cond_broadcast(&audio->thread_input_read_cond);
262 	pthread_mutex_unlock(&audio->thread_input_read_mutex);
263 
264 }
265 
lingot_audio_start(LingotAudioHandler * audio)266 int lingot_audio_start(LingotAudioHandler* audio) {
267 
268 	int result = 0;
269 
270 	switch (audio->audio_system) {
271 	case AUDIO_SYSTEM_JACK:
272 #		ifdef JACK
273 		result = lingot_audio_jack_start(audio);
274 #		else
275 		assert (0);
276 #		endif
277 		break;
278 	default:
279 		pthread_attr_init(&audio->thread_input_read_attr);
280 
281 		// detached thread.
282 		//  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
283 		pthread_mutex_init(&audio->thread_input_read_mutex, NULL );
284 		pthread_cond_init(&audio->thread_input_read_cond, NULL );
285 		pthread_attr_init(&audio->thread_input_read_attr);
286 		pthread_create(&audio->thread_input_read,
287 				&audio->thread_input_read_attr,
288 				(void* (*)(void*)) lingot_audio_run_reading_thread, audio);
289 		break;
290 	}
291 
292 	if (result == 0) {
293 		audio->running = 1;
294 	}
295 
296 	return result;
297 }
298 
299 // function invoked when the audio thread must be cancelled
lingot_audio_cancel(LingotAudioHandler * audio)300 void lingot_audio_cancel(LingotAudioHandler* audio) {
301 	// TODO: avoid
302 	fprintf(stderr, "warning: canceling audio thread\n");
303 	switch (audio->audio_system) {
304 #	ifdef PULSEAUDIO
305 	case AUDIO_SYSTEM_PULSEAUDIO:
306 		lingot_audio_pulseaudio_cancel(audio);
307 		break;
308 #	endif
309 	default:
310 		break;
311 	}
312 }
313 
lingot_audio_stop(LingotAudioHandler * audio)314 void lingot_audio_stop(LingotAudioHandler* audio) {
315 	void* thread_result;
316 
317 	int result;
318 	struct timeval tout, tout_abs;
319 	struct timespec tout_tspec;
320 
321 	gettimeofday(&tout_abs, NULL );
322 	tout.tv_sec = 0;
323 	tout.tv_usec = 500000;
324 
325 	if (audio->running == 1) {
326 		audio->running = 0;
327 		switch (audio->audio_system) {
328 		case AUDIO_SYSTEM_JACK:
329 #		ifdef JACK
330 			lingot_audio_jack_stop(audio);
331 #		else
332 			assert (0);
333 #		endif
334 			break;
335 //		case AUDIO_SYSTEM_PULSEAUDIO:
336 //			pthread_join(audio->thread_input_read, &thread_result);
337 //			pthread_attr_destroy(&audio->thread_input_read_attr);
338 //			pthread_mutex_destroy(&audio->thread_input_read_mutex);
339 //			pthread_cond_destroy(&audio->thread_input_read_cond);
340 //			break;
341 		default:
342 			timeradd(&tout, &tout_abs, &tout_abs);
343 			tout_tspec.tv_sec = tout_abs.tv_sec;
344 			tout_tspec.tv_nsec = 1000 * tout_abs.tv_usec;
345 
346 			// watchdog timer
347 			pthread_mutex_lock(&audio->thread_input_read_mutex);
348 			result = pthread_cond_timedwait(&audio->thread_input_read_cond,
349 					&audio->thread_input_read_mutex, &tout_tspec);
350 			pthread_mutex_unlock(&audio->thread_input_read_mutex);
351 
352 			if (result == ETIMEDOUT) {
353 				pthread_cancel(audio->thread_input_read);
354 				lingot_audio_cancel(audio);
355 			} else {
356 				pthread_join(audio->thread_input_read, &thread_result);
357 			}
358 			pthread_attr_destroy(&audio->thread_input_read_attr);
359 			pthread_mutex_destroy(&audio->thread_input_read_mutex);
360 			pthread_cond_destroy(&audio->thread_input_read_cond);
361 			break;
362 		}
363 	}
364 }
365 
366