/*================================================================== * SwamiObject.c - Main Swami Object * * Swami * Copyright (C) 1999-2003 Josh Green * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA or point your web browser to http://www.gnu.org. * * To contact the author of this program: * Email: Josh Green * Swami homepage: http://swami.sourceforge.net *==================================================================*/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include #include #include "SwamiObject.h" #include "SwamiConfig.h" #include "SwamiLog.h" #include "SwamiPlugin.h" #include "SwamiUndoFuncs.h" #include "i18n.h" #include "marshals.h" /* A flag for IPItem.user_flags for toplevel patch items to indicate that it and all its children are active (a part of the Swami object tree) and should emit signals */ #define SWAMI_ITEM_FLAG_ACTIVE (1 << 0) /* --- macros --- */ #define PARAM_SPEC_PARAM_ID(pspec) ((pspec)->param_id) #define PARAM_SPEC_SET_PARAM_ID(pspec, id) ((pspec)->param_id = (id)) #define SWAMI_OBJECT_WARN_INVALID_PROPERTY_ID(objtype, id) \ g_warning ("%s: invalid property id \"%s\" for Swami item type \"%s\"", \ G_STRLOC, (id), g_type_name (objtype)); /* --- signals and properties --- */ enum { ITEM_ADD, ITEM_REMOVE, ITEM_PROP_CHANGE, ZONE_GEN_CHANGE, UNDO_ENTRY, UNDO, REDO, GROUP_START, GROUP_END, LAST_SIGNAL }; enum { PROP_0, PROP_USER_DATA, PROP_CHANGED, PROP_SAVED, PROP_FILENAME, PROP_NAME, PROP_PSETNUM, PROP_BANK, PROP_LIBRARY, PROP_GENRE, PROP_MORPHOLOGY, PROP_SIZE, PROP_LOOPSTART, PROP_LOOPEND, PROP_SAMPLERATE, PROP_ORIGPITCH, PROP_PITCHADJ, PROP_REFITEM, /* IPSFont info properties */ PROP_INFO_VERSION, PROP_INFO_ENGINE, PROP_INFO_NAME, PROP_INFO_ROM_NAME, PROP_INFO_ROM_VERSION, PROP_INFO_DATE, PROP_INFO_AUTHOR, PROP_INFO_PRODUCT, PROP_INFO_COPYRIGHT, PROP_INFO_COMMENT, PROP_INFO_SOFTWARE, }; /* --- private function prototypes --- */ static void swami_object_class_init (SwamiObjectClass *klass); static void install_property (GType type, int property_id, GParamSpec *pspec); static void swami_object_init (SwamiObject *swami); static char *new_item_unique_name (IPItem *list, int name_offset); static void item_set_property (SwamiObject *swami, IPItem *item, GParamSpec *pspec, GValue *value, const char *property_name); static gboolean item_get_property (SwamiObject *swami, const IPItem *item, GParamSpec *pspec, GValue *value); static GParamSpec *item_lookup_param_spec (const IPItem *item, const char *name); /* --- private data --- */ static SwamiConfigStaticVars swami_config_vars[] = { { "swami", "search_path", G_TOKEN_STRING, {""} }, { NULL, "swap_max_waste", G_TOKEN_INT, {GINT_TO_POINTER (16)} }, { NULL, "sample_max_size", G_TOKEN_INT, {GINT_TO_POINTER (8)} }, { NULL, "temp_bank", G_TOKEN_INT, {GINT_TO_POINTER (127)} }, { NULL, "temp_preset", G_TOKEN_INT, {GINT_TO_POINTER (127)} } }; #define CONFIG_VAR_COUNT (sizeof (swami_config_vars) \ / sizeof (SwamiConfigStaticVars)) static gpointer parent_class = NULL; static guint swami_signals[LAST_SIGNAL] = { 0 }; static GParamSpecPool *pspec_pool; /* parameter spec pool */ /* --- functions --- */ /** * swami_init: * * Initialize Swami (should be called before any other Swami functions) */ void swami_init (void) { swami_config_init (); /* initialize config system */ swami_undo_system_init (); /* initialize undo system */ _swami_plugin_initialize (); /* initialize plugin system */ } GType swami_object_get_type (void) { static GType item_type = 0; if (!item_type) { static const GTypeInfo item_info = { sizeof (SwamiObjectClass), NULL, NULL, (GClassInitFunc) swami_object_class_init, NULL, NULL, sizeof (SwamiObject), 0, (GInstanceInitFunc) swami_object_init, }; item_type = g_type_register_static (G_TYPE_OBJECT, "SwamiObject", &item_info, G_TYPE_FLAG_ABSTRACT); } return (item_type); } /** * swami_item_get_type: * @itemtype: Sound font item type (0 = IPItem, for this function only) * * Get GType of a Swami sound font object type * * Returns: The GType for the requested @itemtype */ GType swami_item_get_type (IPItemType itemtype) { static GType gtypes [IPITEM_COUNT] = { 0 }; static const GTypeInfo item_info = { 0, NULL, NULL, NULL, NULL, NULL, 0, 0, NULL }; g_return_val_if_fail (itemtype >= 0 && itemtype < IPITEM_COUNT, 0); if (!gtypes [0]) { gtypes[IPITEM_NONE] = /* using for IPItem type */ g_type_register_static (G_TYPE_OBJECT, "SwamiIPItem", &item_info, G_TYPE_FLAG_ABSTRACT); gtypes[IPITEM_SFONT] = g_type_register_static (SWAMI_TYPE_SFITEM, "SwamiIPSFont", &item_info, G_TYPE_FLAG_ABSTRACT); gtypes[IPITEM_PRESET] = g_type_register_static (SWAMI_TYPE_SFITEM, "SwamiIPPreset", &item_info, G_TYPE_FLAG_ABSTRACT); gtypes[IPITEM_INST] = g_type_register_static (SWAMI_TYPE_SFITEM, "SwamiIPInst", &item_info, G_TYPE_FLAG_ABSTRACT); gtypes[IPITEM_SAMPLE] = g_type_register_static (SWAMI_TYPE_SFITEM, "SwamiIPSample", &item_info, G_TYPE_FLAG_ABSTRACT); gtypes[IPITEM_ZONE] = g_type_register_static (SWAMI_TYPE_SFITEM, "SwamiIPZone", &item_info, G_TYPE_FLAG_ABSTRACT); gtypes[IPITEM_VBANK] = g_type_register_static (SWAMI_TYPE_SFITEM, "SwamiSFVbank", &item_info, G_TYPE_FLAG_ABSTRACT); gtypes[IPITEM_VBANK_MAP] = g_type_register_static (SWAMI_TYPE_SFITEM, "SwamiSFVbankMap", &item_info, G_TYPE_FLAG_ABSTRACT); } return (gtypes[itemtype]); } static void swami_object_class_init (SwamiObjectClass *klass) { parent_class = g_type_class_ref (G_TYPE_OBJECT); swami_signals[ITEM_ADD] = g_signal_new ("item_add", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST, 0, NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); swami_signals[ITEM_REMOVE] = g_signal_new ("item_remove", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); swami_signals[ITEM_PROP_CHANGE] = g_signal_new ("item_prop_change", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, swami_marshal_VOID__POINTER_STRING, G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_STRING); swami_signals[ZONE_GEN_CHANGE] = g_signal_new ("zone_gen_change", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); swami_signals[UNDO_ENTRY] = g_signal_new ("undo_entry", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (SwamiObjectClass, undo_entry), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); swami_signals[UNDO] = g_signal_new ("undo", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (SwamiObjectClass, undo), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); swami_signals[REDO] = g_signal_new ("redo", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (SwamiObjectClass, redo), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); swami_signals[GROUP_START] = g_signal_new ("group_start", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (SwamiObjectClass, group_start), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); swami_signals[GROUP_END] = g_signal_new ("group_end", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (SwamiObjectClass, group_end), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); pspec_pool = g_param_spec_pool_new (TRUE); install_property (SWAMI_TYPE_SFITEM, PROP_USER_DATA, g_param_spec_pointer ("user_data", "User Data", "Anonymous User Data Pointer", G_PARAM_READWRITE)); install_property (SWAMI_TYPE_SFONT, PROP_CHANGED, g_param_spec_boolean ("changed", "Changed", "Changed Flag", TRUE, G_PARAM_READWRITE)); install_property (SWAMI_TYPE_SFONT, PROP_SAVED, g_param_spec_boolean ("saved", "Saved", "Saved Flag", FALSE, G_PARAM_READWRITE)); install_property (SWAMI_TYPE_SFONT, PROP_FILENAME, g_param_spec_string ("file_name", "File Name", "File Name", "untitled.sf2", G_PARAM_READWRITE)); install_property (SWAMI_TYPE_SFONT, PROP_INFO_VERSION, g_param_spec_string ("version", "Version", "SoundFont Version \"major.minor\"", "2.01", G_PARAM_READWRITE)); install_property (SWAMI_TYPE_SFONT, PROP_INFO_ENGINE, g_param_spec_string ("engine", "Engine", "Sound Synthesis Engine Identifier", "EMU8000", G_PARAM_READWRITE)); install_property (SWAMI_TYPE_SFONT, PROP_INFO_NAME, g_param_spec_string ("name", "Name", "SoundFont Name", "untitled", G_PARAM_READWRITE)); install_property (SWAMI_TYPE_SFONT, PROP_INFO_ROM_NAME, g_param_spec_string ("rom_name", "ROM Name", "ROM Name identifier", NULL, G_PARAM_READWRITE)); install_property (SWAMI_TYPE_SFONT, PROP_INFO_ROM_VERSION, g_param_spec_string ("rom_version", "ROM Version", "ROM Version \"major.minor\"", NULL, G_PARAM_READWRITE)); install_property (SWAMI_TYPE_SFONT, PROP_INFO_DATE, g_param_spec_string ("date", "Date", "Date of creation", NULL, G_PARAM_READWRITE)); install_property (SWAMI_TYPE_SFONT, PROP_INFO_AUTHOR, g_param_spec_string ("author", "Author", "Author of SoundFont", NULL, G_PARAM_READWRITE)); install_property (SWAMI_TYPE_SFONT, PROP_INFO_PRODUCT, g_param_spec_string ("product", "Product", "Product SoundFont is intended for", NULL, G_PARAM_READWRITE)); install_property (SWAMI_TYPE_SFONT, PROP_INFO_COPYRIGHT, g_param_spec_string ("copyright", "Copyright", "Copyright", NULL, G_PARAM_READWRITE)); install_property (SWAMI_TYPE_SFONT, PROP_INFO_COMMENT, g_param_spec_string ("comment", "Comments", "Comments", NULL, G_PARAM_READWRITE)); install_property (SWAMI_TYPE_SFONT, PROP_INFO_SOFTWARE, g_param_spec_string ("software", "Software", "Software used \"created:modified\"", NULL, G_PARAM_READWRITE)); install_property (SWAMI_TYPE_SFPRESET, PROP_NAME, g_param_spec_string ("name", "Name", "Name", NULL, G_PARAM_READWRITE)); install_property (SWAMI_TYPE_SFPRESET, PROP_PSETNUM, g_param_spec_int ("psetnum", "Preset Number", "Preset MIDI Number", 0, 127, 0, G_PARAM_READWRITE)); install_property (SWAMI_TYPE_SFPRESET, PROP_BANK, g_param_spec_int ("bank", "Bank Number", "Bank MIDI Number", 0, 128, 0, G_PARAM_READWRITE)); install_property (SWAMI_TYPE_SFPRESET, PROP_LIBRARY, g_param_spec_uint ("library", "Library", "Library Category", 0, 0xFFFFFFFF, 0, G_PARAM_READWRITE)); install_property (SWAMI_TYPE_SFPRESET, PROP_GENRE, g_param_spec_uint ("genre", "Genre", "Genre Category", 0, 0xFFFFFFFF, 0, G_PARAM_READWRITE)); install_property (SWAMI_TYPE_SFPRESET, PROP_MORPHOLOGY, g_param_spec_uint ("morphology", "Morphology", "Morphology Category", 0, 0xFFFFFFFF, 0, G_PARAM_READWRITE)); install_property (SWAMI_TYPE_SFINST, PROP_NAME, g_param_spec_string ("name", "Name", "Name", NULL, G_PARAM_READWRITE)); install_property (SWAMI_TYPE_SFSAMPLE, PROP_NAME, g_param_spec_string ("name", "Name", "Name", NULL, G_PARAM_READWRITE)); install_property (SWAMI_TYPE_SFSAMPLE, PROP_SIZE, g_param_spec_int ("size", "Size", "Size in samples", 0, 0, 0xFFFFFFFF, G_PARAM_READABLE)); install_property (SWAMI_TYPE_SFSAMPLE, PROP_LOOPSTART, g_param_spec_int ("loopstart", "Loop Start", "Start of loop in samples", 0, 0, 0xFFFFFFFF, G_PARAM_READWRITE)); install_property (SWAMI_TYPE_SFSAMPLE, PROP_LOOPEND, g_param_spec_int ("loopend", "Loop End", "End of loop in samples", 0, 0, 0xFFFFFFFF, G_PARAM_READWRITE)); install_property (SWAMI_TYPE_SFSAMPLE, PROP_SAMPLERATE, g_param_spec_int ("samplerate", "Sample Rate", "Sampling rate in Hertz", 0, 96000, 44100, G_PARAM_READWRITE)); install_property (SWAMI_TYPE_SFSAMPLE, PROP_ORIGPITCH, g_param_spec_int ("origpitch", "Original Pitch", "Original pitch MIDI note number", 0, 127, 60, G_PARAM_READWRITE)); install_property (SWAMI_TYPE_SFSAMPLE, PROP_PITCHADJ, g_param_spec_int ("pitchadj", "Pitch Adjustment", "Pitch adjustment in cents", 0, 100, 0, G_PARAM_READWRITE)); install_property (SWAMI_TYPE_SFZONE, PROP_REFITEM, g_param_spec_pointer ("refitem", "RefItem", "Referenced Item", G_PARAM_READWRITE)); } static void install_property (GType type, int property_id, GParamSpec *pspec) { g_param_spec_ref (pspec); g_param_spec_sink (pspec); PARAM_SPEC_SET_PARAM_ID (pspec, property_id); g_param_spec_pool_insert (pspec_pool, pspec, type); } static void swami_object_init (SwamiObject *swami) { swami->patches = NULL; /* define config vars */ swami_config_add_static_variables (swami_config_vars, CONFIG_VAR_COUNT); swami->undo = g_malloc (sizeof (SwamiUndo)); swami->undo->root = g_node_new (NULL); /* root undo node is a dummy */ swami->undo->curpos = swami->undo->root; swami->undo->groups = NULL; swami->undo->running = FALSE; } /** * swami_object_new: * * Create a new Swami object * * Returns: New Swami object */ SwamiObject * swami_object_new (void) { return SWAMI_OBJECT (g_object_new (SWAMI_TYPE_OBJECT, NULL)); } /** * swami_register_object: * @swami: Swami object * @object: Existing object to register * * Register an existing object to a Swami object. This is done by adding * the @object to the @swami object and setting a "SwamiObject" * variable on @object which points to @swami. */ void swami_register_object (SwamiObject *swami, GObject *object) { g_return_if_fail (SWAMI_IS_OBJECT (swami)); g_return_if_fail (G_IS_OBJECT (object)); g_object_set_data (object, "SwamiObject", swami); swami->objects = g_slist_append (swami->objects, object); } /** * swami_register_object_new: * @swami: Swami object * @type_name: Name of a GObject derived GType of object to create and register * with the Swami Object. * * Create a new object and register it with a Swami object. * Like #swami_register_object but creates a new object rather than using * an existing one. * * Returns: The new GObject created or NULL on error */ GObject * swami_register_object_new (SwamiObject *swami, const char *type_name) { GType type; GObject *obj; g_return_val_if_fail (SWAMI_IS_OBJECT (swami), NULL); g_return_val_if_fail (g_type_from_name (type_name) != 0, NULL); type = g_type_from_name (type_name); g_return_val_if_fail (g_type_is_a (type, G_TYPE_OBJECT), NULL); if (!(obj = g_object_new (type, NULL))) return (NULL); swami_register_object (swami, obj); return (obj); } /** * swami_lookup_objects_by_type: * @obj: Object to start from. This can be an object previously * registered with a #SwamiObject or the SwamiObject itself. * @type_name: Name of GObject derived GType of objects to search for, * objects derived from this type will also match. * * Lookup all objects of a @type_name or derived from @type_name. * * Returns: Newly allocated list of objects of @type_name and/or derived * from it or NULL if no matches to that type. The list should be freed with * g_list_free() when finished with it. */ GList * swami_lookup_objects_by_type (GObject *obj, const char *type_name) { SwamiObject *swami; GList *newlist = NULL; GType type; GSList *p; g_return_val_if_fail (G_IS_OBJECT (obj), NULL); g_return_val_if_fail (g_type_from_name (type_name) != 0, NULL); type = g_type_from_name (type_name); g_return_val_if_fail (g_type_is_a (type, G_TYPE_OBJECT), NULL); if (!SWAMI_IS_OBJECT (obj)) { swami = g_object_get_data (obj, "SwamiObject"); g_return_val_if_fail (SWAMI_IS_OBJECT (swami), NULL); } else swami = SWAMI_OBJECT (obj); p = swami->objects; while (p) { if (g_type_is_a (G_TYPE_FROM_INSTANCE (p->data), type)) newlist = g_list_append (newlist, p->data); p = g_slist_next (p); } return (newlist); } /** * swami_get_object_by_type: * @obj: Object to start search from. This can be an object previously * registered with a #SwamiObject or the SwamiObject itself. * @type_name: Name of GObject derived GType to search for * * Lookup the first object of the given @type_name or derived from it. * A convenience function to get the first item of the given type, if one * expects only one object and doesn't want to deal with a list. * * Returns: The first object of the given type or NULL if none. */ GObject * swami_get_object_by_type (GObject *obj, const char *type_name) { GList *list; GObject *match = NULL; list = swami_lookup_objects_by_type (obj, type_name); /* yeah, who cares? */ if (list) { match = (GObject *)(list->data); g_list_free (list); } return (match); } /** * swami_patch_load: * @swami: Swami object to load into * @filename: Name and path of file to load * * Load an instrument patch file and append to Swami object tree * * Returns: Pointer to toplevel item (#IPSFont for sound fonts, #SFVBank for * virtual banks) that has been loaded into swami object. NULL on error. */ IPItem * swami_patch_load (SwamiObject *swami, const char *filename) { IPSFont *sf; int fd; g_return_val_if_fail (swami != NULL, NULL); g_return_val_if_fail (SWAMI_IS_OBJECT (swami), NULL); g_return_val_if_fail (filename != NULL, NULL); #ifndef MINGW32 if ((fd = open (filename, O_RDONLY)) < 0) #else if ((fd = open (filename, O_RDONLY | O_BINARY)) < 0) #endif { g_critical (_("Failed to open file \"%s\": %s"), filename, g_strerror (errno)); return (NULL); } if (!(sf = instp_sfont_load (fd, IPLOAD_ALL, NULL, NULL))) { close (fd); return (NULL); } instp_set_file_name (sf, filename); swami_item_add (swami, NULL, INSTP_ITEM (sf)); return (INSTP_ITEM (sf)); } /** * swami_patch_save: * @swami: Swami object * @item: Patch item of file to save, its filename should be set prior * to calling this function. * @filename: New file name to save to or NULL to use current one. * * Save an instrument patch file * * Returns: SWAMI_OK on success, SWAMI_FAIL otherwise */ int swami_patch_save (SwamiObject *swami, IPItem *item, const char *filename) { IPSFontSaveHandle *handle; char *dir, *tmpfname, *prop_filename = NULL; char *s, *s2; int tmpfd; g_return_val_if_fail (swami != NULL, SWAMI_FAIL); g_return_val_if_fail (SWAMI_IS_OBJECT (swami), SWAMI_FAIL); g_return_val_if_fail (item != NULL, SWAMI_FAIL); if (item->type != IPITEM_SFONT) { SWAMI_PARAM_ERROR ("item"); return (SWAMI_FAIL); } /* set the software "edited" field */ s = swami_item_get_string (swami, item, "software"); if (s) { s2 = strchr (s, ':'); /* look for : separator */ if (s2) s2 = g_strndup (s, s2 - s + 1); else s2 = g_strconcat (s, ":", NULL); } else s2 = g_strconcat ("SWAMI v" VERSION, ":", NULL); g_free (s); s = g_strconcat (s2, "SWAMI v" VERSION, NULL); g_free (s2); swami_item_set_string (swami, item, "software", s); g_free (s); /* if no filename specified use current one */ if (!filename) { filename = prop_filename = swami_item_get_string (swami, item, "file_name"); if (!filename) { SWAMI_CRITICAL ("Patch file name is not set and none specified"); return (SWAMI_FAIL); } } /* get the destination directory and create a temporary file template */ dir = g_dirname (filename); tmpfname = g_strconcat (dir, G_DIR_SEPARATOR_S "swami_tmpXXXXXX", NULL); g_free (dir); /* string from g_dirname() needs to be freed */ /* open temporary file in same directory as destination */ #ifndef MINGW32 if ((tmpfd = mkstemp (tmpfname)) == -1) #else if (!mktemp (tmpfname) || (tmpfd = open (tmpfname, O_RDWR | O_BINARY | O_CREAT)) == -1) #endif { g_critical (_("Unable to open temp file '%s' for writing: %s"), tmpfname, g_strerror (errno)); g_free (tmpfname); if (prop_filename) g_free (prop_filename); return (SWAMI_FAIL); } if (!(handle = instp_sfont_save_new_handle ())) { close (tmpfd); if (unlink (tmpfname) == -1) g_warning (_("Could not delete temporary file '%s': %s"), tmpfname, g_strerror (errno)); g_free (tmpfname); if (prop_filename) g_free (prop_filename); return (SWAMI_FAIL); } instp_sfont_save_set_sfont (handle, INSTP_SFONT (item)); instp_sfont_save_set_fhandle (handle, tmpfd); /* save the sound font file with sample data migration */ if (instp_sfont_save (handle) != INSTP_OK) { instp_sfont_save_close_handle (handle); close (tmpfd); if (unlink (tmpfname) == -1) g_warning (_("Could not delete temporary file '%s': %s"), tmpfname, g_strerror (errno)); g_free (tmpfname); if (prop_filename) g_free (prop_filename); return (SWAMI_FAIL); } #ifdef MINGW32 /* win32 rename won't overwrite files, so just blindly unlink destination */ unlink (filename); #endif if (rename (tmpfname, filename) == -1) { g_critical (_("Failed to rename temp file to destination file name: %s"), g_strerror (errno)); instp_sfont_save_close_handle (handle); close (tmpfd); if (unlink (tmpfname) == -1) g_warning (_("Could not delete temporary file '%s': %s"), tmpfname, g_strerror (errno)); g_free (tmpfname); if (prop_filename) g_free (prop_filename); return (SWAMI_FAIL); } g_free (tmpfname); if (prop_filename) g_free (prop_filename); swami_item_set_string (swami, item, "file_name", filename); instp_sfont_save_migrate_samples (handle); instp_sfont_save_close_handle (handle); return (SWAMI_OK); } /** * swami_get_patch_list: * @swami: Swami object * * Get master patch file list * * Returns: Pointer to the first IPItem in master patch file list * (NULL if empty list). List should not be modified directly. */ IPItem * swami_get_patch_list (SwamiObject *swami) { g_return_val_if_fail (swami != NULL, NULL); g_return_val_if_fail (SWAMI_IS_OBJECT (swami), NULL); return (swami->patches); } /** * swami_item_insert: * @swami: Swami object owning patch object tree to insert into * @parent: Patch item to parent item to * @item: Patch item to insert * @pos: Position in parent's children to insert item * (0 to prepend, < 0 to append) * * Parents a patch item and inserts it at the given index position. * This function ensures global zones are inserted at pos 0 in their parent * list and that there aren't multiple ones. */ void swami_item_insert (SwamiObject *swami, IPItem *parent, IPItem *item, int pos) { g_return_if_fail (swami != NULL); g_return_if_fail (SWAMI_IS_OBJECT (swami)); g_return_if_fail (item != NULL); if (parent == NULL) /* toplevel patch object */ { if (item->type != IPITEM_SFONT) return; /* flag toplevel items as active (signals emitted by it and children) */ item->user_flags |= SWAMI_ITEM_FLAG_ACTIVE; swami->patches = instp_item_list_insert (swami->patches, item, pos); } else { /* check if item is a global zone */ if (item->type == IPITEM_ZONE && !INSTP_ZONE (item)->refitem) { /* check for duplicate global zone condition */ if ((parent->type == IPITEM_PRESET && INSTP_PRESET (parent)->zone && !INSTP_PRESET (parent)->zone->refitem) || (parent->type == IPITEM_INST && INSTP_INST (parent)->zone && !INSTP_INST (parent)->zone->refitem)) { SWAMI_CRITICAL ("Attempt to add global zone to parent that" " has one already"); return; } pos = 0; } instp_item_insert (parent, item, pos); } g_signal_emit (G_OBJECT (swami), swami_signals[ITEM_ADD], 0, item); swami_undo_save_item_new (swami, item); } /** * swami_item_insert_before: * @swami: Swami object owning patch object tree to insert into * @parent: Patch item to parent item to * @item: Patch item to insert * @sibling: Patch item to insert item before (NULL to append) * * Insert a patch item before another item */ void swami_item_insert_before (SwamiObject *swami, IPItem *parent, IPItem *item, IPItem *sibling) { g_return_if_fail (swami != NULL); g_return_if_fail (SWAMI_IS_OBJECT (swami)); g_return_if_fail (item != NULL); if (parent == NULL) /* toplevel patch object */ { if (item->type != IPITEM_SFONT) return; /* flag toplevel items as active (signals emitted by it and children) */ item->user_flags |= SWAMI_ITEM_FLAG_ACTIVE; swami->patches = instp_item_list_insert_before (swami->patches, item, sibling); } else instp_item_insert_before (parent, item, sibling); g_signal_emit (G_OBJECT (swami), swami_signals[ITEM_ADD], 0, item); swami_undo_save_item_new (swami, item); } /** * swami_item_remove: * @swami: Swami object owning sound font tree to remove item from * @item: Sound font item to remove * * Remove a sound font item. Item is actually just unlinked from the sound font * tree. Only when an item has no more references to it, is it deleted. */ void swami_item_remove (SwamiObject *swami, IPItem *item) { g_return_if_fail (swami != NULL); g_return_if_fail (SWAMI_IS_OBJECT (swami)); g_return_if_fail (item != NULL); g_signal_emit (G_OBJECT (swami), swami_signals[ITEM_REMOVE], 0, item); /* clear active flag, only for toplevel items, item and children will not emit signals */ item->user_flags &= ~SWAMI_ITEM_FLAG_ACTIVE; instp_item_unlink (item); } /** * swami_item_new: * @swami: Swami object to create new item in * @type: Type of item to create * @parent: Parent of new item or NULL for toplevel patch objects or * to create a stand alone item. * @first_property_name: Name of first item property to set or NULL to * not set any properties. * @...: Property value of first_property_name if it is not NULL * followed by property name/value pairs to assign to the new item. List is * terminated by a NULL name parameter. * * Creates a new item of the given type. If `parent' is given then the item is * added to the Swami patch tree and a unique item will automatically be * created if the item's ID properties are not explicitly set. For an * IPITEM_PRESET item the `bank' property can be assigned 128 to create a * unique percussion preset. If an item's ID properties are explicitly set * (`name' for IPITEM_INST and IPITEM_SAMPLE; `name', `bank', and `psetnum' * for IPITEM_PRESET for example) uniqueness is not ensured. * * Returns: The new item or NULL on error */ IPItem * swami_item_new (SwamiObject *swami, IPItemType type, IPItem *parent, const char *first_property_name, ...) { IPItem *item; va_list prop_args; va_start (prop_args, first_property_name); item = swami_item_new_valist (swami, type, parent, first_property_name, prop_args); va_end (prop_args); return (item); } /** * swami_item_new_valist: * @swami: Swami object to create new item in * @type: Type of item to create * @parent: Parent of new item or NULL for toplevel patch objects or * to create a stand alone item. * @first_property_name: Name of first item property to set or NULL to * not set any properties. * @prop_args: Variable argument list with value of first_property_name * if it is not NULL followed by property name/value pairs to assign to * the new item. List is terminated by a NULL name parameter. * * Create a new patch item with a va_list of property arguments. * Like swami_item_new() but uses a va_list for the property name/value * pairs. * * Returns: The new item or NULL on error */ IPItem * swami_item_new_valist (SwamiObject *swami, IPItemType type, IPItem *parent, const char *first_property_name, va_list prop_args) { IPItem *item; IPSFont *sf; IPPreset *preset; IPSample *sample; int bank, psetnum; char *name, *s; g_return_val_if_fail (swami != NULL, NULL); g_return_val_if_fail (SWAMI_IS_OBJECT (swami), NULL); /* create the new item */ if (!(item = instp_item_new (type))) return (NULL); /* set to out of range values to detect explicitly set properties */ if (type == IPITEM_PRESET && parent) { INSTP_PRESET (item)->psetnum = 0xFF; INSTP_PRESET (item)->bank = 0xFF; } if (first_property_name) swami_item_set_valist (swami, item, first_property_name, prop_args); switch (type) { case IPITEM_SFONT: sf = INSTP_SFONT (item); if (!instp_get_info (sf, IPINFO_NAME)) instp_set_info (sf, IPINFO_NAME, _("Untitled")); if (!sf->file_name) instp_set_file_name (sf, _("Untitled.sf2")); /* set the created software field */ s = g_strconcat ("SWAMI v" VERSION, ":", NULL); swami_item_set_string (swami, item, "software", s); g_free (s); break; case IPITEM_PRESET: if (parent) { preset = INSTP_PRESET (item); if (preset->bank == 0xFF || preset->psetnum == 0xFF) { bank = preset->bank; if (bank == 0xFF) bank = 0; psetnum = 0; instp_find_free_preset (INSTP_SFONT (parent), &bank, &psetnum); INSTP_PRESET (item)->bank = bank; INSTP_PRESET (item)->psetnum = psetnum; } if (!preset->name) /* name not explicitly set? */ { name = new_item_unique_name (INSTP_ITEM (INSTP_SFONT (parent)->preset), G_STRUCT_OFFSET (IPPreset, name)); instp_preset_set_name (INSTP_PRESET (item), name); g_free (name); } } break; case IPITEM_INST: if (parent && !INSTP_INST (item)->name) { name = new_item_unique_name (INSTP_ITEM (INSTP_SFONT (parent)->inst), G_STRUCT_OFFSET (IPInst, name)); instp_inst_set_name (INSTP_INST (item), name); g_free (name); } break; case IPITEM_SAMPLE: sample = INSTP_SAMPLE (item); /* point sample to blank sample data */ if (instp_sample_set_blank_data (INSTP_SAMPLE (item)) != INSTP_OK) { instp_item_destroy (item); return (NULL); } if (parent && !sample->name) { name = new_item_unique_name (INSTP_ITEM (INSTP_SFONT (parent)->sample), G_STRUCT_OFFSET (IPSample, name)); instp_sample_set_name (sample, name); g_free (name); } break; default: break; } /* add the item only if it has a parent or is a toplevel item */ if (parent || type == IPITEM_SFONT) swami_item_add (swami, parent, item); return (item); } /* create a new unique name among a list of sound font items. The name is generated from the string "New Item" with a number appended to it. name_offset is the offset into the IPItem object to the name field pointer for the given item type */ static char * new_item_unique_name (IPItem *list, int name_offset) { IPItem *p; gboolean used_numbers[10] = { FALSE }; long int val; int len, max = 0; char *name, *base_name, *endptr; /* TRANSLATORS: Please keep this string less than 15 characters */ base_name = _("New Item"); len = strlen (base_name); p = list; while (p) { name = G_STRUCT_MEMBER (char *, p, name_offset); if (strncmp (name, base_name, len) == 0) { if (*(name + len)) { val = strtol (name + len, &endptr, 10); if (!*endptr) /* valid integer? */ { if (val > 0 && val < 10) /* if 0 < val < 10 */ used_numbers[val] = TRUE; /* mark as used in array */ if (val > max) max = val; /* update max val */ } } else used_numbers[0] = TRUE; /* base name matches (with no number) */ } p = instp_item_next (p); } /* find first unused number between 0 and 9 */ for (val = 0; val < 10; val++) if (!used_numbers[val]) break; if (val == 10) val = max + 1; /* no numbers between 0-9? Use max + 1 */ if (val == 0) return (g_strdup (base_name)); else return (g_strdup_printf ("%s %ld", base_name, val)); } /** * swami_zone_set_gen: * @swami: Swami object * @zone: Sound font zone to set generator in * @genid: Generator ID to set value of * @amt: Amount to set generator to * * Set the value of a sound font zone generator */ void swami_zone_set_gen (SwamiObject *swami, IPZone *zone, guint16 genid, IPGenAmount amt) { g_return_if_fail (swami != NULL); g_return_if_fail (SWAMI_IS_OBJECT (swami)); g_return_if_fail (zone != NULL); instp_zone_set_gen (zone, genid, amt); } /** * swami_zone_unset_gen: * @swami: Swami object * @zone: Sound font zone to set generator in * @genid: Generator ID to unset value of * * Unset the value of a sound font zone generator */ void swami_zone_unset_gen (SwamiObject *swami, IPZone *zone, guint16 genid) { g_return_if_fail (swami != NULL); g_return_if_fail (SWAMI_IS_OBJECT (swami)); g_return_if_fail (zone != NULL); instp_zone_unset_gen (zone, genid); } /** * swami_item_get_zone_references: * @swami: Swami object * @item: Item to locate referencing zones of, must by of type IPInst or * IPSample and be parented to an IPSFont object. * * Get list of zones referencing an IPInst or IPSample * * Returns: List of referencing zones (NULL for no references) */ GList * swami_item_get_zone_references (SwamiObject *swami, IPItem *item) { IPSFont *sf; IPItem *p, *p2; GList *refitems = NULL; int itemofs; g_return_val_if_fail (swami != NULL, NULL); g_return_val_if_fail (SWAMI_IS_OBJECT (swami), NULL); g_return_val_if_fail (item != NULL, NULL); sf = INSTP_SFONT (instp_item_find_parent_by_type (item, IPITEM_SFONT)); if (!sf) SWAMI_PARAM_ERROR ("item"); if (item->type == IPITEM_INST) /* type is an instrument? */ { p = INSTP_ITEM (sf->preset); itemofs = G_STRUCT_OFFSET (IPPreset, zone); } else if (item->type == IPITEM_SAMPLE) /* item is a sample? */ { p = INSTP_ITEM (sf->inst); itemofs = G_STRUCT_OFFSET (IPInst, zone); } else /* bad item type! */ { SWAMI_PARAM_ERROR ("item"); return (NULL); } while (p) { /* a little optimization trick */ p2 = G_STRUCT_MEMBER (IPItem *, p, itemofs); while (p2) { if (INSTP_ZONE (p2)->refitem == item) refitems = g_list_append (refitems, p2); p2 = instp_item_next (p2); } p = instp_item_next (p); } return (refitems); } /** * swami_item_get_formatted_name: * @swami: Swami object * @item: Item to get formatted name of * * Get the formatted name ID of a sound font item * * Returns: Formatted name, \b free it when finished with it. */ char * swami_item_get_formatted_name (SwamiObject *swami, IPItem *item) { char *s, *s2, *s3; IPItem *ref; g_return_val_if_fail (swami != NULL, NULL); g_return_val_if_fail (SWAMI_IS_OBJECT (swami), NULL); g_return_val_if_fail (item != NULL, NULL); switch (item->type) { case IPITEM_SFONT: s2 = swami_item_get_string (swami, item, "name"); s3 = swami_item_get_string (swami, item, "file_name"); s = g_strdup_printf ("%s (%s)", s2, s3); g_free (s2); g_free (s3); break; case IPITEM_PRESET: s2 = swami_item_get_string (swami, item, "name"); s = g_strdup_printf ("%03d-%03d %s", swami_item_get_int (swami, item, "bank"), swami_item_get_int (swami, item, "psetnum"), s2); g_free (s2); break; case IPITEM_INST: s = swami_item_get_string (swami, item, "name"); break; case IPITEM_SAMPLE: s = swami_item_get_string (swami, item, "name"); break; case IPITEM_ZONE: ref = swami_item_get_pointer (swami, item, "refitem"); /* swami_item_get_string allocates the string for us, just use it */ if (ref) s = swami_item_get_string (swami, ref, "name"); else s = g_strdup (_("Global Zone")); break; default: s = NULL; break; } return (s); } /** * swami_item_set_valist: * @swami: Swami object that owns item * @item: Sound font item to set properties of * @first_property_name: First property name to set value of * @var_args: A variable argument list (va_list), first value in list * should be the value to set @first_property_name to, followed by name/value * pairs for each property to set, ending with a NULL property name. * * Set multiple properties of a sound font item using a va_list. */ void swami_item_set_valist (SwamiObject *swami, IPItem *item, const char *first_property_name, va_list var_args) { const char *name; g_return_if_fail (SWAMI_IS_OBJECT (swami)); g_return_if_fail (item != NULL); name = first_property_name; while (name) { GValue value = { 0, }; GParamSpec *pspec; char *error = NULL; pspec = item_lookup_param_spec (item, name); if (!pspec) break; g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec)); G_VALUE_COLLECT (&value, var_args, 0, &error); if (error) { g_warning ("%s: %s", G_STRLOC, error); g_free (error); /* we purposely leak the value here, it might not be * in a sane state if an error condition occoured */ break; } item_set_property (swami, item, pspec, &value, name); g_value_unset (&value); name = va_arg (var_args, char *); } } /** * swami_item_get_valist: * @swami: Swami object that owns item * @item: Sound font item to get properties of * @first_property_name: First property name to get value of * @var_args: A variable argument list (va_list), first value in list * should be a pointer to store the value of @first_property_name to, * followed by name/value ptr pairs for each property to get, ending with * a NULL property name. Each property value pointer should be a pointer to * the type for the given property (int * for integers, char ** for strings, * etc). * * Get multiple properties of a sound font item using a va_list. */ void swami_item_get_valist (SwamiObject *swami, IPItem *item, const char *first_property_name, va_list var_args) { const char *name; g_return_if_fail (SWAMI_IS_OBJECT (swami)); g_return_if_fail (item != NULL); name = first_property_name; while (name) { GValue value = { 0, }; GParamSpec *pspec; gchar *error = NULL; pspec = item_lookup_param_spec (item, name); if (!pspec) break; g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec)); item_get_property (swami, item, pspec, &value); G_VALUE_LCOPY (&value, var_args, 0, &error); if (error) { g_warning ("%s: %s", G_STRLOC, error); g_free (error); g_value_unset (&value); break; } g_value_unset (&value); name = va_arg (var_args, char *); } } /** * swami_item_set: * @swami: Swami object that owns item * @item: Sound font item to set properties of * @first_property_name: First property name to set value of * @Varargs: Variable list of arguments that should start with the * first value to set @first_property_name to, followed by name/value * pairs for each property to set, ending with a NULL property name. * * Set multiple properties of a sound font item. */ void swami_item_set (SwamiObject *swami, IPItem *item, const char *first_property_name, ...) { va_list var_args; va_start (var_args, first_property_name); swami_item_set_valist (swami, item, first_property_name, var_args); va_end (var_args); } /** * swami_item_get: * @swami: Swami object that owns item * @item: Sound font item to get properties of * @first_property_name: First property name to get value of * @Varargs: Variable list of arguments that should start with a * pointer to store the value of first_property_name to, followed by * name/value pointer pairs for each property to get, ending with a * NULL property name. Each property value pointer should be a pointer * to the type for the given property (int * for integers, char ** for * strings, etc). * * Get multiple properties of a sound font item. */ void swami_item_get (SwamiObject *swami, IPItem *item, const char *first_property_name, ...) { va_list var_args; va_start (var_args, first_property_name); swami_item_get_valist (swami, item, first_property_name, var_args); va_end (var_args); } /** * swami_item_set_property: * @swami: Swami object owning item * @item: Sound font item to set property of * @property_name: Property name ID * @value: Value to set property to (should match type for property_name) * * Set one property of a sound font item. */ void swami_item_set_property (SwamiObject *swami, IPItem *item, const char *property_name, GValue *value) { GParamSpec *pspec; g_return_if_fail (swami != NULL); g_return_if_fail (item != NULL); g_return_if_fail (property_name != NULL); g_return_if_fail (value != NULL); pspec = item_lookup_param_spec (item, property_name); if (!pspec) return; item_set_property (swami, item, pspec, value, property_name); } /** * swami_item_set_int: * @swami: Swami object * @item: Sound font item to set property of * @property_name: Name of property of type integer * @value: Value to set property to * * Set a sound font item's property of type integer */ void swami_item_set_int (SwamiObject *swami, IPItem *item, const char *property_name, int value) { GValue v = { 0, }; g_value_set_int (&v, value); swami_item_set_property (swami, item, property_name, &v); g_value_unset (&v); } /** * swami_item_set_float: * @swami: Swami object * @item: Sound font item to set property of * @property_name: Name of property of type float * @value: Value to set property to * * Set a sound font item's property of type float */ void swami_item_set_float (SwamiObject *swami, IPItem *item, const char *property_name, float value) { GValue v = { 0, }; g_value_set_float (&v, value); swami_item_set_property (swami, item, property_name, &v); g_value_unset (&v); } /** * swami_item_set_boolean: * @swami: Swami object * @item: Sound font item to set property of * @property_name: Name of property of type boolean * @value: Value to set property to * * Set a sound font item's property of type boolean */ void swami_item_set_boolean (SwamiObject *swami, IPItem *item, const char *property_name, gboolean value) { GValue v = { 0, }; g_value_set_boolean (&v, value); swami_item_set_property (swami, item, property_name, &v); g_value_unset (&v); } /** * swami_item_set_string: * @swami: Swami object * @item: Sound font item to set property of * @property_name: Name of property of type string * @value: Value to set property to * * Set a sound font item's property of type string */ void swami_item_set_string (SwamiObject *swami, IPItem *item, const char *property_name, const char *value) { GValue v = { 0, }; g_value_set_string (&v, (char *)value); swami_item_set_property (swami, item, property_name, &v); g_value_unset (&v); } /** * swami_item_set_pointer: * @swami: Swami object * @item: Sound font item to set property of * @property_name: Name of property of type pointer * @value: Pointer value to set property to * * Set a sound font item's property of type pointer */ void swami_item_set_pointer (SwamiObject *swami, IPItem *item, const char *property_name, const gpointer value) { GValue v = { 0, }; g_value_set_pointer (&v, value); swami_item_set_property (swami, item, property_name, &v); g_value_unset (&v); } /* FIXME! - Should out_value be initialized to type of property? */ /** * swami_item_get_property: * @swami: Swami object * @item: Sound font item to get property value from * @property_name: Property name to get value of * @out_value: Output: pointer to GValue to store the property's value in * * Get the value of a sound font item property * * Returns: TRUE on success, FALSE otherwise (invalid property) */ gboolean swami_item_get_property (SwamiObject *swami, const IPItem *item, const char *property_name, GValue *out_value) { GParamSpec *pspec; g_return_val_if_fail (swami != NULL, FALSE); g_return_val_if_fail (item != NULL, FALSE); g_return_val_if_fail (property_name != NULL, FALSE); g_return_val_if_fail (out_value != NULL, FALSE); pspec = item_lookup_param_spec (item, property_name); if (!pspec) return (FALSE); if (G_VALUE_TYPE (out_value) != G_PARAM_SPEC_VALUE_TYPE (pspec)) { g_warning ("%s: can't retrieve Swami item property `%s' of type `%s' as" " value of type `%s'", G_STRLOC, pspec->name, g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)), G_VALUE_TYPE_NAME (out_value)); return (FALSE); } return (item_get_property (swami, item, pspec, out_value)); } /** * swami_item_get_int: * @swami: Swami object * @item: Sound font item to get property of * @property_name: Name of property of type integer * * Get a sound font property value of type integer * * Returns: Property value */ int swami_item_get_int (SwamiObject *swami, const IPItem *item, const char *property_name) { GValue v = { 0, }; int retval = 0; g_value_init (&v, G_TYPE_INT); if (swami_item_get_property (swami, item, property_name, &v)) retval = g_value_get_int (&v); g_value_unset (&v); return (retval); } /** * swami_item_get_float: * @swami: Swami object * @item: Sound font item to get property of * @property_name: Name of property of type float * * Get a sound font property value of type float * * Returns: Property value */ float swami_item_get_float (SwamiObject *swami, const IPItem *item, const char *property_name) { GValue v = { 0, }; float retval = 0.0; g_value_init (&v, G_TYPE_FLOAT); if (swami_item_get_property (swami, item, property_name, &v)) retval = g_value_get_float (&v); g_value_unset (&v); return (retval); } /** * swami_item_get_boolean: * @swami: Swami object * @item: Sound font item to get property of * @property_name: Name of property of type boolean * * Get a sound font property value of type boolean * * Returns: Property value */ gboolean swami_item_get_boolean (SwamiObject *swami, const IPItem *item, const char *property_name) { GValue v = { 0, }; gboolean retval = FALSE; g_value_init (&v, G_TYPE_BOOLEAN); if (swami_item_get_property (swami, item, property_name, &v)) retval = g_value_get_boolean (&v); g_value_unset (&v); return (retval); } /** * swami_item_get_string: * @swami: Swami object * @item: Sound font item to get property of * @property_name: Name of property of type string * * Get a sound font property value of type string * * Returns: Property value, should be freed with g_free when done with */ char * swami_item_get_string (SwamiObject *swami, const IPItem *item, const char *property_name) { GValue v = { 0, }; char *retval = NULL; g_value_init (&v, G_TYPE_STRING); if (swami_item_get_property (swami, item, property_name, &v)) retval = g_strdup (g_value_get_string (&v)); g_value_unset (&v); return (retval); } /** * swami_item_get_pointer: * @swami: Swami object * @item: Sound font item to get property of * @property_name: Name of property of type pointer * * Get a sound font property value of type pointer * * Returns: Property value */ gpointer swami_item_get_pointer (SwamiObject *swami, const IPItem *item, const char *property_name) { GValue v = { 0, }; gpointer retval = NULL; g_value_init (&v, G_TYPE_POINTER); if (swami_item_get_property (swami, item, property_name, &v)) retval = g_value_get_pointer (&v); g_value_unset (&v); return (retval); } /* the real item set property function */ static void item_set_property (SwamiObject *swami, IPItem *item, GParamSpec *pspec, GValue *value, const char *property_name) { IPItem *root; IPSFont *sf; GType itemtype; gboolean changed = TRUE; int id; itemtype = SWAMI_ITEM_TYPE (item); id = PARAM_SPEC_PARAM_ID (pspec); /* check for properties of IPItem base type */ if (id == PROP_USER_DATA) item->userptr = g_value_get_pointer (value); switch (item->type) { case IPITEM_SFONT: sf = INSTP_SFONT (item); if (id >= PROP_INFO_VERSION && id <= PROP_INFO_SOFTWARE) { /* convert to info enumeration */ int infoid = id - PROP_INFO_VERSION + IPINFO_VERSION; if (infoid == IPINFO_VERSION || infoid == IPINFO_ROM_VERSION) { guint major, minor; if (sscanf (g_value_get_string (value), "%u.%u", &major, &minor) != 2) SWAMI_PARAM_ERROR ("value"); if (infoid == IPINFO_VERSION) { sf->version.major = major; sf->version.minor = minor; } else { sf->rom_version.major = major; sf->rom_version.minor = minor; } } else instp_set_info (sf, infoid, g_value_get_string (value)); } else { switch (id) { case PROP_CHANGED: sf->flag_changed = g_value_get_boolean (value); break; case PROP_SAVED: sf->flag_saved = g_value_get_boolean (value); break; case PROP_FILENAME: instp_set_file_name (sf, g_value_get_string (value)); break; default: SWAMI_OBJECT_WARN_INVALID_PROPERTY_ID (itemtype, pspec->name); changed = FALSE; break; } } break; case IPITEM_PRESET: switch (id) { case PROP_NAME: instp_preset_set_name (INSTP_PRESET (item), g_value_get_string (value)); break; case PROP_PSETNUM: INSTP_PRESET (item)->psetnum = g_value_get_int (value); break; case PROP_BANK: INSTP_PRESET (item)->bank = g_value_get_int (value); break; case PROP_LIBRARY: INSTP_PRESET (item)->library = g_value_get_uint (value); break; case PROP_GENRE: INSTP_PRESET (item)->genre = g_value_get_uint (value); break; case PROP_MORPHOLOGY: INSTP_PRESET (item)->morphology = g_value_get_uint (value); break; default: SWAMI_OBJECT_WARN_INVALID_PROPERTY_ID (itemtype, pspec->name); changed = FALSE; break; } break; case IPITEM_INST: if (id == PROP_NAME) instp_inst_set_name (INSTP_INST (item), g_value_get_string (value)); else { SWAMI_OBJECT_WARN_INVALID_PROPERTY_ID (itemtype, pspec->name); changed = FALSE; } break; case IPITEM_SAMPLE: switch (id) { case PROP_NAME: instp_sample_set_name (INSTP_SAMPLE (item), g_value_get_string (value)); break; case PROP_LOOPSTART: INSTP_SAMPLE (item)->loopstart = g_value_get_int (value); break; case PROP_LOOPEND: INSTP_SAMPLE (item)->loopend = g_value_get_int (value); break; case PROP_SAMPLERATE: INSTP_SAMPLE (item)->samplerate = g_value_get_int (value); break; case PROP_ORIGPITCH: INSTP_SAMPLE (item)->origpitch = g_value_get_int (value); break; case PROP_PITCHADJ: INSTP_SAMPLE (item)->pitchadj = g_value_get_int (value); break; default: SWAMI_OBJECT_WARN_INVALID_PROPERTY_ID (itemtype, pspec->name); changed = FALSE; break; } break; case IPITEM_ZONE: if (id == PROP_REFITEM) instp_zone_set_refitem (INSTP_ZONE (item), g_value_get_pointer (value)); else { SWAMI_OBJECT_WARN_INVALID_PROPERTY_ID (itemtype, pspec->name); changed = FALSE; } break; default: SWAMI_OBJECT_WARN_INVALID_PROPERTY_ID (itemtype, pspec->name); changed = FALSE; break; } /* only emit prop_change signal if item's root parent is active and property actually changed */ root = instp_item_find_root (item); if (changed && root->user_flags & SWAMI_ITEM_FLAG_ACTIVE) g_signal_emit (G_OBJECT (swami), swami_signals[ITEM_PROP_CHANGE], 0, item, property_name); } static gboolean item_get_property (SwamiObject *swami, const IPItem *item, GParamSpec *pspec, GValue *value) { IPSFont *sf; GType itemtype; int id, infoid; gboolean valid = TRUE; itemtype = SWAMI_ITEM_TYPE (item); id = PARAM_SPEC_PARAM_ID (pspec); /* check for properties of IPItem base type */ if (id == PROP_USER_DATA) g_value_set_pointer (value, item->userptr); switch (item->type) { case IPITEM_SFONT: sf = INSTP_SFONT (item); infoid = id - PROP_INFO_VERSION + IPINFO_VERSION; if (id >= PROP_INFO_VERSION && id <= PROP_INFO_SOFTWARE) { /* convert to info enumeration */ if (infoid == IPINFO_VERSION || infoid == IPINFO_ROM_VERSION) { IPSFontVersion *ver; char *s; if (infoid == IPINFO_VERSION) ver = &sf->version; else ver = &sf->rom_version; s = g_strdup_printf ("%d.%d", ver->major, ver->minor); g_value_set_string (value, s); g_free (s); } else g_value_set_string (value, instp_get_info (sf, infoid)); } else { switch (id) { case PROP_CHANGED: g_value_set_boolean (value, sf->flag_changed); break; case PROP_SAVED: g_value_set_boolean (value, sf->flag_saved); break; case PROP_FILENAME: g_value_set_string (value, sf->file_name); break; default: SWAMI_OBJECT_WARN_INVALID_PROPERTY_ID (itemtype, pspec->name); valid = FALSE; break; } } break; case IPITEM_PRESET: switch (id) { case PROP_NAME: g_value_set_string (value, INSTP_PRESET (item)->name); break; case PROP_PSETNUM: g_value_set_int (value, INSTP_PRESET (item)->psetnum); break; case PROP_BANK: g_value_set_int (value, INSTP_PRESET (item)->bank); break; case PROP_LIBRARY: g_value_set_uint (value, INSTP_PRESET (item)->library); break; case PROP_GENRE: g_value_set_uint (value, INSTP_PRESET (item)->genre); break; case PROP_MORPHOLOGY: g_value_set_uint (value, INSTP_PRESET (item)->morphology); break; default: SWAMI_OBJECT_WARN_INVALID_PROPERTY_ID (itemtype, pspec->name); valid = FALSE; break; } break; case IPITEM_INST: if (id == PROP_NAME) g_value_set_string (value, INSTP_INST (item)->name); else { SWAMI_OBJECT_WARN_INVALID_PROPERTY_ID (itemtype, pspec->name); valid = FALSE; } break; case IPITEM_SAMPLE: switch (id) { case PROP_NAME: g_value_set_string (value, INSTP_SAMPLE (item)->name); break; case PROP_SIZE: g_value_set_int (value, instp_sample_get_size (INSTP_SAMPLE (item))); break; case PROP_LOOPSTART: g_value_set_int (value, INSTP_SAMPLE (item)->loopstart); break; case PROP_LOOPEND: g_value_set_int (value, INSTP_SAMPLE (item)->loopend); break; case PROP_SAMPLERATE: g_value_set_int (value, INSTP_SAMPLE (item)->samplerate); break; case PROP_ORIGPITCH: g_value_set_int (value, INSTP_SAMPLE (item)->origpitch); break; case PROP_PITCHADJ: g_value_set_int (value, INSTP_SAMPLE (item)->pitchadj); break; default: SWAMI_OBJECT_WARN_INVALID_PROPERTY_ID (itemtype, pspec->name); valid = FALSE; break; } break; case IPITEM_ZONE: if (id == PROP_REFITEM) g_value_set_pointer (value, INSTP_ZONE (item)->refitem); else { SWAMI_OBJECT_WARN_INVALID_PROPERTY_ID (itemtype, pspec->name); valid = FALSE; } break; default: SWAMI_OBJECT_WARN_INVALID_PROPERTY_ID (itemtype, pspec->name); valid = FALSE; break; } return (valid); } static GParamSpec * item_lookup_param_spec (const IPItem *item, const char *name) { GParamSpec *pspec; pspec = g_param_spec_pool_lookup (pspec_pool, name, SWAMI_ITEM_TYPE (item), TRUE); if (!pspec) { g_warning ("%s: Swami item `%s' has no property named `%s'", G_STRLOC, g_type_name (SWAMI_ITEM_TYPE (item)), name); return (NULL); } return (pspec); }