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

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

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

revision 1262 by persson, Sun Jul 22 15:07:08 2007 UTC revision 1303 by persson, Sun Aug 26 09:29:52 2007 UTC
# Line 31  Line 31 
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 234  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 253  MainWindow::MainWindow() Line 268  MainWindow::MainWindow()
268      file_is_changed = false;      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()
# Line 407  bool MainWindow::close_confirmation_dial Line 425  bool MainWindow::close_confirmation_dial
425                                   Glib::filename_display_basename(filename).c_str());                                   Glib::filename_display_basename(filename).c_str());
426      Gtk::MessageDialog dialog(*this, msg, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_NONE);      Gtk::MessageDialog dialog(*this, msg, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_NONE);
427      g_free(msg);      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."));      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);      dialog.add_button(_("Close _Without Saving"), Gtk::RESPONSE_NO);
432      dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);      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);      dialog.add_button(file_has_name ? Gtk::Stock::SAVE : Gtk::Stock::SAVE_AS, Gtk::RESPONSE_YES);
434      dialog.set_default_response(Gtk::RESPONSE_YES);      dialog.set_default_response(Gtk::RESPONSE_YES);
435      int response = dialog.run();      int response = dialog.run();
436        dialog.hide();
437      if (response == Gtk::RESPONSE_YES) return file_save();      if (response == Gtk::RESPONSE_YES) return file_save();
438      return response != Gtk::RESPONSE_CANCEL;      return response != Gtk::RESPONSE_CANCEL;
439  }  }
# Line 434  void MainWindow::on_action_file_open() Line 455  void MainWindow::on_action_file_open()
455      if (dialog.run() == Gtk::RESPONSE_OK) {      if (dialog.run() == Gtk::RESPONSE_OK) {
456          std::string filename = dialog.get_filename();          std::string filename = dialog.get_filename();
457          printf("filename=%s\n", filename.c_str());          printf("filename=%s\n", filename.c_str());
         __clear();  
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(filename.c_str());          load_file(filename.c_str());
460          current_dir = Glib::path_get_dirname(filename);          current_dir = Glib::path_get_dirname(filename);
# Line 443  void MainWindow::on_action_file_open() Line 463  void MainWindow::on_action_file_open()
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 483  void MainWindow::on_action_file_save() Line 504  void MainWindow::on_action_file_save()
504      file_save();      file_save();
505  }  }
506    
507  bool MainWindow::file_save()  bool MainWindow::check_if_savable()
508  {  {
509      if (!file) return false;      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();      if (!file_has_name) return file_save_as();
535    
536      std::cout << "Saving file\n" << std::flush;      std::cout << "Saving file\n" << std::flush;
# Line 508  bool MainWindow::file_save() Line 553  bool MainWindow::file_save()
553    
554  void MainWindow::on_action_file_save_as()  void MainWindow::on_action_file_save_as()
555  {  {
556        if (!check_if_savable()) return;
557      file_save_as();      file_save_as();
558  }  }
559    
560  bool MainWindow::file_save_as()  bool MainWindow::file_save_as()
561  {  {
     if (!file) return false;  
562      Gtk::FileChooserDialog dialog(*this, _("Save as"), Gtk::FILE_CHOOSER_ACTION_SAVE);      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);
# Line 576  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 1073  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 1113  void MainWindow::on_action_add_sample() Line 1157  void MainWindow::on_action_add_sample()
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 1199  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();                  file_changed();
1281              }              }
1282              // remove respective row(s) from samples tree view              // remove respective row(s) from samples tree view
# Line 1210  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 1230  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              file_changed();          gig::dimension_def_t* stereo_dimension = 0;
1334              return;          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);

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

  ViewVC Help
Powered by ViewVC