Merge branch 'master' into cairocanvas
[ardour.git] / gtk2_ardour / sfdb_ui.cc
index 85b4f7d7ef5b51bea3618fe9b0e45a6952bec820..84065c69b1b4d8b1192a5a99960baef1da8a7f5e 100644 (file)
 #include <sstream>
 
 #include <unistd.h>
+#include <limits.h>
 #include <sys/stat.h>
-#include <sys/param.h>
 
 #include <gtkmm/box.h>
 #include <gtkmm/stock.h>
+
+#include <glib/gstdio.h>
 #include <glibmm/fileutils.h>
 
 #include "pbd/convert.h"
@@ -64,9 +66,7 @@
 #include "main_clock.h"
 #include "public_editor.h"
 
-#ifdef FREESOUND
 #include "sfdb_freesound_mootcher.h"
-#endif
 
 #include "i18n.h"
 
@@ -80,6 +80,7 @@ using namespace Editing;
 using std::string;
 
 string SoundFileBrowser::persistent_folder;
+typedef TreeView::Selection::ListHandle_Path ListPath;
 
 static ImportMode
 string2importmode (string str)
@@ -121,7 +122,9 @@ SoundFileBox::SoundFileBox (bool persistent)
          length_clock ("sfboxLengthClock", !persistent, "", false, false, true, false),
          timecode_clock ("sfboxTimecodeClock", !persistent, "", false, false, false, false),
          main_box (false, 6),
-         autoplay_btn (_("Auto-play"))
+         autoplay_btn (_("Auto-play")),
+         seek_slider(0,1000,1),
+         _seeking(false)
 
 {
        set_name (X_("SoundFileBox"));
@@ -199,9 +202,18 @@ SoundFileBox::SoundFileBox (bool persistent)
        bottom_box.pack_start(stop_btn, true, true);
        bottom_box.pack_start(autoplay_btn, false, false);
 
+       seek_slider.set_draw_value(false);
+
+       seek_slider.add_events(Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
+       seek_slider.signal_button_press_event().connect(sigc::mem_fun(*this, &SoundFileBox::seek_button_press), false);
+       seek_slider.signal_button_release_event().connect(sigc::mem_fun(*this, &SoundFileBox::seek_button_release), false);
+       main_box.pack_start (seek_slider, false, false);
+
        play_btn.signal_clicked().connect (sigc::mem_fun (*this, &SoundFileBox::audition));
        stop_btn.signal_clicked().connect (sigc::mem_fun (*this, &SoundFileBox::stop_audition));
 
+       stop_btn.set_sensitive (false);
+
        channels_value.set_alignment (0.0f, 0.5f);
        samplerate_value.set_alignment (0.0f, 0.5f);
 }
@@ -217,9 +229,45 @@ SoundFileBox::set_session(Session* s)
        if (!_session) {
                play_btn.set_sensitive (false);
                stop_btn.set_sensitive (false);
+               auditioner_connections.drop_connections();
+       } else {
+               auditioner_connections.drop_connections();
+               _session->AuditionActive.connect(auditioner_connections, invalidator (*this), boost::bind (&SoundFileBox::audition_active, this, _1), gui_context());
+               _session->the_auditioner()->AuditionProgress.connect(auditioner_connections, invalidator (*this), boost::bind (&SoundFileBox::audition_progress, this, _1, _2), gui_context());
+       }
+}
+
+void
+SoundFileBox::audition_active(bool active) {
+       stop_btn.set_sensitive (active);
+       seek_slider.set_sensitive (active);
+       if (!active) {
+               seek_slider.set_value(0);
+       }
+}
+
+void
+SoundFileBox::audition_progress(ARDOUR::framecnt_t pos, ARDOUR::framecnt_t len) {
+       if (!_seeking) {
+               seek_slider.set_value( 1000.0 * pos / len);
+               seek_slider.set_sensitive (true);
        }
 }
 
