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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1091 - (show annotations) (download)
Sat Mar 10 21:01:36 2007 UTC (17 years ago) by schoenebeck
File size: 70242 byte(s)
* sample import works now (also tested with gigextract afterwards),
  there's however one bug left: adding samples, removing them again
  and then issueing 'Save' will cause a crash

1 /*
2 * Copyright (C) 2006, 2007 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 <libintl.h>
21 #include <iostream>
22
23 #include "mainwindow.h"
24
25 #include <gtkmm/filechooserdialog.h>
26 #include <gtkmm/stock.h>
27 #if GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION >= 6
28 #define ABOUT_DIALOG
29 #include <gtkmm/aboutdialog.h>
30 #include <gtkmm/messagedialog.h>
31 #endif
32
33 #include <stdio.h>
34 #include <sndfile.h>
35
36 #define _(String) gettext(String)
37
38 template<class T> inline std::string ToString(T o) {
39 std::stringstream ss;
40 ss << o;
41 return ss.str();
42 }
43
44 bool update_gui;
45
46 uint8_t& access_UnityNote(gig::DimensionRegion* dimreg)
47 {
48 return dimreg->UnityNote;
49 }
50 int16_t& access_FineTune(gig::DimensionRegion* dimreg)
51 {
52 return dimreg->FineTune;
53 }
54 uint32_t& access_SampleLoops(gig::DimensionRegion* dimreg)
55 {
56 return dimreg->SampleLoops;
57 }
58 uint8_t& access_Crossfade_in_start(gig::DimensionRegion* dimreg)
59 {
60 return dimreg->Crossfade.in_start;
61 }
62 uint8_t& access_Crossfade_in_end(gig::DimensionRegion* dimreg)
63 {
64 return dimreg->Crossfade.in_end;
65 }
66 uint8_t& access_Crossfade_out_start(gig::DimensionRegion* dimreg)
67 {
68 return dimreg->Crossfade.out_start;
69 }
70 uint8_t& access_Crossfade_out_end(gig::DimensionRegion* dimreg)
71 {
72 return dimreg->Crossfade.out_end;
73 }
74
75 namespace {
76 const char* const controlChangeTexts[] = {
77 "none", "channelaftertouch", "velocity",
78 0,
79 "modwheel", // "Modulation Wheel or Lever",
80 "breath", // "Breath Controller",
81 0,
82 "foot", // "Foot Controller",
83 "portamentotime", // "Portamento Time",
84 0, 0, 0, 0, 0, 0,
85 "effect1", // "Effect Control 1",
86 "effect2", // "Effect Control 2",
87 0, 0,
88 "genpurpose1", // "General Purpose Controller 1",
89 "genpurpose2", // "General Purpose Controller 2",
90 "genpurpose3", // "General Purpose Controller 3",
91 "genpurpose4", // "General Purpose Controller 4",
92 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
93 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
94 0, 0, 0, 0, 0, 0,
95 "sustainpedal", // "Damper Pedal on/off (Sustain)",
96 "portamento", // "Portamento On/Off",
97 "sostenuto", // "Sustenuto On/Off",
98 "softpedal", // "Soft Pedal On/Off",
99 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
100 "genpurpose5", // "General Purpose Controller 5",
101 "genpurpose6", // "General Purpose Controller 6",
102 "genpurpose7", // "General Purpose Controller 7",
103 "genpurpose8", // "General Purpose Controller 8",
104 0, 0, 0, 0, 0, 0, 0,
105 "effect1depth", // "Effects 1 Depth",
106 "effect2depth", // "Effects 2 Depth",
107 "effect3depth", // "Effects 3 Depth",
108 "effect4depth", // "Effects 4 Depth",
109 "effect5depth", // "Effects 5 Depth"
110 };
111 }
112
113 void MainWindow::addString(char* labelText, Gtk::Label*& label,
114 Gtk::Entry*& widget)
115 {
116 label = new Gtk::Label(Glib::ustring(labelText) + ":");
117 label->set_alignment(Gtk::ALIGN_LEFT);
118
119 table[pageno]->attach(*label, 1, 2, rowno, rowno + 1,
120 Gtk::FILL, Gtk::SHRINK);
121
122 widget = new Gtk::Entry();
123
124 table[pageno]->attach(*widget, 2, 3, rowno, rowno + 1,
125 Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK);
126
127 rowno++;
128 }
129
130 LabelWidget::LabelWidget(char* labelText, Gtk::Widget& widget) :
131 label(Glib::ustring(labelText) + ":"),
132 widget(widget)
133 {
134 label.set_alignment(Gtk::ALIGN_LEFT);
135 }
136
137 void LabelWidget::set_sensitive(bool sensitive)
138 {
139 label.set_sensitive(sensitive);
140 widget.set_sensitive(sensitive);
141 }
142
143 NumEntryGain::NumEntryGain(char* labelText,
144 double lower = 0, double upper = 127,
145 int decimals = 0) :
146 NumEntry<gig::DimensionRegion>(labelText, lower, upper, decimals)
147 {
148 spinbutton.signal_value_changed().connect(
149 sigc::mem_fun(*this, &NumEntryGain::value_changed));
150 }
151
152 void NumEntryGain::value_changed()
153 {
154 if (dimreg && update_gui) {
155 dimreg->Gain = int32_t(spinbutton.get_value() * -655360.0);
156 }
157 }
158
159 void NumEntryGain::set_dimreg(gig::DimensionRegion* dimreg)
160 {
161 this->dimreg = 0;
162 set_value(dimreg->Gain / -655360.0);
163 this->dimreg = dimreg;
164 }
165
166
167 NumEntryPermille::NumEntryPermille(char* labelText,
168 uint16_t gig::DimensionRegion::* param,
169 double lower, double upper, int decimals) :
170 NumEntry<gig::DimensionRegion>(labelText, lower, upper, decimals),
171 param(param)
172 {
173 spinbutton.signal_value_changed().connect(
174 sigc::mem_fun(*this, &NumEntryPermille::value_changed));
175 }
176
177 void NumEntryPermille::value_changed()
178 {
179 if (dimreg && update_gui) {
180 dimreg->*param = uint16_t(spinbutton.get_value() * 10 + 0.5);
181 }
182 }
183
184 void NumEntryPermille::set_dimreg(gig::DimensionRegion* dimreg)
185 {
186 this->dimreg = 0;
187 set_value(dimreg->*param / 10.0);
188 this->dimreg = dimreg;
189 }
190
191
192 NoteEntry::NoteEntry(char* labelText, uint8_t& (*access)(gig::DimensionRegion*)) :
193 NumEntryX<uint8_t>(labelText, access)
194 {
195 spinbutton.signal_input().connect(
196 sigc::mem_fun(*this, &NoteEntry::on_input));
197 spinbutton.signal_output().connect(
198 sigc::mem_fun(*this, &NoteEntry::on_output));
199 }
200
201 const char* notes[] = {
202 "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"
203 };
204
205
206 // Convert the Entry text to a number
207 int NoteEntry::on_input(double* new_value)
208 {
209 const char* str = spinbutton.get_text().c_str();
210
211 int i;
212 for (i = 11 ; i >= 0 ; i--) {
213 if (strncmp(str, notes[i], strlen(notes[i])) == 0) break;
214 }
215 if (i >= 0) {
216 char* endptr;
217 long x = strtol(str + strlen(notes[i]), &endptr, 10);
218 if (endptr != str + strlen(notes[i])) {
219 *new_value = i + (x + 1) * 12;
220 return true;
221 }
222 }
223 return Gtk::INPUT_ERROR;
224 }
225
226 // Convert the Adjustment position to text
227 bool NoteEntry::on_output()
228 {
229 int x = int(spinbutton.get_adjustment()->get_value());
230 char buf[10];
231 sprintf(buf, "%s%d", notes[x % 12], x / 12 - 1);
232 spinbutton.set_text(buf);
233 return true;
234 }
235
236 BoolEntry::BoolEntry(char* labelText, bool gig::DimensionRegion::* param) :
237 LabelWidget(labelText, checkbutton),
238 param(param)
239 {
240 checkbutton.signal_toggled().connect(
241 sigc::mem_fun(*this, &BoolEntry::value_changed));
242 }
243
244 void BoolEntry::value_changed()
245 {
246 if (dimreg && update_gui) {
247 dimreg->*param = checkbutton.get_active();
248 }
249 }
250
251 void BoolEntry::set_dimreg(gig::DimensionRegion* dimreg)
252 {
253 this->dimreg = 0;
254 checkbutton.set_active(dimreg->*param);
255 this->dimreg = dimreg;
256 }
257
258 ChoiceEntryLeverageCtrl::ChoiceEntryLeverageCtrl(
259 char* labelText,
260 gig::leverage_ctrl_t gig::DimensionRegion::* param) :
261 align(0, 0, 0, 0),
262 LabelWidget(labelText, align),
263 param(param)
264 {
265 for (int i = 0 ; i < 99 ; i++) {
266 if (controlChangeTexts[i]) {
267 combobox.append_text(controlChangeTexts[i]);
268 }
269 }
270 combobox.signal_changed().connect(
271 sigc::mem_fun(*this, &ChoiceEntryLeverageCtrl::value_changed));
272 align.add(combobox);
273 }
274
275 void ChoiceEntryLeverageCtrl::value_changed()
276 {
277 if (dimreg && update_gui) {
278 int rowno = combobox.get_active_row_number();
279 switch (rowno)
280 {
281 case -1:
282 break;
283 case 0:
284 (dimreg->*param).type = gig::leverage_ctrl_t::type_none;
285 break;
286 case 1:
287 (dimreg->*param).type =
288 gig::leverage_ctrl_t::type_channelaftertouch;
289 break;
290 case 2:
291 (dimreg->*param).type = gig::leverage_ctrl_t::type_velocity;
292 break;
293 default:
294 (dimreg->*param).type = gig::leverage_ctrl_t::type_controlchange;
295 int x = 3;
296 for (int cc = 0 ; cc < 96 ; cc++) {
297 if (controlChangeTexts[cc + 3]) {
298 if (rowno == x) {
299 (dimreg->*param).controller_number = cc;
300 break;
301 }
302 x++;
303 }
304 }
305 break;
306 }
307 }
308 }
309
310 void ChoiceEntryLeverageCtrl::set_dimreg(gig::DimensionRegion* dimreg)
311 {
312 this->dimreg = 0;
313 gig::leverage_ctrl_t c = dimreg->*param;
314 int x;
315 switch (c.type)
316 {
317 case gig::leverage_ctrl_t::type_none:
318 x = 0;
319 break;
320 case gig::leverage_ctrl_t::type_channelaftertouch:
321 x = 1;
322 break;
323 case gig::leverage_ctrl_t::type_velocity:
324 x = 2;
325 break;
326 case gig::leverage_ctrl_t::type_controlchange:
327 x = -1;
328 for (int cc = 0 ; cc < 96 ; cc++) {
329 if (controlChangeTexts[cc + 3]) {
330 x++;
331 if (c.controller_number == cc) {
332 x += 3;
333 break;
334 }
335 }
336 }
337 break;
338 default:
339 x = -1;
340 break;
341 }
342 combobox.set_active(x);
343 this->dimreg = dimreg;
344 }
345
346 void MainWindow::addHeader(char* text)
347 {
348 if (firstRowInBlock < rowno - 1)
349 {
350 Gtk::Label* filler = new Gtk::Label(" ");
351 table[pageno]->attach(*filler, 0, 1, firstRowInBlock, rowno,
352 Gtk::FILL, Gtk::SHRINK);
353 }
354 Glib::ustring str = "<b>";
355 str += text;
356 str += "</b>";
357 Gtk::Label* label = new Gtk::Label(str);
358 label->set_use_markup();
359 label->set_alignment(Gtk::ALIGN_LEFT);
360 table[pageno]->attach(*label, 0, 3, rowno, rowno + 1,
361 Gtk::FILL, Gtk::SHRINK);
362 rowno++;
363 firstRowInBlock = rowno;
364 }
365
366 void MainWindow::nextPage()
367 {
368 if (firstRowInBlock < rowno - 1)
369 {
370 Gtk::Label* filler = new Gtk::Label(" ");
371 table[pageno]->attach(*filler, 0, 1, firstRowInBlock, rowno,
372 Gtk::FILL, Gtk::SHRINK);
373 }
374 pageno++;
375 rowno = 0;
376 firstRowInBlock = 0;
377 }
378
379 void MainWindow::addProp(LabelWidget& prop)
380 {
381 table[pageno]->attach(prop.label, 1, 2, rowno, rowno + 1,
382 Gtk::FILL, Gtk::SHRINK);
383 table[pageno]->attach(prop.widget, 2, 3, rowno, rowno + 1,
384 Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK);
385 rowno++;
386 }
387
388
389
390
391 MainWindow::MainWindow() :
392 // eSample("Sample", wSample),
393 eVelocityUpperLimit("VelocityUpperLimit",
394 &gig::DimensionRegion::VelocityUpperLimit),
395 eEG1PreAttack("PreAttack", &gig::DimensionRegion::EG1PreAttack, 0, 100, 2),
396 eEG1Attack("Attack", &gig::DimensionRegion::EG1Attack, 0, 60, 3),
397 eEG1Decay1("Decay1", &gig::DimensionRegion::EG1Decay1, 0.005, 60, 3),
398 eEG1Decay2("Decay2", &gig::DimensionRegion::EG1Decay2, 0, 60, 3),
399 eEG1InfiniteSustain("InfiniteSustain",
400 &gig::DimensionRegion::EG1InfiniteSustain),
401 eEG1Sustain("Sustain", &gig::DimensionRegion::EG1Sustain, 0, 100, 2),
402 eEG1Release("Release", &gig::DimensionRegion::EG1Release, 0, 60, 3),
403 eEG1Hold("Hold", &gig::DimensionRegion::EG1Hold),
404 eEG1Controller("Controller", &gig::DimensionRegion::EG1Controller),
405 eEG1ControllerInvert("ControllerInvert",
406 &gig::DimensionRegion::EG1ControllerInvert),
407 eEG1ControllerAttackInfluence("ControllerAttackInfluence",
408 &gig::DimensionRegion::EG1ControllerAttackInfluence,
409 0, 3),
410 eEG1ControllerDecayInfluence("ControllerDecayInfluence",
411 &gig::DimensionRegion::EG1ControllerDecayInfluence,
412 0, 3),
413 eEG1ControllerReleaseInfluence("ControllerReleaseInfluence",
414 &gig::DimensionRegion::EG1ControllerReleaseInfluence,
415 0, 3),
416 eLFO1Frequency("Frequency", &gig::DimensionRegion::LFO1Frequency,
417 0.1, 10, 2),
418 eLFO1InternalDepth("InternalDepth",
419 &gig::DimensionRegion::LFO1InternalDepth, 0, 1200),
420 eLFO1ControlDepth("ControlDepth", &gig::DimensionRegion::LFO1ControlDepth,
421 0, 1200),
422 eLFO1Controller("Controller", &gig::DimensionRegion::LFO1Controller),
423 eLFO1FlipPhase("FlipPhase", &gig::DimensionRegion::LFO1FlipPhase),
424 eLFO1Sync("Sync", &gig::DimensionRegion::LFO1Sync),
425 eEG2PreAttack("PreAttack", &gig::DimensionRegion::EG2PreAttack, 0, 100, 2),
426 eEG2Attack("Attack", &gig::DimensionRegion::EG2Attack, 0, 60, 3),
427 eEG2Decay1("Decay1", &gig::DimensionRegion::EG2Decay1, 0.005, 60, 3),
428 eEG2Decay2("Decay2", &gig::DimensionRegion::EG2Decay2, 0, 60, 3),
429 eEG2InfiniteSustain("InfiniteSustain",
430 &gig::DimensionRegion::EG2InfiniteSustain),
431 eEG2Sustain("Sustain", &gig::DimensionRegion::EG2Sustain, 0, 100, 2),
432 eEG2Release("Release", &gig::DimensionRegion::EG2Release, 0, 60, 3),
433 eEG2Controller("Controller", &gig::DimensionRegion::EG2Controller),
434 eEG2ControllerInvert("ControllerInvert",
435 &gig::DimensionRegion::EG2ControllerInvert),
436 eEG2ControllerAttackInfluence("ControllerAttackInfluence",
437 &gig::DimensionRegion::EG2ControllerAttackInfluence,
438 0, 3),
439 eEG2ControllerDecayInfluence("ControllerDecayInfluence",
440 &gig::DimensionRegion::EG2ControllerDecayInfluence,
441 0, 3),
442 eEG2ControllerReleaseInfluence("ControllerReleaseInfluence",
443 &gig::DimensionRegion::EG2ControllerReleaseInfluence,
444 0, 3),
445 eLFO2Frequency("Frequency", &gig::DimensionRegion::LFO2Frequency,
446 0.1, 10, 2),
447 eLFO2InternalDepth("InternalDepth",
448 &gig::DimensionRegion::LFO2InternalDepth, 0, 1200),
449 eLFO2ControlDepth("ControlDepth",
450 &gig::DimensionRegion::LFO2ControlDepth, 0, 1200),
451 eLFO2Controller("Controller", &gig::DimensionRegion::LFO2Controller),
452 eLFO2FlipPhase("FlipPhase", &gig::DimensionRegion::LFO2FlipPhase),
453 eLFO2Sync("Sync", &gig::DimensionRegion::LFO2Sync),
454 eEG3Attack("Attack", &gig::DimensionRegion::EG3Attack, 0, 10, 3),
455 eEG3Depth("Depth", &gig::DimensionRegion::EG3Depth, -1200, 1200),
456 eLFO3Frequency("Frequency", &gig::DimensionRegion::LFO3Frequency,
457 0.1, 10, 2),
458 eLFO3InternalDepth("InternalDepth",
459 &gig::DimensionRegion::LFO3InternalDepth, 0, 1200),
460 eLFO3ControlDepth("ControlDepth", &gig::DimensionRegion::LFO3ControlDepth,
461 0, 1200),
462 eLFO3Controller("Controller", &gig::DimensionRegion::LFO3Controller),
463 eLFO3Sync("Sync", &gig::DimensionRegion::LFO3Sync),
464 eVCFEnabled("Enabled", &gig::DimensionRegion::VCFEnabled),
465 eVCFType("Type", &gig::DimensionRegion::VCFType),
466 eVCFCutoffController("CutoffController",
467 &gig::DimensionRegion::VCFCutoffController),
468 eVCFCutoffControllerInvert("CutoffControllerInvert",
469 &gig::DimensionRegion::VCFCutoffControllerInvert),
470 eVCFCutoff("Cutoff", &gig::DimensionRegion::VCFCutoff),
471 eVCFVelocityCurve("VelocityCurve", &gig::DimensionRegion::VCFVelocityCurve),
472 eVCFVelocityScale("VelocityScale", &gig::DimensionRegion::VCFVelocityScale),
473 eVCFVelocityDynamicRange("VelocityDynamicRange",
474 &gig::DimensionRegion::VCFVelocityDynamicRange,
475 0, 4),
476 eVCFResonance("Resonance", &gig::DimensionRegion::VCFResonance),
477 eVCFResonanceDynamic("ResonanceDynamic",
478 &gig::DimensionRegion::VCFResonanceDynamic),
479 eVCFResonanceController("ResonanceController",
480 &gig::DimensionRegion::VCFResonanceController),
481 eVCFKeyboardTracking("KeyboardTracking",
482 &gig::DimensionRegion::VCFKeyboardTracking),
483 eVCFKeyboardTrackingBreakpoint("KeyboardTrackingBreakpoint",
484 &gig::DimensionRegion::VCFKeyboardTrackingBreakpoint),
485 eVelocityResponseCurve("VelocityResponseCurve",
486 &gig::DimensionRegion::VelocityResponseCurve),
487 eVelocityResponseDepth("VelocityResponseDepth",
488 &gig::DimensionRegion::VelocityResponseDepth, 0, 4),
489 eVelocityResponseCurveScaling("VelocityResponseCurveScaling",
490 &gig::DimensionRegion::VelocityResponseCurveScaling),
491 eReleaseVelocityResponseCurve("ReleaseVelocityResponseCurve",
492 &gig::DimensionRegion::ReleaseVelocityResponseCurve),
493 eReleaseVelocityResponseDepth("ReleaseVelocityResponseDepth",
494 &gig::DimensionRegion::ReleaseVelocityResponseDepth,
495 0, 4),
496 eReleaseTriggerDecay("ReleaseTriggerDecay",
497 &gig::DimensionRegion::ReleaseTriggerDecay, 0, 8),
498 eCrossfade_in_start("Crossfade.in_start", &access_Crossfade_in_start),
499 eCrossfade_in_end("Crossfade.in_end", &access_Crossfade_in_end),
500 eCrossfade_out_start("Crossfade.out_start", &access_Crossfade_out_start),
501 eCrossfade_out_end("Crossfade.out_end", &access_Crossfade_out_end),
502 ePitchTrack("PitchTrack", &gig::DimensionRegion::PitchTrack),
503 eDimensionBypass("DimensionBypass", &gig::DimensionRegion::DimensionBypass),
504 ePan("Pan", &gig::DimensionRegion::Pan, -64, 63),
505 eSelfMask("SelfMask", &gig::DimensionRegion::SelfMask),
506 eAttenuationController("AttenuationController",
507 &gig::DimensionRegion::AttenuationController),
508 eInvertAttenuationController("InvertAttenuationController",
509 &gig::DimensionRegion::InvertAttenuationController),
510 eAttenuationControllerThreshold("AttenuationControllerThreshold",
511 &gig::DimensionRegion::AttenuationControllerThreshold),
512 eChannelOffset("ChannelOffset", &gig::DimensionRegion::ChannelOffset, 0, 9),
513 eSustainDefeat("SustainDefeat", &gig::DimensionRegion::SustainDefeat),
514 eMSDecode("MSDecode", &gig::DimensionRegion::MSDecode),
515 eSampleStartOffset("SampleStartOffset",
516 &gig::DimensionRegion::SampleStartOffset, 0, 2000),
517 eUnityNote("UnityNote", &access_UnityNote),
518 eFineTune("FineTune", &access_FineTune, -49, 50),
519 eGain("Gain", -96, 0, 2),
520 eSampleLoops("SampleLoops", &access_SampleLoops, 0, 1)
521 {
522 // set_border_width(5);
523 // set_default_size(400, 200);
524
525
526 add(m_VBox);
527
528 // Handle selection
529 Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();
530 tree_sel_ref->signal_changed().connect(
531 sigc::mem_fun(*this, &MainWindow::on_sel_change));
532
533 m_TreeView.signal_button_press_event().connect_notify(
534 sigc::mem_fun(*this, &MainWindow::on_button_release));
535
536 // Add the TreeView tab, inside a ScrolledWindow, with the button underneath:
537 m_ScrolledWindow.add(m_TreeView);
538 // m_ScrolledWindow.set_size_request(200, 600);
539 m_ScrolledWindow.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
540
541 m_ScrolledWindowSamples.add(m_TreeViewSamples);
542 m_ScrolledWindowSamples.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
543
544
545 for (int i = 0 ; i < 5 ; i++) {
546 table[i] = new Gtk::Table(3, 1);
547 table[i]->set_col_spacings(5);
548 }
549
550 pageno = 0;
551 rowno = 0;
552 firstRowInBlock = 0;
553
554 addString("Sample", lSample, wSample);
555 addProp(eVelocityUpperLimit);
556 addHeader("EG1");
557 addProp(eEG1PreAttack);
558 addProp(eEG1Attack);
559 addProp(eEG1Decay1);
560 addProp(eEG1Decay2);
561 addProp(eEG1InfiniteSustain);
562 addProp(eEG1Sustain);
563 addProp(eEG1Release);
564 addProp(eEG1Hold);
565 addProp(eEG1Controller);
566 addProp(eEG1ControllerInvert);
567 addProp(eEG1ControllerAttackInfluence);
568 addProp(eEG1ControllerDecayInfluence);
569 addProp(eEG1ControllerReleaseInfluence);
570 addHeader("LFO1");
571 addProp(eLFO1Frequency);
572 addProp(eLFO1InternalDepth);
573 addProp(eLFO1ControlDepth);
574 {
575 char* choices[] = { "internal", "modwheel", "breath",
576 "internal+modwheel", "internal+breath", 0 };
577 static const gig::lfo1_ctrl_t values[] = {
578 gig::lfo1_ctrl_internal,
579 gig::lfo1_ctrl_modwheel,
580 gig::lfo1_ctrl_breath,
581 gig::lfo1_ctrl_internal_modwheel,
582 gig::lfo1_ctrl_internal_breath
583 };
584 eLFO1Controller.set_choices(choices, values);
585 }
586 addProp(eLFO1Controller);
587 addProp(eLFO1FlipPhase);
588 addProp(eLFO1Sync);
589
590 nextPage();
591 addHeader("EG2");
592 addProp(eEG2PreAttack);
593 addProp(eEG2Attack);
594 addProp(eEG2Decay1);
595 addProp(eEG2Decay2);
596 addProp(eEG2InfiniteSustain);
597 addProp(eEG2Sustain);
598 addProp(eEG2Release);
599 addProp(eEG2Controller);
600 addProp(eEG2ControllerInvert);
601 addProp(eEG2ControllerAttackInfluence);
602 addProp(eEG2ControllerDecayInfluence);
603 addProp(eEG2ControllerReleaseInfluence);
604 addHeader("LFO2");
605 addProp(eLFO2Frequency);
606 addProp(eLFO2InternalDepth);
607 addProp(eLFO2ControlDepth);
608 {
609 char* choices[] = { "internal", "modwheel", "foot",
610 "internal+modwheel", "internal+foot", 0 };
611 static const gig::lfo2_ctrl_t values[] = {
612 gig::lfo2_ctrl_internal,
613 gig::lfo2_ctrl_modwheel,
614 gig::lfo2_ctrl_foot,
615 gig::lfo2_ctrl_internal_modwheel,
616 gig::lfo2_ctrl_internal_foot
617 };
618 eLFO2Controller.set_choices(choices, values);
619 }
620 addProp(eLFO2Controller);
621 addProp(eLFO2FlipPhase);
622 addProp(eLFO2Sync);
623
624 nextPage();
625
626 addHeader("EG3");
627 addProp(eEG3Attack);
628 addProp(eEG3Depth);
629 addHeader("LFO3");
630 addProp(eLFO3Frequency);
631 addProp(eLFO3InternalDepth);
632 addProp(eLFO3ControlDepth);
633 {
634 char* choices[] = { "internal", "modwheel", "aftertouch",
635 "internal+modwheel", "internal+aftertouch", 0 };
636 static const gig::lfo3_ctrl_t values[] = {
637 gig::lfo3_ctrl_internal,
638 gig::lfo3_ctrl_modwheel,
639 gig::lfo3_ctrl_aftertouch,
640 gig::lfo3_ctrl_internal_modwheel,
641 gig::lfo3_ctrl_internal_aftertouch
642 };
643 eLFO3Controller.set_choices(choices, values);
644 }
645 addProp(eLFO3Controller);
646 addProp(eLFO3Sync);
647 addHeader("VCF");
648 addProp(eVCFEnabled);
649 {
650 char* choices[] = { "lowpass", "lowpassturbo", "bandpass",
651 "highpass", "bandreject", 0 };
652 static const gig::vcf_type_t values[] = {
653 gig::vcf_type_lowpass,
654 gig::vcf_type_lowpassturbo,
655 gig::vcf_type_bandpass,
656 gig::vcf_type_highpass,
657 gig::vcf_type_bandreject
658 };
659 eVCFType.set_choices(choices, values);
660 }
661 addProp(eVCFType);
662 {
663 char* choices[] = { "none", "none2", "modwheel", "effect1", "effect2",
664 "breath", "foot", "sustainpedal", "softpedal",
665 "genpurpose7", "genpurpose8", "aftertouch", 0 };
666 static const gig::vcf_cutoff_ctrl_t values[] = {
667 gig::vcf_cutoff_ctrl_none,
668 gig::vcf_cutoff_ctrl_none2,
669 gig::vcf_cutoff_ctrl_modwheel,
670 gig::vcf_cutoff_ctrl_effect1,
671 gig::vcf_cutoff_ctrl_effect2,
672 gig::vcf_cutoff_ctrl_breath,
673 gig::vcf_cutoff_ctrl_foot,
674 gig::vcf_cutoff_ctrl_sustainpedal,
675 gig::vcf_cutoff_ctrl_softpedal,
676 gig::vcf_cutoff_ctrl_genpurpose7,
677 gig::vcf_cutoff_ctrl_genpurpose8,
678 gig::vcf_cutoff_ctrl_aftertouch
679 };
680 eVCFCutoffController.set_choices(choices, values);
681 }
682 addProp(eVCFCutoffController);
683 addProp(eVCFCutoffControllerInvert);
684 addProp(eVCFCutoff);
685 char* curve_type_texts[] = { "nonlinear", "linear", "special", 0 };
686 static const gig::curve_type_t curve_type_values[] = {
687 gig::curve_type_nonlinear,
688 gig::curve_type_linear,
689 gig::curve_type_special
690 };
691 eVCFVelocityCurve.set_choices(curve_type_texts, curve_type_values);
692 addProp(eVCFVelocityCurve);
693 addProp(eVCFVelocityScale);
694 addProp(eVCFVelocityDynamicRange);
695 addProp(eVCFResonance);
696 addProp(eVCFResonanceDynamic);
697 {
698 char* choices[] = { "none", "genpurpose3", "genpurpose4",
699 "genpurpose5", "genpurpose6", 0 };
700 static const gig::vcf_res_ctrl_t values[] = {
701 gig::vcf_res_ctrl_none,
702 gig::vcf_res_ctrl_genpurpose3,
703 gig::vcf_res_ctrl_genpurpose4,
704 gig::vcf_res_ctrl_genpurpose5,
705 gig::vcf_res_ctrl_genpurpose6
706 };
707 eVCFResonanceController.set_choices(choices, values);
708 }
709 addProp(eVCFResonanceController);
710 addProp(eVCFKeyboardTracking);
711 addProp(eVCFKeyboardTrackingBreakpoint);
712
713 nextPage();
714
715 eVelocityResponseCurve.set_choices(curve_type_texts, curve_type_values);
716 addProp(eVelocityResponseCurve);
717 addProp(eVelocityResponseDepth);
718 addProp(eVelocityResponseCurveScaling);
719 eReleaseVelocityResponseCurve.set_choices(curve_type_texts,
720 curve_type_values);
721 addProp(eReleaseVelocityResponseCurve);
722 addProp(eReleaseVelocityResponseDepth);
723 addProp(eReleaseTriggerDecay);
724 addProp(eCrossfade_in_start);
725 addProp(eCrossfade_in_end);
726 addProp(eCrossfade_out_start);
727 addProp(eCrossfade_out_end);
728 addProp(ePitchTrack);
729 {
730 char* choices[] = { "none", "effect4depth", "effect5depth", 0 };
731 static const gig::dim_bypass_ctrl_t values[] = {
732 gig::dim_bypass_ctrl_none,
733 gig::dim_bypass_ctrl_94,
734 gig::dim_bypass_ctrl_95
735 };
736 eDimensionBypass.set_choices(choices, values);
737 }
738 addProp(eDimensionBypass);
739 addProp(ePan);
740 addProp(eSelfMask);
741 addProp(eAttenuationController);
742 addProp(eInvertAttenuationController);
743 addProp(eAttenuationControllerThreshold);
744 addProp(eChannelOffset);
745 addProp(eSustainDefeat);
746
747 nextPage();
748 addProp(eMSDecode);
749 addProp(eSampleStartOffset);
750 addProp(eUnityNote);
751 addProp(eFineTune);
752 addProp(eGain);
753 addProp(eSampleLoops);
754 nextPage();
755
756 eEG1InfiniteSustain.signal_toggled().connect(
757 sigc::mem_fun(*this, &MainWindow::EG1InfiniteSustain_toggled) );
758 eEG2InfiniteSustain.signal_toggled().connect(
759 sigc::mem_fun(*this, &MainWindow::EG2InfiniteSustain_toggled) );
760 eEG1Controller.signal_changed().connect(
761 sigc::mem_fun(*this, &MainWindow::EG1Controller_changed) );
762 eEG2Controller.signal_changed().connect(
763 sigc::mem_fun(*this, &MainWindow::EG2Controller_changed) );
764 eLFO1Controller.signal_changed().connect(
765 sigc::mem_fun(*this, &MainWindow::LFO1Controller_changed) );
766 eLFO2Controller.signal_changed().connect(
767 sigc::mem_fun(*this, &MainWindow::LFO2Controller_changed) );
768 eLFO3Controller.signal_changed().connect(
769 sigc::mem_fun(*this, &MainWindow::LFO3Controller_changed) );
770 eAttenuationController.signal_changed().connect(
771 sigc::mem_fun(*this, &MainWindow::AttenuationController_changed) );
772 eVCFEnabled.signal_toggled().connect(
773 sigc::mem_fun(*this, &MainWindow::VCFEnabled_toggled) );
774 eVCFCutoffController.signal_changed().connect(
775 sigc::mem_fun(*this, &MainWindow::VCFCutoffController_changed) );
776 eVCFResonanceController.signal_changed().connect(
777 sigc::mem_fun(*this, &MainWindow::VCFResonanceController_changed) );
778
779 eCrossfade_in_start.signal_value_changed().connect(
780 sigc::mem_fun(*this, &MainWindow::crossfade1_changed));
781 eCrossfade_in_end.signal_value_changed().connect(
782 sigc::mem_fun(*this, &MainWindow::crossfade2_changed));
783 eCrossfade_out_start.signal_value_changed().connect(
784 sigc::mem_fun(*this, &MainWindow::crossfade3_changed));
785 eCrossfade_out_end.signal_value_changed().connect(
786 sigc::mem_fun(*this, &MainWindow::crossfade4_changed));
787
788 //m_Notebook.append_page(m_ScrolledWindow2, "Table");
789 m_Notebook.append_page(*table[0], "EG1");
790 m_Notebook.append_page(*table[1], "EG2");
791 m_Notebook.append_page(*table[2], "EG3");
792 m_Notebook.append_page(*table[3], "Velocity");
793 m_Notebook.append_page(*table[4], "Misc");
794 // m_Notebook.set_size_request(400, 500);
795
796 m_TreeViewNotebook.set_size_request(300);
797 m_HPaned.add1(m_TreeViewNotebook);
798 m_HPaned.add2(m_Notebook);
799
800
801 m_TreeViewNotebook.append_page(m_ScrolledWindowSamples, "Samples");
802 m_TreeViewNotebook.append_page(m_ScrolledWindow, "Instruments");
803
804
805 actionGroup = Gtk::ActionGroup::create();
806
807 actionGroup->add(Gtk::Action::create("MenuFile", _("_File")));
808 actionGroup->add(Gtk::Action::create("New", Gtk::Stock::NEW),
809 sigc::mem_fun(
810 *this, &MainWindow::on_action_file_new));
811 Glib::RefPtr<Gtk::Action> action =
812 Gtk::Action::create("Open", Gtk::Stock::OPEN);
813 action->property_label() = action->property_label() + "...";
814 actionGroup->add(action,
815 sigc::mem_fun(
816 *this, &MainWindow::on_action_file_open));
817 actionGroup->add(Gtk::Action::create("Save", Gtk::Stock::SAVE),
818 sigc::mem_fun(
819 *this, &MainWindow::on_action_file_save));
820 action = Gtk::Action::create("SaveAs", Gtk::Stock::SAVE_AS);
821 action->property_label() = action->property_label() + "...";
822 actionGroup->add(action,
823 *(new Gtk::AccelKey("<shift><control>s")),
824 sigc::mem_fun(
825 *this, &MainWindow::on_action_file_save_as)
826 );
827 actionGroup->add(Gtk::Action::create("Properties",
828 Gtk::Stock::PROPERTIES),
829 sigc::mem_fun(
830 *this, &MainWindow::on_action_file_properties));
831 actionGroup->add(Gtk::Action::create("InstrProperties",
832 Gtk::Stock::PROPERTIES),
833 sigc::mem_fun(
834 *this, &MainWindow::on_action_file_properties));
835 actionGroup->add(Gtk::Action::create("Quit", Gtk::Stock::QUIT),
836 sigc::mem_fun(
837 *this, &MainWindow::hide));
838 actionGroup->add(Gtk::Action::create("MenuInstrument", _("_Instrument")));
839
840 action = Gtk::Action::create("MenuHelp", Gtk::Stock::HELP);
841 actionGroup->add(Gtk::Action::create("MenuHelp",
842 action->property_label()));
843 #ifdef ABOUT_DIALOG
844 actionGroup->add(Gtk::Action::create("About", Gtk::Stock::ABOUT),
845 sigc::mem_fun(
846 *this, &MainWindow::on_action_help_about));
847 #endif
848 action = Gtk::Action::create("Remove", Gtk::Stock::REMOVE);
849 actionGroup->add(action,
850 sigc::mem_fun(
851 *this, &MainWindow::hide));
852
853 // sample right-click popup actions
854 actionGroup->add(
855 Gtk::Action::create("SampleProperties", Gtk::Stock::PROPERTIES),
856 sigc::mem_fun(*this, &MainWindow::on_action_sample_properties)
857 );
858 actionGroup->add(
859 Gtk::Action::create("AddGroup", _("Add _Group")),
860 sigc::mem_fun(*this, &MainWindow::on_action_add_group)
861 );
862 actionGroup->add(
863 Gtk::Action::create("AddSample", _("Add _Sample(s)")),
864 sigc::mem_fun(*this, &MainWindow::on_action_add_sample)
865 );
866 actionGroup->add(
867 Gtk::Action::create("RemoveSample", Gtk::Stock::REMOVE),
868 sigc::mem_fun(*this, &MainWindow::on_action_remove_sample)
869 );
870
871 uiManager = Gtk::UIManager::create();
872 uiManager->insert_action_group(actionGroup);
873 // add_accel_group(uiManager->get_accel_group());
874
875 Glib::ustring ui_info =
876 "<ui>"
877 " <menubar name='MenuBar'>"
878 " <menu action='MenuFile'>"
879 " <menuitem action='New'/>"
880 " <menuitem action='Open'/>"
881 " <separator/>"
882 " <menuitem action='Save'/>"
883 " <menuitem action='SaveAs'/>"
884 " <separator/>"
885 " <menuitem action='Properties'/>"
886 " <separator/>"
887 " <menuitem action='Quit'/>"
888 " </menu>"
889 " <menu action='MenuInstrument'>"
890 " </menu>"
891 #ifdef ABOUT_DIALOG
892 " <menu action='MenuHelp'>"
893 " <menuitem action='About'/>"
894 " </menu>"
895 #endif
896 " </menubar>"
897 " <popup name='PopupMenu'>"
898 " <menuitem action='InstrProperties'/>"
899 " <menuitem action='Remove'/>"
900 " </popup>"
901 " <popup name='SamplePopupMenu'>"
902 " <menuitem action='SampleProperties'/>"
903 " <menuitem action='AddGroup'/>"
904 " <menuitem action='AddSample'/>"
905 " <separator/>"
906 " <menuitem action='RemoveSample'/>"
907 " </popup>"
908 "</ui>";
909 uiManager->add_ui_from_string(ui_info);
910
911 popup_menu = dynamic_cast<Gtk::Menu*>(uiManager->get_widget("/PopupMenu"));
912
913 Gtk::Widget* menuBar = uiManager->get_widget("/MenuBar");
914 m_VBox.pack_start(*menuBar, Gtk::PACK_SHRINK);
915 m_VBox.pack_start(m_HPaned);
916 m_VBox.pack_start(m_RegionChooser, Gtk::PACK_SHRINK);
917 m_VBox.pack_start(m_DimRegionChooser, Gtk::PACK_SHRINK);
918
919 m_RegionChooser.signal_sel_changed().connect(
920 sigc::mem_fun(*this, &MainWindow::region_changed) );
921 m_DimRegionChooser.signal_sel_changed().connect(
922 sigc::mem_fun(*this, &MainWindow::dimreg_changed) );
923
924
925 // Create the Tree model:
926 m_refTreeModel = Gtk::ListStore::create(m_Columns);
927 m_TreeView.set_model(m_refTreeModel);
928
929 // Add the TreeView's view columns:
930 m_TreeView.append_column("Instrument", m_Columns.m_col_name);
931 m_TreeView.set_headers_visible(false);
932
933 // create samples treeview (including its data model)
934 m_refSamplesTreeModel = Gtk::TreeStore::create(m_SamplesModel);
935 m_TreeViewSamples.set_model(m_refSamplesTreeModel);
936 m_TreeViewSamples.append_column("Samples", m_SamplesModel.m_col_name);
937 m_TreeViewSamples.set_headers_visible(false);
938 m_TreeViewSamples.signal_button_press_event().connect_notify(
939 sigc::mem_fun(*this, &MainWindow::on_sample_treeview_button_release)
940 );
941
942 file = 0;
943
944 show_all_children();
945 }
946
947 MainWindow::~MainWindow()
948 {
949 }
950
951 void MainWindow::region_changed()
952 {
953 m_DimRegionChooser.set_region(m_RegionChooser.get_region());
954 }
955
956 void MainWindow::dimreg_changed()
957 {
958 set_dim_region(m_DimRegionChooser.get_dimregion());
959 }
960
961 void MainWindow::on_sel_change()
962 {
963 Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();
964
965 Gtk::TreeModel::iterator it = tree_sel_ref->get_selected();
966 if (it)
967 {
968 Gtk::TreeModel::Row row = *it;
969 std::cout << row[m_Columns.m_col_name] << std::endl;
970
971 if (row[m_Columns.m_col_instr])
972 m_RegionChooser.set_instrument(row[m_Columns.m_col_instr]);
973 }
974 }
975
976 void MainWindow::set_dim_region(gig::DimensionRegion* d)
977 {
978 update_gui = false;
979 wSample->set_text(d->pSample ? d->pSample->pInfo->Name.c_str() : "NULL");
980 eVelocityUpperLimit.set_dimreg(d);
981 eEG1PreAttack.set_dimreg(d);
982 eEG1Attack.set_dimreg(d);
983 eEG1Decay1.set_dimreg(d);
984 eEG1Decay2.set_dimreg(d);
985 eEG1InfiniteSustain.set_dimreg(d);
986 eEG1Sustain.set_dimreg(d);
987 eEG1Release.set_dimreg(d);
988 eEG1Hold.set_dimreg(d);
989 eEG1Controller.set_dimreg(d);
990 eEG1ControllerInvert.set_dimreg(d);
991 eEG1ControllerAttackInfluence.set_dimreg(d);
992 eEG1ControllerDecayInfluence.set_dimreg(d);
993 eEG1ControllerReleaseInfluence.set_dimreg(d);
994 eLFO1Frequency.set_dimreg(d);
995 eLFO1InternalDepth.set_dimreg(d);
996 eLFO1ControlDepth.set_dimreg(d);
997 eLFO1Controller.set_dimreg(d);
998 eLFO1FlipPhase.set_dimreg(d);
999 eLFO1Sync.set_dimreg(d);
1000 eEG2PreAttack.set_dimreg(d);
1001 eEG2Attack.set_dimreg(d);
1002 eEG2Decay1.set_dimreg(d);
1003 eEG2Decay2.set_dimreg(d);
1004 eEG2InfiniteSustain.set_dimreg(d);
1005 eEG2Sustain.set_dimreg(d);
1006 eEG2Release.set_dimreg(d);
1007 eEG2Controller.set_dimreg(d);
1008 eEG2ControllerInvert.set_dimreg(d);
1009 eEG2ControllerAttackInfluence.set_dimreg(d);
1010 eEG2ControllerDecayInfluence.set_dimreg(d);
1011 eEG2ControllerReleaseInfluence.set_dimreg(d);
1012 eLFO2Frequency.set_dimreg(d);
1013 eLFO2InternalDepth.set_dimreg(d);
1014 eLFO2ControlDepth.set_dimreg(d);
1015 eLFO2Controller.set_dimreg(d);
1016 eLFO2FlipPhase.set_dimreg(d);
1017 eLFO2Sync.set_dimreg(d);
1018 eEG3Attack.set_dimreg(d);
1019 eEG3Depth.set_dimreg(d);
1020 eLFO3Frequency.set_dimreg(d);
1021 eLFO3InternalDepth.set_dimreg(d);
1022 eLFO3ControlDepth.set_dimreg(d);
1023 eLFO3Controller.set_dimreg(d);
1024 eLFO3Sync.set_dimreg(d);
1025 eVCFEnabled.set_dimreg(d);
1026 eVCFType.set_dimreg(d);
1027 eVCFCutoffController.set_dimreg(d);
1028 eVCFCutoffControllerInvert.set_dimreg(d);
1029 eVCFCutoff.set_dimreg(d);
1030 eVCFVelocityCurve.set_dimreg(d);
1031 eVCFVelocityScale.set_dimreg(d);
1032 eVCFVelocityDynamicRange.set_dimreg(d);
1033 eVCFResonance.set_dimreg(d);
1034 eVCFResonanceDynamic.set_dimreg(d);
1035 eVCFResonanceController.set_dimreg(d);
1036 eVCFKeyboardTracking.set_dimreg(d);
1037 eVCFKeyboardTrackingBreakpoint.set_dimreg(d);
1038 eVelocityResponseCurve.set_dimreg(d);
1039 eVelocityResponseDepth.set_dimreg(d);
1040 eVelocityResponseCurveScaling.set_dimreg(d);
1041 eReleaseVelocityResponseCurve.set_dimreg(d);
1042 eReleaseVelocityResponseDepth.set_dimreg(d);
1043 eReleaseTriggerDecay.set_dimreg(d);
1044 eCrossfade_in_start.set_dimreg(d);
1045 eCrossfade_in_end.set_dimreg(d);
1046 eCrossfade_out_start.set_dimreg(d);
1047 eCrossfade_out_end.set_dimreg(d);
1048 ePitchTrack.set_dimreg(d);
1049 eDimensionBypass.set_dimreg(d);
1050 ePan.set_dimreg(d);
1051 eSelfMask.set_dimreg(d);
1052 eAttenuationController.set_dimreg(d);
1053 eInvertAttenuationController.set_dimreg(d);
1054 eAttenuationControllerThreshold.set_dimreg(d);
1055 eChannelOffset.set_dimreg(d);
1056 eSustainDefeat.set_dimreg(d);
1057 eMSDecode.set_dimreg(d);
1058 eSampleStartOffset.set_dimreg(d);
1059 eUnityNote.set_dimreg(d);
1060 eFineTune.set_dimreg(d);
1061 eGain.set_dimreg(d);
1062 eSampleLoops.set_dimreg(d);
1063
1064 VCFEnabled_toggled();
1065
1066 update_gui = true;
1067 }
1068
1069 void MainWindow::VCFEnabled_toggled()
1070 {
1071 bool sensitive = eVCFEnabled.get_active();
1072 eVCFType.set_sensitive(sensitive);
1073 eVCFCutoffController.set_sensitive(sensitive);
1074 eVCFVelocityCurve.set_sensitive(sensitive);
1075 eVCFVelocityScale.set_sensitive(sensitive);
1076 eVCFVelocityDynamicRange.set_sensitive(sensitive);
1077 eVCFResonance.set_sensitive(sensitive);
1078 eVCFResonanceController.set_sensitive(sensitive);
1079 eVCFKeyboardTracking.set_sensitive(sensitive);
1080 eVCFKeyboardTrackingBreakpoint.set_sensitive(sensitive);
1081 eEG2PreAttack.set_sensitive(sensitive);
1082 eEG2Attack.set_sensitive(sensitive);
1083 eEG2Decay1.set_sensitive(sensitive);
1084 eEG2InfiniteSustain.set_sensitive(sensitive);
1085 eEG2Sustain.set_sensitive(sensitive);
1086 eEG2Release.set_sensitive(sensitive);
1087 eEG2Controller.set_sensitive(sensitive);
1088 eEG2ControllerAttackInfluence.set_sensitive(sensitive);
1089 eEG2ControllerDecayInfluence.set_sensitive(sensitive);
1090 eEG2ControllerReleaseInfluence.set_sensitive(sensitive);
1091 eLFO2Frequency.set_sensitive(sensitive);
1092 eLFO2InternalDepth.set_sensitive(sensitive);
1093 eLFO2ControlDepth.set_sensitive(sensitive);
1094 eLFO2Controller.set_sensitive(sensitive);
1095 eLFO2FlipPhase.set_sensitive(sensitive);
1096 eLFO2Sync.set_sensitive(sensitive);
1097 if (sensitive) {
1098 VCFCutoffController_changed();
1099 VCFResonanceController_changed();
1100 EG2InfiniteSustain_toggled();
1101 EG2Controller_changed();
1102 LFO2Controller_changed();
1103 } else {
1104 eVCFCutoffControllerInvert.set_sensitive(false);
1105 eVCFCutoff.set_sensitive(false);
1106 eVCFResonanceDynamic.set_sensitive(false);
1107 eVCFResonance.set_sensitive(false);
1108 eEG2Decay2.set_sensitive(false);
1109 eEG2ControllerInvert.set_sensitive(false);
1110 eLFO2InternalDepth.set_sensitive(false);
1111 eLFO2ControlDepth.set_sensitive(false);
1112 }
1113 }
1114
1115 void MainWindow::VCFCutoffController_changed()
1116 {
1117 int rowno = eVCFCutoffController.get_active_row_number();
1118 bool hasController = rowno != 0 && rowno != 1;
1119
1120 eVCFCutoffControllerInvert.set_sensitive(hasController);
1121 eVCFCutoff.set_sensitive(!hasController);
1122 eVCFResonanceDynamic.set_sensitive(!hasController);
1123 eVCFVelocityScale.label.set_text(hasController ? "MinimumCutoff:" :
1124 "VelocityScale:");
1125 }
1126
1127 void MainWindow::VCFResonanceController_changed()
1128 {
1129 bool hasController = eVCFResonanceController.get_active_row_number() != 0;
1130 eVCFResonance.set_sensitive(!hasController);
1131 }
1132
1133 void MainWindow::EG1InfiniteSustain_toggled()
1134 {
1135 bool infSus = eEG1InfiniteSustain.get_active();
1136 eEG1Decay2.set_sensitive(!infSus);
1137 }
1138
1139 void MainWindow::EG2InfiniteSustain_toggled()
1140 {
1141 bool infSus = eEG2InfiniteSustain.get_active();
1142 eEG2Decay2.set_sensitive(!infSus);
1143 }
1144
1145 void MainWindow::EG1Controller_changed()
1146 {
1147 bool hasController = eEG1Controller.get_active_row_number() != 0;
1148 eEG1ControllerInvert.set_sensitive(hasController);
1149 }
1150
1151 void MainWindow::EG2Controller_changed()
1152 {
1153 bool hasController = eEG2Controller.get_active_row_number() != 0;
1154 eEG2ControllerInvert.set_sensitive(hasController);
1155 }
1156
1157 void MainWindow::AttenuationController_changed()
1158 {
1159 bool hasController = eAttenuationController.get_active_row_number() != 0;
1160 eInvertAttenuationController.set_sensitive(hasController);
1161 }
1162
1163 void MainWindow::LFO1Controller_changed()
1164 {
1165 int rowno = eLFO1Controller.get_active_row_number();
1166 eLFO1ControlDepth.set_sensitive(rowno != 0);
1167 eLFO1InternalDepth.set_sensitive(rowno != 1 && rowno != 2);
1168 }
1169
1170 void MainWindow::LFO2Controller_changed()
1171 {
1172 int rowno = eLFO2Controller.get_active_row_number();
1173 eLFO2ControlDepth.set_sensitive(rowno != 0);
1174 eLFO2InternalDepth.set_sensitive(rowno != 1 && rowno != 2);
1175 }
1176
1177 void MainWindow::LFO3Controller_changed()
1178 {
1179 int rowno = eLFO3Controller.get_active_row_number();
1180 eLFO3ControlDepth.set_sensitive(rowno != 0);
1181 eLFO3InternalDepth.set_sensitive(rowno != 1 && rowno != 2);
1182 }
1183
1184 void MainWindow::crossfade1_changed()
1185 {
1186 double c1 = eCrossfade_in_start.get_value();
1187 double c2 = eCrossfade_in_end.get_value();
1188 if (c1 > c2) eCrossfade_in_end.set_value(c1);
1189 }
1190
1191 void MainWindow::crossfade2_changed()
1192 {
1193 double c1 = eCrossfade_in_start.get_value();
1194 double c2 = eCrossfade_in_end.get_value();
1195 double c3 = eCrossfade_out_start.get_value();
1196
1197 if (c2 < c1) eCrossfade_in_start.set_value(c2);
1198 if (c2 > c3) eCrossfade_out_start.set_value(c2);
1199 }
1200
1201 void MainWindow::crossfade3_changed()
1202 {
1203 double c2 = eCrossfade_in_end.get_value();
1204 double c3 = eCrossfade_out_start.get_value();
1205 double c4 = eCrossfade_out_end.get_value();
1206
1207 if (c3 < c2) eCrossfade_in_end.set_value(c3);
1208 if (c3 > c4) eCrossfade_out_end.set_value(c3);
1209 }
1210
1211 void MainWindow::crossfade4_changed()
1212 {
1213 double c3 = eCrossfade_out_start.get_value();
1214 double c4 = eCrossfade_out_end.get_value();
1215
1216 if (c4 < c3) eCrossfade_out_start.set_value(c4);
1217 }
1218
1219 void loader_progress_callback(gig::progress_t* progress)
1220 {
1221 Loader* loader = static_cast<Loader*>(progress->custom);
1222 loader->progress_callback(progress->factor);
1223 }
1224
1225 void Loader::progress_callback(float fraction)
1226 {
1227 {
1228 Glib::Mutex::Lock lock(progressMutex);
1229 progress = fraction;
1230 }
1231 progress_dispatcher();
1232 }
1233
1234 void Loader::thread_function()
1235 {
1236 printf("thread_function self=%x\n", Glib::Thread::self());
1237 printf("Start %s\n", filename);
1238 RIFF::File* riff = new RIFF::File(filename);
1239 gig = new gig::File(riff);
1240 gig::progress_t progress;
1241 progress.callback = loader_progress_callback;
1242 progress.custom = this;
1243
1244 gig->GetInstrument(0, &progress);
1245 printf("End\n");
1246 finished_dispatcher();
1247 }
1248
1249 Loader::Loader(const char* filename)
1250 : thread(0), filename(filename)
1251 {
1252 }
1253
1254 void Loader::launch()
1255 {
1256 thread = Glib::Thread::create(sigc::mem_fun(*this, &Loader::thread_function), true);
1257 printf("launch thread=%x\n", thread);
1258 }
1259
1260 float Loader::get_progress()
1261 {
1262 float res;
1263 {
1264 Glib::Mutex::Lock lock(progressMutex);
1265 res = progress;
1266 }
1267 return res;
1268 }
1269
1270 Glib::Dispatcher& Loader::signal_progress()
1271 {
1272 return progress_dispatcher;
1273 }
1274
1275 Glib::Dispatcher& Loader::signal_finished()
1276 {
1277 return finished_dispatcher;
1278 }
1279
1280 LoadDialog::LoadDialog()
1281 {
1282 get_vbox()->pack_start(progressBar);
1283 show_all_children();
1284 }
1285
1286 void MainWindow::on_action_file_new()
1287 {
1288 m_SampleImportQueue.clear();
1289 }
1290
1291 void MainWindow::on_action_file_open()
1292 {
1293 Gtk::FileChooserDialog dialog(*this, _("Open file"));
1294 dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1295 dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);
1296 Gtk::FileFilter filter;
1297 filter.add_pattern("*.gig");
1298 dialog.set_filter(filter);
1299 if (dialog.run() == Gtk::RESPONSE_OK) {
1300 printf("filename=%s\n", dialog.get_filename().c_str());
1301
1302 // remove all entries from "Instrument" menu
1303 Gtk::MenuItem* instrument_menu =
1304 dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/MenuBar/MenuInstrument"));
1305 instrument_menu->hide();
1306 for (int i = 0; i < instrument_menu->get_submenu()->items().size(); i++) {
1307 delete &instrument_menu->get_submenu()->items()[i];
1308 }
1309 instrument_menu->get_submenu()->items().clear();
1310
1311 m_SampleImportQueue.clear();
1312 m_refTreeModel->clear();
1313 m_refSamplesTreeModel->clear();
1314 if (file) delete file;
1315
1316 // getInfo(dialog.get_filename().c_str(), *this);
1317
1318 printf("on_action_file_open self=%x\n", Glib::Thread::self());
1319 load_dialog = new LoadDialog(); // Gtk::Dialog("Loading...", *this, true);
1320 load_dialog->show_all();
1321 loader = new Loader(strdup(dialog.get_filename().c_str()));
1322 loader->signal_progress().connect(
1323 sigc::mem_fun(*this, &MainWindow::on_loader_progress));
1324 loader->signal_finished().connect(
1325 sigc::mem_fun(*this, &MainWindow::on_loader_finished));
1326
1327 loader->launch();
1328 }
1329 }
1330
1331 void MainWindow::on_loader_progress()
1332 {
1333 load_dialog->set_fraction(loader->get_progress());
1334 }
1335
1336 void MainWindow::on_loader_finished()
1337 {
1338 printf("Loader finished!\n");
1339 printf("on_loader_finished self=%x\n", Glib::Thread::self());
1340 load_gig(loader->gig, loader->filename);
1341
1342
1343 Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();
1344 tree_sel_ref->select(Gtk::TreePath("0"));
1345
1346 load_dialog->hide();
1347 }
1348
1349 void MainWindow::on_action_file_save()
1350 {
1351 if (!file) return;
1352 file->Save();
1353 __import_queued_samples();
1354 }
1355
1356 void MainWindow::on_action_file_save_as()
1357 {
1358 if (!file) return;
1359 Gtk::FileChooserDialog dialog(*this, "Open", Gtk::FILE_CHOOSER_ACTION_SAVE);
1360 dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1361 dialog.add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK);
1362 Gtk::FileFilter filter;
1363 filter.add_pattern("*.gig");
1364 dialog.set_filter(filter);
1365 if (dialog.run() == Gtk::RESPONSE_OK) {
1366 printf("filename=%s\n", dialog.get_filename().c_str());
1367 file->Save(dialog.get_filename());
1368 __import_queued_samples();
1369 }
1370 }
1371
1372 // actually write the sample(s)' data to the gig file
1373 void MainWindow::__import_queued_samples() {
1374 Glib::ustring error_files;
1375 for (std::list<SampleImportItem>::iterator iter = m_SampleImportQueue.begin(); iter != m_SampleImportQueue.end(); ) {
1376 printf("Importing sample %s\n",(*iter).sample_path.c_str());
1377 SF_INFO info;
1378 info.format = 0;
1379 SNDFILE* hFile = sf_open((*iter).sample_path.c_str(), SFM_READ, &info);
1380 try {
1381 if (!hFile) throw std::string("could not open file");
1382 // determine sample's bit depth
1383 int bitdepth;
1384 switch (info.format & 0xff) {
1385 case SF_FORMAT_PCM_S8:
1386 bitdepth = 16; // we simply convert to 16 bit for now
1387 break;
1388 case SF_FORMAT_PCM_16:
1389 bitdepth = 16;
1390 break;
1391 case SF_FORMAT_PCM_24:
1392 bitdepth = 32; // we simply convert to 32 bit for now
1393 break;
1394 case SF_FORMAT_PCM_32:
1395 bitdepth = 32;
1396 break;
1397 case SF_FORMAT_PCM_U8:
1398 bitdepth = 16; // we simply convert to 16 bit for now
1399 break;
1400 case SF_FORMAT_FLOAT:
1401 bitdepth = 32;
1402 break;
1403 case SF_FORMAT_DOUBLE:
1404 bitdepth = 32; // I guess we will always truncate this to 32 bit
1405 break;
1406 default:
1407 sf_close(hFile); // close sound file
1408 throw std::string("format not supported"); // unsupported subformat (yet?)
1409 }
1410 // allocate appropriate copy buffer (TODO: for now we copy it in one piece, might be tough for very long samples)
1411 // and copy sample data into buffer
1412 int8_t* buffer = NULL;
1413 switch (bitdepth) {
1414 case 16:
1415 buffer = new int8_t[2 * info.channels * info.frames];
1416 sf_readf_short(hFile, (short*) buffer, info.frames); // libsndfile does the conversion for us (if needed)
1417 break;
1418 case 32:
1419 buffer = new int8_t[4 * info.channels * info.frames];
1420 sf_readf_int(hFile, (int*) buffer, info.frames); // libsndfile does the conversion for us (if needed)
1421 break;
1422 }
1423 // write from buffer directly (physically) into .gig file
1424 (*iter).gig_sample->Write(buffer, info.frames);
1425 // cleanup
1426 sf_close(hFile);
1427 delete buffer;
1428 // on success we remove the sample from the import queue, otherwise keep it, maybe it works the next time ?
1429 std::list<SampleImportItem>::iterator cur = iter;
1430 ++iter;
1431 m_SampleImportQueue.erase(cur);
1432 } catch (std::string what) { // remember the files that made trouble (and their cause)
1433 if (error_files.size()) error_files += "\n";
1434 error_files += (*iter).sample_path += " (" + what + ")";
1435 ++iter;
1436 }
1437 }
1438 // show error message box when some sample(s) could not be imported
1439 if (error_files.size()) {
1440 Glib::ustring txt = "Could not import the following sample(s):\n" + error_files;
1441 Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
1442 msg.run();
1443 }
1444 }
1445
1446 void MainWindow::on_action_file_properties()
1447 {
1448 propDialog.show();
1449 propDialog.deiconify();
1450 }
1451
1452 void MainWindow::on_action_help_about()
1453 {
1454 #ifdef ABOUT_DIALOG
1455 Gtk::AboutDialog dialog;
1456 dialog.set_version(VERSION);
1457 dialog.run();
1458 #endif
1459 }
1460
1461 PropDialog::PropDialog()
1462 : table(2,1)
1463 {
1464 table.set_col_spacings(5);
1465 char* propLabels[] = {
1466 "Name:",
1467 "CreationDate:",
1468 "Comments:", // TODO: multiline
1469 "Product:",
1470 "Copyright:",
1471 "Artists:",
1472 "Genre:",
1473 "Keywords:",
1474 "Engineer:",
1475 "Technician:",
1476 "Software:", // TODO: readonly
1477 "Medium:",
1478 "Source:",
1479 "SourceForm:",
1480 "Commissioned:",
1481 "Subject:"
1482 };
1483 for (int i = 0 ; i < sizeof(propLabels) / sizeof(char*) ; i++) {
1484 label[i].set_text(propLabels[i]);
1485 label[i].set_alignment(Gtk::ALIGN_LEFT);
1486 table.attach(label[i], 0, 1, i, i + 1, Gtk::FILL, Gtk::SHRINK);
1487 table.attach(entry[i], 1, 2, i, i + 1, Gtk::FILL | Gtk::EXPAND,
1488 Gtk::SHRINK);
1489 }
1490
1491 add(table);
1492 // add_button(Gtk::Stock::CANCEL, 0);
1493 // add_button(Gtk::Stock::OK, 1);
1494 show_all_children();
1495 }
1496
1497 void PropDialog::set_info(DLS::Info* info)
1498 {
1499 entry[0].set_text(info->Name);
1500 entry[1].set_text(info->CreationDate);
1501 entry[2].set_text(Glib::convert(info->Comments, "UTF-8", "ISO-8859-1"));
1502 entry[3].set_text(info->Product);
1503 entry[4].set_text(info->Copyright);
1504 entry[5].set_text(info->Artists);
1505 entry[6].set_text(info->Genre);
1506 entry[7].set_text(info->Keywords);
1507 entry[8].set_text(info->Engineer);
1508 entry[9].set_text(info->Technician);
1509 entry[10].set_text(info->Software);
1510 entry[11].set_text(info->Medium);
1511 entry[12].set_text(info->Source);
1512 entry[13].set_text(info->SourceForm);
1513 entry[14].set_text(info->Commissioned);
1514 entry[15].set_text(info->Subject);
1515 }
1516
1517
1518 InstrumentProps::InstrumentProps()
1519 : table(2,1),
1520 quitButton(Gtk::Stock::CLOSE)
1521 {
1522 table.set_col_spacings(5);
1523 char* propLabels[] = {
1524 "Name:",
1525 "IsDrum:",
1526 "MIDIBank:",
1527 "MIDIProgram:",
1528 "Attenuation:",
1529 "EffectSend:",
1530 "FineTune:",
1531 "PitchbendRange:",
1532 "PianoReleaseMode:",
1533 "DimensionKeyRange:",
1534 };
1535 int entryIdx = 0, checkIdx = 0;
1536 for (int i = 0 ; i < sizeof(propLabels) / sizeof(char*) ; i++) {
1537 label[i].set_text(propLabels[i]);
1538 label[i].set_alignment(Gtk::ALIGN_LEFT);
1539 table.attach(label[i], 0, 1, i, i + 1, Gtk::FILL, Gtk::SHRINK);
1540 if (i == 1 || i == 8)
1541 table.attach(check[checkIdx++], 1, 2, i, i + 1,
1542 Gtk::FILL | Gtk::EXPAND, Gtk::SHRINK);
1543 else
1544 table.attach(entry[entryIdx++], 1, 2, i, i + 1,
1545 Gtk::FILL | Gtk::EXPAND, Gtk::SHRINK);
1546 }
1547
1548 // vbox { table buttonBox { quitButton } }
1549
1550 //get_vbox()->pack_start(table);
1551 // set_border_width(6);
1552 add(vbox);
1553 table.set_border_width(2);
1554 vbox.pack_start(table);
1555 table.show();
1556 vbox.pack_start(buttonBox);
1557 buttonBox.set_layout(Gtk::BUTTONBOX_END);
1558 buttonBox.set_border_width(5);
1559 buttonBox.show();
1560 buttonBox.pack_start(quitButton);
1561 quitButton.set_flags(Gtk::CAN_DEFAULT);
1562 quitButton.grab_focus();
1563
1564 quitButton.signal_clicked().connect(
1565 sigc::mem_fun(*this, &InstrumentProps::hide));
1566
1567 // quitButton.grab_default();
1568 quitButton.show();
1569 // add(table);
1570 vbox.show();
1571 show_all_children();
1572 }
1573
1574
1575 void InstrumentProps::set_instrument(gig::Instrument* instrument)
1576 {
1577 char buf[100];
1578
1579 int entryIdx = 0, checkIdx = 0;
1580 entry[entryIdx++].set_text(instrument->pInfo->Name);
1581 check[checkIdx++].set_active(instrument->IsDrum);
1582 sprintf(buf, "%d", instrument->MIDIBank);
1583 entry[entryIdx++].set_text(buf);
1584 sprintf(buf, "%d", instrument->MIDIProgram);
1585 entry[entryIdx++].set_text(buf);
1586 sprintf(buf, "%d", instrument->Attenuation);
1587 entry[entryIdx++].set_text(buf);
1588 sprintf(buf, "%d", instrument->EffectSend);
1589 entry[entryIdx++].set_text(buf);
1590 sprintf(buf, "%d", instrument->FineTune);
1591 entry[entryIdx++].set_text(buf);
1592 sprintf(buf, "%d", instrument->PitchbendRange);
1593 entry[entryIdx++].set_text(buf);
1594 check[checkIdx++].set_active(instrument->PianoReleaseMode);
1595 sprintf(buf, "%s%d (%d)..%s%d (%d)",
1596 notes[instrument->DimensionKeyRange.low % 12],
1597 instrument->DimensionKeyRange.low / 12 - 1,
1598 instrument->DimensionKeyRange.low,
1599 notes[instrument->DimensionKeyRange.high % 12],
1600 instrument->DimensionKeyRange.high / 12 - 1,
1601 instrument->DimensionKeyRange.high);
1602 entry[entryIdx].set_text(buf);
1603 }
1604
1605 void MainWindow::getInfo(const char *filename)
1606 {
1607 RIFF::File* riff = new RIFF::File(filename);
1608 gig::File* gig = new gig::File(riff);
1609
1610 load_gig(gig, filename);
1611 }
1612
1613 void MainWindow::load_gig(gig::File* gig, const char* filename)
1614 {
1615 file = gig;
1616
1617 const char *basename = strrchr(filename, '/');
1618 basename = basename ? basename + 1 : filename;
1619
1620 set_title(basename);
1621
1622 propDialog.set_info(gig->pInfo);
1623
1624 Gtk::MenuItem* instrument_menu =
1625 dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/MenuBar/MenuInstrument"));
1626
1627 int instrument_index = 0;
1628 Gtk::RadioMenuItem::Group instrument_group;
1629 for (gig::Instrument* instrument = gig->GetFirstInstrument() ; instrument ;
1630 instrument = gig->GetNextInstrument()) {
1631 Gtk::TreeModel::iterator iter = m_refTreeModel->append();
1632 Gtk::TreeModel::Row row = *iter;
1633 row[m_Columns.m_col_name] = instrument->pInfo->Name.c_str();
1634 row[m_Columns.m_col_instr] = instrument;
1635 // create a menu item for this instrument
1636 Gtk::RadioMenuItem* item= new Gtk::RadioMenuItem(instrument_group, instrument->pInfo->Name.c_str());
1637 instrument_menu->get_submenu()->append(*item);
1638 item->signal_activate().connect(
1639 sigc::bind(
1640 sigc::mem_fun(*this, &MainWindow::on_instrument_selection_change),
1641 instrument_index
1642 )
1643 );
1644 instrument_index++;
1645 }
1646 instrument_menu->show();
1647 instrument_menu->get_submenu()->show_all_children();
1648
1649 for (gig::Group* group = gig->GetFirstGroup(); group; group = gig->GetNextGroup()) {
1650 if (group->Name != "") {
1651 Gtk::TreeModel::iterator iterGroup = m_refSamplesTreeModel->append();
1652 Gtk::TreeModel::Row rowGroup = *iterGroup;
1653 rowGroup[m_SamplesModel.m_col_name] = group->Name.c_str();
1654 rowGroup[m_SamplesModel.m_col_group] = group;
1655 rowGroup[m_SamplesModel.m_col_sample] = NULL;
1656 for (gig::Sample* sample = group->GetFirstSample(); sample; sample = group->GetNextSample()) {
1657 Gtk::TreeModel::iterator iterSample = m_refSamplesTreeModel->append(rowGroup.children());
1658 Gtk::TreeModel::Row rowSample = *iterSample;
1659 rowSample[m_SamplesModel.m_col_name] = sample->pInfo->Name.c_str();
1660 rowSample[m_SamplesModel.m_col_sample] = sample;
1661 rowSample[m_SamplesModel.m_col_group] = NULL;
1662 }
1663 }
1664 }
1665 }
1666
1667 void MainWindow::on_button_release(GdkEventButton* button)
1668 {
1669 if (button->type == GDK_2BUTTON_PRESS) {
1670 Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();
1671 Gtk::TreeModel::iterator it = tree_sel_ref->get_selected();
1672 if (it)
1673 {
1674 Gtk::TreeModel::Row row = *it;
1675 if (row[m_Columns.m_col_instr])
1676 {
1677 instrumentProps.set_instrument(row[m_Columns.m_col_instr]);
1678 instrumentProps.show();
1679 instrumentProps.deiconify();
1680 }
1681 }
1682 } else if (button->type == GDK_BUTTON_PRESS && button->button == 3) {
1683 popup_menu->popup(button->button, button->time);
1684 }
1685 }
1686
1687 void MainWindow::on_instrument_selection_change(int index) {
1688 m_RegionChooser.set_instrument(file->GetInstrument(index));
1689 }
1690
1691 void MainWindow::on_sample_treeview_button_release(GdkEventButton* button) {
1692 if (button->type == GDK_BUTTON_PRESS && button->button == 3) {
1693 Gtk::Menu* sample_popup =
1694 dynamic_cast<Gtk::Menu*>(uiManager->get_widget("/SamplePopupMenu"));
1695 // update enabled/disabled state of sample popup items
1696 Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();
1697 Gtk::TreeModel::iterator it = sel->get_selected();
1698 bool group_selected = false;
1699 bool sample_selected = false;
1700 if (it) {
1701 Gtk::TreeModel::Row row = *it;
1702 group_selected = row[m_SamplesModel.m_col_group];
1703 sample_selected = row[m_SamplesModel.m_col_sample];
1704 }
1705 dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/SamplePopupMenu/SampleProperties"))->set_sensitive(group_selected || sample_selected);
1706 dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/SamplePopupMenu/AddSample"))->set_sensitive(group_selected || sample_selected);
1707 dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/SamplePopupMenu/AddGroup"))->set_sensitive(file);
1708 dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/SamplePopupMenu/RemoveSample"))->set_sensitive(group_selected || sample_selected);
1709 // show sample popup
1710 sample_popup->popup(button->button, button->time);
1711 }
1712 }
1713
1714 void MainWindow::on_action_sample_properties() {
1715 //TODO: show a dialog where the selected sample's properties can be edited
1716 }
1717
1718 void MainWindow::on_action_add_group() {
1719 static int __sample_indexer = 0;
1720 if (!file) return;
1721 gig::Group* group = file->AddGroup();
1722 group->Name = "Unnamed Group";
1723 if (__sample_indexer) group->Name += " " + ToString(__sample_indexer);
1724 __sample_indexer++;
1725 // update sample tree view
1726 Gtk::TreeModel::iterator iterGroup = m_refSamplesTreeModel->append();
1727 Gtk::TreeModel::Row rowGroup = *iterGroup;
1728 rowGroup[m_SamplesModel.m_col_name] = group->Name.c_str();
1729 rowGroup[m_SamplesModel.m_col_sample] = NULL;
1730 rowGroup[m_SamplesModel.m_col_group] = group;
1731 }
1732
1733 void MainWindow::on_action_add_sample() {
1734 if (!file) return;
1735 // get selected group
1736 Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();
1737 Gtk::TreeModel::iterator it = sel->get_selected();
1738 if (!it) return;
1739 Gtk::TreeModel::Row row = *it;
1740 gig::Group* group = row[m_SamplesModel.m_col_group];
1741 if (!group) { // not a group, but a sample is selected (probably)
1742 gig::Sample* sample = row[m_SamplesModel.m_col_sample];
1743 if (!sample) return;
1744 it = row.parent(); // resolve parent (that is the sample's group)
1745 if (!it) return;
1746 row = *it;
1747 group = row[m_SamplesModel.m_col_group];
1748 if (!group) return;
1749 }
1750 // show 'browse for file' dialog
1751 Gtk::FileChooserDialog dialog(*this, _("Add Sample(s)"));
1752 dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1753 dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);
1754 dialog.set_select_multiple(true);
1755 Gtk::FileFilter soundfilter; // matches all file types supported by libsndfile
1756 const char* supportedFileTypes[] = {
1757 "*.wav", "*.WAV", "*.aiff", "*.AIFF", "*.aifc", "*.AIFC", "*.snd",
1758 "*.SND", "*.au", "*.AU", "*.paf", "*.PAF", "*.iff", "*.IFF",
1759 "*.svx", "*.SVX", "*.sf", "*.SF", "*.voc", "*.VOC", "*.w64",
1760 "*.W64", "*.pvf", "*.PVF", "*.xi", "*.XI", "*.htk", "*.HTK",
1761 "*.caf", "*.CAF", NULL
1762 };
1763 for (int i = 0; supportedFileTypes[i]; i++)
1764 soundfilter.add_pattern(supportedFileTypes[i]);
1765 soundfilter.set_name("Sound Files");
1766 Gtk::FileFilter allpassfilter; // matches every file
1767 allpassfilter.add_pattern("*.*");
1768 allpassfilter.set_name("All Files");
1769 dialog.add_filter(soundfilter);
1770 dialog.add_filter(allpassfilter);
1771 if (dialog.run() == Gtk::RESPONSE_OK) {
1772 Glib::ustring error_files;
1773 Glib::SListHandle<Glib::ustring> filenames = dialog.get_filenames();
1774 for (Glib::SListHandle<Glib::ustring>::iterator iter = filenames.begin(); iter != filenames.end(); ++iter) {
1775 printf("Adding sample %s\n",(*iter).c_str());
1776 // use libsndfile to retrieve file informations
1777 SF_INFO info;
1778 info.format = 0;
1779 SNDFILE* hFile = sf_open((*iter).c_str(), SFM_READ, &info);
1780 try {
1781 if (!hFile) throw std::string("could not open file");
1782 int bitdepth;
1783 switch (info.format & 0xff) {
1784 case SF_FORMAT_PCM_S8:
1785 bitdepth = 16; // we simply convert to 16 bit for now
1786 break;
1787 case SF_FORMAT_PCM_16:
1788 bitdepth = 16;
1789 break;
1790 case SF_FORMAT_PCM_24:
1791 bitdepth = 32; // we simply convert to 32 bit for now
1792 break;
1793 case SF_FORMAT_PCM_32:
1794 bitdepth = 32;
1795 break;
1796 case SF_FORMAT_PCM_U8:
1797 bitdepth = 16; // we simply convert to 16 bit for now
1798 break;
1799 case SF_FORMAT_FLOAT:
1800 bitdepth = 32;
1801 break;
1802 case SF_FORMAT_DOUBLE:
1803 bitdepth = 32; // I guess we will always truncate this to 32 bit
1804 break;
1805 default:
1806 sf_close(hFile); // close sound file
1807 throw std::string("format not supported"); // unsupported subformat (yet?)
1808 }
1809 // add a new sample to the .gig file
1810 gig::Sample* sample = file->AddSample();
1811 sample->pInfo->Name = (*iter).substr((*iter).rfind('/') + 1).raw(); // file name without path
1812 sample->Channels = info.channels;
1813 sample->BitDepth = bitdepth;
1814 sample->FrameSize = bitdepth / 8/*1 byte are 8 bits*/ * info.channels;
1815 sample->SamplesPerSecond = info.samplerate;
1816 // schedule resizing the sample (which will be done physically when File::Save() is called)
1817 sample->Resize(info.frames);
1818 // make sure sample is part of the selected group
1819 group->AddSample(sample);
1820 // schedule that physical resize and sample import (data copying), performed when "Save" is requested
1821 SampleImportItem sched_item;
1822 sched_item.gig_sample = sample;
1823 sched_item.sample_path = *iter;
1824 m_SampleImportQueue.push_back(sched_item);
1825 // add sample to the tree view
1826 Gtk::TreeModel::iterator iterSample = m_refSamplesTreeModel->append(row.children());
1827 Gtk::TreeModel::Row rowSample = *iterSample;
1828 rowSample[m_SamplesModel.m_col_name] = sample->pInfo->Name.c_str();
1829 rowSample[m_SamplesModel.m_col_sample] = sample;
1830 rowSample[m_SamplesModel.m_col_group] = NULL;
1831 // close sound file
1832 sf_close(hFile);
1833 } catch (std::string what) { // remember the files that made trouble (and their cause)
1834 if (error_files.size()) error_files += "\n";
1835 error_files += *iter += " (" + what + ")";
1836 }
1837 }
1838 // show error message box when some file(s) could not be opened / added
1839 if (error_files.size()) {
1840 Glib::ustring txt = "Could not add the following sample(s):\n" + error_files;
1841 Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
1842 msg.run();
1843 }
1844 }
1845 }
1846
1847 void MainWindow::on_action_remove_sample() {
1848 if (!file) return;
1849 Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();
1850 Gtk::TreeModel::iterator it = sel->get_selected();
1851 if (it) {
1852 Gtk::TreeModel::Row row = *it;
1853 gig::Group* group = row[m_SamplesModel.m_col_group];
1854 gig::Sample* sample = row[m_SamplesModel.m_col_sample];
1855 Glib::ustring name = row[m_SamplesModel.m_col_name];
1856 try {
1857 // remove group or sample from the gig file
1858 if (group) {
1859 // temporarily remember the samples that bolong to that group (we need that to clean the queue)
1860 std::list<gig::Sample*> members;
1861 for (gig::Sample* pSample = group->GetFirstSample(); pSample; pSample = group->GetNextSample()) {
1862 members.push_back(pSample);
1863 }
1864 // delete the group in the .gig file including the samples that belong to the group
1865 file->DeleteGroup(group);
1866 // if sample(s) were just previously added, remove them from the import queue
1867 for (std::list<gig::Sample*>::iterator member = members.begin(); member != members.end(); ++member) {
1868 for (std::list<SampleImportItem>::iterator iter = m_SampleImportQueue.begin(); iter != m_SampleImportQueue.end(); ++iter) {
1869 if ((*iter).gig_sample == *member) {
1870 printf("Removing previously added sample '%s' from group '%s'\n", (*iter).sample_path.c_str(), name.c_str());
1871 m_SampleImportQueue.erase(iter);
1872 break;
1873 }
1874 }
1875 }
1876 } else if (sample) {
1877 // remove sample from the .gig file
1878 file->DeleteSample(sample);
1879 // if sample was just previously added, remove it from the import queue
1880 for (std::list<SampleImportItem>::iterator iter = m_SampleImportQueue.begin(); iter != m_SampleImportQueue.end(); ++iter) {
1881 if ((*iter).gig_sample == sample) {
1882 printf("Removing previously added sample '%s'\n", (*iter).sample_path.c_str());
1883 m_SampleImportQueue.erase(iter);
1884 break;
1885 }
1886 }
1887 }
1888 // remove respective row(s) from samples tree view
1889 m_refSamplesTreeModel->erase(it);
1890 } catch (RIFF::Exception e) {
1891 Gtk::MessageDialog msg(*this, e.Message.c_str(), false, Gtk::MESSAGE_ERROR);
1892 msg.run();
1893 }
1894 }
1895 }

  ViewVC Help
Powered by ViewVC