1 |
/* -*- c++ -*- |
/* -*- c++ -*- |
2 |
* Copyright (C) 2006-2017 Andreas Persson |
* Copyright (C) 2006-2019 Andreas Persson |
3 |
* |
* |
4 |
* This program is free software; you can redistribute it and/or |
* This program is free software; you can redistribute it and/or |
5 |
* modify it under the terms of the GNU General Public License as |
* modify it under the terms of the GNU General Public License as |
26 |
# include <gig.h> |
# include <gig.h> |
27 |
#endif |
#endif |
28 |
|
|
29 |
|
#include "compat.h" |
30 |
|
|
31 |
#include <cairomm/context.h> |
#include <cairomm/context.h> |
32 |
#include <gtkmm/box.h> |
#include <gtkmm/box.h> |
33 |
#include <gtkmm/drawingarea.h> |
#include <gtkmm/drawingarea.h> |
34 |
#include <gtkmm/entry.h> |
#include <gtkmm/entry.h> |
35 |
#include <gtkmm/label.h> |
#include <gtkmm/label.h> |
36 |
#include <gtkmm/notebook.h> |
#include <gtkmm/notebook.h> |
37 |
#include <gtkmm/table.h> |
#if USE_GTKMM_GRID |
38 |
|
# include <gtkmm/grid.h> |
39 |
|
#else |
40 |
|
# include <gtkmm/table.h> |
41 |
|
#endif |
42 |
|
|
43 |
|
#ifdef LIBLINUXSAMPLER_HEADER_FILE |
44 |
|
# include LIBLINUXSAMPLER_HEADER_FILE(engines/LFO.h) |
45 |
|
#else |
46 |
|
# include <linuxsampler/engines/LFO.h> |
47 |
|
#endif |
48 |
|
|
49 |
#include <set> |
#include <set> |
50 |
|
|
87 |
bool sensitive); |
bool sensitive); |
88 |
}; |
}; |
89 |
|
|
90 |
|
class LFOGraph : public Gtk::DrawingArea { |
91 |
|
public: |
92 |
|
LFOGraph(); |
93 |
|
void set_dim_region(gig::DimensionRegion* d) { dimreg = d; } |
94 |
|
|
95 |
|
protected: |
96 |
|
#if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2 |
97 |
|
bool on_expose_event(GdkEventExpose* e); |
98 |
|
#else |
99 |
|
bool on_draw(const Cairo::RefPtr<Cairo::Context>& cr); |
100 |
|
#endif |
101 |
|
|
102 |
|
virtual LinuxSampler::LFO::wave_t waveType() const = 0; |
103 |
|
virtual float frequency() const = 0; |
104 |
|
virtual float phase() const = 0; |
105 |
|
virtual uint internalDepth() const = 0; |
106 |
|
virtual uint controllerDepth() const = 0; |
107 |
|
virtual bool flipPolarity() const = 0; |
108 |
|
virtual bool signedRange() const = 0; |
109 |
|
virtual LinuxSampler::LFO::start_level_t startLevel() const = 0; |
110 |
|
virtual bool hasControllerAssigned() const = 0; |
111 |
|
|
112 |
|
gig::DimensionRegion* dimreg; |
113 |
|
LinuxSampler::LFO lfo; |
114 |
|
}; |
115 |
|
|
116 |
|
class LFO1Graph : public LFOGraph { |
117 |
|
public: |
118 |
|
LinuxSampler::LFO::wave_t waveType() const OVERRIDE { |
119 |
|
// simply assuming here libgig's and LS's enums are equally value mapped |
120 |
|
return (LinuxSampler::LFO::wave_t) dimreg->LFO1WaveForm; |
121 |
|
} |
122 |
|
float frequency() const OVERRIDE { return dimreg->LFO1Frequency; } |
123 |
|
float phase() const OVERRIDE { return dimreg->LFO1Phase; } |
124 |
|
uint internalDepth() const OVERRIDE { |
125 |
|
const gig::lfo1_ctrl_t ctrl = dimreg->LFO1Controller; |
126 |
|
const bool hasInternalDepth = ( |
127 |
|
ctrl != gig::lfo1_ctrl_modwheel && ctrl != gig::lfo1_ctrl_breath |
128 |
|
); |
129 |
|
return (hasInternalDepth) ? dimreg->LFO1InternalDepth : 0; |
130 |
|
} |
131 |
|
uint controllerDepth() const OVERRIDE { return dimreg->LFO1ControlDepth; } |
132 |
|
bool flipPolarity() const OVERRIDE { return dimreg->LFO1FlipPhase; } |
133 |
|
bool signedRange() const OVERRIDE { return false; } |
134 |
|
virtual LinuxSampler::LFO::start_level_t startLevel() const OVERRIDE { return LinuxSampler::LFO::start_level_mid; } // see https://sourceforge.net/p/linuxsampler/mailman/linuxsampler-devel/thread/2189307.cNP0Xbctxq%40silver/#msg36774029 |
135 |
|
bool hasControllerAssigned() const OVERRIDE { return dimreg->LFO1Controller; } |
136 |
|
}; |
137 |
|
|
138 |
|
class LFO2Graph : public LFOGraph { |
139 |
|
public: |
140 |
|
LinuxSampler::LFO::wave_t waveType() const OVERRIDE { |
141 |
|
// simply assuming here libgig's and LS's enums are equally value mapped |
142 |
|
return (LinuxSampler::LFO::wave_t) dimreg->LFO2WaveForm; |
143 |
|
} |
144 |
|
float frequency() const OVERRIDE { return dimreg->LFO2Frequency; } |
145 |
|
float phase() const OVERRIDE { return dimreg->LFO2Phase; } |
146 |
|
uint internalDepth() const OVERRIDE { |
147 |
|
const gig::lfo2_ctrl_t ctrl = dimreg->LFO2Controller; |
148 |
|
const bool hasInternalDepth = ( |
149 |
|
ctrl != gig::lfo2_ctrl_modwheel && ctrl != gig::lfo2_ctrl_foot |
150 |
|
); |
151 |
|
return (hasInternalDepth) ? dimreg->LFO2InternalDepth : 0; |
152 |
|
} |
153 |
|
uint controllerDepth() const OVERRIDE { return dimreg->LFO2ControlDepth; } |
154 |
|
bool flipPolarity() const OVERRIDE { return dimreg->LFO2FlipPhase; } |
155 |
|
bool signedRange() const OVERRIDE { return false; } |
156 |
|
virtual LinuxSampler::LFO::start_level_t startLevel() const OVERRIDE { return LinuxSampler::LFO::start_level_mid; } // see https://sourceforge.net/p/linuxsampler/mailman/linuxsampler-devel/thread/2189307.cNP0Xbctxq%40silver/#msg36774029 |
157 |
|
bool hasControllerAssigned() const OVERRIDE { return dimreg->LFO2Controller; } |
158 |
|
}; |
159 |
|
|
160 |
|
class LFO3Graph : public LFOGraph { |
161 |
|
public: |
162 |
|
LinuxSampler::LFO::wave_t waveType() const OVERRIDE { |
163 |
|
// simply assuming here libgig's and LS's enums are equally value mapped |
164 |
|
return (LinuxSampler::LFO::wave_t) dimreg->LFO3WaveForm; |
165 |
|
} |
166 |
|
float frequency() const OVERRIDE { return dimreg->LFO3Frequency; } |
167 |
|
float phase() const OVERRIDE { return dimreg->LFO3Phase; } |
168 |
|
uint internalDepth() const OVERRIDE { |
169 |
|
const gig::lfo3_ctrl_t ctrl = dimreg->LFO3Controller; |
170 |
|
const bool hasInternalDepth = ( |
171 |
|
ctrl != gig::lfo3_ctrl_modwheel && ctrl != gig::lfo3_ctrl_aftertouch |
172 |
|
); |
173 |
|
return (hasInternalDepth) ? dimreg->LFO3InternalDepth : 0; |
174 |
|
} |
175 |
|
uint controllerDepth() const OVERRIDE { return dimreg->LFO3ControlDepth; } |
176 |
|
bool flipPolarity() const OVERRIDE { return dimreg->LFO3FlipPhase; } |
177 |
|
bool signedRange() const OVERRIDE { return true; } |
178 |
|
virtual LinuxSampler::LFO::start_level_t startLevel() const OVERRIDE { return LinuxSampler::LFO::start_level_max; } // see https://sourceforge.net/p/linuxsampler/mailman/linuxsampler-devel/thread/2189307.cNP0Xbctxq%40silver/#msg36774029 |
179 |
|
bool hasControllerAssigned() const OVERRIDE { return dimreg->LFO3Controller; } |
180 |
|
}; |
181 |
|
|
182 |
|
class EGStateOptions : public HBox { |
183 |
|
public: |
184 |
|
Gtk::Label label; |
185 |
|
BoolBox checkBoxAttack; |
186 |
|
BoolBox checkBoxAttackHold; |
187 |
|
BoolBox checkBoxDecay1; |
188 |
|
BoolBox checkBoxDecay2; |
189 |
|
BoolBox checkBoxRelease; |
190 |
|
|
191 |
|
EGStateOptions(); |
192 |
|
void on_show_tooltips_changed(); |
193 |
|
}; |
194 |
|
|
195 |
class DimRegionEdit : public Gtk::Notebook |
class DimRegionEdit : public Gtk::Notebook |
196 |
{ |
{ |
197 |
public: |
public: |
235 |
Gtk::Tooltips tooltips; |
Gtk::Tooltips tooltips; |
236 |
#endif |
#endif |
237 |
|
|
238 |
Gtk::Table* table[7]; |
#if USE_GTKMM_GRID |
239 |
|
Gtk::Grid* table[9]; |
240 |
|
#else |
241 |
|
Gtk::Table* table[9]; |
242 |
|
#endif |
243 |
|
|
244 |
Gtk::Label* lSample; |
Gtk::Label* lSample; |
245 |
|
|
247 |
VelocityCurve release_curve; |
VelocityCurve release_curve; |
248 |
VelocityCurve cutoff_curve; |
VelocityCurve cutoff_curve; |
249 |
CrossfadeCurve crossfade_curve; |
CrossfadeCurve crossfade_curve; |
250 |
|
LFO1Graph lfo1Graph; ///< Graphic of Amplitude (Volume) LFO waveform. |
251 |
|
LFO2Graph lfo2Graph; ///< Graphic of Filter Cutoff LFO waveform. |
252 |
|
LFO3Graph lfo3Graph; ///< Graphic of Pitch LFO waveform. |
253 |
|
|
254 |
NumEntryPermille eEG1PreAttack; |
NumEntryPermille eEG1PreAttack; |
255 |
NumEntryTemp<double> eEG1Attack; |
NumEntryTemp<double> eEG1Attack; |
264 |
NumEntryTemp<uint8_t> eEG1ControllerAttackInfluence; |
NumEntryTemp<uint8_t> eEG1ControllerAttackInfluence; |
265 |
NumEntryTemp<uint8_t> eEG1ControllerDecayInfluence; |
NumEntryTemp<uint8_t> eEG1ControllerDecayInfluence; |
266 |
NumEntryTemp<uint8_t> eEG1ControllerReleaseInfluence; |
NumEntryTemp<uint8_t> eEG1ControllerReleaseInfluence; |
267 |
|
EGStateOptions eEG1StateOptions; |
268 |
|
ChoiceEntryLfoWave eLFO1Wave; |
269 |
NumEntryTemp<double> eLFO1Frequency; |
NumEntryTemp<double> eLFO1Frequency; |
270 |
|
NumEntryTemp<double> eLFO1Phase; |
271 |
NumEntryTemp<uint16_t> eLFO1InternalDepth; |
NumEntryTemp<uint16_t> eLFO1InternalDepth; |
272 |
NumEntryTemp<uint16_t> eLFO1ControlDepth; |
NumEntryTemp<uint16_t> eLFO1ControlDepth; |
273 |
ChoiceEntry<gig::lfo1_ctrl_t> eLFO1Controller; |
ChoiceEntry<gig::lfo1_ctrl_t> eLFO1Controller; |
285 |
NumEntryTemp<uint8_t> eEG2ControllerAttackInfluence; |
NumEntryTemp<uint8_t> eEG2ControllerAttackInfluence; |
286 |
NumEntryTemp<uint8_t> eEG2ControllerDecayInfluence; |
NumEntryTemp<uint8_t> eEG2ControllerDecayInfluence; |
287 |
NumEntryTemp<uint8_t> eEG2ControllerReleaseInfluence; |
NumEntryTemp<uint8_t> eEG2ControllerReleaseInfluence; |
288 |
|
EGStateOptions eEG2StateOptions; |
289 |
|
ChoiceEntryLfoWave eLFO2Wave; |
290 |
NumEntryTemp<double> eLFO2Frequency; |
NumEntryTemp<double> eLFO2Frequency; |
291 |
|
NumEntryTemp<double> eLFO2Phase; |
292 |
NumEntryTemp<uint16_t> eLFO2InternalDepth; |
NumEntryTemp<uint16_t> eLFO2InternalDepth; |
293 |
NumEntryTemp<uint16_t> eLFO2ControlDepth; |
NumEntryTemp<uint16_t> eLFO2ControlDepth; |
294 |
ChoiceEntry<gig::lfo2_ctrl_t> eLFO2Controller; |
ChoiceEntry<gig::lfo2_ctrl_t> eLFO2Controller; |
296 |
BoolEntry eLFO2Sync; |
BoolEntry eLFO2Sync; |
297 |
NumEntryTemp<double> eEG3Attack; |
NumEntryTemp<double> eEG3Attack; |
298 |
NumEntryTemp<int16_t> eEG3Depth; |
NumEntryTemp<int16_t> eEG3Depth; |
299 |
|
ChoiceEntryLfoWave eLFO3Wave; |
300 |
NumEntryTemp<double> eLFO3Frequency; |
NumEntryTemp<double> eLFO3Frequency; |
301 |
|
NumEntryTemp<double> eLFO3Phase; |
302 |
NumEntryTemp<int16_t> eLFO3InternalDepth; |
NumEntryTemp<int16_t> eLFO3InternalDepth; |
303 |
NumEntryTemp<int16_t> eLFO3ControlDepth; |
NumEntryTemp<int16_t> eLFO3ControlDepth; |
304 |
ChoiceEntry<gig::lfo3_ctrl_t> eLFO3Controller; |
ChoiceEntry<gig::lfo3_ctrl_t> eLFO3Controller; |
305 |
|
BoolEntry eLFO3FlipPhase; |
306 |
BoolEntry eLFO3Sync; |
BoolEntry eLFO3Sync; |
307 |
BoolEntry eVCFEnabled; |
BoolEntry eVCFEnabled; |
308 |
ChoiceEntry<gig::vcf_type_t> eVCFType; |
ChoiceEntry<gig::vcf_type_t> eVCFType; |
328 |
NumEntryTemp<uint8_t> eCrossfade_out_start; |
NumEntryTemp<uint8_t> eCrossfade_out_start; |
329 |
NumEntryTemp<uint8_t> eCrossfade_out_end; |
NumEntryTemp<uint8_t> eCrossfade_out_end; |
330 |
BoolEntry ePitchTrack; |
BoolEntry ePitchTrack; |
331 |
|
ChoiceEntry<gig::sust_rel_trg_t> eSustainReleaseTrigger; |
332 |
|
BoolEntry eNoNoteOffReleaseTrigger; |
333 |
ChoiceEntry<gig::dim_bypass_ctrl_t> eDimensionBypass; |
ChoiceEntry<gig::dim_bypass_ctrl_t> eDimensionBypass; |
334 |
NumEntryTemp<int8_t> ePan; |
NumEntryTemp<int8_t> ePan; |
335 |
BoolEntry eSelfMask; |
BoolEntry eSelfMask; |
367 |
void addProp(BoolEntry& boolentry); |
void addProp(BoolEntry& boolentry); |
368 |
void addProp(BoolEntryPlus6& boolentry); |
void addProp(BoolEntryPlus6& boolentry); |
369 |
void addProp(LabelWidget& labelwidget); |
void addProp(LabelWidget& labelwidget); |
370 |
|
void addLine(HBox& line); |
371 |
void addString(const char* labelText, Gtk::Label*& label, |
void addString(const char* labelText, Gtk::Label*& label, |
372 |
Gtk::Entry*& widget); |
Gtk::Entry*& widget); |
373 |
void addString(const char* labelText, Gtk::Label*& label, |
void addString(const char* labelText, Gtk::Label*& label, |
396 |
void loop_length_changed(); |
void loop_length_changed(); |
397 |
void loop_infinite_toggled(); |
void loop_infinite_toggled(); |
398 |
void nullOutSampleReference(); |
void nullOutSampleReference(); |
399 |
|
void on_show_tooltips_changed(); |
400 |
|
|
401 |
int update_model; |
int update_model; |
402 |
|
|
403 |
// connect a widget to a setter function in DimRegionEdit |
// connect a widget to a setter function in DimRegionEdit |
404 |
template<typename C, typename T> |
template<typename C, typename T> |
405 |
void connect(C& widget, |
void connect(C& widget, |
406 |
void (DimRegionEdit::*setter)(gig::DimensionRegion*, T)) { |
void (DimRegionEdit::*setter)(gig::DimensionRegion&, T)) { |
407 |
connect<C, T>(widget, |
connect<C, T>(widget, |
408 |
sigc::mem_fun(setter)); |
sigc::mem_fun(setter)); |
409 |
} |
} |
415 |
sigc::bind(sigc::mem_fun(&DimRegionEdit::set_member<T>), member)); |
sigc::bind(sigc::mem_fun(&DimRegionEdit::set_member<T>), member)); |
416 |
} |
} |
417 |
|
|
418 |
|
// connect a widget to a member of a struct member in gig::DimensionRegion |
419 |
|
template<typename C, typename T, typename S> |
420 |
|
void connect(C& widget, S gig::DimensionRegion::* member, T S::* member2) { |
421 |
|
connect<C, T>(widget, |
422 |
|
sigc::bind(sigc::mem_fun(&DimRegionEdit::set_sub_member<T, S>), member, member2)); |
423 |
|
} |
424 |
|
|
425 |
// connect a widget to a setter function in gig::DimensionRegion |
// connect a widget to a setter function in gig::DimensionRegion |
426 |
template<typename C, typename T> |
template<typename C, typename T> |
427 |
void connect(C& widget, |
void connect(C& widget, |
433 |
// helper function for the connect functions above |
// helper function for the connect functions above |
434 |
template<typename C, typename T> |
template<typename C, typename T> |
435 |
void connect(C& widget, |
void connect(C& widget, |
436 |
sigc::slot<void, DimRegionEdit*, gig::DimensionRegion*, T> setter) { |
sigc::slot<void, DimRegionEdit&, gig::DimensionRegion&, T> setter) { |
437 |
widget.signal_value_changed().connect( |
widget.signal_value_changed().connect( |
438 |
sigc::compose(sigc::bind(sigc::mem_fun(*this, &DimRegionEdit::set_many<T>), setter), |
sigc::compose(sigc::bind(sigc::mem_fun(*this, &DimRegionEdit::set_many<T>), setter), |
439 |
sigc::mem_fun(widget, &C::get_value))); |
sigc::mem_fun(widget, &C::get_value))); |
443 |
// each of them |
// each of them |
444 |
template<typename T> |
template<typename T> |
445 |
void set_many(T value, |
void set_many(T value, |
446 |
sigc::slot<void, DimRegionEdit*, gig::DimensionRegion*, T> setter) { |
sigc::slot<void, DimRegionEdit&, gig::DimensionRegion&, T> setter) { |
447 |
if (update_model == 0) { |
if (update_model == 0) { |
448 |
for (std::set<gig::DimensionRegion*>::iterator i = dimregs.begin() ; |
for (std::set<gig::DimensionRegion*>::iterator i = dimregs.begin() ; |
449 |
i != dimregs.end() ; ++i) |
i != dimregs.end() ; ++i) |
450 |
{ |
{ |
451 |
DimRegionChangeGuard(this, *i); |
DimRegionChangeGuard(this, *i); |
452 |
setter(this, *i, value); |
setter(*this, **i, value); |
453 |
} |
} |
454 |
} |
} |
455 |
} |
} |
456 |
|
|
457 |
// set a value of a member variable in the given dimregion |
// set a value of a member variable in the given dimregion |
458 |
template<typename T> |
template<typename T> |
459 |
void set_member(gig::DimensionRegion* d, T value, |
void set_member(gig::DimensionRegion& d, T value, |
460 |
T gig::DimensionRegion::* member) { |
T gig::DimensionRegion::* member) { |
461 |
d->*member = value; |
d.*member = value; |
462 |
|
} |
463 |
|
|
464 |
|
// set a value of a member of a struct member variable in the given dimregion |
465 |
|
template<typename T, typename S> |
466 |
|
void set_sub_member(gig::DimensionRegion& d, T value, |
467 |
|
S gig::DimensionRegion::* member, T S::* member2) { |
468 |
|
d.*member.*member2 = value; |
469 |
} |
} |
470 |
|
|
471 |
// setters for specific dimregion parameters |
// setters for specific dimregion parameters |
472 |
|
|
473 |
void set_UnityNote(gig::DimensionRegion* d, uint8_t value); |
void set_UnityNote(gig::DimensionRegion& d, uint8_t value); |
474 |
void set_FineTune(gig::DimensionRegion* d, int16_t value); |
void set_FineTune(gig::DimensionRegion& d, int16_t value); |
475 |
void set_Crossfade_in_start(gig::DimensionRegion* d, uint8_t value); |
void set_Crossfade_in_start(gig::DimensionRegion& d, uint8_t value); |
476 |
void set_Crossfade_in_end(gig::DimensionRegion* d, uint8_t value); |
void set_Crossfade_in_end(gig::DimensionRegion& d, uint8_t value); |
477 |
void set_Crossfade_out_start(gig::DimensionRegion* d, uint8_t value); |
void set_Crossfade_out_start(gig::DimensionRegion& d, uint8_t value); |
478 |
void set_Crossfade_out_end(gig::DimensionRegion* d, uint8_t value); |
void set_Crossfade_out_end(gig::DimensionRegion& d, uint8_t value); |
479 |
void set_Gain(gig::DimensionRegion* d, int32_t value); |
void set_Gain(gig::DimensionRegion& d, int32_t value); |
480 |
void set_LoopEnabled(gig::DimensionRegion* d, bool value); |
void set_LoopEnabled(gig::DimensionRegion& d, bool value); |
481 |
void set_LoopType(gig::DimensionRegion* d, uint32_t value); |
void set_LoopType(gig::DimensionRegion& d, uint32_t value); |
482 |
void set_LoopStart(gig::DimensionRegion* d, uint32_t value); |
void set_LoopStart(gig::DimensionRegion& d, uint32_t value); |
483 |
void set_LoopLength(gig::DimensionRegion* d, uint32_t value); |
void set_LoopLength(gig::DimensionRegion& d, uint32_t value); |
484 |
void set_LoopInfinite(gig::DimensionRegion* d, bool value); |
void set_LoopInfinite(gig::DimensionRegion& d, bool value); |
485 |
void set_LoopPlayCount(gig::DimensionRegion* d, uint32_t value); |
void set_LoopPlayCount(gig::DimensionRegion& d, uint32_t value); |
486 |
|
|
487 |
void onButtonSelectSamplePressed(); |
void onButtonSelectSamplePressed(); |
488 |
}; |
}; |