/[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 1396 by schoenebeck, Wed Oct 10 15:48:54 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    
 #define _(String) gettext(String)  
   
52  template<class T> inline std::string ToString(T o) {  template<class T> inline std::string ToString(T o) {
53      std::stringstream ss;      std::stringstream ss;
54      ss << o;      ss << o;
# Line 234  MainWindow::MainWindow() Line 245  MainWindow::MainWindow()
245      std::list<Gtk::TargetEntry> drag_target_gig_sample;      std::list<Gtk::TargetEntry> drag_target_gig_sample;
246      drag_target_gig_sample.push_back( Gtk::TargetEntry("gig::Sample") );      drag_target_gig_sample.push_back( Gtk::TargetEntry("gig::Sample") );
247      m_TreeViewSamples.drag_source_set(drag_target_gig_sample);      m_TreeViewSamples.drag_source_set(drag_target_gig_sample);
248        m_TreeViewSamples.signal_drag_begin().connect(
249            sigc::mem_fun(*this, &MainWindow::on_sample_treeview_drag_begin)
250        );
251      m_TreeViewSamples.signal_drag_data_get().connect(      m_TreeViewSamples.signal_drag_data_get().connect(
252          sigc::mem_fun(*this, &MainWindow::on_sample_treeview_drag_data_get)          sigc::mem_fun(*this, &MainWindow::on_sample_treeview_drag_data_get)
253      );      );
# Line 242  MainWindow::MainWindow() Line 256  MainWindow::MainWindow()
256          sigc::mem_fun(*this, &MainWindow::on_sample_label_drop_drag_data_received)          sigc::mem_fun(*this, &MainWindow::on_sample_label_drop_drag_data_received)
257      );      );
258      dimreg_edit.signal_dimreg_changed().connect(      dimreg_edit.signal_dimreg_changed().connect(
259          sigc::mem_fun(*this, &MainWindow::file_changed));          sigc::hide(sigc::mem_fun(*this, &MainWindow::file_changed)));
260      m_RegionChooser.signal_instrument_changed().connect(      m_RegionChooser.signal_instrument_changed().connect(
261          sigc::mem_fun(*this, &MainWindow::file_changed));          sigc::mem_fun(*this, &MainWindow::file_changed));
262      m_DimRegionChooser.signal_region_changed().connect(      m_DimRegionChooser.signal_region_changed().connect(
263          sigc::mem_fun(*this, &MainWindow::file_changed));          sigc::mem_fun(*this, &MainWindow::file_changed));
264      instrumentProps.signal_instrument_changed().connect(      instrumentProps.signal_instrument_changed().connect(
265          sigc::mem_fun(*this, &MainWindow::file_changed));          sigc::mem_fun(*this, &MainWindow::file_changed));
266    
267        dimreg_edit.signal_dimreg_to_be_changed().connect(
268            dimreg_to_be_changed_signal.make_slot());
269        dimreg_edit.signal_dimreg_changed().connect(
270            dimreg_changed_signal.make_slot());
271        dimreg_edit.signal_sample_ref_changed().connect(
272            sample_ref_changed_signal.make_slot());
273    
274        m_RegionChooser.signal_instrument_struct_to_be_changed().connect(
275            sigc::hide(
276                sigc::bind(
277                    file_structure_to_be_changed_signal.make_slot(),
278                    sigc::ref(this->file)
279                )
280            )
281        );
282        m_RegionChooser.signal_instrument_struct_changed().connect(
283            sigc::hide(
284                sigc::bind(
285                    file_structure_changed_signal.make_slot(),
286                    sigc::ref(this->file)
287                )
288            )
289        );
290        m_RegionChooser.signal_region_to_be_changed().connect(
291            region_to_be_changed_signal.make_slot());
292        m_RegionChooser.signal_region_changed_signal().connect(
293            region_changed_signal.make_slot());
294    
295      file = 0;      file = 0;
296      file_is_changed = false;      file_is_changed = false;
297        file_is_shared  = false;
298    
299      show_all_children();      show_all_children();
300    
301        // start with a new gig file by default
302        on_action_file_new();
303  }  }
304    
305  MainWindow::~MainWindow()  MainWindow::~MainWindow()
# Line 261  MainWindow::~MainWindow() Line 308  MainWindow::~MainWindow()
308    
309  bool MainWindow::on_delete_event(GdkEventAny* event)  bool MainWindow::on_delete_event(GdkEventAny* event)
310  {  {
311      return file_is_changed && !close_confirmation_dialog();      return !file_is_shared && file_is_changed && !close_confirmation_dialog();
312  }  }
313    
314  void MainWindow::on_action_quit()  void MainWindow::on_action_quit()
315  {  {
316      if (file_is_changed && !close_confirmation_dialog()) return;      if (!file_is_shared && file_is_changed && !close_confirmation_dialog()) return;
317      hide();      hide();
318  }  }
319    
# Line 380  void MainWindow::__clear() { Line 427  void MainWindow::__clear() {
427      m_refTreeModel->clear();      m_refTreeModel->clear();
428      m_refSamplesTreeModel->clear();      m_refSamplesTreeModel->clear();
429      // free libgig's gig::File instance      // free libgig's gig::File instance
430      if (file) {      if (file && !file_is_shared) delete file;
431          delete file;      file = NULL;
432          file = NULL;      file_is_shared = false;
     }  
