the return of basic FreeSound mootcher functionality, c/o colinf. lots of bugs and workflow issues to still resolve, but good to play with. remember that ardour can't play mp3's

git-svn-id: svn://localhost/ardour2/branches/3.0@10596 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Paul Davis 2011-11-14 22:04:14 +00:00
parent 8171a144e0
commit 1d984b7985
5 changed files with 384 additions and 462 deletions

View file

@ -1,6 +1,7 @@
/* sfdb_freesound_mootcher.cpp ********************************************************************** /* sfdb_freesound_mootcher.cpp **********************************************************************
Adapted for Ardour by Ben Loftis, March 2008 Adapted for Ardour by Ben Loftis, March 2008
Updated to new Freesound API by Colin Fletcher, November 2011
Mootcher 23-8-2005 Mootcher 23-8-2005
@ -43,37 +44,39 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>
#include <iostream>
#include "ardour/audio_library.h" #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) Mootcher::Mootcher(const char *saveLocation)
: curl( NULL ) : curl(curl_easy_init())
, connection( 0 )
{ {
changeWorkingDir(saveLocation); changeWorkingDir(saveLocation);
}; };
//------------------------------------------------------------------------ //------------------------------------------------------------------------
Mootcher:: ~Mootcher() Mootcher:: ~Mootcher()
{ {
remove( "cookiejar.txt" );
} }
//------------------------------------------------------------------------ //------------------------------------------------------------------------
const char* Mootcher::changeWorkingDir(const char *saveLocation) const char* Mootcher::changeWorkingDir(const char *saveLocation)
{ {
basePath = saveLocation; basePath = saveLocation;
#ifdef __WIN32__ #ifdef __WIN32__
std::string replace = "/"; std::string replace = "/";
int pos = (int)basePath.find("\\"); size_t pos = basePath.find("\\");
while( pos != std::string::npos ){ while( pos != std::string::npos ){
basePath.replace(pos, 1, replace); basePath.replace(pos, 1, replace);
pos = (int)basePath.find("\\"); pos = basePath.find("\\");
} }
#endif #endif
// //
int pos2 = basePath.find_last_of("/"); size_t pos2 = basePath.find_last_of("/");
if(basePath.length() != (pos2+1)) basePath += "/"; if(basePath.length() != (pos2+1)) basePath += "/";
// create Freesound directory and sound dir // create Freesound directory and sound dir
@ -91,10 +94,7 @@ size_t Mootcher::WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void
register int realsize = (int)(size * nmemb); register int realsize = (int)(size * nmemb);
struct MemoryStruct *mem = (struct MemoryStruct *)data; struct MemoryStruct *mem = (struct MemoryStruct *)data;
// There might be a realloc() out there that doesn't like mem->memory = (char *)realloc(mem->memory, mem->size + realsize + 1);
// 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);
if (mem->memory) { if (mem->memory) {
memcpy(&(mem->memory[mem->size]), ptr, realsize); memcpy(&(mem->memory[mem->size]), ptr, realsize);
@ -106,11 +106,21 @@ size_t Mootcher::WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void
//------------------------------------------------------------------------ //------------------------------------------------------------------------
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()
@ -120,157 +130,51 @@ void Mootcher::setcUrlOptions()
// some servers don't like requests that are made without a user-agent field, so we provide one // 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"); curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcurl-agent/1.0");
// setup curl error buffer // setup curl error buffer
CURLcode res = curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errorBuffer); 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");
// Allow redirection // Allow redirection
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); 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);
} }
//------------------------------------------------------------------------ std::string Mootcher::doRequest(std::string uri, std::string params)
int Mootcher::doLogin(std::string login, std::string password)
{ {
if(connection==1) std::string result;
return 1;
struct MemoryStruct xml_page; struct MemoryStruct xml_page;
xml_page.memory = NULL; xml_page.memory = NULL;
xml_page.size = 0; 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);
// Do the setup for libcurl
curl = curl_easy_init();
if(curl)
{
setcUrlOptions(); setcUrlOptions();
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *) &xml_page); 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"); // curl_easy_setopt(curl, CURLOPT_HTTPGET, 1);
// use POST for login variables // curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postMessage.c_str());
curl_easy_setopt(curl, CURLOPT_POST, TRUE); // curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, -1);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postMessage.c_str());
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, -1);
// the url to get // the url to get
std::string login_url = "http://www.freesound.org/forum/login.php"; std::string url = base_url + uri + "?";
curl_easy_setopt(curl, CURLOPT_URL, login_url.c_str() ); 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 // perform online request
connection = 1;
CURLcode res = curl_easy_perform(curl); CURLcode res = curl_easy_perform(curl);
if( res != 0 ) { if( res != 0 ) {
toLog("curl login error\n"); std::cerr << "curl error " << res << " (" << curl_easy_strerror(res) << ")" << std::endl;
toLog(curl_easy_strerror(res)); return "";
connection = 0;
}
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)
{
struct MemoryStruct xml_page;
xml_page.memory = NULL;
xml_page.size = 0;
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; result = xml_page.memory;
toLog( result.c_str() );
// free the memory // free the memory
if(xml_page.memory){ if(xml_page.memory){
free( xml_page.memory ); free( xml_page.memory );
@ -278,161 +182,108 @@ std::string Mootcher::searchText(std::string word)
xml_page.size = 0; xml_page.size = 0;
} }
}
}
return result; return result;
}
std::string Mootcher::searchText(std::string query, int page, std::string filter, enum sortMethod sort)
{
std::string params = "";
char buf[24];
if (page > 1) {
snprintf(buf, 23, "p=%d&", page);
params += buf;
}
params += "q=" + query;
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 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"; std::string Mootcher::getSoundResourceFile(std::string ID)
int pos = 0;
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)
{ {
if(curl) { std::string originalSoundURI;
setcUrlOptions();
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&xml_page);
// URL to get
std::string getxml_url = "http://www.freesound.org/samplesViewSingleXML.php?id=";
getxml_url += ID;
curl_easy_setopt(curl, CURLOPT_URL, getxml_url.c_str() );
// 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;
}
}
}
//------------------------------------------------------------------------
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 audioFileName;
std::string filename; std::string xmlFileName;
std::string xml;
std::cerr << "getSoundResourceFile(" << ID << ")" << std::endl;
if(connection != 0) {
// download the xmlfile into xml_page // download the xmlfile into xml_page
GetXml(ID, xml_page); xml = doRequest("/sounds/" + ID, "");
// 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; XMLTree doc;
doc.read_buffer( xml_page.memory ); doc.read_buffer( xml.c_str() );
XMLNode *freesound = doc.root(); XMLNode *freesound = doc.root();
// if the page is not a valid xml document with a 'freesound' root // if the page is not a valid xml document with a 'freesound' root
if (freesound == NULL) { if (freesound == NULL) {
sprintf(message, "getXmlFile: There is no valid root in the xml file"); std::cerr << "getSoundResourceFile: There is no valid root in the xml file" << std::endl;
toLog(message); return "";
} else {
XMLNode *sample = freesound->child("sample");
XMLNode *name = NULL;
XMLNode *filesize = NULL;
if (sample) {
name = sample->child("originalFilename");
filesize = sample->child("filesize");
} }
if (strcmp(doc.root()->name().c_str(), "response") != 0) {
std::cerr << "getSoundResourceFile: root =" << doc.root()->name() << ", != response" << std::endl;
return "";
}
XMLNode *name = freesound->child("original_filename");
XMLNode *filesize = freesound->child("filesize");
// get the file name and size from xml file // get the file name and size from xml file
if (sample && name && filesize) { if (name && filesize) {
audioFileName = name->child("text")->content(); audioFileName = basePath + "snd/" + ID + "-" + name->child("text")->content();
sprintf( message, "getXmlFile: %s needs to be downloaded\n", audioFileName.c_str() );
toLog(message);
length = atoi(filesize->child("text")->content().c_str());
// create new filename with the ID number // create new filename with the ID number
filename = basePath; xmlFileName = basePath;
filename += "snd/"; xmlFileName += "snd/";
filename += sample->property("id")->value(); xmlFileName += freesound->child("id")->child("text")->content();
filename += "-"; xmlFileName += "-";
filename += audioFileName; xmlFileName += name->child("text")->content();
// change the extention into .xml xmlFileName += ".xml";
xmlFileName = changeExtension( filename );
sprintf(message, "getXmlFile: saving XML: %s\n", xmlFileName.c_str() ); // std::cerr << "getSoundResourceFile: saving XML: " << xmlFileName << std::endl;
toLog(message);
// save the xml file to disk // save the xml file to disk
doc.write(xmlFileName.c_str()); doc.write(xmlFileName.c_str());
//store all the tags in the database //store all the tags in the database
XMLNode *tags = sample->child("tags"); XMLNode *tags = freesound->child("tags");
if (tags) { if (tags) {
XMLNodeList children = tags->children(); XMLNodeList children = tags->children();
XMLNodeConstIterator niter; XMLNodeConstIterator niter;
std::vector<std::string> strings; std::vector<std::string> strings;
for (niter = children.begin(); niter != children.end(); ++niter) { for (niter = children.begin(); niter != children.end(); ++niter) {
XMLNode *node = *niter; XMLNode *node = *niter;
if( strcmp( node->name().c_str(), "tag") == 0 ) { if( strcmp( node->name().c_str(), "resource") == 0 ) {
XMLNode *text = node->child("text"); XMLNode *text = node->child("text");
if (text) strings.push_back(text->content()); if (text) {
// std::cerr << "tag: " << text->content() << std::endl;
strings.push_back(text->content());
} }
} }
ARDOUR::Library->set_tags (std::string("//")+filename, strings); }
ARDOUR::Library->set_tags (std::string("//")+audioFileName, strings);
ARDOUR::Library->save_changes (); ARDOUR::Library->save_changes ();
} }
} }
// clear the memory
if(xml_page.memory){
free( xml_page.memory );
xml_page.memory = NULL;
xml_page.size = 0;
}
return audioFileName; return audioFileName;
} }
}
}
else {
return audioFileName;
}
}
int audioFileWrite(void *buffer, size_t size, size_t nmemb, void *file) int audioFileWrite(void *buffer, size_t size, size_t nmemb, void *file)
{ {
@ -440,39 +291,25 @@ int audioFileWrite(void *buffer, size_t size, size_t nmemb, void *file)
}; };
//------------------------------------------------------------------------ //------------------------------------------------------------------------
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 != "" ){
// create new filename with the ID number
audioFileName += basePath;
audioFileName += "snd/";
audioFileName += ID;
audioFileName += "-";
audioFileName += name;
//check to see if audio file already exists //check to see if audio file already exists
FILE *testFile = fopen(audioFileName.c_str(), "r"); FILE *testFile = fopen(audioFileName.c_str(), "r");
if (testFile) { //TODO: should also check length to see if file is complete if (testFile) {
fseek (testFile , 0 , SEEK_END); fseek (testFile , 0 , SEEK_END);
if (ftell (testFile) == length) { if (ftell (testFile) > 256) {
sprintf(message, "%s already exists\n", audioFileName.c_str() ); std::cerr << "audio file " << audioFileName << " already exists" << std::endl;
toLog(message);
fclose (testFile); fclose (testFile);
return audioFileName; return audioFileName;
} else {
remove( audioFileName.c_str() ); //file was not correct length, delete it and try again
}
} }
// else file was small, probably an error, delete it and try again
fclose(testFile);
remove( audioFileName.c_str() );
}
//now download the actual file //now download the actual file
if (curl) { if (curl) {
@ -480,34 +317,37 @@ std::string Mootcher::getFile(std::string ID)
FILE* theFile; FILE* theFile;
theFile = fopen( audioFileName.c_str(), "wb" ); theFile = fopen( audioFileName.c_str(), "wb" );
// create the download url, this url will also update the download statics on the site if (theFile) {
std::string audioURL;
audioURL += "http://www.freesound.org/samplesDownload.php?id="; // create the download url
audioURL += ID; audioURL += "?api_key=" + api_key;
setcUrlOptions(); setcUrlOptions();
curl_easy_setopt(curl, CURLOPT_URL, audioURL.c_str() ); curl_easy_setopt(curl, CURLOPT_URL, audioURL.c_str() );
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, audioFileWrite); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, audioFileWrite);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, theFile); curl_easy_setopt(curl, CURLOPT_WRITEDATA, theFile);
connection = 1; std::cerr << "downloading " << audioFileName << " from " << audioURL << "..." << std::endl;
CURLcode res = curl_easy_perform(curl);
if( res != 0 ) {
toLog("curl login error\n");
toLog(curl_easy_strerror(res));
connection = 0;
}
fclose(theFile); curl_easy_setopt (curl, CURLOPT_NOPROGRESS, 0); // turn on the progress bar
}
/*
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_PROGRESSFUNCTION, progress_callback);
curl_easy_setopt (curl, CURLOPT_PROGRESSDATA, &bar); curl_easy_setopt (curl, CURLOPT_PROGRESSDATA, progress_bar);
*/
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);
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);
}
} }
} }
@ -517,8 +357,17 @@ std::string Mootcher::getFile(std::string ID)
//--------- //---------
int Mootcher::progress_callback(void *bar, double dltotal, double dlnow, double ultotal, double ulnow) int Mootcher::progress_callback(void *bar, double dltotal, double dlnow, double ultotal, double ulnow)
{ {
struct dlprocess *lbar = (struct dlprocess *) bar;
lbar->dltotalMoo = dltotal; //XXX I hope it's OK to do GTK things in this callback. Otherwise
lbar->dlnowMoo = dlnow; // 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; return 0;
} }

