[Rhythmbox-devel] [PATCH] Beats per Minute



Hi,

Here is a patch to make rhythmbox handle the BPM tag in files. The only
issue I have with this is that if you in the song info dialog enter BPM
59.99 for some reason it writes 59.00 to the tag. I can't find the cause
of this so I'm about to just live with it. But if someone who knows more
about rhythmbox can fix this I'd be happy.

I have also attached the patch to 
http://bugzilla.gnome.org/show_bug.cgi?id=454889

//Mattias
Index: rhythmdb/rhythmdb-private.h
===================================================================
--- rhythmdb/rhythmdb-private.h	(revision 5236)
+++ rhythmdb/rhythmdb-private.h	(arbetskopia)
@@ -95,6 +95,7 @@
 	double track_peak;
 	double album_gain;
 	double album_peak;
+	double bpm;
 	GDate date;
 
 	/* filesystem */
Index: rhythmdb/rhythmdb-tree.c
===================================================================
--- rhythmdb/rhythmdb-tree.c	(revision 5236)
+++ rhythmdb/rhythmdb-tree.c	(arbetskopia)
@@ -935,6 +935,9 @@
 		case RHYTHMDB_PROP_LOCATION:
 			save_entry_string(ctx, elt_name, rb_refstring_get (entry->location));
 			break;
+		case RHYTHMDB_PROP_BPM:
+			save_entry_double(ctx, elt_name, entry->bpm);
+			break;
 		case RHYTHMDB_PROP_MOUNTPOINT:
 			/* Avoid crashes on exit when upgrading from 0.8
 			 * and no mountpoint is available from some entries */
Index: rhythmdb/rhythmdb.c
===================================================================
--- rhythmdb/rhythmdb.c	(revision 5236)
+++ rhythmdb/rhythmdb.c	(arbetskopia)
@@ -361,6 +361,9 @@
 	case RHYTHMDB_PROP_ALBUM_PEAK:
 		*field = RB_METADATA_FIELD_ALBUM_PEAK;
 		return TRUE;
+	case RHYTHMDB_PROP_BPM:
+		*field = RB_METADATA_FIELD_BPM;
+		return TRUE;
 	case RHYTHMDB_PROP_MUSICBRAINZ_TRACKID:
 		*field = RB_METADATA_FIELD_MUSICBRAINZ_TRACKID;
 		return TRUE;
@@ -1619,6 +1622,15 @@
 					     RHYTHMDB_PROP_ALBUM_PEAK, &val);
 		g_value_unset (&val);
 	}
+	
+	/* beats per minute */
+	if (rb_metadata_get (metadata,
+			     RB_METADATA_FIELD_BPM,
+			     &val)) {
+		rhythmdb_entry_set_internal (db, entry, TRUE,
+					     RHYTHMDB_PROP_BPM, &val);
+		g_value_unset (&val);
+	}
 }
 
 static gboolean
@@ -2830,6 +2842,9 @@
 			entry->last_played = g_value_get_ulong (value);
 			entry->flags |= RHYTHMDB_ENTRY_LAST_PLAYED_DIRTY;
 			break;
+		case RHYTHMDB_PROP_BPM:
+			entry->bpm = g_value_get_double (value);
+			break;
 		case RHYTHMDB_PROP_MUSICBRAINZ_TRACKID:
 			rb_refstring_unref (entry->musicbrainz_trackid);
 			entry->musicbrainz_trackid = rb_refstring_new (g_value_get_string (value));
@@ -3649,6 +3664,7 @@
 			ENUM_ENTRY (RHYTHMDB_PROP_POST_TIME, "Podcast time of post (gulong) [post-time]"),
 
 			ENUM_ENTRY (RHYTHMDB_PROP_KEYWORD, "Keywords applied to track (gchararray) [keyword]"),
+			ENUM_ENTRY (RHYTHMDB_PROP_BPM, "Beats per minute (gdouble) [beats-per-minute]"),
 			{ 0, 0, 0 }
 		};
 		g_assert ((sizeof (values) / sizeof (values[0]) - 1) == RHYTHMDB_NUM_PROPERTIES);
@@ -4607,6 +4623,8 @@
 		return entry->album_peak;
 	case RHYTHMDB_PROP_RATING:
 		return entry->rating;
