/[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 2538 - (hide annotations) (download)
Tue Apr 22 16:13:50 2014 UTC (9 years, 11 months ago) by schoenebeck
File size: 14714 byte(s)
* fix: only a small set of possible MIDI controllers was selectable for
  EG1 controller, EG2 controller and attenuation controller (and no CC
  number was shown in the combo box)

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

  ViewVC Help
Powered by ViewVC