diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/Makefile.am | 1 | ||||
| -rw-r--r-- | src/audiofile.cc | 17 | ||||
| -rw-r--r-- | src/audiofile.h | 3 | ||||
| -rw-r--r-- | src/dgxmlparser.cc | 166 | ||||
| -rw-r--r-- | src/dgxmlparser.h | 10 | ||||
| -rw-r--r-- | src/domloader.cc | 10 | ||||
| -rw-r--r-- | src/domloader.h | 4 | ||||
| -rw-r--r-- | src/drumkitloader.cc | 33 | ||||
| -rw-r--r-- | src/drumkitloader.h | 2 | ||||
| -rw-r--r-- | src/logger.h | 38 | ||||
| -rw-r--r-- | src/powerlist.cc | 2 | ||||
| -rw-r--r-- | src/settings.h | 10 | 
12 files changed, 233 insertions, 63 deletions
| diff --git a/src/Makefile.am b/src/Makefile.am index b85e1d3..56d44ef 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -76,6 +76,7 @@ EXTRA_DIST = \  	inputprocessor.h \  	instrument.h \  	latencyfilter.h \ +	logger.h \  	midimapparser.h \  	midimapper.h \  	nolocale.h \ diff --git a/src/audiofile.cc b/src/audiofile.cc index c2c5cf9..2d61eb5 100644 --- a/src/audiofile.cc +++ b/src/audiofile.cc @@ -73,7 +73,7 @@ void AudioFile::unload()  #define BUFFER_SIZE 4096 -void AudioFile::load(std::size_t sample_limit) +void AudioFile::load(LogFunction logger, std::size_t sample_limit)  {  	// Make sure we don't unload the object while loading it...  	std::lock_guard<std::mutex> guard(mutex); @@ -89,12 +89,22 @@ void AudioFile::load(std::size_t sample_limit)  	{  		ERR(audiofile,"SNDFILE Error (%s): %s\n",  		    filename.c_str(), sf_strerror(fh)); +		if(logger) +		{ +			logger(LogLevel::Warning, "Could not load '" + filename + +			       "': " + sf_strerror(fh)); +		}  		return;  	}  	if(sf_info.channels < 1)  	{  		// This should never happen but lets check just in case. +		if(logger) +		{ +			logger(LogLevel::Warning, "Could not load '" + filename + +			       "': no audio channels available."); +		}  		return;  	} @@ -116,6 +126,11 @@ void AudioFile::load(std::size_t sample_limit)  		// check filechannel exists  		if(filechannel >= (std::size_t)sf_info.channels)  		{ +			if(logger) +			{ +				logger(LogLevel::Warning, "Audio file '" + filename + +				       "' does no have " + std::to_string(filechannel + 1) + " channels."); +			}  			filechannel = sf_info.channels - 1;  		} diff --git a/src/audiofile.h b/src/audiofile.h index 5a5cc3a..e20d91f 100644 --- a/src/audiofile.h +++ b/src/audiofile.h @@ -36,6 +36,7 @@  #include "audio.h"  #include "channel.h" +#include "logger.h"  class InstrumentChannel; @@ -46,7 +47,7 @@ public:  	          InstrumentChannel* instrument_channel = nullptr);  	~AudioFile(); -	void load(std::size_t sample_limit = std::numeric_limits<std::size_t>::max()); +	void load(LogFunction logger, std::size_t sample_limit = std::numeric_limits<std::size_t>::max());  	void unload();  	bool isLoaded() const; diff --git a/src/dgxmlparser.cc b/src/dgxmlparser.cc index ae0842a..7f62a64 100644 --- a/src/dgxmlparser.cc +++ b/src/dgxmlparser.cc @@ -33,16 +33,34 @@  #include "nolocale.h" -bool probeDrumkitFile(const std::string& filename) +static int getLineNumberFromOffset(const std::string& filename, ptrdiff_t offset) +{ +	FILE* fp = fopen(filename.data(), "rt"); +	if(!fp) +	{ +		return 0; +	} + +	int lineno{1}; +	char c = 0; +	while((c = fgetc(fp)) != EOF && offset--) +	{ +		lineno += c == '\n' ? 1 : 0; +	} +	fclose(fp); +	return lineno; +} + +bool probeDrumkitFile(const std::string& filename, LogFunction logger)  {  	DrumkitDOM d; -	return parseDrumkitFile(filename, d); +	return parseDrumkitFile(filename, d, logger);  } -bool probeInstrumentFile(const std::string& filename) +bool probeInstrumentFile(const std::string& filename, LogFunction logger)  {  	InstrumentDOM d; -	return parseInstrumentFile(filename, d); +	return parseInstrumentFile(filename, d, logger);  }  static bool assign(double& dest, const std::string& val) @@ -77,7 +95,7 @@ static bool assign(main_state_t& dest, const std::string& val)  }  template<typename T> -static bool attrcpy(T& dest, const pugi::xml_node& src, const std::string& attr, bool opt = false) +static bool attrcpy(T& dest, const pugi::xml_node& src, const std::string& attr, LogFunction logger, const std::string& filename, bool opt = false)  {  	const char* val = src.attribute(attr.c_str()).as_string(nullptr);  	if(!val) @@ -86,6 +104,12 @@ static bool attrcpy(T& dest, const pugi::xml_node& src, const std::string& attr,  		{  			ERR(dgxmlparser, "Attribute %s not found in %s, offset %d\n",  			    attr.data(), src.path().data(), (int)src.offset_debug()); +			if(logger) +			{ +				auto lineno = getLineNumberFromOffset(filename, src.offset_debug()); +				logger(LogLevel::Error, "Missing attribute '" + attr + +				       "' at line " + std::to_string(lineno)); +			}  		}  		return opt;  	} @@ -94,6 +118,12 @@ static bool attrcpy(T& dest, const pugi::xml_node& src, const std::string& attr,  	{  		ERR(dgxmlparser, "Attribute %s could not be assigned, offset %d\n",  		    attr.data(), (int)src.offset_debug()); +		if(logger) +		{ +			auto lineno = getLineNumberFromOffset(filename, src.offset_debug()); +			logger(LogLevel::Error, "Attribute '" + attr + +			       "' could not be assigned at line " + std::to_string(lineno)); +		}  		return false;  	} @@ -101,7 +131,7 @@ static bool attrcpy(T& dest, const pugi::xml_node& src, const std::string& attr,  }  template<typename T> -static bool nodecpy(T& dest, const pugi::xml_node& src, const std::string& node, bool opt = false) +static bool nodecpy(T& dest, const pugi::xml_node& src, const std::string& node, LogFunction logger, const std::string& filename, bool opt = false)  {  	auto val = src.child(node.c_str());  	if(val == pugi::xml_node()) @@ -109,7 +139,13 @@ static bool nodecpy(T& dest, const pugi::xml_node& src, const std::string& node,  		if(!opt)  		{  			ERR(dgxmlparser, "Node %s not found in %s, offset %d\n", -			    node.data(), src.path().data(), (int)src.offset_debug()); +			    node.data(), filename.data(), (int)src.offset_debug()); +			if(logger) +			{ +				auto lineno = getLineNumberFromOffset(filename, src.offset_debug()); +				logger(LogLevel::Error, "Node '" + node + +				       "' not found at line " + std::to_string(lineno)); +			}  		}  		return opt;  	} @@ -118,16 +154,27 @@ static bool nodecpy(T& dest, const pugi::xml_node& src, const std::string& node,  	{  		ERR(dgxmlparser, "Attribute %s could not be assigned, offset %d\n",  		    node.data(), (int)src.offset_debug()); +		if(logger) +		{ +			auto lineno = getLineNumberFromOffset(filename, src.offset_debug()); +			logger(LogLevel::Error, "Node '" + node + +			       "' could not be assigned at line " + std::to_string(lineno)); +		}  		return false;  	}  	return true;  } -bool parseDrumkitFile(const std::string& filename, DrumkitDOM& dom) +bool parseDrumkitFile(const std::string& filename, DrumkitDOM& dom, LogFunction logger)  {  	bool res = true; +	if(logger) +	{ +		logger(LogLevel::Info, "Loading " + filename); +	} +  	pugi::xml_document doc;  	pugi::xml_parse_result result = doc.load_file(filename.c_str());  	res &= !result.status; @@ -135,49 +182,56 @@ bool parseDrumkitFile(const std::string& filename, DrumkitDOM& dom)  	{  		ERR(dgxmlparser, "XML parse error: '%s' %d", filename.data(),  		    (int) result.offset); +		if(logger) +		{ +			auto lineno = getLineNumberFromOffset(filename, result.offset); +			logger(LogLevel::Error, "XML parse error in '" + filename + +			       "': " + result.description() + " at line " + +			       std::to_string(lineno)); +		}  		return false;  	}  	pugi::xml_node drumkit = doc.child("drumkit");  	dom.version = "1.0"; -	res &= attrcpy(dom.version, drumkit, "version", true); +	res &= attrcpy(dom.version, drumkit, "version", logger, filename, true);  	dom.samplerate = 44100.0; -	res &= attrcpy(dom.samplerate, drumkit, "samplerate", true); +	res &= attrcpy(dom.samplerate, drumkit, "samplerate", logger, filename, true);  	// Use the old name and description attributes on the drumkit node as fallback -	res &= attrcpy(dom.metadata.title, drumkit, "name", true); -	res &= attrcpy(dom.metadata.description, drumkit, "description", true); +	res &= attrcpy(dom.metadata.title, drumkit, "name", logger, filename, true); +	res &= attrcpy(dom.metadata.description, drumkit, "description", logger, filename, true);  	pugi::xml_node metadata = drumkit.child("metadata");  	if(metadata != pugi::xml_node())  	{  		auto& meta = dom.metadata; -		res &= nodecpy(meta.version, metadata, "version", true); -		res &= nodecpy(meta.title, metadata, "title", true); +		res &= nodecpy(meta.version, metadata, "version", logger, filename, true); +		res &= nodecpy(meta.title, metadata, "title", logger, filename, true);  		pugi::xml_node logo = metadata.child("logo");  		if(logo != pugi::xml_node())  		{ -			res &= attrcpy(meta.logo, logo, "src", true); +			res &= attrcpy(meta.logo, logo, "src", logger, filename, true);  		} -		res &= nodecpy(meta.description, metadata, "description", true); -		res &= nodecpy(meta.license, metadata, "license", true); -		res &= nodecpy(meta.notes, metadata, "notes", true); -		res &= nodecpy(meta.author, metadata, "author", true); -		res &= nodecpy(meta.email, metadata, "email", true); -		res &= nodecpy(meta.website, metadata, "website", true); +		res &= nodecpy(meta.description, metadata, "description", logger, filename, true); +		res &= nodecpy(meta.license, metadata, "license", logger, filename, true); +		res &= nodecpy(meta.notes, metadata, "notes", logger, filename, true); +		res &= nodecpy(meta.author, metadata, "author", logger, filename, true); +		res &= nodecpy(meta.email, metadata, "email", logger, filename, true); +		res &= nodecpy(meta.website, metadata, "website", logger, filename, true);  		pugi::xml_node image = metadata.child("image");  		if(image != pugi::xml_node())  		{ -			res &= attrcpy(meta.image, image, "src", true); -			res &= attrcpy(meta.image_map, image, "map", true); +			res &= attrcpy(meta.image, image, "src", logger, filename, true); +			res &= attrcpy(meta.image_map, image, "map", logger, filename, true);  			for(auto clickmap : image.children("clickmap"))  			{  				meta.clickmaps.emplace_back();  				res &= attrcpy(meta.clickmaps.back().instrument, -				               clickmap, "instrument", true); +				               clickmap, "instrument", logger, filename, true);  				res &= attrcpy(meta.clickmaps.back().colour, -				               clickmap, "colour", true); +				               clickmap, "colour", logger, filename, true);  			}  		}  	} @@ -186,7 +240,7 @@ bool parseDrumkitFile(const std::string& filename, DrumkitDOM& dom)  	for(pugi::xml_node channel: channels.children("channel"))  	{  		dom.channels.emplace_back(); -		res &= attrcpy(dom.channels.back().name, channel, "name"); +		res &= attrcpy(dom.channels.back().name, channel, "name", logger, filename);  	}  	pugi::xml_node instruments = doc.child("drumkit").child("instruments"); @@ -194,18 +248,18 @@ bool parseDrumkitFile(const std::string& filename, DrumkitDOM& dom)  	{  		dom.instruments.emplace_back();  		auto& instrument_ref = dom.instruments.back(); -		res &= attrcpy(instrument_ref.name, instrument, "name"); -		res &= attrcpy(instrument_ref.file, instrument, "file"); -		res &= attrcpy(instrument_ref.group, instrument, "group", true); +		res &= attrcpy(instrument_ref.name, instrument, "name", logger, filename); +		res &= attrcpy(instrument_ref.file, instrument, "file", logger, filename); +		res &= attrcpy(instrument_ref.group, instrument, "group", logger, filename, true);  		for(pugi::xml_node cmap: instrument.children("channelmap"))  		{  			instrument_ref.channel_map.emplace_back();  			auto& channel_map_ref = instrument_ref.channel_map.back(); -			res &= attrcpy(channel_map_ref.in, cmap, "in"); -			res &= attrcpy(channel_map_ref.out, cmap, "out"); +			res &= attrcpy(channel_map_ref.in, cmap, "in", logger, filename); +			res &= attrcpy(channel_map_ref.out, cmap, "out", logger, filename);  			channel_map_ref.main = main_state_t::unset; -			res &= attrcpy(channel_map_ref.main, cmap, "main", true); +			res &= attrcpy(channel_map_ref.main, cmap, "main", logger, filename, true);  		}  		auto num_chokes = std::distance(instrument.children("chokes").begin(), @@ -223,9 +277,9 @@ bool parseDrumkitFile(const std::string& filename, DrumkitDOM& dom)  			{  				instrument_ref.chokes.emplace_back();  				auto& choke_ref = instrument_ref.chokes.back(); -				res &= attrcpy(choke_ref.instrument, choke, "instrument"); +				res &= attrcpy(choke_ref.instrument, choke, "instrument", logger, filename);  				choke_ref.choketime = 68; // default to 68 ms -				res &= attrcpy(choke_ref.choketime, choke, "choketime", true); +				res &= attrcpy(choke_ref.choketime, choke, "choketime", logger, filename, true);  			}  		}  	} @@ -233,32 +287,44 @@ bool parseDrumkitFile(const std::string& filename, DrumkitDOM& dom)  	return res;  } -bool parseInstrumentFile(const std::string& filename, InstrumentDOM& dom) +bool parseInstrumentFile(const std::string& filename, InstrumentDOM& dom, LogFunction logger)  {  	bool res = true; +	if(logger) +	{ +		logger(LogLevel::Info, "Loading " + filename); +	} +  	pugi::xml_document doc;  	pugi::xml_parse_result result = doc.load_file(filename.data());  	res &= !result.status;  	if(!res)  	{ -		ERR(dgxmlparser, "XML parse error: '%s'", filename.data()); +		WARN(dgxmlparser, "XML parse error: '%s'", filename.data()); +		if(logger) +		{ +			auto lineno = getLineNumberFromOffset(filename, result.offset); +			logger(LogLevel::Warning, "XML parse error in '" + filename + +			       "': " + result.description() + " at line " + +			       std::to_string(lineno)); +		}  	}  	//TODO: handle version  	pugi::xml_node instrument = doc.child("instrument"); -	res &= attrcpy(dom.name, instrument, "name"); +	res &= attrcpy(dom.name, instrument, "name", logger, filename);  	dom.version = "1.0"; -	res &= attrcpy(dom.version, instrument, "version", true); -	res &= attrcpy(dom.description, instrument, "description", true); +	res &= attrcpy(dom.version, instrument, "version", logger, filename, true); +	res &= attrcpy(dom.description, instrument, "description", logger, filename, true);  	pugi::xml_node channels = instrument.child("channels");  	for(pugi::xml_node channel : channels.children("channel"))  	{  		dom.instrument_channels.emplace_back(); -		res &= attrcpy(dom.instrument_channels.back().name, channel, "name"); +		res &= attrcpy(dom.instrument_channels.back().name, channel, "name", logger, filename);  		dom.instrument_channels.back().main = main_state_t::unset; -		res &= attrcpy(dom.instrument_channels.back().main, channel, "main", true); +		res &= attrcpy(dom.instrument_channels.back().main, channel, "main", logger, filename, true);  	}  	INFO(dgxmlparser, "XML version: %s\n", dom.version.data()); @@ -267,7 +333,7 @@ bool parseInstrumentFile(const std::string& filename, InstrumentDOM& dom)  	for(pugi::xml_node sample: samples.children("sample"))  	{  		dom.samples.emplace_back(); -		res &= attrcpy(dom.samples.back().name, sample, "name"); +		res &= attrcpy(dom.samples.back().name, sample, "name", logger, filename);  		// Power only part of >= v2.0 instruments.  		if(dom.version == "1.0") @@ -276,20 +342,20 @@ bool parseInstrumentFile(const std::string& filename, InstrumentDOM& dom)  		}  		else  		{ -			res &= attrcpy(dom.samples.back().power, sample, "power"); +			res &= attrcpy(dom.samples.back().power, sample, "power", logger, filename);  		}  		for(pugi::xml_node audiofile: sample.children("audiofile"))  		{  			dom.samples.back().audiofiles.emplace_back();  			res &= attrcpy(dom.samples.back().audiofiles.back().instrument_channel, -			               audiofile, "channel"); +			               audiofile, "channel", logger, filename);  			res &= attrcpy(dom.samples.back().audiofiles.back().file, -				               audiofile, "file"); +				               audiofile, "file", logger, filename);  			// Defaults to channel 1 in mono (1-based)  			dom.samples.back().audiofiles.back().filechannel = 1;  			res &= attrcpy(dom.samples.back().audiofiles.back().filechannel, -			               audiofile, "filechannel", true); +			               audiofile, "filechannel", logger, filename, true);  		}  	} @@ -301,14 +367,14 @@ bool parseInstrumentFile(const std::string& filename, InstrumentDOM& dom)  		{  			dom.velocities.emplace_back(); -			res &= attrcpy(dom.velocities.back().lower, velocity, "lower"); -			res &= attrcpy(dom.velocities.back().upper, velocity, "upper"); +			res &= attrcpy(dom.velocities.back().lower, velocity, "lower", logger, filename); +			res &= attrcpy(dom.velocities.back().upper, velocity, "upper", logger, filename);  			for(auto sampleref : velocity.children("sampleref"))  			{  				dom.velocities.back().samplerefs.emplace_back();  				auto& sref = dom.velocities.back().samplerefs.back(); -				res &= attrcpy(sref.probability, sampleref, "probability"); -				res &= attrcpy(sref.name, sampleref, "name"); +				res &= attrcpy(sref.probability, sampleref, "probability", logger, filename); +				res &= attrcpy(sref.name, sampleref, "name", logger, filename);  			}  		}  	} diff --git a/src/dgxmlparser.h b/src/dgxmlparser.h index 1bc580d..21d045b 100644 --- a/src/dgxmlparser.h +++ b/src/dgxmlparser.h @@ -27,11 +27,13 @@  #pragma once  #include <string> +#include <functional>  #include "DGDOM.h" +#include "logger.h" -bool probeDrumkitFile(const std::string& filename); -bool probeInstrumentFile(const std::string& filename); +bool probeDrumkitFile(const std::string& filename, LogFunction logger = nullptr); +bool probeInstrumentFile(const std::string& filename, LogFunction logger = nullptr); -bool parseDrumkitFile(const std::string& filename, DrumkitDOM& dom); -bool parseInstrumentFile(const std::string& filename, InstrumentDOM& dom); +bool parseDrumkitFile(const std::string& filename, DrumkitDOM& dom, LogFunction logger = nullptr); +bool parseInstrumentFile(const std::string& filename, InstrumentDOM& dom, LogFunction logger = nullptr); diff --git a/src/domloader.cc b/src/domloader.cc index 0e06239..a718ade 100644 --- a/src/domloader.cc +++ b/src/domloader.cc @@ -52,7 +52,7 @@ DOMLoader::DOMLoader(Settings& settings, Random& random)  bool DOMLoader::loadDom(const std::string& basepath,                          const DrumkitDOM& dom,                          const std::vector<InstrumentDOM>& instrumentdoms, -                        DrumKit& drumkit) +                        DrumKit& drumkit, LogFunction logger)  {  	settings.has_bleed_control.store(false); @@ -165,6 +165,9 @@ bool DOMLoader::loadDom(const std::string& basepath,  				{  					ERR(kitparser, "Missing channel '%s' in instrument '%s'\n",  					    instrument_channel.name.c_str(), instrument->getName().c_str()); +					logger(LogLevel::Warning, "Missing channel '" + +					       instrument_channel.name + "' in the '" + +					       instrument->getName() + "' instrument.");  				}  			} @@ -191,6 +194,9 @@ bool DOMLoader::loadDom(const std::string& basepath,  							ERR(kitparser,  							    "Missing sample '%s' from sampleref in instrument '%s'\n",  							    sampleref.name.data(), instrument->getName().data()); +							logger(LogLevel::Warning, "Missing sample '" + +							       sampleref.name + "' in the '" + +							       instrument->getName() + "' instrument.");  							return false;  						}  					} @@ -209,6 +215,8 @@ bool DOMLoader::loadDom(const std::string& basepath,  		if(!found)  		{  			ERR(domloader, "No instrument with name '%s'", instrumentref.name.data()); +			logger(LogLevel::Warning, "No instrument with name '" + +			       instrumentref.name + "'.");  			return false;  		}  	} diff --git a/src/domloader.h b/src/domloader.h index 2901560..103de27 100644 --- a/src/domloader.h +++ b/src/domloader.h @@ -29,6 +29,8 @@  #include <vector>  #include <string> +#include "logger.h" +  struct DrumkitDOM;  struct InstrumentDOM;  class DrumKit; @@ -45,7 +47,7 @@ public:  	bool loadDom(const std::string& basepath,  	             const DrumkitDOM& dom,  	             const std::vector<InstrumentDOM>& instrumentdoms, -	             DrumKit& drumkit); +	             DrumKit& drumkit, LogFunction logger = nullptr);  private:  	static InstrumentChannel* addOrGetChannel(Instrument& instrument, diff --git a/src/drumkitloader.cc b/src/drumkitloader.cc index 933e415..d9f65f0 100644 --- a/src/drumkitloader.cc +++ b/src/drumkitloader.cc @@ -50,6 +50,28 @@ DrumKitLoader::DrumKitLoader(Settings& settings, DrumKit& kit,  	, rand(rand)  	, audio_cache(audio_cache)  { +	logger = +		[&](LogLevel level, const std::string& msg) +		{ +			std::string message; +			switch(level) +			{ +			case LogLevel::Info: +				//message = "[Info]"; +				//break; +				return; // Ignore info level messages +			case LogLevel::Warning: +				message = "[Warning]"; +				break; +			case LogLevel::Error: +				message = "[Error]"; +				break; +			} +			message += " " + msg + "\n"; +			std::string status = settings.load_status_text.load(); +			status += message; +			settings.load_status_text.store(status); +		};  }  DrumKitLoader::~DrumKitLoader() @@ -108,6 +130,8 @@ bool DrumKitLoader::loadkit(const std::string& file)  	// Delete all Channels, Instruments, Samples and AudioFiles.  	kit.clear(); +	settings.load_status_text.store(""); +  	settings.drumkit_load_status.store(LoadStatus::Loading);  	// Parse drumkit and instrument xml @@ -134,7 +158,7 @@ bool DrumKitLoader::loadkit(const std::string& file)  	std::vector<InstrumentDOM> instrumentdoms;  	std::string path = getPath(edited_filename);  	bool parseerror = false; -	bool ret = parseDrumkitFile(edited_filename, drumkitdom); +	bool ret = parseDrumkitFile(edited_filename, drumkitdom, logger);  	if(!ret)  	{  		WARN(drumkitloader, "Drumkit file parser error: '%s'", @@ -146,7 +170,8 @@ bool DrumKitLoader::loadkit(const std::string& file)  	for(const auto& ref : drumkitdom.instruments)  	{  		instrumentdoms.emplace_back(); -		bool ret = parseInstrumentFile(path + "/" + ref.file, instrumentdoms.back()); +		bool ret = parseInstrumentFile(path + "/" + ref.file, instrumentdoms.back(), +		                               logger);  		if(!ret)  		{  			WARN(drumkitloader, "Instrument file parser error: '%s'", @@ -157,7 +182,7 @@ bool DrumKitLoader::loadkit(const std::string& file)  	}  	DOMLoader domloader(settings, rand); -	ret = domloader.loadDom(path, drumkitdom, instrumentdoms, kit); +	ret = domloader.loadDom(path, drumkitdom, instrumentdoms, kit, logger);  	if(!ret)  	{  		WARN(drumkitloader, "DOMLoader error"); @@ -339,7 +364,7 @@ void DrumKitLoader::thread_main()  			filename = audiofile->filename;  			try  			{ -				audiofile->load(preload_samples); +				audiofile->load(logger, preload_samples);  			}  			catch(std::bad_alloc&)  			{ diff --git a/src/drumkitloader.h b/src/drumkitloader.h index a2531d5..0dc6cca 100644 --- a/src/drumkitloader.h +++ b/src/drumkitloader.h @@ -95,4 +95,6 @@ protected:  	Random& rand;  	AudioCache& audio_cache;  	std::size_t preload_samples{std::numeric_limits<std::size_t>::max()}; + +	LogFunction logger;  }; diff --git a/src/logger.h b/src/logger.h new file mode 100644 index 0000000..bd5719e --- /dev/null +++ b/src/logger.h @@ -0,0 +1,38 @@ +/* -*- Mode: c++ -*- */ +/*************************************************************************** + *            logger.h + * + *  Wed Jul 24 19:42:25 CEST 2019 + *  Copyright 2019 Bent Bisballe Nyeng + *  deva@aasimon.org + ****************************************************************************/ + +/* + *  This file is part of DrumGizmo. + * + *  DrumGizmo is free software; you can redistribute it and/or modify + *  it under the terms of the GNU Lesser General Public License as published by + *  the Free Software Foundation; either version 3 of the License, or + *  (at your option) any later version. + * + *  DrumGizmo is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU Lesser General Public License for more details. + * + *  You should have received a copy of the GNU Lesser General Public License + *  along with DrumGizmo; if not, write to the Free Software + *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA. + */ +#pragma once + +#include <functional> + +enum class LogLevel +{ +	Info, +	Warning, +	Error, +}; + +using LogFunction = std::function<void (LogLevel, const std::string&)>; diff --git a/src/powerlist.cc b/src/powerlist.cc index c78b071..23d9795 100644 --- a/src/powerlist.cc +++ b/src/powerlist.cc @@ -81,7 +81,7 @@ const Channel* PowerList::getMasterChannel()  			const Channel* c = pair.first;  			AudioFile* af = pair.second; -			af->load(LOAD_SIZE); +			af->load(nullptr, LOAD_SIZE);  			float silence{0.f};  			std::size_t silence_length{4u}; diff --git a/src/settings.h b/src/settings.h index 64d27b7..97b1cf1 100644 --- a/src/settings.h +++ b/src/settings.h @@ -145,6 +145,9 @@ struct Settings  	Atomic<std::size_t> audition_counter{0};  	Atomic<std::string> audition_instrument;  	Atomic<float> audition_velocity; + +	// Notify UI about load errors +	Atomic<std::string> load_status_text;  };  //! Settings getter class. @@ -206,6 +209,8 @@ struct SettingsGetter  	SettingRef<std::string> audition_instrument;  	SettingRef<float> audition_velocity; +	SettingRef<std::string> load_status_text; +  	SettingsGetter(Settings& settings)  		: drumkit_file(settings.drumkit_file)  		, drumkit_load_status(settings.drumkit_load_status) @@ -250,6 +255,7 @@ struct SettingsGetter  		, audition_counter{settings.audition_counter}  		, audition_instrument{settings.audition_instrument}  		, audition_velocity{settings.audition_velocity} +		, load_status_text{settings.load_status_text}  	{  	}  }; @@ -312,6 +318,8 @@ public:  	Notifier<std::string> audition_instrument;  	Notifier<int> audition_velocity; +	Notifier<std::string> load_status_text; +  	void evaluate()  	{  #define EVAL(x) if(settings.x.hasChanged()) { x(settings.x.getValue()); } @@ -369,6 +377,8 @@ public:  		EVAL(audition_counter);  		EVAL(audition_instrument);  		EVAL(audition_velocity); + +		EVAL(load_status_text);  	}  	SettingsNotifier(Settings& settings) | 
