examples: switch to 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   woodblock = new_fvec (overlap_size);
210   if (output_filename || usejack) {
211     /* dummy assignement to keep egcs happy */
212     found_wood = (onsetfile = new_aubio_sndfile_ro (onset_filename)) ||
213         (onsetfile = new_aubio_sndfile_ro ("sounds/woodblock.aiff")) ||
214         (onsetfile = new_aubio_sndfile_ro ("../sounds/woodblock.aiff"));
215     if (onsetfile == NULL) {
216       outmsg ("Could not find woodblock.aiff\n");
217       exit (1);
218     }
219   }
220   if (onsetfile) {
221     /* read the output sound once */
222     aubio_sndfile_read_mono (onsetfile, overlap_size, woodblock);
223   }
224
225   if (!usejack) {
226     debug ("Opening files ...\n");
227     file = new_aubio_sndfile_ro (input_filename);
228     if (file == NULL) {
229       outmsg ("Could not open input file %s.\n", input_filename);
230       exit (1);
231     }
232     if (verbose)
233       aubio_sndfile_info (file);
234     samplerate = aubio_sndfile_samplerate (file);
235     if (output_filename != NULL)
236       fileout = new_aubio_sndfile_wo (file, output_filename);
237   }
238 #ifdef HAVE_LASH
239   else {
240     aubio_lash_client = lash_init (lash_args, argv[0],
241         LASH_Config_Data_Set | LASH_Terminal, LASH_PROTOCOL (2, 0));
242     if (!aubio_lash_client) {
243       fprintf (stderr, "%s: could not initialise lash\n", __FUNCTION__);
244     }
245     /* tell the lash server our client id */
246     if (lash_enabled (aubio_lash_client)) {
247       lash_event_t *event =
248           (lash_event_t *) lash_event_new_with_type (LASH_Client_Name);
249       lash_event_set_string (event, "aubio");
250       lash_send_event (aubio_lash_client, event);
251       pthread_create (&lash_thread, NULL, lash_thread_main, NULL);
252     }
253   }
254 #endif /* HAVE_LASH */
255
256   uint_t i;
257   ibuf = new_fvec (overlap_size);
258   obuf = new_fvec (overlap_size);
259
260 }
261
262
263 void
264 examples_common_del (void)
265 {
266   uint_t i;
267   del_fvec (ibuf);
268   del_fvec (obuf);
269   del_fvec (woodblock);
270   aubio_cleanup ();
271 }
272
273 #if HAVE_JACK
274 aubio_jack_t *jack_setup;
275 #endif
276
277 void
278 examples_common_process (aubio_process_func_t process_func,
279     aubio_print_func_t print)
280 {
281   if (usejack) {
282
283 #if HAVE_JACK
284     debug ("Jack init ...\n");
285     jack_setup = new_aubio_jack (1, 1,
286         0, 1, (aubio_process_func_t) process_func);
287     debug ("Jack activation ...\n");
288     aubio_jack_activate (jack_setup);
289     debug ("Processing (Ctrl+C to quit) ...\n");
290     pause ();
291     aubio_jack_close (jack_setup);
292 #else
293     usage (stderr, 1);
294     outmsg ("Compiled without jack output, exiting.\n");
295 #endif
296
297   } else {
298     /* phasevoc */
299     debug ("Processing ...\n");
300
301     frames = 0;
302
303     while ((signed) overlap_size ==
304         aubio_sndfile_read_mono (file, overlap_size, ibuf)) {
305       process_func (&ibuf->data, &obuf->data, overlap_size);
306       print ();
307       if (output_filename != NULL) {
308         aubio_sndfile_write (fileout, overlap_size, &obuf);
309       }
310       frames++;
311     }
312
313     debug ("Processed %d frames of %d samples.\n", frames, buffer_size);
314
315     flush_process (process_func, print);
316     del_aubio_sndfile (file);
317
318     if (output_filename != NULL)
319       del_aubio_sndfile (fileout);
320
321   }
322 }
323
324 void
325 flush_process (aubio_process_func_t process_func, aubio_print_func_t print)
326 {
327   uint_t i;
328   fvec_zeros(obuf);
329   for (i = 0; (signed) i < frames_delay; i++) {
330     process_func (&ibuf->data, &obuf->data, overlap_size);
331     print ();
332   }
333 }
334
335 void
336 send_noteon (int pitch, int velo)
337 {
338   smpl_t mpitch = floor (aubio_freqtomidi (pitch) + .5);
339 #if HAVE_JACK
340   jack_midi_event_t ev;
341   ev.size = 3;
342   ev.buffer = malloc (3 * sizeof (jack_midi_data_t)); // FIXME
343   ev.time = 0;
344   if (usejack) {
345     ev.buffer[2] = velo;
346     ev.buffer[1] = mpitch;
347     if (velo == 0) {
348       ev.buffer[0] = 0x80;      /* note off */
349     } else {
350       ev.buffer[0] = 0x90;      /* note on */
351     }
352     aubio_jack_midi_event_write (jack_setup, (jack_midi_event_t *) & ev);
353   } else
354 #endif
355   if (!verbose) {
356     if (velo == 0) {
357       outmsg ("%f\n", frames * overlap_size / (float) samplerate);
358     } else {
359       outmsg ("%f\t%f\t", mpitch, frames * overlap_size / (float) samplerate);
360     }
361   }
362 }
363
364
365 #if HAVE_LASH
366
367 void *
368 lash_thread_main (void *data __attribute__ ((unused)))
369 {
370   printf ("LASH thread running\n");
371
372   while (!lash_main ())
373     usleep (1000);
374
375   printf ("LASH thread finished\n");
376   return NULL;
377 }
378
379 int
380 lash_main (void)
381 {
382   lash_event_t *lash_event;
383   lash_config_t *lash_config;
384
385   while ((lash_event = lash_get_event (aubio_lash_client))) {
386     switch (lash_event_get_type (lash_event)) {
387       case LASH_Quit:
388         lash_event_destroy (lash_event);
389         exit (1);
390         return 1;
391       case LASH_Restore_Data_Set:
392         lash_send_event (aubio_lash_client, lash_event);
393         break;
394       case LASH_Save_Data_Set:
395         save_data ();
396         lash_send_event (aubio_lash_client, lash_event);
397         break;
398       case LASH_Server_Lost:
399         return 1;
400       default:
401         printf ("%s: received unknown LASH event of type %d",
402             __FUNCTION__, lash_event_get_type (lash_event));
403         lash_event_destroy (lash_event);
404         break;
405     }
406   }
407
408   while ((lash_config = lash_get_config (aubio_lash_client))) {
409     restore_data (lash_config);
410     lash_config_destroy (lash_config);
411   }
412
413   return 0;
414 }
415
416 void
417 save_data ()
418 {
419   lash_config_t *lash_config;
420
421   lash_config = lash_config_new_with_key ("threshold");
422   lash_config_set_value_double (lash_config, threshold);
423   lash_send_config (aubio_lash_client, lash_config);
424
425 }
426
427 void
428 restore_data (lash_config_t * lash_config)
429 {
430   const char *lash_key;
431
432   lash_key = lash_config_get_key (lash_config);
433
434   if (strcmp (lash_key, "threshold") == 0) {
435     threshold = lash_config_get_value_double (lash_config);
436     return;
437   }
438
439 }
440
441 #endif /* HAVE_LASH */