+	case RHYTHMDB_PROP_BPM:
+		return entry->bpm;
 	default:
 		g_assert_not_reached ();
 		return 0.0;
Index: rhythmdb/rhythmdb.h
===================================================================
--- rhythmdb/rhythmdb.h	(revision 5236)
+++ rhythmdb/rhythmdb.h	(arbetskopia)
@@ -181,6 +181,7 @@
 	RHYTHMDB_PROP_PLAYBACK_ERROR,
 	RHYTHMDB_PROP_FIRST_SEEN_STR,
 	RHYTHMDB_PROP_LAST_SEEN_STR,
+	RHYTHMDB_PROP_BPM,
 
 	/* synthetic properties */
 	RHYTHMDB_PROP_SEARCH_MATCH,
Index: sources/rb-playlist-source.c
===================================================================
--- sources/rb-playlist-source.c	(revision 5236)
+++ sources/rb-playlist-source.c	(arbetskopia)
@@ -286,6 +286,7 @@
 	rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_PLAY_COUNT, FALSE);
 	rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_LAST_PLAYED, FALSE);
 	rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_FIRST_SEEN, FALSE);
+	rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_BPM, FALSE);
 	rb_entry_view_set_columns_clickable (source->priv->songs, FALSE);
 
 	rb_playlist_source_setup_entry_view (source, source->priv->songs);
Index: sources/rb-browser-source.c
===================================================================
--- sources/rb-browser-source.c	(revision 5236)
+++ sources/rb-browser-source.c	(arbetskopia)
@@ -421,6 +421,7 @@
 	rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_DURATION, FALSE);
  	rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_QUALITY, FALSE);
 	rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_PLAY_COUNT, FALSE);
+	rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_BPM, FALSE);
 
 	g_signal_connect_object (G_OBJECT (source->priv->songs), "show_popup",
 				 G_CALLBACK (rb_browser_source_songs_show_popup_cb), source, 0);
Index: bindings/python/rb.defs
===================================================================
--- bindings/python/rb.defs	(revision 5236)
+++ bindings/python/rb.defs	(arbetskopia)
@@ -196,6 +196,7 @@
     '("first-seen" "RB_ENTRY_VIEW_COL_FIRST_SEEN")
     '("last-seen" "RB_ENTRY_VIEW_COL_LAST_SEEN")
     '("location" "RB_ENTRY_VIEW_COL_LOCATION")
+    '("bpm" "RB_ENTRY_VIEW_COL_BPM")
     '("error" "RB_ENTRY_VIEW_COL_ERROR")
   )
 )
Index: shell/rb-shell-preferences.c
===================================================================
--- shell/rb-shell-preferences.c	(revision 5236)
+++ shell/rb-shell-preferences.c	(arbetskopia)
@@ -93,6 +93,7 @@
 	GtkWidget *play_count_check;
 	GtkWidget *last_played_check;
 	GtkWidget *first_seen_check;
+	GtkWidget *bpm_check;
 	GtkWidget *quality_check;
 	GtkWidget *year_check;
 
@@ -207,6 +208,8 @@
 		glade_xml_get_widget (xml, "last_played_check");
 	shell_preferences->priv->quality_check =
 		glade_xml_get_widget (xml, "quality_check");
+	shell_preferences->priv->bpm_check =
+		glade_xml_get_widget (xml, "bpm_check");
 	shell_preferences->priv->year_check =
 		glade_xml_get_widget (xml, "year_check");
 	shell_preferences->priv->first_seen_check =
@@ -426,6 +429,8 @@
 		colname = "RHYTHMDB_PROP_LAST_PLAYED";
 	else if (butt == GTK_CHECK_BUTTON (shell_preferences->priv->year_check))
 		colname = "RHYTHMDB_PROP_DATE";
+	else if (butt == GTK_CHECK_BUTTON (shell_preferences->priv->bpm_check))
+		colname = "RHYTHMDB_PROP_BPM";
 	else if (butt == GTK_CHECK_BUTTON (shell_preferences->priv->quality_check))
 		colname = "RHYTHMDB_PROP_BITRATE";
 	else if (butt == GTK_CHECK_BUTTON (shell_preferences->priv->first_seen_check))
