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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1097 - (show annotations) (download)
Wed Mar 14 23:19:26 2007 UTC (17 years ago) by schoenebeck
File size: 74423 byte(s)
* implemented renaming of samples, groups and instruments

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 m_refTreeModel->signal_row_changed().connect(
928 sigc::mem_fun(*this, &MainWindow::instrument_name_changed)
929 );
930
931 // Add the TreeView's view columns:
932 m_TreeView.append_column_editable("Instrument", m_Columns.m_col_name);
933 m_TreeView.set_headers_visible(false);
934
935 // create samples treeview (including its data model)
936 m_refSamplesTreeModel = SamplesTreeStore::create(m_SamplesModel);
937 m_TreeViewSamples.set_model(m_refSamplesTreeModel);
938 m_TreeViewSamples.append_column_editable("Samples", m_SamplesModel.m_col_name);
939 m_TreeViewSamples.set_headers_visible(false);
940 m_TreeViewSamples.signal_button_press_event().connect_notify(
941 sigc::mem_fun(*this, &MainWindow::on_sample_treeview_button_release)
942 );
943 m_refSamplesTreeModel->signal_row_changed().connect(
944 sigc::mem_fun(*this, &MainWindow::sample_name_changed)
945 );
946
947 // establish drag&drop between samples tree view and dimension region 'Sample' text entry
948 std::list<Gtk::TargetEntry> drag_target_gig_sample;
949 drag_target_gig_sample.push_back( Gtk::TargetEntry("gig::Sample") );
950 //drag_target_gig_sample.push_back( Gtk::TargetEntry("STRING") );
951 //drag_target_gig_sample.push_back( Gtk::TargetEntry("text/plain") );
952 m_TreeViewSamples.drag_source_set(drag_target_gig_sample);
953 m_TreeViewSamples.signal_drag_data_get().connect(
954 sigc::mem_fun(*this, &MainWindow::on_sample_treeview_drag_data_get)
955 );
956 wSample->drag_dest_set(drag_target_gig_sample);
957 wSample->signal_drag_data_received().connect(
958 sigc::mem_fun(*this, &MainWindow::on_sample_label_drop_drag_data_received)
959 );
960
961 file = 0;
962
963 show_all_children();
964 }
965
966 MainWindow::~MainWindow()
967 {
968 }
969
970 void MainWindow::region_changed()
971 {
972 m_DimRegionChooser.set_region(m_RegionChooser.get_region());
973 }
974
975 void MainWindow::dimreg_changed()
976 {
977 set_dim_region(m_DimRegionChooser.get_dimregion());
978 }
979
980 void MainWindow::on_sel_change()
981 {
982 Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();
983
984 Gtk::TreeModel::iterator it = tree_sel_ref->get_selected();
985 if (it)
986 {
987 Gtk::TreeModel::Row row = *it;
988 std::cout << row[m_Columns.m_col_name] << std::endl;
989
990 if (row[m_Columns.m_col_instr])
991 m_RegionChooser.set_instrument(row[m_Columns.m_col_instr]);
992 }
993 }
994
995 void MainWindow::set_dim_region(gig::DimensionRegion* d)
996 {
997 update_gui = false;
998 wSample->set_text(d->pSample ? d->pSample->pInfo->Name.c_str() : "NULL");
999 eEG1PreAttack.set_dimreg(d);
1000 eEG1Attack.set_dimreg(d);
1001 eEG1Decay1.set_dimreg(d);
1002 eEG1Decay2.set_dimreg(d);
1003 eEG1InfiniteSustain.set_dimreg(d);
1004 eEG1Sustain.set_dimreg(d);
1005 eEG1Release.set_dimreg(d);
1006 eEG1Hold.set_dimreg(d);
1007 eEG1Controller.set_dimreg(d);
1008 eEG1ControllerInvert.set_dimreg(d);
1009 eEG1ControllerAttackInfluence.set_dimreg(d);
1010 eEG1ControllerDecayInfluence.set_dimreg(d);
1011 eEG1ControllerReleaseInfluence.set_dimreg(d);
1012 eLFO1Frequency.set_dimreg(d);
1013 eLFO1InternalDepth.set_dimreg(d);
1014 eLFO1ControlDepth.set_dimreg(d);
1015 eLFO1Controller.set_dimreg(d);
1016 eLFO1FlipPhase.set_dimreg(d);
1017 eLFO1Sync.set_dimreg(d);
1018 eEG2PreAttack.set_dimreg(d);
1019 eEG2Attack.set_dimreg(d);
1020 eEG2Decay1.set_dimreg(d);
1021 eEG2Decay2.set_dimreg(d);
1022 eEG2InfiniteSustain.set_dimreg(d);
1023 eEG2Sustain.set_dimreg(d);
1024 eEG2Release.set_dimreg(d);
1025 eEG2Controller.set_dimreg(d);
1026 eEG2ControllerInvert.set_dimreg(d);
1027 eEG2ControllerAttackInfluence.set_dimreg(d);
1028 eEG2ControllerDecayInfluence.set_dimreg(d);
1029 eEG2ControllerReleaseInfluence.set_dimreg(d);
1030 eLFO2Frequency.set_dimreg(d);
1031 eLFO2InternalDepth.set_dimreg(d);
1032 eLFO2ControlDepth.set_dimreg(d);
1033 eLFO2Controller.set_dimreg(d);
1034 eLFO2FlipPhase.set_dimreg(d);
1035 eLFO2Sync.set_dimreg(d);
1036 eEG3Attack.set_dimreg(d);
1037 eEG3Depth.set_dimreg(d);
1038 eLFO3Frequency.set_dimreg(d);
1039 eLFO3InternalDepth.set_dimreg(d);
1040 eLFO3ControlDepth.set_dimreg(d);
1041 eLFO3Controller.set_dimreg(d);
1042 eLFO3Sync.set_dimreg(d);
1043 eVCFEnabled.set_dimreg(d);
1044 eVCFType.set_dimreg(d);
1045 eVCFCutoffController.set_dimreg(d);
1046 eVCFCutoffControllerInvert.set_dimreg(d);
1047 eVCFCutoff.set_dimreg(d);
1048 eVCFVelocityCurve.set_dimreg(d);
1049 eVCFVelocityScale.set_dimreg(d);
1050 eVCFVelocityDynamicRange.set_dimreg(d);
1051 eVCFResonance.set_dimreg(d);
1052 eVCFResonanceDynamic.set_dimreg(d);
1053 eVCFResonanceController.set_dimreg(d);
1054 eVCFKeyboardTracking.set_dimreg(d);
1055 eVCFKeyboardTrackingBreakpoint.set_dimreg(d);
1056 eVelocityResponseCurve.set_dimreg(d);
1057 eVelocityResponseDepth.set_dimreg(d);
1058 eVelocityResponseCurveScaling.set_dimreg(d);
1059 eReleaseVelocityResponseCurve.set_dimreg(d);
1060 eReleaseVelocityResponseDepth.set_dimreg(d);
1061 eReleaseTriggerDecay.set_dimreg(d);
1062 eCrossfade_in_start.set_dimreg(d);
1063 eCrossfade_in_end.set_dimreg(d);
1064 eCrossfade_out_start.set_dimreg(d);
1065 eCrossfade_out_end.set_dimreg(d);
1066 ePitchTrack.set_dimreg(d);
1067 eDimensionBypass.set_dimreg(d);
1068 ePan.set_dimreg(d);
1069 eSelfMask.set_dimreg(d);
1070 eAttenuationController.set_dimreg(d);
1071 eInvertAttenuationController.set_dimreg(d);
1072 eAttenuationControllerThreshold.set_dimreg(d);
1073 eChannelOffset.set_dimreg(d);
1074 eSustainDefeat.set_dimreg(d);
1075 eMSDecode.set_dimreg(d);
1076 eSampleStartOffset.set_dimreg(d);
1077 eUnityNote.set_dimreg(d);
1078 eFineTune.set_dimreg(d);
1079 eGain.set_dimreg(d);
1080 eSampleLoops.set_dimreg(d);
1081
1082 VCFEnabled_toggled();
1083
1084 update_gui = true;
1085 }
1086
1087 void MainWindow::VCFEnabled_toggled()
1088 {
1089 bool sensitive = eVCFEnabled.get_active();
1090 eVCFType.set_sensitive(sensitive);
1091 eVCFCutoffController.set_sensitive(sensitive);
1092 eVCFVelocityCurve.set_sensitive(sensitive);
1093 eVCFVelocityScale.set_sensitive(sensitive);
1094 eVCFVelocityDynamicRange.set_sensitive(sensitive);
1095 eVCFResonance.set_sensitive(sensitive);
1096 eVCFResonanceController.set_sensitive(sensitive);
1097 eVCFKeyboardTracking.set_sensitive(sensitive);
1098 eVCFKeyboardTrackingBreakpoint.set_sensitive(sensitive);
1099 eEG2PreAttack.set_sensitive(sensitive);
1100 eEG2Attack.set_sensitive(sensitive);
1101 eEG2Decay1.set_sensitive(sensitive);
1102 eEG2InfiniteSustain.set_sensitive(sensitive);
1103 eEG2Sustain.set_sensitive(sensitive);
1104 eEG2Release.set_sensitive(sensitive);
1105 eEG2Controller.set_sensitive(sensitive);
1106 eEG2ControllerAttackInfluence.set_sensitive(sensitive);
1107 eEG2ControllerDecayInfluence.set_sensitive(sensitive);
1108 eEG2ControllerReleaseInfluence.set_sensitive(sensitive);
1109 eLFO2Frequency.set_sensitive(sensitive);
1110 eLFO2InternalDepth.set_sensitive(sensitive);
1111 eLFO2ControlDepth.set_sensitive(sensitive);
1112 eLFO2Controller.set_sensitive(sensitive);
1113 eLFO2FlipPhase.set_sensitive(sensitive);
1114 eLFO2Sync.set_sensitive(sensitive);
1115 if (sensitive) {
1116 VCFCutoffController_changed();
1117 VCFResonanceController_changed();
1118 EG2InfiniteSustain_toggled();
1119 EG2Controller_changed();
1120 LFO2Controller_changed();
1121 } else {
1122 eVCFCutoffControllerInvert.set_sensitive(false);
1123 eVCFCutoff.set_sensitive(false);
1124 eVCFResonanceDynamic.set_sensitive(false);
1125 eVCFResonance.set_sensitive(false);
1126 eEG2Decay2.set_sensitive(false);
1127 eEG2ControllerInvert.set_sensitive(false);
1128 eLFO2InternalDepth.set_sensitive(false);
1129 eLFO2ControlDepth.set_sensitive(false);
1130 }
1131 }
1132
1133 void MainWindow::VCFCutoffController_changed()
1134 {
1135 int rowno = eVCFCutoffController.get_active_row_number();
1136 bool hasController = rowno != 0 && rowno != 1;
1137
1138 eVCFCutoffControllerInvert.set_sensitive(hasController);
1139 eVCFCutoff.set_sensitive(!hasController);
1140 eVCFResonanceDynamic.set_sensitive(!hasController);
1141 eVCFVelocityScale.label.set_text(hasController ? "MinimumCutoff:" :
1142 "VelocityScale:");
1143 }
1144
1145 void MainWindow::VCFResonanceController_changed()
1146 {
1147 bool hasController = eVCFResonanceController.get_active_row_number() != 0;
1148 eVCFResonance.set_sensitive(!hasController);
1149 }
1150
1151 void MainWindow::EG1InfiniteSustain_toggled()
1152 {
1153 bool infSus = eEG1InfiniteSustain.get_active();
1154 eEG1Decay2.set_sensitive(!infSus);
1155 }
1156
1157 void MainWindow::EG2InfiniteSustain_toggled()
1158 {
1159 bool infSus = eEG2InfiniteSustain.get_active();
1160 eEG2Decay2.set_sensitive(!infSus);
1161 }
1162
1163 void MainWindow::EG1Controller_changed()
1164 {
1165 bool hasController = eEG1Controller.get_active_row_number() != 0;
1166 eEG1ControllerInvert.set_sensitive(hasController);
1167 }
1168
1169 void MainWindow::EG2Controller_changed()
1170 {
1171 bool hasController = eEG2Controller.get_active_row_number() != 0;
1172 eEG2ControllerInvert.set_sensitive(hasController);
1173 }
1174
1175 void MainWindow::AttenuationController_changed()
1176 {
1177 bool hasController = eAttenuationController.get_active_row_number() != 0;
1178 eInvertAttenuationController.set_sensitive(hasController);
1179 }
1180
1181 void MainWindow::LFO1Controller_changed()
1182 {
1183 int rowno = eLFO1Controller.get_active_row_number();
1184 eLFO1ControlDepth.set_sensitive(rowno != 0);
1185 eLFO1InternalDepth.set_sensitive(rowno != 1 && rowno != 2);
1186 }
1187
1188 void MainWindow::LFO2Controller_changed()
1189 {
1190 int rowno = eLFO2Controller.get_active_row_number();
1191 eLFO2ControlDepth.set_sensitive(rowno != 0);
1192 eLFO2InternalDepth.set_sensitive(rowno != 1 && rowno != 2);
1193 }
1194
1195 void MainWindow::LFO3Controller_changed()
1196 {
1197 int rowno = eLFO3Controller.get_active_row_number();
1198 eLFO3ControlDepth.set_sensitive(rowno != 0);
1199 eLFO3InternalDepth.set_sensitive(rowno != 1 && rowno != 2);
1200 }
1201
1202 void MainWindow::crossfade1_changed()
1203 {
1204 double c1 = eCrossfade_in_start.get_value();
1205 double c2 = eCrossfade_in_end.get_value();
1206 if (c1 > c2) eCrossfade_in_end.set_value(c1);
1207 }
1208
1209 void MainWindow::crossfade2_changed()
1210 {
1211 double c1 = eCrossfade_in_start.get_value();
1212 double c2 = eCrossfade_in_end.get_value();
1213 double c3 = eCrossfade_out_start.get_value();
1214
1215 if (c2 < c1) eCrossfade_in_start.set_value(c2);
1216 if (c2 > c3) eCrossfade_out_start.set_value(c2);
1217 }
1218
1219 void MainWindow::crossfade3_changed()
1220 {
1221 double c2 = eCrossfade_in_end.get_value();
1222 double c3 = eCrossfade_out_start.get_value();
1223 double c4 = eCrossfade_out_end.get_value();
1224
1225 if (c3 < c2) eCrossfade_in_end.set_value(c3);
1226 if (c3 > c4) eCrossfade_out_end.set_value(c3);
1227 }
1228
1229 void MainWindow::crossfade4_changed()
1230 {
1231 double c3 = eCrossfade_out_start.get_value();
1232 double c4 = eCrossfade_out_end.get_value();
1233
1234 if (c4 < c3) eCrossfade_out_start.set_value(c4);
1235 }
1236
1237 void loader_progress_callback(gig::progress_t* progress)
1238 {
1239 Loader* loader = static_cast<Loader*>(progress->custom);
1240 loader->progress_callback(progress->factor);
1241 }
1242
1243 void Loader::progress_callback(float fraction)
1244 {
1245 {
1246 Glib::Mutex::Lock lock(progressMutex);
1247 progress = fraction;
1248 }
1249 progress_dispatcher();
1250 }
1251
1252 void Loader::thread_function()
1253 {
1254 printf("thread_function self=%x\n", Glib::Thread::self());
1255 printf("Start %s\n", filename);
1256 RIFF::File* riff = new RIFF::File(filename);
1257 gig = new gig::File(riff);
1258 gig::progress_t progress;
1259 progress.callback = loader_progress_callback;
1260 progress.custom = this;
1261
1262 gig->GetInstrument(0, &progress);
1263 printf("End\n");
1264 finished_dispatcher();
1265 }
1266
1267 Loader::Loader(const char* filename)
1268 : thread(0), filename(filename)
1269 {
1270 }
1271
1272 void Loader::launch()
1273 {
1274 thread = Glib::Thread::create(sigc::mem_fun(*this, &Loader::thread_function), true);
1275 printf("launch thread=%x\n", thread);
1276 }
1277
1278 float Loader::get_progress()
1279 {
1280 float res;
1281 {
1282 Glib::Mutex::Lock lock(progressMutex);
1283 res = progress;
1284 }
1285 return res;
1286 }
1287
1288 Glib::Dispatcher& Loader::signal_progress()
1289 {
1290 return progress_dispatcher;
1291 }
1292
1293 Glib::Dispatcher& Loader::signal_finished()
1294 {
1295 return finished_dispatcher;
1296 }
1297
1298 LoadDialog::LoadDialog()
1299 {
1300 get_vbox()->pack_start(progressBar);
1301 show_all_children();
1302 }
1303
1304 void MainWindow::on_action_file_new()
1305 {
1306 m_SampleImportQueue.clear();
1307 }
1308
1309 void MainWindow::on_action_file_open()
1310 {
1311 Gtk::FileChooserDialog dialog(*this, _("Open file"));
1312 dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1313 dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);
1314 Gtk::FileFilter filter;
1315 filter.add_pattern("*.gig");
1316 dialog.set_filter(filter);
1317 if (dialog.run() == Gtk::RESPONSE_OK) {
1318 printf("filename=%s\n", dialog.get_filename().c_str());
1319
1320 // remove all entries from "Instrument" menu
1321 Gtk::MenuItem* instrument_menu =
1322 dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/MenuBar/MenuInstrument"));
1323 instrument_menu->hide();
1324 for (int i = 0; i < instrument_menu->get_submenu()->items().size(); i++) {
1325 delete &instrument_menu->get_submenu()->items()[i];
1326 }
1327 instrument_menu->get_submenu()->items().clear();
1328
1329 m_SampleImportQueue.clear();
1330 m_refTreeModel->clear();
1331 m_refSamplesTreeModel->clear();
1332 if (file) delete file;
1333
1334 // getInfo(dialog.get_filename().c_str(), *this);
1335
1336 printf("on_action_file_open self=%x\n", Glib::Thread::self());
1337 load_dialog = new LoadDialog(); // Gtk::Dialog("Loading...", *this, true);
1338 load_dialog->show_all();
1339 loader = new Loader(strdup(dialog.get_filename().c_str()));
1340 loader->signal_progress().connect(
1341 sigc::mem_fun(*this, &MainWindow::on_loader_progress));
1342 loader->signal_finished().connect(
1343 sigc::mem_fun(*this, &MainWindow::on_loader_finished));
1344
1345 loader->launch();
1346 }
1347 }
1348
1349 void MainWindow::on_loader_progress()
1350 {
1351 load_dialog->set_fraction(loader->get_progress());
1352 }
1353
1354 void MainWindow::on_loader_finished()
1355 {
1356 printf("Loader finished!\n");
1357 printf("on_loader_finished self=%x\n", Glib::Thread::self());
1358 load_gig(loader->gig, loader->filename);
1359
1360
1361 Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();
1362 tree_sel_ref->select(Gtk::TreePath("0"));
1363
1364 load_dialog->hide();
1365 }
1366
1367 void MainWindow::on_action_file_save()
1368 {
1369 if (!file) return;
1370 std::cout << "Saving file\n" << std::flush;
1371 try {
1372 file->Save();
1373 } catch (RIFF::Exception e) {
1374 Glib::ustring txt = "Could not save file: " + e.Message;
1375 Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
1376 msg.run();
1377 return;
1378 }
1379 std::cout << "Saving file done\n" << std::flush;
1380 __import_queued_samples();
1381 }
1382
1383 void MainWindow::on_action_file_save_as()
1384 {
1385 if (!file) return;
1386 Gtk::FileChooserDialog dialog(*this, "Open", Gtk::FILE_CHOOSER_ACTION_SAVE);
1387 dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1388 dialog.add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK);
1389 Gtk::FileFilter filter;
1390 filter.add_pattern("*.gig");
1391 dialog.set_filter(filter);
1392 if (dialog.run() == Gtk::RESPONSE_OK) {
1393 printf("filename=%s\n", dialog.get_filename().c_str());
1394 try {
1395 file->Save(dialog.get_filename());
1396 } catch (RIFF::Exception e) {
1397 Glib::ustring txt = "Could not save file: " + e.Message;
1398 Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
1399 msg.run();
1400 return;
1401 }
1402 __import_queued_samples();
1403 }
1404 }
1405
1406 // actually write the sample(s)' data to the gig file
1407 void MainWindow::__import_queued_samples() {
1408 std::cout << "Starting sample import\n" << std::flush;
1409 Glib::ustring error_files;
1410 printf("Samples to import: %d\n", m_SampleImportQueue.size());
1411 for (std::list<SampleImportItem>::iterator iter = m_SampleImportQueue.begin(); iter != m_SampleImportQueue.end(); ) {
1412 printf("Importing sample %s\n",(*iter).sample_path.c_str());
1413 SF_INFO info;
1414 info.format = 0;
1415 SNDFILE* hFile = sf_open((*iter).sample_path.c_str(), SFM_READ, &info);
1416 try {
1417 if (!hFile) throw std::string("could not open file");
1418 // determine sample's bit depth
1419 int bitdepth;
1420 switch (info.format & 0xff) {
1421 case SF_FORMAT_PCM_S8:
1422 bitdepth = 16; // we simply convert to 16 bit for now
1423 break;
1424 case SF_FORMAT_PCM_16:
1425 bitdepth = 16;
1426 break;
1427 case SF_FORMAT_PCM_24:
1428 bitdepth = 32; // we simply convert to 32 bit for now
1429 break;
1430 case SF_FORMAT_PCM_32:
1431 bitdepth = 32;
1432 break;
1433 case SF_FORMAT_PCM_U8:
1434 bitdepth = 16; // we simply convert to 16 bit for now
1435 break;
1436 case SF_FORMAT_FLOAT:
1437 bitdepth = 32;
1438 break;
1439 case SF_FORMAT_DOUBLE:
1440 bitdepth = 32; // I guess we will always truncate this to 32 bit
1441 break;
1442 default:
1443 sf_close(hFile); // close sound file
1444 throw std::string("format not supported"); // unsupported subformat (yet?)
1445 }
1446 // allocate appropriate copy buffer (TODO: for now we copy it in one piece, might be tough for very long samples)
1447 // and copy sample data into buffer
1448 int8_t* buffer = NULL;
1449 switch (bitdepth) {
1450 case 16:
1451 buffer = new int8_t[2 * info.channels * info.frames];
1452 sf_readf_short(hFile, (short*) buffer, info.frames); // libsndfile does the conversion for us (if needed)
1453 break;
1454 case 32:
1455 buffer = new int8_t[4 * info.channels * info.frames];
1456 sf_readf_int(hFile, (int*) buffer, info.frames); // libsndfile does the conversion for us (if needed)
1457 break;
1458 }
1459 // write from buffer directly (physically) into .gig file
1460 (*iter).gig_sample->Write(buffer, info.frames);
1461 // cleanup
1462 sf_close(hFile);
1463 delete buffer;
1464 // on success we remove the sample from the import queue, otherwise keep it, maybe it works the next time ?
1465 std::list<SampleImportItem>::iterator cur = iter;
1466 ++iter;
1467 m_SampleImportQueue.erase(cur);
1468 } catch (std::string what) { // remember the files that made trouble (and their cause)
1469 if (error_files.size()) error_files += "\n";
1470 error_files += (*iter).sample_path += " (" + what + ")";
1471 ++iter;
1472 }
1473 }
1474 // show error message box when some sample(s) could not be imported
1475 if (error_files.size()) {
1476 Glib::ustring txt = "Could not import the following sample(s):\n" + error_files;
1477 Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
1478 msg.run();
1479 }
1480 }
1481
1482 void MainWindow::on_action_file_properties()
1483 {
1484 propDialog.show();
1485 propDialog.deiconify();
1486 }
1487
1488 void MainWindow::on_action_help_about()
1489 {
1490 #ifdef ABOUT_DIALOG
1491 Gtk::AboutDialog dialog;
1492 dialog.set_version(VERSION);
1493 dialog.run();
1494 #endif
1495 }
1496
1497 PropDialog::PropDialog()
1498 : table(2,1)
1499 {
1500 table.set_col_spacings(5);
1501 char* propLabels[] = {
1502 "Name:",
1503 "CreationDate:",
1504 "Comments:", // TODO: multiline
1505 "Product:",
1506 "Copyright:",
1507 "Artists:",
1508 "Genre:",
1509 "Keywords:",
1510 "Engineer:",
1511 "Technician:",
1512 "Software:", // TODO: readonly
1513 "Medium:",
1514 "Source:",
1515 "SourceForm:",
1516 "Commissioned:",
1517 "Subject:"
1518 };
1519 for (int i = 0 ; i < sizeof(propLabels) / sizeof(char*) ; i++) {
1520 label[i].set_text(propLabels[i]);
1521 label[i].set_alignment(Gtk::ALIGN_LEFT);
1522 table.attach(label[i], 0, 1, i, i + 1, Gtk::FILL, Gtk::SHRINK);
1523 table.attach(entry[i], 1, 2, i, i + 1, Gtk::FILL | Gtk::EXPAND,
1524 Gtk::SHRINK);
1525 }
1526
1527 add(table);
1528 // add_button(Gtk::Stock::CANCEL, 0);
1529 // add_button(Gtk::Stock::OK, 1);
1530 show_all_children();
1531 }
1532
1533 void PropDialog::set_info(DLS::Info* info)
1534 {
1535 entry[0].set_text(info->Name);
1536 entry[1].set_text(info->CreationDate);
1537 entry[2].set_text(Glib::convert(info->Comments, "UTF-8", "ISO-8859-1"));
1538 entry[3].set_text(info->Product);
1539 entry[4].set_text(info->Copyright);
1540 entry[5].set_text(info->Artists);
1541 entry[6].set_text(info->Genre);
1542 entry[7].set_text(info->Keywords);
1543 entry[8].set_text(info->Engineer);
1544 entry[9].set_text(info->Technician);
1545 entry[10].set_text(info->Software);
1546 entry[11].set_text(info->Medium);
1547 entry[12].set_text(info->Source);
1548 entry[13].set_text(info->SourceForm);
1549 entry[14].set_text(info->Commissioned);
1550 entry[15].set_text(info->Subject);
1551 }
1552
1553
1554 InstrumentProps::InstrumentProps()
1555 : table(2,1),
1556 quitButton(Gtk::Stock::CLOSE)
1557 {
1558 table.set_col_spacings(5);
1559 char* propLabels[] = {
1560 "Name:",
1561 "IsDrum:",
1562 "MIDIBank:",
1563 "MIDIProgram:",
1564 "Attenuation:",
1565 "EffectSend:",
1566 "FineTune:",
1567 "PitchbendRange:",
1568 "PianoReleaseMode:",
1569 "DimensionKeyRange:",
1570 };
1571 int entryIdx = 0, checkIdx = 0;
1572 for (int i = 0 ; i < sizeof(propLabels) / sizeof(char*) ; i++) {
1573 label[i].set_text(propLabels[i]);
1574 label[i].set_alignment(Gtk::ALIGN_LEFT);
1575 table.attach(label[i], 0, 1, i, i + 1, Gtk::FILL, Gtk::SHRINK);
1576 if (i == 1 || i == 8)
1577 table.attach(check[checkIdx++], 1, 2, i, i + 1,
1578 Gtk::FILL | Gtk::EXPAND, Gtk::SHRINK);
1579 else
1580 table.attach(entry[entryIdx++], 1, 2, i, i + 1,
1581 Gtk::FILL | Gtk::EXPAND, Gtk::SHRINK);
1582 }
1583
1584 // vbox { table buttonBox { quitButton } }
1585
1586 //get_vbox()->pack_start(table);
1587 // set_border_width(6);
1588 add(vbox);
1589 table.set_border_width(2);
1590 vbox.pack_start(table);
1591 table.show();
1592 vbox.pack_start(buttonBox);
1593 buttonBox.set_layout(Gtk::BUTTONBOX_END);
1594 buttonBox.set_border_width(5);
1595 buttonBox.show();
1596 buttonBox.pack_start(quitButton);
1597 quitButton.set_flags(Gtk::CAN_DEFAULT);
1598 quitButton.grab_focus();
1599
1600 quitButton.signal_clicked().connect(
1601 sigc::mem_fun(*this, &InstrumentProps::hide));
1602
1603 // quitButton.grab_default();
1604 quitButton.show();
1605 // add(table);
1606 vbox.show();
1607 show_all_children();
1608 }
1609
1610
1611 void InstrumentProps::set_instrument(gig::Instrument* instrument)
1612 {
1613 char buf[100];
1614
1615 int entryIdx = 0, checkIdx = 0;
1616 entry[entryIdx++].set_text(instrument->pInfo->Name);
1617 check[checkIdx++].set_active(instrument->IsDrum);
1618 sprintf(buf, "%d", instrument->MIDIBank);
1619 entry[entryIdx++].set_text(buf);
1620 sprintf(buf, "%d", instrument->MIDIProgram);
1621 entry[entryIdx++].set_text(buf);
1622 sprintf(buf, "%d", instrument->Attenuation);
1623 entry[entryIdx++].set_text(buf);
1624 sprintf(buf, "%d", instrument->EffectSend);
1625 entry[entryIdx++].set_text(buf);
1626 sprintf(buf, "%d", instrument->FineTune);
1627 entry[entryIdx++].set_text(buf);
1628 sprintf(buf, "%d", instrument->PitchbendRange);
1629 entry[entryIdx++].set_text(buf);
1630 check[checkIdx++].set_active(instrument->PianoReleaseMode);
1631 sprintf(buf, "%s%d (%d)..%s%d (%d)",
1632 notes[instrument->DimensionKeyRange.low % 12],
1633 instrument->DimensionKeyRange.low / 12 - 1,
1634 instrument->DimensionKeyRange.low,
1635 notes[instrument->DimensionKeyRange.high % 12],
1636 instrument->DimensionKeyRange.high / 12 - 1,
1637 instrument->DimensionKeyRange.high);
1638 entry[entryIdx].set_text(buf);
1639 }
1640
1641 void MainWindow::getInfo(const char *filename)
1642 {
1643 RIFF::File* riff = new RIFF::File(filename);
1644 gig::File* gig = new gig::File(riff);
1645
1646 load_gig(gig, filename);
1647 }
1648
1649 void MainWindow::load_gig(gig::File* gig, const char* filename)
1650 {
1651 file = gig;
1652
1653 const char *basename = strrchr(filename, '/');
1654 basename = basename ? basename + 1 : filename;
1655
1656 set_title(basename);
1657
1658 propDialog.set_info(gig->pInfo);
1659
1660 Gtk::MenuItem* instrument_menu =
1661 dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/MenuBar/MenuInstrument"));
1662
1663 int instrument_index = 0;
1664 Gtk::RadioMenuItem::Group instrument_group;
1665 for (gig::Instrument* instrument = gig->GetFirstInstrument() ; instrument ;
1666 instrument = gig->GetNextInstrument()) {
1667 Gtk::TreeModel::iterator iter = m_refTreeModel->append();
1668 Gtk::TreeModel::Row row = *iter;
1669 row[m_Columns.m_col_name] = instrument->pInfo->Name.c_str();
1670 row[m_Columns.m_col_instr] = instrument;
1671 // create a menu item for this instrument
1672 Gtk::RadioMenuItem* item= new Gtk::RadioMenuItem(instrument_group, instrument->pInfo->Name.c_str());
1673 instrument_menu->get_submenu()->append(*item);
1674 item->signal_activate().connect(
1675 sigc::bind(
1676 sigc::mem_fun(*this, &MainWindow::on_instrument_selection_change),
1677 instrument_index
1678 )
1679 );
1680 instrument_index++;
1681 }
1682 instrument_menu->show();
1683 instrument_menu->get_submenu()->show_all_children();
1684
1685 for (gig::Group* group = gig->GetFirstGroup(); group; group = gig->GetNextGroup()) {
1686 if (group->Name != "") {
1687 Gtk::TreeModel::iterator iterGroup = m_refSamplesTreeModel->append();
1688 Gtk::TreeModel::Row rowGroup = *iterGroup;
1689 rowGroup[m_SamplesModel.m_col_name] = group->Name.c_str();
1690 rowGroup[m_SamplesModel.m_col_group] = group;
1691 rowGroup[m_SamplesModel.m_col_sample] = NULL;
1692 for (gig::Sample* sample = group->GetFirstSample(); sample; sample = group->GetNextSample()) {
1693 Gtk::TreeModel::iterator iterSample = m_refSamplesTreeModel->append(rowGroup.children());
1694 Gtk::TreeModel::Row rowSample = *iterSample;
1695 rowSample[m_SamplesModel.m_col_name] = sample->pInfo->Name.c_str();
1696 rowSample[m_SamplesModel.m_col_sample] = sample;
1697 rowSample[m_SamplesModel.m_col_group] = NULL;
1698 }
1699 }
1700 }
1701 }
1702
1703 void MainWindow::on_button_release(GdkEventButton* button)
1704 {
1705 if (button->type == GDK_2BUTTON_PRESS) {
1706 Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();
1707 Gtk::TreeModel::iterator it = tree_sel_ref->get_selected();
1708 if (it)
1709 {
1710 Gtk::TreeModel::Row row = *it;
1711 if (row[m_Columns.m_col_instr])
1712 {
1713 instrumentProps.set_instrument(row[m_Columns.m_col_instr]);
1714 instrumentProps.show();
1715 instrumentProps.deiconify();
1716 }
1717 }
1718 } else if (button->type == GDK_BUTTON_PRESS && button->button == 3) {
1719 popup_menu->popup(button->button, button->time);
1720 }
1721 }
1722
1723 void MainWindow::on_instrument_selection_change(int index) {
1724 m_RegionChooser.set_instrument(file->GetInstrument(index));
1725 }
1726
1727 void MainWindow::on_sample_treeview_button_release(GdkEventButton* button) {
1728 if (button->type == GDK_BUTTON_PRESS && button->button == 3) {
1729 Gtk::Menu* sample_popup =
1730 dynamic_cast<Gtk::Menu*>(uiManager->get_widget("/SamplePopupMenu"));
1731 // update enabled/disabled state of sample popup items
1732 Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();
1733 Gtk::TreeModel::iterator it = sel->get_selected();
1734 bool group_selected = false;
1735 bool sample_selected = false;
1736 if (it) {
1737 Gtk::TreeModel::Row row = *it;
1738 group_selected = row[m_SamplesModel.m_col_group];
1739 sample_selected = row[m_SamplesModel.m_col_sample];
1740 }
1741 dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/SamplePopupMenu/SampleProperties"))->set_sensitive(group_selected || sample_selected);
1742 dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/SamplePopupMenu/AddSample"))->set_sensitive(group_selected || sample_selected);
1743 dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/SamplePopupMenu/AddGroup"))->set_sensitive(file);
1744 dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/SamplePopupMenu/RemoveSample"))->set_sensitive(group_selected || sample_selected);
1745 // show sample popup
1746 sample_popup->popup(button->button, button->time);
1747 }
1748 }
1749
1750 void MainWindow::on_action_sample_properties() {
1751 //TODO: show a dialog where the selected sample's properties can be edited
1752 }
1753
1754 void MainWindow::on_action_add_group() {
1755 static int __sample_indexer = 0;
1756 if (!file) return;
1757 gig::Group* group = file->AddGroup();
1758 group->Name = "Unnamed Group";
1759 if (__sample_indexer) group->Name += " " + ToString(__sample_indexer);
1760 __sample_indexer++;
1761 // update sample tree view
1762 Gtk::TreeModel::iterator iterGroup = m_refSamplesTreeModel->append();
1763 Gtk::TreeModel::Row rowGroup = *iterGroup;
1764 rowGroup[m_SamplesModel.m_col_name] = group->Name.c_str();
1765 rowGroup[m_SamplesModel.m_col_sample] = NULL;
1766 rowGroup[m_SamplesModel.m_col_group] = group;
1767 }
1768
1769 void MainWindow::on_action_add_sample() {
1770 if (!file) return;
1771 // get selected group
1772 Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();
1773 Gtk::TreeModel::iterator it = sel->get_selected();
1774 if (!it) return;
1775 Gtk::TreeModel::Row row = *it;
1776 gig::Group* group = row[m_SamplesModel.m_col_group];
1777 if (!group) { // not a group, but a sample is selected (probably)
1778 gig::Sample* sample = row[m_SamplesModel.m_col_sample];
1779 if (!sample) return;
1780 it = row.parent(); // resolve parent (that is the sample's group)
1781 if (!it) return;
1782 row = *it;
1783 group = row[m_SamplesModel.m_col_group];
1784 if (!group) return;
1785 }
1786 // show 'browse for file' dialog
1787 Gtk::FileChooserDialog dialog(*this, _("Add Sample(s)"));
1788 dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1789 dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);
1790 dialog.set_select_multiple(true);
1791 Gtk::FileFilter soundfilter; // matches all file types supported by libsndfile
1792 const char* supportedFileTypes[] = {
1793 "*.wav", "*.WAV", "*.aiff", "*.AIFF", "*.aifc", "*.AIFC", "*.snd",
1794 "*.SND", "*.au", "*.AU", "*.paf", "*.PAF", "*.iff", "*.IFF",
1795 "*.svx", "*.SVX", "*.sf", "*.SF", "*.voc", "*.VOC", "*.w64",
1796 "*.W64", "*.pvf", "*.PVF", "*.xi", "*.XI", "*.htk", "*.HTK",
1797 "*.caf", "*.CAF", NULL
1798 };
1799 for (int i = 0; supportedFileTypes[i]; i++)
1800 soundfilter.add_pattern(supportedFileTypes[i]);
1801 soundfilter.set_name("Sound Files");
1802 Gtk::FileFilter allpassfilter; // matches every file
1803 allpassfilter.add_pattern("*.*");
1804 allpassfilter.set_name("All Files");
1805 dialog.add_filter(soundfilter);
1806 dialog.add_filter(allpassfilter);
1807 if (dialog.run() == Gtk::RESPONSE_OK) {
1808 Glib::ustring error_files;
1809 Glib::SListHandle<Glib::ustring> filenames = dialog.get_filenames();
1810 for (Glib::SListHandle<Glib::ustring>::iterator iter = filenames.begin(); iter != filenames.end(); ++iter) {
1811 printf("Adding sample %s\n",(*iter).c_str());
1812 // use libsndfile to retrieve file informations
1813 SF_INFO info;
1814 info.format = 0;
1815 SNDFILE* hFile = sf_open((*iter).c_str(), SFM_READ, &info);
1816 try {
1817 if (!hFile) throw std::string("could not open file");
1818 int bitdepth;
1819 switch (info.format & 0xff) {
1820 case SF_FORMAT_PCM_S8:
1821 bitdepth = 16; // we simply convert to 16 bit for now
1822 break;
1823 case SF_FORMAT_PCM_16:
1824 bitdepth = 16;
1825 break;
1826 case SF_FORMAT_PCM_24:
1827 bitdepth = 32; // we simply convert to 32 bit for now
1828 break;
1829 case SF_FORMAT_PCM_32:
1830 bitdepth = 32;
1831 break;
1832 case SF_FORMAT_PCM_U8:
1833 bitdepth = 16; // we simply convert to 16 bit for now
1834 break;
1835 case SF_FORMAT_FLOAT:
1836 bitdepth = 32;
1837 break;
1838 case SF_FORMAT_DOUBLE:
1839 bitdepth = 32; // I guess we will always truncate this to 32 bit
1840 break;
1841 default:
1842 sf_close(hFile); // close sound file
1843 throw std::string("format not supported"); // unsupported subformat (yet?)
1844 }
1845 // add a new sample to the .gig file
1846 gig::Sample* sample = file->AddSample();
1847 sample->pInfo->Name = (*iter).substr((*iter).rfind('/') + 1).raw(); // file name without path
1848 sample->Channels = info.channels;
1849 sample->BitDepth = bitdepth;
1850 sample->FrameSize = bitdepth / 8/*1 byte are 8 bits*/ * info.channels;
1851 sample->SamplesPerSecond = info.samplerate;
1852 // schedule resizing the sample (which will be done physically when File::Save() is called)
1853 sample->Resize(info.frames);
1854 // make sure sample is part of the selected group
1855 group->AddSample(sample);
1856 // schedule that physical resize and sample import (data copying), performed when "Save" is requested
1857 SampleImportItem sched_item;
1858 sched_item.gig_sample = sample;
1859 sched_item.sample_path = *iter;
1860 m_SampleImportQueue.push_back(sched_item);
1861 // add sample to the tree view
1862 Gtk::TreeModel::iterator iterSample = m_refSamplesTreeModel->append(row.children());
1863 Gtk::TreeModel::Row rowSample = *iterSample;
1864 rowSample[m_SamplesModel.m_col_name] = sample->pInfo->Name.c_str();
1865 rowSample[m_SamplesModel.m_col_sample] = sample;
1866 rowSample[m_SamplesModel.m_col_group] = NULL;
1867 // close sound file
1868 sf_close(hFile);
1869 } catch (std::string what) { // remember the files that made trouble (and their cause)
1870 if (error_files.size()) error_files += "\n";
1871 error_files += *iter += " (" + what + ")";
1872 }
1873 }
1874 // show error message box when some file(s) could not be opened / added
1875 if (error_files.size()) {
1876 Glib::ustring txt = "Could not add the following sample(s):\n" + error_files;
1877 Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
1878 msg.run();
1879 }
1880 }
1881 }
1882
1883 void MainWindow::on_action_remove_sample() {
1884 if (!file) return;
1885 Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();
1886 Gtk::TreeModel::iterator it = sel->get_selected();
1887 if (it) {
1888 Gtk::TreeModel::Row row = *it;
1889 gig::Group* group = row[m_SamplesModel.m_col_group];
1890 gig::Sample* sample = row[m_SamplesModel.m_col_sample];
1891 Glib::ustring name = row[m_SamplesModel.m_col_name];
1892 try {
1893 // remove group or sample from the gig file
1894 if (group) {
1895 // temporarily remember the samples that bolong to that group (we need that to clean the queue)
1896 std::list<gig::Sample*> members;
1897 for (gig::Sample* pSample = group->GetFirstSample(); pSample; pSample = group->GetNextSample()) {
1898 members.push_back(pSample);
1899 }
1900 // delete the group in the .gig file including the samples that belong to the group
1901 file->DeleteGroup(group);
1902 // if sample(s) were just previously added, remove them from the import queue
1903 for (std::list<gig::Sample*>::iterator member = members.begin(); member != members.end(); ++member) {
1904 for (std::list<SampleImportItem>::iterator iter = m_SampleImportQueue.begin(); iter != m_SampleImportQueue.end(); ++iter) {
1905 if ((*iter).gig_sample == *member) {
1906 printf("Removing previously added sample '%s' from group '%s'\n", (*iter).sample_path.c_str(), name.c_str());
1907 m_SampleImportQueue.erase(iter);
1908 break;
1909 }
1910 }
1911 }
1912 } else if (sample) {
1913 // remove sample from the .gig file
1914 file->DeleteSample(sample);
1915 // if sample was just previously added, remove it from the import queue
1916 for (std::list<SampleImportItem>::iterator iter = m_SampleImportQueue.begin(); iter != m_SampleImportQueue.end(); ++iter) {
1917 if ((*iter).gig_sample == sample) {
1918 printf("Removing previously added sample '%s'\n", (*iter).sample_path.c_str());
1919 m_SampleImportQueue.erase(iter);
1920 break;
1921 }
1922 }
1923 }
1924 // remove respective row(s) from samples tree view
1925 m_refSamplesTreeModel->erase(it);
1926 } catch (RIFF::Exception e) {
1927 Gtk::MessageDialog msg(*this, e.Message.c_str(), false, Gtk::MESSAGE_ERROR);
1928 msg.run();
1929 }
1930 }
1931 }
1932
1933 void MainWindow::on_sample_treeview_drag_data_get(const Glib::RefPtr<Gdk::DragContext>&, Gtk::SelectionData& selection_data, guint, guint)
1934 {
1935 // get selected sample
1936 gig::Sample* sample = NULL;
1937 Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();
1938 Gtk::TreeModel::iterator it = sel->get_selected();
1939 if (it) {
1940 Gtk::TreeModel::Row row = *it;
1941 sample = row[m_SamplesModel.m_col_sample];
1942 }
1943 // pass the gig::Sample as pointer
1944 selection_data.set(selection_data.get_target(), 0/*unused*/, (const guchar*)&sample, sizeof(sample)/*length of data in bytes*/);
1945 }
1946
1947 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)
1948 {
1949 gig::DimensionRegion* dimregion = m_DimRegionChooser.get_dimregion();
1950 gig::Sample* sample = *((gig::Sample**) selection_data.get_data());
1951
1952 if (sample && dimregion && selection_data.get_length() == sizeof(gig::Sample*)) {
1953 if (sample != dimregion->pSample) {
1954 dimregion->pSample = sample;
1955 wSample->set_text(dimregion->pSample->pInfo->Name.c_str());
1956 std::cout << "Drop received sample \"" << dimregion->pSample->pInfo->Name.c_str() << "\"" << std::endl;
1957 // drop success
1958 context->drop_reply(true, time);
1959 return;
1960 }
1961 }
1962 // drop failed
1963 context->drop_reply(false, time);
1964 }
1965
1966 void MainWindow::sample_name_changed(const Gtk::TreeModel::Path& path, const Gtk::TreeModel::iterator& iter) {
1967 if (!iter) return;
1968 Gtk::TreeModel::Row row = *iter;
1969 Glib::ustring name = row[m_SamplesModel.m_col_name];
1970 gig::Group* group = row[m_SamplesModel.m_col_group];
1971 gig::Sample* sample = row[m_SamplesModel.m_col_sample];
1972 if (group) {
1973 group->Name = name;
1974 std::cout << "Group name changed\n" << std::flush;
1975 } else if (sample) {
1976 sample->pInfo->Name = name.raw();
1977 std::cout << "Sample name changed\n" << std::flush;
1978 }
1979 }
1980
1981 void MainWindow::instrument_name_changed(const Gtk::TreeModel::Path& path, const Gtk::TreeModel::iterator& iter) {
1982 std::cout << "Instrument name changed\n" << std::flush;
1983 if (!iter) return;
1984 Gtk::TreeModel::Row row = *iter;
1985 Glib::ustring name = row[m_Columns.m_col_name];
1986 gig::Instrument* instrument = row[m_Columns.m_col_instr];
1987 if (instrument) instrument->pInfo->Name = name.raw();
1988 }

  ViewVC Help
Powered by ViewVC