examples/: make use of aubio_onset in aubioonset and aubionotes, simplify, keep only...
[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 *output_filename = NULL;
45 const char *input_filename = NULL;
46 const char *onset_filename =
47     AUBIO_PREFIX "/share/sounds/" PACKAGE "/woodblock.aiff";
48 int frames = 0;
49 int verbose = 0;
50 int usejack = 0;
51 int frames_delay = 0;
52
53
54 char_t * pitch_unit = "default";
55 char_t * pitch_mode = "default";
56
57 /* energy,specdiff,hfc,complexdomain,phase */
58 char_t * onset_mode = "default";
59 smpl_t threshold = 0.3;
60 smpl_t silence = -90.;
61 uint_t buffer_size = 512;       //1024;
62 uint_t overlap_size = 256;      //512;
63 uint_t channels = 1;
64 uint_t samplerate = 44100;
65
66
67 aubio_sndfile_t *file = NULL;
68 aubio_sndfile_t *fileout = NULL;
69
70 fvec_t *ibuf;
71 fvec_t *obuf;
72 fvec_t *woodblock;
73
74 /* badly redeclare some things */
75 smpl_t threshold;
76 smpl_t averaging;
77 const char *prog_name;
78
79 void flush_process (aubio_process_func_t process_func,
80     aubio_print_func_t print);
81
82 void
83 usage (FILE * stream, int exit_code)
84 {
85   fprintf (stream, "usage: %s [ options ] \n", prog_name);
86   fprintf (stream,
87       "       -h      --help          Display this message.\n"
88       "       -v      --verbose       Be verbose.\n"
89       "       -j      --jack          Use Jack.\n"
90       "       -o      --output        Output type.\n"
91       "       -i      --input         Input type.\n"
92       "       -O      --onset         Select onset detection algorithm.\n"
93       "       -t      --threshold     Set onset detection threshold.\n"
94       "       -s      --silence       Select silence threshold.\n"
95       "       -p      --pitch         Select pitch detection algorithm.\n"
96       "       -B      --bufsize       Set buffer size.\n"
97       "       -H      --hopsize       Set hopsize.\n"
98       "       -a      --averaging     Use averaging.\n");
99   exit (exit_code);
100 }
101
102 int
103 parse_args (int argc, char **argv)
104 {
105   const char *options = "hvjo:i:O:t:s:p:B:H:a";
106   int next_option;
107   struct option long_options[] = {
108     {"help", 0, NULL, 'h'},
109     {"verbose", 0, NULL, 'v'},
110     {"jack", 0, NULL, 'j'},
111     {"output", 1, NULL, 'o'},
112     {"input", 1, NULL, 'i'},
113     {"onset", 1, NULL, 'O'},
114     {"threshold", 1, NULL, 't'},
115     {"silence", 1, NULL, 's'},
116     {"pitch", 1, NULL, 'p'},
117     {"averaging", 0, NULL, 'a'},
118     {"bufsize", 1, NULL, 'B'},
119     {"hopsize", 1, NULL, 'H'},
120     {NULL, 0, NULL, 0}
121   };
122 #ifdef HAVE_LASH
123   lash_args = lash_extract_args (&argc, &argv);
124 #endif /* HAVE_LASH */
125   prog_name = argv[0];
126   if (argc < 1) {
127     usage (stderr, 1);
128     return -1;
129   }
130   do {
131     next_option = getopt_long (argc, argv, options, long_options, NULL);
132     switch (next_option) {
133       case 'o':
134         output_filename = optarg;
135         break;
136       case 'i':
137         input_filename = optarg;
138         break;
139       case 'h':                /* help */
140         usage (stdout, 0);
141         return -1;
142       case 'v':                /* verbose */
143         verbose = 1;
144         break;
145       case 'j':
146         usejack = 1;
147         break;
148       case 'O':                /*onset type */
149         onset_mode = optarg;
150         break;
151       case 's':                /* threshold value for onset */
152         silence = (smpl_t) atof (optarg);
153         break;
154       case 't':                /* threshold value for onset */
155         threshold = (smpl_t) atof (optarg);
156         /*
157            if (!isfinite(threshold)) {
158            debug("could not get threshold.\n");
159            abort();
160            }
161          */
162         break;
163       case 'p':
164         pitch_mode = optarg;
165         break;
166       case 'a':
167         averaging = 1;
168         break;
169       case 'B':
170         buffer_size = atoi (optarg);
171         break;
172       case 'H':
173         overlap_size = atoi (optarg);
174         break;
175       case '?':                /* unknown options */
176         usage (stderr, 1);
177         break;
178       case -1:                 /* done with options */
179         break;
180       default:                 /*something else unexpected */
181         fprintf (stderr, "Error parsing option '%c'\n", next_option);
182         abort ();
183     }
184   }
185   while (next_option != -1);
186
187   if (input_filename != NULL) {
188     debug ("Input file : %s\n", input_filename);
189   } else if (input_filename != NULL && output_filename != NULL) {
190     debug ("Input file : %s\n", input_filename);
191     debug ("Output file : %s\n", output_filename);
192   } else {
193 #if HAVE_JACK
194     debug ("Jack input output\n");
195     usejack = 1;
196 #else
197     debug
198         ("Error: Could not switch to jack mode\n   aubio was compiled without jack support\n");
199     exit (1);
200 #endif
201   }
202
203   return 0;
204 }
205
206 void
207 examples_common_init (int argc, char **argv)
208 {
209
210   uint_t found_wood = 0;
211
212   aubio_sndfile_t *onsetfile = NULL;
213   /* parse command line arguments */
214   parse_args (argc, argv);
215
216   woodblock = new_fvec (buffer_size, 1);
217   if (output_filename || usejack) {
218     /* dummy assignement to keep egcs happy */
219     found_wood = (onsetfile = new_aubio_sndfile_ro (onset_filename)) ||
220         (onsetfile = new_aubio_sndfile_ro ("sounds/woodblock.aiff")) ||
221         (onsetfile = new_aubio_sndfile_ro ("../sounds/woodblock.aiff"));
222     if (onsetfile == NULL) {
223       outmsg ("Could not find woodblock.aiff\n");
224       exit (1);
225     }
226   }
227   if (onsetfile) {
228     /* read the output sound once */
229     aubio_sndfile_read (onsetfile, overlap_size, woodblock);
230   }
231
232   if (!usejack) {
233     debug ("Opening files ...\n");
234     file = new_aubio_sndfile_ro (input_filename);
235     if (file == NULL) {
236       outmsg ("Could not open input file %s.\n", input_filename);
237       exit (1);
238     }
239     if (verbose)
240       aubio_sndfile_info (file);
241     channels = aubio_sndfile_channels (file);
242     samplerate = aubio_sndfile_samplerate (file);
243     if (output_filename != NULL)
244       fileout = new_aubio_sndfile_wo (file, output_filename);
245   }
246 #ifdef HAVE_LASH
247   else {
248     aubio_lash_client = lash_init (lash_args, argv[0],
249         LASH_Config_Data_Set | LASH_Terminal, LASH_PROTOCOL (2, 0));
250     if (!aubio_lash_client) {
251       fprintf (stderr, "%s: could not initialise lash\n", __FUNCTION__);
252     }
253     /* tell the lash server our client id */
254     if (lash_enabled (aubio_lash_client)) {
255       lash_event_t *event =
256           (lash_event_t *) lash_event_new_with_type (LASH_Client_Name);
257       lash_event_set_string (event, "aubio");
258       lash_send_event (aubio_lash_client, event);
259       pthread_create (&lash_thread, NULL, lash_thread_main, NULL);
260     }
261   }
262 #endif /* HAVE_LASH */
263
264   ibuf = new_fvec (overlap_size, channels);
265   obuf = new_fvec (overlap_size, channels);
266
267 }
268
269
270 void
271 examples_common_del (void)
272 {
273   del_fvec (ibuf);
274   del_fvec (obuf);
275   del_fvec (woodblock);
276   aubio_cleanup ();
277 }
278
279 #if HAVE_JACK
280 aubio_jack_t *jack_setup;
281 #endif
282
283 void
284 examples_common_process (aubio_process_func_t process_func,
285     aubio_print_func_t print)
286 {
287   if (usejack) {
288
289 #if HAVE_JACK
290     debug ("Jack init ...\n");
291     jack_setup = new_aubio_jack (channels, channels,
292         0, 1, (aubio_process_func_t) process_func);
293     debug ("Jack activation ...\n");
294     aubio_jack_activate (jack_setup);
295     debug ("Processing (Ctrl+C to quit) ...\n");
296     pause ();
297     aubio_jack_close (jack_setup);
298 #else
299     usage (stderr, 1);
300     outmsg ("Compiled without jack output, exiting.\n");
301 #endif
302
303   } else {
304     /* phasevoc */
305     debug ("Processing ...\n");
306
307     frames = 0;
308
309     while ((signed) overlap_size == aubio_sndfile_read (file, overlap_size,
310             ibuf)) {
311       process_func (ibuf->data, obuf->data, overlap_size);
312       print ();
313       if (output_filename != NULL) {
314         aubio_sndfile_write (fileout, overlap_size, obuf);
315       }
316       frames++;
317     }
318
319     debug ("Processed %d frames of %d samples.\n", frames, buffer_size);
320
321     flush_process (process_func, print);
322     del_aubio_sndfile (file);
323
324     if (output_filename != NULL)
325       del_aubio_sndfile (fileout);
326
327   }
328 }
329
330 void
331 flush_process (aubio_process_func_t process_func, aubio_print_func_t print)
332 {
333   uint_t i;
334   fvec_zeros(obuf);
335   for (i = 0; (signed) i < frames_delay; i++) {
336     process_func (ibuf->data, obuf->data, overlap_size);
337     print ();
338   }
339 }
340
341 void
342 send_noteon (int pitch, int velo)
343 {
344   smpl_t mpitch = floor (aubio_freqtomidi (pitch) + .5);
345 #if HAVE_JACK
346   jack_midi_event_t ev;
347   ev.size = 3;
348   ev.buffer = malloc (3 * sizeof (jack_midi_data_t)); // FIXME
349   ev.time = 0;
350   if (usejack) {
351     ev.buffer[2] = velo;
352     ev.buffer[1] = mpitch;
353     if (velo == 0) {
354       ev.buffer[0] = 0x80;      /* note off */
355     } else {
356       ev.buffer[0] = 0x90;      /* note on */
357     }
358     aubio_jack_midi_event_write (jack_setup, (jack_midi_event_t *) & ev);
359   } else
360 #endif
361   if (!verbose) {
362     if (velo == 0) {
363       outmsg ("%f\n", frames * overlap_size / (float) samplerate);
364     } else {
365       outmsg ("%f\t%f\t", mpitch, frames * overlap_size / (float) samplerate);
366     }
367   }
368 }
369
370
371 #if HAVE_LASH
372
373 void *
374 lash_thread_main (void *data __attribute__ ((unused)))
375 {
376   printf ("LASH thread running\n");
377
378   while (!lash_main ())
379     usleep (1000);
380
381   printf ("LASH thread finished\n");
382   return NULL;
383 }
384
385 int
386 lash_main (void)
387 {
388   lash_event_t *lash_event;
389   lash_config_t *lash_config;
390
391   while ((lash_event = lash_get_event (aubio_lash_client))) {
392     switch (lash_event_get_type (lash_event)) {
393       case LASH_Quit:
394         lash_event_destroy (lash_event);
395         exit (1);
396         return 1;
397       case LASH_Restore_Data_Set:
398         lash_send_event (aubio_lash_client, lash_event);
399         break;
400       case LASH_Save_Data_Set:
401         save_data ();
402         lash_send_event (aubio_lash_client, lash_event);
403         break;
404       case LASH_Server_Lost:
405         return 1;
406       default:
407         printf ("%s: received unknown LASH event of type %d",
408             __FUNCTION__, lash_event_get_type (lash_event));
409         lash_event_destroy (lash_event);
410         break;
411     }
412   }
413
414   while ((lash_config = lash_get_config (aubio_lash_client))) {
415     restore_data (lash_config);
416     lash_config_destroy (lash_config);
417   }
418
419   return 0;
420 }
421
422 void
423 save_data ()
424 {
425   lash_config_t *lash_config;
426
427   lash_config = lash_config_new_with_key ("threshold");
428   lash_config_set_value_double (lash_config, threshold);
429   lash_send_config (aubio_lash_client, lash_config);
430
431 }
432
433 void
434 restore_data (lash_config_t * lash_config)
435 {
436   const char *lash_key;
437
438   lash_key = lash_config_get_key (lash_config);
439
440   if (strcmp (lash_key, "threshold") == 0) {
441     threshold = lash_config_get_value_double (lash_config);
442     return;
443   }
444
445 }
446
447 #endif /* HAVE_LASH */