/[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 1261 by persson, Thu Jul 5 17:12:20 2007 UTC revision 1411 by schoenebeck, Fri Oct 12 17:46:29 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 26  Line 25 
25  #include <gtkmm/targetentry.h>  #include <gtkmm/targetentry.h>
26  #include <gtkmm/main.h>  #include <gtkmm/main.h>
27    
28    #include "global.h"
29    
30  #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
31  #define ABOUT_DIALOG  #define ABOUT_DIALOG
32  #include <gtkmm/aboutdialog.h>  #include <gtkmm/aboutdialog.h>
33  #endif  #endif
34    
35    #if (GLIBMM_MAJOR_VERSION == 2 && GLIBMM_MINOR_VERSION < 6) || GLIBMM_MAJOR_VERSION < 2
36    namespace Glib {
37    Glib::ustring filename_display_basename(const std::string& filename)
38    {
39        gchar* gstr = g_path_get_basename(filename.c_str());
40        Glib::ustring str(gstr);
41        g_free(gstr);
42        return Glib::filename_to_utf8(str);
43    }
44    }
45    #endif
46    
47  #include <stdio.h>  #include <stdio.h>
48  #include <sndfile.h>  #include <sndfile.h>
49    
50  #include "mainwindow.h"  #include "mainwindow.h"
51    
52  #define _(String) gettext(String)  #include "../../gfx/status_attached.xpm"
53    #include "../../gfx/status_detached.xpm"
54    
55  template<class T> inline std::string ToString(T o) {  template<class T> inline std::string ToString(T o) {
56      std::stringstream ss;      std::stringstream ss;
# Line 199  MainWindow::MainWindow() Line 213  MainWindow::MainWindow()
213      m_VBox.pack_start(m_HPaned);      m_VBox.pack_start(m_HPaned);
214      m_VBox.pack_start(m_RegionChooser, Gtk::PACK_SHRINK);      m_VBox.pack_start(m_RegionChooser, Gtk::PACK_SHRINK);
215      m_VBox.pack_start(m_DimRegionChooser, Gtk::PACK_SHRINK);      m_VBox.pack_start(m_DimRegionChooser, Gtk::PACK_SHRINK);
216        m_VBox.pack_start(m_StatusBar, Gtk::PACK_SHRINK);
217    
218        // Status Bar:
219        m_StatusBar.pack_start(m_AttachedStateLabel, Gtk::PACK_SHRINK);
220        m_StatusBar.pack_start(m_AttachedStateImage, Gtk::PACK_SHRINK);
221        m_StatusBar.show();
222    
223      m_RegionChooser.signal_region_selected().connect(      m_RegionChooser.signal_region_selected().connect(
224          sigc::mem_fun(*this, &MainWindow::region_changed) );          sigc::mem_fun(*this, &MainWindow::region_changed) );
# Line 234  MainWindow::MainWindow() Line 254  MainWindow::MainWindow()
254      std::list<Gtk::TargetEntry> drag_target_gig_sample;      std::list<Gtk::TargetEntry> drag_target_gig_sample;
255      drag_target_gig_sample.push_back( Gtk::TargetEntry("gig::Sample") );      drag_target_gig_sample.push_back( Gtk::TargetEntry("gig::Sample") );
256      m_TreeViewSamples.drag_source_set(drag_target_gig_sample);      m_TreeViewSamples.drag_source_set(drag_target_gig_sample);
257        m_TreeViewSamples.signal_drag_begin().connect(
258            sigc::mem_fun(*this, &MainWindow::on_sample_treeview_drag_begin)
259        );
260      m_TreeViewSamples.signal_drag_data_get().connect(      m_TreeViewSamples.signal_drag_data_get().connect(
261          sigc::mem_fun(*this, &MainWindow::on_sample_treeview_drag_data_get)          sigc::mem_fun(*this, &MainWindow::on_sample_treeview_drag_data_get)
262      );      );
# Line 242  MainWindow::MainWindow() Line 265  MainWindow::MainWindow()
265          sigc::mem_fun(*this, &MainWindow::on_sample_label_drop_drag_data_received)          sigc::mem_fun(*this, &MainWindow::on_sample_label_drop_drag_data_received)
266      );      );
267      dimreg_edit.signal_dimreg_changed().connect(      dimreg_edit.signal_dimreg_changed().connect(
268          sigc::mem_fun(*this, &MainWindow::file_changed));          sigc::hide(sigc::mem_fun(*this, &MainWindow::file_changed)));
269      m_RegionChooser.signal_instrument_changed().connect(      m_RegionChooser.signal_instrument_changed().connect(
270          sigc::mem_fun(*this, &MainWindow::file_changed));          sigc::mem_fun(*this, &MainWindow::file_changed));
271      m_DimRegionChooser.signal_region_changed().connect(      m_DimRegionChooser.signal_region_changed().connect(
272          sigc::mem_fun(*this, &MainWindow::file_changed));          sigc::mem_fun(*this, &MainWindow::file_changed));
273      instrumentProps.signal_instrument_changed().connect(      instrumentProps.signal_instrument_changed().connect(
274          sigc::mem_fun(*this, &MainWindow::file_changed));          sigc::mem_fun(*this, &MainWindow::file_changed));
275    
276        dimreg_edit.signal_dimreg_to_be_changed().connect(
277            dimreg_to_be_changed_signal.make_slot());
278        dimreg_edit.signal_dimreg_changed().connect(
279            dimreg_changed_signal.make_slot());
280        dimreg_edit.signal_sample_ref_changed().connect(
281            sample_ref_changed_signal.make_slot());
282    
283        m_RegionChooser.signal_instrument_struct_to_be_changed().connect(
284            sigc::hide(
285                sigc::bind(
286                    file_structure_to_be_changed_signal.make_slot(),
287                    sigc::ref(this->file)
288                )
289            )
290        );
291        m_RegionChooser.signal_instrument_struct_changed().connect(
292            sigc::hide(
293                sigc::bind(
294                    file_structure_changed_signal.make_slot(),
295                    sigc::ref(this->file)
296                )
297            )
298        );
299        m_RegionChooser.signal_region_to_be_changed().connect(
300            region_to_be_changed_signal.make_slot());
301        m_RegionChooser.signal_region_changed_signal().connect(
302            region_changed_signal.make_slot());
303    
304      file = 0;      file = 0;
305      file_is_changed = false;      file_is_changed = false;
306        set_file_is_shared(false);
307    
308      show_all_children();      show_all_children();
309    
310        // start with a new gig file by default
311        on_action_file_new();
312  }  }
313    
314  MainWindow::~MainWindow()  MainWindow::~MainWindow()
# Line 261  MainWindow::~MainWindow() Line 317  MainWindow::~MainWindow()
317    
318  bool MainWindow::on_delete_event(GdkEventAny* event)  bool MainWindow::on_delete_event(GdkEventAny* event)
319  {  {
320      return file_is_changed && !close_confirmation_dialog();      return !file_is_shared && file_is_changed && !close_confirmation_dialog();
321  }  }
322    
323  void MainWindow::on_action_quit()  void MainWindow::on_action_quit()
324  {  {
325      if (file_is_changed && !close_confirmation_dialog()) return;      if (!file_is_shared && file_is_changed && !close_confirmation_dialog()) return;
326      hide();      hide();
327  }  }
328    
# Line 380  void MainWindow::__clear() { Line 436  void MainWindow::__clear() {
436      m_refTreeModel->clear();      m_refTreeModel->clear();
437      m_refSamplesTreeModel->clear();      m_refSamplesTreeModel->clear();
438      // free libgig's gig::File instance      // free libgig's gig::File instance
439      if (file) {      if (file && !file_is_shared) delete file;
440          delete file;      file = NULL;
441          file = NULL;      set_file_is_shared(false);
     }  
