/[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 1262 by persson, Sun Jul 22 15:07:08 2007 UTC revision 1582 by persson, Sat Dec 8 12:28:53 2007 UTC
# Line 17  Line 17 
17   * 02110-1301 USA.   * 02110-1301 USA.
18   */   */
19    
 #include <libintl.h>  
20  #include <iostream>  #include <iostream>
21    
22  #include <gtkmm/filechooserdialog.h>  #include <gtkmm/filechooserdialog.h>
# Line 25  Line 24 
24  #include <gtkmm/stock.h>  #include <gtkmm/stock.h>
25  #include <gtkmm/targetentry.h>  #include <gtkmm/targetentry.h>
26  #include <gtkmm/main.h>  #include <gtkmm/main.h>
27    #include <gtkmm/toggleaction.h>
28    
29    #include "global.h"
30    
31  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION >= 6) || GTKMM_MAJOR_VERSION > 2  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION >= 6) || GTKMM_MAJOR_VERSION > 2
32  #define ABOUT_DIALOG  #define ABOUT_DIALOG
33  #include <gtkmm/aboutdialog.h>  #include <gtkmm/aboutdialog.h>
34  #endif  #endif
35    
36    #if (GLIBMM_MAJOR_VERSION == 2 && GLIBMM_MINOR_VERSION < 6) || GLIBMM_MAJOR_VERSION < 2
37    namespace Glib {
38    Glib::ustring filename_display_basename(const std::string& filename)
39    {
40        gchar* gstr = g_path_get_basename(filename.c_str());
41        Glib::ustring str(gstr);
42        g_free(gstr);
43        return Glib::filename_to_utf8(str);
44    }
45    }
46    #endif
47    
48  #include <stdio.h>  #include <stdio.h>
49  #include <sndfile.h>  #include <sndfile.h>
50    
51  #include "mainwindow.h"  #include "mainwindow.h"
52    
53  #define _(String) gettext(String)  #include "../../gfx/status_attached.xpm"
54    #include "../../gfx/status_detached.xpm"
55    
56  template<class T> inline std::string ToString(T o) {  template<class T> inline std::string ToString(T o) {
57      std::stringstream ss;      std::stringstream ss;
# Line 44  template<class T> inline std::string ToS Line 59  template<class T> inline std::string ToS
59      return ss.str();      return ss.str();
60  }  }
61    
62  MainWindow::MainWindow()  Table::Table(int x, int y) : Gtk::Table(x, y), rowno(0) {  }
63    
64    void Table::add(BoolEntry& boolentry)
65    {
66        attach(boolentry.widget, 0, 2, rowno, rowno + 1,
67               Gtk::FILL, Gtk::SHRINK);
68        rowno++;
69    }
70    
71    void Table::add(BoolEntryPlus6& boolentry)
72    {
73        attach(boolentry.widget, 0, 2, rowno, rowno + 1,
74               Gtk::FILL, Gtk::SHRINK);
75        rowno++;
76    }
77    
78    void Table::add(LabelWidget& prop)
79    {
80        attach(prop.label, 1, 2, rowno, rowno + 1,
81               Gtk::FILL, Gtk::SHRINK);
82        attach(prop.widget, 2, 3, rowno, rowno + 1,
83               Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK);
84        rowno++;
85    }
86    
87    MainWindow::MainWindow() :
88        dimreg_label(_("Changes apply to:")),
89        dimreg_all_regions(_("all regions")),
90        dimreg_all_dimregs(_("all dimension splits")),
91        dimreg_stereo(_("both channels"))
92  {  {
93  //    set_border_width(5);  //    set_border_width(5);
94  //    set_default_size(400, 200);  //    set_default_size(400, 200);
# Line 74  MainWindow::MainWindow() Line 118  MainWindow::MainWindow()
118      m_TreeViewNotebook.set_size_request(300);      m_TreeViewNotebook.set_size_request(300);
119    
120      m_HPaned.add1(m_TreeViewNotebook);      m_HPaned.add1(m_TreeViewNotebook);
121      m_HPaned.add2(dimreg_edit);      dimreg_hbox.add(dimreg_label);
122        dimreg_hbox.add(dimreg_all_regions);
123        dimreg_hbox.add(dimreg_all_dimregs);
124        dimreg_stereo.set_active();
125        dimreg_hbox.add(dimreg_stereo);
126        dimreg_vbox.add(dimreg_edit);
127        dimreg_vbox.pack_start(dimreg_hbox, Gtk::PACK_SHRINK);
128        m_HPaned.add2(dimreg_vbox);
129    
130    
131      m_TreeViewNotebook.append_page(m_ScrolledWindowSamples, "Samples");      m_TreeViewNotebook.append_page(m_ScrolledWindowSamples, "Samples");
# Line 115  MainWindow::MainWindow() Line 166  MainWindow::MainWindow()
166                           *this, &MainWindow::on_action_quit));                           *this, &MainWindow::on_action_quit));
167      actionGroup->add(Gtk::Action::create("MenuInstrument", _("_Instrument")));      actionGroup->add(Gtk::Action::create("MenuInstrument", _("_Instrument")));
168    
169        actionGroup->add(Gtk::Action::create("MenuView", _("_View")));
170        Glib::RefPtr<Gtk::ToggleAction> toggle_action =
171            Gtk::ToggleAction::create("Statusbar", _("_Statusbar"));
172        toggle_action->set_active(true);
173        actionGroup->add(toggle_action,
174                         sigc::mem_fun(
175                             *this, &MainWindow::on_action_view_status_bar));
176    
177      action = Gtk::Action::create("MenuHelp", Gtk::Stock::HELP);      action = Gtk::Action::create("MenuHelp", Gtk::Stock::HELP);
178      actionGroup->add(Gtk::Action::create("MenuHelp",      actionGroup->add(Gtk::Action::create("MenuHelp",
179                                           action->property_label()));                                           action->property_label()));
# Line 170  MainWindow::MainWindow() Line 229  MainWindow::MainWindow()
229          "    </menu>"          "    </menu>"
230          "    <menu action='MenuInstrument'>"          "    <menu action='MenuInstrument'>"
231          "    </menu>"          "    </menu>"
232            "    <menu action='MenuView'>"
233            "      <menuitem action='Statusbar'/>"
234            "    </menu>"
235  #ifdef ABOUT_DIALOG  #ifdef ABOUT_DIALOG
236          "    <menu action='MenuHelp'>"          "    <menu action='MenuHelp'>"
237          "      <menuitem action='About'/>"          "      <menuitem action='About'/>"
# Line 199  MainWindow::MainWindow() Line 261  MainWindow::MainWindow()
261      m_VBox.pack_start(m_HPaned);      m_VBox.pack_start(m_HPaned);
262      m_VBox.pack_start(m_RegionChooser, Gtk::PACK_SHRINK);      m_VBox.pack_start(m_RegionChooser, Gtk::PACK_SHRINK);
263      m_VBox.pack_start(m_DimRegionChooser, Gtk::PACK_SHRINK);      m_VBox.pack_start(m_DimRegionChooser, Gtk::PACK_SHRINK);
264        m_VBox.pack_start(m_StatusBar, Gtk::PACK_SHRINK);
265    
266        // Status Bar:
267        m_StatusBar.pack_start(m_AttachedStateLabel, Gtk::PACK_SHRINK);
268        m_StatusBar.pack_start(m_AttachedStateImage, Gtk::PACK_SHRINK);
269        m_StatusBar.show();
270    
271      m_RegionChooser.signal_region_selected().connect(      m_RegionChooser.signal_region_selected().connect(
272          sigc::mem_fun(*this, &MainWindow::region_changed) );          sigc::mem_fun(*this, &MainWindow::region_changed) );
# Line 234  MainWindow::MainWindow() Line 302  MainWindow::MainWindow()
302      std::list<Gtk::TargetEntry> drag_target_gig_sample;      std::list<Gtk::TargetEntry> drag_target_gig_sample;
303      drag_target_gig_sample.push_back( Gtk::TargetEntry("gig::Sample") );      drag_target_gig_sample.push_back( Gtk::TargetEntry("gig::Sample") );
304      m_TreeViewSamples.drag_source_set(drag_target_gig_sample);      m_TreeViewSamples.drag_source_set(drag_target_gig_sample);
305        m_TreeViewSamples.signal_drag_begin().connect(
306            sigc::mem_fun(*this, &MainWindow::on_sample_treeview_drag_begin)
307        );
308      m_TreeViewSamples.signal_drag_data_get().connect(      m_TreeViewSamples.signal_drag_data_get().connect(
309          sigc::mem_fun(*this, &MainWindow::on_sample_treeview_drag_data_get)          sigc::mem_fun(*this, &MainWindow::on_sample_treeview_drag_data_get)
310      );      );
# Line 242  MainWindow::MainWindow() Line 313  MainWindow::MainWindow()
313          sigc::mem_fun(*this, &MainWindow::on_sample_label_drop_drag_data_received)          sigc::mem_fun(*this, &MainWindow::on_sample_label_drop_drag_data_received)
314      );      );
315      dimreg_edit.signal_dimreg_changed().connect(      dimreg_edit.signal_dimreg_changed().connect(
316          sigc::mem_fun(*this, &MainWindow::file_changed));          sigc::hide(sigc::mem_fun(*this, &MainWindow::file_changed)));
317      m_RegionChooser.signal_instrument_changed().connect(      m_RegionChooser.signal_instrument_changed().connect(
318          sigc::mem_fun(*this, &MainWindow::file_changed));          sigc::mem_fun(*this, &MainWindow::file_changed));
319      m_DimRegionChooser.signal_region_changed().connect(      m_DimRegionChooser.signal_region_changed().connect(
320          sigc::mem_fun(*this, &MainWindow::file_changed));          sigc::mem_fun(*this, &MainWindow::file_changed));
321      instrumentProps.signal_instrument_changed().connect(      instrumentProps.signal_instrument_changed().connect(
322          sigc::mem_fun(*this, &MainWindow::file_changed));          sigc::mem_fun(*this, &MainWindow::file_changed));
323        propDialog.signal_info_changed().connect(
324            sigc::mem_fun(*this, &MainWindow::file_changed));
325    
326        dimreg_edit.signal_dimreg_to_be_changed().connect(
327            dimreg_to_be_changed_signal.make_slot());
328        dimreg_edit.signal_dimreg_changed().connect(
329            dimreg_changed_signal.make_slot());
330        dimreg_edit.signal_sample_ref_changed().connect(
331            sample_ref_changed_signal.make_slot());
332    
333        m_RegionChooser.signal_instrument_struct_to_be_changed().connect(
334            sigc::hide(
335                sigc::bind(
336                    file_structure_to_be_changed_signal.make_slot(),
337                    sigc::ref(this->file)
338                )
339            )
340        );
341        m_RegionChooser.signal_instrument_struct_changed().connect(
342            sigc::hide(
343                sigc::bind(
344                    file_structure_changed_signal.make_slot(),
345                    sigc::ref(this->file)
346                )
347            )
348        );
349        m_RegionChooser.signal_region_to_be_changed().connect(
350            region_to_be_changed_signal.make_slot());
351        m_RegionChooser.signal_region_changed_signal().connect(
352            region_changed_signal.make_slot());
353    
354        dimreg_all_regions.signal_toggled().connect(
355            sigc::mem_fun(*this, &MainWindow::update_dimregs));
356        dimreg_all_dimregs.signal_toggled().connect(
357            sigc::mem_fun(*this, &MainWindow::dimreg_all_dimregs_toggled));
358        dimreg_stereo.signal_toggled().connect(
359            sigc::mem_fun(*this, &MainWindow::update_dimregs));
360    
361      file = 0;      file = 0;
362      file_is_changed = false;      file_is_changed = false;
363        set_file_is_shared(false);
364    
365      show_all_children();      show_all_children();
366    
367        // start with a new gig file by default
368        on_action_file_new();
369  }  }
370    
371  MainWindow::~MainWindow()  MainWindow::~MainWindow()
# Line 261  MainWindow::~MainWindow() Line 374  MainWindow::~MainWindow()
374    
375  bool MainWindow::on_delete_event(GdkEventAny* event)  bool MainWindow::on_delete_event(GdkEventAny* event)
376  {  {
377      return file_is_changed && !close_confirmation_dialog();      return !file_is_shared && file_is_changed && !close_confirmation_dialog();
378  }  }
379    
380  void MainWindow::on_action_quit()  void MainWindow::on_action_quit()
381  {  {
382      if (file_is_changed && !close_confirmation_dialog()) return;      if (!file_is_shared && file_is_changed && !close_confirmation_dialog()) return;
383      hide();      hide();
384  }  }
385    
# Line 275  void MainWindow::region_changed() Line 388  void MainWindow::region_changed()
388      m_DimRegionChooser.set_region(m_RegionChooser.get_region());      m_DimRegionChooser.set_region(m_RegionChooser.get_region());
389  }  }
390    
391  void MainWindow::dimreg_changed()  gig::Instrument* MainWindow::get_instrument()
 {  
     dimreg_edit.set_dim_region(m_DimRegionChooser.get_dimregion());  
 }  
   
 void MainWindow::on_sel_change()  
