/[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 1069 by schoenebeck, Sun Mar 4 22:00:46 2007 UTC revision 1104 by persson, Sun Mar 18 17:15:00 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  #define _(String) gettext(String)  #include <stdio.h>
34    #include <sndfile.h>
 bool update_gui;  
35    
36  uint8_t& access_UnityNote(gig::DimensionRegion* dimreg)  #include "mainwindow.h"
 {  
     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;  
 }  
37    
38  void MainWindow::addHeader(char* text)  #define _(String) gettext(String)
 {  
     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;  
 }  
39    
40  void MainWindow::nextPage()  template<class T> inline std::string ToString(T o) {
41  {      std::stringstream ss;
42      if (firstRowInBlock < rowno - 1)      ss << o;
43      {      return ss.str();
         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++;  
44  }  }
45    
46    MainWindow::MainWindow()
   
   
 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 518  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, inside a ScrolledWindow, with the button underneath:      // Add the TreeView tab, inside a ScrolledWindow, with the button underneath:
65      m_ScrolledWindow.add(m_TreeView);      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);
74      pageno = 0;  
75      rowno = 0;      m_HPaned.add1(m_TreeViewNotebook);
76      firstRowInBlock = 0;      m_HPaned.add2(dimreg_edit);
77    
     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);  
78    
79      m_HPaned.add1(m_ScrolledWindow);      m_TreeViewNotebook.append_page(m_ScrolledWindowSamples, "Samples");
80      m_HPaned.add2(m_Notebook);      m_TreeViewNotebook.append_page(m_ScrolledWindow, "Instruments");
81    
82    
83      actionGroup = Gtk::ActionGroup::create();      actionGroup = Gtk::ActionGroup::create();
# Line 812  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 826  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", "Ta bort");      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
136        actionGroup->add(
137            Gtk::Action::create("SampleProperties", Gtk::Stock::PROPERTIES),
138            sigc::mem_fun(*this, &MainWindow::on_action_sample_properties)
139        );
140        actionGroup->add(
141            Gtk::Action::create("AddGroup", _("Add _Group")),
142            sigc::mem_fun(*this, &MainWindow::on_action_add_group)
143        );
144        actionGroup->add(
145            Gtk::Action::create("AddSample", _("Add _Sample(s)")),
146            sigc::mem_fun(*this, &MainWindow::on_action_add_sample)
147        );
148        actionGroup->add(
149            Gtk::Action::create("RemoveSample", Gtk::Stock::REMOVE),
150            sigc::mem_fun(*this, &MainWindow::on_action_remove_sample)
151        );
152    
153      uiManager = Gtk::UIManager::create();      uiManager = Gtk::UIManager::create();
154      uiManager->insert_action_group(actionGroup);      uiManager->insert_action_group(actionGroup);
# Line 859  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>"
185            "  <popup name='SamplePopupMenu'>"
186            "    <menuitem action='SampleProperties'/>"
187            "    <menuitem action='AddGroup'/>"
188            "    <menuitem action='AddSample'/>"
189            "    <separator/>"
190            "    <menuitem action='RemoveSample'/>"
191          "  </popup>"          "  </popup>"
192          "</ui>";          "</ui>";
193      uiManager->add_ui_from_string(ui_info);      uiManager->add_ui_from_string(ui_info);
# Line 873  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)
221        m_refSamplesTreeModel = SamplesTreeStore::create(m_SamplesModel);
222        m_TreeViewSamples.set_model(m_refSamplesTreeModel);
223        // m_TreeViewSamples.set_reorderable();
224        m_TreeViewSamples.append_column_editable("Samples", m_SamplesModel.m_col_name);
225        m_TreeViewSamples.set_headers_visible(false);
226        m_TreeViewSamples.signal_button_press_event().connect_notify(
227            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    
247      show_all_children();      show_all_children();
# Line 902  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 910  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 1224  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 1244  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();  
         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 1282  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 1304  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 1427  InstrumentProps::InstrumentProps() Line 661  InstrumentProps::InstrumentProps()
661      quitButton.grab_focus();      quitButton.grab_focus();
662    
663      quitButton.signal_clicked().connect(      quitButton.signal_clicked().connect(
664          sigc::mem_fun(*this, &InstrumentProps::hide));          sigc::mem_fun(*this, &InstrumentProps::hide));
665    
666      // quitButton.grab_default();      // quitButton.grab_default();
667      quitButton.show();      quitButton.show();
# Line 1436  InstrumentProps::InstrumentProps() Line 670  InstrumentProps::InstrumentProps()
670      show_all_children();      show_all_children();
671  }  }
672    
673    extern char* notes[];
674    
675  void InstrumentProps::set_instrument(gig::Instrument* instrument)  void InstrumentProps::set_instrument(gig::Instrument* instrument)
676  {  {
# Line 1467  void InstrumentProps::set_instrument(gig Line 702  void InstrumentProps::set_instrument(gig
702      entry[entryIdx].set_text(buf);      entry[entryIdx].set_text(buf);
703  }  }
704    
 void MainWindow::getInfo(const char *filename)  
 {  
     RIFF::File* riff = new RIFF::File(filename);  
     gig::File* gig = new gig::File(riff);  
   
     load_gig(gig, filename);  
 }  
   
