View Issue Details
ID | Project | Category | View Status | Date Submitted | Last Update |
---|---|---|---|---|---|
0003884 | ardour | bugs | public | 2011-03-25 18:28 | 2015-09-18 15:14 |
Reporter | colinf | Assigned To | paul | ||
Priority | normal | Severity | minor | Reproducibility | always |
Status | closed | Resolution | fixed | ||
Target Version | 3.X | ||||
Summary | 0003884: Freesound tab doesn't appear in 'Import' dialog | ||||
Description | I built A3 with Freesound, but there's no sign of the 'Freesound' tab in the 'Import' dialog. In fact, I don't think FREESOUND is defined for compilation at all. | ||||
Tags | No tags attached. | ||||
|
FreeSound support is broken now that FreeSound has moved to their new API (which looks as if it might actually work, unlike the old one). FreeSound support will not return until someone volunteers to port the code over to their new API. |
|
I've had a play with the new Freesound API this weekend, and I'm hopeful that making this work might actually be within my capabilities. Patch to follow soonish. |
2011-11-08 18:52
|
freesound-new-api-10499.patch (37,904 bytes)
Index: gtk2_ardour/wscript =================================================================== --- gtk2_ardour/wscript (revision 10499) +++ gtk2_ardour/wscript (working copy) @@ -388,6 +388,7 @@ if bld.is_defined('FREESOUND'): obj.source += [ 'sfdb_freesound_mootcher.cc' ] + obj.defines += [ 'FREESOUND' ] if bld.is_defined('VST_SUPPORT'): obj.source += [ 'vst_pluginui.cc' ] Index: gtk2_ardour/sfdb_freesound_mootcher.cc =================================================================== --- gtk2_ardour/sfdb_freesound_mootcher.cc (revision 10499) +++ gtk2_ardour/sfdb_freesound_mootcher.cc (working copy) @@ -1,6 +1,7 @@ /* sfdb_freesound_mootcher.cpp ********************************************************************** Adapted for Ardour by Ben Loftis, March 2008 + Updated to new Freesound API by Colin Fletcher, November 2011 Mootcher 23-8-2005 @@ -43,37 +44,39 @@ #include <sys/stat.h> #include <sys/types.h> +#include <iostream> #include "ardour/audio_library.h" -#define TRUE 1 +static const std::string base_url = "http://www.freesound.org/api"; +static const std::string api_key = "35abf53d8a694e65bae0adf3aa408fb3"; // test, starlingaudio.co.uk, c0l1n_fl3tch3r + //------------------------------------------------------------------------ -Mootcher:: Mootcher(const char *saveLocation) - : curl( NULL ) - , connection( 0 ) +Mootcher::Mootcher(const char *saveLocation) + : curl(curl_easy_init()) { changeWorkingDir(saveLocation); }; //------------------------------------------------------------------------ -Mootcher:: ~Mootcher() +Mootcher:: ~Mootcher() { - remove( "cookiejar.txt" ); } + //------------------------------------------------------------------------ const char* Mootcher::changeWorkingDir(const char *saveLocation) { basePath = saveLocation; #ifdef __WIN32__ std::string replace = "/"; - int pos = (int)basePath.find("\\"); + size_t pos = basePath.find("\\"); while( pos != std::string::npos ){ basePath.replace(pos, 1, replace); - pos = (int)basePath.find("\\"); + pos = basePath.find("\\"); } #endif // - int pos2 = basePath.find_last_of("/"); + size_t pos2 = basePath.find_last_of("/"); if(basePath.length() != (pos2+1)) basePath += "/"; // create Freesound directory and sound dir @@ -86,15 +89,12 @@ } //------------------------------------------------------------------------ -size_t Mootcher::WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data) +size_t Mootcher::WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data) { register int realsize = (int)(size * nmemb); struct MemoryStruct *mem = (struct MemoryStruct *)data; - // There might be a realloc() out there that doesn't like - // reallocing NULL pointers, so we take care of it here - if(mem->memory) mem->memory = (char *)realloc(mem->memory, mem->size + realsize + 1); - else mem->memory = (char *)malloc(mem->size + realsize + 1); + mem->memory = (char *)realloc(mem->memory, mem->size + realsize + 1); if (mem->memory) { memcpy(&(mem->memory[mem->size]), ptr, realsize); @@ -106,332 +106,183 @@ //------------------------------------------------------------------------ -void Mootcher::toLog(std::string input) -{ -printf("%s\n", input.c_str());// for debugging -} +std::string Mootcher::sortMethodString(enum sortMethod sort) { + switch (sort) { + case sort_duration_desc: return "duration_desc"; + case sort_duration_asc: return "duration_asc"; + case sort_created_desc: return "created_desc"; + case sort_created_asc: return "created_asc"; + case sort_downloads_desc: return "downloads_desc"; + case sort_downloads_asc: return "downloads_asc"; + case sort_rating_desc: return "rating_desc"; + case sort_rating_asc: return "rating_asc"; + default: return ""; + } +} + //------------------------------------------------------------------------ -void Mootcher::setcUrlOptions() +void Mootcher::setcUrlOptions() { // basic init for curl curl_global_init(CURL_GLOBAL_ALL); // some servers don't like requests that are made without a user-agent field, so we provide one curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcurl-agent/1.0"); // setup curl error buffer - CURLcode res = curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errorBuffer); - // always use the cookie with session id which is received at the login - curl_easy_setopt(curl, CURLOPT_COOKIEFILE, "cookiejar.txt"); + curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errorBuffer); // Allow redirection curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); + + // Allow connections to time out (without using signals) + curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); + curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10); + + } -//------------------------------------------------------------------------ -int Mootcher::doLogin(std::string login, std::string password) +std::string Mootcher::doRequest(std::string uri, std::string params) { - if(connection==1) - return 1; - + std::string result; struct MemoryStruct xml_page; xml_page.memory = NULL; xml_page.size = 0; - // create the post message from the login and password - std::string postMessage; - postMessage += "username="; - postMessage += curl_escape(login.c_str(), 0); - postMessage += "&password="; - postMessage += curl_escape(password.c_str(), 0); - postMessage += "&login="; - postMessage += curl_escape("1", 0); - postMessage += "&redirect="; - postMessage += curl_escape("../tests/login.php", 0); + setcUrlOptions(); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *) &xml_page); - // Do the setup for libcurl - curl = curl_easy_init(); + // curl_easy_setopt(curl, CURLOPT_HTTPGET, 1); + // curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postMessage.c_str()); + // curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, -1); - if(curl) - { - setcUrlOptions(); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&xml_page); - // save the sessoin id that is given back by the server in a cookie - curl_easy_setopt(curl, CURLOPT_COOKIEJAR, "cookiejar.txt"); - // use POST for login variables - curl_easy_setopt(curl, CURLOPT_POST, TRUE); - curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postMessage.c_str()); - curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, -1); + // the url to get + std::string url = base_url + uri + "?"; + if (params != "") { + url += params + "&api_key=" + api_key + "&format=xml"; + } else { + url += "api_key=" + api_key + "&format=xml"; + } + + curl_easy_setopt(curl, CURLOPT_URL, url.c_str() ); + std::cerr << "doRequest: " << url << std::endl; + + // perform online request + CURLcode res = curl_easy_perform(curl); + if( res != 0 ) { + std::cerr << "curl error " << res << " (" << curl_easy_strerror(res) << ")" << std::endl; + return ""; + } - // the url to get - std::string login_url = "http://www.freesound.org/forum/login.php"; - curl_easy_setopt(curl, CURLOPT_URL, login_url.c_str() ); + result = xml_page.memory; + // free the memory + if(xml_page.memory){ + free( xml_page.memory ); + xml_page.memory = NULL; + xml_page.size = 0; + } - // perform online request - connection = 1; - CURLcode res = curl_easy_perform(curl); - if( res != 0 ) { - toLog("curl login error\n"); - toLog(curl_easy_strerror(res)); - connection = 0; - } + return result; - if (connection == 1){ - std::string check_page = xml_page.memory; - int test = (int)check_page.find("login"); //logged - if( strcmp(xml_page.memory, "login") == 0 ) - toLog("Logged in.\n"); - else { - toLog("Login failed: Check username and password.\n"); - connection = 0; - } - } +} - // free the memory - if(xml_page.memory){ - free( xml_page.memory ); - xml_page.memory = NULL; - xml_page.size = 0; - } - std::cerr << "Login was cool, connection = " << connection << std::endl; - return connection; - } - else return 3; // will be returned if a curl related problem ocurrs -} -//------------------------------------------------------------------------ -std::string Mootcher::searchText(std::string word) +std::string Mootcher::searchText(std::string query, int page, std::string filter, enum sortMethod sort) { - struct MemoryStruct xml_page; - xml_page.memory = NULL; - xml_page.size = 0; + std::string params = ""; + char buf[24]; - std::string result; - - if(connection != 0) - { - // create a url encoded post message - std::string postMessage; - char tempString[ 128 ]; - char *tempPointer = &tempString[0]; - - postMessage = "search="; - postMessage += curl_escape(word.c_str(), 0); - sprintf( tempPointer, "&searchDescriptions=1"); - postMessage += tempPointer; - sprintf( tempPointer, "&searchtags=1"); - postMessage += tempPointer; - - // Ref: http://www.freesound.org/forum/viewtopic.php?p=19081 - // const ORDER_DEFAULT = 0; - // const ORDER_DOWNLOADS_DESC = 1; - // const ORDER_DOWNLOADS_ASC = 2; - // const ORDER_USERNAME_DESC = 3; - // const ORDER_USERNAME_ASC = 4; - // const ORDER_DATE_DESC = 5; - // const ORDER_DATE_ASC = 6; - // const ORDER_DURATION_DESC = 7; - // const ORDER_DURATION_ASC = 8; - // const ORDER_FILEFORMAT_DESC = 9; - // const ORDER_FILEFORMAT_ASC = 10; - sprintf( tempPointer, "&order=1"); - postMessage += tempPointer; - sprintf( tempPointer, "&start=0"); - postMessage += tempPointer; - sprintf( tempPointer, "&limit=10"); - postMessage += tempPointer; - // The limit of 10 samples is arbitrary, but seems - // reasonable in light of the fact that all of the returned - // samples get downloaded, and downloads are s-l-o-w. - - if(curl) - { - // basic init for curl - setcUrlOptions(); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&xml_page); - // setup the post message - curl_easy_setopt(curl, CURLOPT_POST, TRUE); - curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postMessage.c_str()); - curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, -1); - - // the url to get - std::string search_url = "http://www.freesound.org/searchTextXML.php"; - curl_easy_setopt(curl, CURLOPT_URL, search_url.c_str()); - - // perform the online search - connection = 1; - CURLcode res = curl_easy_perform(curl); - if( res != 0 ) { - toLog("curl login error\n"); - toLog(curl_easy_strerror(res)); - connection = 0; - } - - result = xml_page.memory; - toLog( result.c_str() ); - - // free the memory - if(xml_page.memory){ - free( xml_page.memory ); - xml_page.memory = NULL; - xml_page.size = 0; - } - - } + if (page > 1) { + snprintf(buf, 23, "p=%d&", page); + params += buf; } + + params += "q=" + query; - return result; + if (filter != "") + params += "&f=" + filter; + + if (sort) + params += "&s=" + sortMethodString(sort); + + return doRequest("/sounds/search", params); } //------------------------------------------------------------------------ -std::string Mootcher::changeExtension(std::string filename) + +std::string Mootcher::getSoundResourceFile(std::string ID) { - std::string aiff = ".aiff"; - std::string aif = ".aif"; - std::string wav = ".wav"; - std::string mp3 = ".mp3"; - std::string ogg = ".ogg"; - std::string flac = ".flac"; - std::string replace = ".xml"; - int pos = 0; + std::string originalSoundURI; + std::string audioFileName; + std::string xmlFileName; + std::string xml; - pos = (int)filename.find(aiff); - if(pos != std::string::npos) filename.replace(pos, aiff.size(), replace); - pos = (int)filename.find(aif); - if(pos != std::string::npos) filename.replace(pos, aif.size(), replace); - pos = (int)filename.find(wav); - if(pos != std::string::npos) filename.replace(pos, wav.size(), replace); - pos = (int)filename.find(mp3); - if(pos != std::string::npos) filename.replace(pos, mp3.size(), replace); - pos = (int)filename.find(ogg); - if(pos != std::string::npos) filename.replace(pos, ogg.size(), replace); - pos = (int)filename.find(flac); - if(pos != std::string::npos) filename.replace(pos, flac.size(), replace); - return filename; -} -//------------------------------------------------------------------------ -void Mootcher::GetXml(std::string ID, struct MemoryStruct &xml_page) -{ + std::cerr << "getSoundResourceFile(" << ID << ")" << std::endl; - if(curl) { - setcUrlOptions(); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&xml_page); + // download the xmlfile into xml_page + xml = doRequest("/sounds/" + ID, ""); - // URL to get - std::string getxml_url = "http://www.freesound.org/samplesViewSingleXML.php?id="; - getxml_url += ID; + XMLTree doc; + doc.read_buffer( xml.c_str() ); + XMLNode *freesound = doc.root(); - curl_easy_setopt(curl, CURLOPT_URL, getxml_url.c_str() ); + // if the page is not a valid xml document with a 'freesound' root + if (freesound == NULL) { + std::cerr << "getSoundResourceFile: There is no valid root in the xml file" << std::endl; + return ""; + } - // get it! - connection = 1; - CURLcode res = curl_easy_perform(curl); - if( res != 0 ) { - toLog("curl login error\n"); - toLog(curl_easy_strerror(res)); - connection = 0; - } + if (strcmp(doc.root()->name().c_str(), "response") != 0) { + std::cerr << "getSoundResourceFile: root =" << doc.root()->name() << ", != response" << std::endl; + return ""; } -} -//------------------------------------------------------------------------ -std::string Mootcher::getXmlFile(std::string ID, int &length) -{ - struct MemoryStruct xml_page; - xml_page.memory = NULL; - xml_page.size = NULL; - std::string xmlFileName; - std::string audioFileName; - std::string filename; + XMLNode *name = freesound->child("original_filename"); + XMLNode *filesize = freesound->child("filesize"); - if(connection != 0) { - // download the xmlfile into xml_page - GetXml(ID, xml_page); - // if sample ID does not exist on the freesound website - if(strcmp(xml_page.memory, "sample non existant") == 0){ - free( xml_page.memory ); - sprintf(message, "getXmlFile: sample with ID:%s does not exist!\n", ID.c_str() ); - toLog(message); - return filename; - } else { - XMLTree doc; - doc.read_buffer( xml_page.memory ); - XMLNode *freesound = doc.root(); + // get the file name and size from xml file + if (name && filesize) { - // if the page is not a valid xml document with a 'freesound' root - if( freesound == NULL){ - sprintf(message, "getXmlFile: There is no valid root in the xml file"); - toLog(message); - } else { - XMLNode *sample = freesound->child("sample"); - XMLNode *name = NULL; - XMLNode *filesize = NULL; - if (sample) { - name = sample->child("originalFilename"); - filesize = sample->child("filesize"); - } + audioFileName = basePath + "snd/" + ID + "-" + name->child("text")->content(); - // get the file name and size from xml file - if (sample && name && filesize) { + // create new filename with the ID number + xmlFileName = basePath; + xmlFileName += "snd/"; + xmlFileName += freesound->child("id")->child("text")->content(); + xmlFileName += "-"; + xmlFileName += name->child("text")->content(); + xmlFileName += ".xml"; - audioFileName = name->child("text")->content(); - sprintf( message, "getXmlFile: %s needs to be downloaded\n", audioFileName.c_str() ); - toLog(message); + // std::cerr << "getSoundResourceFile: saving XML: " << xmlFileName << std::endl; - length = atoi(filesize->child("text")->content().c_str()); + // save the xml file to disk + doc.write(xmlFileName.c_str()); - // create new filename with the ID number - filename = basePath; - filename += "snd/"; - filename += sample->property("id")->value(); - filename += "-"; - filename += audioFileName; - // change the extention into .xml - xmlFileName = changeExtension( filename ); - - sprintf(message, "getXmlFile: saving XML: %s\n", xmlFileName.c_str() ); - toLog(message); - - // save the xml file to disk - doc.write(xmlFileName.c_str()); - - //store all the tags in the database - XMLNode *tags = sample->child("tags"); - if (tags) { - XMLNodeList children = tags->children(); - XMLNodeConstIterator niter; - std::vector<std::string> strings; - for (niter = children.begin(); niter != children.end(); ++niter) { - XMLNode *node = *niter; - if( strcmp( node->name().c_str(), "tag") == 0 ) { - XMLNode *text = node->child("text"); - if (text) strings.push_back(text->content()); - } - } - ARDOUR::Library->set_tags (std::string("//")+filename, strings); - ARDOUR::Library->save_changes (); + //store all the tags in the database + XMLNode *tags = freesound->child("tags"); + if (tags) { + XMLNodeList children = tags->children(); + XMLNodeConstIterator niter; + std::vector<std::string> strings; + for (niter = children.begin(); niter != children.end(); ++niter) { + XMLNode *node = *niter; + if( strcmp( node->name().c_str(), "resource") == 0 ) { + XMLNode *text = node->child("text"); + if (text) { + // std::cerr << "tag: " << text->content() << std::endl; + strings.push_back(text->content()); } } - - // clear the memory - if(xml_page.memory){ - free( xml_page.memory ); - xml_page.memory = NULL; - xml_page.size = 0; - } - return audioFileName; } + ARDOUR::Library->set_tags (std::string("//")+audioFileName, strings); + ARDOUR::Library->save_changes (); } } - else { - return audioFileName; - } + return audioFileName; } int audioFileWrite(void *buffer, size_t size, size_t nmemb, void *file) @@ -440,74 +291,63 @@ }; //------------------------------------------------------------------------ -std::string Mootcher::getFile(std::string ID) +std::string Mootcher::getAudioFile(std::string originalFileName, std::string ID, std::string audioURL, Gtk::ProgressBar *progress_bar) { - CURLcode result_curl; - std::string audioFileName; + std::string audioFileName = basePath + "snd/" + ID + "-" + originalFileName; - if(connection != 0) - { - int length; - std::string name = getXmlFile(ID, length); - if( name != "" ){ + //check to see if audio file already exists + FILE *testFile = fopen(audioFileName.c_str(), "r"); + if (testFile) { + fseek (testFile , 0 , SEEK_END); + if (ftell (testFile) > 256) { + std::cerr << "audio file " << audioFileName << " already exists" << std::endl; + fclose (testFile); + return audioFileName; + } + + // else file was small, probably an error, delete it and try again + fclose(testFile); + remove( audioFileName.c_str() ); + } - // create new filename with the ID number - audioFileName += basePath; - audioFileName += "snd/"; - audioFileName += ID; - audioFileName += "-"; - audioFileName += name; + //now download the actual file + if (curl) { - //check to see if audio file already exists - FILE *testFile = fopen(audioFileName.c_str(), "r"); - if (testFile) { //TODO: should also check length to see if file is complete - fseek (testFile , 0 , SEEK_END); - if (ftell (testFile) == length) { - sprintf(message, "%s already exists\n", audioFileName.c_str() ); - toLog(message); - fclose (testFile); - return audioFileName; - } else { - remove( audioFileName.c_str() ); //file was not correct length, delete it and try again - } - } + FILE* theFile; + theFile = fopen( audioFileName.c_str(), "wb" ); + if (theFile) { + + // create the download url + audioURL += "?api_key=" + api_key; + + setcUrlOptions(); + curl_easy_setopt(curl, CURLOPT_URL, audioURL.c_str() ); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, audioFileWrite); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, theFile); - //now download the actual file - if (curl) { + std::cerr << "downloading " << audioFileName << " from " << audioURL << "..." << std::endl; - FILE* theFile; - theFile = fopen( audioFileName.c_str(), "wb" ); + 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, progress_bar); - // create the download url, this url will also update the download statics on the site - std::string audioURL; - audioURL += "http://www.freesound.org/samplesDownload.php?id="; - audioURL += ID; + CURLcode res = curl_easy_perform(curl); + fclose(theFile); - setcUrlOptions(); - curl_easy_setopt(curl, CURLOPT_URL, audioURL.c_str() ); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, audioFileWrite); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, theFile); + curl_easy_setopt (curl, CURLOPT_NOPROGRESS, 1); // turn off the progress bar + progress_bar->set_fraction(0.0); - connection = 1; - CURLcode res = curl_easy_perform(curl); - if( res != 0 ) { - toLog("curl login error\n"); - toLog(curl_easy_strerror(res)); - connection = 0; - } - - fclose(theFile); + if( res != 0 ) { + std::cerr << "curl error " << res << " (" << curl_easy_strerror(res) << ")" << std::endl; + remove( audioFileName.c_str() ); + return ""; + } else { + std::cerr << "done!" << std::endl; + // now download the tags &c. + getSoundResourceFile(ID); } - -/* - bar.dlnowMoo = 0; - bar.dltotalMoo = 0; - curl_easy_setopt (curl, CURLOPT_NOPROGRESS, 0); // turn on the process bar thingy - curl_easy_setopt (curl, CURLOPT_PROGRESSFUNCTION, progress_callback); - curl_easy_setopt (curl, CURLOPT_PROGRESSDATA, &bar); -*/ } } @@ -517,8 +357,17 @@ //--------- int Mootcher::progress_callback(void *bar, double dltotal, double dlnow, double ultotal, double ulnow) { - struct dlprocess *lbar = (struct dlprocess *) bar; - lbar->dltotalMoo = dltotal; - lbar->dlnowMoo = dlnow; + + //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. + + Gtk::ProgressBar *progress_bar = (Gtk::ProgressBar *) bar; + progress_bar->set_fraction(dlnow/dltotal); + /* Make sure the progress widget gets updated */ + while (Glib::MainContext::get_default()->iteration (false)) { + /* do nothing */ + } + std::cerr << "progress: " << dlnow << " of " << dltotal << " \r"; return 0; } + Index: gtk2_ardour/sfdb_freesound_mootcher.h =================================================================== --- gtk2_ardour/sfdb_freesound_mootcher.h (revision 10499) +++ gtk2_ardour/sfdb_freesound_mootcher.h (working copy) @@ -1,6 +1,7 @@ /*sfdb_freesound_mootcher.h**************************************************************************** Adapted for Ardour by Ben Loftis, March 2008 + Updated to new Freesound API by Colin Fletcher, November 2011 Mootcher Online Access to thefreesoundproject website http://freesound.iua.upf.edu/ @@ -19,60 +20,55 @@ #include <string> #include <sstream> #include <vector> +#include <gtkmm/progressbar.h> //#include <ctime> #include "curl/curl.h" - -// mootcher version -#define ___VERSION___ 1.3 - //--- struct to store XML file struct MemoryStruct { char *memory; size_t size; }; -//--- for download process viewing -struct dlprocess { - double dltotalMoo; - double dlnowMoo; +enum sortMethod { + sort_none, // no sort + sort_duration_desc, // Sort by the duration of the sounds, longest sounds first. + sort_duration_asc, // Same as above, but shortest sounds first. + sort_created_desc, // Sort by the date of when the sound was added. newest sounds first. + sort_created_asc, // Same as above, but oldest sounds first. + sort_downloads_desc, // Sort by the number of downloads, most downloaded sounds first. + sort_downloads_asc, // Same as above, but least downloaded sounds first. + sort_rating_desc, // Sort by the average rating given to the sounds, highest rated first. + sort_rating_asc // Same as above, but lowest rated sounds first. }; + class Mootcher { public: Mootcher(const char *saveLocation); ~Mootcher(); - int doLogin(std::string login, std::string password); - std::string getFile(std::string ID); - std::string searchText(std::string word); + std::string getAudioFile(std::string originalFileName, std::string ID, std::string audioURL, Gtk::ProgressBar *progress_bar); + std::string searchText(std::string query, int page, std::string filter, enum sortMethod sort); - - struct dlprocess bar; - private: const char* changeWorkingDir(const char *saveLocation); - std::string getXmlFile(std::string ID, int &length); - void GetXml(std::string ID, struct MemoryStruct &xml_page); - std::string changeExtension(std::string filename); - - void toLog(std::string input); - + std::string doRequest(std::string uri, std::string params); void setcUrlOptions(); - static size_t WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data); - static int progress_callback(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow); + static size_t WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data); + static int progress_callback(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow); + std::string sortMethodString(enum sortMethod sort); + std::string getSoundResourceFile(std::string ID); CURL *curl; char errorBuffer[CURL_ERROR_SIZE]; // storage for cUrl error message - int connection; // is 0 if no connection - char message[128]; // storage for messages that are send to the logfile - std::string basePath; std::string xmlLocation; }; + Index: gtk2_ardour/sfdb_ui.cc =================================================================== --- gtk2_ardour/sfdb_ui.cc (revision 10499) +++ gtk2_ardour/sfdb_ui.cc (working copy) @@ -421,7 +421,7 @@ preview (persistent), found_search_btn (_("Search")), found_list_view (found_list), - freesound_search_btn (_("Start Downloading")), + freesound_search_btn (_("Search")), freesound_list_view (freesound_list) { resetting_ourselves = false; @@ -516,33 +516,53 @@ passbox->set_spacing (6); label = manage (new Label); - label->set_text (_("User:")); + label->set_text (_("Tags:")); passbox->pack_start (*label, false, false); - passbox->pack_start (freesound_name_entry); + passbox->pack_start (freesound_entry, false, false); + label = manage (new Label); - label->set_text (_("Password:")); + label->set_text (_("Sort:")); passbox->pack_start (*label, false, false); - passbox->pack_start (freesound_pass_entry); + passbox->pack_start (freesound_sort, false, false); + freesound_sort.clear_items(); + + // Order of the following must correspond with enum sortMethod + // in sfdb_freesound_mootcher.h + freesound_sort.append_text(_("None")); + freesound_sort.append_text(_("Longest")); + freesound_sort.append_text(_("Shortest")); + freesound_sort.append_text(_("Newest")); + freesound_sort.append_text(_("Oldest")); + freesound_sort.append_text(_("Most downloaded")); + freesound_sort.append_text(_("Least downloaded")); + freesound_sort.append_text(_("Highest rated")); + freesound_sort.append_text(_("Lowest rated")); + freesound_sort.set_active(0); + label = manage (new Label); - label->set_text (_("Tags:")); + label->set_text (_("Page:")); passbox->pack_start (*label, false, false); - passbox->pack_start (freesound_entry, false, false); + passbox->pack_start (freesound_page, false, false); + freesound_page.set_range(1, 1000); + freesound_page.set_increments(1, 10); + passbox->pack_start (freesound_search_btn, false, false); - + passbox->pack_start (progress_bar); + Gtk::ScrolledWindow *scroll = manage(new ScrolledWindow); scroll->add(freesound_list_view); scroll->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); vbox = manage(new VBox); vbox->pack_start (*passbox, PACK_SHRINK); - vbox->pack_start(*scroll); + vbox->pack_start (*scroll); - //vbox->pack_start (freesound_list_view); - - freesound_list_view.append_column(_("Paths"), freesound_list_columns.pathname); + 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.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_list_view_selected)); - //freesound_list_view.get_selection()->set_mode (SELECTION_MULTIPLE); + 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)); @@ -712,13 +732,33 @@ if (!reset_options ()) { set_response_sensitive (RESPONSE_OK, false); } else { + + string path; + path = Glib::get_home_dir(); + path += "/Freesound/"; + Mootcher theMootcher(path.c_str()); // XXX should be a member of SoundFileBrowser + 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()); - file = (*iter)[freesound_list_columns.pathname]; + + 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 = theMootcher.getAudioFile(ofn, id, uri, &progress_bar); + + gdk_window_set_cursor (get_window()->gobj(), prev_cursor); + chooser.set_filename (file); set_response_sensitive (RESPONSE_OK, true); } else { @@ -753,43 +793,16 @@ } } -void* -freesound_search_thread_entry (void* arg) -{ - SessionEvent::create_per_thread_pool ("freesound events", 64); - - static_cast<SoundFileBrowser*>(arg)->freesound_search_thread (); - - return 0; -} - -bool searching = false; -bool canceling = false; - void SoundFileBrowser::freesound_search_clicked () { - if (canceling) //already canceling, button does nothing - return; - - if ( searching ) { - freesound_search_btn.set_label(_("Cancelling..")); - canceling = true; - } else { - searching = true; - freesound_search_btn.set_label(_("Cancel")); - pthread_t freesound_thr; - pthread_create_and_store ("freesound_search", &freesound_thr, freesound_search_thread_entry, this); - } + freesound_search(); } + void -SoundFileBrowser::freesound_search_thread() +SoundFileBrowser::freesound_search() { -#if 0 - - THIS IS ALL TOTALLY THREAD-ILLEGAL ... YOU CANNOT DO GTK STUFF IN THIS THREAD - #ifdef FREESOUND freesound_list->clear(); @@ -798,47 +811,80 @@ path += "/Freesound/"; Mootcher theMootcher(path.c_str()); - string name_string = freesound_name_entry.get_text (); - string pass_string = freesound_pass_entry.get_text (); string search_string = freesound_entry.get_text (); + enum sortMethod sort_method = (enum sortMethod) freesound_sort.get_active_row_number(); + int page = freesound_page.get_value_as_int(); - if ( theMootcher.doLogin( name_string, pass_string ) ) { + 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 theString = theMootcher.searchText(search_string); + string theString = theMootcher.searchText( + search_string, + page, + "", // filter, could do, e.g. "type:wav" + sort_method + ); - XMLTree doc; - doc.read_buffer( theString ); - XMLNode *root = doc.root(); + gdk_window_set_cursor (get_window()->gobj(), prev_cursor); - if (root==NULL) return; + XMLTree doc; + doc.read_buffer( theString ); + XMLNode *root = doc.root(); - if ( strcmp(root->name().c_str(), "freesound") == 0) { + if (!root) { + cerr << "no root XML node!" << endl; + return; + } - XMLNode *node = 0; - XMLNodeList children = root->children(); - XMLNodeConstIterator niter; - for (niter = children.begin(); niter != children.end() && !canceling; ++niter) { - node = *niter; - if( strcmp( node->name().c_str(), "sample") == 0 ){ - XMLProperty *prop=node->property ("id"); - string filename = theMootcher.getFile( prop->value().c_str() ); - if ( filename != "" ) { - TreeModel::iterator new_row = freesound_list->append(); - TreeModel::Row row = *new_row; - string path = Glib::filename_from_uri (string ("file:") + filename); - row[freesound_list_columns.pathname] = path; - } - } - } + if ( strcmp(root->name().c_str(), "response") != 0) { + cerr << "root node name == " << root->name() << ", != \"response\"!" << endl; + return; + } + + XMLNode *sounds_root = root->child("sounds"); + + if (!sounds_root) { + cerr << "no child node \"sounds\" found!" << endl; + return; + } + + XMLNodeList sounds = sounds_root->children(); + XMLNodeConstIterator niter; + XMLNode *node; + for (niter = sounds.begin(); niter != sounds.end(); ++niter) { + node = *niter; + if( strcmp( node->name().c_str(), "resource") != 0 ){ + cerr << "node->name()=" << node->name() << ",!= \"resource\"!" << endl; + continue; // return; } + + // node->dump(cerr, "node:"); + + XMLNode *id_node = node->child ("id"); + XMLNode *uri_node = node->child ("serve"); + XMLNode *ofn_node = node->child ("original_filename"); + + if (id_node && uri_node && ofn_node) { + + std::string id = id_node->child("text")->content(); + std::string uri = uri_node->child("text")->content(); + std::string ofn = ofn_node->child("text")->content(); + + std::string r; + // cerr << "id=" << id << ",uri=" << uri << ",ofn=" << ofn << endl; + + TreeModel::iterator new_row = freesound_list->append(); + TreeModel::Row row = *new_row; + + row[freesound_list_columns.id ] = id; + row[freesound_list_columns.uri ] = uri; + row[freesound_list_columns.filename] = ofn; + + } } - - searching = false; - canceling = false; - freesound_search_btn.set_label(_("Start Downloading")); #endif -#endif - } vector<string> @@ -874,12 +920,29 @@ typedef TreeView::Selection::ListHandle_Path ListPath; + string path; + path = Glib::get_home_dir(); + path += "/Freesound/"; + Mootcher theMootcher(path.c_str()); // XXX should be a member of SoundFileBrowser + + 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 str = (*iter)[freesound_list_columns.pathname]; + 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 = theMootcher.getAudioFile(ofn, id, uri, &progress_bar); results.push_back (str); + + gdk_window_set_cursor (get_window()->gobj(), prev_cursor); + } } Index: gtk2_ardour/sfdb_ui.h =================================================================== --- gtk2_ardour/sfdb_ui.h (revision 10499) +++ gtk2_ardour/sfdb_ui.h (working copy) @@ -114,12 +114,24 @@ FoundTagColumns() { add(pathname); } }; + class FreesoundColumns : public Gtk::TreeModel::ColumnRecord + { + public: + Gtk::TreeModelColumn<std::string> id; + Gtk::TreeModelColumn<std::string> uri; + Gtk::TreeModelColumn<std::string> filename; + + FreesoundColumns() { add(id); add(filename); add(uri); } + }; + FoundTagColumns found_list_columns; Glib::RefPtr<Gtk::ListStore> found_list; - FoundTagColumns freesound_list_columns; + FreesoundColumns freesound_list_columns; Glib::RefPtr<Gtk::ListStore> freesound_list; + Gtk::ProgressBar progress_bar; + public: SoundFileBrowser (Gtk::Window& parent, std::string title, ARDOUR::Session* _s, bool persistent); virtual ~SoundFileBrowser (); @@ -137,13 +149,14 @@ Gtk::Button found_search_btn; Gtk::TreeView found_list_view; - Gtk::Entry freesound_name_entry; - Gtk::Entry freesound_pass_entry; Gtk::Entry freesound_entry; + Gtk::ComboBoxText freesound_sort; + Gtk::SpinButton freesound_page; + Gtk::Button freesound_search_btn; Gtk::TreeView freesound_list_view; - void freesound_search_thread(); + void freesound_search(); protected: bool resetting_ourselves; |
|
I've attached my current attempt at making this work, just so it's backed up somewhere in case my computer is struck by lightning or something. There are still plenty of rough edges, and I haven't taken advantage of any of the nice stuff that the new Freesound API offers. However, I think it works more-or-less as well as the old Freesound support ever did. bugs/wrinkles still remaining: - make the displayed data in the freesound tab more useful (we don't need to show the uri to users). - sort out oddities with the ProgressBar. It probably needs to be made properly thread-safe: I don't know what happens inside libcurl. - the progress bar is also rather arbitrarily placed in the window at the moment: it could probably be put somewhere more logical and/or nicer-looking. - sound file info sometimes doesn't get updated on the first click. - add a means of cancelling sound file downloads. - it uses an API key I registered myself (under an application name of 'test' and with my web site url): I guess someone will need to register a key (or keys) for Ardour. I'm happy to do this, but it might make more sense to do it through a freesound account accessible to one or more main developers. - loads of unnecessarily verbose debug output. - probably plenty more things wrong. |
|
can i apply this? it contains your freesound credentials... |
|
I suppose Ardour ought to have its own API key: do you have a Freesound account to create one, or should there be an Ardour account too? |
|
i thought the idea was the user logged in themselves? |
|
You may be right: the Freesound web site developer help just says "In order to use the Freesound API you need to be authenticated with an API key", but it's a bit ambiguous whether "use" means writing or running code that uses the API. I'll go & have another read & see if it's made any clearer anywhere else. |
|
Looking at various messages in the Freesound google group, it seems that API keys are 'per-application', not 'per-user', so I guess that Ardour will need one. Shall I apply for one, or will you? http://groups.google.com/group/freesound-api/browse_thread/thread/027bb502268cac56# http://groups.google.com/group/freesound-api/browse_thread/thread/9c4280e7bb9df8e8# |
|
colin - it would be great if you could take care of this. thanks. |
2011-11-14 11:39
|
freesound-new-api-10577.patch (37,870 bytes)
Index: gtk2_ardour/wscript =================================================================== --- gtk2_ardour/wscript (revision 10573) +++ gtk2_ardour/wscript (working copy) @@ -389,6 +389,7 @@ if bld.is_defined('FREESOUND'): obj.source += [ 'sfdb_freesound_mootcher.cc' ] + obj.defines += [ 'FREESOUND' ] if bld.is_defined('VST_SUPPORT'): obj.source += [ 'vst_pluginui.cc' ] Index: gtk2_ardour/sfdb_freesound_mootcher.cc =================================================================== --- gtk2_ardour/sfdb_freesound_mootcher.cc (revision 10573) +++ gtk2_ardour/sfdb_freesound_mootcher.cc (working copy) @@ -1,6 +1,7 @@ /* sfdb_freesound_mootcher.cpp ********************************************************************** Adapted for Ardour by Ben Loftis, March 2008 + Updated to new Freesound API by Colin Fletcher, November 2011 Mootcher 23-8-2005 @@ -43,37 +44,39 @@ #include <sys/stat.h> #include <sys/types.h> +#include <iostream> #include "ardour/audio_library.h" -#define TRUE 1 +static const std::string base_url = "http://www.freesound.org/api"; +static const std::string api_key = "9d77cb8d841b4bcfa960e1aae62224eb"; // ardour3 + //------------------------------------------------------------------------ -Mootcher:: Mootcher(const char *saveLocation) - : curl( NULL ) - , connection( 0 ) +Mootcher::Mootcher(const char *saveLocation) + : curl(curl_easy_init()) { changeWorkingDir(saveLocation); }; //------------------------------------------------------------------------ -Mootcher:: ~Mootcher() +Mootcher:: ~Mootcher() { - remove( "cookiejar.txt" ); } + //------------------------------------------------------------------------ const char* Mootcher::changeWorkingDir(const char *saveLocation) { basePath = saveLocation; #ifdef __WIN32__ std::string replace = "/"; - int pos = (int)basePath.find("\\"); + size_t pos = basePath.find("\\"); while( pos != std::string::npos ){ basePath.replace(pos, 1, replace); - pos = (int)basePath.find("\\"); + pos = basePath.find("\\"); } #endif // - int pos2 = basePath.find_last_of("/"); + size_t pos2 = basePath.find_last_of("/"); if(basePath.length() != (pos2+1)) basePath += "/"; // create Freesound directory and sound dir @@ -86,15 +89,12 @@ } //------------------------------------------------------------------------ -size_t Mootcher::WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data) +size_t Mootcher::WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data) { register int realsize = (int)(size * nmemb); struct MemoryStruct *mem = (struct MemoryStruct *)data; - // There might be a realloc() out there that doesn't like - // reallocing NULL pointers, so we take care of it here - if(mem->memory) mem->memory = (char *)realloc(mem->memory, mem->size + realsize + 1); - else mem->memory = (char *)malloc(mem->size + realsize + 1); + mem->memory = (char *)realloc(mem->memory, mem->size + realsize + 1); if (mem->memory) { memcpy(&(mem->memory[mem->size]), ptr, realsize); @@ -106,332 +106,183 @@ //------------------------------------------------------------------------ -void Mootcher::toLog(std::string input) -{ -printf("%s\n", input.c_str());// for debugging -} +std::string Mootcher::sortMethodString(enum sortMethod sort) { + switch (sort) { + case sort_duration_desc: return "duration_desc"; + case sort_duration_asc: return "duration_asc"; + case sort_created_desc: return "created_desc"; + case sort_created_asc: return "created_asc"; + case sort_downloads_desc: return "downloads_desc"; + case sort_downloads_asc: return "downloads_asc"; + case sort_rating_desc: return "rating_desc"; + case sort_rating_asc: return "rating_asc"; + default: return ""; + } +} + //------------------------------------------------------------------------ -void Mootcher::setcUrlOptions() +void Mootcher::setcUrlOptions() { // basic init for curl curl_global_init(CURL_GLOBAL_ALL); // some servers don't like requests that are made without a user-agent field, so we provide one curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcurl-agent/1.0"); // setup curl error buffer - CURLcode res = curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errorBuffer); - // always use the cookie with session id which is received at the login - curl_easy_setopt(curl, CURLOPT_COOKIEFILE, "cookiejar.txt"); + curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errorBuffer); // Allow redirection curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); + + // Allow connections to time out (without using signals) + curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); + curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10); + + } -//------------------------------------------------------------------------ -int Mootcher::doLogin(std::string login, std::string password) +std::string Mootcher::doRequest(std::string uri, std::string params) { - if(connection==1) - return 1; - + std::string result; struct MemoryStruct xml_page; xml_page.memory = NULL; xml_page.size = 0; - // create the post message from the login and password - std::string postMessage; - postMessage += "username="; - postMessage += curl_escape(login.c_str(), 0); - postMessage += "&password="; - postMessage += curl_escape(password.c_str(), 0); - postMessage += "&login="; - postMessage += curl_escape("1", 0); - postMessage += "&redirect="; - postMessage += curl_escape("../tests/login.php", 0); + setcUrlOptions(); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *) &xml_page); - // Do the setup for libcurl - curl = curl_easy_init(); + // curl_easy_setopt(curl, CURLOPT_HTTPGET, 1); + // curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postMessage.c_str()); + // curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, -1); - if(curl) - { - setcUrlOptions(); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&xml_page); - // save the sessoin id that is given back by the server in a cookie - curl_easy_setopt(curl, CURLOPT_COOKIEJAR, "cookiejar.txt"); - // use POST for login variables - curl_easy_setopt(curl, CURLOPT_POST, TRUE); - curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postMessage.c_str()); - curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, -1); + // the url to get + std::string url = base_url + uri + "?"; + if (params != "") { + url += params + "&api_key=" + api_key + "&format=xml"; + } else { + url += "api_key=" + api_key + "&format=xml"; + } + + curl_easy_setopt(curl, CURLOPT_URL, url.c_str() ); + std::cerr << "doRequest: " << url << std::endl; + + // perform online request + CURLcode res = curl_easy_perform(curl); + if( res != 0 ) { + std::cerr << "curl error " << res << " (" << curl_easy_strerror(res) << ")" << std::endl; + return ""; + } - // the url to get - std::string login_url = "http://www.freesound.org/forum/login.php"; - curl_easy_setopt(curl, CURLOPT_URL, login_url.c_str() ); + result = xml_page.memory; + // free the memory + if(xml_page.memory){ + free( xml_page.memory ); + xml_page.memory = NULL; + xml_page.size = 0; + } - // perform online request - connection = 1; - CURLcode res = curl_easy_perform(curl); - if( res != 0 ) { - toLog("curl login error\n"); - toLog(curl_easy_strerror(res)); - connection = 0; - } + return result; - if (connection == 1){ - std::string check_page = xml_page.memory; - int test = (int)check_page.find("login"); //logged - if( strcmp(xml_page.memory, "login") == 0 ) - toLog("Logged in.\n"); - else { - toLog("Login failed: Check username and password.\n"); - connection = 0; - } - } +} - // free the memory - if(xml_page.memory){ - free( xml_page.memory ); - xml_page.memory = NULL; - xml_page.size = 0; - } - std::cerr << "Login was cool, connection = " << connection << std::endl; - return connection; - } - else return 3; // will be returned if a curl related problem ocurrs -} -//------------------------------------------------------------------------ -std::string Mootcher::searchText(std::string word) +std::string Mootcher::searchText(std::string query, int page, std::string filter, enum sortMethod sort) { - struct MemoryStruct xml_page; - xml_page.memory = NULL; - xml_page.size = 0; + std::string params = ""; + char buf[24]; - std::string result; - - if(connection != 0) - { - // create a url encoded post message - std::string postMessage; - char tempString[ 128 ]; - char *tempPointer = &tempString[0]; - - postMessage = "search="; - postMessage += curl_escape(word.c_str(), 0); - sprintf( tempPointer, "&searchDescriptions=1"); - postMessage += tempPointer; - sprintf( tempPointer, "&searchtags=1"); - postMessage += tempPointer; - - // Ref: http://www.freesound.org/forum/viewtopic.php?p=19081 - // const ORDER_DEFAULT = 0; - // const ORDER_DOWNLOADS_DESC = 1; - // const ORDER_DOWNLOADS_ASC = 2; - // const ORDER_USERNAME_DESC = 3; - // const ORDER_USERNAME_ASC = 4; - // const ORDER_DATE_DESC = 5; - // const ORDER_DATE_ASC = 6; - // const ORDER_DURATION_DESC = 7; - // const ORDER_DURATION_ASC = 8; - // const ORDER_FILEFORMAT_DESC = 9; - // const ORDER_FILEFORMAT_ASC = 10; - sprintf( tempPointer, "&order=1"); - postMessage += tempPointer; - sprintf( tempPointer, "&start=0"); - postMessage += tempPointer; - sprintf( tempPointer, "&limit=10"); - postMessage += tempPointer; - // The limit of 10 samples is arbitrary, but seems - // reasonable in light of the fact that all of the returned - // samples get downloaded, and downloads are s-l-o-w. - - if(curl) - { - // basic init for curl - setcUrlOptions(); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&xml_page); - // setup the post message - curl_easy_setopt(curl, CURLOPT_POST, TRUE); - curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postMessage.c_str()); - curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, -1); - - // the url to get - std::string search_url = "http://www.freesound.org/searchTextXML.php"; - curl_easy_setopt(curl, CURLOPT_URL, search_url.c_str()); - - // perform the online search - connection = 1; - CURLcode res = curl_easy_perform(curl); - if( res != 0 ) { - toLog("curl login error\n"); - toLog(curl_easy_strerror(res)); - connection = 0; - } - - result = xml_page.memory; - toLog( result.c_str() ); - - // free the memory - if(xml_page.memory){ - free( xml_page.memory ); - xml_page.memory = NULL; - xml_page.size = 0; - } - - } + if (page > 1) { + snprintf(buf, 23, "p=%d&", page); + params += buf; } + + params += "q=" + query; - return result; + if (filter != "") + params += "&f=" + filter; + + if (sort) + params += "&s=" + sortMethodString(sort); + + return doRequest("/sounds/search", params); } //------------------------------------------------------------------------ -std::string Mootcher::changeExtension(std::string filename) + +std::string Mootcher::getSoundResourceFile(std::string ID) { - std::string aiff = ".aiff"; - std::string aif = ".aif"; - std::string wav = ".wav"; - std::string mp3 = ".mp3"; - std::string ogg = ".ogg"; - std::string flac = ".flac"; - std::string replace = ".xml"; - int pos = 0; + std::string originalSoundURI; + std::string audioFileName; + std::string xmlFileName; + std::string xml; - pos = (int)filename.find(aiff); - if(pos != std::string::npos) filename.replace(pos, aiff.size(), replace); - pos = (int)filename.find(aif); - if(pos != std::string::npos) filename.replace(pos, aif.size(), replace); - pos = (int)filename.find(wav); - if(pos != std::string::npos) filename.replace(pos, wav.size(), replace); - pos = (int)filename.find(mp3); - if(pos != std::string::npos) filename.replace(pos, mp3.size(), replace); - pos = (int)filename.find(ogg); - if(pos != std::string::npos) filename.replace(pos, ogg.size(), replace); - pos = (int)filename.find(flac); - if(pos != std::string::npos) filename.replace(pos, flac.size(), replace); - return filename; -} -//------------------------------------------------------------------------ -void Mootcher::GetXml(std::string ID, struct MemoryStruct &xml_page) -{ + std::cerr << "getSoundResourceFile(" << ID << ")" << std::endl; - if(curl) { - setcUrlOptions(); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&xml_page); + // download the xmlfile into xml_page + xml = doRequest("/sounds/" + ID, ""); - // URL to get - std::string getxml_url = "http://www.freesound.org/samplesViewSingleXML.php?id="; - getxml_url += ID; + XMLTree doc; + doc.read_buffer( xml.c_str() ); + XMLNode *freesound = doc.root(); - curl_easy_setopt(curl, CURLOPT_URL, getxml_url.c_str() ); + // if the page is not a valid xml document with a 'freesound' root + if (freesound == NULL) { + std::cerr << "getSoundResourceFile: There is no valid root in the xml file" << std::endl; + return ""; + } - // get it! - connection = 1; - CURLcode res = curl_easy_perform(curl); - if( res != 0 ) { - toLog("curl login error\n"); - toLog(curl_easy_strerror(res)); - connection = 0; - } + if (strcmp(doc.root()->name().c_str(), "response") != 0) { + std::cerr << "getSoundResourceFile: root =" << doc.root()->name() << ", != response" << std::endl; + return ""; } -} -//------------------------------------------------------------------------ -std::string Mootcher::getXmlFile(std::string ID, int &length) -{ - struct MemoryStruct xml_page; - xml_page.memory = NULL; - xml_page.size = NULL; - std::string xmlFileName; - std::string audioFileName; - std::string filename; + XMLNode *name = freesound->child("original_filename"); + XMLNode *filesize = freesound->child("filesize"); - if(connection != 0) { - // download the xmlfile into xml_page - GetXml(ID, xml_page); - // if sample ID does not exist on the freesound website - if(strcmp(xml_page.memory, "sample non existant") == 0){ - free( xml_page.memory ); - sprintf(message, "getXmlFile: sample with ID:%s does not exist!\n", ID.c_str() ); - toLog(message); - return filename; - } else { - XMLTree doc; - doc.read_buffer( xml_page.memory ); - XMLNode *freesound = doc.root(); + // get the file name and size from xml file + if (name && filesize) { - // if the page is not a valid xml document with a 'freesound' root - if( freesound == NULL){ - sprintf(message, "getXmlFile: There is no valid root in the xml file"); - toLog(message); - } else { - XMLNode *sample = freesound->child("sample"); - XMLNode *name = NULL; - XMLNode *filesize = NULL; - if (sample) { - name = sample->child("originalFilename"); - filesize = sample->child("filesize"); - } + audioFileName = basePath + "snd/" + ID + "-" + name->child("text")->content(); - // get the file name and size from xml file - if (sample && name && filesize) { + // create new filename with the ID number + xmlFileName = basePath; + xmlFileName += "snd/"; + xmlFileName += freesound->child("id")->child("text")->content(); + xmlFileName += "-"; + xmlFileName += name->child("text")->content(); + xmlFileName += ".xml"; - audioFileName = name->child("text")->content(); - sprintf( message, "getXmlFile: %s needs to be downloaded\n", audioFileName.c_str() ); - toLog(message); + // std::cerr << "getSoundResourceFile: saving XML: " << xmlFileName << std::endl; - length = atoi(filesize->child("text")->content().c_str()); + // save the xml file to disk + doc.write(xmlFileName.c_str()); - // create new filename with the ID number - filename = basePath; - filename += "snd/"; - filename += sample->property("id")->value(); - filename += "-"; - filename += audioFileName; - // change the extention into .xml - xmlFileName = changeExtension( filename ); - - sprintf(message, "getXmlFile: saving XML: %s\n", xmlFileName.c_str() ); - toLog(message); - - // save the xml file to disk - doc.write(xmlFileName.c_str()); - - //store all the tags in the database - XMLNode *tags = sample->child("tags"); - if (tags) { - XMLNodeList children = tags->children(); - XMLNodeConstIterator niter; - std::vector<std::string> strings; - for (niter = children.begin(); niter != children.end(); ++niter) { - XMLNode *node = *niter; - if( strcmp( node->name().c_str(), "tag") == 0 ) { - XMLNode *text = node->child("text"); - if (text) strings.push_back(text->content()); - } - } - ARDOUR::Library->set_tags (std::string("//")+filename, strings); - ARDOUR::Library->save_changes (); + //store all the tags in the database + XMLNode *tags = freesound->child("tags"); + if (tags) { + XMLNodeList children = tags->children(); + XMLNodeConstIterator niter; + std::vector<std::string> strings; + for (niter = children.begin(); niter != children.end(); ++niter) { + XMLNode *node = *niter; + if( strcmp( node->name().c_str(), "resource") == 0 ) { + XMLNode *text = node->child("text"); + if (text) { + // std::cerr << "tag: " << text->content() << std::endl; + strings.push_back(text->content()); } } - - // clear the memory - if(xml_page.memory){ - free( xml_page.memory ); - xml_page.memory = NULL; - xml_page.size = 0; - } - return audioFileName; } + ARDOUR::Library->set_tags (std::string("//")+audioFileName, strings); + ARDOUR::Library->save_changes (); } } - else { - return audioFileName; - } + return audioFileName; } int audioFileWrite(void *buffer, size_t size, size_t nmemb, void *file) @@ -440,74 +291,63 @@ }; //------------------------------------------------------------------------ -std::string Mootcher::getFile(std::string ID) +std::string Mootcher::getAudioFile(std::string originalFileName, std::string ID, std::string audioURL, Gtk::ProgressBar *progress_bar) { - CURLcode result_curl; - std::string audioFileName; + std::string audioFileName = basePath + "snd/" + ID + "-" + originalFileName; - if(connection != 0) - { - int length; - std::string name = getXmlFile(ID, length); - if( name != "" ){ + //check to see if audio file already exists + FILE *testFile = fopen(audioFileName.c_str(), "r"); + if (testFile) { + fseek (testFile , 0 , SEEK_END); + if (ftell (testFile) > 256) { + std::cerr << "audio file " << audioFileName << " already exists" << std::endl; + fclose (testFile); + return audioFileName; + } + + // else file was small, probably an error, delete it and try again + fclose(testFile); + remove( audioFileName.c_str() ); + } - // create new filename with the ID number - audioFileName += basePath; - audioFileName += "snd/"; - audioFileName += ID; - audioFileName += "-"; - audioFileName += name; + //now download the actual file + if (curl) { - //check to see if audio file already exists - FILE *testFile = fopen(audioFileName.c_str(), "r"); - if (testFile) { //TODO: should also check length to see if file is complete - fseek (testFile , 0 , SEEK_END); - if (ftell (testFile) == length) { - sprintf(message, "%s already exists\n", audioFileName.c_str() ); - toLog(message); - fclose (testFile); - return audioFileName; - } else { - remove( audioFileName.c_str() ); //file was not correct length, delete it and try again - } - } + FILE* theFile; + theFile = fopen( audioFileName.c_str(), "wb" ); + if (theFile) { + + // create the download url + audioURL += "?api_key=" + api_key; + + setcUrlOptions(); + curl_easy_setopt(curl, CURLOPT_URL, audioURL.c_str() ); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, audioFileWrite); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, theFile); - //now download the actual file - if (curl) { + std::cerr << "downloading " << audioFileName << " from " << audioURL << "..." << std::endl; - FILE* theFile; - theFile = fopen( audioFileName.c_str(), "wb" ); + 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, progress_bar); - // create the download url, this url will also update the download statics on the site - std::string audioURL; - audioURL += "http://www.freesound.org/samplesDownload.php?id="; - audioURL += ID; + CURLcode res = curl_easy_perform(curl); + fclose(theFile); - setcUrlOptions(); - curl_easy_setopt(curl, CURLOPT_URL, audioURL.c_str() ); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, audioFileWrite); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, theFile); + curl_easy_setopt (curl, CURLOPT_NOPROGRESS, 1); // turn off the progress bar + progress_bar->set_fraction(0.0); - connection = 1; - CURLcode res = curl_easy_perform(curl); - if( res != 0 ) { - toLog("curl login error\n"); - toLog(curl_easy_strerror(res)); - connection = 0; - } - - fclose(theFile); + if( res != 0 ) { + std::cerr << "curl error " << res << " (" << curl_easy_strerror(res) << ")" << std::endl; + remove( audioFileName.c_str() ); + return ""; + } else { + std::cerr << "done!" << std::endl; + // now download the tags &c. + getSoundResourceFile(ID); } - -/* - bar.dlnowMoo = 0; - bar.dltotalMoo = 0; - curl_easy_setopt (curl, CURLOPT_NOPROGRESS, 0); // turn on the process bar thingy - curl_easy_setopt (curl, CURLOPT_PROGRESSFUNCTION, progress_callback); - curl_easy_setopt (curl, CURLOPT_PROGRESSDATA, &bar); -*/ } } @@ -517,8 +357,17 @@ //--------- int Mootcher::progress_callback(void *bar, double dltotal, double dlnow, double ultotal, double ulnow) { - struct dlprocess *lbar = (struct dlprocess *) bar; - lbar->dltotalMoo = dltotal; - lbar->dlnowMoo = dlnow; + + //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. + + Gtk::ProgressBar *progress_bar = (Gtk::ProgressBar *) bar; + progress_bar->set_fraction(dlnow/dltotal); + /* Make sure the progress widget gets updated */ + while (Glib::MainContext::get_default()->iteration (false)) { + /* do nothing */ + } + std::cerr << "progress: " << dlnow << " of " << dltotal << " \r"; return 0; } + Index: gtk2_ardour/sfdb_freesound_mootcher.h =================================================================== --- gtk2_ardour/sfdb_freesound_mootcher.h (revision 10573) +++ gtk2_ardour/sfdb_freesound_mootcher.h (working copy) @@ -1,6 +1,7 @@ /*sfdb_freesound_mootcher.h**************************************************************************** Adapted for Ardour by Ben Loftis, March 2008 + Updated to new Freesound API by Colin Fletcher, November 2011 Mootcher Online Access to thefreesoundproject website http://freesound.iua.upf.edu/ @@ -19,60 +20,55 @@ #include <string> #include <sstream> #include <vector> +#include <gtkmm/progressbar.h> //#include <ctime> #include "curl/curl.h" - -// mootcher version -#define ___VERSION___ 1.3 - //--- struct to store XML file struct MemoryStruct { char *memory; size_t size; }; -//--- for download process viewing -struct dlprocess { - double dltotalMoo; - double dlnowMoo; +enum sortMethod { + sort_none, // no sort + sort_duration_desc, // Sort by the duration of the sounds, longest sounds first. + sort_duration_asc, // Same as above, but shortest sounds first. + sort_created_desc, // Sort by the date of when the sound was added. newest sounds first. + sort_created_asc, // Same as above, but oldest sounds first. + sort_downloads_desc, // Sort by the number of downloads, most downloaded sounds first. + sort_downloads_asc, // Same as above, but least downloaded sounds first. + sort_rating_desc, // Sort by the average rating given to the sounds, highest rated first. + sort_rating_asc // Same as above, but lowest rated sounds first. }; + class Mootcher { public: Mootcher(const char *saveLocation); ~Mootcher(); - int doLogin(std::string login, std::string password); - std::string getFile(std::string ID); - std::string searchText(std::string word); + std::string getAudioFile(std::string originalFileName, std::string ID, std::string audioURL, Gtk::ProgressBar *progress_bar); + std::string searchText(std::string query, int page, std::string filter, enum sortMethod sort); - - struct dlprocess bar; - private: const char* changeWorkingDir(const char *saveLocation); - std::string getXmlFile(std::string ID, int &length); - void GetXml(std::string ID, struct MemoryStruct &xml_page); - std::string changeExtension(std::string filename); - - void toLog(std::string input); - + std::string doRequest(std::string uri, std::string params); void setcUrlOptions(); - static size_t WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data); - static int progress_callback(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow); + static size_t WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data); + static int progress_callback(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow); + std::string sortMethodString(enum sortMethod sort); + std::string getSoundResourceFile(std::string ID); CURL *curl; char errorBuffer[CURL_ERROR_SIZE]; // storage for cUrl error message - int connection; // is 0 if no connection - char message[128]; // storage for messages that are send to the logfile - std::string basePath; std::string xmlLocation; }; + Index: gtk2_ardour/sfdb_ui.cc =================================================================== --- gtk2_ardour/sfdb_ui.cc (revision 10573) +++ gtk2_ardour/sfdb_ui.cc (working copy) @@ -421,7 +421,7 @@ preview (persistent), found_search_btn (_("Search")), found_list_view (found_list), - freesound_search_btn (_("Start Downloading")), + freesound_search_btn (_("Search")), freesound_list_view (freesound_list) { resetting_ourselves = false; @@ -516,33 +516,53 @@ passbox->set_spacing (6); label = manage (new Label); - label->set_text (_("User:")); + label->set_text (_("Tags:")); passbox->pack_start (*label, false, false); - passbox->pack_start (freesound_name_entry); + passbox->pack_start (freesound_entry, false, false); + label = manage (new Label); - label->set_text (_("Password:")); + label->set_text (_("Sort:")); passbox->pack_start (*label, false, false); - passbox->pack_start (freesound_pass_entry); + passbox->pack_start (freesound_sort, false, false); + freesound_sort.clear_items(); + + // Order of the following must correspond with enum sortMethod + // in sfdb_freesound_mootcher.h + freesound_sort.append_text(_("None")); + freesound_sort.append_text(_("Longest")); + freesound_sort.append_text(_("Shortest")); + freesound_sort.append_text(_("Newest")); + freesound_sort.append_text(_("Oldest")); + freesound_sort.append_text(_("Most downloaded")); + freesound_sort.append_text(_("Least downloaded")); + freesound_sort.append_text(_("Highest rated")); + freesound_sort.append_text(_("Lowest rated")); + freesound_sort.set_active(0); + label = manage (new Label); - label->set_text (_("Tags:")); + label->set_text (_("Page:")); passbox->pack_start (*label, false, false); - passbox->pack_start (freesound_entry, false, false); + passbox->pack_start (freesound_page, false, false); + freesound_page.set_range(1, 1000); + freesound_page.set_increments(1, 10); + passbox->pack_start (freesound_search_btn, false, false); - + passbox->pack_start (progress_bar); + Gtk::ScrolledWindow *scroll = manage(new ScrolledWindow); scroll->add(freesound_list_view); scroll->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); vbox = manage(new VBox); vbox->pack_start (*passbox, PACK_SHRINK); - vbox->pack_start(*scroll); + vbox->pack_start (*scroll); - //vbox->pack_start (freesound_list_view); - - freesound_list_view.append_column(_("Paths"), freesound_list_columns.pathname); + 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.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_list_view_selected)); - //freesound_list_view.get_selection()->set_mode (SELECTION_MULTIPLE); + 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)); @@ -712,13 +732,33 @@ if (!reset_options ()) { set_response_sensitive (RESPONSE_OK, false); } else { + + string path; + path = Glib::get_home_dir(); + path += "/Freesound/"; + Mootcher theMootcher(path.c_str()); // XXX should be a member of SoundFileBrowser + 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()); - file = (*iter)[freesound_list_columns.pathname]; + + 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 = theMootcher.getAudioFile(ofn, id, uri, &progress_bar); + + gdk_window_set_cursor (get_window()->gobj(), prev_cursor); + chooser.set_filename (file); set_response_sensitive (RESPONSE_OK, true); } else { @@ -753,43 +793,16 @@ } } -void* -freesound_search_thread_entry (void* arg) -{ - SessionEvent::create_per_thread_pool ("freesound events", 64); - - static_cast<SoundFileBrowser*>(arg)->freesound_search_thread (); - - return 0; -} - -bool searching = false; -bool canceling = false; - void SoundFileBrowser::freesound_search_clicked () { - if (canceling) //already canceling, button does nothing - return; - - if ( searching ) { - freesound_search_btn.set_label(_("Cancelling..")); - canceling = true; - } else { - searching = true; - freesound_search_btn.set_label(_("Cancel")); - pthread_t freesound_thr; - pthread_create_and_store ("freesound_search", &freesound_thr, freesound_search_thread_entry, this); - } + freesound_search(); } + void -SoundFileBrowser::freesound_search_thread() +SoundFileBrowser::freesound_search() { -#if 0 - - THIS IS ALL TOTALLY THREAD-ILLEGAL ... YOU CANNOT DO GTK STUFF IN THIS THREAD - #ifdef FREESOUND freesound_list->clear(); @@ -798,47 +811,80 @@ path += "/Freesound/"; Mootcher theMootcher(path.c_str()); - string name_string = freesound_name_entry.get_text (); - string pass_string = freesound_pass_entry.get_text (); string search_string = freesound_entry.get_text (); + enum sortMethod sort_method = (enum sortMethod) freesound_sort.get_active_row_number(); + int page = freesound_page.get_value_as_int(); - if ( theMootcher.doLogin( name_string, pass_string ) ) { + 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 theString = theMootcher.searchText(search_string); + string theString = theMootcher.searchText( + search_string, + page, + "", // filter, could do, e.g. "type:wav" + sort_method + ); - XMLTree doc; - doc.read_buffer( theString ); - XMLNode *root = doc.root(); + gdk_window_set_cursor (get_window()->gobj(), prev_cursor); - if (root==NULL) return; + XMLTree doc; + doc.read_buffer( theString ); + XMLNode *root = doc.root(); - if ( strcmp(root->name().c_str(), "freesound") == 0) { + if (!root) { + cerr << "no root XML node!" << endl; + return; + } - XMLNode *node = 0; - XMLNodeList children = root->children(); - XMLNodeConstIterator niter; - for (niter = children.begin(); niter != children.end() && !canceling; ++niter) { - node = *niter; - if( strcmp( node->name().c_str(), "sample") == 0 ){ - XMLProperty *prop=node->property ("id"); - string filename = theMootcher.getFile( prop->value().c_str() ); - if ( filename != "" ) { - TreeModel::iterator new_row = freesound_list->append(); - TreeModel::Row row = *new_row; - string path = Glib::filename_from_uri (string ("file:") + filename); - row[freesound_list_columns.pathname] = path; - } - } - } + if ( strcmp(root->name().c_str(), "response") != 0) { + cerr << "root node name == " << root->name() << ", != \"response\"!" << endl; + return; + } + + XMLNode *sounds_root = root->child("sounds"); + + if (!sounds_root) { + cerr << "no child node \"sounds\" found!" << endl; + return; + } + + XMLNodeList sounds = sounds_root->children(); + XMLNodeConstIterator niter; + XMLNode *node; + for (niter = sounds.begin(); niter != sounds.end(); ++niter) { + node = *niter; + if( strcmp( node->name().c_str(), "resource") != 0 ){ + cerr << "node->name()=" << node->name() << ",!= \"resource\"!" << endl; + continue; // return; } + + // node->dump(cerr, "node:"); + + XMLNode *id_node = node->child ("id"); + XMLNode *uri_node = node->child ("serve"); + XMLNode *ofn_node = node->child ("original_filename"); + + if (id_node && uri_node && ofn_node) { + + std::string id = id_node->child("text")->content(); + std::string uri = uri_node->child("text")->content(); + std::string ofn = ofn_node->child("text")->content(); + + std::string r; + // cerr << "id=" << id << ",uri=" << uri << ",ofn=" << ofn << endl; + + TreeModel::iterator new_row = freesound_list->append(); + TreeModel::Row row = *new_row; + + row[freesound_list_columns.id ] = id; + row[freesound_list_columns.uri ] = uri; + row[freesound_list_columns.filename] = ofn; + + } } - - searching = false; - canceling = false; - freesound_search_btn.set_label(_("Start Downloading")); #endif -#endif - } vector<string> @@ -874,12 +920,29 @@ typedef TreeView::Selection::ListHandle_Path ListPath; + string path; + path = Glib::get_home_dir(); + path += "/Freesound/"; + Mootcher theMootcher(path.c_str()); // XXX should be a member of SoundFileBrowser + + 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 str = (*iter)[freesound_list_columns.pathname]; + 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 = theMootcher.getAudioFile(ofn, id, uri, &progress_bar); results.push_back (str); + + gdk_window_set_cursor (get_window()->gobj(), prev_cursor); + } } Index: gtk2_ardour/sfdb_ui.h =================================================================== --- gtk2_ardour/sfdb_ui.h (revision 10573) +++ gtk2_ardour/sfdb_ui.h (working copy) @@ -114,12 +114,24 @@ FoundTagColumns() { add(pathname); } }; + class FreesoundColumns : public Gtk::TreeModel::ColumnRecord + { + public: + Gtk::TreeModelColumn<std::string> id; + Gtk::TreeModelColumn<std::string> uri; + Gtk::TreeModelColumn<std::string> filename; + + FreesoundColumns() { add(id); add(filename); add(uri); } + }; + FoundTagColumns found_list_columns; Glib::RefPtr<Gtk::ListStore> found_list; - FoundTagColumns freesound_list_columns; + FreesoundColumns freesound_list_columns; Glib::RefPtr<Gtk::ListStore> freesound_list; + Gtk::ProgressBar progress_bar; + public: SoundFileBrowser (Gtk::Window& parent, std::string title, ARDOUR::Session* _s, bool persistent); virtual ~SoundFileBrowser (); @@ -137,13 +149,14 @@ Gtk::Button found_search_btn; Gtk::TreeView found_list_view; - Gtk::Entry freesound_name_entry; - Gtk::Entry freesound_pass_entry; Gtk::Entry freesound_entry; + Gtk::ComboBoxText freesound_sort; + Gtk::SpinButton freesound_page; + Gtk::Button freesound_search_btn; Gtk::TreeView freesound_list_view; - void freesound_search_thread(); + void freesound_search(); protected: bool resetting_ourselves; |
|
New version of patch uploaded, the same as the previous except that the API key is now one I've created for Ardour 3. In fact, I registered ardour3 as a Freesound user and created the API key from that account: I hope that was a sensible thing to do. I hope I'll have a few moments this week to polish some of the other rough edges, but I'm very happy if you want to apply this version in the meanwhile. |
|
committed in rev 10596 |
2011-12-08 22:23
|
freesound-2011-12-08.patch (7,862 bytes)
Index: gtk2_ardour/sfdb_freesound_mootcher.cc =================================================================== --- gtk2_ardour/sfdb_freesound_mootcher.cc (revision 10941) +++ gtk2_ardour/sfdb_freesound_mootcher.cc (working copy) @@ -136,7 +136,7 @@ // Allow connections to time out (without using signals) curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); - curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10); + curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 30); } @@ -291,7 +291,7 @@ }; //------------------------------------------------------------------------ -std::string Mootcher::getAudioFile(std::string originalFileName, std::string ID, std::string audioURL, Gtk::ProgressBar *progress_bar) +std::string Mootcher::getAudioFile(std::string originalFileName, std::string ID, std::string audioURL, SoundFileBrowser *caller) { std::string audioFileName = basePath + "snd/" + ID + "-" + originalFileName; @@ -328,17 +328,20 @@ curl_easy_setopt(curl, CURLOPT_WRITEDATA, theFile); std::cerr << "downloading " << audioFileName << " from " << audioURL << "..." << std::endl; + /* hack to get rid of the barber-pole stripes */ + caller->progress_bar.hide(); + caller->progress_bar.show(); 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, progress_bar); + curl_easy_setopt (curl, CURLOPT_PROGRESSDATA, caller); CURLcode res = curl_easy_perform(curl); fclose(theFile); curl_easy_setopt (curl, CURLOPT_NOPROGRESS, 1); // turn off the progress bar - progress_bar->set_fraction(0.0); - + caller->progress_bar.set_fraction(0.0); + if( res != 0 ) { std::cerr << "curl error " << res << " (" << curl_easy_strerror(res) << ")" << std::endl; remove( audioFileName.c_str() ); @@ -355,14 +358,18 @@ } //--------- -int Mootcher::progress_callback(void *bar, double dltotal, double dlnow, double ultotal, double ulnow) +int Mootcher::progress_callback(void *caller, double dltotal, double dlnow, double ultotal, double ulnow) { +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_stop) { + return -1; + } - Gtk::ProgressBar *progress_bar = (Gtk::ProgressBar *) bar; - progress_bar->set_fraction(dlnow/dltotal); + + sfb->progress_bar.set_fraction(dlnow/dltotal); /* Make sure the progress widget gets updated */ while (Glib::MainContext::get_default()->iteration (false)) { /* do nothing */ Index: gtk2_ardour/sfdb_freesound_mootcher.h =================================================================== --- gtk2_ardour/sfdb_freesound_mootcher.h (revision 10941) +++ gtk2_ardour/sfdb_freesound_mootcher.h (working copy) @@ -23,6 +23,8 @@ #include <gtkmm/progressbar.h> //#include <ctime> +#include "sfdb_ui.h" + #include "curl/curl.h" //--- struct to store XML file @@ -50,7 +52,7 @@ Mootcher(const char *saveLocation); ~Mootcher(); - std::string getAudioFile(std::string originalFileName, std::string ID, std::string audioURL, Gtk::ProgressBar *progress_bar); + std::string getAudioFile(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); private: Index: gtk2_ardour/sfdb_ui.cc =================================================================== --- gtk2_ardour/sfdb_ui.cc (revision 10941) +++ gtk2_ardour/sfdb_ui.cc (working copy) @@ -548,6 +548,8 @@ passbox->pack_start (freesound_search_btn, false, false); passbox->pack_start (progress_bar); + passbox->pack_end (freesound_stop_btn, false, false); + freesound_stop_btn.set_label(_("Stop")); Gtk::ScrolledWindow *scroll = manage(new ScrolledWindow); scroll->add(freesound_list_view); @@ -559,13 +561,14 @@ 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(_("URI") , freesound_list_columns.uri); freesound_list_view.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_list_view_selected)); 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_stop_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_stop_clicked)); notebook.append_page (*vbox, _("Search Freesound")); } #endif @@ -756,12 +759,15 @@ gdk_window_set_cursor (get_window()->gobj(), gdk_cursor_new(GDK_WATCH)); gdk_flush(); - file = theMootcher.getAudioFile(ofn, id, uri, &progress_bar); + freesound_stop = false; + file = theMootcher.getAudioFile(ofn, id, uri, this); gdk_window_set_cursor (get_window()->gobj(), prev_cursor); - chooser.set_filename (file); - set_response_sensitive (RESPONSE_OK, true); + if (file != "") { + chooser.set_filename (file); + set_response_sensitive (RESPONSE_OK, true); + } } else { set_response_sensitive (RESPONSE_OK, false); } @@ -801,7 +807,13 @@ freesound_search(); } +void +SoundFileBrowser::freesound_stop_clicked () +{ + freesound_stop = true; +} + void SoundFileBrowser::freesound_search() { @@ -940,8 +952,11 @@ gdk_window_set_cursor (get_window()->gobj(), gdk_cursor_new(GDK_WATCH)); gdk_flush(); - string str = theMootcher.getAudioFile(ofn, id, uri, &progress_bar); - results.push_back (str); + freesound_stop = false; + string str = theMootcher.getAudioFile(ofn, id, uri, this); + if (str != "") { + results.push_back (str); + } gdk_window_set_cursor (get_window()->gobj(), prev_cursor); Index: gtk2_ardour/sfdb_ui.h =================================================================== --- gtk2_ardour/sfdb_ui.h (revision 10941) +++ gtk2_ardour/sfdb_ui.h (working copy) @@ -26,6 +26,7 @@ #include <sigc++/signal.h> +#include <gtkmm/stock.h> #include <gtkmm/box.h> #include <gtkmm/button.h> #include <gtkmm/checkbutton.h> @@ -36,7 +37,12 @@ #include <gtkmm/frame.h> #include <gtkmm/label.h> #include <gtkmm/textview.h> +#include <gtkmm/table.h> +#include <gtkmm/liststore.h> +#include <gtkmm/spinbutton.h> +#include <gtkmm/notebook.h> + #include "ardour/audiofilesource.h" #include "ardour/session_handle.h" @@ -130,7 +136,7 @@ FreesoundColumns freesound_list_columns; Glib::RefPtr<Gtk::ListStore> freesound_list; - Gtk::ProgressBar progress_bar; + Gtk::Button freesound_stop_btn; public: SoundFileBrowser (Gtk::Window& parent, std::string title, ARDOUR::Session* _s, bool persistent); @@ -155,7 +161,10 @@ Gtk::Button freesound_search_btn; Gtk::TreeView freesound_list_view; + Gtk::ProgressBar progress_bar; + bool freesound_stop; + void freesound_search(); protected: @@ -189,7 +198,8 @@ void freesound_list_view_selected (); void freesound_list_view_activated (const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn*); void freesound_search_clicked (); - + void freesound_stop_clicked (); + void chooser_file_activated (); bool on_audio_filter (const Gtk::FileFilter::Info& filter_info); |
|
Attached a patch (freesound-2011-12-08.patch) to address a (very) few of the outstanding annoyances with this. The patch: * adds a 'Stop' button. * ups the curl timeout to 30 seconds so it now works via my GPRS phone. * clears the progress bar barbershop pole pattern after a sound file download (in a very hackish way: sorry). * removes the display of the URI in the listbox: only the ID and the file name are displayed now. Maybe some other information could be added, e.g. length, sample rate, &c., if anyone thinks this might be useful. |
|
2011-12-08 patched committed in rev 11265 |
|
I'm going to close this bug for now because of the title. I'm sure there are some more issues to be addressed with freesound support, but lets open new bugs for them. |
|
Closing old issues reported by me: these have long since been fixed. |
Date Modified | Username | Field | Change |
---|---|---|---|
2011-03-25 18:28 | colinf | New Issue | |
2011-03-25 18:35 | cth103 | cost | => 0.00 |
2011-03-25 18:35 | cth103 | Target Version | => 3.0-beta1 |
2011-03-25 20:04 | paul | Note Added: 0010413 | |
2011-03-25 20:04 | paul | Status | new => confirmed |
2011-04-18 23:22 | cth103 | Target Version | 3.0-beta1 => 3.X |
2011-11-06 23:52 | colinf | Note Added: 0011923 | |
2011-11-08 18:52 | colinf | File Added: freesound-new-api-10499.patch | |
2011-11-08 19:02 | colinf | Note Added: 0011954 | |
2011-11-08 19:07 | colinf | Note Edited: 0011954 | |
2011-11-08 19:09 | colinf | Note Edited: 0011954 | |
2011-11-09 11:16 | paul | Note Added: 0011959 | |
2011-11-09 11:16 | paul | Status | confirmed => assigned |
2011-11-09 11:16 | paul | Assigned To | => paul |
2011-11-09 12:42 | colinf | Note Added: 0011963 | |
2011-11-09 12:46 | paul | Note Added: 0011964 | |
2011-11-09 15:16 | colinf | Note Added: 0011965 | |
2011-11-10 13:50 | colinf | Note Added: 0011971 | |
2011-11-10 14:01 | paul | Note Added: 0011972 | |
2011-11-14 11:39 | colinf | File Added: freesound-new-api-10577.patch | |
2011-11-14 11:44 | colinf | Note Added: 0011991 | |
2011-11-14 22:08 | paul | Note Added: 0012019 | |
2011-12-08 22:23 | colinf | File Added: freesound-2011-12-08.patch | |
2011-12-08 22:33 | colinf | Note Added: 0012328 | |
2012-01-18 18:43 | paul | Note Added: 0012567 | |
2012-01-20 11:19 | paul | Note Added: 0012590 | |
2012-01-20 11:19 | paul | Status | assigned => resolved |
2012-01-20 11:19 | paul | Resolution | open => fixed |
2015-09-18 15:14 | colinf | Note Added: 0017262 | |
2015-09-18 15:14 | colinf | Status | resolved => closed |