/[svn]/gigedit/trunk/src/gigedit/mainwindow.cpp
ViewVC logotype

Diff of /gigedit/trunk/src/gigedit/mainwindow.cpp

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1225 by schoenebeck, Sun Jun 10 10:56:11 2007 UTC revision 1303 by persson, Sun Aug 26 09:29:52 2007 UTC
# Line 26  Line 26 
26  #include <gtkmm/targetentry.h>  #include <gtkmm/targetentry.h>
27  #include <gtkmm/main.h>  #include <gtkmm/main.h>
28    
29  #if GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION >= 6  #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION >= 6) || GTKMM_MAJOR_VERSION > 2
30  #define ABOUT_DIALOG  #define ABOUT_DIALOG
31  #include <gtkmm/aboutdialog.h>  #include <gtkmm/aboutdialog.h>
32  #endif  #endif
33    
34    #if (GLIBMM_MAJOR_VERSION == 2 && GLIBMM_MINOR_VERSION < 6) || GLIBMM_MAJOR_VERSION < 2
35    namespace Glib {
36    Glib::ustring filename_display_basename(const std::string& filename)
37    {
38        gchar* gstr = g_path_get_basename(filename.c_str());
39        Glib::ustring str(gstr);
40        g_free(gstr);
41        return Glib::filename_to_utf8(str);
42    }
43    }
44    #endif
45    
46  #include <stdio.h>  #include <stdio.h>
47  #include <sndfile.h>  #include <sndfile.h>
48    
# Line 99  MainWindow::MainWindow() Line 111  MainWindow::MainWindow()
111      action = Gtk::Action::create("SaveAs", Gtk::Stock::SAVE_AS);      action = Gtk::Action::create("SaveAs", Gtk::Stock::SAVE_AS);
112      action->property_label() = action->property_label() + "...";      action->property_label() = action->property_label() + "...";
113      actionGroup->add(action,      actionGroup->add(action,
114                       *(new Gtk::AccelKey("<shift><control>s")),                       Gtk::AccelKey("<shift><control>s"),
115                       sigc::mem_fun(                       sigc::mem_fun(
116                           *this, &MainWindow::on_action_file_save_as)                           *this, &MainWindow::on_action_file_save_as));
         );  
