\r
#include "ardour/audio_library.h"\r
#include "ardour/rc_configuration.h"\r
+#include "pbd/pthread_utils.h"\r
\r
using namespace PBD;\r
\r
\r
//------------------------------------------------------------------------\r
\r
-std::string Mootcher::sortMethodString(enum sortMethod sort) {\r
+std::string Mootcher::sortMethodString(enum sortMethod sort)\r
+{\r
// given a sort type, returns the string value to be passed to the API to\r
// sort the results in the requested way.\r
\r
}\r
\r
\r
+std::string Mootcher::searchSimilar(std::string id)\r
+{\r
+ std::string params = "";\r
+\r
+ params += "&fields=id,original_filename,duration,filesize,samplerate,license,serve";\r
+ params += "&num_results=100";\r
+\r
+ return doRequest("/sounds/" + id + "/similar", params);\r
+}\r
+\r
+//------------------------------------------------------------------------\r
+\r
std::string Mootcher::searchText(std::string query, int page, std::string filter, enum sortMethod sort)\r
{\r
std::string params = "";\r
};\r
\r
//------------------------------------------------------------------------\r
-std::string Mootcher::getAudioFile(std::string originalFileName, std::string ID, std::string audioURL, SoundFileBrowser *caller)\r
+\r
+void *\r
+Mootcher::threadFunc() {\r
+CURLcode res;\r
+\r
+ res = curl_easy_perform (curl);\r
+ fclose (theFile);\r
+ curl_easy_setopt (curl, CURLOPT_NOPROGRESS, 1); // turn off the progress bar\r
+ \r
+ if (res != CURLE_OK) {\r
+ /* it's not an error if the user pressed the stop button */\r
+ if (res != CURLE_ABORTED_BY_CALLBACK) {\r
+ error << string_compose (_("curl error %1 (%2)"), res, curl_easy_strerror(res)) << endmsg;\r
+ }\r
+ remove ( (audioFileName+".part").c_str() ); \r
+ } else {\r
+ rename ( (audioFileName+".part").c_str(), audioFileName.c_str() );\r
+ // now download the tags &c.\r
+ getSoundResourceFile(ID);\r
+ }\r
+\r
+ return (void *) res;\r
+}\r
+\r
+static int \r
+donewithMootcher(void *arg) \r
+{\r
+ Mootcher *thisMootcher = (Mootcher *) arg;\r
+\r
+ // update the sound info pane if the selection in the list box is still us \r
+ thisMootcher->sfb->refresh_display(thisMootcher->ID, thisMootcher->audioFileName);\r
+\r
+ delete(thisMootcher);\r
+ return 0;\r
+}\r
+\r
+static void *\r
+freesound_download_thread_func(void *arg) \r
+{ \r
+ Mootcher *thisMootcher = (Mootcher *) arg;\r
+ void *res;\r
+\r
+ // std::cerr << "freesound_download_thread_func(" << arg << ")" << std::endl;\r
+ res = thisMootcher->threadFunc();\r
+ g_idle_add(donewithMootcher, thisMootcher);\r
+\r
+ return res;\r
+}\r
+\r
+\r
+//------------------------------------------------------------------------\r
+\r
+bool Mootcher::checkAudioFile(std::string originalFileName, std::string theID)\r
{\r
ensureWorkingDir();\r
+ ID = theID;\r
audioFileName = Glib::build_filename (basePath, ID + "-" + originalFileName);\r
\r
// check to see if audio file already exists\r
fseek (testFile , 0 , SEEK_END);\r
if (ftell (testFile) > 256) {\r
fclose (testFile);\r
- return audioFileName;\r
+ return true;\r
}\r
\r
- // else file was small, probably an error, delete it and try again\r
+ // else file was small, probably an error, delete it \r
fclose(testFile);\r
remove( audioFileName.c_str() ); \r
}\r
+ return false;\r
+}\r
\r
- if (!curl) {\r
- return "";\r
- }\r
\r
- // if already cancelling a previous download, bail out here ( this can happen b/c getAudioFile gets called by various UI update funcs )\r
- if ( caller->freesound_download_cancel ) {\r
- return "";\r
+bool Mootcher::fetchAudioFile(std::string originalFileName, std::string theID, std::string audioURL, SoundFileBrowser *caller)\r
+{\r
+ ensureWorkingDir();\r
+ ID = theID;\r
+ audioFileName = Glib::build_filename (basePath, ID + "-" + originalFileName);\r
+\r
+ if (!curl) {\r
+ return false;\r
}\r
- \r
// now download the actual file\r
- FILE* theFile;\r
- theFile = g_fopen( audioFileName.c_str(), "wb" );\r
+ theFile = g_fopen( (audioFileName + ".part").c_str(), "wb" );\r
\r
if (!theFile) {\r
- return "";\r
+ return false;\r
}\r
\r
// create the download url\r
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, audioFileWrite);\r
curl_easy_setopt(curl, CURLOPT_WRITEDATA, theFile);\r
\r
- /* hack to get rid of the barber-pole stripes */\r
- caller->freesound_progress_bar.hide();\r
- caller->freesound_progress_bar.show();\r
-\r
std::string prog;\r
prog = string_compose (_("%1"), originalFileName);\r
- caller->freesound_progress_bar.set_text(prog);\r
+ progress_bar.set_text(prog);\r
+\r
+ Gtk::VBox *freesound_vbox = dynamic_cast<Gtk::VBox *> (caller->notebook.get_nth_page(2));\r
+ freesound_vbox->pack_start(progress_hbox, Gtk::PACK_SHRINK);\r
+ progress_hbox.show();\r
+ cancel_download = false;\r
+ sfb = caller;\r
\r
curl_easy_setopt (curl, CURLOPT_NOPROGRESS, 0); // turn on the progress bar\r
curl_easy_setopt (curl, CURLOPT_PROGRESSFUNCTION, progress_callback);\r
- curl_easy_setopt (curl, CURLOPT_PROGRESSDATA, caller);\r
+ curl_easy_setopt (curl, CURLOPT_PROGRESSDATA, this);\r
\r
- CURLcode res = curl_easy_perform(curl);\r
- fclose(theFile);\r
+ pthread_t freesound_download_thread;\r
+ pthread_create_and_store("freesound_import", &freesound_download_thread, freesound_download_thread_func, this);\r
\r
- curl_easy_setopt (curl, CURLOPT_NOPROGRESS, 1); // turn off the progress bar\r
- caller->freesound_progress_bar.set_fraction(0.0);\r
- caller->freesound_progress_bar.set_text("");\r
- \r
- if( res != 0 ) {\r
- /* it's not an error if the user pressed the stop button */\r
- if (res != CURLE_ABORTED_BY_CALLBACK) {\r
- error << string_compose (_("curl error %1 (%2)"), res, curl_easy_strerror(res)) << endmsg;\r
+ return true;\r
+}\r
+\r
+//---------\r
+struct progressInfo {\r
+ Gtk::ProgressBar *bar;\r
+ double dltotal;\r
+ double dlnow;\r
+};\r
+\r
+static int \r
+updateProgress(void *arg) \r
+{\r
+ struct progressInfo *progress = (struct progressInfo *) arg;\r
+ if (progress->dltotal > 0) {\r
+ double fraction = progress->dlnow / progress->dltotal;\r
+ // std::cerr << "progress idle: " << progress->bar->get_text() << ". " << progress->dlnow << " / " << progress->dltotal << " = " << fraction << std::endl;\r
+ if (fraction > 1.0) {\r
+ fraction = 1.0;\r
+ } else if (fraction < 0.0) {\r
+ fraction = 0.0;\r
}\r
- remove( audioFileName.c_str() ); \r
- return "";\r
- } else {\r
- // now download the tags &c.\r
- getSoundResourceFile(ID);\r
+ progress->bar->set_fraction(fraction);\r
}\r
\r
- return audioFileName;\r
+ delete progress;\r
+ return 0;\r
}\r
\r
-//---------\r
-int Mootcher::progress_callback(void *caller, double dltotal, double dlnow, double /*ultotal*/, double /*ulnow*/)\r
+int \r
+Mootcher::progress_callback(void *caller, double dltotal, double dlnow, double /*ultotal*/, double /*ulnow*/)\r
{\r
+ // It may seem curious to pass a pointer to an instance of an object to a static\r
+ // member function, but we can't use a normal member function as a curl progress callback,\r
+ // and we want access to some private members of Mootcher.\r
\r
-SoundFileBrowser *sfb = (SoundFileBrowser *) caller;\r
- //XXX I hope it's OK to do GTK things in this callback. Otherwise\r
- // I'll have to do stuff like in interthread_progress_window.\r
- if (sfb->freesound_download_cancel) {\r
- return -1;\r
- }\r
+ Mootcher *thisMootcher = (Mootcher *) caller;\r
\r
- \r
- sfb->freesound_progress_bar.set_fraction(dlnow/dltotal);\r
- /* Make sure the progress widget gets updated */\r
- while (Glib::MainContext::get_default()->iteration (false)) {\r
- /* do nothing */\r
+ if (thisMootcher->cancel_download) {\r
+ return -1;\r
}\r
+\r
+ struct progressInfo *progress = new struct progressInfo;\r
+ progress->bar = &thisMootcher->progress_bar;\r
+ progress->dltotal = dltotal;\r
+ progress->dlnow = dlnow;\r
+\r
+ g_idle_add(updateProgress, progress);\r
return 0;\r
}\r
\r
Mootcher();
~Mootcher();
- std::string getAudioFile(std::string originalFileName, std::string ID, std::string audioURL, SoundFileBrowser *caller);
+ bool checkAudioFile(std::string originalFileName, std::string ID);
+ bool fetchAudioFile(std::string originalFileName, std::string ID, std::string audioURL, SoundFileBrowser *caller);
std::string searchText(std::string query, int page, std::string filter, enum sortMethod sort);
+ std::string searchSimilar(std::string id);
+ void * threadFunc();
+ SoundFileBrowser *sfb;
+ std::string audioFileName;
+ std::string ID;
private:
CURL *curl;
char errorBuffer[CURL_ERROR_SIZE]; // storage for cUrl error message
+ FILE* theFile;
+
+ Gtk::HBox progress_hbox;
+ Gtk::ProgressBar progress_bar;
+ Gtk::Button cancel_download_btn;
+
+ bool cancel_download;
+ void cancelDownload() {
+ cancel_download = true;
+ progress_hbox.hide();
+ }
+
std::string basePath;
std::string xmlLocation;
};
using std::string;
string SoundFileBrowser::persistent_folder;
+typedef TreeView::Selection::ListHandle_Path ListPath;
static ImportMode
string2importmode (string str)
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
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);
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);
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
} 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());
}
}
-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 ()
{
}
}
+
+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 ()
{
}
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();
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(
);
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();
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>
}
}
- } 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) {
}
} 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
}
Gtk::TreeModelColumn<std::string> filesize;
Gtk::TreeModelColumn<std::string> smplrate;
Gtk::TreeModelColumn<std::string> license;
+ Gtk::TreeModelColumn<bool> started;
FreesoundColumns() {
add(id);
add(filesize);
add(smplrate);
add(license);
+ add(started);
}
};
Glib::RefPtr<Gtk::ListStore> freesound_list;
Gtk::Button freesound_more_btn;
- Gtk::Button freesound_stop_btn;
+ Gtk::Button freesound_similar_btn;
+ void handle_freesound_results(std::string theString);
public:
SoundFileBrowser (std::string title, ARDOUR::Session* _s, bool persistent);
virtual ~SoundFileBrowser ();
Gtk::Button freesound_search_btn;
Gtk::TreeView freesound_list_view;
- Gtk::ProgressBar freesound_progress_bar;
-
- bool freesound_download_cancel;
+ Gtk::Notebook notebook;
void freesound_search();
+ void refresh_display(std::string ID, std::string file);
protected:
bool resetting_ourselves;
static std::string persistent_folder;
- Gtk::Notebook notebook;
GainMeter* gm;
Gtk::VBox meter_packer;
void freesound_list_view_activated (const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn*);
void freesound_search_clicked ();
void freesound_more_clicked ();
- void freesound_stop_clicked ();
+ void freesound_similar_clicked ();
int freesound_page;
void chooser_file_activated ();
+ std::string freesound_get_audio_file(Gtk::TreeIter iter);
bool on_audio_filter (const Gtk::FileFilter::Info& filter_info);
bool on_midi_filter (const Gtk::FileFilter::Info& filter_info);