/[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 1533 by persson, Sat Dec 1 10:21:07 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  #if GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION >= 6  #include "global.h"
30    
31    #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()  MainWindow::MainWindow() :
63        dimreg_label(_("Changes apply to:")),
64        dimreg_all_regions(_("all regions")),
65        dimreg_all_dimregs(_("all dimension splits")),
66        dimreg_stereo(_("both channels"))
67  {  {
68  //    set_border_width(5);  //    set_border_width(5);
69  //    set_default_size(400, 200);  //    set_default_size(400, 200);
# Line 74  MainWindow::MainWindow() Line 93  MainWindow::MainWindow()
93      m_TreeViewNotebook.set_size_request(300);      m_TreeViewNotebook.set_size_request(300);
94    
95      m_HPaned.add1(m_TreeViewNotebook);      m_HPaned.add1(m_TreeViewNotebook);
96      m_HPaned.add2(dimreg_edit);      dimreg_hbox.add(dimreg_label);
97        dimreg_hbox.add(dimreg_all_regions);
98        dimreg_hbox.add(dimreg_all_dimregs);
99        dimreg_stereo.set_active();
100        dimreg_hbox.add(dimreg_stereo);
101        dimreg_vbox.add(dimreg_edit);
102        dimreg_vbox.add(dimreg_hbox);
103        m_HPaned.add2(dimreg_vbox);
104    
105    
106      m_TreeViewNotebook.append_page(m_ScrolledWindowSamples, "Samples");      m_TreeViewNotebook.append_page(m_ScrolledWindowSamples, "Samples");
# Line 99  MainWindow::MainWindow() Line 125  MainWindow::MainWindow()
125      action = Gtk::Action::create("SaveAs", Gtk::Stock::SAVE_AS);      action = Gtk::Action::create("SaveAs", Gtk::Stock::SAVE_AS);
126      action->property_label() = action->property_label() + "...";      action->property_label() = action->property_label() + "...";
127      actionGroup->add(action,      actionGroup->add(action,
128                       *(new Gtk::AccelKey("<shift><control>s")),                       Gtk::AccelKey("<shift><control>s"),
129                       sigc::mem_fun(                       sigc::mem_fun(
130                           *this, &MainWindow::on_action_file_save_as)                           *this, &MainWindow::on_action_file_save_as));
         );  
131      actionGroup->add(Gtk::Action::create("Properties",      actionGroup->add(Gtk::Action::create("Properties",
132                                           Gtk::Stock::PROPERTIES),                                           Gtk::Stock::PROPERTIES),
133                       sigc::mem_fun(                       sigc::mem_fun(
# Line 113  MainWindow::MainWindow() Line 138  MainWindow::MainWindow()
138                           *this, &MainWindow::show_instr_props));                           *this, &MainWindow::show_instr_props));
139      actionGroup->add(Gtk::Action::create("Quit", Gtk::Stock::QUIT),      actionGroup->add(Gtk::Action::create("Quit", Gtk::Stock::QUIT),
140                       sigc::mem_fun(                       sigc::mem_fun(
141                           *this, &MainWindow::hide));                           *this, &MainWindow::on_action_quit));
142      actionGroup->add(Gtk::Action::create("MenuInstrument", _("_Instrument")));      actionGroup->add(Gtk::Action::create("MenuInstrument", _("_Instrument")));
143    
144        actionGroup->add(Gtk::Action::create("MenuView", _("_View")));
145        Glib::RefPtr<Gtk::ToggleAction> toggle_action =
146            Gtk::ToggleAction::create("Statusbar", _("_Statusbar"));
147        toggle_action->set_active(true);
148        actionGroup->add(toggle_action,
149                         sigc::mem_fun(
150                             *this, &MainWindow::on_action_view_status_bar));
151    
152      action = Gtk::Action::create("MenuHelp", Gtk::Stock::HELP);      action = Gtk::Action::create("MenuHelp", Gtk::Stock::HELP);
153      actionGroup->add(Gtk::Action::create("MenuHelp",      actionGroup->add(Gtk::Action::create("MenuHelp",
154                                           action->property_label()));                                           action->property_label()));
# Line 153  MainWindow::MainWindow() Line 186  MainWindow::MainWindow()
186    
187      uiManager = Gtk::UIManager::create();      uiManager = Gtk::UIManager::create();
188      uiManager->insert_action_group(actionGroup);      uiManager->insert_action_group(actionGroup);
189      // add_accel_group(uiManager->get_accel_group());      add_accel_group(uiManager->get_accel_group());
190    
191      Glib::ustring ui_info =      Glib::ustring ui_info =
192          "<ui>"          "<ui>"
# Line 171  MainWindow::MainWindow() Line 204  MainWindow::MainWindow()
204          "    </menu>"          "    </menu>"
205          "    <menu action='MenuInstrument'>"          "    <menu action='MenuInstrument'>"
206          "    </menu>"          "    </menu>"
207            "    <menu action='MenuView'>"
208            "      <menuitem action='Statusbar'/>"
209            "    </menu>"
210  #ifdef ABOUT_DIALOG  #ifdef ABOUT_DIALOG
211          "    <menu action='MenuHelp'>"          "    <menu action='MenuHelp'>"
212          "      <menuitem action='About'/>"          "      <menuitem action='About'/>"
# Line 200  MainWindow::MainWindow() Line 236  MainWindow::MainWindow()
236      m_VBox.pack_start(m_HPaned);      m_VBox.pack_start(m_HPaned);
237      m_VBox.pack_start(m_RegionChooser, Gtk::PACK_SHRINK);      m_VBox.pack_start(m_RegionChooser, Gtk::PACK_SHRINK);
238      m_VBox.pack_start(m_DimRegionChooser, Gtk::PACK_SHRINK);      m_VBox.pack_start(m_DimRegionChooser, Gtk::PACK_SHRINK);
239        m_VBox.pack_start(m_StatusBar, Gtk::PACK_SHRINK);
240    
241      m_RegionChooser.signal_sel_changed().connect(      // Status Bar:
242        m_StatusBar.pack_start(m_AttachedStateLabel, Gtk::PACK_SHRINK);
243        m_StatusBar.pack_start(m_AttachedStateImage, Gtk::PACK_SHRINK);
244        m_StatusBar.show();
245    
246        m_RegionChooser.signal_region_selected().connect(
247          sigc::mem_fun(*this, &MainWindow::region_changed) );          sigc::mem_fun(*this, &MainWindow::region_changed) );
248      m_DimRegionChooser.signal_sel_changed().connect(      m_DimRegionChooser.signal_dimregion_selected().connect(
249          sigc::mem_fun(*this, &MainWindow::dimreg_changed) );          sigc::mem_fun(*this, &MainWindow::dimreg_changed) );
250    
251    
# Line 235  MainWindow::MainWindow() Line 277  MainWindow::MainWindow()
277      std::list<Gtk::TargetEntry> drag_target_gig_sample;      std::list<Gtk::TargetEntry> drag_target_gig_sample;
278      drag_target_gig_sample.push_back( Gtk::TargetEntry("gig::Sample") );      drag_target_gig_sample.push_back( Gtk::TargetEntry("gig::Sample") );
279      m_TreeViewSamples.drag_source_set(drag_target_gig_sample);      m_TreeViewSamples.drag_source_set(drag_target_gig_sample);
280        m_TreeViewSamples.signal_drag_begin().connect(
281            sigc::mem_fun(*this, &MainWindow::on_sample_treeview_drag_begin)
282        );
283      m_TreeViewSamples.signal_drag_data_get().connect(      m_TreeViewSamples.signal_drag_data_get().connect(
284          sigc::mem_fun(*this, &MainWindow::on_sample_treeview_drag_data_get)          sigc::mem_fun(*this, &MainWindow::on_sample_treeview_drag_data_get)
285      );      );
# Line 242  MainWindow::MainWindow() Line 287  MainWindow::MainWindow()
287      dimreg_edit.wSample->signal_drag_data_received().connect(      dimreg_edit.wSample->signal_drag_data_received().connect(
288          sigc::mem_fun(*this, &MainWindow::on_sample_label_drop_drag_data_received)          sigc::mem_fun(*this, &MainWindow::on_sample_label_drop_drag_data_received)
289      );      );
290        dimreg_edit.signal_dimreg_changed().connect(
291            sigc::hide(sigc::mem_fun(*this, &MainWindow::file_changed)));
292        m_RegionChooser.signal_instrument_changed().connect(
293            sigc::mem_fun(*this, &MainWindow::file_changed));
294        m_DimRegionChooser.signal_region_changed().connect(
295            sigc::mem_fun(*this, &MainWindow::file_changed));
296        instrumentProps.signal_instrument_changed().connect(
297            sigc::mem_fun(*this, &MainWindow::file_changed));
298    
299        dimreg_edit.signal_dimreg_to_be_changed().connect(
300            dimreg_to_be_changed_signal.make_slot());
301        dimreg_edit.signal_dimreg_changed().connect(
302            dimreg_changed_signal.make_slot());
303        dimreg_edit.signal_sample_ref_changed().connect(
304            sample_ref_changed_signal.make_slot());
305    
306        m_RegionChooser.signal_instrument_struct_to_be_changed().connect(
307            sigc::hide(
308                sigc::bind(
309                    file_structure_to_be_changed_signal.make_slot(),
310                    sigc::ref(this->file)
311                )
312            )
313        );
314        m_RegionChooser.signal_instrument_struct_changed().connect(
315            sigc::hide(
316                sigc::bind(
317                    file_structure_changed_signal.make_slot(),
318                    sigc::ref(this->file)
319                )
320            )
321        );
322        m_RegionChooser.signal_region_to_be_changed().connect(
323            region_to_be_changed_signal.make_slot());
324        m_RegionChooser.signal_region_changed_signal().connect(
325            region_changed_signal.make_slot());
326    
327        dimreg_all_regions.signal_toggled().connect(
328            sigc::mem_fun(*this, &MainWindow::update_dimregs));
329        dimreg_all_dimregs.signal_toggled().connect(
330            sigc::mem_fun(*this, &MainWindow::dimreg_all_dimregs_toggled));
331        dimreg_stereo.signal_toggled().connect(
332            sigc::mem_fun(*this, &MainWindow::update_dimregs));
333    
334      file = 0;      file = 0;
335        file_is_changed = false;
336        set_file_is_shared(false);
337    
338      show_all_children();      show_all_children();
339    
340        // start with a new gig file by default
341        on_action_file_new();
342  }  }
343    
344  MainWindow::~MainWindow()  MainWindow::~MainWindow()
345  {  {
346  }  }
347    
348  void MainWindow::region_changed()  bool MainWindow::on_delete_event(GdkEventAny* event)
349  {  {
350      m_DimRegionChooser.set_region(m_RegionChooser.get_region());      return !file_is_shared && file_is_changed && !close_confirmation_dialog();
351  }  }
352    
353  void MainWindow::dimreg_changed()  void MainWindow::on_action_quit()
354  {  {
355      dimreg_edit.set_dim_region(m_DimRegionChooser.get_dimregion());      if (!file_is_shared && file_is_changed && !close_confirmation_dialog()) return;
356        hide();
357  }  }
358    
359  void MainWindow::on_sel_change()  void MainWindow::region_changed()
360    {
361        m_DimRegionChooser.set_region(m_RegionChooser.get_region());
362    }
363    
364    gig::Instrument* MainWindow::get_instrument()
365  {  {
366        gig::Instrument* instrument = 0;
367      Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();      Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();
368    
369      Gtk::TreeModel::iterator it = tree_sel_ref->get_selected();      Gtk::TreeModel::iterator it = tree_sel_ref->get_selected();
370      if (it) {      if (it) {
371          Gtk::TreeModel::Row row = *it;          Gtk::TreeModel::Row row = *it;
372          std::cout << row[m_Columns.m_col_name] << std::endl;          instrument = row[m_Columns.m_col_instr];
373        }
374        return instrument;
375    }
376    
377    void MainWindow::add_region_to_dimregs(gig::Region* region, bool stereo, bool all_dimregs)
378    {
379        if (all_dimregs) {
380            for (int i = 0 ; i < region->DimensionRegions ; i++) {
381                if (region->pDimensionRegions[i]) {
382                    dimreg_edit.dimregs.insert(region->pDimensionRegions[i]);
383                }
384            }
385        } else {
386            m_DimRegionChooser.get_dimregions(region, stereo, dimreg_edit.dimregs);
387        }
388    }
389    
390          m_RegionChooser.set_instrument(row[m_Columns.m_col_instr]);  void MainWindow::update_dimregs()
391    {
392        dimreg_edit.dimregs.clear();
393        bool all_regions = dimreg_all_regions.get_active();
394        bool stereo = dimreg_stereo.get_active();
395        bool all_dimregs = dimreg_all_dimregs.get_active();
396    
397        if (all_regions) {
398            gig::Instrument* instrument = get_instrument();
399            if (instrument) {
400                for (gig::Region* region = instrument->GetFirstRegion() ;
401                     region ;
402                     region = instrument->GetNextRegion()) {
403                    add_region_to_dimregs(region, stereo, all_dimregs);
404                }
405            }
406      } else {      } else {
407          m_RegionChooser.set_instrument(0);          gig::Region* region = m_RegionChooser.get_region();
408            if (region) {
409                add_region_to_dimregs(region, stereo, all_dimregs);
410            }
411      }      }
412  }  }
413    
414    void MainWindow::dimreg_all_dimregs_toggled()
415    {
416        dimreg_stereo.set_sensitive(!dimreg_all_dimregs.get_active());
417        update_dimregs();
418    }
419    
420    void MainWindow::dimreg_changed()
421    {
422        update_dimregs();
423        dimreg_edit.set_dim_region(m_DimRegionChooser.get_dimregion());
424    }
425    
426    void MainWindow::on_sel_change()
427    {
428        m_RegionChooser.set_instrument(get_instrument());
429    }
430    
431  void loader_progress_callback(gig::progress_t* progress)  void loader_progress_callback(gig::progress_t* progress)
432  {  {
433      Loader* loader = static_cast<Loader*>(progress->custom);      Loader* loader = static_cast<Loader*>(progress->custom);
# Line 362  void MainWindow::__clear() { Line 513  void MainWindow::__clear() {
513      m_refTreeModel->clear();      m_refTreeModel->clear();
514      m_refSamplesTreeModel->clear();      m_refSamplesTreeModel->clear();
515      // free libgig's gig::File instance      // free libgig's gig::File instance
516      if (file) {      if (file && !file_is_shared) delete file;
517          delete file;      file = NULL;
518          file = NULL;      set_file_is_shared(false);
     }  
519  }  }
520    
521  void MainWindow::on_action_file_new()  void MainWindow::on_action_file_new()
522  {  {
523        if (!file_is_shared && file_is_changed && !close_confirmation_dialog()) return;
524    
525        if (file_is_shared && !leaving_shared_mode_dialog()) return;
526    
527      // clear all GUI elements      // clear all GUI elements
528      __clear();      __clear();
529      // create a new .gig file (virtually yet)      // create a new .gig file (virtually yet)
# Line 378  void MainWindow::on_action_file_new() Line 532  void MainWindow::on_action_file_new()
532      gig::Instrument* pInstrument = pFile->AddInstrument();      gig::Instrument* pInstrument = pFile->AddInstrument();
533      pInstrument->pInfo->Name = "Unnamed Instrument";      pInstrument->pInfo->Name = "Unnamed Instrument";
534      // update GUI with that new gig::File      // update GUI with that new gig::File
535      load_gig(pFile, NULL /*no file name yet*/);      load_gig(pFile, 0 /*no file name yet*/);
536    }
537    
538    bool MainWindow::close_confirmation_dialog()
539    {
540        gchar* msg = g_strdup_printf(_("Save changes to \"%s\" before closing?"),
541                                     Glib::filename_display_basename(filename).c_str());
542        Gtk::MessageDialog dialog(*this, msg, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_NONE);
543        g_free(msg);
544    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION >= 6) || GTKMM_MAJOR_VERSION > 2
545        dialog.set_secondary_text(_("If you close without saving, your changes will be lost."));
546    #endif
547        dialog.add_button(_("Close _Without Saving"), Gtk::RESPONSE_NO);
548        dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
549        dialog.add_button(file_has_name ? Gtk::Stock::SAVE : Gtk::Stock::SAVE_AS, Gtk::RESPONSE_YES);
550        dialog.set_default_response(Gtk::RESPONSE_YES);
551        int response = dialog.run();
552        dialog.hide();
553        if (response == Gtk::RESPONSE_YES) return file_save();
554        return response != Gtk::RESPONSE_CANCEL;
555    }
556    
557    bool MainWindow::leaving_shared_mode_dialog() {
558        Glib::ustring msg = _("Detach from sampler and proceed working stand-alone?");
559        Gtk::MessageDialog dialog(*this, msg, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_NONE);
560    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION >= 6) || GTKMM_MAJOR_VERSION > 2
561        dialog.set_secondary_text(
562            _("If you proceed to work on another instrument file, it won't be "
563              "used by the sampler until you tell the sampler explicitly to "
564              "load it.")
565       );
566    #endif
567        dialog.add_button(_("_Yes, Detach"), Gtk::RESPONSE_YES);
568        dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
569        dialog.set_default_response(Gtk::RESPONSE_CANCEL);
570        int response = dialog.run();
571        dialog.hide();
572        return response == Gtk::RESPONSE_YES;
573  }  }
574    
575  void MainWindow::on_action_file_open()  void MainWindow::on_action_file_open()
576  {  {
577        if (!file_is_shared && file_is_changed && !close_confirmation_dialog()) return;
578    
579        if (file_is_shared && !leaving_shared_mode_dialog()) return;
580    
581      Gtk::FileChooserDialog dialog(*this, _("Open file"));      Gtk::FileChooserDialog dialog(*this, _("Open file"));
582      dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);      dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
583      dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);      dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);
584        dialog.set_default_response(Gtk::RESPONSE_OK);
585      Gtk::FileFilter filter;      Gtk::FileFilter filter;
586      filter.add_pattern("*.gig");      filter.add_pattern("*.gig");
587      dialog.set_filter(filter);      dialog.set_filter(filter);
588        if (current_dir != "") {
589            dialog.set_current_folder(current_dir);
590        }
591      if (dialog.run() == Gtk::RESPONSE_OK) {      if (dialog.run() == Gtk::RESPONSE_OK) {
592          printf("filename=%s\n", dialog.get_filename().c_str());          std::string filename = dialog.get_filename();
593          __clear();          printf("filename=%s\n", filename.c_str());
594          printf("on_action_file_open self=%x\n", Glib::Thread::self());          printf("on_action_file_open self=%x\n", Glib::Thread::self());
595          load_file(dialog.get_filename().c_str());          load_file(filename.c_str());
596            current_dir = Glib::path_get_dirname(filename);
597      }      }
598  }  }
599    
600  void MainWindow::load_file(const char* name)  void MainWindow::load_file(const char* name)
601  {  {
602        __clear();
603      load_dialog = new LoadDialog("Loading...", *this);      load_dialog = new LoadDialog("Loading...", *this);
604      load_dialog->show_all();      load_dialog->show_all();
605      loader = new Loader(strdup(name));      loader = new Loader(strdup(name));
# Line 416  void MainWindow::load_instrument(gig::In Line 617  void MainWindow::load_instrument(gig::In
617          msg.run();          msg.run();
618          Gtk::Main::quit();          Gtk::Main::quit();
619      }      }
620        // clear all GUI elements
621        __clear();
622        // load the instrument
623      gig::File* pFile = (gig::File*) instr->GetParent();      gig::File* pFile = (gig::File*) instr->GetParent();
624      load_gig(pFile, NULL /*file name*/);      load_gig(pFile, 0 /*file name*/, true /*shared instrument*/);
625      //TODO: automatically select the given instrument      //TODO: automatically select the given instrument
626  }  }
627    
# Line 436  void MainWindow::on_loader_finished() Line 640  void MainWindow::on_loader_finished()
640    
641  void MainWindow::on_action_file_save()  void MainWindow::on_action_file_save()
642  {  {
643      if (!file) return;      file_save();
644    }
645    
646    bool MainWindow::check_if_savable()
647    {
648        if (!file) return false;
649    
650        if (!file->GetFirstSample()) {
651            Gtk::MessageDialog(*this, _("The file could not be saved "
652                                        "because it contains no samples"),
653                               false, Gtk::MESSAGE_ERROR).run();
654            return false;
655        }
656    
657        for (gig::Instrument* instrument = file->GetFirstInstrument() ; instrument ;
658             instrument = file->GetNextInstrument()) {
659            if (!instrument->GetFirstRegion()) {
660                Gtk::MessageDialog(*this, _("The file could not be saved "
661                                            "because there are instruments "
662                                            "that have no regions"),
663                                   false, Gtk::MESSAGE_ERROR).run();
664                return false;
665            }
666        }
667        return true;
668    }
669    
670    bool MainWindow::file_save()
671    {
672        if (!check_if_savable()) return false;
673        if (!file_is_shared && !file_has_name) return file_save_as();
674    
675      std::cout << "Saving file\n" << std::flush;      std::cout << "Saving file\n" << std::flush;
676        file_structure_to_be_changed_signal.emit(this->file);
677      try {      try {
678          file->Save();          file->Save();
679            if (file_is_changed) {
680                set_title(get_title().substr(1));
681                file_is_changed = false;
682            }
683      } catch (RIFF::Exception e) {      } catch (RIFF::Exception e) {
684          Glib::ustring txt = "Could not save file: " + e.Message;          file_structure_changed_signal.emit(this->file);
685            Glib::ustring txt = _("Could not save file: ") + e.Message;
686          Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);          Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
687          msg.run();          msg.run();
688          return;          return false;
689      }      }
690      std::cout << "Saving file done\n" << std::flush;      std::cout << "Saving file done\n" << std::flush;
691      __import_queued_samples();      __import_queued_samples();
692        file_structure_changed_signal.emit(this->file);
693        return true;
694  }  }
695    
696  void MainWindow::on_action_file_save_as()  void MainWindow::on_action_file_save_as()
697  {  {
698      if (!file) return;      if (!check_if_savable()) return;
699      Gtk::FileChooserDialog dialog(*this, "Open", Gtk::FILE_CHOOSER_ACTION_SAVE);      file_save_as();
700    }
701    
702    bool MainWindow::file_save_as()
703    {
704        Gtk::FileChooserDialog dialog(*this, _("Save as"), Gtk::FILE_CHOOSER_ACTION_SAVE);
705      dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);      dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
706      dialog.add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK);      dialog.add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK);
707        dialog.set_default_response(Gtk::RESPONSE_OK);
708    
709    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION >= 8) || GTKMM_MAJOR_VERSION > 2
710        dialog.set_do_overwrite_confirmation();
711        // TODO: an overwrite dialog for gtkmm < 2.8
712    #endif
713      Gtk::FileFilter filter;      Gtk::FileFilter filter;
714      filter.add_pattern("*.gig");      filter.add_pattern("*.gig");
715      dialog.set_filter(filter);      dialog.set_filter(filter);
716    
717        if (Glib::path_is_absolute(filename)) {
718            dialog.set_filename(filename);
719        } else if (current_dir != "") {
720            dialog.set_current_folder(current_dir);
721        }
722        dialog.set_current_name(Glib::filename_display_basename(filename));
723    
724      if (dialog.run() == Gtk::RESPONSE_OK) {      if (dialog.run() == Gtk::RESPONSE_OK) {
725          printf("filename=%s\n", dialog.get_filename().c_str());          file_structure_to_be_changed_signal.emit(this->file);
726          try {          try {
727              file->Save(dialog.get_filename());              std::string filename = dialog.get_filename();
728                if (!Glib::str_has_suffix(filename, ".gig")) {
729                    filename += ".gig";
730                }
731                printf("filename=%s\n", filename.c_str());
732                file->Save(filename);
733                this->filename = filename;
734                current_dir = Glib::path_get_dirname(filename);
735                set_title(Glib::filename_display_basename(filename));
736                file_has_name = true;
737                file_is_changed = false;
738          } catch (RIFF::Exception e) {          } catch (RIFF::Exception e) {
739              Glib::ustring txt = "Could not save file: " + e.Message;              file_structure_changed_signal.emit(this->file);
740                Glib::ustring txt = _("Could not save file: ") + e.Message;
741              Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);              Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
742              msg.run();              msg.run();
743              return;              return false;
744          }          }
745          __import_queued_samples();          __import_queued_samples();
746            file_structure_changed_signal.emit(this->file);
747            return true;
748      }      }
749        return false;
750  }  }
751    
752  // 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 766  void MainWindow::__import_queued_samples
766              int bitdepth;              int bitdepth;
767              switch (info.format & 0xff) {              switch (info.format & 0xff) {
768                  case SF_FORMAT_PCM_S8:                  case SF_FORMAT_PCM_S8:
                     bitdepth = 16; // we simply convert to 16 bit for now  
                     break;  
769                  case SF_FORMAT_PCM_16:                  case SF_FORMAT_PCM_16:
770                    case SF_FORMAT_PCM_U8:
771                      bitdepth = 16;                      bitdepth = 16;
772                      break;                      break;
773                  case SF_FORMAT_PCM_24:                  case SF_FORMAT_PCM_24:
                     bitdepth = 32; // we simply convert to 32 bit for now  
                     break;  
774                  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;  
775                  case SF_FORMAT_FLOAT:                  case SF_FORMAT_FLOAT:
                     bitdepth = 32;  
                     break;  
776                  case SF_FORMAT_DOUBLE:                  case SF_FORMAT_DOUBLE:
777                      bitdepth = 32; // I guess we will always truncate this to 32 bit                      bitdepth = 24;
778                      break;                      break;
779                  default:                  default:
780                      sf_close(hFile); // close sound file                      sf_close(hFile); // close sound file
781                      throw std::string("format not supported"); // unsupported subformat (yet?)                      throw std::string("format not supported"); // unsupported subformat (yet?)
782              }              }
783              // allocate appropriate copy buffer (TODO: for now we copy  
784              // 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;  
785              switch (bitdepth) {              switch (bitdepth) {
786                  case 16:                  case 16: {
787                      buffer = new int8_t[2 * info.channels * info.frames];                      short* buffer = new short[bufsize * info.channels];
788                      // libsndfile does the conversion for us (if needed)                      sf_count_t cnt = info.frames;
789                      sf_readf_short(hFile, (short*) buffer, info.frames);                      while (cnt) {
790                            // libsndfile does the conversion for us (if needed)
791                            int n = sf_readf_short(hFile, buffer, bufsize);
792                            // write from buffer directly (physically) into .gig file
793                            iter->gig_sample->Write(buffer, n);
794                            cnt -= n;
795                        }
796                        delete[] buffer;
797                      break;                      break;
798                  case 32:                  }
799                      buffer = new int8_t[4 * info.channels * info.frames];                  case 24: {
800                      // libsndfile does the conversion for us (if needed)                      int* srcbuf = new int[bufsize * info.channels];
801                      sf_readf_int(hFile, (int*) buffer, info.frames);                      uint8_t* dstbuf = new uint8_t[bufsize * 3 * info.channels];
802                        sf_count_t cnt = info.frames;
803                        while (cnt) {
804                            // libsndfile returns 32 bits, convert to 24
805                            int n = sf_readf_int(hFile, srcbuf, bufsize);
806                            int j = 0;
807                            for (int i = 0 ; i < n * info.channels ; i++) {
808                                dstbuf[j++] = srcbuf[i] >> 8;
809                                dstbuf[j++] = srcbuf[i] >> 16;
810                                dstbuf[j++] = srcbuf[i] >> 24;
811                            }
812                            // write from buffer directly (physically) into .gig file
813                            iter->gig_sample->Write(dstbuf, n);
814                            cnt -= n;
815                        }
816                        delete[] srcbuf;
817                        delete[] dstbuf;
818                      break;                      break;
819                    }
820              }              }
             // write from buffer directly (physically) into .gig file  
             (*iter).gig_sample->Write(buffer, info.frames);  
