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