@@ -519,6 +524,9 @@
 		rb_shell_preferences_sync_column_button (shell_preferences,
 			       				 shell_preferences->priv->quality_check,
 							 columns, "RHYTHMDB_PROP_BITRATE");
+		rb_shell_preferences_sync_column_button (shell_preferences,
+			       				 shell_preferences->priv->bpm_check,
+							 columns, "RHYTHMDB_PROP_BPM");
 	}
 
 	g_free (columns);
Index: data/glade/general-prefs.glade
===================================================================
--- data/glade/general-prefs.glade	(revision 5236)
+++ data/glade/general-prefs.glade	(arbetskopia)
@@ -579,6 +579,29 @@
 				  <property name="y_options"></property>
 				</packing>
 			      </child>
+
+			      <child>
+				<widget class="GtkCheckButton" id="bpm_check">
+				  <property name="visible">True</property>
+				  <property name="can_focus">True</property>
+				  <property name="label" translatable="yes">BPM</property>
+				  <property name="use_underline">True</property>
+				  <property name="relief">GTK_RELIEF_NORMAL</property>
+				  <property name="focus_on_click">True</property>
+				  <property name="active">False</property>
+				  <property name="inconsistent">False</property>
+				  <property name="draw_indicator">True</property>
+				  <signal name="toggled" handler="rb_shell_preferences_column_check_changed_cb" last_modification_time="Fri, 02 May 2003 04:26:32 GMT"/>
+				</widget>
+				<packing>
+				  <property name="left_attach">1</property>
+				  <property name="right_attach">2</property>
+				  <property name="top_attach">5</property>
+				  <property name="bottom_attach">6</property>
+				  <property name="x_options">fill</property>
+				  <property name="y_options"></property>
+				</packing>
+			      </child>
 			    </widget>
 			    <packing>
 			      <property name="padding">0</property>
Index: data/glade/song-info.glade
===================================================================
--- data/glade/song-info.glade	(revision 5236)
+++ data/glade/song-info.glade	(arbetskopia)
@@ -417,6 +417,59 @@
 		  <property name="y_options"></property>
 		</packing>
 	      </child>
+
+	      <child>
+		<widget class="GtkEntry" id="song_info_bpm">
+		  <property name="visible">True</property>
+		  <property name="can_focus">True</property>
+		  <property name="editable">True</property>
+		  <property name="visibility">True</property>
+		  <property name="max_length">0</property>
+		  <property name="text" translatable="yes"></property>
+		  <property name="has_frame">True</property>
+		  <property name="invisible_char">*</property>
+		  <property name="activates_default">True</property>
+		  <accessibility>
+		    <atkrelation target="bpm_label" type="labelled-by"/>
+		  </accessibility>
+		</widget>
+		<packing>
+		  <property name="left_attach">1</property>
+		  <property name="right_attach">2</property>
+		  <property name="top_attach">8</property>
+		  <property name="bottom_attach">9</property>
+		  <property name="y_options"></property>
+		</packing>
+	      </child>
+
+	      <child>
+		<widget class="GtkLabel" id="bpm_label">
+		  <property name="visible">True</property>
+		  <property name="label" translatable="yes">BPM:</property>
+		  <property name="use_underline">True</property>
+		  <property name="use_markup">False</property>
+		  <property name="justify">GTK_JUSTIFY_LEFT</property>
+		  <property name="wrap">False</property>
+		  <property name="selectable">False</property>
+		  <property name="xalign">0</property>
+		  <property name="yalign">0.5</property>
+		  <property name="xpad">0</property>
+		  <property name="ypad">0</property>
+		  <property name="mnemonic_widget">song_info_bpm</property>
+		  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+		  <property name="width_chars">-1</property>
+		  <property name="single_line_mode">False</property>
+		  <property name="angle">0</property>
+		</widget>
+		<packing>
+		  <property name="left_attach">0</property>
+		  <property name="right_attach">1</property>
+		  <property name="top_attach">8</property>
+		  <property name="bottom_attach">9</property>
+		  <property name="x_options">fill</property>
+		  <property name="y_options"></property>
+		</packing>
+	      </child>
 	    </widget>
 	    <packing>
 	      <property name="padding">0</property>
