/[svn]/gigedit/trunk/src/gigedit/paramedit.cpp
ViewVC logotype

Annotation of /gigedit/trunk/src/gigedit/paramedit.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2844 - (hide annotations) (download)
Sun Sep 20 08:49:40 2015 UTC (8 years, 6 months ago) by persson
File size: 17268 byte(s)
* allow building with gtkmm 2 and G/GDK/GTK_DISABLE_DEPRECATED

1 schoenebeck 1225 /*
2 schoenebeck 2690 * Copyright (C) 2006-2015 Andreas Persson
3 schoenebeck 1225 *
4     * This program is free software; you can redistribute it and/or
5     * modify it under the terms of the GNU General Public License as
6     * published by the Free Software Foundation; either version 2, or (at
7     * your option) any later version.
8     *
9     * This program is distributed in the hope that it will be useful, but
10     * WITHOUT ANY WARRANTY; without even the implied warranty of
11     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12     * General Public License for more details.
13     *
14     * You should have received a copy of the GNU General Public License
15     * along with program; see the file COPYING. If not, write to the Free
16     * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
17     * 02110-1301 USA.
18     */
19    
20 persson 1714 #include <cstring>
21    
22 persson 2844 #include <glibmmconfig.h>
23     // threads.h must be included first to be able to build with
24     // G_DISABLE_DEPRECATED
25     #if (GLIBMM_MAJOR_VERSION == 2 && GLIBMM_MINOR_VERSION == 31 && GLIBMM_MICRO_VERSION >= 2) || \
26     (GLIBMM_MAJOR_VERSION == 2 && GLIBMM_MINOR_VERSION > 31) || GLIBMM_MAJOR_VERSION > 2
27     #include <glibmm/threads.h>
28     #endif
29    
30 schoenebeck 1225 #include "paramedit.h"
31    
32 persson 1831 #include "global.h"
33 persson 2169 #include "compat.h"
34 schoenebeck 2541 #include "Settings.h"
35 persson 1831
36 schoenebeck 2541 #include <gtkmm/messagedialog.h>
37    
38 persson 2446 std::string gig_encoding("CP1252");
39    
40     Glib::ustring gig_to_utf8(const gig::String& gig_string) {
41     return Glib::convert_with_fallback(gig_string, "UTF-8", gig_encoding, "?");
42     }
43    
44     gig::String gig_from_utf8(const Glib::ustring& utf8_string) {
45     return Glib::convert_with_fallback(utf8_string, gig_encoding, "UTF-8", "?");
46     }
47    
48    
49 schoenebeck 1225 namespace {
50 schoenebeck 2541 struct CCText {
51     const char* const txt;
52     bool isExtension; ///< True if this is a controller only supported by LinuxSampler, but not supperted by Gigasampler/GigaStudio.
53     };
54     static const CCText controlChangeTexts[] = {
55     // 3 special ones (not being CCs)
56     { _("none") }, { _("channelaftertouch") }, { _("velocity") },
57     {0}, // bank select MSB (hard coded in sampler, so discouraged to be used here, even though considerable)
58     { _("modwheel") }, // "Modulation Wheel or Lever",
59     { _("breath") }, // "Breath Controller",
60     { _("undefined"), true },
61     { _("foot") }, // "Foot Controller",
62     { _("portamentotime") }, // "Portamento Time",
63     { _("data entry MSB"), true },
64     { _("volume"), true },
65     { _("balance"), true },
66     { _("undefined"), true },
67     { _("pan"), true },
68     { _("expression"), true },
69     { _("effect1") }, // "Effect Control 1",
70     { _("effect2") }, // "Effect Control 2",
71     { _("undefined"), true },
72     { _("undefined"), true },
73     { _("genpurpose1") }, // "General Purpose Controller 1",
74     { _("genpurpose2") }, // "General Purpose Controller 2",
75     { _("genpurpose3") }, // "General Purpose Controller 3",
76     { _("genpurpose4") }, // "General Purpose Controller 4",
77     { _("undefined"), true },
78     { _("undefined"), true },
79     { _("undefined"), true },
80     { _("undefined"), true },
81     { _("undefined"), true },
82     { _("undefined"), true },
83     { _("undefined"), true },
84     { _("undefined"), true },
85     { _("undefined"), true },
86     { _("undefined"), true },
87     { _("undefined"), true },
88     { _("undefined"), true },
89 schoenebeck 2538
90     // LSB variant of the various controllers above
91     // (so discouraged to be used here for now)
92 schoenebeck 2541 {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
93     {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
94     {0}, {0}, {0}, {0},
95 schoenebeck 2538
96 schoenebeck 2541 { _("sustainpedal") }, // "Damper Pedal on/off (Sustain)",
97     { _("portamento") }, // "Portamento On/Off",
98     { _("sostenuto") }, // "Sustenuto On/Off",
99     { _("softpedal") }, // "Soft Pedal On/Off",
100     { _("legato"), true },
101     { _("hold2"), true },
102     { _("soundvariation"), true },
103     { _("timbre"), true },
104     { _("releasetime"), true },
105     { _("attacktime"), true },
106     { _("brightness"), true },
107     { _("decaytime"), true },
108     { _("vibratorate"), true },
109     { _("vibratodepth"), true },
110     { _("vibratodelay"), true },
111     { _("undefined"), true },
112     { _("genpurpose5") }, // "General Purpose Controller 5",
113     { _("genpurpose6") }, // "General Purpose Controller 6",
114     { _("genpurpose7") }, // "General Purpose Controller 7",
115     { _("genpurpose8") }, // "General Purpose Controller 8",
116     { _("portamentoctrl"), true },
117     { _("undefined"), true },
118     { _("undefined"), true },
119     { _("undefined"), true },
120     {0}, // high resolution velocity prefix (so discouraged to be used here)
121     { _("undefined"), true },
122     { _("undefined"), true },
123     { _("effect1depth") }, // "Effects 1 Depth",
124     { _("effect2depth") }, // "Effects 2 Depth",
125     { _("effect3depth") }, // "Effects 3 Depth",
126     { _("effect4depth") }, // "Effects 4 Depth",
127     { _("effect5depth") }, // "Effects 5 Depth"
128     { _("dataincrement"), true },
129     { _("datadecrement"), true },
130     {0}, // NRPN LSB (so discouraged to be used here)
131     {0}, // NRPN MSB (so discouraged to be used here)
132     {0}, // RPN LSB (so discouraged to be used here)
133     {0}, // RPN MSB (so discouraged to be used here)
134     { _("undefined"), true },
135     { _("undefined"), true },
136     { _("undefined"), true },
137     { _("undefined"), true },
138     { _("undefined"), true },
139     { _("undefined"), true },
140     { _("undefined"), true },
141     { _("undefined"), true },
142     { _("undefined"), true },
143     { _("undefined"), true },
144     { _("undefined"), true },
145     { _("undefined"), true },
146     { _("undefined"), true },
147     { _("undefined"), true },
148     { _("undefined"), true },
149     { _("undefined"), true },
150     { _("undefined"), true },
151     { _("undefined"), true } // CC 119
152 schoenebeck 2538 // (all other ones that follow [CC 120- CC 127] are hard coded channel
153     // mode messages, so those are discouraged to be used here)
154 schoenebeck 1225 };
155     }
156    
157 schoenebeck 2541 #define controlChangeTextsSize (sizeof(controlChangeTexts) / sizeof(CCText))
158 schoenebeck 2538
159 schoenebeck 1225 LabelWidget::LabelWidget(const char* labelText, Gtk::Widget& widget) :
160     label(Glib::ustring(labelText) + ":"),
161     widget(widget)
162     {
163 persson 2169 label.set_alignment(Gtk::ALIGN_START);
164 schoenebeck 1225 }
165    
166     void LabelWidget::set_sensitive(bool sensitive)
167     {
168     label.set_sensitive(sensitive);
169     widget.set_sensitive(sensitive);
170     }
171    
172 schoenebeck 2690 ReadOnlyLabelWidget::ReadOnlyLabelWidget(const char* leftHandText)
173     : LabelWidget(leftHandText, text)
174     {
175     text.set_alignment(Gtk::ALIGN_START, Gtk::ALIGN_START);
176     }
177    
178     ReadOnlyLabelWidget::ReadOnlyLabelWidget(const char* leftHandText, const char* rightHandText)
179     : LabelWidget(leftHandText, text)
180     {
181     text.set_alignment(Gtk::ALIGN_START, Gtk::ALIGN_START);
182     text.set_text(rightHandText);
183     }
184    
185 schoenebeck 1225 NumEntry::NumEntry(const char* labelText, double lower, double upper,
186     int decimals) :
187 persson 2151 LabelWidget(labelText, box),
188 persson 2169 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
189 schoenebeck 1225 adjust(lower, lower, upper, 1, 10),
190 persson 2169 #else
191     adjust(Gtk::Adjustment::create(lower, lower, upper, 1, 10)),
192     #endif
193 schoenebeck 1225 scale(adjust),
194 persson 2151 spinbutton(adjust)
195 schoenebeck 1225 {
196 persson 2423 scale.set_size_request(70);
197 schoenebeck 1225 spinbutton.set_digits(decimals);
198 persson 1460 spinbutton.set_value(0);
199 persson 2507 spinbutton.set_numeric();
200 schoenebeck 1225 scale.set_draw_value(false);
201     box.pack_start(spinbutton, Gtk::PACK_SHRINK);
202     box.add(scale);
203     }
204    
205     NumEntryGain::NumEntryGain(const char* labelText,
206     double lower, double upper,
207     int decimals, double coeff) :
208     NumEntry(labelText, lower, upper, decimals),
209 persson 2151 value(0),
210 persson 1460 coeff(coeff),
211     connected(true)
212 schoenebeck 1225 {
213     spinbutton.signal_value_changed().connect(
214     sigc::mem_fun(*this, &NumEntryGain::value_changed));
215     }
216    
217     void NumEntryGain::value_changed()
218     {
219 persson 1460 if (!connected) return;
220    
221 schoenebeck 1359 const double f = pow(10, spinbutton.get_digits());
222     int new_value = round_to_int(spinbutton.get_value() * f);
223 persson 1460 if (new_value != round_to_int(value / coeff * f)) {
224     value = round_to_int(new_value / f * coeff);
225     sig_changed();
226 schoenebeck 1225 }
227     }
228    
229 persson 1460 void NumEntryGain::set_value(int32_t value)
230 schoenebeck 1225 {
231 persson 1460 if (value != this->value) {
232     this->value = value;
233    
234     connected = false;
235     bool plus6 = value < 0;
236     spinbutton.set_value(plus6 ? 0 : value / coeff);
237     set_sensitive(!plus6);
238     connected = true;
239    
240     sig_changed();
241     }
242 schoenebeck 1225 }
243    
244    
245     BoolEntryPlus6::BoolEntryPlus6(const char* labelText, NumEntryGain& eGain, int32_t plus6value) :
246     LabelWidget(labelText, checkbutton),
247 persson 1262 checkbutton(labelText),
248 schoenebeck 1225 eGain(eGain),
249     plus6value(plus6value)
250     {
251     checkbutton.signal_toggled().connect(
252     sigc::mem_fun(*this, &BoolEntryPlus6::value_changed));
253     }
254    
255     void BoolEntryPlus6::value_changed()
256     {
257 persson 1460 if (checkbutton.get_active()) eGain.set_value(plus6value);
258     else if (eGain.get_value() < 0) eGain.set_value(0);
259 schoenebeck 1225 }
260    
261 persson 1460 int32_t BoolEntryPlus6::get_value() const
262 schoenebeck 1225 {
263 persson 1460 return eGain.get_value();
264 schoenebeck 1225 }
265    
266 persson 1460 void BoolEntryPlus6::set_value(int32_t value)
267     {
268     checkbutton.set_active(value < 0);
269     }
270    
271 schoenebeck 1225 NumEntryPermille::NumEntryPermille(const char* labelText,
272     double lower, double upper, int decimals) :
273 persson 1460 NumEntry(labelText, lower, upper, decimals),
274     value(0)
275 schoenebeck 1225 {
276     spinbutton.signal_value_changed().connect(
277     sigc::mem_fun(*this, &NumEntryPermille::value_changed));
278     }
279    
280     void NumEntryPermille::value_changed()
281     {
282 persson 1460 uint16_t new_value = uint16_t(spinbutton.get_value() * 10 + 0.5);
283     if (new_value != value) {
284     value = uint16_t(spinbutton.get_value() * 10 + 0.5);
285     sig_changed();
286 schoenebeck 1225 }
287     }
288    
289 persson 1460 void NumEntryPermille::set_value(uint16_t value)
290 schoenebeck 1225 {
291 persson 1460 if (value != this->value) {
292     spinbutton.set_value(value / 10.0);
293     }
294 schoenebeck 1225 }
295    
296    
297     NoteEntry::NoteEntry(const char* labelText) :
298     NumEntryTemp<uint8_t>(labelText)
299     {
300 persson 2507 spin_button_show_notes(spinbutton);
301 schoenebeck 1225 }
302    
303 persson 2507 namespace {
304     const char* notes[] = {
305     _("C"), _("C#"), _("D"), _("D#"), _("E"), _("F"),_("F#"),
306     _("G"), _("G#"), _("A"), _("A#"), _("B")
307     };
308 schoenebeck 1225
309 persson 2507 int note_value(const Glib::ustring& note, double* value)
310     {
311     const char* str = note.c_str();
312 schoenebeck 1225
313 persson 2507 int i;
314     for (i = 11 ; i >= 0 ; i--) {
315     if (strncasecmp(str, notes[i], strlen(notes[i])) == 0) break;
316     }
317     if (i >= 0) {
318     char* endptr;
319     long x = strtol(str + strlen(notes[i]), &endptr, 10);
320     if (endptr != str + strlen(notes[i])) {
321     *value = std::max(0L, std::min(i + (x + 1) * 12, 127L));
322     return true;
323     }
324     } else {
325     char* endptr;
326     long x = strtol(str, &endptr, 10);
327     if (endptr != str) {
328     *value = std::max(0L, std::min(x, 127L));
329     return true;
330     }
331     }
332     return Gtk::INPUT_ERROR;
333     }
334     }
335    
336     int note_value(const Glib::ustring& note)
337 schoenebeck 1225 {
338 persson 2507 double value = 0;
339     note_value(note, &value);
340     return value;
341     }
342 schoenebeck 1225
343 persson 2507 Glib::ustring note_str(int note)
344     {
345     char buf[10];
346     sprintf(buf, "%s%d", notes[note % 12], note / 12 - 1);
347     return buf;
348     }
349    
350     namespace {
351     // Convert the Entry text to a number
352     int on_input(double* new_value, Gtk::SpinButton* spinbutton) {
353     return note_value(spinbutton->get_text(), new_value);
354 schoenebeck 1225 }
355 persson 2507
356     // Convert the Adjustment position to text
357     bool on_output(Gtk::SpinButton* spinbutton) {
358     spinbutton->set_text(
359     note_str(spinbutton->get_adjustment()->get_value() + 0.5));
360     return true;
361 schoenebeck 1225 }
362     }
363    
364 persson 2507 // Make a SpinButton show notes instead of numbers
365     void spin_button_show_notes(Gtk::SpinButton& spin_button)
366 schoenebeck 1225 {
367 persson 2507 spin_button.set_numeric(false);
368     spin_button.set_width_chars(4);
369     spin_button.signal_input().connect(
370     sigc::bind(sigc::ptr_fun(&on_input), &spin_button));
371     spin_button.signal_output().connect(
372     sigc::bind(sigc::ptr_fun(&on_output), &spin_button));
373 schoenebeck 1225 }
374    
375     ChoiceEntryLeverageCtrl::ChoiceEntryLeverageCtrl(const char* labelText) :
376 persson 2151 LabelWidget(labelText, align),
377     align(0, 0, 0, 0)
378 schoenebeck 1225 {
379 schoenebeck 2538 for (int i = 0 ; i < controlChangeTextsSize ; i++) {
380 schoenebeck 2541 if (controlChangeTexts[i].txt) {
381 schoenebeck 2538 const int cc = i - 3;
382     Glib::ustring s = (i < 3)
383 schoenebeck 2541 ? controlChangeTexts[i].txt
384     : Glib::ustring::compose("CC%1: %2%3", cc, controlChangeTexts[i].txt, controlChangeTexts[i].isExtension ? " [EXT]" : "");
385 persson 2507 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 24) || GTKMM_MAJOR_VERSION < 2
386 schoenebeck 2538 combobox.append_text(s);
387 persson 2169 #else
388 schoenebeck 2538 combobox.append(s);
389 persson 2169 #endif
390 schoenebeck 1225 }
391     }
392     combobox.signal_changed().connect(
393     sigc::mem_fun(*this, &ChoiceEntryLeverageCtrl::value_changed));
394     align.add(combobox);
395 persson 1460 value.type = gig::leverage_ctrl_t::type_none;
396     value.controller_number = 0;
397 schoenebeck 1225 }
398    
399     void ChoiceEntryLeverageCtrl::value_changed()
400     {
401 persson 1460 int rowno = combobox.get_active_row_number();
402     switch (rowno)
403     {
404     case -1:
405     break;
406     case 0:
407     value.type = gig::leverage_ctrl_t::type_none;
408     break;
409     case 1:
410     value.type = gig::leverage_ctrl_t::type_channelaftertouch;
411     break;
412     case 2:
413     value.type = gig::leverage_ctrl_t::type_velocity;
414     break;
415     default:
416     value.type = gig::leverage_ctrl_t::type_controlchange;
417     int x = 3;
418 schoenebeck 2538 for (uint cc = 0 ; cc < controlChangeTextsSize - 3 ; cc++) {
419 schoenebeck 2541 if (controlChangeTexts[cc + 3].txt) {
420 persson 1460 if (rowno == x) {
421     value.controller_number = cc;
422 schoenebeck 2541 if (controlChangeTexts[cc + 3].isExtension &&
423     Settings::singleton()->warnUserOnExtensions)
424     {
425     Glib::ustring txt = _("<b>Format Extension</b>\n\nAll controllers marked with \"<b>[EXT]</b>\" are an extension to the original gig sound format. They will only work with LinuxSampler, but they will <b>not work</b> with Gigasampler/GigaStudio!\n\n(You may disable this warning in the <i>Settings</i> menu.)");
426     Gtk::MessageDialog msg(
427     txt, true, Gtk::MESSAGE_WARNING
428     );
429     msg.run();
430     }
431 persson 1460 break;
432 schoenebeck 1225 }
433 persson 1460 x++;
434 schoenebeck 1225 }
435     }
436 persson 1460 break;
437 schoenebeck 1225 }
438 persson 1460 if (rowno >= 0) sig_changed();
439 schoenebeck 1225 }
440    
441 persson 1460 void ChoiceEntryLeverageCtrl::set_value(gig::leverage_ctrl_t value)
442 schoenebeck 1225 {
443 schoenebeck 2538 int comboIndex;
444 persson 1460 switch (value.type)
445 schoenebeck 1225 {
446     case gig::leverage_ctrl_t::type_none:
447 schoenebeck 2538 comboIndex = 0;
448 schoenebeck 1225 break;
449     case gig::leverage_ctrl_t::type_channelaftertouch:
450 schoenebeck 2538 comboIndex = 1;
451 schoenebeck 1225 break;
452     case gig::leverage_ctrl_t::type_velocity:
453 schoenebeck 2538 comboIndex = 2;
454 schoenebeck 1225 break;
455 schoenebeck 2538 case gig::leverage_ctrl_t::type_controlchange: {
456     comboIndex = -1;
457     int x = 3;
458     for (uint cc = 0 ; cc < controlChangeTextsSize - 3 ; cc++) {
459 schoenebeck 2541 if (controlChangeTexts[cc + 3].txt) {
460 persson 1460 if (value.controller_number == cc) {
461 schoenebeck 2538 comboIndex = x;
462 schoenebeck 1225 break;
463     }
464 schoenebeck 2538 x++;
465 schoenebeck 1225 }
466     }
467     break;
468 schoenebeck 2538 }
469 schoenebeck 1225 default:
470 schoenebeck 2538 comboIndex = -1;
471 schoenebeck 1225 break;
472     }
473 schoenebeck 2538 combobox.set_active(comboIndex);
474 schoenebeck 1225 }
475    
476    
477     BoolEntry::BoolEntry(const char* labelText) :
478     LabelWidget(labelText, checkbutton),
479 persson 1460 checkbutton(labelText)
480 schoenebeck 1225 {
481 persson 1460 checkbutton.signal_toggled().connect(sig_changed.make_slot());
482 schoenebeck 1225 }
483    
484    
485     StringEntry::StringEntry(const char* labelText) :
486     LabelWidget(labelText, entry)
487     {
488 persson 1582 entry.signal_changed().connect(sig_changed.make_slot());
489 schoenebeck 1225 }
490    
491 persson 2446 gig::String StringEntry::get_value() const
492     {
493     return gig_from_utf8(entry.get_text());
494     }
495    
496     void StringEntry::set_value(const gig::String& value) {
497     entry.set_text(gig_to_utf8(value));
498     }
499    
500    
501 persson 1582 StringEntryMultiLine::StringEntryMultiLine(const char* labelText) :
502     LabelWidget(labelText, frame)
503 schoenebeck 1225 {
504 persson 1582 text_buffer = text_view.get_buffer();
505     frame.set_shadow_type(Gtk::SHADOW_IN);
506     frame.add(text_view);
507     text_buffer->signal_changed().connect(sig_changed.make_slot());
508 schoenebeck 1225 }
509    
510 persson 1582 gig::String StringEntryMultiLine::get_value() const
511 schoenebeck 1225 {
512 persson 1582 Glib::ustring value = text_buffer->get_text();
513     for (int i = 0 ; (i = value.find("\x0a", i)) >= 0 ; i += 2)
514     value.replace(i, 1, "\x0d\x0a");
515 persson 2446 return gig_from_utf8(value);
516 schoenebeck 1225 }
517 persson 1582
518 persson 2446 void StringEntryMultiLine::set_value(const gig::String& value)
519 persson 1582 {
520 persson 2446 Glib::ustring text = gig_to_utf8(value);
521     for (int i = 0 ; (i = text.find("\x0d\x0a", i, 2)) >= 0 ; i++)
522     text.replace(i, 2, "\x0a");
523     text_buffer->set_text(text);
524 persson 1582 }
525 persson 2423
526    
527     Table::Table(int x, int y) : Gtk::Table(x, y), rowno(0) { }
528    
529     void Table::add(BoolEntry& boolentry)
530     {
531     attach(boolentry.widget, 0, 2, rowno, rowno + 1,
532     Gtk::FILL, Gtk::SHRINK);
533     rowno++;
534     }
535    
536     void Table::add(BoolEntryPlus6& boolentry)
537     {
538     attach(boolentry.widget, 0, 2, rowno, rowno + 1,
539     Gtk::FILL, Gtk::SHRINK);
540     rowno++;
541     }
542    
543     void Table::add(LabelWidget& prop)
544     {
545     attach(prop.label, 1, 2, rowno, rowno + 1,
546     Gtk::FILL, Gtk::SHRINK);
547     attach(prop.widget, 2, 3, rowno, rowno + 1,
548     Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK);
549     rowno++;
550     }

  ViewVC Help
Powered by ViewVC