442  }  }
443    
444  void MainWindow::on_action_file_new()  void MainWindow::on_action_file_new()
445  {  {
446      if (file_is_changed && !close_confirmation_dialog()) return;      if (!file_is_shared && file_is_changed && !close_confirmation_dialog()) return;
447    
448        if (file_is_shared && !leaving_shared_mode_dialog()) return;
449    
450      // clear all GUI elements      // clear all GUI elements
451      __clear();      __clear();
# Line 407  bool MainWindow::close_confirmation_dial Line 464  bool MainWindow::close_confirmation_dial
464                                   Glib::filename_display_basename(filename).c_str());                                   Glib::filename_display_basename(filename).c_str());
465      Gtk::MessageDialog dialog(*this, msg, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_NONE);      Gtk::MessageDialog dialog(*this, msg, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_NONE);
466      g_free(msg);      g_free(msg);
467    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION >= 6) || GTKMM_MAJOR_VERSION > 2
468      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."));
469    #endif
470      dialog.add_button(_("Close _Without Saving"), Gtk::RESPONSE_NO);      dialog.add_button(_("Close _Without Saving"), Gtk::RESPONSE_NO);
471      dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);      dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
472      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);
473      dialog.set_default_response(Gtk::RESPONSE_YES);      dialog.set_default_response(Gtk::RESPONSE_YES);
474      int response = dialog.run();      int response = dialog.run();
475        dialog.hide();
476      if (response == Gtk::RESPONSE_YES) return file_save();      if (response == Gtk::RESPONSE_YES) return file_save();
477      return response != Gtk::RESPONSE_CANCEL;      return response != Gtk::RESPONSE_CANCEL;
478  }  }
479    
480    bool MainWindow::leaving_shared_mode_dialog() {
481        Glib::ustring msg = _("Detach from sampler and proceed working stand-alone?");
482        Gtk::MessageDialog dialog(*this, msg, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_NONE);
483    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION >= 6) || GTKMM_MAJOR_VERSION > 2
484        dialog.set_secondary_text(
485            _("If you proceed to work on another instrument file, it won't be "
486              "used by the sampler until you tell the sampler explicitly to "
487              "load it.")
488       );
489    #endif
490        dialog.add_button(_("_Yes, Detach"), Gtk::RESPONSE_YES);
491        dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
492        dialog.set_default_response(Gtk::RESPONSE_CANCEL);
493        int response = dialog.run();
494        dialog.hide();
495        return response == Gtk::RESPONSE_YES;
496    }
497    
498  void MainWindow::on_action_file_open()  void MainWindow::on_action_file_open()
499  {  {
500      if (file_is_changed && !close_confirmation_dialog()) return;      if (!file_is_shared && file_is_changed && !close_confirmation_dialog()) return;
501    
502        if (file_is_shared && !leaving_shared_mode_dialog()) return;
503    
504      Gtk::FileChooserDialog dialog(*this, _("Open file"));      Gtk::FileChooserDialog dialog(*this, _("Open file"));
505      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 514  void MainWindow::on_action_file_open()
514      if (dialog.run() == Gtk::RESPONSE_OK) {      if (dialog.run() == Gtk::RESPONSE_OK) {
515          std::string filename = dialog.get_filename();          std::string filename = dialog.get_filename();
516          printf("filename=%s\n", filename.c_str());          printf("filename=%s\n", filename.c_str());
         __clear();  
517          printf("on_action_file_open self=%x\n", Glib::Thread::self());          printf("on_action_file_open self=%x\n", Glib::Thread::self());
518          load_file(filename.c_str());          load_file(filename.c_str());
519          current_dir = Glib::path_get_dirname(filename);          current_dir = Glib::path_get_dirname(filename);
# Line 443  void MainWindow::on_action_file_open() Line 522  void MainWindow::on_action_file_open()
522    
523  void MainWindow::load_file(const char* name)  void MainWindow::load_file(const char* name)
524  {  {
525        __clear();
526      load_dialog = new LoadDialog("Loading...", *this);      load_dialog = new LoadDialog("Loading...", *this);
527      load_dialog->show_all();      load_dialog->show_all();
528      loader = new Loader(strdup(name));      loader = new Loader(strdup(name));
# Line 460  void MainWindow::load_instrument(gig::In Line 540  void MainWindow::load_instrument(gig::In
540          msg.run();          msg.run();
541          Gtk::Main::quit();          Gtk::Main::quit();
542      }      }
543        // clear all GUI elements
544        __clear();
545        // load the instrument
546      gig::File* pFile = (gig::File*) instr->GetParent();      gig::File* pFile = (gig::File*) instr->GetParent();
547      load_gig(pFile, 0 /*file name*/);      load_gig(pFile, 0 /*file name*/, true /*shared instrument*/);
548      //TODO: automatically select the given instrument      //TODO: automatically select the given instrument
549  }  }
550    
# Line 483  void MainWindow::on_action_file_save() Line 566  void MainWindow::on_action_file_save()
566      file_save();      file_save();
567  }  }
568    
569  bool MainWindow::file_save()  bool MainWindow::check_if_savable()
570  {  {
571      if (!file) return false;      if (!file) return false;
572      if (!file_has_name) return file_save_as();  
573        if (!file->GetFirstSample()) {
574            Gtk::MessageDialog(*this, _("The file could not be saved "
575                                        "because it contains no samples"),
576                               false, Gtk::MESSAGE_ERROR).run();
577            return false;
578        }
579    
580        for (gig::Instrument* instrument = file->GetFirstInstrument() ; instrument ;
581             instrument = file->GetNextInstrument()) {
582            if (!instrument->GetFirstRegion()) {
583                Gtk::MessageDialog(*this, _("The file could not be saved "
584                                            "because there are instruments "
585                                            "that have no regions"),
586                                   false, Gtk::MESSAGE_ERROR).run();
587                return false;
588            }
589        }
590        return true;
591    }
592    
593    bool MainWindow::file_save()
594    {
595        if (!check_if_savable()) return false;
596        if (!file_is_shared && !file_has_name) return file_save_as();
597    
598      std::cout << "Saving file\n" << std::flush;      std::cout << "Saving file\n" << std::flush;
599        file_structure_to_be_changed_signal.emit(this->file);
600      try {      try {
601          file->Save();          file->Save();
602          if (file_is_changed) {          if (file_is_changed) {
# Line 496  bool MainWindow::file_save() Line 604  bool MainWindow::file_save()
604              file_is_changed = false;              file_is_changed = false;
605          }          }
606      } catch (RIFF::Exception e) {      } catch (RIFF::Exception e) {
607          Glib::ustring txt = "Could not save file: " + e.Message;          file_structure_changed_signal.emit(this->file);
608            Glib::ustring txt = _("Could not save file: ") + e.Message;
609          Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);          Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
610          msg.run();          msg.run();
611          return false;          return false;
612      }      }
613      std::cout << "Saving file done\n" << std::flush;      std::cout << "Saving file done\n" << std::flush;
614      __import_queued_samples();      __import_queued_samples();
615        file_structure_changed_signal.emit(this->file);
616      return true;      return true;
617  }  }
618    
619  void MainWindow::on_action_file_save_as()  void MainWindow::on_action_file_save_as()
620  {  {
621        if (!check_if_savable()) return;
622      file_save_as();      file_save_as();
623  }  }
624    
625  bool MainWindow::file_save_as()  bool MainWindow::file_save_as()
626  {  {
     if (!file) return false;  
627      Gtk::FileChooserDialog dialog(*this, _("Save as"), Gtk::FILE_CHOOSER_ACTION_SAVE);      Gtk::FileChooserDialog dialog(*this, _("Save as"), Gtk::FILE_CHOOSER_ACTION_SAVE);
628      dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);      dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
629      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 645  bool MainWindow::file_save_as()
645      dialog.set_current_name(Glib::filename_display_basename(filename));      dialog.set_current_name(Glib::filename_display_basename(filename));
646    
647      if (dialog.run() == Gtk::RESPONSE_OK) {      if (dialog.run() == Gtk::RESPONSE_OK) {
648            file_structure_to_be_changed_signal.emit(this->file);
649          try {          try {
650              std::string filename = dialog.get_filename();              std::string filename = dialog.get_filename();
651              if (!Glib::str_has_suffix(filename, ".gig")) {              if (!Glib::str_has_suffix(filename, ".gig")) {
# Line 548  bool MainWindow::file_save_as() Line 659  bool MainWindow::file_save_as()
659              file_has_name = true;              file_has_name = true;
660              file_is_changed = false;              file_is_changed = false;
661          } catch (RIFF::Exception e) {          } catch (RIFF::Exception e) {
662              Glib::ustring txt = "Could not save file: " + e.Message;              file_structure_changed_signal.emit(this->file);
663                Glib::ustring txt = _("Could not save file: ") + e.Message;
664              Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);              Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
665              msg.run();              msg.run();
666              return false;              return false;
667          }          }
668          __import_queued_samples();          __import_queued_samples();
669            file_structure_changed_signal.emit(this->file);
670          return true;          return true;
671      }      }
672      return false;      return false;
# Line 576  void MainWindow::__import_queued_samples Line 689  void MainWindow::__import_queued_samples
689              int bitdepth;              int bitdepth;
690              switch (info.format & 0xff) {              switch (info.format & 0xff) {
691                  case SF_FORMAT_PCM_S8:                  case SF_FORMAT_PCM_S8:
                     bitdepth = 16; // we simply convert to 16 bit for now  
                     break;  
692                  case SF_FORMAT_PCM_16:                  case SF_FORMAT_PCM_16:
693                    case SF_FORMAT_PCM_U8:
694                      bitdepth = 16;                      bitdepth = 16;
695                      break;                      break;
696                  case SF_FORMAT_PCM_24:                  case SF_FORMAT_PCM_24:
                     bitdepth = 32; // we simply convert to 32 bit for now  
                     break;  
697                  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;  
698                  case SF_FORMAT_FLOAT:                  case SF_FORMAT_FLOAT:
                     bitdepth = 32;  
                     break;  
699                  case SF_FORMAT_DOUBLE:                  case SF_FORMAT_DOUBLE:
700                      bitdepth = 32; // I guess we will always truncate this to 32 bit                      bitdepth = 24;
701                      break;                      break;
702                  default:                  default:
703                      sf_close(hFile); // close sound file                      sf_close(hFile); // close sound file
704                      throw std::string("format not supported"); // unsupported subformat (yet?)                      throw std::string("format not supported"); // unsupported subformat (yet?)
705              }              }
706              // allocate appropriate copy buffer (TODO: for now we copy  
707              // 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;  
708              switch (bitdepth) {              switch (bitdepth) {
709                  case 16:                  case 16: {
710                      buffer = new int8_t[2 * info.channels * info.frames];                      short* buffer = new short[bufsize * info.channels];
711                      // libsndfile does the conversion for us (if needed)                      sf_count_t cnt = info.frames;
712                      sf_readf_short(hFile, (short*) buffer, info.frames);                      while (cnt) {
713                            // libsndfile does the conversion for us (if needed)
714                            int n = sf_readf_short(hFile, buffer, bufsize);
715                            // write from buffer directly (physically) into .gig file
716                            iter->gig_sample->Write(buffer, n);
717                            cnt -= n;
718                        }
719                        delete[] buffer;
720                      break;                      break;
721                  case 32:                  }
722                      buffer = new int8_t[4 * info.channels * info.frames];                  case 24: {
723                      // libsndfile does the conversion for us (if needed)                      int* srcbuf = new int[bufsize * info.channels];
724                      sf_readf_int(hFile, (int*) buffer, info.frames);                      uint8_t* dstbuf = new uint8_t[bufsize * 3 * info.channels];
725                        sf_count_t cnt = info.frames;
726                        while (cnt) {
727                            // libsndfile returns 32 bits, convert to 24
728                            int n = sf_readf_int(hFile, srcbuf, bufsize);
729                            int j = 0;
730                            for (int i = 0 ; i < n * info.channels ; i++) {
731                                dstbuf[j++] = srcbuf[i] >> 8;
732                                dstbuf[j++] = srcbuf[i] >> 16;
733                                dstbuf[j++] = srcbuf[i] >> 24;
734                            }
735                            // write from buffer directly (physically) into .gig file
736                            iter->gig_sample->Write(dstbuf, n);
737                            cnt -= n;
738                        }
739                        delete[] srcbuf;
740                        delete[] dstbuf;
741                      break;                      break;
742                    }
743              }              }
             // write from buffer directly (physically) into .gig file  
             (*iter).gig_sample->Write(buffer, info.frames);  
744              // cleanup              // cleanup
745              sf_close(hFile);              sf_close(hFile);
             delete[] buffer;  
746              // on success we remove the sample from the import queue,              // on success we remove the sample from the import queue,
747              // otherwise keep it, maybe it works the next time ?              // otherwise keep it, maybe it works the next time ?
748              std::list<SampleImportItem>::iterator cur = iter;              std::list<SampleImportItem>::iterator cur = iter;
# Line 635  void MainWindow::__import_queued_samples Line 757  void MainWindow::__import_queued_samples
757      }      }
758      // show error message box when some sample(s) could not be imported      // show error message box when some sample(s) could not be imported
759      if (error_files.size()) {      if (error_files.size()) {
760          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;
761          Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);          Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
762          msg.run();          msg.run();
763      }      }
# Line 712  void PropDialog::set_info(DLS::Info* inf Line 834  void PropDialog::set_info(DLS::Info* inf
834      entry[15].set_text(info->Subject);      entry[15].set_text(info->Subject);
835  }  }
836    
837    void InstrumentProps::add_prop(BoolEntry& boolentry)
838    {
839        table.attach(boolentry.widget, 0, 2, rowno, rowno + 1,
840                     Gtk::FILL, Gtk::SHRINK);
841        rowno++;
842        boolentry.signal_changed_by_user().connect(instrument_changed.make_slot());
843    }
844    
845    void InstrumentProps::add_prop(BoolEntryPlus6& boolentry)
846    {
847        table.attach(boolentry.widget, 0, 2, rowno, rowno + 1,
848                     Gtk::FILL, Gtk::SHRINK);
849        rowno++;
850        boolentry.signal_changed_by_user().connect(instrument_changed.make_slot());
851    }
852    
853  void InstrumentProps::add_prop(LabelWidget& prop)  void InstrumentProps::add_prop(LabelWidget& prop)
854  {  {
855      table.attach(prop.label, 0, 1, rowno, rowno + 1,      table.attach(prop.label, 0, 1, rowno, rowno + 1,
# Line 726  InstrumentProps::InstrumentProps() Line 864  InstrumentProps::InstrumentProps()
864      : table(2,1),      : table(2,1),
865        quitButton(Gtk::Stock::CLOSE),        quitButton(Gtk::Stock::CLOSE),
866        eName("Name"),        eName("Name"),
867        eIsDrum("IsDrum"),        eIsDrum("Is drum"),
868        eMIDIBank("MIDIBank", 0, 16383),        eMIDIBank("MIDI bank", 0, 16383),
869        eMIDIProgram("MIDIProgram"),        eMIDIProgram("MIDI program"),
870        eAttenuation("Attenuation", 0, 96, 0, 1),        eAttenuation("Attenuation", 0, 96, 0, 1),
871        eGainPlus6("Gain +6dB", eAttenuation, -6),        eGainPlus6("Gain +6dB", eAttenuation, -6),
872        eEffectSend("EffectSend", 0, 65535),        eEffectSend("Effect send", 0, 65535),
873        eFineTune("FineTune", -8400, 8400),        eFineTune("Fine tune", -8400, 8400),
874        ePitchbendRange("PitchbendRange", 0, 12),        ePitchbendRange("Pitchbend range", 0, 12),
875        ePianoReleaseMode("PianoReleaseMode"),        ePianoReleaseMode("Piano release mode"),
876        eDimensionKeyRangeLow("DimensionKeyRangeLow"),        eDimensionKeyRangeLow("Dimension key range low"),
877        eDimensionKeyRangeHigh("DimensionKeyRangeHigh")        eDimensionKeyRangeHigh("Dimension key range high")
878  {  {
879      set_title("Instrument properties");      set_title("Instrument properties");
880    
# Line 813  void InstrumentProps::key_range_high_cha Line 951  void InstrumentProps::key_range_high_cha
951      if (h < l) eDimensionKeyRangeLow.set_value(h);      if (h < l) eDimensionKeyRangeLow.set_value(h);
952  }  }
953    
954  sigc::signal<void> InstrumentProps::signal_instrument_changed()  sigc::signal<void>& InstrumentProps::signal_instrument_changed()
955  {  {
956      return instrument_changed;      return instrument_changed;
957  }  }
# Line 826  void MainWindow::file_changed() Line 964  void MainWindow::file_changed()
964      }      }
965  }  }
966    
967  void MainWindow::load_gig(gig::File* gig, const char* filename)  void MainWindow::load_gig(gig::File* gig, const char* filename, bool isSharedInstrument)
968  {  {
969      file = 0;      file = 0;
970        set_file_is_shared(isSharedInstrument);
971    
972      this->filename = filename ? filename : _("Unsaved Gig File");      this->filename = filename ? filename : _("Unsaved Gig File");
973      set_title(Glib::filename_display_basename(this->filename));      set_title(Glib::filename_display_basename(this->filename));
# Line 962  void MainWindow::on_action_add_instrumen Line 1101  void MainWindow::on_action_add_instrumen
1101    
1102  void MainWindow::on_action_remove_instrument() {  void MainWindow::on_action_remove_instrument() {
1103      if (!file) return;      if (!file) return;
1104        if (file_is_shared) {
1105            Gtk::MessageDialog msg(
1106                *this,
1107                 _("You cannot delete an instrument from this file, since it's "
1108                   "currently used by the sampler."),
1109                 false, Gtk::MESSAGE_INFO
1110            );
1111            msg.run();
1112            return;
1113        }
1114    
1115      Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeView.get_selection();      Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeView.get_selection();
1116      Gtk::TreeModel::iterator it = sel->get_selected();      Gtk::TreeModel::iterator it = sel->get_selected();
1117      if (it) {      if (it) {
# Line 1027  void MainWindow::on_action_add_sample() Line 1177  void MainWindow::on_action_add_sample()
1177      dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);      dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);
1178      dialog.set_select_multiple(true);      dialog.set_select_multiple(true);
1179      Gtk::FileFilter soundfilter; // matches all file types supported by libsndfile      Gtk::FileFilter soundfilter; // matches all file types supported by libsndfile
1180      const char* supportedFileTypes[] = {      const char* const supportedFileTypes[] = {
1181          "*.wav", "*.WAV", "*.aiff", "*.AIFF", "*.aifc", "*.AIFC", "*.snd",          "*.wav", "*.WAV", "*.aiff", "*.AIFF", "*.aifc", "*.AIFC", "*.snd",
1182          "*.SND", "*.au", "*.AU", "*.paf", "*.PAF", "*.iff", "*.IFF",          "*.SND", "*.au", "*.AU", "*.paf", "*.PAF", "*.iff", "*.IFF",
1183          "*.svx", "*.SVX", "*.sf", "*.SF", "*.voc", "*.VOC", "*.w64",          "*.svx", "*.SVX", "*.sf", "*.SF", "*.voc", "*.VOC", "*.w64",
# Line 1057  void MainWindow::on_action_add_sample() Line 1207  void MainWindow::on_action_add_sample()
1207                  int bitdepth;                  int bitdepth;
1208                  switch (info.format & 0xff) {                  switch (info.format & 0xff) {
1209                      case SF_FORMAT_PCM_S8:                      case SF_FORMAT_PCM_S8:
                         bitdepth = 16; // we simply convert to 16 bit for now  
                         break;  
1210                      case SF_FORMAT_PCM_16:                      case SF_FORMAT_PCM_16:
1211                        case SF_FORMAT_PCM_U8:
1212                          bitdepth = 16;                          bitdepth = 16;
1213                          break;                          break;
1214                      case SF_FORMAT_PCM_24:                      case SF_FORMAT_PCM_24:
                         bitdepth = 32; // we simply convert to 32 bit for now  
                         break;  
1215                      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;  
1216                      case SF_FORMAT_FLOAT:                      case SF_FORMAT_FLOAT:
                         bitdepth = 32;  
                         break;  
1217                      case SF_FORMAT_DOUBLE:                      case SF_FORMAT_DOUBLE:
1218                          bitdepth = 32; // I guess we will always truncate this to 32 bit                          bitdepth = 24;
1219                          break;                          break;
1220                      default:                      default:
1221                          sf_close(hFile); // close sound file                          sf_close(hFile); // close sound file
# Line 1084  void MainWindow::on_action_add_sample() Line 1224  void MainWindow::on_action_add_sample()
1224                  // add a new sample to the .gig file                  // add a new sample to the .gig file
1225                  gig::Sample* sample = file->AddSample();                  gig::Sample* sample = file->AddSample();
1226                  // file name without path                  // file name without path
1227                  sample->pInfo->Name = (*iter).substr((*iter).rfind('/') + 1).raw();                  Glib::ustring filename = Glib::filename_display_basename(*iter);
1228                    // remove file extension if there is one
1229                    for (int i = 0; supportedFileTypes[i]; i++) {
1230                        if (Glib::str_has_suffix(filename, supportedFileTypes[i] + 1)) {
1231                            filename.erase(filename.length() - strlen(supportedFileTypes[i] + 1));
1232                            break;
1233                        }
1234                    }
1235                    sample->pInfo->Name = filename;
1236                  sample->Channels = info.channels;                  sample->Channels = info.channels;
1237                  sample->BitDepth = bitdepth;                  sample->BitDepth = bitdepth;
1238                  sample->FrameSize = bitdepth / 8/*1 byte are 8 bits*/ * info.channels;                  sample->FrameSize = bitdepth / 8/*1 byte are 8 bits*/ * info.channels;
1239                  sample->SamplesPerSecond = info.samplerate;                  sample->SamplesPerSecond = info.samplerate;
1240                    sample->AverageBytesPerSecond = sample->FrameSize * sample->SamplesPerSecond;
1241                    sample->BlockAlign = sample->FrameSize;
1242                    sample->SamplesTotal = info.frames;
1243    
1244                    SF_INSTRUMENT instrument;
1245                    if (sf_command(hFile, SFC_GET_INSTRUMENT,
1246                                   &instrument, sizeof(instrument)) != SF_FALSE)
1247                    {
1248                        sample->MIDIUnityNote = instrument.basenote;
1249    
1250    #if HAVE_SF_INSTRUMENT_LOOPS
1251                        if (instrument.loop_count && instrument.loops[0].mode != SF_LOOP_NONE) {
1252                            sample->Loops = 1;
1253    
1254                            switch (instrument.loops[0].mode) {
1255                            case SF_LOOP_FORWARD:
1256                                sample->LoopType = gig::loop_type_normal;
1257                                break;
1258                            case SF_LOOP_BACKWARD:
1259                                sample->LoopType = gig::loop_type_backward;
1260                                break;
1261                            case SF_LOOP_ALTERNATING:
1262                                sample->LoopType = gig::loop_type_bidirectional;
1263                                break;
1264                            }
1265                            sample->LoopStart = instrument.loops[0].start;
1266                            sample->LoopEnd = instrument.loops[0].end;
1267                            sample->LoopPlayCount = instrument.loops[0].count;
1268                            sample->LoopSize = sample->LoopEnd - sample->LoopStart + 1;
1269                        }
1270    #endif
1271                    }
1272    
1273                  // schedule resizing the sample (which will be done                  // schedule resizing the sample (which will be done
1274                  // physically when File::Save() is called)                  // physically when File::Save() is called)
1275                  sample->Resize(info.frames);                  sample->Resize(info.frames);
# Line 1104  void MainWindow::on_action_add_sample() Line 1285  void MainWindow::on_action_add_sample()
1285                  Gtk::TreeModel::iterator iterSample =                  Gtk::TreeModel::iterator iterSample =
1286                      m_refSamplesTreeModel->append(row.children());                      m_refSamplesTreeModel->append(row.children());
1287                  Gtk::TreeModel::Row rowSample = *iterSample;                  Gtk::TreeModel::Row rowSample = *iterSample;
1288                  rowSample[m_SamplesModel.m_col_name]   = sample->pInfo->Name.c_str();                  rowSample[m_SamplesModel.m_col_name]   = filename;
1289                  rowSample[m_SamplesModel.m_col_sample] = sample;                  rowSample[m_SamplesModel.m_col_sample] = sample;
1290                  rowSample[m_SamplesModel.m_col_group]  = NULL;                  rowSample[m_SamplesModel.m_col_group]  = NULL;
1291                  // close sound file                  // close sound file
# Line 1117  void MainWindow::on_action_add_sample() Line 1298  void MainWindow::on_action_add_sample()
1298          }          }
1299          // 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
1300          if (error_files.size()) {          if (error_files.size()) {
1301              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;
1302              Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);              Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
1303              msg.run();              msg.run();
1304          }          }
# Line 1143  void MainWindow::on_action_remove_sample Line 1324  void MainWindow::on_action_remove_sample
1324                       pSample; pSample = group->GetNextSample()) {                       pSample; pSample = group->GetNextSample()) {
1325                      members.push_back(pSample);                      members.push_back(pSample);
1326                  }                  }
1327                    // notify everybody that we're going to remove these samples
1328                    samples_to_be_removed_signal.emit(members);
1329                  // delete the group in the .gig file including the                  // delete the group in the .gig file including the
1330                  // samples that belong to the group                  // samples that belong to the group
1331                  file->DeleteGroup(group);                  file->DeleteGroup(group);
1332                    // notify that we're done with removal
1333                    samples_removed_signal.emit();
1334                  // if sample(s) were just previously added, remove                  // if sample(s) were just previously added, remove
1335                  // them from the import queue                  // them from the import queue
1336                  for (std::list<gig::Sample*>::iterator member = members.begin();                  for (std::list<gig::Sample*>::iterator member = members.begin();
# Line 1162  void MainWindow::on_action_remove_sample Line 1347  void MainWindow::on_action_remove_sample
1347                  }                  }
1348                  file_changed();                  file_changed();
1349              } else if (sample) {              } else if (sample) {
1350                    // notify everybody that we're going to remove this sample
1351                    std::list<gig::Sample*> lsamples;
1352                    lsamples.push_back(sample);
1353                    samples_to_be_removed_signal.emit(lsamples);
1354                  // remove sample from the .gig file                  // remove sample from the .gig file
1355                  file->DeleteSample(sample);                  file->DeleteSample(sample);
1356                    // notify that we're done with removal
1357                    samples_removed_signal.emit();
1358                  // if sample was just previously added, remove it from                  // if sample was just previously added, remove it from
1359                  // the import queue                  // the import queue
1360                  for (std::list<SampleImportItem>::iterator iter = m_SampleImportQueue.begin();                  for (std::list<SampleImportItem>::iterator iter = m_SampleImportQueue.begin();
# Line 1175  void MainWindow::on_action_remove_sample Line 1366  void MainWindow::on_action_remove_sample
1366                          break;                          break;
1367                      }                      }
1368                  }                  }
1369                    dimreg_changed();
1370                  file_changed();                  file_changed();
1371              }              }
1372              // remove respective row(s) from samples tree view              // remove respective row(s) from samples tree view
1373              m_refSamplesTreeModel->erase(it);              m_refSamplesTreeModel->erase(it);
1374          } catch (RIFF::Exception e) {          } catch (RIFF::Exception e) {
1375                // pretend we're done with removal (i.e. to avoid dead locks)
1376                samples_removed_signal.emit();
1377                // show error message
1378              Gtk::MessageDialog msg(*this, e.Message.c_str(), false, Gtk::MESSAGE_ERROR);              Gtk::MessageDialog msg(*this, e.Message.c_str(), false, Gtk::MESSAGE_ERROR);
1379              msg.run();              msg.run();
1380          }          }
1381      }      }
1382  }  }
1383    
1384    // For some reason drag_data_get gets called two times for each
1385    // drag'n'drop (at least when target is an Entry). This work-around
1386    // makes sure the code in drag_data_get and drop_drag_data_received is
1387    // only executed once, as drag_begin only gets called once.
1388    void MainWindow::on_sample_treeview_drag_begin(const Glib::RefPtr<Gdk::DragContext>& context)
1389    {
1390        first_call_to_drag_data_get = true;
1391    }
1392    
1393  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>&,
1394                                                    Gtk::SelectionData& selection_data, guint, guint)                                                    Gtk::SelectionData& selection_data, guint, guint)
1395  {  {
1396        if (!first_call_to_drag_data_get) return;
1397        first_call_to_drag_data_get = false;
1398    
1399      // get selected sample      // get selected sample
1400      gig::Sample* sample = NULL;      gig::Sample* sample = NULL;
1401      Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();      Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();
# Line 1206  void MainWindow::on_sample_label_drop_dr Line 1413  void MainWindow::on_sample_label_drop_dr
1413      const Glib::RefPtr<Gdk::DragContext>& context, int, int,      const Glib::RefPtr<Gdk::DragContext>& context, int, int,
1414      const Gtk::SelectionData& selection_data, guint, guint time)      const Gtk::SelectionData& selection_data, guint, guint time)
1415  {  {
     gig::DimensionRegion* dimregion = m_DimRegionChooser.get_dimregion();  
1416      gig::Sample* sample = *((gig::Sample**) selection_data.get_data());      gig::Sample* sample = *((gig::Sample**) selection_data.get_data());
1417    
1418      if (sample && dimregion && selection_data.get_length() == sizeof(gig::Sample*)) {      if (sample && selection_data.get_length() == sizeof(gig::Sample*)) {
1419          if (sample != dimregion->pSample) {          std::cout << "Drop received sample \"" <<
1420              dimregion->pSample = sample;              sample->pInfo->Name << "\"" << std::endl;
1421              dimreg_edit.wSample->set_text(dimregion->pSample->pInfo->Name.c_str());          // drop success
1422              std::cout << "Drop received sample \"" <<          context->drop_reply(true, time);
1423                  dimregion->pSample->pInfo->Name.c_str() << "\"" << std::endl;  
1424              // drop success          //TODO: we should better move most of the following code to DimRegionEdit::set_sample()
1425              context->drop_reply(true, time);  
1426              file_changed();          // notify everybody that we're going to alter the region
1427              return;          gig::Region* region = m_RegionChooser.get_region();
1428            region_to_be_changed_signal.emit(region);
1429    
1430            // find the samplechannel dimension
1431            gig::dimension_def_t* stereo_dimension = 0;
1432            for (int i = 0 ; i < region->Dimensions ; i++) {
1433                if (region->pDimensionDefinitions[i].dimension ==
1434                    gig::dimension_samplechannel) {
1435                    stereo_dimension = &region->pDimensionDefinitions[i];
1436                    break;
1437                }
1438          }          }
1439            bool channels_changed = false;
1440            if (sample->Channels == 1 && stereo_dimension) {
1441                // remove the samplechannel dimension
1442                region->DeleteDimension(stereo_dimension);
1443                channels_changed = true;
1444                region_changed();
1445            }
1446            dimreg_edit.set_sample(sample);
1447    
1448            if (sample->Channels == 2 && !stereo_dimension) {
1449                // add samplechannel dimension
1450                gig::dimension_def_t dim;
1451                dim.dimension = gig::dimension_samplechannel;
1452                dim.bits = 1;
1453                dim.zones = 2;
1454                region->AddDimension(&dim);
1455                channels_changed = true;
1456                region_changed();
1457            }
1458            if (channels_changed) {
1459                // unmap all samples with wrong number of channels
1460                // TODO: maybe there should be a warning dialog for this
1461                for (int i = 0 ; i < region->DimensionRegions ; i++) {
1462                    gig::DimensionRegion* d = region->pDimensionRegions[i];
1463                    if (d->pSample && d->pSample->Channels != sample->Channels) {
1464                        gig::Sample* oldref = d->pSample;
1465                        d->pSample = NULL;
1466                        sample_ref_changed_signal.emit(oldref, NULL);
1467                    }
1468                }
1469            }
1470    
1471            // notify we're done with altering
1472            region_changed_signal.emit(region);
1473    
1474            return;
1475      }      }
1476      // drop failed      // drop failed
1477      context->drop_reply(false, time);      context->drop_reply(false, time);
# Line 1258  void MainWindow::instrument_name_changed Line 1510  void MainWindow::instrument_name_changed
1510          file_changed();          file_changed();
1511      }      }
1512  }  }
1513    
1514    void MainWindow::set_file_is_shared(bool b) {
1515        this->file_is_shared = b;
1516    
1517        if (file_is_shared) {
1518            m_AttachedStateLabel.set_label(_("live-mode"));
1519            m_AttachedStateImage.set(
1520                Gdk::Pixbuf::create_from_xpm_data(status_attached_xpm)
1521            );
1522        } else {
1523            m_AttachedStateLabel.set_label(_("stand-alone"));
1524            m_AttachedStateImage.set(
1525                Gdk::Pixbuf::create_from_xpm_data(status_detached_xpm)
1526            );
1527        }
1528    }
1529    
1530    sigc::signal<void, gig::File*>& MainWindow::signal_file_structure_to_be_changed() {
1531        return file_structure_to_be_changed_signal;
1532    }
1533    
1534    sigc::signal<void, gig::File*>& MainWindow::signal_file_structure_changed() {
1535        return file_structure_changed_signal;
1536    }
1537    
1538    sigc::signal<void, std::list<gig::Sample*> >& MainWindow::signal_samples_to_be_removed() {
1539        return samples_to_be_removed_signal;
1540    }
1541    
1542    sigc::signal<void>& MainWindow::signal_samples_removed() {
1543        return samples_removed_signal;
1544    }
1545    
1546    sigc::signal<void, gig::Region*>& MainWindow::signal_region_to_be_changed() {
1547        return region_to_be_changed_signal;
1548    }
1549    
1550    sigc::signal<void, gig::Region*>& MainWindow::signal_region_changed() {
1551        return region_changed_signal;
1552    }
1553    
1554    sigc::signal<void, gig::Sample*/*old*/, gig::Sample*/*new*/>& MainWindow::signal_sample_ref_changed() {
1555        return sample_ref_changed_signal;
1556    }
1557    
1558    sigc::signal<void, gig::DimensionRegion*>& MainWindow::signal_dimreg_to_be_changed() {
1559        return dimreg_to_be_changed_signal;
1560    }
1561    
1562    sigc::signal<void, gig::DimensionRegion*>& MainWindow::signal_dimreg_changed() {
1563        return dimreg_changed_signal;
1564    }

Legend:
Removed from v.1261  
changed lines
  Added in v.1411

  ViewVC Help
Powered by ViewVC