/[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 1654 by schoenebeck, Wed Jan 30 02:20:48 2008 UTC
# Line 1  Line 1 
1  /*  /*
2   * Copyright (C) 2006, 2007 Andreas Persson   * Copyright (C) 2006 - 2008 Andreas Persson
3   *   *
4   * This program is free software; you can redistribute it and/or   * This program is free software; you can redistribute it and/or
5   * modify it under the terms of the GNU General Public License as   * modify it under the terms of the GNU General Public License as
# Line 17  Line 17 
17   * 02110-1301 USA.   * 02110-1301 USA.
18   */   */
19    
 #include <libintl.h>  
20  #include <iostream>  #include <iostream>
21    
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        note_on_signal.connect(
355            sigc::mem_fun(m_RegionChooser, &RegionChooser::on_note_on_event));
356        note_off_signal.connect(
357            sigc::mem_fun(m_RegionChooser, &RegionChooser::on_note_off_event));
358    
359        dimreg_all_regions.signal_toggled().connect(
360            sigc::mem_fun(*this, &MainWindow::update_dimregs));
361        dimreg_all_dimregs.signal_toggled().connect(
362            sigc::mem_fun(*this, &MainWindow::dimreg_all_dimregs_toggled));
363        dimreg_stereo.signal_toggled().connect(
364            sigc::mem_fun(*this, &MainWindow::update_dimregs));
365    
366      file = 0;      file = 0;
367      file_is_changed = false;      file_is_changed = false;
368        set_file_is_shared(false);
369    
370      show_all_children();      show_all_children();
371    
372        // start with a new gig file by default
373        on_action_file_new();
374  }  }
375    
376  MainWindow::~MainWindow()  MainWindow::~MainWindow()
# Line 261  MainWindow::~MainWindow() Line 379  MainWindow::~MainWindow()
379    
380  bool MainWindow::on_delete_event(GdkEventAny* event)  bool MainWindow::on_delete_event(GdkEventAny* event)
381  {  {
382      return file_is_changed && !close_confirmation_dialog();      return !file_is_shared && file_is_changed && !close_confirmation_dialog();
383  }  }
384    
385  void MainWindow::on_action_quit()  void MainWindow::on_action_quit()
386  {  {
387      if (file_is_changed && !close_confirmation_dialog()) return;      if (!file_is_shared && file_is_changed && !close_confirmation_dialog()) return;
388      hide();      hide();
389  }  }
390    
# Line 275  void MainWindow::region_changed() Line 393  void MainWindow::region_changed()
393      m_DimRegionChooser.set_region(m_RegionChooser.get_region());      m_DimRegionChooser.set_region(m_RegionChooser.get_region());
394  }  }
395    
396  void MainWindow::dimreg_changed()  gig::Instrument* MainWindow::get_instrument()
 {  
     dimreg_edit.set_dim_region(m_DimRegionChooser.get_dimregion());  
 }  
   
 void MainWindow::on_sel_change()  
