/[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 1080 by schoenebeck, Tue Mar 6 23:16:18 2007 UTC revision 1138 by persson, Sat Mar 31 09:33:40 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;  
   
 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;  
 }  
35    
36  void MainWindow::addHeader(char* text)  #include "mainwindow.h"
 {  
     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;  
 }  
37    
38  void MainWindow::nextPage()  #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);  
     }  
     pageno++;  
     rowno = 0;  
     firstRowInBlock = 0;  
 }  
39    
40  void MainWindow::addProp(LabelWidget& prop)  template<class T> inline std::string ToString(T o) {
41  {      std::stringstream ss;
42      table[pageno]->attach(prop.label, 1, 2, rowno, rowno + 1,      ss << o;
43                            Gtk::FILL, Gtk::SHRINK);      return ss.str();
     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 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);
         table[i]->set_col_spacings(5);  
     }  
71    
     pageno = 0;  
     rowno = 0;  
     firstRowInBlock = 0;  
72    
73      addString("Sample", lSample, wSample);      m_TreeViewNotebook.set_size_request(300);
     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 816  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 830  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 863  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 877  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(
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    
# Line 912  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 920  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 1234  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 1254  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 1293  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 1315  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 1390  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    void InstrumentProps::add_prop(LabelWidget& prop)
617    {
618        table.attach(prop.label, 0, 1, rowno, rowno + 1,
619                     Gtk::FILL, Gtk::SHRINK);
620        table.attach(prop.widget, 1, 2, rowno, rowno + 1,
621                     Gtk::FILL | Gtk::EXPAND, Gtk::SHRINK);
622        rowno++;
623    }
624    
625  InstrumentProps::InstrumentProps()  InstrumentProps::InstrumentProps()
626      : table(2,1),      : table(2,1),
627        quitButton(Gtk::Stock::CLOSE)        quitButton(Gtk::Stock::CLOSE),
628          eName("Name"),
629          eIsDrum("IsDrum"),
630          eMIDIBank("MIDIBank", 0, 16383),
631          eMIDIProgram("MIDIProgram"),
632          eAttenuation("Attenuation", 0, 96, 0, 1),
633          eGainPlus6("Gain +6dB", eAttenuation, -6),
634          eEffectSend("EffectSend", 0, 65535),
635          eFineTune("FineTune", -8400, 8400),
636          ePitchbendRange("PitchbendRange", 0, 12),
637          ePianoReleaseMode("PianoReleaseMode"),
638          eDimensionKeyRangeLow("DimensionKeyRangeLow"),
639          eDimensionKeyRangeHigh("DimensionKeyRangeHigh")
640  {  {
641        set_title("Instrument properties");
642    
643        rowno = 0;
644      table.set_col_spacings(5);      table.set_col_spacings(5);
     char* propLabels[] = {  
         "Name:",  
         "IsDrum:",  
         "MIDIBank:",  
         "MIDIProgram:",  
         "Attenuation:",  
         "EffectSend:",  
         "FineTune:",  
         "PitchbendRange:",  
         "PianoReleaseMode:",  
         "DimensionKeyRange:",  
     };  
     int entryIdx = 0, checkIdx = 0;  
     for (int i = 0 ; i < sizeof(propLabels) / sizeof(char*) ; i++) {  
         label[i].set_text(propLabels[i]);  
         label[i].set_alignment(Gtk::ALIGN_LEFT);  
         table.attach(label[i], 0, 1, i, i + 1, Gtk::FILL, Gtk::SHRINK);  
         if (i == 1 || i == 8)  
             table.attach(check[checkIdx++], 1, 2, i, i + 1,  
                          Gtk::FILL | Gtk::EXPAND, Gtk::SHRINK);  
         else  
             table.attach(entry[entryIdx++], 1, 2, i, i + 1,  
                          Gtk::FILL | Gtk::EXPAND, Gtk::SHRINK);  
     }  
645    
646      // vbox { table buttonBox { quitButton } }      add_prop(eName);
647        add_prop(eIsDrum);
648        add_prop(eMIDIBank);
649        add_prop(eMIDIProgram);
650        add_prop(eAttenuation);
651        add_prop(eGainPlus6);
652        add_prop(eEffectSend);
653        add_prop(eFineTune);
654        add_prop(ePitchbendRange);
655        add_prop(ePianoReleaseMode);
656        add_prop(eDimensionKeyRangeLow);
657        add_prop(eDimensionKeyRangeHigh);
658    
659        eDimensionKeyRangeLow.signal_value_changed().connect(
660            sigc::mem_fun(*this, &InstrumentProps::key_range_low_changed));
661        eDimensionKeyRangeHigh.signal_value_changed().connect(
662            sigc::mem_fun(*this, &InstrumentProps::key_range_high_changed));
663    
     //get_vbox()->pack_start(table);  
     // set_border_width(6);  
664      add(vbox);      add(vbox);
665      table.set_border_width(2);      table.set_border_width(5);
666      vbox.pack_start(table);      vbox.pack_start(table);
667      table.show();      table.show();
668      vbox.pack_start(buttonBox);      vbox.pack_start(buttonBox, Gtk::PACK_SHRINK);
669      buttonBox.set_layout(Gtk::BUTTONBOX_END);      buttonBox.set_layout(Gtk::BUTTONBOX_END);
670      buttonBox.set_border_width(5);      buttonBox.set_border_width(5);
671      buttonBox.show();      buttonBox.show();
# Line 1438  InstrumentProps::InstrumentProps() Line 674  InstrumentProps::InstrumentProps()
674      quitButton.grab_focus();      quitButton.grab_focus();
675    
676      quitButton.signal_clicked().connect(      quitButton.signal_clicked().connect(
677          sigc::mem_fun(*this, &InstrumentProps::hide));          sigc::mem_fun(*this, &InstrumentProps::hide));
678    
     // quitButton.grab_default();  
679      quitButton.show();      quitButton.show();
     // add(table);  
680      vbox.show();      vbox.show();
681      show_all_children();      show_all_children();
682  }  }
683    
   
684  void InstrumentProps::set_instrument(gig::Instrument* instrument)  void InstrumentProps::set_instrument(gig::Instrument* instrument)
685  {  {
686      char buf[100];      update_gui = false;
687        eName.set_ptr(&instrument->pInfo->Name);
688      int entryIdx = 0, checkIdx = 0;      eIsDrum.set_ptr(&instrument->IsDrum);
689      entry[entryIdx++].set_text(instrument->pInfo->Name);      eMIDIBank.set_ptr(&instrument->MIDIBank);
690      check[checkIdx++].set_active(instrument->IsDrum);      eMIDIProgram.set_ptr(&instrument->MIDIProgram);
691      sprintf(buf, "%d", instrument->MIDIBank);      eAttenuation.set_ptr(&instrument->Attenuation);
692      entry[entryIdx++].set_text(buf);      eGainPlus6.set_ptr(&instrument->Attenuation);
693      sprintf(buf, "%d", instrument->MIDIProgram);      eEffectSend.set_ptr(&instrument->EffectSend);
694      entry[entryIdx++].set_text(buf);      eFineTune.set_ptr(&instrument->FineTune);
695      sprintf(buf, "%d", instrument->Attenuation);      ePitchbendRange.set_ptr(&instrument->PitchbendRange);
696      entry[entryIdx++].set_text(buf);      ePianoReleaseMode.set_ptr(&instrument->PianoReleaseMode);
697      sprintf(buf, "%d", instrument->EffectSend);      eDimensionKeyRangeLow.set_ptr(&instrument->DimensionKeyRange.low);
698      entry[entryIdx++].set_text(buf);      eDimensionKeyRangeHigh.set_ptr(&instrument->DimensionKeyRange.high);
699      sprintf(buf, "%d", instrument->FineTune);      update_gui = true;
     entry[entryIdx++].set_text(buf);  
     sprintf(buf, "%d", instrument->PitchbendRange);  
     entry[entryIdx++].set_text(buf);  
     check[checkIdx++].set_active(instrument->PianoReleaseMode);  
     sprintf(buf, "%s%d (%d)..%s%d (%d)",  
             notes[instrument->DimensionKeyRange.low % 12],  
             instrument->DimensionKeyRange.low / 12 - 1,  
             instrument->DimensionKeyRange.low,  
             notes[instrument->DimensionKeyRange.high % 12],  
             instrument->DimensionKeyRange.high / 12 - 1,  
             instrument->DimensionKeyRange.high);  
     entry[entryIdx].set_text(buf);  
700  }  }
701    
702  void MainWindow::getInfo(const char *filename)  void InstrumentProps::key_range_low_changed()
703  {  {
704      RIFF::File* riff = new RIFF::File(filename);      double l = eDimensionKeyRangeLow.get_value();
705      gig::File* gig = new gig::File(riff);      double h = eDimensionKeyRangeHigh.get_value();
706        if (h < l) eDimensionKeyRangeHigh.set_value(l);
707    }
708    
709      load_gig(gig, filename);  void InstrumentProps::key_range_high_changed()
710    {
711        double l = eDimensionKeyRangeLow.get_value();
712        double h = eDimensionKeyRangeHigh.get_value();
713        if (h < l) eDimensionKeyRangeLow.set_value(h);
714  }  }
715    
716  void MainWindow::load_gig(gig::File* gig, const char* filename)  void MainWindow::load_gig(gig::File* gig, const char* filename)
717  {  {
718      file = gig;      file = gig;
719    
720      const char *basename = strrchr(filename, '/');      if (filename) {
721      basename = basename ? basename + 1 : filename;          const char *basename = strrchr(filename, '/');
722            basename = basename ? basename + 1 : filename;
723      set_title(basename);          set_title(basename);
724        } else {
725            set_title("unnamed");
726        }
727    
728      propDialog.set_info(gig->pInfo);      propDialog.set_info(gig->pInfo);
729    
# Line 1503  void MainWindow::load_gig(gig::File* gig Line 733  void MainWindow::load_gig(gig::File* gig
733      int instrument_index = 0;      int instrument_index = 0;
734      Gtk::RadioMenuItem::Group instrument_group;      Gtk::RadioMenuItem::Group instrument_group;
735      for (gig::Instrument* instrument = gig->GetFirstInstrument() ; instrument ;      for (gig::Instrument* instrument = gig->GetFirstInstrument() ; instrument ;
736           instrument = gig->GetNextInstrument()) {           instrument = gig->GetNextInstrument()) {
737          Gtk::TreeModel::iterator iter = m_refTreeModel->append();          Gtk::TreeModel::iterator iter = m_refTreeModel->append();
738          Gtk::TreeModel::Row row = *iter;          Gtk::TreeModel::Row row = *iter;
739          row[m_Columns.m_col_name] = instrument->pInfo->Name.c_str();          row[m_Columns.m_col_name] = instrument->pInfo->Name.c_str();
740          row[m_Columns.m_col_instr] = instrument;          row[m_Columns.m_col_instr] = instrument;
741          // create a menu item for this instrument          // create a menu item for this instrument
742          Gtk::RadioMenuItem* item= new Gtk::RadioMenuItem(instrument_group, instrument->pInfo->Name.c_str());          Gtk::RadioMenuItem* item =
743                new Gtk::RadioMenuItem(instrument_group, instrument->pInfo->Name.c_str());
744          instrument_menu->get_submenu()->append(*item);          instrument_menu->get_submenu()->append(*item);
745          item->signal_activate().connect(          item->signal_activate().connect(
746              sigc::bind(              sigc::bind(
# Line 1523  void MainWindow::load_gig(gig::File* gig Line 754  void MainWindow::load_gig(gig::File* gig
754      instrument_menu->get_submenu()->show_all_children();      instrument_menu->get_submenu()->show_all_children();
755    
756      for (gig::Group* group = gig->GetFirstGroup(); group; group = gig->GetNextGroup()) {      for (gig::Group* group = gig->GetFirstGroup(); group; group = gig->GetNextGroup()) {
757          Gtk::TreeModel::iterator iterGroup = m_refSamplesTreeModel->append();          if (group->Name != "") {
758          Gtk::TreeModel::Row rowGroup = *iterGroup;              Gtk::TreeModel::iterator iterGroup = m_refSamplesTreeModel->append();
759          rowGroup[m_SamplesModel.m_col_name]   = group->Name.c_str();              Gtk::TreeModel::Row rowGroup = *iterGroup;
760          rowGroup[m_SamplesModel.m_col_sample] = group;              rowGroup[m_SamplesModel.m_col_name]   = group->Name.c_str();
761          for (gig::Sample* sample = group->GetFirstSample(); sample; sample = group->GetNextSample()) {              rowGroup[m_SamplesModel.m_col_group]  = group;
762              Gtk::TreeModel::iterator iterSample = m_refSamplesTreeModel->append(rowGroup.children());              rowGroup[m_SamplesModel.m_col_sample] = NULL;
763              Gtk::TreeModel::Row rowSample = *iterSample;              for (gig::Sample* sample = group->GetFirstSample();
764              rowSample[m_SamplesModel.m_col_name]   = sample->pInfo->Name.c_str();                   sample; sample = group->GetNextSample()) {
765              rowSample[m_SamplesModel.m_col_sample] = sample;                  Gtk::TreeModel::iterator iterSample =
766                        m_refSamplesTreeModel->append(rowGroup.children());
767                    Gtk::TreeModel::Row rowSample = *iterSample;
768                    rowSample[m_SamplesModel.m_col_name]   = sample->pInfo->Name.c_str();
769                    rowSample[m_SamplesModel.m_col_sample] = sample;
770                    rowSample[m_SamplesModel.m_col_group]  = NULL;
771                }
772          }          }
773      }      }
774    
775        // select the first instrument
776        Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();
777        tree_sel_ref->select(Gtk::TreePath("0"));
778  }  }
779    
780  void MainWindow::on_button_release(GdkEventButton* button)  void MainWindow::show_instr_props()
781  {  {
782      if (button->type == GDK_2BUTTON_PRESS) {      Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();
783          Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();      Gtk::TreeModel::iterator it = tree_sel_ref->get_selected();
784          Gtk::TreeModel::iterator it = tree_sel_ref->get_selected();      if (it)
785          if (it)      {
786            Gtk::TreeModel::Row row = *it;
787            if (row[m_Columns.m_col_instr])
788          {          {
789              Gtk::TreeModel::Row row = *it;              instrumentProps.set_instrument(row[m_Columns.m_col_instr]);
790              if (row[m_Columns.m_col_instr])              instrumentProps.show();
791              {              instrumentProps.deiconify();
                 instrumentProps.set_instrument(row[m_Columns.m_col_instr]);  
                 instrumentProps.show();  
                 instrumentProps.deiconify();  
             }  
792          }          }
793        }
794    }
795    
796    void MainWindow::on_button_release(GdkEventButton* button)
797    {
798        if (button->type == GDK_2BUTTON_PRESS) {
799            show_instr_props();
800      } else if (button->type == GDK_BUTTON_PRESS && button->button == 3) {      } else if (button->type == GDK_BUTTON_PRESS && button->button == 3) {
801          popup_menu->popup(button->button, button->time);          popup_menu->popup(button->button, button->time);
802      }      }
# Line 1559  void MainWindow::on_button_release(GdkEv Line 805  void MainWindow::on_button_release(GdkEv
805  void MainWindow::on_instrument_selection_change(int index) {  void MainWindow::on_instrument_selection_change(int index) {
806      m_RegionChooser.set_instrument(file->GetInstrument(index));      m_RegionChooser.set_instrument(file->GetInstrument(index));
807  }  }
808    
809    void MainWindow::on_sample_treeview_button_release(GdkEventButton* button) {
810        if (button->type == GDK_BUTTON_PRESS && button->button == 3) {
811            Gtk::Menu* sample_popup =
812                dynamic_cast<Gtk::Menu*>(uiManager->get_widget("/SamplePopupMenu"));
813            // update enabled/disabled state of sample popup items
814            Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();
815            Gtk::TreeModel::iterator it = sel->get_selected();
816            bool group_selected  = false;
817            bool sample_selected = false;
818            if (it) {
819                Gtk::TreeModel::Row row = *it;
820                group_selected  = row[m_SamplesModel.m_col_group];
821                sample_selected = row[m_SamplesModel.m_col_sample];
822            }
823            dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/SamplePopupMenu/SampleProperties"))->
824                set_sensitive(group_selected || sample_selected);
825            dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/SamplePopupMenu/AddSample"))->
826                set_sensitive(group_selected || sample_selected);
827            dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/SamplePopupMenu/AddGroup"))->
828                set_sensitive(file);
829            dynamic_cast<Gtk::MenuItem*>(uiManager->get_widget("/SamplePopupMenu/RemoveSample"))->
830                set_sensitive(group_selected || sample_selected);
831            // show sample popup
832            sample_popup->popup(button->button, button->time);
833        }
834    }
835    
836    void MainWindow::on_action_add_instrument() {
837        static int __instrument_indexer = 0;
838        if (!file) return;
839        gig::Instrument* instrument = file->AddInstrument();
840        __instrument_indexer++;
841        instrument->pInfo->Name =
842            "Unnamed Instrument " + ToString(__instrument_indexer);
843        // update instrument tree view
844        Gtk::TreeModel::iterator iterInstr = m_refTreeModel->append();
845        Gtk::TreeModel::Row rowInstr = *iterInstr;
846        rowInstr[m_Columns.m_col_name] = instrument->pInfo->Name.c_str();
847        rowInstr[m_Columns.m_col_instr] = instrument;
848    }
849    
850    void MainWindow::on_action_remove_instrument() {
851        if (!file) return;
852        Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeView.get_selection();
853        Gtk::TreeModel::iterator it = sel->get_selected();
854        if (it) {
855            Gtk::TreeModel::Row row = *it;
856            gig::Instrument* instr = row[m_Columns.m_col_instr];
857            try {
858                // remove instrument from the gig file
859                if (instr) file->DeleteInstrument(instr);
860                // remove respective row from instruments tree view
861                m_refTreeModel->erase(it);
862            } catch (RIFF::Exception e) {
863                Gtk::MessageDialog msg(*this, e.Message.c_str(), false, Gtk::MESSAGE_ERROR);
864                msg.run();
865            }
866        }
867    }
868    
869    void MainWindow::on_action_sample_properties() {
870        //TODO: show a dialog where the selected sample's properties can be edited
871        Gtk::MessageDialog msg(
872            *this, "Sorry, yet to be implemented!", false, Gtk::MESSAGE_INFO
873        );
874        msg.run();
875    }
876    
877    void MainWindow::on_action_add_group() {
878        static int __sample_indexer = 0;
879        if (!file) return;
880        gig::Group* group = file->AddGroup();
881        group->Name = "Unnamed Group";
882        if (__sample_indexer) group->Name += " " + ToString(__sample_indexer);
883        __sample_indexer++;
884        // update sample tree view
885        Gtk::TreeModel::iterator iterGroup = m_refSamplesTreeModel->append();
886        Gtk::TreeModel::Row rowGroup = *iterGroup;
887        rowGroup[m_SamplesModel.m_col_name] = group->Name.c_str();
888        rowGroup[m_SamplesModel.m_col_sample] = NULL;
889        rowGroup[m_SamplesModel.m_col_group] = group;
890    }
891    
892    void MainWindow::on_action_add_sample() {
893        if (!file) return;
894        // get selected group
895        Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();
896        Gtk::TreeModel::iterator it = sel->get_selected();
897        if (!it) return;
898        Gtk::TreeModel::Row row = *it;
899        gig::Group* group = row[m_SamplesModel.m_col_group];
900        if (!group) { // not a group, but a sample is selected (probably)
901            gig::Sample* sample = row[m_SamplesModel.m_col_sample];
902            if (!sample) return;
903            it = row.parent(); // resolve parent (that is the sample's group)
904            if (!it) return;
905            row = *it;
906            group = row[m_SamplesModel.m_col_group];
907            if (!group) return;
908        }
909        // show 'browse for file' dialog
910        Gtk::FileChooserDialog dialog(*this, _("Add Sample(s)"));
911        dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
912        dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);
913        dialog.set_select_multiple(true);
914        Gtk::FileFilter soundfilter; // matches all file types supported by libsndfile
915        const char* supportedFileTypes[] = {
916            "*.wav", "*.WAV", "*.aiff", "*.AIFF", "*.aifc", "*.AIFC", "*.snd",
917            "*.SND", "*.au", "*.AU", "*.paf", "*.PAF", "*.iff", "*.IFF",
918            "*.svx", "*.SVX", "*.sf", "*.SF", "*.voc", "*.VOC", "*.w64",
919            "*.W64", "*.pvf", "*.PVF", "*.xi", "*.XI", "*.htk", "*.HTK",
920            "*.caf", "*.CAF", NULL
921        };
922        for (int i = 0; supportedFileTypes[i]; i++)
923            soundfilter.add_pattern(supportedFileTypes[i]);
924        soundfilter.set_name("Sound Files");
925        Gtk::FileFilter allpassfilter; // matches every file
926        allpassfilter.add_pattern("*.*");
927        allpassfilter.set_name("All Files");
928        dialog.add_filter(soundfilter);
929        dialog.add_filter(allpassfilter);
930        if (dialog.run() == Gtk::RESPONSE_OK) {
931            Glib::ustring error_files;
932            Glib::SListHandle<Glib::ustring> filenames = dialog.get_filenames();
933            for (Glib::SListHandle<Glib::ustring>::iterator iter = filenames.begin();
934                 iter != filenames.end(); ++iter) {
935                printf("Adding sample %s\n",(*iter).c_str());
936                // use libsndfile to retrieve file informations
937                SF_INFO info;
938                info.format = 0;
939                SNDFILE* hFile = sf_open((*iter).c_str(), SFM_READ, &info);
940                try {
941                    if (!hFile) throw std::string("could not open file");
942                    int bitdepth;
943                    switch (info.format & 0xff) {
944                        case SF_FORMAT_PCM_S8:
945                            bitdepth = 16; // we simply convert to 16 bit for now
946                            break;
947                        case SF_FORMAT_PCM_16:
948                            bitdepth = 16;
949                            break;
950                        case SF_FORMAT_PCM_24:
951                            bitdepth = 32; // we simply convert to 32 bit for now
952                            break;
953                        case SF_FORMAT_PCM_32:
954                            bitdepth = 32;
955                            break;
956                        case SF_FORMAT_PCM_U8:
957                            bitdepth = 16; // we simply convert to 16 bit for now
958                            break;
959                        case SF_FORMAT_FLOAT:
960                            bitdepth = 32;
961                            break;
962                        case SF_FORMAT_DOUBLE:
963                            bitdepth = 32; // I guess we will always truncate this to 32 bit
964                            break;
965                        default:
966                            sf_close(hFile); // close sound file
967                            throw std::string("format not supported"); // unsupported subformat (yet?)
968                    }
969                    // add a new sample to the .gig file
970                    gig::Sample* sample = file->AddSample();
971                    // file name without path
972                    sample->pInfo->Name = (*iter).substr((*iter).rfind('/') + 1).raw();
973                    sample->Channels = info.channels;
974                    sample->BitDepth = bitdepth;
975                    sample->FrameSize = bitdepth / 8/*1 byte are 8 bits*/ * info.channels;
976                    sample->SamplesPerSecond = info.samplerate;
977                    // schedule resizing the sample (which will be done
978                    // physically when File::Save() is called)
979                    sample->Resize(info.frames);
980                    // make sure sample is part of the selected group
981                    group->AddSample(sample);
982                    // schedule that physical resize and sample import
983                    // (data copying), performed when "Save" is requested
984                    SampleImportItem sched_item;
985                    sched_item.gig_sample  = sample;
986                    sched_item.sample_path = *iter;
987                    m_SampleImportQueue.push_back(sched_item);
988                    // add sample to the tree view
989                    Gtk::TreeModel::iterator iterSample =
990                        m_refSamplesTreeModel->append(row.children());
991                    Gtk::TreeModel::Row rowSample = *iterSample;
992                    rowSample[m_SamplesModel.m_col_name]   = sample->pInfo->Name.c_str();
993                    rowSample[m_SamplesModel.m_col_sample] = sample;
994                    rowSample[m_SamplesModel.m_col_group]  = NULL;
995                    // close sound file
996                    sf_close(hFile);
997                } catch (std::string what) { // remember the files that made trouble (and their cause)
998                    if (error_files.size()) error_files += "\n";
999                    error_files += *iter += " (" + what + ")";
1000                }
1001            }
1002            // show error message box when some file(s) could not be opened / added
1003            if (error_files.size()) {
1004                Glib::ustring txt = "Could not add the following sample(s):\n" + error_files;
1005                Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
1006                msg.run();
1007            }
1008        }
1009    }
1010    
1011    void MainWindow::on_action_remove_sample() {
1012        if (!file) return;
1013        Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();
1014        Gtk::TreeModel::iterator it = sel->get_selected();
1015        if (it) {
1016            Gtk::TreeModel::Row row = *it;
1017            gig::Group* group   = row[m_SamplesModel.m_col_group];
1018            gig::Sample* sample = row[m_SamplesModel.m_col_sample];
1019            Glib::ustring name  = row[m_SamplesModel.m_col_name];
1020            try {
1021                // remove group or sample from the gig file
1022                if (group) {
1023                    // temporarily remember the samples that bolong to
1024                    // that group (we need that to clean the queue)
1025                    std::list<gig::Sample*> members;
1026                    for (gig::Sample* pSample = group->GetFirstSample();
1027                         pSample; pSample = group->GetNextSample()) {
1028                        members.push_back(pSample);
1029                    }
1030                    // delete the group in the .gig file including the
1031                    // samples that belong to the group
1032                    file->DeleteGroup(group);
1033                    // if sample(s) were just previously added, remove
1034                    // them from the import queue
1035                    for (std::list<gig::Sample*>::iterator member = members.begin();
1036                         member != members.end(); ++member) {
1037                        for (std::list<SampleImportItem>::iterator iter = m_SampleImportQueue.begin();
1038                             iter != m_SampleImportQueue.end(); ++iter) {
1039                            if ((*iter).gig_sample == *member) {
1040                                printf("Removing previously added sample '%s' from group '%s'\n",
1041                                       (*iter).sample_path.c_str(), name.c_str());
1042                                m_SampleImportQueue.erase(iter);
1043                                break;
1044                            }
1045                        }
1046                    }
1047                } else if (sample) {
1048                    // remove sample from the .gig file
1049                    file->DeleteSample(sample);
1050                    // if sample was just previously added, remove it from
1051                    // the import queue
1052                    for (std::list<SampleImportItem>::iterator iter = m_SampleImportQueue.begin();
1053                         iter != m_SampleImportQueue.end(); ++iter) {
1054                        if ((*iter).gig_sample == sample) {
1055                            printf("Removing previously added sample '%s'\n",
1056                                   (*iter).sample_path.c_str());
1057                            m_SampleImportQueue.erase(iter);
1058                            break;
1059                        }
1060                    }
1061                }
1062                // remove respective row(s) from samples tree view
1063                m_refSamplesTreeModel->erase(it);
1064            } catch (RIFF::Exception e) {
1065                Gtk::MessageDialog msg(*this, e.Message.c_str(), false, Gtk::MESSAGE_ERROR);
1066                msg.run();
1067            }
1068        }
1069    }
1070    
1071    void MainWindow::on_sample_treeview_drag_data_get(const Glib::RefPtr<Gdk::DragContext>&,
1072                                                      Gtk::SelectionData& selection_data, guint, guint)
1073    {
1074        // get selected sample
1075        gig::Sample* sample = NULL;
1076        Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();
1077        Gtk::TreeModel::iterator it = sel->get_selected();
1078        if (it) {
1079            Gtk::TreeModel::Row row = *it;
1080            sample = row[m_SamplesModel.m_col_sample];
1081        }
1082        // pass the gig::Sample as pointer
1083        selection_data.set(selection_data.get_target(), 0/*unused*/, (const guchar*)&sample,
1084                           sizeof(sample)/*length of data in bytes*/);
1085    }
1086    
1087    void MainWindow::on_sample_label_drop_drag_data_received(
1088        const Glib::RefPtr<Gdk::DragContext>& context, int, int,
1089        const Gtk::SelectionData& selection_data, guint, guint time)
1090    {
1091        gig::DimensionRegion* dimregion = m_DimRegionChooser.get_dimregion();
1092        gig::Sample* sample = *((gig::Sample**) selection_data.get_data());
1093    
1094        if (sample && dimregion && selection_data.get_length() == sizeof(gig::Sample*)) {
1095            if (sample != dimregion->pSample) {
1096                dimregion->pSample = sample;
1097                dimreg_edit.wSample->set_text(dimregion->pSample->pInfo->Name.c_str());
1098                std::cout << "Drop received sample \"" <<
1099                    dimregion->pSample->pInfo->Name.c_str() << "\"" << std::endl;
1100                // drop success
1101                context->drop_reply(true, time);
1102                return;
1103            }
1104        }
1105        // drop failed
1106        context->drop_reply(false, time);
1107    }
1108    
1109    void MainWindow::sample_name_changed(const Gtk::TreeModel::Path& path,
1110                                         const Gtk::TreeModel::iterator& iter) {
1111        if (!iter) return;
1112        Gtk::TreeModel::Row row = *iter;
1113        Glib::ustring name  = row[m_SamplesModel.m_col_name];
1114        gig::Group* group   = row[m_SamplesModel.m_col_group];
1115        gig::Sample* sample = row[m_SamplesModel.m_col_sample];
1116        if (group) {
1117            group->Name = name;
1118        } else if (sample) {
1119            sample->pInfo->Name = name.raw();
1120        }
1121    }
1122    
1123    void MainWindow::instrument_name_changed(const Gtk::TreeModel::Path& path,
1124                                             const Gtk::TreeModel::iterator& iter) {
1125        if (!iter) return;
1126        Gtk::TreeModel::Row row = *iter;
1127        Glib::ustring name = row[m_Columns.m_col_name];
1128        gig::Instrument* instrument = row[m_Columns.m_col_instr];
1129        if (instrument) instrument->pInfo->Name = name.raw();
1130    }

Legend:
Removed from v.1080  
changed lines
  Added in v.1138

  ViewVC Help
Powered by ViewVC