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

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

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

revision 1225 by schoenebeck, Sun Jun 10 10:56:11 2007 UTC revision 1799 by persson, Sat Dec 6 13:49:26 2008 UTC
# Line 1  Line 1 
1  /*  /*
2   * Copyright (C) 2006, 2007 Andreas Persson   * Copyright (C) 2006 - 2008 Andreas Persson
3   *   *
4   * This program is free software; you can redistribute it and/or   * This program is free software; you can redistribute it and/or
5   * modify it under the terms of the GNU General Public License as   * modify it under the terms of the GNU General Public License as
# Line 17  Line 17 
17   * 02110-1301 USA.   * 02110-1301 USA.
18   */   */
19    
 #include <libintl.h>  
20  #include <iostream>  #include <iostream>
21    #include <cstring>
22    
23  #include <gtkmm/filechooserdialog.h>  #include <gtkmm/filechooserdialog.h>
24  #include <gtkmm/messagedialog.h>  #include <gtkmm/messagedialog.h>
25  #include <gtkmm/stock.h>  #include <gtkmm/stock.h>
26  #include <gtkmm/targetentry.h>  #include <gtkmm/targetentry.h>
27  #include <gtkmm/main.h>  #include <gtkmm/main.h>
28    #include <gtkmm/toggleaction.h>
29    #include "wrapLabel.hh"
30    
31  #if GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION >= 6  #include "global.h"
32    
33    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION >= 6) || GTKMM_MAJOR_VERSION > 2
34  #define ABOUT_DIALOG  #define ABOUT_DIALOG
35  #include <gtkmm/aboutdialog.h>  #include <gtkmm/aboutdialog.h>
36  #endif  #endif
37    
38    #if (GLIBMM_MAJOR_VERSION == 2 && GLIBMM_MINOR_VERSION < 6) || GLIBMM_MAJOR_VERSION < 2
39    namespace Glib {
40    Glib::ustring filename_display_basename(const std::string& filename)
41    {
42        gchar* gstr = g_path_get_basename(filename.c_str());
43        Glib::ustring str(gstr);
44        g_free(gstr);
45        return Glib::filename_to_utf8(str);
46    }
47    }
48    #endif
49    
50  #include <stdio.h>  #include <stdio.h>
51  #include <sndfile.h>  #include <sndfile.h>
52    
53  #include "mainwindow.h"  #include "mainwindow.h"
54    
55  #define _(String) gettext(String)  #include "../../gfx/status_attached.xpm"
56    #include "../../gfx/status_detached.xpm"
57    
58  template<class T> inline std::string ToString(T o) {  template<class T> inline std::string ToString(T o) {
59      std::stringstream ss;      std::stringstream ss;
# Line 44  template<class T> inline std::string ToS Line 61  template<class T> inline std::string ToS
61      return ss.str();      return ss.str();
62  }  }
63    
64  MainWindow::MainWindow()  Table::Table(int x, int y) : Gtk::Table(x, y), rowno(0) {  }
65    
66    void Table::add(BoolEntry& boolentry)
67    {
68        attach(boolentry.widget, 0, 2, rowno, rowno + 1,
69               Gtk::FILL, Gtk::SHRINK);
70        rowno++;
71    }
72    
73    void Table::add(BoolEntryPlus6& boolentry)
74    {
75        attach(boolentry.widget, 0, 2, rowno, rowno + 1,
76               Gtk::FILL, Gtk::SHRINK);
77        rowno++;
78    }
79    
80    void Table::add(LabelWidget& prop)
81    {
82        attach(prop.label, 1, 2, rowno, rowno + 1,
83               Gtk::FILL, Gtk::SHRINK);
84        attach(prop.widget, 2, 3, rowno, rowno + 1,
85               Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK);
86        rowno++;
87    }
88    
89    MainWindow::MainWindow() :
90        dimreg_label(_("Changes apply to:")),
91        dimreg_all_regions(_("all regions")),
92        dimreg_all_dimregs(_("all dimension splits")),
93        dimreg_stereo(_("both channels"))
94  {  {
95  //    set_border_width(5);  //    set_border_width(5);
96  //    set_default_size(400, 200);  //    set_default_size(400, 200);
# Line 74  MainWindow::MainWindow() Line 120  MainWindow::MainWindow()
120      m_TreeViewNotebook.set_size_request(300);      m_TreeViewNotebook.set_size_request(300);
121    
122      m_HPaned.add1(m_TreeViewNotebook);      m_HPaned.add1(m_TreeViewNotebook);
123      m_HPaned.add2(dimreg_edit);      dimreg_hbox.add(dimreg_label);
124        dimreg_hbox.add(dimreg_all_regions);
125        dimreg_hbox.add(dimreg_all_dimregs);
126        dimreg_stereo.set_active();
127        dimreg_hbox.add(dimreg_stereo);
128        dimreg_vbox.add(dimreg_edit);
129        dimreg_vbox.pack_start(dimreg_hbox, Gtk::PACK_SHRINK);
130        m_HPaned.add2(dimreg_vbox);
131    
132    
133      m_TreeViewNotebook.append_page(m_ScrolledWindowSamples, "Samples");      m_TreeViewNotebook.append_page(m_ScrolledWindowSamples, "Samples");
# Line 99  MainWindow::MainWindow() Line 152  MainWindow::MainWindow()
152      action = Gtk::Action::create("SaveAs", Gtk::Stock::SAVE_AS);      action = Gtk::Action::create("SaveAs", Gtk::Stock::SAVE_AS);
153      action->property_label() = action->property_label() + "...";      action->property_label() = action->property_label() + "...";
154      actionGroup->add(action,      actionGroup->add(action,
155                       *(new Gtk::AccelKey("<shift><control>s")),                       Gtk::AccelKey("<shift><control>s"),
156                       sigc::mem_fun(                       sigc::mem_fun(
157                           *this, &MainWindow::on_action_file_save_as)                           *this, &MainWindow::on_action_file_save_as));
         );  
158      actionGroup->add(Gtk::Action::create("Properties",      actionGroup->add(Gtk::Action::create("Properties",
159                                           Gtk::Stock::PROPERTIES),                                           Gtk::Stock::PROPERTIES),
160                       sigc::mem_fun(                       sigc::mem_fun(
# Line 113  MainWindow::MainWindow() Line 165  MainWindow::MainWindow()
165                           *this, &MainWindow::show_instr_props));                           *this, &MainWindow::show_instr_props));
166      actionGroup->add(Gtk::Action::create("Quit", Gtk::Stock::QUIT),      actionGroup->add(Gtk::Action::create("Quit", Gtk::Stock::QUIT),
167                       sigc::mem_fun(                       sigc::mem_fun(
168                           *this, &MainWindow::hide));                           *this, &MainWindow::on_action_quit));
169      actionGroup->add(Gtk::Action::create("MenuInstrument", _("_Instrument")));      actionGroup->add(Gtk::Action::create("MenuInstrument", _("_Instrument")));
170    
171        actionGroup->add(Gtk::Action::create("MenuView", _("_View")));
172        Glib::RefPtr<Gtk::ToggleAction> toggle_action =
173            Gtk::ToggleAction::create("Statusbar", _("_Statusbar"));
174        toggle_action->set_active(true);
175        actionGroup->add(toggle_action,
176                         sigc::mem_fun(
177                             *this, &MainWindow::on_action_view_status_bar));
178    
179      action = Gtk::Action::create("MenuHelp", Gtk::Stock::HELP);      action = Gtk::Action::create("MenuHelp", Gtk::Stock::HELP);
180      actionGroup->add(Gtk::Action::create("MenuHelp",      actionGroup->add(Gtk::Action::create("MenuHelp",
181                                           action->property_label()));                                           action->property_label()));
# Line 143  MainWindow::MainWindow() Line 203  MainWindow::MainWindow()
203          sigc::mem_fun(*this, &MainWindow::on_action_add_group)          sigc::mem_fun(*this, &MainWindow::on_action_add_group)
204      );      );
205      actionGroup->add(      actionGroup->add(
206          Gtk::Action::create("AddSample", _("Add _Sample(s)")),          Gtk::Action::create("AddSample", _("Add _Sample(s)...")),
207          sigc::mem_fun(*this, &MainWindow::on_action_add_sample)          sigc::mem_fun(*this, &MainWindow::on_action_add_sample)
208      );      );
209      actionGroup->add(      actionGroup->add(
210          Gtk::Action::create("RemoveSample", Gtk::Stock::REMOVE),          Gtk::Action::create("RemoveSample", Gtk::Stock::REMOVE),
211          sigc::mem_fun(*this, &MainWindow::on_action_remove_sample)          sigc::mem_fun(*this, &MainWindow::on_action_remove_sample)
212      );      );
213        actionGroup->add(
214            Gtk::Action::create("ReplaceAllSamplesInAllGroups",
215                                _("Replace All Samples in All Groups...")),
216            sigc::mem_fun(*this, &MainWindow::on_action_replace_all_samples_in_all_groups)
217        );
218    
219      uiManager = Gtk::UIManager::create();      uiManager = Gtk::UIManager::create();
220      uiManager->insert_action_group(actionGroup);      uiManager->insert_action_group(actionGroup);
221      // add_accel_group(uiManager->get_accel_group());      add_accel_group(uiManager->get_accel_group());
222    
223      Glib::ustring ui_info =      Glib::ustring ui_info =
224          "<ui>"          "<ui>"
# Line 171  MainWindow::MainWindow() Line 236  MainWindow::MainWindow()
236          "    </menu>"          "    </menu>"
237          "    <menu action='MenuInstrument'>"          "    <menu action='MenuInstrument'>"
238          "    </menu>"          "    </menu>"
239            "    <menu action='MenuView'>"
240            "      <menuitem action='Statusbar'/>"
241            "    </menu>"
242  #ifdef ABOUT_DIALOG  #ifdef ABOUT_DIALOG
243          "    <menu action='MenuHelp'>"          "    <menu action='MenuHelp'>"
244          "      <menuitem action='About'/>"          "      <menuitem action='About'/>"
# Line 187  MainWindow::MainWindow() Line 255  MainWindow::MainWindow()
255          "    <menuitem action='SampleProperties'/>"          "    <menuitem action='SampleProperties'/>"
256          "    <menuitem action='AddGroup'/>"          "    <menuitem action='AddGroup'/>"
257          "    <menuitem action='AddSample'/>"          "    <menuitem action='AddSample'/>"
258            "    <menuitem action='ReplaceAllSamplesInAllGroups' />"
259          "    <separator/>"          "    <separator/>"
260          "    <menuitem action='RemoveSample'/>"          "    <menuitem action='RemoveSample'/>"
261          "  </popup>"          "  </popup>"
# Line 199  MainWindow::MainWindow() Line 268  MainWindow::MainWindow()
268      m_VBox.pack_start(*menuBar, Gtk::PACK_SHRINK);      m_VBox.pack_start(*menuBar, Gtk::PACK_SHRINK);
269      m_VBox.pack_start(m_HPaned);      m_VBox.pack_start(m_HPaned);
270      m_VBox.pack_start(m_RegionChooser, Gtk::PACK_SHRINK);      m_VBox.pack_start(m_RegionChooser, Gtk::PACK_SHRINK);
271        m_VBox.pack_start(m_RegionChooser.m_VirtKeybPropsBox, Gtk::PACK_SHRINK);
272      m_VBox.pack_start(m_DimRegionChooser, Gtk::PACK_SHRINK);      m_VBox.pack_start(m_DimRegionChooser, Gtk::PACK_SHRINK);
273        m_VBox.pack_start(m_StatusBar, Gtk::PACK_SHRINK);
274    
275        // Status Bar:
276        m_StatusBar.pack_start(m_AttachedStateLabel, Gtk::PACK_SHRINK);
277        m_StatusBar.pack_start(m_AttachedStateImage, Gtk::PACK_SHRINK);
278        m_StatusBar.show();
279    
280      m_RegionChooser.signal_sel_changed().connect(      m_RegionChooser.signal_region_selected().connect(
281          sigc::mem_fun(*this, &MainWindow::region_changed) );          sigc::mem_fun(*this, &MainWindow::region_changed) );
282      m_DimRegionChooser.signal_sel_changed().connect(      m_DimRegionChooser.signal_dimregion_selected().connect(
283          sigc::mem_fun(*this, &MainWindow::dimreg_changed) );          sigc::mem_fun(*this, &MainWindow::dimreg_changed) );
284    
285    
# Line 235  MainWindow::MainWindow() Line 311  MainWindow::MainWindow()
311      std::list<Gtk::TargetEntry> drag_target_gig_sample;      std::list<Gtk::TargetEntry> drag_target_gig_sample;
312      drag_target_gig_sample.push_back( Gtk::TargetEntry("gig::Sample") );      drag_target_gig_sample.push_back( Gtk::TargetEntry("gig::Sample") );
313      m_TreeViewSamples.drag_source_set(drag_target_gig_sample);      m_TreeViewSamples.drag_source_set(drag_target_gig_sample);
314        m_TreeViewSamples.signal_drag_begin().connect(
315            sigc::mem_fun(*this, &MainWindow::on_sample_treeview_drag_begin)
316        );
317      m_TreeViewSamples.signal_drag_data_get().connect(      m_TreeViewSamples.signal_drag_data_get().connect(
318          sigc::mem_fun(*this, &MainWindow::on_sample_treeview_drag_data_get)          sigc::mem_fun(*this, &MainWindow::on_sample_treeview_drag_data_get)
319      );      );
# Line 242  MainWindow::MainWindow() Line 321  MainWindow::MainWindow()
321      dimreg_edit.wSample->signal_drag_data_received().connect(      dimreg_edit.wSample->signal_drag_data_received().connect(
322          sigc::mem_fun(*this, &MainWindow::on_sample_label_drop_drag_data_received)          sigc::mem_fun(*this, &MainWindow::on_sample_label_drop_drag_data_received)
323      );      );
324        dimreg_edit.signal_dimreg_changed().connect(
325            sigc::hide(sigc::mem_fun(*this, &MainWindow::file_changed)));
326        m_RegionChooser.signal_instrument_changed().connect(
327            sigc::mem_fun(*this, &MainWindow::file_changed));
328        m_DimRegionChooser.signal_region_changed().connect(
329            sigc::mem_fun(*this, &MainWindow::file_changed));
330        instrumentProps.signal_instrument_changed().connect(
331            sigc::mem_fun(*this, &MainWindow::file_changed));
332        propDialog.signal_info_changed().connect(
333            sigc::mem_fun(*this, &MainWindow::file_changed));
334    
335        dimreg_edit.signal_dimreg_to_be_changed().connect(
336            dimreg_to_be_changed_signal.make_slot());
337        dimreg_edit.signal_dimreg_changed().connect(
338            dimreg_changed_signal.make_slot());
339        dimreg_edit.signal_sample_ref_changed().connect(
340            sample_ref_changed_signal.make_slot());
341    
342        m_RegionChooser.signal_instrument_struct_to_be_changed().connect(
343            sigc::hide(
344                sigc::bind(
345                    file_structure_to_be_changed_signal.make_slot(),
346                    sigc::ref(this->file)
347                )
348            )
349        );
350        m_RegionChooser.signal_instrument_struct_changed().connect(
351            sigc::hide(
352                sigc::bind(
353                    file_structure_changed_signal.make_slot(),
354                    sigc::ref(this->file)
355                )
356            )
357        );
358        m_RegionChooser.signal_region_to_be_changed().connect(
359            region_to_be_changed_signal.make_slot());
360        m_RegionChooser.signal_region_changed_signal().connect(
361            region_changed_signal.make_slot());
362    
363        note_on_signal.connect(
364            sigc::mem_fun(m_RegionChooser, &RegionChooser::on_note_on_event));
365        note_off_signal.connect(
366            sigc::mem_fun(m_RegionChooser, &RegionChooser::on_note_off_event));
367    
368        dimreg_all_regions.signal_toggled().connect(
369            sigc::mem_fun(*this, &MainWindow::update_dimregs));
370        dimreg_all_dimregs.signal_toggled().connect(
371            sigc::mem_fun(*this, &MainWindow::dimreg_all_dimregs_toggled));
372        dimreg_stereo.signal_toggled().connect(
373            sigc::mem_fun(*this, &MainWindow::update_dimregs));
374    
375      file = 0;      file = 0;
376        file_is_changed = false;
377        set_file_is_shared(false);
378    
379      show_all_children();      show_all_children();
380    
381        // start with a new gig file by default
382        on_action_file_new();
383  }  }
384    
385  MainWindow::~MainWindow()  MainWindow::~MainWindow()
386  {  {
387  }  }
388    
389  void MainWindow::region_changed()  bool MainWindow::on_delete_event(GdkEventAny* event)
390  {  {
391      m_DimRegionChooser.set_region(m_RegionChooser.get_region());      return !file_is_shared && file_is_changed && !close_confirmation_dialog();
392  }  }
393    
394  void MainWindow::dimreg_changed()  void MainWindow::on_action_quit()
395  {  {
396      dimreg_edit.set_dim_region(m_DimRegionChooser.get_dimregion());      if (!file_is_shared && file_is_changed && !close_confirmation_dialog()) return;
397        hide();
398  }  }
399    
400  void MainWindow::on_sel_change()  void MainWindow::region_changed()
401    {
402        m_DimRegionChooser.set_region(m_RegionChooser.get_region());
403    }
404    
405    gig::Instrument* MainWindow::get_instrument()
406  {  {
407        gig::Instrument* instrument = 0;
408      Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();      Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();
409    
410      Gtk::TreeModel::iterator it = tree_sel_ref->get_selected();      Gtk::TreeModel::iterator it = tree_sel_ref->get_selected();
411      if (it) {      if (it) {
412          Gtk::TreeModel::Row row = *it;          Gtk::TreeModel::Row row = *it;
413          std::cout << row[m_Columns.m_col_name] << std::endl;          instrument = row[m_Columns.m_col_instr];
414        }
415        return instrument;
416    }
417    
418          m_RegionChooser.set_instrument(row[m_Columns.m_col_instr]);  void MainWindow::add_region_to_dimregs(gig::Region* region, bool stereo, bool all_dimregs)
419    {
420        if (all_dimregs) {
421            for (int i = 0 ; i < region->DimensionRegions ; i++) {
422                if (region->pDimensionRegions[i]) {
423                    dimreg_edit.dimregs.insert(region->pDimensionRegions[i]);
424                }
425            }
426      } else {      } else {
427          m_RegionChooser.set_instrument(0);          m_DimRegionChooser.get_dimregions(region, stereo, dimreg_edit.dimregs);
428        }
429    }
430    
431    void MainWindow::update_dimregs()
432    {
433        dimreg_edit.dimregs.clear();
434        bool all_regions = dimreg_all_regions.get_active();
435        bool stereo = dimreg_stereo.get_active();
436        bool all_dimregs = dimreg_all_dimregs.get_active();
437    
438        if (all_regions) {
439            gig::Instrument* instrument = get_instrument();
440            if (instrument) {
441                for (gig::Region* region = instrument->GetFirstRegion() ;
442                     region ;
443                     region = instrument->GetNextRegion()) {
444                    add_region_to_dimregs(region, stereo, all_dimregs);
445                }
446            }
447        } else {
448            gig::Region* region = m_RegionChooser.get_region();
449            if (region) {
450                add_region_to_dimregs(region, stereo, all_dimregs);
451            }
452      }      }
453  }  }
454    
455    void MainWindow::dimreg_all_dimregs_toggled()
456    {
457        dimreg_stereo.set_sensitive(!dimreg_all_dimregs.get_active());
458        update_dimregs();
459    }
460    
461    void MainWindow::dimreg_changed()
462    {
463        update_dimregs();
464        dimreg_edit.set_dim_region(m_DimRegionChooser.get_dimregion());
465    }
466    
467    void MainWindow::on_sel_change()
468    {
469        m_RegionChooser.set_instrument(get_instrument());
470    }
471    
472  void loader_progress_callback(gig::progress_t* progress)  void loader_progress_callback(gig::progress_t* progress)
473  {  {
474      Loader* loader = static_cast<Loader*>(progress->custom);      Loader* loader = static_cast<Loader*>(progress->custom);
# Line 362  void MainWindow::__clear() { Line 554  void MainWindow::__clear() {
554      m_refTreeModel->clear();      m_refTreeModel->clear();
555      m_refSamplesTreeModel->clear();      m_refSamplesTreeModel->clear();
556      // free libgig's gig::File instance      // free libgig's gig::File instance
557      if (file) {      if (file && !file_is_shared) delete file;
558          delete file;      file = NULL;
559          file = NULL;      set_file_is_shared(false);
     }  
560  }  }
561    
562  void MainWindow::on_action_file_new()  void MainWindow::on_action_file_new()
563  {  {
564        if (!file_is_shared && file_is_changed && !close_confirmation_dialog()) return;
565    
566        if (file_is_shared && !leaving_shared_mode_dialog()) return;
567    
568      // clear all GUI elements      // clear all GUI elements
569      __clear();      __clear();
570      // create a new .gig file (virtually yet)      // create a new .gig file (virtually yet)
# Line 378  void MainWindow::on_action_file_new() Line 573  void MainWindow::on_action_file_new()
573      gig::Instrument* pInstrument = pFile->AddInstrument();      gig::Instrument* pInstrument = pFile->AddInstrument();
574      pInstrument->pInfo->Name = "Unnamed Instrument";      pInstrument->pInfo->Name = "Unnamed Instrument";
575      // update GUI with that new gig::File      // update GUI with that new gig::File
576      load_gig(pFile, NULL /*no file name yet*/);      load_gig(pFile, 0 /*no file name yet*/);
577    }
578    
579    bool MainWindow::close_confirmation_dialog()
580    {
581        gchar* msg = g_strdup_printf(_("Save changes to \"%s\" before closing?"),
582                                     Glib::filename_display_basename(filename).c_str());
583        Gtk::MessageDialog dialog(*this, msg, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_NONE);
584        g_free(msg);
585    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION >= 6) || GTKMM_MAJOR_VERSION > 2
586        dialog.set_secondary_text(_("If you close without saving, your changes will be lost."));
587    #endif
588        dialog.add_button(_("Close _Without Saving"), Gtk::RESPONSE_NO);
589        dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
590        dialog.add_button(file_has_name ? Gtk::Stock::SAVE : Gtk::Stock::SAVE_AS, Gtk::RESPONSE_YES);
591        dialog.set_default_response(Gtk::RESPONSE_YES);
592        int response = dialog.run();
593        dialog.hide();
594        if (response == Gtk::RESPONSE_YES) return file_save();
595        return response != Gtk::RESPONSE_CANCEL;
596    }
597    
598    bool MainWindow::leaving_shared_mode_dialog() {
599        Glib::ustring msg = _("Detach from sampler and proceed working stand-alone?");
600        Gtk::MessageDialog dialog(*this, msg, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_NONE);
601    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION >= 6) || GTKMM_MAJOR_VERSION > 2
602        dialog.set_secondary_text(
603            _("If you proceed to work on another instrument file, it won't be "
604              "used by the sampler until you tell the sampler explicitly to "
605              "load it.")
606       );
607    #endif
608        dialog.add_button(_("_Yes, Detach"), Gtk::RESPONSE_YES);
609        dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
610        dialog.set_default_response(Gtk::RESPONSE_CANCEL);
611        int response = dialog.run();
612        dialog.hide();
613        return response == Gtk::RESPONSE_YES;
614  }  }
615    
616  void MainWindow::on_action_file_open()  void MainWindow::on_action_file_open()
617  {  {
618        if (!file_is_shared && file_is_changed && !close_confirmation_dialog()) return;
619    
620        if (file_is_shared && !leaving_shared_mode_dialog()) return;
621    
622      Gtk::FileChooserDialog dialog(*this, _("Open file"));      Gtk::FileChooserDialog dialog(*this, _("Open file"));
623      dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);      dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
624      dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);      dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);
625        dialog.set_default_response(Gtk::RESPONSE_OK);
626      Gtk::FileFilter filter;      Gtk::FileFilter filter;
627      filter.add_pattern("*.gig");      filter.add_pattern("*.gig");
628      dialog.set_filter(filter);      dialog.set_filter(filter);
629        if (current_gig_dir != "") {
630            dialog.set_current_folder(current_gig_dir);
631        }
632      if (dialog.run() == Gtk::RESPONSE_OK) {      if (dialog.run() == Gtk::RESPONSE_OK) {
633          printf("filename=%s\n", dialog.get_filename().c_str());          std::string filename = dialog.get_filename();
634          __clear();          printf("filename=%s\n", filename.c_str());
635          printf("on_action_file_open self=%x\n", Glib::Thread::self());          printf("on_action_file_open self=%x\n", Glib::Thread::self());
636          load_file(dialog.get_filename().c_str());          load_file(filename.c_str());
637            current_gig_dir = Glib::path_get_dirname(filename);
638      }      }
639  }  }
640    
641  void MainWindow::load_file(const char* name)  void MainWindow::load_file(const char* name)
642  {  {
643        __clear();
644      load_dialog = new LoadDialog("Loading...", *this);      load_dialog = new LoadDialog("Loading...", *this);
645      load_dialog->show_all();      load_dialog->show_all();
646      loader = new Loader(strdup(name));      loader = new Loader(strdup(name));
# Line 416  void MainWindow::load_instrument(gig::In Line 658  void MainWindow::load_instrument(gig::In
658          msg.run();          msg.run();
659          Gtk::Main::quit();          Gtk::Main::quit();
660      }      }
661        // clear all GUI elements
662        __clear();
663        // load the instrument
664      gig::File* pFile = (gig::File*) instr->GetParent();      gig::File* pFile = (gig::File*) instr->GetParent();
665      load_gig(pFile, NULL /*file name*/);      load_gig(pFile, 0 /*file name*/, true /*shared instrument*/);
666      //TODO: automatically select the given instrument      //TODO: automatically select the given instrument
667  }  }
668    
# Line 436  void MainWindow::on_loader_finished() Line 681  void MainWindow::on_loader_finished()
681    
682  void MainWindow::on_action_file_save()  void MainWindow::on_action_file_save()
683  {  {
684      if (!file) return;      file_save();
685    }
686    
687    bool MainWindow::check_if_savable()
688    {
689        if (!file) return false;
690    
691        if (!file->GetFirstSample()) {
692            Gtk::MessageDialog(*this, _("The file could not be saved "
693                                        "because it contains no samples"),
694                               false, Gtk::MESSAGE_ERROR).run();
695            return false;
696        }
697    
698        for (gig::Instrument* instrument = file->GetFirstInstrument() ; instrument ;
699             instrument = file->GetNextInstrument()) {
700            if (!instrument->GetFirstRegion()) {
701                Gtk::MessageDialog(*this, _("The file could not be saved "
702                                            "because there are instruments "
703                                            "that have no regions"),
704                                   false, Gtk::MESSAGE_ERROR).run();
705                return false;
706            }
707        }
708        return true;
709    }
710    
711    bool MainWindow::file_save()
712    {
713        if (!check_if_savable()) return false;
714        if (!file_is_shared && !file_has_name) return file_save_as();
715    
716      std::cout << "Saving file\n" << std::flush;      std::cout << "Saving file\n" << std::flush;
717        file_structure_to_be_changed_signal.emit(this->file);
718      try {      try {
719          file->Save();          file->Save();
720            if (file_is_changed) {
721                set_title(get_title().substr(1));
722                file_is_changed = false;
723            }
724      } catch (RIFF::Exception e) {      } catch (RIFF::Exception e) {
725          Glib::ustring txt = "Could not save file: " + e.Message;          file_structure_changed_signal.emit(this->file);
726            Glib::ustring txt = _("Could not save file: ") + e.Message;
727          Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);          Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
728          msg.run();          msg.run();
729          return;          return false;
730      }      }
731      std::cout << "Saving file done\n" << std::flush;      std::cout << "Saving file done\n" << std::flush;
732      __import_queued_samples();      __import_queued_samples();
733        file_structure_changed_signal.emit(this->file);
734        return true;
735  }  }
736    
737  void MainWindow::on_action_file_save_as()  void MainWindow::on_action_file_save_as()
738  {  {
739      if (!file) return;      if (!check_if_savable()) return;
740      Gtk::FileChooserDialog dialog(*this, "Open", Gtk::FILE_CHOOSER_ACTION_SAVE);      file_save_as();
741    }
742    
743    bool MainWindow::file_save_as()
744    {
745        Gtk::FileChooserDialog dialog(*this, _("Save as"), Gtk::FILE_CHOOSER_ACTION_SAVE);
746      dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);      dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
747      dialog.add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK);      dialog.add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK);
748        dialog.set_default_response(Gtk::RESPONSE_OK);
749    
750    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION >= 8) || GTKMM_MAJOR_VERSION > 2
751        dialog.set_do_overwrite_confirmation();
752        // TODO: an overwrite dialog for gtkmm < 2.8
753    #endif
754      Gtk::FileFilter filter;      Gtk::FileFilter filter;
755      filter.add_pattern("*.gig");      filter.add_pattern("*.gig");
756      dialog.set_filter(filter);      dialog.set_filter(filter);
757    
758        // set initial dir and filename of the Save As dialog
759        // and prepare that initial filename as a copy of the gig
760        {
761            std::string basename = Glib::path_get_basename(filename);
762            std::string dir = Glib::path_get_dirname(filename);
763            basename = std::string("copy_of_") + basename;
764            Glib::ustring copyFileName = Glib::build_filename(dir, basename);
765            if (Glib::path_is_absolute(filename)) {
766                dialog.set_filename(copyFileName);
767            } else {
768                if (current_gig_dir != "") dialog.set_current_folder(current_gig_dir);
769            }
770            dialog.set_current_name(Glib::filename_display_basename(copyFileName));
771        }
772    
773        // show warning in the dialog
774        Gtk::HBox descriptionArea;
775        descriptionArea.set_spacing(15);
776        Gtk::Image warningIcon(Gtk::Stock::DIALOG_WARNING, Gtk::IconSize(Gtk::ICON_SIZE_DIALOG));
777        descriptionArea.pack_start(warningIcon, Gtk::PACK_SHRINK);
778        view::WrapLabel description;
779        description.set_markup(
780            _("\n<b>CAUTION:</b> You <b>MUST</b> use the "
781              "<span style=\"italic\">\"Save\"</span> dialog instead of "
782              "<span style=\"italic\">\"Save As...\"</span> if you want to save "
783              "to the same .gig file. Using "
784              "<span style=\"italic\">\"Save As...\"</span> for writing to the "
785              "same .gig file will end up in corrupted sample wave data!\n")
786        );
787        descriptionArea.pack_start(description);
788        dialog.get_vbox()->pack_start(descriptionArea, Gtk::PACK_SHRINK);
789        descriptionArea.show_all();
790    
791      if (dialog.run() == Gtk::RESPONSE_OK) {      if (dialog.run() == Gtk::RESPONSE_OK) {
792          printf("filename=%s\n", dialog.get_filename().c_str());          file_structure_to_be_changed_signal.emit(this->file);
793          try {          try {
794              file->Save(dialog.get_filename());              std::string filename = dialog.get_filename();
795                if (!Glib::str_has_suffix(filename, ".gig")) {
796                    filename += ".gig";
797                }
798                printf("filename=%s\n", filename.c_str());
799                file->Save(filename);
800                this->filename = filename;
801                current_gig_dir = Glib::path_get_dirname(filename);
802                set_title(Glib::filename_display_basename(filename));
803                file_has_name = true;
804                file_is_changed = false;
805          } catch (RIFF::Exception e) {          } catch (RIFF::Exception e) {
806              Glib::ustring txt = "Could not save file: " + e.Message;              file_structure_changed_signal.emit(this->file);
807                Glib::ustring txt = _("Could not save file: ") + e.Message;
808              Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);              Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
809              msg.run();              msg.run();
810              return;              return false;
811          }          }
812          __import_queued_samples();          __import_queued_samples();
813            file_structure_changed_signal.emit(this->file);
814            return true;
815      }      }
816        return false;
817  }  }
818    
819  // actually write the sample(s)' data to the gig file  // actually write the sample(s)' data to the gig file
# Line 490  void MainWindow::__import_queued_samples Line 833  void MainWindow::__import_queued_samples
833              int bitdepth;              int bitdepth;
834              switch (info.format & 0xff) {              switch (info.format & 0xff) {
835                  case SF_FORMAT_PCM_S8:                  case SF_FORMAT_PCM_S8:
                     bitdepth = 16; // we simply convert to 16 bit for now  
                     break;  
836                  case SF_FORMAT_PCM_16:                  case SF_FORMAT_PCM_16:
837                    case SF_FORMAT_PCM_U8:
838                      bitdepth = 16;                      bitdepth = 16;
839                      break;                      break;
840                  case SF_FORMAT_PCM_24:                  case SF_FORMAT_PCM_24:
                     bitdepth = 32; // we simply convert to 32 bit for now  
                     break;  
841                  case SF_FORMAT_PCM_32:                  case SF_FORMAT_PCM_32:
                     bitdepth = 32;  
                     break;  
                 case SF_FORMAT_PCM_U8:  
                     bitdepth = 16; // we simply convert to 16 bit for now  
                     break;  
842                  case SF_FORMAT_FLOAT:                  case SF_FORMAT_FLOAT:
                     bitdepth = 32;  
                     break;  
843                  case SF_FORMAT_DOUBLE:                  case SF_FORMAT_DOUBLE:
844                      bitdepth = 32; // I guess we will always truncate this to 32 bit                      bitdepth = 24;
845                      break;                      break;
846                  default:                  default:
847                      sf_close(hFile); // close sound file                      sf_close(hFile); // close sound file
848                      throw std::string("format not supported"); // unsupported subformat (yet?)                      throw std::string("format not supported"); // unsupported subformat (yet?)
849              }              }
850              // allocate appropriate copy buffer (TODO: for now we copy  
851              // it in one piece, might be tough for very long samples)              const int bufsize = 10000;
             // and copy sample data into buffer  
             int8_t* buffer = NULL;  
