1 /**********************************************************
2 *
3 * libmp3splt -- library based on mp3splt,
4 * for mp3/ogg splitting without decoding
5 *
6 * Copyright (c) 2002-2005 M. Trotta - <mtrotta@users.sourceforge.net>
7 * Copyright (c) 2005-2014 Alexandru Munteanu - m@ioalex.net
8 *
9 * http://mp3splt.sourceforge.net
10 *
11 *********************************************************/
12
13 /**********************************************************
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
28 * USA.
29 *
30 *********************************************************/
31
32 /*! \file
33
34 Actually split the input file
35 */
36
37 #include <sys/stat.h>
38 #include <string.h>
39 #include <math.h>
40
41 #include "splt.h"
42
43 static splt_code splt_s_open_full_log_filename(splt_state *state);
44 static void splt_s_close_full_log_filename(splt_state *state);
45
46 /****************************/
47 /*! normal split */
48
splt_s_real_split(double splt_beg,double splt_end,int save_end_point,int * error,splt_state * state)49 static long splt_s_real_split(double splt_beg, double splt_end,
50 int save_end_point, int *error, splt_state *state)
51 {
52 char *final_fname = splt_su_get_fname_with_path_and_extension(state,error);
53 long new_end_point = splt_co_time_to_long_ceil(splt_end);
54
55 if (*error >= 0)
56 {
57 double new_sec_end_point =
58 splt_p_split(state, final_fname, splt_beg, splt_end, error, save_end_point);
59
60 if (new_sec_end_point == -1.0)
61 {
62 new_end_point = LONG_MAX;
63 }
64 else
65 {
66 new_end_point = splt_co_time_to_long_ceil(new_sec_end_point);
67 }
68
69 if (*error >= 0)
70 {
71 splt_c_update_progress(state,1.0,1.0,1,1,1);
72
73 int err = SPLT_OK;
74 err = splt_c_put_split_file(state, final_fname);
75 if (err < 0) { *error = err; }
76 }
77 }
78
79 if (final_fname)
80 {
81 free(final_fname);
82 final_fname = NULL;
83 }
84
85 return new_end_point;
86 }
87
88 //! Extract the file portion between two split points
splt_s_split(splt_state * state,int first_splitpoint,int second_splitpoint,int * error)89 static long splt_s_split(splt_state *state, int first_splitpoint,
90 int second_splitpoint, int *error)
91 {
92 int get_error = SPLT_OK;
93 long split_begin = splt_sp_get_splitpoint_value(state, first_splitpoint, &get_error);
94 long split_end = splt_sp_get_splitpoint_value(state, second_splitpoint, &get_error);
95
96 long new_end_point = split_end;
97
98 int save_end_point = SPLT_TRUE;
99 if (splt_sp_get_splitpoint_type(state, second_splitpoint, &get_error) == SPLT_SKIPPOINT ||
100 splt_o_get_long_option(state, SPLT_OPT_OVERLAP_TIME) > 0)
101 {
102 save_end_point = SPLT_FALSE;
103 }
104
105 if (get_error == SPLT_OK)
106 {
107 //if no error
108 if (*error >= 0)
109 {
110 //if the first splitpoint different than the end point
111 if (split_begin != split_end)
112 {
113 //convert to float for hundredth
114 // 34.6 --> 34 seconds and 6 hundredth
115 double splt_beg = split_begin / 100;
116 splt_beg += ((split_begin % 100) / 100.);
117 double splt_end = 0;
118
119 //LONG_MAX == EOF
120 if (split_end == LONG_MAX)
121 {
122 splt_end = -1;
123 }
124 else
125 {
126 splt_end = split_end / 100;
127 splt_end += ((split_end % 100) / 100.);
128 }
129
130 new_end_point = splt_s_real_split(splt_beg, splt_end, save_end_point, error, state);
131 }
132 else
133 {
134 splt_e_set_error_data_from_splitpoint(state, split_begin);
135 *error = SPLT_ERROR_EQUAL_SPLITPOINTS;
136 }
137 }
138 }
139 else
140 {
141 *error = get_error;
142 }
143
144 return new_end_point;
145 }
146
147 //!splits the file with multiple points
splt_s_multiple_split(splt_state * state,int * error)148 void splt_s_multiple_split(splt_state *state, int *error)
149 {
150 int split_type = splt_o_get_int_option(state, SPLT_OPT_SPLIT_MODE);
151 int err = SPLT_OK;
152
153 splt_of_set_oformat_digits(state);
154
155 if (split_type == SPLT_OPTION_NORMAL_MODE)
156 {
157 splt_c_put_info_message_to_client(state, _(" info: starting normal split\n"));
158 }
159
160 splt_u_print_overlap_time(state);
161
162 int get_error = SPLT_OK;
163
164 splt_array *new_end_points = splt_array_new();
165
166 int i = 0;
167 int number_of_splitpoints = splt_t_get_splitnumber(state);
168
169 int save_end_point = SPLT_TRUE;
170 if (splt_o_get_long_option(state, SPLT_OPT_OVERLAP_TIME) > 0)
171 {
172 save_end_point = SPLT_FALSE;
173 }
174
175 while (i < number_of_splitpoints - 1)
176 {
177 splt_t_set_current_split(state, i);
178
179 if (!splt_t_split_is_canceled(state))
180 {
181 get_error = SPLT_OK;
182
183 int first_splitpoint_type = splt_sp_get_splitpoint_type(state, i, &get_error);
184 if (first_splitpoint_type == SPLT_SKIPPOINT)
185 {
186 splt_d_print_debug(state, "SKIP splitpoint at _%d_\n", i);
187 i++;
188 continue;
189 }
190
191 splt_tu_auto_increment_tracknumber(state);
192
193 long saved_end_point = splt_sp_get_splitpoint_value(state, i+1, &get_error);
194 splt_sp_overlap_time(state, i + 1);
195
196 err = splt_u_finish_tags_and_put_output_format_filename(state, i);
197 if (err < 0) { *error = err; goto end; }
198
199 int end_point_index = i+1;
200 long new_end_point = splt_s_split(state, i, end_point_index, error);
201
202 if (save_end_point)
203 {
204 splt_il_pair *index_end_point = splt_il_pair_new(end_point_index, new_end_point);
205 splt_array_append(new_end_points, (void *)index_end_point);
206 }
207
208 splt_sp_set_splitpoint_value(state, i + 1, saved_end_point);
209
210 if ((*error < 0) || (*error == SPLT_OK_SPLIT_EOF))
211 {
212 break;
213 }
214 }
215 else
216 {
217 *error = SPLT_SPLIT_CANCELLED;
218 goto end;
219 }
220
221 i++;
222 }
223
224 end:
225 for (i = 0;i < splt_array_length(new_end_points);i++)
226 {
227 splt_il_pair *index_end_point = (splt_il_pair *) splt_array_get(new_end_points, i);
228
229 splt_sp_set_splitpoint_value(state,
230 splt_il_pair_first(index_end_point),
231 splt_il_pair_second(index_end_point));
232
233 splt_il_pair_free(&index_end_point);
234 }
235
236 splt_array_free(&new_end_points);
237 }
238
splt_s_normal_split(splt_state * state,int * error)239 void splt_s_normal_split(splt_state *state, int *error)
240 {
241 int output_filenames = splt_o_get_int_option(state,SPLT_OPT_OUTPUT_FILENAMES);
242 if (output_filenames == SPLT_OUTPUT_DEFAULT)
243 {
244 splt_of_set_oformat(state, SPLT_DEFAULT_OUTPUT, error, SPLT_TRUE);
245 if (*error < 0) { return; }
246 }
247
248 splt_s_multiple_split(state, error);
249 }
250
251 //!the sync error mode
splt_s_error_split(splt_state * state,int * error)252 void splt_s_error_split(splt_state *state, int *error)
253 {
254 splt_c_put_info_message_to_client(state, _(" info: starting error mode split\n"));
255 char *final_fname = NULL;
256
257 //we detect sync errors
258 splt_p_search_syncerrors(state, error);
259
260 //automatically set progress callback to 100% after
261 //the error detection
262 splt_c_update_progress(state,1.0,1.0,1,1,1);
263
264 int err = SPLT_OK;
265
266 //if no error
267 if (*error >= 0)
268 {
269 //we put the number of sync errors
270 splt_t_set_splitnumber(state, state->serrors->serrors_points_num - 1);
271
272 splt_of_set_oformat_digits(state);
273
274 if (splt_o_get_int_option(state,SPLT_OPT_OUTPUT_FILENAMES) == SPLT_OUTPUT_DEFAULT)
275 {
276 splt_of_set_oformat(state, SPLT_DEFAULT_SYNCERROR_OUTPUT, &err, SPLT_TRUE);
277 if (err < 0) { *error = err; goto bloc_end; }
278 }
279
280 //we split all sync errors
281 int i = 0;
282 for (i = 0; i < state->serrors->serrors_points_num - 1; i++)
283 {
284 //if we don't cancel the split
285 if (!splt_t_split_is_canceled(state))
286 {
287 //we put the current file to split
288 splt_t_set_current_split(state, i);
289
290 splt_tu_auto_increment_tracknumber(state);
291
292 //we append a splitpoint
293 int err = splt_sp_append_splitpoint(state, 0, "", SPLT_SPLITPOINT);
294 if (err < 0) { *error = err; goto bloc_end; }
295
296 err = splt_u_finish_tags_and_put_output_format_filename(state, -1);
297 if (err < 0) { *error = err; goto bloc_end; }
298
299 final_fname = splt_su_get_fname_with_path_and_extension(state, error);
300
301 if (*error >= 0)
302 {
303 splt_io_create_output_dirs_if_necessary(state, final_fname, error);
304 if (error < 0)
305 {
306 goto bloc_end;
307 }
308
309 //we split with the detected splitpoints
310 int split_result = splt_p_simple_split(state, final_fname,
311 (off_t) state->serrors->serrors_points[i],
312 (off_t) state->serrors->serrors_points[i+1]);
313
314 //automatically set progress callback to 100%
315 splt_c_update_progress(state,1.0,1.0,1,1,1);
316
317 if (split_result >= 0)
318 {
319 *error = SPLT_SYNC_OK;
320 }
321 else
322 {
323 *error = split_result;
324 }
325
326 //if the split has been a success
327 if (*error == SPLT_SYNC_OK)
328 {
329 err = splt_c_put_split_file(state, final_fname);
330 if (err < 0) { *error = err; goto bloc_end; }
331 }
332 }
333 else
334 {
335 //error
336 goto bloc_end;
337 }
338
339 //free some memory
340 if (final_fname)
341 {
342 free(final_fname);
343 final_fname = NULL;
344 }
345 }
346 //if we cancel the split
347 else
348 {
349 *error = SPLT_SPLIT_CANCELLED;
350 goto bloc_end;
351 }
352 }
353 }
354 else
355 {
356 if (*error >= 0 && err < 0)
357 {
358 *error = err;
359 }
360 }
361
362 bloc_end:
363 //free possible unfreed 'final_fname'
364 if (final_fname)
365 {
366 free(final_fname);
367 final_fname = NULL;
368 }
369 }
370
371 /************************************/
372 /*! time and length split */
373
splt_s_get_real_end_time_splitpoint(splt_state * state,int current_split,long total_time)374 static double splt_s_get_real_end_time_splitpoint(splt_state *state,
375 int current_split, long total_time)
376 {
377 long overlapped_time = splt_sp_overlap_time(state, current_split+1);
378 double overlapped_end = -1;
379 if (overlapped_time == LONG_MAX)
380 {
381 return overlapped_end;
382 }
383
384 overlapped_end = (double) ((double) overlapped_time / 100.0);
385
386 if (total_time <= 0)
387 {
388 return overlapped_end;
389 }
390
391 long minimum_length = splt_o_get_long_option(state, SPLT_OPT_TIME_MINIMUM_THEORETICAL_LENGTH);
392 long remaining_time = total_time - overlapped_time;
393 if (remaining_time > 0 && remaining_time < minimum_length)
394 {
395 splt_sp_set_splitpoint_value(state, current_split + 1, total_time);
396 return -1.0;
397 }
398
399 return overlapped_end;
400 }
401
splt_s_split_by_time(splt_state * state,int * error,double split_time_length,int number_of_files)402 static void splt_s_split_by_time(splt_state *state, int *error,
403 double split_time_length, int number_of_files)
404 {
405 char *final_fname = NULL;
406 int j=0, tracks=1;
407 double begin = 0.f;
408 double end = split_time_length;
409 long total_time = splt_t_get_total_time(state);
410
411 if (split_time_length >= 0)
412 {
413 splt_u_print_overlap_time(state);
414
415 int err = SPLT_OK;
416
417 int temp_int = number_of_files + 1;
418 if (total_time > 0 && number_of_files == -1)
419 {
420 temp_int = (int)floor(((total_time / 100.0) / (split_time_length))+1) + 1;
421 }
422 splt_t_set_splitnumber(state, temp_int);
423
424 splt_of_set_oformat_digits(state);
425
426 //if we have the default output
427 int output_filenames = splt_o_get_int_option(state, SPLT_OPT_OUTPUT_FILENAMES);
428 if (output_filenames == SPLT_OUTPUT_DEFAULT)
429 {
430 splt_of_set_oformat(state, SPLT_DEFAULT_OUTPUT, &err, SPLT_TRUE);
431 if (err < 0) { *error = err; return; }
432 }
433
434 //we append a splitpoint
435 err = splt_sp_append_splitpoint(state, 0, "", SPLT_SPLITPOINT);
436 if (err >= 0)
437 {
438 int save_end_point = SPLT_TRUE;
439 if (splt_o_get_long_option(state, SPLT_OPT_OVERLAP_TIME) > 0)
440 {
441 save_end_point = SPLT_FALSE;
442 }
443
444 splt_array *new_end_points = splt_array_new();
445
446 do {
447 if (!splt_t_split_is_canceled(state))
448 {
449 err = splt_sp_append_splitpoint(state, 0, "", SPLT_SPLITPOINT);
450 if (err < 0) { *error = err; break; }
451
452 splt_t_set_current_split(state, tracks-1);
453
454 splt_tu_auto_increment_tracknumber(state);
455
456 int current_split = splt_t_get_current_split(state);
457
458 splt_sp_set_splitpoint_value(state, current_split,
459 splt_co_time_to_long_ceil(begin));
460 long end_splitpoint = splt_co_time_to_long_ceil(end);
461 splt_sp_set_splitpoint_value(state, current_split+1, end_splitpoint);
462
463 double real_end_splitpoint =
464 splt_s_get_real_end_time_splitpoint(state, current_split, total_time);
465
466 err = splt_u_finish_tags_and_put_output_format_filename(state, -1);
467 if (err < 0) { *error = err; break; }
468
469 final_fname = splt_su_get_fname_with_path_and_extension(state,&err);
470 if (err < 0) { *error = err; break; }
471
472 double new_sec_end_point = splt_p_split(state, final_fname,
473 begin, real_end_splitpoint, error, save_end_point);
474
475 if (save_end_point)
476 {
477 long new_end_point = 0;
478 if (new_sec_end_point == -1.0)
479 {
480 new_end_point = LONG_MAX;
481 }
482 else
483 {
484 new_end_point = splt_co_time_to_long_ceil(new_sec_end_point);
485 }
486
487 int end_point_index = current_split + 1;
488 splt_il_pair *index_end_point = splt_il_pair_new(end_point_index, new_end_point);
489 splt_array_append(new_end_points, (void *) index_end_point);
490 }
491
492 //if no error for the split, put the split file
493 if (*error >= 0)
494 {
495 err = splt_c_put_split_file(state, final_fname);
496 if (err < 0) { *error = err; break; }
497 }
498
499 //set new splitpoints
500 begin = end;
501 end += split_time_length;
502 tracks++;
503
504 //get out if error
505 if ((*error == SPLT_MIGHT_BE_VBR) ||
506 (*error == SPLT_OK_SPLIT_EOF) ||
507 (*error < 0))
508 {
509 tracks = 0;
510 }
511
512 if (*error==SPLT_ERROR_BEGIN_OUT_OF_FILE)
513 {
514 j--;
515 }
516
517 if (final_fname)
518 {
519 //free memory
520 free(final_fname);
521 final_fname = NULL;
522 }
523 }
524 else
525 {
526 *error = SPLT_SPLIT_CANCELLED;
527 break;
528 }
529
530 } while (j++<tracks);
531
532 if (final_fname)
533 {
534 free(final_fname);
535 final_fname = NULL;
536 }
537
538 int i = 0;
539 for (i = 0;i < splt_array_length(new_end_points);i++)
540 {
541 splt_il_pair *index_end_point = (splt_il_pair *) splt_array_get(new_end_points, i);
542
543 splt_sp_set_splitpoint_value(state,
544 splt_il_pair_first(index_end_point),
545 splt_il_pair_second(index_end_point));
546
547 splt_il_pair_free(&index_end_point);
548 }
549
550 splt_array_free(&new_end_points);
551 }
552 else
553 {
554 *error = err;
555 }
556
557 //we put the time split error
558 switch (*error)
559 {
560 /* case SPLT_MIGHT_BE_VBR:
561 *error = SPLT_TIME_SPLIT_OK;
562 break; */
563
564 case SPLT_OK_SPLIT:
565 *error = SPLT_TIME_SPLIT_OK;
566 break;
567 case SPLT_OK_SPLIT_EOF:
568 *error = SPLT_TIME_SPLIT_OK;
569 break;
570 case SPLT_ERROR_BEGIN_OUT_OF_FILE:
571 *error = SPLT_TIME_SPLIT_OK;
572 break;
573 default:
574 break;
575 }
576 }
577 else
578 {
579 *error = SPLT_ERROR_NEGATIVE_TIME_SPLIT;
580 }
581 }
582
583 /*! function used with the -t option (time split)
584
585 create an indefinite number of smaller files with a fixed time
586 length specified by options.split_time in seconds
587 */
splt_s_time_split(splt_state * state,int * error)588 void splt_s_time_split(splt_state *state, int *error)
589 {
590 splt_c_put_info_message_to_client(state, _(" info: starting time mode split\n"));
591
592 long split_time_length = splt_o_get_long_option(state, SPLT_OPT_SPLIT_TIME);
593 if (split_time_length == 0)
594 {
595 *error = SPLT_ERROR_TIME_SPLIT_VALUE_INVALID;
596 return;
597 }
598
599 splt_s_split_by_time(state, error, split_time_length / 100.0, -1);
600 }
601
602 /*! function used with the -L option (length split)
603
604 split into X files
605 X is defined by SPLT_OPT_LENGTH_SPLIT_FILE_NUMBER
606 */
splt_s_equal_length_split(splt_state * state,int * error)607 void splt_s_equal_length_split(splt_state *state, int *error)
608 {
609 splt_c_put_info_message_to_client(state, _(" info: starting 'split in equal tracks' mode\n"));
610
611 double total_time = splt_t_get_total_time_as_double_secs(state);
612 if (total_time > 0)
613 {
614 int number_of_files =
615 splt_o_get_int_option(state, SPLT_OPT_LENGTH_SPLIT_FILE_NUMBER);
616
617 if (number_of_files > 0)
618 {
619 double split_time_length = total_time / number_of_files;
620 splt_s_split_by_time(state, error, split_time_length, number_of_files);
621 }
622 else
623 {
624 *error = SPLT_ERROR_LENGTH_SPLIT_VALUE_INVALID;
625 return;
626 }
627 }
628 else
629 {
630 *error = SPLT_ERROR_CANNOT_GET_TOTAL_TIME;
631 return;
632 }
633
634 if (*error == SPLT_TIME_SPLIT_OK)
635 {
636 *error = SPLT_LENGTH_SPLIT_OK;
637 }
638 }
639
splt_s_set_trim_silence_splitpoints(splt_state * state,int * error)640 int splt_s_set_trim_silence_splitpoints(splt_state *state, int *error)
641 {
642 splt_d_print_debug(state, "Search and set trim silence splitpoints...\n");
643
644 int found = 0;
645 struct splt_ssplit *temp = NULL;
646 int append_error = SPLT_OK;
647
648 if (! splt_o_get_int_option(state,SPLT_OPT_QUIET_MODE))
649 {
650 splt_c_put_info_message_to_client(state,
651 _(" Trim silence split - Th: %.1f dB, Min: %.2f sec\n"),
652 splt_o_get_float_option(state, SPLT_OPT_PARAM_THRESHOLD),
653 splt_o_get_float_option(state, SPLT_OPT_PARAM_MIN_LENGTH));
654 }
655
656 if (state->split.get_silence_level)
657 {
658 state->split.get_silence_level(0, INT_MAX, state->split.silence_level_client_data);
659 }
660 found = splt_p_scan_trim_silence(state, error);
661 if (*error < 0) { goto end; }
662
663 if (splt_t_split_is_canceled(state))
664 {
665 *error = SPLT_SPLIT_CANCELLED;
666 goto end;
667 }
668
669 temp = state->silence_list;
670 int i;
671 long previous = 0;
672 for (i = 1; i < found + 1; i++)
673 {
674 if (temp == NULL)
675 {
676 found = i;
677 break;
678 }
679
680 long temp_silence_pos = splt_siu_silence_position(temp, 0) * 100;
681
682 if (i > 1 && temp_silence_pos < previous)
683 {
684 temp_silence_pos = LONG_MAX;
685 }
686
687 append_error = splt_sp_append_splitpoint(state, temp_silence_pos, NULL, SPLT_SPLITPOINT);
688 if (append_error != SPLT_OK) { *error = append_error; found = i; break; }
689
690 temp = temp->next;
691
692 previous = temp_silence_pos;
693 }
694
695 end:
696 splt_siu_ssplit_free(&state->silence_list);
697 splt_t_set_splitnumber(state, found);
698
699 return found;
700 }
701
702 /************************************/
703 /*! Split with split points setermined by silence detection
704
705 Sets the silence splitpoints in state->split.splitpoints
706
707 \return the number of split points found or the number of tracks
708 specified in the options
709 */
splt_s_set_silence_splitpoints(splt_state * state,int * error)710 int splt_s_set_silence_splitpoints(splt_state *state, int *error)
711 {
712 splt_d_print_debug(state,"Search and set silence splitpoints...\n");
713
714 int found = 0;
715 int splitpoints_appended = 0;
716 struct splt_ssplit *temp = NULL;
717 int append_error = SPLT_OK;
718
719 float offset = splt_o_get_float_option(state,SPLT_OPT_PARAM_OFFSET);
720 int number_tracks = splt_o_get_int_option(state, SPLT_OPT_PARAM_NUMBER_TRACKS);
721
722 int we_read_silence_from_logs = SPLT_FALSE;
723
724 FILE *log_file = NULL;
725 char *log_fname = splt_t_get_silence_log_fname(state);
726 if (splt_o_get_int_option(state, SPLT_OPT_ENABLE_SILENCE_LOG))
727 {
728 if ((log_file = splt_io_fopen(log_fname, "r")))
729 {
730 char *log_silence_fname = splt_io_readline(log_file, error);
731 if (*error < 0)
732 {
733 if (log_silence_fname)
734 {
735 free(log_silence_fname);
736 log_silence_fname = NULL;
737 }
738 fclose(log_file);
739 return found;
740 }
741
742 if (log_silence_fname && log_silence_fname[0] != '\0')
743 {
744 log_silence_fname[strlen(log_silence_fname)-1] = '\0';
745 if (strcmp(log_silence_fname, splt_t_get_filename_to_split(state)) == 0)
746 {
747 we_read_silence_from_logs = SPLT_TRUE;
748 float threshold = SPLT_DEFAULT_PARAM_THRESHOLD;
749 float min = SPLT_DEFAULT_PARAM_MINIMUM_LENGTH;
750 int shots = SPLT_DEFAULT_PARAM_SHOTS;
751 int i = fscanf(log_file, "%f\t%f\t%d", &threshold, &min, &shots);
752
753 //compatibility with older versions; allow missing shots
754 if (i == 2) { shots = SPLT_DEFAULT_PARAM_SHOTS; }
755
756 if ((i < 2) ||
757 (threshold != splt_o_get_float_option(state, SPLT_OPT_PARAM_THRESHOLD)) ||
758 (splt_o_get_float_option(state, SPLT_OPT_PARAM_MIN_LENGTH) != min) ||
759 (splt_o_get_int_option(state, SPLT_OPT_PARAM_SHOTS) != shots))
760 {
761 we_read_silence_from_logs = SPLT_FALSE;
762 }
763 else
764 {
765 splt_o_set_float_option(state, SPLT_OPT_PARAM_THRESHOLD, threshold);
766 splt_o_set_float_option(state, SPLT_OPT_PARAM_MIN_LENGTH, min);
767 splt_o_set_int_option(state, SPLT_OPT_PARAM_SHOTS, shots);
768 }
769 }
770
771 free(log_silence_fname);
772 log_silence_fname = NULL;
773 }
774
775 if (!we_read_silence_from_logs && log_file)
776 {
777 fclose(log_file);
778 log_file = NULL;
779 }
780 }
781 }
782
783 char remove_str[128] = { '\0' };
784 if (splt_o_get_int_option(state, SPLT_OPT_PARAM_REMOVE_SILENCE))
785 {
786 snprintf(remove_str, 128, "%s(%.2f-%.2f)", _ ("YES"),
787 splt_o_get_float_option(state, SPLT_OPT_KEEP_SILENCE_LEFT),
788 splt_o_get_float_option(state, SPLT_OPT_KEEP_SILENCE_RIGHT));
789 }
790 else
791 {
792 snprintf(remove_str, 128 ,_("NO"));
793 }
794
795 char auto_user_str[128] = { '\0' };
796 if (splt_o_get_int_option(state, SPLT_OPT_PARAM_NUMBER_TRACKS) > 0)
797 {
798 snprintf(auto_user_str,128,_("User"));
799 }
800 else
801 {
802 snprintf(auto_user_str,128,_("Auto"));
803 }
804
805 if (! splt_o_get_int_option(state, SPLT_OPT_QUIET_MODE))
806 {
807 char *other_options = NULL;
808
809 if (splt_o_get_float_option(state, SPLT_OPT_PARAM_MIN_TRACK_JOIN) > 0)
810 {
811 char *min_track_join =
812 splt_su_get_formatted_message(state, ", %s: %.2f", "Min track join",
813 splt_o_get_float_option(state, SPLT_OPT_PARAM_MIN_TRACK_JOIN));
814
815 int err = splt_su_append_str(&other_options, min_track_join, NULL);
816 if (err < 0) { *error = err; goto end; }
817
818 free(min_track_join);
819 }
820
821 splt_c_put_info_message_to_client(state,
822 _(" Silence split type: %s mode (Th: %.1f dB,"
823 " Off: %.2f, Min: %.2f, Remove: %s, Min track: %.2f, Shots: %d%s)\n"),
824 auto_user_str,
825 splt_o_get_float_option(state, SPLT_OPT_PARAM_THRESHOLD),
826 splt_o_get_float_option(state, SPLT_OPT_PARAM_OFFSET),
827 splt_o_get_float_option(state, SPLT_OPT_PARAM_MIN_LENGTH),
828 remove_str,
829 splt_o_get_float_option(state, SPLT_OPT_PARAM_MIN_TRACK_LENGTH),
830 splt_o_get_int_option(state, SPLT_OPT_PARAM_SHOTS),
831 other_options == NULL ? "" : other_options);
832
833 if (other_options)
834 {
835 free(other_options);
836 }
837 }
838
839 short read_silence_from_logs = SPLT_FALSE;
840 if (we_read_silence_from_logs)
841 {
842 if (state->split.get_silence_level)
843 {
844 state->split.get_silence_level(0, INT_MAX, state->split.silence_level_client_data);
845 }
846
847 splt_c_put_info_message_to_client(state,
848 _(" Found silence log file '%s' ! Reading"
849 " silence points from file to save time ;)\n"), log_fname);
850
851 found = splt_siu_parse_ssplit_file(state, log_file, error);
852 if (log_file)
853 {
854 fclose(log_file);
855 log_file = NULL;
856 }
857
858 read_silence_from_logs = SPLT_TRUE;
859 }
860 else
861 {
862 if (state->split.get_silence_level)
863 {
864 state->split.get_silence_level(0, INT_MAX, state->split.silence_level_client_data);
865 }
866
867 int err = splt_s_open_full_log_filename(state);
868 if (err < 0) { *error = err; goto end; }
869
870 found = splt_p_scan_silence(state, error);
871
872 splt_s_close_full_log_filename(state);
873 }
874
875 //if no error
876 if (*error >= 0)
877 {
878 if (!read_silence_from_logs)
879 {
880 splt_c_put_info_message_to_client(state, "\n");
881 }
882
883 splt_c_put_info_message_to_client(state, _(" Total silence points found: %d."), found);
884
885 if (found > 0)
886 {
887 int selected_tracks = found + 1;
888 int param_number_of_tracks = splt_o_get_int_option(state, SPLT_OPT_PARAM_NUMBER_TRACKS);
889 if (param_number_of_tracks > 0)
890 {
891 selected_tracks = param_number_of_tracks;
892 }
893
894 splt_c_put_info_message_to_client(state,
895 _(" (Selected %d tracks)\n"), selected_tracks);
896 }
897 else
898 {
899 splt_c_put_info_message_to_client(state, "\n");
900 }
901
902 //we set the number of tracks
903 if (!splt_t_split_is_canceled(state))
904 {
905 found++;
906 if ((number_tracks > 0) &&
907 (number_tracks < SPLT_MAXSILENCE))
908 {
909 if (number_tracks < found)
910 {
911 found = number_tracks;
912 }
913 }
914
915 temp = state->silence_list;
916
917 int i;
918
919 for (i = 1; i < found; i++)
920 {
921 if (temp == NULL)
922 {
923 found = i;
924 break;
925 }
926
927 if (i == 1)
928 {
929 append_error = splt_sp_append_splitpoint(state, 0, NULL, SPLT_SPLITPOINT);
930 if (append_error < 0) { *error = append_error; found = i; break;}
931
932 splitpoints_appended++;
933 }
934
935 if (splt_o_get_int_option(state, SPLT_OPT_PARAM_REMOVE_SILENCE))
936 {
937 long end_track_point = splt_co_time_to_long(temp->begin_position);
938 long end_track_point_after_silence = splt_co_time_to_long(temp->end_position);
939 long silence_length = end_track_point_after_silence - end_track_point;
940
941 float keep_silence_left = splt_o_get_float_option(state, SPLT_OPT_KEEP_SILENCE_LEFT);
942 float keep_silence_right = splt_o_get_float_option(state, SPLT_OPT_KEEP_SILENCE_RIGHT);
943 long keep_silence_total = splt_co_time_to_long(keep_silence_left + keep_silence_right);
944
945 if (silence_length > keep_silence_total)
946 {
947 long adjusted_silence_left = splt_co_time_to_long(temp->begin_position + keep_silence_right);
948 long adjusted_silence_right = splt_co_time_to_long(temp->end_position - keep_silence_left);
949
950 append_error = splt_sp_append_splitpoint(state, adjusted_silence_left, NULL, SPLT_SKIPPOINT);
951 if (append_error < 0) { *error = append_error; found = i; break;}
952 append_error =
953 splt_sp_append_splitpoint(state, adjusted_silence_right, NULL, SPLT_SPLITPOINT);
954 if (append_error < 0) { *error = append_error; found = i; break;}
955
956 splitpoints_appended += 2;
957 }
958 else
959 {
960 float offset = keep_silence_right / (keep_silence_left + keep_silence_right);
961 long end_track_point = splt_co_time_to_long(splt_siu_silence_position(temp, offset));
962 append_error = splt_sp_append_splitpoint(state, end_track_point, NULL, SPLT_SPLITPOINT);
963 if (append_error < 0) { *error = append_error; found = i; break;}
964 splitpoints_appended++;
965 }
966 }
967 else
968 {
969 long end_track_point = splt_co_time_to_long(splt_siu_silence_position(temp, offset));
970 append_error = splt_sp_append_splitpoint(state, end_track_point, NULL, SPLT_SPLITPOINT);
971 if (append_error != SPLT_OK) { *error = append_error; found = i; break; }
972
973 splitpoints_appended++;
974 }
975
976 temp = temp->next;
977 }
978
979 splt_d_print_debug(state,"Order splitpoints...\n");
980 splt_sp_order_splitpoints(state, splitpoints_appended);
981
982 if (*error >= 0)
983 {
984 long total_time = splt_t_get_total_time(state);
985 if (total_time <= 0)
986 {
987 total_time = LONG_MAX;
988 }
989
990 //last splitpoint, end of file
991 append_error =
992 splt_sp_append_splitpoint(state, total_time, NULL, SPLT_SPLITPOINT);
993 if (append_error != SPLT_OK) { *error = append_error; }
994 }
995
996 splt_sp_join_minimum_tracks_splitpoints(state, error);
997 if (*error < 0) { goto end; }
998
999 splt_sp_skip_minimum_track_length_splitpoints(state, error);
1000 }
1001 else
1002 {
1003 *error = SPLT_SPLIT_CANCELLED;
1004 }
1005
1006 //if splitpoints are found
1007 if ((*error >= 0) && (found > 0) && !we_read_silence_from_logs)
1008 {
1009 //if we write the silence points log file
1010 if (splt_o_get_int_option(state, SPLT_OPT_ENABLE_SILENCE_LOG))
1011 {
1012 char *fname = splt_t_get_silence_log_fname(state);
1013
1014 splt_c_put_info_message_to_client(state, _(" Writing silence log file '%s' ...\n"), fname);
1015
1016 if (! splt_o_get_int_option(state, SPLT_OPT_PRETEND_TO_SPLIT))
1017 {
1018 FILE *log_file = NULL;
1019 if (!(log_file = splt_io_fopen(fname, "w")))
1020 {
1021 splt_e_set_strerror_msg_with_data(state, fname);
1022 *error = SPLT_ERROR_CANNOT_OPEN_FILE;
1023 }
1024 else
1025 {
1026 //do the effective write
1027 struct splt_ssplit *temp = state->silence_list;
1028 fprintf(log_file, "%s\n", splt_t_get_filename_to_split(state));
1029 fprintf(log_file, "%.2f\t%.2f\t%d\n",
1030 splt_o_get_float_option(state, SPLT_OPT_PARAM_THRESHOLD),
1031 splt_o_get_float_option(state, SPLT_OPT_PARAM_MIN_LENGTH),
1032 splt_o_get_int_option(state, SPLT_OPT_PARAM_SHOTS));
1033 while (temp != NULL)
1034 {
1035 fprintf(log_file, "%f\t%f\t%ld\n",
1036 temp->begin_position, temp->end_position, temp->len);
1037 temp = temp->next;
1038 }
1039 fflush(log_file);
1040 if (log_file)
1041 {
1042 fclose(log_file);
1043 log_file = NULL;
1044 }
1045 temp = NULL;
1046 }
1047 }
1048 }
1049 }
1050 }
1051
1052 end:
1053 splt_siu_ssplit_free(&state->silence_list);
1054 splt_t_set_splitnumber(state, splitpoints_appended + 1);
1055
1056 return found;
1057 }
1058
1059 /*! Do the silence split
1060
1061 \param error The code of a eventual error that has occoured
1062 */
splt_s_silence_split(splt_state * state,int * error)1063 void splt_s_silence_split(splt_state *state, int *error)
1064 {
1065 splt_d_print_debug(state,"Starting silence split ...\n");
1066
1067 //print some useful infos to the client
1068 splt_c_put_info_message_to_client(state, _(" info: starting silence mode split\n"));
1069
1070 int found = splt_s_set_silence_splitpoints(state, error);
1071
1072 //if no error
1073 if (*error >= 0)
1074 {
1075 //if we have found splitpoints, write the silence tracks
1076 if (found > 1)
1077 {
1078 splt_d_print_debug(state,"Writing silence tracks...\n");
1079
1080 //set the default silence output
1081 int output_filenames = splt_o_get_int_option(state,SPLT_OPT_OUTPUT_FILENAMES);
1082 if (output_filenames == SPLT_OUTPUT_DEFAULT)
1083 {
1084 splt_of_set_oformat(state, SPLT_DEFAULT_SILENCE_OUTPUT, error, SPLT_TRUE);
1085 if (*error < 0) { return; }
1086 }
1087
1088 splt_s_multiple_split(state, error);
1089
1090 //we put the silence split errors
1091 switch (*error)
1092 {
1093 case SPLT_OK_SPLIT:
1094 *error = SPLT_SILENCE_OK;
1095 break;
1096 case SPLT_OK_SPLIT_EOF:
1097 *error = SPLT_SILENCE_OK;
1098 break;
1099 default:
1100 break;
1101 }
1102 }
1103 else
1104 {
1105 *error = SPLT_NO_SILENCE_SPLITPOINTS_FOUND;
1106 }
1107 }
1108 }
1109
1110 /*! Do the trim silence split
1111
1112 \param error The code of a eventual error that has occoured
1113 */
splt_s_trim_silence_split(splt_state * state,int * error)1114 void splt_s_trim_silence_split(splt_state *state, int *error)
1115 {
1116 splt_c_put_info_message_to_client(state, _(" info: starting trim using silence mode split\n"));
1117
1118 int found = splt_s_set_trim_silence_splitpoints(state, error);
1119 if (*error < 0) { return; }
1120
1121 if (found < 1)
1122 {
1123 *error = SPLT_NO_SILENCE_SPLITPOINTS_FOUND;
1124 return;
1125 }
1126
1127 splt_d_print_debug(state,"Writing tracks...\n");
1128
1129 int output_filenames = splt_o_get_int_option(state,SPLT_OPT_OUTPUT_FILENAMES);
1130 if (output_filenames == SPLT_OUTPUT_DEFAULT)
1131 {
1132 splt_of_set_oformat(state, SPLT_DEFAULT_TRIM_SILENCE_OUTPUT, error, SPLT_TRUE);
1133 if (*error < 0) { return; }
1134 }
1135
1136 splt_s_multiple_split(state, error);
1137
1138 switch (*error)
1139 {
1140 case SPLT_OK_SPLIT:
1141 *error = SPLT_TRIM_SILENCE_OK;
1142 break;
1143 case SPLT_OK_SPLIT_EOF:
1144 *error = SPLT_TRIM_SILENCE_OK;
1145 break;
1146 default:
1147 break;
1148 }
1149 }
1150
splt_s_open_full_log_filename(splt_state * state)1151 static splt_code splt_s_open_full_log_filename(splt_state *state)
1152 {
1153 char *fname = splt_t_get_silence_full_log_fname(state);
1154 if (!fname || fname[0] == '\0')
1155 {
1156 return SPLT_OK;
1157 }
1158
1159 state->full_log_file_descriptor = splt_io_fopen(fname, "w");
1160 if (!state->full_log_file_descriptor)
1161 {
1162 splt_e_set_strerror_msg_with_data(state, fname);
1163 return SPLT_ERROR_CANNOT_OPEN_FILE;
1164 }
1165
1166 return SPLT_OK;
1167 }
1168
splt_s_close_full_log_filename(splt_state * state)1169 static void splt_s_close_full_log_filename(splt_state *state)
1170 {
1171 if (!state->full_log_file_descriptor)
1172 {
1173 return;
1174 }
1175
1176 fflush(state->full_log_file_descriptor);
1177 fclose(state->full_log_file_descriptor);
1178 state->full_log_file_descriptor = NULL;
1179 }
1180
1181 /****************************/
1182 /*! Automatically split a file that has been created by mp3wrap
1183
1184 do the wrap split
1185 */
splt_s_wrap_split(splt_state * state,int * error)1186 void splt_s_wrap_split(splt_state *state, int *error)
1187 {
1188 char *new_filename_path = splt_t_get_new_filename_path(state);
1189 char *filename = splt_t_get_filename_to_split(state);
1190
1191 splt_d_print_debug(state,"Begin wrap split for the file _%s_\n", filename);
1192
1193 splt_c_put_info_message_to_client(state, _(" info: starting wrap mode split\n"));
1194
1195 splt_p_dewrap(state, SPLT_FALSE, new_filename_path, error);
1196 }
1197
1198