Index: metadata/rb-metadata.h
===================================================================
--- metadata/rb-metadata.h	(revision 5236)
+++ metadata/rb-metadata.h	(arbetskopia)
@@ -56,6 +56,7 @@
 	RB_METADATA_FIELD_ALBUM_GAIN,		   /* double */
 	RB_METADATA_FIELD_ALBUM_PEAK,		   /* double */
 	RB_METADATA_FIELD_LANGUAGE_CODE,	   /* string */
+	RB_METADATA_FIELD_BPM,	   				/* double */
 	RB_METADATA_FIELD_MUSICBRAINZ_TRACKID,     /* string */
 	RB_METADATA_FIELD_MUSICBRAINZ_ARTISTID,    /* string */
 	RB_METADATA_FIELD_MUSICBRAINZ_ALBUMID,     /* string */
Index: metadata/rb-metadata-common.c
===================================================================
--- metadata/rb-metadata-common.c	(revision 5236)
+++ metadata/rb-metadata-common.c	(arbetskopia)
@@ -61,6 +61,7 @@
 	/* RB_METADATA_FIELD_ALBUM_GAIN */ 		{ G_TYPE_DOUBLE, "replaygain-album-gain" },
 	/* RB_METADATA_FIELD_ALBUM_PEAK */ 		{ G_TYPE_DOUBLE, "replaygain-album-peak" },
 	/* RB_METADATA_FIELD_LANGUAGE_CODE */		{ G_TYPE_STRING, "language-code" },
+	/* RB_METADATA_FIELD_BPM */ 			{ G_TYPE_DOUBLE, "beats-per-minute" },
 	/* RB_METADATA_FIELD_MUSICBRAINZ_TRACKID */	{ G_TYPE_STRING, "musicbrainz-trackid" },
 	/* RB_METADATA_FIELD_MUSICBRAINZ_ARTISTID */	{ G_TYPE_STRING, "musicbrainz-artistid" },
 	/* RB_METADATA_FIELD_MUSICBRAINZ_ALBUMID */	{ G_TYPE_STRING, "musicbrainz-albumid" },
Index: metadata/rb-metadata-gst.c
===================================================================
--- metadata/rb-metadata-gst.c	(revision 5236)
+++ metadata/rb-metadata-gst.c	(arbetskopia)
@@ -453,6 +453,8 @@
 		return RB_METADATA_FIELD_ALBUM_GAIN;
 	else if (!strcmp (tag, GST_TAG_ALBUM_PEAK))
 		return RB_METADATA_FIELD_ALBUM_PEAK;
+	else if (!strcmp (tag, GST_TAG_BEATS_PER_MINUTE))
+		return RB_METADATA_FIELD_BPM;
 #ifdef GST_TAG_MUSICBRAINZ_TRACKID
 	else if (!strcmp (tag, GST_TAG_MUSICBRAINZ_TRACKID))
 		return RB_METADATA_FIELD_MUSICBRAINZ_TRACKID;
@@ -525,6 +527,8 @@
 		return GST_TAG_ALBUM_GAIN;
 	case RB_METADATA_FIELD_ALBUM_PEAK:
 		return GST_TAG_ALBUM_PEAK;
+	case RB_METADATA_FIELD_BPM:
+		return GST_TAG_BEATS_PER_MINUTE;
 #ifdef GST_TAG_MUSICBRAINZ_TRACKID
 	case RB_METADATA_FIELD_MUSICBRAINZ_TRACKID:
 		return GST_TAG_MUSICBRAINZ_TRACKID;
Index: widgets/rb-entry-view.c
===================================================================
--- widgets/rb-entry-view.c	(revision 5236)
+++ widgets/rb-entry-view.c	(arbetskopia)
@@ -743,6 +743,31 @@
 }
 
 static void
