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

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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1082 by schoenebeck, Thu Mar 8 01:43:18 2007 UTC revision 1117 by persson, Sat Mar 24 13:05:58 2007 UTC
# Line 20  Line 20 
20  #include <libintl.h>  #include <libintl.h>
21  #include <iostream>  #include <iostream>
22    
 #include "mainwindow.h"  
   
23  #include <gtkmm/filechooserdialog.h>  #include <gtkmm/filechooserdialog.h>
24    #include <gtkmm/messagedialog.h>
25  #include <gtkmm/stock.h>  #include <gtkmm/stock.h>
26    #include <gtkmm/targetentry.h>
27    
28  #if GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION >= 6  #if GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION >= 6
29  #define ABOUT_DIALOG  #define ABOUT_DIALOG
30  #include <gtkmm/aboutdialog.h>  #include <gtkmm/aboutdialog.h>
31  #endif  #endif
32    
33    #include <stdio.h>
34    #include <sndfile.h>
35    
36    #include "mainwindow.h"
37    
38  #define _(String) gettext(String)  #define _(String) gettext(String)
39    
40  template<class T> inline std::string ToString(T o) {  template<class T> inline std::string ToString(T o) {
# Line 37  template<class T> inline std::string ToS Line 43  template<class T> inline std::string ToS
43      return ss.str();      return ss.str();
44  }  }
45    
46  bool update_gui;  MainWindow::MainWindow()
   
 uint8_t& access_UnityNote(gig::DimensionRegion* dimreg)  
 {  
     return dimreg->UnityNote;  
 }  
 int16_t& access_FineTune(gig::DimensionRegion* dimreg)  
 {  
     return dimreg->FineTune;  
 }  
 uint32_t& access_SampleLoops(gig::DimensionRegion* dimreg)  
 {  
     return dimreg->SampleLoops;  
 }  
 uint8_t& access_Crossfade_in_start(gig::DimensionRegion* dimreg)  
 {  
     return dimreg->Crossfade.in_start;  
 }  
 uint8_t& access_Crossfade_in_end(gig::DimensionRegion* dimreg)  
 {  
     return dimreg->Crossfade.in_end;  
 }  
 uint8_t& access_Crossfade_out_start(gig::DimensionRegion* dimreg)  
 {  
     return dimreg->Crossfade.out_start;  
 }  
 uint8_t& access_Crossfade_out_end(gig::DimensionRegion* dimreg)  
 {  
     return dimreg->Crossfade.out_end;  
 }  
   
 namespace {  
     const char* const controlChangeTexts[] = {  
         "none", "channelaftertouch", "velocity",  
         0,  
         "modwheel", // "Modulation Wheel or Lever",  
         "breath", // "Breath Controller",  
         0,  
         "foot", // "Foot Controller",  
         "portamentotime", // "Portamento Time",  
         0, 0, 0, 0, 0, 0,  
         "effect1", // "Effect Control 1",  
         "effect2", // "Effect Control 2",  
         0, 0,  
         "genpurpose1", // "General Purpose Controller 1",  
         "genpurpose2", // "General Purpose Controller 2",  
         "genpurpose3", // "General Purpose Controller 3",  
         "genpurpose4", // "General Purpose Controller 4",  
         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  
         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  
         0, 0, 0, 0, 0, 0,  
         "sustainpedal", // "Damper Pedal on/off (Sustain)",  
         "portamento", // "Portamento On/Off",  
         "sostenuto", // "Sustenuto On/Off",  
         "softpedal", // "Soft Pedal On/Off",  
         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  
         "genpurpose5", // "General Purpose Controller 5",  
         "genpurpose6", // "General Purpose Controller 6",  
         "genpurpose7", // "General Purpose Controller 7",  
         "genpurpose8", // "General Purpose Controller 8",  
         0, 0, 0, 0, 0, 0, 0,  
         "effect1depth", // "Effects 1 Depth",  
         "effect2depth", // "Effects 2 Depth",  
         "effect3depth", // "Effects 3 Depth",  
         "effect4depth", // "Effects 4 Depth",  
         "effect5depth", // "Effects 5 Depth"  
     };  
 }  
   
 void MainWindow::addString(char* labelText, Gtk::Label*& label,  
                            Gtk::Entry*& widget)  
 {  
     label = new Gtk::Label(Glib::ustring(labelText) + ":");  
     label->set_alignment(Gtk::ALIGN_LEFT);  
   
     table[pageno]->attach(*label, 1, 2, rowno, rowno + 1,  
                           Gtk::FILL, Gtk::SHRINK);  
   
     widget = new Gtk::Entry();  
   
     table[pageno]->attach(*widget, 2, 3, rowno, rowno + 1,  
                           Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK);  
   
     rowno++;  
 }  
   
 LabelWidget::LabelWidget(char* labelText, Gtk::Widget& widget) :  
     label(Glib::ustring(labelText) + ":"),  
     widget(widget)  
 {  
     label.set_alignment(Gtk::ALIGN_LEFT);  
 }  
   
 void LabelWidget::set_sensitive(bool sensitive)  
 {  
     label.set_sensitive(sensitive);  
     widget.set_sensitive(sensitive);  
 }  
   
 NumEntryGain::NumEntryGain(char* labelText,  
                            double lower = 0, double upper = 127,  
                            int decimals = 0) :  
     NumEntry<gig::DimensionRegion>(labelText, lower, upper, decimals)  
 {  
     spinbutton.signal_value_changed().connect(  
         sigc::mem_fun(*this, &NumEntryGain::value_changed));  
 }  
   
 void NumEntryGain::value_changed()  
 {  
     if (dimreg && update_gui) {  
       dimreg->Gain = int32_t(spinbutton.get_value() * -655360.0);  
     }  
 }  
   
 void NumEntryGain::set_dimreg(gig::DimensionRegion* dimreg)  
 {  
     this->dimreg = 0;  
     set_value(dimreg->Gain / -655360.0);  
     this->dimreg = dimreg;  
 }  
   
   
 NumEntryPermille::NumEntryPermille(char* labelText,  
                                    uint16_t gig::DimensionRegion::* param,  
                                    double lower, double upper, int decimals) :  
     NumEntry<gig::DimensionRegion>(labelText, lower, upper, decimals),  
     param(param)  
 {  
     spinbutton.signal_value_changed().connect(  
         sigc::mem_fun(*this, &NumEntryPermille::value_changed));  
 }  
   
 void NumEntryPermille::value_changed()  
 {  
     if (dimreg && update_gui) {  
         dimreg->*param = uint16_t(spinbutton.get_value() * 10 + 0.5);  
     }  
 }  
   
 void NumEntryPermille::set_dimreg(gig::DimensionRegion* dimreg)  
 {  
     this->dimreg = 0;  
     set_value(dimreg->*param / 10.0);  
     this->dimreg = dimreg;  
 }  
   
   
 NoteEntry::NoteEntry(char* labelText, uint8_t& (*access)(gig::DimensionRegion*)) :  
     NumEntryX<uint8_t>(labelText, access)  
 {  
     spinbutton.signal_input().connect(  
         sigc::mem_fun(*this, &NoteEntry::on_input));  
     spinbutton.signal_output().connect(  
         sigc::mem_fun(*this, &NoteEntry::on_output));  
 }  
   
 const char* notes[] = {  
     "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"  
 };  
   
   
 // Convert the Entry text to a number  
 int NoteEntry::on_input(double* new_value)  
 {  
     const char* str = spinbutton.get_text().c_str();  
   
     int i;  
     for (i = 11 ; i >= 0 ; i--) {  
         if (strncmp(str, notes[i], strlen(notes[i])) == 0) break;  
     }  
     if (i >= 0) {  
         char* endptr;  
         long x = strtol(str + strlen(notes[i]), &endptr, 10);  
         if (endptr != str + strlen(notes[i])) {  
             *new_value = i + (x + 1) * 12;  
             return true;  
         }  
     }  
     return Gtk::INPUT_ERROR;  
 }  
   
 // Convert the Adjustment position to text  
 bool NoteEntry::on_output()  
 {  
     int x = int(spinbutton.get_adjustment()->get_value());  
     char buf[10];  
     sprintf(buf, "%s%d", notes[x % 12], x / 12 - 1);  
     spinbutton.set_text(buf);  
     return true;  
 }  
   
 BoolEntry::BoolEntry(char* labelText, bool gig::DimensionRegion::* param) :  
     LabelWidget(labelText, checkbutton),  
     param(param)  
 {  
     checkbutton.signal_toggled().connect(  
         sigc::mem_fun(*this, &BoolEntry::value_changed));  
 }  
   
 void BoolEntry::value_changed()  
 {  
     if (dimreg && update_gui) {  
         dimreg->*param = checkbutton.get_active();  
     }  
 }  
   
 void BoolEntry::set_dimreg(gig::DimensionRegion* dimreg)  
 {  
     this->dimreg = 0;  
     checkbutton.set_active(dimreg->*param);  
     this->dimreg = dimreg;  
 }  
   
 ChoiceEntryLeverageCtrl::ChoiceEntryLeverageCtrl(  
     char* labelText,  
     gig::leverage_ctrl_t gig::DimensionRegion::* param) :  
     align(0, 0, 0, 0),  
     LabelWidget(labelText, align),  
     param(param)  
 {  
     for (int i = 0 ; i < 99 ; i++) {  
         if (controlChangeTexts[i]) {  
             combobox.append_text(controlChangeTexts[i]);  
         }  
     }  
     combobox.signal_changed().connect(  
         sigc::mem_fun(*this, &ChoiceEntryLeverageCtrl::value_changed));  
     align.add(combobox);  
 }  
   
 void ChoiceEntryLeverageCtrl::value_changed()  
 {  
     if (dimreg && update_gui) {  
         int rowno = combobox.get_active_row_number();  
         switch (rowno)  
         {  
         case -1:  
             break;  
         case 0:  
             (dimreg->*param).type = gig::leverage_ctrl_t::type_none;  
             break;  
         case 1:  
             (dimreg->*param).type =  
                 gig::leverage_ctrl_t::type_channelaftertouch;  
             break;  
         case 2:  
             (dimreg->*param).type = gig::leverage_ctrl_t::type_velocity;  
             break;  
         default:  
             (dimreg->*param).type = gig::leverage_ctrl_t::type_controlchange;  
             int x = 3;  
             for (int cc = 0 ; cc < 96 ; cc++) {  
                 if (controlChangeTexts[cc + 3]) {  
                     if (rowno == x) {  
                         (dimreg->*param).controller_number = cc;  
                         break;  
                     }  
                     x++;  
                 }  
             }  
             break;  
         }  
     }  
 }  
   
 void ChoiceEntryLeverageCtrl::set_dimreg(gig::DimensionRegion* dimreg)  
 {  
     this->dimreg = 0;  
     gig::leverage_ctrl_t c = dimreg->*param;  
     int x;  
     switch (c.type)  
     {  
     case gig::leverage_ctrl_t::type_none:  
         x = 0;  
         break;  
     case gig::leverage_ctrl_t::type_channelaftertouch:  
         x = 1;  
         break;  
     case gig::leverage_ctrl_t::type_velocity:  
         x = 2;  
         break;  
     case gig::leverage_ctrl_t::type_controlchange:  
         x = -1;  
         for (int cc = 0 ; cc < 96 ; cc++) {  
             if (controlChangeTexts[cc + 3]) {  
                 x++;  
                 if (c.controller_number == cc) {  
                     x += 3;  
                     break;  
                 }  
             }  
         }  
         break;  
     default:  
         x = -1;  
         break;  
     }  
     combobox.set_active(x);  
     this->dimreg = dimreg;  
 }  
   
 void MainWindow::addHeader(char* text)  
 {  
     if (firstRowInBlock < rowno - 1)  
     {  
         Gtk::Label* filler = new Gtk::Label("    ");  
         table[pageno]->attach(*filler, 0, 1, firstRowInBlock, rowno,  
                               Gtk::FILL, Gtk::SHRINK);  
     }  
     Glib::ustring str = "<b>";  
     str += text;  
     str += "</b>";  
     Gtk::Label* label = new Gtk::Label(str);  
     label->set_use_markup();  
     label->set_alignment(Gtk::ALIGN_LEFT);  
     table[pageno]->attach(*label, 0, 3, rowno, rowno + 1,  
                           Gtk::FILL, Gtk::SHRINK);  
     rowno++;  
     firstRowInBlock = rowno;  
 }  
   
 void MainWindow::nextPage()  
 {  
     if (firstRowInBlock < rowno - 1)  
     {  
         Gtk::Label* filler = new Gtk::Label("    ");  
         table[pageno]->attach(*filler, 0, 1, firstRowInBlock, rowno,  
                               Gtk::FILL, Gtk::SHRINK);  
     }  
     pageno++;  
     rowno = 0;  
     firstRowInBlock = 0;  
 }  
   
 void MainWindow::addProp(LabelWidget& prop)  
 {  
     table[pageno]->attach(prop.label, 1, 2, rowno, rowno + 1,  
                           Gtk::FILL, Gtk::SHRINK);  
     table[pageno]->attach(prop.widget, 2, 3, rowno, rowno + 1,  
                           Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK);  
     rowno++;  
 }  
   
   
   
   
 MainWindow::MainWindow() :  
 //    eSample("Sample", wSample),  
     eVelocityUpperLimit("VelocityUpperLimit",  
                         &gig::DimensionRegion::VelocityUpperLimit),  
     eEG1PreAttack("PreAttack", &gig::DimensionRegion::EG1PreAttack, 0, 100, 2),  
     eEG1Attack("Attack", &gig::DimensionRegion::EG1Attack, 0, 60, 3),  
     eEG1Decay1("Decay1", &gig::DimensionRegion::EG1Decay1, 0.005, 60, 3),  
     eEG1Decay2("Decay2", &gig::DimensionRegion::EG1Decay2, 0, 60, 3),  
     eEG1InfiniteSustain("InfiniteSustain",  
                         &gig::DimensionRegion::EG1InfiniteSustain),  
     eEG1Sustain("Sustain", &gig::DimensionRegion::EG1Sustain, 0, 100, 2),  
     eEG1Release("Release", &gig::DimensionRegion::EG1Release, 0, 60, 3),  
     eEG1Hold("Hold", &gig::DimensionRegion::EG1Hold),  
     eEG1Controller("Controller", &gig::DimensionRegion::EG1Controller),  
     eEG1ControllerInvert("ControllerInvert",  
                          &gig::DimensionRegion::EG1ControllerInvert),  
     eEG1ControllerAttackInfluence("ControllerAttackInfluence",  
                                   &gig::DimensionRegion::EG1ControllerAttackInfluence,  
                                   0, 3),  
     eEG1ControllerDecayInfluence("ControllerDecayInfluence",  
                                  &gig::DimensionRegion::EG1ControllerDecayInfluence,  
                                  0, 3),  
     eEG1ControllerReleaseInfluence("ControllerReleaseInfluence",  
                                    &gig::DimensionRegion::EG1ControllerReleaseInfluence,  
                                    0, 3),  
     eLFO1Frequency("Frequency", &gig::DimensionRegion::LFO1Frequency,  
                    0.1, 10, 2),  
     eLFO1InternalDepth("InternalDepth",  
                        &gig::DimensionRegion::LFO1InternalDepth, 0, 1200),  
     eLFO1ControlDepth("ControlDepth", &gig::DimensionRegion::LFO1ControlDepth,  
                       0, 1200),  
     eLFO1Controller("Controller", &gig::DimensionRegion::LFO1Controller),  
     eLFO1FlipPhase("FlipPhase", &gig::DimensionRegion::LFO1FlipPhase),  
     eLFO1Sync("Sync", &gig::DimensionRegion::LFO1Sync),  
     eEG2PreAttack("PreAttack", &gig::DimensionRegion::EG2PreAttack, 0, 100, 2),  
     eEG2Attack("Attack", &gig::DimensionRegion::EG2Attack, 0, 60, 3),  
     eEG2Decay1("Decay1", &gig::DimensionRegion::EG2Decay1, 0.005, 60, 3),  
     eEG2Decay2("Decay2", &gig::DimensionRegion::EG2Decay2, 0, 60, 3),  
     eEG2InfiniteSustain("InfiniteSustain",  
                         &gig::DimensionRegion::EG2InfiniteSustain),  
     eEG2Sustain("Sustain", &gig::DimensionRegion::EG2Sustain, 0, 100, 2),  
     eEG2Release("Release", &gig::DimensionRegion::EG2Release, 0, 60, 3),  
     eEG2Controller("Controller", &gig::DimensionRegion::EG2Controller),  
     eEG2ControllerInvert("ControllerInvert",  
                          &gig::DimensionRegion::EG2ControllerInvert),  
     eEG2ControllerAttackInfluence("ControllerAttackInfluence",  
                                   &gig::DimensionRegion::EG2ControllerAttackInfluence,  
                                   0, 3),  
     eEG2ControllerDecayInfluence("ControllerDecayInfluence",  
                                  &gig::DimensionRegion::EG2ControllerDecayInfluence,  
                                  0, 3),  
     eEG2ControllerReleaseInfluence("ControllerReleaseInfluence",  
                                    &gig::DimensionRegion::EG2ControllerReleaseInfluence,  
                                    0, 3),  
     eLFO2Frequency("Frequency", &gig::DimensionRegion::LFO2Frequency,  
                    0.1, 10, 2),  
     eLFO2InternalDepth("InternalDepth",  
                        &gig::DimensionRegion::LFO2InternalDepth, 0, 1200),  
     eLFO2ControlDepth("ControlDepth",  
                       &gig::DimensionRegion::LFO2ControlDepth, 0, 1200),  
     eLFO2Controller("Controller", &gig::DimensionRegion::LFO2Controller),  
     eLFO2FlipPhase("FlipPhase", &gig::DimensionRegion::LFO2FlipPhase),  
     eLFO2Sync("Sync", &gig::DimensionRegion::LFO2Sync),  
     eEG3Attack("Attack", &gig::DimensionRegion::EG3Attack, 0, 10, 3),  
     eEG3Depth("Depth", &gig::DimensionRegion::EG3Depth, -1200, 1200),  
     eLFO3Frequency("Frequency", &gig::DimensionRegion::LFO3Frequency,  
                    0.1, 10, 2),  
     eLFO3InternalDepth("InternalDepth",  
                        &gig::DimensionRegion::LFO3InternalDepth, 0, 1200),  
     eLFO3ControlDepth("ControlDepth", &gig::DimensionRegion::LFO3ControlDepth,  
                       0, 1200),  
     eLFO3Controller("Controller", &gig::DimensionRegion::LFO3Controller),  
     eLFO3Sync("Sync", &gig::DimensionRegion::LFO3Sync),  
     eVCFEnabled("Enabled", &gig::DimensionRegion::VCFEnabled),  
     eVCFType("Type", &gig::DimensionRegion::VCFType),  
     eVCFCutoffController("CutoffController",  
                          &gig::DimensionRegion::VCFCutoffController),  
     eVCFCutoffControllerInvert("CutoffControllerInvert",  
                                &gig::DimensionRegion::VCFCutoffControllerInvert),  
     eVCFCutoff("Cutoff", &gig::DimensionRegion::VCFCutoff),  
     eVCFVelocityCurve("VelocityCurve", &gig::DimensionRegion::VCFVelocityCurve),  
     eVCFVelocityScale("VelocityScale", &gig::DimensionRegion::VCFVelocityScale),  
     eVCFVelocityDynamicRange("VelocityDynamicRange",  
                              &gig::DimensionRegion::VCFVelocityDynamicRange,  
                              0, 4),  
     eVCFResonance("Resonance", &gig::DimensionRegion::VCFResonance),  
     eVCFResonanceDynamic("ResonanceDynamic",  
                          &gig::DimensionRegion::VCFResonanceDynamic),  
     eVCFResonanceController("ResonanceController",  
                             &gig::DimensionRegion::VCFResonanceController),  
     eVCFKeyboardTracking("KeyboardTracking",  
                          &gig::DimensionRegion::VCFKeyboardTracking),  
     eVCFKeyboardTrackingBreakpoint("KeyboardTrackingBreakpoint",  
                                    &gig::DimensionRegion::VCFKeyboardTrackingBreakpoint),  
     eVelocityResponseCurve("VelocityResponseCurve",  
                            &gig::DimensionRegion::VelocityResponseCurve),  
     eVelocityResponseDepth("VelocityResponseDepth",  
                            &gig::DimensionRegion::VelocityResponseDepth, 0, 4),  
     eVelocityResponseCurveScaling("VelocityResponseCurveScaling",  
                                   &gig::DimensionRegion::VelocityResponseCurveScaling),  
     eReleaseVelocityResponseCurve("ReleaseVelocityResponseCurve",  
                                   &gig::DimensionRegion::ReleaseVelocityResponseCurve),  
     eReleaseVelocityResponseDepth("ReleaseVelocityResponseDepth",  
                                   &gig::DimensionRegion::ReleaseVelocityResponseDepth,  
                                   0, 4),  
     eReleaseTriggerDecay("ReleaseTriggerDecay",  
                          &gig::DimensionRegion::ReleaseTriggerDecay, 0, 8),  
     eCrossfade_in_start("Crossfade.in_start", &access_Crossfade_in_start),  
     eCrossfade_in_end("Crossfade.in_end", &access_Crossfade_in_end),  
     eCrossfade_out_start("Crossfade.out_start", &access_Crossfade_out_start),  
     eCrossfade_out_end("Crossfade.out_end", &access_Crossfade_out_end),  
     ePitchTrack("PitchTrack", &gig::DimensionRegion::PitchTrack),  
     eDimensionBypass("DimensionBypass", &gig::DimensionRegion::DimensionBypass),  
     ePan("Pan", &gig::DimensionRegion::Pan, -64, 63),  
     eSelfMask("SelfMask", &gig::DimensionRegion::SelfMask),  
     eAttenuationController("AttenuationController",  
                            &gig::DimensionRegion::AttenuationController),  
     eInvertAttenuationController("InvertAttenuationController",  
                                  &gig::DimensionRegion::InvertAttenuationController),  
     eAttenuationControllerThreshold("AttenuationControllerThreshold",  
                                     &gig::DimensionRegion::AttenuationControllerThreshold),  
     eChannelOffset("ChannelOffset", &gig::DimensionRegion::ChannelOffset, 0, 9),  
     eSustainDefeat("SustainDefeat", &gig::DimensionRegion::SustainDefeat),  
     eMSDecode("MSDecode", &gig::DimensionRegion::MSDecode),  
     eSampleStartOffset("SampleStartOffset",  
                        &gig::DimensionRegion::SampleStartOffset, 0, 2000),  
     eUnityNote("UnityNote", &access_UnityNote),  
     eFineTune("FineTune", &access_FineTune, -49, 50),  
     eGain("Gain", -96, 0, 2),  
     eSampleLoops("SampleLoops", &access_SampleLoops, 0, 1)  
