--- gigedit/trunk/src/gigedit/dimregionedit.cpp 2015/01/04 19:46:54 2691 +++ gigedit/trunk/src/gigedit/dimregionedit.cpp 2018/01/19 19:17:41 3408 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2015 Andreas Persson + * Copyright (C) 2006-2017 Andreas Persson * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -17,11 +17,17 @@ * 02110-1301 USA. */ +#include "global.h" #include "dimregionedit.h" -#include "global.h" #include "compat.h" +#if USE_GTKMM_GRID +# include +#else +# include +#endif + VelocityCurve::VelocityCurve(double (gig::DimensionRegion::*getter)(uint8_t)) : getter(getter), dimreg(0) { set_size_request(80, 80); @@ -147,6 +153,41 @@ } +EGStateOptions::EGStateOptions() : HBox(), + label(_("May be cancelled: ")), + checkBoxAttack(_("Attack")), + checkBoxAttackHold(_("Attack Hold")), + checkBoxDecay1(_("Decay 1")), + checkBoxDecay2(_("Decay 2")), + checkBoxRelease(_("Release")) +{ + set_spacing(6); + + pack_start(label); + pack_start(checkBoxAttack, Gtk::PACK_SHRINK); + pack_start(checkBoxAttackHold, Gtk::PACK_SHRINK); + pack_start(checkBoxDecay1, Gtk::PACK_SHRINK); + pack_start(checkBoxDecay2, Gtk::PACK_SHRINK); + pack_start(checkBoxRelease, Gtk::PACK_SHRINK); + + checkBoxAttack.set_tooltip_text(_( + "If checked: a note-off aborts the 'attack' stage." + )); + checkBoxAttackHold.set_tooltip_text(_( + "If checked: a note-off aborts the 'attack hold' stage." + )); + checkBoxDecay1.set_tooltip_text(_( + "If checked: a note-off aborts the 'decay 1' stage." + )); + checkBoxDecay2.set_tooltip_text(_( + "If checked: a note-off aborts the 'decay 2' stage." + )); + checkBoxRelease.set_tooltip_text(_( + "If checked: a note-on reverts back from the 'release' stage." + )); +} + + DimRegionEdit::DimRegionEdit() : velocity_curve(&gig::DimensionRegion::GetVelocityAttenuation), release_curve(&gig::DimensionRegion::GetVelocityRelease), @@ -230,20 +271,26 @@ eMSDecode(_("Decode Mid/Side Recordings")), eSampleStartOffset(_("Sample start offset"), 0, 2000), eUnityNote(_("Unity note")), + eSampleGroup(_("Sample Group")), eSampleFormatInfo(_("Sample Format")), eSampleID("Sample ID"), + eChecksum("Wave Data CRC-32"), eFineTune(_("Fine tune"), -49, 50), eGain(_("Gain"), -96, 0, 2, -655360), eGainPlus6(_("Gain +6dB"), eGain, 6 * -655360), eSampleLoopEnabled(_("Enabled")), - eSampleLoopStart(_("Loop start positon")), + eSampleLoopStart(_("Loop start position")), eSampleLoopLength(_("Loop size")), eSampleLoopType(_("Loop type")), eSampleLoopInfinite(_("Infinite loop")), eSampleLoopPlayCount(_("Playback count"), 1), - buttonSelectSample(Glib::ustring("<- ") + _("Select Sample")), + buttonSelectSample(UNICODE_LEFT_ARROW + " " + _("Select Sample")), update_model(0) { + // make synthesis parameter page tabs scrollable + // (workaround for GTK3: default theme uses huge tabs which breaks layout) + set_scrollable(); + connect(eEG1PreAttack, &gig::DimensionRegion::EG1PreAttack); connect(eEG1Attack, &gig::DimensionRegion::EG1Attack); connect(eEG1Decay1, &gig::DimensionRegion::EG1Decay1); @@ -260,6 +307,26 @@ &gig::DimensionRegion::EG1ControllerDecayInfluence); connect(eEG1ControllerReleaseInfluence, &gig::DimensionRegion::EG1ControllerReleaseInfluence); + { + ClassMemberPtr mp(offsetof(gig::DimensionRegion, EG1Options.AttackCancel)); + connect(eEG1StateOptions.checkBoxAttack, mp.pmember); + } + { + ClassMemberPtr mp(offsetof(gig::DimensionRegion, EG1Options.AttackHoldCancel)); + connect(eEG1StateOptions.checkBoxAttackHold, mp.pmember); + } + { + ClassMemberPtr mp(offsetof(gig::DimensionRegion, EG1Options.Decay1Cancel)); + connect(eEG1StateOptions.checkBoxDecay1, mp.pmember); + } + { + ClassMemberPtr mp(offsetof(gig::DimensionRegion, EG1Options.Decay2Cancel)); + connect(eEG1StateOptions.checkBoxDecay2, mp.pmember); + } + { + ClassMemberPtr mp(offsetof(gig::DimensionRegion, EG1Options.ReleaseCancel)); + connect(eEG1StateOptions.checkBoxRelease, mp.pmember); + } connect(eLFO1Frequency, &gig::DimensionRegion::LFO1Frequency); connect(eLFO1InternalDepth, &gig::DimensionRegion::LFO1InternalDepth); connect(eLFO1ControlDepth, &gig::DimensionRegion::LFO1ControlDepth); @@ -281,6 +348,26 @@ &gig::DimensionRegion::EG2ControllerDecayInfluence); connect(eEG2ControllerReleaseInfluence, &gig::DimensionRegion::EG2ControllerReleaseInfluence); + { + ClassMemberPtr mp(offsetof(gig::DimensionRegion, EG2Options.AttackCancel)); + connect(eEG2StateOptions.checkBoxAttack, mp.pmember); + } + { + ClassMemberPtr mp(offsetof(gig::DimensionRegion, EG2Options.AttackHoldCancel)); + connect(eEG2StateOptions.checkBoxAttackHold, mp.pmember); + } + { + ClassMemberPtr mp(offsetof(gig::DimensionRegion, EG2Options.Decay1Cancel)); + connect(eEG2StateOptions.checkBoxDecay1, mp.pmember); + } + { + ClassMemberPtr mp(offsetof(gig::DimensionRegion, EG2Options.Decay2Cancel)); + connect(eEG2StateOptions.checkBoxDecay2, mp.pmember); + } + { + ClassMemberPtr mp(offsetof(gig::DimensionRegion, EG2Options.ReleaseCancel)); + connect(eEG2StateOptions.checkBoxRelease, mp.pmember); + } connect(eLFO2Frequency, &gig::DimensionRegion::LFO2Frequency); connect(eLFO2InternalDepth, &gig::DimensionRegion::LFO2InternalDepth); connect(eLFO2ControlDepth, &gig::DimensionRegion::LFO2ControlDepth); @@ -356,8 +443,24 @@ ); for (int i = 0 ; i < 7 ; i++) { +#if USE_GTKMM_GRID + table[i] = new Gtk::Grid; + table[i]->set_column_spacing(7); +#else table[i] = new Gtk::Table(3, 1); table[i]->set_col_spacings(7); +#endif + +// on Gtk 3 there is absolutely no margin by default +#if GTKMM_MAJOR_VERSION >= 3 +# if GTKMM_MAJOR_VERSION == 3 && GTKMM_MINOR_VERSION < 12 + table[i]->set_margin_left(12); + table[i]->set_margin_right(12); +# else + table[i]->set_margin_start(12); + table[i]->set_margin_end(12); +# endif +#endif } // set tooltips @@ -450,7 +553,12 @@ firstRowInBlock = 0; addHeader(_("Mandatory Settings")); - addString(_("Sample"), lSample, wSample); + addString(_("Sample"), lSample, wSample, buttonNullSampleReference); + buttonNullSampleReference->set_label("X"); + buttonNullSampleReference->set_tooltip_text(_("Remove current sample reference (NULL reference). This can be used to define a \"silent\" case where no sample shall be played.")); + buttonNullSampleReference->signal_clicked().connect( + sigc::mem_fun(*this, &DimRegionEdit::nullOutSampleReference) + ); //TODO: the following would break drag&drop: wSample->property_editable().set_value(false); or this: wSample->set_editable(false); #ifdef OLD_TOOLTIPS tooltips.set_tip(*wSample, _("Drag & drop a sample here")); @@ -458,8 +566,10 @@ wSample->set_tooltip_text(_("Drag & drop a sample here")); #endif addProp(eUnityNote); + addProp(eSampleGroup); addProp(eSampleFormatInfo); addProp(eSampleID); + addProp(eChecksum); addRightHandSide(buttonSelectSample); addHeader(_("Optional Settings")); addProp(eSampleStartOffset); @@ -501,6 +611,7 @@ addProp(eEG1ControllerAttackInfluence); addProp(eEG1ControllerDecayInfluence); addProp(eEG1ControllerReleaseInfluence); + addLine(eEG1StateOptions); nextPage(); @@ -534,8 +645,17 @@ Gtk::Frame* frame = new Gtk::Frame; frame->add(crossfade_curve); + // on Gtk 3 there is no margin at all by default +#if GTKMM_MAJOR_VERSION >= 3 + frame->set_margin_top(12); + frame->set_margin_bottom(12); +#endif +#if USE_GTKMM_GRID + table[pageno]->attach(*frame, 1, rowno, 2); +#else table[pageno]->attach(*frame, 1, 3, rowno, rowno + 1, Gtk::SHRINK, Gtk::SHRINK); +#endif rowno++; eCrossfade_in_start.signal_value_changed().connect( @@ -609,8 +729,17 @@ frame = new Gtk::Frame; frame->add(cutoff_curve); + // on Gtk 3 there is no margin at all by default +#if GTKMM_MAJOR_VERSION >= 3 + frame->set_margin_top(12); + frame->set_margin_bottom(12); +#endif +#if USE_GTKMM_GRID + table[pageno]->attach(*frame, 1, rowno, 2); +#else table[pageno]->attach(*frame, 1, 3, rowno, rowno + 1, Gtk::SHRINK, Gtk::SHRINK); +#endif rowno++; addProp(eVCFResonance); @@ -646,6 +775,7 @@ addProp(eEG2ControllerAttackInfluence); addProp(eEG2ControllerDecayInfluence); addProp(eEG2ControllerReleaseInfluence); + addLine(eEG2StateOptions); lLFO2 = addHeader(_("Filter Cutoff Oscillator (LFO2)")); addProp(eLFO2Frequency); addProp(eLFO2InternalDepth); @@ -710,8 +840,17 @@ frame = new Gtk::Frame; frame->add(velocity_curve); + // on Gtk 3 there is no margin at all by default +#if GTKMM_MAJOR_VERSION >= 3 + frame->set_margin_top(12); + frame->set_margin_bottom(12); +#endif +#if USE_GTKMM_GRID + table[pageno]->attach(*frame, 1, rowno, 2); +#else table[pageno]->attach(*frame, 1, 3, rowno, rowno + 1, Gtk::SHRINK, Gtk::SHRINK); +#endif rowno++; addHeader(_("Release Velocity Response")); @@ -726,8 +865,17 @@ sigc::mem_fun(release_curve, &VelocityCurve::queue_draw)); frame = new Gtk::Frame; frame->add(release_curve); + // on Gtk 3 there is no margin at all by default +#if GTKMM_MAJOR_VERSION >= 3 + frame->set_margin_top(12); + frame->set_margin_bottom(12); +#endif +#if USE_GTKMM_GRID + table[pageno]->attach(*frame, 1, rowno, 2); +#else table[pageno]->attach(*frame, 1, 3, rowno, rowno + 1, Gtk::SHRINK, Gtk::SHRINK); +#endif rowno++; addProp(eReleaseTriggerDecay); @@ -822,15 +970,61 @@ Gtk::Entry*& widget) { label = new Gtk::Label(Glib::ustring(labelText) + ":"); +#if HAS_GTKMM_ALIGNMENT label->set_alignment(Gtk::ALIGN_START); +#else + label->set_halign(Gtk::Align::START); +#endif +#if USE_GTKMM_GRID + table[pageno]->attach(*label, 1, rowno); +#else table[pageno]->attach(*label, 1, 2, rowno, rowno + 1, Gtk::FILL, Gtk::SHRINK); +#endif widget = new Gtk::Entry(); +#if USE_GTKMM_GRID + table[pageno]->attach(*widget, 2, rowno); +#else table[pageno]->attach(*widget, 2, 3, rowno, rowno + 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK); +#endif + + rowno++; +} + +void DimRegionEdit::addString(const char* labelText, Gtk::Label*& label, + Gtk::Entry*& widget, Gtk::Button*& button) +{ + label = new Gtk::Label(Glib::ustring(labelText) + ":"); +#if HAS_GTKMM_ALIGNMENT + label->set_alignment(Gtk::ALIGN_START); +#else + label->set_halign(Gtk::Align::START); +#endif + +#if USE_GTKMM_GRID + table[pageno]->attach(*label, 1, rowno); +#else + table[pageno]->attach(*label, 1, 2, rowno, rowno + 1, + Gtk::FILL, Gtk::SHRINK); +#endif + + widget = new Gtk::Entry(); + button = new Gtk::Button(); + + HBox* hbox = new HBox; + hbox->pack_start(*widget); + hbox->pack_start(*button, Gtk::PACK_SHRINK); + +#if USE_GTKMM_GRID + table[pageno]->attach(*hbox, 2, rowno); +#else + table[pageno]->attach(*hbox, 2, 3, rowno, rowno + 1, + Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK); +#endif rowno++; } @@ -840,17 +1034,34 @@ if (firstRowInBlock < rowno - 1) { Gtk::Label* filler = new Gtk::Label(" "); +#if USE_GTKMM_GRID + table[pageno]->attach(*filler, 0, firstRowInBlock); +#else table[pageno]->attach(*filler, 0, 1, firstRowInBlock, rowno, Gtk::FILL, Gtk::SHRINK); +#endif } Glib::ustring str = ""; str += text; str += ""; Gtk::Label* label = new Gtk::Label(str); label->set_use_markup(); +#if HAS_GTKMM_ALIGNMENT label->set_alignment(Gtk::ALIGN_START); +#else + label->set_halign(Gtk::Align::START); +#endif + // on GTKMM 3 there is absolutely no margin by default +#if GTKMM_MAJOR_VERSION >= 3 + label->set_margin_top(18); + label->set_margin_bottom(13); +#endif +#if USE_GTKMM_GRID + table[pageno]->attach(*label, 0, rowno, 3); +#else table[pageno]->attach(*label, 0, 3, rowno, rowno + 1, Gtk::FILL, Gtk::SHRINK); +#endif rowno++; firstRowInBlock = rowno; return label; @@ -861,8 +1072,12 @@ if (firstRowInBlock < rowno - 1) { Gtk::Label* filler = new Gtk::Label(" "); +#if USE_GTKMM_GRID + table[pageno]->attach(*filler, 0, firstRowInBlock); +#else table[pageno]->attach(*filler, 0, 1, firstRowInBlock, rowno, Gtk::FILL, Gtk::SHRINK); +#endif } pageno++; rowno = 0; @@ -871,31 +1086,59 @@ void DimRegionEdit::addProp(BoolEntry& boolentry) { +#if USE_GTKMM_GRID + table[pageno]->attach(boolentry.widget, 1, rowno, 2); +#else table[pageno]->attach(boolentry.widget, 1, 3, rowno, rowno + 1, Gtk::FILL, Gtk::SHRINK); +#endif rowno++; } void DimRegionEdit::addProp(BoolEntryPlus6& boolentry) { +#if USE_GTKMM_GRID + table[pageno]->attach(boolentry.widget, 1, rowno, 2); +#else table[pageno]->attach(boolentry.widget, 1, 3, rowno, rowno + 1, Gtk::FILL, Gtk::SHRINK); +#endif rowno++; } void DimRegionEdit::addProp(LabelWidget& prop) { +#if USE_GTKMM_GRID + table[pageno]->attach(prop.label, 1, rowno); + table[pageno]->attach(prop.widget, 2, rowno); +#else table[pageno]->attach(prop.label, 1, 2, rowno, rowno + 1, Gtk::FILL, Gtk::SHRINK); table[pageno]->attach(prop.widget, 2, 3, rowno, rowno + 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK); +#endif + rowno++; +} + +void DimRegionEdit::addLine(HBox& line) +{ +#if USE_GTKMM_GRID + table[pageno]->attach(line, 1, rowno, 2); +#else + table[pageno]->attach(line, 1, 3, rowno, rowno + 1, + Gtk::FILL, Gtk::SHRINK); +#endif rowno++; } void DimRegionEdit::addRightHandSide(Gtk::Widget& widget) { +#if USE_GTKMM_GRID + table[pageno]->attach(widget, 2, rowno); +#else table[pageno]->attach(widget, 2, 3, rowno, rowno + 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK); +#endif rowno++; } @@ -924,6 +1167,11 @@ eEG1ControllerAttackInfluence.set_value(d->EG1ControllerAttackInfluence); eEG1ControllerDecayInfluence.set_value(d->EG1ControllerDecayInfluence); eEG1ControllerReleaseInfluence.set_value(d->EG1ControllerReleaseInfluence); + eEG1StateOptions.checkBoxAttack.set_value(d->EG1Options.AttackCancel); + eEG1StateOptions.checkBoxAttackHold.set_value(d->EG1Options.AttackHoldCancel); + eEG1StateOptions.checkBoxDecay1.set_value(d->EG1Options.Decay1Cancel); + eEG1StateOptions.checkBoxDecay2.set_value(d->EG1Options.Decay2Cancel); + eEG1StateOptions.checkBoxRelease.set_value(d->EG1Options.ReleaseCancel); eLFO1Frequency.set_value(d->LFO1Frequency); eLFO1InternalDepth.set_value(d->LFO1InternalDepth); eLFO1ControlDepth.set_value(d->LFO1ControlDepth); @@ -942,6 +1190,11 @@ eEG2ControllerAttackInfluence.set_value(d->EG2ControllerAttackInfluence); eEG2ControllerDecayInfluence.set_value(d->EG2ControllerDecayInfluence); eEG2ControllerReleaseInfluence.set_value(d->EG2ControllerReleaseInfluence); + eEG2StateOptions.checkBoxAttack.set_value(d->EG2Options.AttackCancel); + eEG2StateOptions.checkBoxAttackHold.set_value(d->EG2Options.AttackHoldCancel); + eEG2StateOptions.checkBoxDecay1.set_value(d->EG2Options.Decay1Cancel); + eEG2StateOptions.checkBoxDecay2.set_value(d->EG2Options.Decay2Cancel); + eEG2StateOptions.checkBoxRelease.set_value(d->EG2Options.ReleaseCancel); eLFO2Frequency.set_value(d->LFO2Frequency); eLFO2InternalDepth.set_value(d->LFO2InternalDepth); eLFO2ControlDepth.set_value(d->LFO2ControlDepth); @@ -990,6 +1243,13 @@ eMSDecode.set_value(d->MSDecode); eSampleStartOffset.set_value(d->SampleStartOffset); eUnityNote.set_value(d->UnityNote); + // show sample group name + { + Glib::ustring s = "---"; + if (d->pSample && d->pSample->GetGroup()) + s = d->pSample->GetGroup()->Name; + eSampleGroup.text.set_text(s); + } // assemble sample format info string { Glib::ustring s; @@ -1021,6 +1281,16 @@ } eSampleID.text.set_text(s); } + // generate raw wave form data CRC-32 checksum string + { + Glib::ustring s = "---"; + if (d->pSample) { + char buf[64] = {}; + snprintf(buf, sizeof(buf), "%x", d->pSample->GetWaveDataCRC32Checksum()); + s = buf; + } + eChecksum.text.set_text(s); + } buttonSelectSample.set_sensitive(d && d->pSample); eFineTune.set_value(d->FineTune); eGain.set_value(d->Gain); @@ -1070,6 +1340,7 @@ eEG2ControllerAttackInfluence.set_sensitive(sensitive); eEG2ControllerDecayInfluence.set_sensitive(sensitive); eEG2ControllerReleaseInfluence.set_sensitive(sensitive); + eEG2StateOptions.set_sensitive(sensitive); lLFO2->set_sensitive(sensitive); eLFO2Frequency.set_sensitive(sensitive); eLFO2InternalDepth.set_sensitive(sensitive); @@ -1263,18 +1534,29 @@ bool DimRegionEdit::set_sample(gig::Sample* sample, bool copy_sample_unity, bool copy_sample_tune, bool copy_sample_loop) { - if (dimregion) { + bool result = false; + for (std::set::iterator itDimReg = dimregs.begin(); + itDimReg != dimregs.end(); ++itDimReg) + { + result |= set_sample(*itDimReg, sample, copy_sample_unity, copy_sample_tune, copy_sample_loop); + } + return result; +} + +bool DimRegionEdit::set_sample(gig::DimensionRegion* dimreg, gig::Sample* sample, bool copy_sample_unity, bool copy_sample_tune, bool copy_sample_loop) +{ + if (dimreg) { //TODO: we should better move the code from MainWindow::on_sample_label_drop_drag_data_received() here // currently commented because we're sending a similar signal in MainWindow::on_sample_label_drop_drag_data_received() - //dimreg_to_be_changed_signal.emit(dimregion); + //DimRegionChangeGuard(this, dimregion); // make sure stereo samples always are the same in both // dimregs in the samplechannel dimension int nbDimregs = 1; - gig::DimensionRegion* d[2] = { dimregion, 0 }; + gig::DimensionRegion* d[2] = { dimreg, 0 }; if (sample->Channels == 2) { - gig::Region* region = dimregion->GetParent(); + gig::Region* region = dimreg->GetParent(); int bitcount = 0; int stereo_bit = 0; @@ -1289,7 +1571,7 @@ if (stereo_bit) { int dimregno; for (dimregno = 0 ; dimregno < region->DimensionRegions ; dimregno++) { - if (region->pDimensionRegions[dimregno] == dimregion) { + if (region->pDimensionRegions[dimregno] == dimreg) { break; } } @@ -1299,7 +1581,7 @@ } } - gig::Sample* oldref = dimregion->pSample; + gig::Sample* oldref = dimreg->pSample; for (int i = 0 ; i < nbDimregs ; i++) { d[i]->pSample = sample; @@ -1329,16 +1611,14 @@ // update ui update_model++; - wSample->set_text(gig_to_utf8(dimregion->pSample->pInfo->Name)); - eUnityNote.set_value(dimregion->UnityNote); - eFineTune.set_value(dimregion->FineTune); - eSampleLoopEnabled.set_value(dimregion->SampleLoops); + wSample->set_text(gig_to_utf8(dimreg->pSample->pInfo->Name)); + eUnityNote.set_value(dimreg->UnityNote); + eFineTune.set_value(dimreg->FineTune); + eSampleLoopEnabled.set_value(dimreg->SampleLoops); update_loop_elements(); update_model--; sample_ref_changed_signal.emit(oldref, sample); - // currently commented because we're sending a similar signal in MainWindow::on_sample_label_drop_drag_data_received() - //dimreg_changed_signal.emit(dimregion); return true; } return false; @@ -1407,24 +1687,24 @@ if (value) { // create a new sample loop in case there is none yet if (!d->SampleLoops) { + DimRegionChangeGuard(this, d); + DLS::sample_loop_t loop; loop.LoopType = gig::loop_type_normal; // loop the whole sample by default loop.LoopStart = 0; loop.LoopLength = (d->pSample) ? d->pSample->SamplesTotal : 0; - dimreg_to_be_changed_signal.emit(d); d->AddSampleLoop(&loop); - dimreg_changed_signal.emit(d); } } else { if (d->SampleLoops) { - dimreg_to_be_changed_signal.emit(d); + DimRegionChangeGuard(this, d); + // delete ALL existing sample loops while (d->SampleLoops) { d->DeleteSampleLoop(&d->pSampleLoops[0]); } - dimreg_changed_signal.emit(d); } } } @@ -1469,6 +1749,51 @@ if (d->pSample) d->pSample->LoopPlayCount = value; } +void DimRegionEdit::nullOutSampleReference() { + if (!dimregion) return; + gig::Sample* oldref = dimregion->pSample; + if (!oldref) return; + + DimRegionChangeGuard(this, dimregion); + + // in case currently assigned sample is a stereo one, then remove both + // references (expected to be due to a "stereo dimension") + gig::DimensionRegion* d[2] = { dimregion, NULL }; + if (oldref->Channels == 2) { + gig::Region* region = dimregion->GetParent(); + { + int stereo_bit = 0; + int bitcount = 0; + for (int dim = 0 ; dim < region->Dimensions ; dim++) { + if (region->pDimensionDefinitions[dim].dimension == gig::dimension_samplechannel) { + stereo_bit = 1 << bitcount; + break; + } + bitcount += region->pDimensionDefinitions[dim].bits; + } + + if (stereo_bit) { + int dimregno; + for (dimregno = 0 ; dimregno < region->DimensionRegions ; dimregno++) { + if (region->pDimensionRegions[dimregno] == dimregion) { + break; + } + } + d[0] = region->pDimensionRegions[dimregno & ~stereo_bit]; + d[1] = region->pDimensionRegions[dimregno | stereo_bit]; + } + } + } + + if (d[0]) d[0]->pSample = NULL; + if (d[1]) d[1]->pSample = NULL; + + // update UI elements + set_dim_region(dimregion); + + sample_ref_changed_signal.emit(oldref, NULL); +} + void DimRegionEdit::onButtonSelectSamplePressed() { if (!dimregion) return; if (!dimregion->pSample) return;