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

Annotation of /gigedit/trunk/src/gigedit/dimensionmanager.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1733 - (hide annotations) (download)
Sat May 3 09:54:36 2008 UTC (15 years, 11 months ago) by persson
File size: 14866 byte(s)
* allow to create amounts of dimension zones that aren't powers of two
  (patch by Devin Anderson, #89, slightly modified)

1 schoenebeck 1225 /* -*- c++ -*-
2 persson 1623 * Copyright (C) 2006-2008 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     #include "dimensionmanager.h"
21    
22     #include <gtkmm/stock.h>
23     #include <gtkmm/messagedialog.h>
24     #include <gtkmm/dialog.h>
25     #include <gtkmm/comboboxtext.h>
26 persson 1733 #include <gtkmm/spinbutton.h>
27     #include <gtkmm/table.h>
28 schoenebeck 1225
29     // returns a human readable name of the given dimension type
30     static Glib::ustring __dimTypeAsString(gig::dimension_t d) {
31     char buf[32];
32     switch (d) {
33     case gig::dimension_none:
34     return "None";
35     case gig::dimension_samplechannel:
36     return "Sample Channel";
37     case gig::dimension_layer:
38     return "Layer";
39     case gig::dimension_velocity:
40     return "Velocity";
41     case gig::dimension_channelaftertouch:
42     return "Aftertouch";
43     case gig::dimension_releasetrigger:
44     return "Release Trigger";
45     case gig::dimension_keyboard:
46     return "Keyswitching";
47     case gig::dimension_roundrobin:
48     return "Round Robin";
49     case gig::dimension_random:
50     return "Random Generator";
51     case gig::dimension_smartmidi:
52     return "Smart MIDI";
53     case gig::dimension_roundrobinkeyboard:
54     return "Keyboard Round Robin";
55     case gig::dimension_modwheel:
56     return "Modulation Wheel";
57     case gig::dimension_breath:
58     return "Breath Ctrl.";
59     case gig::dimension_foot:
60     return "Foot Ctrl.";
61     case gig::dimension_portamentotime:
62     return "Portamento Time Ctrl.";
63     case gig::dimension_effect1:
64     return "Effect Ctrl. 1";
65     case gig::dimension_effect2:
66     return "Effect Ctrl. 2";
67     case gig::dimension_genpurpose1:
68     return "General Purpose Ctrl. 1";
69     case gig::dimension_genpurpose2:
70     return "General Purpose Ctrl. 2";
71     case gig::dimension_genpurpose3:
72     return "General Purpose Ctrl. 3";
73     case gig::dimension_genpurpose4:
74     return "General Purpose Ctrl. 4";
75     case gig::dimension_sustainpedal:
76     return "Sustain Pedal";
77     case gig::dimension_portamento:
78     return "Portamento Ctrl.";
79     case gig::dimension_sostenutopedal:
80     return "Sostenuto Pedal";
81     case gig::dimension_softpedal:
82     return "Soft Pedal";
83     case gig::dimension_genpurpose5:
84     return "General Purpose Ctrl. 5";
85     case gig::dimension_genpurpose6:
86     return "General Purpose Ctrl. 6";
87     case gig::dimension_genpurpose7:
88     return "General Purpose Ctrl. 7";
89     case gig::dimension_genpurpose8:
90     return "General Purpose Ctrl. 8";
91     case gig::dimension_effect1depth:
92     return "Effect 1 Depth";
93     case gig::dimension_effect2depth:
94     return "Effect 2 Depth";
95     case gig::dimension_effect3depth:
96     return "Effect 3 Depth";
97     case gig::dimension_effect4depth:
98     return "Effect 4 Depth";
99     case gig::dimension_effect5depth:
100     return "Effect 5 Depth";
101     default:
102     sprintf(buf, "Unknown Type (0x%x) !!!", d);
103     return buf;
104     }
105     }
106    
107     // returns a human readable description of the given dimension
108     static Glib::ustring __dimDescriptionAsString(gig::dimension_t d) {
109     switch (d) {
110     case gig::dimension_none:
111     return "Dimension not in use";
112     case gig::dimension_samplechannel:
113     return "If used sample has more than one channel (thus is not mono)";
114     case gig::dimension_layer:
115     return "For layering of up to 8 instruments (and eventually crossfading of 2 or 4 layers";
116     case gig::dimension_velocity:
117     return "Key Velocity (this is the only dimension in gig2 where the ranges can exactly be defined)";
118     case gig::dimension_channelaftertouch:
119     return "Channel Key Pressure";
120     case gig::dimension_releasetrigger:
121     return "Special dimension for triggering samples on releasing a key";
122     case gig::dimension_keyboard:
123     return "Dimension for keyswitching (keyboard)";
124     case gig::dimension_roundrobin:
125     return "Different samples triggered each time a note is played, dimension regions selected in sequence";
126     case gig::dimension_random:
127     return "Different samples triggered each time a note is played, random order";
128     case gig::dimension_smartmidi:
129     return "For MIDI tools like legato and repetition mode";
130     case gig::dimension_roundrobinkeyboard:
131     return "Different samples triggered each time a note is played, any key advances the counter";
132     case gig::dimension_modwheel:
133     return "MIDI Controller 1";
134     case gig::dimension_breath:
135     return "MIDI Controller 2";
136     case gig::dimension_foot:
137     return "MIDI Controller 4";
138     case gig::dimension_portamentotime:
139     return "MIDI Controller 5";
140     case gig::dimension_effect1:
141     return "MIDI Controller 12";
142     case gig::dimension_effect2:
143     return "MIDI Controller 13";
144     case gig::dimension_genpurpose1:
145     return "Slider, MIDI Controller 16";
146     case gig::dimension_genpurpose2:
147     return "Slider, MIDI Controller 17";
148     case gig::dimension_genpurpose3:
149     return "Slider, MIDI Controller 18";
150     case gig::dimension_genpurpose4:
151     return "Slider, MIDI Controller 19";
152     case gig::dimension_sustainpedal:
153     return "MIDI Controller 64";
154     case gig::dimension_portamento:
155     return "MIDI Controller 65";
156     case gig::dimension_sostenutopedal:
157     return "MIDI Controller 66";
158     case gig::dimension_softpedal:
159     return "MIDI Controller 67";
160     case gig::dimension_genpurpose5:
161     return "Button, MIDI Controller 80";
162     case gig::dimension_genpurpose6:
163     return "Button, MIDI Controller 81";
164     case gig::dimension_genpurpose7:
165     return "Button, MIDI Controller 82";
166     case gig::dimension_genpurpose8:
167     return "Button, MIDI Controller 83";
168     case gig::dimension_effect1depth:
169     return "MIDI Controller 91";
170     case gig::dimension_effect2depth:
171     return "MIDI Controller 92";
172     case gig::dimension_effect3depth:
173     return "MIDI Controller 93";
174     case gig::dimension_effect4depth:
175     return "MIDI Controller 94";
176     case gig::dimension_effect5depth:
177     return "MIDI Controller 95";
178     default:
179     return "Please report this !!!";
180     }
181     }
182    
183     DimensionManager::DimensionManager() :
184     addButton(Gtk::Stock::ADD), removeButton(Gtk::Stock::REMOVE)
185     {
186     set_title("Dimensions of selected Region");
187     add(vbox);
188     scrolledWindow.add(treeView);
189     vbox.pack_start(scrolledWindow);
190     scrolledWindow.show();
191 schoenebeck 1411 vbox.pack_start(buttonBox, Gtk::PACK_SHRINK);
192 schoenebeck 1225 buttonBox.set_layout(Gtk::BUTTONBOX_END);
193     buttonBox.set_border_width(5);
194     buttonBox.show();
195 schoenebeck 1411 buttonBox.pack_start(addButton, Gtk::PACK_SHRINK);
196     buttonBox.pack_start(removeButton, Gtk::PACK_SHRINK);
197 schoenebeck 1225 addButton.show();
198     removeButton.show();
199    
200     // setup the table
201     refTableModel = Gtk::ListStore::create(tableModel);
202     treeView.set_model(refTableModel);
203     treeView.append_column("Dimension Type", tableModel.m_dim_type);
204 persson 1303 treeView.append_column("Bits", tableModel.m_bits);
205     treeView.append_column("Zones", tableModel.m_zones);
206 schoenebeck 1225 treeView.append_column("Description", tableModel.m_description);
207     treeView.show();
208    
209     addButton.signal_clicked().connect(
210     sigc::mem_fun(*this, &DimensionManager::addDimension)
211     );
212    
213     removeButton.signal_clicked().connect(
214     sigc::mem_fun(*this, &DimensionManager::removeDimension)
215     );
216    
217     show_all_children();
218     }
219    
220     // update all GUI elements according to current gig::Region informations
221     void DimensionManager::refreshManager() {
222     refTableModel->clear();
223 persson 1677 if (region) {
224     for (int i = 0; i < region->Dimensions; i++) {
225     gig::dimension_def_t* dim = &region->pDimensionDefinitions[i];
226     Gtk::TreeModel::Row row = *(refTableModel->append());
227     row[tableModel.m_dim_type] = __dimTypeAsString(dim->dimension);
228     row[tableModel.m_bits] = dim->bits;
229 persson 1733 row[tableModel.m_zones] = dim->zones;
230 persson 1677 row[tableModel.m_description] = __dimDescriptionAsString(dim->dimension);
231     row[tableModel.m_definition] = dim;
232     }
233 schoenebeck 1225 }
234 persson 1677 set_sensitive(region);
235 schoenebeck 1225 }
236    
237     void DimensionManager::show(gig::Region* region) {
238     this->region = region;
239     refreshManager();
240     Gtk::Window::show();
241     deiconify();
242     }
243    
244 persson 1677 void DimensionManager::set_region(gig::Region* region) {
245     this->region = region;
246     refreshManager();
247     }
248    
249 schoenebeck 1225 void DimensionManager::addDimension() {
250     try {
251     Gtk::Dialog dialog("New Dimension", true /*modal*/);
252     // add dimension type combo box to the dialog
253     Glib::RefPtr<Gtk::ListStore> refComboModel = Gtk::ListStore::create(comboModel);
254     for (int i = 0x01; i < 0xff; i++) {
255     Glib::ustring sType =
256     __dimTypeAsString(static_cast<gig::dimension_t>(i));
257     if (sType.find("Unknown") != 0) {
258     Gtk::TreeModel::Row row = *(refComboModel->append());
259     row[comboModel.m_type_id] = i;
260     row[comboModel.m_type_name] = sType;
261     }
262     }
263 persson 1733 Gtk::Table table(2, 2);
264     Gtk::Label labelDimType("Dimension:", Gtk::ALIGN_LEFT);
265 schoenebeck 1225 Gtk::ComboBox comboDimType;
266     comboDimType.set_model(refComboModel);
267     comboDimType.pack_start(comboModel.m_type_id);
268     comboDimType.pack_start(comboModel.m_type_name);
269 persson 1733 Gtk::Label labelZones("Zones:", Gtk::ALIGN_LEFT);
270     table.attach(labelDimType, 0, 1, 0, 1);
271     table.attach(comboDimType, 1, 2, 0, 1);
272     table.attach(labelZones, 0, 1, 1, 2);
273     dialog.get_vbox()->pack_start(table);
274    
275     // number of zones: use a combo box with fix values for gig
276     // v2 and a spin button for v3
277 schoenebeck 1225 Gtk::ComboBoxText comboZones;
278 persson 1733 Gtk::SpinButton spinZones;
279     bool version2 = false;
280     if (region) {
281     gig::File* file = (gig::File*)region->GetParent()->GetParent();
282     version2 = file->pVersion && file->pVersion->major == 2;
283 schoenebeck 1225 }
284 persson 1733 if (version2) {
285     for (int i = 1; i <= 5; i++) {
286     char buf[3];
287     sprintf(buf, "%d", 1 << i);
288     comboZones.append_text(buf);
289     }
290     table.attach(comboZones, 1, 2, 1, 2);
291     } else {
292     spinZones.set_increments(1, 8);
293     spinZones.set_numeric(true);
294     spinZones.set_range(2, 128);
295     spinZones.set_value(2);
296     table.attach(spinZones, 1, 2, 1, 2);
297     }
298    
299 schoenebeck 1225 dialog.add_button(Gtk::Stock::OK, 0);
300     dialog.add_button(Gtk::Stock::CANCEL, 1);
301     dialog.show_all_children();
302 persson 1733
303 schoenebeck 1225 if (!dialog.run()) { // OK selected ...
304     Gtk::TreeModel::iterator iterType = comboDimType.get_active();
305     if (!iterType) return;
306     Gtk::TreeModel::Row rowType = *iterType;
307     if (!rowType) return;
308     gig::dimension_def_t dim;
309     int iTypeID = rowType[comboModel.m_type_id];
310     dim.dimension = static_cast<gig::dimension_t>(iTypeID);
311 persson 1733
312     if (version2) {
313     if (comboZones.get_active_row_number() < 0) return;
314     dim.bits = comboZones.get_active_row_number() + 1;
315     dim.zones = 1 << dim.bits;
316     } else {
317     dim.zones = spinZones.get_value_as_int();
318     // Find the number of bits required to hold the
319     // specified amount of zones.
320     int zoneBits = dim.zones - 1;
321     for (dim.bits = 0; zoneBits > 1; dim.bits += 2, zoneBits >>= 2);
322     dim.bits += zoneBits;
323     }
324 schoenebeck 1225 printf(
325     "Adding dimension (type=0x%x, bits=%d, zones=%d)\n",
326     dim.dimension, dim.bits, dim.zones
327     );
328 schoenebeck 1322 // notify everybody that we're going to update the region
329     region_to_be_changed_signal.emit(region);
330 schoenebeck 1225 // add the new dimension to the region
331     // (implicitly creates new dimension regions)
332     region->AddDimension(&dim);
333     // let everybody know there was a change
334 schoenebeck 1322 region_changed_signal.emit(region);
335 schoenebeck 1225 // update all GUI elements
336     refreshManager();
337     }
338     } catch (RIFF::Exception e) {
339 schoenebeck 1322 // notify that the changes are over (i.e. to avoid dead locks)
340     region_changed_signal.emit(region);
341     // show error message
342 schoenebeck 1225 Glib::ustring txt = "Could not add dimension: " + e.Message;
343     Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
344     msg.run();
345     }
346     }
347    
348     void DimensionManager::removeDimension() {
349     Glib::RefPtr<Gtk::TreeSelection> sel = treeView.get_selection();
350     Gtk::TreeModel::iterator it = sel->get_selected();
351     if (it) {
352     try {
353 schoenebeck 1322 // notify everybody that we're going to update the region
354     region_to_be_changed_signal.emit(region);
355 schoenebeck 1225 // remove selected dimension
356     Gtk::TreeModel::Row row = *it;
357     gig::dimension_def_t* dim = row[tableModel.m_definition];
358     region->DeleteDimension(dim);
359     // let everybody know there was a change
360 schoenebeck 1322 region_changed_signal.emit(region);
361 persson 1623 // update all GUI elements
362     refreshManager();
363 schoenebeck 1225 } catch (RIFF::Exception e) {
364 schoenebeck 1322 // notify that the changes are over (i.e. to avoid dead locks)
365     region_changed_signal.emit(region);
366     // show error message
367 schoenebeck 1225 Glib::ustring txt = "Could not remove dimension: " + e.Message;
368     Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
369     msg.run();
370     }
371     }
372     }

  ViewVC Help
Powered by ViewVC