47  {  {
48  //    set_border_width(5);  //    set_border_width(5);
49      set_default_size(400, 200);  //    set_default_size(400, 200);
50    
51    
52      add(m_VBox);      add(m_VBox);
# Line 524  MainWindow::MainWindow() : Line 54  MainWindow::MainWindow() :
54      // Handle selection      // Handle selection
55      Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();      Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();
56      tree_sel_ref->signal_changed().connect(      tree_sel_ref->signal_changed().connect(
57          sigc::mem_fun(*this, &MainWindow::on_sel_change));          sigc::mem_fun(*this, &MainWindow::on_sel_change));
58    
59        // m_TreeView.set_reorderable();
60    
61      m_TreeView.signal_button_press_event().connect_notify(      m_TreeView.signal_button_press_event().connect_notify(
62          sigc::mem_fun(*this, &MainWindow::on_button_release));          sigc::mem_fun(*this, &MainWindow::on_button_release));
63    
64      // Add the TreeView tab, inside a ScrolledWindow, with the button underneath:      // Add the TreeView tab, inside a ScrolledWindow, with the button underneath:
65      m_ScrolledWindow.add(m_TreeViewNotebook);      m_ScrolledWindow.add(m_TreeView);
66      m_ScrolledWindow.set_size_request(400, 600);  //    m_ScrolledWindow.set_size_request(200, 600);
67      m_ScrolledWindow.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);      m_ScrolledWindow.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
68    
69      for (int i = 0 ; i < 5 ; i++) {      m_ScrolledWindowSamples.add(m_TreeViewSamples);
70          table[i] = new Gtk::Table(3, 1);      m_ScrolledWindowSamples.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
71          table[i]->set_col_spacings(5);  
72      }  
73        m_TreeViewNotebook.set_size_request(300);
     pageno = 0;  
     rowno = 0;  
     firstRowInBlock = 0;  
   
     addString("Sample", lSample, wSample);  
     addProp(eVelocityUpperLimit);  
     addHeader("EG1");  
     addProp(eEG1PreAttack);  
     addProp(eEG1Attack);  
     addProp(eEG1Decay1);  
     addProp(eEG1Decay2);  
     addProp(eEG1InfiniteSustain);  
     addProp(eEG1Sustain);  
     addProp(eEG1Release);  
     addProp(eEG1Hold);  
     addProp(eEG1Controller);  
     addProp(eEG1ControllerInvert);  
     addProp(eEG1ControllerAttackInfluence);  
     addProp(eEG1ControllerDecayInfluence);  
     addProp(eEG1ControllerReleaseInfluence);  
     addHeader("LFO1");  
     addProp(eLFO1Frequency);  
     addProp(eLFO1InternalDepth);  
     addProp(eLFO1ControlDepth);  
     {  
         char* choices[] = { "internal", "modwheel", "breath",  
                             "internal+modwheel", "internal+breath", 0 };  
         static const gig::lfo1_ctrl_t values[] = {  
             gig::lfo1_ctrl_internal,  
             gig::lfo1_ctrl_modwheel,  
             gig::lfo1_ctrl_breath,  
             gig::lfo1_ctrl_internal_modwheel,  
             gig::lfo1_ctrl_internal_breath  
         };  
         eLFO1Controller.set_choices(choices, values);  
     }  
     addProp(eLFO1Controller);  
     addProp(eLFO1FlipPhase);  
     addProp(eLFO1Sync);  
   
     nextPage();  
     addHeader("EG2");  
     addProp(eEG2PreAttack);  
     addProp(eEG2Attack);  
     addProp(eEG2Decay1);  
     addProp(eEG2Decay2);  
     addProp(eEG2InfiniteSustain);  
     addProp(eEG2Sustain);  
     addProp(eEG2Release);  
     addProp(eEG2Controller);  
     addProp(eEG2ControllerInvert);  
     addProp(eEG2ControllerAttackInfluence);  
     addProp(eEG2ControllerDecayInfluence);  
     addProp(eEG2ControllerReleaseInfluence);  
     addHeader("LFO2");  
     addProp(eLFO2Frequency);  
     addProp(eLFO2InternalDepth);  
     addProp(eLFO2ControlDepth);  
     {  
         char* choices[] = { "internal", "modwheel", "foot",  
                             "internal+modwheel", "internal+foot", 0 };  
         static const gig::lfo2_ctrl_t values[] = {  
             gig::lfo2_ctrl_internal,  
             gig::lfo2_ctrl_modwheel,  
             gig::lfo2_ctrl_foot,  
             gig::lfo2_ctrl_internal_modwheel,  
             gig::lfo2_ctrl_internal_foot  
         };  
         eLFO2Controller.set_choices(choices, values);  
     }  
     addProp(eLFO2Controller);  
     addProp(eLFO2FlipPhase);  
     addProp(eLFO2Sync);  
   
     nextPage();  
   
     addHeader("EG3");  
     addProp(eEG3Attack);  
     addProp(eEG3Depth);  
     addHeader("LFO3");  
     addProp(eLFO3Frequency);  
     addProp(eLFO3InternalDepth);  
     addProp(eLFO3ControlDepth);  
     {  
         char* choices[] = { "internal", "modwheel", "aftertouch",  
                             "internal+modwheel", "internal+aftertouch", 0 };  
         static const gig::lfo3_ctrl_t values[] = {  
             gig::lfo3_ctrl_internal,  
             gig::lfo3_ctrl_modwheel,  
             gig::lfo3_ctrl_aftertouch,  
             gig::lfo3_ctrl_internal_modwheel,  
             gig::lfo3_ctrl_internal_aftertouch  
         };  
         eLFO3Controller.set_choices(choices, values);  
     }  
     addProp(eLFO3Controller);  
     addProp(eLFO3Sync);  
     addHeader("VCF");  
     addProp(eVCFEnabled);  
     {  
         char* choices[] = { "lowpass", "lowpassturbo", "bandpass",  
                             "highpass", "bandreject", 0 };  
         static const gig::vcf_type_t values[] = {  
             gig::vcf_type_lowpass,  
             gig::vcf_type_lowpassturbo,  
             gig::vcf_type_bandpass,  
             gig::vcf_type_highpass,  
             gig::vcf_type_bandreject  
         };  
         eVCFType.set_choices(choices, values);  
     }  
     addProp(eVCFType);  
     {  
         char* choices[] = { "none", "none2", "modwheel", "effect1", "effect2",  
                             "breath", "foot", "sustainpedal", "softpedal",  
                             "genpurpose7", "genpurpose8", "aftertouch", 0 };  
         static const gig::vcf_cutoff_ctrl_t values[] = {  
             gig::vcf_cutoff_ctrl_none,  
             gig::vcf_cutoff_ctrl_none2,  
             gig::vcf_cutoff_ctrl_modwheel,  
             gig::vcf_cutoff_ctrl_effect1,  
             gig::vcf_cutoff_ctrl_effect2,  
             gig::vcf_cutoff_ctrl_breath,  
             gig::vcf_cutoff_ctrl_foot,  
             gig::vcf_cutoff_ctrl_sustainpedal,  
             gig::vcf_cutoff_ctrl_softpedal,  
             gig::vcf_cutoff_ctrl_genpurpose7,  
             gig::vcf_cutoff_ctrl_genpurpose8,  
             gig::vcf_cutoff_ctrl_aftertouch  
         };  
         eVCFCutoffController.set_choices(choices, values);  
     }  
     addProp(eVCFCutoffController);  
     addProp(eVCFCutoffControllerInvert);  
     addProp(eVCFCutoff);  
     char* curve_type_texts[] = { "nonlinear", "linear", "special", 0 };  
     static const gig::curve_type_t curve_type_values[] = {  
         gig::curve_type_nonlinear,  
         gig::curve_type_linear,  
         gig::curve_type_special  
     };  
     eVCFVelocityCurve.set_choices(curve_type_texts, curve_type_values);  
     addProp(eVCFVelocityCurve);  
     addProp(eVCFVelocityScale);  
     addProp(eVCFVelocityDynamicRange);  
     addProp(eVCFResonance);  
     addProp(eVCFResonanceDynamic);  
     {  
         char* choices[] = { "none", "genpurpose3", "genpurpose4",  
                             "genpurpose5", "genpurpose6", 0 };  
         static const gig::vcf_res_ctrl_t values[] = {  
             gig::vcf_res_ctrl_none,  
             gig::vcf_res_ctrl_genpurpose3,  
             gig::vcf_res_ctrl_genpurpose4,  
             gig::vcf_res_ctrl_genpurpose5,  
             gig::vcf_res_ctrl_genpurpose6  
         };  
         eVCFResonanceController.set_choices(choices, values);  
     }  
     addProp(eVCFResonanceController);  
     addProp(eVCFKeyboardTracking);  
     addProp(eVCFKeyboardTrackingBreakpoint);  
   
     nextPage();  
   
     eVelocityResponseCurve.set_choices(curve_type_texts, curve_type_values);  
     addProp(eVelocityResponseCurve);  
     addProp(eVelocityResponseDepth);  
     addProp(eVelocityResponseCurveScaling);  
     eReleaseVelocityResponseCurve.set_choices(curve_type_texts,  
                                               curve_type_values);  
     addProp(eReleaseVelocityResponseCurve);  
     addProp(eReleaseVelocityResponseDepth);  
     addProp(eReleaseTriggerDecay);  
     addProp(eCrossfade_in_start);  
     addProp(eCrossfade_in_end);  
     addProp(eCrossfade_out_start);  
     addProp(eCrossfade_out_end);  
     addProp(ePitchTrack);  
     {  
         char* choices[] = { "none", "effect4depth", "effect5depth", 0 };  
         static const gig::dim_bypass_ctrl_t values[] = {  
             gig::dim_bypass_ctrl_none,  
             gig::dim_bypass_ctrl_94,  
             gig::dim_bypass_ctrl_95  
         };  
         eDimensionBypass.set_choices(choices, values);  
     }  
     addProp(eDimensionBypass);  
     addProp(ePan);  
     addProp(eSelfMask);  
     addProp(eAttenuationController);  
     addProp(eInvertAttenuationController);  
     addProp(eAttenuationControllerThreshold);  
     addProp(eChannelOffset);  
     addProp(eSustainDefeat);  
   
     nextPage();  
     addProp(eMSDecode);  
     addProp(eSampleStartOffset);  
     addProp(eUnityNote);  
     addProp(eFineTune);  
     addProp(eGain);  
     addProp(eSampleLoops);  
     nextPage();  
   
     eEG1InfiniteSustain.signal_toggled().connect(  
         sigc::mem_fun(*this, &MainWindow::EG1InfiniteSustain_toggled) );  
     eEG2InfiniteSustain.signal_toggled().connect(  
         sigc::mem_fun(*this, &MainWindow::EG2InfiniteSustain_toggled) );  
     eEG1Controller.signal_changed().connect(  
         sigc::mem_fun(*this, &MainWindow::EG1Controller_changed) );  
     eEG2Controller.signal_changed().connect(  
         sigc::mem_fun(*this, &MainWindow::EG2Controller_changed) );  
     eLFO1Controller.signal_changed().connect(  
         sigc::mem_fun(*this, &MainWindow::LFO1Controller_changed) );  
     eLFO2Controller.signal_changed().connect(  
         sigc::mem_fun(*this, &MainWindow::LFO2Controller_changed) );  
     eLFO3Controller.signal_changed().connect(  
         sigc::mem_fun(*this, &MainWindow::LFO3Controller_changed) );  
     eAttenuationController.signal_changed().connect(  
         sigc::mem_fun(*this, &MainWindow::AttenuationController_changed) );  
     eVCFEnabled.signal_toggled().connect(  
         sigc::mem_fun(*this, &MainWindow::VCFEnabled_toggled) );  
     eVCFCutoffController.signal_changed().connect(  
         sigc::mem_fun(*this, &MainWindow::VCFCutoffController_changed) );  
     eVCFResonanceController.signal_changed().connect(  
         sigc::mem_fun(*this, &MainWindow::VCFResonanceController_changed) );  
   
     eCrossfade_in_start.signal_value_changed().connect(  
         sigc::mem_fun(*this, &MainWindow::crossfade1_changed));  
     eCrossfade_in_end.signal_value_changed().connect(  
         sigc::mem_fun(*this, &MainWindow::crossfade2_changed));  
     eCrossfade_out_start.signal_value_changed().connect(  
         sigc::mem_fun(*this, &MainWindow::crossfade3_changed));  
     eCrossfade_out_end.signal_value_changed().connect(  
         sigc::mem_fun(*this, &MainWindow::crossfade4_changed));  
   
     //m_Notebook.append_page(m_ScrolledWindow2, "Table");  
     m_Notebook.append_page(*table[0], "EG1");  
     m_Notebook.append_page(*table[1], "EG2");  
     m_Notebook.append_page(*table[2], "EG3");  
     m_Notebook.append_page(*table[3], "Velocity");  
     m_Notebook.append_page(*table[4], "Misc");  
     m_Notebook.set_size_request(400, 500);  
74    
75      m_HPaned.add1(m_ScrolledWindow);      m_HPaned.add1(m_TreeViewNotebook);
76      m_HPaned.add2(m_Notebook);      m_HPaned.add2(dimreg_edit);
77    
78    
79      m_TreeViewNotebook.append_page(m_TreeViewSamples, "Samples");      m_TreeViewNotebook.append_page(m_ScrolledWindowSamples, "Samples");
80      m_TreeViewNotebook.append_page(m_TreeView, "Instruments");      m_TreeViewNotebook.append_page(m_ScrolledWindow, "Instruments");
81    
82    
83      actionGroup = Gtk::ActionGroup::create();      actionGroup = Gtk::ActionGroup::create();
# Line 822  MainWindow::MainWindow() : Line 109  MainWindow::MainWindow() :
109      actionGroup->add(Gtk::Action::create("InstrProperties",      actionGroup->add(Gtk::Action::create("InstrProperties",
110                                           Gtk::Stock::PROPERTIES),                                           Gtk::Stock::PROPERTIES),
111                       sigc::mem_fun(                       sigc::mem_fun(
112                           *this, &MainWindow::on_action_file_properties));                           *this, &MainWindow::show_instr_props));
113      actionGroup->add(Gtk::Action::create("Quit", Gtk::Stock::QUIT),      actionGroup->add(Gtk::Action::create("Quit", Gtk::Stock::QUIT),
114                       sigc::mem_fun(                       sigc::mem_fun(
115                           *this, &MainWindow::hide));                           *this, &MainWindow::hide));
# Line 836  MainWindow::MainWindow() : Line 123  MainWindow::MainWindow() :
123                       sigc::mem_fun(                       sigc::mem_fun(
124                           *this, &MainWindow::on_action_help_about));                           *this, &MainWindow::on_action_help_about));
125  #endif  #endif
126      action = Gtk::Action::create("Remove", Gtk::Stock::REMOVE);      actionGroup->add(
127      actionGroup->add(action,          Gtk::Action::create("AddInstrument", _("Add _Instrument")),
128                       sigc::mem_fun(          sigc::mem_fun(*this, &MainWindow::on_action_add_instrument)
129                           *this, &MainWindow::hide));      );
130        actionGroup->add(
131            Gtk::Action::create("RemoveInstrument", Gtk::Stock::REMOVE),
132            sigc::mem_fun(*this, &MainWindow::on_action_remove_instrument)
133        );
134    
135      // sample right-click popup actions      // sample right-click popup actions
136      actionGroup->add(      actionGroup->add(
# Line 851  MainWindow::MainWindow() : Line 142  MainWindow::MainWindow() :
142          sigc::mem_fun(*this, &MainWindow::on_action_add_group)          sigc::mem_fun(*this, &MainWindow::on_action_add_group)
143      );      );
144      actionGroup->add(      actionGroup->add(
145          Gtk::Action::create("AddSample", _("Add _Sample")),          Gtk::Action::create("AddSample", _("Add _Sample(s)")),
146          sigc::mem_fun(*this, &MainWindow::on_action_add_sample)          sigc::mem_fun(*this, &MainWindow::on_action_add_sample)
147      );      );
148      actionGroup->add(      actionGroup->add(
# Line 887  MainWindow::MainWindow() : Line 178  MainWindow::MainWindow() :
178          "  </menubar>"          "  </menubar>"
179          "  <popup name='PopupMenu'>"          "  <popup name='PopupMenu'>"
180          "    <menuitem action='InstrProperties'/>"          "    <menuitem action='InstrProperties'/>"
181          "    <menuitem action='Remove'/>"          "    <menuitem action='AddInstrument'/>"
182            "    <separator/>"
183            "    <menuitem action='RemoveInstrument'/>"
184          "  </popup>"          "  </popup>"
185          "  <popup name='SamplePopupMenu'>"          "  <popup name='SamplePopupMenu'>"
186          "    <menuitem action='SampleProperties'/>"          "    <menuitem action='SampleProperties'/>"
# Line 908  MainWindow::MainWindow() : Line 201  MainWindow::MainWindow() :
201      m_VBox.pack_start(m_DimRegionChooser, Gtk::PACK_SHRINK);      m_VBox.pack_start(m_DimRegionChooser, Gtk::PACK_SHRINK);
202    
203      m_RegionChooser.signal_sel_changed().connect(      m_RegionChooser.signal_sel_changed().connect(
204          sigc::mem_fun(*this, &MainWindow::region_changed) );          sigc::mem_fun(*this, &MainWindow::region_changed) );
205      m_DimRegionChooser.signal_sel_changed().connect(      m_DimRegionChooser.signal_sel_changed().connect(
206          sigc::mem_fun(*this, &MainWindow::dimreg_changed) );          sigc::mem_fun(*this, &MainWindow::dimreg_changed) );
207    
208    
209      // Create the Tree model:      // Create the Tree model:
210      m_refTreeModel = Gtk::ListStore::create(m_Columns);      m_refTreeModel = Gtk::ListStore::create(m_Columns);
211      m_TreeView.set_model(m_refTreeModel);      m_TreeView.set_model(m_refTreeModel);
212        m_refTreeModel->signal_row_changed().connect(
213            sigc::mem_fun(*this, &MainWindow::instrument_name_changed)
214        );
215    
216      // Add the TreeView's view columns:      // Add the TreeView's view columns:
217      m_TreeView.append_column("Instrument", m_Columns.m_col_name);      m_TreeView.append_column_editable("Instrument", m_Columns.m_col_name);
218      m_TreeView.set_headers_visible(false);      m_TreeView.set_headers_visible(false);
219    
220      // create samples treeview (including its data model)      // create samples treeview (including its data model)
221      m_refSamplesTreeModel = Gtk::TreeStore::create(m_SamplesModel);      m_refSamplesTreeModel = SamplesTreeStore::create(m_SamplesModel);
222      m_TreeViewSamples.set_model(m_refSamplesTreeModel);      m_TreeViewSamples.set_model(m_refSamplesTreeModel);
223      m_TreeViewSamples.append_column("Samples", m_SamplesModel.m_col_name);      // m_TreeViewSamples.set_reorderable();
224        m_TreeViewSamples.append_column_editable("Samples", m_SamplesModel.m_col_name);
225      m_TreeViewSamples.set_headers_visible(false);      m_TreeViewSamples.set_headers_visible(false);
226      m_TreeViewSamples.signal_button_press_event().connect_notify(      m_TreeViewSamples.signal_button_press_event().connect_notify(
227          sigc::mem_fun(*this, &MainWindow::on_sample_treeview_button_release)          sigc::mem_fun(*this, &MainWindow::on_sample_treeview_button_release)
228      );      );
229        m_refSamplesTreeModel->signal_row_changed().connect(
230            sigc::mem_fun(*this, &MainWindow::sample_name_changed)
231        );
232    
233        // establish drag&drop between samples tree view and dimension region 'Sample' text entry
234        std::list<Gtk::TargetEntry> drag_target_gig_sample;
235        drag_target_gig_sample.push_back( Gtk::TargetEntry("gig::Sample") );
236        m_TreeViewSamples.drag_source_set(drag_target_gig_sample);
237        m_TreeViewSamples.signal_drag_data_get().connect(
238            sigc::mem_fun(*this, &MainWindow::on_sample_treeview_drag_data_get)
239        );
240        dimreg_edit.wSample->drag_dest_set(drag_target_gig_sample);
241        dimreg_edit.wSample->signal_drag_data_received().connect(
242            sigc::mem_fun(*this, &MainWindow::on_sample_label_drop_drag_data_received)
243        );
244    
245      file = 0;      file = 0;
246    
# Line 946  void MainWindow::region_changed() Line 258  void MainWindow::region_changed()
258    
259  void MainWindow::dimreg_changed()  void MainWindow::dimreg_changed()
260  {  {
261      set_dim_region(m_DimRegionChooser.get_dimregion());      dimreg_edit.set_dim_region(m_DimRegionChooser.get_dimregion());
262  }  }
263    
264  void MainWindow::on_sel_change()  void MainWindow::on_sel_change()
# Line 954  void MainWindow::on_sel_change() Line 266  void MainWindow::on_sel_change()
266      Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();      Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();
267    
268      Gtk::TreeModel::iterator it = tree_sel_ref->get_selected();      Gtk::TreeModel::iterator it = tree_sel_ref->get_selected();
269      if (it)      if (it) {
270      {          Gtk::TreeModel::Row row = *it;
271          Gtk::TreeModel::Row row = *it;          std::cout << row[m_Columns.m_col_name] << std::endl;
         std::cout << row[m_Columns.m_col_name] << std::endl;  
   
         if (row[m_Columns.m_col_instr])  
             m_RegionChooser.set_instrument(row[m_Columns.m_col_instr]);  
     }  
 }  
272    
273  void MainWindow::set_dim_region(gig::DimensionRegion* d)          m_RegionChooser.set_instrument(row[m_Columns.m_col_instr]);
 {  
     update_gui = false;  
     wSample->set_text(d->pSample ? d->pSample->pInfo->Name.c_str() : "NULL");  
     eVelocityUpperLimit.set_dimreg(d);  
     eEG1PreAttack.set_dimreg(d);  
     eEG1Attack.set_dimreg(d);  
     eEG1Decay1.set_dimreg(d);  
     eEG1Decay2.set_dimreg(d);  
     eEG1InfiniteSustain.set_dimreg(d);  
     eEG1Sustain.set_dimreg(d);  
     eEG1Release.set_dimreg(d);  
     eEG1Hold.set_dimreg(d);  
     eEG1Controller.set_dimreg(d);  
     eEG1ControllerInvert.set_dimreg(d);  
     eEG1ControllerAttackInfluence.set_dimreg(d);  
     eEG1ControllerDecayInfluence.set_dimreg(d);  
     eEG1ControllerReleaseInfluence.set_dimreg(d);  
     eLFO1Frequency.set_dimreg(d);  
     eLFO1InternalDepth.set_dimreg(d);  
     eLFO1ControlDepth.set_dimreg(d);  
     eLFO1Controller.set_dimreg(d);  
     eLFO1FlipPhase.set_dimreg(d);  
     eLFO1Sync.set_dimreg(d);  
     eEG2PreAttack.set_dimreg(d);  
     eEG2Attack.set_dimreg(d);  
     eEG2Decay1.set_dimreg(d);  
     eEG2Decay2.set_dimreg(d);  
     eEG2InfiniteSustain.set_dimreg(d);  
     eEG2Sustain.set_dimreg(d);  
     eEG2Release.set_dimreg(d);  
     eEG2Controller.set_dimreg(d);  
     eEG2ControllerInvert.set_dimreg(d);  
     eEG2ControllerAttackInfluence.set_dimreg(d);  
     eEG2ControllerDecayInfluence.set_dimreg(d);  
     eEG2ControllerReleaseInfluence.set_dimreg(d);  
     eLFO2Frequency.set_dimreg(d);  
     eLFO2InternalDepth.set_dimreg(d);  
     eLFO2ControlDepth.set_dimreg(d);  
     eLFO2Controller.set_dimreg(d);  
     eLFO2FlipPhase.set_dimreg(d);  
     eLFO2Sync.set_dimreg(d);  
     eEG3Attack.set_dimreg(d);  
     eEG3Depth.set_dimreg(d);  
     eLFO3Frequency.set_dimreg(d);  
     eLFO3InternalDepth.set_dimreg(d);  
     eLFO3ControlDepth.set_dimreg(d);  
     eLFO3Controller.set_dimreg(d);  
     eLFO3Sync.set_dimreg(d);  
     eVCFEnabled.set_dimreg(d);  
     eVCFType.set_dimreg(d);  
     eVCFCutoffController.set_dimreg(d);  
     eVCFCutoffControllerInvert.set_dimreg(d);  
     eVCFCutoff.set_dimreg(d);  
     eVCFVelocityCurve.set_dimreg(d);  
     eVCFVelocityScale.set_dimreg(d);  
     eVCFVelocityDynamicRange.set_dimreg(d);  
     eVCFResonance.set_dimreg(d);  
     eVCFResonanceDynamic.set_dimreg(d);  
     eVCFResonanceController.set_dimreg(d);  
     eVCFKeyboardTracking.set_dimreg(d);  
     eVCFKeyboardTrackingBreakpoint.set_dimreg(d);  
     eVelocityResponseCurve.set_dimreg(d);  
     eVelocityResponseDepth.set_dimreg(d);  
     eVelocityResponseCurveScaling.set_dimreg(d);  
     eReleaseVelocityResponseCurve.set_dimreg(d);  
     eReleaseVelocityResponseDepth.set_dimreg(d);  
     eReleaseTriggerDecay.set_dimreg(d);  
     eCrossfade_in_start.set_dimreg(d);  
     eCrossfade_in_end.set_dimreg(d);  
     eCrossfade_out_start.set_dimreg(d);  
     eCrossfade_out_end.set_dimreg(d);  
     ePitchTrack.set_dimreg(d);  
     eDimensionBypass.set_dimreg(d);  
     ePan.set_dimreg(d);  
     eSelfMask.set_dimreg(d);  
     eAttenuationController.set_dimreg(d);  
     eInvertAttenuationController.set_dimreg(d);  
     eAttenuationControllerThreshold.set_dimreg(d);  
     eChannelOffset.set_dimreg(d);  
     eSustainDefeat.set_dimreg(d);  
     eMSDecode.set_dimreg(d);  
     eSampleStartOffset.set_dimreg(d);  
     eUnityNote.set_dimreg(d);  
     eFineTune.set_dimreg(d);  
     eGain.set_dimreg(d);  
     eSampleLoops.set_dimreg(d);  
   
     VCFEnabled_toggled();  
   
     update_gui = true;  
 }  
   
 void MainWindow::VCFEnabled_toggled()  
 {  
     bool sensitive = eVCFEnabled.get_active();  
     eVCFType.set_sensitive(sensitive);  
     eVCFCutoffController.set_sensitive(sensitive);  
     eVCFVelocityCurve.set_sensitive(sensitive);  
     eVCFVelocityScale.set_sensitive(sensitive);  
     eVCFVelocityDynamicRange.set_sensitive(sensitive);  
     eVCFResonance.set_sensitive(sensitive);  
     eVCFResonanceController.set_sensitive(sensitive);  
     eVCFKeyboardTracking.set_sensitive(sensitive);  
     eVCFKeyboardTrackingBreakpoint.set_sensitive(sensitive);  
     eEG2PreAttack.set_sensitive(sensitive);  
     eEG2Attack.set_sensitive(sensitive);  
     eEG2Decay1.set_sensitive(sensitive);  
     eEG2InfiniteSustain.set_sensitive(sensitive);  
     eEG2Sustain.set_sensitive(sensitive);  
     eEG2Release.set_sensitive(sensitive);  
     eEG2Controller.set_sensitive(sensitive);  
     eEG2ControllerAttackInfluence.set_sensitive(sensitive);  
     eEG2ControllerDecayInfluence.set_sensitive(sensitive);  
     eEG2ControllerReleaseInfluence.set_sensitive(sensitive);  
     eLFO2Frequency.set_sensitive(sensitive);  
     eLFO2InternalDepth.set_sensitive(sensitive);  
     eLFO2ControlDepth.set_sensitive(sensitive);  
     eLFO2Controller.set_sensitive(sensitive);  
     eLFO2FlipPhase.set_sensitive(sensitive);  
     eLFO2Sync.set_sensitive(sensitive);  
     if (sensitive) {  
         VCFCutoffController_changed();  
         VCFResonanceController_changed();  
         EG2InfiniteSustain_toggled();  
         EG2Controller_changed();  
         LFO2Controller_changed();  
274      } else {      } else {
275          eVCFCutoffControllerInvert.set_sensitive(false);          m_RegionChooser.set_instrument(0);
         eVCFCutoff.set_sensitive(false);  
         eVCFResonanceDynamic.set_sensitive(false);  
         eVCFResonance.set_sensitive(false);  
         eEG2Decay2.set_sensitive(false);  
         eEG2ControllerInvert.set_sensitive(false);  
         eLFO2InternalDepth.set_sensitive(false);  
         eLFO2ControlDepth.set_sensitive(false);  
276      }      }
277  }  }
278    
 void MainWindow::VCFCutoffController_changed()  
 {  
     int rowno = eVCFCutoffController.get_active_row_number();  
     bool hasController = rowno != 0 && rowno != 1;  
   
     eVCFCutoffControllerInvert.set_sensitive(hasController);  
     eVCFCutoff.set_sensitive(!hasController);  
     eVCFResonanceDynamic.set_sensitive(!hasController);  
     eVCFVelocityScale.label.set_text(hasController ? "MinimumCutoff:" :  
                                      "VelocityScale:");  
 }  
   
 void MainWindow::VCFResonanceController_changed()  
 {  
     bool hasController = eVCFResonanceController.get_active_row_number() != 0;  
     eVCFResonance.set_sensitive(!hasController);  
 }  
   
 void MainWindow::EG1InfiniteSustain_toggled()  
 {  
     bool infSus = eEG1InfiniteSustain.get_active();  
     eEG1Decay2.set_sensitive(!infSus);  
 }  
   
 void MainWindow::EG2InfiniteSustain_toggled()  
 {  
     bool infSus = eEG2InfiniteSustain.get_active();  
     eEG2Decay2.set_sensitive(!infSus);  
 }  
   
 void MainWindow::EG1Controller_changed()  
 {  
     bool hasController = eEG1Controller.get_active_row_number() != 0;  
     eEG1ControllerInvert.set_sensitive(hasController);  
 }  
   
 void MainWindow::EG2Controller_changed()  
 {  
     bool hasController = eEG2Controller.get_active_row_number() != 0;  
     eEG2ControllerInvert.set_sensitive(hasController);  
 }  
   
 void MainWindow::AttenuationController_changed()  
 {  
     bool hasController = eAttenuationController.get_active_row_number() != 0;  
     eInvertAttenuationController.set_sensitive(hasController);  
 }  
   
 void MainWindow::LFO1Controller_changed()  
 {  
     int rowno = eLFO1Controller.get_active_row_number();  
     eLFO1ControlDepth.set_sensitive(rowno != 0);  
     eLFO1InternalDepth.set_sensitive(rowno != 1 && rowno != 2);  
 }  
   
 void MainWindow::LFO2Controller_changed()  
 {  
     int rowno = eLFO2Controller.get_active_row_number();  
     eLFO2ControlDepth.set_sensitive(rowno != 0);  
     eLFO2InternalDepth.set_sensitive(rowno != 1 && rowno != 2);  
 }  
   
 void MainWindow::LFO3Controller_changed()  
 {  
     int rowno = eLFO3Controller.get_active_row_number();  
     eLFO3ControlDepth.set_sensitive(rowno != 0);  
     eLFO3InternalDepth.set_sensitive(rowno != 1 && rowno != 2);  
 }  
   
 void MainWindow::crossfade1_changed()  
 {  
     double c1 = eCrossfade_in_start.get_value();  
     double c2 = eCrossfade_in_end.get_value();  
     if (c1 > c2) eCrossfade_in_end.set_value(c1);  
 }  
   
 void MainWindow::crossfade2_changed()  
 {  
     double c1 = eCrossfade_in_start.get_value();  
     double c2 = eCrossfade_in_end.get_value();  
     double c3 = eCrossfade_out_start.get_value();  
   
     if (c2 < c1) eCrossfade_in_start.set_value(c2);  
     if (c2 > c3) eCrossfade_out_start.set_value(c2);  
 }  
   
 void MainWindow::crossfade3_changed()  
 {  
     double c2 = eCrossfade_in_end.get_value();  
     double c3 = eCrossfade_out_start.get_value();  
     double c4 = eCrossfade_out_end.get_value();  
   
     if (c3 < c2) eCrossfade_in_end.set_value(c3);  
     if (c3 > c4) eCrossfade_out_end.set_value(c3);  
 }  
   
 void MainWindow::crossfade4_changed()  
 {  
     double c3 = eCrossfade_out_start.get_value();  
     double c4 = eCrossfade_out_end.get_value();  
   
     if (c4 < c3) eCrossfade_out_start.set_value(c4);  
 }  
   
