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