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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1733 - (show 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 /* -*- c++ -*-
2 * Copyright (C) 2006-2008 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 "dimensionmanager.h"
21
22 #include <gtkmm/stock.h>
23 #include <gtkmm/messagedialog.h>
24 #include <gtkmm/dialog.h>
25 #include <gtkmm/comboboxtext.h>
26 #include <gtkmm/spinbutton.h>
27 #include <gtkmm/table.h>
28
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 vbox.pack_start(buttonBox, Gtk::PACK_SHRINK);
192 buttonBox.set_layout(Gtk::BUTTONBOX_END);
193 buttonBox.set_border_width(5);
194 buttonBox.show();
195 buttonBox.pack_start(addButton, Gtk::PACK_SHRINK);
196 buttonBox.pack_start(removeButton, Gtk::PACK_SHRINK);
197 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 treeView.append_column("Bits", tableModel.m_bits);
205 treeView.append_column("Zones", tableModel.m_zones);
206 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 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 row[tableModel.m_zones] = dim->zones;
230 row[tableModel.m_description] = __dimDescriptionAsString(dim->dimension);
231 row[tableModel.m_definition] = dim;
232 }
233 }
234 set_sensitive(region);
235 }
236
237 void DimensionManager::show(gig::Region* region) {
238 this->region = region;
239 refreshManager();
240 Gtk::Window::show();
241 deiconify();
242 }
243
244 void DimensionManager::set_region(gig::Region* region) {
245 this->region = region;
246 refreshManager();
247 }
248
249 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 Gtk::Table table(2, 2);
264 Gtk::Label labelDimType("Dimension:", Gtk::ALIGN_LEFT);
265 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 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 Gtk::ComboBoxText comboZones;
278 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 }
284 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 dialog.add_button(Gtk::Stock::OK, 0);
300 dialog.add_button(Gtk::Stock::CANCEL, 1);
301 dialog.show_all_children();
302
303 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
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 printf(
325 "Adding dimension (type=0x%x, bits=%d, zones=%d)\n",
326 dim.dimension, dim.bits, dim.zones
327 );
328 // notify everybody that we're going to update the region
329 region_to_be_changed_signal.emit(region);
330 // 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 region_changed_signal.emit(region);
335 // update all GUI elements
336 refreshManager();
337 }
338 } catch (RIFF::Exception e) {
339 // notify that the changes are over (i.e. to avoid dead locks)
340 region_changed_signal.emit(region);
341 // show error message
342 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 // notify everybody that we're going to update the region
354 region_to_be_changed_signal.emit(region);
355 // 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 region_changed_signal.emit(region);
361 // update all GUI elements
362 refreshManager();
363 } catch (RIFF::Exception e) {
364 // notify that the changes are over (i.e. to avoid dead locks)
365 region_changed_signal.emit(region);
366 // show error message
367 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