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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2844 - (show 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 /*
2 * Copyright (C) 2006-2015 Andreas Persson
3 *
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 #include <cstring>
21
22 #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 #include "paramedit.h"
31
32 #include "global.h"
33 #include "compat.h"
34 #include "Settings.h"
35
36 #include <gtkmm/messagedialog.h>
37
38 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 namespace {
50 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
90 // LSB variant of the various controllers above
91 // (so discouraged to be used here for now)
92 {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
96 { _("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 // (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 };
155 }
156
157 #define controlChangeTextsSize (sizeof(controlChangeTexts) / sizeof(CCText))
158
159 LabelWidget::LabelWidget(const char* labelText, Gtk::Widget& widget) :
160 label(Glib::ustring(labelText) + ":"),
161 widget(widget)
162 {
163 label.set_alignment(Gtk::ALIGN_START);
164 }
165
166 void LabelWidget::set_sensitive(bool sensitive)
167 {
168 label.set_sensitive(sensitive);
169 widget.set_sensitive(sensitive);
170 }
171
172 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 NumEntry::NumEntry(const char* labelText, double lower, double upper,
186 int decimals) :
187 LabelWidget(labelText, box),
188 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
189 adjust(lower, lower, upper, 1, 10),
190 #else
191 adjust(Gtk::Adjustment::create(lower, lower, upper, 1, 10)),
192 #endif
193 scale(adjust),
194 spinbutton(adjust)
195 {
196 scale.set_size_request(70);
197 spinbutton.set_digits(decimals);
198 spinbutton.set_value(0);
199 spinbutton.set_numeric();
200 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 value(0),
210 coeff(coeff),
211 connected(true)
212 {
213 spinbutton.signal_value_changed().connect(
214 sigc::mem_fun(*this, &NumEntryGain::value_changed));
215 }
216
217 void NumEntryGain::value_changed()
218 {
219 if (!connected) return;
220
221 const double f = pow(10, spinbutton.get_digits());
222 int new_value = round_to_int(spinbutton.get_value() * f);
223 if (new_value != round_to_int(value / coeff * f)) {
224 value = round_to_int(new_value / f * coeff);
225 sig_changed();
226 }
227 }
228
229 void NumEntryGain::set_value(int32_t value)
230 {
231 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 }
243
244
245 BoolEntryPlus6::BoolEntryPlus6(const char* labelText, NumEntryGain& eGain, int32_t plus6value) :
246 LabelWidget(labelText, checkbutton),
247 checkbutton(labelText),
248 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 if (checkbutton.get_active()) eGain.set_value(plus6value);
258 else if (eGain.get_value() < 0) eGain.set_value(0);
259 }
260
261 int32_t BoolEntryPlus6::get_value() const
262 {
263 return eGain.get_value();
264 }
265
266 void BoolEntryPlus6::set_value(int32_t value)
267 {
268 checkbutton.set_active(value < 0);
269 }
270
271 NumEntryPermille::NumEntryPermille(const char* labelText,
272 double lower, double upper, int decimals) :
273 NumEntry(labelText, lower, upper, decimals),
274 value(0)
275 {
276 spinbutton.signal_value_changed().connect(
277 sigc::mem_fun(*this, &NumEntryPermille::value_changed));
278 }
279
280 void NumEntryPermille::value_changed()
281 {
282 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 }
287 }
288
289 void NumEntryPermille::set_value(uint16_t value)
290 {
291 if (value != this->value) {
292 spinbutton.set_value(value / 10.0);
293 }
294 }
295
296
297 NoteEntry::NoteEntry(const char* labelText) :
298 NumEntryTemp<uint8_t>(labelText)
299 {
300 spin_button_show_notes(spinbutton);
301 }
302
303 namespace {
304 const char* notes[] = {
305 _("C"), _("C#"), _("D"), _("D#"), _("E"), _("F"),_("F#"),
306 _("G"), _("G#"), _("A"), _("A#"), _("B")
307 };
308
309 int note_value(const Glib::ustring& note, double* value)
310 {
311 const char* str = note.c_str();
312
313 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 {
338 double value = 0;
339 note_value(note, &value);
340 return value;
341 }
342
343 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 }
355
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 }
362 }
363
364 // Make a SpinButton show notes instead of numbers
365 void spin_button_show_notes(Gtk::SpinButton& spin_button)
366 {
367 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 }
374
375 ChoiceEntryLeverageCtrl::ChoiceEntryLeverageCtrl(const char* labelText) :
376 LabelWidget(labelText, align),
377 align(0, 0, 0, 0)
378 {
379 for (int i = 0 ; i < controlChangeTextsSize ; i++) {
380 if (controlChangeTexts[i].txt) {
381 const int cc = i - 3;
382 Glib::ustring s = (i < 3)
383 ? controlChangeTexts[i].txt
384 : Glib::ustring::compose("CC%1: %2%3", cc, controlChangeTexts[i].txt, controlChangeTexts[i].isExtension ? " [EXT]" : "");
385 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 24) || GTKMM_MAJOR_VERSION < 2
386 combobox.append_text(s);
387 #else
388 combobox.append(s);
389 #endif
390 }
391 }
392 combobox.signal_changed().connect(
393 sigc::mem_fun(*this, &ChoiceEntryLeverageCtrl::value_changed));
394 align.add(combobox);
395 value.type = gig::leverage_ctrl_t::type_none;
396 value.controller_number = 0;
397 }
398
399 void ChoiceEntryLeverageCtrl::value_changed()
400 {
401 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 for (uint cc = 0 ; cc < controlChangeTextsSize - 3 ; cc++) {
419 if (controlChangeTexts[cc + 3].txt) {
420 if (rowno == x) {
421 value.controller_number = cc;
422 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 break;
432 }
433 x++;
434 }
435 }
436 break;
437 }
438 if (rowno >= 0) sig_changed();
439 }
440
441 void ChoiceEntryLeverageCtrl::set_value(gig::leverage_ctrl_t value)
442 {
443 int comboIndex;
444 switch (value.type)
445 {
446 case gig::leverage_ctrl_t::type_none:
447 comboIndex = 0;
448 break;
449 case gig::leverage_ctrl_t::type_channelaftertouch:
450 comboIndex = 1;
451 break;
452 case gig::leverage_ctrl_t::type_velocity:
453 comboIndex = 2;
454 break;
455 case gig::leverage_ctrl_t::type_controlchange: {
456 comboIndex = -1;
457 int x = 3;
458 for (uint cc = 0 ; cc < controlChangeTextsSize - 3 ; cc++) {
459 if (controlChangeTexts[cc + 3].txt) {
460 if (value.controller_number == cc) {
461 comboIndex = x;
462 break;
463 }
464 x++;
465 }
466 }
467 break;
468 }
469 default:
470 comboIndex = -1;
471 break;
472 }
473 combobox.set_active(comboIndex);
474 }
475
476
477 BoolEntry::BoolEntry(const char* labelText) :
478 LabelWidget(labelText, checkbutton),
479 checkbutton(labelText)
480 {
481 checkbutton.signal_toggled().connect(sig_changed.make_slot());
482 }
483
484
485 StringEntry::StringEntry(const char* labelText) :
486 LabelWidget(labelText, entry)
487 {
488 entry.signal_changed().connect(sig_changed.make_slot());
489 }
490
491 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 StringEntryMultiLine::StringEntryMultiLine(const char* labelText) :
502 LabelWidget(labelText, frame)
503 {
504 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 }
509
510 gig::String StringEntryMultiLine::get_value() const
511 {
512 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 return gig_from_utf8(value);
516 }
517
518 void StringEntryMultiLine::set_value(const gig::String& value)
519 {
520 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 }
525
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