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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1094 - (hide annotations) (download)
Sun Mar 11 17:47:21 2007 UTC (17 years ago) by schoenebeck
File size: 70760 byte(s)
- fixed previously mentioned crash, root cause is yet to be fixed in libgig
  (seems as not all RIFF chunks are deleted yet when calling
  gig::File::DeleteSample())

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 schoenebeck 1094 std::cout << "Saving file\n" << std::flush;
1349     try {
1350     file->Save();
1351     } catch (RIFF::Exception e) {
1352     Glib::ustring txt = "Could not save file: " + e.Message;
1353     Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
1354     msg.run();
1355     return;
1356     }
1357     std::cout << "Saving file done\n" << std::flush;
1358 schoenebeck 1087 __import_queued_samples();
1359 persson 1052 }
1360    
1361     void MainWindow::on_action_file_save_as()
1362     {
1363 schoenebeck 1087 if (!file) return;
1364 persson 1052 Gtk::FileChooserDialog dialog(*this, "Open", Gtk::FILE_CHOOSER_ACTION_SAVE);
1365     dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1366     dialog.add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK);
1367     Gtk::FileFilter filter;
1368     filter.add_pattern("*.gig");
1369     dialog.set_filter(filter);
1370     if (dialog.run() == Gtk::RESPONSE_OK) {
1371     printf("filename=%s\n", dialog.get_filename().c_str());
1372 schoenebeck 1094 try {
1373     file->Save(dialog.get_filename());
1374     } catch (RIFF::Exception e) {
1375     Glib::ustring txt = "Could not save file: " + e.Message;
1376     Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
1377     msg.run();
1378     return;
1379     }
1380 schoenebeck 1087 __import_queued_samples();
1381 persson 1052 }
1382     }
1383    
1384 schoenebeck 1087 // actually write the sample(s)' data to the gig file
1385     void MainWindow::__import_queued_samples() {
1386 schoenebeck 1094 std::cout << "Starting sample import\n" << std::flush;
1387 schoenebeck 1087 Glib::ustring error_files;
1388 schoenebeck 1094 printf("Samples to import: %d\n", m_SampleImportQueue.size());
1389 schoenebeck 1091 for (std::list<SampleImportItem>::iterator iter = m_SampleImportQueue.begin(); iter != m_SampleImportQueue.end(); ) {
1390 schoenebeck 1087 printf("Importing sample %s\n",(*iter).sample_path.c_str());
1391     SF_INFO info;
1392     info.format = 0;
1393     SNDFILE* hFile = sf_open((*iter).sample_path.c_str(), SFM_READ, &info);
1394     try {
1395     if (!hFile) throw std::string("could not open file");
1396     // determine sample's bit depth
1397     int bitdepth;
1398     switch (info.format & 0xff) {
1399     case SF_FORMAT_PCM_S8:
1400     bitdepth = 16; // we simply convert to 16 bit for now
1401     break;
1402     case SF_FORMAT_PCM_16:
1403     bitdepth = 16;
1404     break;
1405     case SF_FORMAT_PCM_24:
1406     bitdepth = 32; // we simply convert to 32 bit for now
1407     break;
1408     case SF_FORMAT_PCM_32:
1409     bitdepth = 32;
1410     break;
1411     case SF_FORMAT_PCM_U8:
1412     bitdepth = 16; // we simply convert to 16 bit for now
1413     break;
1414     case SF_FORMAT_FLOAT:
1415     bitdepth = 32;
1416     break;
1417     case SF_FORMAT_DOUBLE:
1418     bitdepth = 32; // I guess we will always truncate this to 32 bit
1419     break;
1420     default:
1421     sf_close(hFile); // close sound file
1422     throw std::string("format not supported"); // unsupported subformat (yet?)
1423     }
1424     // allocate appropriate copy buffer (TODO: for now we copy it in one piece, might be tough for very long samples)
1425     // and copy sample data into buffer
1426     int8_t* buffer = NULL;
1427     switch (bitdepth) {
1428     case 16:
1429     buffer = new int8_t[2 * info.channels * info.frames];
1430     sf_readf_short(hFile, (short*) buffer, info.frames); // libsndfile does the conversion for us (if needed)
1431     break;
1432     case 32:
1433     buffer = new int8_t[4 * info.channels * info.frames];
1434     sf_readf_int(hFile, (int*) buffer, info.frames); // libsndfile does the conversion for us (if needed)
1435     break;
1436     }
1437     // write from buffer directly (physically) into .gig file
1438     (*iter).gig_sample->Write(buffer, info.frames);
1439     // cleanup
1440     sf_close(hFile);
1441     delete buffer;
1442     // on success we remove the sample from the import queue, otherwise keep it, maybe it works the next time ?
1443 schoenebeck 1091 std::list<SampleImportItem>::iterator cur = iter;
1444     ++iter;
1445     m_SampleImportQueue.erase(cur);
1446 schoenebeck 1087 } catch (std::string what) { // remember the files that made trouble (and their cause)
1447     if (error_files.size()) error_files += "\n";
1448     error_files += (*iter).sample_path += " (" + what + ")";
1449 schoenebeck 1091 ++iter;
1450 schoenebeck 1087 }
1451     }
1452     // show error message box when some sample(s) could not be imported
1453     if (error_files.size()) {
1454     Glib::ustring txt = "Could not import the following sample(s):\n" + error_files;
1455     Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
1456     msg.run();
1457     }
1458     }
1459    
1460 persson 1052 void MainWindow::on_action_file_properties()
1461     {
1462     propDialog.show();
1463     propDialog.deiconify();
1464     }
1465    
1466     void MainWindow::on_action_help_about()
1467     {
1468     #ifdef ABOUT_DIALOG
1469     Gtk::AboutDialog dialog;
1470     dialog.set_version(VERSION);
1471     dialog.run();
1472     #endif
1473     }
1474    
1475     PropDialog::PropDialog()
1476     : table(2,1)
1477     {
1478     table.set_col_spacings(5);
1479     char* propLabels[] = {
1480     "Name:",
1481     "CreationDate:",
1482     "Comments:", // TODO: multiline
1483     "Product:",
1484     "Copyright:",
1485     "Artists:",
1486     "Genre:",
1487     "Keywords:",
1488     "Engineer:",
1489     "Technician:",
1490     "Software:", // TODO: readonly
1491     "Medium:",
1492     "Source:",
1493     "SourceForm:",
1494     "Commissioned:",
1495     "Subject:"
1496     };
1497     for (int i = 0 ; i < sizeof(propLabels) / sizeof(char*) ; i++) {
1498     label[i].set_text(propLabels[i]);
1499     label[i].set_alignment(Gtk::ALIGN_LEFT);
1500     table.attach(label[i], 0, 1, i, i + 1, Gtk::FILL, Gtk::SHRINK);
1501     table.attach(entry[i], 1, 2, i, i + 1, Gtk::FILL | Gtk::EXPAND,
1502     Gtk::SHRINK);
1503     }
1504    
1505     add(table);
1506     // add_button(Gtk::Stock::CANCEL, 0);
1507     // add_button(Gtk::Stock::OK, 1);
1508     show_all_children();
1509     }
1510    
1511     void PropDialog::set_info(DLS::Info* info)
1512     {
1513     entry[0].set_text(info->Name);
1514     entry[1].set_text(info->CreationDate);
1515     entry[2].set_text(Glib::convert(info->Comments, "UTF-8", "ISO-8859-1"));
1516     entry[3].set_text(info->Product);
1517     entry[4].set_text(info->Copyright);
1518     entry[5].set_text(info->Artists);
1519     entry[6].set_text(info->Genre);
1520     entry[7].set_text(info->Keywords);
1521     entry[8].set_text(info->Engineer);
1522     entry[9].set_text(info->Technician);
1523     entry[10].set_text(info->Software);
1524     entry[11].set_text(info->Medium);
1525     entry[12].set_text(info->Source);
1526     entry[13].set_text(info->SourceForm);
1527     entry[14].set_text(info->Commissioned);
1528     entry[15].set_text(info->Subject);
1529     }
1530    
1531    
1532     InstrumentProps::InstrumentProps()
1533     : table(2,1),
1534     quitButton(Gtk::Stock::CLOSE)
1535     {
1536     table.set_col_spacings(5);
1537     char* propLabels[] = {
1538     "Name:",
1539     "IsDrum:",
1540     "MIDIBank:",
1541     "MIDIProgram:",
1542     "Attenuation:",
1543     "EffectSend:",
1544     "FineTune:",
1545     "PitchbendRange:",
1546     "PianoReleaseMode:",
1547     "DimensionKeyRange:",
1548     };
1549     int entryIdx = 0, checkIdx = 0;
1550     for (int i = 0 ; i < sizeof(propLabels) / sizeof(char*) ; i++) {
1551     label[i].set_text(propLabels[i]);
1552     label[i].set_alignment(Gtk::ALIGN_LEFT);
1553     table.attach(label[i], 0, 1, i, i + 1, Gtk::FILL, Gtk::SHRINK);
1554     if (i == 1 || i == 8)
1555     table.attach(check[checkIdx++], 1, 2, i, i + 1,
1556     Gtk::FILL | Gtk::EXPAND, Gtk::SHRINK);
1557     else
1558     table.attach(entry[entryIdx++], 1, 2, i, i + 1,
1559     Gtk::FILL | Gtk::EXPAND, Gtk::SHRINK);
1560     }
1561    
1562     // vbox { table buttonBox { quitButton } }
1563    
1564     //get_vbox()->pack_start(table);
1565     // set_border_width(6);
1566     add(vbox);
1567     table.set_border_width(2);
1568     vbox.pack_start(table);
1569     table.show();
1570     vbox.pack_start(buttonBox);
1571     buttonBox.set_layout(Gtk::BUTTONBOX_END);
1572     buttonBox.set_border_width(5);
1573     buttonBox.show();
1574     buttonBox.pack_start(quitButton);
1575     quitButton.set_flags(Gtk::CAN_DEFAULT);
1576     quitButton.grab_focus();
1577    
1578     quitButton.signal_clicked().connect(
1579     sigc::mem_fun(*this, &InstrumentProps::hide));
1580    
1581     // quitButton.grab_default();
1582     quitButton.show();
1583     // add(table);
1584     vbox.show();
1585     show_all_children();
1586     }
1587    
1588    
1589     void InstrumentProps::set_instrument(gig::Instrument* instrument)
1590     {
1591     char buf[100];
1592    
1593     int entryIdx = 0, checkIdx = 0;
1594     entry[entryIdx++].set_text(instrument->pInfo->Name);
1595     check[checkIdx++].set_active(instrument->IsDrum);
1596     sprintf(buf, "%d", instrument->MIDIBank);
1597     entry[entryIdx++].set_text(buf);
1598     sprintf(buf, "%d", instrument->MIDIProgram);
1599     entry[entryIdx++].set_text(buf);
1600     sprintf(buf, "%d", instrument->Attenuation);
1601     entry[entryIdx++].set_text(buf);
1602     sprintf(buf, "%d", instrument->EffectSend);
1603     entry[entryIdx++].set_text(buf);
1604     sprintf(buf, "%d", instrument->FineTune);
1605     entry[entryIdx++].set_text(buf);
1606     sprintf(buf, "%d", instrument->PitchbendRange);
1607     entry[entryIdx++].set_text(buf);
1608     check[checkIdx++].set_active(instrument->PianoReleaseMode);
1609     sprintf(buf, "%s%d (%d)..%s%d (%d)",
1610     notes[instrument->DimensionKeyRange.low % 12],
1611     instrument->DimensionKeyRange.low / 12 - 1,
1612     instrument->DimensionKeyRange.low,
1613     notes[instrument->DimensionKeyRange.high % 12],
1614     instrument->DimensionKeyRange.high / 12 - 1,
1615     instrument->DimensionKeyRange.high);
1616     entry[entryIdx].set_text(buf);
1617     }
1618    
1619     void MainWindow::getInfo(const char *filename)
1620     {
1621     RIFF::File* riff = new RIFF::File(filename);
1622     gig::File* gig = new gig::File(riff);
1623    
1624     load_gig(gig, filename);
1625     }
1626    
1627     void MainWindow::load_gig(gig::File* gig, const char* filename)
1628     {
1629     file = gig;
1630    
1631     const char *basename = strrchr(filename, '/');
1632     basename = basename ? basename + 1 : filename;
1633    
1634     set_title(basename);
1635    
1636     propDialog.set_info(gig->pInfo);
1637    
1638 schoenebeck 1069 Gtk::MenuItem* instrument_menu =
1639     dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/MenuBar/MenuInstrument"));
1640    
1641     int instrument_index = 0;
1642 schoenebeck 1075 Gtk::RadioMenuItem::Group instrument_group;
1643 persson 1052 for (gig::Instrument* instrument = gig->GetFirstInstrument() ; instrument ;
1644     instrument = gig->GetNextInstrument()) {
1645     Gtk::TreeModel::iterator iter = m_refTreeModel->append();
1646     Gtk::TreeModel::Row row = *iter;
1647     row[m_Columns.m_col_name] = instrument->pInfo->Name.c_str();
1648     row[m_Columns.m_col_instr] = instrument;
1649 schoenebeck 1069 // create a menu item for this instrument
1650 schoenebeck 1075 Gtk::RadioMenuItem* item= new Gtk::RadioMenuItem(instrument_group, instrument->pInfo->Name.c_str());
1651 schoenebeck 1069 instrument_menu->get_submenu()->append(*item);
1652     item->signal_activate().connect(
1653     sigc::bind(
1654     sigc::mem_fun(*this, &MainWindow::on_instrument_selection_change),
1655     instrument_index
1656     )
1657     );
1658     instrument_index++;
1659 persson 1052 }
1660 schoenebeck 1069 instrument_menu->show();
1661     instrument_menu->get_submenu()->show_all_children();
1662 schoenebeck 1080
1663     for (gig::Group* group = gig->GetFirstGroup(); group; group = gig->GetNextGroup()) {
1664 persson 1088 if (group->Name != "") {
1665     Gtk::TreeModel::iterator iterGroup = m_refSamplesTreeModel->append();
1666     Gtk::TreeModel::Row rowGroup = *iterGroup;
1667     rowGroup[m_SamplesModel.m_col_name] = group->Name.c_str();
1668     rowGroup[m_SamplesModel.m_col_group] = group;
1669     rowGroup[m_SamplesModel.m_col_sample] = NULL;
1670     for (gig::Sample* sample = group->GetFirstSample(); sample; sample = group->GetNextSample()) {
1671     Gtk::TreeModel::iterator iterSample = m_refSamplesTreeModel->append(rowGroup.children());
1672     Gtk::TreeModel::Row rowSample = *iterSample;
1673     rowSample[m_SamplesModel.m_col_name] = sample->pInfo->Name.c_str();
1674     rowSample[m_SamplesModel.m_col_sample] = sample;
1675     rowSample[m_SamplesModel.m_col_group] = NULL;
1676     }
1677 schoenebeck 1080 }
1678     }
1679 persson 1052 }
1680    
1681     void MainWindow::on_button_release(GdkEventButton* button)
1682     {
1683     if (button->type == GDK_2BUTTON_PRESS) {
1684     Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();
1685     Gtk::TreeModel::iterator it = tree_sel_ref->get_selected();
1686     if (it)
1687     {
1688     Gtk::TreeModel::Row row = *it;
1689     if (row[m_Columns.m_col_instr])
1690     {
1691     instrumentProps.set_instrument(row[m_Columns.m_col_instr]);
1692     instrumentProps.show();
1693     instrumentProps.deiconify();
1694     }
1695     }
1696     } else if (button->type == GDK_BUTTON_PRESS && button->button == 3) {
1697     popup_menu->popup(button->button, button->time);
1698     }
1699     }
1700 schoenebeck 1069
1701     void MainWindow::on_instrument_selection_change(int index) {
1702     m_RegionChooser.set_instrument(file->GetInstrument(index));
1703     }
1704 schoenebeck 1082
1705     void MainWindow::on_sample_treeview_button_release(GdkEventButton* button) {
1706     if (button->type == GDK_BUTTON_PRESS && button->button == 3) {
1707     Gtk::Menu* sample_popup =
1708     dynamic_cast<Gtk::Menu*>(uiManager->get_widget("/SamplePopupMenu"));
1709     // update enabled/disabled state of sample popup items
1710     Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();
1711     Gtk::TreeModel::iterator it = sel->get_selected();
1712     bool group_selected = false;
1713     bool sample_selected = false;
1714     if (it) {
1715     Gtk::TreeModel::Row row = *it;
1716     group_selected = row[m_SamplesModel.m_col_group];
1717     sample_selected = row[m_SamplesModel.m_col_sample];
1718     }
1719     dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/SamplePopupMenu/SampleProperties"))->set_sensitive(group_selected || sample_selected);
1720     dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/SamplePopupMenu/AddSample"))->set_sensitive(group_selected || sample_selected);
1721     dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/SamplePopupMenu/AddGroup"))->set_sensitive(file);
1722     dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/SamplePopupMenu/RemoveSample"))->set_sensitive(group_selected || sample_selected);
1723     // show sample popup
1724     sample_popup->popup(button->button, button->time);
1725     }
1726     }
1727    
1728     void MainWindow::on_action_sample_properties() {
1729     //TODO: show a dialog where the selected sample's properties can be edited
1730     }
1731    
1732     void MainWindow::on_action_add_group() {
1733     static int __sample_indexer = 0;
1734     if (!file) return;
1735     gig::Group* group = file->AddGroup();
1736     group->Name = "Unnamed Group";
1737     if (__sample_indexer) group->Name += " " + ToString(__sample_indexer);
1738     __sample_indexer++;
1739     // update sample tree view
1740     Gtk::TreeModel::iterator iterGroup = m_refSamplesTreeModel->append();
1741     Gtk::TreeModel::Row rowGroup = *iterGroup;
1742     rowGroup[m_SamplesModel.m_col_name] = group->Name.c_str();
1743     rowGroup[m_SamplesModel.m_col_sample] = NULL;
1744     rowGroup[m_SamplesModel.m_col_group] = group;
1745     }
1746    
1747     void MainWindow::on_action_add_sample() {
1748 schoenebeck 1085 if (!file) return;
1749     // get selected group
1750     Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();
1751     Gtk::TreeModel::iterator it = sel->get_selected();
1752     if (!it) return;
1753     Gtk::TreeModel::Row row = *it;
1754     gig::Group* group = row[m_SamplesModel.m_col_group];
1755     if (!group) { // not a group, but a sample is selected (probably)
1756     gig::Sample* sample = row[m_SamplesModel.m_col_sample];
1757     if (!sample) return;
1758     it = row.parent(); // resolve parent (that is the sample's group)
1759     if (!it) return;
1760     row = *it;
1761     group = row[m_SamplesModel.m_col_group];
1762     if (!group) return;
1763     }
1764     // show 'browse for file' dialog
1765     Gtk::FileChooserDialog dialog(*this, _("Add Sample(s)"));
1766     dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1767     dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);
1768     dialog.set_select_multiple(true);
1769 schoenebeck 1091 Gtk::FileFilter soundfilter; // matches all file types supported by libsndfile
1770     const char* supportedFileTypes[] = {
1771     "*.wav", "*.WAV", "*.aiff", "*.AIFF", "*.aifc", "*.AIFC", "*.snd",
1772     "*.SND", "*.au", "*.AU", "*.paf", "*.PAF", "*.iff", "*.IFF",
1773     "*.svx", "*.SVX", "*.sf", "*.SF", "*.voc", "*.VOC", "*.w64",
1774     "*.W64", "*.pvf", "*.PVF", "*.xi", "*.XI", "*.htk", "*.HTK",
1775     "*.caf", "*.CAF", NULL
1776     };
1777     for (int i = 0; supportedFileTypes[i]; i++)
1778     soundfilter.add_pattern(supportedFileTypes[i]);
1779 schoenebeck 1085 soundfilter.set_name("Sound Files");
1780     Gtk::FileFilter allpassfilter; // matches every file
1781     allpassfilter.add_pattern("*.*");
1782     allpassfilter.set_name("All Files");
1783     dialog.add_filter(soundfilter);
1784     dialog.add_filter(allpassfilter);
1785     if (dialog.run() == Gtk::RESPONSE_OK) {
1786     Glib::ustring error_files;
1787     Glib::SListHandle<Glib::ustring> filenames = dialog.get_filenames();
1788     for (Glib::SListHandle<Glib::ustring>::iterator iter = filenames.begin(); iter != filenames.end(); ++iter) {
1789     printf("Adding sample %s\n",(*iter).c_str());
1790     // use libsndfile to retrieve file informations
1791     SF_INFO info;
1792     info.format = 0;
1793     SNDFILE* hFile = sf_open((*iter).c_str(), SFM_READ, &info);
1794     try {
1795     if (!hFile) throw std::string("could not open file");
1796     int bitdepth;
1797     switch (info.format & 0xff) {
1798     case SF_FORMAT_PCM_S8:
1799 schoenebeck 1087 bitdepth = 16; // we simply convert to 16 bit for now
1800 schoenebeck 1085 break;
1801     case SF_FORMAT_PCM_16:
1802     bitdepth = 16;
1803     break;
1804     case SF_FORMAT_PCM_24:
1805 schoenebeck 1087 bitdepth = 32; // we simply convert to 32 bit for now
1806 schoenebeck 1085 break;
1807     case SF_FORMAT_PCM_32:
1808     bitdepth = 32;
1809     break;
1810 schoenebeck 1087 case SF_FORMAT_PCM_U8:
1811     bitdepth = 16; // we simply convert to 16 bit for now
1812     break;
1813     case SF_FORMAT_FLOAT:
1814     bitdepth = 32;
1815     break;
1816     case SF_FORMAT_DOUBLE:
1817     bitdepth = 32; // I guess we will always truncate this to 32 bit
1818     break;
1819 schoenebeck 1085 default:
1820     sf_close(hFile); // close sound file
1821     throw std::string("format not supported"); // unsupported subformat (yet?)
1822     }
1823     // add a new sample to the .gig file
1824     gig::Sample* sample = file->AddSample();
1825 schoenebeck 1087 sample->pInfo->Name = (*iter).substr((*iter).rfind('/') + 1).raw(); // file name without path
1826 schoenebeck 1085 sample->Channels = info.channels;
1827     sample->BitDepth = bitdepth;
1828     sample->FrameSize = bitdepth / 8/*1 byte are 8 bits*/ * info.channels;
1829     sample->SamplesPerSecond = info.samplerate;
1830     // schedule resizing the sample (which will be done physically when File::Save() is called)
1831     sample->Resize(info.frames);
1832 schoenebeck 1091 // make sure sample is part of the selected group
1833     group->AddSample(sample);
1834 schoenebeck 1087 // schedule that physical resize and sample import (data copying), performed when "Save" is requested
1835     SampleImportItem sched_item;
1836     sched_item.gig_sample = sample;
1837     sched_item.sample_path = *iter;
1838     m_SampleImportQueue.push_back(sched_item);
1839 schoenebeck 1085 // add sample to the tree view
1840     Gtk::TreeModel::iterator iterSample = m_refSamplesTreeModel->append(row.children());
1841     Gtk::TreeModel::Row rowSample = *iterSample;
1842     rowSample[m_SamplesModel.m_col_name] = sample->pInfo->Name.c_str();
1843     rowSample[m_SamplesModel.m_col_sample] = sample;
1844     rowSample[m_SamplesModel.m_col_group] = NULL;
1845     // close sound file
1846     sf_close(hFile);
1847     } catch (std::string what) { // remember the files that made trouble (and their cause)
1848     if (error_files.size()) error_files += "\n";
1849     error_files += *iter += " (" + what + ")";
1850     }
1851     }
1852     // show error message box when some file(s) could not be opened / added
1853     if (error_files.size()) {
1854     Glib::ustring txt = "Could not add the following sample(s):\n" + error_files;
1855     Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
1856     msg.run();
1857     }
1858     }
1859 schoenebeck 1082 }
1860    
1861     void MainWindow::on_action_remove_sample() {
1862 schoenebeck 1084 if (!file) return;
1863     Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();
1864     Gtk::TreeModel::iterator it = sel->get_selected();
1865     if (it) {
1866     Gtk::TreeModel::Row row = *it;
1867     gig::Group* group = row[m_SamplesModel.m_col_group];
1868     gig::Sample* sample = row[m_SamplesModel.m_col_sample];
1869 schoenebeck 1091 Glib::ustring name = row[m_SamplesModel.m_col_name];
1870 schoenebeck 1084 try {
1871     // remove group or sample from the gig file
1872     if (group) {
1873 schoenebeck 1091 // temporarily remember the samples that bolong to that group (we need that to clean the queue)
1874     std::list<gig::Sample*> members;
1875     for (gig::Sample* pSample = group->GetFirstSample(); pSample; pSample = group->GetNextSample()) {
1876     members.push_back(pSample);
1877     }
1878     // delete the group in the .gig file including the samples that belong to the group
1879 schoenebeck 1084 file->DeleteGroup(group);
1880 schoenebeck 1091 // if sample(s) were just previously added, remove them from the import queue
1881     for (std::list<gig::Sample*>::iterator member = members.begin(); member != members.end(); ++member) {
1882     for (std::list<SampleImportItem>::iterator iter = m_SampleImportQueue.begin(); iter != m_SampleImportQueue.end(); ++iter) {
1883     if ((*iter).gig_sample == *member) {
1884     printf("Removing previously added sample '%s' from group '%s'\n", (*iter).sample_path.c_str(), name.c_str());
1885     m_SampleImportQueue.erase(iter);
1886     break;
1887     }
1888     }
1889     }
1890 schoenebeck 1084 } else if (sample) {
1891 schoenebeck 1091 // remove sample from the .gig file
1892 schoenebeck 1084 file->DeleteSample(sample);
1893 schoenebeck 1091 // if sample was just previously added, remove it from the import queue
1894 schoenebeck 1087 for (std::list<SampleImportItem>::iterator iter = m_SampleImportQueue.begin(); iter != m_SampleImportQueue.end(); ++iter) {
1895     if ((*iter).gig_sample == sample) {
1896 schoenebeck 1091 printf("Removing previously added sample '%s'\n", (*iter).sample_path.c_str());
1897 schoenebeck 1087 m_SampleImportQueue.erase(iter);
1898     break;
1899     }
1900     }
1901     }
1902 schoenebeck 1084 // remove respective row(s) from samples tree view
1903     m_refSamplesTreeModel->erase(it);
1904     } catch (RIFF::Exception e) {
1905     Gtk::MessageDialog msg(*this, e.Message.c_str(), false, Gtk::MESSAGE_ERROR);
1906     msg.run();
1907     }
1908     }
1909 schoenebeck 1082 }

  ViewVC Help
Powered by ViewVC