+rb_entry_view_bpm_cell_data_func (GtkTreeViewColumn *column,
+				   GtkCellRenderer *renderer,
+				   GtkTreeModel *tree_model,
+				   GtkTreeIter *iter,
+				   struct RBEntryViewCellDataFuncData *data)
+{
+	RhythmDBEntry *entry;
+	char *str;
+	gdouble val;
+
+	entry = rhythmdb_query_model_iter_to_entry (data->view->priv->model, iter);
+
+	val = rhythmdb_entry_get_double (entry, data->propid);
+
+	if (val > 0)
+		str = g_strdup_printf ("%.2f", val);
+	else
+		str = g_strdup ("");
+
+	g_object_set (renderer, "text", str, NULL);
+	g_free (str);
+	rhythmdb_entry_unref (entry);
+}
+
+static void
 rb_entry_view_long_cell_data_func (GtkTreeViewColumn *column,
 				   GtkCellRenderer *renderer,
 				   GtkTreeModel *tree_model,
@@ -1248,6 +1273,16 @@
 		key = "Location";
 		ellipsize = TRUE;
 		break;
+	case RB_ENTRY_VIEW_COL_BPM:
+		propid = RHYTHMDB_PROP_BPM;
+		cell_data->propid = propid;
+		cell_data_func = (GtkTreeCellDataFunc) rb_entry_view_bpm_cell_data_func;
+		sort_func = (GCompareDataFunc) rhythmdb_query_model_double_ceiling_sort_func;
+		title = _("BPM");
+		key = "BPM";
+		strings[0] = title;
+		strings[1] = "999.99";
+		break;
 	case RB_ENTRY_VIEW_COL_ERROR:
 		propid = RHYTHMDB_PROP_PLAYBACK_ERROR;
 		cell_data->propid = RHYTHMDB_PROP_PLAYBACK_ERROR;
@@ -2152,6 +2187,7 @@
 			ENUM_ENTRY (RB_ENTRY_VIEW_COL_FIRST_SEEN, "First Seen"),
 			ENUM_ENTRY (RB_ENTRY_VIEW_COL_LAST_SEEN, "Last Seen"),
 			ENUM_ENTRY (RB_ENTRY_VIEW_COL_LOCATION, "Location"),
+			ENUM_ENTRY (RB_ENTRY_VIEW_COL_BPM, "BPM"),
 			ENUM_ENTRY (RB_ENTRY_VIEW_COL_ERROR, "Error"),
 			{ 0, 0, 0 }
 		};
Index: widgets/rb-entry-view.h
===================================================================
--- widgets/rb-entry-view.h	(revision 5236)
+++ widgets/rb-entry-view.h	(arbetskopia)
@@ -55,6 +55,7 @@
 	RB_ENTRY_VIEW_COL_FIRST_SEEN,
 	RB_ENTRY_VIEW_COL_LAST_SEEN,
 	RB_ENTRY_VIEW_COL_LOCATION,
+	RB_ENTRY_VIEW_COL_BPM,
 	RB_ENTRY_VIEW_COL_ERROR
 } RBEntryViewColumn;
 
Index: widgets/rb-query-creator-properties.c
===================================================================
--- widgets/rb-query-creator-properties.c	(revision 5236)
+++ widgets/rb-query-creator-properties.c	(arbetskopia)
@@ -33,6 +33,7 @@
 const RBQueryCreatorPropertyType string_property_type;
 const RBQueryCreatorPropertyType escaped_string_property_type;
 const RBQueryCreatorPropertyType rating_property_type;
+const RBQueryCreatorPropertyType double_property_type;
 const RBQueryCreatorPropertyType integer_property_type;
 const RBQueryCreatorPropertyType year_property_type;
 const RBQueryCreatorPropertyType duration_property_type;
@@ -46,6 +47,9 @@
 static GtkWidget * ratingCriteriaCreateWidget (gboolean *constrain);
 static void ratingCriteriaSetWidgetData (GtkWidget *widget, GValue *val);
 static void ratingCriteriaGetWidgetData (GtkWidget *widget, GValue *val);
+static GtkWidget * doubleCriteriaCreateWidget (gboolean *constrain);
+static void doubleCriteriaSetWidgetData (GtkWidget *widget, GValue *val);
+static void doubleCriteriaGetWidgetData (GtkWidget *widget, GValue *val);
 static GtkWidget * integerCriteriaCreateWidget (gboolean *constrain);
 static void integerCriteriaSetWidgetData (GtkWidget *widget, GValue *val);
 static void integerCriteriaGetWidgetData (GtkWidget *widget, GValue *val);
