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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1094 - (show annotations) (download)
Sun Mar 11 17:47:21 2007 UTC (17 years, 1 month ago) by schoenebeck
File size: 70760 byte(s)
- fixed previously mentioned crash, root cause is yet to be fixed in libgig
  (seems as not all RIFF chunks are deleted yet when calling
  gig::File::DeleteSample())

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 std::cout << "Saving file\n" << std::flush;
1349 try {
1350 file->Save();
1351 } catch (RIFF::Exception e) {
1352 Glib::ustring txt = "Could not save file: " + e.Message;
1353 Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
1354 msg.run();
1355 return;
1356 }
1357 std::cout << "Saving file done\n" << std::flush;
1358 __import_queued_samples();
1359 }
1360
1361 void MainWindow::on_action_file_save_as()
1362 {
1363 if (!file) return;
1364 Gtk::FileChooserDialog dialog(*this, "Open", Gtk::FILE_CHOOSER_ACTION_SAVE);
1365 dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1366 dialog.add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK);
1367 Gtk::FileFilter filter;
1368 filter.add_pattern("*.gig");
1369 dialog.set_filter(filter);
1370 if (dialog.run() == Gtk::RESPONSE_OK) {
1371 printf("filename=%s\n", dialog.get_filename().c_str());
1372 try {
1373 file->Save(dialog.get_filename());
1374 } catch (RIFF::Exception e) {
1375 Glib::ustring txt = "Could not save file: " + e.Message;
1376 Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
1377 msg.run();
1378 return;
1379 }
1380 __import_queued_samples();
1381 }
1382 }
1383
1384 // actually write the sample(s)' data to the gig file
1385 void MainWindow::__import_queued_samples() {
1386 std::cout << "Starting sample import\n" << std::flush;
1387 Glib::ustring error_files;
1388 printf("Samples to import: %d\n", m_SampleImportQueue.size());
1389 for (std::list<SampleImportItem>::iterator iter = m_SampleImportQueue.begin(); iter != m_SampleImportQueue.end(); ) {
1390 printf("Importing sample %s\n",(*iter).sample_path.c_str());
1391 SF_INFO info;
1392 info.format = 0;
1393 SNDFILE* hFile = sf_open((*iter).sample_path.c_str(), SFM_READ, &info);
1394 try {
1395 if (!hFile) throw std::string("could not open file");
1396 // determine sample's bit depth
1397 int bitdepth;
1398 switch (info.format & 0xff) {
1399 case SF_FORMAT_PCM_S8:
1400 bitdepth = 16; // we simply convert to 16 bit for now
1401 break;
1402 case SF_FORMAT_PCM_16:
1403 bitdepth = 16;
1404 break;
1405 case SF_FORMAT_PCM_24:
1406 bitdepth = 32; // we simply convert to 32 bit for now
1407 break;
1408 case SF_FORMAT_PCM_32:
1409 bitdepth = 32;
1410 break;
1411 case SF_FORMAT_PCM_U8:
1412 bitdepth = 16; // we simply convert to 16 bit for now
1413 break;
1414 case SF_FORMAT_FLOAT:
1415 bitdepth = 32;
1416 break;
1417 case SF_FORMAT_DOUBLE:
1418 bitdepth = 32; // I guess we will always truncate this to 32 bit
1419 break;
1420 default:
1421 sf_close(hFile); // close sound file
1422 throw std::string("format not supported"); // unsupported subformat (yet?)
1423 }
1424 // allocate appropriate copy buffer (TODO: for now we copy it in one piece, might be tough for very long samples)
1425 // and copy sample data into buffer
1426 int8_t* buffer = NULL;
1427 switch (bitdepth) {
1428 case 16:
1429 buffer = new int8_t[2 * info.channels * info.frames];
1430 sf_readf_short(hFile, (short*) buffer, info.frames); // libsndfile does the conversion for us (if needed)
1431 break;
1432 case 32:
1433 buffer = new int8_t[4 * info.channels * info.frames];
1434 sf_readf_int(hFile, (int*) buffer, info.frames); // libsndfile does the conversion for us (if needed)
1435 break;
1436 }
1437 // write from buffer directly (physically) into .gig file
1438 (*iter).gig_sample->Write(buffer, info.frames);
1439 // cleanup
1440 sf_close(hFile);
1441 delete buffer;
1442 // on success we remove the sample from the import queue, otherwise keep it, maybe it works the next time ?
1443 std::list<SampleImportItem>::iterator cur = iter;
1444 ++iter;
1445 m_SampleImportQueue.erase(cur);
1446 } catch (std::string what) { // remember the files that made trouble (and their cause)
1447 if (error_files.size()) error_files += "\n";
1448 error_files += (*iter).sample_path += " (" + what + ")";
1449 ++iter;
1450 }
1451 }
1452 // show error message box when some sample(s) could not be imported
1453 if (error_files.size()) {
1454 Glib::ustring txt = "Could not import the following sample(s):\n" + error_files;
1455 Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
1456 msg.run();
1457 }
1458 }
1459
1460 void MainWindow::on_action_file_properties()
1461 {
1462 propDialog.show();
1463 propDialog.deiconify();
1464 }
1465
1466 void MainWindow::on_action_help_about()
1467 {
1468 #ifdef ABOUT_DIALOG
1469 Gtk::AboutDialog dialog;
1470 dialog.set_version(VERSION);
1471 dialog.run();
1472 #endif
1473 }
1474
1475 PropDialog::PropDialog()
1476 : table(2,1)
1477 {
1478 table.set_col_spacings(5);
1479 char* propLabels[] = {
1480 "Name:",
1481 "CreationDate:",
1482 "Comments:", // TODO: multiline
1483 "Product:",
1484 "Copyright:",
1485 "Artists:",
1486 "Genre:",
1487 "Keywords:",
1488 "Engineer:",
1489 "Technician:",
1490 "Software:", // TODO: readonly
1491 "Medium:",
1492 "Source:",
1493 "SourceForm:",
1494 "Commissioned:",
1495 "Subject:"
1496 };
1497 for (int i = 0 ; i < sizeof(propLabels) / sizeof(char*) ; i++) {
1498 label[i].set_text(propLabels[i]);
1499 label[i].set_alignment(Gtk::ALIGN_LEFT);
1500 table.attach(label[i], 0, 1, i, i + 1, Gtk::FILL, Gtk::SHRINK);
1501 table.attach(entry[i], 1, 2, i, i + 1, Gtk::FILL | Gtk::EXPAND,
1502 Gtk::SHRINK);
1503 }
1504
1505 add(table);
1506 // add_button(Gtk::Stock::CANCEL, 0);
1507 // add_button(Gtk::Stock::OK, 1);
1508 show_all_children();
1509 }
1510
1511 void PropDialog::set_info(DLS::Info* info)
1512 {
1513 entry[0].set_text(info->Name);
1514 entry[1].set_text(info->CreationDate);
1515 entry[2].set_text(Glib::convert(info->Comments, "UTF-8", "ISO-8859-1"));
1516 entry[3].set_text(info->Product);
1517 entry[4].set_text(info->Copyright);
1518 entry[5].set_text(info->Artists);
1519 entry[6].set_text(info->Genre);
1520 entry[7].set_text(info->Keywords);
1521 entry[8].set_text(info->Engineer);
1522 entry[9].set_text(info->Technician);
1523 entry[10].set_text(info->Software);
1524 entry[11].set_text(info->Medium);
1525 entry[12].set_text(info->Source);
1526 entry[13].set_text(info->SourceForm);
1527 entry[14].set_text(info->Commissioned);
1528 entry[15].set_text(info->Subject);
1529 }
1530
1531
1532 InstrumentProps::InstrumentProps()
1533 : table(2,1),
1534 quitButton(Gtk::Stock::CLOSE)
1535 {
1536 table.set_col_spacings(5);
1537 char* propLabels[] = {
1538 "Name:",
1539 "IsDrum:",
1540 "MIDIBank:",
1541 "MIDIProgram:",
1542 "Attenuation:",
1543 "EffectSend:",
1544 "FineTune:",
1545 "PitchbendRange:",
1546 "PianoReleaseMode:",
1547 "DimensionKeyRange:",
1548 };
1549 int entryIdx = 0, checkIdx = 0;
1550 for (int i = 0 ; i < sizeof(propLabels) / sizeof(char*) ; i++) {
1551 label[i].set_text(propLabels[i]);
1552 label[i].set_alignment(Gtk::ALIGN_LEFT);
1553 table.attach(label[i], 0, 1, i, i + 1, Gtk::FILL, Gtk::SHRINK);
1554 if (i == 1 || i == 8)
1555 table.attach(check[checkIdx++], 1, 2, i, i + 1,
1556 Gtk::FILL | Gtk::EXPAND, Gtk::SHRINK);
1557 else
1558 table.attach(entry[entryIdx++], 1, 2, i, i + 1,
1559 Gtk::FILL | Gtk::EXPAND, Gtk::SHRINK);
1560 }
1561
1562 // vbox { table buttonBox { quitButton } }
1563
1564 //get_vbox()->pack_start(table);
1565 // set_border_width(6);
1566 add(vbox);
1567 table.set_border_width(2);
1568 vbox.pack_start(table);
1569 table.show();
1570 vbox.pack_start(buttonBox);
1571 buttonBox.set_layout(Gtk::BUTTONBOX_END);
1572 buttonBox.set_border_width(5);
1573 buttonBox.show();
1574 buttonBox.pack_start(quitButton);
1575 quitButton.set_flags(Gtk::CAN_DEFAULT);
1576 quitButton.grab_focus();
1577
1578 quitButton.signal_clicked().connect(
1579 sigc::mem_fun(*this, &InstrumentProps::hide));
1580
1581 // quitButton.grab_default();
1582 quitButton.show();
1583 // add(table);
1584 vbox.show();
1585 show_all_children();
1586 }
1587
1588
1589 void InstrumentProps::set_instrument(gig::Instrument* instrument)
1590 {
1591 char buf[100];
1592
1593 int entryIdx = 0, checkIdx = 0;
1594 entry[entryIdx++].set_text(instrument->pInfo->Name);
1595 check[checkIdx++].set_active(instrument->IsDrum);
1596 sprintf(buf, "%d", instrument->MIDIBank);
1597 entry[entryIdx++].set_text(buf);
1598 sprintf(buf, "%d", instrument->MIDIProgram);
1599 entry[entryIdx++].set_text(buf);
1600 sprintf(buf, "%d", instrument->Attenuation);
1601 entry[entryIdx++].set_text(buf);
1602 sprintf(buf, "%d", instrument->EffectSend);
1603 entry[entryIdx++].set_text(buf);
1604 sprintf(buf, "%d", instrument->FineTune);
1605 entry[entryIdx++].set_text(buf);
1606 sprintf(buf, "%d", instrument->PitchbendRange);
1607 entry[entryIdx++].set_text(buf);
1608 check[checkIdx++].set_active(instrument->PianoReleaseMode);
1609 sprintf(buf, "%s%d (%d)..%s%d (%d)",
1610 notes[instrument->DimensionKeyRange.low % 12],
1611 instrument->DimensionKeyRange.low / 12 - 1,
1612 instrument->DimensionKeyRange.low,
1613 notes[instrument->DimensionKeyRange.high % 12],
1614 instrument->DimensionKeyRange.high / 12 - 1,
1615 instrument->DimensionKeyRange.high);
1616 entry[entryIdx].set_text(buf);
1617 }
1618
1619 void MainWindow::getInfo(const char *filename)
1620 {
1621 RIFF::File* riff = new RIFF::File(filename);
1622 gig::File* gig = new gig::File(riff);
1623
1624 load_gig(gig, filename);
1625 }
1626
1627 void MainWindow::load_gig(gig::File* gig, const char* filename)
1628 {
1629 file = gig;
1630
1631 const char *basename = strrchr(filename, '/');
1632 basename = basename ? basename + 1 : filename;
1633
1634 set_title(basename);
1635
1636 propDialog.set_info(gig->pInfo);
1637
1638 Gtk::MenuItem* instrument_menu =
1639 dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/MenuBar/MenuInstrument"));
1640
1641 int instrument_index = 0;
1642 Gtk::RadioMenuItem::Group instrument_group;
1643 for (gig::Instrument* instrument = gig->GetFirstInstrument() ; instrument ;
1644 instrument = gig->GetNextInstrument()) {
1645 Gtk::TreeModel::iterator iter = m_refTreeModel->append();
1646 Gtk::TreeModel::Row row = *iter;
1647 row[m_Columns.m_col_name] = instrument->pInfo->Name.c_str();
1648 row[m_Columns.m_col_instr] = instrument;
1649 // create a menu item for this instrument
1650 Gtk::RadioMenuItem* item= new Gtk::RadioMenuItem(instrument_group, instrument->pInfo->Name.c_str());
1651 instrument_menu->get_submenu()->append(*item);
1652 item->signal_activate().connect(
1653 sigc::bind(
1654 sigc::mem_fun(*this, &MainWindow::on_instrument_selection_change),
1655 instrument_index
1656 )
1657 );
1658 instrument_index++;
1659 }
1660 instrument_menu->show();
1661 instrument_menu->get_submenu()->show_all_children();
1662
1663 for (gig::Group* group = gig->GetFirstGroup(); group; group = gig->GetNextGroup()) {
1664 if (group->Name != "") {
1665 Gtk::TreeModel::iterator iterGroup = m_refSamplesTreeModel->append();
1666 Gtk::TreeModel::Row rowGroup = *iterGroup;
1667 rowGroup[m_SamplesModel.m_col_name] = group->Name.c_str();
1668 rowGroup[m_SamplesModel.m_col_group] = group;
1669 rowGroup[m_SamplesModel.m_col_sample] = NULL;
1670 for (gig::Sample* sample = group->GetFirstSample(); sample; sample = group->GetNextSample()) {
1671 Gtk::TreeModel::iterator iterSample = m_refSamplesTreeModel->append(rowGroup.children());
1672 Gtk::TreeModel::Row rowSample = *iterSample;
1673 rowSample[m_SamplesModel.m_col_name] = sample->pInfo->Name.c_str();
1674 rowSample[m_SamplesModel.m_col_sample] = sample;
1675 rowSample[m_SamplesModel.m_col_group] = NULL;
1676 }
1677 }
1678 }
1679 }
1680
1681 void MainWindow::on_button_release(GdkEventButton* button)
1682 {
1683 if (button->type == GDK_2BUTTON_PRESS) {
1684 Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();
1685 Gtk::TreeModel::iterator it = tree_sel_ref->get_selected();
1686 if (it)
1687 {
1688 Gtk::TreeModel::Row row = *it;
1689 if (row[m_Columns.m_col_instr])
1690 {
1691 instrumentProps.set_instrument(row[m_Columns.m_col_instr]);
1692 instrumentProps.show();
1693 instrumentProps.deiconify();
1694 }
1695 }
1696 } else if (button->type == GDK_BUTTON_PRESS && button->button == 3) {
1697 popup_menu->popup(button->button, button->time);
1698 }
1699 }
1700
1701 void MainWindow::on_instrument_selection_change(int index) {
1702 m_RegionChooser.set_instrument(file->GetInstrument(index));
1703 }
1704
1705 void MainWindow::on_sample_treeview_button_release(GdkEventButton* button) {
1706 if (button->type == GDK_BUTTON_PRESS && button->button == 3) {
1707 Gtk::Menu* sample_popup =
1708 dynamic_cast<Gtk::Menu*>(uiManager->get_widget("/SamplePopupMenu"));
1709 // update enabled/disabled state of sample popup items
1710 Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();
1711 Gtk::TreeModel::iterator it = sel->get_selected();
1712 bool group_selected = false;
1713 bool sample_selected = false;
1714 if (it) {
1715 Gtk::TreeModel::Row row = *it;
1716 group_selected = row[m_SamplesModel.m_col_group];
1717 sample_selected = row[m_SamplesModel.m_col_sample];
1718 }
1719 dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/SamplePopupMenu/SampleProperties"))->set_sensitive(group_selected || sample_selected);
1720 dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/SamplePopupMenu/AddSample"))->set_sensitive(group_selected || sample_selected);
1721 dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/SamplePopupMenu/AddGroup"))->set_sensitive(file);
1722 dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/SamplePopupMenu/RemoveSample"))->set_sensitive(group_selected || sample_selected);
1723 // show sample popup
1724 sample_popup->popup(button->button, button->time);
1725 }
1726 }
1727
1728 void MainWindow::on_action_sample_properties() {
1729 //TODO: show a dialog where the selected sample's properties can be edited
1730 }
1731
1732 void MainWindow::on_action_add_group() {
1733 static int __sample_indexer = 0;
1734 if (!file) return;
1735 gig::Group* group = file->AddGroup();
1736 group->Name = "Unnamed Group";
1737 if (__sample_indexer) group->Name += " " + ToString(__sample_indexer);
1738 __sample_indexer++;
1739 // update sample tree view
1740 Gtk::TreeModel::iterator iterGroup = m_refSamplesTreeModel->append();
1741 Gtk::TreeModel::Row rowGroup = *iterGroup;
1742 rowGroup[m_SamplesModel.m_col_name] = group->Name.c_str();
1743 rowGroup[m_SamplesModel.m_col_sample] = NULL;
1744 rowGroup[m_SamplesModel.m_col_group] = group;
1745 }
1746
1747 void MainWindow::on_action_add_sample() {
1748 if (!file) return;
1749 // get selected group
1750 Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();
1751 Gtk::TreeModel::iterator it = sel->get_selected();
1752 if (!it) return;
1753 Gtk::TreeModel::Row row = *it;
1754 gig::Group* group = row[m_SamplesModel.m_col_group];
1755 if (!group) { // not a group, but a sample is selected (probably)
1756 gig::Sample* sample = row[m_SamplesModel.m_col_sample];
1757 if (!sample) return;
1758 it = row.parent(); // resolve parent (that is the sample's group)
1759 if (!it) return;
1760 row = *it;
1761 group = row[m_SamplesModel.m_col_group];
1762 if (!group) return;
1763 }
1764 // show 'browse for file' dialog
1765 Gtk::FileChooserDialog dialog(*this, _("Add Sample(s)"));
1766 dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1767 dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);
1768 dialog.set_select_multiple(true);
1769 Gtk::FileFilter soundfilter; // matches all file types supported by libsndfile
1770 const char* supportedFileTypes[] = {
1771 "*.wav", "*.WAV", "*.aiff", "*.AIFF", "*.aifc", "*.AIFC", "*.snd",
1772 "*.SND", "*.au", "*.AU", "*.paf", "*.PAF", "*.iff", "*.IFF",
1773 "*.svx", "*.SVX", "*.sf", "*.SF", "*.voc", "*.VOC", "*.w64",
1774 "*.W64", "*.pvf", "*.PVF", "*.xi", "*.XI", "*.htk", "*.HTK",
1775 "*.caf", "*.CAF", NULL
1776 };
1777 for (int i = 0; supportedFileTypes[i]; i++)
1778 soundfilter.add_pattern(supportedFileTypes[i]);
1779 soundfilter.set_name("Sound Files");
1780 Gtk::FileFilter allpassfilter; // matches every file
1781 allpassfilter.add_pattern("*.*");
1782 allpassfilter.set_name("All Files");
1783 dialog.add_filter(soundfilter);
1784 dialog.add_filter(allpassfilter);
1785 if (dialog.run() == Gtk::RESPONSE_OK) {
1786 Glib::ustring error_files;
1787 Glib::SListHandle<Glib::ustring> filenames = dialog.get_filenames();
1788 for (Glib::SListHandle<Glib::ustring>::iterator iter = filenames.begin(); iter != filenames.end(); ++iter) {
1789 printf("Adding sample %s\n",(*iter).c_str());
1790 // use libsndfile to retrieve file informations
1791 SF_INFO info;
1792 info.format = 0;
1793 SNDFILE* hFile = sf_open((*iter).c_str(), SFM_READ, &info);
1794 try {
1795 if (!hFile) throw std::string("could not open file");
1796 int bitdepth;
1797 switch (info.format & 0xff) {
1798 case SF_FORMAT_PCM_S8:
1799 bitdepth = 16; // we simply convert to 16 bit for now
1800 break;
1801 case SF_FORMAT_PCM_16:
1802 bitdepth = 16;
1803 break;
1804 case SF_FORMAT_PCM_24:
1805 bitdepth = 32; // we simply convert to 32 bit for now
1806 break;
1807 case SF_FORMAT_PCM_32:
1808 bitdepth = 32;
1809 break;
1810 case SF_FORMAT_PCM_U8:
1811 bitdepth = 16; // we simply convert to 16 bit for now
1812 break;
1813 case SF_FORMAT_FLOAT:
1814 bitdepth = 32;
1815 break;
1816 case SF_FORMAT_DOUBLE:
1817 bitdepth = 32; // I guess we will always truncate this to 32 bit
1818 break;
1819 default:
1820 sf_close(hFile); // close sound file
1821 throw std::string("format not supported"); // unsupported subformat (yet?)
1822 }
1823 // add a new sample to the .gig file
1824 gig::Sample* sample = file->AddSample();
1825 sample->pInfo->Name = (*iter).substr((*iter).rfind('/') + 1).raw(); // file name without path
1826 sample->Channels = info.channels;
1827 sample->BitDepth = bitdepth;
1828 sample->FrameSize = bitdepth / 8/*1 byte are 8 bits*/ * info.channels;
1829 sample->SamplesPerSecond = info.samplerate;
1830 // schedule resizing the sample (which will be done physically when File::Save() is called)
1831 sample->Resize(info.frames);
1832 // make sure sample is part of the selected group
1833 group->AddSample(sample);
1834 // schedule that physical resize and sample import (data copying), performed when "Save" is requested
1835 SampleImportItem sched_item;
1836 sched_item.gig_sample = sample;
1837 sched_item.sample_path = *iter;
1838 m_SampleImportQueue.push_back(sched_item);
1839 // add sample to the tree view
1840 Gtk::TreeModel::iterator iterSample = m_refSamplesTreeModel->append(row.children());
1841 Gtk::TreeModel::Row rowSample = *iterSample;
1842 rowSample[m_SamplesModel.m_col_name] = sample->pInfo->Name.c_str();
1843 rowSample[m_SamplesModel.m_col_sample] = sample;
1844 rowSample[m_SamplesModel.m_col_group] = NULL;
1845 // close sound file
1846 sf_close(hFile);
1847 } catch (std::string what) { // remember the files that made trouble (and their cause)
1848 if (error_files.size()) error_files += "\n";
1849 error_files += *iter += " (" + what + ")";
1850 }
1851 }
1852 // show error message box when some file(s) could not be opened / added
1853 if (error_files.size()) {
1854 Glib::ustring txt = "Could not add the following sample(s):\n" + error_files;
1855 Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
1856 msg.run();
1857 }
1858 }
1859 }
1860
1861 void MainWindow::on_action_remove_sample() {
1862 if (!file) return;
1863 Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();
1864 Gtk::TreeModel::iterator it = sel->get_selected();
1865 if (it) {
1866 Gtk::TreeModel::Row row = *it;
1867 gig::Group* group = row[m_SamplesModel.m_col_group];
1868 gig::Sample* sample = row[m_SamplesModel.m_col_sample];
1869 Glib::ustring name = row[m_SamplesModel.m_col_name];
1870 try {
1871 // remove group or sample from the gig file
1872 if (group) {
1873 // temporarily remember the samples that bolong to that group (we need that to clean the queue)
1874 std::list<gig::Sample*> members;
1875 for (gig::Sample* pSample = group->GetFirstSample(); pSample; pSample = group->GetNextSample()) {
1876 members.push_back(pSample);
1877 }
1878 // delete the group in the .gig file including the samples that belong to the group
1879 file->DeleteGroup(group);
1880 // if sample(s) were just previously added, remove them from the import queue
1881 for (std::list<gig::Sample*>::iterator member = members.begin(); member != members.end(); ++member) {
1882 for (std::list<SampleImportItem>::iterator iter = m_SampleImportQueue.begin(); iter != m_SampleImportQueue.end(); ++iter) {
1883 if ((*iter).gig_sample == *member) {
1884 printf("Removing previously added sample '%s' from group '%s'\n", (*iter).sample_path.c_str(), name.c_str());
1885 m_SampleImportQueue.erase(iter);
1886 break;
1887 }
1888 }
1889 }
1890 } else if (sample) {
1891 // remove sample from the .gig file
1892 file->DeleteSample(sample);
1893 // if sample was just previously added, remove it from the import queue
1894 for (std::list<SampleImportItem>::iterator iter = m_SampleImportQueue.begin(); iter != m_SampleImportQueue.end(); ++iter) {
1895 if ((*iter).gig_sample == sample) {
1896 printf("Removing previously added sample '%s'\n", (*iter).sample_path.c_str());
1897 m_SampleImportQueue.erase(iter);
1898 break;
1899 }
1900 }
1901 }
1902 // remove respective row(s) from samples tree view
1903 m_refSamplesTreeModel->erase(it);
1904 } catch (RIFF::Exception e) {
1905 Gtk::MessageDialog msg(*this, e.Message.c_str(), false, Gtk::MESSAGE_ERROR);
1906 msg.run();
1907 }
1908 }
1909 }

  ViewVC Help
Powered by ViewVC