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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1091 - (hide annotations) (download)
Sat Mar 10 21:01:36 2007 UTC (17 years, 1 month ago) by schoenebeck
File size: 70242 byte(s)
* sample import works now (also tested with gigextract afterwards),
  there's however one bug left: adding samples, removing them again
  and then issueing 'Save' will cause a crash

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

  ViewVC Help
Powered by ViewVC