View file

@ -1,6 +1,7 @@
/*sfdb_freesound_mootcher.h**************************************************************************** /*sfdb_freesound_mootcher.h****************************************************************************
Adapted for Ardour by Ben Loftis, March 2008 Adapted for Ardour by Ben Loftis, March 2008
Updated to new Freesound API by Colin Fletcher, November 2011
Mootcher Online Access to thefreesoundproject website Mootcher Online Access to thefreesoundproject website
http://freesound.iua.upf.edu/ http://freesound.iua.upf.edu/
@ -19,60 +20,55 @@
#include <string> #include <string>
#include <sstream> #include <sstream>
#include <vector> #include <vector>
#include <gtkmm/progressbar.h>
//#include <ctime> //#include <ctime>
#include "curl/curl.h" #include "curl/curl.h"
// mootcher version
#define ___VERSION___ 1.3
//--- struct to store XML file //--- struct to store XML file
struct MemoryStruct { struct MemoryStruct {
char *memory; char *memory;
size_t size; size_t size;
}; };
//--- for download process viewing enum sortMethod {
struct dlprocess { sort_none, // no sort
double dltotalMoo; sort_duration_desc, // Sort by the duration of the sounds, longest sounds first.
double dlnowMoo; 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 class Mootcher
{ {
public: public:
Mootcher(const char *saveLocation); Mootcher(const char *saveLocation);
~Mootcher(); ~Mootcher();
int doLogin(std::string login, std::string password); std::string getAudioFile(std::string originalFileName, std::string ID, std::string audioURL, Gtk::ProgressBar *progress_bar);
std::string getFile(std::string ID); std::string searchText(std::string query, int page, std::string filter, enum sortMethod sort);
std::string searchText(std::string word);
struct dlprocess bar;
private: private:
const char* changeWorkingDir(const char *saveLocation); const char* changeWorkingDir(const char *saveLocation);
std::string getXmlFile(std::string ID, int &length); std::string doRequest(std::string uri, std::string params);
void GetXml(std::string ID, struct MemoryStruct &xml_page);
std::string changeExtension(std::string filename);
void toLog(std::string input);
void setcUrlOptions(); void setcUrlOptions();
static size_t WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data); 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 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; CURL *curl;
char errorBuffer[CURL_ERROR_SIZE]; // storage for cUrl error message 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 basePath;
std::string xmlLocation; std::string xmlLocation;
}; };

View file

@ -421,7 +421,7 @@ SoundFileBrowser::SoundFileBrowser (Gtk::Window& parent, string title, ARDOUR::S
preview (persistent), preview (persistent),
found_search_btn (_("Search")), found_search_btn (_("Search")),
found_list_view (found_list), found_list_view (found_list),
freesound_search_btn (_("Start Downloading")), freesound_search_btn (_("Search")),
freesound_list_view (freesound_list) freesound_list_view (freesound_list)
{ {
resetting_ourselves = false; resetting_ourselves = false;
@ -515,19 +515,39 @@ SoundFileBrowser::SoundFileBrowser (Gtk::Window& parent, string title, ARDOUR::S
passbox->set_border_width (12); passbox->set_border_width (12);
passbox->set_spacing (6); passbox->set_spacing (6);
label = manage (new Label);
label->set_text (_("User:"));
passbox->pack_start (*label, false, false);
passbox->pack_start (freesound_name_entry);
label = manage (new Label);
label->set_text (_("Password:"));
passbox->pack_start (*label, false, false);
passbox->pack_start (freesound_pass_entry);
label = manage (new Label); label = manage (new Label);
label->set_text (_("Tags:")); label->set_text (_("Tags:"));
passbox->pack_start (*label, false, false); passbox->pack_start (*label, false, false);
passbox->pack_start (freesound_entry, false, false); passbox->pack_start (freesound_entry, false, false);
label = manage (new Label);
label->set_text (_("Sort:"));
passbox->pack_start (*label, false, false);
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 (_("Page:"));
passbox->pack_start (*label, 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 (freesound_search_btn, false, false);
passbox->pack_start (progress_bar);
Gtk::ScrolledWindow *scroll = manage(new ScrolledWindow); Gtk::ScrolledWindow *scroll = manage(new ScrolledWindow);
scroll->add(freesound_list_view); scroll->add(freesound_list_view);
@ -537,12 +557,12 @@ SoundFileBrowser::SoundFileBrowser (Gtk::Window& parent, string title, ARDOUR::S
vbox->pack_start (*passbox, PACK_SHRINK); 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(_("ID") , freesound_list_columns.id);
freesound_list_view.append_column(_("Filename"), freesound_list_columns.filename);
freesound_list_view.append_column(_("Paths"), freesound_list_columns.pathname); 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()->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_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_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_entry.signal_activate().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_search_clicked));
@ -712,13 +732,33 @@ SoundFileBrowser::freesound_list_view_selected ()
if (!reset_options ()) { if (!reset_options ()) {
set_response_sensitive (RESPONSE_OK, false); set_response_sensitive (RESPONSE_OK, false);
} else { } else {
string path;
path = Glib::get_home_dir();
path += "/Freesound/";
Mootcher theMootcher(path.c_str()); // XXX should be a member of SoundFileBrowser
string file; string file;
TreeView::Selection::ListHandle_Path rows = freesound_list_view.get_selection()->get_selected_rows (); TreeView::Selection::ListHandle_Path rows = freesound_list_view.get_selection()->get_selected_rows ();
if (!rows.empty()) { if (!rows.empty()) {
TreeIter iter = freesound_list->get_iter(*rows.begin()); 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); chooser.set_filename (file);
set_response_sensitive (RESPONSE_OK, true); set_response_sensitive (RESPONSE_OK, true);
} else { } else {
@ -753,43 +793,16 @@ SoundFileBrowser::found_search_clicked ()
} }
} }
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 void
SoundFileBrowser::freesound_search_clicked () SoundFileBrowser::freesound_search_clicked ()
{ {
if (canceling) //already canceling, button does nothing freesound_search();
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);
}
}
void 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 #ifdef FREESOUND
freesound_list->clear(); freesound_list->clear();
@ -798,48 +811,81 @@ SoundFileBrowser::freesound_search_thread()
path += "/Freesound/"; path += "/Freesound/";
Mootcher theMootcher(path.c_str()); 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 (); 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
);
gdk_window_set_cursor (get_window()->gobj(), prev_cursor);
XMLTree doc; XMLTree doc;
doc.read_buffer( theString ); doc.read_buffer( theString );
XMLNode *root = doc.root(); XMLNode *root = doc.root();
if (root==NULL) return; if (!root) {
cerr << "no root XML node!" << endl;
return;
}
if ( strcmp(root->name().c_str(), "freesound") == 0) { if ( strcmp(root->name().c_str(), "response") != 0) {
cerr << "root node name == " << root->name() << ", != \"response\"!" << endl;
return;
}
XMLNode *node = 0; XMLNode *sounds_root = root->child("sounds");
XMLNodeList children = root->children();
if (!sounds_root) {
cerr << "no child node \"sounds\" found!" << endl;
return;
}
XMLNodeList sounds = sounds_root->children();
XMLNodeConstIterator niter; XMLNodeConstIterator niter;
for (niter = children.begin(); niter != children.end() && !canceling; ++niter) { XMLNode *node;
for (niter = sounds.begin(); niter != sounds.end(); ++niter) {
node = *niter; node = *niter;
if( strcmp( node->name().c_str(), "sample") == 0 ){ if( strcmp( node->name().c_str(), "resource") != 0 ){
XMLProperty *prop=node->property ("id"); cerr << "node->name()=" << node->name() << ",!= \"resource\"!" << endl;
string filename = theMootcher.getFile( prop->value().c_str() ); continue; // return;
if ( filename != "" ) { }
// 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::iterator new_row = freesound_list->append();
TreeModel::Row row = *new_row; TreeModel::Row row = *new_row;
string path = Glib::filename_from_uri (string ("file:") + filename);
row[freesound_list_columns.pathname] = path;
}
}
}
}
}
searching = false; row[freesound_list_columns.id ] = id;
canceling = false; row[freesound_list_columns.uri ] = uri;
freesound_search_btn.set_label(_("Start Downloading")); row[freesound_list_columns.filename] = ofn;
#endif
#endif
} }
}
#endif
}
vector<string> vector<string>
SoundFileBrowser::get_paths () SoundFileBrowser::get_paths ()
@ -874,12 +920,29 @@ SoundFileBrowser::get_paths ()
typedef TreeView::Selection::ListHandle_Path ListPath; 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 (); ListPath rows = freesound_list_view.get_selection()->get_selected_rows ();
for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) { for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
TreeIter iter = freesound_list->get_iter(*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); results.push_back (str);
gdk_window_set_cursor (get_window()->gobj(), prev_cursor);
} }
} }

View file

@ -114,12 +114,24 @@ class SoundFileBrowser : public ArdourDialog
FoundTagColumns() { add(pathname); } 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; FoundTagColumns found_list_columns;
Glib::RefPtr<Gtk::ListStore> found_list; Glib::RefPtr<Gtk::ListStore> found_list;
FoundTagColumns freesound_list_columns; FreesoundColumns freesound_list_columns;
Glib::RefPtr<Gtk::ListStore> freesound_list; Glib::RefPtr<Gtk::ListStore> freesound_list;
Gtk::ProgressBar progress_bar;
public: public:
SoundFileBrowser (Gtk::Window& parent, std::string title, ARDOUR::Session* _s, bool persistent); SoundFileBrowser (Gtk::Window& parent, std::string title, ARDOUR::Session* _s, bool persistent);
virtual ~SoundFileBrowser (); virtual ~SoundFileBrowser ();
@ -137,13 +149,14 @@ class SoundFileBrowser : public ArdourDialog
Gtk::Button found_search_btn; Gtk::Button found_search_btn;
Gtk::TreeView found_list_view; Gtk::TreeView found_list_view;
Gtk::Entry freesound_name_entry;
Gtk::Entry freesound_pass_entry;
Gtk::Entry freesound_entry; Gtk::Entry freesound_entry;
Gtk::ComboBoxText freesound_sort;
Gtk::SpinButton freesound_page;
Gtk::Button freesound_search_btn; Gtk::Button freesound_search_btn;
Gtk::TreeView freesound_list_view; Gtk::TreeView freesound_list_view;
void freesound_search_thread(); void freesound_search();
protected: protected:
bool resetting_ourselves; bool resetting_ourselves;

View file

@ -389,6 +389,7 @@ def build(bld):
if bld.is_defined('FREESOUND'): if bld.is_defined('FREESOUND'):
obj.source += [ 'sfdb_freesound_mootcher.cc' ] obj.source += [ 'sfdb_freesound_mootcher.cc' ]
obj.defines += [ 'FREESOUND' ]
if bld.is_defined('VST_SUPPORT'): if bld.is_defined('VST_SUPPORT'):
obj.source += [ 'vst_pluginui.cc' ] obj.source += [ 'vst_pluginui.cc' ]