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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1088 - (show annotations) (download)
Sat Mar 10 08:16:38 2007 UTC (17 years, 1 month ago) by persson
File size: 68287 byte(s)
* fixed scrollbar behaviour on sample and instrument lists

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

  ViewVC Help
Powered by ViewVC