@@ -76,6 +80,7 @@
 	{ N_("Track Number"), RHYTHMDB_PROP_TRACK_NUMBER, RHYTHMDB_PROP_TRACK_NUMBER, &integer_property_type },
 	{ N_("Disc Number"), RHYTHMDB_PROP_DISC_NUMBER, RHYTHMDB_PROP_DISC_NUMBER, &integer_property_type },
 	{ N_("Bitrate"), RHYTHMDB_PROP_BITRATE, RHYTHMDB_PROP_BITRATE, &integer_property_type },
+	{ N_("Beats Per Minute"), RHYTHMDB_PROP_BPM, RHYTHMDB_PROP_BPM, &double_property_type },
 
 	{ N_("Duration"), RHYTHMDB_PROP_DURATION, RHYTHMDB_PROP_DURATION, &duration_property_type },
 
@@ -173,6 +178,15 @@
 	ratingCriteriaGetWidgetData
 };
 
+const RBQueryCreatorPropertyType double_property_type =
+{
+	G_N_ELEMENTS (numeric_criteria_options),
+	numeric_criteria_options,
+	doubleCriteriaCreateWidget,
+	doubleCriteriaSetWidgetData,
+	doubleCriteriaGetWidgetData
+};
+
 const RBQueryCreatorPropertyType integer_property_type =
 {
 	G_N_ELEMENTS (numeric_criteria_options),
@@ -326,6 +340,37 @@
 }
 
 /*
+ * Implementation for the double properties, using a single GtkSpinButton.
+ */
+
+static GtkWidget *
+doubleCriteriaCreateWidget (gboolean *constrain)
+{
+	GtkWidget *spin;
+	spin = gtk_spin_button_new_with_range (0.0, G_MAXDOUBLE, 1.0);	
+	gtk_spin_button_set_digits(GTK_SPIN_BUTTON(spin), 2);
+	return spin;
+}
+
+static void
+doubleCriteriaSetWidgetData (GtkWidget *widget, GValue *val)
+{
+	gdouble num = g_value_get_double (val);
+	g_assert (num <= G_MAXDOUBLE);
+
+	gtk_spin_button_set_value (GTK_SPIN_BUTTON (widget), num );
+}
+
+static void
+doubleCriteriaGetWidgetData (GtkWidget *widget, GValue *val)
+{
+	gdouble num = gtk_spin_button_get_value (GTK_SPIN_BUTTON (widget));
+	g_assert (num >= 0);
+
+	g_value_init (val, G_TYPE_DOUBLE);
+	g_value_set_double (val, num);
+}
+/*
  * Implementation for the integer properties, using a single GtkSpinButton.
  */
 
Index: widgets/rb-song-info.c
===================================================================
--- widgets/rb-song-info.c	(revision 5236)
+++ widgets/rb-song-info.c	(arbetskopia)
@@ -49,6 +49,7 @@
 #include "eel-gconf-extensions.h"
 #include "rb-source.h"
 #include "rb-shell.h"
+#include "rb-debug.h"
 
 static void rb_song_info_class_init (RBSongInfoClass *klass);
 static void rb_song_info_init (RBSongInfo *song_info);
@@ -122,6 +123,7 @@
 	GtkWidget   *year;
 	GtkWidget   *playback_error_box;
 	GtkWidget   *playback_error_label;
+	GtkWidget   *bpm;
 
 	GtkWidget   *bitrate;
 	GtkWidget   *duration;
@@ -277,6 +279,7 @@
 	song_info->priv->track_cur     = glade_xml_get_widget (xml, "song_info_track_cur");
 	song_info->priv->bitrate       = glade_xml_get_widget (xml, "song_info_bitrate");
 	song_info->priv->duration      = glade_xml_get_widget (xml, "song_info_duration");
+	song_info->priv->bpm       = glade_xml_get_widget (xml, "song_info_bpm");
 	song_info->priv->location = glade_xml_get_widget (xml, "song_info_location");
 	song_info->priv->filesize = glade_xml_get_widget (xml, "song_info_filesize");
 	song_info->priv->play_count    = glade_xml_get_widget (xml, "song_info_playcount");
@@ -292,6 +295,7 @@
 	rb_glade_boldify_label (xml, "play_count_label");
 	rb_glade_boldify_label (xml, "duration_label");
 	rb_glade_boldify_label (xml, "bitrate_label");
+	rb_glade_boldify_label (xml, "bpm_label");
 
 	/* whenever you press a mnemonic, the associated GtkEntry's text gets highlighted */
 	g_signal_connect_object (G_OBJECT (song_info->priv->title),
@@ -769,6 +773,18 @@
 }
 
 static void
