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

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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1460 by persson, Sat Oct 27 12:28:33 2007 UTC revision 2541 by schoenebeck, Wed Apr 23 16:49:05 2014 UTC
# Line 1  Line 1 
1  /*  /*
2   * Copyright (C) 2006, 2007 Andreas Persson   * Copyright (C) 2006-2014 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
# Line 17  Line 17 
17   * 02110-1301 USA.   * 02110-1301 USA.
18   */   */
19    
20    #include <cstring>
21    
22  #include "paramedit.h"  #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 {  namespace {
42      const char* const controlChangeTexts[] = {      struct CCText {
43          "none", "channelaftertouch", "velocity",          const char* const txt;
44          0,          bool isExtension; ///< True if this is a controller only supported by LinuxSampler, but not supperted by Gigasampler/GigaStudio.
45          "modwheel", // "Modulation Wheel or Lever",      };
46          "breath", // "Breath Controller",      static const CCText controlChangeTexts[] = {
47          0,          // 3 special ones (not being CCs)
48          "foot", // "Foot Controller",          { _("none") }, { _("channelaftertouch") }, { _("velocity") },
49          "portamentotime", // "Portamento Time",          {0}, // bank select MSB (hard coded in sampler, so discouraged to be used here, even though considerable)
50          0, 0, 0, 0, 0, 0,          { _("modwheel") }, // "Modulation Wheel or Lever",
51          "effect1", // "Effect Control 1",          { _("breath") }, // "Breath Controller",
52          "effect2", // "Effect Control 2",          { _("undefined"), true },
53          0, 0,          { _("foot") }, // "Foot Controller",
54          "genpurpose1", // "General Purpose Controller 1",          { _("portamentotime") }, // "Portamento Time",
55          "genpurpose2", // "General Purpose Controller 2",          { _("data entry MSB"), true },
56          "genpurpose3", // "General Purpose Controller 3",          { _("volume"), true },
57          "genpurpose4", // "General Purpose Controller 4",          { _("balance"), true },
58          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,          { _("undefined"), true },
59          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,          { _("pan"), true },
60          0, 0, 0, 0, 0, 0,          { _("expression"), true },
61          "sustainpedal", // "Damper Pedal on/off (Sustain)",          { _("effect1") }, // "Effect Control 1",
62          "portamento", // "Portamento On/Off",          { _("effect2") }, // "Effect Control 2",
63          "sostenuto", // "Sustenuto On/Off",          { _("undefined"), true },
64          "softpedal", // "Soft Pedal On/Off",          { _("undefined"), true },
65          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,          { _("genpurpose1") }, // "General Purpose Controller 1",
66          "genpurpose5", // "General Purpose Controller 5",          { _("genpurpose2") }, // "General Purpose Controller 2",
67          "genpurpose6", // "General Purpose Controller 6",          { _("genpurpose3") }, // "General Purpose Controller 3",
68          "genpurpose7", // "General Purpose Controller 7",          { _("genpurpose4") }, // "General Purpose Controller 4",
69          "genpurpose8", // "General Purpose Controller 8",          { _("undefined"), true },
70          0, 0, 0, 0, 0, 0, 0,          { _("undefined"), true },
71          "effect1depth", // "Effects 1 Depth",          { _("undefined"), true },
72          "effect2depth", // "Effects 2 Depth",          { _("undefined"), true },
73          "effect3depth", // "Effects 3 Depth",          { _("undefined"), true },
74          "effect4depth", // "Effects 4 Depth",          { _("undefined"), true },
75          "effect5depth", // "Effects 5 Depth"          { _("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) :  LabelWidget::LabelWidget(const char* labelText, Gtk::Widget& widget) :
152      label(Glib::ustring(labelText) + ":"),      label(Glib::ustring(labelText) + ":"),
153      widget(widget)      widget(widget)
154  {  {
155      label.set_alignment(Gtk::ALIGN_LEFT);      label.set_alignment(Gtk::ALIGN_START);
156  }  }
157    
158  void LabelWidget::set_sensitive(bool sensitive)  void LabelWidget::set_sensitive(bool sensitive)
# Line 72  void LabelWidget::set_sensitive(bool sen Line 163  void LabelWidget::set_sensitive(bool sen
163    
164  NumEntry::NumEntry(const char* labelText, double lower, double upper,  NumEntry::NumEntry(const char* labelText, double lower, double upper,
165                     int decimals) :                     int decimals) :
166        LabelWidget(labelText, box),
167    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
168      adjust(lower, lower, upper, 1, 10),      adjust(lower, lower, upper, 1, 10),
169    #else
170        adjust(Gtk::Adjustment::create(lower, lower, upper, 1, 10)),
171    #endif
172      scale(adjust),      scale(adjust),
173      spinbutton(adjust),      spinbutton(adjust)
     LabelWidget(labelText, box)  
174  {  {
175        scale.set_size_request(70);
176      spinbutton.set_digits(decimals);      spinbutton.set_digits(decimals);
177      spinbutton.set_value(0);      spinbutton.set_value(0);
178        spinbutton.set_numeric();
179      scale.set_draw_value(false);      scale.set_draw_value(false);
180      box.pack_start(spinbutton, Gtk::PACK_SHRINK);      box.pack_start(spinbutton, Gtk::PACK_SHRINK);
181      box.add(scale);      box.add(scale);
# Line 88  NumEntryGain::NumEntryGain(const char* l Line 185  NumEntryGain::NumEntryGain(const char* l
185                             double lower, double upper,                             double lower, double upper,
186                             int decimals, double coeff) :                             int decimals, double coeff) :
187      NumEntry(labelText, lower, upper, decimals),      NumEntry(labelText, lower, upper, decimals),
     coeff(coeff),  
188      value(0),      value(0),
189        coeff(coeff),
190      connected(true)      connected(true)
191  {  {
192      spinbutton.signal_value_changed().connect(      spinbutton.signal_value_changed().connect(
# Line 179  void NumEntryPermille::set_value(uint16_ Line 276  void NumEntryPermille::set_value(uint16_
276  NoteEntry::NoteEntry(const char* labelText) :  NoteEntry::NoteEntry(const char* labelText) :
277      NumEntryTemp<uint8_t>(labelText)      NumEntryTemp<uint8_t>(labelText)
278  {  {
279      spinbutton.signal_input().connect(      spin_button_show_notes(spinbutton);
         sigc::mem_fun(*this, &NoteEntry::on_input));  
     spinbutton.signal_output().connect(  
         sigc::mem_fun(*this, &NoteEntry::on_output));  
280  }  }
281    
282  const char* notes[] = {  namespace {
283      "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"      const char* notes[] = {
284  };          _("C"), _("C#"), _("D"), _("D#"), _("E"), _("F"),_("F#"),
285            _("G"), _("G#"), _("A"), _("A#"), _("B")
286        };
287    
288        int note_value(const Glib::ustring& note, double* value)
289        {
290            const char* str = note.c_str();
291    
292            int i;
293            for (i = 11 ; i >= 0 ; i--) {
294                if (strncasecmp(str, notes[i], strlen(notes[i])) == 0) break;
295            }
296            if (i >= 0) {
297                char* endptr;
298                long x = strtol(str + strlen(notes[i]), &endptr, 10);
299                if (endptr != str + strlen(notes[i])) {
300                    *value = std::max(0L, std::min(i + (x + 1) * 12, 127L));
301                    return true;
302                }
303            } else {
304                char* endptr;
305                long x = strtol(str, &endptr, 10);
306                if (endptr != str) {
307                    *value = std::max(0L, std::min(x, 127L));
308                    return true;
309                }
310            }
311            return Gtk::INPUT_ERROR;
312        }
313    }
314    
315  // Convert the Entry text to a number  int note_value(const Glib::ustring& note)
 int NoteEntry::on_input(double* new_value)  
316  {  {
317      const char* str = spinbutton.get_text().c_str();      double value = 0;
318        note_value(note, &value);
319        return value;
320    }
321    
322      int i;  Glib::ustring note_str(int note)
323      for (i = 11 ; i >= 0 ; i--) {  {
324          if (strncmp(str, notes[i], strlen(notes[i])) == 0) break;      char buf[10];
325        sprintf(buf, "%s%d", notes[note % 12], note / 12 - 1);
326        return buf;
327    }
328    
329    namespace {
330        // Convert the Entry text to a number
331        int on_input(double* new_value, Gtk::SpinButton* spinbutton) {
332            return note_value(spinbutton->get_text(), new_value);
333      }      }
334      if (i >= 0) {  
335          char* endptr;      // Convert the Adjustment position to text
336          long x = strtol(str + strlen(notes[i]), &endptr, 10);      bool on_output(Gtk::SpinButton* spinbutton) {
337          if (endptr != str + strlen(notes[i])) {          spinbutton->set_text(
338              *new_value = i + (x + 1) * 12;              note_str(spinbutton->get_adjustment()->get_value() + 0.5));
339              return true;          return true;
         }  
340      }      }
     return Gtk::INPUT_ERROR;  
341  }  }
342    
343  // Convert the Adjustment position to text  // Make a SpinButton show notes instead of numbers
344  bool NoteEntry::on_output()  void spin_button_show_notes(Gtk::SpinButton& spin_button)
345  {  {
346      int x = int(spinbutton.get_adjustment()->get_value() + 0.5);      spin_button.set_numeric(false);
347      char buf[10];      spin_button.set_width_chars(4);
348      sprintf(buf, "%s%d", notes[x % 12], x / 12 - 1);      spin_button.signal_input().connect(
349      spinbutton.set_text(buf);          sigc::bind(sigc::ptr_fun(&on_input), &spin_button));
350      return true;      spin_button.signal_output().connect(
351            sigc::bind(sigc::ptr_fun(&on_output), &spin_button));
352  }  }
353    
354  ChoiceEntryLeverageCtrl::ChoiceEntryLeverageCtrl(const char* labelText) :  ChoiceEntryLeverageCtrl::ChoiceEntryLeverageCtrl(const char* labelText) :
355      align(0, 0, 0, 0),      LabelWidget(labelText, align),
356      LabelWidget(labelText, align)      align(0, 0, 0, 0)
357  {  {
358      for (int i = 0 ; i < 99 ; i++) {      for (int i = 0 ; i < controlChangeTextsSize ; i++) {
359          if (controlChangeTexts[i]) {          if (controlChangeTexts[i].txt) {
360              combobox.append_text(controlChangeTexts[i]);              const int cc = i - 3;
361                Glib::ustring s = (i < 3)
362                    ? controlChangeTexts[i].txt
363                    : Glib::ustring::compose("CC%1: %2%3", cc, controlChangeTexts[i].txt, controlChangeTexts[i].isExtension ? " [EXT]" : "");
364    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 24) || GTKMM_MAJOR_VERSION < 2
365                combobox.append_text(s);
366    #else
367                combobox.append(s);
368    #endif
369          }          }
370      }      }
371      combobox.signal_changed().connect(      combobox.signal_changed().connect(
# Line 255  void ChoiceEntryLeverageCtrl::value_chan Line 394  void ChoiceEntryLeverageCtrl::value_chan
394      default:      default:
395          value.type = gig::leverage_ctrl_t::type_controlchange;          value.type = gig::leverage_ctrl_t::type_controlchange;
396          int x = 3;          int x = 3;
397          for (int cc = 0 ; cc < 96 ; cc++) {          for (uint cc = 0 ; cc < controlChangeTextsSize - 3 ; cc++) {
398              if (controlChangeTexts[cc + 3]) {              if (controlChangeTexts[cc + 3].txt) {
399                  if (rowno == x) {                  if (rowno == x) {
400                      value.controller_number = cc;                      value.controller_number = cc;
401                        if (controlChangeTexts[cc + 3].isExtension &&
402                            Settings::singleton()->warnUserOnExtensions)
403                        {
404                            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.)");
405                            Gtk::MessageDialog msg(
406                                txt, true, Gtk::MESSAGE_WARNING
407                            );
408                            msg.run();
409                        }
410                      break;                      break;
411                  }                  }
412                  x++;                  x++;
# Line 271  void ChoiceEntryLeverageCtrl::value_chan Line 419  void ChoiceEntryLeverageCtrl::value_chan
419    
420  void ChoiceEntryLeverageCtrl::set_value(gig::leverage_ctrl_t value)  void ChoiceEntryLeverageCtrl::set_value(gig::leverage_ctrl_t value)
421  {  {
422      int x;      int comboIndex;
423      switch (value.type)      switch (value.type)
424      {      {
425      case gig::leverage_ctrl_t::type_none:      case gig::leverage_ctrl_t::type_none:
426          x = 0;          comboIndex = 0;
427          break;          break;
428      case gig::leverage_ctrl_t::type_channelaftertouch:      case gig::leverage_ctrl_t::type_channelaftertouch:
429          x = 1;          comboIndex = 1;
430          break;          break;
431      case gig::leverage_ctrl_t::type_velocity:      case gig::leverage_ctrl_t::type_velocity:
432          x = 2;          comboIndex = 2;
433          break;          break;
434      case gig::leverage_ctrl_t::type_controlchange:      case gig::leverage_ctrl_t::type_controlchange: {
435          x = -1;          comboIndex = -1;
436          for (int cc = 0 ; cc < 96 ; cc++) {          int x = 3;
437              if (controlChangeTexts[cc + 3]) {          for (uint cc = 0 ; cc < controlChangeTextsSize - 3 ; cc++) {
438                  x++;              if (controlChangeTexts[cc + 3].txt) {
439                  if (value.controller_number == cc) {                  if (value.controller_number == cc) {
440                      x += 3;                      comboIndex = x;
441                      break;                      break;
442                  }                  }
443                    x++;
444              }              }
445          }          }
446          break;          break;
447        }
448      default:      default:
449          x = -1;          comboIndex = -1;
450          break;          break;
451      }      }
452      combobox.set_active(x);      combobox.set_active(comboIndex);
453  }  }
454    
455    
# Line 314  BoolEntry::BoolEntry(const char* labelTe Line 464  BoolEntry::BoolEntry(const char* labelTe
464  StringEntry::StringEntry(const char* labelText) :  StringEntry::StringEntry(const char* labelText) :
465      LabelWidget(labelText, entry)      LabelWidget(labelText, entry)
466  {  {
467      entry.signal_changed().connect(      entry.signal_changed().connect(sig_changed.make_slot());
         sigc::mem_fun(*this, &StringEntry::value_changed));  
468  }  }
469    
470  void StringEntry::value_changed()  gig::String StringEntry::get_value() const
471  {  {
472      if (ptr) {      return gig_from_utf8(entry.get_text());
473          *ptr = entry.get_text();  }
474          sig_changed();  
475      }  void StringEntry::set_value(const gig::String& value) {
476        entry.set_text(gig_to_utf8(value));
477    }
478    
479    
480    StringEntryMultiLine::StringEntryMultiLine(const char* labelText) :
481        LabelWidget(labelText, frame)
482    {
483        text_buffer = text_view.get_buffer();
484        frame.set_shadow_type(Gtk::SHADOW_IN);
485        frame.add(text_view);
486        text_buffer->signal_changed().connect(sig_changed.make_slot());
487    }
488    
489    gig::String StringEntryMultiLine::get_value() const
490    {
491        Glib::ustring value = text_buffer->get_text();
492        for (int i = 0 ; (i = value.find("\x0a", i)) >= 0 ; i += 2)
493            value.replace(i, 1, "\x0d\x0a");
494        return gig_from_utf8(value);
495    }
496    
497    void StringEntryMultiLine::set_value(const gig::String& value)
498    {
499        Glib::ustring text = gig_to_utf8(value);
500        for (int i = 0 ; (i = text.find("\x0d\x0a", i, 2)) >= 0 ; i++)
501            text.replace(i, 2, "\x0a");
502        text_buffer->set_text(text);
503    }
504    
505    
506    Table::Table(int x, int y) : Gtk::Table(x, y), rowno(0) {  }
507    
508    void Table::add(BoolEntry& boolentry)
509    {
510        attach(boolentry.widget, 0, 2, rowno, rowno + 1,
511               Gtk::FILL, Gtk::SHRINK);
512        rowno++;
513    }
514    
515    void Table::add(BoolEntryPlus6& boolentry)
516    {
517        attach(boolentry.widget, 0, 2, rowno, rowno + 1,
518               Gtk::FILL, Gtk::SHRINK);
519        rowno++;
520  }  }
521    
522  void StringEntry::set_ptr(gig::String* ptr)  void Table::add(LabelWidget& prop)
523  {  {
524      this->ptr = 0;      attach(prop.label, 1, 2, rowno, rowno + 1,
525      entry.set_text(*ptr);             Gtk::FILL, Gtk::SHRINK);
526      this->ptr = ptr;      attach(prop.widget, 2, 3, rowno, rowno + 1,
527               Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK);
528        rowno++;
529  }  }

Legend:
Removed from v.1460  
changed lines
  Added in v.2541

  ViewVC Help
Powered by ViewVC