/* GStreamer * Copyright (C) 2001 Steve Baker * * unitconvert.c: Conversion between units of measurement * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include "unitconvert.h" #include static GHashTable *_gst_units; static GHashTable *_gst_unit_domain_defaults; static gboolean _gst_unitconv_init_done = FALSE; typedef struct _GstUnit GstUnit; struct _GstUnit { GParamSpec *unit_spec; const gchar *domain_name; gboolean domain_default; gboolean logarithmic; GHashTable *convert_to_funcs; GSList *convert_paramspecs; }; static void gst_unitconv_add_core_converters (void); static void gst_unitconv_class_init (GstUnitConvertClass * klass); static void gst_unitconv_init (GstUnitConvert * unitconv); static void gst_unitconv_dispose (GObject * object); GType gst_unitconv_get_type (void) { static GType unitconv_type = 0; if (!unitconv_type) { static const GTypeInfo unitconv_info = { sizeof (GstUnitConvertClass), NULL, NULL, (GClassInitFunc) gst_unitconv_class_init, NULL, NULL, sizeof (GstUnitConvert), 0, (GInstanceInitFunc) gst_unitconv_init, }; unitconv_type = g_type_register_static (GST_TYPE_OBJECT, "GstUnitConvert", &unitconv_info, 0); } return unitconv_type; } static void gst_unitconv_class_init (GstUnitConvertClass * klass) { GObjectClass *gobject_class; GstUnitConvertClass *unitconv_class; GstObjectClass *gstobject_class; gobject_class = (GObjectClass *) klass; unitconv_class = (GstUnitConvertClass *) klass; gstobject_class = (GstObjectClass *) klass; gobject_class->dispose = gst_unitconv_dispose; } static void gst_unitconv_init (GstUnitConvert * unitconv) { g_return_if_fail (unitconv != NULL); unitconv->convert_func_chain = NULL; unitconv->convert_params = g_hash_table_new (g_str_hash, g_str_equal); } GstUnitConvert * gst_unitconv_new (void) { GstUnitConvert *unitconv; unitconv = g_object_new (gst_unitconv_get_type (), NULL); return unitconv; } static void gst_unitconv_init_for_change_state (GstUnitConvert * unitconv) { unitconv->convert_func_chain = NULL; } gboolean gst_unitconv_set_convert_units (GstUnitConvert * unitconv, gchar * from_unit_named, gchar * to_unit_named) { GHashTable *convert_funcs; GstUnit *from_unit, *to_unit; GstUnitConvertFunc convert_func; g_return_val_if_fail (unitconv != NULL, FALSE); g_return_val_if_fail (from_unit_named != NULL, FALSE); g_return_val_if_fail (to_unit_named != NULL, FALSE); g_return_val_if_fail (GST_IS_UNIT_CONVERT (unitconv), FALSE); from_unit = g_hash_table_lookup (_gst_units, from_unit_named); to_unit = g_hash_table_lookup (_gst_units, to_unit_named); g_return_val_if_fail (from_unit != NULL, FALSE); g_return_val_if_fail (to_unit != NULL, FALSE); convert_funcs = from_unit->convert_to_funcs; convert_func = g_hash_table_lookup (convert_funcs, to_unit); if (convert_func == NULL) { g_warning ("cannot convert from %s to %s", from_unit_named, to_unit_named); } gst_unitconv_init_for_change_state (unitconv); unitconv->convert_func_chain = g_slist_append (unitconv->convert_func_chain, convert_func); return TRUE; } gboolean gst_unitconv_convert_value (GstUnitConvert * unitconv, GValue * from_value, GValue * to_value) { GstUnitConvertFunc convert_func; GSList *convert_func_chain; g_return_val_if_fail (unitconv->convert_func_chain != NULL, FALSE); /* only do this until we can chain convert funcs */ g_return_val_if_fail (g_slist_length (unitconv->convert_func_chain) == 1, FALSE); convert_func_chain = unitconv->convert_func_chain; convert_func = (GstUnitConvertFunc) (convert_func_chain); convert_func (unitconv, from_value, to_value); return TRUE; } gboolean gst_unitconv_unit_exists (gchar * unit_name) { g_return_val_if_fail (unit_name != NULL, FALSE); return (g_hash_table_lookup (_gst_units, unit_name) != NULL); } gboolean gst_unitconv_unit_is_logarithmic (gchar * unit_name) { GstUnit *unit; g_return_val_if_fail (unit_name != NULL, FALSE); unit = g_hash_table_lookup (_gst_units, unit_name); g_return_val_if_fail (unit != NULL, FALSE); return unit->logarithmic; } GParamSpec * gst_unitconv_unit_spec (gchar * unit_name) { GstUnit *unit; g_return_val_if_fail (unit_name != NULL, NULL); unit = g_hash_table_lookup (_gst_units, unit_name); g_return_val_if_fail (unit != NULL, NULL); return unit->unit_spec; } static void gst_unitconv_dispose (GObject * object) { } void _gst_unitconv_initialize (void) { if (_gst_unitconv_init_done) return; _gst_unitconv_init_done = TRUE; _gst_units = g_hash_table_new (g_str_hash, g_str_equal); _gst_unit_domain_defaults = g_hash_table_new (g_str_hash, g_str_equal); /* frequency based units */ gst_unitconv_register_unit ("frequency", TRUE, TRUE, g_param_spec_float ("hertz", "Hz", "Frequency in hertz", 0, G_MAXFLOAT, 0, 0)); gst_unitconv_register_unit ("frequency", FALSE, TRUE, g_param_spec_float ("hertz-rate-bound", "Hz", "Frequency in hertz, bound by the sample rate", 0.0, G_MAXFLOAT, 0.0, 0)); gst_unitconv_register_unit ("frequency", FALSE, FALSE, g_param_spec_string ("twelve-tone-scale", "note", "Name of the note from the western twelve tone scale", "C", 0)); gst_unitconv_register_unit ("frequency", FALSE, FALSE, g_param_spec_int ("midi-note", "midi note", "MIDI note value of the frequency", 1, 127, 1, 0)); /* time based units */ gst_unitconv_register_unit ("time", TRUE, FALSE, g_param_spec_float ("seconds", "s", "Time in seconds", -G_MAXFLOAT, G_MAXFLOAT, 0, 0)); gst_unitconv_register_unit ("time", FALSE, FALSE, g_param_spec_int64 ("nanoseconds", "ns", "Time in nanoseconds", G_MININT64, G_MAXINT64, 0, 0)); gst_unitconv_register_unit ("time", FALSE, FALSE, g_param_spec_int64 ("samples", "samples", "Time in number of samples", G_MININT64, G_MAXINT64, 0, 0)); gst_unitconv_register_convert_property ("samples", g_param_spec_int ("samplerate", "samplerate", "samplerate", 0, G_MAXINT, 0, G_PARAM_READWRITE)); /* magnitude based units */ gst_unitconv_register_unit ("magnitude", TRUE, FALSE, g_param_spec_float ("scalar", "scalar", "Magnitude as a scalar", -G_MAXFLOAT, G_MAXFLOAT, 0, 0)); gst_unitconv_register_unit ("magnitude", FALSE, FALSE, g_param_spec_int ("scalar-int", "scalar int", "Magnitude as an integer scalar", G_MININT, G_MAXINT, 0, 0)); gst_unitconv_register_unit ("magnitude", FALSE, TRUE, g_param_spec_float ("decibel", "dB", "Magnitude in decibels", -G_MAXFLOAT, G_MAXFLOAT, 0, 0)); gst_unitconv_register_unit ("magnitude", FALSE, FALSE, g_param_spec_float ("percent", "%", "Magnitude in percent", -G_MAXFLOAT, G_MAXFLOAT, 0, 0)); /* generic units */ gst_unitconv_register_unit ("float_default", TRUE, FALSE, g_param_spec_float ("float", "float", "Float value", -G_MAXFLOAT, G_MAXFLOAT, 0, 0)); gst_unitconv_register_unit ("int_default", TRUE, FALSE, g_param_spec_int ("int", "int", "Integer value", G_MININT, G_MAXINT, 0, 0)); gst_unitconv_register_unit ("int64_default", TRUE, FALSE, g_param_spec_int64 ("int64", "int64", "64 bit integer value", G_MININT, G_MAXINT, 0, 0)); gst_unitconv_add_core_converters (); } gboolean gst_unitconv_register_unit (const gchar * domain_name, gboolean is_domain_default, gboolean is_logarithmic, GParamSpec * unit_spec) { GstUnit *unit; gchar *unit_name; g_return_val_if_fail (unit_spec != NULL, FALSE); g_return_val_if_fail (G_IS_PARAM_SPEC (unit_spec), FALSE); g_return_val_if_fail (domain_name != NULL, FALSE); unit_name = g_strdup (g_param_spec_get_name (unit_spec)); /* check if this unit name already exists */ if (g_hash_table_lookup (_gst_units, unit_name) != NULL) { g_free (unit_name); return FALSE; } if (is_domain_default) { /* check if an default unit already exists for this domain */ g_return_val_if_fail (g_hash_table_lookup (_gst_unit_domain_defaults, domain_name) == NULL, FALSE); } GST_DEBUG ("creating unit: %s", unit_name); unit = g_new0 (GstUnit, 1); unit->unit_spec = unit_spec; unit->domain_name = domain_name; unit->domain_default = is_domain_default; unit->logarithmic = is_logarithmic; unit->convert_to_funcs = g_hash_table_new (NULL, NULL); /* unit->convert_properties = g_hash_table_new(g_str_hash,g_str_equal); */ g_hash_table_insert (_gst_units, unit_name, unit); if (is_domain_default) { g_hash_table_insert (_gst_unit_domain_defaults, g_strdup (domain_name), unit); } return TRUE; } gboolean gst_unitconv_register_convert_func (gchar * from_unit_named, gchar * to_unit_named, GstUnitConvertFunc convert_func) { GHashTable *convert_funcs; GstUnit *from_unit, *to_unit; g_return_val_if_fail (from_unit_named != NULL, FALSE); g_return_val_if_fail (to_unit_named != NULL, FALSE); from_unit = g_hash_table_lookup (_gst_units, from_unit_named); to_unit = g_hash_table_lookup (_gst_units, to_unit_named); g_return_val_if_fail (from_unit != NULL, FALSE); g_return_val_if_fail (to_unit != NULL, FALSE); convert_funcs = from_unit->convert_to_funcs; g_return_val_if_fail (g_hash_table_lookup (convert_funcs, to_unit) == NULL, FALSE); GST_DEBUG ("adding unit converter from %s to %s", g_param_spec_get_name (from_unit->unit_spec), g_param_spec_get_name (to_unit->unit_spec)); g_hash_table_insert (convert_funcs, to_unit, convert_func); return TRUE; } gboolean gst_unitconv_register_convert_property (gchar * unit_name, GParamSpec * convert_prop_spec) { GstUnit *unit; g_return_val_if_fail (unit_name != NULL, FALSE); g_return_val_if_fail (convert_prop_spec != NULL, FALSE); unit = g_hash_table_lookup (_gst_units, unit_name); g_return_val_if_fail (unit != NULL, FALSE); unit->convert_paramspecs = g_slist_append (unit->convert_paramspecs, convert_prop_spec); return TRUE; } static void gst_unitconv_time_seconds_to_nanoseconds (GstUnitConvert * unitconv, GValue * seconds_val, GValue * nanos_val) { g_value_set_int64 (nanos_val, (gint64) (g_value_get_float (seconds_val) * 1000000000.0)); } static void gst_unitconv_time_nanoseconds_to_seconds (GstUnitConvert * unitconv, GValue * nanos_val, GValue * seconds_val) { g_value_set_float (seconds_val, ((gfloat) g_value_get_int64 (nanos_val)) / 1000000000.0); } static void gst_unitconv_time_seconds_to_samples (GstUnitConvert * unitconv, GValue * seconds_val, GValue * samples_val) { /* GValue *samplerate; GValue *samplerate = g_hash_table_lookup(unitconv->currentToUnit->convert_properties, "samplerate"); g_value_set_int64(samples_val, (gint64)(g_value_get_float(seconds_val) * (gfloat)g_value_get_int(samplerate))); */ } static void gst_unitconv_time_samples_to_seconds (GstUnitConvert * unitconv, GValue * samples_val, GValue * seconds_val) { /* GValue *samplerate; GValue *samplerate = g_hash_table_lookup(unitconv->currentFromUnit->convert_properties, "samplerate"); g_value_set_float(seconds_val, ((gfloat)g_value_get_int64(samples_val)) / (gfloat)g_value_get_int(samplerate)); */ } static void gst_unitconv_magnitude_scalar_to_percent (GstUnitConvert * unitconv, GValue * scalar_val, GValue * percent_val) { g_value_set_float (percent_val, g_value_get_float (scalar_val) * 100.0); } static void gst_unitconv_magnitude_percent_to_scalar (GstUnitConvert * unitconv, GValue * percent_val, GValue * scalar_val) { g_value_set_float (scalar_val, g_value_get_float (percent_val) / 100.0); } static void gst_unitconv_add_core_converters (void) { gst_unitconv_register_convert_func ("nanoseconds", "seconds", gst_unitconv_time_nanoseconds_to_seconds); gst_unitconv_register_convert_func ("seconds", "nanoseconds", gst_unitconv_time_seconds_to_nanoseconds); gst_unitconv_register_convert_func ("seconds", "samples", gst_unitconv_time_seconds_to_samples); gst_unitconv_register_convert_func ("samples", "seconds", gst_unitconv_time_samples_to_seconds); gst_unitconv_register_convert_func ("scalar", "percent", gst_unitconv_magnitude_scalar_to_percent); gst_unitconv_register_convert_func ("percent", "scalar", gst_unitconv_magnitude_percent_to_scalar); }