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;
