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