392  {  {
393        gig::Instrument* instrument = 0;
394      Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();      Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();
395    
396      Gtk::TreeModel::iterator it = tree_sel_ref->get_selected();      Gtk::TreeModel::iterator it = tree_sel_ref->get_selected();
397      if (it) {      if (it) {
398          Gtk::TreeModel::Row row = *it;          Gtk::TreeModel::Row row = *it;
399          std::cout << row[m_Columns.m_col_name] << std::endl;          instrument = row[m_Columns.m_col_instr];
400        }
401        return instrument;
402    }
403    
404          m_RegionChooser.set_instrument(row[m_Columns.m_col_instr]);  void MainWindow::add_region_to_dimregs(gig::Region* region, bool stereo, bool all_dimregs)
405    {
406        if (all_dimregs) {
407            for (int i = 0 ; i < region->DimensionRegions ; i++) {
408                if (region->pDimensionRegions[i]) {
409                    dimreg_edit.dimregs.insert(region->pDimensionRegions[i]);
410                }
411            }
412      } else {      } else {
413          m_RegionChooser.set_instrument(0);          m_DimRegionChooser.get_dimregions(region, stereo, dimreg_edit.dimregs);
414      }      }
415  }  }
416    
417    void MainWindow::update_dimregs()
418    {
419        dimreg_edit.dimregs.clear();
420        bool all_regions = dimreg_all_regions.get_active();
421        bool stereo = dimreg_stereo.get_active();
422        bool all_dimregs = dimreg_all_dimregs.get_active();
423    
424        if (all_regions) {
425            gig::Instrument* instrument = get_instrument();
426            if (instrument) {
427                for (gig::Region* region = instrument->GetFirstRegion() ;
428                     region ;
429                     region = instrument->GetNextRegion()) {
430                    add_region_to_dimregs(region, stereo, all_dimregs);
431                }
432            }
433        } else {
434            gig::Region* region = m_RegionChooser.get_region();
435            if (region) {
436                add_region_to_dimregs(region, stereo, all_dimregs);
437            }
438        }
439    }
440    
441    void MainWindow::dimreg_all_dimregs_toggled()
442    {
443        dimreg_stereo.set_sensitive(!dimreg_all_dimregs.get_active());
444        update_dimregs();
445    }
446    
447    void MainWindow::dimreg_changed()
448    {
449        update_dimregs();
450        dimreg_edit.set_dim_region(m_DimRegionChooser.get_dimregion());
451    }
452    
453    void MainWindow::on_sel_change()
454    {
455        m_RegionChooser.set_instrument(get_instrument());
456    }
457    
458  void loader_progress_callback(gig::progress_t* progress)  void loader_progress_callback(gig::progress_t* progress)
459  {  {
460      Loader* loader = static_cast<Loader*>(progress->custom);      Loader* loader = static_cast<Loader*>(progress->custom);
# Line 380  void MainWindow::__clear() { Line 540  void MainWindow::__clear() {
540      m_refTreeModel->clear();      m_refTreeModel->clear();
541      m_refSamplesTreeModel->clear();      m_refSamplesTreeModel->clear();
542      // free libgig's gig::File instance      // free libgig's gig::File instance
543      if (file) {      if (file && !file_is_shared) delete file;
544          delete file;      file = NULL;
545          file = NULL;      set_file_is_shared(false);
     }  
546  }  }
547    
548  void MainWindow::on_action_file_new()  void MainWindow::on_action_file_new()
549  {  {
550      if (file_is_changed && !close_confirmation_dialog()) return;      if (!file_is_shared && file_is_changed && !close_confirmation_dialog()) return;
551    
552        if (file_is_shared && !leaving_shared_mode_dialog()) return;
553    
554      // clear all GUI elements      // clear all GUI elements
555      __clear();      __clear();
# Line 407  bool MainWindow::close_confirmation_dial Line 568  bool MainWindow::close_confirmation_dial
568                                   Glib::filename_display_basename(filename).c_str());                                   Glib::filename_display_basename(filename).c_str());
569      Gtk::MessageDialog dialog(*this, msg, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_NONE);      Gtk::MessageDialog dialog(*this, msg, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_NONE);
570      g_free(msg);      g_free(msg);
571    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION >= 6) || GTKMM_MAJOR_VERSION > 2
572      dialog.set_secondary_text(_("If you close without saving, your changes will be lost."));      dialog.set_secondary_text(_("If you close without saving, your changes will be lost."));
573    #endif
574      dialog.add_button(_("Close _Without Saving"), Gtk::RESPONSE_NO);      dialog.add_button(_("Close _Without Saving"), Gtk::RESPONSE_NO);
575      dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);      dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
576      dialog.add_button(file_has_name ? Gtk::Stock::SAVE : Gtk::Stock::SAVE_AS, Gtk::RESPONSE_YES);      dialog.add_button(file_has_name ? Gtk::Stock::SAVE : Gtk::Stock::SAVE_AS, Gtk::RESPONSE_YES);
577      dialog.set_default_response(Gtk::RESPONSE_YES);      dialog.set_default_response(Gtk::RESPONSE_YES);
578      int response = dialog.run();      int response = dialog.run();
579        dialog.hide();
580      if (response == Gtk::RESPONSE_YES) return file_save();      if (response == Gtk::RESPONSE_YES) return file_save();
581      return response != Gtk::RESPONSE_CANCEL;      return response != Gtk::RESPONSE_CANCEL;
582  }  }
583    
584    bool MainWindow::leaving_shared_mode_dialog() {
585        Glib::ustring msg = _("Detach from sampler and proceed working stand-alone?");
586        Gtk::MessageDialog dialog(*this, msg, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_NONE);
587    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION >= 6) || GTKMM_MAJOR_VERSION > 2
588        dialog.set_secondary_text(
589            _("If you proceed to work on another instrument file, it won't be "
590              "used by the sampler until you tell the sampler explicitly to "
591              "load it.")
592       );
593    #endif
594        dialog.add_button(_("_Yes, Detach"), Gtk::RESPONSE_YES);
595        dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
596        dialog.set_default_response(Gtk::RESPONSE_CANCEL);
597        int response = dialog.run();
598        dialog.hide();
599        return response == Gtk::RESPONSE_YES;
600    }
601    
602  void MainWindow::on_action_file_open()  void MainWindow::on_action_file_open()
603  {  {
604      if (file_is_changed && !close_confirmation_dialog()) return;      if (!file_is_shared && file_is_changed && !close_confirmation_dialog()) return;
605    
606        if (file_is_shared && !leaving_shared_mode_dialog()) return;
607    
608      Gtk::FileChooserDialog dialog(*this, _("Open file"));      Gtk::FileChooserDialog dialog(*this, _("Open file"));
609      dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);      dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
# Line 434  void MainWindow::on_action_file_open() Line 618  void MainWindow::on_action_file_open()
618      if (dialog.run() == Gtk::RESPONSE_OK) {      if (dialog.run() == Gtk::RESPONSE_OK) {
619          std::string filename = dialog.get_filename();          std::string filename = dialog.get_filename();
620          printf("filename=%s\n", filename.c_str());          printf("filename=%s\n", filename.c_str());
         __clear();  
621          printf("on_action_file_open self=%x\n", Glib::Thread::self());          printf("on_action_file_open self=%x\n", Glib::Thread::self());
622          load_file(filename.c_str());          load_file(filename.c_str());
623          current_dir = Glib::path_get_dirname(filename);          current_dir = Glib::path_get_dirname(filename);
# Line 443  void MainWindow::on_action_file_open() Line 626  void MainWindow::on_action_file_open()
626    
627  void MainWindow::load_file(const char* name)  void MainWindow::load_file(const char* name)
628  {  {
629        __clear();
630      load_dialog = new LoadDialog("Loading...", *this);      load_dialog = new LoadDialog("Loading...", *this);
631      load_dialog->show_all();      load_dialog->show_all();
632      loader = new Loader(strdup(name));      loader = new Loader(strdup(name));
# Line 460  void MainWindow::load_instrument(gig::In Line 644  void MainWindow::load_instrument(gig::In
644          msg.run();          msg.run();
645          Gtk::Main::quit();          Gtk::Main::quit();
646      }      }
647        // clear all GUI elements
648        __clear();
649        // load the instrument
650      gig::File* pFile = (gig::File*) instr->GetParent();      gig::File* pFile = (gig::File*) instr->GetParent();
651      load_gig(pFile, 0 /*file name*/);      load_gig(pFile, 0 /*file name*/, true /*shared instrument*/);
652      //TODO: automatically select the given instrument      //TODO: automatically select the given instrument
653  }  }
654    
# Line 483  void MainWindow::on_action_file_save() Line 670  void MainWindow::on_action_file_save()
670      file_save();      file_save();
671  }  }
672    
673  bool MainWindow::file_save()  bool MainWindow::check_if_savable()
674  {  {
675      if (!file) return false;      if (!file) return false;
676      if (!file_has_name) return file_save_as();  
677        if (!file->GetFirstSample()) {
678            Gtk::MessageDialog(*this, _("The file could not be saved "
679                                        "because it contains no samples"),
680                               false, Gtk::MESSAGE_ERROR).run();
681            return false;
682        }
683    
684        for (gig::Instrument* instrument = file->GetFirstInstrument() ; instrument ;
685             instrument = file->GetNextInstrument()) {
686            if (!instrument->GetFirstRegion()) {
687                Gtk::MessageDialog(*this, _("The file could not be saved "
688                                            "because there are instruments "
689                                            "that have no regions"),
690                                   false, Gtk::MESSAGE_ERROR).run();
691                return false;
692            }
693        }
694        return true;
695    }
696    
697    bool MainWindow::file_save()
698    {
699        if (!check_if_savable()) return false;
700        if (!file_is_shared && !file_has_name) return file_save_as();
701    
702      std::cout << "Saving file\n" << std::flush;      std::cout << "Saving file\n" << std::flush;
703        file_structure_to_be_changed_signal.emit(this->file);
704      try {      try {
705          file->Save();          file->Save();
706          if (file_is_changed) {          if (file_is_changed) {
# Line 496  bool MainWindow::file_save() Line 708  bool MainWindow::file_save()
708              file_is_changed = false;              file_is_changed = false;
709          }          }
710      } catch (RIFF::Exception e) {      } catch (RIFF::Exception e) {
711          Glib::ustring txt = "Could not save file: " + e.Message;          file_structure_changed_signal.emit(this->file);
712            Glib::ustring txt = _("Could not save file: ") + e.Message;
713          Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);          Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
714          msg.run();          msg.run();
715          return false;          return false;
716      }      }
717      std::cout << "Saving file done\n" << std::flush;      std::cout << "Saving file done\n" << std::flush;
718      __import_queued_samples();      __import_queued_samples();
719        file_structure_changed_signal.emit(this->file);
720      return true;      return true;
721  }  }
722    
723  void MainWindow::on_action_file_save_as()  void MainWindow::on_action_file_save_as()
724  {  {
725        if (!check_if_savable()) return;
726      file_save_as();      file_save_as();
727  }  }
728    
729  bool MainWindow::file_save_as()  bool MainWindow::file_save_as()
730  {  {
     if (!file) return false;  
731      Gtk::FileChooserDialog dialog(*this, _("Save as"), Gtk::FILE_CHOOSER_ACTION_SAVE);      Gtk::FileChooserDialog dialog(*this, _("Save as"), Gtk::FILE_CHOOSER_ACTION_SAVE);
732      dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);      dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
733      dialog.add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK);      dialog.add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK);
# Line 535  bool MainWindow::file_save_as() Line 749  bool MainWindow::file_save_as()
749      dialog.set_current_name(Glib::filename_display_basename(filename));      dialog.set_current_name(Glib::filename_display_basename(filename));
750    
751      if (dialog.run() == Gtk::RESPONSE_OK) {      if (dialog.run() == Gtk::RESPONSE_OK) {
752            file_structure_to_be_changed_signal.emit(this->file);
753          try {          try {
754              std::string filename = dialog.get_filename();              std::string filename = dialog.get_filename();
755              if (!Glib::str_has_suffix(filename, ".gig")) {              if (!Glib::str_has_suffix(filename, ".gig")) {
# Line 548  bool MainWindow::file_save_as() Line 763  bool MainWindow::file_save_as()
763              file_has_name = true;              file_has_name = true;
764              file_is_changed = false;              file_is_changed = false;
765          } catch (RIFF::Exception e) {          } catch (RIFF::Exception e) {
766              Glib::ustring txt = "Could not save file: " + e.Message;              file_structure_changed_signal.emit(this->file);
767                Glib::ustring txt = _("Could not save file: ") + e.Message;
768              Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);              Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
769              msg.run();              msg.run();
770              return false;              return false;
771          }          }
772          __import_queued_samples();          __import_queued_samples();
773            file_structure_changed_signal.emit(this->file);
774          return true;          return true;
775      }      }
776      return false;      return false;
# Line 576  void MainWindow::__import_queued_samples Line 793  void MainWindow::__import_queued_samples
793              int bitdepth;              int bitdepth;
794              switch (info.format & 0xff) {              switch (info.format & 0xff) {
795                  case SF_FORMAT_PCM_S8:                  case SF_FORMAT_PCM_S8:
                     bitdepth = 16; // we simply convert to 16 bit for now  
                     break;  
796                  case SF_FORMAT_PCM_16:                  case SF_FORMAT_PCM_16:
797                    case SF_FORMAT_PCM_U8:
798                      bitdepth = 16;                      bitdepth = 16;
799                      break;                      break;
800                  case SF_FORMAT_PCM_24:                  case SF_FORMAT_PCM_24:
                     bitdepth = 32; // we simply convert to 32 bit for now  
                     break;  
801                  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;  
802                  case SF_FORMAT_FLOAT:                  case SF_FORMAT_FLOAT:
                     bitdepth = 32;  
                     break;  
803                  case SF_FORMAT_DOUBLE:                  case SF_FORMAT_DOUBLE:
804                      bitdepth = 32; // I guess we will always truncate this to 32 bit                      bitdepth = 24;
805                      break;                      break;
806                  default:                  default:
807                      sf_close(hFile); // close sound file                      sf_close(hFile); // close sound file
808                      throw std::string("format not supported"); // unsupported subformat (yet?)                      throw std::string("format not supported"); // unsupported subformat (yet?)
809              }              }
810              // allocate appropriate copy buffer (TODO: for now we copy  
811              // 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;  
812              switch (bitdepth) {              switch (bitdepth) {
813                  case 16:                  case 16: {
814                      buffer = new int8_t[2 * info.channels * info.frames];                      short* buffer = new short[bufsize * info.channels];
815                      // libsndfile does the conversion for us (if needed)                      sf_count_t cnt = info.frames;
816                      sf_readf_short(hFile, (short*) buffer, info.frames);                      while (cnt) {
817                            // libsndfile does the conversion for us (if needed)
818                            int n = sf_readf_short(hFile, buffer, bufsize);
819                            // write from buffer directly (physically) into .gig file
820                            iter->gig_sample->Write(buffer, n);
821                            cnt -= n;
822                        }
823                        delete[] buffer;
824                      break;                      break;
825                  case 32:                  }
826                      buffer = new int8_t[4 * info.channels * info.frames];                  case 24: {
827                      // libsndfile does the conversion for us (if needed)                      int* srcbuf = new int[bufsize * info.channels];
828                      sf_readf_int(hFile, (int*) buffer, info.frames);                      uint8_t* dstbuf = new uint8_t[bufsize * 3 * info.channels];
829                        sf_count_t cnt = info.frames;
830                        while (cnt) {
831                            // libsndfile returns 32 bits, convert to 24
832                            int n = sf_readf_int(hFile, srcbuf, bufsize);
833                            int j = 0;
834                            for (int i = 0 ; i < n * info.channels ; i++) {
835                                dstbuf[j++] = srcbuf[i] >> 8;
836                                dstbuf[j++] = srcbuf[i] >> 16;
837                                dstbuf[j++] = srcbuf[i] >> 24;
838                            }
839                            // write from buffer directly (physically) into .gig file
840                            iter->gig_sample->Write(dstbuf, n);
841                            cnt -= n;
842                        }
843                        delete[] srcbuf;
844                        delete[] dstbuf;
845                      break;                      break;
846                    }
847              }              }
             // write from buffer directly (physically) into .gig file  
             (*iter).gig_sample->Write(buffer, info.frames);  
848              // cleanup              // cleanup
849              sf_close(hFile);              sf_close(hFile);
             delete[] buffer;  
850              // on success we remove the sample from the import queue,              // on success we remove the sample from the import queue,
851              // otherwise keep it, maybe it works the next time ?              // otherwise keep it, maybe it works the next time ?
852              std::list<SampleImportItem>::iterator cur = iter;              std::list<SampleImportItem>::iterator cur = iter;
# Line 635  void MainWindow::__import_queued_samples Line 861  void MainWindow::__import_queued_samples
861      }      }
862      // show error message box when some sample(s) could not be imported      // show error message box when some sample(s) could not be imported
863      if (error_files.size()) {      if (error_files.size()) {
864          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;
865          Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);          Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
866          msg.run();          msg.run();
867      }      }
# Line 652  void MainWindow::on_action_help_about() Line 878  void MainWindow::on_action_help_about()
878  #ifdef ABOUT_DIALOG  #ifdef ABOUT_DIALOG
879      Gtk::AboutDialog dialog;      Gtk::AboutDialog dialog;
880      dialog.set_version(VERSION);      dialog.set_version(VERSION);
881        dialog.set_copyright("Copyright (C) 2006,2007 Andreas Persson");
882        dialog.set_comments(
883            "Released under the GNU General Public License.\n"
884            "\n"
885            "Please notice that this is still a very young instrument editor. "
886            "So better backup your Gigasampler files before editing them with "
887            "this application.\n"
888            "\n"
889            "Please report bugs to: http://bugs.linuxsampler.org"
890        );
891        dialog.set_website("http://www.linuxsampler.org");
892        dialog.set_website_label("http://www.linuxsampler.org");
893      dialog.run();      dialog.run();
894  #endif  #endif
895  }  }
896    
897  PropDialog::PropDialog()  PropDialog::PropDialog()
898      : table(2,1)      : table(2,1),
899          eName("Name"),
900          eCreationDate("Creation date"),
901          eComments("Comments"),
902          eProduct("Product"),
903          eCopyright("Copyright"),
904          eArtists("Artists"),
905          eGenre("Genre"),
906          eKeywords("Keywords"),
907          eEngineer("Engineer"),
908          eTechnician("Technician"),
909          eSoftware("Software"),
910          eMedium("Medium"),
911          eSource("Source"),
912          eSourceForm("Source form"),
913          eCommissioned("Commissioned"),
914          eSubject("Subject"),
915          quitButton(Gtk::Stock::CLOSE),
916          update_model(0)
917  {  {
918        set_title("File Properties");
919        eName.set_width_chars(50);
920    
921        connect(eName, &DLS::Info::Name);
922        connect(eCreationDate, &DLS::Info::CreationDate);
923        connect(eComments, &DLS::Info::Comments);
924        connect(eProduct, &DLS::Info::Product);
925        connect(eCopyright, &DLS::Info::Copyright);
926        connect(eArtists, &DLS::Info::Artists);
927        connect(eGenre, &DLS::Info::Genre);
928        connect(eKeywords, &DLS::Info::Keywords);
929        connect(eEngineer, &DLS::Info::Engineer);
930        connect(eTechnician, &DLS::Info::Technician);
931        connect(eSoftware, &DLS::Info::Software);
932        connect(eMedium, &DLS::Info::Medium);
933        connect(eSource, &DLS::Info::Source);
934        connect(eSourceForm, &DLS::Info::SourceForm);
935        connect(eCommissioned, &DLS::Info::Commissioned);
936        connect(eSubject, &DLS::Info::Subject);
937    
938        table.add(eName);
939        table.add(eCreationDate);
940        table.add(eComments);
941        table.add(eProduct);
942        table.add(eCopyright);
943        table.add(eArtists);
944        table.add(eGenre);
945        table.add(eKeywords);
946        table.add(eEngineer);
947        table.add(eTechnician);
948        table.add(eSoftware);
949        table.add(eMedium);
950        table.add(eSource);
951        table.add(eSourceForm);
952        table.add(eCommissioned);
953        table.add(eSubject);
954    
955      table.set_col_spacings(5);      table.set_col_spacings(5);
956      const char* propLabels[] = {      add(vbox);
957          "Name:",      table.set_border_width(5);
958          "CreationDate:",      vbox.add(table);
959          "Comments:", // TODO: multiline      vbox.pack_start(buttonBox, Gtk::PACK_SHRINK);
960          "Product:",      buttonBox.set_layout(Gtk::BUTTONBOX_END);
961          "Copyright:",      buttonBox.set_border_width(5);
962          "Artists:",      buttonBox.show();
963          "Genre:",      buttonBox.pack_start(quitButton);
964          "Keywords:",      quitButton.set_flags(Gtk::CAN_DEFAULT);
965          "Engineer:",      quitButton.grab_focus();
966          "Technician:",      quitButton.signal_clicked().connect(
967          "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);  
     }  
968    
969      add(table);      quitButton.show();
970      // add_button(Gtk::Stock::CANCEL, 0);      vbox.show();
     // add_button(Gtk::Stock::OK, 1);  
971      show_all_children();      show_all_children();
972  }  }
973    
974  void PropDialog::set_info(DLS::Info* info)  void PropDialog::set_info(DLS::Info* info)
975  {  {
976      entry[0].set_text(info->Name);      this->info = info;
977      entry[1].set_text(info->CreationDate);      update_model++;
978      entry[2].set_text(Glib::convert(info->Comments, "UTF-8", "ISO-8859-1"));      eName.set_value(info->Name);
979      entry[3].set_text(info->Product);      eCreationDate.set_value(info->CreationDate);
980      entry[4].set_text(info->Copyright);      eComments.set_value(info->Comments);
981      entry[5].set_text(info->Artists);      eProduct.set_value(info->Product);
982      entry[6].set_text(info->Genre);      eCopyright.set_value(info->Copyright);
983      entry[7].set_text(info->Keywords);      eArtists.set_value(info->Artists);
984      entry[8].set_text(info->Engineer);      eGenre.set_value(info->Genre);
985      entry[9].set_text(info->Technician);      eKeywords.set_value(info->Keywords);
986      entry[10].set_text(info->Software);      eEngineer.set_value(info->Engineer);
987      entry[11].set_text(info->Medium);      eTechnician.set_value(info->Technician);
988      entry[12].set_text(info->Source);      eSoftware.set_value(info->Software);
989      entry[13].set_text(info->SourceForm);      eMedium.set_value(info->Medium);
990      entry[14].set_text(info->Commissioned);      eSource.set_value(info->Source);
991      entry[15].set_text(info->Subject);      eSourceForm.set_value(info->SourceForm);
992        eCommissioned.set_value(info->Commissioned);
993        eSubject.set_value(info->Subject);
994        update_model--;
995  }  }
996    
997  void InstrumentProps::add_prop(BoolEntry& boolentry)  sigc::signal<void>& PropDialog::signal_info_changed()
998  {  {
999      table.attach(boolentry.widget, 0, 2, rowno, rowno + 1,      return info_changed;
                  Gtk::FILL, Gtk::SHRINK);  
     rowno++;  
     boolentry.signal_changed_by_user().connect(instrument_changed.make_slot());  
1000  }  }
1001    
1002  void InstrumentProps::add_prop(BoolEntryPlus6& boolentry)  void InstrumentProps::set_IsDrum(bool value)
1003  {  {
1004      table.attach(boolentry.widget, 0, 2, rowno, rowno + 1,      instrument->IsDrum = value;
                  Gtk::FILL, Gtk::SHRINK);  
     rowno++;  
     boolentry.signal_changed_by_user().connect(instrument_changed.make_slot());  
1005  }  }
1006    
1007  void InstrumentProps::add_prop(LabelWidget& prop)  void InstrumentProps::set_MIDIBank(uint16_t value)
1008  {  {
1009      table.attach(prop.label, 0, 1, rowno, rowno + 1,      instrument->MIDIBank = value;
1010                   Gtk::FILL, Gtk::SHRINK);  }
1011      table.attach(prop.widget, 1, 2, rowno, rowno + 1,  
1012                   Gtk::FILL | Gtk::EXPAND, Gtk::SHRINK);  void InstrumentProps::set_MIDIProgram(uint32_t value)
1013      rowno++;  {
1014      prop.signal_changed_by_user().connect(instrument_changed.make_slot());      instrument->MIDIProgram = value;
1015    }
1016    
1017    void InstrumentProps::set_DimensionKeyRange_low(uint8_t value)
1018    {
1019        instrument->DimensionKeyRange.low = value;
1020        if (value > instrument->DimensionKeyRange.high) {
1021            eDimensionKeyRangeHigh.set_value(value);
1022        }
1023    }
1024    
1025    void InstrumentProps::set_DimensionKeyRange_high(uint8_t value)
1026    {
1027        instrument->DimensionKeyRange.high = value;
1028        if (value < instrument->DimensionKeyRange.low) {
1029            eDimensionKeyRangeLow.set_value(value);
1030        }
1031  }  }
1032    
1033  InstrumentProps::InstrumentProps()  InstrumentProps::InstrumentProps()
# Line 752  InstrumentProps::InstrumentProps() Line 1044  InstrumentProps::InstrumentProps()
1044        ePitchbendRange("Pitchbend range", 0, 12),        ePitchbendRange("Pitchbend range", 0, 12),
1045        ePianoReleaseMode("Piano release mode"),        ePianoReleaseMode("Piano release mode"),
1046        eDimensionKeyRangeLow("Dimension key range low"),        eDimensionKeyRangeLow("Dimension key range low"),
1047        eDimensionKeyRangeHigh("Dimension key range high")        eDimensionKeyRangeHigh("Dimension key range high"),
1048          update_model(0)
1049  {  {
1050      set_title("Instrument properties");      set_title("Instrument Properties");
1051    
1052        connect(eIsDrum, &InstrumentProps::set_IsDrum);
1053        connect(eMIDIBank, &InstrumentProps::set_MIDIBank);
1054        connect(eMIDIProgram, &InstrumentProps::set_MIDIProgram);
1055        connect(eAttenuation, &gig::Instrument::Attenuation);
1056        connect(eGainPlus6, &gig::Instrument::Attenuation);
1057        connect(eEffectSend, &gig::Instrument::EffectSend);
1058        connect(eFineTune, &gig::Instrument::FineTune);
1059        connect(ePitchbendRange, &gig::Instrument::PitchbendRange);
1060        connect(ePianoReleaseMode, &gig::Instrument::PianoReleaseMode);
1061        connect(eDimensionKeyRangeLow,
1062                &InstrumentProps::set_DimensionKeyRange_low);
1063        connect(eDimensionKeyRangeHigh,
1064                &InstrumentProps::set_DimensionKeyRange_high);
1065    
     rowno = 0;  
1066      table.set_col_spacings(5);      table.set_col_spacings(5);
1067    
1068      add_prop(eName);      table.add(eName);
1069      add_prop(eIsDrum);      table.add(eIsDrum);
1070      add_prop(eMIDIBank);      table.add(eMIDIBank);
1071      add_prop(eMIDIProgram);      table.add(eMIDIProgram);
1072      add_prop(eAttenuation);      table.add(eAttenuation);
1073      add_prop(eGainPlus6);      table.add(eGainPlus6);
1074      add_prop(eEffectSend);      table.add(eEffectSend);
1075      add_prop(eFineTune);      table.add(eFineTune);
1076      add_prop(ePitchbendRange);      table.add(ePitchbendRange);
1077      add_prop(ePianoReleaseMode);      table.add(ePianoReleaseMode);
1078      add_prop(eDimensionKeyRangeLow);      table.add(eDimensionKeyRangeLow);
1079      add_prop(eDimensionKeyRangeHigh);      table.add(eDimensionKeyRangeHigh);
   
     eDimensionKeyRangeLow.signal_changed_by_user().connect(  
         sigc::mem_fun(*this, &InstrumentProps::key_range_low_changed));  
     eDimensionKeyRangeHigh.signal_changed_by_user().connect(  
         sigc::mem_fun(*this, &InstrumentProps::key_range_high_changed));  
1080    
1081      add(vbox);      add(vbox);
1082      table.set_border_width(5);      table.set_border_width(5);
# Line 799  InstrumentProps::InstrumentProps() Line 1100  InstrumentProps::InstrumentProps()
1100    
1101  void InstrumentProps::set_instrument(gig::Instrument* instrument)  void InstrumentProps::set_instrument(gig::Instrument* instrument)
1102  {  {
1103      eName.set_ptr(&instrument->pInfo->Name);      this->instrument = instrument;
     eIsDrum.set_ptr(&instrument->IsDrum);  
     eMIDIBank.set_ptr(&instrument->MIDIBank);  
     eMIDIProgram.set_ptr(&instrument->MIDIProgram);  
     eAttenuation.set_ptr(&instrument->Attenuation);  
     eGainPlus6.set_ptr(&instrument->Attenuation);  
     eEffectSend.set_ptr(&instrument->EffectSend);  
     eFineTune.set_ptr(&instrument->FineTune);  
     ePitchbendRange.set_ptr(&instrument->PitchbendRange);  
     ePianoReleaseMode.set_ptr(&instrument->PianoReleaseMode);  
     eDimensionKeyRangeLow.set_ptr(0);  
     eDimensionKeyRangeHigh.set_ptr(0);  
     eDimensionKeyRangeLow.set_ptr(&instrument->DimensionKeyRange.low);  
     eDimensionKeyRangeHigh.set_ptr(&instrument->DimensionKeyRange.high);  
 }  
1104    
1105  void InstrumentProps::key_range_low_changed()      update_model++;
1106  {      eName.set_value(instrument->pInfo->Name);
1107      double l = eDimensionKeyRangeLow.get_value();      eIsDrum.set_value(instrument->IsDrum);
1108      double h = eDimensionKeyRangeHigh.get_value();      eMIDIBank.set_value(instrument->MIDIBank);
1109      if (h < l) eDimensionKeyRangeHigh.set_value(l);      eMIDIProgram.set_value(instrument->MIDIProgram);
1110  }      eAttenuation.set_value(instrument->Attenuation);
1111        eGainPlus6.set_value(instrument->Attenuation);
1112  void InstrumentProps::key_range_high_changed()      eEffectSend.set_value(instrument->EffectSend);
1113  {      eFineTune.set_value(instrument->FineTune);
1114      double l = eDimensionKeyRangeLow.get_value();      ePitchbendRange.set_value(instrument->PitchbendRange);
1115      double h = eDimensionKeyRangeHigh.get_value();      ePianoReleaseMode.set_value(instrument->PianoReleaseMode);
1116      if (h < l) eDimensionKeyRangeLow.set_value(h);      eDimensionKeyRangeLow.set_value(instrument->DimensionKeyRange.low);
1117        eDimensionKeyRangeHigh.set_value(instrument->DimensionKeyRange.high);
1118        update_model--;
1119  }  }
1120    
1121  sigc::signal<void> InstrumentProps::signal_instrument_changed()  sigc::signal<void>& InstrumentProps::signal_instrument_changed()
1122  {  {
1123      return instrument_changed;      return instrument_changed;
1124  }  }
# Line 842  void MainWindow::file_changed() Line 1131  void MainWindow::file_changed()
1131      }      }
1132  }  }
1133    
1134  void MainWindow::load_gig(gig::File* gig, const char* filename)  void MainWindow::load_gig(gig::File* gig, const char* filename, bool isSharedInstrument)
1135  {  {
1136      file = 0;      file = 0;
1137        set_file_is_shared(isSharedInstrument);
1138    
1139      this->filename = filename ? filename : _("Unsaved Gig File");      this->filename = filename ? filename : _("Unsaved Gig File");
1140      set_title(Glib::filename_display_basename(this->filename));      set_title(Glib::filename_display_basename(this->filename));
# Line 907  void MainWindow::load_gig(gig::File* gig Line 1197  void MainWindow::load_gig(gig::File* gig
1197    
1198  void MainWindow::show_instr_props()  void MainWindow::show_instr_props()
1199  {  {
1200      Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();      gig::Instrument* instrument = get_instrument();
1201      Gtk::TreeModel::iterator it = tree_sel_ref->get_selected();      if (instrument)
     if (it)  
1202      {      {
1203          Gtk::TreeModel::Row row = *it;          instrumentProps.set_instrument(instrument);
1204          if (row[m_Columns.m_col_instr])          instrumentProps.show();
1205          {          instrumentProps.deiconify();
1206              instrumentProps.set_instrument(row[m_Columns.m_col_instr]);      }
1207              instrumentProps.show();  }
1208              instrumentProps.deiconify();  
1209          }  void MainWindow::on_action_view_status_bar() {
1210        Gtk::CheckMenuItem* item =
1211            dynamic_cast<Gtk::CheckMenuItem*>(uiManager->get_widget("/MenuBar/MenuView/Statusbar"));
1212        if (!item) {
1213            std::cerr << "/MenuBar/MenuView/Statusbar == NULL\n";
1214            return;
1215      }      }
1216        if (item->get_active()) m_StatusBar.show();
1217        else                    m_StatusBar.hide();
1218  }  }
1219    
1220  void MainWindow::on_button_release(GdkEventButton* button)  void MainWindow::on_button_release(GdkEventButton* button)
# Line 978  void MainWindow::on_action_add_instrumen Line 1274  void MainWindow::on_action_add_instrumen
1274    
1275  void MainWindow::on_action_remove_instrument() {  void MainWindow::on_action_remove_instrument() {
1276      if (!file) return;      if (!file) return;
1277        if (file_is_shared) {
1278            Gtk::MessageDialog msg(
1279                *this,
1280                 _("You cannot delete an instrument from this file, since it's "
1281                   "currently used by the sampler."),
1282                 false, Gtk::MESSAGE_INFO
1283            );
1284            msg.run();
1285            return;
1286        }
1287    
1288      Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeView.get_selection();      Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeView.get_selection();
1289      Gtk::TreeModel::iterator it = sel->get_selected();      Gtk::TreeModel::iterator it = sel->get_selected();
1290      if (it) {      if (it) {
# Line 1073  void MainWindow::on_action_add_sample() Line 1380  void MainWindow::on_action_add_sample()
1380                  int bitdepth;                  int bitdepth;
1381                  switch (info.format & 0xff) {                  switch (info.format & 0xff) {
1382                      case SF_FORMAT_PCM_S8:                      case SF_FORMAT_PCM_S8:
                         bitdepth = 16; // we simply convert to 16 bit for now  
                         break;  
1383                      case SF_FORMAT_PCM_16:                      case SF_FORMAT_PCM_16:
1384                        case SF_FORMAT_PCM_U8:
1385                          bitdepth = 16;                          bitdepth = 16;
1386                          break;                          break;
1387                      case SF_FORMAT_PCM_24:                      case SF_FORMAT_PCM_24:
                         bitdepth = 32; // we simply convert to 32 bit for now  
                         break;  
1388                      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;  
1389                      case SF_FORMAT_FLOAT:                      case SF_FORMAT_FLOAT:
                         bitdepth = 32;  
                         break;  
1390                      case SF_FORMAT_DOUBLE:                      case SF_FORMAT_DOUBLE:
1391                          bitdepth = 32; // I guess we will always truncate this to 32 bit                          bitdepth = 24;
1392                          break;                          break;
1393                      default:                      default:
1394                          sf_close(hFile); // close sound file                          sf_close(hFile); // close sound file
# Line 1113  void MainWindow::on_action_add_sample() Line 1410  void MainWindow::on_action_add_sample()
1410                  sample->BitDepth = bitdepth;                  sample->BitDepth = bitdepth;
1411                  sample->FrameSize = bitdepth / 8/*1 byte are 8 bits*/ * info.channels;                  sample->FrameSize = bitdepth / 8/*1 byte are 8 bits*/ * info.channels;
1412                  sample->SamplesPerSecond = info.samplerate;                  sample->SamplesPerSecond = info.samplerate;
1413                    sample->AverageBytesPerSecond = sample->FrameSize * sample->SamplesPerSecond;
1414                    sample->BlockAlign = sample->FrameSize;
1415                    sample->SamplesTotal = info.frames;
1416    
1417                    SF_INSTRUMENT instrument;
1418                    if (sf_command(hFile, SFC_GET_INSTRUMENT,
1419                                   &instrument, sizeof(instrument)) != SF_FALSE)
1420                    {
1421                        sample->MIDIUnityNote = instrument.basenote;
1422    
1423    #if HAVE_SF_INSTRUMENT_LOOPS
1424                        if (instrument.loop_count && instrument.loops[0].mode != SF_LOOP_NONE) {
1425                            sample->Loops = 1;
1426    
1427                            switch (instrument.loops[0].mode) {
1428                            case SF_LOOP_FORWARD:
1429                                sample->LoopType = gig::loop_type_normal;
1430                                break;
1431                            case SF_LOOP_BACKWARD:
1432                                sample->LoopType = gig::loop_type_backward;
1433                                break;
1434                            case SF_LOOP_ALTERNATING:
1435                                sample->LoopType = gig::loop_type_bidirectional;
1436                                break;
1437                            }
1438                            sample->LoopStart = instrument.loops[0].start;
1439                            sample->LoopEnd = instrument.loops[0].end;
1440                            sample->LoopPlayCount = instrument.loops[0].count;
1441                            sample->LoopSize = sample->LoopEnd - sample->LoopStart + 1;
1442                        }
1443    #endif
1444                    }
1445    
1446                  // schedule resizing the sample (which will be done                  // schedule resizing the sample (which will be done
1447                  // physically when File::Save() is called)                  // physically when File::Save() is called)
1448                  sample->Resize(info.frames);                  sample->Resize(info.frames);
# Line 1141  void MainWindow::on_action_add_sample() Line 1471  void MainWindow::on_action_add_sample()
1471          }          }
1472          // 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
1473          if (error_files.size()) {          if (error_files.size()) {
1474              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;
1475              Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);              Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
1476              msg.run();              msg.run();
1477          }          }
# Line 1167  void MainWindow::on_action_remove_sample Line 1497  void MainWindow::on_action_remove_sample
1497                       pSample; pSample = group->GetNextSample()) {                       pSample; pSample = group->GetNextSample()) {
1498                      members.push_back(pSample);                      members.push_back(pSample);
1499                  }                  }
1500                    // notify everybody that we're going to remove these samples
1501                    samples_to_be_removed_signal.emit(members);
1502                  // delete the group in the .gig file including the                  // delete the group in the .gig file including the
1503                  // samples that belong to the group                  // samples that belong to the group
1504                  file->DeleteGroup(group);                  file->DeleteGroup(group);
1505                    // notify that we're done with removal
1506                    samples_removed_signal.emit();
1507                  // if sample(s) were just previously added, remove                  // if sample(s) were just previously added, remove
1508                  // them from the import queue                  // them from the import queue
1509                  for (std::list<gig::Sample*>::iterator member = members.begin();                  for (std::list<gig::Sample*>::iterator member = members.begin();
# Line 1186  void MainWindow::on_action_remove_sample Line 1520  void MainWindow::on_action_remove_sample
1520                  }                  }
1521                  file_changed();                  file_changed();
1522              } else if (sample) {              } else if (sample) {
1523                    // notify everybody that we're going to remove this sample
1524                    std::list<gig::Sample*> lsamples;
1525                    lsamples.push_back(sample);
1526                    samples_to_be_removed_signal.emit(lsamples);
1527                  // remove sample from the .gig file                  // remove sample from the .gig file
1528                  file->DeleteSample(sample);                  file->DeleteSample(sample);
1529                    // notify that we're done with removal
1530                    samples_removed_signal.emit();
1531                  // if sample was just previously added, remove it from                  // if sample was just previously added, remove it from
1532                  // the import queue                  // the import queue
1533                  for (std::list<SampleImportItem>::iterator iter = m_SampleImportQueue.begin();                  for (std::list<SampleImportItem>::iterator iter = m_SampleImportQueue.begin();
# Line 1199  void MainWindow::on_action_remove_sample Line 1539  void MainWindow::on_action_remove_sample
1539                          break;                          break;
1540                      }                      }
1541                  }                  }
1542                    dimreg_changed();
1543                  file_changed();                  file_changed();
1544              }              }
1545              // remove respective row(s) from samples tree view              // remove respective row(s) from samples tree view
1546              m_refSamplesTreeModel->erase(it);              m_refSamplesTreeModel->erase(it);
1547          } catch (RIFF::Exception e) {          } catch (RIFF::Exception e) {
1548                // pretend we're done with removal (i.e. to avoid dead locks)
1549                samples_removed_signal.emit();
1550                // show error message
1551              Gtk::MessageDialog msg(*this, e.Message.c_str(), false, Gtk::MESSAGE_ERROR);              Gtk::MessageDialog msg(*this, e.Message.c_str(), false, Gtk::MESSAGE_ERROR);
1552              msg.run();              msg.run();
1553          }          }
1554      }      }
1555  }  }
1556    
1557    // For some reason drag_data_get gets called two times for each
1558    // drag'n'drop (at least when target is an Entry). This work-around
1559    // makes sure the code in drag_data_get and drop_drag_data_received is
1560    // only executed once, as drag_begin only gets called once.
1561    void MainWindow::on_sample_treeview_drag_begin(const Glib::RefPtr<Gdk::DragContext>& context)
1562    {
1563        first_call_to_drag_data_get = true;
1564    }
1565    
1566  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>&,
1567                                                    Gtk::SelectionData& selection_data, guint, guint)                                                    Gtk::SelectionData& selection_data, guint, guint)
1568  {  {
1569        if (!first_call_to_drag_data_get) return;
1570        first_call_to_drag_data_get = false;
1571    
1572      // get selected sample      // get selected sample
1573      gig::Sample* sample = NULL;      gig::Sample* sample = NULL;
1574      Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();      Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();
# Line 1230  void MainWindow::on_sample_label_drop_dr Line 1586  void MainWindow::on_sample_label_drop_dr
1586      const Glib::RefPtr<Gdk::DragContext>& context, int, int,      const Glib::RefPtr<Gdk::DragContext>& context, int, int,
1587      const Gtk::SelectionData& selection_data, guint, guint time)      const Gtk::SelectionData& selection_data, guint, guint time)
1588  {  {
     gig::DimensionRegion* dimregion = m_DimRegionChooser.get_dimregion();  
1589      gig::Sample* sample = *((gig::Sample**) selection_data.get_data());      gig::Sample* sample = *((gig::Sample**) selection_data.get_data());
1590    
1591      if (sample && dimregion && selection_data.get_length() == sizeof(gig::Sample*)) {      if (sample && selection_data.get_length() == sizeof(gig::Sample*)) {
1592          if (sample != dimregion->pSample) {          std::cout << "Drop received sample \"" <<
1593              dimregion->pSample = sample;              sample->pInfo->Name << "\"" << std::endl;
1594              dimreg_edit.wSample->set_text(dimregion->pSample->pInfo->Name.c_str());          // drop success
1595              std::cout << "Drop received sample \"" <<          context->drop_reply(true, time);
1596                  dimregion->pSample->pInfo->Name.c_str() << "\"" << std::endl;  
1597              // drop success          //TODO: we should better move most of the following code to DimRegionEdit::set_sample()
1598              context->drop_reply(true, time);  
1599              file_changed();          // notify everybody that we're going to alter the region
1600              return;          gig::Region* region = m_RegionChooser.get_region();
1601            region_to_be_changed_signal.emit(region);
1602    
1603            // find the samplechannel dimension
1604            gig::dimension_def_t* stereo_dimension = 0;
1605            for (int i = 0 ; i < region->Dimensions ; i++) {
1606                if (region->pDimensionDefinitions[i].dimension ==
1607                    gig::dimension_samplechannel) {
1608                    stereo_dimension = &region->pDimensionDefinitions[i];
1609                    break;
1610                }
1611            }
1612            bool channels_changed = false;
1613            if (sample->Channels == 1 && stereo_dimension) {
1614                // remove the samplechannel dimension
1615                region->DeleteDimension(stereo_dimension);
1616                channels_changed = true;
1617                region_changed();
1618          }          }
1619            dimreg_edit.set_sample(sample);
1620    
1621            if (sample->Channels == 2 && !stereo_dimension) {
1622                // add samplechannel dimension
1623                gig::dimension_def_t dim;
1624                dim.dimension = gig::dimension_samplechannel;
1625                dim.bits = 1;
1626                dim.zones = 2;
1627                region->AddDimension(&dim);
1628                channels_changed = true;
1629                region_changed();
1630            }
1631            if (channels_changed) {
1632                // unmap all samples with wrong number of channels
1633                // TODO: maybe there should be a warning dialog for this
1634                for (int i = 0 ; i < region->DimensionRegions ; i++) {
1635                    gig::DimensionRegion* d = region->pDimensionRegions[i];
1636                    if (d->pSample && d->pSample->Channels != sample->Channels) {
1637                        gig::Sample* oldref = d->pSample;
1638                        d->pSample = NULL;
1639                        sample_ref_changed_signal.emit(oldref, NULL);
1640                    }
1641                }
1642            }
1643    
1644            // notify we're done with altering
1645            region_changed_signal.emit(region);
1646    
1647            file_changed();
1648    
1649            return;
1650      }      }
1651      // drop failed      // drop failed
1652      context->drop_reply(false, time);      context->drop_reply(false, time);
# Line 1282  void MainWindow::instrument_name_changed Line 1685  void MainWindow::instrument_name_changed
1685          file_changed();          file_changed();
1686      }      }
1687  }  }
1688    
1689    void MainWindow::set_file_is_shared(bool b) {
1690        this->file_is_shared = b;
1691    
1692        if (file_is_shared) {
1693            m_AttachedStateLabel.set_label(_("live-mode"));
1694            m_AttachedStateImage.set(
1695                Gdk::Pixbuf::create_from_xpm_data(status_attached_xpm)
1696            );
1697        } else {
1698            m_AttachedStateLabel.set_label(_("stand-alone"));
1699            m_AttachedStateImage.set(
1700                Gdk::Pixbuf::create_from_xpm_data(status_detached_xpm)
1701            );
1702        }
1703    }
1704    
1705    sigc::signal<void, gig::File*>& MainWindow::signal_file_structure_to_be_changed() {
1706        return file_structure_to_be_changed_signal;
1707    }
1708    
1709    sigc::signal<void, gig::File*>& MainWindow::signal_file_structure_changed() {
1710        return file_structure_changed_signal;
1711    }
1712    
1713    sigc::signal<void, std::list<gig::Sample*> >& MainWindow::signal_samples_to_be_removed() {
1714        return samples_to_be_removed_signal;
1715    }
1716    
1717    sigc::signal<void>& MainWindow::signal_samples_removed() {
1718        return samples_removed_signal;
1719    }
1720    
1721    sigc::signal<void, gig::Region*>& MainWindow::signal_region_to_be_changed() {
1722        return region_to_be_changed_signal;
1723    }
1724    
1725    sigc::signal<void, gig::Region*>& MainWindow::signal_region_changed() {
1726        return region_changed_signal;
1727    }
1728    
1729    sigc::signal<void, gig::Sample*/*old*/, gig::Sample*/*new*/>& MainWindow::signal_sample_ref_changed() {
1730        return sample_ref_changed_signal;
1731    }
1732    
1733    sigc::signal<void, gig::DimensionRegion*>& MainWindow::signal_dimreg_to_be_changed() {
1734        return dimreg_to_be_changed_signal;
1735    }
1736    
1737    sigc::signal<void, gig::DimensionRegion*>& MainWindow::signal_dimreg_changed() {
1738        return dimreg_changed_signal;
1739    }

Legend:
Removed from v.1262  
changed lines
  Added in v.1582

  ViewVC Help
Powered by ViewVC