--- gigedit/trunk/src/gigedit/dimregionedit.cpp 2013/01/07 20:41:16 2392 +++ gigedit/trunk/src/gigedit/dimregionedit.cpp 2014/05/20 14:35:36 2566 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2013 Andreas Persson + * Copyright (C) 2006-2014 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 @@ -42,24 +42,24 @@ int h = get_height(); for (int pass = 0 ; pass < 2 ; pass++) { - for (int x = 0 ; x < w ; x++) { - int vel = int(x * 126.0 / w + 1.5); - int y = int((1 - (dimreg->*getter)(vel)) * (h - 1)); + for (double x = 0 ; x <= w ; x++) { + int vel = int(x * (127 - 1e-10) / w + 1); + double y = (1 - (dimreg->*getter)(vel)) * (h - 3) + 1.5; - if (x == 0) { + if (x < 1e-10) { cr->move_to(x, y); } else { cr->line_to(x, y); } } if (pass == 0) { - cr->line_to(w - 1, h - 1); - cr->line_to(0, h - 1); - cr->set_source_rgba(0.5, 0.44, 1.0, 0.2); + cr->line_to(w, h); + cr->line_to(0, h); + cr->set_source_rgba(0.5, 0.44, 1.0, is_sensitive() ? 0.2 : 0.1); cr->fill(); } else { cr->set_line_width(3); - cr->set_source_rgb(0.5, 0.44, 1.0); + cr->set_source_rgba(0.5, 0.44, 1.0, is_sensitive() ? 1.0 : 0.3); cr->stroke(); } } @@ -82,29 +82,68 @@ #else bool CrossfadeCurve::on_draw(const Cairo::RefPtr& cr) { #endif - if (dimreg && dimreg->Crossfade.out_end) { - int w = get_width(); - int h = get_height(); - + if (dimreg) { + cr->translate(1.5, 0); + + // first, draw curves for the other layers + gig::Region* region = dimreg->GetParent(); + int dimregno; + for (dimregno = 0 ; dimregno < region->DimensionRegions ; dimregno++) { + if (region->pDimensionRegions[dimregno] == dimreg) { + break; + } + } + int bitcount = 0; + for (int dim = 0 ; dim < region->Dimensions ; dim++) { + if (region->pDimensionDefinitions[dim].dimension == + gig::dimension_layer) { + int mask = + ~(((1 << region->pDimensionDefinitions[dim].bits) - 1) << + bitcount); + int c = dimregno & mask; // mask away the layer dimension + + for (int i = 0 ; i < region->pDimensionDefinitions[dim].zones ; + i++) { + gig::DimensionRegion* d = + region->pDimensionRegions[c + (i << bitcount)]; + if (d != dimreg) { + draw_one_curve(cr, d, false); + } + } + break; + } + bitcount += region->pDimensionDefinitions[dim].bits; + } + + // then, draw the currently selected layer + draw_one_curve(cr, dimreg, is_sensitive()); + } + return true; +} + +void CrossfadeCurve::draw_one_curve(const Cairo::RefPtr& cr, + const gig::DimensionRegion* d, + bool sensitive) { + int w = get_width(); + int h = get_height(); + + if (d->Crossfade.out_end) { for (int pass = 0 ; pass < 2 ; pass++) { - cr->move_to(dimreg->Crossfade.in_start / 127.0 * (w - 4) + 2, h); - cr->line_to(dimreg->Crossfade.in_end / 127.0 * (w - 4) + 2, 2); - cr->line_to(dimreg->Crossfade.out_start / 127.0 * (w - 4) + 2, 2); - cr->line_to(dimreg->Crossfade.out_end / 127.0 * (w - 4) + 2, h); + cr->move_to(d->Crossfade.in_start / 127.0 * (w - 3), h); + cr->line_to(d->Crossfade.in_end / 127.0 * (w - 3), 1.5); + cr->line_to(d->Crossfade.out_start / 127.0 * (w - 3), 1.5); + cr->line_to(d->Crossfade.out_end / 127.0 * (w - 3), h); if (pass == 0) { - cr->line_to(dimreg->Crossfade.in_start / 127.0 * (w - 4) + 2, - h); - cr->set_source_rgba(0.5, 0.44, 1.0, 0.2); + cr->set_source_rgba(0.5, 0.44, 1.0, sensitive ? 0.2 : 0.1); cr->fill(); } else { cr->set_line_width(3); - cr->set_source_rgb(0.5, 0.44, 1.0); + cr->set_source_rgba(0.5, 0.44, 1.0, sensitive ? 1.0 : 0.3); cr->stroke(); } } } - return true; } @@ -112,14 +151,14 @@ velocity_curve(&gig::DimensionRegion::GetVelocityAttenuation), release_curve(&gig::DimensionRegion::GetVelocityRelease), cutoff_curve(&gig::DimensionRegion::GetVelocityCutoff), - eEG1PreAttack(_("Pre-attack"), 0, 100, 2), - eEG1Attack(_("Attack"), 0, 60, 3), - eEG1Decay1(_("Decay 1"), 0.005, 60, 3), - eEG1Decay2(_("Decay 2"), 0, 60, 3), + eEG1PreAttack(_("Pre-attack Level (%)"), 0, 100, 2), + eEG1Attack(_("Attack Time (seconds)"), 0, 60, 3), + eEG1Decay1(_("Decay 1 Time (seconds)"), 0.005, 60, 3), + eEG1Decay2(_("Decay 2 Time (seconds)"), 0, 60, 3), eEG1InfiniteSustain(_("Infinite sustain")), - eEG1Sustain(_("Sustain"), 0, 100, 2), - eEG1Release(_("Release"), 0, 60, 3), - eEG1Hold(_("Hold")), + eEG1Sustain(_("Sustain Level (%)"), 0, 100, 2), + eEG1Release(_("Release Time (seconds)"), 0, 60, 3), + eEG1Hold(_("Hold Attack Stage until Loop End")), eEG1Controller(_("Controller")), eEG1ControllerInvert(_("Controller invert")), eEG1ControllerAttackInfluence(_("Controller attack influence"), 0, 3), @@ -131,13 +170,13 @@ eLFO1Controller(_("Controller")), eLFO1FlipPhase(_("Flip phase")), eLFO1Sync(_("Sync")), - eEG2PreAttack(_("Pre-attack"), 0, 100, 2), - eEG2Attack(_("Attack"), 0, 60, 3), - eEG2Decay1(_("Decay 1"), 0.005, 60, 3), - eEG2Decay2(_("Decay 2"), 0, 60, 3), + eEG2PreAttack(_("Pre-attack Level (%)"), 0, 100, 2), + eEG2Attack(_("Attack Time (seconds)"), 0, 60, 3), + eEG2Decay1(_("Decay 1 Time (seconds)"), 0.005, 60, 3), + eEG2Decay2(_("Decay 2 Time (seconds)"), 0, 60, 3), eEG2InfiniteSustain(_("Infinite sustain")), - eEG2Sustain(_("Sustain"), 0, 100, 2), - eEG2Release(_("Release"), 0, 60, 3), + eEG2Sustain(_("Sustain Level (%)"), 0, 100, 2), + eEG2Release(_("Release Time (seconds)"), 0, 60, 3), eEG2Controller(_("Controller")), eEG2ControllerInvert(_("Controller invert")), eEG2ControllerAttackInfluence(_("Controller attack influence"), 0, 3), @@ -182,13 +221,13 @@ ePitchTrack(_("Pitch track")), eDimensionBypass(_("Dimension bypass")), ePan(_("Pan"), -64, 63), - eSelfMask(_("Self mask")), + eSelfMask(_("Kill lower velocity voices (a.k.a \"Self mask\")")), eAttenuationController(_("Attenuation controller")), eInvertAttenuationController(_("Invert attenuation controller")), eAttenuationControllerThreshold(_("Attenuation controller threshold")), eChannelOffset(_("Channel offset"), 0, 9), - eSustainDefeat(_("Sustain defeat")), - eMSDecode(_("MS decode")), + eSustainDefeat(_("Ignore Hold Pedal (a.k.a. \"Sustain defeat\")")), + eMSDecode(_("Decode Mid/Side Recordings")), eSampleStartOffset(_("Sample start offset"), 0, 2000), eUnityNote(_("Unity note")), eFineTune(_("Fine tune"), -49, 50), @@ -349,6 +388,53 @@ "Caution: this setting is stored on Sample side, thus is shared " "among all dimension regions that use this sample!") ); + + eEG1PreAttack.set_tip( + "Very first level this EG starts with. It rises then in Attack Time " + "seconds from this initial level to 100%." + ); + eEG1Attack.set_tip( + "Duration of the EG's Attack stage, which raises its level from " + "Pre-Attack Level to 100%." + ); + eEG1Hold.set_tip( + "On looped sounds, enabling this will cause the Decay 1 stage not to " + "enter before the loop has been passed one time." + ); + eAttenuationController.set_tip(_( + "If you are not using the 'Layer' dimension, then this controller " + "simply alters the volume. If you are using the 'Layer' dimension, " + "then this controller is controlling the crossfade between Layers in " + "real-time." + )); + + eLFO1Sync.set_tip( + "If not checked, every voice will use its own LFO instance, which " + "causes voices triggered at different points in time to have different " + "LFO levels. By enabling 'Sync' here the voices will instead use and " + "share one single LFO, causing all voices to have the same LFO level, " + "no matter when the individual notes have been triggered." + ); + eLFO2Sync.set_tip( + "If not checked, every voice will use its own LFO instance, which " + "causes voices triggered at different points in time to have different " + "LFO levels. By enabling 'Sync' here the voices will instead use and " + "share one single LFO, causing all voices to have the same LFO level, " + "no matter when the individual notes have been triggered." + ); + eLFO3Sync.set_tip( + "If not checked, every voice will use its own LFO instance, which " + "causes voices triggered at different points in time to have different " + "LFO levels. By enabling 'Sync' here the voices will instead use and " + "share one single LFO, causing all voices to have the same LFO level, " + "no matter when the individual notes have been triggered." + ); + eLFO1FlipPhase.set_tip( + "Inverts the LFO's generated wave vertically." + ); + eLFO2FlipPhase.set_tip( + "Inverts the LFO's generated wave vertically." + ); pageno = 0; rowno = 0; @@ -358,9 +444,9 @@ addString(_("Sample"), lSample, wSample); //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, _("Drop a sample here")); + tooltips.set_tip(*wSample, _("Drag & drop a sample here")); #else - wSample->set_tooltip_text(_("Drop a sample here")); + wSample->set_tooltip_text(_("Drag & drop a sample here")); #endif addProp(eUnityNote); addHeader(_("Optional Settings")); @@ -392,12 +478,12 @@ addHeader(_("Amplitude Envelope (EG1)")); addProp(eEG1PreAttack); addProp(eEG1Attack); + addProp(eEG1Hold); addProp(eEG1Decay1); addProp(eEG1Decay2); addProp(eEG1InfiniteSustain); addProp(eEG1Sustain); addProp(eEG1Release); - addProp(eEG1Hold); addProp(eEG1Controller); addProp(eEG1ControllerInvert); addProp(eEG1ControllerAttackInfluence); @@ -597,7 +683,7 @@ nextPage(); - addHeader(_("Velocity Reponse")); + addHeader(_("Velocity Response")); eVelocityResponseCurve.set_choices(curve_type_texts, curve_type_values); addProp(eVelocityResponseCurve); addProp(eVelocityResponseDepth); @@ -616,7 +702,7 @@ Gtk::SHRINK, Gtk::SHRINK); rowno++; - addHeader(_("Release Velocity Reponse")); + addHeader(_("Release Velocity Response")); eReleaseVelocityResponseCurve.set_choices(curve_type_texts, curve_type_values); addProp(eReleaseVelocityResponseCurve); @@ -643,8 +729,24 @@ eDimensionBypass.set_choices(choices, values); } addProp(eDimensionBypass); + eSelfMask.widget.set_tooltip_text(_( + "If enabled: new notes with higher velocity value will stop older " + "notes with lower velocity values, that way you can save voices that " + "would barely be audible. This is also useful for certain drum sounds." + )); addProp(eSelfMask); + eSustainDefeat.widget.set_tooltip_text(_( + "If enabled: sustain pedal will not hold a note. This way you can use " + "the sustain pedal for other purposes, for example to switch among " + "dimension regions." + )); addProp(eSustainDefeat); + eMSDecode.widget.set_tooltip_text(_( + "Defines if Mid/Side Recordings should be decoded. Mid/Side Recordings " + "are an alternative way to record sounds in stereo. The sampler needs " + "to decode such samples to actually make use of them. Note: this " + "feature is currently not supported by LinuxSampler." + )); addProp(eMSDecode); nextPage(); @@ -886,7 +988,8 @@ d->pSample ? d->pSample->LoopPlayCount : 0); update_model--; - wSample->set_text(d->pSample ? d->pSample->pInfo->Name.c_str() : _("NULL")); + wSample->set_text(d->pSample ? gig_to_utf8(d->pSample->pInfo->Name) : + _("NULL")); update_loop_elements(); VCFEnabled_toggled(); @@ -901,6 +1004,7 @@ eVCFVelocityCurve.set_sensitive(sensitive); eVCFVelocityScale.set_sensitive(sensitive); eVCFVelocityDynamicRange.set_sensitive(sensitive); + cutoff_curve.set_sensitive(sensitive); eVCFResonance.set_sensitive(sensitive); eVCFResonanceController.set_sensitive(sensitive); eVCFKeyboardTracking.set_sensitive(sensitive); @@ -993,6 +1097,7 @@ eCrossfade_in_end.set_sensitive(hasController); eCrossfade_out_start.set_sensitive(hasController); eCrossfade_out_end.set_sensitive(hasController); + crossfade_curve.set_sensitive(hasController); } void DimRegionEdit::LFO1Controller_changed() @@ -1106,7 +1211,7 @@ update_model--; } -bool DimRegionEdit::set_sample(gig::Sample* sample) +bool DimRegionEdit::set_sample(gig::Sample* sample, bool copy_sample_unity, bool copy_sample_tune, bool copy_sample_loop) { if (dimregion) { //TODO: we should better move the code from MainWindow::on_sample_label_drop_drag_data_received() here @@ -1150,29 +1255,31 @@ d[i]->pSample = sample; // copy sample information from Sample to DimensionRegion - - d[i]->UnityNote = sample->MIDIUnityNote; - d[i]->FineTune = sample->FineTune; - - int loops = sample->Loops ? 1 : 0; - while (d[i]->SampleLoops > loops) { - d[i]->DeleteSampleLoop(&d[i]->pSampleLoops[0]); - } - while (d[i]->SampleLoops < sample->Loops) { - DLS::sample_loop_t loop; - d[i]->AddSampleLoop(&loop); - } - if (loops) { - d[i]->pSampleLoops[0].Size = sizeof(DLS::sample_loop_t); - d[i]->pSampleLoops[0].LoopType = sample->LoopType; - d[i]->pSampleLoops[0].LoopStart = sample->LoopStart; - d[i]->pSampleLoops[0].LoopLength = sample->LoopEnd - sample->LoopStart + 1; + if (copy_sample_unity) + d[i]->UnityNote = sample->MIDIUnityNote; + if (copy_sample_tune) + d[i]->FineTune = sample->FineTune; + if (copy_sample_loop) { + int loops = sample->Loops ? 1 : 0; + while (d[i]->SampleLoops > loops) { + d[i]->DeleteSampleLoop(&d[i]->pSampleLoops[0]); + } + while (d[i]->SampleLoops < sample->Loops) { + DLS::sample_loop_t loop; + d[i]->AddSampleLoop(&loop); + } + if (loops) { + d[i]->pSampleLoops[0].Size = sizeof(DLS::sample_loop_t); + d[i]->pSampleLoops[0].LoopType = sample->LoopType; + d[i]->pSampleLoops[0].LoopStart = sample->LoopStart; + d[i]->pSampleLoops[0].LoopLength = sample->LoopEnd - sample->LoopStart + 1; + } } } // update ui update_model++; - wSample->set_text(dimregion->pSample->pInfo->Name); + 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);