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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1096 - (hide annotations) (download)
Tue Mar 13 17:14:38 2007 UTC (17 years, 1 month 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 persson 1052 /*
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 schoenebeck 1084 #include <gtkmm/messagedialog.h>
31 schoenebeck 1096 #include <gtkmm/targetentry.h>
32 persson 1052 #endif
33    
34 schoenebeck 1085 #include <stdio.h>
35     #include <sndfile.h>
36    
37 persson 1052 #define _(String) gettext(String)
38    
39 schoenebeck 1082 template<class T> inline std::string ToString(T o) {
40     std::stringstream ss;
41     ss << o;
42     return ss.str();
43     }
44    
45 persson 1052 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 persson 1088 // set_default_size(400, 200);
523 persson 1052
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 schoenebeck 1080 // Add the TreeView tab, inside a ScrolledWindow, with the button underneath:
536 persson 1088 m_ScrolledWindow.add(m_TreeView);
537     // m_ScrolledWindow.set_size_request(200, 600);
538 persson 1052 m_ScrolledWindow.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
539    
540 persson 1088 m_ScrolledWindowSamples.add(m_TreeViewSamples);
541     m_ScrolledWindowSamples.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
542    
543    
544 persson 1052 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 schoenebeck 1096 //TODO: the following would break drag&drop: wSample->property_editable().set_value(false); or this: wSample->set_editable(false);
555 persson 1052 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 persson 1088 // m_Notebook.set_size_request(400, 500);
794 persson 1052
795 persson 1088 m_TreeViewNotebook.set_size_request(300);
796     m_HPaned.add1(m_TreeViewNotebook);
797 persson 1052 m_HPaned.add2(m_Notebook);
798    
799    
800 persson 1088 m_TreeViewNotebook.append_page(m_ScrolledWindowSamples, "Samples");
801     m_TreeViewNotebook.append_page(m_ScrolledWindow, "Instruments");
802 schoenebeck 1080
803    
804 persson 1052 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 schoenebeck 1069 actionGroup->add(Gtk::Action::create("MenuInstrument", _("_Instrument")));
838    
839 persson 1052 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 schoenebeck 1082 action = Gtk::Action::create("Remove", Gtk::Stock::REMOVE);
848 persson 1052 actionGroup->add(action,
849     sigc::mem_fun(
850     *this, &MainWindow::hide));
851    
852 schoenebeck 1082 // 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 schoenebeck 1085 Gtk::Action::create("AddSample", _("Add _Sample(s)")),
863 schoenebeck 1082 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 persson 1052 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 schoenebeck 1069 " <menu action='MenuInstrument'>"
889     " </menu>"
890 persson 1052 #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 schoenebeck 1082 " <popup name='SamplePopupMenu'>"
901     " <menuitem action='SampleProperties'/>"
902     " <menuitem action='AddGroup'/>"
903     " <menuitem action='AddSample'/>"
904     " <separator/>"
905     " <menuitem action='RemoveSample'/>"
906     " </popup>"
907 persson 1052 "</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 schoenebeck 1080 // create samples treeview (including its data model)
933 schoenebeck 1096 m_refSamplesTreeModel = SamplesTreeStore::create(m_SamplesModel);
934 schoenebeck 1080 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 schoenebeck 1082 m_TreeViewSamples.signal_button_press_event().connect_notify(
938     sigc::mem_fun(*this, &MainWindow::on_sample_treeview_button_release)
939     );
940 schoenebeck 1080
941 schoenebeck 1096 // 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 persson 1052 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 schoenebeck 1087 m_SampleImportQueue.clear();
1301 persson 1052 }
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 schoenebeck 1069 // 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 schoenebeck 1087 m_SampleImportQueue.clear();
1324 persson 1052 m_refTreeModel->clear();
1325 schoenebeck 1080 m_refSamplesTreeModel->clear();
1326 persson 1052 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 schoenebeck 1087 if (!file) return;
1364 schoenebeck 1094 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 schoenebeck 1087 __import_queued_samples();
1375 persson 1052 }
1376    
1377     void MainWindow::on_action_file_save_as()
1378     {
1379 schoenebeck 1087 if (!file) return;
1380 persson 1052 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 schoenebeck 1094 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 schoenebeck 1087 __import_queued_samples();
1397 persson 1052 }
1398     }
1399    
1400 schoenebeck 1087 // actually write the sample(s)' data to the gig file
1401     void MainWindow::__import_queued_samples() {
1402 schoenebeck 1094 std::cout << "Starting sample import\n" << std::flush;
1403 schoenebeck 1087 Glib::ustring error_files;
1404 schoenebeck 1094 printf("Samples to import: %d\n", m_SampleImportQueue.size());
1405 schoenebeck 1091 for (std::list<SampleImportItem>::iterator iter = m_SampleImportQueue.begin(); iter != m_SampleImportQueue.end(); ) {
1406 schoenebeck 1087 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 schoenebeck 1091 std::list<SampleImportItem>::iterator cur = iter;
1460     ++iter;
1461     m_SampleImportQueue.erase(cur);
1462 schoenebeck 1087 } 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 schoenebeck 1091 ++iter;
1466 schoenebeck 1087 }
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 persson 1052 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 schoenebeck 1069 Gtk::MenuItem* instrument_menu =
1655     dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/MenuBar/MenuInstrument"));
1656    
1657     int instrument_index = 0;
1658 schoenebeck 1075 Gtk::RadioMenuItem::Group instrument_group;
1659 persson 1052 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 schoenebeck 1069 // create a menu item for this instrument
1666 schoenebeck 1075 Gtk::RadioMenuItem* item= new Gtk::RadioMenuItem(instrument_group, instrument->pInfo->Name.c_str());
1667 schoenebeck 1069 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 persson 1052 }
1676 schoenebeck 1069 instrument_menu->show();
1677     instrument_menu->get_submenu()->show_all_children();
1678 schoenebeck 1080
1679     for (gig::Group* group = gig->GetFirstGroup(); group; group = gig->GetNextGroup()) {
1680 persson 1088 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 schoenebeck 1080 }
1694     }
1695 persson 1052 }
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 schoenebeck 1069
1717     void MainWindow::on_instrument_selection_change(int index) {
1718     m_RegionChooser.set_instrument(file->GetInstrument(index));
1719     }
1720 schoenebeck 1082
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 schoenebeck 1085 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 schoenebeck 1091 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 schoenebeck 1085 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 schoenebeck 1087 bitdepth = 16; // we simply convert to 16 bit for now
1816 schoenebeck 1085 break;
1817     case SF_FORMAT_PCM_16:
1818     bitdepth = 16;
1819     break;
1820     case SF_FORMAT_PCM_24:
1821 schoenebeck 1087 bitdepth = 32; // we simply convert to 32 bit for now
1822 schoenebeck 1085 break;
1823     case SF_FORMAT_PCM_32:
1824     bitdepth = 32;
1825     break;
1826 schoenebeck 1087 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 schoenebeck 1085 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 schoenebeck 1087 sample->pInfo->Name = (*iter).substr((*iter).rfind('/') + 1).raw(); // file name without path
1842 schoenebeck 1085 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 schoenebeck 1091 // make sure sample is part of the selected group
1849     group->AddSample(sample);
1850 schoenebeck 1087 // 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 schoenebeck 1085 // 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 schoenebeck 1082 }
1876    
1877     void MainWindow::on_action_remove_sample() {
1878 schoenebeck 1084 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 schoenebeck 1091 Glib::ustring name = row[m_SamplesModel.m_col_name];
1886 schoenebeck 1084 try {
1887     // remove group or sample from the gig file
1888     if (group) {
1889 schoenebeck 1091 // 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 schoenebeck 1084 file->DeleteGroup(group);
1896 schoenebeck 1091 // 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 schoenebeck 1084 } else if (sample) {
1907 schoenebeck 1091 // remove sample from the .gig file
1908 schoenebeck 1084 file->DeleteSample(sample);
1909 schoenebeck 1091 // if sample was just previously added, remove it from the import queue
1910 schoenebeck 1087 for (std::list<SampleImportItem>::iterator iter = m_SampleImportQueue.begin(); iter != m_SampleImportQueue.end(); ++iter) {
1911     if ((*iter).gig_sample == sample) {
1912 schoenebeck 1091 printf("Removing previously added sample '%s'\n", (*iter).sample_path.c_str());
1913 schoenebeck 1087 m_SampleImportQueue.erase(iter);
1914     break;
1915     }
1916     }
1917     }
1918 schoenebeck 1084 // 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 schoenebeck 1082 }
1926 schoenebeck 1096
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