821              // cleanup              // cleanup
822              sf_close(hFile);              sf_close(hFile);
             delete[] buffer;  
823              // on success we remove the sample from the import queue,              // on success we remove the sample from the import queue,
824              // otherwise keep it, maybe it works the next time ?              // otherwise keep it, maybe it works the next time ?
825              std::list<SampleImportItem>::iterator cur = iter;              std::list<SampleImportItem>::iterator cur = iter;
# Line 549  void MainWindow::__import_queued_samples Line 834  void MainWindow::__import_queued_samples
834      }      }
835      // show error message box when some sample(s) could not be imported      // show error message box when some sample(s) could not be imported
836      if (error_files.size()) {      if (error_files.size()) {
837          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;
838          Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);          Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
839          msg.run();          msg.run();
840      }      }
# Line 566  void MainWindow::on_action_help_about() Line 851  void MainWindow::on_action_help_about()
851  #ifdef ABOUT_DIALOG  #ifdef ABOUT_DIALOG
852      Gtk::AboutDialog dialog;      Gtk::AboutDialog dialog;
853      dialog.set_version(VERSION);      dialog.set_version(VERSION);
854        dialog.set_copyright("Copyright (C) 2006,2007 Andreas Persson");
855        dialog.set_comments(
856            "Released under the GNU General Public License.\n"
857            "\n"
858            "Please notice that this is still a very young instrument editor. "
859            "So better backup your Gigasampler files before editing them with "
860            "this application.\n"
861            "\n"
862            "Please report bugs to: http://bugs.linuxsampler.org"
863        );
864        dialog.set_website("http://www.linuxsampler.org");
865        dialog.set_website_label("http://www.linuxsampler.org");
866      dialog.run();      dialog.run();
867  #endif  #endif
868  }  }
# Line 626  void PropDialog::set_info(DLS::Info* inf Line 923  void PropDialog::set_info(DLS::Info* inf
923      entry[15].set_text(info->Subject);      entry[15].set_text(info->Subject);
924  }  }
925    
926    void InstrumentProps::set_IsDrum(bool value)
927    {
928        instrument->IsDrum = value;
929    }
930    
931    void InstrumentProps::set_MIDIBank(uint16_t value)
932    {
933        instrument->MIDIBank = value;
934    }
935    
936    void InstrumentProps::set_MIDIProgram(uint32_t value)
937    {
938        instrument->MIDIProgram = value;
939    }
940    
941    void InstrumentProps::set_DimensionKeyRange_low(uint8_t value)
942    {
943        instrument->DimensionKeyRange.low = value;
944        if (value > instrument->DimensionKeyRange.high) {
945            eDimensionKeyRangeHigh.set_value(value);
946        }
947    }
948    
949    void InstrumentProps::set_DimensionKeyRange_high(uint8_t value)
950    {
951        instrument->DimensionKeyRange.high = value;
952        if (value < instrument->DimensionKeyRange.low) {
953            eDimensionKeyRangeLow.set_value(value);
954        }
955    }
956    
957    void InstrumentProps::add_prop(BoolEntry& boolentry)
958    {
959        table.attach(boolentry.widget, 0, 2, rowno, rowno + 1,
960                     Gtk::FILL, Gtk::SHRINK);
961        rowno++;
962    }
963    
964    void InstrumentProps::add_prop(BoolEntryPlus6& boolentry)
965    {
966        table.attach(boolentry.widget, 0, 2, rowno, rowno + 1,
967                     Gtk::FILL, Gtk::SHRINK);
968        rowno++;
969    }
970    
971  void InstrumentProps::add_prop(LabelWidget& prop)  void InstrumentProps::add_prop(LabelWidget& prop)
972  {  {
973      table.attach(prop.label, 0, 1, rowno, rowno + 1,      table.attach(prop.label, 0, 1, rowno, rowno + 1,
# Line 639  InstrumentProps::InstrumentProps() Line 981  InstrumentProps::InstrumentProps()
981      : table(2,1),      : table(2,1),
982        quitButton(Gtk::Stock::CLOSE),        quitButton(Gtk::Stock::CLOSE),
983        eName("Name"),        eName("Name"),
984        eIsDrum("IsDrum"),        eIsDrum("Is drum"),
985        eMIDIBank("MIDIBank", 0, 16383),        eMIDIBank("MIDI bank", 0, 16383),
986        eMIDIProgram("MIDIProgram"),        eMIDIProgram("MIDI program"),
987        eAttenuation("Attenuation", 0, 96, 0, 1),        eAttenuation("Attenuation", 0, 96, 0, 1),
988        eGainPlus6("Gain +6dB", eAttenuation, -6),        eGainPlus6("Gain +6dB", eAttenuation, -6),
989        eEffectSend("EffectSend", 0, 65535),        eEffectSend("Effect send", 0, 65535),
990        eFineTune("FineTune", -8400, 8400),        eFineTune("Fine tune", -8400, 8400),
991        ePitchbendRange("PitchbendRange", 0, 12),        ePitchbendRange("Pitchbend range", 0, 12),
992        ePianoReleaseMode("PianoReleaseMode"),        ePianoReleaseMode("Piano release mode"),
993        eDimensionKeyRangeLow("DimensionKeyRangeLow"),        eDimensionKeyRangeLow("Dimension key range low"),
994        eDimensionKeyRangeHigh("DimensionKeyRangeHigh")        eDimensionKeyRangeHigh("Dimension key range high"),
995          update_model(0)
996  {  {
997      set_title("Instrument properties");      set_title("Instrument properties");
998    
999        connect(eIsDrum, &InstrumentProps::set_IsDrum);
1000        connect(eMIDIBank, &InstrumentProps::set_MIDIBank);
1001        connect(eMIDIProgram, &InstrumentProps::set_MIDIProgram);
1002        connect(eAttenuation, &gig::Instrument::Attenuation);
1003        connect(eGainPlus6, &gig::Instrument::Attenuation);
1004        connect(eEffectSend, &gig::Instrument::EffectSend);
1005        connect(eFineTune, &gig::Instrument::FineTune);
1006        connect(ePitchbendRange, &gig::Instrument::PitchbendRange);
1007        connect(ePianoReleaseMode, &gig::Instrument::PianoReleaseMode);
1008        connect(eDimensionKeyRangeLow,
1009                &InstrumentProps::set_DimensionKeyRange_low);
1010        connect(eDimensionKeyRangeHigh,
1011                &InstrumentProps::set_DimensionKeyRange_high);
1012    
1013      rowno = 0;      rowno = 0;
1014      table.set_col_spacings(5);      table.set_col_spacings(5);
1015    
# Line 669  InstrumentProps::InstrumentProps() Line 1026  InstrumentProps::InstrumentProps()
1026      add_prop(eDimensionKeyRangeLow);      add_prop(eDimensionKeyRangeLow);
1027      add_prop(eDimensionKeyRangeHigh);      add_prop(eDimensionKeyRangeHigh);
1028    
     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));  
   
1029      add(vbox);      add(vbox);
1030      table.set_border_width(5);      table.set_border_width(5);
1031      vbox.pack_start(table);      vbox.pack_start(table);
# Line 696  InstrumentProps::InstrumentProps() Line 1048  InstrumentProps::InstrumentProps()
1048    
1049  void InstrumentProps::set_instrument(gig::Instrument* instrument)  void InstrumentProps::set_instrument(gig::Instrument* instrument)
1050  {  {
1051      update_gui = false;      this->instrument = instrument;
1052    
1053        update_model++;
1054      eName.set_ptr(&instrument->pInfo->Name);      eName.set_ptr(&instrument->pInfo->Name);
1055      eIsDrum.set_ptr(&instrument->IsDrum);      eIsDrum.set_value(instrument->IsDrum);
1056      eMIDIBank.set_ptr(&instrument->MIDIBank);      eMIDIBank.set_value(instrument->MIDIBank);
1057      eMIDIProgram.set_ptr(&instrument->MIDIProgram);      eMIDIProgram.set_value(instrument->MIDIProgram);
1058      eAttenuation.set_ptr(&instrument->Attenuation);      eAttenuation.set_value(instrument->Attenuation);
1059      eGainPlus6.set_ptr(&instrument->Attenuation);      eGainPlus6.set_value(instrument->Attenuation);
1060      eEffectSend.set_ptr(&instrument->EffectSend);      eEffectSend.set_value(instrument->EffectSend);
1061      eFineTune.set_ptr(&instrument->FineTune);      eFineTune.set_value(instrument->FineTune);
1062      ePitchbendRange.set_ptr(&instrument->PitchbendRange);      ePitchbendRange.set_value(instrument->PitchbendRange);
1063      ePianoReleaseMode.set_ptr(&instrument->PianoReleaseMode);      ePianoReleaseMode.set_value(instrument->PianoReleaseMode);
1064      eDimensionKeyRangeLow.set_ptr(&instrument->DimensionKeyRange.low);      eDimensionKeyRangeLow.set_value(instrument->DimensionKeyRange.low);
1065      eDimensionKeyRangeHigh.set_ptr(&instrument->DimensionKeyRange.high);      eDimensionKeyRangeHigh.set_value(instrument->DimensionKeyRange.high);
1066      update_gui = true;      update_model--;
1067  }  }
1068    
1069  void InstrumentProps::key_range_low_changed()  sigc::signal<void>& InstrumentProps::signal_instrument_changed()
1070  {  {
1071      double l = eDimensionKeyRangeLow.get_value();      return instrument_changed;
     double h = eDimensionKeyRangeHigh.get_value();  
     if (h < l) eDimensionKeyRangeHigh.set_value(l);  
1072  }  }
1073    
1074  void InstrumentProps::key_range_high_changed()  void MainWindow::file_changed()
1075  {  {
1076      double l = eDimensionKeyRangeLow.get_value();      if (file && !file_is_changed) {
1077      double h = eDimensionKeyRangeHigh.get_value();          set_title("*" + get_title());
1078      if (h < l) eDimensionKeyRangeLow.set_value(h);          file_is_changed = true;
1079        }
1080  }  }
1081    
1082  void MainWindow::load_gig(gig::File* gig, const char* filename)  void MainWindow::load_gig(gig::File* gig, const char* filename, bool isSharedInstrument)
1083  {  {
1084      file = gig;      file = 0;
1085        set_file_is_shared(isSharedInstrument);
1086    
1087      if (filename) {      this->filename = filename ? filename : _("Unsaved Gig File");
1088          const char *basename = strrchr(filename, '/');      set_title(Glib::filename_display_basename(this->filename));
1089          basename = basename ? basename + 1 : filename;      file_has_name = filename;
1090          set_title(basename);      file_is_changed = false;
     } else {  
         set_title("unnamed");  
     }  
1091    
1092      propDialog.set_info(gig->pInfo);      propDialog.set_info(gig->pInfo);
1093    
# Line 785  void MainWindow::load_gig(gig::File* gig Line 1136  void MainWindow::load_gig(gig::File* gig
1136          }          }
1137      }      }
1138    
1139        file = gig;
1140    
1141      // select the first instrument      // select the first instrument
1142      Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();      Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();
1143      tree_sel_ref->select(Gtk::TreePath("0"));      tree_sel_ref->select(Gtk::TreePath("0"));
# Line 792  void MainWindow::load_gig(gig::File* gig Line 1145  void MainWindow::load_gig(gig::File* gig
1145    
1146  void MainWindow::show_instr_props()  void MainWindow::show_instr_props()
1147  {  {
1148      Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();      gig::Instrument* instrument = get_instrument();
1149      Gtk::TreeModel::iterator it = tree_sel_ref->get_selected();      if (instrument)
     if (it)  
1150      {      {
1151          Gtk::TreeModel::Row row = *it;          instrumentProps.set_instrument(instrument);
1152          if (row[m_Columns.m_col_instr])          instrumentProps.show();
1153          {          instrumentProps.deiconify();
1154              instrumentProps.set_instrument(row[m_Columns.m_col_instr]);      }
1155              instrumentProps.show();  }
1156              instrumentProps.deiconify();  
1157          }  void MainWindow::on_action_view_status_bar() {
1158        Gtk::CheckMenuItem* item =
1159            dynamic_cast<Gtk::CheckMenuItem*>(uiManager->get_widget("/MenuBar/MenuView/Statusbar"));
1160        if (!item) {
1161            std::cerr << "/MenuBar/MenuView/Statusbar == NULL\n";
1162            return;
1163      }      }
1164        if (item->get_active()) m_StatusBar.show();
1165        else                    m_StatusBar.hide();
1166  }  }
1167    
1168  void MainWindow::on_button_release(GdkEventButton* button)  void MainWindow::on_button_release(GdkEventButton* button)
# Line 858  void MainWindow::on_action_add_instrumen Line 1217  void MainWindow::on_action_add_instrumen
1217      Gtk::TreeModel::Row rowInstr = *iterInstr;      Gtk::TreeModel::Row rowInstr = *iterInstr;
1218      rowInstr[m_Columns.m_col_name] = instrument->pInfo->Name.c_str();      rowInstr[m_Columns.m_col_name] = instrument->pInfo->Name.c_str();
1219      rowInstr[m_Columns.m_col_instr] = instrument;      rowInstr[m_Columns.m_col_instr] = instrument;
1220        file_changed();
1221  }  }
1222    
1223  void MainWindow::on_action_remove_instrument() {  void MainWindow::on_action_remove_instrument() {
1224      if (!file) return;      if (!file) return;
1225        if (file_is_shared) {
1226            Gtk::MessageDialog msg(
1227                *this,
1228                 _("You cannot delete an instrument from this file, since it's "
1229                   "currently used by the sampler."),
1230                 false, Gtk::MESSAGE_INFO
1231            );
1232            msg.run();
1233            return;
1234        }
1235    
1236      Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeView.get_selection();      Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeView.get_selection();
1237      Gtk::TreeModel::iterator it = sel->get_selected();      Gtk::TreeModel::iterator it = sel->get_selected();
1238      if (it) {      if (it) {
# Line 872  void MainWindow::on_action_remove_instru Line 1243  void MainWindow::on_action_remove_instru
1243              if (instr) file->DeleteInstrument(instr);              if (instr) file->DeleteInstrument(instr);
1244              // remove respective row from instruments tree view              // remove respective row from instruments tree view
1245              m_refTreeModel->erase(it);              m_refTreeModel->erase(it);
1246                file_changed();
1247          } catch (RIFF::Exception e) {          } catch (RIFF::Exception e) {
1248              Gtk::MessageDialog msg(*this, e.Message.c_str(), false, Gtk::MESSAGE_ERROR);              Gtk::MessageDialog msg(*this, e.Message.c_str(), false, Gtk::MESSAGE_ERROR);
1249              msg.run();              msg.run();
# Line 900  void MainWindow::on_action_add_group() { Line 1272  void MainWindow::on_action_add_group() {
1272      rowGroup[m_SamplesModel.m_col_name] = group->Name.c_str();      rowGroup[m_SamplesModel.m_col_name] = group->Name.c_str();
1273      rowGroup[m_SamplesModel.m_col_sample] = NULL;      rowGroup[m_SamplesModel.m_col_sample] = NULL;
1274      rowGroup[m_SamplesModel.m_col_group] = group;      rowGroup[m_SamplesModel.m_col_group] = group;
1275        file_changed();
1276  }  }
1277    
1278  void MainWindow::on_action_add_sample() {  void MainWindow::on_action_add_sample() {
# Line 925  void MainWindow::on_action_add_sample() Line 1298  void MainWindow::on_action_add_sample()
1298      dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);      dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);
1299      dialog.set_select_multiple(true);      dialog.set_select_multiple(true);
1300      Gtk::FileFilter soundfilter; // matches all file types supported by libsndfile      Gtk::FileFilter soundfilter; // matches all file types supported by libsndfile
1301      const char* supportedFileTypes[] = {      const char* const supportedFileTypes[] = {
1302          "*.wav", "*.WAV", "*.aiff", "*.AIFF", "*.aifc", "*.AIFC", "*.snd",          "*.wav", "*.WAV", "*.aiff", "*.AIFF", "*.aifc", "*.AIFC", "*.snd",
1303          "*.SND", "*.au", "*.AU", "*.paf", "*.PAF", "*.iff", "*.IFF",          "*.SND", "*.au", "*.AU", "*.paf", "*.PAF", "*.iff", "*.IFF",
1304          "*.svx", "*.SVX", "*.sf", "*.SF", "*.voc", "*.VOC", "*.w64",          "*.svx", "*.SVX", "*.sf", "*.SF", "*.voc", "*.VOC", "*.w64",
# Line 955  void MainWindow::on_action_add_sample() Line 1328  void MainWindow::on_action_add_sample()
1328                  int bitdepth;                  int bitdepth;
1329                  switch (info.format & 0xff) {                  switch (info.format & 0xff) {
1330                      case SF_FORMAT_PCM_S8:                      case SF_FORMAT_PCM_S8:
                         bitdepth = 16; // we simply convert to 16 bit for now  
                         break;  
1331                      case SF_FORMAT_PCM_16:                      case SF_FORMAT_PCM_16:
1332                        case SF_FORMAT_PCM_U8:
1333                          bitdepth = 16;                          bitdepth = 16;
1334                          break;                          break;
1335                      case SF_FORMAT_PCM_24:                      case SF_FORMAT_PCM_24:
                         bitdepth = 32; // we simply convert to 32 bit for now  
                         break;  
1336                      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;  
1337                      case SF_FORMAT_FLOAT:                      case SF_FORMAT_FLOAT:
                         bitdepth = 32;  
                         break;  
1338                      case SF_FORMAT_DOUBLE:                      case SF_FORMAT_DOUBLE:
1339                          bitdepth = 32; // I guess we will always truncate this to 32 bit                          bitdepth = 24;
1340                          break;                          break;
1341                      default:                      default:
1342                          sf_close(hFile); // close sound file                          sf_close(hFile); // close sound file
# Line 982  void MainWindow::on_action_add_sample() Line 1345  void MainWindow::on_action_add_sample()
1345                  // add a new sample to the .gig file                  // add a new sample to the .gig file
1346                  gig::Sample* sample = file->AddSample();                  gig::Sample* sample = file->AddSample();
1347                  // file name without path                  // file name without path
1348                  sample->pInfo->Name = (*iter).substr((*iter).rfind('/') + 1).raw();                  Glib::ustring filename = Glib::filename_display_basename(*iter);
1349                    // remove file extension if there is one
1350                    for (int i = 0; supportedFileTypes[i]; i++) {
1351                        if (Glib::str_has_suffix(filename, supportedFileTypes[i] + 1)) {
1352                            filename.erase(filename.length() - strlen(supportedFileTypes[i] + 1));
1353                            break;
1354                        }
1355                    }
1356                    sample->pInfo->Name = filename;
1357                  sample->Channels = info.channels;                  sample->Channels = info.channels;
1358                  sample->BitDepth = bitdepth;                  sample->BitDepth = bitdepth;
1359                  sample->FrameSize = bitdepth / 8/*1 byte are 8 bits*/ * info.channels;                  sample->FrameSize = bitdepth / 8/*1 byte are 8 bits*/ * info.channels;
1360                  sample->SamplesPerSecond = info.samplerate;                  sample->SamplesPerSecond = info.samplerate;
1361                    sample->AverageBytesPerSecond = sample->FrameSize * sample->SamplesPerSecond;
1362                    sample->BlockAlign = sample->FrameSize;
1363                    sample->SamplesTotal = info.frames;
1364    
1365                    SF_INSTRUMENT instrument;
1366                    if (sf_command(hFile, SFC_GET_INSTRUMENT,
1367                                   &instrument, sizeof(instrument)) != SF_FALSE)
1368                    {
1369                        sample->MIDIUnityNote = instrument.basenote;
1370    
1371    #if HAVE_SF_INSTRUMENT_LOOPS
1372                        if (instrument.loop_count && instrument.loops[0].mode != SF_LOOP_NONE) {
1373                            sample->Loops = 1;
1374    
1375                            switch (instrument.loops[0].mode) {
1376                            case SF_LOOP_FORWARD:
1377                                sample->LoopType = gig::loop_type_normal;
1378                                break;
1379                            case SF_LOOP_BACKWARD:
1380                                sample->LoopType = gig::loop_type_backward;
1381                                break;
1382                            case SF_LOOP_ALTERNATING:
1383                                sample->LoopType = gig::loop_type_bidirectional;
1384                                break;
1385                            }
1386                            sample->LoopStart = instrument.loops[0].start;
1387                            sample->LoopEnd = instrument.loops[0].end;
1388                            sample->LoopPlayCount = instrument.loops[0].count;
1389                            sample->LoopSize = sample->LoopEnd - sample->LoopStart + 1;
1390                        }
1391    #endif
1392                    }
1393    
1394                  // schedule resizing the sample (which will be done                  // schedule resizing the sample (which will be done
1395                  // physically when File::Save() is called)                  // physically when File::Save() is called)
1396                  sample->Resize(info.frames);                  sample->Resize(info.frames);
# Line 1002  void MainWindow::on_action_add_sample() Line 1406  void MainWindow::on_action_add_sample()
1406                  Gtk::TreeModel::iterator iterSample =                  Gtk::TreeModel::iterator iterSample =
1407                      m_refSamplesTreeModel->append(row.children());                      m_refSamplesTreeModel->append(row.children());
1408                  Gtk::TreeModel::Row rowSample = *iterSample;                  Gtk::TreeModel::Row rowSample = *iterSample;
1409                  rowSample[m_SamplesModel.m_col_name]   = sample->pInfo->Name.c_str();                  rowSample[m_SamplesModel.m_col_name]   = filename;
1410                  rowSample[m_SamplesModel.m_col_sample] = sample;                  rowSample[m_SamplesModel.m_col_sample] = sample;
1411                  rowSample[m_SamplesModel.m_col_group]  = NULL;                  rowSample[m_SamplesModel.m_col_group]  = NULL;
1412                  // close sound file                  // close sound file
1413                  sf_close(hFile);                  sf_close(hFile);
1414                    file_changed();
1415              } 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)
1416                  if (error_files.size()) error_files += "\n";                  if (error_files.size()) error_files += "\n";
1417                  error_files += *iter += " (" + what + ")";                  error_files += *iter += " (" + what + ")";
# Line 1014  void MainWindow::on_action_add_sample() Line 1419  void MainWindow::on_action_add_sample()
1419          }          }
1420          // 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
1421          if (error_files.size()) {          if (error_files.size()) {
1422              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;
1423              Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);              Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
1424              msg.run();              msg.run();
1425          }          }
# Line 1040  void MainWindow::on_action_remove_sample Line 1445  void MainWindow::on_action_remove_sample
1445                       pSample; pSample = group->GetNextSample()) {                       pSample; pSample = group->GetNextSample()) {
1446                      members.push_back(pSample);                      members.push_back(pSample);
1447                  }                  }
1448                    // notify everybody that we're going to remove these samples
1449                    samples_to_be_removed_signal.emit(members);
1450                  // delete the group in the .gig file including the                  // delete the group in the .gig file including the
1451                  // samples that belong to the group                  // samples that belong to the group
1452                  file->DeleteGroup(group);                  file->DeleteGroup(group);
1453                    // notify that we're done with removal
1454                    samples_removed_signal.emit();
1455                  // if sample(s) were just previously added, remove                  // if sample(s) were just previously added, remove
1456                  // them from the import queue                  // them from the import queue
1457                  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 1466  void MainWindow::on_action_remove_sample
1466                          }                          }
1467                      }                      }
1468                  }                  }
1469                    file_changed();
1470              } else if (sample) {              } else if (sample) {
1471                    // notify everybody that we're going to remove this sample
1472                    std::list<gig::Sample*> lsamples;
1473                    lsamples.push_back(sample);
1474                    samples_to_be_removed_signal.emit(lsamples);
1475                  // remove sample from the .gig file                  // remove sample from the .gig file
1476                  file->DeleteSample(sample);                  file->DeleteSample(sample);
1477                    // notify that we're done with removal
1478                    samples_removed_signal.emit();
1479                  // if sample was just previously added, remove it from                  // if sample was just previously added, remove it from
1480                  // the import queue                  // the import queue
1481                  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 1487  void MainWindow::on_action_remove_sample
1487                          break;                          break;
1488                      }                      }
1489                  }                  }
1490                    dimreg_changed();
1491                    file_changed();
1492              }              }
1493              // remove respective row(s) from samples tree view              // remove respective row(s) from samples tree view
1494              m_refSamplesTreeModel->erase(it);              m_refSamplesTreeModel->erase(it);
1495          } catch (RIFF::Exception e) {          } catch (RIFF::Exception e) {
1496                // pretend we're done with removal (i.e. to avoid dead locks)
1497                samples_removed_signal.emit();
1498                // show error message
1499              Gtk::MessageDialog msg(*this, e.Message.c_str(), false, Gtk::MESSAGE_ERROR);              Gtk::MessageDialog msg(*this, e.Message.c_str(), false, Gtk::MESSAGE_ERROR);
1500              msg.run();              msg.run();
1501          }          }
1502      }      }
1503  }  }
1504    
1505    // For some reason drag_data_get gets called two times for each
1506    // drag'n'drop (at least when target is an Entry). This work-around
1507    // makes sure the code in drag_data_get and drop_drag_data_received is
1508    // only executed once, as drag_begin only gets called once.
1509    void MainWindow::on_sample_treeview_drag_begin(const Glib::RefPtr<Gdk::DragContext>& context)
1510    {
1511        first_call_to_drag_data_get = true;
1512    }
1513    
1514  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>&,
1515                                                    Gtk::SelectionData& selection_data, guint, guint)                                                    Gtk::SelectionData& selection_data, guint, guint)
1516  {  {
1517        if (!first_call_to_drag_data_get) return;
1518        first_call_to_drag_data_get = false;
1519    
1520      // get selected sample      // get selected sample
1521      gig::Sample* sample = NULL;      gig::Sample* sample = NULL;
1522      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 1534  void MainWindow::on_sample_label_drop_dr
1534      const Glib::RefPtr<Gdk::DragContext>& context, int, int,      const Glib::RefPtr<Gdk::DragContext>& context, int, int,
1535      const Gtk::SelectionData& selection_data, guint, guint time)      const Gtk::SelectionData& selection_data, guint, guint time)
1536  {  {
     gig::DimensionRegion* dimregion = m_DimRegionChooser.get_dimregion();  
1537      gig::Sample* sample = *((gig::Sample**) selection_data.get_data());      gig::Sample* sample = *((gig::Sample**) selection_data.get_data());
1538    
1539      if (sample && dimregion && selection_data.get_length() == sizeof(gig::Sample*)) {      if (sample && selection_data.get_length() == sizeof(gig::Sample*)) {
1540          if (sample != dimregion->pSample) {          std::cout << "Drop received sample \"" <<
1541              dimregion->pSample = sample;              sample->pInfo->Name << "\"" << std::endl;
1542              dimreg_edit.wSample->set_text(dimregion->pSample->pInfo->Name.c_str());          // drop success
1543              std::cout << "Drop received sample \"" <<          context->drop_reply(true, time);
1544                  dimregion->pSample->pInfo->Name.c_str() << "\"" << std::endl;  
1545              // drop success          //TODO: we should better move most of the following code to DimRegionEdit::set_sample()
1546              context->drop_reply(true, time);  
1547              return;          // notify everybody that we're going to alter the region
1548            gig::Region* region = m_RegionChooser.get_region();
1549            region_to_be_changed_signal.emit(region);
1550    
1551            // find the samplechannel dimension
1552            gig::dimension_def_t* stereo_dimension = 0;
1553            for (int i = 0 ; i < region->Dimensions ; i++) {
1554                if (region->pDimensionDefinitions[i].dimension ==
1555                    gig::dimension_samplechannel) {
1556                    stereo_dimension = &region->pDimensionDefinitions[i];
1557                    break;
1558                }
1559            }
1560            bool channels_changed = false;
1561            if (sample->Channels == 1 && stereo_dimension) {
1562                // remove the samplechannel dimension
1563                region->DeleteDimension(stereo_dimension);
1564                channels_changed = true;
1565                region_changed();
1566            }
1567            dimreg_edit.set_sample(sample);
1568    
1569            if (sample->Channels == 2 && !stereo_dimension) {
1570                // add samplechannel dimension
1571                gig::dimension_def_t dim;
1572                dim.dimension = gig::dimension_samplechannel;
1573                dim.bits = 1;
1574                dim.zones = 2;
1575                region->AddDimension(&dim);
1576                channels_changed = true;
1577                region_changed();
1578            }
1579            if (channels_changed) {
1580                // unmap all samples with wrong number of channels
1581                // TODO: maybe there should be a warning dialog for this
1582                for (int i = 0 ; i < region->DimensionRegions ; i++) {
1583                    gig::DimensionRegion* d = region->pDimensionRegions[i];
1584                    if (d->pSample && d->pSample->Channels != sample->Channels) {
1585                        gig::Sample* oldref = d->pSample;
1586                        d->pSample = NULL;
1587                        sample_ref_changed_signal.emit(oldref, NULL);
1588                    }
1589                }
1590          }          }
1591    
1592            // notify we're done with altering
1593            region_changed_signal.emit(region);
1594    
1595            file_changed();
1596    
1597            return;
1598      }      }
1599      // drop failed      // drop failed
1600      context->drop_reply(false, time);      context->drop_reply(false, time);
# Line 1127  void MainWindow::sample_name_changed(con Line 1608  void MainWindow::sample_name_changed(con
1608      gig::Group* group   = row[m_SamplesModel.m_col_group];      gig::Group* group   = row[m_SamplesModel.m_col_group];
1609      gig::Sample* sample = row[m_SamplesModel.m_col_sample];      gig::Sample* sample = row[m_SamplesModel.m_col_sample];
1610      if (group) {      if (group) {
1611          group->Name = name;          if (group->Name != name) {
1612                group->Name = name;
1613                printf("group name changed\n");
1614                file_changed();
1615            }
1616      } else if (sample) {      } else if (sample) {
1617          sample->pInfo->Name = name.raw();          if (sample->pInfo->Name != name.raw()) {
1618                sample->pInfo->Name = name.raw();
1619                printf("sample name changed\n");
1620                file_changed();
1621            }
1622      }      }
1623  }  }
1624    
# Line 1139  void MainWindow::instrument_name_changed Line 1628  void MainWindow::instrument_name_changed
1628      Gtk::TreeModel::Row row = *iter;      Gtk::TreeModel::Row row = *iter;
1629      Glib::ustring name = row[m_Columns.m_col_name];      Glib::ustring name = row[m_Columns.m_col_name];
1630      gig::Instrument* instrument = row[m_Columns.m_col_instr];      gig::Instrument* instrument = row[m_Columns.m_col_instr];
1631      if (instrument) instrument->pInfo->Name = name.raw();      if (instrument && instrument->pInfo->Name != name.raw()) {
1632            instrument->pInfo->Name = name.raw();
1633            file_changed();
1634        }
1635    }
1636    
1637    void MainWindow::set_file_is_shared(bool b) {
1638        this->file_is_shared = b;
1639    
1640        if (file_is_shared) {
1641            m_AttachedStateLabel.set_label(_("live-mode"));
1642            m_AttachedStateImage.set(
1643                Gdk::Pixbuf::create_from_xpm_data(status_attached_xpm)
1644            );
1645        } else {
1646            m_AttachedStateLabel.set_label(_("stand-alone"));
1647            m_AttachedStateImage.set(
1648                Gdk::Pixbuf::create_from_xpm_data(status_detached_xpm)
1649            );
1650        }
1651    }
1652    
1653    sigc::signal<void, gig::File*>& MainWindow::signal_file_structure_to_be_changed() {
1654        return file_structure_to_be_changed_signal;
1655    }
1656    
1657    sigc::signal<void, gig::File*>& MainWindow::signal_file_structure_changed() {
1658        return file_structure_changed_signal;
1659    }
1660    
1661    sigc::signal<void, std::list<gig::Sample*> >& MainWindow::signal_samples_to_be_removed() {
1662        return samples_to_be_removed_signal;
1663    }
1664    
1665    sigc::signal<void>& MainWindow::signal_samples_removed() {
1666        return samples_removed_signal;
1667    }
1668    
1669    sigc::signal<void, gig::Region*>& MainWindow::signal_region_to_be_changed() {
1670        return region_to_be_changed_signal;
1671    }
1672    
1673    sigc::signal<void, gig::Region*>& MainWindow::signal_region_changed() {
1674        return region_changed_signal;
1675    }
1676    
1677    sigc::signal<void, gig::Sample*/*old*/, gig::Sample*/*new*/>& MainWindow::signal_sample_ref_changed() {
1678        return sample_ref_changed_signal;
1679    }
1680    
1681    sigc::signal<void, gig::DimensionRegion*>& MainWindow::signal_dimreg_to_be_changed() {
1682        return dimreg_to_be_changed_signal;
1683    }
1684    
1685    sigc::signal<void, gig::DimensionRegion*>& MainWindow::signal_dimreg_changed() {
1686        return dimreg_changed_signal;
1687  }  }

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

  ViewVC Help
Powered by ViewVC