+bool
+SoundFileBox::seek_button_press(GdkEventButton*) {
+       _seeking = true;
+       return false; // pass on to slider
+}
+
+bool
+SoundFileBox::seek_button_release(GdkEventButton*) {
+       _seeking = false;
+       _session->the_auditioner()->seek_to_percent(seek_slider.get_value() / 10.0);
+       seek_slider.set_sensitive (false);
+       return false; // pass on to slider
+}
+
 bool
 SoundFileBox::setup_labels (const string& filename)
 {
@@ -341,7 +389,8 @@ SoundFileBox::audition ()
                try {
                        afs = boost::dynamic_pointer_cast<AudioFileSource> (
                                SourceFactory::createExternal (DataType::AUDIO, *_session,
-                                                              path, n, Source::Flag (0), false));
+                                                              path, n,
+                                                              Source::Flag (0), false));
                        
                        srclist.push_back(afs);
 
@@ -512,12 +561,8 @@ SoundFileBrowser::SoundFileBrowser (string title, ARDOUR::Session* s, bool persi
        found_search_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::found_search_clicked));
        found_entry.signal_activate().connect(sigc::mem_fun(*this, &SoundFileBrowser::found_search_clicked));
        
-       freesound_stop_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_stop_clicked));
-       
        notebook.append_page (*vbox, _("Search Tags"));
 
-#ifdef FREESOUND
-
        //add freesound search
 
        HBox* passbox;
@@ -555,9 +600,9 @@ SoundFileBrowser::SoundFileBrowser (string title, ARDOUR::Session* s, bool persi
        freesound_more_btn.set_label(_("More"));
        freesound_more_btn.set_sensitive(false);
 
-       passbox->pack_end   (freesound_stop_btn, false, false);
-       freesound_stop_btn.set_label(_("Stop"));
-       freesound_stop_btn.set_sensitive(false);
+       passbox->pack_start (freesound_similar_btn, false, false);
+       freesound_similar_btn.set_label(_("Similar"));
+       freesound_similar_btn.set_sensitive(false);
        
        scroll = manage(new ScrolledWindow);
        scroll->add(freesound_list_view);
@@ -566,9 +611,8 @@ SoundFileBrowser::SoundFileBrowser (string title, ARDOUR::Session* s, bool persi
        vbox = manage(new VBox);
        vbox->set_spacing (3);
        vbox->pack_start (*passbox, PACK_SHRINK);
-       vbox->pack_start (freesound_progress_bar, PACK_SHRINK);
        vbox->pack_start (*scroll);
-       
+
        freesound_list_view.append_column(_("ID")      , freesound_list_columns.id);
        freesound_list_view.append_column(_("Filename"), freesound_list_columns.filename);
        // freesound_list_view.append_column(_("URI")     , freesound_list_columns.uri);
@@ -577,22 +621,23 @@ SoundFileBrowser::SoundFileBrowser (string title, ARDOUR::Session* s, bool persi
        freesound_list_view.append_column(_("Samplerate"), freesound_list_columns.smplrate);
        freesound_list_view.append_column(_("License"), freesound_list_columns.license);
        freesound_list_view.get_column(0)->set_alignment(0.5);
-       freesound_list_view.get_column(1)->set_expand(true);
+       freesound_list_view.get_column(1)->set_expand(true); // filename
+       freesound_list_view.get_column(1)->set_resizable(true); // filename
        freesound_list_view.get_column(2)->set_alignment(0.5);
        freesound_list_view.get_column(3)->set_alignment(0.5);
        freesound_list_view.get_column(4)->set_alignment(0.5);
        freesound_list_view.get_column(5)->set_alignment(0.5);
        
        freesound_list_view.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_list_view_selected));
+       freesound_list_view.set_tooltip_column(1);
 
        freesound_list_view.get_selection()->set_mode (SELECTION_MULTIPLE);
        freesound_list_view.signal_row_activated().connect (sigc::mem_fun (*this, &SoundFileBrowser::freesound_list_view_activated));
        freesound_search_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_search_clicked));
        freesound_entry.signal_activate().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_search_clicked));
        freesound_more_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_more_clicked));
