1 /* Determining Starts and Ends of Tracks
2 
3  * Copyright (C) 1998 J.A. Bezemer
4  *
5  * Licensed under the terms of the GNU General Public License.
6  * ABSOLUTELY NO WARRANTY.
7  * See the file `COPYING' in this directory.
8  */
9 
10 #include "tracksplit.h"
11 #ifndef SWIG
12 #include "tracksplit_filenm.h"
13 #include "tracksplit_parammenu.h"
14 #endif
15 #include "signpr_wav.h"
16 #include "fmtheaders.h"
17 #include "secshms.h"
18 #include "signpr_general.h"
19 #include "errorwindow.h"
20 #ifndef SWIG
21 #include "clrscr.h"
22 #endif
23 
24 #include <sys/stat.h>
25 #include <stdlib.h>
26 #include <math.h>
27 #include <string.h>
28 #ifndef SWIG
29 #ifndef OLD_CURSES
30 #include <stdio.h>
31 #include <ncurses.h>
32 #else
33 #include <curses.h>
34 #endif
35 #else
36 #include <stdio.h>
37 #endif
38 
39 
40 #ifndef SWIG
41 int
tracksplit_get_options(char * startdir,char * filename,int * make_use_rms,int * make_graphs,long * blocklen,int * global_silence_factor,int * local_silence_threshold,int * min_silence_blocks,int * min_track_blocks,int * extra_blocks_start,int * extra_blocks_end)42 tracksplit_get_options (char *startdir, char *filename,
43 			int *make_use_rms, int *make_graphs, long *blocklen,
44 			int *global_silence_factor,
45 			int *local_silence_threshold,
46 			int *min_silence_blocks,
47 			int *min_track_blocks, int *extra_blocks_start,
48 			int *extra_blocks_end)
49 /* Returns 0: Cancel, 1: OK */
50 {
51   int currscreen = 0;
52   int options_ready = 0;
53   int returnval = 0;		/* 0: Cancel, 1: OK */
54 
55   do
56     switch (currscreen)
57       {
58       case 0:
59 	switch (tracksplit_select_file (startdir, filename))
60 	  /* 0: Cancel,
61 	     1: PreviousScreen,
62 	     2: NextScreen/Start */
63 	  {
64 	  case 0:
65 	    options_ready = 1;
66 	    returnval = 0;
67 	    break;
68 	  case 2:
69 	    currscreen = 1;
70 	    break;
71 	    /* default: currscreen+=0 */
72 	  }
73 	break;
74 
75       case 1:
76 	switch (tracksplit_parammenu (make_use_rms, make_graphs, blocklen,
77 				      global_silence_factor,
78 				      local_silence_threshold,
79 				      min_silence_blocks,
80 				      min_track_blocks, extra_blocks_start,
81 				      extra_blocks_end))
82 	  /* 0: Cancel,
83 	     1: PreviousScreen,
84 	     2: NextScreen/Start */
85 	  {
86 	  case 0:
87 	    options_ready = 1;
88 	    returnval = 0;
89 	    break;
90 	  case 1:
91 	    currscreen = 0;
92 	    break;
93 	  case 2:
94 	    returnval = 1;
95 	    options_ready = 1;
96 	    break;
97 	    /* default: currscreen+=0 */
98 	  }
99 	break;
100       }
101   while (!options_ready);
102 
103   return returnval;
104 }
105 #endif
106 
107 
108 void
tracksplit_merge(short * typearray,long * startarray,long * endarray,long * num_of_parts)109 tracksplit_merge (short *typearray, long *startarray, long *endarray,
110 		  long *num_of_parts)
111 {
112   long l;
113   long l2 = 0;
114 
115   for (l = 1; l < *num_of_parts; l++)
116     if (typearray[l] == typearray[l2])
117       /* same type as previous -> merge */
118       endarray[l2] = endarray[l];
119     else
120       {
121 	/* different */
122 	l2++;
123 	typearray[l2] = typearray[l];
124 	startarray[l2] = startarray[l];
125 	endarray[l2] = endarray[l];
126       }
127 
128   *num_of_parts = l2 + 1;
129 }
130 
131 
132 void
tracksplit_findtracks(double * medarray,long total_blocks,double global_silence_threshold,int local_silence_threshold,int min_silence_blocks,int min_track_blocks,int extra_blocks_start,int extra_blocks_end,long * trackstarts,long * trackends,int * detected_tracks)133 tracksplit_findtracks (double *medarray,	/* inputs */
134 		       long total_blocks,
135 		       double global_silence_threshold,
136 		       int local_silence_threshold,
137 		       int min_silence_blocks,
138 		       int min_track_blocks,
139 		       int extra_blocks_start,
140 		       int extra_blocks_end,
141 
142 		       long *trackstarts,	/* outputs */
143 		       long *trackends,
144 		       int *detected_tracks)
145 {
146   double *above_threshold;
147   double *above_th_rms;
148 
149   short *part_type;
150   long *part_start;
151   long *part_end;
152   long num_parts;
153 
154   short type_now;
155   short type_left, type_right;
156 
157   double local_mean;
158 
159   register long l;
160   register long l2;
161   double tempdouble;
162 
163 
164 /* These modes must be >0 and all different */
165 #define POSSIBLE_TRACK     1
166 #define POSSIBLE_SILENCE   2
167 #define CERTAIN_TRACK      3
168 #define CERTAIN_SILENCE    4
169 
170 #define SECOND_THRESHOLD   500
171 
172 
173   /* reserve space for arrays */
174   above_threshold = (double *) malloc (total_blocks * sizeof (double));
175   above_th_rms = (double *) malloc (total_blocks * sizeof (double));
176   part_type = (short *) malloc (total_blocks * sizeof (short));
177   part_start = (long *) malloc (total_blocks * sizeof (long));
178   part_end = (long *) malloc (total_blocks * sizeof (long));
179 
180   /* apply global threshold */
181   for (l = 0; l < total_blocks; l++)
182     {
183       if (medarray[l] > global_silence_threshold)
184 	above_threshold[l] = 1000;
185       else
186 	above_threshold[l] = 0;
187 
188       above_th_rms[l] = 0;
189     }
190 
191   /* smooth the data a little by `running RMS' of length 11 */
192   for (l = 0; l < total_blocks; l++)
193     {
194       tempdouble = 0;
195       for (l2 = l - 5; l2 <= l + 5; l2++)
196 	if (l2 >= 0 && l2 < total_blocks)
197 	  tempdouble += above_threshold[l2] * above_threshold[l2];
198       /* else tempdouble += 0 */
199       above_th_rms[l] = sqrt (tempdouble / (2 * 5 + 1));
200     }
201 
202   /* before first track is certainly nothing (this is necessary for the
203      computation later on) */
204   part_type[0] = CERTAIN_SILENCE;
205   part_start[0] = -2;
206   part_end[0] = -2;
207 
208   type_now = POSSIBLE_SILENCE;
209   num_parts = 1;
210   l2 = -1;			/* l2 = start of current mode */
211 
212   for (l = 0; l < total_blocks; l++)
213     {
214       if (type_now == POSSIBLE_SILENCE &&
215 	  above_th_rms[l] > SECOND_THRESHOLD)
216 	{
217 	  part_type[num_parts] = type_now;
218 	  part_start[num_parts] = l2;
219 	  part_end[num_parts] = l - 1;
220 	  l2 = l;
221 	  type_now = POSSIBLE_TRACK;
222 	  num_parts++;
223 	}
224 
225       if (type_now == POSSIBLE_TRACK &&
226 	  above_th_rms[l] <= SECOND_THRESHOLD)
227 	{
228 	  part_type[num_parts] = type_now;
229 	  part_start[num_parts] = l2;
230 	  part_end[num_parts] = l - 1;
231 	  l2 = l;
232 	  type_now = POSSIBLE_SILENCE;
233 	  num_parts++;
234 	}
235     }
236 
237   /* close last track/silence */
238   part_type[num_parts] = type_now;
239   part_start[num_parts] = l2;
240   part_end[num_parts] = l - 1;
241   l2 = l;
242   num_parts++;
243 
244   /* after last block there's certainly nothing */
245   part_type[num_parts] = CERTAIN_SILENCE;
246   part_start[num_parts] = l2;
247   part_end[num_parts] = l2;
248   num_parts++;
249 
250 
251   /* search for certain tracks/silences */
252   for (l = 0; l < num_parts; l++)
253     {
254       if (part_type[l] == POSSIBLE_SILENCE
255 	  && part_end[l] - part_start[l] + 1 >= min_silence_blocks)
256 	part_type[l] = CERTAIN_SILENCE;
257 
258       if (part_type[l] == POSSIBLE_TRACK
259 	  && part_end[l] - part_start[l] + 1 >= min_track_blocks)
260 	part_type[l] = CERTAIN_TRACK;
261     }
262 
263 #define notPART_DEBUG
264 #ifdef PART_DEBUG
265   for (l = 0; l < num_parts; l++)
266     fprintf (stderr, "\n\rBlk: %ld  Typ: %hd  Start: %ld  End: %ld",
267 	     l, part_type[l], part_start[l], part_end[l]);
268   sleep (5);
269 #endif
270 
271   /* If first silence (blocks -1 .. ??) shorter than min_sil, it would
272      be added in front of the first track. That's not what we want, so
273      force it to be certain silence. Likewise with the last silence
274      (if there is one). */
275 
276   /* Part 0, block -2 only, already was certain silence;
277      part 1 always starts at block -1 and is either possible or certain
278      silence. */
279   if (part_type[1] == POSSIBLE_SILENCE)
280     part_type[1] = CERTAIN_SILENCE;
281   /* At this point, both _blocks_ -2 and -1 are certain silence. */
282 
283   /* Part num_parts-1 is block total_blocks only, and is certain silence;
284      part num_parts-2 may be all modes. */
285   if (part_type[num_parts - 2] == POSSIBLE_SILENCE)
286     part_type[num_parts - 2] = CERTAIN_SILENCE;
287   /* At this point, _block_ total_blocks is certain silence. */
288 
289   /* Concluding, now all `virtual' blocks (outside range 0...total_blocks-1)
290      are certain silence, and won't be (illegal) parts of tracks. */
291 
292 
293   /* Search for poss_sil poss_tr poss_sil, to account for ticks within
294      silences; convert to (poss_sil)^3
295 
296      This works, but may do some strange things. For example: c_t p_s p_t
297      p_s c_t might become c_t p_s p_s p_s c_t -> c_t p_s c_t -> c_t c_s c_t.
298      In words: a more-or-less common occurrence within one (1) track could
299      get interpreted as a inter-track silence.
300 
301      Actually, this is not really a problem, because it is much easier to
302      join two parts of one track than to manually split one `track' in two
303      pieces at the right spot. So, it doesn't matter if there are a few
304      silences too much. */
305   for (l = 1; l < num_parts - 1; l++)
306     {
307       if (part_type[l] == POSSIBLE_TRACK
308 	  && part_type[l - 1] == POSSIBLE_SILENCE
309 	  && part_type[l + 1] == POSSIBLE_SILENCE
310 	  && part_end[l] - part_start[l] < 10)
311 	part_type[l] = POSSIBLE_SILENCE;
312     }
313 
314   tracksplit_merge (part_type, part_start, part_end,
315 		    &num_parts);
316 
317   /* now some (poss_sil)^3 sequences may be > min_silence_blocks, so
318      check again */
319   for (l = 0; l < num_parts; l++)
320     {
321       if (part_type[l] == POSSIBLE_SILENCE
322 	  && part_end[l] - part_start[l] + 1 >= min_silence_blocks)
323 	part_type[l] = CERTAIN_SILENCE;
324     }
325 
326 
327   /* More rules here? */
328 
329 
330 #ifdef PART_DEBUG
331   for (l = 0; l < num_parts; l++)
332     fprintf (stderr, "\n\rBlk: %ld  Typ: %hd  Start: %ld  End: %ld",
333 	     l, part_type[l], part_start[l], part_end[l]);
334   sleep (5);
335 #endif
336 
337   /* now resolve all other possible_* */
338   for (l = 0; l < num_parts; l++)
339     if (part_type[l] == POSSIBLE_SILENCE || part_type[l] == POSSIBLE_TRACK)
340       {
341 	/* search what is certain on left side */
342 	l2 = l;
343 	type_left = 0;
344 	while (l2 >= 0 && type_left == 0)
345 	  {
346 	    if (part_type[l2] == CERTAIN_SILENCE
347 		|| part_type[l2] == CERTAIN_TRACK)
348 	      type_left = part_type[l2];
349 	    l2--;
350 	  }
351 	if (type_left == 0)
352 	  type_left = CERTAIN_SILENCE;
353 
354 	/* search what is certain on right side */
355 	l2 = l;
356 	type_right = 0;
357 	while (l2 < num_parts && type_right == 0)
358 	  {
359 	    if (part_type[l2] == CERTAIN_SILENCE
360 		|| part_type[l2] == CERTAIN_TRACK)
361 	      type_right = part_type[l2];
362 	    l2++;
363 	  }
364 	if (type_right == 0)
365 	  type_right = CERTAIN_SILENCE;
366 
367 	/* decide what this one is going to be */
368 	if (type_left == CERTAIN_SILENCE && type_right == CERTAIN_SILENCE)
369 	  part_type[l] = CERTAIN_SILENCE;
370 	else			/* CERTAIN_TRACK on either or both sides */
371 	  part_type[l] = CERTAIN_TRACK;
372       }
373 
374   tracksplit_merge (part_type, part_start, part_end,
375 		    &num_parts);
376 
377   /* Get rid of (illegal) blocks -2, -1 and total_blocks */
378   if (part_end[0] >= 0)
379     part_start[0] = 0;
380   else
381     {
382       for (l = 0; l < num_parts - 1; l++)
383 	{
384 	  part_type[l] = part_type[l + 1];
385 	  part_start[l] = part_start[l + 1];
386 	  part_end[l] = part_end[l + 1];
387 	}
388       num_parts--;
389     }
390 
391   if (part_start[num_parts - 1] <= total_blocks - 1)
392     part_end[num_parts - 1] = total_blocks - 1;
393   else
394     num_parts--;
395 
396 #ifdef PART_DEBUG
397   for (l = 0; l < num_parts; l++)
398     fprintf (stderr, "\n\rBlk: %ld  Typ: %hd  Start: %ld  End: %ld",
399 	     l, part_type[l], part_start[l], part_end[l]);
400   sleep (5);
401 #endif
402 
403   /* fine-search for track starts/ends */
404   for (l = 0; l < num_parts; l++)
405     if (part_type[l] == CERTAIN_SILENCE &&
406 	part_end[l] - part_start[l] + 1 >= 10)
407       {
408 	/* find local mean; exclude silence start/end */
409 	local_mean = 0;
410 	for (l2 = part_start[l] + 3; l2 <= part_end[l] - 3; l2++)
411 	  local_mean += medarray[l2];
412 	local_mean /= (part_end[l] - part_start[l] + 1 - 6);
413 
414 	while (medarray[part_start[l]] > local_mean *
415 	       (1 + (local_silence_threshold / 100.))
416 	       && part_start[l] < part_end[l])
417 	  part_start[l]++;
418 
419 	while (medarray[part_end[l]] > local_mean *
420 	       (1 + (local_silence_threshold / 100.))
421 	       && part_end[l] > part_start[l])
422 	  part_end[l]--;
423 
424 	/* minimize lost fade-in/out by adding extra blocks to track
425 	   start/end (if possible) */
426 	if (part_end[l] - part_start[l] + 1 >=
427 	    extra_blocks_end + extra_blocks_start + 1)
428 	  {
429 	    part_start[l] += extra_blocks_end;
430 	    part_end[l] -= extra_blocks_start;
431 	  }
432 
433 	/* Now silence may be too short, regard it as silence-in-a-track;
434 	   except first and last silence. */
435 	if (part_end[l] - part_start[l] + 1 < min_silence_blocks
436 	    && l > 0 && l < num_parts - 1)
437 	  part_type[l] = CERTAIN_TRACK;
438 
439 	/* Adjust adjecent tracks */
440 	if (l > 0)
441 	  part_end[l - 1] = part_start[l] - 1;
442 	if (l < num_parts - 1)
443 	  part_start[l + 1] = part_end[l] + 1;
444       }
445 
446   /* if too-short-c_s -> c_t, we should merge c_t's */
447   tracksplit_merge (part_type, part_start, part_end,
448 		    &num_parts);
449 
450 #ifdef PART_DEBUG
451   for (l = 0; l < num_parts; l++)
452     fprintf (stderr, "\n\rBlk: %ld  Typ: %hd  Start: %ld  End: %ld",
453 	     l, part_type[l], part_start[l], part_end[l]);
454   sleep (5);
455 #endif
456 
457   /* Make an array with tracks only */
458   *detected_tracks = 0;
459   for (l = 0; l < num_parts && *detected_tracks < 99; l++)
460     if (part_type[l] == CERTAIN_TRACK)
461       {
462 	trackstarts[*detected_tracks] = part_start[l];
463 	trackends[*detected_tracks] = part_end[l];
464 	(*detected_tracks)++;
465       }
466 
467 #if 0
468 /* TESTING: determine mean(localmeans) */
469 /* NB: what if NO certain silences? -> divide by 0 ?? */
470   tempdouble = 0;
471   for (l = 0; l < num_parts; l++)
472     if (part_type[l] == CERTAIN_SILENCE)
473       {
474 	local_mean = 0;
475 	for (l2 = part_start[l]; l2 <= part_end[l]; l2++)
476 	  local_mean += medarray[l2];
477 	local_mean /= (part_end[l] - part_start[l] + 1);
478 	tempdouble += local_mean;
479       }
480   l2 = 0;
481   for (l = 0; l < num_parts; l++)
482     if (part_type[l] == CERTAIN_SILENCE)
483       l2++;
484   tempdouble /= l2;
485   fprintf (stderr, "mean(locmean)= %f ", tempdouble);
486 /* END TESTING */
487 #endif /* 0 */
488 
489   free (above_threshold);
490   free (above_th_rms);
491   free (part_type);
492   free (part_start);
493   free (part_end);
494 }
495 
496 
497 void
498 #ifndef SWIG
tracksplit_main(char * startdir)499 tracksplit_main (char *startdir)
500 #else
501 tracksplit_main (char *filename,
502                  int make_use_rms, int make_graphs, long blocklen,
503                  int global_silence_factor,
504                  int local_silence_threshold,
505                  int min_silence_blocks,
506                  int min_track_blocks, int extra_blocks_start,
507                  int extra_blocks_end)
508 #endif
509 {
510 #ifndef SWIG
511   char filename[250];
512 
513   /* options menu defaults */
514   int make_use_rms = 1;
515   int make_graphs = 0;
516   long blocklen = 4410;
517   int global_silence_factor = 150;
518   int local_silence_threshold = 5;
519   int min_silence_blocks = 20;
520   int min_track_blocks = 50;
521   int extra_blocks_start = 3;
522   int extra_blocks_end = 6;
523 #endif
524 
525   sample_t sample;
526 
527   double *rmsarray = NULL;	/* Otherwise gcc complains */
528   double *medarray;
529   double *sortarray;
530 
531   long total_samples, total_samples_read;
532   struct stat buf;
533   register long l;
534   long samples_read;
535   long current_block, total_blocks;
536   double sum_left, sum_right;
537   int i;
538   FILE *tempfile;
539   FILE *tempfile2;
540 
541 #define dontCOMPUTE_GLOBAL_MEAN
542 #ifdef COMPUTE_GLOBAL_MEAN
543   double global_mean;
544 #endif
545 
546   long trackstarts[100];
547   long trackends[100];
548   int detected_tracks;
549   char tempstring[250];
550   double global_silence_threshold;
551   double min_poss_threshold, max_poss_threshold;
552   int compute_rms_now;
553   long templong;
554 #ifndef SWIG
555   int in_ch;
556 
557   filename[0] = '\0';
558 
559   if (!tracksplit_get_options (startdir, filename,
560 			       &make_use_rms, &make_graphs, &blocklen,
561 			       &global_silence_factor,
562 			       &local_silence_threshold, &min_silence_blocks,
563 			       &min_track_blocks, &extra_blocks_start,
564 			       &extra_blocks_end))
565     return;
566 
567   clearscreen (TRACKSPLIT_COMPUTE_HEADERTEXT);
568   move (0, 79);
569   refresh ();
570 #else
571   int lastpercent;
572 #endif
573 
574   compute_rms_now = 0;		/* Should we compute RMS? */
575 
576   if (!make_use_rms)
577     compute_rms_now = 1;
578 
579   if (!compute_rms_now)		/* RMS must exist */
580     {
581       strcpy (tempstring, filename);
582       strcat (tempstring, ".rms");
583       tempfile = fopen (tempstring, "r");
584       if (tempfile == NULL)
585 	compute_rms_now = 1;
586     }
587 
588   if (!compute_rms_now)		/* Right RMS format */
589     {
590       fgets (tempstring, 100, tempfile);
591       if (strncasecmp (tempstring, "GramoFile Binary RMS Data", 25))
592 	{
593 	  fclose (tempfile);
594 	  compute_rms_now = 1;
595 	}
596     }
597 
598   if (!compute_rms_now)		/* Read blocklen */
599     {
600       if (fread (&templong, sizeof (long), 1, tempfile) < 1)
601 	{
602 	  fclose (tempfile);
603 	  compute_rms_now = 1;
604 	}
605     }
606 
607   if (!compute_rms_now)		/* blocklen same? */
608     {
609       if (templong != blocklen)
610 	{
611 	  fclose (tempfile);
612 	  compute_rms_now = 1;
613 	}
614     }
615 
616   if (!compute_rms_now)		/* Read total_blocks */
617     {
618       if (fread (&templong, sizeof (long), 1, tempfile) < 1)
619 	{
620 	  fclose (tempfile);
621 	  compute_rms_now = 1;
622 	}
623     }
624 
625   if (!compute_rms_now)		/* total_blocks reasonable? */
626     {
627       if (templong < 1)
628 	{
629 	  fclose (tempfile);
630 	  compute_rms_now = 1;
631 	}
632       else
633 	/* NOW we're satisfied */
634 	{
635 	  total_blocks = templong;
636 
637 	  rmsarray = (double *) malloc (total_blocks * sizeof (double));
638 
639 	  fread (rmsarray, sizeof (double), total_blocks, tempfile);
640 	  fclose (tempfile);
641 	}
642     }
643 
644   if (compute_rms_now)		/* Well, we can't be lazy always... */
645     {
646       if (stat (filename, &buf))
647 	{
648 	  error_window ("Sound file could not be opened.");
649 	  return;
650 	}
651 
652       total_samples = (buf.st_size - sizeof (wavhead)) / (2 * 2);
653 
654       total_blocks = (total_samples / blocklen) + 1;
655 
656       if (!openwavsource (filename))
657 	{
658 	  error_window ("Sound file could not be opened.");
659 	  return;
660 	}
661 
662       error_window_display ("Computing signal power (RMS)...",
663 			    " Cancel ");
664 #ifndef SWIG
665       nodelay (stdscr, TRUE);
666 #else
667       lastpercent = 0;
668 #endif
669 
670       rmsarray = (double *) malloc (total_blocks * sizeof (double));
671 
672       total_samples_read = 0;
673       current_block = 0;
674 
675       while (total_samples_read < total_samples)
676 	{
677 	  if (!(current_block % 5))
678 	    {
679 #ifndef SWIG
680 	      mvprintw (ERROR_WINDOW_Y + 2, ERROR_WINDOW_X + 1,
681 			"Done : %3d %%",
682 			(int) (current_block * 100. / total_blocks));
683 	      move (0, 79);
684 #else
685               int percent;
686               percent = (((int) (current_block * 100. / total_blocks) / 5) * 5);              if (percent!=lastpercent) {
687                 printf ("Done : %3d %%\n",percent);
688                 lastpercent=percent;
689               }
690 #endif
691 	    }
692 
693 	  samples_read = 0;	/* Compute RMS */
694 	  sum_left = 0;
695 	  sum_right = 0;
696 	  for (l = 0; l < blocklen; l++)
697 	    if (total_samples_read < total_samples)
698 	      {
699 		sample = readsamplesource ();
700 		sum_left += sample.left * (long) sample.left;
701 		sum_right += sample.right * (long) sample.right;
702 		/* (long) => faster & accurate */
703 		samples_read++;
704 		total_samples_read++;
705 	      }
706 
707 	  sum_left = sqrt (fabs (sum_left / samples_read));
708 	  sum_right = sqrt (fabs (sum_right / samples_read));
709 
710 	  if (sum_right > sum_left)
711 	    sum_left = sum_right;
712 	  /* now left = max */
713 
714 	  /* sum_left: 0..32767 but doublecheck */
715 	  if (sum_left < 0)
716 	    sum_left = 0;
717 	  if (sum_left > 32767)
718 	    sum_left = 32767;
719 
720 	  rmsarray[current_block] = sum_left;	/* store in array */
721 
722 	  current_block++;
723 
724 #ifndef SWIG
725 	  in_ch = getch ();	/* Check for keypress */
726 	  if (in_ch == 27 || in_ch == 13 || in_ch == KEY_ENTER)
727 	    {
728 	      reset_prog_mode ();
729 	      nodelay (stdscr, FALSE);
730 	      closewavsource ();
731 	      return;
732 	    }
733 #endif
734 	}
735 
736       closewavsource ();
737 
738 #ifndef SWIG
739       reset_prog_mode ();
740       nodelay (stdscr, FALSE);
741 #endif
742 
743       if (make_use_rms)		/* Write .RMS if requested */
744 	{
745 	  strcpy (tempstring, filename);
746 	  strcat (tempstring, ".rms");
747 	  tempfile = fopen (tempstring, "w");
748 	  fprintf (tempfile, "GramoFile Binary RMS Data\n");
749 	  fwrite (&blocklen, sizeof (long), 1, tempfile);
750 	  fwrite (&total_blocks, sizeof (long), 1, tempfile);
751 	  fwrite (rmsarray, sizeof (double), total_blocks, tempfile);
752 	  fclose (tempfile);
753 	}
754 
755     }				/* if compute_rms */
756 
757 
758   /* RMS data available now. Start real work... */
759 
760   medarray = (double *) malloc (total_blocks * sizeof (double));
761   sortarray = (double *) malloc (total_blocks * sizeof (double));
762 
763   medarray[0] = rmsarray[0];	/* Take Median-3 */
764   medarray[total_blocks - 1] = rmsarray[total_blocks - 1];
765 
766   /* A more or less optimized version of a median computation... */
767   for (l = 1; l < total_blocks - 1; l++)
768     if (rmsarray[l - 1] < rmsarray[l])
769       /* a < b */
770       {
771 	if (rmsarray[l] < rmsarray[l + 1])
772 	  /* b < c */
773 	  medarray[l] = rmsarray[l];
774 	else
775 	  /* b > c */
776 	  {
777 	    if (rmsarray[l - 1] < rmsarray[l + 1])
778 	      /* a < c */
779 	      medarray[l] = rmsarray[l + 1];
780 	    else
781 	      /* c > a */
782 	      medarray[l] = rmsarray[l - 1];
783 	  }
784       }
785     else
786       /* a > b */
787       {
788 	if (rmsarray[l] < rmsarray[l + 1])
789 	  /* b < c */
790 	  {
791 	    if (rmsarray[l - 1] < rmsarray[l + 1])
792 	      /* a < c */
793 	      medarray[l] = rmsarray[l - 1];
794 	    else
795 	      /* a > c */
796 	      medarray[l] = rmsarray[l + 1];
797 	  }
798 	else
799 	  /* b > c */
800 	  medarray[l] = rmsarray[l];
801       }
802 
803 /* #define: up, up, up! */
804 #ifdef COMPUTE_GLOBAL_MEAN
805   global_mean = 0;		/* Global Mean - Not used any more */
806   for (l = 0; l < total_blocks; l++)
807     global_mean += medarray[l];
808   global_mean /= total_blocks;
809 
810   /* fprintf(stderr, "\nGlobMean:%f\n",global_mean); sleep(5); */
811 #endif
812 
813   for (l = 0; l < total_blocks; l++)	/* Fill arrays */
814     sortarray[l] = medarray[l];
815 
816   qsort2double (sortarray, total_blocks);	/* Sort meds. Fast! */
817 
818 
819   min_poss_threshold = sortarray[10];
820   max_poss_threshold = sortarray[total_blocks / 2];
821 
822 
823 #define dontDISPLAY_SOME_THRESHOLDS
824 #ifdef DISPLAY_SOME_THRESHOLDS
825   fprintf (stderr, "\n\r%f to %f\n\r", min_poss_threshold, max_poss_threshold);
826 #define NUMTRIES 50
827   for (l = 0; l < NUMTRIES; l++)
828     {
829       /* Try some different thresholds between min_poss en max_poss;
830          you need a looong xterm to see all of it ;-) */
831       global_silence_threshold = ((max_poss_threshold - min_poss_threshold)
832 				  / (NUMTRIES - 1))
833 	* l
834 	+ min_poss_threshold;
835       tracksplit_findtracks (medarray,
836 			     total_blocks,
837 			     global_silence_threshold,
838 			     local_silence_threshold,
839 			     min_silence_blocks,
840 			     min_track_blocks,
841 			     extra_blocks_start,
842 			     extra_blocks_end,
843 
844 			     trackstarts,
845 			     trackends,
846 			     &detected_tracks);
847       fprintf (stderr, "Glob.sil.thr.: %f  Tracks: %d\n\r",
848 	       global_silence_threshold, detected_tracks);
849     }
850 #endif /* DISPLAY_SOME_THRESHOLDS */
851 
852 
853   global_silence_threshold = (max_poss_threshold - min_poss_threshold)
854     * (global_silence_factor / 1000.)
855     + min_poss_threshold;
856 
857   /* fprintf(stderr, "New global threshold: %f\n\r",
858      global_silence_threshold); */
859 
860   tracksplit_findtracks (medarray,
861 			 total_blocks,
862 			 global_silence_threshold,
863 			 local_silence_threshold,
864 			 min_silence_blocks,
865 			 min_track_blocks,
866 			 extra_blocks_start,
867 			 extra_blocks_end,
868 
869 			 trackstarts,
870 			 trackends,
871 			 &detected_tracks);
872 
873   /* sleep(5); */
874 
875 
876   /* Write the .tracks file */
877   strcpy (tempstring, filename);
878   strcat (tempstring, ".tracks");
879   tempfile = fopen (tempstring, "w");
880   if (tempfile == NULL)
881     {
882       error_window ("The .tracks file could not be written.");
883       return;
884     }
885   fprintf (tempfile, "\
886 # GramoFile Tracks File\n\
887 #\n\
888 # This file contains information on track starts/ends. It is automatically\n\
889 # generated and will be overwritten completely by subsequent track-\n\
890 # splitting actions on the same audio file.\n\
891 \n\
892 # Blank lines and lines starting with `#' are ignored.\n\
893 \n\
894 [Tracks]\n\
895 # These values are not used (yet), but are included for reference /\n\
896 # regeneration purposes.\n\
897 ");
898   fprintf (tempfile, "Blocklen=%ld\n", blocklen);
899   fprintf (tempfile, "Global_silence_factor=%d\n",
900 	   global_silence_factor);
901   fprintf (tempfile, "Local_silence_factor=%d\n",
902 	   local_silence_threshold);
903   fprintf (tempfile, "Min_silence_blocks=%d\n", min_silence_blocks);
904   fprintf (tempfile, "Min_track_blocks=%d\n", min_track_blocks);
905   fprintf (tempfile, "Extra_blocks_start=%d\n", extra_blocks_start);
906   fprintf (tempfile, "Extra_blocks_end=%d\n", extra_blocks_end);
907   fprintf (tempfile, "\
908 \n\
909 # Below are start/end times of tracks. These are used to create separate\n\
910 # soundfiles during signal processing. You may modify the computed values\n\
911 # if you disagree... The block-numbers are those used in the .med file.\n\
912 \n\
913 ");
914 
915   fprintf (tempfile, "Number_of_tracks=%d\n", detected_tracks);
916 
917   for (l = 0; l < detected_tracks; l++)
918     {
919       fsec2hmsf ((trackends[l] - trackstarts[l] + 1) *
920 		 (double) blocklen / 44100.,
921 		 tempstring);
922       fprintf (tempfile,
923 	       "\n# Track %ld - blocks %ld to %ld - length: %s\n",
924 	       l + 1, trackstarts[l], trackends[l], tempstring);
925       fsec2hmsf (trackstarts[l] * (double) blocklen / 44100.,
926 		 tempstring);
927       fprintf (tempfile, "Track%02ldstart=%s\n", l + 1, tempstring);
928       fsec2hmsf ((trackends[l] + 1) * (double) blocklen / 44100.,
929 		 tempstring);
930       fprintf (tempfile, "Track%02ldend=%s\n", l + 1, tempstring);
931     }
932 
933   fprintf (tempfile, "\n");
934   fclose (tempfile);
935 
936 
937   if (make_graphs)		/* Write graphs */
938     {
939       strcpy (tempstring, filename);
940       strcat (tempstring, ".med");
941       tempfile2 = fopen (tempstring, "w");
942       fprintf (tempfile2, "Med(RMS(signal))\n");
943       fprintf (tempfile2, "Threshold: %f\n\n", global_silence_threshold);
944       for (l = 0; l < total_blocks; l++)
945 	{
946 	  fprintf (tempfile2, "%5ld:%8.2f ", l, medarray[l]);
947 	  for (i = 0; i < fabs (medarray[l] / 80); i++)
948 	    fprintf (tempfile2, "=");
949 	  fprintf (tempfile2, "\n");
950 	}
951       fclose (tempfile2);
952 
953       strcpy (tempstring, filename);
954       strcat (tempstring, ".sor");
955       tempfile2 = fopen (tempstring, "w");
956       fprintf (tempfile2, "Sort(Med(RMS(signal)))\n");
957       fprintf (tempfile2, "Threshold: %f\n\n", global_silence_threshold);
958       for (l = 0; l < total_blocks; l++)
959 	{
960 	  fprintf (tempfile2, "%5ld:%8.2f ", l, sortarray[l]);
961 	  for (i = 0; i < fabs (sortarray[l] / 80); i++)
962 	    fprintf (tempfile2, "=");
963 	  fprintf (tempfile2, "\n");
964 	}
965       fclose (tempfile2);
966 
967     }
968 
969 
970   sprintf (tempstring, "%d tracks have been detected. More information \
971 is in the `.tracks' file.", detected_tracks);
972   error_window (tempstring);
973 
974 
975   free (rmsarray);
976   free (medarray);
977   free (sortarray);
978 }
979