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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1096 - (show annotations) (download)
Tue Mar 13 17:14:38 2007 UTC (17 years ago) by schoenebeck
File size: 73156 byte(s)
* implemented drag&drop samples tree view -> dimension region sample text
  entry field, to allow assigning / changing samples of dimension regions

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

  ViewVC Help
Powered by ViewVC