-       freesound_stop_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_stop_clicked));
+       freesound_similar_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_similar_clicked));
        notebook.append_page (*vbox, _("Search Freesound"));
-#endif
 
        notebook.set_size_request (500, -1);
        notebook.signal_switch_page().connect (sigc::hide_return (sigc::hide (sigc::hide (sigc::mem_fun (*this, &SoundFileBrowser::reset_options)))));
@@ -711,7 +756,7 @@ SoundFileBrowser::add_gain_meter ()
        boost::shared_ptr<Route> r = _session->the_auditioner ();
 
        gm->set_controls (r, r->shared_peak_meter(), r->amp());
-       gm->set_fader_name (X_("AudioTrackFader"));
+       gm->set_fader_name (X_("GainFader"));
 
        meter_packer.set_border_width (12);
        meter_packer.pack_start (*gm, false, true);
@@ -787,7 +832,7 @@ SoundFileBrowser::found_list_view_selected ()
        } else {
                string file;
 
-               TreeView::Selection::ListHandle_Path rows = found_list_view.get_selection()->get_selected_rows ();
+               ListPath rows = found_list_view.get_selection()->get_selected_rows ();
 
                if (!rows.empty()) {
                        TreeIter iter = found_list->get_iter(*rows.begin());
@@ -802,55 +847,6 @@ SoundFileBrowser::found_list_view_selected ()
        }
 }
 
-void
-SoundFileBrowser::freesound_list_view_selected ()
-{
-       freesound_download_cancel = false;
-       freesound_stop_btn.set_sensitive(true);
-
-#ifdef FREESOUND
-       if (!reset_options ()) {
-               set_action_sensitive (false);
-       } else {
-               Mootcher mootcher; 
-               string file;
-
-               TreeView::Selection::ListHandle_Path rows = freesound_list_view.get_selection()->get_selected_rows ();
-
-               if (!rows.empty()) {
-                       TreeIter iter = freesound_list->get_iter(*rows.begin());
-
-                       string id  = (*iter)[freesound_list_columns.id];
-                       string uri = (*iter)[freesound_list_columns.uri];
-                       string ofn = (*iter)[freesound_list_columns.filename];
-
-                       // download the sound file                      
-                       GdkCursor *prev_cursor;
-                       prev_cursor = gdk_window_get_cursor (get_window()->gobj());
-                       gdk_window_set_cursor (get_window()->gobj(), gdk_cursor_new(GDK_WATCH));
-                       gdk_flush();
-
-                       file = mootcher.getAudioFile(ofn, id, uri, this);
-
-                       gdk_window_set_cursor (get_window()->gobj(), prev_cursor);
-
-                       if (file != "") {
-                               chooser.set_filename (file);
-                               set_action_sensitive (true);
-                       }
-               } else {
-                       set_action_sensitive (false);
-               }
-
-               freesound_progress_bar.set_text(
-                       string_compose(P_("found %1 match", "found %1 matches", matches), matches));
-
-               preview.setup_labels (file);
-       }
-#endif
-       freesound_stop_btn.set_sensitive(false);
-}
-
 void
 SoundFileBrowser::found_search_clicked ()
 {
@@ -875,6 +871,91 @@ SoundFileBrowser::found_search_clicked ()
        }
 }
 
