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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

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

  ViewVC Help
Powered by ViewVC