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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1092 - (show annotations) (download)
Sun Mar 11 15:21:58 2007 UTC (17 years, 1 month ago) by persson
File size: 70055 byte(s)
* implemented editing of dimension region upper limits

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

  ViewVC Help
Powered by ViewVC