433  }  }
434    
435  void MainWindow::on_action_file_new()  void MainWindow::on_action_file_new()
436  {  {
437      if (file_is_changed && !close_confirmation_dialog()) return;      if (!file_is_shared && file_is_changed && !close_confirmation_dialog()) return;
438    
439        if (file_is_shared && !leaving_shared_mode_dialog()) return;
440    
441      // clear all GUI elements      // clear all GUI elements
442      __clear();      __clear();
# Line 407  bool MainWindow::close_confirmation_dial Line 455  bool MainWindow::close_confirmation_dial
455                                   Glib::filename_display_basename(filename).c_str());                                   Glib::filename_display_basename(filename).c_str());
456      Gtk::MessageDialog dialog(*this, msg, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_NONE);      Gtk::MessageDialog dialog(*this, msg, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_NONE);
457      g_free(msg);      g_free(msg);
458    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION >= 6) || GTKMM_MAJOR_VERSION > 2
459      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."));
460    #endif
461      dialog.add_button(_("Close _Without Saving"), Gtk::RESPONSE_NO);      dialog.add_button(_("Close _Without Saving"), Gtk::RESPONSE_NO);
462      dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);      dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
463      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);
464      dialog.set_default_response(Gtk::RESPONSE_YES);      dialog.set_default_response(Gtk::RESPONSE_YES);
465      int response = dialog.run();      int response = dialog.run();
466        dialog.hide();
467      if (response == Gtk::RESPONSE_YES) return file_save();      if (response == Gtk::RESPONSE_YES) return file_save();
468      return response != Gtk::RESPONSE_CANCEL;      return response != Gtk::RESPONSE_CANCEL;
469  }  }
470    
471    bool MainWindow::leaving_shared_mode_dialog() {
472        Glib::ustring msg = _("Detach from sampler and proceed working stand-alone?");
473        Gtk::MessageDialog dialog(*this, msg, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_NONE);
474    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION >= 6) || GTKMM_MAJOR_VERSION > 2
475        dialog.set_secondary_text(
476            _("If you proceed to work on another instrument file, it won't be "
477              "used by the sampler until you tell the sampler explicitly to "
478              "load it.")
479       );
480    #endif
481        dialog.add_button(_("_Yes, Detach"), Gtk::RESPONSE_YES);
482        dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
483        dialog.set_default_response(Gtk::RESPONSE_CANCEL);
484        int response = dialog.run();
485        dialog.hide();
486        return response == Gtk::RESPONSE_YES;
487    }
488    
489  void MainWindow::on_action_file_open()  void MainWindow::on_action_file_open()
490  {  {
491      if (file_is_changed && !close_confirmation_dialog()) return;      if (!file_is_shared && file_is_changed && !close_confirmation_dialog()) return;
492    
493        if (file_is_shared && !leaving_shared_mode_dialog()) return;
494    
495      Gtk::FileChooserDialog dialog(*this, _("Open file"));      Gtk::FileChooserDialog dialog(*this, _("Open file"));
496      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 505  void MainWindow::on_action_file_open()
505      if (dialog.run() == Gtk::RESPONSE_OK) {      if (dialog.run() == Gtk::RESPONSE_OK) {
506          std::string filename = dialog.get_filename();          std::string filename = dialog.get_filename();
507          printf("filename=%s\n", filename.c_str());          printf("filename=%s\n", filename.c_str());
         __clear();  
508          printf("on_action_file_open self=%x\n", Glib::Thread::self());          printf("on_action_file_open self=%x\n", Glib::Thread::self());
509          load_file(filename.c_str());          load_file(filename.c_str());
510          current_dir = Glib::path_get_dirname(filename);          current_dir = Glib::path_get_dirname(filename);
# Line 443  void MainWindow::on_action_file_open() Line 513  void MainWindow::on_action_file_open()
513    
514  void MainWindow::load_file(const char* name)  void MainWindow::load_file(const char* name)
515  {  {
516        __clear();
517      load_dialog = new LoadDialog("Loading...", *this);      load_dialog = new LoadDialog("Loading...", *this);
518      load_dialog->show_all();      load_dialog->show_all();
519      loader = new Loader(strdup(name));      loader = new Loader(strdup(name));
# Line 460  void MainWindow::load_instrument(gig::In Line 531  void MainWindow::load_instrument(gig::In
531          msg.run();          msg.run();
532          Gtk::Main::quit();          Gtk::Main::quit();
533      }      }
534        // clear all GUI elements
535        __clear();
536        // load the instrument
537      gig::File* pFile = (gig::File*) instr->GetParent();      gig::File* pFile = (gig::File*) instr->GetParent();
538      load_gig(pFile, 0 /*file name*/);      load_gig(pFile, 0 /*file name*/, true /*shared instrument*/);
539      //TODO: automatically select the given instrument      //TODO: automatically select the given instrument
540  }  }
541    
# Line 483  void MainWindow::on_action_file_save() Line 557  void MainWindow::on_action_file_save()
557      file_save();      file_save();
558  }  }
559    
560  bool MainWindow::file_save()  bool MainWindow::check_if_savable()
561  {  {
562      if (!file) return false;      if (!file) return false;
563      if (!file_has_name) return file_save_as();  
564        if (!file->GetFirstSample()) {
565            Gtk::MessageDialog(*this, _("The file could not be saved "
566                                        "because it contains no samples"),
567                               false, Gtk::MESSAGE_ERROR).run();
568            return false;
569        }
570    
571        for (gig::Instrument* instrument = file->GetFirstInstrument() ; instrument ;
572             instrument = file->GetNextInstrument()) {
573            if (!instrument->GetFirstRegion()) {
574                Gtk::MessageDialog(*this, _("The file could not be saved "
575                                            "because there are instruments "
576                                            "that have no regions"),
577                                   false, Gtk::MESSAGE_ERROR).run();
578                return false;
579            }
580        }
581        return true;
582    }
583    
584    bool MainWindow::file_save()
585    {
586        if (!check_if_savable()) return false;
587        if (!file_is_shared && !file_has_name) return file_save_as();
588    
589      std::cout << "Saving file\n" << std::flush;      std::cout << "Saving file\n" << std::flush;
590        file_structure_to_be_changed_signal.emit(this->file);
591      try {      try {
592          file->Save();          file->Save();
593          if (file_is_changed) {          if (file_is_changed) {
# Line 496  bool MainWindow::file_save() Line 595  bool MainWindow::file_save()
595              file_is_changed = false;              file_is_changed = false;
596          }          }
597      } catch (RIFF::Exception e) {      } catch (RIFF::Exception e) {
598          Glib::ustring txt = "Could not save file: " + e.Message;          file_structure_changed_signal.emit(this->file);
599            Glib::ustring txt = _("Could not save file: ") + e.Message;
600          Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);          Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
601          msg.run();          msg.run();
602          return false;          return false;
603      }      }
604      std::cout << "Saving file done\n" << std::flush;      std::cout << "Saving file done\n" << std::flush;
605      __import_queued_samples();      __import_queued_samples();
606        file_structure_changed_signal.emit(this->file);
607      return true;      return true;
608  }  }
609    
610  void MainWindow::on_action_file_save_as()  void MainWindow::on_action_file_save_as()
611  {  {
612        if (!check_if_savable()) return;
613      file_save_as();      file_save_as();
614  }  }
615    
616  bool MainWindow::file_save_as()  bool MainWindow::file_save_as()
617  {  {
     if (!file) return false;  
618      Gtk::FileChooserDialog dialog(*this, _("Save as"), Gtk::FILE_CHOOSER_ACTION_SAVE);      Gtk::FileChooserDialog dialog(*this, _("Save as"), Gtk::FILE_CHOOSER_ACTION_SAVE);
619      dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);      dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
620      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 636  bool MainWindow::file_save_as()
636      dialog.set_current_name(Glib::filename_display_basename(filename));      dialog.set_current_name(Glib::filename_display_basename(filename));
637    
638      if (dialog.run() == Gtk::RESPONSE_OK) {      if (dialog.run() == Gtk::RESPONSE_OK) {
639            file_structure_to_be_changed_signal.emit(this->file);
640          try {          try {
641              std::string filename = dialog.get_filename();              std::string filename = dialog.get_filename();
642              if (!Glib::str_has_suffix(filename, ".gig")) {              if (!Glib::str_has_suffix(filename, ".gig")) {
# Line 548  bool MainWindow::file_save_as() Line 650  bool MainWindow::file_save_as()
650              file_has_name = true;              file_has_name = true;
651              file_is_changed = false;              file_is_changed = false;
652          } catch (RIFF::Exception e) {          } catch (RIFF::Exception e) {
653              Glib::ustring txt = "Could not save file: " + e.Message;              file_structure_changed_signal.emit(this->file);
654                Glib::ustring txt = _("Could not save file: ") + e.Message;
655              Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);              Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
656              msg.run();              msg.run();
657              return false;              return false;
658          }          }
659          __import_queued_samples();          __import_queued_samples();
660            file_structure_changed_signal.emit(this->file);
661          return true;          return true;
662      }      }
663      return false;      return false;
# Line 576  void MainWindow::__import_queued_samples Line 680  void MainWindow::__import_queued_samples
680              int bitdepth;              int bitdepth;
681              switch (info.format & 0xff) {              switch (info.format & 0xff) {
682                  case SF_FORMAT_PCM_S8:                  case SF_FORMAT_PCM_S8:
                     bitdepth = 16; // we simply convert to 16 bit for now  
                     break;  
683                  case SF_FORMAT_PCM_16:                  case SF_FORMAT_PCM_16:
684                    case SF_FORMAT_PCM_U8:
685                      bitdepth = 16;                      bitdepth = 16;
686                      break;                      break;
687                  case SF_FORMAT_PCM_24:                  case SF_FORMAT_PCM_24:
                     bitdepth = 32; // we simply convert to 32 bit for now  
                     break;  
688                  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;  
689                  case SF_FORMAT_FLOAT:                  case SF_FORMAT_FLOAT:
                     bitdepth = 32;  
                     break;  
690                  case SF_FORMAT_DOUBLE:                  case SF_FORMAT_DOUBLE:
691                      bitdepth = 32; // I guess we will always truncate this to 32 bit                      bitdepth = 24;
692                      break;                      break;
693                  default:                  default:
694                      sf_close(hFile); // close sound file                      sf_close(hFile); // close sound file
695                      throw std::string("format not supported"); // unsupported subformat (yet?)                      throw std::string("format not supported"); // unsupported subformat (yet?)
696              }              }
697              // allocate appropriate copy buffer (TODO: for now we copy  
698              // 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;  
699              switch (bitdepth) {              switch (bitdepth) {
700                  case 16:                  case 16: {
701                      buffer = new int8_t[2 * info.channels * info.frames];                      short* buffer = new short[bufsize * info.channels];
702                      // libsndfile does the conversion for us (if needed)                      sf_count_t cnt = info.frames;
703                      sf_readf_short(hFile, (short*) buffer, info.frames);                      while (cnt) {
704                            // libsndfile does the conversion for us (if needed)
705                            int n = sf_readf_short(hFile, buffer, bufsize);
706                            // write from buffer directly (physically) into .gig file
707                            iter->gig_sample->Write(buffer, n);
708                            cnt -= n;
709                        }
710                        delete[] buffer;
711                      break;                      break;
712                  case 32:                  }
713                      buffer = new int8_t[4 * info.channels * info.frames];                  case 24: {
714                      // libsndfile does the conversion for us (if needed)                      int* srcbuf = new int[bufsize * info.channels];
715                      sf_readf_int(hFile, (int*) buffer, info.frames);                      uint8_t* dstbuf = new uint8_t[bufsize * 3 * info.channels];
716                        sf_count_t cnt = info.frames;
717                        while (cnt) {
718                            // libsndfile returns 32 bits, convert to 24
719                            int n = sf_readf_int(hFile, srcbuf, bufsize);
720                            int j = 0;
721                            for (int i = 0 ; i < n * info.channels ; i++) {
722                                dstbuf[j++] = srcbuf[i] >> 8;
723                                dstbuf[j++] = srcbuf[i] >> 16;
724                                dstbuf[j++] = srcbuf[i] >> 24;
725                            }
726                            // write from buffer directly (physically) into .gig file
727                            iter->gig_sample->Write(dstbuf, n);
728                            cnt -= n;
729                        }
730                        delete[] srcbuf;
731                        delete[] dstbuf;
732                      break;                      break;
733                    }
734              }              }
             // write from buffer directly (physically) into .gig file  
             (*iter).gig_sample->Write(buffer, info.frames);  
735              // cleanup              // cleanup
736              sf_close(hFile);              sf_close(hFile);
             delete[] buffer;  
737              // on success we remove the sample from the import queue,              // on success we remove the sample from the import queue,
738              // otherwise keep it, maybe it works the next time ?              // otherwise keep it, maybe it works the next time ?
739              std::list<SampleImportItem>::iterator cur = iter;              std::list<SampleImportItem>::iterator cur = iter;
# Line 635  void MainWindow::__import_queued_samples Line 748  void MainWindow::__import_queued_samples
748      }      }
749      // show error message box when some sample(s) could not be imported      // show error message box when some sample(s) could not be imported
750      if (error_files.size()) {      if (error_files.size()) {
751          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;
752          Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);          Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
753          msg.run();          msg.run();
754      }      }
# Line 712  void PropDialog::set_info(DLS::Info* inf Line 825  void PropDialog::set_info(DLS::Info* inf
825      entry[15].set_text(info->Subject);      entry[15].set_text(info->Subject);
826  }  }
827    
828    void InstrumentProps::add_prop(BoolEntry& boolentry)
829    {
830        table.attach(boolentry.widget, 0, 2, rowno, rowno + 1,
831                     Gtk::FILL, Gtk::SHRINK);
832        rowno++;
833        boolentry.signal_changed_by_user().connect(instrument_changed.make_slot());
834    }
835    
836    void InstrumentProps::add_prop(BoolEntryPlus6& boolentry)
837    {
838        table.attach(boolentry.widget, 0, 2, rowno, rowno + 1,
839                     Gtk::FILL, Gtk::SHRINK);
840        rowno++;
841        boolentry.signal_changed_by_user().connect(instrument_changed.make_slot());
842    }
843    
844  void InstrumentProps::add_prop(LabelWidget& prop)  void InstrumentProps::add_prop(LabelWidget& prop)
845  {  {
846      table.attach(prop.label, 0, 1, rowno, rowno + 1,      table.attach(prop.label, 0, 1, rowno, rowno + 1,
# Line 726  InstrumentProps::InstrumentProps() Line 855  InstrumentProps::InstrumentProps()
855      : table(2,1),      : table(2,1),
856        quitButton(Gtk::Stock::CLOSE),        quitButton(Gtk::Stock::CLOSE),
857        eName("Name"),        eName("Name"),
858        eIsDrum("IsDrum"),        eIsDrum("Is drum"),
859        eMIDIBank("MIDIBank", 0, 16383),        eMIDIBank("MIDI bank", 0, 16383),
860        eMIDIProgram("MIDIProgram"),        eMIDIProgram("MIDI program"),
861        eAttenuation("Attenuation", 0, 96, 0, 1),        eAttenuation("Attenuation", 0, 96, 0, 1),
862        eGainPlus6("Gain +6dB", eAttenuation, -6),        eGainPlus6("Gain +6dB", eAttenuation, -6),
863        eEffectSend("EffectSend", 0, 65535),        eEffectSend("Effect send", 0, 65535),
864        eFineTune("FineTune", -8400, 8400),        eFineTune("Fine tune", -8400, 8400),
865        ePitchbendRange("PitchbendRange", 0, 12),        ePitchbendRange("Pitchbend range", 0, 12),
866        ePianoReleaseMode("PianoReleaseMode"),        ePianoReleaseMode("Piano release mode"),
867        eDimensionKeyRangeLow("DimensionKeyRangeLow"),        eDimensionKeyRangeLow("Dimension key range low"),
868        eDimensionKeyRangeHigh("DimensionKeyRangeHigh")        eDimensionKeyRangeHigh("Dimension key range high")
869  {  {
870      set_title("Instrument properties");      set_title("Instrument properties");
871    
# Line 813  void InstrumentProps::key_range_high_cha Line 942  void InstrumentProps::key_range_high_cha
942      if (h < l) eDimensionKeyRangeLow.set_value(h);      if (h < l) eDimensionKeyRangeLow.set_value(h);
943  }  }
944    
945  sigc::signal<void> InstrumentProps::signal_instrument_changed()  sigc::signal<void>& InstrumentProps::signal_instrument_changed()
946  {  {
947      return instrument_changed;      return instrument_changed;
948  }  }
# Line 826  void MainWindow::file_changed() Line 955  void MainWindow::file_changed()
955      }      }
956  }  }
957    
958  void MainWindow::load_gig(gig::File* gig, const char* filename)  void MainWindow::load_gig(gig::File* gig, const char* filename, bool isSharedInstrument)
959  {  {
960      file = 0;      file = 0;
961        file_is_shared = isSharedInstrument;
962    
963      this->filename = filename ? filename : _("Unsaved Gig File");      this->filename = filename ? filename : _("Unsaved Gig File");
964      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 1092  void MainWindow::on_action_add_instrumen
1092    
1093  void MainWindow::on_action_remove_instrument() {  void MainWindow::on_action_remove_instrument() {
1094      if (!file) return;      if (!file) return;
1095        if (file_is_shared) {
1096            Gtk::MessageDialog msg(
1097                *this,
1098                 _("You cannot delete an instrument from this file, since it's "
1099                   "currently used by the sampler."),
1100                 false, Gtk::MESSAGE_INFO
1101            );
1102            msg.run();
1103            return;
1104        }
1105    
1106      Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeView.get_selection();      Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeView.get_selection();
1107      Gtk::TreeModel::iterator it = sel->get_selected();      Gtk::TreeModel::iterator it = sel->get_selected();
1108      if (it) {      if (it) {
# Line 1027  void MainWindow::on_action_add_sample() Line 1168  void MainWindow::on_action_add_sample()
1168      dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);      dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);
1169      dialog.set_select_multiple(true);      dialog.set_select_multiple(true);
1170      Gtk::FileFilter soundfilter; // matches all file types supported by libsndfile      Gtk::FileFilter soundfilter; // matches all file types supported by libsndfile
1171      const char* supportedFileTypes[] = {      const char* const supportedFileTypes[] = {
1172          "*.wav", "*.WAV", "*.aiff", "*.AIFF", "*.aifc", "*.AIFC", "*.snd",          "*.wav", "*.WAV", "*.aiff", "*.AIFF", "*.aifc", "*.AIFC", "*.snd",
1173          "*.SND", "*.au", "*.AU", "*.paf", "*.PAF", "*.iff", "*.IFF",          "*.SND", "*.au", "*.AU", "*.paf", "*.PAF", "*.iff", "*.IFF",
1174          "*.svx", "*.SVX", "*.sf", "*.SF", "*.voc", "*.VOC", "*.w64",          "*.svx", "*.SVX", "*.sf", "*.SF", "*.voc", "*.VOC", "*.w64",
# Line 1057  void MainWindow::on_action_add_sample() Line 1198  void MainWindow::on_action_add_sample()
1198                  int bitdepth;                  int bitdepth;
1199                  switch (info.format & 0xff) {                  switch (info.format & 0xff) {
1200                      case SF_FORMAT_PCM_S8:                      case SF_FORMAT_PCM_S8:
                         bitdepth = 16; // we simply convert to 16 bit for now  
                         break;  
1201                      case SF_FORMAT_PCM_16:                      case SF_FORMAT_PCM_16:
1202                        case SF_FORMAT_PCM_U8:
1203                          bitdepth = 16;                          bitdepth = 16;
1204                          break;                          break;
1205                      case SF_FORMAT_PCM_24:                      case SF_FORMAT_PCM_24:
                         bitdepth = 32; // we simply convert to 32 bit for now  
                         break;  
1206                      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;  
1207                      case SF_FORMAT_FLOAT:                      case SF_FORMAT_FLOAT:
                         bitdepth = 32;  
                         break;  
1208                      case SF_FORMAT_DOUBLE:                      case SF_FORMAT_DOUBLE:
1209                          bitdepth = 32; // I guess we will always truncate this to 32 bit                          bitdepth = 24;
1210                          break;                          break;
1211                      default:                      default:
1212                          sf_close(hFile); // close sound file                          sf_close(hFile); // close sound file
# Line 1084  void MainWindow::on_action_add_sample() Line 1215  void MainWindow::on_action_add_sample()
1215                  // add a new sample to the .gig file                  // add a new sample to the .gig file
1216                  gig::Sample* sample = file->AddSample();                  gig::Sample* sample = file->AddSample();
1217                  // file name without path                  // file name without path
1218                  sample->pInfo->Name = (*iter).substr((*iter).rfind('/') + 1).raw();                  Glib::ustring filename = Glib::filename_display_basename(*iter);
1219                    // remove file extension if there is one
1220                    for (int i = 0; supportedFileTypes[i]; i++) {
1221                        if (Glib::str_has_suffix(filename, supportedFileTypes[i] + 1)) {
1222                            filename.erase(filename.length() - strlen(supportedFileTypes[i] + 1));
1223                            break;
1224                        }
1225                    }
1226                    sample->pInfo->Name = filename;
1227                  sample->Channels = info.channels;                  sample->Channels = info.channels;
1228                  sample->BitDepth = bitdepth;                  sample->BitDepth = bitdepth;
1229                  sample->FrameSize = bitdepth / 8/*1 byte are 8 bits*/ * info.channels;                  sample->FrameSize = bitdepth / 8/*1 byte are 8 bits*/ * info.channels;
1230                  sample->SamplesPerSecond = info.samplerate;                  sample->SamplesPerSecond = info.samplerate;
1231                    sample->AverageBytesPerSecond = sample->FrameSize * sample->SamplesPerSecond;
1232                    sample->BlockAlign = sample->FrameSize;
1233                    sample->SamplesTotal = info.frames;
1234    
1235                    SF_INSTRUMENT instrument;
1236                    if (sf_command(hFile, SFC_GET_INSTRUMENT,
1237                                   &instrument, sizeof(instrument)) != SF_FALSE)
1238                    {
1239                        sample->MIDIUnityNote = instrument.basenote;
1240    
1241    #if HAVE_SF_INSTRUMENT_LOOPS
1242                        if (instrument.loop_count && instrument.loops[0].mode != SF_LOOP_NONE) {
1243                            sample->Loops = 1;
1244    
1245                            switch (instrument.loops[0].mode) {
1246                            case SF_LOOP_FORWARD:
1247                                sample->LoopType = gig::loop_type_normal;
1248                                break;
1249                            case SF_LOOP_BACKWARD:
1250                                sample->LoopType = gig::loop_type_backward;
1251                                break;
1252                            case SF_LOOP_ALTERNATING:
1253                                sample->LoopType = gig::loop_type_bidirectional;
1254                                break;
1255                            }
1256                            sample->LoopStart = instrument.loops[0].start;
1257                            sample->LoopEnd = instrument.loops[0].end;
1258                            sample->LoopPlayCount = instrument.loops[0].count;
1259                            sample->LoopSize = sample->LoopEnd - sample->LoopStart + 1;
1260                        }
1261    #endif
1262                    }
1263    
1264                  // schedule resizing the sample (which will be done                  // schedule resizing the sample (which will be done
1265                  // physically when File::Save() is called)                  // physically when File::Save() is called)
1266                  sample->Resize(info.frames);                  sample->Resize(info.frames);
# Line 1104  void MainWindow::on_action_add_sample() Line 1276  void MainWindow::on_action_add_sample()
1276                  Gtk::TreeModel::iterator iterSample =                  Gtk::TreeModel::iterator iterSample =
1277                      m_refSamplesTreeModel->append(row.children());                      m_refSamplesTreeModel->append(row.children());
1278                  Gtk::TreeModel::Row rowSample = *iterSample;                  Gtk::TreeModel::Row rowSample = *iterSample;
1279                  rowSample[m_SamplesModel.m_col_name]   = sample->pInfo->Name.c_str();                  rowSample[m_SamplesModel.m_col_name]   = filename;
1280                  rowSample[m_SamplesModel.m_col_sample] = sample;                  rowSample[m_SamplesModel.m_col_sample] = sample;
1281                  rowSample[m_SamplesModel.m_col_group]  = NULL;                  rowSample[m_SamplesModel.m_col_group]  = NULL;
1282                  // close sound file                  // close sound file
# Line 1117  void MainWindow::on_action_add_sample() Line 1289  void MainWindow::on_action_add_sample()
1289          }          }
1290          // 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
1291          if (error_files.size()) {          if (error_files.size()) {
1292              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;
1293              Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);              Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
1294              msg.run();              msg.run();
1295          }          }
# Line 1143  void MainWindow::on_action_remove_sample Line 1315  void MainWindow::on_action_remove_sample
1315                       pSample; pSample = group->GetNextSample()) {                       pSample; pSample = group->GetNextSample()) {
1316                      members.push_back(pSample);                      members.push_back(pSample);
1317                  }                  }
1318                    // notify everybody that we're going to remove these samples
1319                    samples_to_be_removed_signal.emit(members);
1320                  // delete the group in the .gig file including the                  // delete the group in the .gig file including the
1321                  // samples that belong to the group                  // samples that belong to the group
1322                  file->DeleteGroup(group);                  file->DeleteGroup(group);
1323                    // notify that we're done with removal
1324                    samples_removed_signal.emit();
1325                  // if sample(s) were just previously added, remove                  // if sample(s) were just previously added, remove
1326                  // them from the import queue                  // them from the import queue
1327                  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 1338  void MainWindow::on_action_remove_sample
1338                  }                  }
1339                  file_changed();                  file_changed();
1340              } else if (sample) {              } else if (sample) {
1341                    // notify everybody that we're going to remove this sample
1342                    std::list<gig::Sample*> lsamples;
1343                    lsamples.push_back(sample);
1344                    samples_to_be_removed_signal.emit(lsamples);
1345                  // remove sample from the .gig file                  // remove sample from the .gig file
1346                  file->DeleteSample(sample);                  file->DeleteSample(sample);
1347                    // notify that we're done with removal
1348                    samples_removed_signal.emit();
1349                  // if sample was just previously added, remove it from                  // if sample was just previously added, remove it from
1350                  // the import queue                  // the import queue
1351                  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 1357  void MainWindow::on_action_remove_sample
1357                          break;                          break;
1358                      }                      }
1359                  }                  }
1360                    dimreg_changed();
1361                  file_changed();                  file_changed();
1362              }              }
1363              // remove respective row(s) from samples tree view              // remove respective row(s) from samples tree view
1364              m_refSamplesTreeModel->erase(it);              m_refSamplesTreeModel->erase(it);
1365          } catch (RIFF::Exception e) {          } catch (RIFF::Exception e) {
1366                // pretend we're done with removal (i.e. to avoid dead locks)
1367                samples_removed_signal.emit();
1368                // show error message
1369              Gtk::MessageDialog msg(*this, e.Message.c_str(), false, Gtk::MESSAGE_ERROR);              Gtk::MessageDialog msg(*this, e.Message.c_str(), false, Gtk::MESSAGE_ERROR);
1370              msg.run();              msg.run();
1371          }          }
1372      }      }
1373  }  }
1374    
1375    // For some reason drag_data_get gets called two times for each
1376    // drag'n'drop (at least when target is an Entry). This work-around
1377    // makes sure the code in drag_data_get and drop_drag_data_received is
1378    // only executed once, as drag_begin only gets called once.
1379    void MainWindow::on_sample_treeview_drag_begin(const Glib::RefPtr<Gdk::DragContext>& context)
1380    {
1381        first_call_to_drag_data_get = true;
1382    }
1383    
1384  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>&,
1385                                                    Gtk::SelectionData& selection_data, guint, guint)                                                    Gtk::SelectionData& selection_data, guint, guint)
1386  {  {
1387        if (!first_call_to_drag_data_get) return;
1388        first_call_to_drag_data_get = false;
1389    
1390      // get selected sample      // get selected sample
1391      gig::Sample* sample = NULL;      gig::Sample* sample = NULL;
1392      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 1404  void MainWindow::on_sample_label_drop_dr
1404      const Glib::RefPtr<Gdk::DragContext>& context, int, int,      const Glib::RefPtr<Gdk::DragContext>& context, int, int,
1405      const Gtk::SelectionData& selection_data, guint, guint time)      const Gtk::SelectionData& selection_data, guint, guint time)
1406  {  {
     gig::DimensionRegion* dimregion = m_DimRegionChooser.get_dimregion();  
1407      gig::Sample* sample = *((gig::Sample**) selection_data.get_data());      gig::Sample* sample = *((gig::Sample**) selection_data.get_data());
1408    
1409      if (sample && dimregion && selection_data.get_length() == sizeof(gig::Sample*)) {      if (sample && selection_data.get_length() == sizeof(gig::Sample*)) {
1410          if (sample != dimregion->pSample) {          std::cout << "Drop received sample \"" <<
1411              dimregion->pSample = sample;              sample->pInfo->Name << "\"" << std::endl;
1412              dimreg_edit.wSample->set_text(dimregion->pSample->pInfo->Name.c_str());          // drop success
1413              std::cout << "Drop received sample \"" <<          context->drop_reply(true, time);
1414                  dimregion->pSample->pInfo->Name.c_str() << "\"" << std::endl;  
1415              // drop success          //TODO: we should better move most of the following code to DimRegionEdit::set_sample()
1416              context->drop_reply(true, time);  
1417              file_changed();          // notify everybody that we're going to alter the region
1418              return;          gig::Region* region = m_RegionChooser.get_region();
1419            region_to_be_changed_signal.emit(region);
1420    
1421            // find the samplechannel dimension
1422            gig::dimension_def_t* stereo_dimension = 0;
1423            for (int i = 0 ; i < region->Dimensions ; i++) {
1424                if (region->pDimensionDefinitions[i].dimension ==
1425                    gig::dimension_samplechannel) {
1426                    stereo_dimension = &region->pDimensionDefinitions[i];
1427                    break;
1428                }
1429            }
1430            bool channels_changed = false;
1431            if (sample->Channels == 1 && stereo_dimension) {
1432                // remove the samplechannel dimension
1433                region->DeleteDimension(stereo_dimension);
1434                channels_changed = true;
1435                region_changed();
1436            }
1437            dimreg_edit.set_sample(sample);
1438    
1439            if (sample->Channels == 2 && !stereo_dimension) {
1440                // add samplechannel dimension
1441                gig::dimension_def_t dim;
1442                dim.dimension = gig::dimension_samplechannel;
1443                dim.bits = 1;
1444                dim.zones = 2;
1445                region->AddDimension(&dim);
1446                channels_changed = true;
1447                region_changed();
1448          }          }
1449            if (channels_changed) {
1450                // unmap all samples with wrong number of channels
1451                // TODO: maybe there should be a warning dialog for this
1452                for (int i = 0 ; i < region->DimensionRegions ; i++) {
1453                    gig::DimensionRegion* d = region->pDimensionRegions[i];
1454                    if (d->pSample && d->pSample->Channels != sample->Channels) {
1455                        gig::Sample* oldref = d->pSample;
1456                        d->pSample = NULL;
1457                        sample_ref_changed_signal.emit(oldref, NULL);
1458                    }
1459                }
1460            }
1461    
1462            // notify we're done with altering
1463            region_changed_signal.emit(region);
1464    
1465            return;
1466      }      }
1467      // drop failed      // drop failed
1468      context->drop_reply(false, time);      context->drop_reply(false, time);
# Line 1258  void MainWindow::instrument_name_changed Line 1501  void MainWindow::instrument_name_changed
1501          file_changed();          file_changed();
1502      }      }
1503  }  }
1504    
1505    sigc::signal<void, gig::File*>& MainWindow::signal_file_structure_to_be_changed() {
1506        return file_structure_to_be_changed_signal;
1507    }
1508    
1509    sigc::signal<void, gig::File*>& MainWindow::signal_file_structure_changed() {
1510        return file_structure_changed_signal;
1511    }
1512    
1513    sigc::signal<void, std::list<gig::Sample*> >& MainWindow::signal_samples_to_be_removed() {
1514        return samples_to_be_removed_signal;
1515    }
1516    
1517    sigc::signal<void>& MainWindow::signal_samples_removed() {
1518        return samples_removed_signal;
1519    }
1520    
1521    sigc::signal<void, gig::Region*>& MainWindow::signal_region_to_be_changed() {
1522        return region_to_be_changed_signal;
1523    }
1524    
1525    sigc::signal<void, gig::Region*>& MainWindow::signal_region_changed() {
1526        return region_changed_signal;
1527    }
1528    
1529    sigc::signal<void, gig::Sample*/*old*/, gig::Sample*/*new*/>& MainWindow::signal_sample_ref_changed() {
1530        return sample_ref_changed_signal;
1531    }
1532    
1533    sigc::signal<void, gig::DimensionRegion*>& MainWindow::signal_dimreg_to_be_changed() {
1534        return dimreg_to_be_changed_signal;
1535    }
1536    
1537    sigc::signal<void, gig::DimensionRegion*>& MainWindow::signal_dimreg_changed() {
1538        return dimreg_changed_signal;
1539    }

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

  ViewVC Help
Powered by ViewVC