705  void MainWindow::load_gig(gig::File* gig, const char* filename)  void MainWindow::load_gig(gig::File* gig, const char* filename)
706  {  {
707      file = gig;      file = gig;
708    
709      const char *basename = strrchr(filename, '/');      if (filename) {
710      basename = basename ? basename + 1 : filename;          const char *basename = strrchr(filename, '/');
711            basename = basename ? basename + 1 : filename;
712      set_title(basename);          set_title(basename);
713        } else {
714            set_title("unnamed");
715        }
716    
717      propDialog.set_info(gig->pInfo);      propDialog.set_info(gig->pInfo);
718    
# Line 1490  void MainWindow::load_gig(gig::File* gig Line 720  void MainWindow::load_gig(gig::File* gig
720          dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/MenuBar/MenuInstrument"));          dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/MenuBar/MenuInstrument"));
721    
722      int instrument_index = 0;      int instrument_index = 0;
723        Gtk::RadioMenuItem::Group instrument_group;
724      for (gig::Instrument* instrument = gig->GetFirstInstrument() ; instrument ;      for (gig::Instrument* instrument = gig->GetFirstInstrument() ; instrument ;
725           instrument = gig->GetNextInstrument()) {           instrument = gig->GetNextInstrument()) {
726          Gtk::TreeModel::iterator iter = m_refTreeModel->append();          Gtk::TreeModel::iterator iter = m_refTreeModel->append();
727          Gtk::TreeModel::Row row = *iter;          Gtk::TreeModel::Row row = *iter;
728          row[m_Columns.m_col_name] = instrument->pInfo->Name.c_str();          row[m_Columns.m_col_name] = instrument->pInfo->Name.c_str();
729          row[m_Columns.m_col_instr] = instrument;          row[m_Columns.m_col_instr] = instrument;
730          // create a menu item for this instrument          // create a menu item for this instrument
731          Gtk::MenuItem* item= new Gtk::MenuItem(instrument->pInfo->Name.c_str());          Gtk::RadioMenuItem* item =
732                new Gtk::RadioMenuItem(instrument_group, instrument->pInfo->Name.c_str());
733          instrument_menu->get_submenu()->append(*item);          instrument_menu->get_submenu()->append(*item);
734          item->signal_activate().connect(          item->signal_activate().connect(
735              sigc::bind(              sigc::bind(
# Line 1509  void MainWindow::load_gig(gig::File* gig Line 741  void MainWindow::load_gig(gig::File* gig
741      }      }
742      instrument_menu->show();      instrument_menu->show();
743      instrument_menu->get_submenu()->show_all_children();      instrument_menu->get_submenu()->show_all_children();
744    
745        for (gig::Group* group = gig->GetFirstGroup(); group; group = gig->GetNextGroup()) {
746            if (group->Name != "") {
747                Gtk::TreeModel::iterator iterGroup = m_refSamplesTreeModel->append();
748                Gtk::TreeModel::Row rowGroup = *iterGroup;
749                rowGroup[m_SamplesModel.m_col_name]   = group->Name.c_str();
750                rowGroup[m_SamplesModel.m_col_group]  = group;
751                rowGroup[m_SamplesModel.m_col_sample] = NULL;
752                for (gig::Sample* sample = group->GetFirstSample();
753                     sample; sample = group->GetNextSample()) {
754                    Gtk::TreeModel::iterator iterSample =
755                        m_refSamplesTreeModel->append(rowGroup.children());
756                    Gtk::TreeModel::Row rowSample = *iterSample;
757                    rowSample[m_SamplesModel.m_col_name]   = sample->pInfo->Name.c_str();
758                    rowSample[m_SamplesModel.m_col_sample] = sample;
759                    rowSample[m_SamplesModel.m_col_group]  = NULL;
760                }
761            }
762        }
763    
764        // select the first instrument
765        Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();
766        tree_sel_ref->select(Gtk::TreePath("0"));
767  }  }
768    
769  void MainWindow::on_button_release(GdkEventButton* button)  void MainWindow::show_instr_props()
770  {  {
771      if (button->type == GDK_2BUTTON_PRESS) {      Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();
772          Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();      Gtk::TreeModel::iterator it = tree_sel_ref->get_selected();
773          Gtk::TreeModel::iterator it = tree_sel_ref->get_selected();      if (it)
774          if (it)      {
775            Gtk::TreeModel::Row row = *it;
776            if (row[m_Columns.m_col_instr])
777          {          {
778              Gtk::TreeModel::Row row = *it;              instrumentProps.set_instrument(row[m_Columns.m_col_instr]);
779              if (row[m_Columns.m_col_instr])              instrumentProps.show();
780              {              instrumentProps.deiconify();
                 instrumentProps.set_instrument(row[m_Columns.m_col_instr]);  
                 instrumentProps.show();  
                 instrumentProps.deiconify();  
             }  
781          }          }
782        }
783    }
784    
785    void MainWindow::on_button_release(GdkEventButton* button)
786    {
787        if (button->type == GDK_2BUTTON_PRESS) {
788            show_instr_props();
789      } else if (button->type == GDK_BUTTON_PRESS && button->button == 3) {      } else if (button->type == GDK_BUTTON_PRESS && button->button == 3) {
790          popup_menu->popup(button->button, button->time);          popup_menu->popup(button->button, button->time);
791      }      }
# Line 1534  void MainWindow::on_button_release(GdkEv Line 794  void MainWindow::on_button_release(GdkEv
794  void MainWindow::on_instrument_selection_change(int index) {  void MainWindow::on_instrument_selection_change(int index) {
795      m_RegionChooser.set_instrument(file->GetInstrument(index));      m_RegionChooser.set_instrument(file->GetInstrument(index));
796  }  }
797    
798    void MainWindow::on_sample_treeview_button_release(GdkEventButton* button) {
799        if (button->type == GDK_BUTTON_PRESS && button->button == 3) {
800            Gtk::Menu* sample_popup =
801                dynamic_cast<Gtk::Menu*>(uiManager->get_widget("/SamplePopupMenu"));
802            // update enabled/disabled state of sample popup items
803            Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();
804            Gtk::TreeModel::iterator it = sel->get_selected();
805            bool group_selected  = false;
806            bool sample_selected = false;
807            if (it) {
808                Gtk::TreeModel::Row row = *it;
809                group_selected  = row[m_SamplesModel.m_col_group];
810                sample_selected = row[m_SamplesModel.m_col_sample];
811            }
812            dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/SamplePopupMenu/SampleProperties"))->
813                set_sensitive(group_selected || sample_selected);
814            dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/SamplePopupMenu/AddSample"))->
815                set_sensitive(group_selected || sample_selected);
816            dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/SamplePopupMenu/AddGroup"))->
817                set_sensitive(file);
818            dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/SamplePopupMenu/RemoveSample"))->
819                set_sensitive(group_selected || sample_selected);
820            // show sample popup
821            sample_popup->popup(button->button, button->time);
822        }
823    }
824    
825    void MainWindow::on_action_add_instrument() {
826        static int __instrument_indexer = 0;
827        if (!file) return;
828        gig::Instrument* instrument = file->AddInstrument();
829        __instrument_indexer++;
830        instrument->pInfo->Name =
831            "Unnamed Instrument " + ToString(__instrument_indexer);
832        // update instrument tree view
833        Gtk::TreeModel::iterator iterInstr = m_refTreeModel->append();
834        Gtk::TreeModel::Row rowInstr = *iterInstr;
835        rowInstr[m_Columns.m_col_name] = instrument->pInfo->Name.c_str();
836        rowInstr[m_Columns.m_col_instr] = instrument;
837    }
838    
839    void MainWindow::on_action_remove_instrument() {
840        if (!file) return;
841        Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeView.get_selection();
842        Gtk::TreeModel::iterator it = sel->get_selected();
843        if (it) {
844            Gtk::TreeModel::Row row = *it;
845            gig::Instrument* instr = row[m_Columns.m_col_instr];
846            try {
847                // remove instrument from the gig file
848                if (instr) file->DeleteInstrument(instr);
849                // remove respective row from instruments tree view
850                m_refTreeModel->erase(it);
851            } catch (RIFF::Exception e) {
852                Gtk::MessageDialog msg(*this, e.Message.c_str(), false, Gtk::MESSAGE_ERROR);
853                msg.run();
854            }
855        }
856    }
857    
858    void MainWindow::on_action_sample_properties() {
859        //TODO: show a dialog where the selected sample's properties can be edited
860        Gtk::MessageDialog msg(
861            *this, "Sorry, yet to be implemented!", false, Gtk::MESSAGE_INFO
862        );
863        msg.run();
864    }
865    
866    void MainWindow::on_action_add_group() {
867        static int __sample_indexer = 0;
868        if (!file) return;
869        gig::Group* group = file->AddGroup();
870        group->Name = "Unnamed Group";
871        if (__sample_indexer) group->Name += " " + ToString(__sample_indexer);
872        __sample_indexer++;
873        // update sample tree view
874        Gtk::TreeModel::iterator iterGroup = m_refSamplesTreeModel->append();
875        Gtk::TreeModel::Row rowGroup = *iterGroup;
876        rowGroup[m_SamplesModel.m_col_name] = group->Name.c_str();
877        rowGroup[m_SamplesModel.m_col_sample] = NULL;
878        rowGroup[m_SamplesModel.m_col_group] = group;
879    }
880    
881    void MainWindow::on_action_add_sample() {
882        if (!file) return;
883        // get selected group
884        Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();
885        Gtk::TreeModel::iterator it = sel->get_selected();
886        if (!it) return;
887        Gtk::TreeModel::Row row = *it;
888        gig::Group* group = row[m_SamplesModel.m_col_group];
889        if (!group) { // not a group, but a sample is selected (probably)
890            gig::Sample* sample = row[m_SamplesModel.m_col_sample];
891            if (!sample) return;
892            it = row.parent(); // resolve parent (that is the sample's group)
893            if (!it) return;
894            row = *it;
895            group = row[m_SamplesModel.m_col_group];
896            if (!group) return;
897        }
898        // show 'browse for file' dialog
899        Gtk::FileChooserDialog dialog(*this, _("Add Sample(s)"));
900        dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
901        dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);
902        dialog.set_select_multiple(true);
903        Gtk::FileFilter soundfilter; // matches all file types supported by libsndfile
904        const char* supportedFileTypes[] = {
905            "*.wav", "*.WAV", "*.aiff", "*.AIFF", "*.aifc", "*.AIFC", "*.snd",
906            "*.SND", "*.au", "*.AU", "*.paf", "*.PAF", "*.iff", "*.IFF",
907            "*.svx", "*.SVX", "*.sf", "*.SF", "*.voc", "*.VOC", "*.w64",
908            "*.W64", "*.pvf", "*.PVF", "*.xi", "*.XI", "*.htk", "*.HTK",
909            "*.caf", "*.CAF", NULL
910        };
911        for (int i = 0; supportedFileTypes[i]; i++)
912            soundfilter.add_pattern(supportedFileTypes[i]);
913        soundfilter.set_name("Sound Files");
914        Gtk::FileFilter allpassfilter; // matches every file
915        allpassfilter.add_pattern("*.*");
916        allpassfilter.set_name("All Files");
917        dialog.add_filter(soundfilter);
918        dialog.add_filter(allpassfilter);
919        if (dialog.run() == Gtk::RESPONSE_OK) {
920            Glib::ustring error_files;
921            Glib::SListHandle<Glib::ustring> filenames = dialog.get_filenames();
922            for (Glib::SListHandle<Glib::ustring>::iterator iter = filenames.begin();
923                 iter != filenames.end(); ++iter) {
924                printf("Adding sample %s\n",(*iter).c_str());
925                // use libsndfile to retrieve file informations
926                SF_INFO info;
927                info.format = 0;
928                SNDFILE* hFile = sf_open((*iter).c_str(), SFM_READ, &info);
929                try {
930                    if (!hFile) throw std::string("could not open file");
931                    int bitdepth;
932                    switch (info.format & 0xff) {
933                        case SF_FORMAT_PCM_S8:
934                            bitdepth = 16; // we simply convert to 16 bit for now
935                            break;
936                        case SF_FORMAT_PCM_16:
937                            bitdepth = 16;
938                            break;
939                        case SF_FORMAT_PCM_24:
940                            bitdepth = 32; // we simply convert to 32 bit for now
941                            break;
942                        case SF_FORMAT_PCM_32:
943                            bitdepth = 32;
944                            break;
945                        case SF_FORMAT_PCM_U8:
946                            bitdepth = 16; // we simply convert to 16 bit for now
947                            break;
948                        case SF_FORMAT_FLOAT:
949                            bitdepth = 32;
950                            break;
951                        case SF_FORMAT_DOUBLE:
952                            bitdepth = 32; // I guess we will always truncate this to 32 bit
953                            break;
954                        default:
955                            sf_close(hFile); // close sound file
956                            throw std::string("format not supported"); // unsupported subformat (yet?)
957                    }
958                    // add a new sample to the .gig file
959                    gig::Sample* sample = file->AddSample();
960                    // file name without path
961                    sample->pInfo->Name = (*iter).substr((*iter).rfind('/') + 1).raw();
962                    sample->Channels = info.channels;
963                    sample->BitDepth = bitdepth;
964                    sample->FrameSize = bitdepth / 8/*1 byte are 8 bits*/ * info.channels;
965                    sample->SamplesPerSecond = info.samplerate;
966                    // schedule resizing the sample (which will be done
967                    // physically when File::Save() is called)
968                    sample->Resize(info.frames);
969                    // make sure sample is part of the selected group
970                    group->AddSample(sample);
971                    // schedule that physical resize and sample import
972                    // (data copying), performed when "Save" is requested
973                    SampleImportItem sched_item;
974                    sched_item.gig_sample  = sample;
975                    sched_item.sample_path = *iter;
976                    m_SampleImportQueue.push_back(sched_item);
977                    // add sample to the tree view
978                    Gtk::TreeModel::iterator iterSample =
979                        m_refSamplesTreeModel->append(row.children());
980                    Gtk::TreeModel::Row rowSample = *iterSample;
981                    rowSample[m_SamplesModel.m_col_name]   = sample->pInfo->Name.c_str();
982                    rowSample[m_SamplesModel.m_col_sample] = sample;
983                    rowSample[m_SamplesModel.m_col_group]  = NULL;
984                    // close sound file
985                    sf_close(hFile);
986                } catch (std::string what) { // remember the files that made trouble (and their cause)
987                    if (error_files.size()) error_files += "\n";
988                    error_files += *iter += " (" + what + ")";
989                }
990            }
991            // show error message box when some file(s) could not be opened / added
992            if (error_files.size()) {
993                Glib::ustring txt = "Could not add the following sample(s):\n" + error_files;
994                Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
995                msg.run();
996            }
997        }
998    }
999    
1000    void MainWindow::on_action_remove_sample() {
1001        if (!file) return;
1002        Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();
1003        Gtk::TreeModel::iterator it = sel->get_selected();
1004        if (it) {
1005            Gtk::TreeModel::Row row = *it;
1006            gig::Group* group   = row[m_SamplesModel.m_col_group];
1007            gig::Sample* sample = row[m_SamplesModel.m_col_sample];
1008            Glib::ustring name  = row[m_SamplesModel.m_col_name];
1009            try {
1010                // remove group or sample from the gig file
1011                if (group) {
1012                    // temporarily remember the samples that bolong to
1013                    // that group (we need that to clean the queue)
1014                    std::list<gig::Sample*> members;
1015                    for (gig::Sample* pSample = group->GetFirstSample();
1016                         pSample; pSample = group->GetNextSample()) {
1017                        members.push_back(pSample);
1018                    }
1019                    // delete the group in the .gig file including the
1020                    // samples that belong to the group
1021                    file->DeleteGroup(group);
1022                    // if sample(s) were just previously added, remove
1023                    // them from the import queue
1024                    for (std::list<gig::Sample*>::iterator member = members.begin();
1025                         member != members.end(); ++member) {
1026                        for (std::list<SampleImportItem>::iterator iter = m_SampleImportQueue.begin();
1027                             iter != m_SampleImportQueue.end(); ++iter) {
1028                            if ((*iter).gig_sample == *member) {
1029                                printf("Removing previously added sample '%s' from group '%s'\n",
1030                                       (*iter).sample_path.c_str(), name.c_str());
1031                                m_SampleImportQueue.erase(iter);
1032                                break;
1033                            }
1034                        }
1035                    }
1036                } else if (sample) {
1037                    // remove sample from the .gig file
1038                    file->DeleteSample(sample);
1039                    // if sample was just previously added, remove it from
1040                    // the import queue
1041                    for (std::list<SampleImportItem>::iterator iter = m_SampleImportQueue.begin();
1042                         iter != m_SampleImportQueue.end(); ++iter) {
1043                        if ((*iter).gig_sample == sample) {
1044                            printf("Removing previously added sample '%s'\n",
1045                                   (*iter).sample_path.c_str());
1046                            m_SampleImportQueue.erase(iter);
1047                            break;
1048                        }
1049                    }
1050                }
1051                // remove respective row(s) from samples tree view
1052                m_refSamplesTreeModel->erase(it);
1053            } catch (RIFF::Exception e) {
1054                Gtk::MessageDialog msg(*this, e.Message.c_str(), false, Gtk::MESSAGE_ERROR);
1055                msg.run();
1056            }
1057        }
1058    }
1059    
1060    void MainWindow::on_sample_treeview_drag_data_get(const Glib::RefPtr<Gdk::DragContext>&,
1061                                                      Gtk::SelectionData& selection_data, guint, guint)
1062    {
1063        // get selected sample
1064        gig::Sample* sample = NULL;
1065        Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();
1066        Gtk::TreeModel::iterator it = sel->get_selected();
1067        if (it) {
1068            Gtk::TreeModel::Row row = *it;
1069            sample = row[m_SamplesModel.m_col_sample];
1070        }
1071        // pass the gig::Sample as pointer
1072        selection_data.set(selection_data.get_target(), 0/*unused*/, (const guchar*)&sample,
1073                           sizeof(sample)/*length of data in bytes*/);
1074    }
1075    
1076    void MainWindow::on_sample_label_drop_drag_data_received(
1077        const Glib::RefPtr<Gdk::DragContext>& context, int, int,
1078        const Gtk::SelectionData& selection_data, guint, guint time)
1079    {
1080        gig::DimensionRegion* dimregion = m_DimRegionChooser.get_dimregion();
1081        gig::Sample* sample = *((gig::Sample**) selection_data.get_data());
1082    
1083        if (sample && dimregion && selection_data.get_length() == sizeof(gig::Sample*)) {
1084            if (sample != dimregion->pSample) {
1085                dimregion->pSample = sample;
1086                dimreg_edit.wSample->set_text(dimregion->pSample->pInfo->Name.c_str());
1087                std::cout << "Drop received sample \"" <<
1088                    dimregion->pSample->pInfo->Name.c_str() << "\"" << std::endl;
1089                // drop success
1090                context->drop_reply(true, time);
1091                return;
1092            }
1093        }
1094        // drop failed
1095        context->drop_reply(false, time);
1096    }
1097    
1098    void MainWindow::sample_name_changed(const Gtk::TreeModel::Path& path,
1099                                         const Gtk::TreeModel::iterator& iter) {
1100        if (!iter) return;
1101        Gtk::TreeModel::Row row = *iter;
1102        Glib::ustring name  = row[m_SamplesModel.m_col_name];
1103        gig::Group* group   = row[m_SamplesModel.m_col_group];
1104        gig::Sample* sample = row[m_SamplesModel.m_col_sample];
1105        if (group) {
1106            group->Name = name;
1107            std::cout << "Group name changed\n" << std::flush;
1108        } else if (sample) {
1109            sample->pInfo->Name = name.raw();
1110            std::cout << "Sample name changed\n" << std::flush;
1111        }
1112    }
1113    
1114    void MainWindow::instrument_name_changed(const Gtk::TreeModel::Path& path,
1115                                             const Gtk::TreeModel::iterator& iter) {
1116        std::cout << "Instrument name changed\n" << std::flush;
1117        if (!iter) return;
1118        Gtk::TreeModel::Row row = *iter;
1119        Glib::ustring name = row[m_Columns.m_col_name];
1120        gig::Instrument* instrument = row[m_Columns.m_col_instr];
1121        if (instrument) instrument->pInfo->Name = name.raw();
1122    }

Legend:
Removed from v.1069  
changed lines
  Added in v.1104

  ViewVC Help
Powered by ViewVC