/* * SwamiUISampleView.c - Sample viewer 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 #include "SwamiUIObject.h" #include "SwamiUISampleView.h" #include "util.h" #include "widgets/samview.h" #include "widgets/ptrstrip.h" #include "i18n.h" /* order of markers determines order of overlap (last = on top) */ enum { MARK_SAMLOOPSTART, MARK_SAMLOOPEND, /* Zone, sam loop/end, not settable */ MARK_SAMSTARTOFS, MARK_SAMENDOFS, /* Zone only, sample start/end ofs */ MARK_LOOPSTART, MARK_LOOPEND, /* Sample loop start/end or Zone loop ofs */ MARK_COUNT }; /* pointer index enumerations */ enum { PTR_LOOPSTART, PTR_LOOPEND, PTR_SAMSTARTOFS, PTR_SAMENDOFS, PTR_COUNT }; static void swamiui_sampleview_class_init (SwamiUISampleViewClass *klass); static void swamiui_sampleview_init (SwamiUISampleView *sampleview); static GtkWidget *create_spinbtn (SwamiUISampleView *sampleview, int markenum); static void update_spinbtn (SwamiUISampleView *sampleview, int markenum); static void update_all_spin_buttons (SwamiUISampleView *sampleview); static void set_spinbtn_value_nosig (SwamiUISampleView *sampleview, int markenum, int val); static void set_loopmenu_value_nosig (SwamiUISampleView *sampleview, int val); static void cb_loopmenu_selection_done (GtkWidget *menushell, gpointer data); static void cb_cut_btn_clicked (GtkWidget *btn, void *data); static void set_samplemark_pos (SwamiUISampleView *sampleview, int markenum, gint32 val); static int get_samplemark_pos (SwamiUISampleView *sampleview, int markenum); static void get_samplemark_bounds (SwamiUISampleView *sampleview, int markenum, int *pmin, int *pmax, int *pminpad, int *pmaxpad); static int clamp_samplemark_pos (SwamiUISampleView *sampleview, int markenum, int val); static void cb_spinbtn_value_changed (GtkAdjustment *adj, void *data); static void cb_ptrstrip_select (GtkWidget *widg, int ptrndx, void *data); static void cb_ptrstrip_unselect (GtkWidget *widg, guint ptrndx, void *data); static void cb_ptrstrip_change (GtkWidget *widg, guint ptrndx, void *data); static void cb_samview_change (SamView *samview, void *data); static void update_ptrstrip (SwamiUISampleView *sampleview); guint swamiui_sampleview_get_type (void) { static guint obj_type = 0; if (!obj_type) { GtkTypeInfo obj_info = { "SwamiUISampleView", sizeof (SwamiUISampleView), sizeof (SwamiUISampleViewClass), (GtkClassInitFunc) swamiui_sampleview_class_init, (GtkObjectInitFunc) swamiui_sampleview_init, (GtkArgSetFunc) NULL, (GtkArgGetFunc) NULL, }; obj_type = gtk_type_unique (gtk_vbox_get_type (), &obj_info); } return obj_type; } static void swamiui_sampleview_class_init (SwamiUISampleViewClass *klass) { } static void swamiui_sampleview_init (SwamiUISampleView *sampleview) { GtkWidget *box, *vbox; GtkWidget *lbl; GtkWidget *sbar; GtkWidget *frame; GtkWidget *menu; GtkWidget *mitem; GdkColor clr; sampleview->item = NULL; box = gtk_hbox_new (FALSE, 2); gtk_widget_show (box); lbl = gtk_label_new (_("Loop:")); gtk_widget_show (lbl); gtk_box_pack_start (GTK_BOX (box), lbl, FALSE, FALSE, 0); /* we don't show the menu on purpose */ sampleview->loopmenu = gtk_option_menu_new (); gtk_box_pack_start (GTK_BOX (box), sampleview->loopmenu, FALSE, FALSE, 0); menu = gtk_menu_new (); gtk_widget_show (menu); mitem = gtk_menu_item_new_with_label (_("Single Shot")); gtk_widget_show (mitem); gtk_menu_append (GTK_MENU (menu), mitem); mitem = gtk_menu_item_new_with_label (_("Continuous")); gtk_widget_show (mitem); gtk_menu_append (GTK_MENU (menu), mitem); mitem = gtk_menu_item_new_with_label (_("Until Release")); gtk_widget_show (mitem); gtk_menu_append (GTK_MENU (menu), mitem); gtk_option_menu_set_menu (GTK_OPTION_MENU (sampleview->loopmenu), menu); gtk_signal_connect (GTK_OBJECT (menu), "selection-done", (GtkSignalFunc) cb_loopmenu_selection_done, sampleview); /* disable unused spin button pointers */ sampleview->spinbtns[MARK_SAMLOOPSTART] = NULL; sampleview->spinbtns[MARK_SAMLOOPEND] = NULL; /* loop start spin button */ sampleview->spinbtns[MARK_LOOPSTART] = create_spinbtn (sampleview, MARK_LOOPSTART); gtk_box_pack_start (GTK_BOX (box), sampleview->spinbtns[MARK_LOOPSTART], FALSE, FALSE, 0); /* loop end spin button */ sampleview->spinbtns[MARK_LOOPEND] = create_spinbtn (sampleview, MARK_LOOPEND); gtk_box_pack_start (GTK_BOX (box), sampleview->spinbtns[MARK_LOOPEND], FALSE, FALSE, 0); lbl = gtk_label_new (_("Sample:")); gtk_widget_show (lbl); gtk_box_pack_start (GTK_BOX (box), lbl, FALSE, FALSE, 0); /* sample start offset spin button */ sampleview->spinbtns[MARK_SAMSTARTOFS] = create_spinbtn (sampleview, MARK_SAMSTARTOFS); gtk_box_pack_start (GTK_BOX (box), sampleview->spinbtns[MARK_SAMSTARTOFS], FALSE, FALSE, 0); /* sample end offset spin button */ sampleview->spinbtns[MARK_SAMENDOFS] = create_spinbtn (sampleview, MARK_SAMENDOFS); gtk_box_pack_start (GTK_BOX (box), sampleview->spinbtns[MARK_SAMENDOFS], FALSE, FALSE, 0); /* cut button */ sampleview->cut_btn = gtk_button_new_with_label (_("Cut")); gtk_widget_show (sampleview->cut_btn); gtk_signal_connect (GTK_OBJECT (sampleview->cut_btn), "clicked", (GtkSignalFunc)cb_cut_btn_clicked, NULL); gtk_box_pack_start (GTK_BOX (box), sampleview->cut_btn, FALSE, FALSE, 0); /* vbox to set vertical spacing of upper outtie frame */ vbox = gtk_vbox_new (FALSE, 0); gtk_widget_show (vbox); gtk_box_pack_start (GTK_BOX (vbox), box, FALSE, FALSE, 2); /* upper outtie frame, with sample mark text entries etc. */ frame = gtk_frame_new (NULL); gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT); gtk_container_set_border_width (GTK_CONTAINER (frame), 0); gtk_widget_show (frame); gtk_box_pack_start (GTK_BOX (sampleview), frame, FALSE, FALSE, 0); gtk_container_add (GTK_CONTAINER (frame), vbox); /* lower inset frame for sample viewer */ frame = gtk_frame_new (NULL); gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN); gtk_container_set_border_width (GTK_CONTAINER (frame), 0); gtk_widget_show (frame); gtk_box_pack_start (GTK_BOX (sampleview), frame, TRUE, TRUE, 0); /* vbox within frame to put samview and mark pointer strip */ vbox = gtk_vbox_new (FALSE, 0); gtk_widget_show (vbox); gtk_container_add (GTK_CONTAINER (frame), vbox); sampleview->ptrstrip = ptrstrip_new (); ptrstrip_new_pointer (PTRSTRIP (sampleview->ptrstrip), -1); ptrstrip_new_pointer (PTRSTRIP (sampleview->ptrstrip), -1); ptrstrip_new_pointer (PTRSTRIP (sampleview->ptrstrip), -1); ptrstrip_new_pointer (PTRSTRIP (sampleview->ptrstrip), -1); gtk_signal_connect (GTK_OBJECT (sampleview->ptrstrip), "pointer_select", (GtkSignalFunc)cb_ptrstrip_select, sampleview); gtk_signal_connect (GTK_OBJECT (sampleview->ptrstrip), "pointer_unselect", (GtkSignalFunc)cb_ptrstrip_unselect, sampleview); gtk_signal_connect (GTK_OBJECT (sampleview->ptrstrip), "pointer_change", (GtkSignalFunc)cb_ptrstrip_change, sampleview); gtk_widget_show (sampleview->ptrstrip); gtk_box_pack_start (GTK_BOX (vbox), sampleview->ptrstrip, FALSE, FALSE, 1); sampleview->samview = samview_new (); gtk_signal_connect_after (GTK_OBJECT (sampleview->samview), "view_change", (GtkSignalFunc)cb_samview_change, sampleview); /* MARK sample loop START/END (not interactive) */ RGB2GDK (clr, 80, 160, 80); samview_new_marker (SAMVIEW (sampleview->samview), &clr); samview_new_marker (SAMVIEW (sampleview->samview), &clr); /* MARK sample START/END OFS */ RGB2GDK (clr, 255, 0, 0); samview_new_marker (SAMVIEW (sampleview->samview), &clr); samview_new_marker (SAMVIEW (sampleview->samview), &clr); /* MARK loop START/END */ RGB2GDK (clr, 0, 255, 0); samview_new_marker (SAMVIEW (sampleview->samview), &clr); samview_new_marker (SAMVIEW (sampleview->samview), &clr); gtk_widget_show (sampleview->samview); gtk_box_pack_start (GTK_BOX (vbox), sampleview->samview, TRUE, TRUE, 0); sbar = gtk_hscrollbar_new (SAMVIEW (sampleview->samview)->adj); gtk_widget_show (sbar); gtk_box_pack_start (GTK_BOX (sampleview), sbar, FALSE, FALSE, 0); } /** * Create a new sample view object * Returns: new widget of type SwamiUISampleView */ GtkWidget * swamiui_sampleview_new (void) { return (GTK_WIDGET (gtk_type_new (swamiui_sampleview_get_type ()))); } /** * Set the patch item to sync sample view to * @sampleview Sample viewer object * @item Patch item to sync sample view to (only IPSample and instrument * IPZones used) or NULL to de-activate. Incorrect item types are considered * NULL. */ void swamiui_sampleview_set_item (SwamiUISampleView *sampleview, IPItem *item) { IPItem *parent; IPGenAmount amt; gint i; if (item) parent = instp_item_parent (item); if (item && !INSTP_IS_SAMPLE (item) && !(INSTP_IS_ZONE (item) && parent && INSTP_IS_INST (parent))) item = NULL; if (sampleview->item == item) return; /* same item requested? */ if (sampleview->item) instp_item_unref (sampleview->item); /* -- remove item reference */ if (item && INSTP_IS_SAMPLE (item)) /* sync item is a sample? */ { /* disable zone related samview markers */ samview_set_marker (SAMVIEW (sampleview->samview), MARK_SAMSTARTOFS, -1); samview_set_marker (SAMVIEW (sampleview->samview), MARK_SAMENDOFS, -1); samview_set_marker (SAMVIEW (sampleview->samview), MARK_SAMLOOPSTART,-1); samview_set_marker (SAMVIEW (sampleview->samview), MARK_SAMLOOPEND, -1); /* disable zone related pointer strip pointers */ ptrstrip_set_pointer (PTRSTRIP (sampleview->ptrstrip), PTR_SAMSTARTOFS, -1); ptrstrip_set_pointer (PTRSTRIP (sampleview->ptrstrip), PTR_SAMENDOFS, -1); /* make used spin buttons sensitive */ gtk_widget_set_sensitive (sampleview->spinbtns[MARK_LOOPSTART], TRUE); gtk_widget_set_sensitive (sampleview->spinbtns[MARK_LOOPEND], TRUE); /* clear and disable unused spin buttons */ set_spinbtn_value_nosig (sampleview, MARK_SAMSTARTOFS, 0); gtk_widget_set_sensitive (sampleview->spinbtns[MARK_SAMSTARTOFS], FALSE); set_spinbtn_value_nosig (sampleview, MARK_SAMENDOFS, 0); gtk_widget_set_sensitive (sampleview->spinbtns[MARK_SAMENDOFS], FALSE); gtk_widget_hide (sampleview->loopmenu); gtk_widget_show (sampleview->cut_btn); /* show sample cut button */ } else if (item && INSTP_IS_ZONE (item) /* item is a zone ref'ing a sample? */ && INSTP_ZONE (item)->refitem && INSTP_IS_SAMPLE (INSTP_ZONE (item)->refitem)) { /* enable all spin buttons */ gtk_widget_set_sensitive (sampleview->spinbtns[MARK_LOOPSTART], TRUE); gtk_widget_set_sensitive (sampleview->spinbtns[MARK_LOOPEND], TRUE); gtk_widget_set_sensitive (sampleview->spinbtns[MARK_SAMSTARTOFS], TRUE); gtk_widget_set_sensitive (sampleview->spinbtns[MARK_SAMENDOFS], TRUE); gtk_widget_show (sampleview->loopmenu); instp_zone_get_gen (INSTP_ZONE (item), IPGEN_SAMPLE_MODES, &amt); set_loopmenu_value_nosig (sampleview, amt.uword & IPSAMPLE_LOOP_MASK); gtk_widget_hide (sampleview->cut_btn); /* hide the sample cut button */ } else /* item is NULL or not the right type */ { /* set samview sample data pointer to NULL before anything else! */ samview_set_data (SAMVIEW (sampleview->samview), NULL, 0); for (i = 0; i < MARK_COUNT; i++) /* disable markers and spin buttons */ { samview_set_marker (SAMVIEW (sampleview->samview), i, -1); if (sampleview->spinbtns[i]) /* only 4 spin buttons */ { set_spinbtn_value_nosig (sampleview, i, 0); gtk_widget_set_sensitive (sampleview->spinbtns[i], FALSE); } } for (i = 0; i < PTR_COUNT; i++) /* disable pointer strip pointers */ ptrstrip_set_pointer (PTRSTRIP (sampleview->ptrstrip), i, -1); /* hide loop options */ gtk_widget_hide (sampleview->loopmenu); gtk_widget_hide (sampleview->cut_btn); /* hide the sample cut button */ sampleview->item = NULL; return; } instp_item_ref (item); /* ++ add a reference to item */ sampleview->item = item; swamiui_sampleview_update (sampleview); } /** * Update the sample viewer * @sampleview Sample view object */ void swamiui_sampleview_update (SwamiUISampleView *sampleview) { IPSample *sample; IPSampleStore *store; IPGenAmount amt; void *dataptr; guint pos; if (!sampleview->item) return; if (INSTP_IS_SAMPLE (sampleview->item)) sample = INSTP_SAMPLE (sampleview->item); else sample = INSTP_SAMPLE (INSTP_ZONE (sampleview->item)->refitem); g_return_if_fail (sample->sampledata != NULL); /* set the sample data to view (must be done before other samview stuff!) */ store = instp_sample_data_find_store (sample->sampledata, 0, IPSAMPLE_STORE_FIND_FASTEST | IPSAMPLE_STORE_FIND_READABLE); g_return_if_fail (store != NULL); if (store->method->type != IPSAMPLE_METHOD_RAM) if (!(store = instp_sample_store_duplicate (sample->sampledata, store, IPSAMPLE_METHOD_RAM))) return; /* get the pointer to the sample data in RAM and set the samview to it */ dataptr = instp_sample_method_RAM_get_pointer (sample->sampledata, store); samview_set_data (SAMVIEW (sampleview->samview), dataptr, instp_sample_get_size (sample)); if (INSTP_IS_SAMPLE (sampleview->item)) /* item is sample */ { pos = get_samplemark_pos (sampleview, MARK_LOOPSTART); samview_set_marker (SAMVIEW (sampleview->samview), MARK_LOOPSTART, pos); pos = get_samplemark_pos (sampleview, MARK_LOOPEND); samview_set_marker (SAMVIEW (sampleview->samview), MARK_LOOPEND, pos); update_ptrstrip (sampleview); /* update pointer strip */ } else /* item is instrument zone */ { /* set the sample loop start/end markers (user cannot change them) */ samview_set_marker (SAMVIEW (sampleview->samview), MARK_SAMLOOPSTART, get_samplemark_pos (sampleview, MARK_SAMLOOPSTART)); samview_set_marker (SAMVIEW (sampleview->samview), MARK_SAMLOOPEND, get_samplemark_pos (sampleview, MARK_SAMLOOPEND)); /* set the 4 other markers in the view and set up spin buttons */ pos = get_samplemark_pos (sampleview, MARK_LOOPSTART); pos += get_samplemark_pos (sampleview, MARK_SAMLOOPSTART); samview_set_marker (SAMVIEW (sampleview->samview), MARK_LOOPSTART, pos); pos = get_samplemark_pos (sampleview, MARK_LOOPEND); pos += get_samplemark_pos (sampleview, MARK_SAMLOOPEND); samview_set_marker (SAMVIEW (sampleview->samview), MARK_LOOPEND, pos); pos = get_samplemark_pos (sampleview, MARK_SAMSTARTOFS); samview_set_marker (SAMVIEW (sampleview->samview), MARK_SAMSTARTOFS, pos); pos = get_samplemark_pos (sampleview, MARK_SAMENDOFS); pos += swami_item_get_int (swami_object, INSTP_ITEM (sample), "size") -1; samview_set_marker (SAMVIEW (sampleview->samview), MARK_SAMENDOFS, pos); update_ptrstrip (sampleview); /* update pointer strip */ instp_zone_get_gen (INSTP_ZONE (sampleview->item), IPGEN_SAMPLE_MODES, &amt); set_loopmenu_value_nosig (sampleview, amt.uword & IPSAMPLE_LOOP_MASK); } /* update spin buttons */ update_all_spin_buttons (sampleview); } static GtkWidget * create_spinbtn (SwamiUISampleView *sampleview, int markenum) { GtkObject *adj; GtkWidget *spbtn; adj = gtk_adjustment_new (0.0, 0.0, 0.0, 1.0, 10.0, 0.0); gtk_object_set_data (GTK_OBJECT (adj), "sampleview", sampleview); spbtn = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spbtn), TRUE); gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (spbtn), GTK_UPDATE_IF_VALID); gtk_widget_set_usize (spbtn, 80, -1); gtk_signal_connect (GTK_OBJECT (adj), "value-changed", (GtkSignalFunc) cb_spinbtn_value_changed, GINT_TO_POINTER (markenum)); gtk_widget_show (spbtn); return (spbtn); } /* update a spin button */ static void update_spinbtn (SwamiUISampleView *sampleview, int markenum) { GtkAdjustment *adj; int pos, min, max, minpad, maxpad; get_samplemark_bounds (sampleview, markenum, &min, &max, &minpad, &maxpad); adj = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (sampleview->spinbtns [markenum])); adj->lower = min + minpad; adj->upper = max + maxpad; gtk_adjustment_changed (adj); pos = get_samplemark_pos (sampleview, markenum); set_spinbtn_value_nosig (sampleview, markenum, pos); } /* update all spin buttons */ static void update_all_spin_buttons (SwamiUISampleView *sampleview) { update_spinbtn (sampleview, MARK_LOOPSTART); update_spinbtn (sampleview, MARK_LOOPEND); /* update instrument zone related spin buttons */ if (!INSTP_IS_SAMPLE (sampleview->item)) { update_spinbtn (sampleview, MARK_SAMSTARTOFS); update_spinbtn (sampleview, MARK_SAMENDOFS); } } /* set value of mark spin button and without causing value-changed signal */ static void set_spinbtn_value_nosig (SwamiUISampleView *sampleview, int markenum, int val) { GtkAdjustment *adj; adj = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (sampleview->spinbtns [markenum])); gtk_signal_handler_block_by_func (GTK_OBJECT (adj), (GtkSignalFunc)cb_spinbtn_value_changed, GINT_TO_POINTER (markenum)); gtk_adjustment_set_value (adj, (float)val); gtk_signal_handler_unblock_by_func (GTK_OBJECT (adj), (GtkSignalFunc)cb_spinbtn_value_changed, GINT_TO_POINTER (markenum)); } /* set the menu option widget selection without causing signal */ static void set_loopmenu_value_nosig (SwamiUISampleView *sampleview, int value) { GtkWidget *menu; menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (sampleview->loopmenu)); gtk_signal_handler_block_by_func (GTK_OBJECT (menu), (GtkSignalFunc)cb_loopmenu_selection_done, sampleview); if (value == IPSAMPLE_LOOP) value = 1; else if (value == IPSAMPLE_LOOP_UNROLL) value = 2; else value = 0; gtk_option_menu_set_history (GTK_OPTION_MENU (sampleview->loopmenu), value); gtk_signal_handler_unblock_by_func (GTK_OBJECT (menu), (GtkSignalFunc)cb_loopmenu_selection_done, sampleview); } static void cb_loopmenu_selection_done (GtkWidget *menushell, gpointer data) { SwamiUISampleView *sampleview = SWAMIUI_SAMPLEVIEW (data); IPGenAmount amt; int ndx; if (!sampleview->item) return; /* FIXME wtbl_loop_sam_as_inst = btnactv; */ if (!INSTP_IS_SAMPLE (sampleview->item)) /* item is instrument zone? */ { swami_zone_get_gen (swami_object, INSTP_ZONE (sampleview->item), IPGEN_SAMPLE_MODES, &amt); ndx = swamiui_util_option_menu_index (sampleview->loopmenu); amt.uword &= ~IPSAMPLE_LOOP_MASK; if (ndx == 1) amt.uword |= IPSAMPLE_LOOP; else if (ndx == 2) amt.uword |= IPSAMPLE_LOOP_UNROLL; swami_zone_set_gen (swami_object, INSTP_ZONE (sampleview->item), IPGEN_SAMPLE_MODES, amt); } } /* cut sample button pressed */ static void cb_cut_btn_clicked (GtkWidget *btn, void *data) { #if 0 SwamiUISampleView *sampleview = SWAMIUI_SAMPLEVIEW (data); SamView *samview; samview = SAMVIEW (samview_widg); if (!sampleview->item || !INSTP_IS_SAMPLE (sampleview->item) || samview->select_start == -1) return; cut_sample (INSTP_SAMPLE (sampleview->item), samview->select_start, samview->select_end); uisf_set_sam_in_view (sam_in_view, uisf_selected_uisfont->sf, TRUE); samview_update (); wtbl_sfitem_changed (((IPSample *)uisf_selected_elem)->itemid, WTBL_ITEM_CHANGE); #endif } /* set sample position for the active SAMPLE/IZONE mark enumeration */ static void set_samplemark_pos (SwamiUISampleView *sampleview, int markenum, gint32 val) { IPGenAmount msamt, lsamt; GObject *wavetbl; int msgen = -1, lsgen; msamt.sword = val >> 15; /* most significant 32k portion */ lsamt.sword = val & 0x7FFF; /* least significant portion */ if (INSTP_IS_SAMPLE (sampleview->item)) { /* sample view mode */ if (markenum == MARK_LOOPSTART) /* set loop start? */ { swami_item_set_int (swami_object, sampleview->item, "loopstart", val); msgen = IPGEN_START_LOOP_ADDR_COARSE_OFS; lsgen = IPGEN_START_LOOP_ADDR_OFS; } else if (markenum == MARK_LOOPEND) /* set loop end? */ { swami_item_set_int (swami_object, sampleview->item, "loopend", val); msgen = IPGEN_END_LOOP_ADDR_COARSE_OFS; lsgen = IPGEN_END_LOOP_ADDR_OFS; } } else { switch (markenum) { case MARK_LOOPSTART: msgen = IPGEN_START_LOOP_ADDR_COARSE_OFS; lsgen = IPGEN_START_LOOP_ADDR_OFS; break; case MARK_LOOPEND: msgen = IPGEN_END_LOOP_ADDR_COARSE_OFS; lsgen = IPGEN_END_LOOP_ADDR_OFS; break; case MARK_SAMSTARTOFS: msgen = IPGEN_START_ADDR_COARSE_OFS; lsgen = IPGEN_START_ADDR_OFS; break; case MARK_SAMENDOFS: msgen = IPGEN_END_ADDR_COARSE_OFS; lsgen = IPGEN_END_ADDR_OFS; break; } if (msgen != -1) { swami_zone_set_gen (swami_object, INSTP_ZONE (sampleview->item), msgen, msamt); swami_zone_set_gen (swami_object, INSTP_ZONE (sampleview->item), lsgen, lsamt); } } wavetbl = swami_get_object_by_type (G_OBJECT (swami_object), "SwamiWavetbl"); if (wavetbl && msgen != -1) { IPItem *layer = NULL, *item; if (INSTP_IS_ZONE (sampleview->item)) { layer = sampleview->item; item = instp_item_parent (layer); } else item = sampleview->item; swami_wavetbl_set_gen_realtime (SWAMI_WAVETBL (wavetbl), item, layer, msgen, msamt.sword); swami_wavetbl_set_gen_realtime (SWAMI_WAVETBL (wavetbl), item, layer, lsgen, lsamt.sword); } } /* get sample position for the active SAMPLE/IZONE mark enumeration */ static int get_samplemark_pos (SwamiUISampleView *sampleview, int markenum) { int pos = 0; IPGenAmount msamt, lsamt; if (INSTP_IS_SAMPLE (sampleview->item)) { /* sample view mode */ if (markenum == MARK_LOOPSTART) pos = INSTP_SAMPLE (sampleview->item)->loopstart; else if (markenum == MARK_LOOPEND) pos = INSTP_SAMPLE (sampleview->item)->loopend; } else { IPZone *zone; IPSample *sample; zone = INSTP_ZONE (sampleview->item); sample = INSTP_SAMPLE (INSTP_ZONE (sampleview->item)->refitem); switch (markenum) { case MARK_LOOPSTART: instp_zone_get_gen (zone, IPGEN_START_LOOP_ADDR_COARSE_OFS, &msamt); instp_zone_get_gen (zone, IPGEN_START_LOOP_ADDR_OFS, &lsamt); pos = ((gint32)msamt.sword << 15) + lsamt.sword; break; case MARK_LOOPEND: instp_zone_get_gen (zone, IPGEN_END_LOOP_ADDR_COARSE_OFS, &msamt); instp_zone_get_gen (zone, IPGEN_END_LOOP_ADDR_OFS, &lsamt); pos = ((gint32)msamt.sword << 15) + lsamt.sword; break; case MARK_SAMSTARTOFS: instp_zone_get_gen (zone, IPGEN_START_ADDR_COARSE_OFS, &msamt); instp_zone_get_gen (zone, IPGEN_START_ADDR_OFS, &lsamt); pos = ((gint32)msamt.sword << 15) + lsamt.sword; break; case MARK_SAMENDOFS: instp_zone_get_gen (zone, IPGEN_END_ADDR_COARSE_OFS, &msamt); instp_zone_get_gen (zone, IPGEN_END_ADDR_OFS, &lsamt); pos = ((gint32)msamt.sword << 15) + lsamt.sword; break; case MARK_SAMLOOPSTART: pos = swami_item_get_int (swami_object, INSTP_ITEM (sample), "loopstart"); break; case MARK_SAMLOOPEND: pos = swami_item_get_int (swami_object, INSTP_ITEM (sample), "loopend"); break; } } return (pos); } /* returns the absolute bounds and padding for the specified mark enum */ static void get_samplemark_bounds (SwamiUISampleView *sampleview, int markenum, int *pmin, int *pmax, int *pminpad, int *pmaxpad) { gint min, max; /* absolute min and max bounds */ /* FIXME - better handling of min loop padding, disabled for now */ gint minpad = 0, maxpad = 0; /* pad values for min and max */ if (INSTP_IS_SAMPLE (sampleview->item)) { if (markenum == MARK_LOOPSTART) { min = 1; /* abs 'hard' minumum allowed */ max = swami_item_get_int (swami_object, sampleview->item, "loopend") - 1; /* abs max */ } else if (markenum == MARK_LOOPEND) { min = swami_item_get_int (swami_object, sampleview->item, "loopstart") + 1; max = swami_item_get_int (swami_object, sampleview->item, "size") - 1; } } else /* item is instrument zone */ { IPSample *sample = INSTP_SAMPLE (INSTP_ZONE (sampleview->item)->refitem); switch (markenum) { case MARK_LOOPSTART: min = get_samplemark_pos (sampleview, MARK_SAMSTARTOFS) - swami_item_get_int (swami_object, INSTP_ITEM (sample), "loopstart") + 1; max = (get_samplemark_pos (sampleview, MARK_SAMLOOPEND) + get_samplemark_pos (sampleview, MARK_LOOPEND)) - get_samplemark_pos (sampleview, MARK_SAMLOOPSTART) - 1; break; case MARK_LOOPEND: min = (get_samplemark_pos (sampleview, MARK_SAMLOOPSTART) + get_samplemark_pos (sampleview, MARK_LOOPSTART)) - swami_item_get_int (swami_object, INSTP_ITEM (sample), "loopend") + 1; max = (swami_item_get_int (swami_object, INSTP_ITEM (sample), "size") + get_samplemark_pos (sampleview, MARK_SAMENDOFS) - 1) - get_samplemark_pos (sampleview, MARK_SAMLOOPEND); break; case MARK_SAMSTARTOFS: min = 0; max = (get_samplemark_pos (sampleview, MARK_SAMLOOPSTART) + get_samplemark_pos (sampleview, MARK_LOOPSTART)) - 1; break; case MARK_SAMENDOFS: min = (get_samplemark_pos (sampleview, MARK_SAMLOOPEND) + get_samplemark_pos (sampleview, MARK_LOOPEND)) - swami_item_get_int (swami_object, INSTP_ITEM (sample), "size") + 1; max = 0; break; } } *pmin = min; *pmax = max; *pminpad = minpad; *pmaxpad = maxpad; } /* clamp pos to valid range for the specified mark enum */ static int clamp_samplemark_pos (SwamiUISampleView *sampleview, int markenum, int val) { int min, max; /* absolute min and max values to clamp to */ int minpad, maxpad; /* minimum padding */ get_samplemark_bounds (sampleview, markenum, &min, &max, &minpad, &maxpad); /* pos is clamped to ensure that the minumum padding amount is satisfied (min + minpad <= val <= max + maxpad), except where SAMPLE/IZONE values already break min pad amounts, then the value is clamped to min, max */ /* loop points already break minloop/padding sizes? */ if (min + minpad > max + maxpad) return (CLAMP (val, min, max)); /* ?: yes, clamp to absolute min/max */ else /* ?: no, 'soft' clamp to ensure minimum padding */ return (CLAMP (val, min + minpad, max + maxpad)); } /* value in a samview spin button changed */ static void cb_spinbtn_value_changed (GtkAdjustment *adj, void *data) { int markenum = GPOINTER_TO_INT (data); SwamiUISampleView *sampleview; int val; int pos, pos2; sampleview = gtk_object_get_data (GTK_OBJECT (adj), "sampleview"); val = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (sampleview->spinbtns [markenum])); pos = clamp_samplemark_pos (sampleview, markenum, val); set_samplemark_pos (sampleview, markenum, pos); pos2 = pos; /* if this is an offset marker, then add absolute position */ if (INSTP_IS_ZONE (sampleview->item)) { IPSample *sample = INSTP_SAMPLE (INSTP_ZONE (sampleview->item)->refitem); if (markenum == MARK_LOOPSTART) pos2 += get_samplemark_pos (sampleview, MARK_SAMLOOPSTART); else if (markenum == MARK_LOOPEND) pos2 += get_samplemark_pos (sampleview, MARK_SAMLOOPEND); else if (markenum == MARK_SAMENDOFS) pos2 += swami_item_get_int (swami_object, INSTP_ITEM (sample), "size") - 1; } samview_set_marker (SAMVIEW (sampleview->samview), markenum, pos2); /* update spin buttons (low and upper bounds) */ update_all_spin_buttons (sampleview); /* update pointer strip */ update_ptrstrip (sampleview); if (pos != val) /* if value got clamped, update adj value */ adj->value = pos; } static void cb_ptrstrip_select (GtkWidget *widg, int ptrndx, void *data) { SwamiUISampleView *sampleview = SWAMIUI_SAMPLEVIEW (data); switch (ptrndx) { case PTR_LOOPSTART: samview_select_marker (SAMVIEW (sampleview->samview), MARK_LOOPSTART); break; case PTR_LOOPEND: samview_select_marker (SAMVIEW (sampleview->samview), MARK_LOOPEND); break; case PTR_SAMSTARTOFS: samview_select_marker (SAMVIEW (sampleview->samview), MARK_SAMSTARTOFS); break; case PTR_SAMENDOFS: samview_select_marker (SAMVIEW (sampleview->samview), MARK_SAMENDOFS); break; } } static void cb_ptrstrip_unselect (GtkWidget *widg, guint ptrndx, void *data) { SwamiUISampleView *sampleview = SWAMIUI_SAMPLEVIEW (data); samview_unselect_marker (SAMVIEW (sampleview->samview)); } static void cb_ptrstrip_change (GtkWidget *widg, guint ptrndx, void *data) { SwamiUISampleView *sampleview = SWAMIUI_SAMPLEVIEW (data); SamView *samview; SamViewMark *mark; PtrStripPointer *ptr; int markenum; int xpos; int pos, clamped, absval = 0; samview = SAMVIEW (sampleview->samview); if (!samview->sel_marker) return; mark = samview->sel_marker; markenum = samview_get_mark_index (samview, mark); ptr = (PtrStripPointer *)(PTRSTRIP (sampleview->ptrstrip)->selpointer->data); /* convert x pixel position of pointer to sample position */ pos = samview_calc_sample_pos (samview, ptr->xpos); /* if this is an offset marker, then subtract absolute position */ if (INSTP_IS_ZONE (sampleview->item)) { IPSample *sample = INSTP_SAMPLE (INSTP_ZONE (sampleview->item)->refitem); if (markenum == MARK_LOOPSTART) absval = get_samplemark_pos (sampleview, MARK_SAMLOOPSTART); else if (markenum == MARK_LOOPEND) absval = get_samplemark_pos (sampleview, MARK_SAMLOOPEND); else if (markenum == MARK_SAMENDOFS) absval = swami_item_get_int (swami_object, INSTP_ITEM (sample), "size") - 1; pos -= absval; } /* clamp sample position */ clamped = clamp_samplemark_pos (sampleview, markenum, pos); /* if value was clamped, then change ptr to reflect it */ if (clamped != pos) { pos = clamped; /* if this is an offset marker, then add absolute position */ if (INSTP_IS_ZONE (sampleview->item)) pos += absval; ptr->xpos = samview_calc_xpos (samview, pos); } /* set the sound font variable to sample position */ set_samplemark_pos (sampleview, markenum, clamped); /* update the spin button */ update_all_spin_buttons (sampleview); /* set selected samview marker to the xpos of the pointer */ xpos = ptr->xpos; samview_set_selected_marker_xpos (samview, &xpos); } /* update pointers on pointer strip every time samview changes */ static void cb_samview_change (SamView *samview, void *data) { SwamiUISampleView *sampleview = SWAMIUI_SAMPLEVIEW (data); if (!sampleview->item) return; update_ptrstrip (sampleview); } static void update_ptrstrip (SwamiUISampleView *sampleview) { SamView *samview; SamViewMark *mark; int xpos; samview = SAMVIEW (sampleview->samview); mark = samview_get_nth_mark (samview, MARK_LOOPSTART); xpos = samview_calc_xpos (samview, mark->pos); ptrstrip_set_pointer (PTRSTRIP (sampleview->ptrstrip), PTR_LOOPSTART, xpos); mark = samview_get_nth_mark (samview, MARK_LOOPEND); xpos = samview_calc_xpos (samview, mark->pos); ptrstrip_set_pointer (PTRSTRIP (sampleview->ptrstrip), PTR_LOOPEND, xpos); if (INSTP_IS_ZONE (sampleview->item)) /* item is an instrument zone? */ { mark = samview_get_nth_mark (samview, MARK_SAMSTARTOFS); xpos = samview_calc_xpos (samview, mark->pos); ptrstrip_set_pointer (PTRSTRIP (sampleview->ptrstrip), PTR_SAMSTARTOFS, xpos); mark = samview_get_nth_mark (samview, MARK_SAMENDOFS); xpos = samview_calc_xpos (samview, mark->pos); ptrstrip_set_pointer (PTRSTRIP (sampleview->ptrstrip), PTR_SAMENDOFS, xpos); } }