/[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 2538 - (show annotations) (download)
Tue Apr 22 16:13:50 2014 UTC (10 years 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 /*
2 * Copyright (C) 2006-2014 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
27 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 namespace {
39 const char* const controlChangeTexts[] = {
40 _("none"), _("channelaftertouch"), _("velocity"),
41 0, // bank select MSB (hard coded in sampler, so discouraged to be used here, even though considerable)
42 _("modwheel"), // "Modulation Wheel or Lever",
43 _("breath"), // "Breath Controller",
44 _("undefined"),
45 _("foot"), // "Foot Controller",
46 _("portamentotime"), // "Portamento Time",
47 _("data entry MSB"),
48 _("volume"),
49 _("balance"),
50 _("undefined"),
51 _("pan"),
52 _("expression"),
53 _("effect1"), // "Effect Control 1",
54 _("effect2"), // "Effect Control 2",
55 _("undefined"),
56 _("undefined"),
57 _("genpurpose1"), // "General Purpose Controller 1",
58 _("genpurpose2"), // "General Purpose Controller 2",
59 _("genpurpose3"), // "General Purpose Controller 3",
60 _("genpurpose4"), // "General Purpose Controller 4",
61 _("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 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
80 _("sustainpedal"), // "Damper Pedal on/off (Sustain)",
81 _("portamento"), // "Portamento On/Off",
82 _("sostenuto"), // "Sustenuto On/Off",
83 _("softpedal"), // "Soft Pedal On/Off",
84 _("legato"),
85 _("hold2"),
86 _("soundvariation"),
87 _("timbre"),
88 _("releasetime"),
89 _("attacktime"),
90 _("brightness"),
91 _("decaytime"),
92 _("vibratorate"),
93 _("vibratodepth"),
94 _("vibratodelay"),
95 _("undefined"),
96 _("genpurpose5"), // "General Purpose Controller 5",
97 _("genpurpose6"), // "General Purpose Controller 6",
98 _("genpurpose7"), // "General Purpose Controller 7",
99 _("genpurpose8"), // "General Purpose Controller 8",
100 _("portamentoctrl"),
101 _("undefined"),
102 _("undefined"),
103 _("undefined"),
104 0, // high resolution velocity prefix (so discouraged to be used here)
105 _("undefined"),
106 _("undefined"),
107 _("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 _("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 };
139 }
140
141 #define controlChangeTextsSize (sizeof(controlChangeTexts) / sizeof(char*))
142
143 LabelWidget::LabelWidget(const char* labelText, Gtk::Widget& widget) :
144 label(Glib::ustring(labelText) + ":"),
145 widget(widget)
146 {
147 label.set_alignment(Gtk::ALIGN_START);
148 }
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 LabelWidget(labelText, box),
159 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
160 adjust(lower, lower, upper, 1, 10),
161 #else
162 adjust(Gtk::Adjustment::create(lower, lower, upper, 1, 10)),
163 #endif
164 scale(adjust),
165 spinbutton(adjust)
166 {
167 scale.set_size_request(70);
168 spinbutton.set_digits(decimals);
169 spinbutton.set_value(0);
170 spinbutton.set_numeric();
171 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 value(0),
181 coeff(coeff),
182 connected(true)
183 {
184 spinbutton.signal_value_changed().connect(
185 sigc::mem_fun(*this, &NumEntryGain::value_changed));
186 }
187
188 void NumEntryGain::value_changed()
189 {
190 if (!connected) return;
191
192 const double f = pow(10, spinbutton.get_digits());
193 int new_value = round_to_int(spinbutton.get_value() * f);
194 if (new_value != round_to_int(value / coeff * f)) {
195 value = round_to_int(new_value / f * coeff);
196 sig_changed();
197 }
198 }
199
200 void NumEntryGain::set_value(int32_t value)
201 {
202 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 }
214
215
216 BoolEntryPlus6::BoolEntryPlus6(const char* labelText, NumEntryGain& eGain, int32_t plus6value) :
217 LabelWidget(labelText, checkbutton),
218 checkbutton(labelText),
219 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 if (checkbutton.get_active()) eGain.set_value(plus6value);
229 else if (eGain.get_value() < 0) eGain.set_value(0);
230 }
231
232 int32_t BoolEntryPlus6::get_value() const
233 {
234 return eGain.get_value();
235 }
236
237 void BoolEntryPlus6::set_value(int32_t value)
238 {
239 checkbutton.set_active(value < 0);
240 }
241
242 NumEntryPermille::NumEntryPermille(const char* labelText,
243 double lower, double upper, int decimals) :
244 NumEntry(labelText, lower, upper, decimals),
245 value(0)
246 {
247 spinbutton.signal_value_changed().connect(
248 sigc::mem_fun(*this, &NumEntryPermille::value_changed));
249 }
250
251 void NumEntryPermille::value_changed()
252 {
253 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 }
258 }
259
260 void NumEntryPermille::set_value(uint16_t value)
261 {
262 if (value != this->value) {
263 spinbutton.set_value(value / 10.0);
264 }
265 }
266
267
268 NoteEntry::NoteEntry(const char* labelText) :
269 NumEntryTemp<uint8_t>(labelText)
270 {
271 spin_button_show_notes(spinbutton);
272 }
273
274 namespace {
275 const char* notes[] = {
276 _("C"), _("C#"), _("D"), _("D#"), _("E"), _("F"),_("F#"),
277 _("G"), _("G#"), _("A"), _("A#"), _("B")
278 };
279
280 int note_value(const Glib::ustring& note, double* value)
281 {
282 const char* str = note.c_str();
283
284 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 {
309 double value = 0;
310 note_value(note, &value);
311 return value;
312 }
313
314 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 }
326
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 }
333 }
334
335 // Make a SpinButton show notes instead of numbers
336 void spin_button_show_notes(Gtk::SpinButton& spin_button)
337 {
338 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 }
345
346 ChoiceEntryLeverageCtrl::ChoiceEntryLeverageCtrl(const char* labelText) :
347 LabelWidget(labelText, align),
348 align(0, 0, 0, 0)
349 {
350 for (int i = 0 ; i < controlChangeTextsSize ; i++) {
351 if (controlChangeTexts[i]) {
352 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 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 24) || GTKMM_MAJOR_VERSION < 2
357 combobox.append_text(s);
358 #else
359 combobox.append(s);
360 #endif
361 }
362 }
363 combobox.signal_changed().connect(
364 sigc::mem_fun(*this, &ChoiceEntryLeverageCtrl::value_changed));
365 align.add(combobox);
366 value.type = gig::leverage_ctrl_t::type_none;
367 value.controller_number = 0;
368 }
369
370 void ChoiceEntryLeverageCtrl::value_changed()
371 {
372 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 for (uint cc = 0 ; cc < controlChangeTextsSize - 3 ; cc++) {
390 if (controlChangeTexts[cc + 3]) {
391 if (rowno == x) {
392 value.controller_number = cc;
393 break;
394 }
395 x++;
396 }
397 }
398 break;
399 }
400 if (rowno >= 0) sig_changed();
401 }
402
403 void ChoiceEntryLeverageCtrl::set_value(gig::leverage_ctrl_t value)
404 {
405 int comboIndex;
406 switch (value.type)
407 {
408 case gig::leverage_ctrl_t::type_none:
409 comboIndex = 0;
410 break;
411 case gig::leverage_ctrl_t::type_channelaftertouch:
412 comboIndex = 1;
413 break;
414 case gig::leverage_ctrl_t::type_velocity:
415 comboIndex = 2;
416 break;
417 case gig::leverage_ctrl_t::type_controlchange: {
418 comboIndex = -1;
419 int x = 3;
420 for (uint cc = 0 ; cc < controlChangeTextsSize - 3 ; cc++) {
421 if (controlChangeTexts[cc + 3]) {
422 if (value.controller_number == cc) {
423 comboIndex = x;
424 break;
425 }
426 x++;
427 }
428 }
429 break;
430 }
431 default:
432 comboIndex = -1;
433 break;
434 }
435 combobox.set_active(comboIndex);
436 }
437
438
439 BoolEntry::BoolEntry(const char* labelText) :
440 LabelWidget(labelText, checkbutton),
441 checkbutton(labelText)
442 {
443 checkbutton.signal_toggled().connect(sig_changed.make_slot());
444 }
445
446
447 StringEntry::StringEntry(const char* labelText) :
448 LabelWidget(labelText, entry)
449 {
450 entry.signal_changed().connect(sig_changed.make_slot());
451 }
452
453 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 StringEntryMultiLine::StringEntryMultiLine(const char* labelText) :
464 LabelWidget(labelText, frame)
465 {
466 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 }
471
472 gig::String StringEntryMultiLine::get_value() const
473 {
474 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 return gig_from_utf8(value);
478 }
479
480 void StringEntryMultiLine::set_value(const gig::String& value)
481 {
482 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 }
487
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