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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1087 - (hide annotations) (download)
Fri Mar 9 19:45:45 2007 UTC (17 years ago) by schoenebeck
File size: 67998 byte(s)
* coarsely finished 'Sample Add' feature: works non-destructive, that is
  samples are just queued to be imported and the heavy task of resizing the
  .gig file physically and importing the sample data is done when 'Save' is
  issued (Note however: unfortunately it seems to crash yet when calling
  'Save')

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

  ViewVC Help
Powered by ViewVC