/*================================================================== * SwamiUIModEdit.c - User interface generator control 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 *==================================================================*/ #include #include #include #include #include "SwamiUIModEdit.h" #include "SwamiUIObject.h" #include "glade_interface.h" #include "widgets/pixmap-combo.h" #include "pixmap.h" #include "util.h" #include "i18n.h" /* Modulator General Controller palette descriptions */ struct { int ctrlnum; char *descr; } modctrl_descr[] = { { IPMOD_CONTROL_NONE, N_("No Controller") }, { IPMOD_CONTROL_NOTE_ON_VELOCITY, N_("Note-On Velocity") }, { IPMOD_CONTROL_KEY_NUMBER, N_("Note-On Key Number") }, { IPMOD_CONTROL_POLY_PRESSURE, N_("Poly Pressure") }, { IPMOD_CONTROL_CHAN_PRESSURE, N_("Channel Pressure") }, { IPMOD_CONTROL_PITCH_WHEEL, N_("Pitch Wheel") }, { IPMOD_CONTROL_BEND_RANGE, N_("Bend Range") } }; #define MODCTRL_DESCR_COUNT \ (sizeof (modctrl_descr) / sizeof (modctrl_descr[0])) /* MIDI Continuous Controller descriptions */ struct { int ctrlnum; char *descr; } midicc_descr[] = { { 1, N_("Modulation") }, { 2, N_("Breath Controller") }, { 3, N_("Undefined") }, { 4, N_("Foot Controller") }, { 5, N_("Portamento Time") }, { 7, N_("Main Volume") }, { 8, N_("Balance") }, { 9, N_("Undefined") }, { 10, N_("Panpot") }, { 11, N_("Expression Pedal") }, { 12, N_("Effect Control 1") }, { 13, N_("Effect Control 2") }, { 14, N_("Undefined") }, { 15, N_("Undefined") }, { 16, N_("General Purpose 1") }, { 17, N_("General Purpose 2") }, { 18, N_("General Purpose 3") }, { 19, N_("General Purpose 4") }, /* 20-31 Undefined, 33-63 LSB for controllers 1-31 */ { 64, N_("Hold 1 (Damper)") }, { 65, N_("Portamento") }, { 66, N_("Sostenuto") }, { 67, N_("Soft Pedal") }, { 68, N_("Undefined") }, { 69, N_("Hold 2 (Freeze)") }, /* 70-79 Undefined */ { 80, N_("General Purpose 5") }, { 81, N_("General Purpose 6") }, { 82, N_("General Purpose 7") }, { 83, N_("General Purpose 8") }, /* 84-90 Undefined */ { 91, N_("Effect 1 (Reverb)") }, { 92, N_("Effect 2 (Tremolo)") }, { 93, N_("Effect 3 (Chorus)") }, { 94, N_("Effect 4 (Celeste)") }, { 95, N_("Effect 5 (Phaser)") }, { 96, N_("Data Increment") }, { 97, N_("Data Decrement") } /* 102-119 Undefined */ }; #define MIDICC_DESCR_COUNT (sizeof (midicc_descr) / sizeof (midicc_descr[0])) char *modgroup_names[] = { N_("Sample"), N_("Pitch/Effects"), N_("Volume Envelope"), N_("Modulation Envelope"), N_("Modulation LFO"), N_("Vibrato LFO") }; #define MODGROUP_COUNT (sizeof (modgroup_names) / sizeof (modgroup_names[0])) #define MODGROUP_SEPARATOR (-1) int modgroup_gens[] = { /* Sample group */ IPGEN_START_ADDR_OFS, IPGEN_START_ADDR_COARSE_OFS, IPGEN_END_ADDR_OFS, IPGEN_END_ADDR_COARSE_OFS, IPGEN_START_LOOP_ADDR_OFS, IPGEN_START_LOOP_ADDR_COARSE_OFS, IPGEN_END_LOOP_ADDR_OFS, IPGEN_END_LOOP_ADDR_COARSE_OFS, MODGROUP_SEPARATOR, /* Pitch/Effects group */ IPGEN_COARSE_TUNE, IPGEN_FINE_TUNE, IPGEN_FILTER_Q, IPGEN_FILTER_FC, IPGEN_REVERB_SEND, IPGEN_CHORUS_SEND, IPGEN_PAN, MODGROUP_SEPARATOR, /* Volumen Envelope group */ IPGEN_VOL_ENV_DELAY, IPGEN_VOL_ENV_ATTACK, IPGEN_VOL_ENV_HOLD, IPGEN_VOL_ENV_DECAY, IPGEN_VOL_ENV_SUSTAIN, IPGEN_VOL_ENV_RELEASE, IPGEN_ATTENUATION, IPGEN_KEY_TO_VOL_ENV_HOLD, IPGEN_KEY_TO_VOL_ENV_DECAY, MODGROUP_SEPARATOR, /* Modulation Envelope group */ IPGEN_MOD_ENV_DELAY, IPGEN_MOD_ENV_ATTACK, IPGEN_MOD_ENV_HOLD, IPGEN_MOD_ENV_DECAY, IPGEN_MOD_ENV_SUSTAIN, IPGEN_MOD_ENV_RELEASE, IPGEN_MOD_ENV_TO_PITCH, IPGEN_MOD_ENV_TO_FILTER_FC, IPGEN_KEY_TO_MOD_ENV_HOLD, IPGEN_KEY_TO_MOD_ENV_DECAY, MODGROUP_SEPARATOR, /* Modulation LFO group */ IPGEN_MOD_LFO_DELAY, IPGEN_MOD_LFO_FREQ, IPGEN_MOD_LFO_TO_PITCH, IPGEN_MOD_LFO_TO_FILTER_FC, IPGEN_MOD_LFO_TO_VOL, MODGROUP_SEPARATOR, /* Vibrato LFO group */ IPGEN_VIB_LFO_DELAY, IPGEN_VIB_LFO_FREQ, IPGEN_VIB_LFO_TO_PITCH, MODGROUP_SEPARATOR }; #define MODGROUP_GENS_SIZE (sizeof (modgroup_gens) / sizeof (modgroup_gens[0])) /* elements for source modulator transform pixmap combo widget */ static PixmapComboElement modtransform_elements[] = { { N_("Linear Positive Unipolar"), mod_linear_PU_xpm, IPMOD_TYPE_LINEAR | IPMOD_DIRECTION_POSITIVE | IPMOD_POLARITY_UNIPOLAR }, { N_("Linear Negative Unipolar"), mod_linear_NU_xpm, IPMOD_TYPE_LINEAR | IPMOD_DIRECTION_NEGATIVE | IPMOD_POLARITY_UNIPOLAR }, { N_("Linear Positive Bipolar"), mod_linear_PB_xpm, IPMOD_TYPE_LINEAR | IPMOD_DIRECTION_POSITIVE | IPMOD_POLARITY_BIPOLAR }, { N_("Linear Negative Bipolar"), mod_linear_NB_xpm, IPMOD_TYPE_LINEAR | IPMOD_DIRECTION_NEGATIVE | IPMOD_POLARITY_BIPOLAR }, { N_("Concave Positive Unipolar"), mod_concave_PU_xpm, IPMOD_TYPE_CONCAVE | IPMOD_DIRECTION_POSITIVE | IPMOD_POLARITY_UNIPOLAR }, { N_("Concave Negative Unipolar"), mod_concave_NU_xpm, IPMOD_TYPE_CONCAVE | IPMOD_DIRECTION_NEGATIVE | IPMOD_POLARITY_UNIPOLAR }, { N_("Concave Positive Bipolar"), mod_concave_PB_xpm, IPMOD_TYPE_CONCAVE | IPMOD_DIRECTION_POSITIVE | IPMOD_POLARITY_BIPOLAR }, { N_("Concave Negative Bipolar"), mod_concave_NB_xpm, IPMOD_TYPE_CONCAVE | IPMOD_DIRECTION_NEGATIVE | IPMOD_POLARITY_BIPOLAR }, { N_("Convex Positive Unipolar"), mod_convex_PU_xpm, IPMOD_TYPE_CONVEX | IPMOD_DIRECTION_POSITIVE | IPMOD_POLARITY_UNIPOLAR }, { N_("Convex Negative Unipolar"), mod_convex_NU_xpm, IPMOD_TYPE_CONVEX | IPMOD_DIRECTION_NEGATIVE | IPMOD_POLARITY_UNIPOLAR }, { N_("Convex Positive Bipolar"), mod_convex_PB_xpm, IPMOD_TYPE_CONVEX | IPMOD_DIRECTION_POSITIVE | IPMOD_POLARITY_BIPOLAR }, { N_("Convex Negative Bipolar"), mod_convex_NB_xpm, IPMOD_TYPE_CONVEX | IPMOD_DIRECTION_NEGATIVE | IPMOD_POLARITY_BIPOLAR }, { N_("Switch Positive Unipolar"), mod_switch_PU_xpm, IPMOD_TYPE_SWITCH | IPMOD_DIRECTION_POSITIVE | IPMOD_POLARITY_UNIPOLAR }, { N_("Switch Negative Unipolar"), mod_switch_NU_xpm, IPMOD_TYPE_SWITCH | IPMOD_DIRECTION_NEGATIVE | IPMOD_POLARITY_UNIPOLAR }, { N_("Switch Positive Bipolar"), mod_switch_PB_xpm, IPMOD_TYPE_SWITCH | IPMOD_DIRECTION_POSITIVE | IPMOD_POLARITY_BIPOLAR }, { N_("Switch Negative Bipolar"), mod_switch_NB_xpm, IPMOD_TYPE_SWITCH | IPMOD_DIRECTION_NEGATIVE | IPMOD_POLARITY_BIPOLAR } }; static void swamiui_modedit_class_init (SwamiUIModEditClass *klass); static void swamiui_modedit_init (SwamiUIModEdit *modedit); static void swamiui_modedit_cb_mod_select (GtkCList *clist, gint row, gint col, GdkEventButton *event, SwamiUIModEdit *modedit); void swamiui_modedit_cb_new_clicked (GtkButton *btn, SwamiUIModEdit *modedit); void swamiui_modedit_cb_delete_clicked (GtkButton *btn, SwamiUIModEdit *modedit); static void swamiui_modedit_cb_group_select (GtkMenuShell *menushell, SwamiUIModEdit *modedit); static void swamiui_modedit_cb_gen_select (GtkMenuShell *menushell, SwamiUIModEdit *modedit); static void swamiui_modedit_cb_pixcombo_changed (PixmapCombo *pixcombo, int id, SwamiUIModEdit *modedit); static void swamiui_modedit_cb_combo_list_select (GtkList *list, GtkWidget *litem, SwamiUIModEdit *modedit); static void swamiui_modedit_cb_amtsrc_changed (GtkAdjustment *adj, SwamiUIModEdit *modedit); static void swamiui_modedit_add_source_combo_strings (GtkCombo *combo); static void swamiui_modedit_update (SwamiUIModEdit *modedit); static void swamiui_modedit_update_mod (SwamiUIModEdit *modedit, IPMod *mod, gboolean apply_global); static void swamiui_modedit_set_mod (SwamiUIModEdit *modedit, IPMod *mod, gboolean force); static gint swamiui_modedit_find_ctrl (gconstpointer a, gconstpointer ctrlnum); static char *swamiui_modedit_get_control_name (guint16 modsrc); static char **swamiui_modedit_find_transform_pixmap (guint16 modsrc); static int swamiui_modedit_find_gen_group (int genid, int *index); guint swamiui_modedit_get_type (void) { static guint obj_type = 0; if (!obj_type) { GtkTypeInfo obj_info = { "SwamiUIModEdit", sizeof (SwamiUIModEdit), sizeof (SwamiUIModEditClass), (GtkClassInitFunc) swamiui_modedit_class_init, (GtkObjectInitFunc) swamiui_modedit_init, (GtkArgSetFunc) NULL, (GtkArgGetFunc) NULL, }; obj_type = gtk_type_unique (gtk_scrolled_window_get_type (), &obj_info); } return obj_type; } static void swamiui_modedit_class_init (SwamiUIModEditClass *klass) { } static void swamiui_modedit_init (SwamiUIModEdit *modedit) { GtkWidget *glade_widg; GtkWidget *pixmap; GtkWidget *pixcombo; GtkWidget *menu; GtkWidget *mitem; GtkWidget *widg; int i, i2; gtk_scrolled_window_set_hadjustment (GTK_SCROLLED_WINDOW (modedit), NULL); gtk_scrolled_window_set_vadjustment (GTK_SCROLLED_WINDOW (modedit), NULL); gtk_container_border_width (GTK_CONTAINER (modedit), 0); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (modedit), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); modedit->zone = NULL; modedit->mod = NULL; modedit->global_mods = FALSE; modedit->block_callbacks = FALSE; glade_widg = create_glade_ModEdit (); glade_widg = swamiui_util_rip_guts (glade_widg, "glade_ModEdit"); modedit->glade_widg = glade_widg; /* set up modulator clist widget */ widg = gtk_object_get_data (GTK_OBJECT (glade_widg), "CLSTMod"); gtk_clist_set_column_auto_resize (GTK_CLIST (widg), 0, TRUE); gtk_clist_set_column_auto_resize (GTK_CLIST (widg), 1, TRUE); gtk_clist_set_column_auto_resize (GTK_CLIST (widg), 2, TRUE); gtk_clist_set_column_auto_resize (GTK_CLIST (widg), 3, TRUE); gtk_signal_connect (GTK_OBJECT (widg), "select-row", GTK_SIGNAL_FUNC (swamiui_modedit_cb_mod_select), modedit); gtk_signal_connect (GTK_OBJECT (widg), "unselect-row", GTK_SIGNAL_FUNC (swamiui_modedit_cb_mod_select), modedit); /* configure callbacks on action buttons */ widg = gtk_object_get_data (GTK_OBJECT (glade_widg), "BTNNew"); gtk_signal_connect (GTK_OBJECT (widg), "clicked", GTK_SIGNAL_FUNC (swamiui_modedit_cb_new_clicked), modedit); widg = gtk_object_get_data (GTK_OBJECT (glade_widg), "BTNDel"); gtk_signal_connect (GTK_OBJECT (widg), "clicked", GTK_SIGNAL_FUNC (swamiui_modedit_cb_delete_clicked), modedit); /* nice modulator junction pixmap */ pixmap = swamiui_util_create_pixmap (mod_junct_xpm); gtk_widget_show (pixmap); widg = gtk_object_get_data (GTK_OBJECT (glade_widg), "HBXPixmap"); gtk_box_pack_start (GTK_BOX (widg), pixmap, FALSE, 0, 0); gtk_box_reorder_child (GTK_BOX (widg), pixmap, 0); /* create source modulator pixmap combo */ pixcombo = pixmap_combo_new (modtransform_elements, 4, 4); gtk_widget_show (pixcombo); gtk_object_set_data (GTK_OBJECT (glade_widg), "PIXSrc", pixcombo); widg = gtk_object_get_data (GTK_OBJECT (glade_widg), "HBXSrc"); gtk_box_pack_start (GTK_BOX (widg), pixcombo, FALSE, 0, 0); gtk_box_reorder_child (GTK_BOX (widg), pixcombo, 0); gtk_signal_connect (GTK_OBJECT (pixcombo), "changed", GTK_SIGNAL_FUNC (swamiui_modedit_cb_pixcombo_changed), modedit); /* create amount source modulator pixmap combo */ pixcombo = pixmap_combo_new (modtransform_elements, 4, 4); gtk_widget_show (pixcombo); gtk_object_set_data (GTK_OBJECT (glade_widg), "PIXAmtSrc", pixcombo); widg = gtk_object_get_data (GTK_OBJECT (glade_widg), "HBXAmtSrc"); gtk_box_pack_start (GTK_BOX (widg), pixcombo, FALSE, 0, 0); gtk_box_reorder_child (GTK_BOX (widg), pixcombo, 0); gtk_signal_connect (GTK_OBJECT (pixcombo), "changed", GTK_SIGNAL_FUNC (swamiui_modedit_cb_pixcombo_changed), modedit); /* add modulator source controller description strings to combos */ widg = gtk_object_get_data (GTK_OBJECT (glade_widg), "COMSrcCtrl"); swamiui_modedit_add_source_combo_strings (GTK_COMBO (widg)); gtk_signal_connect (GTK_OBJECT (GTK_COMBO (widg)->list), "select-child", GTK_SIGNAL_FUNC (swamiui_modedit_cb_combo_list_select), modedit); widg = gtk_object_get_data (GTK_OBJECT (glade_widg), "COMAmtCtrl"); swamiui_modedit_add_source_combo_strings (GTK_COMBO (widg)); gtk_signal_connect (GTK_OBJECT (GTK_COMBO (widg)->list), "select-child", GTK_SIGNAL_FUNC (swamiui_modedit_cb_combo_list_select), modedit); /* add value changed signal to amount spin button */ widg = gtk_object_get_data (GTK_OBJECT (glade_widg), "SPBAmount"); gtk_signal_connect (GTK_OBJECT (gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (widg))), "value-changed", GTK_SIGNAL_FUNC (swamiui_modedit_cb_amtsrc_changed), modedit); /* add generator groups to option menu */ widg = gtk_object_get_data (GTK_OBJECT (glade_widg), "OPDstGroup"); menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (widg)); /* HACK to get option menu to resize, kill old menu and create new one */ gtk_widget_destroy (menu); menu = gtk_menu_new (); for (i = 0, i2 = 0; i < MODGROUP_COUNT; i++) { mitem = gtk_menu_item_new_with_label (modgroup_names[i]); gtk_widget_show (mitem); gtk_object_set_data (GTK_OBJECT (mitem), "index", GINT_TO_POINTER (i2)); gtk_menu_append (GTK_MENU (menu), mitem); /* find start index in modgroup_gens of next group */ while (modgroup_gens[i2] != MODGROUP_SEPARATOR) i2++; i2++; } gtk_option_menu_set_menu (GTK_OPTION_MENU (widg), menu); /* HACK continued */ gtk_signal_connect (GTK_OBJECT (menu), "selection-done", GTK_SIGNAL_FUNC (swamiui_modedit_cb_group_select), modedit); gtk_option_menu_set_history (GTK_OPTION_MENU (widg), 0); swamiui_modedit_set_mod (modedit, NULL, TRUE); /* disable editor */ gtk_widget_show (glade_widg); gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (modedit), glade_widg); } /** * Create a new modulator editor object * Returns: New widget of type SwamiUIModEdit */ GtkWidget * swamiui_modedit_new (void) { return (GTK_WIDGET (gtk_type_new (swamiui_modedit_get_type ()))); } /** * Set item to synchronize to * @modedit Modulation editor object * @item Item to sync to (only IPZone items used, any other item type or * NULL disables the editor). */ void swamiui_modedit_set_item (SwamiUIModEdit *modedit, IPItem *item) { g_return_if_fail (modedit != NULL); g_return_if_fail (SWAMIUI_IS_MODEDIT (modedit)); if (item && !INSTP_IS_ZONE (item)) item = NULL; if ((void *)modedit->zone == (void *)item) return; modedit->zone = (IPZone *)(item); modedit->global_mods = FALSE; swamiui_modedit_update (modedit); } /* sets the modulator editor to the global modulator list */ void swamiui_modedit_global_mods (SwamiUIModEdit *modedit) { g_return_if_fail (modedit != NULL); g_return_if_fail (SWAMIUI_IS_MODEDIT (modedit)); modedit->zone = NULL; modedit->global_mods = TRUE; swamiui_modedit_update (modedit); } /* callback for when a modulator gets selected/unselected in the clist */ static void swamiui_modedit_cb_mod_select (GtkCList *clist, gint row, gint col, GdkEventButton *event, SwamiUIModEdit *modedit) { GList *sel; IPMod *mod; sel = clist->selection; if (sel && !sel->next) { mod = gtk_clist_get_row_data (GTK_CLIST (clist), GPOINTER_TO_UINT (sel->data)); if (mod) swamiui_modedit_set_mod (modedit, mod, FALSE); } else swamiui_modedit_set_mod (modedit, NULL, FALSE); } /* callback for new modulator button click */ void swamiui_modedit_cb_new_clicked (GtkButton *btn, SwamiUIModEdit *modedit) { GtkWidget *clist; IPMod *newmod; char *ctext[4] = { NULL }; int row; if (!modedit->zone && !modedit->global_mods) return; newmod = instp_mod_new (); g_return_if_fail (newmod != NULL); if (modedit->global_mods) swamiui_object->global_mods = instp_mod_list_insert (swamiui_object->global_mods, newmod, -1); else instp_zone_insert_mod (modedit->zone, newmod, -1); clist = gtk_object_get_data (GTK_OBJECT (modedit->glade_widg), "CLSTMod"); row = gtk_clist_append (GTK_CLIST (clist), ctext); gtk_clist_set_row_data (GTK_CLIST (clist), row, newmod); swamiui_modedit_update_mod (modedit, newmod, TRUE); } /* callback for delete modulator button click */ void swamiui_modedit_cb_delete_clicked (GtkButton *btn, SwamiUIModEdit *modedit) { GtkWidget *clist; GList *sel = NULL, *p; IPMod *mod; gboolean update_globals = FALSE; gint row; if (!modedit->zone && !modedit->global_mods) return; clist = gtk_object_get_data (GTK_OBJECT (modedit->glade_widg), "CLSTMod"); gtk_clist_freeze (GTK_CLIST (clist)); /* create list of selected modulators */ p = GTK_CLIST (clist)->selection; while (p) { mod = gtk_clist_get_row_data (GTK_CLIST (clist), GPOINTER_TO_INT (p->data)); if (mod) sel = g_list_prepend (sel, mod); p = g_list_next (p); } p = sel; while (p) /* loop over selected modulators and delete them */ { mod = (IPMod *)(p->data); if (mod) { if (modedit->global_mods) { swamiui_object->global_mods = instp_mod_list_remove_by_ptr (swamiui_object->global_mods, mod); update_globals = TRUE; } else instp_zone_remove_mod_by_ptr (modedit->zone, mod); } /* lookup the row by its data since it's index may have changed */ row = gtk_clist_find_row_from_data (GTK_CLIST (clist), mod); if (row != -1) gtk_clist_remove (GTK_CLIST (clist), row); p = g_list_next (p); } if (update_globals) /* apply global modulator list if needed */ swamiui_update_global_mods (); g_list_free (sel); gtk_clist_thaw (GTK_CLIST (clist)); } /* callback for when a destination group gets selected from the option menu */ static void swamiui_modedit_cb_group_select (GtkMenuShell *menushell, SwamiUIModEdit *modedit) { GtkWidget *widg; GtkWidget *menu; GtkWidget *mitem; char *s; int i; mitem = gtk_menu_get_active (GTK_MENU (menushell)); if (!mitem) return; i = GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT (mitem), "index")); widg = gtk_object_get_data (GTK_OBJECT (modedit->glade_widg), "OPDstSelect"); menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (widg)); /* HACK to get option menu to resize, kill old menu and create new one has an added side effect of not needing to remove all menu items :) */ gtk_widget_destroy (menu); menu = gtk_menu_new (); if (i != -1) { while (modgroup_gens[i] != MODGROUP_SEPARATOR) { s = instp_gen_info[modgroup_gens[i]].label; mitem = gtk_menu_item_new_with_label (s); gtk_widget_show (mitem); gtk_object_set_data (GTK_OBJECT (mitem), "genid", GINT_TO_POINTER (modgroup_gens[i])); gtk_menu_append (GTK_MENU (menu), mitem); i++; } } gtk_signal_connect (GTK_OBJECT (menu), "selection-done", GTK_SIGNAL_FUNC (swamiui_modedit_cb_gen_select), modedit); gtk_option_menu_set_menu (GTK_OPTION_MENU (widg), menu); /* HACK continued */ } /* callback for when a destination generator gets selected from option menu */ static void swamiui_modedit_cb_gen_select (GtkMenuShell *menushell, SwamiUIModEdit *modedit) { GtkWidget *mitem; int genid; if (modedit->block_callbacks || !modedit->mod) return; mitem = gtk_menu_get_active (GTK_MENU (menushell)); if (!mitem) return; genid = GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT (mitem), "genid")); modedit->mod->dest = genid; swamiui_modedit_update_mod (modedit, modedit->mod, TRUE); } /* callback for modulator source controller transform pixmap combo change */ static void swamiui_modedit_cb_pixcombo_changed (PixmapCombo *pixcombo, int id, SwamiUIModEdit *modedit) { guint16 *src; if (modedit->block_callbacks || !modedit->mod) return; if (pixcombo == gtk_object_get_data (GTK_OBJECT (modedit->glade_widg), "PIXSrc")) src = &modedit->mod->src; else src = &modedit->mod->amtsrc; *src &= ~(IPMOD_TYPE_MASK | IPMOD_DIRECTION_FLAG | IPMOD_POLARITY_FLAG); *src |= id; swamiui_modedit_update_mod (modedit, modedit->mod, TRUE); } /* callback for modulator source controller combo list */ static void swamiui_modedit_cb_combo_list_select (GtkList *list, GtkWidget *litem, SwamiUIModEdit *modedit) { GtkWidget *widg; guint16 *src; int ctrl; if (modedit->block_callbacks || !modedit->mod) return; ctrl = GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT (litem), "ctrlnum")); widg = gtk_object_get_data (GTK_OBJECT (modedit->glade_widg), "COMSrcCtrl"); if ((void *)list == (void *)(GTK_COMBO (widg)->list)) src = &modedit->mod->src; else src = &modedit->mod->amtsrc; *src &= ~(IPMOD_INDEX_MASK | IPMOD_CC_FLAG); *src |= ctrl; swamiui_modedit_update_mod (modedit, modedit->mod, TRUE); } /* callback for modulator amount source spin button value change */ static void swamiui_modedit_cb_amtsrc_changed (GtkAdjustment *adj, SwamiUIModEdit *modedit) { if (modedit->block_callbacks || !modedit->mod) return; modedit->mod->amount = (gint16)(adj->value); swamiui_modedit_update_mod (modedit, modedit->mod, TRUE); } /* add modulator source controller descriptions to a combo list */ static void swamiui_modedit_add_source_combo_strings (GtkCombo *combo) { GtkWidget *item; char *descr, *s; int i, descrndx; /* add controls from the General Controller palette */ for (i = 0; i < MODCTRL_DESCR_COUNT; i++) { item = gtk_list_item_new_with_label (_(modctrl_descr[i].descr)); gtk_widget_show (item); gtk_object_set_data (GTK_OBJECT (item), "ctrlnum", GINT_TO_POINTER (modctrl_descr[i].ctrlnum)); gtk_container_add (GTK_CONTAINER (GTK_COMBO (combo)->list), item); } /* loop over all MIDI CC controllers up to last valid one (119) */ for (i = 0, descrndx = 0; i < 120; i++) { if (midicc_descr[descrndx].ctrlnum == i) { descr = _(midicc_descr[descrndx].descr); if (descrndx < MIDICC_DESCR_COUNT - 1) descrndx++; } else if ((i >= 20 && i <= 31) || (i >= 70 && i <= 79) || (i >= 84 && i <= 90) || (i >= 102 && i <= 119)) descr = _("Undefined"); else descr = NULL; if (descr) { s = g_strdup_printf (_("CC %d %s"), i, descr); item = gtk_list_item_new_with_label (s); gtk_widget_show (item); g_free (s); /* use the MIDI ctrl number with the modulator CC flag set */ gtk_object_set_data (GTK_OBJECT (item), "ctrlnum", GINT_TO_POINTER (i | IPMOD_CC_FLAG)); gtk_container_add (GTK_CONTAINER (GTK_COMBO (combo)->list), item); } } } /* synchronizes modulator editor to current patch item */ static void swamiui_modedit_update (SwamiUIModEdit *modedit) { GtkWidget *clist; IPMod *mod; char *ctext[4] = { NULL }; /* text for each column in CList */ int row; clist = gtk_object_get_data (GTK_OBJECT (modedit->glade_widg), "CLSTMod"); if (modedit->zone || modedit->global_mods) gtk_clist_freeze (GTK_CLIST (clist)); gtk_clist_clear (GTK_CLIST (clist)); swamiui_modedit_set_mod (modedit, NULL, FALSE); /* disable edit widgets */ if (!modedit->zone && !modedit->global_mods) return; if (modedit->global_mods) mod = swamiui_object->global_mods; else mod = instp_zone_first_mod (modedit->zone); while (mod) { row = gtk_clist_append (GTK_CLIST (clist), ctext); gtk_clist_set_row_data (GTK_CLIST (clist), row, mod); swamiui_modedit_update_mod (modedit, mod, FALSE); mod = instp_mod_next (mod); } gtk_clist_thaw (GTK_CLIST (clist)); } /* update a modulator in the CList */ static void swamiui_modedit_update_mod (SwamiUIModEdit *modedit, IPMod *mod, gboolean apply_global) { GtkWidget *clist; GdkPixmap *pixmap; GdkBitmap *mask; char **xpm_data; int group, row; char *s; clist = gtk_object_get_data (GTK_OBJECT (modedit->glade_widg), "CLSTMod"); row = gtk_clist_find_row_from_data (GTK_CLIST (clist), mod); if (row == -1) return; /* apply global modulator list if requested */ if (apply_global && modedit->global_mods) swamiui_update_global_mods (); group = swamiui_modedit_find_gen_group (mod->dest, NULL); if (group >= 0) s = g_strdup_printf ("%s: %s", _(modgroup_names[group]), _(instp_gen_info[mod->dest].label)); else s = g_strdup_printf (_("Invalid (genid = %d)"), mod->dest); gtk_clist_set_text (GTK_CLIST (clist), row, 0, s); g_free (s); s = swamiui_modedit_get_control_name (mod->src); xpm_data = swamiui_modedit_find_transform_pixmap (mod->src); if (xpm_data) { pixmap_get (xpm_data, &pixmap, &mask); gtk_clist_set_pixtext (GTK_CLIST (clist), row, 1, s, 4, pixmap, mask); } else gtk_clist_set_text (GTK_CLIST (clist), row, 1, s); g_free (s); s = swamiui_modedit_get_control_name (mod->amtsrc); xpm_data = swamiui_modedit_find_transform_pixmap (mod->amtsrc); if (xpm_data) { pixmap_get (xpm_data, &pixmap, &mask); gtk_clist_set_pixtext (GTK_CLIST (clist), row, 2, s, 4, pixmap, mask); } else gtk_clist_set_text (GTK_CLIST (clist), row, 2, s); g_free (s); s = g_strdup_printf ("%d", mod->amount); gtk_clist_set_text (GTK_CLIST (clist), row, 3, s); g_free (s); } /* set the modulator that is being edited, or NULL to disable */ static void swamiui_modedit_set_mod (SwamiUIModEdit *modedit, IPMod *mod, gboolean force) { GtkWidget *pixsrc, *comsrc, *dstgrp, *dstsel, *spbamt, *pixamt, *comamt; GtkWidget *gw, *widg; GList *children, *found; int transform, ctrlnum, group, index; if (!force && modedit->mod == mod) return; modedit->mod = mod; gw = modedit->glade_widg; pixsrc = gtk_object_get_data (GTK_OBJECT (gw), "PIXSrc"); gtk_widget_set_sensitive (pixsrc, mod != NULL); comsrc = gtk_object_get_data (GTK_OBJECT (gw), "COMSrcCtrl"); gtk_widget_set_sensitive (comsrc, mod != NULL); dstgrp = gtk_object_get_data (GTK_OBJECT (gw), "OPDstGroup"); gtk_widget_set_sensitive (dstgrp, mod != NULL); dstsel = gtk_object_get_data (GTK_OBJECT (gw), "OPDstSelect"); gtk_widget_set_sensitive (dstsel, mod != NULL); spbamt = gtk_object_get_data (GTK_OBJECT (gw), "SPBAmount"); gtk_widget_set_sensitive (spbamt, mod != NULL); pixamt = gtk_object_get_data (GTK_OBJECT (gw), "PIXAmtSrc"); gtk_widget_set_sensitive (pixamt, mod != NULL); comamt = gtk_object_get_data (GTK_OBJECT (gw), "COMAmtCtrl"); gtk_widget_set_sensitive (comamt, mod != NULL); modedit->block_callbacks = TRUE; /* block signal callbacks */ /* set transform pixmap for source control */ transform = mod ? mod->src & (IPMOD_TYPE_MASK | IPMOD_POLARITY_FLAG | IPMOD_DIRECTION_FLAG) : 0; pixmap_combo_select_pixmap (PIXMAP_COMBO (pixsrc), transform); /* set control combo for source control */ ctrlnum = mod ? mod->src & (IPMOD_INDEX_MASK | IPMOD_CC_FLAG) : 0; children = gtk_container_children (GTK_CONTAINER (GTK_COMBO (comsrc)->list)); found = g_list_find_custom (children, GINT_TO_POINTER (ctrlnum), (GCompareFunc)swamiui_modedit_find_ctrl); if (found) gtk_list_select_child (GTK_LIST (GTK_COMBO (comsrc)->list), GTK_WIDGET (found->data)); else gtk_list_select_item (GTK_LIST (GTK_COMBO (comsrc)->list), 0); g_list_free (children); /* set destination generator group option menu */ group = mod ? swamiui_modedit_find_gen_group (mod->dest, &index) : -1; if (group >= 0) { gtk_option_menu_set_history (GTK_OPTION_MENU (dstgrp), group); /* HACK to get around GTK not issuing selection-done signal on menu when we explicitly set it, grrr */ widg = gtk_option_menu_get_menu (GTK_OPTION_MENU (dstgrp)); swamiui_modedit_cb_group_select (GTK_MENU_SHELL (widg), modedit); gtk_option_menu_set_history (GTK_OPTION_MENU (dstsel), index); } else gtk_option_menu_set_history (GTK_OPTION_MENU (dstgrp), 0); /* set amount spin button */ gtk_spin_button_set_value (GTK_SPIN_BUTTON (spbamt), mod ? mod->amount : 0); /* set transform pixmap for amount source control */ transform = mod ? mod->amtsrc & (IPMOD_TYPE_MASK | IPMOD_POLARITY_FLAG | IPMOD_DIRECTION_FLAG) : 0; pixmap_combo_select_pixmap (PIXMAP_COMBO (pixamt), transform); /* set control combo for amount source control */ ctrlnum = mod ? mod->amtsrc & (IPMOD_INDEX_MASK | IPMOD_CC_FLAG) : 0; children = gtk_container_children (GTK_CONTAINER (GTK_COMBO (comamt)->list)); found = g_list_find_custom (children, GINT_TO_POINTER (ctrlnum), (GCompareFunc)swamiui_modedit_find_ctrl); if (found) gtk_list_select_child (GTK_LIST (GTK_COMBO (comamt)->list), GTK_WIDGET (found->data)); else gtk_list_select_item (GTK_LIST (GTK_COMBO (comamt)->list), 0); g_list_free (children); modedit->block_callbacks = FALSE; /* unblock callbacks */ } /* a GCompareFunc for g_list_find_custom to locate a child GtkListItem in a list with a particular modulator control index */ static gint swamiui_modedit_find_ctrl (gconstpointer a, gconstpointer ctrlnum) { GtkListItem *litem = GTK_LIST_ITEM ((GtkListItem *)a); return (!(gtk_object_get_data (GTK_OBJECT (litem), "ctrlnum") == ctrlnum)); } /* returns a description for the control of a modulator source enumeration, string should be freed when finished with */ static char * swamiui_modedit_get_control_name (guint16 modsrc) { int ctrlnum, i; ctrlnum = modsrc & IPMOD_INDEX_MASK; if (modsrc & IPMOD_CC_FLAG) { /* MIDI CC controller */ if ((ctrlnum >= 20 && ctrlnum <= 31) || (ctrlnum >= 70 && ctrlnum <= 79) || (ctrlnum >= 84 && ctrlnum <= 90) || (ctrlnum >= 102 && ctrlnum <= 119)) return (g_strdup_printf (_("CC %d Undefined"), ctrlnum)); /* loop over control descriptions */ for (i = 0; i < MIDICC_DESCR_COUNT; i++) { if (midicc_descr[i].ctrlnum == ctrlnum) return (g_strdup_printf (_("CC %d %s"), ctrlnum, _(midicc_descr[i].descr))); } } else { /* general modulator source controller */ for (i = 0; i < MODCTRL_DESCR_COUNT; i++) { if (modctrl_descr[i].ctrlnum == ctrlnum) return (g_strdup (_(modctrl_descr[i].descr))); } } return (g_strdup_printf (_("Invalid (cc = %d, index = %d)"), ((modsrc & IPMOD_CC_FLAG) != 0), ctrlnum)); } /* returns the pixmap XPM data for the transform type of the given modulator source enumration or NULL if invalid */ static char ** swamiui_modedit_find_transform_pixmap (guint16 modsrc) { int transform; int i; transform = modsrc & (IPMOD_TYPE_MASK | IPMOD_POLARITY_FLAG | IPMOD_DIRECTION_FLAG); for (i = 0; i < 16; i++) { if (modtransform_elements[i].id == transform) return (modtransform_elements[i].xpm_data); } return (NULL); } /* determines the group a generator is part of and returns the group index or -1 if generator is not a valid modulator source, if index != NULL then the index within the group is stored in it */ static int swamiui_modedit_find_gen_group (int genid, int *index) { int group = 0; int i, groupndx = 0; for (i = 0; i < MODGROUP_GENS_SIZE; i++) { if (modgroup_gens[i] != MODGROUP_SEPARATOR) { if (modgroup_gens[i] == genid) break; groupndx++; } else /* group separator */ { group++; groupndx = 0; } } if (index) *index = groupndx; if (i < MODGROUP_GENS_SIZE) return (group); else return (-1); }