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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1087 - (show annotations) (download)
Fri Mar 9 19:45:45 2007 UTC (17 years, 1 month ago) by schoenebeck
File size: 67998 byte(s)
* coarsely finished 'Sample Add' feature: works non-destructive, that is
  samples are just queued to be imported and the heavy task of resizing the
  .gig file physically and importing the sample data is done when 'Save' is
  issued (Note however: unfortunately it seems to crash yet when calling
  'Save')

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_TreeViewNotebook);
538 m_ScrolledWindow.set_size_request(400, 600);
539 m_ScrolledWindow.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
540
541 for (int i = 0 ; i < 5 ; i++) {
542 table[i] = new Gtk::Table(3, 1);
543 table[i]->set_col_spacings(5);
544 }
545
546 pageno = 0;
547 rowno = 0;
548 firstRowInBlock = 0;
549
550 addString("Sample", lSample, wSample);
551 addProp(eVelocityUpperLimit);
552 addHeader("EG1");
553 addProp(eEG1PreAttack);
554 addProp(eEG1Attack);
555 addProp(eEG1Decay1);
556 addProp(eEG1Decay2);
557 addProp(eEG1InfiniteSustain);
558 addProp(eEG1Sustain);
559 addProp(eEG1Release);
560 addProp(eEG1Hold);
561 addProp(eEG1Controller);
562 addProp(eEG1ControllerInvert);
563 addProp(eEG1ControllerAttackInfluence);
564 addProp(eEG1ControllerDecayInfluence);
565 addProp(eEG1ControllerReleaseInfluence);
566 addHeader("LFO1");
567 addProp(eLFO1Frequency);
568 addProp(eLFO1InternalDepth);
569 addProp(eLFO1ControlDepth);
570 {
571 char* choices[] = { "internal", "modwheel", "breath",
572 "internal+modwheel", "internal+breath", 0 };
573 static const gig::lfo1_ctrl_t values[] = {
574 gig::lfo1_ctrl_internal,
575 gig::lfo1_ctrl_modwheel,
576 gig::lfo1_ctrl_breath,
577 gig::lfo1_ctrl_internal_modwheel,
578 gig::lfo1_ctrl_internal_breath
579 };
580 eLFO1Controller.set_choices(choices, values);
581 }
582 addProp(eLFO1Controller);
583 addProp(eLFO1FlipPhase);
584 addProp(eLFO1Sync);
585
586 nextPage();
587 addHeader("EG2");
588 addProp(eEG2PreAttack);
589 addProp(eEG2Attack);
590 addProp(eEG2Decay1);
591 addProp(eEG2Decay2);
592 addProp(eEG2InfiniteSustain);
593 addProp(eEG2Sustain);
594 addProp(eEG2Release);
595 addProp(eEG2Controller);
596 addProp(eEG2ControllerInvert);
597 addProp(eEG2ControllerAttackInfluence);
598 addProp(eEG2ControllerDecayInfluence);
599 addProp(eEG2ControllerReleaseInfluence);
600 addHeader("LFO2");
601 addProp(eLFO2Frequency);
602 addProp(eLFO2InternalDepth);
603 addProp(eLFO2ControlDepth);
604 {
605 char* choices[] = { "internal", "modwheel", "foot",
606 "internal+modwheel", "internal+foot", 0 };
607 static const gig::lfo2_ctrl_t values[] = {
608 gig::lfo2_ctrl_internal,
609 gig::lfo2_ctrl_modwheel,
610 gig::lfo2_ctrl_foot,
611 gig::lfo2_ctrl_internal_modwheel,
612 gig::lfo2_ctrl_internal_foot
613 };
614 eLFO2Controller.set_choices(choices, values);
615 }
616 addProp(eLFO2Controller);
617 addProp(eLFO2FlipPhase);
618 addProp(eLFO2Sync);
619
620 nextPage();
621
622 addHeader("EG3");
623 addProp(eEG3Attack);
624 addProp(eEG3Depth);
625 addHeader("LFO3");
626 addProp(eLFO3Frequency);
627 addProp(eLFO3InternalDepth);
628 addProp(eLFO3ControlDepth);
629 {
630 char* choices[] = { "internal", "modwheel", "aftertouch",
631 "internal+modwheel", "internal+aftertouch", 0 };
632 static const gig::lfo3_ctrl_t values[] = {
633 gig::lfo3_ctrl_internal,
634 gig::lfo3_ctrl_modwheel,
635 gig::lfo3_ctrl_aftertouch,
636 gig::lfo3_ctrl_internal_modwheel,
637 gig::lfo3_ctrl_internal_aftertouch
638 };
639 eLFO3Controller.set_choices(choices, values);
640 }
641 addProp(eLFO3Controller);
642 addProp(eLFO3Sync);
643 addHeader("VCF");
644 addProp(eVCFEnabled);
645 {
646 char* choices[] = { "lowpass", "lowpassturbo", "bandpass",
647 "highpass", "bandreject", 0 };
648 static const gig::vcf_type_t values[] = {
649 gig::vcf_type_lowpass,
650 gig::vcf_type_lowpassturbo,
651 gig::vcf_type_bandpass,
652 gig::vcf_type_highpass,
653 gig::vcf_type_bandreject
654 };
655 eVCFType.set_choices(choices, values);
656 }
657 addProp(eVCFType);
658 {
659 char* choices[] = { "none", "none2", "modwheel", "effect1", "effect2",
660 "breath", "foot", "sustainpedal", "softpedal",
661 "genpurpose7", "genpurpose8", "aftertouch", 0 };
662 static const gig::vcf_cutoff_ctrl_t values[] = {
663 gig::vcf_cutoff_ctrl_none,
664 gig::vcf_cutoff_ctrl_none2,
665 gig::vcf_cutoff_ctrl_modwheel,
666 gig::vcf_cutoff_ctrl_effect1,
667 gig::vcf_cutoff_ctrl_effect2,
668 gig::vcf_cutoff_ctrl_breath,
669 gig::vcf_cutoff_ctrl_foot,
670 gig::vcf_cutoff_ctrl_sustainpedal,
671 gig::vcf_cutoff_ctrl_softpedal,
672 gig::vcf_cutoff_ctrl_genpurpose7,
673 gig::vcf_cutoff_ctrl_genpurpose8,
674 gig::vcf_cutoff_ctrl_aftertouch
675 };
676 eVCFCutoffController.set_choices(choices, values);
677 }
678 addProp(eVCFCutoffController);
679 addProp(eVCFCutoffControllerInvert);
680 addProp(eVCFCutoff);
681 char* curve_type_texts[] = { "nonlinear", "linear", "special", 0 };
682 static const gig::curve_type_t curve_type_values[] = {
683 gig::curve_type_nonlinear,
684 gig::curve_type_linear,
685 gig::curve_type_special
686 };
687 eVCFVelocityCurve.set_choices(curve_type_texts, curve_type_values);
688 addProp(eVCFVelocityCurve);
689 addProp(eVCFVelocityScale);
690 addProp(eVCFVelocityDynamicRange);
691 addProp(eVCFResonance);
692 addProp(eVCFResonanceDynamic);
693 {
694 char* choices[] = { "none", "genpurpose3", "genpurpose4",
695 "genpurpose5", "genpurpose6", 0 };
696 static const gig::vcf_res_ctrl_t values[] = {
697 gig::vcf_res_ctrl_none,
698 gig::vcf_res_ctrl_genpurpose3,
699 gig::vcf_res_ctrl_genpurpose4,
700 gig::vcf_res_ctrl_genpurpose5,
701 gig::vcf_res_ctrl_genpurpose6
702 };
703 eVCFResonanceController.set_choices(choices, values);
704 }
705 addProp(eVCFResonanceController);
706 addProp(eVCFKeyboardTracking);
707 addProp(eVCFKeyboardTrackingBreakpoint);
708
709 nextPage();
710
711 eVelocityResponseCurve.set_choices(curve_type_texts, curve_type_values);
712 addProp(eVelocityResponseCurve);
713 addProp(eVelocityResponseDepth);
714 addProp(eVelocityResponseCurveScaling);
715 eReleaseVelocityResponseCurve.set_choices(curve_type_texts,
716 curve_type_values);
717 addProp(eReleaseVelocityResponseCurve);
718 addProp(eReleaseVelocityResponseDepth);
719 addProp(eReleaseTriggerDecay);
720 addProp(eCrossfade_in_start);
721 addProp(eCrossfade_in_end);
722 addProp(eCrossfade_out_start);
723 addProp(eCrossfade_out_end);
724 addProp(ePitchTrack);
725 {
726 char* choices[] = { "none", "effect4depth", "effect5depth", 0 };
727 static const gig::dim_bypass_ctrl_t values[] = {
728 gig::dim_bypass_ctrl_none,
729 gig::dim_bypass_ctrl_94,
730 gig::dim_bypass_ctrl_95
731 };
732 eDimensionBypass.set_choices(choices, values);
733 }
734 addProp(eDimensionBypass);
735 addProp(ePan);
736 addProp(eSelfMask);
737 addProp(eAttenuationController);
738 addProp(eInvertAttenuationController);
739 addProp(eAttenuationControllerThreshold);
740 addProp(eChannelOffset);
741 addProp(eSustainDefeat);
742
743 nextPage();
744 addProp(eMSDecode);
745 addProp(eSampleStartOffset);
746 addProp(eUnityNote);
747 addProp(eFineTune);
748 addProp(eGain);
749 addProp(eSampleLoops);
750 nextPage();
751
752 eEG1InfiniteSustain.signal_toggled().connect(
753 sigc::mem_fun(*this, &MainWindow::EG1InfiniteSustain_toggled) );
754 eEG2InfiniteSustain.signal_toggled().connect(
755 sigc::mem_fun(*this, &MainWindow::EG2InfiniteSustain_toggled) );
756 eEG1Controller.signal_changed().connect(
757 sigc::mem_fun(*this, &MainWindow::EG1Controller_changed) );
758 eEG2Controller.signal_changed().connect(
759 sigc::mem_fun(*this, &MainWindow::EG2Controller_changed) );
760 eLFO1Controller.signal_changed().connect(
761 sigc::mem_fun(*this, &MainWindow::LFO1Controller_changed) );
762 eLFO2Controller.signal_changed().connect(
763 sigc::mem_fun(*this, &MainWindow::LFO2Controller_changed) );
764 eLFO3Controller.signal_changed().connect(
765 sigc::mem_fun(*this, &MainWindow::LFO3Controller_changed) );
766 eAttenuationController.signal_changed().connect(
767 sigc::mem_fun(*this, &MainWindow::AttenuationController_changed) );
768 eVCFEnabled.signal_toggled().connect(
769 sigc::mem_fun(*this, &MainWindow::VCFEnabled_toggled) );
770 eVCFCutoffController.signal_changed().connect(
771 sigc::mem_fun(*this, &MainWindow::VCFCutoffController_changed) );
772 eVCFResonanceController.signal_changed().connect(
773 sigc::mem_fun(*this, &MainWindow::VCFResonanceController_changed) );
774
775 eCrossfade_in_start.signal_value_changed().connect(
776 sigc::mem_fun(*this, &MainWindow::crossfade1_changed));
777 eCrossfade_in_end.signal_value_changed().connect(
778 sigc::mem_fun(*this, &MainWindow::crossfade2_changed));
779 eCrossfade_out_start.signal_value_changed().connect(
780 sigc::mem_fun(*this, &MainWindow::crossfade3_changed));
781 eCrossfade_out_end.signal_value_changed().connect(
782 sigc::mem_fun(*this, &MainWindow::crossfade4_changed));
783
784 //m_Notebook.append_page(m_ScrolledWindow2, "Table");
785 m_Notebook.append_page(*table[0], "EG1");
786 m_Notebook.append_page(*table[1], "EG2");
787 m_Notebook.append_page(*table[2], "EG3");
788 m_Notebook.append_page(*table[3], "Velocity");
789 m_Notebook.append_page(*table[4], "Misc");
790 m_Notebook.set_size_request(400, 500);
791
792 m_HPaned.add1(m_ScrolledWindow);
793 m_HPaned.add2(m_Notebook);
794
795
796 m_TreeViewNotebook.append_page(m_TreeViewSamples, "Samples");
797 m_TreeViewNotebook.append_page(m_TreeView, "Instruments");
798
799
800 actionGroup = Gtk::ActionGroup::create();
801
802 actionGroup->add(Gtk::Action::create("MenuFile", _("_File")));
803 actionGroup->add(Gtk::Action::create("New", Gtk::Stock::NEW),
804 sigc::mem_fun(
805 *this, &MainWindow::on_action_file_new));
806 Glib::RefPtr<Gtk::Action> action =
807 Gtk::Action::create("Open", Gtk::Stock::OPEN);
808 action->property_label() = action->property_label() + "...";
809 actionGroup->add(action,
810 sigc::mem_fun(
811 *this, &MainWindow::on_action_file_open));
812 actionGroup->add(Gtk::Action::create("Save", Gtk::Stock::SAVE),
813 sigc::mem_fun(
814 *this, &MainWindow::on_action_file_save));
815 action = Gtk::Action::create("SaveAs", Gtk::Stock::SAVE_AS);
816 action->property_label() = action->property_label() + "...";
817 actionGroup->add(action,
818 *(new Gtk::AccelKey("<shift><control>s")),
819 sigc::mem_fun(
820 *this, &MainWindow::on_action_file_save_as)
821 );
822 actionGroup->add(Gtk::Action::create("Properties",
823 Gtk::Stock::PROPERTIES),
824 sigc::mem_fun(
825 *this, &MainWindow::on_action_file_properties));
826 actionGroup->add(Gtk::Action::create("InstrProperties",
827 Gtk::Stock::PROPERTIES),
828 sigc::mem_fun(
829 *this, &MainWindow::on_action_file_properties));
830 actionGroup->add(Gtk::Action::create("Quit", Gtk::Stock::QUIT),
831 sigc::mem_fun(
832 *this, &MainWindow::hide));
833 actionGroup->add(Gtk::Action::create("MenuInstrument", _("_Instrument")));
834
835 action = Gtk::Action::create("MenuHelp", Gtk::Stock::HELP);
836 actionGroup->add(Gtk::Action::create("MenuHelp",
837 action->property_label()));
838 #ifdef ABOUT_DIALOG
839 actionGroup->add(Gtk::Action::create("About", Gtk::Stock::ABOUT),
840 sigc::mem_fun(
841 *this, &MainWindow::on_action_help_about));
842 #endif
843 action = Gtk::Action::create("Remove", Gtk::Stock::REMOVE);
844 actionGroup->add(action,
845 sigc::mem_fun(
846 *this, &MainWindow::hide));
847
848 // sample right-click popup actions
849 actionGroup->add(
850 Gtk::Action::create("SampleProperties", Gtk::Stock::PROPERTIES),
851 sigc::mem_fun(*this, &MainWindow::on_action_sample_properties)
852 );
853 actionGroup->add(
854 Gtk::Action::create("AddGroup", _("Add _Group")),
855 sigc::mem_fun(*this, &MainWindow::on_action_add_group)
856 );
857 actionGroup->add(
858 Gtk::Action::create("AddSample", _("Add _Sample(s)")),
859 sigc::mem_fun(*this, &MainWindow::on_action_add_sample)
860 );
861 actionGroup->add(
862 Gtk::Action::create("RemoveSample", Gtk::Stock::REMOVE),
863 sigc::mem_fun(*this, &MainWindow::on_action_remove_sample)
864 );
865
866 uiManager = Gtk::UIManager::create();
867 uiManager->insert_action_group(actionGroup);
868 // add_accel_group(uiManager->get_accel_group());
869
870 Glib::ustring ui_info =
871 "<ui>"
872 " <menubar name='MenuBar'>"
873 " <menu action='MenuFile'>"
874 " <menuitem action='New'/>"
875 " <menuitem action='Open'/>"
876 " <separator/>"
877 " <menuitem action='Save'/>"
878 " <menuitem action='SaveAs'/>"
879 " <separator/>"
880 " <menuitem action='Properties'/>"
881 " <separator/>"
882 " <menuitem action='Quit'/>"
883 " </menu>"
884 " <menu action='MenuInstrument'>"
885 " </menu>"
886 #ifdef ABOUT_DIALOG
887 " <menu action='MenuHelp'>"
888 " <menuitem action='About'/>"
889 " </menu>"
890 #endif
891 " </menubar>"
892 " <popup name='PopupMenu'>"
893 " <menuitem action='InstrProperties'/>"
894 " <menuitem action='Remove'/>"
895 " </popup>"
896 " <popup name='SamplePopupMenu'>"
897 " <menuitem action='SampleProperties'/>"
898 " <menuitem action='AddGroup'/>"
899 " <menuitem action='AddSample'/>"
900 " <separator/>"
901 " <menuitem action='RemoveSample'/>"
902 " </popup>"
903 "</ui>";
904 uiManager->add_ui_from_string(ui_info);
905
906 popup_menu = dynamic_cast<Gtk::Menu*>(uiManager->get_widget("/PopupMenu"));
907
908 Gtk::Widget* menuBar = uiManager->get_widget("/MenuBar");
909 m_VBox.pack_start(*menuBar, Gtk::PACK_SHRINK);
910 m_VBox.pack_start(m_HPaned);
911 m_VBox.pack_start(m_RegionChooser, Gtk::PACK_SHRINK);
912 m_VBox.pack_start(m_DimRegionChooser, Gtk::PACK_SHRINK);
913
914 m_RegionChooser.signal_sel_changed().connect(
915 sigc::mem_fun(*this, &MainWindow::region_changed) );
916 m_DimRegionChooser.signal_sel_changed().connect(
917 sigc::mem_fun(*this, &MainWindow::dimreg_changed) );
918
919
920 // Create the Tree model:
921 m_refTreeModel = Gtk::ListStore::create(m_Columns);
922 m_TreeView.set_model(m_refTreeModel);
923
924 // Add the TreeView's view columns:
925 m_TreeView.append_column("Instrument", m_Columns.m_col_name);
926 m_TreeView.set_headers_visible(false);
927
928 // create samples treeview (including its data model)
929 m_refSamplesTreeModel = Gtk::TreeStore::create(m_SamplesModel);
930 m_TreeViewSamples.set_model(m_refSamplesTreeModel);
931 m_TreeViewSamples.append_column("Samples", m_SamplesModel.m_col_name);
932 m_TreeViewSamples.set_headers_visible(false);
933 m_TreeViewSamples.signal_button_press_event().connect_notify(
934 sigc::mem_fun(*this, &MainWindow::on_sample_treeview_button_release)
935 );
936
937 file = 0;
938
939 show_all_children();
940 }
941
942 MainWindow::~MainWindow()
943 {
944 }
945
946 void MainWindow::region_changed()
947 {
948 m_DimRegionChooser.set_region(m_RegionChooser.get_region());
949 }
950
951 void MainWindow::dimreg_changed()
952 {
953 set_dim_region(m_DimRegionChooser.get_dimregion());
954 }
955
956 void MainWindow::on_sel_change()
957 {
958 Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();
959
960 Gtk::TreeModel::iterator it = tree_sel_ref->get_selected();
961 if (it)
962 {
963 Gtk::TreeModel::Row row = *it;
964 std::cout << row[m_Columns.m_col_name] << std::endl;
965
966 if (row[m_Columns.m_col_instr])
967 m_RegionChooser.set_instrument(row[m_Columns.m_col_instr]);
968 }
969 }
970
971 void MainWindow::set_dim_region(gig::DimensionRegion* d)
972 {
973 update_gui = false;
974 wSample->set_text(d->pSample ? d->pSample->pInfo->Name.c_str() : "NULL");
975 eVelocityUpperLimit.set_dimreg(d);
976 eEG1PreAttack.set_dimreg(d);
977 eEG1Attack.set_dimreg(d);
978 eEG1Decay1.set_dimreg(d);
979 eEG1Decay2.set_dimreg(d);
980 eEG1InfiniteSustain.set_dimreg(d);
981 eEG1Sustain.set_dimreg(d);
982 eEG1Release.set_dimreg(d);
983 eEG1Hold.set_dimreg(d);
984 eEG1Controller.set_dimreg(d);
985 eEG1ControllerInvert.set_dimreg(d);
986 eEG1ControllerAttackInfluence.set_dimreg(d);
987 eEG1ControllerDecayInfluence.set_dimreg(d);
988 eEG1ControllerReleaseInfluence.set_dimreg(d);
989 eLFO1Frequency.set_dimreg(d);
990 eLFO1InternalDepth.set_dimreg(d);
991 eLFO1ControlDepth.set_dimreg(d);
992 eLFO1Controller.set_dimreg(d);
993 eLFO1FlipPhase.set_dimreg(d);
994 eLFO1Sync.set_dimreg(d);
995 eEG2PreAttack.set_dimreg(d);
996 eEG2Attack.set_dimreg(d);
997 eEG2Decay1.set_dimreg(d);
998 eEG2Decay2.set_dimreg(d);
999 eEG2InfiniteSustain.set_dimreg(d);
1000 eEG2Sustain.set_dimreg(d);
1001 eEG2Release.set_dimreg(d);
1002 eEG2Controller.set_dimreg(d);
1003 eEG2ControllerInvert.set_dimreg(d);
1004 eEG2ControllerAttackInfluence.set_dimreg(d);
1005 eEG2ControllerDecayInfluence.set_dimreg(d);
1006 eEG2ControllerReleaseInfluence.set_dimreg(d);
1007 eLFO2Frequency.set_dimreg(d);
1008 eLFO2InternalDepth.set_dimreg(d);
1009 eLFO2ControlDepth.set_dimreg(d);
1010 eLFO2Controller.set_dimreg(d);
1011 eLFO2FlipPhase.set_dimreg(d);
1012 eLFO2Sync.set_dimreg(d);
1013 eEG3Attack.set_dimreg(d);
1014 eEG3Depth.set_dimreg(d);
1015 eLFO3Frequency.set_dimreg(d);
1016 eLFO3InternalDepth.set_dimreg(d);
1017 eLFO3ControlDepth.set_dimreg(d);
1018 eLFO3Controller.set_dimreg(d);
1019 eLFO3Sync.set_dimreg(d);
1020 eVCFEnabled.set_dimreg(d);
1021 eVCFType.set_dimreg(d);
1022 eVCFCutoffController.set_dimreg(d);
1023 eVCFCutoffControllerInvert.set_dimreg(d);
1024 eVCFCutoff.set_dimreg(d);
1025 eVCFVelocityCurve.set_dimreg(d);
1026 eVCFVelocityScale.set_dimreg(d);
1027 eVCFVelocityDynamicRange.set_dimreg(d);
1028 eVCFResonance.set_dimreg(d);
1029 eVCFResonanceDynamic.set_dimreg(d);
1030 eVCFResonanceController.set_dimreg(d);
1031 eVCFKeyboardTracking.set_dimreg(d);
1032 eVCFKeyboardTrackingBreakpoint.set_dimreg(d);
1033 eVelocityResponseCurve.set_dimreg(d);
1034 eVelocityResponseDepth.set_dimreg(d);
1035 eVelocityResponseCurveScaling.set_dimreg(d);
1036 eReleaseVelocityResponseCurve.set_dimreg(d);
1037 eReleaseVelocityResponseDepth.set_dimreg(d);
1038 eReleaseTriggerDecay.set_dimreg(d);
1039 eCrossfade_in_start.set_dimreg(d);
1040 eCrossfade_in_end.set_dimreg(d);
1041 eCrossfade_out_start.set_dimreg(d);
1042 eCrossfade_out_end.set_dimreg(d);
1043 ePitchTrack.set_dimreg(d);
1044 eDimensionBypass.set_dimreg(d);
1045 ePan.set_dimreg(d);
1046 eSelfMask.set_dimreg(d);
1047 eAttenuationController.set_dimreg(d);
1048 eInvertAttenuationController.set_dimreg(d);
1049 eAttenuationControllerThreshold.set_dimreg(d);
1050 eChannelOffset.set_dimreg(d);
1051 eSustainDefeat.set_dimreg(d);
1052 eMSDecode.set_dimreg(d);
1053 eSampleStartOffset.set_dimreg(d);
1054 eUnityNote.set_dimreg(d);
1055 eFineTune.set_dimreg(d);
1056 eGain.set_dimreg(d);
1057 eSampleLoops.set_dimreg(d);
1058
1059 VCFEnabled_toggled();
1060
1061 update_gui = true;
1062 }
1063
1064 void MainWindow::VCFEnabled_toggled()
1065 {
1066 bool sensitive = eVCFEnabled.get_active();
1067 eVCFType.set_sensitive(sensitive);
1068 eVCFCutoffController.set_sensitive(sensitive);
1069 eVCFVelocityCurve.set_sensitive(sensitive);
1070 eVCFVelocityScale.set_sensitive(sensitive);
1071 eVCFVelocityDynamicRange.set_sensitive(sensitive);
1072 eVCFResonance.set_sensitive(sensitive);
1073 eVCFResonanceController.set_sensitive(sensitive);
1074 eVCFKeyboardTracking.set_sensitive(sensitive);
1075 eVCFKeyboardTrackingBreakpoint.set_sensitive(sensitive);
1076 eEG2PreAttack.set_sensitive(sensitive);
1077 eEG2Attack.set_sensitive(sensitive);
1078 eEG2Decay1.set_sensitive(sensitive);
1079 eEG2InfiniteSustain.set_sensitive(sensitive);
1080 eEG2Sustain.set_sensitive(sensitive);
1081 eEG2Release.set_sensitive(sensitive);
1082 eEG2Controller.set_sensitive(sensitive);
1083 eEG2ControllerAttackInfluence.set_sensitive(sensitive);
1084 eEG2ControllerDecayInfluence.set_sensitive(sensitive);
1085 eEG2ControllerReleaseInfluence.set_sensitive(sensitive);
1086 eLFO2Frequency.set_sensitive(sensitive);
1087 eLFO2InternalDepth.set_sensitive(sensitive);
1088 eLFO2ControlDepth.set_sensitive(sensitive);
1089 eLFO2Controller.set_sensitive(sensitive);
1090 eLFO2FlipPhase.set_sensitive(sensitive);
1091 eLFO2Sync.set_sensitive(sensitive);
1092 if (sensitive) {
1093 VCFCutoffController_changed();
1094 VCFResonanceController_changed();
1095 EG2InfiniteSustain_toggled();
1096 EG2Controller_changed();
1097 LFO2Controller_changed();
1098 } else {
1099 eVCFCutoffControllerInvert.set_sensitive(false);
1100 eVCFCutoff.set_sensitive(false);
1101 eVCFResonanceDynamic.set_sensitive(false);
1102 eVCFResonance.set_sensitive(false);
1103 eEG2Decay2.set_sensitive(false);
1104 eEG2ControllerInvert.set_sensitive(false);
1105 eLFO2InternalDepth.set_sensitive(false);
1106 eLFO2ControlDepth.set_sensitive(false);
1107 }
1108 }
1109
1110 void MainWindow::VCFCutoffController_changed()
1111 {
1112 int rowno = eVCFCutoffController.get_active_row_number();
1113 bool hasController = rowno != 0 && rowno != 1;
1114
1115 eVCFCutoffControllerInvert.set_sensitive(hasController);
1116 eVCFCutoff.set_sensitive(!hasController);
1117 eVCFResonanceDynamic.set_sensitive(!hasController);
1118 eVCFVelocityScale.label.set_text(hasController ? "MinimumCutoff:" :
1119 "VelocityScale:");
1120 }
1121
1122 void MainWindow::VCFResonanceController_changed()
1123 {
1124 bool hasController = eVCFResonanceController.get_active_row_number() != 0;
1125 eVCFResonance.set_sensitive(!hasController);
1126 }
1127
1128 void MainWindow::EG1InfiniteSustain_toggled()
1129 {
1130 bool infSus = eEG1InfiniteSustain.get_active();
1131 eEG1Decay2.set_sensitive(!infSus);
1132 }
1133
1134 void MainWindow::EG2InfiniteSustain_toggled()
1135 {
1136 bool infSus = eEG2InfiniteSustain.get_active();
1137 eEG2Decay2.set_sensitive(!infSus);
1138 }
1139
1140 void MainWindow::EG1Controller_changed()
1141 {
1142 bool hasController = eEG1Controller.get_active_row_number() != 0;
1143 eEG1ControllerInvert.set_sensitive(hasController);
1144 }
1145
1146 void MainWindow::EG2Controller_changed()
1147 {
1148 bool hasController = eEG2Controller.get_active_row_number() != 0;
1149 eEG2ControllerInvert.set_sensitive(hasController);
1150 }
1151
1152 void MainWindow::AttenuationController_changed()
1153 {
1154 bool hasController = eAttenuationController.get_active_row_number() != 0;
1155 eInvertAttenuationController.set_sensitive(hasController);
1156 }
1157
1158 void MainWindow::LFO1Controller_changed()
1159 {
1160 int rowno = eLFO1Controller.get_active_row_number();
1161 eLFO1ControlDepth.set_sensitive(rowno != 0);
1162 eLFO1InternalDepth.set_sensitive(rowno != 1 && rowno != 2);
1163 }
1164
1165 void MainWindow::LFO2Controller_changed()
1166 {
1167 int rowno = eLFO2Controller.get_active_row_number();
1168 eLFO2ControlDepth.set_sensitive(rowno != 0);
1169 eLFO2InternalDepth.set_sensitive(rowno != 1 && rowno != 2);
1170 }
1171
1172 void MainWindow::LFO3Controller_changed()
1173 {
1174 int rowno = eLFO3Controller.get_active_row_number();
1175 eLFO3ControlDepth.set_sensitive(rowno != 0);
1176 eLFO3InternalDepth.set_sensitive(rowno != 1 && rowno != 2);
1177 }
1178
1179 void MainWindow::crossfade1_changed()
1180 {
1181 double c1 = eCrossfade_in_start.get_value();
1182 double c2 = eCrossfade_in_end.get_value();
1183 if (c1 > c2) eCrossfade_in_end.set_value(c1);
1184 }
1185
1186 void MainWindow::crossfade2_changed()
1187 {
1188 double c1 = eCrossfade_in_start.get_value();
1189 double c2 = eCrossfade_in_end.get_value();
1190 double c3 = eCrossfade_out_start.get_value();
1191
1192 if (c2 < c1) eCrossfade_in_start.set_value(c2);
1193 if (c2 > c3) eCrossfade_out_start.set_value(c2);
1194 }
1195
1196 void MainWindow::crossfade3_changed()
1197 {
1198 double c2 = eCrossfade_in_end.get_value();
1199 double c3 = eCrossfade_out_start.get_value();
1200 double c4 = eCrossfade_out_end.get_value();
1201
1202 if (c3 < c2) eCrossfade_in_end.set_value(c3);
1203 if (c3 > c4) eCrossfade_out_end.set_value(c3);
1204 }
1205
1206 void MainWindow::crossfade4_changed()
1207 {
1208 double c3 = eCrossfade_out_start.get_value();
1209 double c4 = eCrossfade_out_end.get_value();
1210
1211 if (c4 < c3) eCrossfade_out_start.set_value(c4);
1212 }
1213
1214 void loader_progress_callback(gig::progress_t* progress)
1215 {
1216 Loader* loader = static_cast<Loader*>(progress->custom);
1217 loader->progress_callback(progress->factor);
1218 }
1219
1220 void Loader::progress_callback(float fraction)
1221 {
1222 {
1223 Glib::Mutex::Lock lock(progressMutex);
1224 progress = fraction;
1225 }
1226 progress_dispatcher();
1227 }
1228
1229 void Loader::thread_function()
1230 {
1231 printf("thread_function self=%x\n", Glib::Thread::self());
1232 printf("Start %s\n", filename);
1233 RIFF::File* riff = new RIFF::File(filename);
1234 gig = new gig::File(riff);
1235 gig::progress_t progress;
1236 progress.callback = loader_progress_callback;
1237 progress.custom = this;
1238
1239 gig->GetInstrument(0, &progress);
1240 printf("End\n");
1241 finished_dispatcher();
1242 }
1243
1244 Loader::Loader(const char* filename)
1245 : thread(0), filename(filename)
1246 {
1247 }
1248
1249 void Loader::launch()
1250 {
1251 thread = Glib::Thread::create(sigc::mem_fun(*this, &Loader::thread_function), true);
1252 printf("launch thread=%x\n", thread);
1253 }
1254
1255 float Loader::get_progress()
1256 {
1257 float res;
1258 {
1259 Glib::Mutex::Lock lock(progressMutex);
1260 res = progress;
1261 }
1262 return res;
1263 }
1264
1265 Glib::Dispatcher& Loader::signal_progress()
1266 {
1267 return progress_dispatcher;
1268 }
1269
1270 Glib::Dispatcher& Loader::signal_finished()
1271 {
1272 return finished_dispatcher;
1273 }
1274
1275 LoadDialog::LoadDialog()
1276 {
1277 get_vbox()->pack_start(progressBar);
1278 show_all_children();
1279 }
1280
1281 void MainWindow::on_action_file_new()
1282 {
1283 m_SampleImportQueue.clear();
1284 }
1285
1286 void MainWindow::on_action_file_open()
1287 {
1288 Gtk::FileChooserDialog dialog(*this, _("Open file"));
1289 dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1290 dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);
1291 Gtk::FileFilter filter;
1292 filter.add_pattern("*.gig");
1293 dialog.set_filter(filter);
1294 if (dialog.run() == Gtk::RESPONSE_OK) {
1295 printf("filename=%s\n", dialog.get_filename().c_str());
1296
1297 // remove all entries from "Instrument" menu
1298 Gtk::MenuItem* instrument_menu =
1299 dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/MenuBar/MenuInstrument"));
1300 instrument_menu->hide();
1301 for (int i = 0; i < instrument_menu->get_submenu()->items().size(); i++) {
1302 delete &instrument_menu->get_submenu()->items()[i];
1303 }
1304 instrument_menu->get_submenu()->items().clear();
1305
1306 m_SampleImportQueue.clear();
1307 m_refTreeModel->clear();
1308 m_refSamplesTreeModel->clear();
1309 if (file) delete file;
1310
1311 // getInfo(dialog.get_filename().c_str(), *this);
1312
1313 printf("on_action_file_open self=%x\n", Glib::Thread::self());
1314 load_dialog = new LoadDialog(); // Gtk::Dialog("Loading...", *this, true);
1315 load_dialog->show_all();
1316 loader = new Loader(strdup(dialog.get_filename().c_str()));
1317 loader->signal_progress().connect(
1318 sigc::mem_fun(*this, &MainWindow::on_loader_progress));
1319 loader->signal_finished().connect(
1320 sigc::mem_fun(*this, &MainWindow::on_loader_finished));
1321
1322 loader->launch();
1323 }
1324 }
1325
1326 void MainWindow::on_loader_progress()
1327 {
1328 load_dialog->set_fraction(loader->get_progress());
1329 }
1330
1331 void MainWindow::on_loader_finished()
1332 {
1333 printf("Loader finished!\n");
1334 printf("on_loader_finished self=%x\n", Glib::Thread::self());
1335 load_gig(loader->gig, loader->filename);
1336
1337
1338 Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();
1339 tree_sel_ref->select(Gtk::TreePath("0"));
1340
1341 load_dialog->hide();
1342 }
1343
1344 void MainWindow::on_action_file_save()
1345 {
1346 if (!file) return;
1347 file->Save();
1348 __import_queued_samples();
1349 }
1350
1351 void MainWindow::on_action_file_save_as()
1352 {
1353 if (!file) return;
1354 Gtk::FileChooserDialog dialog(*this, "Open", Gtk::FILE_CHOOSER_ACTION_SAVE);
1355 dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1356 dialog.add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK);
1357 Gtk::FileFilter filter;
1358 filter.add_pattern("*.gig");
1359 dialog.set_filter(filter);
1360 if (dialog.run() == Gtk::RESPONSE_OK) {
1361 printf("filename=%s\n", dialog.get_filename().c_str());
1362 file->Save(dialog.get_filename());
1363 __import_queued_samples();
1364 }
1365 }
1366
1367 // actually write the sample(s)' data to the gig file
1368 void MainWindow::__import_queued_samples() {
1369 Glib::ustring error_files;
1370 for (std::list<SampleImportItem>::iterator iter = m_SampleImportQueue.begin(); iter != m_SampleImportQueue.end(); ++iter) {
1371 printf("Importing sample %s\n",(*iter).sample_path.c_str());
1372 SF_INFO info;
1373 info.format = 0;
1374 SNDFILE* hFile = sf_open((*iter).sample_path.c_str(), SFM_READ, &info);
1375 try {
1376 if (!hFile) throw std::string("could not open file");
1377 // determine sample's bit depth
1378 int bitdepth;
1379 switch (info.format & 0xff) {
1380 case SF_FORMAT_PCM_S8:
1381 bitdepth = 16; // we simply convert to 16 bit for now
1382 break;
1383 case SF_FORMAT_PCM_16:
1384 bitdepth = 16;
1385 break;
1386 case SF_FORMAT_PCM_24:
1387 bitdepth = 32; // we simply convert to 32 bit for now
1388 break;
1389 case SF_FORMAT_PCM_32:
1390 bitdepth = 32;
1391 break;
1392 case SF_FORMAT_PCM_U8:
1393 bitdepth = 16; // we simply convert to 16 bit for now
1394 break;
1395 case SF_FORMAT_FLOAT:
1396 bitdepth = 32;
1397 break;
1398 case SF_FORMAT_DOUBLE:
1399 bitdepth = 32; // I guess we will always truncate this to 32 bit
1400 break;
1401 default:
1402 sf_close(hFile); // close sound file
1403 throw std::string("format not supported"); // unsupported subformat (yet?)
1404 }
1405 // allocate appropriate copy buffer (TODO: for now we copy it in one piece, might be tough for very long samples)
1406 // and copy sample data into buffer
1407 int8_t* buffer = NULL;
1408 switch (bitdepth) {
1409 case 16:
1410 buffer = new int8_t[2 * info.channels * info.frames];
1411 sf_readf_short(hFile, (short*) buffer, info.frames); // libsndfile does the conversion for us (if needed)
1412 break;
1413 case 32:
1414 buffer = new int8_t[4 * info.channels * info.frames];
1415 sf_readf_int(hFile, (int*) buffer, info.frames); // libsndfile does the conversion for us (if needed)
1416 break;
1417 }
1418 // write from buffer directly (physically) into .gig file
1419 (*iter).gig_sample->Write(buffer, info.frames);
1420 // cleanup
1421 sf_close(hFile);
1422 delete buffer;
1423 // on success we remove the sample from the import queue, otherwise keep it, maybe it works the next time ?
1424 m_SampleImportQueue.erase(iter);
1425 } catch (std::string what) { // remember the files that made trouble (and their cause)
1426 if (error_files.size()) error_files += "\n";
1427 error_files += (*iter).sample_path += " (" + what + ")";
1428 }
1429 }
1430 // show error message box when some sample(s) could not be imported
1431 if (error_files.size()) {
1432 Glib::ustring txt = "Could not import the following sample(s):\n" + error_files;
1433 Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
1434 msg.run();
1435 }
1436 }
1437
1438 void MainWindow::on_action_file_properties()
1439 {
1440 propDialog.show();
1441 propDialog.deiconify();
1442 }
1443
1444 void MainWindow::on_action_help_about()
1445 {
1446 #ifdef ABOUT_DIALOG
1447 Gtk::AboutDialog dialog;
1448 dialog.set_version(VERSION);
1449 dialog.run();
1450 #endif
1451 }
1452
1453 PropDialog::PropDialog()
1454 : table(2,1)
1455 {
1456 table.set_col_spacings(5);
1457 char* propLabels[] = {
1458 "Name:",
1459 "CreationDate:",
1460 "Comments:", // TODO: multiline
1461 "Product:",
1462 "Copyright:",
1463 "Artists:",
1464 "Genre:",
1465 "Keywords:",
1466 "Engineer:",
1467 "Technician:",
1468 "Software:", // TODO: readonly
1469 "Medium:",
1470 "Source:",
1471 "SourceForm:",
1472 "Commissioned:",
1473 "Subject:"
1474 };
1475 for (int i = 0 ; i < sizeof(propLabels) / sizeof(char*) ; i++) {
1476 label[i].set_text(propLabels[i]);
1477 label[i].set_alignment(Gtk::ALIGN_LEFT);
1478 table.attach(label[i], 0, 1, i, i + 1, Gtk::FILL, Gtk::SHRINK);
1479 table.attach(entry[i], 1, 2, i, i + 1, Gtk::FILL | Gtk::EXPAND,
1480 Gtk::SHRINK);
1481 }
1482
1483 add(table);
1484 // add_button(Gtk::Stock::CANCEL, 0);
1485 // add_button(Gtk::Stock::OK, 1);
1486 show_all_children();
1487 }
1488
1489 void PropDialog::set_info(DLS::Info* info)
1490 {
1491 entry[0].set_text(info->Name);
1492 entry[1].set_text(info->CreationDate);
1493 entry[2].set_text(Glib::convert(info->Comments, "UTF-8", "ISO-8859-1"));
1494 entry[3].set_text(info->Product);
1495 entry[4].set_text(info->Copyright);
1496 entry[5].set_text(info->Artists);
1497 entry[6].set_text(info->Genre);
1498 entry[7].set_text(info->Keywords);
1499 entry[8].set_text(info->Engineer);
1500 entry[9].set_text(info->Technician);
1501 entry[10].set_text(info->Software);
1502 entry[11].set_text(info->Medium);
1503 entry[12].set_text(info->Source);
1504 entry[13].set_text(info->SourceForm);
1505 entry[14].set_text(info->Commissioned);
1506 entry[15].set_text(info->Subject);
1507 }
1508
1509
1510 InstrumentProps::InstrumentProps()
1511 : table(2,1),
1512 quitButton(Gtk::Stock::CLOSE)
1513 {
1514 table.set_col_spacings(5);
1515 char* propLabels[] = {
1516 "Name:",
1517 "IsDrum:",
1518 "MIDIBank:",
1519 "MIDIProgram:",
1520 "Attenuation:",
1521 "EffectSend:",
1522 "FineTune:",
1523 "PitchbendRange:",
1524 "PianoReleaseMode:",
1525 "DimensionKeyRange:",
1526 };
1527 int entryIdx = 0, checkIdx = 0;
1528 for (int i = 0 ; i < sizeof(propLabels) / sizeof(char*) ; i++) {
1529 label[i].set_text(propLabels[i]);
1530 label[i].set_alignment(Gtk::ALIGN_LEFT);
1531 table.attach(label[i], 0, 1, i, i + 1, Gtk::FILL, Gtk::SHRINK);
1532 if (i == 1 || i == 8)
1533 table.attach(check[checkIdx++], 1, 2, i, i + 1,
1534 Gtk::FILL | Gtk::EXPAND, Gtk::SHRINK);
1535 else
1536 table.attach(entry[entryIdx++], 1, 2, i, i + 1,
1537 Gtk::FILL | Gtk::EXPAND, Gtk::SHRINK);
1538 }
1539
1540 // vbox { table buttonBox { quitButton } }
1541
1542 //get_vbox()->pack_start(table);
1543 // set_border_width(6);
1544 add(vbox);
1545 table.set_border_width(2);
1546 vbox.pack_start(table);
1547 table.show();
1548 vbox.pack_start(buttonBox);
1549 buttonBox.set_layout(Gtk::BUTTONBOX_END);
1550 buttonBox.set_border_width(5);
1551 buttonBox.show();
1552 buttonBox.pack_start(quitButton);
1553 quitButton.set_flags(Gtk::CAN_DEFAULT);
1554 quitButton.grab_focus();
1555
1556 quitButton.signal_clicked().connect(
1557 sigc::mem_fun(*this, &InstrumentProps::hide));
1558
1559 // quitButton.grab_default();
1560 quitButton.show();
1561 // add(table);
1562 vbox.show();
1563 show_all_children();
1564 }
1565
1566
1567 void InstrumentProps::set_instrument(gig::Instrument* instrument)
1568 {
1569 char buf[100];
1570
1571 int entryIdx = 0, checkIdx = 0;
1572 entry[entryIdx++].set_text(instrument->pInfo->Name);
1573 check[checkIdx++].set_active(instrument->IsDrum);
1574 sprintf(buf, "%d", instrument->MIDIBank);
1575 entry[entryIdx++].set_text(buf);
1576 sprintf(buf, "%d", instrument->MIDIProgram);
1577 entry[entryIdx++].set_text(buf);
1578 sprintf(buf, "%d", instrument->Attenuation);
1579 entry[entryIdx++].set_text(buf);
1580 sprintf(buf, "%d", instrument->EffectSend);
1581 entry[entryIdx++].set_text(buf);
1582 sprintf(buf, "%d", instrument->FineTune);
1583 entry[entryIdx++].set_text(buf);
1584 sprintf(buf, "%d", instrument->PitchbendRange);
1585 entry[entryIdx++].set_text(buf);
1586 check[checkIdx++].set_active(instrument->PianoReleaseMode);
1587 sprintf(buf, "%s%d (%d)..%s%d (%d)",
1588 notes[instrument->DimensionKeyRange.low % 12],
1589 instrument->DimensionKeyRange.low / 12 - 1,
1590 instrument->DimensionKeyRange.low,
1591 notes[instrument->DimensionKeyRange.high % 12],
1592 instrument->DimensionKeyRange.high / 12 - 1,
1593 instrument->DimensionKeyRange.high);
1594 entry[entryIdx].set_text(buf);
1595 }
1596
1597 void MainWindow::getInfo(const char *filename)
1598 {
1599 RIFF::File* riff = new RIFF::File(filename);
1600 gig::File* gig = new gig::File(riff);
1601
1602 load_gig(gig, filename);
1603 }
1604
1605 void MainWindow::load_gig(gig::File* gig, const char* filename)
1606 {
1607 file = gig;
1608
1609 const char *basename = strrchr(filename, '/');
1610 basename = basename ? basename + 1 : filename;
1611
1612 set_title(basename);
1613
1614 propDialog.set_info(gig->pInfo);
1615
1616 Gtk::MenuItem* instrument_menu =
1617 dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/MenuBar/MenuInstrument"));
1618
1619 int instrument_index = 0;
1620 Gtk::RadioMenuItem::Group instrument_group;
1621 for (gig::Instrument* instrument = gig->GetFirstInstrument() ; instrument ;
1622 instrument = gig->GetNextInstrument()) {
1623 Gtk::TreeModel::iterator iter = m_refTreeModel->append();
1624 Gtk::TreeModel::Row row = *iter;
1625 row[m_Columns.m_col_name] = instrument->pInfo->Name.c_str();
1626 row[m_Columns.m_col_instr] = instrument;
1627 // create a menu item for this instrument
1628 Gtk::RadioMenuItem* item= new Gtk::RadioMenuItem(instrument_group, instrument->pInfo->Name.c_str());
1629 instrument_menu->get_submenu()->append(*item);
1630 item->signal_activate().connect(
1631 sigc::bind(
1632 sigc::mem_fun(*this, &MainWindow::on_instrument_selection_change),
1633 instrument_index
1634 )
1635 );
1636 instrument_index++;
1637 }
1638 instrument_menu->show();
1639 instrument_menu->get_submenu()->show_all_children();
1640
1641 for (gig::Group* group = gig->GetFirstGroup(); group; group = gig->GetNextGroup()) {
1642 Gtk::TreeModel::iterator iterGroup = m_refSamplesTreeModel->append();
1643 Gtk::TreeModel::Row rowGroup = *iterGroup;
1644 rowGroup[m_SamplesModel.m_col_name] = group->Name.c_str();
1645 rowGroup[m_SamplesModel.m_col_group] = group;
1646 rowGroup[m_SamplesModel.m_col_sample] = NULL;
1647 for (gig::Sample* sample = group->GetFirstSample(); sample; sample = group->GetNextSample()) {
1648 Gtk::TreeModel::iterator iterSample = m_refSamplesTreeModel->append(rowGroup.children());
1649 Gtk::TreeModel::Row rowSample = *iterSample;
1650 rowSample[m_SamplesModel.m_col_name] = sample->pInfo->Name.c_str();
1651 rowSample[m_SamplesModel.m_col_sample] = sample;
1652 rowSample[m_SamplesModel.m_col_group] = NULL;
1653 }
1654 }
1655 }
1656
1657 void MainWindow::on_button_release(GdkEventButton* button)
1658 {
1659 if (button->type == GDK_2BUTTON_PRESS) {
1660 Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();
1661 Gtk::TreeModel::iterator it = tree_sel_ref->get_selected();
1662 if (it)
1663 {
1664 Gtk::TreeModel::Row row = *it;
1665 if (row[m_Columns.m_col_instr])
1666 {
1667 instrumentProps.set_instrument(row[m_Columns.m_col_instr]);
1668 instrumentProps.show();
1669 instrumentProps.deiconify();
1670 }
1671 }
1672 } else if (button->type == GDK_BUTTON_PRESS && button->button == 3) {
1673 popup_menu->popup(button->button, button->time);
1674 }
1675 }
1676
1677 void MainWindow::on_instrument_selection_change(int index) {
1678 m_RegionChooser.set_instrument(file->GetInstrument(index));
1679 }
1680
1681 void MainWindow::on_sample_treeview_button_release(GdkEventButton* button) {
1682 if (button->type == GDK_BUTTON_PRESS && button->button == 3) {
1683 Gtk::Menu* sample_popup =
1684 dynamic_cast<Gtk::Menu*>(uiManager->get_widget("/SamplePopupMenu"));
1685 // update enabled/disabled state of sample popup items
1686 Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();
1687 Gtk::TreeModel::iterator it = sel->get_selected();
1688 bool group_selected = false;
1689 bool sample_selected = false;
1690 if (it) {
1691 Gtk::TreeModel::Row row = *it;
1692 group_selected = row[m_SamplesModel.m_col_group];
1693 sample_selected = row[m_SamplesModel.m_col_sample];
1694 }
1695 dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/SamplePopupMenu/SampleProperties"))->set_sensitive(group_selected || sample_selected);
1696 dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/SamplePopupMenu/AddSample"))->set_sensitive(group_selected || sample_selected);
1697 dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/SamplePopupMenu/AddGroup"))->set_sensitive(file);
1698 dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/SamplePopupMenu/RemoveSample"))->set_sensitive(group_selected || sample_selected);
1699 // show sample popup
1700 sample_popup->popup(button->button, button->time);
1701 }
1702 }
1703
1704 void MainWindow::on_action_sample_properties() {
1705 //TODO: show a dialog where the selected sample's properties can be edited
1706 }
1707
1708 void MainWindow::on_action_add_group() {
1709 static int __sample_indexer = 0;
1710 if (!file) return;
1711 gig::Group* group = file->AddGroup();
1712 group->Name = "Unnamed Group";
1713 if (__sample_indexer) group->Name += " " + ToString(__sample_indexer);
1714 __sample_indexer++;
1715 // update sample tree view
1716 Gtk::TreeModel::iterator iterGroup = m_refSamplesTreeModel->append();
1717 Gtk::TreeModel::Row rowGroup = *iterGroup;
1718 rowGroup[m_SamplesModel.m_col_name] = group->Name.c_str();
1719 rowGroup[m_SamplesModel.m_col_sample] = NULL;
1720 rowGroup[m_SamplesModel.m_col_group] = group;
1721 }
1722
1723 void MainWindow::on_action_add_sample() {
1724 if (!file) return;
1725 // get selected group
1726 Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();
1727 Gtk::TreeModel::iterator it = sel->get_selected();
1728 if (!it) return;
1729 Gtk::TreeModel::Row row = *it;
1730 gig::Group* group = row[m_SamplesModel.m_col_group];
1731 if (!group) { // not a group, but a sample is selected (probably)
1732 gig::Sample* sample = row[m_SamplesModel.m_col_sample];
1733 if (!sample) return;
1734 it = row.parent(); // resolve parent (that is the sample's group)
1735 if (!it) return;
1736 row = *it;
1737 group = row[m_SamplesModel.m_col_group];
1738 if (!group) return;
1739 }
1740 // show 'browse for file' dialog
1741 Gtk::FileChooserDialog dialog(*this, _("Add Sample(s)"));
1742 dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1743 dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);
1744 dialog.set_select_multiple(true);
1745 Gtk::FileFilter soundfilter; // matches all file types supported by libsndfile (yet to do ;-)
1746 soundfilter.add_pattern("*.wav");
1747 soundfilter.set_name("Sound Files");
1748 Gtk::FileFilter allpassfilter; // matches every file
1749 allpassfilter.add_pattern("*.*");
1750 allpassfilter.set_name("All Files");
1751 dialog.add_filter(soundfilter);
1752 dialog.add_filter(allpassfilter);
1753 if (dialog.run() == Gtk::RESPONSE_OK) {
1754 Glib::ustring error_files;
1755 Glib::SListHandle<Glib::ustring> filenames = dialog.get_filenames();
1756 for (Glib::SListHandle<Glib::ustring>::iterator iter = filenames.begin(); iter != filenames.end(); ++iter) {
1757 printf("Adding sample %s\n",(*iter).c_str());
1758 // use libsndfile to retrieve file informations
1759 SF_INFO info;
1760 info.format = 0;
1761 SNDFILE* hFile = sf_open((*iter).c_str(), SFM_READ, &info);
1762 try {
1763 if (!hFile) throw std::string("could not open file");
1764 int bitdepth;
1765 switch (info.format & 0xff) {
1766 case SF_FORMAT_PCM_S8:
1767 bitdepth = 16; // we simply convert to 16 bit for now
1768 break;
1769 case SF_FORMAT_PCM_16:
1770 bitdepth = 16;
1771 break;
1772 case SF_FORMAT_PCM_24:
1773 bitdepth = 32; // we simply convert to 32 bit for now
1774 break;
1775 case SF_FORMAT_PCM_32:
1776 bitdepth = 32;
1777 break;
1778 case SF_FORMAT_PCM_U8:
1779 bitdepth = 16; // we simply convert to 16 bit for now
1780 break;
1781 case SF_FORMAT_FLOAT:
1782 bitdepth = 32;
1783 break;
1784 case SF_FORMAT_DOUBLE:
1785 bitdepth = 32; // I guess we will always truncate this to 32 bit
1786 break;
1787 default:
1788 sf_close(hFile); // close sound file
1789 throw std::string("format not supported"); // unsupported subformat (yet?)
1790 }
1791 // add a new sample to the .gig file
1792 gig::Sample* sample = file->AddSample();
1793 sample->pInfo->Name = (*iter).substr((*iter).rfind('/') + 1).raw(); // file name without path
1794 sample->Channels = info.channels;
1795 sample->BitDepth = bitdepth;
1796 sample->FrameSize = bitdepth / 8/*1 byte are 8 bits*/ * info.channels;
1797 sample->SamplesPerSecond = info.samplerate;
1798 // schedule resizing the sample (which will be done physically when File::Save() is called)
1799 sample->Resize(info.frames);
1800 // schedule that physical resize and sample import (data copying), performed when "Save" is requested
1801 SampleImportItem sched_item;
1802 sched_item.gig_sample = sample;
1803 sched_item.sample_path = *iter;
1804 m_SampleImportQueue.push_back(sched_item);
1805 // add sample to the tree view
1806 Gtk::TreeModel::iterator iterSample = m_refSamplesTreeModel->append(row.children());
1807 Gtk::TreeModel::Row rowSample = *iterSample;
1808 rowSample[m_SamplesModel.m_col_name] = sample->pInfo->Name.c_str();
1809 rowSample[m_SamplesModel.m_col_sample] = sample;
1810 rowSample[m_SamplesModel.m_col_group] = NULL;
1811 // close sound file
1812 sf_close(hFile);
1813 } catch (std::string what) { // remember the files that made trouble (and their cause)
1814 if (error_files.size()) error_files += "\n";
1815 error_files += *iter += " (" + what + ")";
1816 }
1817 }
1818 // show error message box when some file(s) could not be opened / added
1819 if (error_files.size()) {
1820 Glib::ustring txt = "Could not add the following sample(s):\n" + error_files;
1821 Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
1822 msg.run();
1823 }
1824 }
1825 }
1826
1827 void MainWindow::on_action_remove_sample() {
1828 if (!file) return;
1829 Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();
1830 Gtk::TreeModel::iterator it = sel->get_selected();
1831 if (it) {
1832 Gtk::TreeModel::Row row = *it;
1833 gig::Group* group = row[m_SamplesModel.m_col_group];
1834 gig::Sample* sample = row[m_SamplesModel.m_col_sample];
1835 try {
1836 // remove group or sample from the gig file
1837 if (group) {
1838 file->DeleteGroup(group);
1839 } else if (sample) {
1840 file->DeleteSample(sample);
1841 }
1842 // if sample was just previously added, remove it from the import queue
1843 if (sample) {
1844 for (std::list<SampleImportItem>::iterator iter = m_SampleImportQueue.begin(); iter != m_SampleImportQueue.end(); ++iter) {
1845 if ((*iter).gig_sample == sample) {
1846 m_SampleImportQueue.erase(iter);
1847 break;
1848 }
1849 }
1850 }
1851 // remove respective row(s) from samples tree view
1852 m_refSamplesTreeModel->erase(it);
1853 } catch (RIFF::Exception e) {
1854 Gtk::MessageDialog msg(*this, e.Message.c_str(), false, Gtk::MESSAGE_ERROR);
1855 msg.run();
1856 }
1857 }
1858 }

  ViewVC Help
Powered by ViewVC