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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1092 - (hide annotations) (download)
Sun Mar 11 15:21:58 2007 UTC (17 years, 1 month ago) by persson
File size: 70055 byte(s)
* implemented editing of dimension region upper limits

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

  ViewVC Help
Powered by ViewVC