397  {  {
398        gig::Instrument* instrument = 0;
399      Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();      Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();
400    
401      Gtk::TreeModel::iterator it = tree_sel_ref->get_selected();      Gtk::TreeModel::iterator it = tree_sel_ref->get_selected();
402      if (it) {      if (it) {
403          Gtk::TreeModel::Row row = *it;          Gtk::TreeModel::Row row = *it;
404          std::cout << row[m_Columns.m_col_name] << std::endl;          instrument = row[m_Columns.m_col_instr];
405        }
406        return instrument;
407    }
408    
409    void MainWindow::add_region_to_dimregs(gig::Region* region, bool stereo, bool all_dimregs)
410    {
411        if (all_dimregs) {
412            for (int i = 0 ; i < region->DimensionRegions ; i++) {
413                if (region->pDimensionRegions[i]) {
414                    dimreg_edit.dimregs.insert(region->pDimensionRegions[i]);
415                }
416            }
417        } else {
418            m_DimRegionChooser.get_dimregions(region, stereo, dimreg_edit.dimregs);
419        }
420    }
421    
422    void MainWindow::update_dimregs()
423    {
424        dimreg_edit.dimregs.clear();
425        bool all_regions = dimreg_all_regions.get_active();
426        bool stereo = dimreg_stereo.get_active();
427        bool all_dimregs = dimreg_all_dimregs.get_active();
428    
429          m_RegionChooser.set_instrument(row[m_Columns.m_col_instr]);      if (all_regions) {
430            gig::Instrument* instrument = get_instrument();
431            if (instrument) {
432                for (gig::Region* region = instrument->GetFirstRegion() ;
433                     region ;
434                     region = instrument->GetNextRegion()) {
435                    add_region_to_dimregs(region, stereo, all_dimregs);
436                }
437            }
438      } else {      } else {
439          m_RegionChooser.set_instrument(0);          gig::Region* region = m_RegionChooser.get_region();
440            if (region) {
441                add_region_to_dimregs(region, stereo, all_dimregs);
442            }
443      }      }
444  }  }
445    
446    void MainWindow::dimreg_all_dimregs_toggled()
447    {
448        dimreg_stereo.set_sensitive(!dimreg_all_dimregs.get_active());
449        update_dimregs();
450    }
451    
452    void MainWindow::dimreg_changed()
453    {
454        update_dimregs();
455        dimreg_edit.set_dim_region(m_DimRegionChooser.get_dimregion());
456    }
457    
458    void MainWindow::on_sel_change()
459    {
460        m_RegionChooser.set_instrument(get_instrument());
461    }
462    
463  void loader_progress_callback(gig::progress_t* progress)  void loader_progress_callback(gig::progress_t* progress)
464  {  {
465      Loader* loader = static_cast<Loader*>(progress->custom);      Loader* loader = static_cast<Loader*>(progress->custom);
# Line 380  void MainWindow::__clear() { Line 545  void MainWindow::__clear() {
545      m_refTreeModel->clear();      m_refTreeModel->clear();
546      m_refSamplesTreeModel->clear();      m_refSamplesTreeModel->clear();
547      // free libgig's gig::File instance      // free libgig's gig::File instance
548      if (file) {      if (file && !file_is_shared) delete file;
549          delete file;      file = NULL;
550          file = NULL;      set_file_is_shared(false);
     }  
551  }  }
552    
553  void MainWindow::on_action_file_new()  void MainWindow::on_action_file_new()
554  {  {
555      if (file_is_changed && !close_confirmation_dialog()) return;      if (!file_is_shared && file_is_changed && !close_confirmation_dialog()) return;
556    
557        if (file_is_shared && !leaving_shared_mode_dialog()) return;
558    
559      // clear all GUI elements      // clear all GUI elements
560      __clear();      __clear();
# Line 407  bool MainWindow::close_confirmation_dial Line 573  bool MainWindow::close_confirmation_dial
573                                   Glib::filename_display_basename(filename).c_str());                                   Glib::filename_display_basename(filename).c_str());
574      Gtk::MessageDialog dialog(*this, msg, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_NONE);      Gtk::MessageDialog dialog(*this, msg, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_NONE);
575      g_free(msg);      g_free(msg);
576    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION >= 6) || GTKMM_MAJOR_VERSION > 2
577      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."));
578    #endif
579      dialog.add_button(_("Close _Without Saving"), Gtk::RESPONSE_NO);      dialog.add_button(_("Close _Without Saving"), Gtk::RESPONSE_NO);
580      dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);      dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
581      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);
582      dialog.set_default_response(Gtk::RESPONSE_YES);      dialog.set_default_response(Gtk::RESPONSE_YES);
583      int response = dialog.run();      int response = dialog.run();
584        dialog.hide();
585      if (response == Gtk::RESPONSE_YES) return file_save();      if (response == Gtk::RESPONSE_YES) return file_save();
586      return response != Gtk::RESPONSE_CANCEL;      return response != Gtk::RESPONSE_CANCEL;
587  }  }
588    
589    bool MainWindow::leaving_shared_mode_dialog() {
590        Glib::ustring msg = _("Detach from sampler and proceed working stand-alone?");
591        Gtk::MessageDialog dialog(*this, msg, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_NONE);
592    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION >= 6) || GTKMM_MAJOR_VERSION > 2
593        dialog.set_secondary_text(
594            _("If you proceed to work on another instrument file, it won't be "
595              "used by the sampler until you tell the sampler explicitly to "
596              "load it.")
597       );
598    #endif
599        dialog.add_button(_("_Yes, Detach"), Gtk::RESPONSE_YES);
600        dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
601        dialog.set_default_response(Gtk::RESPONSE_CANCEL);
602        int response = dialog.run();
603        dialog.hide();
604        return response == Gtk::RESPONSE_YES;
605    }
606    
607  void MainWindow::on_action_file_open()  void MainWindow::on_action_file_open()
608  {  {
609      if (file_is_changed && !close_confirmation_dialog()) return;      if (!file_is_shared && file_is_changed && !close_confirmation_dialog()) return;
610    
611        if (file_is_shared && !leaving_shared_mode_dialog()) return;
612    
613      Gtk::FileChooserDialog dialog(*this, _("Open file"));      Gtk::FileChooserDialog dialog(*this, _("Open file"));
614      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 623  void MainWindow::on_action_file_open()
623      if (dialog.run() == Gtk::RESPONSE_OK) {      if (dialog.run() == Gtk::RESPONSE_OK) {
624          std::string filename = dialog.get_filename();          std::string filename = dialog.get_filename();
625          printf("filename=%s\n", filename.c_str());          printf("filename=%s\n", filename.c_str());
         __clear();  
626          printf("on_action_file_open self=%x\n", Glib::Thread::self());          printf("on_action_file_open self=%x\n", Glib::Thread::self());
627          load_file(filename.c_str());          load_file(filename.c_str());
628          current_dir = Glib::path_get_dirname(filename);          current_dir = Glib::path_get_dirname(filename);
# Line 443  void MainWindow::on_action_file_open() Line 631  void MainWindow::on_action_file_open()
631    
632  void MainWindow::load_file(const char* name)  void MainWindow::load_file(const char* name)
633  {  {
634        __clear();
635      load_dialog = new LoadDialog("Loading...", *this);      load_dialog = new LoadDialog("Loading...", *this);
636      load_dialog->show_all();      load_dialog->show_all();
637      loader = new Loader(strdup(name));      loader = new Loader(strdup(name));
# Line 460  void MainWindow::load_instrument(gig::In Line 649  void MainWindow::load_instrument(gig::In
649          msg.run();          msg.run();
650          Gtk::Main::quit();          Gtk::Main::quit();
651      }      }
652        // clear all GUI elements
653        __clear();
654        // load the instrument
655      gig::File* pFile = (gig::File*) instr->GetParent();      gig::File* pFile = (gig::File*) instr->GetParent();
656      load_gig(pFile, 0 /*file name*/);      load_gig(pFile, 0 /*file name*/, true /*shared instrument*/);
657      //TODO: automatically select the given instrument      //TODO: automatically select the given instrument
658  }  }
659    
# Line 483  void MainWindow::on_action_file_save() Line 675  void MainWindow::on_action_file_save()
675      file_save();      file_save();
676  }  }
677    
678  bool MainWindow::file_save()  bool MainWindow::check_if_savable()
679  {  {
680      if (!file) return false;      if (!file) return false;
681      if (!file_has_name) return file_save_as();  
682        if (!file->GetFirstSample()) {
683            Gtk::MessageDialog(*this, _("The file could not be saved "
684                                        "because it contains no samples"),
685                               false, Gtk::MESSAGE_ERROR).run();
686            return false;
687        }
688    
689        for (gig::Instrument* instrument = file->GetFirstInstrument() ; instrument ;
690             instrument = file->GetNextInstrument()) {
691            if (!instrument->GetFirstRegion()) {
692                Gtk::MessageDialog(*this, _("The file could not be saved "
693                                            "because there are instruments "
694                                            "that have no regions"),
695                                   false, Gtk::MESSAGE_ERROR).run();
696                return false;
697            }
698        }
699        return true;
700    }
701    
702    bool MainWindow::file_save()
703    {
704        if (!check_if_savable()) return false;
705        if (!file_is_shared && !file_has_name) return file_save_as();
706    
707      std::cout << "Saving file\n" << std::flush;      std::cout << "Saving file\n" << std::flush;
708        file_structure_to_be_changed_signal.emit(this->file);
709      try {      try {
710          file->Save();          file->Save();
711          if (file_is_changed) {          if (file_is_changed) {
# Line 496  bool MainWindow::file_save() Line 713  bool MainWindow::file_save()
713              file_is_changed = false;              file_is_changed = false;
714          }          }
715      } catch (RIFF::Exception e) {      } catch (RIFF::Exception e) {
716          Glib::ustring txt = "Could not save file: " + e.Message;          file_structure_changed_signal.emit(this->file);
717            Glib::ustring txt = _("Could not save file: ") + e.Message;
718          Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);          Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
719          msg.run();          msg.run();
720          return false;          return false;
721      }      }
722      std::cout << "Saving file done\n" << std::flush;      std::cout << "Saving file done\n" << std::flush;
723      __import_queued_samples();      __import_queued_samples();
724        file_structure_changed_signal.emit(this->file);
725      return true;      return true;
726  }  }
727    
728  void MainWindow::on_action_file_save_as()  void MainWindow::on_action_file_save_as()
729  {  {
730        if (!check_if_savable()) return;
731      file_save_as();      file_save_as();
732  }  }
733    
734  bool MainWindow::file_save_as()  bool MainWindow::file_save_as()
735  {  {
     if (!file) return false;  
736      Gtk::FileChooserDialog dialog(*this, _("Save as"), Gtk::FILE_CHOOSER_ACTION_SAVE);      Gtk::FileChooserDialog dialog(*this, _("Save as"), Gtk::FILE_CHOOSER_ACTION_SAVE);
737      dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);      dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
738      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 754  bool MainWindow::file_save_as()
754      dialog.set_current_name(Glib::filename_display_basename(filename));      dialog.set_current_name(Glib::filename_display_basename(filename));
755    
756      if (dialog.run() == Gtk::RESPONSE_OK) {      if (dialog.run() == Gtk::RESPONSE_OK) {
757            file_structure_to_be_changed_signal.emit(this->file);
758          try {          try {
759              std::string filename = dialog.get_filename();              std::string filename = dialog.get_filename();
760              if (!Glib::str_has_suffix(filename, ".gig")) {              if (!Glib::str_has_suffix(filename, ".gig")) {
# Line 548  bool MainWindow::file_save_as() Line 768  bool MainWindow::file_save_as()
768              file_has_name = true;              file_has_name = true;
769              file_is_changed = false;              file_is_changed = false;
770          } catch (RIFF::Exception e) {          } catch (RIFF::Exception e) {
771              Glib::ustring txt = "Could not save file: " + e.Message;              file_structure_changed_signal.emit(this->file);
772                Glib::ustring txt = _("Could not save file: ") + e.Message;
773              Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);              Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
774              msg.run();              msg.run();
775              return false;              return false;
776          }          }
777          __import_queued_samples();          __import_queued_samples();
778            file_structure_changed_signal.emit(this->file);
779          return true;          return true;
780      }      }
781      return false;      return false;
# Line 576  void MainWindow::__import_queued_samples Line 798  void MainWindow::__import_queued_samples
798              int bitdepth;              int bitdepth;
799              switch (info.format & 0xff) {              switch (info.format & 0xff) {
800                  case SF_FORMAT_PCM_S8:                  case SF_FORMAT_PCM_S8:
                     bitdepth = 16; // we simply convert to 16 bit for now  
                     break;  
801                  case SF_FORMAT_PCM_16:                  case SF_FORMAT_PCM_16:
802                    case SF_FORMAT_PCM_U8:
803                      bitdepth = 16;                      bitdepth = 16;
804                      break;                      break;
805                  case SF_FORMAT_PCM_24:                  case SF_FORMAT_PCM_24:
                     bitdepth = 32; // we simply convert to 32 bit for now  
                     break;  
806                  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;  
807                  case SF_FORMAT_FLOAT:                  case SF_FORMAT_FLOAT:
                     bitdepth = 32;  
                     break;  
808                  case SF_FORMAT_DOUBLE:                  case SF_FORMAT_DOUBLE:
809                      bitdepth = 32; // I guess we will always truncate this to 32 bit                      bitdepth = 24;
810                      break;                      break;
811                  default:                  default:
812                      sf_close(hFile); // close sound file                      sf_close(hFile); // close sound file
813                      throw std::string("format not supported"); // unsupported subformat (yet?)                      throw std::string("format not supported"); // unsupported subformat (yet?)
814              }              }
815              // allocate appropriate copy buffer (TODO: for now we copy  
816              // 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;  
817              switch (bitdepth) {              switch (bitdepth) {
818                  case 16:                  case 16: {
819                      buffer = new int8_t[2 * info.channels * info.frames];                      short* buffer = new short[bufsize * info.channels];
820                      // libsndfile does the conversion for us (if needed)                      sf_count_t cnt = info.frames;
821                      sf_readf_short(hFile, (short*) buffer, info.frames);                      while (cnt) {
822                            // libsndfile does the conversion for us (if needed)
823                            int n = sf_readf_short(hFile, buffer, bufsize);
824                            // write from buffer directly (physically) into .gig file
825                            iter->gig_sample->Write(buffer, n);
826                            cnt -= n;
827                        }
828                        delete[] buffer;
829                      break;                      break;
830                  case 32:                  }
831                      buffer = new int8_t[4 * info.channels * info.frames];                  case 24: {
832                      // libsndfile does the conversion for us (if needed)                      int* srcbuf = new int[bufsize * info.channels];
833                      sf_readf_int(hFile, (int*) buffer, info.frames);                      uint8_t* dstbuf = new uint8_t[bufsize * 3 * info.channels];
834                        sf_count_t cnt = info.frames;
835                        while (cnt) {
836                            // libsndfile returns 32 bits, convert to 24
837                            int n = sf_readf_int(hFile, srcbuf, bufsize);
838                            int j = 0;
839                            for (int i = 0 ; i < n * info.channels ; i++) {
840                                dstbuf[j++] = srcbuf[i] >> 8;
841                                dstbuf[j++] = srcbuf[i] >> 16;
842                                dstbuf[j++] = srcbuf[i] >> 24;
843                            }
844                            // write from buffer directly (physically) into .gig file
845                            iter->gig_sample->Write(dstbuf, n);
846                            cnt -= n;
847                        }
848                        delete[] srcbuf;
849                        delete[] dstbuf;
850                      break;                      break;
851                    }
852              }              }
             // write from buffer directly (physically) into .gig file  
             (*iter).gig_sample->Write(buffer, info.frames);  
853              // cleanup              // cleanup
854              sf_close(hFile);              sf_close(hFile);
             delete[] buffer;  
855              // on success we remove the sample from the import queue,              // on success we remove the sample from the import queue,
856              // otherwise keep it, maybe it works the next time ?              // otherwise keep it, maybe it works the next time ?
857              std::list<SampleImportItem>::iterator cur = iter;              std::list<SampleImportItem>::iterator cur = iter;
# Line 635  void MainWindow::__import_queued_samples Line 866  void MainWindow::__import_queued_samples
866      }      }
867      // show error message box when some sample(s) could not be imported      // show error message box when some sample(s) could not be imported
868      if (error_files.size()) {      if (error_files.size()) {
869          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;
870          Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);          Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
871          msg.run();          msg.run();
872      }      }
# Line 652  void MainWindow::on_action_help_about() Line 883  void MainWindow::on_action_help_about()
883  #ifdef ABOUT_DIALOG  #ifdef ABOUT_DIALOG
884      Gtk::AboutDialog dialog;      Gtk::AboutDialog dialog;
885      dialog.set_version(VERSION);      dialog.set_version(VERSION);
886        dialog.set_copyright("Copyright (C) 2006,2007 Andreas Persson");
887        dialog.set_comments(
888            "Released under the GNU General Public License.\n"
889            "\n"
890            "Please notice that this is still a very young instrument editor. "
891            "So better backup your Gigasampler files before editing them with "
892            "this application.\n"
893            "\n"
894            "Please report bugs to: http://bugs.linuxsampler.org"
895        );
896        dialog.set_website("http://www.linuxsampler.org");
897        dialog.set_website_label("http://www.linuxsampler.org");
898      dialog.run();      dialog.run();
899  #endif  #endif
900  }  }
901    
902  PropDialog::PropDialog()  PropDialog::PropDialog()
903      : table(2,1)      : table(2,1),
904          eName("Name"),
905          eCreationDate("Creation date"),
906          eComments("Comments"),
907          eProduct("Product"),
908          eCopyright("Copyright"),
909          eArtists("Artists"),
910          eGenre("Genre"),
911          eKeywords("Keywords"),
912          eEngineer("Engineer"),
913          eTechnician("Technician"),
914          eSoftware("Software"),
915          eMedium("Medium"),
916          eSource("Source"),
917          eSourceForm("Source form"),
918          eCommissioned("Commissioned"),
919          eSubject("Subject"),
920          quitButton(Gtk::Stock::CLOSE),
921          update_model(0)
922  {  {
923        set_title("File Properties");
924        eName.set_width_chars(50);
925    
926        connect(eName, &DLS::Info::Name);
927        connect(eCreationDate, &DLS::Info::CreationDate);
928        connect(eComments, &DLS::Info::Comments);
929        connect(eProduct, &DLS::Info::Product);
930        connect(eCopyright, &DLS::Info::Copyright);
931        connect(eArtists, &DLS::Info::Artists);
932        connect(eGenre, &DLS::Info::Genre);
933        connect(eKeywords, &DLS::Info::Keywords);
934        connect(eEngineer, &DLS::Info::Engineer);
935        connect(eTechnician, &DLS::Info::Technician);
936        connect(eSoftware, &DLS::Info::Software);
937        connect(eMedium, &DLS::Info::Medium);
938        connect(eSource, &DLS::Info::Source);
939        connect(eSourceForm, &DLS::Info::SourceForm);
940        connect(eCommissioned, &DLS::Info::Commissioned);
941        connect(eSubject, &DLS::Info::Subject);
942    
943        table.add(eName);
944        table.add(eCreationDate);
945        table.add(eComments);
946        table.add(eProduct);
947        table.add(eCopyright);
948        table.add(eArtists);
949        table.add(eGenre);
950        table.add(eKeywords);
951        table.add(eEngineer);
952        table.add(eTechnician);
953        table.add(eSoftware);
954        table.add(eMedium);
955        table.add(eSource);
956        table.add(eSourceForm);
957        table.add(eCommissioned);
958        table.add(eSubject);
959    
960      table.set_col_spacings(5);      table.set_col_spacings(5);
961      const char* propLabels[] = {      add(vbox);
962          "Name:",      table.set_border_width(5);
963          "CreationDate:",      vbox.add(table);
964          "Comments:", // TODO: multiline      vbox.pack_start(buttonBox, Gtk::PACK_SHRINK);
965          "Product:",      buttonBox.set_layout(Gtk::BUTTONBOX_END);
966          "Copyright:",      buttonBox.set_border_width(5);
967          "Artists:",      buttonBox.show();
968          "Genre:",      buttonBox.pack_start(quitButton);
969          "Keywords:",      quitButton.set_flags(Gtk::CAN_DEFAULT);
970          "Engineer:",      quitButton.grab_focus();
971          "Technician:",      quitButton.signal_clicked().connect(
972          "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);  
     }  
973    
974      add(table);      quitButton.show();
975      // add_button(Gtk::Stock::CANCEL, 0);      vbox.show();
     // add_button(Gtk::Stock::OK, 1);  
976      show_all_children();      show_all_children();
977  }  }
978    
979  void PropDialog::set_info(DLS::Info* info)  void PropDialog::set_info(DLS::Info* info)
980  {  {
981      entry[0].set_text(info->Name);      this->info = info;
982      entry[1].set_text(info->CreationDate);      update_model++;
983      entry[2].set_text(Glib::convert(info->Comments, "UTF-8", "ISO-8859-1"));      eName.set_value(info->Name);
984      entry[3].set_text(info->Product);      eCreationDate.set_value(info->CreationDate);
985      entry[4].set_text(info->Copyright);      eComments.set_value(info->Comments);
986      entry[5].set_text(info->Artists);      eProduct.set_value(info->Product);
987      entry[6].set_text(info->Genre);      eCopyright.set_value(info->Copyright);
988      entry[7].set_text(info->Keywords);      eArtists.set_value(info->Artists);
989      entry[8].set_text(info->Engineer);      eGenre.set_value(info->Genre);
990      entry[9].set_text(info->Technician);      eKeywords.set_value(info->Keywords);
991      entry[10].set_text(info->Software);      eEngineer.set_value(info->Engineer);
992      entry[11].set_text(info->Medium);      eTechnician.set_value(info->Technician);
993      entry[12].set_text(info->Source);      eSoftware.set_value(info->Software);
994      entry[13].set_text(info->SourceForm);      eMedium.set_value(info->Medium);
995      entry[14].set_text(info->Commissioned);      eSource.set_value(info->Source);
996      entry[15].set_text(info->Subject);      eSourceForm.set_value(info->SourceForm);
997        eCommissioned.set_value(info->Commissioned);
998        eSubject.set_value(info->Subject);
999        update_model--;
1000  }  }
1001    
1002  void InstrumentProps::add_prop(BoolEntry& boolentry)  sigc::signal<void>& PropDialog::signal_info_changed()
1003  {  {
1004      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());  
1005  }  }
1006    
1007  void InstrumentProps::add_prop(BoolEntryPlus6& boolentry)  void InstrumentProps::set_IsDrum(bool value)
1008  {  {
1009      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());  
1010  }  }
1011    
1012  void InstrumentProps::add_prop(LabelWidget& prop)  void InstrumentProps::set_MIDIBank(uint16_t value)
1013  {  {
1014      table.attach(prop.label, 0, 1, rowno, rowno + 1,      instrument->MIDIBank = value;
1015                   Gtk::FILL, Gtk::SHRINK);  }
1016      table.attach(prop.widget, 1, 2, rowno, rowno + 1,  
1017                   Gtk::FILL | Gtk::EXPAND, Gtk::SHRINK);  void InstrumentProps::set_MIDIProgram(uint32_t value)
1018      rowno++;  {
1019      prop.signal_changed_by_user().connect(instrument_changed.make_slot());      instrument->MIDIProgram = value;
1020    }
1021    
1022    void InstrumentProps::set_DimensionKeyRange_low(uint8_t value)
1023    {
1024        instrument->DimensionKeyRange.low = value;
1025        if (value > instrument->DimensionKeyRange.high) {
1026            eDimensionKeyRangeHigh.set_value(value);
1027        }
1028    }
1029    
1030    void InstrumentProps::set_DimensionKeyRange_high(uint8_t value)
1031    {
1032        instrument->DimensionKeyRange.high = value;
1033        if (value < instrument->DimensionKeyRange.low) {
1034            eDimensionKeyRangeLow.set_value(value);
1035        }
1036  }  }
1037    
1038  InstrumentProps::InstrumentProps()  InstrumentProps::InstrumentProps()
# Line 752  InstrumentProps::InstrumentProps() Line 1049  InstrumentProps::InstrumentProps()
1049        ePitchbendRange("Pitchbend range", 0, 12),        ePitchbendRange("Pitchbend range", 0, 12),
1050        ePianoReleaseMode("Piano release mode"),        ePianoReleaseMode("Piano release mode"),
1051        eDimensionKeyRangeLow("Dimension key range low"),        eDimensionKeyRangeLow("Dimension key range low"),
1052        eDimensionKeyRangeHigh("Dimension key range high")        eDimensionKeyRangeHigh("Dimension key range high"),
1053          update_model(0)
1054  {  {
1055      set_title("Instrument properties");      set_title("Instrument Properties");
1056    
1057        connect(eIsDrum, &InstrumentProps::set_IsDrum);
1058        connect(eMIDIBank, &InstrumentProps::set_MIDIBank);
1059        connect(eMIDIProgram, &InstrumentProps::set_MIDIProgram);
1060        connect(eAttenuation, &gig::Instrument::Attenuation);
1061        connect(eGainPlus6, &gig::Instrument::Attenuation);
1062        connect(eEffectSend, &gig::Instrument::EffectSend);
1063        connect(eFineTune, &gig::Instrument::FineTune);
1064        connect(ePitchbendRange, &gig::Instrument::PitchbendRange);
1065        connect(ePianoReleaseMode, &gig::Instrument::PianoReleaseMode);
1066        connect(eDimensionKeyRangeLow,
1067                &InstrumentProps::set_DimensionKeyRange_low);
1068        connect(eDimensionKeyRangeHigh,
1069                &InstrumentProps::set_DimensionKeyRange_high);
1070    
     rowno = 0;  
1071      table.set_col_spacings(5);      table.set_col_spacings(5);
1072    
1073      add_prop(eName);      table.add(eName);
1074      add_prop(eIsDrum);      table.add(eIsDrum);
1075      add_prop(eMIDIBank);      table.add(eMIDIBank);
1076      add_prop(eMIDIProgram);      table.add(eMIDIProgram);
1077      add_prop(eAttenuation);      table.add(eAttenuation);
1078      add_prop(eGainPlus6);      table.add(eGainPlus6);
1079      add_prop(eEffectSend);      table.add(eEffectSend);
1080      add_prop(eFineTune);      table.add(eFineTune);
1081      add_prop(ePitchbendRange);      table.add(ePitchbendRange);
1082      add_prop(ePianoReleaseMode);      table.add(ePianoReleaseMode);
1083      add_prop(eDimensionKeyRangeLow);      table.add(eDimensionKeyRangeLow);
1084      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));  
1085    
1086      add(vbox);      add(vbox);
1087      table.set_border_width(5);      table.set_border_width(5);
# Line 799  InstrumentProps::InstrumentProps() Line 1105  InstrumentProps::InstrumentProps()
1105    
1106  void InstrumentProps::set_instrument(gig::Instrument* instrument)  void InstrumentProps::set_instrument(gig::Instrument* instrument)
1107  {  {
1108      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);  
 }  
   
 void InstrumentProps::key_range_low_changed()  
 {  
     double l = eDimensionKeyRangeLow.get_value();  
     double h = eDimensionKeyRangeHigh.get_value();  
     if (h < l) eDimensionKeyRangeHigh.set_value(l);  
 }  
