examples/utils.c: exit if an output file could not be opened
[aubio.git] / examples / utils.c
1 /*
2   Copyright (C) 2003-2009 Paul Brossier <piem@aubio.org>
3
4   This file is part of aubio.
5
6   aubio is free software: you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation, either version 3 of the License, or
9   (at your option) any later version.
10
11   aubio is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with aubio.  If not, see <http://www.gnu.org/licenses/>.
18
19 */
20
21 /**
22
23   This file includes some tools common to all examples. Code specific to the
24   algorithm performed by each program should go in the source file of that
25   program instead.
26
27 */
28
29 #include "utils.h"
30
31 #ifdef HAVE_LASH
32 #include <lash/lash.h>
33 #include <pthread.h>
34 lash_client_t *aubio_lash_client;
35 lash_args_t *lash_args;
36 void *lash_thread_main (void *data);
37 int lash_main (void);
38 void save_data (void);
39 void restore_data (lash_config_t * lash_config);
40 pthread_t lash_thread;
41 #endif /* HAVE_LASH */
42
43 /* settings */
44 const char *sink_uri = NULL;
45 const char *source_uri = NULL;
46 int frames = 0;
47 int verbose = 0;
48 int usejack = 0;
49 int frames_delay = 0;
50
51
52 char_t * pitch_unit = "default";
53 char_t * pitch_mode = "default";
54
55 /* energy,specdiff,hfc,complexdomain,phase */
56 char_t * onset_mode = "default";
57 smpl_t threshold = 0.0;         // leave unset, only set as asked 
58 smpl_t silence = -90.;
59 uint_t buffer_size = 512;       //1024;
60 uint_t overlap_size = 256;      //512;
61 uint_t samplerate = 44100;
62
63 aubio_source_t *this_source = NULL;
64 aubio_sink_t *this_sink = NULL;
65
66 fvec_t *ibuf;
67 fvec_t *obuf;
68 fvec_t *woodblock;
69
70 /* badly redeclare some things */
71 smpl_t threshold;
72 smpl_t averaging;
73 const char *prog_name;
74
75 void flush_process (aubio_process_func_t process_func,
76     aubio_print_func_t print);
77
78 void
79 usage (FILE * stream, int exit_code)
80 {
81   fprintf (stream, "usage: %s [ options ] \n", prog_name);
82   fprintf (stream,
83       "       -h      --help          Display this message.\n"
84       "       -v      --verbose       Be verbose.\n"
85       "       -j      --jack          Use Jack.\n"
86       "       -o      --output        Output type.\n"
87       "       -i      --input         Input type.\n"
88       "       -O      --onset         Select onset detection algorithm.\n"
89       "       -t      --threshold     Set onset detection threshold.\n"
90       "       -s      --silence       Select silence threshold.\n"
91       "       -p      --pitch         Select pitch detection algorithm.\n"
92       "       -B      --bufsize       Set buffer size.\n"
93       "       -H      --hopsize       Set hopsize.\n"
94       "       -a      --averaging     Use averaging.\n");
95   exit (exit_code);
96 }
97
98 int
99 parse_args (int argc, char **argv)
100 {
101   const char *options = "hvjo:i:O:t:s:p:B:H:a";
102   int next_option;
103   struct option long_options[] = {
104     {"help", 0, NULL, 'h'},
105     {"verbose", 0, NULL, 'v'},
106     {"jack", 0, NULL, 'j'},
107     {"output", 1, NULL, 'o'},
108     {"input", 1, NULL, 'i'},
109     {"onset", 1, NULL, 'O'},
110     {"threshold", 1, NULL, 't'},
111     {"silence", 1, NULL, 's'},
112     {"pitch", 1, NULL, 'p'},
113     {"averaging", 0, NULL, 'a'},
114     {"bufsize", 1, NULL, 'B'},
115     {"hopsize", 1, NULL, 'H'},
116     {NULL, 0, NULL, 0}
117   };
118 #ifdef HAVE_LASH
119   lash_args = lash_extract_args (&argc, &argv);
120 #endif /* HAVE_LASH */
121   prog_name = argv[0];
122   if (argc < 1) {
123     usage (stderr, 1);
124     return -1;
125   }
126   do {
127     next_option = getopt_long (argc, argv, options, long_options, NULL);
128     switch (next_option) {
129       case 'o':
130         sink_uri = optarg;
131         break;
132       case 'i':
133         source_uri = optarg;
134         break;
135       case 'h':                /* help */
136         usage (stdout, 0);
137         return -1;
138       case 'v':                /* verbose */
139         verbose = 1;
140         break;
141       case 'j':
142         usejack = 1;
143         break;
144       case 'O':                /*onset type */
145         onset_mode = optarg;
146         break;
147       case 's':                /* silence value for onset */
148         silence = (smpl_t) atof (optarg);
149         break;
150       case 't':                /* threshold value for onset */
151         threshold = (smpl_t) atof (optarg);
152         break;
153       case 'p':
154         pitch_mode = optarg;
155         break;
156       case 'a':
157         averaging = 1;
158         break;
159       case 'B':
160         buffer_size = atoi (optarg);
161         break;
162       case 'H':
163         overlap_size = atoi (optarg);
164         break;
165       case '?':                /* unknown options */
166         usage (stderr, 1);
167         break;
168       case -1:                 /* done with options */
169         break;
170       default:                 /*something else unexpected */
171         fprintf (stderr, "Error parsing option '%c'\n", next_option);
172         abort ();
173     }
174   }
175   while (next_option != -1);
176
177   if (source_uri != NULL) {
178     debug ("Input file : %s\n", source_uri);
179   } else if (source_uri != NULL && sink_uri != NULL) {
180     debug ("Input file : %s\n", source_uri);
181     debug ("Output file : %s\n", sink_uri);
182   } else {
183 #if HAVE_JACK
184     debug ("Jack input output\n");
185     usejack = 1;
186 #else
187     errmsg("Error: no arguments given (and no available audio input)\n");
188     usage ( stderr, 1 );
189 #endif
190   }
191
192   return 0;
193 }
194
195 void
196 examples_common_init (int argc, char **argv)
197 {
198
199   /* parse command line arguments */
200   parse_args (argc, argv);
201
202   if (!usejack) {
203     debug ("Opening files ...\n");
204     this_source = new_aubio_source ((char_t*)source_uri, 0, overlap_size);
205     if (this_source == NULL) {
206       outmsg ("Could not open input file %s.\n", source_uri);
207       exit (1);
208     }
209     samplerate = aubio_source_get_samplerate(this_source);
210     if (sink_uri != NULL) {
211       this_sink = new_aubio_sink ((char_t*)sink_uri, samplerate);
212       if (this_sink == NULL) {
213         outmsg ("Could not open output file %s.\n", sink_uri);
214         exit (1);
215       }
216     }
217   }
218 #ifdef HAVE_LASH
219   else {
220     aubio_lash_client = lash_init (lash_args, argv[0],
221         LASH_Config_Data_Set | LASH_Terminal, LASH_PROTOCOL (2, 0));
222     if (!aubio_lash_client) {
223       fprintf (stderr, "%s: could not initialise lash\n", __FUNCTION__);
224     }
225     /* tell the lash server our client id */
226     if (lash_enabled (aubio_lash_client)) {
227       lash_event_t *event =
228           (lash_event_t *) lash_event_new_with_type (LASH_Client_Name);
229       lash_event_set_string (event, "aubio");
230       lash_send_event (aubio_lash_client, event);
231       pthread_create (&lash_thread, NULL, lash_thread_main, NULL);
232     }
233   }
234 #endif /* HAVE_LASH */
235
236   woodblock = new_fvec (overlap_size);
237   //TODO create woodblock sound
238
239   ibuf = new_fvec (overlap_size);
240   obuf = new_fvec (overlap_size);
241
242 }
243
244 void
245 examples_common_del (void)
246 {
247   del_fvec (ibuf);
248   del_fvec (obuf);
249   del_fvec (woodblock);
250   aubio_cleanup ();
251 }
252
253 #if HAVE_JACK
254 aubio_jack_t *jack_setup;
255 #endif
256
257 void
258 examples_common_process (aubio_process_func_t process_func,
259     aubio_print_func_t print)
260 {
261
262   uint_t read = 0;
263   if (usejack) {
264
265 #if HAVE_JACK
266     debug ("Jack init ...\n");
267     jack_setup = new_aubio_jack (1, 1,
268         0, 1, (aubio_process_func_t) process_func);
269     debug ("Jack activation ...\n");
270     aubio_jack_activate (jack_setup);
271     debug ("Processing (Ctrl+C to quit) ...\n");
272     pause ();
273     aubio_jack_close (jack_setup);
274 #else
275     usage (stderr, 1);
276     outmsg ("Compiled without jack output, exiting.\n");
277 #endif
278
279   } else {
280     /* phasevoc */
281     debug ("Processing ...\n");
282
283     frames = 0;
284
285     do {
286       aubio_source_do (this_source, ibuf, &read);
287       process_func (&ibuf->data, &obuf->data, overlap_size);
288       print ();
289       if (this_sink) {
290         aubio_sink_do (this_sink, obuf, overlap_size);
291       }
292       frames++;
293     } while (read == overlap_size);
294
295     debug ("Processed %d frames of %d samples.\n", frames, buffer_size);
296
297     flush_process (process_func, print);
298     del_aubio_source (this_source);
299     del_aubio_sink   (this_sink);
300
301   }
302 }
303
304 void
305 flush_process (aubio_process_func_t process_func, aubio_print_func_t print)
306 {
307   uint_t i;
308   fvec_zeros(obuf);
309   for (i = 0; (signed) i < frames_delay; i++) {
310     process_func (&ibuf->data, &obuf->data, overlap_size);
311     print ();
312   }
313 }
314
315 void
316 send_noteon (int pitch, int velo)
317 {
318   smpl_t mpitch = floor (aubio_freqtomidi (pitch) + .5);
319 #if HAVE_JACK
320   jack_midi_event_t ev;
321   ev.size = 3;
322   ev.buffer = malloc (3 * sizeof (jack_midi_data_t)); // FIXME
323   ev.time = 0;
324   if (usejack) {
325     ev.buffer[2] = velo;
326     ev.buffer[1] = mpitch;
327     if (velo == 0) {
328       ev.buffer[0] = 0x80;      /* note off */
329     } else {
330       ev.buffer[0] = 0x90;      /* note on */
331     }
332     aubio_jack_midi_event_write (jack_setup, (jack_midi_event_t *) & ev);
333   } else
334 #endif
335   if (!verbose) {
336     if (velo == 0) {
337       outmsg ("%f\n", frames * overlap_size / (float) samplerate);
338     } else {
339       outmsg ("%f\t%f\t", mpitch, frames * overlap_size / (float) samplerate);
340     }
341   }
342 }
343
344
345 #if HAVE_LASH
346
347 void *
348 lash_thread_main (void *data __attribute__ ((unused)))
349 {
350   printf ("LASH thread running\n");
351
352   while (!lash_main ())
353     usleep (1000);
354
355   printf ("LASH thread finished\n");
356   return NULL;
357 }
358
359 int
360 lash_main (void)
361 {
362   lash_event_t *lash_event;
363   lash_config_t *lash_config;
364
365   while ((lash_event = lash_get_event (aubio_lash_client))) {
366     switch (lash_event_get_type (lash_event)) {
367       case LASH_Quit:
368         lash_event_destroy (lash_event);
369         exit (1);
370         return 1;
371       case LASH_Restore_Data_Set:
372         lash_send_event (aubio_lash_client, lash_event);
373         break;
374       case LASH_Save_Data_Set:
375         save_data ();
376         lash_send_event (aubio_lash_client, lash_event);
377         break;
378       case LASH_Server_Lost:
379         return 1;
380       default:
381         printf ("%s: received unknown LASH event of type %d",
382             __FUNCTION__, lash_event_get_type (lash_event));
383         lash_event_destroy (lash_event);
384         break;
385     }
386   }
387
388   while ((lash_config = lash_get_config (aubio_lash_client))) {
389     restore_data (lash_config);
390     lash_config_destroy (lash_config);
391   }
392
393   return 0;
394 }
395
396 void
397 save_data ()
398 {
399   lash_config_t *lash_config;
400
401   lash_config = lash_config_new_with_key ("threshold");
402   lash_config_set_value_double (lash_config, threshold);
403   lash_send_config (aubio_lash_client, lash_config);
404
405 }
406
407 void
408 restore_data (lash_config_t * lash_config)
409 {
410   const char *lash_key;
411
412   lash_key = lash_config_get_key (lash_config);
413
414   if (strcmp (lash_key, "threshold") == 0) {
415     threshold = lash_config_get_value_double (lash_config);
416     return;
417   }
418
419 }
420
421 #endif /* HAVE_LASH */