852              switch (bitdepth) {              switch (bitdepth) {
853                  case 16:                  case 16: {
854                      buffer = new int8_t[2 * info.channels * info.frames];                      short* buffer = new short[bufsize * info.channels];
855                      // libsndfile does the conversion for us (if needed)                      sf_count_t cnt = info.frames;
856                      sf_readf_short(hFile, (short*) buffer, info.frames);                      while (cnt) {
857                            // libsndfile does the conversion for us (if needed)
858                            int n = sf_readf_short(hFile, buffer, bufsize);
859                            // write from buffer directly (physically) into .gig file
860                            iter->gig_sample->Write(buffer, n);
861                            cnt -= n;
862                        }
863                        delete[] buffer;
864                      break;                      break;
865                  case 32:                  }
866                      buffer = new int8_t[4 * info.channels * info.frames];                  case 24: {
867                      // libsndfile does the conversion for us (if needed)                      int* srcbuf = new int[bufsize * info.channels];
868                      sf_readf_int(hFile, (int*) buffer, info.frames);                      uint8_t* dstbuf = new uint8_t[bufsize * 3 * info.channels];
869                        sf_count_t cnt = info.frames;
870                        while (cnt) {
871                            // libsndfile returns 32 bits, convert to 24
872                            int n = sf_readf_int(hFile, srcbuf, bufsize);
873                            int j = 0;
874                            for (int i = 0 ; i < n * info.channels ; i++) {
875                                dstbuf[j++] = srcbuf[i] >> 8;
876                                dstbuf[j++] = srcbuf[i] >> 16;
877                                dstbuf[j++] = srcbuf[i] >> 24;
878                            }
879                            // write from buffer directly (physically) into .gig file
880                            iter->gig_sample->Write(dstbuf, n);
881                            cnt -= n;
882                        }
883                        delete[] srcbuf;
884                        delete[] dstbuf;
885                      break;                      break;
886                    }
887              }              }
             // write from buffer directly (physically) into .gig file  
             (*iter).gig_sample->Write(buffer, info.frames);  