1109    
1110  void InstrumentProps::key_range_high_changed()      update_model++;
1111  {      eName.set_value(instrument->pInfo->Name);
1112      double l = eDimensionKeyRangeLow.get_value();      eIsDrum.set_value(instrument->IsDrum);
1113      double h = eDimensionKeyRangeHigh.get_value();      eMIDIBank.set_value(instrument->MIDIBank);
1114      if (h < l) eDimensionKeyRangeLow.set_value(h);      eMIDIProgram.set_value(instrument->MIDIProgram);
1115        eAttenuation.set_value(instrument->Attenuation);
1116        eGainPlus6.set_value(instrument->Attenuation);
1117        eEffectSend.set_value(instrument->EffectSend);
1118        eFineTune.set_value(instrument->FineTune);
1119        ePitchbendRange.set_value(instrument->PitchbendRange);
1120        ePianoReleaseMode.set_value(instrument->PianoReleaseMode);
1121        eDimensionKeyRangeLow.set_value(instrument->DimensionKeyRange.low);
1122        eDimensionKeyRangeHigh.set_value(instrument->DimensionKeyRange.high);
1123        update_model--;
1124  }  }
1125    
1126  sigc::signal<void> InstrumentProps::signal_instrument_changed()  sigc::signal<void>& InstrumentProps::signal_instrument_changed()
1127  {  {
1128      return instrument_changed;      return instrument_changed;
1129  }  }
# Line 842  void MainWindow::file_changed() Line 1136  void MainWindow::file_changed()
1136      }      }
1137  }  }
1138    
1139  void MainWindow::load_gig(gig::File* gig, const char* filename)  void MainWindow::load_gig(gig::File* gig, const char* filename, bool isSharedInstrument)
1140  {  {
1141      file = 0;      file = 0;
1142        set_file_is_shared(isSharedInstrument);
1143    
1144      this->filename = filename ? filename : _("Unsaved Gig File");      this->filename = filename ? filename : _("Unsaved Gig File");
1145      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 1202  void MainWindow::load_gig(gig::File* gig
1202    
1203  void MainWindow::show_instr_props()  void MainWindow::show_instr_props()
1204  {  {
1205      Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();      gig::Instrument* instrument = get_instrument();
1206      Gtk::TreeModel::iterator it = tree_sel_ref->get_selected();      if (instrument)
     if (it)  
1207      {      {
1208          Gtk::TreeModel::Row row = *it;          instrumentProps.set_instrument(instrument);
1209          if (row[m_Columns.m_col_instr])          instrumentProps.show();
1210          {          instrumentProps.deiconify();
1211              instrumentProps.set_instrument(row[m_Columns.m_col_instr]);      }
1212              instrumentProps.show();  }
1213              instrumentProps.deiconify();  
1214          }  void MainWindow::on_action_view_status_bar() {
1215        Gtk::CheckMenuItem* item =
1216            dynamic_cast<Gtk::CheckMenuItem*>(uiManager->get_widget("/MenuBar/MenuView/Statusbar"));
1217        if (!item) {
1218            std::cerr << "/MenuBar/MenuView/Statusbar == NULL\n";
1219            return;
1220      }      }
1221        if (item->get_active()) m_StatusBar.show();
1222        else                    m_StatusBar.hide();
1223  }  }
1224    
1225  void MainWindow::on_button_release(GdkEventButton* button)  void MainWindow::on_button_release(GdkEventButton* button)
# Line 978  void MainWindow::on_action_add_instrumen Line 1279  void MainWindow::on_action_add_instrumen
1279    
1280  void MainWindow::on_action_remove_instrument() {  void MainWindow::on_action_remove_instrument() {
1281      if (!file) return;      if (!file) return;
1282        if (file_is_shared) {
1283            Gtk::MessageDialog msg(
1284                *this,
1285                 _("You cannot delete an instrument from this file, since it's "
1286                   "currently used by the sampler."),
1287                 false, Gtk::MESSAGE_INFO
1288            );
1289            msg.run();
1290            return;
1291        }
1292    
1293      Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeView.get_selection();      Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeView.get_selection();
1294      Gtk::TreeModel::iterator it = sel->get_selected();      Gtk::TreeModel::iterator it = sel->get_selected();
1295      if (it) {      if (it) {
# Line 1073  void MainWindow::on_action_add_sample() Line 1385  void MainWindow::on_action_add_sample()
1385                  int bitdepth;                  int bitdepth;
1386                  switch (info.format & 0xff) {                  switch (info.format & 0xff) {
1387                      case SF_FORMAT_PCM_S8:                      case SF_FORMAT_PCM_S8:
                         bitdepth = 16; // we simply convert to 16 bit for now  
                         break;  
1388                      case SF_FORMAT_PCM_16:                      case SF_FORMAT_PCM_16:
1389                        case SF_FORMAT_PCM_U8:
1390                          bitdepth = 16;                          bitdepth = 16;
1391                          break;                          break;
1392                      case SF_FORMAT_PCM_24:                      case SF_FORMAT_PCM_24:
                         bitdepth = 32; // we simply convert to 32 bit for now  
                         break;  
1393                      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;  
1394                      case SF_FORMAT_FLOAT:                      case SF_FORMAT_FLOAT:
                         bitdepth = 32;  
                         break;  
1395                      case SF_FORMAT_DOUBLE:                      case SF_FORMAT_DOUBLE:
1396                          bitdepth = 32; // I guess we will always truncate this to 32 bit                          bitdepth = 24;
1397                          break;                          break;
1398                      default:                      default:
1399                          sf_close(hFile); // close sound file                          sf_close(hFile); // close sound file
# Line 1113  void MainWindow::on_action_add_sample() Line 1415  void MainWindow::on_action_add_sample()
1415                  sample->BitDepth = bitdepth;                  sample->BitDepth = bitdepth;
1416                  sample->FrameSize = bitdepth / 8/*1 byte are 8 bits*/ * info.channels;                  sample->FrameSize = bitdepth / 8/*1 byte are 8 bits*/ * info.channels;
1417                  sample->SamplesPerSecond = info.samplerate;                  sample->SamplesPerSecond = info.samplerate;
1418                    sample->AverageBytesPerSecond = sample->FrameSize * sample->SamplesPerSecond;
1419                    sample->BlockAlign = sample->FrameSize;
1420                    sample->SamplesTotal = info.frames;
1421    
1422                    SF_INSTRUMENT instrument;
1423                    if (sf_command(hFile, SFC_GET_INSTRUMENT,
1424                                   &instrument, sizeof(instrument)) != SF_FALSE)
1425                    {
1426                        sample->MIDIUnityNote = instrument.basenote;
1427    
1428    #if HAVE_SF_INSTRUMENT_LOOPS
1429                        if (instrument.loop_count && instrument.loops[0].mode != SF_LOOP_NONE) {
1430                            sample->Loops = 1;
1431    
1432                            switch (instrument.loops[0].mode) {
1433                            case SF_LOOP_FORWARD:
1434                                sample->LoopType = gig::loop_type_normal;
1435                                break;
1436                            case SF_LOOP_BACKWARD:
1437                                sample->LoopType = gig::loop_type_backward;
1438                                break;
1439                            case SF_LOOP_ALTERNATING:
1440                                sample->LoopType = gig::loop_type_bidirectional;
1441                                break;
1442                            }
1443                            sample->LoopStart = instrument.loops[0].start;
1444                            sample->LoopEnd = instrument.loops[0].end;
1445                            sample->LoopPlayCount = instrument.loops[0].count;
1446                            sample->LoopSize = sample->LoopEnd - sample->LoopStart + 1;
1447                        }
1448    #endif
1449                    }
1450    
1451                  // schedule resizing the sample (which will be done                  // schedule resizing the sample (which will be done
1452                  // physically when File::Save() is called)                  // physically when File::Save() is called)
1453                  sample->Resize(info.frames);                  sample->Resize(info.frames);
# Line 1141  void MainWindow::on_action_add_sample() Line 1476  void MainWindow::on_action_add_sample()
1476          }          }
1477          // 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
1478          if (error_files.size()) {          if (error_files.size()) {
1479              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;
1480              Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);              Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
1481              msg.run();              msg.run();
1482          }          }
# Line 1167  void MainWindow::on_action_remove_sample Line 1502  void MainWindow::on_action_remove_sample
1502                       pSample; pSample = group->GetNextSample()) {                       pSample; pSample = group->GetNextSample()) {
1503                      members.push_back(pSample);                      members.push_back(pSample);
1504                  }                  }
1505                    // notify everybody that we're going to remove these samples
1506                    samples_to_be_removed_signal.emit(members);
1507                  // delete the group in the .gig file including the                  // delete the group in the .gig file including the
1508                  // samples that belong to the group                  // samples that belong to the group
1509                  file->DeleteGroup(group);                  file->DeleteGroup(group);
1510                    // notify that we're done with removal
1511                    samples_removed_signal.emit();
1512                  // if sample(s) were just previously added, remove                  // if sample(s) were just previously added, remove
1513                  // them from the import queue                  // them from the import queue
1514                  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 1525  void MainWindow::on_action_remove_sample
1525                  }                  }
1526                  file_changed();                  file_changed();
1527              } else if (sample) {              } else if (sample) {
1528                    // notify everybody that we're going to remove this sample
1529                    std::list<gig::Sample*> lsamples;
1530                    lsamples.push_back(sample);
1531                    samples_to_be_removed_signal.emit(lsamples);
1532                  // remove sample from the .gig file                  // remove sample from the .gig file
1533                  file->DeleteSample(sample);                  file->DeleteSample(sample);
1534                    // notify that we're done with removal
1535                    samples_removed_signal.emit();
1536                  // if sample was just previously added, remove it from                  // if sample was just previously added, remove it from
1537                  // the import queue                  // the import queue
1538                  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 1544  void MainWindow::on_action_remove_sample
1544                          break;                          break;
1545                      }                      }
1546                  }                  }
1547                    dimreg_changed();
1548                  file_changed();                  file_changed();
1549              }              }
1550              // remove respective row(s) from samples tree view              // remove respective row(s) from samples tree view
1551              m_refSamplesTreeModel->erase(it);              m_refSamplesTreeModel->erase(it);
1552          } catch (RIFF::Exception e) {          } catch (RIFF::Exception e) {
1553                // pretend we're done with removal (i.e. to avoid dead locks)
1554                samples_removed_signal.emit();
1555                // show error message
1556              Gtk::MessageDialog msg(*this, e.Message.c_str(), false, Gtk::MESSAGE_ERROR);              Gtk::MessageDialog msg(*this, e.Message.c_str(), false, Gtk::MESSAGE_ERROR);
1557              msg.run();              msg.run();
1558          }          }
1559      }      }
1560  }  }
1561    
1562    // For some reason drag_data_get gets called two times for each
1563    // drag'n'drop (at least when target is an Entry). This work-around
1564    // makes sure the code in drag_data_get and drop_drag_data_received is
1565    // only executed once, as drag_begin only gets called once.
1566    void MainWindow::on_sample_treeview_drag_begin(const Glib::RefPtr<Gdk::DragContext>& context)
1567    {
1568        first_call_to_drag_data_get = true;
1569    }
1570    
1571  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>&,
1572                                                    Gtk::SelectionData& selection_data, guint, guint)                                                    Gtk::SelectionData& selection_data, guint, guint)
1573  {  {
1574        if (!first_call_to_drag_data_get) return;
1575        first_call_to_drag_data_get = false;
1576    
1577      // get selected sample      // get selected sample
1578      gig::Sample* sample = NULL;      gig::Sample* sample = NULL;
1579      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 1591  void MainWindow::on_sample_label_drop_dr
1591      const Glib::RefPtr<Gdk::DragContext>& context, int, int,      const Glib::RefPtr<Gdk::DragContext>& context, int, int,
1592      const Gtk::SelectionData& selection_data, guint, guint time)      const Gtk::SelectionData& selection_data, guint, guint time)
1593  {  {
     gig::DimensionRegion* dimregion = m_DimRegionChooser.get_dimregion();  
1594      gig::Sample* sample = *((gig::Sample**) selection_data.get_data());      gig::Sample* sample = *((gig::Sample**) selection_data.get_data());
1595    
1596      if (sample && dimregion && selection_data.get_length() == sizeof(gig::Sample*)) {      if (sample && selection_data.get_length() == sizeof(gig::Sample*)) {
1597          if (sample != dimregion->pSample) {          std::cout << "Drop received sample \"" <<
1598              dimregion->pSample = sample;              sample->pInfo->Name << "\"" << std::endl;
1599              dimreg_edit.wSample->set_text(dimregion->pSample->pInfo->Name.c_str());          // drop success
1600              std::cout << "Drop received sample \"" <<          context->drop_reply(true, time);
1601                  dimregion->pSample->pInfo->Name.c_str() << "\"" << std::endl;  
1602              // drop success          //TODO: we should better move most of the following code to DimRegionEdit::set_sample()
1603              context->drop_reply(true, time);  
1604              file_changed();          // notify everybody that we're going to alter the region
1605              return;          gig::Region* region = m_RegionChooser.get_region();
1606            region_to_be_changed_signal.emit(region);
1607    
1608            // find the samplechannel dimension
1609            gig::dimension_def_t* stereo_dimension = 0;
1610            for (int i = 0 ; i < region->Dimensions ; i++) {
1611                if (region->pDimensionDefinitions[i].dimension ==
1612                    gig::dimension_samplechannel) {
1613                    stereo_dimension = &region->pDimensionDefinitions[i];
1614                    break;
1615                }
1616            }
1617            bool channels_changed = false;
1618            if (sample->Channels == 1 && stereo_dimension) {
1619                // remove the samplechannel dimension
1620                region->DeleteDimension(stereo_dimension);
1621                channels_changed = true;
1622                region_changed();
1623            }
1624            dimreg_edit.set_sample(sample);
1625    
1626            if (sample->Channels == 2 && !stereo_dimension) {
1627                // add samplechannel dimension
1628                gig::dimension_def_t dim;
1629                dim.dimension = gig::dimension_samplechannel;
1630                dim.bits = 1;
1631                dim.zones = 2;
1632                region->AddDimension(&dim);
1633                channels_changed = true;
1634                region_changed();
1635            }
1636            if (channels_changed) {
1637                // unmap all samples with wrong number of channels
1638                // TODO: maybe there should be a warning dialog for this
1639                for (int i = 0 ; i < region->DimensionRegions ; i++) {
1640                    gig::DimensionRegion* d = region->pDimensionRegions[i];
1641                    if (d->pSample && d->pSample->Channels != sample->Channels) {
1642                        gig::Sample* oldref = d->pSample;
1643                        d->pSample = NULL;
1644                        sample_ref_changed_signal.emit(oldref, NULL);
1645                    }
1646                }
1647          }          }
1648    
1649            // notify we're done with altering
1650            region_changed_signal.emit(region);
1651    
1652            file_changed();
1653    
1654            return;
1655      }      }
1656      // drop failed      // drop failed
1657      context->drop_reply(false, time);      context->drop_reply(false, time);
# Line 1282  void MainWindow::instrument_name_changed Line 1690  void MainWindow::instrument_name_changed
1690          file_changed();          file_changed();
1691      }      }
1692  }  }
1693    
1694    void MainWindow::set_file_is_shared(bool b) {
1695        this->file_is_shared = b;
1696    
1697        if (file_is_shared) {
1698            m_AttachedStateLabel.set_label(_("live-mode"));
1699            m_AttachedStateImage.set(
1700                Gdk::Pixbuf::create_from_xpm_data(status_attached_xpm)
1701            );
1702        } else {
1703            m_AttachedStateLabel.set_label(_("stand-alone"));
1704            m_AttachedStateImage.set(
1705                Gdk::Pixbuf::create_from_xpm_data(status_detached_xpm)
1706            );
1707        }
1708    }
1709    
1710    sigc::signal<void, gig::File*>& MainWindow::signal_file_structure_to_be_changed() {
1711        return file_structure_to_be_changed_signal;
1712    }
1713    
1714    sigc::signal<void, gig::File*>& MainWindow::signal_file_structure_changed() {
1715        return file_structure_changed_signal;
1716    }
1717    
1718    sigc::signal<void, std::list<gig::Sample*> >& MainWindow::signal_samples_to_be_removed() {
1719        return samples_to_be_removed_signal;
1720    }
1721    
1722    sigc::signal<void>& MainWindow::signal_samples_removed() {
1723        return samples_removed_signal;
1724    }
1725    
1726    sigc::signal<void, gig::Region*>& MainWindow::signal_region_to_be_changed() {
1727        return region_to_be_changed_signal;
1728    }
1729    
1730    sigc::signal<void, gig::Region*>& MainWindow::signal_region_changed() {
1731        return region_changed_signal;
1732    }
1733    
1734    sigc::signal<void, gig::Sample*/*old*/, gig::Sample*/*new*/>& MainWindow::signal_sample_ref_changed() {
1735        return sample_ref_changed_signal;
1736    }
1737    
1738    sigc::signal<void, gig::DimensionRegion*>& MainWindow::signal_dimreg_to_be_changed() {
1739        return dimreg_to_be_changed_signal;
1740    }
1741    
1742    sigc::signal<void, gig::DimensionRegion*>& MainWindow::signal_dimreg_changed() {
1743        return dimreg_changed_signal;
1744    }
1745    
1746    sigc::signal<void, int/*key*/, int/*velocity*/>& MainWindow::signal_note_on() {
1747        return note_on_signal;
1748    }
1749    
1750    sigc::signal<void, int/*key*/, int/*velocity*/>& MainWindow::signal_note_off() {
1751        return note_off_signal;
1752    }

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

  ViewVC Help
Powered by ViewVC