+rb_song_info_populate_dnum_field (GtkEntry *field, gdouble num)
+{
+	char *tmp;
+	if (num > 0)
+		tmp = g_strdup_printf ("%.2f", num);
+	else
+		tmp = g_strdup (_("Unknown"));
+	gtk_entry_set_text (field, tmp);
+	g_free (tmp);
+}
+
+static void
 rb_song_info_populate_dialog_multiple (RBSongInfo *song_info)
 {
 	gboolean mixed_artists = FALSE;
@@ -858,6 +874,7 @@
 	const char *text;
 	char *tmp;
 	gulong num;
+	gdouble dnum;
 
 	g_assert (song_info->priv->current_entry);
 
@@ -882,6 +899,8 @@
 	rb_song_info_populate_num_field (GTK_ENTRY (song_info->priv->track_cur), num);
 	num = rhythmdb_entry_get_ulong (song_info->priv->current_entry, RHYTHMDB_PROP_DISC_NUMBER);
 	rb_song_info_populate_num_field (GTK_ENTRY (song_info->priv->disc_cur), num);
+	dnum = rhythmdb_entry_get_double (song_info->priv->current_entry, RHYTHMDB_PROP_BPM);
+	rb_song_info_populate_dnum_field (GTK_ENTRY (song_info->priv->bpm), dnum);
 
 	rb_song_info_update_duration (song_info);
 	rb_song_info_update_location (song_info);
@@ -1338,12 +1357,15 @@
 	const char *tracknum_str;
 	const char *discnum_str;
 	const char *year_str;
+	const char *bpm_str;
 	const char *entry_string;
 	char *endptr;
 	GType type;
 	gulong tracknum;
 	gulong discnum;
 	gulong year;
+	gdouble bpm;
+	gdouble dentry_val;
 	gulong entry_val;
 	GValue val = {0,};
 	gboolean changed = FALSE;
@@ -1356,6 +1378,7 @@
 	tracknum_str = gtk_entry_get_text (GTK_ENTRY (dialog->priv->track_cur));
 	discnum_str = gtk_entry_get_text (GTK_ENTRY (dialog->priv->disc_cur));
 	year_str = gtk_entry_get_text (GTK_ENTRY (dialog->priv->year));
+	bpm_str = gtk_entry_get_text (GTK_ENTRY (dialog->priv->bpm));
 
 	g_signal_emit (dialog, rb_song_info_signals[PRE_METADATA_CHANGE], 0,
 		       entry);
@@ -1414,6 +1437,18 @@
 		if (date)
 			g_date_free (date);
 	}
+	
+	bpm = g_ascii_strtod (bpm_str, &endptr);
+	dentry_val = rhythmdb_entry_get_double (entry, RHYTHMDB_PROP_BPM);
+	if ((endptr != bpm_str) && (bpm != dentry_val)) {
+		type = rhythmdb_get_property_type (dialog->priv->db,
+						   RHYTHMDB_PROP_BPM);
+		g_value_init (&val, type);
+		g_value_set_double (&val, bpm);
+		rhythmdb_entry_set (dialog->priv->db, entry, RHYTHMDB_PROP_BPM, &val);
+		g_value_unset (&val);
+		changed = TRUE;
+	}
 
 	entry_string = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_TITLE);
 	if (strcmp (title, entry_string)) {
Index: backends/gstreamer/rb-encoder-gst.c
===================================================================
--- backends/gstreamer/rb-encoder-gst.c	(revision 5236)
+++ backends/gstreamer/rb-encoder-gst.c	(arbetskopia)
@@ -374,6 +374,7 @@
 			  GST_TAG_ALBUM_VOLUME_NUMBER, rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_DISC_NUMBER),
 			  GST_TAG_ALBUM, rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_ALBUM),
 			  GST_TAG_GENRE, rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_GENRE),
+			  GST_TAG_BEATS_PER_MINUTE, rhythmdb_entry_get_double (entry, RHYTHMDB_PROP_BPM),
 			  GST_TAG_ENCODER, "Rhythmbox",
 			  GST_TAG_ENCODER_VERSION, VERSION,
 			  NULL);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]