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

Contents of /gigedit/trunk/src/gigedit/midirules.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3225 - (show annotations) (download)
Fri May 26 22:10:16 2017 UTC (6 years, 10 months ago) by schoenebeck
File size: 19020 byte(s)
* Assigned more useful default dimensions (and default position) for various
  windows and dialogs (if auto-restore of user's own custom window
  dimensions is disabled).
* Bumped version (1.0.0.svn51).

1 /*
2 * Copyright (C) 2013-2017 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 of the
7 * License, or (at 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 this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301, USA.
18 */
19
20 #include "global.h"
21 #include "midirules.h"
22
23 #include <gtkmm/stock.h>
24
25
26 MidiRules::MidiRules() :
27 label(_("Midi rule:")),
28 quit_button(Gtk::Stock::CLOSE),
29 unknown(_("unknown"))
30 {
31 if (!Settings::singleton()->autoRestoreWindowDimension) {
32 //set_default_size(470, 390);
33 set_position(Gtk::WIN_POS_MOUSE);
34 }
35
36 set_title(_("Midi Rules"));
37 set_border_width(6);
38
39 add(vbox);
40
41 hbox.set_border_width(6);
42 hbox.set_spacing(6);
43 hbox.pack_start(label, Gtk::PACK_SHRINK);
44 hbox.pack_start(combo, Gtk::PACK_SHRINK);
45 const char* choices[] = { _("none"), _("Controller trigger"),
46 _("Legato"), 0 };
47 for (int i = 0 ; choices[i] ; i++) {
48 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 24) || GTKMM_MAJOR_VERSION < 2
49 combo.append_text(choices[i]);
50 #else
51 combo.append(choices[i]);
52 #endif
53 }
54 combo.signal_changed().connect(
55 sigc::mem_fun(*this, &MidiRules::combo_changed));
56 vbox.pack_start(hbox, Gtk::PACK_SHRINK);
57
58 box.set_border_width(6);
59 vbox.pack_start(box);
60
61 button_box.set_border_width(6);
62 button_box.set_layout(Gtk::BUTTONBOX_END);
63 button_box.pack_start(quit_button);
64 quit_button.set_can_default();
65 quit_button.grab_focus();
66 quit_button.signal_clicked().connect(
67 sigc::mem_fun(*this, &MidiRules::hide));
68 vbox.pack_start(button_box, Gtk::PACK_SHRINK);
69
70 legato.signal_changed().connect(sig_changed.make_slot());
71 ctrl_trigger.signal_changed().connect(sig_changed.make_slot());
72
73 show_all_children();
74 }
75
76 void MidiRules::combo_changed() {
77 if (update_model) return;
78
79 int rowno = combo.get_active_row_number();
80
81 if (remove_unknown_from_combo()) {
82 rowno--;
83 }
84
85 gig::MidiRule* rule = m->GetMidiRule(0);
86 switch (rowno) {
87 case NONE:
88 if (rule) {
89 m->DeleteMidiRule(0);
90 set_instrument(m);
91 }
92 break;
93 case CTRL_TRIGGER:
94 if (!dynamic_cast<gig::MidiRuleCtrlTrigger*>(rule)) {
95 m->AddMidiRuleCtrlTrigger();
96 set_instrument(m);
97 }
98 break;
99 case LEGATO:
100 if (!dynamic_cast<gig::MidiRuleLegato*>(rule)) {
101 m->AddMidiRuleLegato();
102 set_instrument(m);
103 }
104 break;
105 }
106 sig_changed();
107 }
108
109 void MidiRules::set_instrument(gig::Instrument* instrument) {
110 m = instrument;
111 update_model++;
112
113 std::vector<Widget*> children = box.get_children();
114 if (children.size() == 1) {
115 box.remove(*children[0]);
116 }
117
118 gig::MidiRule* rule = instrument->GetMidiRule(0);
119 int active = -1;
120 if (!rule) {
121 active = NONE;
122 } else if (gig::MidiRuleLegato* r =
123 dynamic_cast<gig::MidiRuleLegato*>(rule)) {
124 active = LEGATO;
125 box.add(legato);
126 legato.set_rule(r);
127 } else if (gig::MidiRuleCtrlTrigger* r =
128 dynamic_cast<gig::MidiRuleCtrlTrigger*>(rule)) {
129 active = CTRL_TRIGGER;
130 box.add(ctrl_trigger);
131 ctrl_trigger.set_rule(r);
132 } else {
133 if (combo.get_model()->children().size() == NUMBER_OF_RULES) {
134 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 24) || GTKMM_MAJOR_VERSION < 2
135 combo.prepend_text(unknown);
136 #else
137 combo.prepend(unknown);
138 #endif
139 }
140 combo.set_active(0);
141 }
142 if (active != -1) {
143 remove_unknown_from_combo();
144 combo.set_active(active);
145 }
146 show_all_children();
147 update_model--;
148 }
149
150 bool MidiRules::remove_unknown_from_combo() {
151 if (combo.get_model()->children().size() == NUMBER_OF_RULES + 1) {
152 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
153 combo.remove_text(unknown);
154 #else
155 combo.remove_text(0);
156 #endif
157 return true;
158 }
159 return false;
160 }
161
162
163 MidiRuleCtrlTrigger::MidiRuleCtrlTrigger() :
164 table(2, 1),
165 eControllerNumber(_("Controller"))
166 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
167 , add_button(Gtk::Stock::ADD),
168 remove_button(Gtk::Stock::REMOVE)
169 #endif
170 {
171 connect(eControllerNumber, &gig::MidiRuleCtrlTrigger::ControllerNumber);
172
173 set_spacing(6);
174
175 scrolled_window.set_size_request(-1, 120);
176
177 list_store = Gtk::ListStore::create(columns);
178 tree_view.set_model(list_store);
179 list_store->signal_row_changed().connect(
180 sigc::mem_fun(*this, &MidiRuleCtrlTrigger::row_changed));
181 list_store->signal_row_inserted().connect(
182 sigc::mem_fun(*this, &MidiRuleCtrlTrigger::row_inserted));
183 list_store->signal_row_deleted().connect(
184 sigc::mem_fun(*this, &MidiRuleCtrlTrigger::row_deleted));
185
186 append_num_column(_("Trigger point"), columns.trigger_point);
187 tree_view.append_column_editable(_("Descending"), columns.descending);
188 append_num_column(_("Vel sensitivity"), columns.vel_sensitivity, 1, 100);
189 append_note_column(_("Key"), columns.key);
190 tree_view.append_column_editable(_("Note off"), columns.note_off);
191 tree_view.append_column_editable(_("Switch"), columns.switch_logic);
192
193 int cols_count = append_num_column(_("Velocity"), columns.velocity);
194 Gtk::TreeViewColumn* col = tree_view.get_column(cols_count - 1);
195 col->add_attribute(*col->get_first_cell(), "visible", columns.switch_logic);
196 cols_count = tree_view.append_column_editable(_("Override pedal"),
197 columns.override_pedal);
198 col = tree_view.get_column(cols_count - 1);
199 col->add_attribute(*col->get_first_cell(), "visible", columns.note_off);
200
201 tree_view.get_selection()->signal_changed().connect(
202 sigc::mem_fun(*this, &MidiRuleCtrlTrigger::sel_changed));
203
204 scrolled_window.add(tree_view);
205 scrolled_window.set_shadow_type(Gtk::SHADOW_IN);
206 scrolled_window.set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
207
208 table.set_col_spacings(5);
209 table.add(eControllerNumber);
210 pack_start(table, Gtk::PACK_SHRINK);
211
212 vbox.add(scrolled_window);
213
214 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
215 vbox.set_spacing(6);
216 toolbar.set_layout(Gtk::BUTTONBOX_START);
217 toolbar.set_homogeneous();
218 toolbar.set_spacing(6);
219 #else
220 toolbar.set_toolbar_style(Gtk::TOOLBAR_ICONS);
221 toolbar.set_show_arrow(false);
222 toolbar.set_icon_size(Gtk::IconSize(1));
223 toolbar.get_style_context()->add_class("inline-toolbar");
224
225 add_button.set_icon_name("list-add-symbolic");
226 remove_button.set_icon_name("list-remove-symbolic");
227 #endif
228
229 add_button.signal_clicked().connect(
230 sigc::mem_fun(*this, &MidiRuleCtrlTrigger::add_row));
231 toolbar.add(add_button);
232
233 remove_button.signal_clicked().connect(
234 sigc::mem_fun(*this, &MidiRuleCtrlTrigger::remove_row));
235 toolbar.add(remove_button);
236
237 vbox.pack_start(toolbar, Gtk::PACK_SHRINK);
238 add(vbox);
239 }
240
241 int MidiRuleCtrlTrigger::append_num_column(
242 const char* title,
243 const Gtk::TreeModelColumn<int>& column,
244 int lower, int upper) {
245 Gtk::CellRendererSpin* renderer = Gtk::manage(new Gtk::CellRendererSpin());
246 renderer->property_editable() = true;
247 renderer->signal_editing_started().connect(
248 sigc::bind(
249 sigc::mem_fun(*this, &MidiRuleCtrlTrigger::num_editing_started),
250 renderer));
251 renderer->signal_edited().connect(
252 sigc::bind(
253 sigc::mem_fun(*this, &MidiRuleCtrlTrigger::num_edited),
254 column));
255 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
256 renderer->property_adjustment() = new Gtk::Adjustment(lower, lower, upper);
257 #else
258 renderer->property_adjustment() =
259 Gtk::Adjustment::create(lower, lower, upper);
260 #endif
261
262 int cols_count = tree_view.append_column(title, *renderer);
263 Gtk::TreeViewColumn* col = tree_view.get_column(cols_count - 1);
264 col->add_attribute(*renderer, "text", column);
265 col->set_min_width(92);
266 return cols_count;
267 }
268
269 int MidiRuleCtrlTrigger::append_note_column(
270 const char* title,
271 const Gtk::TreeModelColumn<Glib::ustring>& column) {
272 Gtk::CellRendererSpin* renderer = Gtk::manage(new Gtk::CellRendererSpin());
273 renderer->property_editable() = true;
274 renderer->signal_editing_started().connect(
275 sigc::bind(
276 sigc::mem_fun(*this, &MidiRuleCtrlTrigger::note_editing_started),
277 renderer));
278 renderer->signal_edited().connect(
279 sigc::bind(
280 sigc::mem_fun(*this, &MidiRuleCtrlTrigger::note_edited),
281 column));
282 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
283 renderer->property_adjustment() = new Gtk::Adjustment(0, 0, 127);
284 #else
285 renderer->property_adjustment() = Gtk::Adjustment::create(0, 0, 127);
286 #endif
287
288 int cols_count = tree_view.append_column(title, *renderer);
289 Gtk::TreeViewColumn* col = tree_view.get_column(cols_count - 1);
290 col->add_attribute(*renderer, "text", column);
291 col->set_min_width(98);
292 return cols_count;
293 }
294
295 void MidiRuleCtrlTrigger::set_rule(gig::MidiRuleCtrlTrigger* r) {
296 update_model++;
297 update(r);
298 list_store->clear();
299 for (int i = 0 ; i < r->Triggers ; i++) {
300 Gtk::TreeModel::Row row = *list_store->append();
301 row[columns.trigger_point] = r->pTriggers[i].TriggerPoint;
302 row[columns.descending] = r->pTriggers[i].Descending;
303 row[columns.vel_sensitivity] = r->pTriggers[i].VelSensitivity;
304 row[columns.key] = note_str(r->pTriggers[i].Key);
305 row[columns.note_off] = r->pTriggers[i].NoteOff;
306 row[columns.switch_logic] = r->pTriggers[i].Velocity != 255;
307 if (r->pTriggers[i].Velocity != 255) {
308 row[columns.velocity] = r->pTriggers[i].Velocity;
309 }
310 row[columns.override_pedal] = r->pTriggers[i].OverridePedal;
311 }
312 sel_changed();
313 add_button.set_sensitive();
314 if (r->Triggers == 32) add_button.set_sensitive(false);
315 update_model--;
316 }
317
318 void MidiRuleCtrlTrigger::num_editing_started(
319 Gtk::CellEditable* editable,
320 const Glib::ustring& path,
321 Gtk::CellRendererSpin* renderer) {
322 int lower = renderer->property_adjustment().get_value()->get_lower();
323 int upper = renderer->property_adjustment().get_value()->get_upper();
324 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
325 renderer->property_adjustment() = new Gtk::Adjustment(lower, lower, upper);
326 #else
327 renderer->property_adjustment() =
328 Gtk::Adjustment::create(lower, lower, upper);
329 #endif
330 Gtk::SpinButton* spin_button = dynamic_cast<Gtk::SpinButton*>(editable);
331 if (spin_button) {
332 spin_button->set_numeric();
333 }
334 }
335
336 void MidiRuleCtrlTrigger::note_editing_started(
337 Gtk::CellEditable* editable,
338 const Glib::ustring& path,
339 Gtk::CellRendererSpin* renderer) {
340 int value = note_value(renderer->property_text());
341 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
342 renderer->property_adjustment() = new Gtk::Adjustment(0, 0, 127);
343 #else
344 renderer->property_adjustment() = Gtk::Adjustment::create(0, 0, 127);
345 #endif
346 Gtk::SpinButton* spin_button = dynamic_cast<Gtk::SpinButton*>(editable);
347 if (spin_button) {
348 spin_button->get_adjustment()->set_value(value);
349 spin_button_show_notes(*spin_button);
350 }
351 }
352
353 void MidiRuleCtrlTrigger::num_edited(
354 const Glib::ustring& path,
355 const Glib::ustring& new_text,
356 const Gtk::TreeModelColumn<int>& column) {
357 Gtk::TreeModel::Row row = *list_store->get_iter(path);
358
359 Gtk::TreeModel::Path cpath;
360 Gtk::TreeViewColumn* col;
361 tree_view.get_cursor(cpath, col);
362
363 int lower = 0;
364 int upper = 127;
365 const Gtk::CellRenderer* r = col->get_first_cell();
366 if (const Gtk::CellRendererSpin* renderer =
367 dynamic_cast<const Gtk::CellRendererSpin*>(r)) {
368 lower = renderer->property_adjustment().get_value()->get_lower();
369 upper = renderer->property_adjustment().get_value()->get_upper();
370 }
371
372 row[column] = std::max(lower, std::min(atoi(new_text.c_str()), upper));
373 }
374
375 void MidiRuleCtrlTrigger::note_edited(
376 const Glib::ustring& path,
377 const Glib::ustring& new_text,
378 const Gtk::TreeModelColumn<Glib::ustring>& column) {
379 Gtk::TreeModel::Row row = *list_store->get_iter(path);
380
381 row[column] = note_str(note_value(new_text));
382 }
383
384 void MidiRuleCtrlTrigger::sel_changed() {
385 Gtk::TreeModel::iterator it = tree_view.get_selection()->get_selected();
386 remove_button.set_sensitive();
387 if (!it) remove_button.set_sensitive(false);
388 }
389
390 void MidiRuleCtrlTrigger::add_row() {
391 Gtk::TreeModel::Path path;
392 Gtk::TreeViewColumn* col;
393 tree_view.get_cursor(path, col);
394 if (!path.empty()) tree_view.set_cursor(path);
395
396 Gtk::TreeModel::iterator it = list_store->append();
397 Gtk::TreeModel::Row row = *it;
398
399 update_model++;
400 row[columns.trigger_point] = 64;
401 row[columns.descending] = false;
402 row[columns.vel_sensitivity] = 50;
403 row[columns.key] = note_str(60);
404 row[columns.note_off] = false;
405 row[columns.switch_logic] = false;
406 row[columns.override_pedal] = false;
407 update_model--;
408
409 tree_view.get_selection()->select(row);
410 path = list_store->get_path(it);
411 tree_view.scroll_to_row(path);
412 tree_view.set_cursor(path);
413 }
414
415 void MidiRuleCtrlTrigger::remove_row() {
416 Gtk::TreeModel::Path cpath;
417 Gtk::TreeViewColumn* col;
418 tree_view.get_cursor(cpath, col);
419 if (!cpath.empty()) tree_view.set_cursor(cpath);
420
421 Gtk::TreeModel::iterator it = tree_view.get_selection()->get_selected();
422 if (it) {
423 Gtk::TreePath path = list_store->get_path(it);
424 list_store->erase(it);
425
426 it = tree_view.get_selection()->get_selected();
427 if (!it) {
428 int i = path[0];
429 int n = list_store->children().size();
430 if (n) {
431 if (i >= n) i = n - 1;
432 path[0] = i;
433 tree_view.get_selection()->select(path);
434 }
435 }
436 }
437 }
438
439 void MidiRuleCtrlTrigger::row_changed(const Gtk::TreeModel::Path& path,
440 const Gtk::TreeModel::iterator& iter) {
441 if (update_model) return;
442
443 Gtk::TreeModel::Row row = *iter;
444 int i = path[0];
445
446 if (m->pTriggers[i].Velocity == 255 && row[columns.switch_logic]) {
447 update_model++;
448 row[columns.velocity] = 100;
449 update_model--;
450 }
451
452 int key = note_value(row[columns.key]);
453
454 if (m->pTriggers[i].TriggerPoint != row[columns.trigger_point] ||
455 m->pTriggers[i].Descending != row[columns.descending] ||
456 m->pTriggers[i].VelSensitivity != row[columns.vel_sensitivity] ||
457 m->pTriggers[i].Key != key ||
458 m->pTriggers[i].NoteOff != row[columns.note_off] ||
459 (m->pTriggers[i].Velocity != 255) != row[columns.switch_logic] ||
460 m->pTriggers[i].Velocity != row[columns.velocity] ||
461 m->pTriggers[i].OverridePedal != row[columns.override_pedal])
462 {
463 m->pTriggers[i].TriggerPoint = row[columns.trigger_point];
464 m->pTriggers[i].Descending = row[columns.descending];
465 m->pTriggers[i].VelSensitivity = row[columns.vel_sensitivity];
466 m->pTriggers[i].Key = key;
467 m->pTriggers[i].NoteOff = row[columns.note_off];
468 m->pTriggers[i].Velocity =
469 row[columns.switch_logic] ? row[columns.velocity] : 255;
470 m->pTriggers[i].OverridePedal = row[columns.override_pedal];
471 sig_changed();
472 }
473 }
474
475 void MidiRuleCtrlTrigger::row_inserted(const Gtk::TreeModel::Path& path,
476 const Gtk::TreeModel::iterator& iter) {
477 if (update_model) return;
478 int i = m->Triggers++;
479 m->pTriggers[i].TriggerPoint = 64;
480 m->pTriggers[i].Descending = false;
481 m->pTriggers[i].VelSensitivity = 50;
482 m->pTriggers[i].Key = 60;
483 m->pTriggers[i].NoteOff = false;
484 m->pTriggers[i].Velocity = 255;
485 m->pTriggers[i].OverridePedal = false;
486 add_button.set_sensitive();
487 if (m->Triggers == 32) add_button.set_sensitive(false);
488 sig_changed();
489 }
490
491 void MidiRuleCtrlTrigger::row_deleted(const Gtk::TreeModel::Path& path) {
492 if (update_model) return;
493 for (int i = path[0] + 1 ; i < m->Triggers ; i++) {
494 m->pTriggers[i - 1] = m->pTriggers[i];
495 }
496 m->Triggers--;
497 add_button.set_sensitive();
498 sig_changed();
499 }
500
501
502
503 MidiRuleLegato::MidiRuleLegato() :
504 Table(2, 1),
505 eBypassUseController(_("Bypass use controller")),
506 eBypassKey(_("Bypass key")),
507 eBypassController(_("Bypass controller")),
508 eThresholdTime(_("Threshold time"), 10, 500),
509 eReleaseTime(_("Release time"), 10, 500),
510 eKeyRangeLow(_("Key range low")),
511 eKeyRangeHigh(_("Key range high")),
512 eReleaseTriggerKey(_("Release trigger key")),
513 eAltSustain1Key(_("Alt sustain 1 key")),
514 eAltSustain2Key(_("Alt sustain 2 key"))
515 {
516 connect(eBypassUseController, &gig::MidiRuleLegato::BypassUseController);
517 connect(eBypassKey, &gig::MidiRuleLegato::BypassKey);
518 connect(eBypassController, &gig::MidiRuleLegato::BypassController);
519 connect(eThresholdTime, &gig::MidiRuleLegato::ThresholdTime);
520 connect(eReleaseTime, &gig::MidiRuleLegato::ReleaseTime);
521 connect(eKeyRangeLow, eKeyRangeHigh, &gig::MidiRuleLegato::KeyRange);
522 connect(eReleaseTriggerKey, &gig::MidiRuleLegato::ReleaseTriggerKey);
523 connect(eAltSustain1Key, &gig::MidiRuleLegato::AltSustain1Key);
524 connect(eAltSustain2Key, &gig::MidiRuleLegato::AltSustain2Key);
525
526 set_col_spacings(5);
527
528 add(eBypassUseController);
529 add(eBypassKey);
530 add(eBypassController);
531 add(eThresholdTime);
532 add(eReleaseTime);
533 add(eKeyRangeLow);
534 add(eKeyRangeHigh);
535 add(eReleaseTriggerKey);
536 add(eAltSustain1Key);
537 add(eAltSustain2Key);
538
539 eBypassUseController.signal_value_changed().connect(
540 sigc::mem_fun(*this, &MidiRuleLegato::BypassUseController_toggled));
541 }
542
543 void MidiRuleLegato::BypassUseController_toggled() {
544 bool useController = eBypassUseController.get_value();
545 eBypassKey.set_sensitive(!useController);
546 eBypassController.set_sensitive(useController);
547 }
548
549 void MidiRuleLegato::set_rule(gig::MidiRuleLegato* r) {
550 update_model++;
551 update(r);
552 BypassUseController_toggled();
553 update_model--;
554 }

Properties

Name Value
svn:eol-style native

  ViewVC Help
Powered by ViewVC