117      actionGroup->add(Gtk::Action::create("Properties",      actionGroup->add(Gtk::Action::create("Properties",
118                                           Gtk::Stock::PROPERTIES),                                           Gtk::Stock::PROPERTIES),
119                       sigc::mem_fun(                       sigc::mem_fun(
# Line 113  MainWindow::MainWindow() Line 124  MainWindow::MainWindow()
124                           *this, &MainWindow::show_instr_props));                           *this, &MainWindow::show_instr_props));
125      actionGroup->add(Gtk::Action::create("Quit", Gtk::Stock::QUIT),      actionGroup->add(Gtk::Action::create("Quit", Gtk::Stock::QUIT),
126                       sigc::mem_fun(                       sigc::mem_fun(
127                           *this, &MainWindow::hide));                           *this, &MainWindow::on_action_quit));
128      actionGroup->add(Gtk::Action::create("MenuInstrument", _("_Instrument")));      actionGroup->add(Gtk::Action::create("MenuInstrument", _("_Instrument")));
129    
130      action = Gtk::Action::create("MenuHelp", Gtk::Stock::HELP);      action = Gtk::Action::create("MenuHelp", Gtk::Stock::HELP);
# Line 153  MainWindow::MainWindow() Line 164  MainWindow::MainWindow()
164    
165      uiManager = Gtk::UIManager::create();      uiManager = Gtk::UIManager::create();
166      uiManager->insert_action_group(actionGroup);      uiManager->insert_action_group(actionGroup);
167      // add_accel_group(uiManager->get_accel_group());      add_accel_group(uiManager->get_accel_group());
168    
169      Glib::ustring ui_info =      Glib::ustring ui_info =
170          "<ui>"          "<ui>"
# Line 201  MainWindow::MainWindow() Line 212  MainWindow::MainWindow()
212      m_VBox.pack_start(m_RegionChooser, Gtk::PACK_SHRINK);      m_VBox.pack_start(m_RegionChooser, Gtk::PACK_SHRINK);
213      m_VBox.pack_start(m_DimRegionChooser, Gtk::PACK_SHRINK);      m_VBox.pack_start(m_DimRegionChooser, Gtk::PACK_SHRINK);
214    
215      m_RegionChooser.signal_sel_changed().connect(      m_RegionChooser.signal_region_selected().connect(
216          sigc::mem_fun(*this, &MainWindow::region_changed) );          sigc::mem_fun(*this, &MainWindow::region_changed) );
217      m_DimRegionChooser.signal_sel_changed().connect(      m_DimRegionChooser.signal_dimregion_selected().connect(
218          sigc::mem_fun(*this, &MainWindow::dimreg_changed) );          sigc::mem_fun(*this, &MainWindow::dimreg_changed) );
219    
220    
# Line 235  MainWindow::MainWindow() Line 246  MainWindow::MainWindow()
246      std::list<Gtk::TargetEntry> drag_target_gig_sample;      std::list<Gtk::TargetEntry> drag_target_gig_sample;
247      drag_target_gig_sample.push_back( Gtk::TargetEntry("gig::Sample") );      drag_target_gig_sample.push_back( Gtk::TargetEntry("gig::Sample") );
248      m_TreeViewSamples.drag_source_set(drag_target_gig_sample);      m_TreeViewSamples.drag_source_set(drag_target_gig_sample);
249        m_TreeViewSamples.signal_drag_begin().connect(
250            sigc::mem_fun(*this, &MainWindow::on_sample_treeview_drag_begin)
251        );
252      m_TreeViewSamples.signal_drag_data_get().connect(      m_TreeViewSamples.signal_drag_data_get().connect(
253          sigc::mem_fun(*this, &MainWindow::on_sample_treeview_drag_data_get)          sigc::mem_fun(*this, &MainWindow::on_sample_treeview_drag_data_get)
254      );      );
# Line 242  MainWindow::MainWindow() Line 256  MainWindow::MainWindow()
256      dimreg_edit.wSample->signal_drag_data_received().connect(      dimreg_edit.wSample->signal_drag_data_received().connect(
257          sigc::mem_fun(*this, &MainWindow::on_sample_label_drop_drag_data_received)          sigc::mem_fun(*this, &MainWindow::on_sample_label_drop_drag_data_received)
258      );      );
259        dimreg_edit.signal_dimreg_changed().connect(
260            sigc::mem_fun(*this, &MainWindow::file_changed));
261        m_RegionChooser.signal_instrument_changed().connect(
262            sigc::mem_fun(*this, &MainWindow::file_changed));
263        m_DimRegionChooser.signal_region_changed().connect(
264            sigc::mem_fun(*this, &MainWindow::file_changed));
265        instrumentProps.signal_instrument_changed().connect(
266            sigc::mem_fun(*this, &MainWindow::file_changed));
267      file = 0;      file = 0;
268        file_is_changed = false;
269    
270      show_all_children();      show_all_children();
271    
272        // start with a new gig file by default
273        on_action_file_new();
274  }  }
275    
276  MainWindow::~MainWindow()  MainWindow::~MainWindow()
277  {  {
278  }  }
279    
280    bool MainWindow::on_delete_event(GdkEventAny* event)
281    {
282        return file_is_changed && !close_confirmation_dialog();
283    }
284    
285    void MainWindow::on_action_quit()
286    {
287        if (file_is_changed && !close_confirmation_dialog()) return;
288        hide();
289    }
290    
291  void MainWindow::region_changed()  void MainWindow::region_changed()
292  {  {
293      m_DimRegionChooser.set_region(m_RegionChooser.get_region());      m_DimRegionChooser.set_region(m_RegionChooser.get_region());
# Line 370  void MainWindow::__clear() { Line 406  void MainWindow::__clear() {
406    
407  void MainWindow::on_action_file_new()  void MainWindow::on_action_file_new()
408  {  {
409        if (file_is_changed && !close_confirmation_dialog()) return;
410    
411      // clear all GUI elements      // clear all GUI elements
412      __clear();      __clear();
413      // create a new .gig file (virtually yet)      // create a new .gig file (virtually yet)
# Line 378  void MainWindow::on_action_file_new() Line 416  void MainWindow::on_action_file_new()
416      gig::Instrument* pInstrument = pFile->AddInstrument();      gig::Instrument* pInstrument = pFile->AddInstrument();
417      pInstrument->pInfo->Name = "Unnamed Instrument";      pInstrument->pInfo->Name = "Unnamed Instrument";
418      // update GUI with that new gig::File      // update GUI with that new gig::File
419      load_gig(pFile, NULL /*no file name yet*/);      load_gig(pFile, 0 /*no file name yet*/);
420    }
421    
422    bool MainWindow::close_confirmation_dialog()
423    {
424        gchar* msg = g_strdup_printf(_("Save changes to \"%s\" before closing?"),
425                                     Glib::filename_display_basename(filename).c_str());
426        Gtk::MessageDialog dialog(*this, msg, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_NONE);
427        g_free(msg);
428    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION >= 6) || GTKMM_MAJOR_VERSION > 2
429        dialog.set_secondary_text(_("If you close without saving, your changes will be lost."));
430    #endif
431        dialog.add_button(_("Close _Without Saving"), Gtk::RESPONSE_NO);
432        dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
433        dialog.add_button(file_has_name ? Gtk::Stock::SAVE : Gtk::Stock::SAVE_AS, Gtk::RESPONSE_YES);
434        dialog.set_default_response(Gtk::RESPONSE_YES);
435        int response = dialog.run();
436        dialog.hide();
437        if (response == Gtk::RESPONSE_YES) return file_save();
438        return response != Gtk::RESPONSE_CANCEL;
439  }  }
440    
441  void MainWindow::on_action_file_open()  void MainWindow::on_action_file_open()
442  {  {
443        if (file_is_changed && !close_confirmation_dialog()) return;
444    
445      Gtk::FileChooserDialog dialog(*this, _("Open file"));      Gtk::FileChooserDialog dialog(*this, _("Open file"));
446      dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);      dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
447      dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);      dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);
448        dialog.set_default_response(Gtk::RESPONSE_OK);
449      Gtk::FileFilter filter;      Gtk::FileFilter filter;
450      filter.add_pattern("*.gig");      filter.add_pattern("*.gig");
451      dialog.set_filter(filter);      dialog.set_filter(filter);
452        if (current_dir != "") {
453            dialog.set_current_folder(current_dir);
454        }
455      if (dialog.run() == Gtk::RESPONSE_OK) {      if (dialog.run() == Gtk::RESPONSE_OK) {
456          printf("filename=%s\n", dialog.get_filename().c_str());          std::string filename = dialog.get_filename();
457          __clear();          printf("filename=%s\n", filename.c_str());
458          printf("on_action_file_open self=%x\n", Glib::Thread::self());          printf("on_action_file_open self=%x\n", Glib::Thread::self());
459          load_file(dialog.get_filename().c_str());          load_file(filename.c_str());
460            current_dir = Glib::path_get_dirname(filename);
461      }      }
462  }  }
463    
464  void MainWindow::load_file(const char* name)  void MainWindow::load_file(const char* name)
465  {  {
466        __clear();
467      load_dialog = new LoadDialog("Loading...", *this);      load_dialog = new LoadDialog("Loading...", *this);
468      load_dialog->show_all();      load_dialog->show_all();
469      loader = new Loader(strdup(name));      loader = new Loader(strdup(name));
# Line 417  void MainWindow::load_instrument(gig::In Line 482  void MainWindow::load_instrument(gig::In
482          Gtk::Main::quit();          Gtk::Main::quit();
483      }      }
484      gig::File* pFile = (gig::File*) instr->GetParent();      gig::File* pFile = (gig::File*) instr->GetParent();
485      load_gig(pFile, NULL /*file name*/);      load_gig(pFile, 0 /*file name*/);
486      //TODO: automatically select the given instrument      //TODO: automatically select the given instrument
487  }  }
488    
# Line 436  void MainWindow::on_loader_finished() Line 501  void MainWindow::on_loader_finished()
501    
502  void MainWindow::on_action_file_save()  void MainWindow::on_action_file_save()
503  {  {
504      if (!file) return;      file_save();
505    }
506    
507    bool MainWindow::check_if_savable()
508    {
509        if (!file) return false;
510    
511        if (!file->GetFirstSample()) {
512            Gtk::MessageDialog(*this, _("The file could not be saved "
513                                        "because it contains no samples"),
514                               false, Gtk::MESSAGE_ERROR).run();
515            return false;
516        }
517    
518        for (gig::Instrument* instrument = file->GetFirstInstrument() ; instrument ;
519             instrument = file->GetNextInstrument()) {
520            if (!instrument->GetFirstRegion()) {
521                Gtk::MessageDialog(*this, _("The file could not be saved "
522                                            "because there are instruments "
523                                            "that have no regions"),
524                                   false, Gtk::MESSAGE_ERROR).run();
525                return false;
526            }
527        }
528        return true;
529    }
530    
531    bool MainWindow::file_save()
532    {
533        if (!check_if_savable()) return false;
534        if (!file_has_name) return file_save_as();
535    
536      std::cout << "Saving file\n" << std::flush;      std::cout << "Saving file\n" << std::flush;
537      try {      try {
538          file->Save();          file->Save();
539            if (file_is_changed) {
540                set_title(get_title().substr(1));
541                file_is_changed = false;
542            }
543      } catch (RIFF::Exception e) {      } catch (RIFF::Exception e) {
544          Glib::ustring txt = "Could not save file: " + e.Message;          Glib::ustring txt = "Could not save file: " + e.Message;
545          Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);          Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
546          msg.run();          msg.run();
547          return;          return false;
548      }      }
549      std::cout << "Saving file done\n" << std::flush;      std::cout << "Saving file done\n" << std::flush;
550      __import_queued_samples();      __import_queued_samples();
551        return true;
552  }  }
553    
554  void MainWindow::on_action_file_save_as()  void MainWindow::on_action_file_save_as()
555  {  {
556      if (!file) return;      if (!check_if_savable()) return;
557      Gtk::FileChooserDialog dialog(*this, "Open", Gtk::FILE_CHOOSER_ACTION_SAVE);      file_save_as();
558    }
559    
560    bool MainWindow::file_save_as()
561    {
562        Gtk::FileChooserDialog dialog(*this, _("Save as"), Gtk::FILE_CHOOSER_ACTION_SAVE);
563      dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);      dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
564      dialog.add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK);      dialog.add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK);
565        dialog.set_default_response(Gtk::RESPONSE_OK);
566    
567    #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION >= 8) || GTKMM_MAJOR_VERSION > 2
568        dialog.set_do_overwrite_confirmation();
569        // TODO: an overwrite dialog for gtkmm < 2.8
570    #endif
571      Gtk::FileFilter filter;      Gtk::FileFilter filter;
572      filter.add_pattern("*.gig");      filter.add_pattern("*.gig");
573      dialog.set_filter(filter);      dialog.set_filter(filter);
574    
575        if (Glib::path_is_absolute(filename)) {
576            dialog.set_filename(filename);
577        } else if (current_dir != "") {
578            dialog.set_current_folder(current_dir);
579        }
580        dialog.set_current_name(Glib::filename_display_basename(filename));
581    
582      if (dialog.run() == Gtk::RESPONSE_OK) {      if (dialog.run() == Gtk::RESPONSE_OK) {
         printf("filename=%s\n", dialog.get_filename().c_str());  
583          try {          try {
584              file->Save(dialog.get_filename());              std::string filename = dialog.get_filename();
585                if (!Glib::str_has_suffix(filename, ".gig")) {
586                    filename += ".gig";
587                }
588                printf("filename=%s\n", filename.c_str());
589                file->Save(filename);
590                this->filename = filename;
591                current_dir = Glib::path_get_dirname(filename);
592                set_title(Glib::filename_display_basename(filename));
593                file_has_name = true;
594                file_is_changed = false;
595          } catch (RIFF::Exception e) {          } catch (RIFF::Exception e) {
596              Glib::ustring txt = "Could not save file: " + e.Message;              Glib::ustring txt = "Could not save file: " + e.Message;
597              Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);              Gtk::MessageDialog msg(*this, txt, false, Gtk::MESSAGE_ERROR);
598              msg.run();              msg.run();
599              return;              return false;
600          }          }
601          __import_queued_samples();          __import_queued_samples();
602            return true;
603      }      }
604        return false;
605  }  }
606    
607  // actually write the sample(s)' data to the gig file  // actually write the sample(s)' data to the gig file
# Line 490  void MainWindow::__import_queued_samples Line 621  void MainWindow::__import_queued_samples
621              int bitdepth;              int bitdepth;
622              switch (info.format & 0xff) {              switch (info.format & 0xff) {
623                  case SF_FORMAT_PCM_S8:                  case SF_FORMAT_PCM_S8:
                     bitdepth = 16; // we simply convert to 16 bit for now  
                     break;  
624                  case SF_FORMAT_PCM_16:                  case SF_FORMAT_PCM_16:
625                    case SF_FORMAT_PCM_U8:
626                      bitdepth = 16;                      bitdepth = 16;
627                      break;                      break;
628                  case SF_FORMAT_PCM_24:                  case SF_FORMAT_PCM_24:
                     bitdepth = 32; // we simply convert to 32 bit for now  
                     break;  
629                  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;  
630                  case SF_FORMAT_FLOAT:                  case SF_FORMAT_FLOAT:
                     bitdepth = 32;  
                     break;  
631                  case SF_FORMAT_DOUBLE:                  case SF_FORMAT_DOUBLE:
632                      bitdepth = 32; // I guess we will always truncate this to 32 bit                      bitdepth = 24;
633                      break;                      break;
634                  default:                  default:
635                      sf_close(hFile); // close sound file                      sf_close(hFile); // close sound file
636                      throw std::string("format not supported"); // unsupported subformat (yet?)                      throw std::string("format not supported"); // unsupported subformat (yet?)
637              }              }
638              // allocate appropriate copy buffer (TODO: for now we copy  
639              // 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;  
640              switch (bitdepth) {              switch (bitdepth) {
641                  case 16:                  case 16: {
642                      buffer = new int8_t[2 * info.channels * info.frames];                      short* buffer = new short[bufsize * info.channels];
643                      // libsndfile does the conversion for us (if needed)                      sf_count_t cnt = info.frames;
644                      sf_readf_short(hFile, (short*) buffer, info.frames);                      while (cnt) {
645                            // libsndfile does the conversion for us (if needed)
646                            int n = sf_readf_short(hFile, buffer, bufsize);
647                            // write from buffer directly (physically) into .gig file
648                            iter->gig_sample->Write(buffer, n);
649                            cnt -= n;
650                        }
651                        delete[] buffer;
652                      break;                      break;
653                  case 32:                  }
654                      buffer = new int8_t[4 * info.channels * info.frames];                  case 24: {
655                      // libsndfile does the conversion for us (if needed)                      int* srcbuf = new int[bufsize * info.channels];
656                      sf_readf_int(hFile, (int*) buffer, info.frames);                      uint8_t* dstbuf = new uint8_t[bufsize * 3 * info.channels];
657                        sf_count_t cnt = info.frames;
658                        while (cnt) {
659                            // libsndfile returns 32 bits, convert to 24
660                            int n = sf_readf_int(hFile, srcbuf, bufsize);
661                            int j = 0;
662                            for (int i = 0 ; i < n * info.channels ; i++) {
663                                dstbuf[j++] = srcbuf[i] >> 8;
664                                dstbuf[j++] = srcbuf[i] >> 16;
665                                dstbuf[j++] = srcbuf[i] >> 24;
666                            }
667                            // write from buffer directly (physically) into .gig file
668                            iter->gig_sample->Write(dstbuf, n);
669                            cnt -= n;
670                        }
671                        delete[] srcbuf;
672                        delete[] dstbuf;
673                      break;                      break;
674                    }
675              }              }
             // write from buffer directly (physically) into .gig file  
             (*iter).gig_sample->Write(buffer, info.frames);  
