/*================================================================== * item_paste.c - Patch item paste routines * * 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 *==================================================================*/ #include #include #include #include #include #include "SwamiUIObject.h" #include "SwamiUIProp.h" #include "glade_interface.h" #include "item_paste.h" #include "i18n.h" #include "util.h" /* bag structure used for item paste routine */ typedef struct { SwamiPasteStatus status; /* current status of paste */ IPItem *dstitem; /* destination patch item */ IPItem *dstpatch; /* destination root patch file */ GList *srcitems; /* source items */ GList *curitem; /* current source item being processed */ GHashTable *item_hash; /* hash of item relations (choices) */ GList *func_bags; /* recursive function variable bags */ IPItem *dupitem; /* when status == SWAMIUI_PASTE_DUPLICATE the source item causing duplicate */ IPItem *dupmatch; /* when status == SWAMIUI_PASTE_DUPLICATE the located item causing duplicate */ gpointer data; /* user definable data */ } ItemPasteBag; /* structure used to remember user decisions */ typedef struct { SwamiPasteStatus all; /* choice for all items or 0 for none */ GList *types; /* per type choices */ } RememberChoices; static void swamiui_paste_items_real (IPItem *dstitem, GList *items, void *handle); static void dup_item_dialog (void *handle, gchar *lbl1, ...); static gboolean paste_cb_dup_dialog_destroy (GtkWidget *dialog); static void paste_cb_choice (GtkWidget *btn, gpointer data); static void paste_cb_item_modify_cancel (GtkWidget *btn, GtkWidget *vbox); static void paste_cb_item_modify_change (GtkWidget *btn, GtkWidget *vbox); static void paste_GFunc_ref_items (gpointer data); static void paste_GFunc_unref_items (gpointer data); static IPItem *dup_preset (IPPreset *preset, ItemPasteBag *bag, GList *func_bag); static IPItem *dup_inst (IPInst *inst, ItemPasteBag *bag, GList *func_bag); static IPItem *dup_sample (IPSample *sample, ItemPasteBag *bag, GList *func_bag); static IPItem *new_preset_from_inst (IPInst *inst, ItemPasteBag *bag, GList *func_bag); static IPItem *new_inst_from_sample (IPSample *sample, ItemPasteBag *bag, GList *func_bag); static IPItem *paste_presetzone (IPItem *srcitem, ItemPasteBag *bag, GList *func_bag); static IPItem *paste_instzone (IPItem *srcitem, ItemPasteBag *bag, GList *func_bag); /** * Paste patch items user interface routine * @dstitem Destination patch item for paste * @items List of source patch items to paste to destination item. */ void swamiui_paste_items (IPItem *dstitem, GList *items) { swamiui_paste_items_real (dstitem, items, NULL); } /* the real user interface paste routine */ static void swamiui_paste_items_real (IPItem *dstitem, GList *items, void *handle) { void *h = handle; IPItem *dupitem, *dupmatch, *parent; RememberChoices *choices = NULL; char *s[10]; int bank, psetnum; char *type; GList *p; int i; if (h) choices = swamiui_paste_get_data (h); while (TRUE) { swamiui_paste_process (dstitem, items, &h); if (!h) break; swamiui_paste_get_dupinfo (h, &dupitem, &dupmatch); if (choices) { if (choices->all != 0) /* check for a "all" choice */ { swamiui_paste_set_choice (h, choices->all); continue; } p = choices->types; /* check per type choices */ while (p) { int type, choice; type = GPOINTER_TO_INT (p->data); choice = type >> 16; type &= 0xFFFF; if (dupitem->type == type) { swamiui_paste_set_choice (h, choice); break; } } if (p) continue; /* type matched? Then restart paste process */ } else { choices = g_malloc0 (sizeof (RememberChoices)); swamiui_paste_set_data (h, choices); } memset (s, 0, sizeof (s)); /* clear string pointers */ type = NULL; if (dupitem->type == IPITEM_ZONE) { dupitem = instp_item_parent (dupitem); dupmatch = instp_item_parent (dupmatch); if (dupitem->type == IPITEM_PRESET) type = _("Preset Global Zone"); else type = _("Instrument Global Zone"); } switch (dupitem->type) { case IPITEM_PRESET: swami_item_get (swami_object, dupitem, "name", &s[0], "bank", &bank, "psetnum", &psetnum, NULL); s[2] = g_strdup_printf ("%d", bank); s[4] = g_strdup_printf ("%d", psetnum); parent = instp_item_parent (dupitem); if (parent) swami_item_get (swami_object, parent, "name", &s[6], "file_name", &s[8], NULL); swami_item_get (swami_object, dupmatch, "name", &s[1], "bank", &bank, "psetnum", &psetnum, NULL); s[3] = g_strdup_printf ("%d", bank); s[5] = g_strdup_printf ("%d", psetnum); parent = instp_item_parent (dupmatch); if (parent) swami_item_get (swami_object, parent, "name", &s[7], "file_name", &s[9], NULL); if (!type) type = _("Preset"); dup_item_dialog (h, _("Type"), type, type, _("Name"), s[0], s[1], _("Bank"), s[2], s[3], _("Preset"), s[4], s[5], _("Patch"), s[6], s[7], _("File"), s[8], s[9], NULL); break; case IPITEM_INST: s[0] = swami_item_get_string (swami_object, dupmatch, "name"); parent = instp_item_parent (dupitem); if (parent) swami_item_get (swami_object, parent, "name", &s[2], "file_name", &s[4], NULL); s[1] = swami_item_get_string (swami_object, dupmatch, "name"); parent = instp_item_parent (dupmatch); if (parent) swami_item_get (swami_object, parent, "name", &s[3], "file_name", &s[5], NULL); if (!type) type = _("Instrument"); dup_item_dialog (h, _("Type"), type, type, _("Name"), s[0], s[1], _("Patch"), s[2], s[3], _("File"), s[4], s[5], NULL); break; case IPITEM_SAMPLE: s[0] = swami_item_get_string (swami_object, dupmatch, "name"); parent = instp_item_parent (dupitem); if (parent) swami_item_get (swami_object, parent, "name", &s[2], "file_name", &s[4], NULL); s[1] = swami_item_get_string (swami_object, dupmatch, "name"); parent = instp_item_parent (dupmatch); if (parent) swami_item_get (swami_object, parent, "name", &s[3], "file_name", &s[5], NULL); dup_item_dialog (h, _("Type"), _("Sample"), _("Sample"), _("Name"), s[0], s[1], _("Patch"), s[2], s[3], _("File"), s[4], s[5], NULL); break; default: SWAMI_CRITICAL ("Unhandled type"); break; } for (i=0; i < 10; i++) g_free (s[i]); /* free allocated strings */ return; /* return, dialog will re-start paste */ } if (choices) { g_list_free (choices->types); g_free (choices); } } /* creates duplicate item dialog and inserts label, src value and dest value triplet parameters. (gchar *lbl1, gchar *srcval1, gchar *dstval1, gchar *lbl2, ...) */ static void dup_item_dialog (void *handle, gchar *lbl1, ...) { GtkWidget *dialog; GtkWidget *btn; va_list ap; GtkText *src, *dst; gchar *s, *lbl, *val; dialog = create_glade_DupItem (); src = gtk_object_get_data (GTK_OBJECT (dialog), "TXTsrc"); dst = gtk_object_get_data (GTK_OBJECT (dialog), "TXTdst"); lbl = lbl1; va_start (ap, lbl1); while (lbl) { val = va_arg (ap, gchar *); if (val) { s = g_strconcat (lbl, ": ", val, "\n", NULL); gtk_text_insert (src, NULL, NULL, NULL, s, -1); g_free (s); } val = va_arg (ap, gchar *); if (val) { s = g_strconcat (lbl, ": ", val, "\n", NULL); gtk_text_insert (dst, NULL, NULL, NULL, s, -1); g_free (s); } lbl = va_arg (ap, gchar *); } gtk_object_set_data (GTK_OBJECT (dialog), "handle", handle); /* if dup window gets destroyed, cancel paste operation */ gtk_signal_connect (GTK_OBJECT (dialog), "destroy", GTK_SIGNAL_FUNC (paste_cb_dup_dialog_destroy), NULL); btn = gtk_object_get_data (GTK_OBJECT (dialog), "BTNKeep"); gtk_signal_connect (GTK_OBJECT (btn), "clicked", GTK_SIGNAL_FUNC (paste_cb_choice), GINT_TO_POINTER (SWAMIUI_PASTE_KEEP)); btn = gtk_object_get_data (GTK_OBJECT (dialog), "BTNSrcModify"); gtk_object_set_data (GTK_OBJECT (btn), "id", GINT_TO_POINTER (0)); gtk_signal_connect (GTK_OBJECT (btn), "clicked", GTK_SIGNAL_FUNC (paste_cb_choice), GINT_TO_POINTER (SWAMIUI_PASTE_CHANGE)); btn = gtk_object_get_data (GTK_OBJECT (dialog), "BTNDstModify"); gtk_object_set_data (GTK_OBJECT (btn), "id", GINT_TO_POINTER (1)); gtk_signal_connect (GTK_OBJECT (btn), "clicked", GTK_SIGNAL_FUNC (paste_cb_choice), GINT_TO_POINTER (SWAMIUI_PASTE_CHANGE)); gtk_widget_show (dialog); } static gboolean paste_cb_dup_dialog_destroy (GtkWidget *dialog) { void *handle; handle = gtk_object_get_data (GTK_OBJECT (dialog), "handle"); swamiui_paste_set_choice (handle, SWAMIUI_PASTE_CANCEL); swamiui_paste_items_real (NULL, NULL, handle); return (FALSE); } /* gets user choice from duplicate item dialog and restarts paste routine */ static void paste_cb_choice (GtkWidget *btnwidg, gpointer data) { GtkWidget *dialog; GtkWidget *widg; int choice = GPOINTER_TO_INT (data); void *handle; RememberChoices *choices; IPItem *dupitem, *dupmatch; int i; dialog = swamiui_util_lookup_widget (btnwidg, "glade_DupItem"); handle = gtk_object_get_data (GTK_OBJECT (dialog), "handle"); choices = swamiui_paste_get_data (handle); swamiui_paste_get_dupinfo (handle, &dupitem, &dupmatch); if (choice == SWAMIUI_PASTE_CHANGE) { GtkWidget *hidewidg; GtkWidget *prop; GtkWidget *vbox; GtkWidget *box; GtkWidget *btn; GtkWidget *lbl; IPItem *item; i = GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT (btnwidg), "id")); if (i != 1) /* Modify source item */ { i = 0; hidewidg = gtk_object_get_data (GTK_OBJECT (dialog), "VBOXSrc"); item = dupitem; } else /* Modify conflict item */ { hidewidg = gtk_object_get_data (GTK_OBJECT (dialog), "VBOXDst"); item = dupmatch; } gtk_widget_hide (hidewidg); vbox = gtk_vbox_new (FALSE, 2); gtk_object_set_data (GTK_OBJECT (vbox), "show", hidewidg); gtk_object_set_data (GTK_OBJECT (vbox), "dialog", dialog); box = gtk_object_get_data (GTK_OBJECT (dialog), "HBOXConflict"); gtk_box_pack_start (GTK_BOX (box), vbox, TRUE, TRUE, 0); gtk_box_reorder_child (GTK_BOX (box), vbox, i); prop = swamiui_prop_new (); gtk_object_set_data (GTK_OBJECT (vbox), "prop", prop); swamiui_prop_set_item (SWAMIUI_PROP (prop), item); gtk_widget_show (prop); gtk_box_pack_start (GTK_BOX (vbox), prop, TRUE, TRUE, 0); lbl = gtk_label_new (""); /* hidden label for error messages */ gtk_object_set_data (GTK_OBJECT (vbox), "label", lbl); gtk_box_pack_start (GTK_BOX (vbox), lbl, FALSE, FALSE, 0); box = gtk_hbox_new (FALSE, 0); gtk_widget_show (box); gtk_box_pack_start (GTK_BOX (vbox), box, FALSE, FALSE, 0); btn = gtk_button_new_with_label (_("Change")); gtk_signal_connect (GTK_OBJECT (btn), "clicked", GTK_SIGNAL_FUNC (paste_cb_item_modify_change), vbox); gtk_widget_show (btn); gtk_box_pack_start (GTK_BOX (box), btn, TRUE, TRUE, 0); btn = gtk_button_new_with_label (_("Cancel")); gtk_signal_connect (GTK_OBJECT (btn), "clicked", GTK_SIGNAL_FUNC (paste_cb_item_modify_cancel), vbox); gtk_widget_show (btn); gtk_box_pack_start (GTK_BOX (box), btn, TRUE, TRUE, 0); gtk_widget_show (vbox); return; } widg = gtk_object_get_data (GTK_OBJECT (dialog), "OPRemember"); switch (swamiui_util_option_menu_index (widg)) { case 1: /* Use choice for all items of same type */ i = dupitem->type | (choice << 16); choices->types = g_list_append (choices->types, GINT_TO_POINTER (i)); break; case 2: /* Remember choice for all items */ choices->all = choice; break; default: break; } gtk_signal_disconnect_by_func (GTK_OBJECT (dialog), GTK_SIGNAL_FUNC (paste_cb_dup_dialog_destroy), NULL); gtk_widget_destroy (dialog); swamiui_paste_set_choice (handle, choice); swamiui_paste_items_real (NULL, NULL, handle); } /* callback for item modify cancel button */ static void paste_cb_item_modify_cancel (GtkWidget *btn, GtkWidget *vbox) { GtkWidget *show; show = gtk_object_get_data (GTK_OBJECT (vbox), "show"); gtk_widget_destroy (vbox); gtk_widget_show (show); } /* callback for item modify change button */ static void paste_cb_item_modify_change (GtkWidget *btn, GtkWidget *vbox) { GtkWidget *dialog; GtkWidget *prop; void *handle; char *errmsg; dialog = gtk_object_get_data (GTK_OBJECT (vbox), "dialog"); handle = gtk_object_get_data (GTK_OBJECT (dialog), "handle"); prop = gtk_object_get_data (GTK_OBJECT (vbox), "prop"); if (swamiui_prop_commit (SWAMIUI_PROP (prop), &errmsg)) { gtk_signal_disconnect_by_func (GTK_OBJECT (dialog), GTK_SIGNAL_FUNC (paste_cb_dup_dialog_destroy), NULL); gtk_widget_destroy (dialog); swamiui_paste_set_choice (handle, SWAMIUI_PASTE_CHANGE); swamiui_paste_items_real (NULL, NULL, handle); } else /* failed for some reason, display error */ { GtkWidget *lbl; lbl = gtk_object_get_data (GTK_OBJECT (vbox), "label"); gtk_label_set_text (GTK_LABEL (lbl), errmsg); gtk_widget_show (lbl); } } /* * Non interactive paste patch process routine * @dstitem Destination patch item for paste * @items List of source patch items to paste to destination item. * @handle Pointer to store Paste handle to, which should be * initialized to NULL on first invocation. If function returns and * handle is not NULL then a status code is available and a decision * needs to be made. This function should then be re-invoked with * the same handle to begin where it left off using the new * decision. The other function parameters are not required on * successive invocations and are ignored. * Returns: SWAMI_OK on success or decision required (depending on value of * handle) or SWAMI_FAIL on error, in which case handle will be set to NULL. */ int swamiui_paste_process (IPItem *dstitem, GList *items, void **handle) { ItemPasteBag *bag; IPItem *srcpatch; int dsttype, srctype; IPItem *srcitem, *retitem; int retval = SWAMI_OK; g_return_val_if_fail (handle != NULL, SWAMI_FAIL); if (*handle == NULL) /* start? */ { /* no destination or no source item? */ if (!dstitem || !items) return (SWAMI_OK); /* make a copy of the source item list and add references since these will be reclaimed after this routine returns */ if (!swamiui_tree_item_is_dummy (dstitem)) instp_item_ref (dstitem); items = g_list_copy (items); g_list_foreach (items, (GFunc)paste_GFunc_ref_items, NULL); bag = g_malloc (sizeof (ItemPasteBag)); bag->status = SWAMIUI_PASTE_NORM; bag->dupitem = NULL; bag->dstitem = dstitem; bag->dstpatch = instp_item_find_root (bag->dstitem); bag->srcitems = items; bag->curitem = items; bag->item_hash = g_hash_table_new (NULL, NULL); bag->func_bags = NULL; *handle = bag; // sfdo_group (_("Paste sound font items")); } else bag = *handle; dsttype = bag->dstitem->type; while (bag->curitem) /* loop over source items */ { srcitem = INSTP_ITEM (bag->curitem->data); srctype = srcitem->type; srcpatch = instp_item_find_root (srcitem); if (srctype == IPITEM_PRESET && (dsttype == IPITEM_SFONT || dsttype == SWAMIUI_TREE_PRESET_ROOT || dsttype == SWAMIUI_TREE_PRESET_MELODIC || dsttype == SWAMIUI_TREE_PRESET_PERCUSS)) /* clone preset */ retitem = dup_preset (INSTP_PRESET (srcitem), bag, bag->func_bags); else if (srctype == IPITEM_INST /* clone instrument */ && (dsttype == IPITEM_SFONT || dsttype == SWAMIUI_TREE_INST_ROOT)) retitem = dup_inst (INSTP_INST (srcitem), bag, bag->func_bags); else if (srctype == IPITEM_SAMPLE && (dsttype == IPITEM_SFONT || dsttype == SWAMIUI_TREE_SAMPLE_ROOT || dsttype == SWAMIUI_TREE_SAMPLE_USER || dsttype == SWAMIUI_TREE_SAMPLE_ROM)) /* clone sample */ retitem = dup_sample (INSTP_SAMPLE (srcitem), bag, bag->func_bags); else if (dsttype == IPITEM_PRESET && /* paste preset zone */ (srctype == IPITEM_INST || srctype == IPITEM_ZONE)) retitem = paste_presetzone (srcitem, bag, bag->func_bags); else if (dsttype == IPITEM_INST && /* paste instrument zone */ (srctype == IPITEM_SAMPLE || srctype == IPITEM_ZONE)) retitem = paste_instzone (srcitem, bag, bag->func_bags); else if (srctype == IPITEM_INST /* create preset from instrument */ && (dsttype == SWAMIUI_TREE_PRESET_ROOT || dsttype == SWAMIUI_TREE_PRESET_MELODIC || dsttype == SWAMIUI_TREE_PRESET_PERCUSS)) retitem = new_preset_from_inst (INSTP_INST (srcitem), bag, bag->func_bags); else if (srctype == IPITEM_SAMPLE /* create instrument from sample */ && (dsttype == SWAMIUI_TREE_INST_ROOT)) retitem = new_inst_from_sample (INSTP_SAMPLE (srcitem), bag, bag->func_bags); /* choice needs to be made? */ if (bag->status == SWAMIUI_PASTE_DUPLICATE) return (SWAMI_OK); /* User requested Cancel or a function returned NULL */ if (bag->status == SWAMIUI_PASTE_CANCEL || !retitem) { if (bag->status != SWAMIUI_PASTE_CANCEL) /* error occured? */ retval = SWAMI_FAIL; // sfdo_retract (); /* undo partially copied selection */ break; } bag->status = SWAMIUI_PASTE_NORM; bag->curitem = g_list_next (bag->curitem); } // sfdo_done (); g_hash_table_destroy (bag->item_hash); /* unref items and destroy source list */ if (!swamiui_tree_item_is_dummy (bag->dstitem)) instp_item_unref (bag->dstitem); g_list_foreach (bag->srcitems, (GFunc)paste_GFunc_unref_items, NULL); g_list_free (bag->srcitems); g_free (bag); *handle = NULL; return (retval); } /* function to reference a GList of IPItems */ static void paste_GFunc_ref_items (gpointer data) { IPItem *item = data; if (!swamiui_tree_item_is_dummy (item)) instp_item_ref (item); } /* function to unreference a GList of IPItems */ static void paste_GFunc_unref_items (gpointer data) { IPItem *item = data; if (!swamiui_tree_item_is_dummy (item)) instp_item_unref (item); } /** * Get duplicate item info for a paste handle * @handle Paste handle returned from #swamiui_paste_process * @dupitem Pointer to store a pointer to the duplicate source item or * NULL * @dupmatch Pointer to store a pointer to the duplicate conflict item or * NULL */ void swamiui_paste_get_dupinfo (void *handle, IPItem **dupitem, IPItem **dupmatch) { ItemPasteBag *bag = handle; g_return_if_fail (handle != NULL); if (dupitem) *dupitem = bag->dupitem; if (dupmatch) *dupmatch = bag->dupmatch; } /** * Make a choice on a paste conflict * @handle Paste handle returned from #swamiui_paste_process * @choice The choice made for the current conflict */ void swamiui_paste_set_choice (void *handle, SwamiPasteStatus choice) { ItemPasteBag *bag = handle; g_return_if_fail (handle != NULL); bag->status = choice; } /** * Set custom pointer in paste handle * @handle Paste handle returned from #swamiui_paste_process * @data Value to set custom pointer field to */ void swamiui_paste_set_data (void *handle, gpointer data) { ItemPasteBag *bag = handle; g_return_if_fail (handle != NULL); bag->data = data; } /** * Get custom pointer from a paste handle * @handle Paste handle returned from #swamiui_paste_process * Returns: Value in custom pointer field */ gpointer swamiui_paste_get_data (void *handle) { ItemPasteBag *bag = handle; g_return_val_if_fail (handle != NULL, NULL); return (bag->data); } /* preset paste routine */ static IPItem * dup_preset (IPPreset *preset, ItemPasteBag *bag, GList *func_bag) { typedef struct { IPPreset *dup; IPSFont *srcsf; IPZone *curzone; gboolean check; } PresetPasteBag; PresetPasteBag *psetbag = NULL; IPPreset *checkdup; IPItem *inst, *retitem = NULL; if (!func_bag) { IPPreset *dup = instp_preset_duplicate (preset); if (!dup) return (NULL); psetbag = g_malloc (sizeof (PresetPasteBag)); psetbag->dup = dup; psetbag->srcsf = INSTP_SFONT (instp_item_find_root (INSTP_ITEM (preset))); psetbag->curzone = dup->zone; psetbag->check = FALSE; /* add to the list of function bags (variable structures) */ bag->func_bags = g_list_append (bag->func_bags, psetbag); func_bag = g_list_last (bag->func_bags); } else psetbag = (PresetPasteBag *)(func_bag->data); if (!psetbag->check) /* duplicate check done? */ { if (bag->status == SWAMIUI_PASTE_NORM || bag->status == SWAMIUI_PASTE_CHANGE) { /* check for duplicate preset (including itself) */ if ((checkdup = instp_find_preset (INSTP_SFONT (bag->dstpatch), psetbag->dup->name, psetbag->dup->bank, psetbag->dup->psetnum, NULL))) { bag->status = SWAMIUI_PASTE_DUPLICATE; bag->dupitem = INSTP_ITEM (psetbag->dup); bag->dupmatch = INSTP_ITEM (checkdup); return (NULL); /* return to wait for choice */ } } switch (bag->status) { case SWAMIUI_PASTE_KEEP: /* Keep existing duplicate preset */ instp_item_destroy (INSTP_ITEM (psetbag->dup)); retitem = bag->dupmatch; goto _cleanup; case SWAMIUI_PASTE_CANCEL: /* Cancel paste operation */ instp_item_destroy (INSTP_ITEM (psetbag->dup)); goto _cleanup; default: break; } psetbag->check = TRUE; /* flag duplicate check as done */ bag->status = SWAMIUI_PASTE_NORM; /* Reset mode */ } /* if src and dest sound font is different, copy instruments/samples too */ if ((void *)bag->dstpatch != (void *)psetbag->srcsf) { while (psetbag->curzone) /* loop over preset zones */ { /* if zone has an inst then duplicate it */ if (psetbag->curzone->refitem) { inst = dup_inst (INSTP_INST (psetbag->curzone->refitem), bag, func_bag->next); if (bag->status == SWAMIUI_PASTE_DUPLICATE) return (NULL); /* inst_paste() wants choice? */ else if (!inst || bag->status == SWAMIUI_PASTE_CANCEL) { /* catch error or cancel */ instp_item_destroy (INSTP_ITEM (psetbag->dup)); goto _cleanup; } bag->status = SWAMIUI_PASTE_NORM; /* Reset mode */ } else inst = NULL; /* assign instrument pointer */ instp_zone_set_refitem (psetbag->curzone, inst); psetbag->curzone = instp_zone_next (psetbag->curzone); } } /* add the duplicated preset to the destination sound font */ swami_item_add (swami_object, INSTP_ITEM (bag->dstpatch), INSTP_ITEM (psetbag->dup)); retitem = INSTP_ITEM (psetbag->dup); _cleanup: bag->func_bags = g_list_remove (bag->func_bags, psetbag); g_free (psetbag); return (retitem); } static IPItem * dup_inst (IPInst *inst, ItemPasteBag *bag, GList *func_bag) { typedef struct { IPInst *dup; IPSFont *srcsf; IPZone *curzone; gboolean check; } InstPasteBag; InstPasteBag *instbag = NULL; IPInst *checkdup; IPItem *sample, *retitem = NULL; if (!func_bag) { IPInst *dup; /* check if this instrument has already been processed */ if ((dup = g_hash_table_lookup (bag->item_hash, inst))) return (INSTP_ITEM (dup)); dup = instp_inst_duplicate (inst); if (!dup) return (NULL); instbag = g_malloc (sizeof (InstPasteBag)); instbag->dup = dup; instbag->srcsf = INSTP_SFONT (instp_item_find_root (INSTP_ITEM (inst))); instbag->curzone = dup->zone; instbag->check = FALSE; /* add to the list of function bags (variable structures) */ bag->func_bags = g_list_append (bag->func_bags, instbag); func_bag = g_list_last (bag->func_bags); } else instbag = (InstPasteBag *)(func_bag->data); if (!instbag->check) /* duplicate check done? */ { if (bag->status == SWAMIUI_PASTE_NORM || bag->status == SWAMIUI_PASTE_CHANGE) { /* check for duplicate inst (including itself) */ if ((checkdup = instp_find_inst (INSTP_SFONT (bag->dstpatch), instbag->dup->name, NULL))) { bag->status = SWAMIUI_PASTE_DUPLICATE; bag->dupitem = INSTP_ITEM (instbag->dup); bag->dupmatch = INSTP_ITEM (checkdup); return (NULL); /* return to wait for choice */ } } switch (bag->status) { case SWAMIUI_PASTE_KEEP: /* Keep existing duplicate inst */ instp_item_destroy (INSTP_ITEM (instbag->dup)); retitem = bag->dupmatch; goto _cleanup; case SWAMIUI_PASTE_CANCEL: /* Cancel paste operation */ instp_item_destroy (INSTP_ITEM (instbag->dup)); goto _cleanup; default: break; } instbag->check = TRUE; /* flag duplicate check as done */ bag->status = SWAMIUI_PASTE_NORM; /* Reset mode */ } /* if src and dest sound font is different, copy samples too */ if ((void *)bag->dstpatch != (void *)instbag->srcsf) { while (instbag->curzone) /* loop over inst zones */ { /* if zone has a sample then duplicate it */ if (instbag->curzone->refitem) { sample = dup_sample (INSTP_SAMPLE (instbag->curzone->refitem), bag, func_bag->next); if (bag->status == SWAMIUI_PASTE_DUPLICATE) return (NULL); /* dup_sample() wants choice? */ else if (!sample || bag->status == SWAMIUI_PASTE_CANCEL) { /* catch error or cancel */ instp_item_destroy (INSTP_ITEM (instbag->dup)); goto _cleanup; } bag->status = SWAMIUI_PASTE_NORM; /* Reset mode */ } else sample = NULL; /* assign instrument pointer */ instp_zone_set_refitem (instbag->curzone, sample); instbag->curzone = instp_zone_next (instbag->curzone); } } /* add the duplicated inst to the destination sound font */ swami_item_add (swami_object, INSTP_ITEM (bag->dstpatch), INSTP_ITEM (instbag->dup)); retitem = INSTP_ITEM (instbag->dup); _cleanup: bag->func_bags = g_list_remove (bag->func_bags, instbag); g_free (instbag); /* add the instrument relation to the item hash table */ if (retitem) g_hash_table_insert (bag->item_hash, inst, retitem); return (retitem); } static IPItem * dup_sample (IPSample *sample, ItemPasteBag *bag, GList *func_bag) { typedef struct { IPSample *dup; IPSFont *srcsf; } SamplePasteBag; SamplePasteBag *samplebag = NULL; IPSample *checkdup; IPItem *retitem = NULL; if (!func_bag) { IPSample *dup; /* check if sample has already been processed */ if ((dup = g_hash_table_lookup (bag->item_hash, sample))) return (INSTP_ITEM (dup)); dup = instp_sample_duplicate (sample); if (!dup) return (NULL); samplebag = g_malloc (sizeof (SamplePasteBag)); samplebag->dup = dup; samplebag->srcsf = INSTP_SFONT (instp_item_find_root (INSTP_ITEM (sample))); /* add to the list of function bags (variable structures) */ bag->func_bags = g_list_append (bag->func_bags, samplebag); func_bag = g_list_last (bag->func_bags); } else samplebag = (SamplePasteBag *)(func_bag->data); if (bag->status == SWAMIUI_PASTE_NORM || bag->status == SWAMIUI_PASTE_CHANGE) { /* check for duplicate sample (including itself) */ if ((checkdup = instp_find_sample (INSTP_SFONT (bag->dstpatch), samplebag->dup->name, NULL))) { bag->status = SWAMIUI_PASTE_DUPLICATE; bag->dupitem = INSTP_ITEM (samplebag->dup); bag->dupmatch = INSTP_ITEM (checkdup); return (NULL); /* return to wait for user input */ } } switch (bag->status) { case SWAMIUI_PASTE_KEEP: /* Keep existing duplicate sample */ instp_item_destroy (INSTP_ITEM (samplebag->dup)); retitem = bag->dupmatch; goto _cleanup; case SWAMIUI_PASTE_CANCEL: /* Cancel paste operation */ instp_item_destroy (INSTP_ITEM (samplebag->dup)); goto _cleanup; default: break; } /* add the duplicated sample to the destination sound font */ swami_item_add (swami_object, INSTP_ITEM (bag->dstpatch), INSTP_ITEM (samplebag->dup)); retitem = INSTP_ITEM (samplebag->dup); _cleanup: bag->func_bags = g_list_remove (bag->func_bags, samplebag); g_free (samplebag); /* add the sample relation to the item hash table */ if (retitem) g_hash_table_insert (bag->item_hash, sample, retitem); return (retitem); } static IPItem * new_preset_from_inst (IPInst *inst, ItemPasteBag *bag, GList *func_bag) { typedef struct { IPPreset *preset; IPSFont *srcsf; gboolean check; } PresetFromInstBag; PresetFromInstBag *pfibag; IPItem *item, *retitem = NULL; IPPreset *checkdup; IPZone *zone; if (!func_bag) { IPItem *preset; char *name; int bank = 0, psetnum = 0; name = swami_item_get_string (swami_object, INSTP_ITEM (inst), "name"); preset = swami_item_new (swami_object, IPITEM_PRESET, NULL, "name", name, NULL); g_free (name); if (!preset) return (NULL); /* create new percussion preset if percussion branch is the dest. */ if (bag->dstitem->type == SWAMIUI_TREE_PRESET_PERCUSS) INSTP_PRESET (preset)->bank = 128; /* find next available bank:psetnum */ instp_find_free_preset (INSTP_SFONT (bag->dstpatch), &bank, &psetnum); INSTP_PRESET (preset)->bank = bank; INSTP_PRESET (preset)->psetnum = psetnum; pfibag = g_malloc (sizeof (PresetFromInstBag)); pfibag->preset = INSTP_PRESET (preset); pfibag->srcsf = INSTP_SFONT (instp_item_find_root (INSTP_ITEM (inst))); pfibag->check = FALSE; /* add to the list of function bags (variable structures) */ bag->func_bags = g_list_append (bag->func_bags, pfibag); func_bag = g_list_last (bag->func_bags); } else pfibag = (PresetFromInstBag *)(func_bag->data); if (!pfibag->check) { if (bag->status == SWAMIUI_PASTE_NORM || bag->status == SWAMIUI_PASTE_CHANGE) { /* check for duplicate preset */ if ((checkdup = instp_find_preset (INSTP_SFONT (bag->dstpatch), pfibag->preset->name, pfibag->preset->bank, pfibag->preset->psetnum, NULL))) { bag->status = SWAMIUI_PASTE_DUPLICATE; bag->dupitem = INSTP_ITEM (pfibag->preset); bag->dupmatch = INSTP_ITEM (checkdup); return (NULL); /* return to wait for choice */ } } switch (bag->status) { case SWAMIUI_PASTE_KEEP: /* Keep existing duplicate preset */ instp_item_destroy (INSTP_ITEM (pfibag->preset)); retitem = bag->dupmatch; goto _cleanup; case SWAMIUI_PASTE_CANCEL: /* Cancel paste operation */ instp_item_destroy (INSTP_ITEM (pfibag->preset)); goto _cleanup; default: break; } pfibag->check = TRUE; /* flag duplicate check as done */ bag->status = SWAMIUI_PASTE_NORM; /* Reset mode */ } /* if src and dest sound font is different, copy instrument/samples too */ if ((void *)bag->dstpatch != (void *)pfibag->srcsf) { /* duplicate the instrument */ item = dup_inst (inst, bag, func_bag->next); if (bag->status == SWAMIUI_PASTE_DUPLICATE) return (NULL); /* inst_paste() wants choice? */ else if (!item || bag->status == SWAMIUI_PASTE_CANCEL) { /* catch cancel request or error */ instp_item_destroy (INSTP_ITEM (pfibag->preset)); goto _cleanup; } bag->status = SWAMIUI_PASTE_NORM; /* Reset mode */ } else item = INSTP_ITEM (inst); /* create new zone */ zone = instp_zone_new (); instp_zone_set_refitem (zone, item); instp_preset_add_zone (pfibag->preset, zone); /* add the new preset to the destination sound font */ swami_item_add (swami_object, INSTP_ITEM (bag->dstpatch), INSTP_ITEM (pfibag->preset)); retitem = INSTP_ITEM (pfibag->preset); _cleanup: bag->func_bags = g_list_remove (bag->func_bags, pfibag); g_free (pfibag); return (retitem); } static IPItem * new_inst_from_sample (IPSample *sample, ItemPasteBag *bag, GList *func_bag) { typedef struct { IPInst *inst; IPSFont *srcsf; gboolean check; } InstFromSampleBag; InstFromSampleBag *ifsbag; IPItem *item, *retitem = NULL; IPInst *checkdup; IPZone *zone; if (!func_bag) { IPItem *inst; char *name; name = swami_item_get_string (swami_object, INSTP_ITEM (sample), "name"); inst = swami_item_new (swami_object, IPITEM_INST, NULL, "name", name, NULL); g_free (name); if (!inst) return (NULL); ifsbag = g_malloc (sizeof (InstFromSampleBag)); ifsbag->inst = INSTP_INST (inst); ifsbag->srcsf = INSTP_SFONT (instp_item_find_root (INSTP_ITEM (sample))); ifsbag->check = FALSE; /* add to the list of function bags (variable structures) */ bag->func_bags = g_list_append (bag->func_bags, ifsbag); func_bag = g_list_last (bag->func_bags); } else ifsbag = (InstFromSampleBag *)(func_bag->data); if (!ifsbag->check) { if (bag->status == SWAMIUI_PASTE_NORM || bag->status == SWAMIUI_PASTE_CHANGE) { /* check for duplicate inst */ if ((checkdup = instp_find_inst (INSTP_SFONT (bag->dstpatch), ifsbag->inst->name, NULL))) { bag->status = SWAMIUI_PASTE_DUPLICATE; bag->dupitem = INSTP_ITEM (ifsbag->inst); bag->dupmatch = INSTP_ITEM (checkdup); return (NULL); /* return to wait for choice */ } } switch (bag->status) { case SWAMIUI_PASTE_KEEP: /* Keep existing duplicate inst */ instp_item_destroy (INSTP_ITEM (ifsbag->inst)); retitem = bag->dupmatch; goto _cleanup; case SWAMIUI_PASTE_CANCEL: /* Cancel paste operation */ instp_item_destroy (INSTP_ITEM (ifsbag->inst)); goto _cleanup; default: break; } ifsbag->check = TRUE; /* flag duplicate check as done */ bag->status = SWAMIUI_PASTE_NORM; /* Reset mode */ } /* if src and dest sound font is different, copy sample */ if ((void *)bag->dstpatch != (void *)ifsbag->srcsf) { /* duplicate the sample */ item = dup_sample (sample, bag, func_bag->next); if (bag->status == SWAMIUI_PASTE_DUPLICATE) return (NULL); /* sample_paste() wants choice? */ else if (!item || bag->status == SWAMIUI_PASTE_CANCEL) { /* catch cancel request or error */ instp_item_destroy (INSTP_ITEM (ifsbag->inst)); goto _cleanup; } bag->status = SWAMIUI_PASTE_NORM; /* Reset mode */ } else item = INSTP_ITEM (sample); /* create new zone */ zone = instp_zone_new (); instp_zone_set_refitem (zone, item); instp_inst_add_zone (ifsbag->inst, zone); /* add the new instrument to the destination sound font */ swami_item_add (swami_object, INSTP_ITEM (bag->dstpatch), INSTP_ITEM (ifsbag->inst)); retitem = INSTP_ITEM (ifsbag->inst); _cleanup: bag->func_bags = g_list_remove (bag->func_bags, ifsbag); g_free (ifsbag); return (retitem); } /* preset zone paste */ static IPItem * paste_presetzone (IPItem *srcitem, ItemPasteBag *bag, GList *func_bag) { IPSFont *srcsf; IPItem *inst; IPZone *zone; IPPreset *dstpreset; srcsf = INSTP_SFONT (instp_item_find_root (srcitem)); dstpreset = INSTP_PRESET (bag->dstitem); if (srcitem->type == IPITEM_INST) /* item is an instrument? */ { if ((void *)bag->dstpatch != (void *)srcsf) /* diff SF, dup inst */ { inst = dup_inst (INSTP_INST (srcitem), bag, func_bag); if (!inst) return (NULL); } else inst = srcitem; zone = instp_zone_new (); if (!zone) return (NULL); } else if (srcitem->type == IPITEM_ZONE) /* item is a zone? */ { inst = INSTP_ZONE (srcitem)->refitem; if (inst) /* Global Zone? */ { if ((void *)bag->dstpatch != (void *)srcsf) /* diff SF, dup inst */ { inst = dup_inst (INSTP_INST (inst), bag, func_bag); if (!inst) return (NULL); } } else /* its a global zone */ { if (bag->status == SWAMIUI_PASTE_NORM) { /* preset already has Global Zone? */ if (dstpreset->zone && !dstpreset->zone->refitem) { bag->status = SWAMIUI_PASTE_DUPLICATE; bag->dupitem = srcitem; bag->dupmatch = INSTP_ITEM (dstpreset->zone); return (NULL); /* return to wait for choice */ } } else if (bag->status == SWAMIUI_PASTE_KEEP) return (bag->dupmatch); inst = NULL; } if (bag->status == SWAMIUI_PASTE_CANCEL) /* catch cancel request */ return (NULL); zone = instp_zone_duplicate (srcitem); /* duplicate the zone */ } instp_zone_set_refitem (INSTP_ZONE (zone), inst); swami_item_add (swami_object, bag->dstitem, INSTP_ITEM (zone)); return (INSTP_ITEM (zone)); } /* instrument zone paste */ static IPItem * paste_instzone (IPItem *srcitem, ItemPasteBag *bag, GList *func_bag) { IPSFont *srcsf; IPItem *sample; IPZone *zone; IPInst *dstinst; srcsf = INSTP_SFONT (instp_item_find_root (srcitem)); dstinst = INSTP_INST (bag->dstitem); if (srcitem->type == IPITEM_SAMPLE) /* item is a sample? */ { if ((void *)bag->dstpatch != (void *)srcsf) /* diff SF, dup sample */ { sample = dup_sample (INSTP_SAMPLE (srcitem), bag, func_bag); if (!sample) return (NULL); } else sample = srcitem; zone = instp_zone_new (); if (!zone) return (NULL); } else if (srcitem->type == IPITEM_ZONE) /* item is a zone? */ { sample = INSTP_ZONE (srcitem)->refitem; if (sample) /* Global Zone? */ { if ((void *)bag->dstpatch != (void *)srcsf) /* diff SF, dup sample */ { sample = dup_sample (INSTP_SAMPLE (sample), bag, func_bag); if (!sample) return (NULL); } } else /* its a global zone */ { if (bag->status == SWAMIUI_PASTE_NORM) { /* instrument already has Global Zone? */ if (dstinst->zone && !dstinst->zone->refitem) { bag->status = SWAMIUI_PASTE_DUPLICATE; bag->dupitem = srcitem; bag->dupmatch = INSTP_ITEM (dstinst->zone); return (NULL); /* return to wait for choice */ } } else if (bag->status == SWAMIUI_PASTE_KEEP) return (bag->dupmatch); sample = NULL; } if (bag->status == SWAMIUI_PASTE_CANCEL) /* catch cancel request */ return (NULL); zone = instp_zone_duplicate (srcitem); /* duplicate the zone */ } instp_zone_set_refitem (INSTP_ZONE (zone), sample); swami_item_add (swami_object, bag->dstitem, INSTP_ITEM (zone)); return (INSTP_ITEM (zone)); }