summaryrefslogtreecommitdiff
path: root/gtk2_ardour/sfdb_freesound_mootcher.cc
diff options
context:
space:
mode:
authorColin Fletcher <colin.m.fletcher@googlemail.com>2013-06-14 19:17:24 +0100
committerColin Fletcher <colin.m.fletcher@googlemail.com>2013-06-21 21:30:52 +0100
commit0483803186c83e27db708f77189a4dc9974f1712 (patch)
tree23554536a603008bce83b4bbe2ab3f94c417db39 /gtk2_ardour/sfdb_freesound_mootcher.cc
parent1eff5a8215319c680ea511e90eba7fd5e4e66edd (diff)
Further Freesound tweaks.
Make download of sound files multi-threaded. Each sound file download takes place in its own thread, and has its own progress bar and cancel button, which stack up from the bottom of the list of results. Sound files download into a file with a '.part' suffix, which is then renamed to the intended name on success. Add a 'Similar' button, which searches Freesound for sounds similar to the currently-selected sound in the results list.
Diffstat (limited to 'gtk2_ardour/sfdb_freesound_mootcher.cc')
-rw-r--r--gtk2_ardour/sfdb_freesound_mootcher.cc181
1 files changed, 132 insertions, 49 deletions
diff --git a/gtk2_ardour/sfdb_freesound_mootcher.cc b/gtk2_ardour/sfdb_freesound_mootcher.cc
index e8b44ff4a7..38d53aaa70 100644
--- a/gtk2_ardour/sfdb_freesound_mootcher.cc
+++ b/gtk2_ardour/sfdb_freesound_mootcher.cc
@@ -54,6 +54,7 @@
#include "ardour/audio_library.h"
#include "ardour/rc_configuration.h"
+#include "pbd/pthread_utils.h"
using namespace PBD;
@@ -119,7 +120,8 @@ size_t Mootcher::WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void
//------------------------------------------------------------------------
-std::string Mootcher::sortMethodString(enum sortMethod sort) {
+std::string Mootcher::sortMethodString(enum sortMethod sort)
+{
// given a sort type, returns the string value to be passed to the API to
// sort the results in the requested way.
@@ -200,6 +202,18 @@ std::string Mootcher::doRequest(std::string uri, std::string params)
}
+std::string Mootcher::searchSimilar(std::string id)
+{
+ std::string params = "";
+
+ params += "&fields=id,original_filename,duration,filesize,samplerate,license,serve";
+ params += "&num_results=100";
+
+ return doRequest("/sounds/" + id + "/similar", params);
+}
+
+//------------------------------------------------------------------------
+
std::string Mootcher::searchText(std::string query, int page, std::string filter, enum sortMethod sort)
{
std::string params = "";
@@ -294,9 +308,62 @@ int audioFileWrite(void *buffer, size_t size, size_t nmemb, void *file)
};
//------------------------------------------------------------------------
-std::string Mootcher::getAudioFile(std::string originalFileName, std::string ID, std::string audioURL, SoundFileBrowser *caller)
+
+void *
+Mootcher::threadFunc() {
+CURLcode res;
+
+ res = curl_easy_perform (curl);
+ fclose (theFile);
+ curl_easy_setopt (curl, CURLOPT_NOPROGRESS, 1); // turn off the progress bar
+
+ if (res != CURLE_OK) {
+ /* it's not an error if the user pressed the stop button */
+ if (res != CURLE_ABORTED_BY_CALLBACK) {
+ error << string_compose (_("curl error %1 (%2)"), res, curl_easy_strerror(res)) << endmsg;
+ }
+ remove ( (audioFileName+".part").c_str() );
+ } else {
+ rename ( (audioFileName+".part").c_str(), audioFileName.c_str() );
+ // now download the tags &c.
+ getSoundResourceFile(ID);
+ }
+
+ return (void *) res;
+}
+
+static int
+donewithMootcher(void *arg)
+{
+ Mootcher *thisMootcher = (Mootcher *) arg;
+
+ // update the sound info pane if the selection in the list box is still us
+ thisMootcher->sfb->refresh_display(thisMootcher->ID, thisMootcher->audioFileName);
+
+ delete(thisMootcher);
+ return 0;
+}
+
+static void *
+freesound_download_thread_func(void *arg)
+{
+ Mootcher *thisMootcher = (Mootcher *) arg;
+ void *res;
+
+ // std::cerr << "freesound_download_thread_func(" << arg << ")" << std::endl;
+ res = thisMootcher->threadFunc();
+ g_idle_add(donewithMootcher, thisMootcher);
+
+ return res;
+}
+
+
+//------------------------------------------------------------------------
+
+bool Mootcher::checkAudioFile(std::string originalFileName, std::string theID)
{
ensureWorkingDir();
+ ID = theID;
audioFileName = Glib::build_filename (basePath, ID + "-" + originalFileName);
// check to see if audio file already exists
@@ -305,29 +372,31 @@ std::string Mootcher::getAudioFile(std::string originalFileName, std::string ID,
fseek (testFile , 0 , SEEK_END);
if (ftell (testFile) > 256) {
fclose (testFile);
- return audioFileName;
+ return true;
}
- // else file was small, probably an error, delete it and try again
+ // else file was small, probably an error, delete it
fclose(testFile);
remove( audioFileName.c_str() );
}
+ return false;
+}
- if (!curl) {
- return "";
- }
- // if already cancelling a previous download, bail out here ( this can happen b/c getAudioFile gets called by various UI update funcs )
- if ( caller->freesound_download_cancel ) {
- return "";
+bool Mootcher::fetchAudioFile(std::string originalFileName, std::string theID, std::string audioURL, SoundFileBrowser *caller)
+{
+ ensureWorkingDir();
+ ID = theID;
+ audioFileName = Glib::build_filename (basePath, ID + "-" + originalFileName);
+
+ if (!curl) {
+ return false;
}
-
// now download the actual file
- FILE* theFile;
- theFile = g_fopen( audioFileName.c_str(), "wb" );
+ theFile = g_fopen( (audioFileName + ".part").c_str(), "wb" );
if (!theFile) {
- return "";
+ return false;
}
// create the download url
@@ -338,57 +407,71 @@ std::string Mootcher::getAudioFile(std::string originalFileName, std::string ID,
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, audioFileWrite);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, theFile);
- /* hack to get rid of the barber-pole stripes */
- caller->freesound_progress_bar.hide();
- caller->freesound_progress_bar.show();
-
std::string prog;
prog = string_compose (_("%1"), originalFileName);
- caller->freesound_progress_bar.set_text(prog);
+ progress_bar.set_text(prog);
+
+ Gtk::VBox *freesound_vbox = dynamic_cast<Gtk::VBox *> (caller->notebook.get_nth_page(2));
+ freesound_vbox->pack_start(progress_hbox, Gtk::PACK_SHRINK);
+ progress_hbox.show();
+ cancel_download = false;
+ sfb = caller;
curl_easy_setopt (curl, CURLOPT_NOPROGRESS, 0); // turn on the progress bar
curl_easy_setopt (curl, CURLOPT_PROGRESSFUNCTION, progress_callback);
- curl_easy_setopt (curl, CURLOPT_PROGRESSDATA, caller);
+ curl_easy_setopt (curl, CURLOPT_PROGRESSDATA, this);
- CURLcode res = curl_easy_perform(curl);
- fclose(theFile);
+ pthread_t freesound_download_thread;
+ pthread_create_and_store("freesound_import", &freesound_download_thread, freesound_download_thread_func, this);
- curl_easy_setopt (curl, CURLOPT_NOPROGRESS, 1); // turn off the progress bar
- caller->freesound_progress_bar.set_fraction(0.0);
- caller->freesound_progress_bar.set_text("");
-
- if( res != 0 ) {
- /* it's not an error if the user pressed the stop button */
- if (res != CURLE_ABORTED_BY_CALLBACK) {
- error << string_compose (_("curl error %1 (%2)"), res, curl_easy_strerror(res)) << endmsg;
+ return true;
+}
+
+//---------
+struct progressInfo {
+ Gtk::ProgressBar *bar;
+ double dltotal;
+ double dlnow;
+};
+
+static int
+updateProgress(void *arg)
+{
+ struct progressInfo *progress = (struct progressInfo *) arg;
+ if (progress->dltotal > 0) {
+ double fraction = progress->dlnow / progress->dltotal;
+ // std::cerr << "progress idle: " << progress->bar->get_text() << ". " << progress->dlnow << " / " << progress->dltotal << " = " << fraction << std::endl;
+ if (fraction > 1.0) {
+ fraction = 1.0;
+ } else if (fraction < 0.0) {
+ fraction = 0.0;
}
- remove( audioFileName.c_str() );
- return "";
- } else {
- // now download the tags &c.
- getSoundResourceFile(ID);
+ progress->bar->set_fraction(fraction);
}
- return audioFileName;
+ delete progress;
+ return 0;
}
-//---------
-int Mootcher::progress_callback(void *caller, double dltotal, double dlnow, double /*ultotal*/, double /*ulnow*/)
+int
+Mootcher::progress_callback(void *caller, double dltotal, double dlnow, double /*ultotal*/, double /*ulnow*/)
{
+ // It may seem curious to pass a pointer to an instance of an object to a static
+ // member function, but we can't use a normal member function as a curl progress callback,
+ // and we want access to some private members of Mootcher.
-SoundFileBrowser *sfb = (SoundFileBrowser *) caller;
- //XXX I hope it's OK to do GTK things in this callback. Otherwise
- // I'll have to do stuff like in interthread_progress_window.
- if (sfb->freesound_download_cancel) {
- return -1;
- }
+ Mootcher *thisMootcher = (Mootcher *) caller;
-
- sfb->freesound_progress_bar.set_fraction(dlnow/dltotal);
- /* Make sure the progress widget gets updated */
- while (Glib::MainContext::get_default()->iteration (false)) {
- /* do nothing */
+ if (thisMootcher->cancel_download) {
+ return -1;
}
+
+ struct progressInfo *progress = new struct progressInfo;
+ progress->bar = &thisMootcher->progress_bar;
+ progress->dltotal = dltotal;
+ progress->dlnow = dlnow;
+
+ g_idle_add(updateProgress, progress);
return 0;
}