/[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 2690 - (hide 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 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 schoenebeck 1225 #include "paramedit.h"
23    
24 persson 1831 #include "global.h"
25 persson 2169 #include "compat.h"
26 schoenebeck 2541 #include "Settings.h"
27 persson 1831
28 schoenebeck 2541 #include <gtkmm/messagedialog.h>
29    
30 persson 2446 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 schoenebeck 1225 namespace {
42 schoenebeck 2541 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 schoenebeck 2538
82     // LSB variant of the various controllers above
83     // (so discouraged to be used here for now)
84 schoenebeck 2541 {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 schoenebeck 2538
88 schoenebeck 2541 { _("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 schoenebeck 2538 // (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 schoenebeck 1225 };
147     }
148    
149 schoenebeck 2541 #define controlChangeTextsSize (sizeof(controlChangeTexts) / sizeof(CCText))
150 schoenebeck 2538
151 schoenebeck 1225 LabelWidget::LabelWidget(const char* labelText, Gtk::Widget& widget) :
152     label(Glib::ustring(labelText) + ":"),
153     widget(widget)
154     {
155 persson 2169 label.set_alignment(Gtk::ALIGN_START);
156 schoenebeck 1225 }
157    
158     void LabelWidget::set_sensitive(bool sensitive)
159     {
160     label.set_sensitive(sensitive);
161     widget.set_sensitive(sensitive);
162     }
163    
164 schoenebeck 2690 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 schoenebeck 1225 NumEntry::NumEntry(const char* labelText, double lower, double upper,
178     int decimals) :
179 persson 2151 LabelWidget(labelText, box),
180 persson 2169 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
181 schoenebeck 1225 adjust(lower, lower, upper, 1, 10),
182 persson 2169 #else
183     adjust(Gtk::Adjustment::create(lower, lower, upper, 1, 10)),
184     #endif
185 schoenebeck 1225 scale(adjust),
186 persson 2151 spinbutton(adjust)
187 schoenebeck 1225 {
188 persson 2423 scale.set_size_request(70);
189 schoenebeck 1225 spinbutton.set_digits(decimals);
190 persson 1460 spinbutton.set_value(0);
191 persson 2507 spinbutton.set_numeric();
192 schoenebeck 1225 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 persson 2151 value(0),
202 persson 1460 coeff(coeff),
203     connected(true)
204 schoenebeck 1225 {
205     spinbutton.signal_value_changed().connect(
206     sigc::mem_fun(*this, &NumEntryGain::value_changed));
207     }
208    
209     void NumEntryGain::value_changed()
210     {
211 persson 1460 if (!connected) return;
212    
213 schoenebeck 1359 const double f = pow(10, spinbutton.get_digits());
214     int new_value = round_to_int(spinbutton.get_value() * f);
215 persson 1460 if (new_value != round_to_int(value / coeff * f)) {
216     value = round_to_int(new_value / f * coeff);
217     sig_changed();
218 schoenebeck 1225 }
219     }
220    
221 persson 1460 void NumEntryGain::set_value(int32_t value)
222 schoenebeck 1225 {
223 persson 1460 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 schoenebeck 1225 }
235    
236    
237     BoolEntryPlus6::BoolEntryPlus6(const char* labelText, NumEntryGain& eGain, int32_t plus6value) :
238     LabelWidget(labelText, checkbutton),
239 persson 1262 checkbutton(labelText),
240 schoenebeck 1225 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 persson 1460 if (checkbutton.get_active()) eGain.set_value(plus6value);
250     else if (eGain.get_value() < 0) eGain.set_value(0);
251 schoenebeck 1225 }
252    
253 persson 1460 int32_t BoolEntryPlus6::get_value() const
254 schoenebeck 1225 {
255 persson 1460 return eGain.get_value();
256 schoenebeck 1225 }
257    
258 persson 1460 void BoolEntryPlus6::set_value(int32_t value)
259     {
260     checkbutton.set_active(value < 0);
261     }
262    
263 schoenebeck 1225 NumEntryPermille::NumEntryPermille(const char* labelText,
264     double lower, double upper, int decimals) :
265 persson 1460 NumEntry(labelText, lower, upper, decimals),
266     value(0)
267 schoenebeck 1225 {
268     spinbutton.signal_value_changed().connect(
269     sigc::mem_fun(*this, &NumEntryPermille::value_changed));
270     }
271    
272     void NumEntryPermille::value_changed()
273     {
274 persson 1460 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 schoenebeck 1225 }
279     }
280    
281 persson 1460 void NumEntryPermille::set_value(uint16_t value)
282 schoenebeck 1225 {
283 persson 1460 if (value != this->value) {
284     spinbutton.set_value(value / 10.0);
285     }
286 schoenebeck 1225 }
287    
288    
289     NoteEntry::NoteEntry(const char* labelText) :
290     NumEntryTemp<uint8_t>(labelText)
291     {
292 persson 2507 spin_button_show_notes(spinbutton);
293 schoenebeck 1225 }
294    
295 persson 2507 namespace {
296     const char* notes[] = {
297     _("C"), _("C#"), _("D"), _("D#"), _("E"), _("F"),_("F#"),
298     _("G"), _("G#"), _("A"), _("A#"), _("B")
299     };
300 schoenebeck 1225
301 persson 2507 int note_value(const Glib::ustring& note, double* value)
302     {
303     const char* str = note.c_str();
304 schoenebeck 1225
305 persson 2507 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 schoenebeck 1225 {
330 persson 2507 double value = 0;
331     note_value(note, &value);
332     return value;
333     }
334 schoenebeck 1225
335 persson 2507 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 schoenebeck 1225 }
347 persson 2507
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 schoenebeck 1225 }
354     }
355    
356 persson 2507 // Make a SpinButton show notes instead of numbers
357     void spin_button_show_notes(Gtk::SpinButton& spin_button)
358 schoenebeck 1225 {
359 persson 2507 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 schoenebeck 1225 }
366    
367     ChoiceEntryLeverageCtrl::ChoiceEntryLeverageCtrl(const char* labelText) :
368 persson 2151 LabelWidget(labelText, align),
369     align(0, 0, 0, 0)
370 schoenebeck 1225 {
371 schoenebeck 2538 for (int i = 0 ; i < controlChangeTextsSize ; i++) {
372 schoenebeck 2541 if (controlChangeTexts[i].txt) {
373 schoenebeck 2538 const int cc = i - 3;
374     Glib::ustring s = (i < 3)
375 schoenebeck 2541 ? controlChangeTexts[i].txt
376     : Glib::ustring::compose("CC%1: %2%3", cc, controlChangeTexts[i].txt, controlChangeTexts[i].isExtension ? " [EXT]" : "");
377 persson 2507 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 24) || GTKMM_MAJOR_VERSION < 2
378 schoenebeck 2538 combobox.append_text(s);
379 persson 2169 #else
380 schoenebeck 2538 combobox.append(s);
381 persson 2169 #endif
382 schoenebeck 1225 }
383     }
384     combobox.signal_changed().connect(
385     sigc::mem_fun(*this, &ChoiceEntryLeverageCtrl::value_changed));
386     align.add(combobox);
387 persson 1460 value.type = gig::leverage_ctrl_t::type_none;
388     value.controller_number = 0;
389 schoenebeck 1225 }
390    
391     void ChoiceEntryLeverageCtrl::value_changed()
392     {
393 persson 1460 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 schoenebeck 2538 for (uint cc = 0 ; cc < controlChangeTextsSize - 3 ; cc++) {
411 schoenebeck 2541 if (controlChangeTexts[cc + 3].txt) {
412 persson 1460 if (rowno == x) {
413     value.controller_number = cc;
414 schoenebeck 2541 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 persson 1460 break;
424 schoenebeck 1225 }
425 persson 1460 x++;
426 schoenebeck 1225 }
427     }
428 persson 1460 break;
429 schoenebeck 1225 }
430 persson 1460 if (rowno >= 0) sig_changed();
431 schoenebeck 1225 }
432    
433 persson 1460 void ChoiceEntryLeverageCtrl::set_value(gig::leverage_ctrl_t value)
434 schoenebeck 1225 {
435 schoenebeck 2538 int comboIndex;
436 persson 1460 switch (value.type)
437 schoenebeck 1225 {
438     case gig::leverage_ctrl_t::type_none:
439 schoenebeck 2538 comboIndex = 0;
440 schoenebeck 1225 break;
441     case gig::leverage_ctrl_t::type_channelaftertouch:
442 schoenebeck 2538 comboIndex = 1;
443 schoenebeck 1225 break;
444     case gig::leverage_ctrl_t::type_velocity:
445 schoenebeck 2538 comboIndex = 2;
446 schoenebeck 1225 break;
447 schoenebeck 2538 case gig::leverage_ctrl_t::type_controlchange: {
448     comboIndex = -1;
449     int x = 3;
450     for (uint cc = 0 ; cc < controlChangeTextsSize - 3 ; cc++) {
451 schoenebeck 2541 if (controlChangeTexts[cc + 3].txt) {
452 persson 1460 if (value.controller_number == cc) {
453 schoenebeck 2538 comboIndex = x;
454 schoenebeck 1225 break;
455     }
456 schoenebeck 2538 x++;
457 schoenebeck 1225 }
458     }
459     break;
460 schoenebeck 2538 }
461 schoenebeck 1225 default:
462 schoenebeck 2538 comboIndex = -1;
463 schoenebeck 1225 break;
464     }
465 schoenebeck 2538 combobox.set_active(comboIndex);
466 schoenebeck 1225 }
467    
468    
469     BoolEntry::BoolEntry(const char* labelText) :
470     LabelWidget(labelText, checkbutton),
471 persson 1460 checkbutton(labelText)
472 schoenebeck 1225 {
473 persson 1460 checkbutton.signal_toggled().connect(sig_changed.make_slot());
474 schoenebeck 1225 }
475    
476    
477     StringEntry::StringEntry(const char* labelText) :
478     LabelWidget(labelText, entry)
479     {
480 persson 1582 entry.signal_changed().connect(sig_changed.make_slot());
481 schoenebeck 1225 }
482    
483 persson 2446 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 persson 1582 StringEntryMultiLine::StringEntryMultiLine(const char* labelText) :
494     LabelWidget(labelText, frame)
495 schoenebeck 1225 {
496 persson 1582 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 schoenebeck 1225 }
501    
502 persson 1582 gig::String StringEntryMultiLine::get_value() const
503 schoenebeck 1225 {
504 persson 1582 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 persson 2446 return gig_from_utf8(value);
508 schoenebeck 1225 }
509 persson 1582
510 persson 2446 void StringEntryMultiLine::set_value(const gig::String& value)
511 persson 1582 {
512 persson 2446 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 persson 1582 }
517 persson 2423
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