+
+std::string
+SoundFileBrowser::freesound_get_audio_file(Gtk::TreeIter iter)
+{
+
+       Mootcher *mootcher = new Mootcher;
+       std::string file;
+
+       string id  = (*iter)[freesound_list_columns.id];
+       string uri = (*iter)[freesound_list_columns.uri];
+       string ofn = (*iter)[freesound_list_columns.filename];
+
+       if (mootcher->checkAudioFile(ofn, id)) {
+               // file already exists, no need to download it again
+               file = mootcher->audioFileName;
+               delete mootcher;
+               (*iter)[freesound_list_columns.started] = false;
+               return file;
+       }
+       if (!(*iter)[freesound_list_columns.started]) {
+               // start downloading the sound file
+               (*iter)[freesound_list_columns.started] = true;
+               mootcher->fetchAudioFile(ofn, id, uri, this);
+       }
+       return "";
+}
+
+void
+SoundFileBrowser::freesound_list_view_selected ()
+{
+
+       if (!reset_options ()) {
+               set_action_sensitive (false);
+       } else {
+               std::string file;
+               ListPath rows = freesound_list_view.get_selection()->get_selected_rows ();
+               for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
+                       file = freesound_get_audio_file (freesound_list->get_iter(*i));
+               }
+
+               switch (rows.size()) {
+                       case 0:
+                               // nothing selected
+                               freesound_similar_btn.set_sensitive(false);
+                               set_action_sensitive (false);
+                               break;
+                       case 1:
+                               // exactly one item selected
+                               if (file != "") {
+                                       // file exists on disk already
+                                       chooser.set_filename (file);
+                                       preview.setup_labels (file);
+                                       set_action_sensitive (true);
+                               }
+                               freesound_similar_btn.set_sensitive(true);
+                               break;
+                       default:
+                               // multiple items selected
+                               preview.setup_labels ("");
+                               freesound_similar_btn.set_sensitive(false);
+                               break;
+               }
+
+       }
+}
+
+void
+SoundFileBrowser::refresh_display(std::string ID, std::string file)
+{
+       // called when the mootcher has finished downloading a file
+       ListPath rows = freesound_list_view.get_selection()->get_selected_rows ();
+       if (rows.size() == 1) {
+               // there's a single item selected in the freesound list
+               //XXX make a function to be used to construct the actual file name both here and in the mootcher
+               Gtk::TreeIter row = freesound_list->get_iter(*rows.begin());
+               std::string selected_ID = (*row)[freesound_list_columns.id]; 
+               if (ID == selected_ID) {
+                       // the selected item in the freesound list is the item that has just finished downloading
+                       chooser.set_filename(file);
+                       preview.setup_labels (file);
+                       set_action_sensitive (true);
+               }
+       }
+}
+
 void
 SoundFileBrowser::freesound_search_clicked ()
 {
@@ -895,18 +976,32 @@ SoundFileBrowser::freesound_more_clicked ()
 }
 
 void
-SoundFileBrowser::freesound_stop_clicked ()
+SoundFileBrowser::freesound_similar_clicked ()
 {
-       freesound_download_cancel = true;
+       ListPath rows = freesound_list_view.get_selection()->get_selected_rows ();
+       if (rows.size() == 1) {
+               Mootcher mootcher;
+               string id;
+               Gtk::TreeIter iter = freesound_list->get_iter(*rows.begin());
+               id = (*iter)[freesound_list_columns.id];
+               freesound_list->clear();
+
+               GdkCursor *prev_cursor;
+               prev_cursor = gdk_window_get_cursor (get_window()->gobj());
+               gdk_window_set_cursor (get_window()->gobj(), gdk_cursor_new(GDK_WATCH));
+               gdk_flush();
+               
+               std::string theString = mootcher.searchSimilar(id);
+               
+               gdk_window_set_cursor (get_window()->gobj(), prev_cursor);
+               handle_freesound_results(theString);
+       }
 }
 
-
 void
 SoundFileBrowser::freesound_search()
 {
-#ifdef FREESOUND
        Mootcher mootcher;
-       freesound_list_view.get_column(1)->set_sizing(TREE_VIEW_COLUMN_GROW_ONLY);
 
        string search_string = freesound_entry.get_text ();
        enum sortMethod sort_method = (enum sortMethod) freesound_sort.get_active_row_number();
@@ -914,7 +1009,6 @@ SoundFileBrowser::freesound_search()
        GdkCursor *prev_cursor;
        prev_cursor = gdk_window_get_cursor (get_window()->gobj());
        gdk_window_set_cursor (get_window()->gobj(), gdk_cursor_new(GDK_WATCH));
-       freesound_progress_bar.set_fraction(0.0);
        gdk_flush();
 
        std::string theString = mootcher.searchText(
@@ -929,7 +1023,11 @@ SoundFileBrowser::freesound_search()
                        );
 
        gdk_window_set_cursor (get_window()->gobj(), prev_cursor);
+       handle_freesound_results(theString);
+}
 
