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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1097 - (hide annotations) (download)
Wed Mar 14 23:19:26 2007 UTC (17 years ago) by schoenebeck
File size: 74423 byte(s)
* implemented renaming of samples, groups and instruments

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

  ViewVC Help
Powered by ViewVC