279  void loader_progress_callback(gig::progress_t* progress)  void loader_progress_callback(gig::progress_t* progress)
280  {  {
281      Loader* loader = static_cast<Loader*>(progress->custom);      Loader* loader = static_cast<Loader*>(progress->custom);
# Line 1268  Glib::Dispatcher& Loader::signal_finishe Line 337  Glib::Dispatcher& Loader::signal_finishe
337      return finished_dispatcher;      return finished_dispatcher;
338  }  }
339    
340  LoadDialog::LoadDialog()  LoadDialog::LoadDialog(const Glib::ustring& title, Gtk::Window& parent)
341        : Gtk::Dialog(title, parent, true)
342  {  {
343      get_vbox()->pack_start(progressBar);      get_vbox()->pack_start(progressBar);
344      show_all_children();      show_all_children();
345  }  }
346    
347    // Clear all GUI elements / controls. This method is typically called
348    // before a new .gig file is to be created or to be loaded.
349    void MainWindow::__clear() {
350        // remove all entries from "Instrument" menu
351        Gtk::MenuItem* instrument_menu =
352            dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/MenuBar/MenuInstrument"));
353        instrument_menu->hide();
354        for (int i = 0; i < instrument_menu->get_submenu()->items().size(); i++) {
355            delete &instrument_menu->get_submenu()->items()[i];
356        }
357        instrument_menu->get_submenu()->items().clear();
358        // forget all samples that ought to be imported
359        m_SampleImportQueue.clear();
360        // clear the samples and instruments tree views
361        m_refTreeModel->clear();
362        m_refSamplesTreeModel->clear();
363        // free libgig's gig::File instance
364        if (file) {
365            delete file;
366            file = NULL;
367        }
368    }
369    
370  void MainWindow::on_action_file_new()  void MainWindow::on_action_file_new()
371  {  {
372        // clear all GUI elements
373        __clear();
374        // create a new .gig file (virtually yet)
375        gig::File* pFile = new gig::File;
376        // already add one new instrument by default
377        gig::Instrument* pInstrument = pFile->AddInstrument();
378        pInstrument->pInfo->Name = "Unnamed Instrument";
379        // update GUI with that new gig::File
380        load_gig(pFile, NULL /*no file name yet*/);
381  }  }
382    
383  void MainWindow::on_action_file_open()  void MainWindow::on_action_file_open()
# Line 1288  void MainWindow::on_action_file_open() Line 390  void MainWindow::on_action_file_open()
390      dialog.set_filter(filter);      dialog.set_filter(filter);
391      if (dialog.run() == Gtk::RESPONSE_OK) {      if (dialog.run() == Gtk::RESPONSE_OK) {
392          printf("filename=%s\n", dialog.get_filename().c_str());          printf("filename=%s\n", dialog.get_filename().c_str());
393            __clear();
         // remove all entries from "Instrument" menu  
         Gtk::MenuItem* instrument_menu =  
             dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/MenuBar/MenuInstrument"));  
         instrument_menu->hide();  
         for (int i = 0; i < instrument_menu->get_submenu()->items().size(); i++) {  
             delete &instrument_menu->get_submenu()->items()[i];  
         }  
         instrument_menu->get_submenu()->items().clear();  
   
         m_refTreeModel->clear();  
         m_refSamplesTreeModel->clear();  
         if (file) delete file;  
   
         // getInfo(dialog.get_filename().c_str(), *this);  
   
394          printf("on_action_file_open self=%x\n", Glib::Thread::self());          printf("on_action_file_open self=%x\n", Glib::Thread::self());
395          load_dialog = new LoadDialog(); // Gtk::Dialog("Loading...", *this, true);          load_file(dialog.get_filename().c_str());
         load_dialog->show_all();  
         loader = new Loader(strdup(dialog.get_filename().c_str()));  
         loader->signal_progress().connect(  
             sigc::mem_fun(*this, &MainWindow::on_loader_progress));  
         loader->signal_finished().connect(  
             sigc::mem_fun(*this, &MainWindow::on_loader_finished));  
   
         loader->launch();  
396      }      }
397  }  }
398    
399    void MainWindow::load_file(const char* name)
400    {
401        load_dialog = new LoadDialog("Loading...", *this);
402        load_dialog->show_all();
403        loader = new Loader(strdup(name));
404        loader->signal_progress().connect(
405            sigc::mem_fun(*this, &MainWindow::on_loader_progress));
406        loader->signal_finished().connect(
407            sigc::mem_fun(*this, &MainWindow::on_loader_finished));
408        loader->launch();
409    }
410    
411  void MainWindow::on_loader_progress()  void MainWindow::on_loader_progress()
412  {  {
413      load_dialog->set_fraction(loader->get_progress());      load_dialog->set_fraction(loader->get_progress());
# Line 1327  void MainWindow::on_loader_finished() Line 418  void MainWindow::on_loader_finished()
418      printf("Loader finished!\n");      printf("Loader finished!\n");
419      printf("on_loader_finished self=%x\n", Glib::Thread::self());      printf("on_loader_finished self=%x\n", Glib::Thread::self());
420      load_gig(loader->gig, loader->filename);      load_gig(loader->gig, loader->filename);
   
   
     Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();  
     tree_sel_ref->select(Gtk::TreePath("0"));  
   
421      load_dialog->hide();      load_dialog->hide();
422  }  }
423    
424  void MainWindow::on_action_file_save()  void MainWindow::on_action_file_save()
425  {  {
426        if (!file) return;
427        std::cout << "Saving file\n" << std::flush;
428        try {
429            file->Save();
430        } catch (RIFF::Exception e) {
431            Glib::ustring txt = "Could not save file: " + e.Message;
432            Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
433            msg.run();
434            return;
435        }
436        std::cout << "Saving file done\n" << std::flush;
437        __import_queued_samples();
438  }  }
439    
440  void MainWindow::on_action_file_save_as()  void MainWindow::on_action_file_save_as()
441  {  {
442        if (!file) return;
443      Gtk::FileChooserDialog dialog(*this, "Open", Gtk::FILE_CHOOSER_ACTION_SAVE);      Gtk::FileChooserDialog dialog(*this, "Open", Gtk::FILE_CHOOSER_ACTION_SAVE);
444      dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);      dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
445      dialog.add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK);      dialog.add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK);
# Line 1349  void MainWindow::on_action_file_save_as( Line 448  void MainWindow::on_action_file_save_as(
448      dialog.set_filter(filter);      dialog.set_filter(filter);
449      if (dialog.run() == Gtk::RESPONSE_OK) {      if (dialog.run() == Gtk::RESPONSE_OK) {
450          printf("filename=%s\n", dialog.get_filename().c_str());          printf("filename=%s\n", dialog.get_filename().c_str());
451          file->Save(dialog.get_filename());          try {
452                file->Save(dialog.get_filename());
453            } catch (RIFF::Exception e) {
454                Glib::ustring txt = "Could not save file: " + e.Message;
455                Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
456                msg.run();
457                return;
458            }
459            __import_queued_samples();
460        }
461    }
462    
463    // actually write the sample(s)' data to the gig file
464    void MainWindow::__import_queued_samples() {
465        std::cout << "Starting sample import\n" << std::flush;
466        Glib::ustring error_files;
467        printf("Samples to import: %d\n", m_SampleImportQueue.size());
468        for (std::list<SampleImportItem>::iterator iter = m_SampleImportQueue.begin();
469             iter != m_SampleImportQueue.end(); ) {
470            printf("Importing sample %s\n",(*iter).sample_path.c_str());
471            SF_INFO info;
472            info.format = 0;
473            SNDFILE* hFile = sf_open((*iter).sample_path.c_str(), SFM_READ, &info);
474            try {
475                if (!hFile) throw std::string("could not open file");
476                // determine sample's bit depth
477                int bitdepth;
478                switch (info.format & 0xff) {
479                    case SF_FORMAT_PCM_S8:
480                        bitdepth = 16; // we simply convert to 16 bit for now
481                        break;
482                    case SF_FORMAT_PCM_16:
483                        bitdepth = 16;
484                        break;
485                    case SF_FORMAT_PCM_24:
486                        bitdepth = 32; // we simply convert to 32 bit for now
487                        break;
488                    case SF_FORMAT_PCM_32:
489                        bitdepth = 32;
490                        break;
491                    case SF_FORMAT_PCM_U8:
492                        bitdepth = 16; // we simply convert to 16 bit for now
493                        break;
494                    case SF_FORMAT_FLOAT:
495                        bitdepth = 32;
496                        break;
497                    case SF_FORMAT_DOUBLE:
498                        bitdepth = 32; // I guess we will always truncate this to 32 bit
499                        break;
500                    default:
501                        sf_close(hFile); // close sound file
502                        throw std::string("format not supported"); // unsupported subformat (yet?)
503                }
504                // allocate appropriate copy buffer (TODO: for now we copy
505                // it in one piece, might be tough for very long samples)
506                // and copy sample data into buffer
507                int8_t* buffer = NULL;
508                switch (bitdepth) {
509                    case 16:
510                        buffer = new int8_t[2 * info.channels * info.frames];
511                        // libsndfile does the conversion for us (if needed)
512                        sf_readf_short(hFile, (short*) buffer, info.frames);
513                        break;
514                    case 32:
515                        buffer = new int8_t[4 * info.channels * info.frames];
516                        // libsndfile does the conversion for us (if needed)
517                        sf_readf_int(hFile, (int*) buffer, info.frames);
518                        break;
519                }
520                // write from buffer directly (physically) into .gig file
521                (*iter).gig_sample->Write(buffer, info.frames);
522                // cleanup
523                sf_close(hFile);
524                delete[] buffer;
525                // on success we remove the sample from the import queue,
526                // otherwise keep it, maybe it works the next time ?
527                std::list<SampleImportItem>::iterator cur = iter;
528                ++iter;
529                m_SampleImportQueue.erase(cur);
530            } catch (std::string what) {
531                // remember the files that made trouble (and their cause)
532                if (error_files.size()) error_files += "\n";
533                error_files += (*iter).sample_path += " (" + what + ")";
534                ++iter;
535            }
536        }
537        // show error message box when some sample(s) could not be imported
538        if (error_files.size()) {
539            Glib::ustring txt = "Could not import the following sample(s):\n" + error_files;
540            Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
541            msg.run();
542      }      }
543  }  }
544    
# Line 1424  void PropDialog::set_info(DLS::Info* inf Line 613  void PropDialog::set_info(DLS::Info* inf
613      entry[15].set_text(info->Subject);      entry[15].set_text(info->Subject);
614  }  }
615    
616    namespace {
617        uint16_t& access_MIDIBank(gig::Instrument* instr)
618        {
619            // TODO: update MIDIBankCoarse/Fine too?
620            return instr->MIDIBank;
621        }
622        uint32_t& access_MIDIProgram(gig::Instrument* instr)
623        {
624            return instr->MIDIProgram;
625        }
626    }
627    
628  InstrumentProps::InstrumentProps()  InstrumentProps::InstrumentProps()
629      : table(2,1),      : table(2,1),
630        quitButton(Gtk::Stock::CLOSE)        quitButton(Gtk::Stock::CLOSE),
631          eMIDIBank("MIDIBank", &access_MIDIBank, 0, 16383),
632          eMIDIProgram("MIDIProgram", &access_MIDIProgram),
633          eAttenuation("Attenuation", &gig::Instrument::Attenuation),
634          eEffectSend("EffectSend", &gig::Instrument::EffectSend, 0, 65536),
635          eFineTune("FineTune", &gig::Instrument::FineTune, -8400, 8400),
636          ePianoReleaseMode("PianoReleaseMode", &gig::Instrument::PianoReleaseMode)
637  {  {
638      table.set_col_spacings(5);      table.set_col_spacings(5);
639      char* propLabels[] = {      char* propLabels[] = {
# Line 1444  InstrumentProps::InstrumentProps() Line 650  InstrumentProps::InstrumentProps()
650      };      };
651      int entryIdx = 0, checkIdx = 0;      int entryIdx = 0, checkIdx = 0;
652      for (int i = 0 ; i < sizeof(propLabels) / sizeof(char*) ; i++) {      for (int i = 0 ; i < sizeof(propLabels) / sizeof(char*) ; i++) {
653    #if 0
654            if (i == 3) {
655                table.attach(eMIDIProgram.label, 0, 1, i, i + 1,
656                             Gtk::FILL, Gtk::SHRINK);
657                table.attach(eMIDIProgram.widget, 1, 2, i, i + 1,
658                             Gtk::FILL | Gtk::EXPAND, Gtk::SHRINK);
659                continue;
660            }
661    #endif
662          label[i].set_text(propLabels[i]);          label[i].set_text(propLabels[i]);
663          label[i].set_alignment(Gtk::ALIGN_LEFT);          label[i].set_alignment(Gtk::ALIGN_LEFT);
664          table.attach(label[i], 0, 1, i, i + 1, Gtk::FILL, Gtk::SHRINK);          table.attach(label[i], 0, 1, i, i + 1, Gtk::FILL, Gtk::SHRINK);
# Line 1472  InstrumentProps::InstrumentProps() Line 687  InstrumentProps::InstrumentProps()
687      quitButton.grab_focus();      quitButton.grab_focus();
688    
689      quitButton.signal_clicked().connect(      quitButton.signal_clicked().connect(
690          sigc::mem_fun(*this, &InstrumentProps::hide));          sigc::mem_fun(*this, &InstrumentProps::hide));
691    
692      // quitButton.grab_default();      // quitButton.grab_default();
693      quitButton.show();      quitButton.show();
# Line 1481  InstrumentProps::InstrumentProps() Line 696  InstrumentProps::InstrumentProps()
696      show_all_children();      show_all_children();
697  }  }
698    
699    extern char* notes[];
700    
701  void InstrumentProps::set_instrument(gig::Instrument* instrument)  void InstrumentProps::set_instrument(gig::Instrument* instrument)
702  {  {
# Line 1512  void InstrumentProps::set_instrument(gig Line 728  void InstrumentProps::set_instrument(gig
728      entry[entryIdx].set_text(buf);      entry[entryIdx].set_text(buf);
729  }  }
730    
 void MainWindow::getInfo(const char *filename)  
 {  
     RIFF::File* riff = new RIFF::File(filename);  
     gig::File* gig = new gig::File(riff);  
   
     load_gig(gig, filename);  
 }  
   
731  void MainWindow::load_gig(gig::File* gig, const char* filename)  void MainWindow::load_gig(gig::File* gig, const char* filename)
732  {  {
733      file = gig;      file = gig;
734    
735      const char *basename = strrchr(filename, '/');      if (filename) {
736      basename = basename ? basename + 1 : filename;          const char *basename = strrchr(filename, '/');
737            basename = basename ? basename + 1 : filename;
738      set_title(basename);          set_title(basename);
739        } else {
740            set_title("unnamed");
741        }
742    
743      propDialog.set_info(gig->pInfo);      propDialog.set_info(gig->pInfo);
744    
# Line 1537  void MainWindow::load_gig(gig::File* gig Line 748  void MainWindow::load_gig(gig::File* gig
748      int instrument_index = 0;      int instrument_index = 0;
749      Gtk::RadioMenuItem::Group instrument_group;      Gtk::RadioMenuItem::Group instrument_group;
750      for (gig::Instrument* instrument = gig->GetFirstInstrument() ; instrument ;      for (gig::Instrument* instrument = gig->GetFirstInstrument() ; instrument ;
751           instrument = gig->GetNextInstrument()) {           instrument = gig->GetNextInstrument()) {
752          Gtk::TreeModel::iterator iter = m_refTreeModel->append();          Gtk::TreeModel::iterator iter = m_refTreeModel->append();
753          Gtk::TreeModel::Row row = *iter;          Gtk::TreeModel::Row row = *iter;
754          row[m_Columns.m_col_name] = instrument->pInfo->Name.c_str();          row[m_Columns.m_col_name] = instrument->pInfo->Name.c_str();
755          row[m_Columns.m_col_instr] = instrument;          row[m_Columns.m_col_instr] = instrument;
756          // create a menu item for this instrument          // create a menu item for this instrument
757          Gtk::RadioMenuItem* item= new Gtk::RadioMenuItem(instrument_group, instrument->pInfo->Name.c_str());          Gtk::RadioMenuItem* item =
758                new Gtk::RadioMenuItem(instrument_group, instrument->pInfo->Name.c_str());
759          instrument_menu->get_submenu()->append(*item);          instrument_menu->get_submenu()->append(*item);
760          item->signal_activate().connect(          item->signal_activate().connect(
761              sigc::bind(              sigc::bind(
# Line 1557  void MainWindow::load_gig(gig::File* gig Line 769  void MainWindow::load_gig(gig::File* gig
769      instrument_menu->get_submenu()->show_all_children();      instrument_menu->get_submenu()->show_all_children();
770    
771      for (gig::Group* group = gig->GetFirstGroup(); group; group = gig->GetNextGroup()) {      for (gig::Group* group = gig->GetFirstGroup(); group; group = gig->GetNextGroup()) {
772          Gtk::TreeModel::iterator iterGroup = m_refSamplesTreeModel->append();          if (group->Name != "") {
773          Gtk::TreeModel::Row rowGroup = *iterGroup;              Gtk::TreeModel::iterator iterGroup = m_refSamplesTreeModel->append();
774          rowGroup[m_SamplesModel.m_col_name]   = group->Name.c_str();              Gtk::TreeModel::Row rowGroup = *iterGroup;
775          rowGroup[m_SamplesModel.m_col_group]  = group;              rowGroup[m_SamplesModel.m_col_name]   = group->Name.c_str();
776          rowGroup[m_SamplesModel.m_col_sample] = NULL;              rowGroup[m_SamplesModel.m_col_group]  = group;
777          for (gig::Sample* sample = group->GetFirstSample(); sample; sample = group->GetNextSample()) {              rowGroup[m_SamplesModel.m_col_sample] = NULL;
778              Gtk::TreeModel::iterator iterSample = m_refSamplesTreeModel->append(rowGroup.children());              for (gig::Sample* sample = group->GetFirstSample();
779              Gtk::TreeModel::Row rowSample = *iterSample;                   sample; sample = group->GetNextSample()) {
780              rowSample[m_SamplesModel.m_col_name]   = sample->pInfo->Name.c_str();                  Gtk::TreeModel::iterator iterSample =
781              rowSample[m_SamplesModel.m_col_sample] = sample;                      m_refSamplesTreeModel->append(rowGroup.children());
782              rowSample[m_SamplesModel.m_col_group]  = NULL;                  Gtk::TreeModel::Row rowSample = *iterSample;
783                    rowSample[m_SamplesModel.m_col_name]   = sample->pInfo->Name.c_str();
784                    rowSample[m_SamplesModel.m_col_sample] = sample;
785                    rowSample[m_SamplesModel.m_col_group]  = NULL;
786                }
787          }          }
788      }      }
789    
790        // select the first instrument
791        Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();
792        tree_sel_ref->select(Gtk::TreePath("0"));
793  }  }
794    
795  void MainWindow::on_button_release(GdkEventButton* button)  void MainWindow::show_instr_props()
796  {  {
797      if (button->type == GDK_2BUTTON_PRESS) {      Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();
798          Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();      Gtk::TreeModel::iterator it = tree_sel_ref->get_selected();
799          Gtk::TreeModel::iterator it = tree_sel_ref->get_selected();      if (it)
800          if (it)      {
801            Gtk::TreeModel::Row row = *it;
802            if (row[m_Columns.m_col_instr])
803          {          {
804              Gtk::TreeModel::Row row = *it;              instrumentProps.set_instrument(row[m_Columns.m_col_instr]);
805              if (row[m_Columns.m_col_instr])              instrumentProps.show();
806              {              instrumentProps.deiconify();
                 instrumentProps.set_instrument(row[m_Columns.m_col_instr]);  
                 instrumentProps.show();  
                 instrumentProps.deiconify();  
             }  
807          }          }
808        }
809    }
810    
811    void MainWindow::on_button_release(GdkEventButton* button)
812    {
813        if (button->type == GDK_2BUTTON_PRESS) {
814            show_instr_props();
815      } else if (button->type == GDK_BUTTON_PRESS && button->button == 3) {      } else if (button->type == GDK_BUTTON_PRESS && button->button == 3) {
816          popup_menu->popup(button->button, button->time);          popup_menu->popup(button->button, button->time);
817      }      }
# Line 1610  void MainWindow::on_sample_treeview_butt Line 835  void MainWindow::on_sample_treeview_butt
835              group_selected  = row[m_SamplesModel.m_col_group];              group_selected  = row[m_SamplesModel.m_col_group];
836              sample_selected = row[m_SamplesModel.m_col_sample];              sample_selected = row[m_SamplesModel.m_col_sample];
837          }          }
838          dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/SamplePopupMenu/SampleProperties"))->set_sensitive(group_selected || sample_selected);          dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/SamplePopupMenu/SampleProperties"))->
839          dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/SamplePopupMenu/AddSample"))->set_sensitive(group_selected || sample_selected);              set_sensitive(group_selected || sample_selected);
840          dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/SamplePopupMenu/AddGroup"))->set_sensitive(file);          dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/SamplePopupMenu/AddSample"))->
841          dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/SamplePopupMenu/RemoveSample"))->set_sensitive(group_selected || sample_selected);              set_sensitive(group_selected || sample_selected);
842            dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/SamplePopupMenu/AddGroup"))->
843                set_sensitive(file);
844            dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/SamplePopupMenu/RemoveSample"))->
845                set_sensitive(group_selected || sample_selected);
846          // show sample popup          // show sample popup
847          sample_popup->popup(button->button, button->time);          sample_popup->popup(button->button, button->time);
848      }      }
849  }  }
850    
851    void MainWindow::on_action_add_instrument() {
852        static int __instrument_indexer = 0;
853        if (!file) return;
854        gig::Instrument* instrument = file->AddInstrument();
855        __instrument_indexer++;
856        instrument->pInfo->Name =
857            "Unnamed Instrument " + ToString(__instrument_indexer);
858        // update instrument tree view
859        Gtk::TreeModel::iterator iterInstr = m_refTreeModel->append();
860        Gtk::TreeModel::Row rowInstr = *iterInstr;
861        rowInstr[m_Columns.m_col_name] = instrument->pInfo->Name.c_str();
862        rowInstr[m_Columns.m_col_instr] = instrument;
863    }
864    
865    void MainWindow::on_action_remove_instrument() {
866        if (!file) return;
867        Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeView.get_selection();
868        Gtk::TreeModel::iterator it = sel->get_selected();
869        if (it) {
870            Gtk::TreeModel::Row row = *it;
871            gig::Instrument* instr = row[m_Columns.m_col_instr];
872            try {
873                // remove instrument from the gig file
874                if (instr) file->DeleteInstrument(instr);
875                // remove respective row from instruments tree view
876                m_refTreeModel->erase(it);
877            } catch (RIFF::Exception e) {
878                Gtk::MessageDialog msg(*this, e.Message.c_str(), false, Gtk::MESSAGE_ERROR);
879                msg.run();
880            }
881        }
882    }
883    
884  void MainWindow::on_action_sample_properties() {  void MainWindow::on_action_sample_properties() {
885       //TODO: show a dialog where the selected sample's properties can be edited      //TODO: show a dialog where the selected sample's properties can be edited
886        Gtk::MessageDialog msg(
887            *this, "Sorry, yet to be implemented!", false, Gtk::MESSAGE_INFO
888        );
889        msg.run();
890  }  }
891    
892  void MainWindow::on_action_add_group() {  void MainWindow::on_action_add_group() {
# Line 1639  void MainWindow::on_action_add_group() { Line 905  void MainWindow::on_action_add_group() {
905  }  }
906    
907  void MainWindow::on_action_add_sample() {  void MainWindow::on_action_add_sample() {
908      //TODO: open browse for file dialog for adding new samples      if (!file) return;
909        // get selected group
910        Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();
911        Gtk::TreeModel::iterator it = sel->get_selected();
912        if (!it) return;
913        Gtk::TreeModel::Row row = *it;
914        gig::Group* group = row[m_SamplesModel.m_col_group];
915        if (!group) { // not a group, but a sample is selected (probably)
916            gig::Sample* sample = row[m_SamplesModel.m_col_sample];
917            if (!sample) return;
918            it = row.parent(); // resolve parent (that is the sample's group)
919            if (!it) return;
920            row = *it;
921            group = row[m_SamplesModel.m_col_group];
922            if (!group) return;
923        }
924        // show 'browse for file' dialog
925        Gtk::FileChooserDialog dialog(*this, _("Add Sample(s)"));
926        dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
927        dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);
928        dialog.set_select_multiple(true);
929        Gtk::FileFilter soundfilter; // matches all file types supported by libsndfile
930        const char* supportedFileTypes[] = {
931            "*.wav", "*.WAV", "*.aiff", "*.AIFF", "*.aifc", "*.AIFC", "*.snd",
932            "*.SND", "*.au", "*.AU", "*.paf", "*.PAF", "*.iff", "*.IFF",
933            "*.svx", "*.SVX", "*.sf", "*.SF", "*.voc", "*.VOC", "*.w64",
934            "*.W64", "*.pvf", "*.PVF", "*.xi", "*.XI", "*.htk", "*.HTK",
935            "*.caf", "*.CAF", NULL
936        };
937        for (int i = 0; supportedFileTypes[i]; i++)
938            soundfilter.add_pattern(supportedFileTypes[i]);
939        soundfilter.set_name("Sound Files");
940        Gtk::FileFilter allpassfilter; // matches every file
941        allpassfilter.add_pattern("*.*");
942        allpassfilter.set_name("All Files");
943        dialog.add_filter(soundfilter);
944        dialog.add_filter(allpassfilter);
945        if (dialog.run() == Gtk::RESPONSE_OK) {
946            Glib::ustring error_files;
947            Glib::SListHandle<Glib::ustring> filenames = dialog.get_filenames();
948            for (Glib::SListHandle<Glib::ustring>::iterator iter = filenames.begin();
949                 iter != filenames.end(); ++iter) {
950                printf("Adding sample %s\n",(*iter).c_str());
951                // use libsndfile to retrieve file informations
952                SF_INFO info;
953                info.format = 0;
954                SNDFILE* hFile = sf_open((*iter).c_str(), SFM_READ, &info);
955                try {
956                    if (!hFile) throw std::string("could not open file");
957                    int bitdepth;
958                    switch (info.format & 0xff) {
959                        case SF_FORMAT_PCM_S8:
960                            bitdepth = 16; // we simply convert to 16 bit for now
961                            break;
962                        case SF_FORMAT_PCM_16:
963                            bitdepth = 16;
964                            break;
965                        case SF_FORMAT_PCM_24:
966                            bitdepth = 32; // we simply convert to 32 bit for now
967                            break;
968                        case SF_FORMAT_PCM_32:
969                            bitdepth = 32;
970                            break;
971                        case SF_FORMAT_PCM_U8:
972                            bitdepth = 16; // we simply convert to 16 bit for now
973                            break;
974                        case SF_FORMAT_FLOAT:
975                            bitdepth = 32;
976                            break;
977                        case SF_FORMAT_DOUBLE:
978                            bitdepth = 32; // I guess we will always truncate this to 32 bit
979                            break;
980                        default:
981                            sf_close(hFile); // close sound file
982                            throw std::string("format not supported"); // unsupported subformat (yet?)
983                    }
984                    // add a new sample to the .gig file
985                    gig::Sample* sample = file->AddSample();
986                    // file name without path
987                    sample->pInfo->Name = (*iter).substr((*iter).rfind('/') + 1).raw();
988                    sample->Channels = info.channels;
989                    sample->BitDepth = bitdepth;
990                    sample->FrameSize = bitdepth / 8/*1 byte are 8 bits*/ * info.channels;
991                    sample->SamplesPerSecond = info.samplerate;
992                    // schedule resizing the sample (which will be done
993                    // physically when File::Save() is called)
994                    sample->Resize(info.frames);
995                    // make sure sample is part of the selected group
996                    group->AddSample(sample);
997                    // schedule that physical resize and sample import
998                    // (data copying), performed when "Save" is requested
999                    SampleImportItem sched_item;
1000                    sched_item.gig_sample  = sample;
1001                    sched_item.sample_path = *iter;
1002                    m_SampleImportQueue.push_back(sched_item);
1003                    // add sample to the tree view
1004                    Gtk::TreeModel::iterator iterSample =
1005                        m_refSamplesTreeModel->append(row.children());
1006                    Gtk::TreeModel::Row rowSample = *iterSample;
1007                    rowSample[m_SamplesModel.m_col_name]   = sample->pInfo->Name.c_str();
1008                    rowSample[m_SamplesModel.m_col_sample] = sample;
1009                    rowSample[m_SamplesModel.m_col_group]  = NULL;
1010                    // close sound file
1011                    sf_close(hFile);
1012                } catch (std::string what) { // remember the files that made trouble (and their cause)
1013                    if (error_files.size()) error_files += "\n";
1014                    error_files += *iter += " (" + what + ")";
1015                }
1016            }
1017            // show error message box when some file(s) could not be opened / added
1018            if (error_files.size()) {
1019                Glib::ustring txt = "Could not add the following sample(s):\n" + error_files;
1020                Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
1021                msg.run();
1022            }
1023        }
1024  }  }
1025    
1026  void MainWindow::on_action_remove_sample() {  void MainWindow::on_action_remove_sample() {
1027      //TODO: remove the selected group or sample      if (!file) return;
1028        Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();
1029        Gtk::TreeModel::iterator it = sel->get_selected();
1030        if (it) {
1031            Gtk::TreeModel::Row row = *it;
1032            gig::Group* group   = row[m_SamplesModel.m_col_group];
1033            gig::Sample* sample = row[m_SamplesModel.m_col_sample];
1034            Glib::ustring name  = row[m_SamplesModel.m_col_name];
1035            try {
1036                // remove group or sample from the gig file
1037                if (group) {
1038                    // temporarily remember the samples that bolong to
1039                    // that group (we need that to clean the queue)
1040                    std::list<gig::Sample*> members;
1041                    for (gig::Sample* pSample = group->GetFirstSample();
1042                         pSample; pSample = group->GetNextSample()) {
1043                        members.push_back(pSample);
1044                    }
1045                    // delete the group in the .gig file including the
1046                    // samples that belong to the group
1047                    file->DeleteGroup(group);
1048                    // if sample(s) were just previously added, remove
1049                    // them from the import queue
1050                    for (std::list<gig::Sample*>::iterator member = members.begin();
1051                         member != members.end(); ++member) {
1052                        for (std::list<SampleImportItem>::iterator iter = m_SampleImportQueue.begin();
1053                             iter != m_SampleImportQueue.end(); ++iter) {
1054                            if ((*iter).gig_sample == *member) {
1055                                printf("Removing previously added sample '%s' from group '%s'\n",
1056                                       (*iter).sample_path.c_str(), name.c_str());
1057                                m_SampleImportQueue.erase(iter);
1058                                break;
1059                            }
1060                        }
1061                    }
1062                } else if (sample) {
1063                    // remove sample from the .gig file
1064                    file->DeleteSample(sample);
1065                    // if sample was just previously added, remove it from
1066                    // the import queue
1067                    for (std::list<SampleImportItem>::iterator iter = m_SampleImportQueue.begin();
1068                         iter != m_SampleImportQueue.end(); ++iter) {
1069                        if ((*iter).gig_sample == sample) {
1070                            printf("Removing previously added sample '%s'\n",
1071                                   (*iter).sample_path.c_str());
1072                            m_SampleImportQueue.erase(iter);
1073                            break;
1074                        }
1075                    }
1076                }
1077                // remove respective row(s) from samples tree view
1078                m_refSamplesTreeModel->erase(it);
1079            } catch (RIFF::Exception e) {
1080                Gtk::MessageDialog msg(*this, e.Message.c_str(), false, Gtk::MESSAGE_ERROR);
1081                msg.run();
1082            }
1083        }
1084    }
1085    
1086    void MainWindow::on_sample_treeview_drag_data_get(const Glib::RefPtr<Gdk::DragContext>&,
1087                                                      Gtk::SelectionData& selection_data, guint, guint)
1088    {
1089        // get selected sample
1090        gig::Sample* sample = NULL;
1091        Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();
1092        Gtk::TreeModel::iterator it = sel->get_selected();
1093        if (it) {
1094            Gtk::TreeModel::Row row = *it;
1095            sample = row[m_SamplesModel.m_col_sample];
1096        }
1097        // pass the gig::Sample as pointer
1098        selection_data.set(selection_data.get_target(), 0/*unused*/, (const guchar*)&sample,
1099                           sizeof(sample)/*length of data in bytes*/);
1100    }
1101    
1102    void MainWindow::on_sample_label_drop_drag_data_received(
1103        const Glib::RefPtr<Gdk::DragContext>& context, int, int,
1104        const Gtk::SelectionData& selection_data, guint, guint time)
1105    {
1106        gig::DimensionRegion* dimregion = m_DimRegionChooser.get_dimregion();
1107        gig::Sample* sample = *((gig::Sample**) selection_data.get_data());
1108    
1109        if (sample && dimregion && selection_data.get_length() == sizeof(gig::Sample*)) {
1110            if (sample != dimregion->pSample) {
1111                dimregion->pSample = sample;
1112                dimreg_edit.wSample->set_text(dimregion->pSample->pInfo->Name.c_str());
1113                std::cout << "Drop received sample \"" <<
1114                    dimregion->pSample->pInfo->Name.c_str() << "\"" << std::endl;
1115                // drop success
1116                context->drop_reply(true, time);
1117                return;
1118            }
1119        }
1120        // drop failed
1121        context->drop_reply(false, time);
1122    }
1123    
1124    void MainWindow::sample_name_changed(const Gtk::TreeModel::Path& path,
1125                                         const Gtk::TreeModel::iterator& iter) {
1126        if (!iter) return;
1127        Gtk::TreeModel::Row row = *iter;
1128        Glib::ustring name  = row[m_SamplesModel.m_col_name];
1129        gig::Group* group   = row[m_SamplesModel.m_col_group];
1130        gig::Sample* sample = row[m_SamplesModel.m_col_sample];
1131        if (group) {
1132            group->Name = name;
1133            std::cout << "Group name changed\n" << std::flush;
1134        } else if (sample) {
1135            sample->pInfo->Name = name.raw();
1136            std::cout << "Sample name changed\n" << std::flush;
1137        }
1138    }
1139    
1140    void MainWindow::instrument_name_changed(const Gtk::TreeModel::Path& path,
1141                                             const Gtk::TreeModel::iterator& iter) {
1142        std::cout << "Instrument name changed\n" << std::flush;
1143        if (!iter) return;
1144        Gtk::TreeModel::Row row = *iter;
1145        Glib::ustring name = row[m_Columns.m_col_name];
1146        gig::Instrument* instrument = row[m_Columns.m_col_instr];
1147        if (instrument) instrument->pInfo->Name = name.raw();
1148  }  }

Legend:
Removed from v.1082  
changed lines
  Added in v.1117

  ViewVC Help
Powered by ViewVC