commit 400e3393ae7c565ecaca350ef3e96d73e6e0bd18
Author: phantomjinx <[email protected]>
Date: Fri Dec 9 22:01:25 2011 +0000
Fix for restoring functionality of track normalization
* Ensure that internal soundcheck functions populate a GError rather than
displaying a warning dialog. The latter does not work well inside threads!
* Save up all error messages until the end of the normalization run
* Use the platform progress bar rather than bringing up a custom dialog
* Provide the action for normalizing a playlist to the playlist plugins
menus.
libgtkpod/file.c | 26 ++--
libgtkpod/file.h | 2 +-
libgtkpod/tools.c | 221 ++++++++++----------
plugins/playlist_display/playlist_display.ui | 1 +
.../playlist_display/playlist_display_actions.c | 12 +
.../playlist_display/playlist_display_actions.h | 1 +
plugins/playlist_display/plugin.c | 8 +
plugins/track_display/plugin.c | 12 +-
8 files changed, 153 insertions(+), 130 deletions(-)
---
diff --git a/libgtkpod/file.c b/libgtkpod/file.c
index 6551145..7f3b3cc 100644
--- a/libgtkpod/file.c
+++ b/libgtkpod/file.c
@@ -2056,35 +2056,35 @@ void parse_offline_playcount(void) {
*
* Return value: TRUE, if gain could be read
*/
-gboolean read_soundcheck(Track *track) {
- gchar *path;
+gboolean read_soundcheck(Track *track, GError **error) {
+ gchar *path, *buf;
FileType *filetype;
gboolean result = FALSE;
- GError *error = NULL;
- gchar *msg = g_strdup_printf(_("Failed to read sound check from track
because"));
g_return_val_if_fail (track, FALSE);
path = get_file_name_from_source(track, SOURCE_PREFER_LOCAL);
+ if (!path) {
+ buf = g_strdup_printf(_("Failed to read sound check from track with no
path setting."));
+ gtkpod_log_error(error, buf);
+ g_free(buf);
+ return FALSE;
+ }
+
filetype = determine_filetype(path);
if (! filetype) {
- gtkpod_warning(_("%s\n\nfiletype of %s is not recognised."), msg,
path);
+ buf = g_strdup_printf(_("Failed to read sound check from track because
filetype is not recognised."));
+ gtkpod_log_error(error, buf);
+ g_free(buf);
}
else {
- if (!filetype_read_soundcheck(filetype, path, track, &error)) {
- if (error) {
- gtkpod_warning(_("%s\n\n%s"), msg, error->message);
- } else {
- gtkpod_warning(_("%s\n\n%s"), msg, UNKNOWN_ERROR);
- }
- } else {
+ if (filetype_read_soundcheck(filetype, path, track, error)) {
// track read successfully
result = TRUE;
}
}
g_free(path);
- g_free(msg);
return result;
}
diff --git a/libgtkpod/file.h b/libgtkpod/file.h
index 01ba239..e62e71b 100644
--- a/libgtkpod/file.h
+++ b/libgtkpod/file.h
@@ -89,7 +89,7 @@ void gp_info_deleted_tracks (iTunesDB *itdb,
void update_charset_info (Track *track);
void parse_offline_playcount (void);
-gboolean read_soundcheck (Track *track);
+gboolean read_soundcheck (Track *track, GError **error);
gboolean read_lyrics_from_file (Track *track, gchar **lyrics);
gboolean write_lyrics_to_file (Track *track);
diff --git a/libgtkpod/tools.c b/libgtkpod/tools.c
index 0fa6e19..ae90ad8 100644
--- a/libgtkpod/tools.c
+++ b/libgtkpod/tools.c
@@ -33,6 +33,7 @@
#include "misc.h"
#include "misc_track.h"
#include "prefs.h"
+#include "gp_private.h"
#include "tools.h"
#include <errno.h>
#include <fcntl.h>
@@ -44,6 +45,12 @@
#include <unistd.h>
#include <glib/gi18n-lib.h>
+/* Structure to keep all necessary information */
+struct nm {
+ Track *track; /* track to be normalised */
+ GError *error; /* Errors generated during the normalisation */
+};
+
/*pipe's definition*/
enum {
READ = 0, WRITE = 1
@@ -75,10 +82,11 @@ static gboolean mutex_data = FALSE;
* Return value: TRUE if the command ran successfully, FALSE if any
* error occurred.
*/
-static gboolean run_exec_on_track(const gchar *commandline, const gchar
*track_path) {
+static gboolean run_exec_on_track(const gchar *commandline, const gchar
*track_path, GError **error) {
gchar *command_full_path = NULL;
gchar *command = NULL;
gchar *command_base = NULL;
+ gchar *buf;
const gchar *nextarg;
gboolean success = FALSE;
gboolean percs = FALSE;
@@ -105,7 +113,9 @@ static gboolean run_exec_on_track(const gchar *commandline,
const gchar *track_p
command_full_path = g_find_program_in_path(command);
if (!command_full_path) {
- gtkpod_warning(_("Could not find '%s'.\nPlease specifiy the exact path
in the Tools section of the preference dialog or install the program if it is
not installed on your system.\n\n"), command);
+ buf = g_strdup_printf(_("Could not find '%s'.\nPlease specifiy the
exact path in the Tools section of the preference dialog or install the program
if it is not installed on your system.\n\n"), command);
+ gtkpod_log_error(error, buf);
+ g_free(buf);
goto cleanup;
}
@@ -187,7 +197,9 @@ static gboolean run_exec_on_track(const gchar *commandline,
const gchar *track_p
else
ret = 2;
if (ret > 1) {
- gtkpod_warning(_("Execution of '%s' failed.\n\n"),
command_full_path);
+ buf = g_strdup_printf(_("Execution of '%s' failed.\n\n"),
command_full_path);
+ gtkpod_log_error(error, buf);
+ g_free(buf);
}
else {
success = TRUE;
@@ -203,38 +215,44 @@ static gboolean run_exec_on_track(const gchar
*commandline, const gchar *track_p
}
/* reread the soundcheck value from the file */
-static gboolean nm_get_soundcheck(Track *track) {
- gchar *path;
+static gboolean nm_get_soundcheck(Track *track, GError **error) {
+ gchar *path, *buf;
gchar *commandline = NULL;
FileType *filetype;
g_return_val_if_fail (track, FALSE);
- if (read_soundcheck(track))
+ if (read_soundcheck(track, error))
return TRUE;
+ if (error && *error)
+ return FALSE;
+
path = get_file_name_from_source(track, SOURCE_PREFER_LOCAL);
filetype = determine_filetype(path);
if (!path || !filetype) {
- gchar *buf = get_track_info(track, FALSE);
- gtkpod_warning(_("Normalization failed: file not available
(%s).\n\n"), buf);
+ buf = get_track_info(track, FALSE);
+ buf = g_strdup_printf(_("Normalization failed: file not available
(%s)."), buf);
+ gtkpod_log_error(error, buf);
g_free(buf);
return FALSE;
}
commandline = filetype_get_gain_cmd(filetype);
if (commandline) {
- if (run_exec_on_track(commandline, path)) {
+ if (run_exec_on_track(commandline, path, error)) {
g_free(path);
- return read_soundcheck(track);
+ return read_soundcheck(track, error);
}
}
else {
- gtkpod_warning(_("Normalization failed for file %s: file type not
supported.\n"
- "To normalize mp3 and aac files ensure the following commands
paths have been set in the Tools section\n"
- "\tmp3 files: mp3gain\n"
+ buf = g_strdup_printf(_("Normalization failed for file %s: file type
not supported."
+ "To normalize mp3 and aac files ensure the following commands
paths have been set in the Tools section"
+ "\tmp3 files: mp3gain"
"\taac files: aacgain"), path);
+ gtkpod_log_error(error, buf);
+ g_free(buf);
}
return FALSE;
@@ -242,8 +260,9 @@ static gboolean nm_get_soundcheck(Track *track) {
#ifdef G_THREADS_ENABLED
/* Threaded getTrackGain*/
-static gpointer th_nm_get_soundcheck(gpointer track) {
- gboolean success = nm_get_soundcheck((Track *) track);
+static gpointer th_nm_get_soundcheck(gpointer data) {
+ struct nm *nm = data;
+ gboolean success = nm_get_soundcheck(nm->track, &(nm->error));
g_mutex_lock (mutex);
mutex_data = TRUE; /* signal that thread will end */
g_cond_signal (cond);
@@ -270,20 +289,36 @@ void nm_new_tracks(iTunesDB *itdb) {
g_list_free(tracks);
}
-static void normalization_abort(gboolean *abort) {
- *abort = TRUE;
+static void nm_report_errors_and_free(GString *errors) {
+ if (errors && errors->len > 0) {
+ gtkpod_confirmation(-1, /* gint id, */
+ TRUE, /* gboolean modal, */
+ _("Normalization Errors"), /* title */
+ _("Errors created by track normalisation"), /* label */
+ errors->str, /* scrolled text */
+ NULL, 0, NULL, /* option 1 */
+ NULL, 0, NULL, /* option 2 */
+ TRUE, /* gboolean confirm_again, */
+ "show_normalization_errors",/* confirm_again_key,*/
+ CONF_NULL_HANDLER, /* ConfHandler ok_handler,*/
+ NULL, /* don't show "Apply" button */
+ NULL, /* cancel_handler,*/
+ NULL, /* gpointer user_data1,*/
+ NULL); /* gpointer user_data2,*/
+
+ g_string_free(errors, TRUE);
+ }
}
void nm_tracks_list(GList *list) {
gint count, succ_count, n;
+ gdouble fraction = 0;
+ gdouble old_fraction = 0;
guint32 old_soundcheck;
gboolean success;
- static gboolean abort;
- GtkWidget *dialog, *progress_bar, *label, *track_label;
- GtkWidget *image, *hbox;
- GtkWidget *content_area;
- time_t diff, start, fullsecs, hrs, mins, secs;
gchar *progtext = NULL;
+ struct nm *nm;
+ GString *errors = g_string_new(""); /* Errors generated during the
normalisation */
#ifdef G_THREADS_ENABLED
GThread *thread = NULL;
@@ -296,46 +331,6 @@ void nm_tracks_list(GList *list) {
block_widgets();
- /* create the dialog window */
- dialog
- = gtk_dialog_new_with_buttons(_("Information"), GTK_WINDOW
(gtkpod_app), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_CANCEL,
GTK_RESPONSE_NONE, NULL);
-
- /* emulate gtk_message_dialog_new */
- image = gtk_image_new_from_stock(GTK_STOCK_DIALOG_INFO,
GTK_ICON_SIZE_DIALOG);
- label = gtk_label_new(_("Press button to abort."));
-
- gtk_misc_set_alignment(GTK_MISC (image), 0.5, 0.0);
- gtk_label_set_line_wrap(GTK_LABEL (label), TRUE);
- gtk_label_set_selectable(GTK_LABEL (label), TRUE);
-
- /* hbox to put the image+label in */
- hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6);
- gtk_box_pack_start(GTK_BOX (hbox), image, FALSE, FALSE, 0);
- gtk_box_pack_start(GTK_BOX (hbox), label, FALSE, FALSE, 0);
-
- /* Create the progress bar */
- progress_bar = gtk_progress_bar_new();
- progtext = g_strdup(_("Normalizing..."));
- gtk_progress_bar_set_text(GTK_PROGRESS_BAR (progress_bar), progtext);
- g_free(progtext);
-
- /* Create label for track name */
- track_label = gtk_label_new(NULL);
- gtk_label_set_line_wrap(GTK_LABEL (label), TRUE);
- gtk_label_set_selectable(GTK_LABEL (label), TRUE);
-
- /* Indicate that user wants to abort */
- g_signal_connect_swapped (G_OBJECT (dialog), "response",
- G_CALLBACK (normalization_abort),
- &abort);
-
- /* Add the image/label + progress bar to dialog */
- content_area = gtk_dialog_get_content_area(GTK_DIALOG (dialog));
- gtk_box_pack_start(GTK_BOX (content_area), hbox, FALSE, FALSE, 0);
- gtk_box_pack_start(GTK_BOX (content_area), track_label, FALSE, FALSE, 0);
- gtk_box_pack_start(GTK_BOX (content_area), progress_bar, FALSE, FALSE, 0);
- gtk_widget_show_all(dialog);
-
while (widgets_blocked && gtk_events_pending())
gtk_main_iteration();
@@ -343,55 +338,36 @@ void nm_tracks_list(GList *list) {
n = g_list_length(list);
count = 0; /* tracks processed */
succ_count = 0; /* tracks normalized */
- abort = FALSE;
- start = time(NULL);
if (n == 0) {
- /* FIXME we should tell something*/
-
- }
- else {
- /* we need ***much*** longer timeout */
- g_message("TODO tools:nm_tracks_list - statusbar\n");
- // gtkpod_statusbar_timeout (30*STATUSBAR_TIMEOUT);
+ // nothing to do
+ return;
}
- while (!abort && (list != NULL)) {
- Track *track = list->data;
- gchar *label_buf = g_strdup_printf("%d/%d", count, n);
- gtk_label_set_text(GTK_LABEL (track_label), label_buf);
+ gtkpod_statusbar_reset_progress(100);
- g_message("TODO tools:nm_tracks_list - statusbar\n");
- // gtkpod_statusbar_message (_("%s - %s"),
- // track->artist, track->title);
- C_FREE (label_buf);
+ nm = g_malloc0(sizeof(struct nm));
+ while (list) {
+ nm->track = list->data;
+ nm->error = NULL;
while (widgets_blocked && gtk_events_pending())
gtk_main_iteration();
/* need to know so we can update the display when necessary */
- old_soundcheck = track->soundcheck;
+ old_soundcheck = nm->track->soundcheck;
#ifdef G_THREADS_ENABLED
mutex_data = FALSE;
- thread = g_thread_create (th_nm_get_soundcheck, track, TRUE, NULL);
+
+ thread = g_thread_create (th_nm_get_soundcheck, nm, TRUE, NULL);
if (thread) {
- gboolean first_abort = TRUE;
g_mutex_lock (mutex);
do {
while (widgets_blocked && gtk_events_pending())
gtk_main_iteration();
/* wait a maximum of 10 ms */
- if (abort && first_abort) {
- first_abort = FALSE;
- progtext = g_strdup(_("Aborting..."));
- gtk_progress_bar_set_text(GTK_PROGRESS_BAR (progress_bar),
progtext);
- g_free(progtext);
- gtkpod_statusbar_message(_("Will abort after current
mp3gain process ends."));
- while (widgets_blocked && gtk_events_pending())
- gtk_main_iteration();
- }
g_get_current_time(>ime);
g_time_val_add(>ime, 20000);
g_cond_timed_wait (cond, mutex, >ime);
@@ -402,54 +378,69 @@ void nm_tracks_list(GList *list) {
}
else {
g_warning ("Thread creation failed, falling back to default.\n");
- success = nm_get_soundcheck(track);
+ success = nm_get_soundcheck(nm->track, &(nm->error));
+
}
#else
- success = nm_get_soundcheck (track);
+ success = nm_get_soundcheck (nm->track, nm->error);
#endif
/*normalization part*/
if (!success) {
- gchar *path = get_file_name_from_source(track,
SOURCE_PREFER_LOCAL);
- gtkpod_warning(_("'%s-%s' (%s) could not be normalized.\n\n"),
track->artist, track->title, path ? path : "");
+ gchar *path = get_file_name_from_source(nm->track,
SOURCE_PREFER_LOCAL);
+
+ if (nm->error) {
+ errors = g_string_append(errors, g_strdup_printf(_("'%s-%s'
(%s) could not be normalized. %s\n"), nm->track->artist, nm->track->title, path
? path : "", nm->error->message));
+ }
+ else {
+ errors = g_string_append(errors, g_strdup_printf(_("'%s-%s'
(%s) could not be normalized. Unknown error.\n"), nm->track->artist,
nm->track->title, path ? path : ""));
+ }
+
g_free(path);
}
else {
++succ_count;
- if (old_soundcheck != track->soundcheck) {
- gtkpod_track_updated(track);
- data_changed(track->itdb);
+ if (old_soundcheck != nm->track->soundcheck) {
+ gtkpod_track_updated(nm->track);
+ data_changed(nm->track->itdb);
}
}
/*end normalization*/
++count;
- gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR (progress_bar),
(gdouble) count / n);
-
- diff = time(NULL) - start;
- fullsecs = (diff * n / count) - diff;
- hrs = fullsecs / 3600;
- mins = (fullsecs % 3600) / 60;
- secs = ((fullsecs % 60) / 5) * 5;
- /* don't bounce up too quickly (>10% change only) */
- /* left = ((mins < left) || (100*mins >= 110*left)) ? mins :
left;*/
- progtext = g_strdup_printf(_("%d%% (%d:%02d:%02d left)"), count * 100
/ n, (int) hrs, (int) mins, (int) secs);
- gtk_progress_bar_set_text(GTK_PROGRESS_BAR (progress_bar), progtext);
+ fraction = (gdouble) count / (gdouble) n;
+ progtext = g_strdup_printf(_("%d%% (%d tracks left)"), count * 100 /
n, n - count);
+
+ gdouble ticks = fraction - old_fraction;
+ gtkpod_statusbar_increment_progress_ticks(ticks * 100, progtext);
+
+ old_fraction = fraction;
g_free(progtext);
+ if (fraction == 1) {
+ /* All finished */
+ gtkpod_statusbar_reset_progress(100);
+ gtkpod_statusbar_message(ngettext ("Normalized %d of %d track.",
"Normalized %d of %d tracks.", n), count, n);
+ }
+
while (widgets_blocked && gtk_events_pending())
gtk_main_iteration();
+
list = g_list_next(list);
+
+ if (nm->error)
+ g_error_free(nm->error);
+
} /*end while*/
- g_message("TODO tools:nm_tracks_list - statusbar\n");
- // gtkpod_statusbar_timeout (0);
+ g_free(nm);
+
+ nm_report_errors_and_free(errors);
- // gtkpod_statusbar_message (ngettext ("Normalized %d of %d tracks.",
- // "Normalized %d of %d tracks.", n),
- // count, n);
+ gtkpod_statusbar_message (ngettext ("Normalized %d of %d tracks.",
+ "Normalized %d of %d tracks.", n),
+ count, n);
- gtk_widget_destroy(dialog);
release_widgets();
}
diff --git a/plugins/playlist_display/playlist_display.ui
b/plugins/playlist_display/playlist_display.ui
index 1b22e0d..178901c 100644
--- a/plugins/playlist_display/playlist_display.ui
+++ b/plugins/playlist_display/playlist_display.ui
@@ -36,6 +36,7 @@
<menuitem name="Selected Playlist"
action="ActionUpdatePlaylist" />
</menu>
<menuitem name="Sync Playlist with Dir(s)"
action="ActionSyncPlaylistWithDir"/>
+ <menuitem name="Normalize Playlist(s)"
action="ActionNormalizePlaylist"/>
</placeholder>
</menu>
<menu name="MenuEdit" action="ActionMenuEdit">
diff --git a/plugins/playlist_display/playlist_display_actions.c
b/plugins/playlist_display/playlist_display_actions.c
index 8f34f17..71e42de 100644
--- a/plugins/playlist_display/playlist_display_actions.c
+++ b/plugins/playlist_display/playlist_display_actions.c
@@ -43,6 +43,7 @@
#include "libgtkpod/misc_playlist.h"
#include "libgtkpod/file.h"
#include "libgtkpod/syncdir.h"
+#include "libgtkpod/tools.h"
#include <gdk/gdk.h>
/* Callback after directories to add have been selected */
@@ -703,3 +704,14 @@ void on_sync_playlists_with_dirs(GtkAction *action,
PlaylistDisplayPlugin* plugi
playlists = playlists->next;
}
}
+
+void on_normalize_selected_playlist (GtkMenuItem *menuitem, gpointer
user_data) {
+ GList *playlists = pm_get_selected_playlists();
+ while (playlists) {
+ Playlist *pl = playlists->data;
+ if (pl) {
+ nm_tracks_list (pl->members);
+ }
+ playlists = playlists->next;
+ }
+}
diff --git a/plugins/playlist_display/playlist_display_actions.h
b/plugins/playlist_display/playlist_display_actions.h
index 5d7b6d2..c1f6fc2 100644
--- a/plugins/playlist_display/playlist_display_actions.h
+++ b/plugins/playlist_display/playlist_display_actions.h
@@ -69,5 +69,6 @@ void
on_delete_selected_playlists_including_tracks_from_device(GtkAction *action
void on_update_selected_playlists (GtkAction *action, PlaylistDisplayPlugin*
plugin);
void on_sync_playlists_with_dirs(GtkAction *action, PlaylistDisplayPlugin*
plugin);
+void on_normalize_selected_playlist (GtkMenuItem *menuitem, gpointer
user_data);
#endif
diff --git a/plugins/playlist_display/plugin.c
b/plugins/playlist_display/plugin.c
index 407c55c..9ef7016 100644
--- a/plugins/playlist_display/plugin.c
+++ b/plugins/playlist_display/plugin.c
@@ -119,6 +119,14 @@ static GtkActionEntry playlist_actions[] =
G_CALLBACK (on_sync_playlists_with_dirs)
},
{
+ "ActionNormalizePlaylist",
+ GTK_STOCK_EXECUTE,
+ N_("Normalize"),
+ NULL,
+ NULL,
+ G_CALLBACK (on_normalize_selected_playlist)
+ },
+ {
ACTION_NEW_PLAYLIST_MENU,
NULL,
N_("_New Playlist"),
diff --git a/plugins/track_display/plugin.c b/plugins/track_display/plugin.c
index 69b0634..a0e1e65 100644
--- a/plugins/track_display/plugin.c
+++ b/plugins/track_display/plugin.c
@@ -36,6 +36,7 @@
#include "libgtkpod/gtkpod_app_iface.h"
#include "libgtkpod/gp_private.h"
#include "libgtkpod/prefs.h"
+#include "libgtkpod/tools.h"
#include "plugin.h"
#include "display_tracks.h"
#include "track_display_actions.h"
@@ -135,6 +136,8 @@ static gboolean activate_track_display_plugin(AnjutaPlugin
*plugin) {
gtk_widget_show_all(track_display_plugin->track_window);
anjuta_shell_add_widget(plugin->shell, track_display_plugin->track_window,
"TrackDisplayPlugin", _(" Playlist Tracks"), NULL, ANJUTA_SHELL_PLACEMENT_TOP,
NULL);
+ gtkpod_register_track_command(TRACK_COMMAND(track_display_plugin));
+
return TRUE; /* FALSE if activation failed */
}
@@ -211,8 +214,15 @@ static void
ipreferences_iface_init(IAnjutaPreferencesIface* iface) {
iface->unmerge = ipreferences_unmerge;
}
+static void track_command_iface_init(TrackCommandInterface *iface) {
+ iface->id = "track_display_normalise_track_command";
+ iface->text = _("Normalise");
+ iface->execute = nm_tracks_list;
+}
+
ANJUTA_PLUGIN_BEGIN (TrackDisplayPlugin, track_display_plugin);
- ANJUTA_PLUGIN_ADD_INTERFACE(ipreferences,
IANJUTA_TYPE_PREFERENCES);ANJUTA_PLUGIN_END
+ANJUTA_PLUGIN_ADD_INTERFACE(track_command, TRACK_COMMAND_TYPE);
+ANJUTA_PLUGIN_ADD_INTERFACE(ipreferences,
IANJUTA_TYPE_PREFERENCES);ANJUTA_PLUGIN_END
;
ANJUTA_SIMPLE_PLUGIN (TrackDisplayPlugin, track_display_plugin)
------------------------------------------------------------------------------
Learn Windows Azure Live! Tuesday, Dec 13, 2011
Microsoft is holding a special Learn Windows Azure training event for
developers. It will provide a great way to learn Windows Azure and what it
provides. You can attend the event by watching it streamed LIVE online.
Learn more at http://p.sf.net/sfu/ms-windowsazure
_______________________________________________
gtkpod-cvs2 mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/gtkpod-cvs2