/[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 2690 - (show annotations) (download)
Sun Jan 4 18:36:42 2015 UTC (9 years, 3 months ago) by schoenebeck
File size: 16936 byte(s)
* Dimension Region Editor: Show coarse sample format info (audio channels,
  bit depth, sample rate) and unique sample ID (since the gig format allows
  different samples to have the same name).

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

  ViewVC Help
Powered by ViewVC