676              // cleanup              // cleanup
677              sf_close(hFile);              sf_close(hFile);
             delete[] buffer;  
678              // on success we remove the sample from the import queue,              // on success we remove the sample from the import queue,
679              // otherwise keep it, maybe it works the next time ?              // otherwise keep it, maybe it works the next time ?
680              std::list<SampleImportItem>::iterator cur = iter;              std::list<SampleImportItem>::iterator cur = iter;
# Line 626  void PropDialog::set_info(DLS::Info* inf Line 766  void PropDialog::set_info(DLS::Info* inf
766      entry[15].set_text(info->Subject);      entry[15].set_text(info->Subject);
767  }  }
768    
769    void InstrumentProps::add_prop(BoolEntry& boolentry)
770    {
771        table.attach(boolentry.widget, 0, 2, rowno, rowno + 1,
772                     Gtk::FILL, Gtk::SHRINK);
773        rowno++;
774        boolentry.signal_changed_by_user().connect(instrument_changed.make_slot());
775    }
776    
777    void InstrumentProps::add_prop(BoolEntryPlus6& boolentry)
778    {
779        table.attach(boolentry.widget, 0, 2, rowno, rowno + 1,
780                     Gtk::FILL, Gtk::SHRINK);
781        rowno++;
782        boolentry.signal_changed_by_user().connect(instrument_changed.make_slot());
783    }
784    
785  void InstrumentProps::add_prop(LabelWidget& prop)  void InstrumentProps::add_prop(LabelWidget& prop)
786  {  {
787      table.attach(prop.label, 0, 1, rowno, rowno + 1,      table.attach(prop.label, 0, 1, rowno, rowno + 1,
# Line 633  void InstrumentProps::add_prop(LabelWidg Line 789  void InstrumentProps::add_prop(LabelWidg
789      table.attach(prop.widget, 1, 2, rowno, rowno + 1,      table.attach(prop.widget, 1, 2, rowno, rowno + 1,
790                   Gtk::FILL | Gtk::EXPAND, Gtk::SHRINK);                   Gtk::FILL | Gtk::EXPAND, Gtk::SHRINK);
791      rowno++;      rowno++;
792        prop.signal_changed_by_user().connect(instrument_changed.make_slot());
793  }  }
794    
795  InstrumentProps::InstrumentProps()  InstrumentProps::InstrumentProps()
796      : table(2,1),      : table(2,1),
797        quitButton(Gtk::Stock::CLOSE),        quitButton(Gtk::Stock::CLOSE),
798        eName("Name"),        eName("Name"),
799        eIsDrum("IsDrum"),        eIsDrum("Is drum"),
800        eMIDIBank("MIDIBank", 0, 16383),        eMIDIBank("MIDI bank", 0, 16383),
801        eMIDIProgram("MIDIProgram"),        eMIDIProgram("MIDI program"),
802        eAttenuation("Attenuation", 0, 96, 0, 1),        eAttenuation("Attenuation", 0, 96, 0, 1),
803        eGainPlus6("Gain +6dB", eAttenuation, -6),        eGainPlus6("Gain +6dB", eAttenuation, -6),
804        eEffectSend("EffectSend", 0, 65535),        eEffectSend("Effect send", 0, 65535),
805        eFineTune("FineTune", -8400, 8400),        eFineTune("Fine tune", -8400, 8400),
806        ePitchbendRange("PitchbendRange", 0, 12),        ePitchbendRange("Pitchbend range", 0, 12),
807        ePianoReleaseMode("PianoReleaseMode"),        ePianoReleaseMode("Piano release mode"),
808        eDimensionKeyRangeLow("DimensionKeyRangeLow"),        eDimensionKeyRangeLow("Dimension key range low"),
809        eDimensionKeyRangeHigh("DimensionKeyRangeHigh")        eDimensionKeyRangeHigh("Dimension key range high")
810  {  {
811      set_title("Instrument properties");      set_title("Instrument properties");
812    
# Line 669  InstrumentProps::InstrumentProps() Line 826  InstrumentProps::InstrumentProps()
826      add_prop(eDimensionKeyRangeLow);      add_prop(eDimensionKeyRangeLow);
827      add_prop(eDimensionKeyRangeHigh);      add_prop(eDimensionKeyRangeHigh);
828    
829      eDimensionKeyRangeLow.signal_value_changed().connect(      eDimensionKeyRangeLow.signal_changed_by_user().connect(
830          sigc::mem_fun(*this, &InstrumentProps::key_range_low_changed));          sigc::mem_fun(*this, &InstrumentProps::key_range_low_changed));
831      eDimensionKeyRangeHigh.signal_value_changed().connect(      eDimensionKeyRangeHigh.signal_changed_by_user().connect(
832          sigc::mem_fun(*this, &InstrumentProps::key_range_high_changed));          sigc::mem_fun(*this, &InstrumentProps::key_range_high_changed));
833    
834      add(vbox);      add(vbox);
# Line 696  InstrumentProps::InstrumentProps() Line 853  InstrumentProps::InstrumentProps()
853    
854  void InstrumentProps::set_instrument(gig::Instrument* instrument)  void InstrumentProps::set_instrument(gig::Instrument* instrument)
855  {  {
     update_gui = false;  
856      eName.set_ptr(&instrument->pInfo->Name);      eName.set_ptr(&instrument->pInfo->Name);
857      eIsDrum.set_ptr(&instrument->IsDrum);      eIsDrum.set_ptr(&instrument->IsDrum);
858      eMIDIBank.set_ptr(&instrument->MIDIBank);      eMIDIBank.set_ptr(&instrument->MIDIBank);
# Line 707  void InstrumentProps::set_instrument(gig Line 863  void InstrumentProps::set_instrument(gig
863      eFineTune.set_ptr(&instrument->FineTune);      eFineTune.set_ptr(&instrument->FineTune);
864      ePitchbendRange.set_ptr(&instrument->PitchbendRange);      ePitchbendRange.set_ptr(&instrument->PitchbendRange);
865      ePianoReleaseMode.set_ptr(&instrument->PianoReleaseMode);      ePianoReleaseMode.set_ptr(&instrument->PianoReleaseMode);
866        eDimensionKeyRangeLow.set_ptr(0);
867        eDimensionKeyRangeHigh.set_ptr(0);
868      eDimensionKeyRangeLow.set_ptr(&instrument->DimensionKeyRange.low);      eDimensionKeyRangeLow.set_ptr(&instrument->DimensionKeyRange.low);
869      eDimensionKeyRangeHigh.set_ptr(&instrument->DimensionKeyRange.high);      eDimensionKeyRangeHigh.set_ptr(&instrument->DimensionKeyRange.high);
     update_gui = true;  
870  }  }
871    
872  void InstrumentProps::key_range_low_changed()  void InstrumentProps::key_range_low_changed()
# Line 726  void InstrumentProps::key_range_high_cha Line 883  void InstrumentProps::key_range_high_cha
883      if (h < l) eDimensionKeyRangeLow.set_value(h);      if (h < l) eDimensionKeyRangeLow.set_value(h);
884  }  }
885    
886  void MainWindow::load_gig(gig::File* gig, const char* filename)  sigc::signal<void> InstrumentProps::signal_instrument_changed()
887  {  {
888      file = gig;      return instrument_changed;
889    }
890    
891      if (filename) {  void MainWindow::file_changed()
892          const char *basename = strrchr(filename, '/');  {
893          basename = basename ? basename + 1 : filename;      if (file && !file_is_changed) {
894          set_title(basename);          set_title("*" + get_title());
895      } else {          file_is_changed = true;
         set_title("unnamed");  
896      }      }
897    }
898    
899    void MainWindow::load_gig(gig::File* gig, const char* filename)
900    {
901        file = 0;
902    
903        this->filename = filename ? filename : _("Unsaved Gig File");
904        set_title(Glib::filename_display_basename(this->filename));
905        file_has_name = filename;
906        file_is_changed = false;
907    
908      propDialog.set_info(gig->pInfo);      propDialog.set_info(gig->pInfo);
909    
# Line 785  void MainWindow::load_gig(gig::File* gig Line 952  void MainWindow::load_gig(gig::File* gig
952          }          }
953      }      }
954    
955        file = gig;
956    
957      // select the first instrument      // select the first instrument
958      Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();      Glib::RefPtr<Gtk::TreeSelection> tree_sel_ref = m_TreeView.get_selection();
959      tree_sel_ref->select(Gtk::TreePath("0"));      tree_sel_ref->select(Gtk::TreePath("0"));
# Line 858  void MainWindow::on_action_add_instrumen Line 1027  void MainWindow::on_action_add_instrumen
1027      Gtk::TreeModel::Row rowInstr = *iterInstr;      Gtk::TreeModel::Row rowInstr = *iterInstr;
1028      rowInstr[m_Columns.m_col_name] = instrument->pInfo->Name.c_str();      rowInstr[m_Columns.m_col_name] = instrument->pInfo->Name.c_str();
1029      rowInstr[m_Columns.m_col_instr] = instrument;      rowInstr[m_Columns.m_col_instr] = instrument;
1030        file_changed();
1031  }  }
1032    
1033  void MainWindow::on_action_remove_instrument() {  void MainWindow::on_action_remove_instrument() {
# Line 872  void MainWindow::on_action_remove_instru Line 1042  void MainWindow::on_action_remove_instru
1042              if (instr) file->DeleteInstrument(instr);              if (instr) file->DeleteInstrument(instr);
1043              // remove respective row from instruments tree view              // remove respective row from instruments tree view
1044              m_refTreeModel->erase(it);              m_refTreeModel->erase(it);
1045                file_changed();
1046          } catch (RIFF::Exception e) {          } catch (RIFF::Exception e) {
1047              Gtk::MessageDialog msg(*this, e.Message.c_str(), false, Gtk::MESSAGE_ERROR);              Gtk::MessageDialog msg(*this, e.Message.c_str(), false, Gtk::MESSAGE_ERROR);
1048              msg.run();              msg.run();
# Line 900  void MainWindow::on_action_add_group() { Line 1071  void MainWindow::on_action_add_group() {
1071      rowGroup[m_SamplesModel.m_col_name] = group->Name.c_str();      rowGroup[m_SamplesModel.m_col_name] = group->Name.c_str();
1072      rowGroup[m_SamplesModel.m_col_sample] = NULL;      rowGroup[m_SamplesModel.m_col_sample] = NULL;
1073      rowGroup[m_SamplesModel.m_col_group] = group;      rowGroup[m_SamplesModel.m_col_group] = group;
1074        file_changed();
1075  }  }
1076    
1077  void MainWindow::on_action_add_sample() {  void MainWindow::on_action_add_sample() {
# Line 925  void MainWindow::on_action_add_sample() Line 1097  void MainWindow::on_action_add_sample()
1097      dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);      dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);
1098      dialog.set_select_multiple(true);      dialog.set_select_multiple(true);
1099      Gtk::FileFilter soundfilter; // matches all file types supported by libsndfile      Gtk::FileFilter soundfilter; // matches all file types supported by libsndfile
1100      const char* supportedFileTypes[] = {      const char* const supportedFileTypes[] = {
1101          "*.wav", "*.WAV", "*.aiff", "*.AIFF", "*.aifc", "*.AIFC", "*.snd",          "*.wav", "*.WAV", "*.aiff", "*.AIFF", "*.aifc", "*.AIFC", "*.snd",
1102          "*.SND", "*.au", "*.AU", "*.paf", "*.PAF", "*.iff", "*.IFF",          "*.SND", "*.au", "*.AU", "*.paf", "*.PAF", "*.iff", "*.IFF",
1103          "*.svx", "*.SVX", "*.sf", "*.SF", "*.voc", "*.VOC", "*.w64",          "*.svx", "*.SVX", "*.sf", "*.SF", "*.voc", "*.VOC", "*.w64",
# Line 955  void MainWindow::on_action_add_sample() Line 1127  void MainWindow::on_action_add_sample()
1127                  int bitdepth;                  int bitdepth;
1128                  switch (info.format & 0xff) {                  switch (info.format & 0xff) {
1129                      case SF_FORMAT_PCM_S8:                      case SF_FORMAT_PCM_S8:
                         bitdepth = 16; // we simply convert to 16 bit for now  
                         break;  
1130                      case SF_FORMAT_PCM_16:                      case SF_FORMAT_PCM_16:
1131                        case SF_FORMAT_PCM_U8:
1132                          bitdepth = 16;                          bitdepth = 16;
1133                          break;                          break;
1134                      case SF_FORMAT_PCM_24:                      case SF_FORMAT_PCM_24:
                         bitdepth = 32; // we simply convert to 32 bit for now  
                         break;  
1135                      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;  
1136                      case SF_FORMAT_FLOAT:                      case SF_FORMAT_FLOAT:
                         bitdepth = 32;  
                         break;  
1137                      case SF_FORMAT_DOUBLE:                      case SF_FORMAT_DOUBLE:
1138                          bitdepth = 32; // I guess we will always truncate this to 32 bit                          bitdepth = 24;
1139                          break;                          break;
1140                      default:                      default:
1141                          sf_close(hFile); // close sound file                          sf_close(hFile); // close sound file
# Line 982  void MainWindow::on_action_add_sample() Line 1144  void MainWindow::on_action_add_sample()
1144                  // add a new sample to the .gig file                  // add a new sample to the .gig file
1145                  gig::Sample* sample = file->AddSample();                  gig::Sample* sample = file->AddSample();
1146                  // file name without path                  // file name without path
1147                  sample->pInfo->Name = (*iter).substr((*iter).rfind('/') + 1).raw();                  Glib::ustring filename = Glib::filename_display_basename(*iter);
1148                    // remove file extension if there is one
1149                    for (int i = 0; supportedFileTypes[i]; i++) {
1150                        if (Glib::str_has_suffix(filename, supportedFileTypes[i] + 1)) {
1151                            filename.erase(filename.length() - strlen(supportedFileTypes[i] + 1));
1152                            break;
1153                        }
1154                    }
1155                    sample->pInfo->Name = filename;
1156                  sample->Channels = info.channels;                  sample->Channels = info.channels;
1157                  sample->BitDepth = bitdepth;                  sample->BitDepth = bitdepth;
1158                  sample->FrameSize = bitdepth / 8/*1 byte are 8 bits*/ * info.channels;                  sample->FrameSize = bitdepth / 8/*1 byte are 8 bits*/ * info.channels;
1159                  sample->SamplesPerSecond = info.samplerate;                  sample->SamplesPerSecond = info.samplerate;
1160                    sample->AverageBytesPerSecond = sample->FrameSize * sample->SamplesPerSecond;
1161                    sample->BlockAlign = sample->FrameSize;
1162                    sample->SamplesTotal = info.frames;
1163    
1164                    SF_INSTRUMENT instrument;
1165                    if (sf_command(hFile, SFC_GET_INSTRUMENT,
1166                                   &instrument, sizeof(instrument)) != SF_FALSE)
1167                    {
1168                        sample->MIDIUnityNote = instrument.basenote;
1169    
1170    #if HAVE_SF_INSTRUMENT_LOOPS
1171                        if (instrument.loop_count && instrument.loops[0].mode != SF_LOOP_NONE) {
1172                            sample->Loops = 1;
1173    
1174                            switch (instrument.loops[0].mode) {
1175                            case SF_LOOP_FORWARD:
1176                                sample->LoopType = gig::loop_type_normal;
1177                                break;
1178                            case SF_LOOP_BACKWARD:
1179                                sample->LoopType = gig::loop_type_backward;
1180                                break;
1181                            case SF_LOOP_ALTERNATING:
1182                                sample->LoopType = gig::loop_type_bidirectional;
1183                                break;
1184                            }
1185                            sample->LoopStart = instrument.loops[0].start;
1186                            sample->LoopEnd = instrument.loops[0].end;
1187                            sample->LoopPlayCount = instrument.loops[0].count;
1188                            sample->LoopSize = sample->LoopEnd - sample->LoopStart + 1;
1189                        }
1190    #endif
1191                    }
1192    
1193                  // schedule resizing the sample (which will be done                  // schedule resizing the sample (which will be done
1194                  // physically when File::Save() is called)                  // physically when File::Save() is called)
1195                  sample->Resize(info.frames);                  sample->Resize(info.frames);
# Line 1002  void MainWindow::on_action_add_sample() Line 1205  void MainWindow::on_action_add_sample()
1205                  Gtk::TreeModel::iterator iterSample =                  Gtk::TreeModel::iterator iterSample =
1206                      m_refSamplesTreeModel->append(row.children());                      m_refSamplesTreeModel->append(row.children());
1207                  Gtk::TreeModel::Row rowSample = *iterSample;                  Gtk::TreeModel::Row rowSample = *iterSample;
1208                  rowSample[m_SamplesModel.m_col_name]   = sample->pInfo->Name.c_str();                  rowSample[m_SamplesModel.m_col_name]   = filename;
1209                  rowSample[m_SamplesModel.m_col_sample] = sample;                  rowSample[m_SamplesModel.m_col_sample] = sample;
1210                  rowSample[m_SamplesModel.m_col_group]  = NULL;                  rowSample[m_SamplesModel.m_col_group]  = NULL;
1211                  // close sound file                  // close sound file
1212                  sf_close(hFile);                  sf_close(hFile);
1213                    file_changed();
1214              } catch (std::string what) { // remember the files that made trouble (and their cause)              } catch (std::string what) { // remember the files that made trouble (and their cause)
1215                  if (error_files.size()) error_files += "\n";                  if (error_files.size()) error_files += "\n";
1216                  error_files += *iter += " (" + what + ")";                  error_files += *iter += " (" + what + ")";
# Line 1057  void MainWindow::on_action_remove_sample Line 1261  void MainWindow::on_action_remove_sample
1261                          }                          }
1262                      }                      }
1263                  }                  }
1264                    file_changed();
1265              } else if (sample) {              } else if (sample) {
1266                  // remove sample from the .gig file                  // remove sample from the .gig file
1267                  file->DeleteSample(sample);                  file->DeleteSample(sample);
# Line 1071  void MainWindow::on_action_remove_sample Line 1276  void MainWindow::on_action_remove_sample
1276                          break;                          break;
1277                      }                      }
1278                  }                  }
1279                    dimreg_changed();
1280                    file_changed();
1281              }              }
1282              // remove respective row(s) from samples tree view              // remove respective row(s) from samples tree view
1283              m_refSamplesTreeModel->erase(it);              m_refSamplesTreeModel->erase(it);
# Line 1081  void MainWindow::on_action_remove_sample Line 1288  void MainWindow::on_action_remove_sample
1288      }      }
1289  }  }
1290    
1291    // For some reason drag_data_get gets called two times for each
1292    // drag'n'drop (at least when target is an Entry). This work-around
1293    // makes sure the code in drag_data_get and drop_drag_data_received is
1294    // only executed once, as drag_begin only gets called once.
1295    void MainWindow::on_sample_treeview_drag_begin(const Glib::RefPtr<Gdk::DragContext>& context)
1296    {
1297        first_call_to_drag_data_get = true;
1298    }
1299    
1300  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>&,
1301                                                    Gtk::SelectionData& selection_data, guint, guint)                                                    Gtk::SelectionData& selection_data, guint, guint)
1302  {  {
1303        if (!first_call_to_drag_data_get) return;
1304        first_call_to_drag_data_get = false;
1305    
1306      // get selected sample      // get selected sample
1307      gig::Sample* sample = NULL;      gig::Sample* sample = NULL;
1308      Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();      Glib::RefPtr<Gtk::TreeSelection> sel = m_TreeViewSamples.get_selection();
# Line 1101  void MainWindow::on_sample_label_drop_dr Line 1320  void MainWindow::on_sample_label_drop_dr
1320      const Glib::RefPtr<Gdk::DragContext>& context, int, int,      const Glib::RefPtr<Gdk::DragContext>& context, int, int,
1321      const Gtk::SelectionData& selection_data, guint, guint time)      const Gtk::SelectionData& selection_data, guint, guint time)
1322  {  {
     gig::DimensionRegion* dimregion = m_DimRegionChooser.get_dimregion();  
1323      gig::Sample* sample = *((gig::Sample**) selection_data.get_data());      gig::Sample* sample = *((gig::Sample**) selection_data.get_data());
1324    
1325      if (sample && dimregion && selection_data.get_length() == sizeof(gig::Sample*)) {      if (sample && selection_data.get_length() == sizeof(gig::Sample*)) {
1326          if (sample != dimregion->pSample) {          std::cout << "Drop received sample \"" <<
1327              dimregion->pSample = sample;              sample->pInfo->Name << "\"" << std::endl;
1328              dimreg_edit.wSample->set_text(dimregion->pSample->pInfo->Name.c_str());          // drop success
1329              std::cout << "Drop received sample \"" <<          context->drop_reply(true, time);
1330                  dimregion->pSample->pInfo->Name.c_str() << "\"" << std::endl;  
1331              // drop success          // find the samplechannel dimension
1332              context->drop_reply(true, time);          gig::Region* region = m_RegionChooser.get_region();
1333              return;          gig::dimension_def_t* stereo_dimension = 0;
1334            for (int i = 0 ; i < region->Dimensions ; i++) {
1335                if (region->pDimensionDefinitions[i].dimension ==
1336                    gig::dimension_samplechannel) {
1337                    stereo_dimension = &region->pDimensionDefinitions[i];
1338                    break;
1339                }
1340            }
1341            bool channels_changed = false;
1342            if (sample->Channels == 1 && stereo_dimension) {
1343                // remove the samplechannel dimension
1344                region->DeleteDimension(stereo_dimension);
1345                channels_changed = true;
1346                region_changed();
1347            }
1348            dimreg_edit.set_sample(sample);
1349    
1350            if (sample->Channels == 2 && !stereo_dimension) {
1351                // add samplechannel dimension
1352                gig::dimension_def_t dim;
1353                dim.dimension = gig::dimension_samplechannel;
1354                dim.bits = 1;
1355                dim.zones = 2;
1356                region->AddDimension(&dim);
1357                channels_changed = true;
1358                region_changed();
1359            }
1360            if (channels_changed) {
1361                // unmap all samples with wrong number of channels
1362                // TODO: maybe there should be a warning dialog for this
1363                for (int i = 0 ; i < region->DimensionRegions ; i++) {
1364                    gig::DimensionRegion* d = region->pDimensionRegions[i];
1365                    if (d->pSample && d->pSample->Channels != sample->Channels) {
1366                        d->pSample = 0;
1367                    }
1368                }
1369          }          }
1370    
1371            return;
1372      }      }
1373      // drop failed      // drop failed
1374      context->drop_reply(false, time);      context->drop_reply(false, time);
# Line 1127  void MainWindow::sample_name_changed(con Line 1382  void MainWindow::sample_name_changed(con
1382      gig::Group* group   = row[m_SamplesModel.m_col_group];      gig::Group* group   = row[m_SamplesModel.m_col_group];
1383      gig::Sample* sample = row[m_SamplesModel.m_col_sample];      gig::Sample* sample = row[m_SamplesModel.m_col_sample];
1384      if (group) {      if (group) {
1385          group->Name = name;          if (group->Name != name) {
1386                group->Name = name;
1387                printf("group name changed\n");
1388                file_changed();
1389            }
1390      } else if (sample) {      } else if (sample) {
1391          sample->pInfo->Name = name.raw();          if (sample->pInfo->Name != name.raw()) {
1392                sample->pInfo->Name = name.raw();
1393                printf("sample name changed\n");
1394                file_changed();
1395            }
1396      }      }
1397  }  }
1398    
# Line 1139  void MainWindow::instrument_name_changed Line 1402  void MainWindow::instrument_name_changed
1402      Gtk::TreeModel::Row row = *iter;      Gtk::TreeModel::Row row = *iter;
1403      Glib::ustring name = row[m_Columns.m_col_name];      Glib::ustring name = row[m_Columns.m_col_name];
1404      gig::Instrument* instrument = row[m_Columns.m_col_instr];      gig::Instrument* instrument = row[m_Columns.m_col_instr];
1405      if (instrument) instrument->pInfo->Name = name.raw();      if (instrument && instrument->pInfo->Name != name.raw()) {
1406            instrument->pInfo->Name = name.raw();
1407            file_changed();
1408        }
1409  }  }

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

  ViewVC Help
Powered by ViewVC