mp3splt-gtk
splitpoints_window.c
Go to the documentation of this file.
1 /**********************************************************
2  *
3  * mp3splt-gtk -- utility based on mp3splt,
4  * for mp3/ogg splitting without decoding
5  *
6  * Copyright: (C) 2005-2012 Alexandru Munteanu
7  * Contact: io_fx@yahoo.fr
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
28  * USA.
29  *
30  *********************************************************/
31 
32 /*!********************************************************
33  * \file
34  * The splitpoints tab
35  *
36  * this file is used for the Splitpoints tab
37  * (which in turn contains the splitpoints table)
38  **********************************************************/
39 
40 #include "splitpoints_window.h"
41 
43 static gboolean check_if_splitpoint_does_not_exists(gint minutes, gint seconds, gint hundr_secs,
44  gint current_split, ui_state *ui)
45 {
46  GtkTreeModel *model = gtk_tree_view_get_model(ui->gui->tree_view);
47 
48  GtkTreeIter iter;
49  if (!gtk_tree_model_get_iter_first(model, &iter))
50  {
51  return TRUE;
52  }
53 
54  gint tree_minutes;
55  gint tree_seconds;
56  gint tree_hundr_secs;
57 
58  while (TRUE)
59  {
60  gtk_tree_model_get(GTK_TREE_MODEL(model), &iter,
61  COL_MINUTES, &tree_minutes,
62  COL_SECONDS, &tree_seconds,
63  COL_HUNDR_SECS, &tree_hundr_secs,
64  -1);
65 
66  GtkTreePath *path = gtk_tree_model_get_path(model, &iter);
67  gint i = gtk_tree_path_get_indices (path)[0];
68 
69  if ((minutes == tree_minutes) &&
70  (seconds == tree_seconds) &&
71  (hundr_secs == tree_hundr_secs) &&
72  (i != current_split))
73  {
74  gtk_tree_path_free(path);
75  return FALSE;
76  }
77 
78  gtk_tree_path_free(path);
79 
80  if (!gtk_tree_model_iter_next(model, &iter))
81  {
82  break;
83  }
84  }
85 
86  return TRUE;
87 }
88 
94 static void update_add_button(ui_state *ui)
95 {
96  gui_status *status = ui->status;
97  if (check_if_splitpoint_does_not_exists(status->spin_mins, status->spin_secs, status->spin_hundr_secs,-1, ui))
98  {
99  gtk_widget_set_sensitive(GTK_WIDGET(ui->gui->add_button), TRUE);
100  }
101  else
102  {
103  gtk_widget_set_sensitive(GTK_WIDGET(ui->gui->add_button), FALSE);
104  }
105 }
106 
108 void update_minutes_from_spinner(GtkWidget *widget, ui_state *ui)
109 {
110  ui->status->spin_mins = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(ui->gui->spinner_minutes));
111  update_add_button(ui);
112 }
113 
115 void update_seconds_from_spinner(GtkWidget *widget, ui_state *ui)
116 {
117  ui->status->spin_secs = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(ui->gui->spinner_seconds));
118  update_add_button(ui);
119 }
120 
122 void update_hundr_secs_from_spinner(GtkWidget *widget, ui_state *ui)
123 {
124  ui->status->spin_hundr_secs = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(ui->gui->spinner_hundr_secs));
125  update_add_button(ui);
126 }
127 
129 static GtkTreeModel *create_model()
130 {
131  GtkListStore * model = gtk_list_store_new(NUM_COLUMNS,
132  G_TYPE_BOOLEAN,
133  G_TYPE_STRING,
134  G_TYPE_INT,
135  G_TYPE_INT,
136  G_TYPE_INT,
137  G_TYPE_STRING,
138  GDK_TYPE_PIXBUF,
139  GDK_TYPE_PIXBUF);
140 
141  return GTK_TREE_MODEL(model);
142 }
143 
145 static void recompute_length_column(ui_state *ui)
146 {
147  gint line_mins, line_secs, line_hundr;
148  gint line1_mins, line1_secs, line1_hundr;
149 
150  gchar new_length_string[30];
151 
152  GtkTreeModel *model = gtk_tree_view_get_model(ui->gui->tree_view);
153 
154  gint number = 0;
155  for (number = 0;number < ui->infos->splitnumber; number++)
156  {
157  GtkTreePath *path = gtk_tree_path_new_from_indices(number ,-1);
158  GtkTreeIter iter;
159  gtk_tree_model_get_iter(model, &iter, path);
160 
161  if (number != ui->infos->splitnumber-1)
162  {
163  GtkTreePath *path2 = gtk_tree_path_new_from_indices (number+1 ,-1);
164  GtkTreeIter iter2;
165  gtk_tree_model_get_iter(model, &iter2, path2);
166 
167  gtk_tree_model_get(GTK_TREE_MODEL(model), &iter,
168  COL_MINUTES, &line_mins,
169  COL_SECONDS, &line_secs,
170  COL_HUNDR_SECS, &line_hundr,
171  -1);
172  gtk_tree_model_get(GTK_TREE_MODEL(model), &iter2,
173  COL_MINUTES, &line1_mins,
174  COL_SECONDS, &line1_secs,
175  COL_HUNDR_SECS, &line1_hundr,
176  -1);
177 
178  gint result_secs = 0,result_hundr = 0;
179  gint result_mins = line1_mins - line_mins;
180  if ((result_secs = line1_secs - line_secs) < 0)
181  {
182  result_secs = 60 - line_secs + line1_secs;
183  result_mins--;
184  }
185 
186  if ((result_hundr = line1_hundr - line_hundr) < 0)
187  {
188  result_hundr = 100 - line_hundr + line1_hundr;
189  result_secs--;
190  if (result_secs < 0)
191  {
192  result_mins--;
193  result_secs = 0;
194  }
195  }
196 
197  g_snprintf(new_length_string, 30, "%d:%02d:%02d", result_mins, result_secs, result_hundr);
198 
199  gtk_tree_path_free(path2);
200  }
201  else
202  {
203  g_snprintf(new_length_string, 30, "%s","-");
204  }
205 
206  gtk_tree_path_free(path);
207 
208  gtk_list_store_set(GTK_LIST_STORE(model), &iter, COL_NUMBER, new_length_string, -1);
209  }
210 }
211 
219 static gboolean check_if_description_exists(gchar *descr, gint number, ui_state *ui)
220 {
221  GtkTreeModel *model = gtk_tree_view_get_model(ui->gui->tree_view);
222 
223  GtkTreeIter iter;
224  if (!gtk_tree_model_get_iter_first(model, &iter))
225  {
226  return TRUE;
227  }
228 
229  gint count = 0;
230  while (TRUE)
231  {
232  gchar *description = NULL;
233  gtk_tree_model_get(GTK_TREE_MODEL(model), &iter,
234  COL_DESCRIPTION, &description,
235  -1);
236 
237  if (description != NULL && strcmp(descr, description) == 0 && count != number)
238  {
239  g_free(description);
240  return FALSE;
241  }
242 
243  g_free(description);
244 
245  if (!gtk_tree_model_iter_next(model, &iter))
246  break;
247 
248  count++;
249  }
250 
251  return TRUE;
252 }
253 
256 {
257  gint splitpoint_selected = -1;
258 
259  GtkTreeModel *model = gtk_tree_view_get_model(gui->tree_view);
260  GtkTreeSelection *selection = gtk_tree_view_get_selection(gui->tree_view);
261 
262  GList *selected_list =
263  gtk_tree_selection_get_selected_rows(GTK_TREE_SELECTION(selection), &model);
264 
265  if (g_list_length(selected_list) > 0)
266  {
267  GList *current_element = g_list_first(selected_list);
268  GtkTreePath *path = current_element->data;
269  splitpoint_selected = gtk_tree_path_get_indices (path)[0];
270 
271  g_list_foreach(selected_list, (GFunc)gtk_tree_path_free, NULL);
272  g_list_free(selected_list);
273  }
274 
275  return splitpoint_selected;
276 }
277 
279 static void row_selection_event(GtkTreeSelection *selection, ui_state *ui)
280 {
281  gtk_widget_set_sensitive(ui->gui->remove_row_button, TRUE);
282 }
283 
294 static void update_current_description(gchar *descr, gint number, ui_state *ui)
295 {
296  gint ll = 0;
297 
298  gchar *current_description = ui->status->current_description;
299 
300  g_snprintf(current_description, 255, "%s", descr);
301 
302  while (ll < ui->infos->splitnumber)
303  {
304  if (check_if_description_exists(current_description, number, ui))
305  {
306  ll++;
307  continue;
308  }
309 
310  //we cut the part _* from the string and put it back
311  gchar *tmp = NULL;
312  gchar *t = current_description;
313  while ((t = strstr(t, _("_part"))) != NULL)
314  {
315  tmp = t++;
316  }
317 
318  if (tmp != NULL)
319  {
320  *tmp = '\0';
321  }
322 
323  gchar *temp = g_strdup(current_description);
324  g_snprintf(current_description, 255, _("%s_part%d"), temp, ll + 2);
325  g_free(temp);
326 
327  ll++;
328  }
329 }
330 
335 void get_hundr_secs_mins_time(gint time_pos, gint *time_hundr,
336  gint *time_secs,gint *time_mins)
337 {
338  *time_hundr = time_pos % 100;
339  time_pos = time_pos / 100;
340  *time_secs = time_pos % 60;
341  time_pos = time_pos / 60;
342  *time_mins = time_pos;
343 }
344 
346 void select_splitpoint(gint index, gui_state *gui)
347 {
348  GtkTreeSelection *selection = gtk_tree_view_get_selection(gui->tree_view);
349  GtkTreeModel *model = gtk_tree_view_get_model(gui->tree_view);
350  GtkTreePath *path = gtk_tree_path_new_from_indices(index ,-1);
351 
352  GtkTreeIter iter;
353  gtk_tree_model_get_iter(model, &iter, path);
354  gtk_tree_selection_unselect_all(selection);
355  gtk_tree_selection_select_iter(selection, &iter);
356 
357  gtk_tree_path_free(path);
358 
360 }
361 
366 void remove_splitpoint(gint index, gint stop_preview, ui_state *ui)
367 {
368  g_array_remove_index(ui->splitpoints, index);
369 
370  GtkTreeModel *model = gtk_tree_view_get_model(ui->gui->tree_view);
371  GtkTreePath *path = gtk_tree_path_new_from_indices (index ,-1);
372 
373  GtkTreeIter iter;
374  gtk_tree_model_get_iter(model, &iter, path);
375 
376  //cancel quick preview if necessary
377  if (((index == ui->status->preview_start_splitpoint) && stop_preview) ||
378  ((index == get_quick_preview_end_splitpoint_safe(ui)) &&
379  (get_quick_preview_end_splitpoint_safe(ui) == (ui->infos->splitnumber-1)) && stop_preview))
380  {
382  }
383 
384  //if we remove a point at the left of the play preview, move the indexes
385  if (index < ui->status->preview_start_splitpoint)
386  {
387  ui->status->preview_start_splitpoint--;
388  set_quick_preview_end_splitpoint_safe(ui->status->preview_start_splitpoint + 1, ui);
389  }
390 
391  gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
392  gtk_tree_path_free(path);
393 
394  ui->infos->splitnumber--;
395 
396  if (get_first_splitpoint_selected(ui->gui) == -1)
397  {
398  gtk_widget_set_sensitive(ui->gui->remove_row_button, FALSE);
399  }
400 
401  if (ui->infos->splitnumber == 0)
402  {
403  gtk_widget_set_sensitive(ui->gui->remove_all_button, FALSE);
404  }
405 
406  recompute_length_column(ui);
407  remove_status_message(ui->gui);
408  update_add_button(ui);
410  refresh_drawing_area(ui->gui);
411 }
412 
419 static void add_splitpoint(Split_point my_split_point, gint old_index, ui_state *ui)
420 {
421  if (check_if_splitpoint_does_not_exists(my_split_point.mins,
422  my_split_point.secs, my_split_point.hundr_secs,-1, ui))
423  {
424  gint k = 0;
425 
426  gchar *temp = g_strdup(ui->status->current_description);
427  update_current_description(temp, -1, ui);
428  if (temp)
429  {
430  free(temp);
431  temp = NULL;
432  }
433 
434  GtkTreeModel *model = gtk_tree_view_get_model(ui->gui->tree_view);
435 
436  GtkTreeIter iter;
437  if (gtk_tree_model_get_iter_first(model, &iter))
438  {
439  while (k < ui->infos->splitnumber)
440  {
441  gint tree_minutes;
442  gint tree_seconds;
443  gint tree_hundr_secs;
444  gtk_tree_model_get(GTK_TREE_MODEL(model), &iter,
445  COL_MINUTES, &tree_minutes,
446  COL_SECONDS, &tree_seconds,
447  COL_HUNDR_SECS, &tree_hundr_secs,
448  -1);
449 
450  if (my_split_point.mins < tree_minutes)
451  {
452  break;
453  }
454  else if (my_split_point.mins == tree_minutes)
455  {
456  if (my_split_point.secs < tree_seconds)
457  {
458  break;
459  }
460  else if (my_split_point.secs == tree_seconds)
461  {
462  if (my_split_point.hundr_secs < tree_hundr_secs)
463  {
464  break;
465  }
466  }
467  }
468 
469  gtk_tree_model_iter_next(model, &iter);
470  k++;
471  }
472 
473  gtk_list_store_insert(GTK_LIST_STORE(model), &iter,k--);
474  g_array_insert_val(ui->splitpoints, k+1, my_split_point);
475  }
476  else
477  {
478  gtk_list_store_append(GTK_LIST_STORE(model), &iter);
479  g_array_append_val(ui->splitpoints, my_split_point);
480  }
481 
482  ui->infos->splitnumber++;
483 
484  //we keep the selection on the previous splipoint
485  if ((ui->status->first_splitpoint_selected == old_index) &&
486  (old_index != -1))
487  {
488  GtkTreePath *path = gtk_tree_model_get_path(model, &iter);
489  gtk_tree_view_set_cursor(ui->gui->tree_view, path, NULL, FALSE);
490  gtk_tree_path_free(path);
491  }
492 
493  if (ui->status->quick_preview)
494  {
495  //if we move the current start preview splitpoint
496  //at the right of the current time, we cancel preview
497  if (old_index == ui->status->preview_start_splitpoint)
498  {
499  if (ui->infos->current_time < get_splitpoint_time(ui->status->preview_start_splitpoint, ui))
500  {
501  cancel_quick_preview(ui->status);
502  }
503  }
504  }
505 
506  //we manage the play preview here
507  if (old_index != -1)
508  {
509  //if we have a split preview on going
510  //if we move the point from the left to the right of the
511  //the start preview splitpoint
512  if ((old_index < ui->status->preview_start_splitpoint))
513  {
514  if ((k+1) >= ui->status->preview_start_splitpoint)
515  {
516  ui->status->preview_start_splitpoint--;
517  set_quick_preview_end_splitpoint_safe(ui->status->preview_start_splitpoint + 1, ui);
518  }
519  }
520  else
521  {
522  //if we move from the right of the split preview to his left
523  if ((old_index > ui->status->preview_start_splitpoint))
524  {
525  if ((k+1) <= ui->status->preview_start_splitpoint)
526  {
527  ui->status->preview_start_splitpoint++;
528  set_quick_preview_end_splitpoint_safe(ui->status->preview_start_splitpoint + 1, ui);
529  }
530  }
531  else
532  {
533  //if we move the start splitpoint on the right of the end splitpoint
534  if (old_index == ui->status->preview_start_splitpoint)
535  {
536  if ((k+1) > ui->status->preview_start_splitpoint)
537  {
538  ui->status->preview_start_splitpoint += (k+1) - ui->status->preview_start_splitpoint;
539  set_quick_preview_end_splitpoint_safe(ui->status->preview_start_splitpoint + 1, ui);
540  }
541  else
542  {
543  //if we move the start splitpoint at the left
544  if ((k+1) < ui->status->preview_start_splitpoint)
545  {
546  ui->status->preview_start_splitpoint -= ui->status->preview_start_splitpoint - (k + 1);
547  set_quick_preview_end_splitpoint_safe(ui->status->preview_start_splitpoint + 1, ui);
548  }
549  }
550  }
551  }
552  }
553 
554  if (ui->status->preview_start_splitpoint == (ui->infos->splitnumber-1))
555  {
557  }
558  }
559  else
560  {
561  //if we add a splitpoint at the left of the quick
562  //preview start, add 1
563  if ((k+1) <= ui->status->preview_start_splitpoint)
564  {
565  ui->status->preview_start_splitpoint++;
566  set_quick_preview_end_splitpoint_safe(ui->status->preview_start_splitpoint + 1, ui);
567  }
568  }
569 
570  //put values in the line
571  //sets text in the minute, second and milisecond column
572  gtk_list_store_set(GTK_LIST_STORE(model),
573  &iter,
574  COL_CHECK, my_split_point.checked,
575  COL_DESCRIPTION, ui->status->current_description,
576  COL_MINUTES, my_split_point.mins,
577  COL_SECONDS, my_split_point.secs,
578  COL_HUNDR_SECS, my_split_point.hundr_secs,
579  -1);
580 
581  gtk_widget_set_sensitive(ui->gui->remove_all_button, TRUE);
582 
583  recompute_length_column(ui);
584  remove_status_message(ui->gui);
585  }
586  else
587  {
588  put_status_message(_(" error: you already have the splitpoint in table"), ui);
589  }
590 
591  if (gtk_toggle_button_get_active(ui->gui->names_from_filename))
592  {
593  copy_filename_to_current_description(get_input_filename(ui->gui), ui);
594  }
595  else
596  {
597  g_snprintf(ui->status->current_description, 255, "%s", _("description here"));
598  }
599 
600  update_add_button(ui);
601  refresh_drawing_area(ui->gui);
603 }
604 
614 void update_splitpoint(gint index, Split_point new_point, ui_state *ui)
615 {
616  int splitpoint_does_not_exists =
617  check_if_splitpoint_does_not_exists(new_point.mins, new_point.secs, new_point.hundr_secs,-1, ui);
618 
619  Split_point old_point = g_array_index(ui->splitpoints, Split_point, index);
620 
621  if (splitpoint_does_not_exists ||
622  (old_point.checked != new_point.checked))
623  {
624  ui->status->first_splitpoint_selected = get_first_splitpoint_selected(ui->gui);
625 
626  gchar *description = get_splitpoint_name(index, ui);
627  g_snprintf(ui->status->current_description, 255, "%s", description);
628  g_free(description);
629 
630  remove_splitpoint(index, FALSE, ui);
631  add_splitpoint(new_point, index, ui);
632  }
633  else
634  {
635  //don't put error if we move the same splitpoint
636  //on the same place
637  if ((new_point.mins == old_point.mins) &&
638  (new_point.secs == old_point.secs) &&
639  (new_point.hundr_secs == old_point.hundr_secs))
640  {
641  }
642  else
643  {
644  put_status_message(_(" error: you already have the splitpoint in table"), ui);
645  }
646  }
647 }
648 
653 void update_splitpoint_from_time(gint index, gdouble time, ui_state *ui)
654 {
655  Split_point new_point;
656  get_hundr_secs_mins_time((gint)time, &new_point.hundr_secs, &new_point.secs, &new_point.mins);
657  Split_point old_point = g_array_index(ui->splitpoints, Split_point, index);
658  new_point.checked = old_point.checked;
659 
660  update_splitpoint(index, new_point, ui);
661 }
662 
668 void update_splitpoint_check(gint index, ui_state *ui)
669 {
670  Split_point old_point = g_array_index(ui->splitpoints, Split_point, index);
671  old_point.checked ^= 1;
672  update_splitpoint(index, old_point, ui);
673 }
674 
675 void clear_current_description(ui_state *ui)
676 {
677  update_current_description(_("description here"), -1, ui);
678 }
679 
680 void copy_filename_to_current_description(const gchar *fname, ui_state *ui)
681 {
682  if (strcmp(fname, "") == 0)
683  {
684  clear_current_description(ui);
685  }
686 
687  gchar *temp = g_strdup(g_path_get_basename(fname));
688  gchar *tmp = strrchr(temp,'.');
689  if (tmp != NULL) { *tmp = '\0'; }
690 
691  g_snprintf(ui->status->current_description, 255, "%s", temp);
692  g_free(temp);
693 }
694 
696 static void cell_edited_event(GtkCellRendererText *cell, gchar *path_string, gchar *new_text, ui_state *ui)
697 {
698  GtkTreePath *path = gtk_tree_path_new_from_string (path_string);
699  GtkTreeModel *model = gtk_tree_view_get_model(ui->gui->tree_view);
700 
701  gint col = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(cell), "col"));
702 
703  GtkTreeIter iter;
704  gtk_tree_model_get_iter(model, &iter, path);
705  gint i = gtk_tree_path_get_indices (path)[0];
706  Split_point old_point = g_array_index(ui->splitpoints, Split_point, i);
707 
708  Split_point new_point;
709  new_point.checked = old_point.checked;
710 
711  switch (col)
712  {
713  case COL_DESCRIPTION:
714  update_current_description(new_text, i, ui);
715 
716  //put the new content in the list
717  gtk_list_store_set(GTK_LIST_STORE(model), &iter,
718  col, ui->status->current_description,
719  -1);
720 
721  if (gtk_toggle_button_get_active(ui->gui->names_from_filename))
722  {
723  copy_filename_to_current_description(get_input_filename(ui->gui), ui);
724  }
725  else
726  {
727  g_snprintf(ui->status->current_description, 255, "%s", _("description here"));
728  }
729  break;
730  //seconds column
731  case COL_SECONDS:
732  new_point.mins = old_point.mins;
733  new_point.secs = atoi(new_text);
734  new_point.hundr_secs = old_point.hundr_secs;
735 
736  if (new_point.secs < 0)
737  {
738  new_point.secs = 0;
739  }
740  if (new_point.secs > 59)
741  {
742  new_point.secs = 59;
743  }
744 
745  update_splitpoint(i, new_point, ui);
746  break;
747  //minutes column
748  case COL_MINUTES:
749  new_point.mins = atoi(new_text);
750  new_point.secs = old_point.secs;
751  new_point.hundr_secs = old_point.hundr_secs;
752 
753  if (new_point.mins < 0)
754  {
755  new_point.mins = 0;
756  }
757  if (new_point.mins > INT_MAX/6000)
758  {
759  new_point.mins = INT_MAX/6000;
760  }
761 
762  update_splitpoint(i, new_point, ui);
763  break;
764  //hundreth column
765  case COL_HUNDR_SECS:
766  new_point.mins = old_point.mins;
767  new_point.secs = old_point.secs;
768  new_point.hundr_secs = atoi(new_text);
769 
770  if (new_point.hundr_secs < 0)
771  {
772  new_point.hundr_secs = 0;
773  }
774  if (new_point.hundr_secs > 99)
775  {
776  new_point.hundr_secs = 99;
777  }
778 
779  update_splitpoint(i, new_point, ui);
780  break;
781  default:
782  break;
783  }
784 
785  gtk_tree_path_free(path);
786 }
787 
788 void add_splitpoint_from_player(GtkWidget *widget, ui_state *ui)
789 {
790  if (!ui->status->timer_active)
791  {
792  return;
793  }
794 
795  Split_point my_split_point;
796  my_split_point.mins = ui->infos->player_minutes;
797  my_split_point.secs = ui->infos->player_seconds;
798  my_split_point.hundr_secs = ui->infos->player_hundr_secs;
799  my_split_point.checked = TRUE;
800 
801  add_splitpoint(my_split_point, -1, ui);
802 }
803 
805 void add_row(gboolean checked, ui_state *ui)
806 {
807  gui_status *status = ui->status;
808 
809  Split_point my_split_point;
810  my_split_point.mins = status->spin_mins;
811  my_split_point.secs = status->spin_secs;
812  my_split_point.hundr_secs = status->spin_hundr_secs;
813  my_split_point.checked = checked;
814 
815  add_splitpoint(my_split_point, -1, ui);
816 }
817 
818 static void add_row_clicked(GtkWidget *button, ui_state *ui)
819 {
820  add_row(TRUE, ui);
821 }
822 
823 static gboolean detect_silence_and_set_splitpoints_end(ui_with_err *ui_err)
824 {
825  gint err = ui_err->err;
826  ui_state *ui = ui_err->ui;
827 
828  mp3splt_set_int_option(ui->mp3splt_state, SPLT_OPT_PRETEND_TO_SPLIT, SPLT_FALSE);
829  mp3splt_set_split_filename_function(ui->mp3splt_state, lmanager_put_split_filename, ui);
830 
831  if (err >= 0)
832  {
834  }
835 
837 
838  gtk_widget_set_sensitive(ui->gui->cancel_button, FALSE);
839  gtk_widget_set_sensitive(ui->gui->scan_silence_button, TRUE);
840  gtk_widget_set_sensitive(ui->gui->scan_silence_button_player, TRUE);
841  gtk_widget_set_sensitive(ui->gui->scan_trim_silence_button, TRUE);
842  gtk_widget_set_sensitive(ui->gui->scan_trim_silence_button_player, TRUE);
843 
844  set_is_splitting_safe(FALSE, ui);
845 
846  set_process_in_progress_and_wait_safe(FALSE, ui);
847 
848  g_free(ui_err);
849 
850  return FALSE;
851 }
852 
853 static void set_should_trim_safe(gboolean value, ui_state *ui)
854 {
855  lock_mutex(&ui->variables_mutex);
856  ui->status->should_trim = value;
857  unlock_mutex(&ui->variables_mutex);
858 }
859 
860 static gint get_should_trim_safe(ui_state *ui)
861 {
862  lock_mutex(&ui->variables_mutex);
863  gint should_trim = ui->status->should_trim;
864  unlock_mutex(&ui->variables_mutex);
865  return should_trim;
866 }
867 
869 static gpointer detect_silence_and_set_splitpoints(ui_state *ui)
870 {
871  set_process_in_progress_and_wait_safe(TRUE, ui);
872 
873  set_is_splitting_safe(TRUE, ui);
874 
875  gint err = SPLT_OK;
876 
877  enter_threads();
878 
879  gtk_widget_set_sensitive(ui->gui->scan_silence_button, FALSE);
880  gtk_widget_set_sensitive(ui->gui->scan_silence_button_player, FALSE);
881  gtk_widget_set_sensitive(ui->gui->scan_trim_silence_button, FALSE);
882  gtk_widget_set_sensitive(ui->gui->scan_trim_silence_button_player, FALSE);
883  gtk_widget_set_sensitive(ui->gui->cancel_button, TRUE);
884  gchar *format = strdup(gtk_entry_get_text(GTK_ENTRY(ui->gui->output_entry)));
885 
886  lock_mutex(&ui->variables_mutex);
887  mp3splt_set_filename_to_split(ui->mp3splt_state, get_input_filename(ui->gui));
888  unlock_mutex(&ui->variables_mutex);
889 
890  gint checked_output_radio_box = get_checked_output_radio_box(ui);
891 
892  exit_threads();
893 
894  mp3splt_erase_all_splitpoints(ui->mp3splt_state, &err);
895 
896  if (checked_output_radio_box == 0)
897  {
898  mp3splt_set_oformat(ui->mp3splt_state, format, &err);
899  }
900  if (format)
901  {
902  free(format);
903  format = NULL;
904  }
905 
906  mp3splt_set_int_option(ui->mp3splt_state, SPLT_OPT_PRETEND_TO_SPLIT, SPLT_TRUE);
907  mp3splt_set_split_filename_function(ui->mp3splt_state, NULL, ui);
908  mp3splt_set_int_option(ui->mp3splt_state, SPLT_OPT_TAGS, SPLT_TAGS_ORIGINAL_FILE);
909 
910  print_status_bar_confirmation_in_idle(err, ui);
911 
912  err = SPLT_OK;
913  int old_split_mode = mp3splt_get_int_option(ui->mp3splt_state, SPLT_OPT_SPLIT_MODE, &err);
914  int old_tags_option = mp3splt_get_int_option(ui->mp3splt_state, SPLT_OPT_TAGS, &err);
915 
916  if (get_should_trim_safe(ui))
917  {
918  mp3splt_set_trim_silence_points(ui->mp3splt_state, &err);
919  }
920  else
921  {
922  mp3splt_set_silence_points(ui->mp3splt_state, &err);
923  }
924 
925  mp3splt_set_int_option(ui->mp3splt_state, SPLT_OPT_TAGS, old_tags_option);
926  mp3splt_set_int_option(ui->mp3splt_state, SPLT_OPT_SPLIT_MODE, old_split_mode);
927 
928  ui_with_err *ui_err = g_malloc0(sizeof(ui_with_err));
929  ui_err->err = err;
930  ui_err->ui = ui;
931 
932  gdk_threads_add_idle_full(G_PRIORITY_HIGH_IDLE,
933  (GSourceFunc)detect_silence_and_set_splitpoints_end, ui_err, NULL);
934 
935  return NULL;
936 }
937 
938 static void detect_silence_and_set_splitpoints_action(ui_state *ui)
939 {
940  create_thread((GThreadFunc)detect_silence_and_set_splitpoints, ui);
941 }
942 
944 static void detect_silence_and_add_splitpoints_start_thread(ui_state *ui)
945 {
946  set_should_trim_safe(FALSE, ui);
947  detect_silence_and_set_splitpoints_action(ui);
948 }
949 
950 static void detect_silence_and_add_trim_splitpoints_start_thread(ui_state *ui)
951 {
952  set_should_trim_safe(TRUE, ui);
953  detect_silence_and_set_splitpoints_action(ui);
954 }
955 
957 static void update_silence_parameters(GtkWidget *widget, ui_state *ui)
958 {
959  ui_infos *infos = ui->infos;
960  gui_state *gui = ui->gui;
961 
962  infos->silence_threshold_value =
963  gtk_spin_button_get_value(GTK_SPIN_BUTTON(gui->spinner_silence_threshold));
964  if (gui->spinner_silence_offset != NULL)
965  {
966  infos->silence_offset_value =
967  gtk_spin_button_get_value(GTK_SPIN_BUTTON(gui->spinner_silence_offset));
968  }
969  if (gui->spinner_silence_number_tracks != NULL)
970  {
971  infos->silence_number_of_tracks =
972  gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(gui->spinner_silence_number_tracks));
973  }
974  if (gui->spinner_silence_minimum != NULL)
975  {
976  infos->silence_minimum_length =
977  gtk_spin_button_get_value(GTK_SPIN_BUTTON(gui->spinner_silence_minimum));
978  }
979  if (gui->spinner_silence_minimum_track != NULL)
980  {
981  infos->silence_minimum_track_length =
982  gtk_spin_button_get_value(GTK_SPIN_BUTTON(gui->spinner_silence_minimum_track));
983  }
984  if (gui->silence_remove_silence != NULL)
985  {
986  infos->silence_remove_silence_between_tracks =
987  gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gui->silence_remove_silence));
988  }
989 }
990 
992 static void silence_remove_silence_checked(GtkToggleButton *button, ui_state *ui)
993 {
994  update_silence_parameters(GTK_WIDGET(button), ui);
995 }
996 
997 void create_trim_silence_window(GtkWidget *button, ui_state *ui)
998 {
999  GtkWidget *silence_detection_window =
1000  gtk_dialog_new_with_buttons(_("Set trim splitpoints using silence detection"),
1001  GTK_WINDOW(ui->gui->window),
1002  GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
1003  GTK_STOCK_OK,
1004  GTK_RESPONSE_YES,
1005  GTK_STOCK_CANCEL,
1006  GTK_RESPONSE_CANCEL,
1007  NULL);
1008 
1009  gtk_widget_set_size_request(silence_detection_window, 300, 90);
1010 
1011  GtkWidget *general_inside_vbox = wh_vbox_new();
1012 
1013  GtkWidget *horiz_fake = wh_hbox_new();
1014  gtk_box_pack_start(GTK_BOX(general_inside_vbox), horiz_fake, FALSE, FALSE, 10);
1015 
1016  //vertical parameter box
1017  GtkWidget *param_vbox = wh_vbox_new();
1018  gtk_box_pack_start(GTK_BOX(horiz_fake), param_vbox, FALSE, FALSE, 25);
1019 
1020  //horizontal box fake for threshold level
1021  horiz_fake = wh_hbox_new();
1022  gtk_box_pack_start(GTK_BOX(param_vbox), horiz_fake, FALSE, FALSE, 0);
1023 
1024  //threshold level
1025  GtkWidget *label = gtk_label_new(_("Threshold level (dB):"));
1026  gtk_box_pack_start(GTK_BOX(horiz_fake), label, FALSE, FALSE, 0);
1027 
1028  //adjustement for the threshold spinner
1029  GtkAdjustment *adj = (GtkAdjustment *) gtk_adjustment_new(0.0, -96.0, 0.0, 0.5, 10.0, 0.0);
1030  GtkWidget *spinner_silence_threshold = gtk_spin_button_new(adj, 0.5, 2);
1031  ui->gui->spinner_silence_threshold = spinner_silence_threshold;
1032  gtk_box_pack_start(GTK_BOX(horiz_fake), spinner_silence_threshold, FALSE, FALSE, 6);
1033  gtk_spin_button_set_value(GTK_SPIN_BUTTON(spinner_silence_threshold), ui->infos->silence_threshold_value);
1034  g_signal_connect(G_OBJECT(spinner_silence_threshold), "value_changed",
1035  G_CALLBACK(update_silence_parameters), ui);
1036 
1037  gtk_widget_show_all(general_inside_vbox);
1038  gtk_container_add(GTK_CONTAINER(
1039  gtk_dialog_get_content_area(GTK_DIALOG(silence_detection_window))), general_inside_vbox);
1040 
1041  gint result = gtk_dialog_run(GTK_DIALOG(silence_detection_window));
1042 
1043  gtk_widget_destroy(silence_detection_window);
1044 
1045  if (result == GTK_RESPONSE_YES)
1046  {
1047  mp3splt_set_float_option(ui->mp3splt_state, SPLT_OPT_PARAM_THRESHOLD, ui->infos->silence_threshold_value);
1048  detect_silence_and_add_trim_splitpoints_start_thread(ui);
1049  }
1050 }
1051 
1054 {
1055  ui_infos *infos = ui->infos;
1056  gui_state *gui = ui->gui;
1057 
1058  GtkWidget *silence_detection_window =
1059  gtk_dialog_new_with_buttons(_("Set splitpoints from silence detection"),
1060  GTK_WINDOW(gui->window),
1061  GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
1062  GTK_STOCK_OK,
1063  GTK_RESPONSE_YES,
1064  GTK_STOCK_CANCEL,
1065  GTK_RESPONSE_CANCEL,
1066  NULL);
1067 
1068  GtkWidget *general_inside_vbox = wh_vbox_new();
1069  GtkWidget *horiz_fake = wh_hbox_new();
1070  gtk_box_pack_start(GTK_BOX(general_inside_vbox), horiz_fake, FALSE, FALSE, 10);
1071 
1072  //vertical parameter box
1073  GtkWidget *param_vbox = wh_vbox_new();
1074  gtk_box_pack_start(GTK_BOX(horiz_fake), param_vbox, FALSE, FALSE, 25);
1075 
1076  //horizontal box fake for threshold level
1077  horiz_fake = wh_hbox_new();
1078  gtk_box_pack_start(GTK_BOX(param_vbox), horiz_fake, FALSE, FALSE, 0);
1079 
1080  //threshold level
1081  GtkWidget *label = gtk_label_new(_("Threshold level (dB):"));
1082  gtk_box_pack_start(GTK_BOX(horiz_fake), label, FALSE, FALSE, 0);
1083 
1084  //adjustement for the threshold spinner
1085  GtkAdjustment *adj = (GtkAdjustment *) gtk_adjustment_new(0.0, -96.0, 0.0, 0.5, 10.0, 0.0);
1086  GtkWidget *spinner_silence_threshold = gtk_spin_button_new(adj, 0.5, 2);
1087  gui->spinner_silence_threshold = spinner_silence_threshold;
1088  gtk_box_pack_start(GTK_BOX(horiz_fake), spinner_silence_threshold, FALSE, FALSE, 6);
1089 
1090  //horizontal box fake for the offset level
1091  horiz_fake = wh_hbox_new();
1092  gtk_box_pack_start(GTK_BOX(param_vbox), horiz_fake, FALSE, FALSE, 0);
1093 
1094  //offset level
1095  label = gtk_label_new(_("Cutpoint offset (0 is the begin of silence,"
1096  "and 1 the end):"));
1097  gtk_box_pack_start(GTK_BOX(horiz_fake), label, FALSE, FALSE, 0);
1098 
1099  //adjustement for the offset spinner
1100  adj = (GtkAdjustment *) gtk_adjustment_new(0.0, -2, 2, 0.05, 10.0, 0.0);
1101  GtkWidget *spinner_silence_offset = gtk_spin_button_new(adj, 0.05, 2);
1102  gui->spinner_silence_offset = spinner_silence_offset;
1103  gtk_box_pack_start(GTK_BOX(horiz_fake), spinner_silence_offset, FALSE, FALSE, 6);
1104 
1105  //number of tracks
1106  horiz_fake = wh_hbox_new();
1107  gtk_box_pack_start(GTK_BOX(param_vbox), horiz_fake, FALSE, FALSE, 0);
1108 
1109  label = gtk_label_new(_("Number of tracks (0 means all tracks):"));
1110  gtk_box_pack_start(GTK_BOX(horiz_fake), label, FALSE, FALSE, 0);
1111 
1112  adj = (GtkAdjustment *)gtk_adjustment_new(0.0, 0, 2000, 1, 10.0, 0.0);
1113  GtkWidget *spinner_silence_number_tracks = gtk_spin_button_new(adj, 1, 0);
1114  gui->spinner_silence_number_tracks = spinner_silence_number_tracks;
1115  gtk_box_pack_start(GTK_BOX(horiz_fake), spinner_silence_number_tracks, FALSE, FALSE, 6);
1116 
1117  //minimum length
1118  horiz_fake = wh_hbox_new();
1119  gtk_box_pack_start(GTK_BOX(param_vbox), horiz_fake, FALSE, FALSE, 0);
1120 
1121  label = gtk_label_new(_("Minimum silence length (seconds):"));
1122  gtk_box_pack_start(GTK_BOX(horiz_fake), label, FALSE, FALSE, 0);
1123 
1124  adj = (GtkAdjustment *)gtk_adjustment_new(0.0, 0, 2000, 0.5, 10.0, 0.0);
1125  GtkWidget *spinner_silence_minimum = gtk_spin_button_new(adj, 1, 2);
1126  gui->spinner_silence_minimum = spinner_silence_minimum;
1127  gtk_box_pack_start(GTK_BOX(horiz_fake), spinner_silence_minimum, FALSE, FALSE, 6);
1128 
1129  //the minimum track length parameter
1130  horiz_fake = wh_hbox_new();
1131  gtk_box_pack_start(GTK_BOX(param_vbox), horiz_fake, FALSE, FALSE, 0);
1132 
1133  label = gtk_label_new(_("Minimum track length (seconds):"));
1134  gtk_box_pack_start(GTK_BOX(horiz_fake), label, FALSE, FALSE, 0);
1135 
1136  adj = (GtkAdjustment *)gtk_adjustment_new(0.0, 0, 2000, 0.5, 10.0, 0.0);
1137  GtkWidget *spinner_silence_minimum_track = gtk_spin_button_new(adj, 1, 2);
1138  gui->spinner_silence_minimum_track = spinner_silence_minimum_track;
1139  gtk_box_pack_start(GTK_BOX(horiz_fake), spinner_silence_minimum_track, FALSE, FALSE, 6);
1140 
1141  //remove silence (rm): allows you to remove the silence between
1142  //tracks
1143  GtkWidget *silence_remove_silence = gtk_check_button_new_with_mnemonic(_("_Remove silence between tracks"));
1144  gui->silence_remove_silence = silence_remove_silence;
1145  gtk_box_pack_start(GTK_BOX(param_vbox), silence_remove_silence, FALSE, FALSE, 0);
1146 
1147  //we set the default parameters for the silence split
1148  gtk_spin_button_set_value(GTK_SPIN_BUTTON(spinner_silence_threshold),
1149  infos->silence_threshold_value);
1150  gtk_spin_button_set_value(GTK_SPIN_BUTTON(spinner_silence_offset),
1151  infos->silence_offset_value);
1152  gtk_spin_button_set_value(GTK_SPIN_BUTTON(spinner_silence_number_tracks),
1153  infos->silence_number_of_tracks);
1154  gtk_spin_button_set_value(GTK_SPIN_BUTTON(spinner_silence_minimum),
1155  infos->silence_minimum_length);
1156  gtk_spin_button_set_value(GTK_SPIN_BUTTON(spinner_silence_minimum_track),
1157  infos->silence_minimum_track_length);
1158  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(silence_remove_silence),
1159  infos->silence_remove_silence_between_tracks);
1160 
1161  //add actions when changing the values
1162  g_signal_connect(G_OBJECT(spinner_silence_threshold), "value_changed",
1163  G_CALLBACK(update_silence_parameters), ui);
1164  g_signal_connect(G_OBJECT(spinner_silence_offset), "value_changed",
1165  G_CALLBACK(update_silence_parameters), ui);
1166  g_signal_connect(G_OBJECT(spinner_silence_number_tracks), "value_changed",
1167  G_CALLBACK(update_silence_parameters), ui);
1168  g_signal_connect(G_OBJECT(spinner_silence_minimum), "value_changed",
1169  G_CALLBACK(update_silence_parameters), ui);
1170  g_signal_connect(G_OBJECT(spinner_silence_minimum_track), "value_changed",
1171  G_CALLBACK(update_silence_parameters), ui);
1172  g_signal_connect(G_OBJECT(silence_remove_silence), "toggled",
1173  G_CALLBACK(silence_remove_silence_checked), ui);
1174 
1175  gtk_widget_show_all(general_inside_vbox);
1176  gtk_container_add(GTK_CONTAINER(
1177  gtk_dialog_get_content_area(GTK_DIALOG(silence_detection_window))),
1178  general_inside_vbox);
1179 
1180  gint result = gtk_dialog_run(GTK_DIALOG(silence_detection_window));
1181 
1182  gtk_widget_destroy(silence_detection_window);
1183 
1184  if (result == GTK_RESPONSE_YES)
1185  {
1186  mp3splt_set_float_option(ui->mp3splt_state, SPLT_OPT_PARAM_THRESHOLD,
1187  infos->silence_threshold_value);
1188  mp3splt_set_float_option(ui->mp3splt_state, SPLT_OPT_PARAM_OFFSET,
1189  infos->silence_offset_value);
1190  mp3splt_set_int_option(ui->mp3splt_state, SPLT_OPT_PARAM_NUMBER_TRACKS,
1191  infos->silence_number_of_tracks);
1192  mp3splt_set_float_option(ui->mp3splt_state, SPLT_OPT_PARAM_MIN_LENGTH,
1193  infos->silence_minimum_length);
1194  mp3splt_set_float_option(ui->mp3splt_state, SPLT_OPT_PARAM_MIN_TRACK_LENGTH,
1195  infos->silence_minimum_track_length);
1196  mp3splt_set_int_option(ui->mp3splt_state, SPLT_OPT_PARAM_REMOVE_SILENCE,
1197  infos->silence_remove_silence_between_tracks);
1198 
1199  detect_silence_and_add_splitpoints_start_thread(ui);
1200  }
1201 }
1202 
1204 static void remove_row(GtkWidget *widget, ui_state *ui)
1205 {
1206  GtkTreeModel *model = gtk_tree_view_get_model(ui->gui->tree_view);
1207  GtkTreeSelection *selection = gtk_tree_view_get_selection(ui->gui->tree_view);
1208 
1209  GList *selected_list = gtk_tree_selection_get_selected_rows(selection, &model);
1210 
1211  while ((g_list_length(selected_list) > 0) && (ui->infos->splitnumber > 0))
1212  {
1213  GList *current_element = g_list_last(selected_list);
1214  GtkTreePath *path = current_element->data;
1215  gint i = gtk_tree_path_get_indices (path)[0];
1216 
1217  remove_splitpoint(i, TRUE, ui);
1218 
1219  selected_list = g_list_remove(selected_list, path);
1220 
1221  gtk_tree_path_free(path);
1222  }
1223 
1224  g_list_foreach(selected_list, (GFunc)gtk_tree_path_free, NULL);
1225  g_list_free(selected_list);
1226 }
1227 
1229 void remove_all_rows(GtkWidget *widget, ui_state *ui)
1230 {
1231  GtkTreeModel *model = gtk_tree_view_get_model(ui->gui->tree_view);
1232 
1233  while (ui->infos->splitnumber > 0)
1234  {
1235  GtkTreeIter iter;
1236  gtk_tree_model_get_iter_first(model, &iter);
1237  gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
1238  g_array_remove_index(ui->splitpoints, (ui->infos->splitnumber-1));
1239  ui->infos->splitnumber--;
1240  }
1241 
1242  gtk_widget_set_sensitive(ui->gui->remove_all_button, FALSE);
1243  gtk_widget_set_sensitive(ui->gui->remove_row_button, FALSE);
1244 
1245  remove_status_message(ui->gui);
1247  update_add_button(ui);
1248  refresh_drawing_area(ui->gui);
1250 }
1251 
1253 static GtkWidget *create_init_spinner(GtkWidget *bottomhbox1, gint min, gint max,
1254  gchar *label_text, gint type, ui_state *ui)
1255 {
1256  GtkWidget *spinner_box = wh_vbox_new();
1257  GtkWidget *label = gtk_label_new(label_text);
1258  gtk_box_pack_start(GTK_BOX(spinner_box), label, TRUE, FALSE, 0);
1259 
1260  GtkAdjustment *adj = (GtkAdjustment *) gtk_adjustment_new(0.0, min, max, 1.0, 10.0, 0.0);
1261  GtkWidget *spinner = gtk_spin_button_new(adj, 0, 0);
1262  gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(spinner), TRUE);
1263 
1264  if (type == 0)
1265  {
1266  g_signal_connect(G_OBJECT(spinner), "value_changed",
1267  G_CALLBACK(update_minutes_from_spinner), ui);
1268  }
1269  else if (type == 1)
1270  {
1271  g_signal_connect(G_OBJECT(spinner), "value_changed",
1272  G_CALLBACK(update_seconds_from_spinner), ui);
1273  }
1274  else
1275  {
1276  g_signal_connect(G_OBJECT(spinner), "value_changed",
1277  G_CALLBACK(update_hundr_secs_from_spinner), ui);
1278  }
1279 
1280  gtk_box_pack_start(GTK_BOX(spinner_box), spinner, TRUE, FALSE, 0);
1281  gtk_box_pack_start(GTK_BOX(bottomhbox1), spinner_box, FALSE, FALSE, 5);
1282 
1283  return spinner;
1284 }
1285 
1287 static GtkWidget *create_init_spinners_buttons(ui_state *ui)
1288 {
1289  GtkWidget *hbox = wh_hbox_new();
1290  gtk_container_set_border_width(GTK_CONTAINER(hbox), 0);
1291 
1292  //0 means spinner minutes
1293  ui->gui->spinner_minutes = create_init_spinner(hbox, 0, INT_MAX/6000, _("Minutes:"), 0, ui);
1294  //1 means spinner seconds
1295  ui->gui->spinner_seconds = create_init_spinner(hbox, 0, 59, _("Seconds:"), 1, ui);
1296  //2 means spinner hundredth
1297  ui->gui->spinner_hundr_secs = create_init_spinner(hbox, 0, 99, _("Hundredths:"), 2, ui);
1298 
1299  /* add button */
1300  GtkWidget *add_button = wh_create_cool_button(GTK_STOCK_ADD, _("_Add"), FALSE);
1301  ui->gui->add_button = add_button;
1302 
1303  gtk_button_set_relief(GTK_BUTTON(add_button), GTK_RELIEF_NONE);
1304  gtk_widget_set_sensitive(add_button, TRUE);
1305  g_signal_connect(G_OBJECT(add_button), "clicked", G_CALLBACK(add_row_clicked), ui);
1306  gtk_box_pack_start(GTK_BOX(hbox), add_button, FALSE, FALSE, 5);
1307  gtk_widget_set_tooltip_text(add_button,_("Add splitpoint"));
1308 
1309  /* remove row button */
1310  GtkWidget *remove_row_button = wh_create_cool_button(GTK_STOCK_REMOVE, _("_Remove"), FALSE);
1311  ui->gui->remove_row_button = remove_row_button;
1312 
1313  gtk_button_set_relief(GTK_BUTTON(remove_row_button), GTK_RELIEF_NONE);
1314  gtk_widget_set_sensitive(remove_row_button, FALSE);
1315  g_signal_connect(G_OBJECT(remove_row_button), "clicked", G_CALLBACK(remove_row), ui);
1316  gtk_box_pack_start(GTK_BOX(hbox), remove_row_button, FALSE, FALSE, 5);
1317  gtk_widget_set_tooltip_text(remove_row_button, _("Remove rows"));
1318 
1319  /* remove all rows button */
1320  GtkWidget *remove_all_button = wh_create_cool_button(GTK_STOCK_CLEAR, _("R_emove all"), FALSE);
1321  ui->gui->remove_all_button = remove_all_button;
1322 
1323  gtk_button_set_relief(GTK_BUTTON(remove_all_button), GTK_RELIEF_NONE);
1324  gtk_widget_set_sensitive(remove_all_button, FALSE);
1325  g_signal_connect(G_OBJECT(remove_all_button), "clicked", G_CALLBACK(remove_all_rows), ui);
1326  gtk_box_pack_start(GTK_BOX(hbox), remove_all_button, FALSE, FALSE, 5);
1327  gtk_widget_set_tooltip_text(remove_all_button, _("Remove all rows"));
1328 
1329  return hbox;
1330 }
1331 
1333 static void create_init_special_buttons(ui_state *ui)
1334 {
1335  /* set splitpoints from trim silence detection */
1336  GtkWidget *scan_trim_silence_button =
1337  wh_create_cool_button(GTK_STOCK_CUT, _("_Trim splitpoints"), FALSE);
1338  ui->gui->scan_trim_silence_button = scan_trim_silence_button;
1339  gtk_widget_set_sensitive(scan_trim_silence_button, TRUE);
1340  g_signal_connect(G_OBJECT(scan_trim_silence_button), "clicked",
1341  G_CALLBACK(create_trim_silence_window), ui);
1342  gtk_widget_set_tooltip_text(scan_trim_silence_button,
1343  _("Set trim splitpoints using silence detection"));
1344 
1345  /* set splitpoints from silence detection */
1346  GtkWidget *scan_silence_button =
1347  wh_create_cool_button(GTK_STOCK_FIND_AND_REPLACE, _("_Silence detection"), FALSE);
1348  ui->gui->scan_silence_button = scan_silence_button;
1349  gtk_widget_set_sensitive(scan_silence_button, TRUE);
1350  g_signal_connect(G_OBJECT(scan_silence_button), "clicked",
1352  gtk_widget_set_tooltip_text(scan_silence_button,
1353  _("Set splitpoints from silence detection"));
1354 }
1355 
1360 gchar *get_splitpoint_name(gint index, ui_state *ui)
1361 {
1362  GtkTreeModel *model = gtk_tree_view_get_model(ui->gui->tree_view);
1363 
1364  gchar *description = NULL;
1365 
1366  GtkTreeIter iter;
1367  if (!gtk_tree_model_get_iter_first(model, &iter))
1368  {
1369  return NULL;
1370  }
1371 
1372  if (index == -1)
1373  {
1374  index = 0;
1375  }
1376 
1377  if (index >= 0)
1378  {
1379  GtkTreePath *path = gtk_tree_path_new_from_indices(index ,-1);
1380  gtk_tree_model_get_iter(model, &iter, path);
1381  gtk_tree_model_get(GTK_TREE_MODEL(model), &iter,
1382  COL_DESCRIPTION,&description,
1383  -1);
1384  gtk_tree_path_free(path);
1385  }
1386 
1387  return description;
1388 }
1389 
1391 gint get_splitpoint_time(gint splitpoint_index, ui_state *ui)
1392 {
1393  if (splitpoint_index < 0 ||
1394  splitpoint_index >= ui->splitpoints->len)
1395  {
1396  return -1;
1397  }
1398 
1399  Split_point point = g_array_index(ui->splitpoints, Split_point, splitpoint_index);
1400  return point.mins * 6000 + point.secs * 100 + point.hundr_secs;
1401 }
1402 
1403 static gboolean split_preview_end(ui_with_err *ui_err)
1404 {
1405  gint err = ui_err->err;
1406  ui_state *ui = ui_err->ui;
1407 
1409 
1410  gchar *split_file = get_filename_from_split_files(1, ui->gui);
1411  if (split_file != NULL && err > 0)
1412  {
1413  connect_button_event(ui->gui->connect_button, ui);
1414 
1415  change_current_filename(split_file, ui);
1416  g_free(split_file);
1417 
1418  //0 means start playing
1420  }
1421 
1422  if (err > 0)
1423  {
1424  gtk_progress_bar_set_fraction(ui->gui->percent_progress_bar, 1.0);
1425  gtk_progress_bar_set_text(ui->gui->percent_progress_bar, _(" finished"));
1426  }
1427 
1428  set_process_in_progress_and_wait_safe(FALSE, ui_err->ui);
1429 
1430  g_free(ui_err);
1431 
1432  return FALSE;
1433 }
1434 
1435 static gpointer split_preview(ui_state *ui)
1436 {
1437  set_process_in_progress_and_wait_safe(TRUE, ui);
1438 
1439  int err = 0;
1440  mp3splt_erase_all_splitpoints(ui->mp3splt_state, &err);
1441  mp3splt_erase_all_tags(ui->mp3splt_state, &err);
1442 
1443  enter_threads();
1444 
1445  mp3splt_append_splitpoint(ui->mp3splt_state, get_preview_start_position_safe(ui),
1446  "preview", SPLT_SPLITPOINT);
1447 
1448  mp3splt_append_splitpoint(ui->mp3splt_state,
1449  get_splitpoint_time(get_quick_preview_end_splitpoint_safe(ui), ui),
1450  NULL, SPLT_SKIPPOINT);
1451 
1452  lock_mutex(&ui->variables_mutex);
1453  mp3splt_set_filename_to_split(ui->mp3splt_state, get_input_filename(ui->gui));
1454  unlock_mutex(&ui->variables_mutex);
1455 
1456  mp3splt_set_int_option(ui->mp3splt_state, SPLT_OPT_OUTPUT_FILENAMES, SPLT_OUTPUT_CUSTOM);
1457  mp3splt_set_int_option(ui->mp3splt_state, SPLT_OPT_SPLIT_MODE, SPLT_OPTION_NORMAL_MODE);
1458 
1461 
1462  exit_threads();
1463 
1464  gchar *fname_path = get_preferences_filename();
1465  fname_path[strlen(fname_path) - 18] = '\0';
1466  mp3splt_set_path_of_split(ui->mp3splt_state, fname_path);
1467  if (fname_path) { g_free(fname_path); }
1468 
1469  err = mp3splt_split(ui->mp3splt_state);
1470 
1471  ui_with_err *ui_err = g_malloc0(sizeof(ui_with_err));
1472  ui_err->err = err;
1473  ui_err->ui = ui;
1474 
1475  gdk_threads_add_idle_full(G_PRIORITY_HIGH_IDLE, (GSourceFunc)split_preview_end, ui_err, NULL);
1476 
1477  return NULL;
1478 }
1479 
1480 static void split_preview_action(ui_state *ui)
1481 {
1482  create_thread((GThreadFunc)split_preview, ui);
1483 }
1484 
1486 static void preview_song(GtkTreeView *tree_view, GtkTreePath *path,
1487  GtkTreeViewColumn *col, ui_state *ui)
1488 {
1489  gint number = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(col), "col"));
1490  if (number != COL_PREVIEW && number != COL_SPLIT_PREVIEW)
1491  {
1492  return;
1493  }
1494 
1495  if (!ui->status->timer_active)
1496  {
1497  put_status_message(_(" cannot preview, not connected to player"), ui);
1498  return;
1499  }
1500 
1501  //get the split begin position to find the end position
1502  gint preview_row = gtk_tree_path_get_indices(path)[0];
1503  ui->status->preview_row = preview_row;
1504  if (number == COL_PREVIEW)
1505  {
1506  player_quick_preview(preview_row, ui);
1507  }
1508  else if (number == COL_SPLIT_PREVIEW)
1509  {
1510  set_preview_start_position_safe(get_splitpoint_time(preview_row, ui), ui);
1511  set_quick_preview_end_splitpoint_safe(preview_row + 1, ui);
1512 
1513  if (ui->status->preview_row + 1 == ui->infos->splitnumber)
1514  {
1515  put_status_message(_(" cannot split preview last splitpoint"), ui);
1516  return;
1517  }
1518 
1519  split_preview_action(ui);
1520  }
1521 }
1522 
1524 static void toggled_splitpoint_event(GtkCellRendererToggle *cell,
1525  gchar *path_str, ui_state *ui)
1526 {
1527  GtkTreeModel *model = gtk_tree_view_get_model(ui->gui->tree_view);
1528  GtkTreePath *path = gtk_tree_path_new_from_string(path_str);
1529  gboolean checked = FALSE;
1530 
1531  GtkTreeIter iter;
1532  gtk_tree_model_get_iter(model, &iter, path);
1533  gtk_tree_model_get(model, &iter, COL_CHECK, &checked, -1);
1534 
1535  //toggle the value
1536  checked ^= 1;
1537 
1538  //get the indice
1539  gint index = gtk_tree_path_get_indices (path)[0];
1540  Split_point new_point;
1541  Split_point old_point;
1542 
1543  //put new 'checked' value to splitpoint
1544  old_point = g_array_index(ui->splitpoints, Split_point, index);
1545  new_point.mins = old_point.mins;
1546  new_point.secs = old_point.secs;
1547  new_point.hundr_secs = old_point.hundr_secs;
1548  new_point.checked = checked;
1549 
1550  update_splitpoint(index, new_point, ui);
1551 
1552  gtk_tree_path_free(path);
1553 }
1554 
1556 static void create_columns(ui_state *ui)
1557 {
1558  gui_state *gui = ui->gui;
1559 
1560  GtkTreeView *tree_view = gui->tree_view;
1561 
1562  GtkCellRendererText *renderer;
1563  GtkCellRendererPixbuf *renderer_pix;
1564  GtkCellRendererToggle *renderer_toggle;
1565 
1566  GtkTreeViewColumn *column_number;
1567  GtkTreeViewColumn *column_check = NULL;
1568  GtkTreeViewColumn *column_description;
1569  GtkTreeViewColumn *column_hundr_secs;
1570  GtkTreeViewColumn *column_minutes;
1571  GtkTreeViewColumn *column_seconds;
1572  GtkTreeViewColumn *column_preview;
1573  GtkTreeViewColumn *column_split_preview;
1574 
1575  /* Check point / skip point */
1576  renderer_toggle = GTK_CELL_RENDERER_TOGGLE(gtk_cell_renderer_toggle_new());
1577  g_signal_connect(renderer_toggle, "toggled", G_CALLBACK(toggled_splitpoint_event), ui);
1578  g_object_set_data(G_OBJECT(renderer_toggle), "col", GINT_TO_POINTER(COL_CHECK));
1579  column_check = gtk_tree_view_column_new_with_attributes
1580  (_("Keep"), GTK_CELL_RENDERER(renderer_toggle), "active", COL_CHECK, NULL);
1581 
1582  /* description */
1583  renderer = GTK_CELL_RENDERER_TEXT(gtk_cell_renderer_text_new());
1584  g_signal_connect(renderer, "edited", G_CALLBACK(cell_edited_event), ui);
1585  g_object_set(renderer, "editable", TRUE, NULL);
1586  g_object_set_data(G_OBJECT(renderer), "col", GINT_TO_POINTER(COL_DESCRIPTION));
1587  column_description = gtk_tree_view_column_new_with_attributes
1588  (_("Filename"), GTK_CELL_RENDERER(renderer), "text", COL_DESCRIPTION, NULL);
1589 
1590  /* seconds */
1591  renderer = GTK_CELL_RENDERER_TEXT(gtk_cell_renderer_text_new());
1592  g_signal_connect(renderer, "edited", G_CALLBACK(cell_edited_event), ui);
1593  g_object_set(renderer, "editable", TRUE, NULL);
1594  g_object_set_data(G_OBJECT(renderer), "col", GINT_TO_POINTER(COL_SECONDS));
1595  column_seconds = gtk_tree_view_column_new_with_attributes
1596  (_("Secs"), GTK_CELL_RENDERER(renderer), "text", COL_SECONDS, NULL);
1597 
1598  /* minutes */
1599  renderer = GTK_CELL_RENDERER_TEXT(gtk_cell_renderer_text_new());
1600  g_signal_connect(renderer, "edited", G_CALLBACK(cell_edited_event), ui);
1601  g_object_set(renderer, "editable", TRUE, NULL);
1602  g_object_set_data(G_OBJECT(renderer), "col", GINT_TO_POINTER(COL_MINUTES));
1603  column_minutes = gtk_tree_view_column_new_with_attributes
1604  (_("Mins"), GTK_CELL_RENDERER(renderer), "text", COL_MINUTES, NULL);
1605 
1606  /* hundr secs */
1607  renderer = GTK_CELL_RENDERER_TEXT(gtk_cell_renderer_text_new());
1608  g_signal_connect(renderer, "edited", G_CALLBACK(cell_edited_event), ui);
1609  g_object_set(renderer, "editable", TRUE, NULL);
1610  g_object_set_data(G_OBJECT(renderer), "col", GINT_TO_POINTER(COL_HUNDR_SECS));
1611  column_hundr_secs = gtk_tree_view_column_new_with_attributes
1612  (_("Hundr"), GTK_CELL_RENDERER(renderer), "text", COL_HUNDR_SECS, NULL);
1613 
1614  /* Length column */
1615  //renderer creation
1616  renderer = GTK_CELL_RENDERER_TEXT(gtk_cell_renderer_text_new());
1617  g_object_set(G_OBJECT (renderer), "xalign", 1.0, NULL);
1618  g_object_set_data(G_OBJECT(renderer), "col", GINT_TO_POINTER(COL_NUMBER));
1619  column_number = gtk_tree_view_column_new_with_attributes
1620  (_("Length"), GTK_CELL_RENDERER(renderer), "text", COL_NUMBER, NULL);
1621 
1622  /* column preview */
1623  renderer_pix = GTK_CELL_RENDERER_PIXBUF(gtk_cell_renderer_pixbuf_new());
1624  g_object_set(renderer_pix,"stock-id",GTK_STOCK_MEDIA_PLAY,
1625  "stock-size",GTK_ICON_SIZE_MENU,NULL);
1626  column_preview = gtk_tree_view_column_new_with_attributes
1627  (_("LiveP"), GTK_CELL_RENDERER(renderer_pix), "pixbuf",COL_PREVIEW, NULL);
1628  g_object_set_data(G_OBJECT(column_preview), "col", GINT_TO_POINTER(COL_PREVIEW));
1629 
1630  /* split preview */
1631  renderer_pix = GTK_CELL_RENDERER_PIXBUF(gtk_cell_renderer_pixbuf_new());
1632  g_object_set(renderer_pix,"stock-id",GTK_STOCK_MEDIA_PLAY,
1633  "stock-size",GTK_ICON_SIZE_MENU,NULL);
1634  column_split_preview = gtk_tree_view_column_new_with_attributes
1635  (_("SplitP"), GTK_CELL_RENDERER(renderer_pix), "pixbuf",COL_SPLIT_PREVIEW, NULL);
1636  g_object_set_data(G_OBJECT(column_split_preview), "col", GINT_TO_POINTER(COL_SPLIT_PREVIEW));
1637 
1638  gtk_tree_view_insert_column(GTK_TREE_VIEW(tree_view), column_check, COL_CHECK);
1639  gtk_tree_view_insert_column(GTK_TREE_VIEW(tree_view), column_description, COL_DESCRIPTION);
1640  gtk_tree_view_insert_column(GTK_TREE_VIEW(tree_view), column_minutes, COL_MINUTES);
1641  gtk_tree_view_insert_column(GTK_TREE_VIEW(tree_view), column_seconds, COL_SECONDS);
1642  gtk_tree_view_insert_column(GTK_TREE_VIEW(tree_view), column_hundr_secs, COL_HUNDR_SECS);
1643  gtk_tree_view_insert_column(GTK_TREE_VIEW(tree_view), column_number, COL_NUMBER);
1644  gtk_tree_view_insert_column(GTK_TREE_VIEW(tree_view), column_preview, COL_PREVIEW);
1645  gtk_tree_view_insert_column(GTK_TREE_VIEW(tree_view), column_split_preview, COL_SPLIT_PREVIEW);
1646 
1647  gtk_tree_view_column_set_alignment(column_check, 0.5);
1648  gtk_tree_view_column_set_alignment(column_description, 0.5);
1649  gtk_tree_view_column_set_alignment(column_minutes, 0.5);
1650  gtk_tree_view_column_set_alignment(column_seconds, 0.5);
1651  gtk_tree_view_column_set_alignment(column_hundr_secs, 0.5);
1652  gtk_tree_view_column_set_alignment(column_number, 0.5);
1653  gtk_tree_view_column_set_alignment(column_preview, 0.5);
1654  gtk_tree_view_column_set_alignment(column_split_preview, 0.5);
1655 
1656  gtk_tree_view_column_set_sizing(column_check, GTK_TREE_VIEW_COLUMN_FIXED);
1657  gtk_tree_view_column_set_fixed_width(column_check, 70);
1658 
1659  gtk_tree_view_column_set_resizable(column_description, TRUE);
1660 
1661  gtk_tree_view_column_set_reorderable(column_check, TRUE);
1662  gtk_tree_view_column_set_reorderable(column_description, TRUE);
1663  gtk_tree_view_column_set_reorderable(column_minutes, TRUE);
1664  gtk_tree_view_column_set_reorderable(column_seconds, TRUE);
1665  gtk_tree_view_column_set_reorderable(column_hundr_secs, TRUE);
1666  gtk_tree_view_column_set_reorderable(column_number, TRUE);
1667  gtk_tree_view_column_set_reorderable(column_preview, TRUE);
1668  gtk_tree_view_column_set_reorderable(column_split_preview, TRUE);
1669 
1670  gtk_tree_view_column_set_expand(column_description, TRUE);
1671 }
1672 
1674 static void create_tree_view(ui_state *ui)
1675 {
1676  GtkTreeView *tree_view = GTK_TREE_VIEW(gtk_tree_view_new_with_model(create_model()));
1677  dnd_add_drag_data_received_to_widget(GTK_WIDGET(tree_view), DND_DATA_FILES, ui);
1678 
1679  ui->gui->tree_view = tree_view;
1680 
1681  g_signal_connect(tree_view, "row-activated", G_CALLBACK(preview_song), ui);
1682 
1683  GtkTreeSelection *selection = gtk_tree_view_get_selection(tree_view);
1684  g_signal_connect(selection, "changed", G_CALLBACK(row_selection_event), ui);
1685 }
1686 
1693 {
1694  gui_state *gui = ui->gui;
1695 
1696  create_tree_view(ui);
1697 
1698  /* choose splitpoins vbox */
1699  GtkWidget *choose_splitpoints_vbox = wh_vbox_new();
1700  gtk_container_set_border_width(GTK_CONTAINER(choose_splitpoints_vbox), 0);
1701 
1702  /* spinner buttons hbox */
1703  GtkWidget *spinners_buttons_hbox = create_init_spinners_buttons(ui);
1704  gtk_box_pack_start(GTK_BOX(choose_splitpoints_vbox), spinners_buttons_hbox, FALSE, FALSE, 3);
1705 
1706  /* horizontal box for the tree */
1707  GtkWidget *tree_hbox = wh_hbox_new();
1708  gtk_box_pack_start(GTK_BOX(choose_splitpoints_vbox), tree_hbox, TRUE, TRUE, 0);
1709 
1710  /* scrolled window for the tree */
1711  GtkWidget *scrolled_window = gtk_scrolled_window_new(NULL, NULL);
1712  gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW(scrolled_window), GTK_SHADOW_NONE);
1713  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
1714  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1715  gtk_box_pack_start(GTK_BOX(tree_hbox), scrolled_window, TRUE, TRUE, 0);
1716 
1717  GtkTreeSelection *selection = gtk_tree_view_get_selection(gui->tree_view);
1718  gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE);
1719  create_columns(ui);
1720  gtk_container_add(GTK_CONTAINER(scrolled_window), GTK_WIDGET(gui->tree_view));
1721 
1722  /* special buttons like 'set silence from silence detection' */
1723  create_init_special_buttons(ui);
1724 
1725  return choose_splitpoints_vbox;
1726 }
1727 
1728 static void garray_to_array(GArray *spltpoints, glong *hundredth, ui_state *ui)
1729 {
1730  gint i = 0;
1731  for(i = 0; i < ui->infos->splitnumber; i++ )
1732  {
1733  Split_point point = g_array_index(ui->splitpoints, Split_point, i);
1734  if (point.mins >= (INT_MAX-1)/6000)
1735  {
1736  hundredth[i] = LONG_MAX;
1737  }
1738  else
1739  {
1740  hundredth[i] = point.mins * 6000 +
1741  point.secs * 100 + point.hundr_secs;
1742  }
1743  }
1744 }
1745 
1748 {
1749  glong hundr[ui->infos->splitnumber];
1750  garray_to_array(ui->splitpoints, hundr, ui);
1751 
1752  GtkTreeModel *model = gtk_tree_view_get_model(ui->gui->tree_view);
1753 
1754  gint i;
1755  for (i = 0; i < ui->infos->splitnumber; i++)
1756  {
1757  GtkTreePath *path = gtk_tree_path_new_from_indices(i ,-1);
1758  GtkTreeIter iter;
1759  gtk_tree_model_get_iter(model, &iter, path);
1760  gchar *description = NULL;
1761  gtk_tree_model_get(GTK_TREE_MODEL(model), &iter,
1762  COL_DESCRIPTION,&description,
1763  -1);
1764 
1765  //get the 'checked' value from the current splitpoint
1766  Split_point point = g_array_index(ui->splitpoints, Split_point, i);
1767  gint splitpoint_type = SPLT_SPLITPOINT;
1768 
1769  if (point.checked == FALSE)
1770  {
1771  splitpoint_type = SPLT_SKIPPOINT;
1772  }
1773 
1774  mp3splt_append_splitpoint(state,hundr[i], description, splitpoint_type);
1775 
1776  gtk_tree_path_free(path);
1777  }
1778 }
1779 
1780