+void
+SoundFileBrowser::handle_freesound_results(std::string theString) {
        XMLTree doc;
        doc.read_buffer( theString );
        XMLNode *root = doc.root();
@@ -1065,14 +1163,6 @@ SoundFileBrowser::freesound_search()
                        matches++;
                }
        }
-
-       if (matches == 0) {
-               freesound_progress_bar.set_text(_("Search returned no results."));
-       } else {
-               freesound_progress_bar.set_text(string_compose(P_("Found %1 match", "Found %1 matches", matches), matches));
-       }
-       freesound_list_view.get_column(1)->set_sizing(TREE_VIEW_COLUMN_AUTOSIZE);
-#endif
 }
 
 vector<string>
@@ -1093,9 +1183,7 @@ SoundFileBrowser::get_paths ()
                        }
                }
 
-       } else if (n==1){
-
-               typedef TreeView::Selection::ListHandle_Path ListPath;
+       } else if (n == 1) {
 
                ListPath rows = found_list_view.get_selection()->get_selected_rows ();
                for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
@@ -1105,31 +1193,13 @@ SoundFileBrowser::get_paths ()
                        results.push_back (str);
                }
        } else {
-#ifdef FREESOUND
-               typedef TreeView::Selection::ListHandle_Path ListPath;
-               Mootcher mootcher;
-
                ListPath rows = freesound_list_view.get_selection()->get_selected_rows ();
                for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
-                       TreeIter iter = freesound_list->get_iter(*i);
-                       string id  = (*iter)[freesound_list_columns.id];
-                       string uri = (*iter)[freesound_list_columns.uri];
-                       string ofn = (*iter)[freesound_list_columns.filename];
-
-                       GdkCursor *prev_cursor;
-                       prev_cursor = gdk_window_get_cursor (get_window()->gobj());
-                       gdk_window_set_cursor (get_window()->gobj(), gdk_cursor_new(GDK_WATCH));
-                       gdk_flush();
-
-                       string str = mootcher.getAudioFile(ofn, id, uri, this);
+                       string str = freesound_get_audio_file (freesound_list->get_iter(*i));
                        if (str != "") {
                                results.push_back (str);
                        }
-                       
-                       gdk_window_set_cursor (get_window()->gobj(), prev_cursor);
-
                }
-#endif
        }
 
        return results;
@@ -1436,6 +1506,9 @@ SoundFileOmega::check_info (const vector<string>& paths, bool& same_size, bool&
 bool
 SoundFileOmega::check_link_status (const Session* s, const vector<string>& paths)
 {
+#ifdef PLATFORM_WINDOWS
+       return false;
+#else
        std::string tmpdir(Glib::build_filename (s->session_directory().sound_path(), "linktest"));
        bool ret = false;
 
@@ -1447,7 +1520,7 @@ SoundFileOmega::check_link_status (const Session* s, const vector<string>& paths
 
        for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
 
-               char tmpc[MAXPATHLEN+1];
+               char tmpc[PATH_MAX+1];
 
                snprintf (tmpc, sizeof(tmpc), "%s/%s", tmpdir.c_str(), Glib::path_get_basename (*i).c_str());
 
@@ -1457,7 +1530,7 @@ SoundFileOmega::check_link_status (const Session* s, const vector<string>& paths
                        goto out;
                }
 
-               unlink (tmpc);
+               ::g_unlink (tmpc);
        }
 
        ret = true;
@@ -1465,6 +1538,7 @@ SoundFileOmega::check_link_status (const Session* s, const vector<string>& paths
   out:
        rmdir (tmpdir.c_str());
        return ret;
+#endif
 }
 
 SoundFileChooser::SoundFileChooser (string title, ARDOUR::Session* s)