888              // cleanup              // cleanup
889              sf_close(hFile);              sf_close(hFile);
             delete[] buffer;  
890              // on success we remove the sample from the import queue,              // on success we remove the sample from the import queue,
891              // otherwise keep it, maybe it works the next time ?              // otherwise keep it, maybe it works the next time ?
892              std::list<SampleImportItem>::iterator cur = iter;              std::list<SampleImportItem>::iterator cur = iter;
# Line 549  void MainWindow::__import_queued_samples Line 901  void MainWindow::__import_queued_samples
901      }      }
902      // show error message box when some sample(s) could not be imported      // show error message box when some sample(s) could not be imported
903      if (error_files.size()) {      if (error_files.size()) {
904          Glib::ustring txt = "Could not import the following sample(s):\n" + error_files;          Glib::ustring txt = _("Could not import the following sample(s):\n") + error_files;
905          Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);          Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
906          msg.run();          msg.run();
907      }      }
# Line 566  void MainWindow::on_action_help_about() Line 918  void MainWindow::on_action_help_about()
918  #ifdef ABOUT_DIALOG  #ifdef ABOUT_DIALOG
919      Gtk::AboutDialog dialog;      Gtk::AboutDialog dialog;
920      dialog.set_version(VERSION);      dialog.set_version(VERSION);
921        dialog.set_copyright("Copyright (C) 2006,2007 Andreas Persson");
922        dialog.set_comments(
923            "Released under the GNU General Public License.\n"
924            "\n"
925            "Please notice that this is still a very young instrument editor. "
926            "So better backup your Gigasampler files before editing them with "
927            "this application.\n"
928            "\n"
929            "Please report bugs to: http://bugs.linuxsampler.org"
930        );
931        dialog.set_website("http://www.linuxsampler.org");
932        dialog.set_website_label("http://www.linuxsampler.org");
933      dialog.run();      dialog.run();
934  #endif  #endif
935  }  }
936    
937  PropDialog::PropDialog()  PropDialog::PropDialog()
938      : table(2,1)      : table(2,1),
939          eName("Name"),
940          eCreationDate("Creation date"),
941          eComments("Comments"),
942          eProduct("Product"),
943          eCopyright("Copyright"),
944          eArtists("Artists"),
945          eGenre("Genre"),
946          eKeywords("Keywords"),
947          eEngineer("Engineer"),
948          eTechnician("Technician"),
949          eSoftware("Software"),
950          eMedium("Medium"),
951          eSource("Source"),
952          eSourceForm("Source form"),
953          eCommissioned("Commissioned"),
954          eSubject("Subject"),
955          quitButton(Gtk::Stock::CLOSE),
956          update_model(0)
957  {  {
958        set_title("File Properties");
959        eName.set_width_chars(50);
960    
961        connect(eName, &DLS::Info::Name);
962        connect(eCreationDate, &DLS::Info::CreationDate);
963        connect(eComments, &DLS::Info::Comments);
964        connect(eProduct, &DLS::Info::Product);
965        connect(eCopyright, &DLS::Info::Copyright);
966        connect(eArtists, &DLS::Info::Artists);
967        connect(eGenre, &DLS::Info::Genre);
968        connect(eKeywords, &DLS::Info::Keywords);
969        connect(eEngineer, &DLS::Info::Engineer);
970        connect(eTechnician, &DLS::Info::Technician);
971        connect(eSoftware, &DLS::Info::Software);
972        connect(eMedium, &DLS::Info::Medium);
973        connect(eSource, &DLS::Info::Source);
974        connect(eSourceForm, &DLS::Info::SourceForm);
975        connect(eCommissioned, &DLS::Info::Commissioned);
976        connect(eSubject, &DLS::Info::Subject);
977    
978        table.add(eName);
979        table.add(eCreationDate);
980        table.add(eComments);
981        table.add(eProduct);
982        table.add(eCopyright);
983        table.add(eArtists);
984        table.add(eGenre);
985        table.add(eKeywords);
986        table.add(eEngineer);
987        table.add(eTechnician);
988        table.add(eSoftware);
989        table.add(eMedium);
990        table.add(eSource);
991        table.add(eSourceForm);
992        table.add(eCommissioned);
993        table.add(eSubject);
994    
995      table.set_col_spacings(5);      table.set_col_spacings(5);
996      const char* propLabels[] = {      add(vbox);
997          "Name:",      table.set_border_width(5);
998          "CreationDate:",      vbox.add(table);
999          "Comments:", // TODO: multiline      vbox.pack_start(buttonBox, Gtk::PACK_SHRINK);
1000          "Product:",      buttonBox.set_layout(Gtk::BUTTONBOX_END);
1001          "Copyright:",      buttonBox.set_border_width(5);
1002          "Artists:",      buttonBox.show();
1003          "Genre:",      buttonBox.pack_start(quitButton);
1004          "Keywords:",      quitButton.set_flags(Gtk::CAN_DEFAULT);
1005          "Engineer:",      quitButton.grab_focus();
1006          "Technician:",      quitButton.signal_clicked().connect(
1007          "Software:", // TODO: readonly          sigc::mem_fun(*this, &PropDialog::hide));
         "Medium:",  
         "Source:",  
         "SourceForm:",  
         "Commissioned:",  
         "Subject:"  
     };  
     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);  
         table.attach(entry[i], 1, 2, i, i + 1, Gtk::FILL | Gtk::EXPAND,  
                      Gtk::SHRINK);  
     }  
1008    
1009      add(table);      quitButton.show();
1010      // add_button(Gtk::Stock::CANCEL, 0);      vbox.show();
     // add_button(Gtk::Stock::OK, 1);  
1011      show_all_children();      show_all_children();
1012  }  }
1013    
1014  void PropDialog::set_info(DLS::Info* info)  void PropDialog::set_info(DLS::Info* info)
1015  {  {
1016      entry[0].set_text(info->Name);      this->info = info;
1017      entry[1].set_text(info->CreationDate);      update_model++;
1018      entry[2].set_text(Glib::convert(info->Comments, "UTF-8", "ISO-8859-1"));      eName.set_value(info->Name);
1019      entry[3].set_text(info->Product);      eCreationDate.set_value(info->CreationDate);
1020      entry[4].set_text(info->Copyright);      eComments.set_value(info->Comments);
1021      entry[5].set_text(info->Artists);      eProduct.set_value(info->Product);
1022      entry[6].set_text(info->Genre);      eCopyright.set_value(info->Copyright);
1023      entry[7].set_text(info->Keywords);      eArtists.set_value(info->Artists);
1024      entry[8].set_text(info->Engineer);      eGenre.set_value(info->Genre);
1025      entry[9].set_text(info->Technician);      eKeywords.set_value(info->Keywords);
1026      entry[10].set_text(info->Software);      eEngineer.set_value(info->Engineer);
1027      entry[11].set_text(info->Medium);      eTechnician.set_value(info->Technician);
1028      entry[12].set_text(info->Source);      eSoftware.set_value(info->Software);
1029      entry[13].set_text(info->SourceForm);      eMedium.set_value(info->Medium);
1030      entry[14].set_text(info->Commissioned);      eSource.set_value(info->Source);
1031      entry[15].set_text(info->Subject);      eSourceForm.set_value(info->SourceForm);
1032  }      eCommissioned.set_value(info->Commissioned);
1033        eSubject.set_value(info->Subject);
1034  void InstrumentProps::add_prop(LabelWidget& prop)      update_model--;
1035  {  }
1036      table.attach(prop.label, 0, 1, rowno, rowno + 1,  
1037                   Gtk::FILL, Gtk::SHRINK);  sigc::signal<void>& PropDialog::signal_info_changed()
1038      table.attach(prop.widget, 1, 2, rowno, rowno + 1,  {
1039                   Gtk::FILL | Gtk::EXPAND, Gtk::SHRINK);      return info_changed;
1040      rowno++;  }
1041    
1042    void InstrumentProps::set_IsDrum(bool value)
1043    {
1044        instrument->IsDrum = value;
1045    }
1046    
1047    void InstrumentProps::set_MIDIBank(uint16_t value)
1048    {
1049        instrument->MIDIBank = value;
1050    }
1051    
1052    void InstrumentProps::set_MIDIProgram(uint32_t value)
1053    {
1054        instrument->MIDIProgram = value;
1055    }
1056    
1057    void InstrumentProps::set_DimensionKeyRange_low(uint8_t value)
1058    {
1059        instrument->DimensionKeyRange.low = value;
1060        if (value > instrument->DimensionKeyRange.high) {
1061            eDimensionKeyRangeHigh.set_value(value);
1062        }
1063    }
1064    
1065    void InstrumentProps::set_DimensionKeyRange_high(uint8_t value)
1066    {
1067        instrument->DimensionKeyRange.high = value;
1068        if (value < instrument->DimensionKeyRange.low) {
1069            eDimensionKeyRangeLow.set_value(value);
1070        }
1071  }  }
1072    
1073  InstrumentProps::InstrumentProps()  InstrumentProps::InstrumentProps()
1074      : table(2,1),      : table(2,1),
1075        quitButton(Gtk::Stock::CLOSE),        quitButton(Gtk::Stock::CLOSE),
1076        eName("Name"),        eName("Name"),
1077        eIsDrum("IsDrum"),        eIsDrum("Is drum"),
1078        eMIDIBank("MIDIBank", 0, 16383),        eMIDIBank("MIDI bank", 0, 16383),
1079        eMIDIProgram("MIDIProgram"),        eMIDIProgram("MIDI program"),
1080        eAttenuation("Attenuation", 0, 96, 0, 1),        eAttenuation("Attenuation", 0, 96, 0, 1),
1081        eGainPlus6("Gain +6dB", eAttenuation, -6),        eGainPlus6("Gain +6dB", eAttenuation, -6),
1082        eEffectSend("EffectSend", 0, 65535),        eEffectSend("Effect send", 0, 65535),
1083        eFineTune("FineTune", -8400, 8400),        eFineTune("Fine tune", -8400, 8400),
1084        ePitchbendRange("PitchbendRange", 0, 12),        ePitchbendRange("Pitchbend range", 0, 12),
1085        ePianoReleaseMode("PianoReleaseMode"),        ePianoReleaseMode("Piano release mode"),
1086        eDimensionKeyRangeLow("DimensionKeyRangeLow"),        eDimensionKeyRangeLow("Keyswitching range low"),
1087        eDimensionKeyRangeHigh("DimensionKeyRangeHigh")        eDimensionKeyRangeHigh("Keyswitching range high"),
1088  {        update_model(0)
1089      set_title("Instrument properties");  {
1090        set_title("Instrument Properties");
1091    
1092        eDimensionKeyRangeLow.set_tip(
1093            _("start of the keyboard area which should switch the "
1094              "\"keyswitching\" dimension")
1095        );
1096        eDimensionKeyRangeHigh.set_tip(
1097            _("end of the keyboard area which should switch the "
1098              "\"keyswitching\" dimension")
1099        );
1100    
1101        connect(eIsDrum, &InstrumentProps::set_IsDrum);
1102        connect(eMIDIBank, &InstrumentProps::set_MIDIBank);
1103        connect(eMIDIProgram, &InstrumentProps::set_MIDIProgram);
1104        connect(eAttenuation, &gig::Instrument::Attenuation);
1105        connect(eGainPlus6, &gig::Instrument::Attenuation);
1106        connect(eEffectSend, &gig::Instrument::EffectSend);
1107        connect(eFineTune, &gig::Instrument::FineTune);
1108        connect(ePitchbendRange, &gig::Instrument::PitchbendRange);
1109        connect(ePianoReleaseMode, &gig::Instrument::PianoReleaseMode);
1110        connect(eDimensionKeyRangeLow,
1111                &InstrumentProps::set_DimensionKeyRange_low);
1112        connect(eDimensionKeyRangeHigh,
1113                &InstrumentProps::set_DimensionKeyRange_high);
1114    
     rowno = 0;  
1115      table.set_col_spacings(5);      table.set_col_spacings(5);
1116    
1117      add_prop(eName);      table.add(eName);
1118      add_prop(eIsDrum);      table.add(eIsDrum);
1119      add_prop(eMIDIBank);      table.add(eMIDIBank);
1120      add_prop(eMIDIProgram);      table.add(eMIDIProgram);
1121      add_prop(eAttenuation);      table.add(eAttenuation);
1122      add_prop(eGainPlus6);      table.add(eGainPlus6);
1123      add_prop(eEffectSend);      table.add(eEffectSend);
1124      add_prop(eFineTune);      table.add(eFineTune);
1125      add_prop(ePitchbendRange);      table.add(ePitchbendRange);
1126      add_prop(ePianoReleaseMode);      table.add(ePianoReleaseMode);
1127      add_prop(eDimensionKeyRangeLow);      table.add(eDimensionKeyRangeLow);
1128      add_prop(eDimensionKeyRangeHigh);      table.add(eDimensionKeyRangeHigh);
   
     eDimensionKeyRangeLow.signal_value_changed().connect(  
         sigc::mem_fun(*this, &InstrumentProps::key_range_low_changed));  
     eDimensionKeyRangeHigh.signal_value_changed().connect(  
         sigc::mem_fun(*this, &InstrumentProps::key_range_high_changed));  
1129    
1130      add(vbox);      add(vbox);
1131      table.set_border_width(5);      table.set_border_width(5);
# Line 696  InstrumentProps::InstrumentProps() Line 1149  InstrumentProps::InstrumentProps()
1149    
1150  void InstrumentProps::set_instrument(gig::Instrument* instrument)  void InstrumentProps::set_instrument(gig::Instrument* instrument)
1151  {  {
1152      update_gui = false;      this->instrument = instrument;
1153      eName.set_ptr(&instrument->pInfo->Name);  
1154      eIsDrum.set_ptr(&instrument->IsDrum);      update_model++;
1155      eMIDIBank.set_ptr(&instrument->MIDIBank);      eName.set_value(instrument->pInfo->Name);
1156      eMIDIProgram.set_ptr(&instrument->MIDIProgram);      eIsDrum.set_value(instrument->IsDrum);
1157      eAttenuation.set_ptr(&instrument->Attenuation);      eMIDIBank.set_value(instrument->MIDIBank);
1158      eGainPlus6.set_ptr(&instrument->Attenuation);      eMIDIProgram.set_value(instrument->MIDIProgram);
1159      eEffectSend.set_ptr(&instrument->EffectSend);      eAttenuation.set_value(instrument->Attenuation);
1160      eFineTune.set_ptr(&instrument->FineTune);      eGainPlus6.set_value(instrument->Attenuation);
1161      ePitchbendRange.set_ptr(&instrument->PitchbendRange);      eEffectSend.set_value(instrument->EffectSend);
1162      ePianoReleaseMode.set_ptr(&instrument->PianoReleaseMode);      eFineTune.set_value(instrument->FineTune);
1163      eDimensionKeyRangeLow.set_ptr(&instrument->DimensionKeyRange.low);      ePitchbendRange.set_value(instrument->PitchbendRange);
1164      eDimensionKeyRangeHigh.set_ptr(&instrument->DimensionKeyRange.high);      ePianoReleaseMode.set_value(instrument->PianoReleaseMode);
1165      update_gui = true;      eDimensionKeyRangeLow.set_value(instrument->DimensionKeyRange.low);
1166        eDimensionKeyRangeHigh.set_value(instrument->DimensionKeyRange.high);
1167        update_model--;
1168  }  }
1169    
1170  void InstrumentProps::key_range_low_changed()  sigc::signal<void>& InstrumentProps::signal_instrument_changed()
1171  {  {
1172      double l = eDimensionKeyRangeLow.get_value();      return instrument_changed;
     double h = eDimensionKeyRangeHigh.get_value();  
     if (h < l) eDimensionKeyRangeHigh.set_value(l);  
1173  }  }
1174    
1175  void InstrumentProps::key_range_high_changed()  void MainWindow::file_changed()
1176  {  {
1177      double l = eDimensionKeyRangeLow.get_value();      if (file && !file_is_changed) {
1178      double h = eDimensionKeyRangeHigh.get_value();          set_title("*" + get_title());
1179      if (h < l) eDimensionKeyRangeLow.set_value(h);          file_is_changed = true;
1180        }
1181  }  }
1182    
1183  void MainWindow::load_gig(gig::File* gig, const char* filename)  void MainWindow::load_gig(gig::File* gig, const char* filename, bool isSharedInstrument)
1184  {  {
1185      file = gig;      file = 0;
1186        set_file_is_shared(isSharedInstrument);
1187    
1188      if (filename) {      this->filename = filename ? filename : _("Unsaved Gig File");
1189          const char *basename = strrchr(filename, '/');      set_title(Glib::filename_display_basename(this->filename));
1190          basename = basename ? basename + 1 : filename;      file_has_name = filename;
1191          set_title(basename);      file_is_changed = false;
     } else {  
         set_title("unnamed");  
     }  
1192    
1193      propDialog.set_info(gig->pInfo);      propDialog.set_info(gig->pInfo);
1194    
# Line 785  void MainWindow::load_gig(gig::File* gig Line 1237  void MainWindow::load_gig(gig::File* gig
1237          }          }
1238      }      }
1239    
1240        file = gig;
1241    
1242      // select the first instrument      // select the first instrument
1243      Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();      Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();
1244      tree_sel_ref->select(Gtk::TreePath("0"));      tree_sel_ref->select(Gtk::TreePath("0"));
# Line 792  void MainWindow::load_gig(gig::File* gig Line 1246  void MainWindow::load_gig(gig::File* gig
1246    
1247  void MainWindow::show_instr_props()  void MainWindow::show_instr_props()
1248  {  {
1249      Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();      gig::Instrument* instrument = get_instrument();
1250      Gtk::TreeModel::iterator it = tree_sel_ref->get_selected();      if (instrument)
     if (it)  
1251      {      {
1252          Gtk::TreeModel::Row row = *it;          instrumentProps.set_instrument(instrument);
1253          if (row[m_Columns.m_col_instr])          instrumentProps.show();
1254          {          instrumentProps.deiconify();
             instrumentProps.set_instrument(row[m_Columns.m_col_instr]);  
             instrumentProps.show();  
             instrumentProps.deiconify();  
         }  
1255      }      }
1256  }  }
1257    
1258    void MainWindow::on_action_view_status_bar() {
1259        Gtk::CheckMenuItem* item =
1260            dynamic_cast<Gtk::CheckMenuItem*>(uiManager->get_widget("/MenuBar/MenuView/Statusbar"));
1261        if (!item) {
1262            std::cerr << "/MenuBar/MenuView/Statusbar == NULL\n";
1263            return;
1264        }
1265        if (item->get_active()) m_StatusBar.show();
1266        else                    m_StatusBar.hide();
1267    }
1268    
1269  void MainWindow::on_button_release(GdkEventButton* button)  void MainWindow::on_button_release(GdkEventButton* button)
1270  {  {
1271      if (button->type == GDK_2BUTTON_PRESS) {      if (button->type == GDK_2BUTTON_PRESS) {
# Line 858  void MainWindow::on_action_add_instrumen Line 1318  void MainWindow::on_action_add_instrumen
1318      Gtk::TreeModel::Row rowInstr = *iterInstr;      Gtk::TreeModel::Row rowInstr = *iterInstr;
1319      rowInstr[m_Columns.m_col_name] = instrument->pInfo->Name.c_str();      rowInstr[m_Columns.m_col_name] = instrument->pInfo->Name.c_str();
1320      rowInstr[m_Columns.m_col_instr] = instrument;      rowInstr[m_Columns.m_col_instr] = instrument;
1321        file_changed();
1322  }  }
1323    
1324  void MainWindow::on_action_remove_instrument() {  void MainWindow::on_action_remove_instrument() {
1325      if (!file) return;      if (!file) return;
1326        if (file_is_shared) {
1327            Gtk::MessageDialog msg(
1328                *this,
1329                 _("You cannot delete an instrument from this file, since it's "
1330                   "currently used by the sampler."),
1331                 false, Gtk::MESSAGE_INFO
1332            );
1333            msg.run();
1334            return;
1335        }
1336    
1337      Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeView.get_selection();      Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeView.get_selection();
1338      Gtk::TreeModel::iterator it = sel->get_selected();      Gtk::TreeModel::iterator it = sel->get_selected();
1339      if (it) {      if (it) {
# Line 872  void MainWindow::on_action_remove_instru Line 1344  void MainWindow::on_action_remove_instru
1344              if (instr) file->DeleteInstrument(instr);              if (instr) file->DeleteInstrument(instr);
1345              // remove respective row from instruments tree view              // remove respective row from instruments tree view
1346              m_refTreeModel->erase(it);              m_refTreeModel->erase(it);
1347                file_changed();
1348          } catch (RIFF::Exception e) {          } catch (RIFF::Exception e) {
1349              Gtk::MessageDialog msg(*this, e.Message.c_str(), false, Gtk::MESSAGE_ERROR);              Gtk::MessageDialog msg(*this, e.Message.c_str(), false, Gtk::MESSAGE_ERROR);
1350              msg.run();              msg.run();
# Line 900  void MainWindow::on_action_add_group() { Line 1373  void MainWindow::on_action_add_group() {
1373      rowGroup[m_SamplesModel.m_col_name] = group->Name.c_str();      rowGroup[m_SamplesModel.m_col_name] = group->Name.c_str();
1374      rowGroup[m_SamplesModel.m_col_sample] = NULL;      rowGroup[m_SamplesModel.m_col_sample] = NULL;
1375      rowGroup[m_SamplesModel.m_col_group] = group;      rowGroup[m_SamplesModel.m_col_group] = group;
1376        file_changed();
1377  }  }
1378    
1379  void MainWindow::on_action_add_sample() {  void MainWindow::on_action_add_sample() {
# Line 925  void MainWindow::on_action_add_sample() Line 1399  void MainWindow::on_action_add_sample()
1399      dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);      dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);
1400      dialog.set_select_multiple(true);      dialog.set_select_multiple(true);
1401      Gtk::FileFilter soundfilter; // matches all file types supported by libsndfile      Gtk::FileFilter soundfilter; // matches all file types supported by libsndfile
1402      const char* supportedFileTypes[] = {      const char* const supportedFileTypes[] = {
1403          "*.wav", "*.WAV", "*.aiff", "*.AIFF", "*.aifc", "*.AIFC", "*.snd",          "*.wav", "*.WAV", "*.aiff", "*.AIFF", "*.aifc", "*.AIFC", "*.snd",
1404          "*.SND", "*.au", "*.AU", "*.paf", "*.PAF", "*.iff", "*.IFF",          "*.SND", "*.au", "*.AU", "*.paf", "*.PAF", "*.iff", "*.IFF",
1405          "*.svx", "*.SVX", "*.sf", "*.SF", "*.voc", "*.VOC", "*.w64",          "*.svx", "*.SVX", "*.sf", "*.SF", "*.voc", "*.VOC", "*.w64",
# Line 940  void MainWindow::on_action_add_sample() Line 1414  void MainWindow::on_action_add_sample()
1414      allpassfilter.set_name("All Files");      allpassfilter.set_name("All Files");
1415      dialog.add_filter(soundfilter);      dialog.add_filter(soundfilter);
1416      dialog.add_filter(allpassfilter);      dialog.add_filter(allpassfilter);
1417        if (current_sample_dir != "") {
1418            dialog.set_current_folder(current_sample_dir);
1419        }
1420      if (dialog.run() == Gtk::RESPONSE_OK) {      if (dialog.run() == Gtk::RESPONSE_OK) {
1421            current_sample_dir = dialog.get_current_folder();
1422          Glib::ustring error_files;          Glib::ustring error_files;
1423          Glib::SListHandle<Glib::ustring> filenames = dialog.get_filenames();          Glib::SListHandle<Glib::ustring> filenames = dialog.get_filenames();
1424          for (Glib::SListHandle<Glib::ustring>::iterator iter = filenames.begin();          for (Glib::SListHandle<Glib::ustring>::iterator iter = filenames.begin();
# Line 955  void MainWindow::on_action_add_sample() Line 1433  void MainWindow::on_action_add_sample()
1433                  int bitdepth;                  int bitdepth;
1434                  switch (info.format & 0xff) {                  switch (info.format & 0xff) {
1435                      case SF_FORMAT_PCM_S8:                      case SF_FORMAT_PCM_S8:
                         bitdepth = 16; // we simply convert to 16 bit for now  
                         break;  
1436                      case SF_FORMAT_PCM_16:                      case SF_FORMAT_PCM_16:
1437                        case SF_FORMAT_PCM_U8:
1438                          bitdepth = 16;                          bitdepth = 16;
1439                          break;                          break;
1440                      case SF_FORMAT_PCM_24:                      case SF_FORMAT_PCM_24:
                         bitdepth = 32; // we simply convert to 32 bit for now  
                         break;  
1441                      case SF_FORMAT_PCM_32:                      case SF_FORMAT_PCM_32:
                         bitdepth = 32;  
                         break;  
                     case SF_FORMAT_PCM_U8:  
                         bitdepth = 16; // we simply convert to 16 bit for now  
                         break;  
1442                      case SF_FORMAT_FLOAT:                      case SF_FORMAT_FLOAT:
                         bitdepth = 32;  
                         break;  
1443                      case SF_FORMAT_DOUBLE:                      case SF_FORMAT_DOUBLE:
1444                          bitdepth = 32; // I guess we will always truncate this to 32 bit                          bitdepth = 24;
1445                          break;                          break;
1446                      default:                      default:
1447                          sf_close(hFile); // close sound file                          sf_close(hFile); // close sound file
# Line 982  void MainWindow::on_action_add_sample() Line 1450  void MainWindow::on_action_add_sample()
1450                  // add a new sample to the .gig file                  // add a new sample to the .gig file
1451                  gig::Sample* sample = file->AddSample();                  gig::Sample* sample = file->AddSample();
1452                  // file name without path                  // file name without path
1453                  sample->pInfo->Name = (*iter).substr((*iter).rfind('/') + 1).raw();                  Glib::ustring filename = Glib::filename_display_basename(*iter);
1454                    // remove file extension if there is one
1455                    for (int i = 0; supportedFileTypes[i]; i++) {
1456                        if (Glib::str_has_suffix(filename, supportedFileTypes[i] + 1)) {
1457                            filename.erase(filename.length() - strlen(supportedFileTypes[i] + 1));
1458                            break;
1459                        }
1460                    }
1461                    sample->pInfo->Name = filename;
1462                  sample->Channels = info.channels;                  sample->Channels = info.channels;
1463                  sample->BitDepth = bitdepth;                  sample->BitDepth = bitdepth;
1464                  sample->FrameSize = bitdepth / 8/*1 byte are 8 bits*/ * info.channels;                  sample->FrameSize = bitdepth / 8/*1 byte are 8 bits*/ * info.channels;
1465                  sample->SamplesPerSecond = info.samplerate;                  sample->SamplesPerSecond = info.samplerate;
1466                    sample->AverageBytesPerSecond = sample->FrameSize * sample->SamplesPerSecond;
1467                    sample->BlockAlign = sample->FrameSize;
1468                    sample->SamplesTotal = info.frames;
1469    
1470                    SF_INSTRUMENT instrument;
1471                    if (sf_command(hFile, SFC_GET_INSTRUMENT,
1472                                   &instrument, sizeof(instrument)) != SF_FALSE)
1473                    {
1474                        sample->MIDIUnityNote = instrument.basenote;
1475    
1476    #if HAVE_SF_INSTRUMENT_LOOPS
1477                        if (instrument.loop_count && instrument.loops[0].mode != SF_LOOP_NONE) {
1478                            sample->Loops = 1;
1479    
1480                            switch (instrument.loops[0].mode) {
1481                            case SF_LOOP_FORWARD:
1482                                sample->LoopType = gig::loop_type_normal;
1483                                break;
1484                            case SF_LOOP_BACKWARD:
1485                                sample->LoopType = gig::loop_type_backward;
1486                                break;
1487                            case SF_LOOP_ALTERNATING:
1488                                sample->LoopType = gig::loop_type_bidirectional;
1489                                break;
1490                            }
1491                            sample->LoopStart = instrument.loops[0].start;
1492                            sample->LoopEnd = instrument.loops[0].end;
1493                            sample->LoopPlayCount = instrument.loops[0].count;
1494                            sample->LoopSize = sample->LoopEnd - sample->LoopStart + 1;
1495                        }
1496    #endif
1497                    }
1498    
1499                  // schedule resizing the sample (which will be done                  // schedule resizing the sample (which will be done
1500                  // physically when File::Save() is called)                  // physically when File::Save() is called)
1501                  sample->Resize(info.frames);                  sample->Resize(info.frames);
# Line 1002  void MainWindow::on_action_add_sample() Line 1511  void MainWindow::on_action_add_sample()
1511                  Gtk::TreeModel::iterator iterSample =                  Gtk::TreeModel::iterator iterSample =
1512                      m_refSamplesTreeModel->append(row.children());                      m_refSamplesTreeModel->append(row.children());
1513                  Gtk::TreeModel::Row rowSample = *iterSample;                  Gtk::TreeModel::Row rowSample = *iterSample;
1514                  rowSample[m_SamplesModel.m_col_name]   = sample->pInfo->Name.c_str();                  rowSample[m_SamplesModel.m_col_name]   = filename;
1515                  rowSample[m_SamplesModel.m_col_sample] = sample;                  rowSample[m_SamplesModel.m_col_sample] = sample;
1516                  rowSample[m_SamplesModel.m_col_group]  = NULL;                  rowSample[m_SamplesModel.m_col_group]  = NULL;
1517                  // close sound file                  // close sound file
1518                  sf_close(hFile);                  sf_close(hFile);
1519                    file_changed();
1520              } catch (std::string what) { // remember the files that made trouble (and their cause)              } catch (std::string what) { // remember the files that made trouble (and their cause)
1521                  if (error_files.size()) error_files += "\n";                  if (error_files.size()) error_files += "\n";
1522                  error_files += *iter += " (" + what + ")";                  error_files += *iter += " (" + what + ")";
# Line 1014  void MainWindow::on_action_add_sample() Line 1524  void MainWindow::on_action_add_sample()
1524          }          }
1525          // show error message box when some file(s) could not be opened / added          // show error message box when some file(s) could not be opened / added
1526          if (error_files.size()) {          if (error_files.size()) {
1527              Glib::ustring txt = "Could not add the following sample(s):\n" + error_files;              Glib::ustring txt = _("Could not add the following sample(s):\n") + error_files;
1528                Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
1529                msg.run();
1530            }
1531        }
1532    }
1533    
1534    void MainWindow::on_action_replace_all_samples_in_all_groups()
1535    {
1536        if (!file) return;
1537        Gtk::FileChooserDialog dialog(*this, _("Select Folder"),
1538                                      Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER);
1539        view::WrapLabel description(
1540            _("This is a very specific function. It tries to replace all samples "
1541              "in the current gig file by samples located in the chosen "
1542              "directory.\n\n"
1543              "It works like this: For each sample in the gig file, it tries to "
1544              "find a sample file in the selected directory with the same name as "
1545              "the sample in the gig file. Optionally, you can add a filename "
1546              "extension below, which will be added to the filename expected to be "
1547              "found. That is, assume you have a gig file with a sample called "
1548              "'Snare', if you enter '.wav' below (like it's done by default), it "
1549              "expects to find a sample file called 'Snare.wav' and will replace "
1550              "the sample in the gig file accordingly. If you don't need an "
1551              "extension, blank the field below. Any gig sample where no "
1552              "appropriate sample file could be found will be reported and left "
1553              "untouched.\n")
1554        );
1555        Gtk::HBox entryArea;
1556        Gtk::Label entryLabel( _("Add filename extension: "), Gtk::ALIGN_RIGHT);
1557        Gtk::Entry postfixEntryBox;
1558        postfixEntryBox.set_text(".wav");
1559        entryArea.pack_start(entryLabel);
1560        entryArea.pack_start(postfixEntryBox);
1561        dialog.get_vbox()->pack_start(description, Gtk::PACK_SHRINK);
1562        dialog.get_vbox()->pack_start(entryArea, Gtk::PACK_SHRINK);
1563        description.show();
1564        entryArea.show_all();
1565        dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1566        dialog.add_button(_("Select"), Gtk::RESPONSE_OK);
1567        dialog.set_select_multiple(false);
1568        if (current_sample_dir != "") {
1569            dialog.set_current_folder(current_sample_dir);
1570        }
1571        if (dialog.run() == Gtk::RESPONSE_OK)
1572        {
1573            current_sample_dir = dialog.get_current_folder();
1574            Glib::ustring error_files;
1575            Glib::ustring folder = dialog.get_filename();
1576            for (gig::Sample* sample = file->GetFirstSample();
1577                 sample; sample = file->GetNextSample())
1578            {
1579                std::string filename =
1580                    folder + G_DIR_SEPARATOR_S + sample->pInfo->Name +
1581                    postfixEntryBox.get_text().raw();
1582                SF_INFO info;
1583                info.format = 0;
1584                SNDFILE* hFile = sf_open(filename.c_str(), SFM_READ, &info);
1585                try
1586                {
1587                    if (!hFile) throw std::string("could not open file");
1588                    int bitdepth;
1589                    switch (info.format & 0xff) {
1590                        case SF_FORMAT_PCM_S8:
1591                        case SF_FORMAT_PCM_16:
1592                        case SF_FORMAT_PCM_U8:
1593                            bitdepth = 16;
1594                            break;
1595                        case SF_FORMAT_PCM_24:
1596                        case SF_FORMAT_PCM_32:
1597                        case SF_FORMAT_FLOAT:
1598                        case SF_FORMAT_DOUBLE:
1599                            bitdepth = 24;
1600                            break;
1601                        default:
1602                            sf_close(hFile);
1603                            throw std::string("format not supported");
1604                    }
1605                    SampleImportItem sched_item;
1606                    sched_item.gig_sample  = sample;
1607                    sched_item.sample_path = filename;
1608                    m_SampleImportQueue.push_back(sched_item);
1609                    sf_close(hFile);
1610                    file_changed();
1611                }
1612                catch (std::string what)
1613                {
1614                    if (error_files.size()) error_files += "\n";
1615                        error_files += filename += " (" + what + ")";
1616                }
1617            }
1618            // show error message box when some file(s) could not be opened / added
1619            if (error_files.size()) {
1620                Glib::ustring txt =
1621                    _("Could not replace the following sample(s):\n") + error_files;
1622              Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);              Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
1623              msg.run();              msg.run();
1624          }          }
# Line 1040  void MainWindow::on_action_remove_sample Line 1644  void MainWindow::on_action_remove_sample
1644                       pSample; pSample = group->GetNextSample()) {                       pSample; pSample = group->GetNextSample()) {
1645                      members.push_back(pSample);                      members.push_back(pSample);
1646                  }                  }
1647                    // notify everybody that we're going to remove these samples
1648                    samples_to_be_removed_signal.emit(members);
1649                  // delete the group in the .gig file including the                  // delete the group in the .gig file including the
1650                  // samples that belong to the group                  // samples that belong to the group
1651                  file->DeleteGroup(group);                  file->DeleteGroup(group);
1652                    // notify that we're done with removal
1653                    samples_removed_signal.emit();
1654                  // if sample(s) were just previously added, remove                  // if sample(s) were just previously added, remove
1655                  // them from the import queue                  // them from the import queue
1656                  for (std::list<gig::Sample*>::iterator member = members.begin();                  for (std::list<gig::Sample*>::iterator member = members.begin();
# Line 1057  void MainWindow::on_action_remove_sample Line 1665  void MainWindow::on_action_remove_sample
1665                          }                          }
1666                      }                      }
1667                  }                  }
1668                    file_changed();
1669              } else if (sample) {              } else if (sample) {
1670                    // notify everybody that we're going to remove this sample
1671                    std::list<gig::Sample*> lsamples;
1672                    lsamples.push_back(sample);
1673                    samples_to_be_removed_signal.emit(lsamples);
1674                  // remove sample from the .gig file                  // remove sample from the .gig file
1675                  file->DeleteSample(sample);                  file->DeleteSample(sample);
1676                    // notify that we're done with removal
1677                    samples_removed_signal.emit();
1678                  // if sample was just previously added, remove it from                  // if sample was just previously added, remove it from
1679                  // the import queue                  // the import queue
1680                  for (std::list<SampleImportItem>::iterator iter = m_SampleImportQueue.begin();                  for (std::list<SampleImportItem>::iterator iter = m_SampleImportQueue.begin();
# Line 1071  void MainWindow::on_action_remove_sample Line 1686  void MainWindow::on_action_remove_sample
1686                          break;                          break;
1687                      }                      }
1688                  }                  }
1689                    dimreg_changed();
1690                    file_changed();
1691              }              }
1692              // remove respective row(s) from samples tree view              // remove respective row(s) from samples tree view
1693              m_refSamplesTreeModel->erase(it);              m_refSamplesTreeModel->erase(it);
1694          } catch (RIFF::Exception e) {          } catch (RIFF::Exception e) {
1695                // pretend we're done with removal (i.e. to avoid dead locks)
1696                samples_removed_signal.emit();
1697                // show error message
1698              Gtk::MessageDialog msg(*this, e.Message.c_str(), false, Gtk::MESSAGE_ERROR);              Gtk::MessageDialog msg(*this, e.Message.c_str(), false, Gtk::MESSAGE_ERROR);
1699              msg.run();              msg.run();
1700          }          }
1701      }      }
1702  }  }
1703    
1704    // For some reason drag_data_get gets called two times for each
1705    // drag'n'drop (at least when target is an Entry). This work-around
1706    // makes sure the code in drag_data_get and drop_drag_data_received is
1707    // only executed once, as drag_begin only gets called once.
1708    void MainWindow::on_sample_treeview_drag_begin(const Glib::RefPtr<Gdk::DragContext>& context)
1709    {
1710        first_call_to_drag_data_get = true;
1711    }
1712    
1713  void MainWindow::on_sample_treeview_drag_data_get(const Glib::RefPtr<Gdk::DragContext>&,  void MainWindow::on_sample_treeview_drag_data_get(const Glib::RefPtr<Gdk::DragContext>&,
1714                                                    Gtk::SelectionData& selection_data, guint, guint)                                                    Gtk::SelectionData& selection_data, guint, guint)
1715  {  {
1716        if (!first_call_to_drag_data_get) return;
1717        first_call_to_drag_data_get = false;
1718    
1719      // get selected sample      // get selected sample
1720      gig::Sample* sample = NULL;      gig::Sample* sample = NULL;
1721      Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();      Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();
# Line 1101  void MainWindow::on_sample_label_drop_dr Line 1733  void MainWindow::on_sample_label_drop_dr
1733      const Glib::RefPtr<Gdk::DragContext>& context, int, int,      const Glib::RefPtr<Gdk::DragContext>& context, int, int,
1734      const Gtk::SelectionData& selection_data, guint, guint time)      const Gtk::SelectionData& selection_data, guint, guint time)
1735  {  {
     gig::DimensionRegion* dimregion = m_DimRegionChooser.get_dimregion();  
1736      gig::Sample* sample = *((gig::Sample**) selection_data.get_data());      gig::Sample* sample = *((gig::Sample**) selection_data.get_data());
1737    
1738      if (sample && dimregion && selection_data.get_length() == sizeof(gig::Sample*)) {      if (sample && selection_data.get_length() == sizeof(gig::Sample*)) {
1739          if (sample != dimregion->pSample) {          std::cout << "Drop received sample \"" <<
1740              dimregion->pSample = sample;              sample->pInfo->Name << "\"" << std::endl;
1741              dimreg_edit.wSample->set_text(dimregion->pSample->pInfo->Name.c_str());          // drop success
1742              std::cout << "Drop received sample \"" <<          context->drop_reply(true, time);
1743                  dimregion->pSample->pInfo->Name.c_str() << "\"" << std::endl;  
1744              // drop success          //TODO: we should better move most of the following code to DimRegionEdit::set_sample()
1745              context->drop_reply(true, time);  
1746              return;          // notify everybody that we're going to alter the region
1747            gig::Region* region = m_RegionChooser.get_region();
1748            region_to_be_changed_signal.emit(region);
1749    
1750            // find the samplechannel dimension
1751            gig::dimension_def_t* stereo_dimension = 0;
1752            for (int i = 0 ; i < region->Dimensions ; i++) {
1753                if (region->pDimensionDefinitions[i].dimension ==
1754                    gig::dimension_samplechannel) {
1755                    stereo_dimension = &region->pDimensionDefinitions[i];
1756                    break;
1757                }
1758            }
1759            bool channels_changed = false;
1760            if (sample->Channels == 1 && stereo_dimension) {
1761                // remove the samplechannel dimension
1762                region->DeleteDimension(stereo_dimension);
1763                channels_changed = true;
1764                region_changed();
1765          }          }
1766            dimreg_edit.set_sample(sample);
1767    
1768            if (sample->Channels == 2 && !stereo_dimension) {
1769                // add samplechannel dimension
1770                gig::dimension_def_t dim;
1771                dim.dimension = gig::dimension_samplechannel;
1772                dim.bits = 1;
1773                dim.zones = 2;
1774                region->AddDimension(&dim);
1775                channels_changed = true;
1776                region_changed();
1777            }
1778            if (channels_changed) {
1779                // unmap all samples with wrong number of channels
1780                // TODO: maybe there should be a warning dialog for this
1781                for (int i = 0 ; i < region->DimensionRegions ; i++) {
1782                    gig::DimensionRegion* d = region->pDimensionRegions[i];
1783                    if (d->pSample && d->pSample->Channels != sample->Channels) {
1784                        gig::Sample* oldref = d->pSample;
1785                        d->pSample = NULL;
1786                        sample_ref_changed_signal.emit(oldref, NULL);
1787                    }
1788                }
1789            }
1790    
1791            // notify we're done with altering
1792            region_changed_signal.emit(region);
1793    
1794            file_changed();
1795    
1796            return;
1797      }      }
1798      // drop failed      // drop failed
1799      context->drop_reply(false, time);      context->drop_reply(false, time);
# Line 1127  void MainWindow::sample_name_changed(con Line 1807  void MainWindow::sample_name_changed(con
1807      gig::Group* group   = row[m_SamplesModel.m_col_group];      gig::Group* group   = row[m_SamplesModel.m_col_group];
1808      gig::Sample* sample = row[m_SamplesModel.m_col_sample];      gig::Sample* sample = row[m_SamplesModel.m_col_sample];
1809      if (group) {      if (group) {
1810          group->Name = name;          if (group->Name != name) {
1811                group->Name = name;
1812                printf("group name changed\n");
1813                file_changed();
1814            }
1815      } else if (sample) {      } else if (sample) {
1816          sample->pInfo->Name = name.raw();          if (sample->pInfo->Name != name.raw()) {
1817                sample->pInfo->Name = name.raw();
1818                printf("sample name changed\n");
1819                file_changed();
1820            }
1821      }      }
1822  }  }
1823    
# Line 1139  void MainWindow::instrument_name_changed Line 1827  void MainWindow::instrument_name_changed
1827      Gtk::TreeModel::Row row = *iter;      Gtk::TreeModel::Row row = *iter;
1828      Glib::ustring name = row[m_Columns.m_col_name];      Glib::ustring name = row[m_Columns.m_col_name];
1829      gig::Instrument* instrument = row[m_Columns.m_col_instr];      gig::Instrument* instrument = row[m_Columns.m_col_instr];
1830      if (instrument) instrument->pInfo->Name = name.raw();      if (instrument && instrument->pInfo->Name != name.raw()) {
1831            instrument->pInfo->Name = name.raw();
1832            file_changed();
1833        }
1834    }
1835    
1836    void MainWindow::set_file_is_shared(bool b) {
1837        this->file_is_shared = b;
1838    
1839        if (file_is_shared) {
1840            m_AttachedStateLabel.set_label(_("live-mode"));
1841            m_AttachedStateImage.set(
1842                Gdk::Pixbuf::create_from_xpm_data(status_attached_xpm)
1843            );
1844        } else {
1845            m_AttachedStateLabel.set_label(_("stand-alone"));
1846            m_AttachedStateImage.set(
1847                Gdk::Pixbuf::create_from_xpm_data(status_detached_xpm)
1848            );
1849        }
1850    }
1851    
1852    sigc::signal<void, gig::File*>& MainWindow::signal_file_structure_to_be_changed() {
1853        return file_structure_to_be_changed_signal;
1854    }
1855    
1856    sigc::signal<void, gig::File*>& MainWindow::signal_file_structure_changed() {
1857        return file_structure_changed_signal;
1858    }
1859    
1860    sigc::signal<void, std::list<gig::Sample*> >& MainWindow::signal_samples_to_be_removed() {
1861        return samples_to_be_removed_signal;
1862    }
1863    
1864    sigc::signal<void>& MainWindow::signal_samples_removed() {
1865        return samples_removed_signal;
1866    }
1867    
1868    sigc::signal<void, gig::Region*>& MainWindow::signal_region_to_be_changed() {
1869        return region_to_be_changed_signal;
1870    }
1871    
1872    sigc::signal<void, gig::Region*>& MainWindow::signal_region_changed() {
1873        return region_changed_signal;
1874    }
1875    
1876    sigc::signal<void, gig::Sample*/*old*/, gig::Sample*/*new*/>& MainWindow::signal_sample_ref_changed() {
1877        return sample_ref_changed_signal;
1878    }
1879    
1880    sigc::signal<void, gig::DimensionRegion*>& MainWindow::signal_dimreg_to_be_changed() {
1881        return dimreg_to_be_changed_signal;
1882    }
1883    
1884    sigc::signal<void, gig::DimensionRegion*>& MainWindow::signal_dimreg_changed() {
1885        return dimreg_changed_signal;
1886    }
1887    
1888    sigc::signal<void, int/*key*/, int/*velocity*/>& MainWindow::signal_note_on() {
1889        return note_on_signal;
1890    }
1891    
1892    sigc::signal<void, int/*key*/, int/*velocity*/>& MainWindow::signal_note_off() {
1893        return note_off_signal;
1894    }
1895    
1896    sigc::signal<void, int/*key*/, int/*velocity*/>& MainWindow::signal_keyboard_key_hit() {
1897        return m_RegionChooser.signal_keyboard_key_hit();
1898    }
1899    
1900    sigc::signal<void, int/*key*/, int/*velocity*/>& MainWindow::signal_keyboard_key_released() {
1901        return m_RegionChooser.signal_keyboard_key_released();
1902  }  }

Legend:
Removed from v.1225  
changed lines
  Added in v.1799

  ViewVC Help
Powered by ViewVC