From 9d1ea1e7cfa256c7f5cac027382d92f658734ccb Mon Sep 17 00:00:00 2001 From: Bent Bisballe Nyeng Date: Thu, 25 Jul 2019 17:49:16 +0200 Subject: Add generic logger interface for propagating messages while loading drumkits to the commandline and/or plugin UI. --- src/Makefile.am | 1 + src/audiofile.cc | 17 +++++- src/audiofile.h | 3 +- src/dgxmlparser.cc | 166 +++++++++++++++++++++++++++++++++++---------------- src/dgxmlparser.h | 10 ++-- src/domloader.cc | 10 +++- src/domloader.h | 4 +- src/drumkitloader.cc | 33 ++++++++-- src/drumkitloader.h | 2 + src/logger.h | 38 ++++++++++++ src/powerlist.cc | 2 +- src/settings.h | 10 ++++ 12 files changed, 233 insertions(+), 63 deletions(-) create mode 100644 src/logger.h (limited to 'src') 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 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::max()); + void load(LogFunction logger, std::size_t sample_limit = std::numeric_limits::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 -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 -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 +#include #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& 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 #include +#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& 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 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::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 + +enum class LogLevel +{ + Info, + Warning, + Error, +}; + +using LogFunction = std::function; 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 audition_counter{0}; Atomic audition_instrument; Atomic audition_velocity; + + // Notify UI about load errors + Atomic load_status_text; }; //! Settings getter class. @@ -206,6 +209,8 @@ struct SettingsGetter SettingRef audition_instrument; SettingRef audition_velocity; + SettingRef 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 audition_instrument; Notifier audition_velocity; + Notifier 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) -- cgit v1.2.3