diff options
Diffstat (limited to 'src')
36 files changed, 942 insertions, 1047 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index a1b1615..4d167af 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -13,7 +13,6 @@ EXTRA_DIST = \ channelmixer.h \ chresampler.h \ configfile.h \ - configuration.h \ configparser.h \ cpp11fix.h \ drumgizmo.h \ @@ -24,13 +23,11 @@ EXTRA_DIST = \ instrument.h \ instrumentparser.h \ memchecker.h \ - message.h \ - messagehandler.h \ - messagereceiver.h \ midimapparser.h \ midimapper.h \ mutex.h \ nolocale.h \ + notifier.h \ path.h \ powerlist.h \ rangemap.h \ @@ -54,7 +51,6 @@ EXTRA_DIST = \ channelmixer.cc \ chresampler.cc \ configfile.cc \ - configuration.cc \ configparser.cc \ drumgizmo.cc \ drumkit.cc \ @@ -64,8 +60,6 @@ EXTRA_DIST = \ instrument.cc \ instrumentparser.cc \ memchecker.cc \ - messagehandler.cc \ - messagereceiver.cc \ midimapparser.cc \ midimapper.cc \ mutex.cc \ diff --git a/src/Makefile.am.drumgizmo b/src/Makefile.am.drumgizmo index 8f648d0..6fddded 100644 --- a/src/Makefile.am.drumgizmo +++ b/src/Makefile.am.drumgizmo @@ -11,7 +11,6 @@ DRUMGIZMO_SOURCES = \ $(top_srcdir)/src/channelmixer.cc \ $(top_srcdir)/src/chresampler.cc \ $(top_srcdir)/src/configfile.cc \ - $(top_srcdir)/src/configuration.cc \ $(top_srcdir)/src/configparser.cc \ $(top_srcdir)/src/drumgizmo.cc \ $(top_srcdir)/src/drumkit.cc \ @@ -21,8 +20,6 @@ DRUMGIZMO_SOURCES = \ $(top_srcdir)/src/instrument.cc \ $(top_srcdir)/src/instrumentparser.cc \ $(top_srcdir)/src/memchecker.cc \ - $(top_srcdir)/src/messagehandler.cc \ - $(top_srcdir)/src/messagereceiver.cc \ $(top_srcdir)/src/midimapparser.cc \ $(top_srcdir)/src/midimapper.cc \ $(top_srcdir)/src/mutex.cc \ diff --git a/src/atomic.h b/src/atomic.h new file mode 100644 index 0000000..95a5e9d --- /dev/null +++ b/src/atomic.h @@ -0,0 +1,182 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * atomic.h + * + * Wed Mar 23 09:15:05 CET 2016 + * Copyright 2016 Christian Glöckner + * cgloeckner@freenet.de + ****************************************************************************/ + +/* + * This file is part of DrumGizmo. + * + * DrumGizmo is free software; you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU 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 <type_traits> +#include <atomic> + +#include <mutex> +#include "mutex.h" + +template <typename T, typename = void> +class Atomic; + +// use std::atomic if possible +template <typename T> +class Atomic<T, typename std::enable_if<std::is_pod<T>::value>::type> + : public std::atomic<T> +{ +public: + // inherit methods + using std::atomic<T>::atomic; + using std::atomic<T>::operator=; +}; + +// else work around it using a mutex +template <typename T> +class Atomic<T, typename std::enable_if<!std::is_pod<T>::value>::type> +{ +public: + using self_type = + Atomic<T, typename std::enable_if<!std::is_pod<T>::value>::type>; + + Atomic() + : data{} + , mutex{} + { + } + + Atomic(T data) + : data{std::move(data)} + , mutex{} + { + } + + Atomic(self_type const & other) + : data{} + , mutex{} + { + std::lock_guard<std::mutex> lock{other.mutex}; + data = other.data; + } + + Atomic(self_type&& other) + : data{} + , mutex{} + { + std::lock_guard<std::mutex> lock{other.mutex}; + std::swap(data, other.data); + } + + T operator=(T data) + { + std::lock_guard<std::mutex> lock{mutex}; + this->data = std::move(data); + return this->data; + } + + operator T() const + { + return load(); + } + + bool is_lock_free() const + { + return false; + } + + void store(T data) + { + std::lock_guard<std::mutex> lock{mutex}; + this->data = std::move(data); + } + + T load() const { + std::lock_guard<std::mutex> lock{mutex}; + return data; + } + + T exchange(T data){ + std::lock_guard<std::mutex> lock{mutex}; + std::swap(data, this->data); + return data; + } + + bool operator==(const T& other) const + { + std::lock_guard<std::mutex> lock{mutex}; + return other == data; + } + + bool operator!=(const T& other) const + { + std::lock_guard<std::mutex> lock{mutex}; + return !(other == data); + } + + bool operator==(const Atomic<T>& other) const + { + std::lock_guard<std::mutex> lock{mutex}; + return other.load() == data; + } + + bool operator!=(const Atomic<T>& other) const + { + std::lock_guard<std::mutex> lock{mutex}; + return !(other.load() == data); + } + +private: + T data; + mutable std::mutex mutex; +}; + +//! Getter utility class. +template <typename T> class SettingRef +{ +public: + SettingRef(Atomic<T>& value) + : value(value) + { + // string isn't lock free either + assert((std::is_same<T, std::string>::value || value.is_lock_free())); + } + + bool hasChanged() + { + T tmp = cache; + cache.exchange(value); + + if(firstAccess) + { + firstAccess = false; + return true; + } + + return cache != tmp; + } + + T getValue() const + { + return cache; + } + +private: + bool firstAccess{true}; + Atomic<T>& value; + Atomic<T> cache; +}; diff --git a/src/audiofile.cc b/src/audiofile.cc index 58b248b..84329f8 100644 --- a/src/audiofile.cc +++ b/src/audiofile.cc @@ -36,8 +36,6 @@ #include <sndfile.h> #include <hugin.hpp> -#include "configuration.h" - AudioFile::AudioFile(const std::string& filename, int filechannel) { is_loaded = false; diff --git a/src/configuration.cc b/src/configuration.cc deleted file mode 100644 index 72f6e4a..0000000 --- a/src/configuration.cc +++ /dev/null @@ -1,38 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/*************************************************************************** - * configuration.cc - * - * Sat Oct 8 14:37:14 CEST 2011 - * Copyright 2011 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. - */ -#include "configuration.h" - -bool Conf::enable_velocity_modifier = true; -float Conf::velocity_modifier_falloff = 0.5; -float Conf::velocity_modifier_weight = 0.25; - -bool Conf::enable_velocity_randomiser = false; -float Conf::velocity_randomiser_weight = 0.1; - -int Conf::samplerate = 44100; - -bool Conf::enable_resampling = true; diff --git a/src/configuration.h b/src/configuration.h deleted file mode 100644 index 3adf525..0000000 --- a/src/configuration.h +++ /dev/null @@ -1,44 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/*************************************************************************** - * configuration.h - * - * Sat Oct 8 14:37:13 CEST 2011 - * Copyright 2011 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. - */ -#ifndef __DRUMGIZMO_CONFIGURATION_H__ -#define __DRUMGIZMO_CONFIGURATION_H__ - -namespace Conf { - extern bool enable_velocity_modifier; - extern float velocity_modifier_falloff; - extern float velocity_modifier_weight; - - extern bool enable_velocity_randomiser; - extern float velocity_randomiser_weight; - - extern int samplerate; - - extern bool enable_resampling; -}; - - -#endif/*__DRUMGIZMO_CONFIGURATION_H__*/ diff --git a/src/drumgizmo.cc b/src/drumgizmo.cc index 853e93d..aa6be23 100644 --- a/src/drumgizmo.cc +++ b/src/drumgizmo.cc @@ -38,26 +38,27 @@ #include <hugin.hpp> #include <config.h> +#include <memory> #include "drumkitparser.h" #include "audioinputenginemidi.h" -#include "configuration.h" #include "configparser.h" #include "nolocale.h" -DrumGizmo::DrumGizmo(AudioOutputEngine *o, AudioInputEngine *i) - : MessageReceiver(MSGRCV_ENGINE) - , loader() +DrumGizmo::DrumGizmo(Settings& settings, + AudioOutputEngine *o, AudioInputEngine *i) + : loader(settings) , oe(o) , ie(i) , framesize(0) , freewheel(false) , events{} + , settings(settings) { is_stopping = false; audioCache.init(10000); // start thread - + events.reserve(1000); } @@ -68,9 +69,12 @@ DrumGizmo::~DrumGizmo() bool DrumGizmo::loadkit(std::string file) { + settings.drumkit_load_status.store(LoadStatus::Idle); + if(file == "") { - return 1; + settings.drumkit_load_status.store(LoadStatus::Error); + return false; } DEBUG(drumgizmo, "loadkit(%s)\n", file.c_str()); @@ -81,27 +85,31 @@ bool DrumGizmo::loadkit(std::string file) // Delete all Channels, Instruments, Samples and AudioFiles. kit.clear(); - DrumKitParser parser(kit); + settings.drumkit_load_status.store(LoadStatus::Loading); + + DrumKitParser parser(settings, kit); if(parser.parseFile(file)) { ERR(drumgizmo, "Drumkit parser failed: %s\n", file.c_str()); + settings.drumkit_load_status.store(LoadStatus::Error); return false; } - // Check if there is enough free RAM to load the drumkit. - if(!memchecker.enoughFreeMemory(kit)) - { - printf("WARNING: " - "There doesn't seem to be enough RAM available to load the kit.\n" - "Trying to load it anyway...\n"); - } + // TODO: Re-introduce when the code has been moved to the loader thread. + //// Check if there is enough free RAM to load the drumkit. + //if(!memchecker.enoughFreeMemory(kit)) + //{ + // printf("WARNING: " + // "There doesn't seem to be enough RAM available to load the kit.\n" + // "Trying to load it anyway...\n"); + //} loader.loadKit(&kit); #ifdef WITH_RESAMPLER for(int i = 0; i < MAX_NUM_CHANNELS; ++i) { - resampler[i].setup(kit.getSamplerate(), Conf::samplerate); + resampler[i].setup(kit.getSamplerate(), settings.samplerate.load()); } #endif/*WITH_RESAMPLER*/ @@ -125,79 +133,6 @@ bool DrumGizmo::init() return true; } -void DrumGizmo::handleMessage(Message *msg) -{ - DEBUG(msg, "got message."); - switch(msg->type()) { - case Message::LoadDrumKit: - { - DEBUG(msg, "got LoadDrumKitMessage message."); - LoadDrumKitMessage *m = (LoadDrumKitMessage*)msg; - loadkit(m->drumkitfile); - //init(true); - } - break; - case Message::LoadMidimap: - DEBUG(msg, "got LoadMidimapMessage message."); - if(!ie->isMidiEngine()) - { - break; - } - { - AudioInputEngineMidi *aim = (AudioInputEngineMidi*)ie; - LoadMidimapMessage *m = (LoadMidimapMessage*)msg; - bool ret = aim->loadMidiMap(m->midimapfile, kit.instruments); - - LoadStatusMessageMidimap *ls = new LoadStatusMessageMidimap(); - ls->success = ret; - msghandler.sendMessage(MSGRCV_UI, ls); - } - break; - case Message::EngineSettingsMessage: - { - bool mmap_loaded = false; - std::string mmapfile; - if(ie->isMidiEngine()) - { - AudioInputEngineMidi *aim = (AudioInputEngineMidi*)ie; - mmapfile = aim->getMidimapFile(); - mmap_loaded = aim->isValid(); - } - - EngineSettingsMessage *msg = new EngineSettingsMessage(); - msg->midimapfile = mmapfile; - msg->midimap_loaded = mmap_loaded; - msg->drumkitfile = kit.getFile(); - msg->drumkit_loaded = loader.isDone(); - msg->enable_velocity_modifier = Conf::enable_velocity_modifier; - msg->velocity_modifier_falloff = Conf::velocity_modifier_falloff; - msg->velocity_modifier_weight = Conf::velocity_modifier_weight; - msg->enable_velocity_randomiser = Conf::enable_velocity_randomiser; - msg->velocity_randomiser_weight = Conf::velocity_randomiser_weight; - msghandler.sendMessage(MSGRCV_UI, msg); - } - break; - case Message::ChangeSettingMessage: - { - ChangeSettingMessage *ch = (ChangeSettingMessage*)msg; - switch(ch->name) { - case ChangeSettingMessage::enable_velocity_modifier: - Conf::enable_velocity_modifier = ch->value; - break; - case ChangeSettingMessage::velocity_modifier_weight: - Conf::velocity_modifier_weight = ch->value; - break; - case ChangeSettingMessage::velocity_modifier_falloff: - Conf::velocity_modifier_falloff = ch->value; - break; - } - } - break; - default: - break; - } -} - void DrumGizmo::setFrameSize(size_t framesize) { // If we are resampling override the frame size. @@ -259,8 +194,31 @@ bool DrumGizmo::run(size_t pos, sample_t *samples, size_t nsamples) { setFrameSize(nsamples); - // Handle engine messages, at most one in each iteration: - handleMessages(1); + // TODO: Move this to DrumKitLoader thread. + if(getter.drumkit_file.hasChanged()) + { + loadkit(getter.drumkit_file.getValue()); + } + + // TODO: Move this to DrumKitLoader thread. + if(getter.midimap_file.hasChanged()) + { + auto ie_midi = dynamic_cast<AudioInputEngineMidi*>(ie); + if(ie_midi) + { + settings.midimap_load_status.store(LoadStatus::Loading); + bool ret = ie_midi->loadMidiMap(getter.midimap_file.getValue(), + kit.instruments); + if(ret) + { + settings.midimap_load_status.store(LoadStatus::Done); + } + else + { + settings.midimap_load_status.store(LoadStatus::Error); + } + } + } ie->pre(); oe->pre(nsamples); @@ -398,7 +356,7 @@ bool DrumGizmo::run(size_t pos, sample_t *samples, size_t nsamples) // Write audio // #ifdef WITH_RESAMPLER - if((Conf::enable_resampling == false) || + if((settings.enable_resampling.load() == false) || (resampler[0].getRatio() == 1.0)) // No resampling needed { #endif @@ -636,17 +594,17 @@ void DrumGizmo::stop() int DrumGizmo::samplerate() { - return Conf::samplerate; + return settings.samplerate.load(); } void DrumGizmo::setSamplerate(int samplerate) { DEBUG(dgeditor, "%s samplerate: %d\n", __PRETTY_FUNCTION__, samplerate); - Conf::samplerate = samplerate; + settings.samplerate.store(samplerate); #ifdef WITH_RESAMPLER for(int i = 0; i < MAX_NUM_CHANNELS; ++i) { - resampler[i].setup(kit.getSamplerate(), Conf::samplerate); + resampler[i].setup(kit.getSamplerate(), settings.samplerate.load()); } if(resampler[0].getRatio() != 1) { @@ -691,15 +649,15 @@ std::string DrumGizmo::configString() " <value name=\"drumkitfile\">" + kit.getFile() + "</value>\n" " <value name=\"midimapfile\">" + mmapfile + "</value>\n" " <value name=\"enable_velocity_modifier\">" + - bool2str(Conf::enable_velocity_modifier) + "</value>\n" + bool2str(settings.enable_velocity_modifier.load()) + "</value>\n" " <value name=\"velocity_modifier_falloff\">" + - float2str(Conf::velocity_modifier_falloff) + "</value>\n" + float2str(settings.velocity_modifier_falloff.load()) + "</value>\n" " <value name=\"velocity_modifier_weight\">" + - float2str(Conf::velocity_modifier_weight) + "</value>\n" + float2str(settings.velocity_modifier_weight.load()) + "</value>\n" " <value name=\"enable_velocity_randomiser\">" + - bool2str(Conf::enable_velocity_randomiser) + "</value>\n" + bool2str(settings.enable_velocity_randomiser.load()) + "</value>\n" " <value name=\"velocity_randomiser_weight\">" + - float2str(Conf::velocity_randomiser_weight) + "</value>\n" + float2str(settings.velocity_randomiser_weight.load()) + "</value>\n" "</config>"; } @@ -711,68 +669,50 @@ bool DrumGizmo::setConfigString(std::string cfg) ConfigParser p; if(p.parseString(cfg)) { - ERR(drumgizmo, "Config parse error.\n"); - return false; + ERR(drumgizmo, "Config parse error.\n"); + return false; } if(p.value("enable_velocity_modifier") != "") { - Conf::enable_velocity_modifier = - p.value("enable_velocity_modifier") == "true"; + settings.enable_velocity_modifier.store(p.value("enable_velocity_modifier") == "true"); } if(p.value("velocity_modifier_falloff") != "") { - Conf::velocity_modifier_falloff = - str2float(p.value("velocity_modifier_falloff")); + settings.velocity_modifier_falloff.store(str2float(p.value("velocity_modifier_falloff"))); } if(p.value("velocity_modifier_weight") != "") { - Conf::velocity_modifier_weight = - str2float(p.value("velocity_modifier_weight")); + settings.velocity_modifier_weight.store(str2float(p.value("velocity_modifier_weight"))); } if(p.value("enable_velocity_randomiser") != "") { - Conf::enable_velocity_randomiser = - p.value("enable_velocity_randomiser") == "true"; + settings.enable_velocity_randomiser.store(p.value("enable_velocity_randomiser") == "true"); } if(p.value("velocity_randomiser_weight") != "") { - Conf::velocity_randomiser_weight = - str2float(p.value("velocity_randomiser_weight")); + settings.velocity_randomiser_weight.store(str2float(p.value("velocity_randomiser_weight"))); } if(p.value("enable_resampling") != "") { - Conf::enable_resampling = - p.value("enable_resampling") == "true"; + settings.enable_resampling.store(p.value("enable_resampling") == "true"); } std::string newkit = p.value("drumkitfile"); - if(newkit != "" && kit.getFile() != newkit) + if(newkit != "") { - /* - if(!loadkit(p.values["drumkitfile"])) - { - return false; - } - init(true); - */ - LoadDrumKitMessage *msg = new LoadDrumKitMessage(); - msg->drumkitfile = newkit; - msghandler.sendMessage(MSGRCV_ENGINE, msg); + settings.drumkit_file.store(newkit); } std::string newmidimap = p.value("midimapfile"); if(newmidimap != "") { - //midimapfile = newmidimap; - LoadMidimapMessage *msg = new LoadMidimapMessage(); - msg->midimapfile = newmidimap; - msghandler.sendMessage(MSGRCV_ENGINE, msg); + settings.midimap_file.store(newmidimap); } return true; diff --git a/src/drumgizmo.h b/src/drumgizmo.h index 632d5fc..7af5dbb 100644 --- a/src/drumgizmo.h +++ b/src/drumgizmo.h @@ -31,34 +31,26 @@ #include "audiooutputengine.h" #include "audioinputengine.h" - #include "events.h" #include "audiofile.h" #include "drumkit.h" #include "memchecker.h" - #include "drumkitloader.h" #include "audiocache.h" - #include "mutex.h" - -#include "message.h" - -#include "messagereceiver.h" - #include "chresampler.h" - #include "configfile.h" +#include "settings.h" #define MAX_NUM_CHANNELS 64 #define REFSFILE "refs.conf" #define RESAMPLER_INPUT_BUFFER 64 class DrumGizmo - : public MessageReceiver { public: - DrumGizmo(AudioOutputEngine *outputengine, AudioInputEngine *inputengine); + DrumGizmo(Settings& settings, + AudioOutputEngine *outputengine, AudioInputEngine *inputengine); virtual ~DrumGizmo(); bool loadkit(std::string kitfile); @@ -74,8 +66,6 @@ public: std::string configString(); bool setConfigString(std::string cfg); - void handleMessage(Message *msg); - int samplerate(); void setSamplerate(int samplerate); @@ -106,6 +96,8 @@ protected: size_t framesize; bool freewheel; - + std::vector<event_t> events; + Settings& settings; + SettingsGetter getter{settings}; }; diff --git a/src/drumkit.cc b/src/drumkit.cc index 1b95c87..f25a6ea 100644 --- a/src/drumkit.cc +++ b/src/drumkit.cc @@ -39,12 +39,11 @@ DrumKit::~DrumKit() void DrumKit::clear() { - Instruments::iterator i = instruments.begin(); - while(i != instruments.end()) + for(auto& instrument : instruments) { - delete *i; - i++; + delete instrument; } + instruments.clear(); channels.clear(); @@ -78,20 +77,3 @@ size_t DrumKit::getSamplerate() const { return _samplerate; } - -#ifdef TEST_DRUMKIT -// Additional dependency files -// deps: -// Required cflags (autoconf vars may be used) -// cflags: -// Required link options (autoconf vars may be used) -// libs: -#include "test.h" - -TEST_BEGIN; - -// TODO: Put some testcode here (see test.h for usable macros). - -TEST_END; - -#endif /*TEST_DRUMKIT*/ diff --git a/src/drumkit.h b/src/drumkit.h index 1ceef3e..e3ae783 100644 --- a/src/drumkit.h +++ b/src/drumkit.h @@ -33,11 +33,9 @@ #include "instrument.h" #include "versionstr.h" -class DrumKitParser; class DrumKit { friend class DrumKitParser; - public: DrumKit(); ~DrumKit(); diff --git a/src/drumkitloader.cc b/src/drumkitloader.cc index ff489ea..3a0e096 100644 --- a/src/drumkitloader.cc +++ b/src/drumkitloader.cc @@ -26,14 +26,17 @@ */ #include "drumkitloader.h" +#include <iostream> + #include <hugin.hpp> #include "drumkitparser.h" #include "drumgizmo.h" -DrumKitLoader::DrumKitLoader() - : semaphore("drumkitloader") - , framesize(0) +DrumKitLoader::DrumKitLoader(Settings& settings) + : framesize(0) + , settings(settings) + , getter(settings) { run(); run_semaphore.wait(); // Wait for the thread to actually start. @@ -55,7 +58,7 @@ DrumKitLoader::~DrumKitLoader() void DrumKitLoader::stop() { { - MutexAutolock l(mutex); + std::lock_guard<std::mutex> guard(mutex); load_queue.clear(); } @@ -66,68 +69,48 @@ void DrumKitLoader::stop() void DrumKitLoader::skip() { - MutexAutolock l(mutex); + std::lock_guard<std::mutex> guard(mutex); load_queue.clear(); } void DrumKitLoader::setFrameSize(size_t framesize) { - DEBUG(loader, "%s pre\n", __PRETTY_FUNCTION__); - - { - MutexAutolock l(mutex); - this->framesize = framesize; - framesize_semaphore.post(); // Signal that the framesize has been set. - } - - DEBUG(loader, "%s post\n", __PRETTY_FUNCTION__); + std::lock_guard<std::mutex> guard(mutex); + this->framesize = framesize; + framesize_semaphore.post(); // Signal that the framesize has been set. } bool DrumKitLoader::isDone() { - MutexAutolock l(mutex); + std::lock_guard<std::mutex> guard(mutex); return load_queue.size() == 0; } void DrumKitLoader::loadKit(DrumKit *kit) { - MutexAutolock l(mutex); + std::lock_guard<std::mutex> guard(mutex); DEBUG(loader, "Create AudioFile queue from DrumKit\n"); - total_num_audiofiles = 0;// For UI Progress Messages - - { // Count total number of files that need loading: - Instruments::iterator i = kit->instruments.begin(); - while(i != kit->instruments.end()) - { - Instrument *instr = *i; - total_num_audiofiles += instr->audiofiles.size(); - ++i; - } - } + std::size_t total_num_audiofiles = 0;// For UI Progress Messages - fraction = total_num_audiofiles / 200; - if(fraction == 0) + // Count total number of files that need loading: + for(auto instr : kit->instruments) { - fraction = 1; + total_num_audiofiles += instr->audiofiles.size(); } - { // Now actually queue them for loading: - Instruments::iterator i = kit->instruments.begin(); - while(i != kit->instruments.end()) - { - Instrument *instr = *i; - - std::vector<AudioFile*>::iterator af = instr->audiofiles.begin(); - while(af != instr->audiofiles.end()) - { - AudioFile *audiofile = *af; - load_queue.push_back(audiofile); - af++; - } + settings.number_of_files.store(total_num_audiofiles); - ++i; + // Now actually queue them for loading: + for(auto instr : kit->instruments) + { + std::vector<AudioFile*>::iterator af = instr->audiofiles.begin(); + while(af != instr->audiofiles.end()) + { + AudioFile *audiofile = *af; + load_queue.push_back(audiofile); + af++; } } @@ -151,23 +134,35 @@ void DrumKitLoader::thread_main() { size_t size; { - MutexAutolock l(mutex); + std::lock_guard<std::mutex> guard(mutex); size = load_queue.size(); } // Only sleep if queue is empty. if(size == 0) { - semaphore.wait(); + semaphore.wait(std::chrono::milliseconds(1000)); + } + + if(getter.drumkit_file.hasChanged()) + { + //std::cout << "RELOAD DRUMKIT!" << std::endl; + } + + if(getter.midimap_file.hasChanged()) + { + //std::cout << "RELOAD MIDIMAP!" << std::endl; } std::string filename; { - MutexAutolock l(mutex); + std::lock_guard<std::mutex> guard(mutex); + if(load_queue.size() == 0) { continue; } + AudioFile *audiofile = load_queue.front(); load_queue.pop_front(); filename = audiofile->filename; @@ -183,15 +178,13 @@ void DrumKitLoader::thread_main() audiofile->load(preload_size); } - loaded++; + ++loaded; + + settings.number_of_files_loaded.store(loaded); - if(loaded % fraction == 0 || loaded == total_num_audiofiles) + if(settings.number_of_files.load() == loaded) { - LoadStatusMessage *ls = new LoadStatusMessage(); - ls->number_of_files = total_num_audiofiles; - ls->numer_of_files_loaded = loaded; - ls->current_file = filename; - msghandler.sendMessage(MSGRCV_UI, ls); + settings.drumkit_load_status.store(LoadStatus::Done); } } diff --git a/src/drumkitloader.h b/src/drumkitloader.h index 3656839..3fd7ec1 100644 --- a/src/drumkitloader.h +++ b/src/drumkitloader.h @@ -28,12 +28,14 @@ #include <string> #include <list> +#include <mutex> +#include "mutex.h" #include "thread.h" #include "semaphore.h" -#include "mutex.h" #include "drumkit.h" +#include "settings.h" //! This class is responsible for loading the drumkits in its own thread. //! All interaction calls are simply modifying queues and not doing any @@ -45,7 +47,7 @@ class DrumKitLoader { public: //! The constrcutor starts the loader thread. - DrumKitLoader(); + DrumKitLoader(Settings& settings); //! The destructor signals the thread to stop and waits to merge before //! returning (ie. deleting the object will garantuee that the thread has @@ -75,11 +77,11 @@ protected: Semaphore run_semaphore; Semaphore semaphore; Semaphore framesize_semaphore; - Mutex mutex; + std::mutex mutex; volatile bool running{false}; std::list<AudioFile*> load_queue; - size_t total_num_audiofiles{0}; - size_t fraction{1}; - size_t loaded{0}; - size_t framesize{0}; + std::size_t loaded{0}; + std::size_t framesize{0}; + Settings& settings; + SettingsGetter getter; }; diff --git a/src/drumkitparser.cc b/src/drumkitparser.cc index 3ba69c8..048a05b 100644 --- a/src/drumkitparser.cc +++ b/src/drumkitparser.cc @@ -34,9 +34,10 @@ #include "path.h" #include "drumgizmo.h" -DrumKitParser::DrumKitParser(DrumKit& kit) - : kit(kit) - , refs(REFSFILE) +DrumKitParser::DrumKitParser(Settings& settings, DrumKit& k) + : kit(k) + , refs(REFSFILE) + , settings(settings) { } @@ -46,9 +47,9 @@ int DrumKitParser::parseFile(const std::string& filename) if(refs.load()) { - if(filename.size() > 1 && filename[0] == '@') + if((filename.size() > 1) && (filename[0] == '@')) { - edited_filename = refs.getValue(filename.substr(1)); + edited_filename = refs.getValue(filename.substr(1)); } } else @@ -57,9 +58,10 @@ int DrumKitParser::parseFile(const std::string& filename) } path = getPath(edited_filename); - auto result = SAXParser::parseFile(filename); + auto result = SAXParser::parseFile(edited_filename); - if (result == 0) { + if(result == 0) + { kit._file = edited_filename; } @@ -101,7 +103,7 @@ void DrumKitParser::startTag(const std::string& name, const attr_t& attr) { ERR(kitparser, "Error parsing version number: %s, using 1.0\n", err); kit._version = VersionStr(1,0,0); - } + } } else { @@ -112,7 +114,7 @@ void DrumKitParser::startTag(const std::string& name, const attr_t& attr) if(name == "channels") { - + } if(name == "channel") @@ -140,6 +142,7 @@ void DrumKitParser::startTag(const std::string& name, const attr_t& attr) ERR(kitparser, "Missing name in instrument tag.\n"); return; } + if(attr.find("file") == attr.end()) { ERR(kitparser, "Missing file in instrument tag.\n"); @@ -180,12 +183,14 @@ void DrumKitParser::endTag(const std::string& name) { if(name == "instrument") { - Instrument* i = new Instrument(); - i->setGroup(instr_group); - // Instrument &i = kit.instruments[kit.instruments.size() - 1]; - InstrumentParser parser(*i); + Instrument* instrument = new Instrument(settings); + instrument->setGroup(instr_group); + + InstrumentParser parser(*instrument); parser.parseFile(path + "/" + instr_file); - kit.instruments.push_back(i); + + // Transfer ownership to the DrumKit object. + kit.instruments.push_back(instrument); // Assign kit channel numbers to instruments channels. std::vector<InstrumentChannel*>::iterator ic = parser.channellist.begin(); @@ -206,16 +211,18 @@ void DrumKitParser::endTag(const std::string& name) c->num = kit.channels[cnt].num; } } + if(c->num == NO_CHANNEL) { ERR(kitparser, "Missing channel '%s' in instrument '%s'\n", - c->name.c_str(), i->getName().c_str()); + c->name.c_str(), instrument->getName().c_str()); } - else { + else + { /* - DEBUG(kitparser, "Assigned channel '%s' to number %d in instrument '%s'\n", - c->name.c_str(), c->num, i.name().c_str()); - */ + DEBUG(kitparser, "Assigned channel '%s' to number %d in instrument '%s'\n", + c->name.c_str(), c->num, i.name().c_str()); + */ } ic++; } diff --git a/src/drumkitparser.h b/src/drumkitparser.h index b0c8d8f..0adccb9 100644 --- a/src/drumkitparser.h +++ b/src/drumkitparser.h @@ -34,7 +34,7 @@ class DrumKitParser : public SAXParser { public: - DrumKitParser(DrumKit& kit); + DrumKitParser(Settings& setting, DrumKit& kit); virtual int parseFile(const std::string& filename) override; @@ -52,4 +52,5 @@ private: std::string instr_group; ConfigFile refs; + Settings& settings; }; diff --git a/src/instrument.cc b/src/instrument.cc index 9f18233..cc052e9 100644 --- a/src/instrument.cc +++ b/src/instrument.cc @@ -26,15 +26,12 @@ */ #include "instrument.h" -#include <stdlib.h> -#include <stdio.h> - #include <hugin.hpp> #include "sample.h" -#include "configuration.h" -Instrument::Instrument() +Instrument::Instrument(Settings& settings) + : settings(settings) { DEBUG(instrument, "new %p\n", this); mod = 1.0; @@ -45,7 +42,7 @@ Instrument::Instrument() Instrument::~Instrument() { - magic = NULL; + magic = nullptr; DEBUG(instrument, "delete %p\n", this); std::vector<AudioFile*>::iterator i = audiofiles.begin(); @@ -63,16 +60,26 @@ bool Instrument::isValid() const Sample* Instrument::sample(level_t level, size_t pos) { - Sample *sample = NULL; + // Read out all values from settings. + auto enable_velocity_randomiser = settings.enable_velocity_randomiser.load(); + auto velocity_randomiser_weight = settings.velocity_randomiser_weight.load(); + auto samplerate = settings.samplerate.load(); + auto velocity_modifier_falloff = settings.velocity_modifier_falloff.load(); + auto enable_velocity_modifier = settings.enable_velocity_modifier.load(); + auto velocity_modifier_weight = settings.velocity_modifier_weight.load(); + + Sample *sample = nullptr; - if(Conf::enable_velocity_modifier == false) { + if(enable_velocity_modifier == false) + { mod = 1.0; lastpos = 0; } - if(Conf::enable_velocity_randomiser) { - float r = rand.floatInRange(-1.0*Conf::velocity_randomiser_weight, - Conf::velocity_randomiser_weight); + if(enable_velocity_randomiser) + { + float r = rand.floatInRange(-1.0 * velocity_randomiser_weight, + velocity_randomiser_weight); level += r; if(level > 1.0) { @@ -84,9 +91,9 @@ Sample* Instrument::sample(level_t level, size_t pos) } } - if(Conf::enable_velocity_modifier) { - mod += (pos - lastpos) / - (Conf::samplerate * Conf::velocity_modifier_falloff); + if(enable_velocity_modifier) + { + mod += (pos - lastpos) / (samplerate * velocity_modifier_falloff); if(mod > 1.0) { mod = 1.0; @@ -98,21 +105,22 @@ Sample* Instrument::sample(level_t level, size_t pos) // Version 2.0 sample = powerlist.get(level * mod); } - else { + else + { // Version 1.0 std::vector<Sample*> s = samples.get(level * mod); if(s.size() == 0) { - return NULL; + return nullptr; } sample = rand.choose(s); } - if(Conf::enable_velocity_modifier) + if(enable_velocity_modifier) { lastpos = pos; - mod *= Conf::velocity_modifier_weight; + mod *= velocity_modifier_weight; } return sample; @@ -157,41 +165,3 @@ void Instrument::setGroup(const std::string& g) { _group = g; } - -#ifdef TEST_INSTRUMENT -// deps: channel.cc sample.cc audiofile.cc -// cflags: $(SNDFILE_CFLAGS) -// libs: $(SNDFILE_LIBS) -#include "test.h" - -TEST_BEGIN; - -Instrument i("test"); - -Sample* a = new Sample(); -i.addSample(0.0, 1.0, a); - -Sample* b = new Sample(); -i.addSample(0.0, 1.0, b); - -Sample* c = new Sample(); -i.addSample(1.5, 1.7, c); - -TEST_EQUAL(i.sample(0.0), b, "?"); -TEST_EQUAL(i.sample(0.0), a, "?"); -TEST_EQUAL(i.sample(0.0), b, "?"); -TEST_EQUAL(i.sample(0.0), b, "?"); -TEST_EQUAL(i.sample(0.0), b, "?"); -TEST_EQUAL(i.sample(0.0), b, "?"); -TEST_EQUAL(i.sample(0.0), a, "?"); -TEST_EQUAL(i.sample(0.0), a, "?"); - -TEST_EQUAL(i.sample(2.0), NULL, "?"); - -TEST_EQUAL(i.sample(1.6), c, "?"); -TEST_EQUAL(i.sample(1.6), c, "?"); -TEST_EQUAL(i.sample(1.6), c, "?"); - -TEST_END; - -#endif /*TEST_INSTRUMENT*/ diff --git a/src/instrument.h b/src/instrument.h index de5546b..a531aec 100644 --- a/src/instrument.h +++ b/src/instrument.h @@ -36,13 +36,13 @@ #include "versionstr.h" #include "random.h" -class InstrumentParser; +#include "settings.h" + class Instrument { friend class InstrumentParser; - public: - Instrument(); + Instrument(Settings& settings); ~Instrument(); Sample* sample(level_t level, size_t pos); @@ -78,7 +78,7 @@ private: size_t lastpos; float mod; - + Settings& settings; Random rand; }; diff --git a/src/instrumentparser.cc b/src/instrumentparser.cc index 268f8f3..1e42cc3 100644 --- a/src/instrumentparser.cc +++ b/src/instrumentparser.cc @@ -35,8 +35,8 @@ #include "nolocale.h" -InstrumentParser::InstrumentParser(Instrument& i) - : instrument(i) +InstrumentParser::InstrumentParser(Instrument& instrument) + : instrument(instrument) { } @@ -64,14 +64,15 @@ void InstrumentParser::startTag(const std::string& name, const attr_t& attr) if(attr.find("version") != attr.end()) { - try { + try + { instrument.version = VersionStr(attr.at("version")); } - catch(const char *err) + catch(const char* err) { ERR(instrparser, "Error parsing version number: %s, using 1.0\n", err); instrument.version = VersionStr(1,0,0); - } + } } else { @@ -82,7 +83,6 @@ void InstrumentParser::startTag(const std::string& name, const attr_t& attr) if(name == "samples") { - } if(name == "sample") @@ -93,10 +93,10 @@ void InstrumentParser::startTag(const std::string& name, const attr_t& attr) return; } - float power; + float power; if(attr.find("power") == attr.end()) { - power = -1; + power = -1; } else { @@ -105,12 +105,12 @@ void InstrumentParser::startTag(const std::string& name, const attr_t& attr) } // TODO get rid of new or delete it properly - s = new Sample(attr.at("name"), power); + sample = new Sample(attr.at("name"), power); } if(name == "audiofile") { - if(s == nullptr) + if(sample == nullptr) { ERR(instrparser,"Missing Sample!\n"); return; @@ -139,18 +139,24 @@ void InstrumentParser::startTag(const std::string& name, const attr_t& attr) } } - filechannel = filechannel - 1; // 1-based in file, but zero-based internally - // TODO do those next two lines correspond with proper deletes? If not fix it. - AudioFile *af = new AudioFile(path + "/" + attr.at("file"), filechannel); - InstrumentChannel *ch = new InstrumentChannel(attr.at("channel")); - channellist.push_back(ch); - s->addAudioFile(ch, af); - instrument.audiofiles.push_back(af); + filechannel = filechannel - 1; // 1-based in file but zero-based internally. + + AudioFile *audio_file = + new AudioFile(path + "/" + attr.at("file"), filechannel); + + // TODO: This is not deleted anywhere... + InstrumentChannel *instrument_channel = + new InstrumentChannel(attr.at("channel")); + + channellist.push_back(instrument_channel); + sample->addAudioFile(instrument_channel, audio_file); + + // Transfer audio_file ownership to the instrument. + instrument.audiofiles.push_back(audio_file); } if(name == "velocities") { - } if(name == "velocity") @@ -179,19 +185,17 @@ void InstrumentParser::startTag(const std::string& name, const attr_t& attr) return; } - Sample* sample = nullptr; - std::vector<Sample *>::iterator i = instrument.samplelist.begin(); - while(i != instrument.samplelist.end()) + Sample* sample_ref = nullptr; + for(auto& sample : instrument.samplelist) { - if((*i)->name == attr.at("name")) + if(sample->name == attr.at("name")) { - sample = *i; + sample_ref = sample; break; } - i++; } - if(sample == nullptr) + if(sample_ref == nullptr) { ERR(instrparser,"Samplref pointed at non-existing sample.\n"); return; @@ -200,7 +204,7 @@ void InstrumentParser::startTag(const std::string& name, const attr_t& attr) if(instrument.version == VersionStr("1.0")) { // Old "velocity group" algorithm needs this - instrument.addSample(lower, upper, sample); + instrument.addSample(lower, upper, sample_ref); } } } @@ -209,15 +213,15 @@ void InstrumentParser::endTag(const std::string& name) { if(name == "sample") { - if(s == nullptr) + if(sample == nullptr) { ERR(instrparser,"Missing Sample.\n"); return; } - instrument.samplelist.push_back(s); + instrument.samplelist.push_back(sample); - s = nullptr; + sample = nullptr; } if(name == "instrument") { diff --git a/src/instrumentparser.h b/src/instrumentparser.h index 965694a..6cbaf8a 100644 --- a/src/instrumentparser.h +++ b/src/instrumentparser.h @@ -47,7 +47,7 @@ protected: private: Instrument& instrument; - Sample* s{nullptr}; + Sample* sample{nullptr}; std::string path; diff --git a/src/message.h b/src/message.h deleted file mode 100644 index 71d0da6..0000000 --- a/src/message.h +++ /dev/null @@ -1,121 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/*************************************************************************** - * message.h - * - * Wed Mar 20 15:50:57 CET 2013 - * Copyright 2013 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. - */ -#ifndef __DRUMGIZMO_MESSAGE_H__ -#define __DRUMGIZMO_MESSAGE_H__ - -#include <string> - -class MessageHandler; - -class Message { -public: - typedef enum { - // Engine -> GUI Messages: - LoadStatus, // Signal GUI the current load status. - LoadStatusMidimap, // Signal GUI the current load status of the midimap. - - // GUI -> Engine, Engine -> Engine Messages: - LoadDrumKit, // Signal engine to load drumkit. - LoadMidimap, // Signal engine to load midimap. - EngineSettingsMessage, // Request or receive engine settings. - ChangeSettingMessage, // Update named setting in engine. - } type_t; - - typedef enum { - NormalProcessing, // Just add to the queue - FilterMultiple, // Ignore top message if it has the same type. - // SyncWait, // Block the send call until the message has been handled by the receiver. - } processing_mode_t; - - virtual ~Message() {} - virtual type_t type() = 0; - virtual processing_mode_t processing_mode() { return NormalProcessing; } -}; - -class LoadStatusMessage : public Message { -public: - type_t type() { return Message::LoadStatus; } - processing_mode_t processing_mode() { return FilterMultiple; } - unsigned int number_of_files; - unsigned int numer_of_files_loaded; - std::string current_file; -}; - -class LoadStatusMessageMidimap : public Message { -public: - type_t type() { return Message::LoadStatusMidimap; } - bool success; -}; - -class LoadDrumKitMessage : public Message { -public: - type_t type() { return Message::LoadDrumKit; } - std::string drumkitfile; -}; - -class LoadMidimapMessage : public Message { -public: - type_t type() { return Message::LoadMidimap; } - std::string midimapfile; -}; - -class EngineSettingsMessage : public Message { -public: - type_t type() { return Message::EngineSettingsMessage; } - std::string midimapfile; - bool midimap_loaded; - - std::string drumkitfile; - bool drumkit_loaded; - - float enable_velocity_modifier; - float velocity_modifier_falloff; - float velocity_modifier_weight; - float enable_velocity_randomiser; - float velocity_randomiser_weight; -}; - -class ChangeSettingMessage : public Message { -public: - typedef enum { - enable_velocity_modifier, - velocity_modifier_weight, - velocity_modifier_falloff, - } setting_name_t; - - ChangeSettingMessage(setting_name_t n, float v) { - name = n; - value = v; - } - - type_t type() { return Message::ChangeSettingMessage; } - - setting_name_t name; - float value; -}; - -#endif/*__DRUMGIZMO_MESSAGE_H__*/ diff --git a/src/messagehandler.cc b/src/messagehandler.cc deleted file mode 100644 index 7a0c7ea..0000000 --- a/src/messagehandler.cc +++ /dev/null @@ -1,89 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/*************************************************************************** - * messagehandler.cc - * - * Fri Jun 14 20:30:43 CEST 2013 - * Copyright 2013 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. - */ -#include "messagehandler.h" - -#include <hugin.hpp> - -#include "messagereceiver.h" - -// Global messagehandler: -MessageHandler msghandler; - -MessageHandler::MessageHandler() -{ -} - -void MessageHandler::addReceiver(message_receiver_id_t id, - MessageReceiver *receiver) -{ - MutexAutolock l(mutex); - - receivers[id] = receiver; -} - -void MessageHandler::removeReceiver(MessageReceiver *receiver) -{ - MutexAutolock l(mutex); - - std::map<message_receiver_id_t, MessageReceiver *>::iterator i = - receivers.begin(); - while(i != receivers.end()) { - if(i->second == receiver) { - receivers.erase(i); - break; - } - i++; - } -} - -bool MessageHandler::sendMessage(message_receiver_id_t id, Message* msg) -{ - MutexAutolock l(mutex); - - if(receivers.find(id) == receivers.end()) { - //WARN(msghandler, "Could not find id %d\n", id); - delete msg; - return false; - } - - //DEBUG(msghandler, "Sending message to id %d\n", id); - - MessageReceiver *receiver = receivers[id]; - /* // This code causes sporadic segfaults on windows. - if(msg->processing_mode() == Message::FilterMultiple) { - Message *pmsg; - MutexAutolock lock(receiver->message_mutex); // Make peek/receive atomic. - while( (pmsg = receiver->peekMessage()) != NULL) { - if(pmsg->type() != msg->type()) break; - // Remove all old messages with same type. - delete receiver->receiveMessage(); - } - } - */ - receiver->sendMessage(msg); - return true; -} diff --git a/src/messagehandler.h b/src/messagehandler.h deleted file mode 100644 index 2b6c40e..0000000 --- a/src/messagehandler.h +++ /dev/null @@ -1,66 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/*************************************************************************** - * messagehandler.h - * - * Fri Jun 14 20:30:43 CEST 2013 - * Copyright 2013 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. - */ -#ifndef __DRUMGIZMO_MESSAGEHANDLER_H__ -#define __DRUMGIZMO_MESSAGEHANDLER_H__ - -#include <map> - -#include "message.h" -#include "mutex.h" - -typedef enum { - MSGRCV_ENGINE = 1, - MSGRCV_UI = 2, - MSGRCV_LOADER = 3, -} message_receiver_id_t; - -class MessageReceiver; - -class MessageHandler { -public: - MessageHandler(); - - void addReceiver(message_receiver_id_t id, MessageReceiver *receiver); - void removeReceiver(MessageReceiver *receiver); - - /** - * Send Message to receiver with specified id. - * @return Return true if id is registered. Return false if id is not - * currently registered. - */ - bool sendMessage(message_receiver_id_t id, Message* msg); - -private: - std::map<message_receiver_id_t, MessageReceiver *> receivers; - - Mutex mutex; -}; - -// Global MessageHandler; -extern MessageHandler msghandler; - -#endif/*__DRUMGIZMO_MESSAGEHANDLER_H__*/ diff --git a/src/messagereceiver.cc b/src/messagereceiver.cc deleted file mode 100644 index 590c98a..0000000 --- a/src/messagereceiver.cc +++ /dev/null @@ -1,78 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/*************************************************************************** - * messagereceiver.cc - * - * Sun Jun 16 12:09:06 CEST 2013 - * Copyright 2013 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. - */ -#include "messagereceiver.h" - -#include <hugin.hpp> - -MessageReceiver::MessageReceiver(message_receiver_id_t id) -{ - msghandler.addReceiver(id, this); -} - -MessageReceiver::~MessageReceiver() -{ - msghandler.removeReceiver(this); -} - -void MessageReceiver::sendMessage(Message *msg) -{ - MutexAutolock l(message_mutex); - - message_queue.push_back(msg); -} - -Message *MessageReceiver::receiveMessage() -{ - Message *msg = NULL; - if(message_queue.size()) { - msg = message_queue.front(); - message_queue.pop_front(); - } - return msg; -} - -Message *MessageReceiver::peekMessage() -{ - Message *msg = NULL; - if(message_queue.size()) { - msg = message_queue.front(); - } - return msg; -} - -void MessageReceiver::handleMessages(size_t max) -{ - MutexAutolock l(message_mutex); - bool process_all = false; - if(max == 0) process_all = true; - - while((process_all || max--) && peekMessage()) { - Message *msg = receiveMessage(); - handleMessage(msg); - delete msg; - } -} diff --git a/src/messagereceiver.h b/src/messagereceiver.h deleted file mode 100644 index c1a8e60..0000000 --- a/src/messagereceiver.h +++ /dev/null @@ -1,75 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/*************************************************************************** - * messagereceiver.h - * - * Sun Jun 16 12:09:06 CEST 2013 - * Copyright 2013 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. - */ -#ifndef __DRUMGIZMO_MESSAGERECEIVER_H__ -#define __DRUMGIZMO_MESSAGERECEIVER_H__ - -#include <list> - -#include "mutex.h" -#include "message.h" -#include "messagehandler.h" - -class MessageReceiver { - friend class MessageHandler; -public: - MessageReceiver(message_receiver_id_t id); - ~MessageReceiver(); - - /** - * Receive message from the message queue. - */ - Message *receiveMessage(); - - /** - * Receive message from the message queue without removing it. - */ - Message *peekMessage(); - - /** - * Add a message to the message queue. - */ - void sendMessage(Message *msg); - - /** - * Handle messages from the event queue. - * @param max_number_of_events the maximum number of events to be handled in - * this call. 0 means all. - */ - void handleMessages(size_t max_number_of_events = 0); - - /** - * Handler to be implemented in child classes. - * Handles a single event. - */ - virtual void handleMessage(Message *msg) = 0; - -private: - Mutex message_mutex; - std::list<Message *> message_queue; -}; - -#endif/*__DRUMGIZMO_MESSAGERECEIVER_H__*/ diff --git a/src/midimapparser.cc b/src/midimapparser.cc index ec4c10d..cc97280 100644 --- a/src/midimapparser.cc +++ b/src/midimapparser.cc @@ -30,7 +30,8 @@ void MidiMapParser::startTag(const std::string& name, const attr_t& attr) { if(name == "map") { - if(attr.find("note") != attr.end() && attr.find("instr") != attr.end()) + if((attr.find("note") != attr.end()) && + (attr.find("instr") != attr.end())) { midimap[std::stoi(attr.at("note"))] = attr.at("instr"); } diff --git a/src/midimapparser.h b/src/midimapparser.h index 740cb60..8ec76c0 100644 --- a/src/midimapparser.h +++ b/src/midimapparser.h @@ -26,8 +26,6 @@ */ #pragma once -#include <stdio.h> - #include "saxparser.h" #include "midimapper.h" diff --git a/src/notifier.h b/src/notifier.h new file mode 100644 index 0000000..ff59741 --- /dev/null +++ b/src/notifier.h @@ -0,0 +1,163 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * notifier.h + * + * Thu Sep 3 15:48:39 CEST 2015 + * Copyright 2015 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> +#include <vector> +#include <map> +#include <set> +#include <memory> + +namespace aux +{ + template<int> + struct placeholder + { + }; +} + +namespace std +{ + template<int N> + struct is_placeholder<aux::placeholder<N>> + : integral_constant<int, N+1> + { + }; +} + +namespace aux +{ + // std::integer_sequence introduced in C++14 so remove this once we start requiring that. + + template<int... Ns> + struct int_sequence + { + }; + + template<int N, int... Ns> + struct gen_int_sequence + : gen_int_sequence<N-1, N-1, Ns...> + { + }; + + template<int... Ns> + struct gen_int_sequence<0, Ns...> + : int_sequence<Ns...> + { + }; +}; + + +//namespace GUI { + +class Listener; +class NotifierBase { +public: + virtual void disconnect(Listener* object) {} +}; + +class Listener { +public: + virtual ~Listener() + { + for(auto signal : signals) + { + signal->disconnect(this); + } + } + + void registerNotifier(NotifierBase* signal) + { + signals.insert(signal); + } + + void unregisterNotifier(NotifierBase* signal) + { + signals.erase(signal); + } + +private: + std::set<NotifierBase*> signals; +}; + +template<typename... Args> +class Notifier : public NotifierBase { +public: + Notifier() {} + + //! \brief When dtor is called it will automatically disconnect all its listeners. + ~Notifier() + { + for(auto& slot : slots) + { + slot.first->unregisterNotifier(this); + } + } + + using callback_type = std::function<void(Args...)>; + + //! \brief Connect object to this Notifier. + template<typename O, typename F> + void connect(O* p, const F& fn) + { + slots[p] = std::move(construct_mem_fn(fn, p, aux::gen_int_sequence<sizeof...(Args)>{})); + if(p && dynamic_cast<Listener*>(p)) + { + dynamic_cast<Listener*>(p)->registerNotifier(this); + } + } + + //! \brief Disconnect object from this Notifier. + void disconnect(Listener* object) + { + slots.erase(object); + } + + //! \brief Activate this notifier by pretending it is a function. + //! Example: Notifier<int> foo; foo(42); + void operator()(Args... args) + { + for(auto& slot : slots) + { + slot.second(args...); + } + } + +private: + std::map<Listener*, callback_type> slots; + + template<typename F, typename O, int... Ns> + callback_type construct_mem_fn(const F& fn, O* p, aux::int_sequence<Ns...>) const + { + return std::bind(fn, p, aux::placeholder<Ns>{}...); + } + +}; + +//} // GUI:: + +#define CONNECT(SRC, SIG, TAR, SLO) (SRC)->SIG.connect(TAR, SLO) diff --git a/src/path.cc b/src/path.cc index 43c64f0..c2e7910 100644 --- a/src/path.cc +++ b/src/path.cc @@ -35,17 +35,19 @@ std::string getPath(const std::string& file) { - std::string p; -#ifndef __MINGW32__ - char *b = strdup(file.c_str()); - p = dirname(b); - free(b); -#else + std::string path; + +#ifdef __MINGW32__ char drive[_MAX_DRIVE]; char dir[_MAX_DIR]; _splitpath(file.c_str(), drive, dir, NULL, NULL); - p = std::string(drive) + dir; + path = std::string(drive) + dir; +#else + // POSIX + char* buffer = strdup(file.c_str()); + path = dirname(buffer); + free(buffer); #endif - return p; + return path; } @@ -28,4 +28,5 @@ #include <string> +//! \returns path component of full filename with path. std::string getPath(const std::string& file); diff --git a/src/sample.cc b/src/sample.cc index 66fe3c5..ced8a47 100644 --- a/src/sample.cc +++ b/src/sample.cc @@ -65,24 +65,3 @@ AudioFile* Sample::getAudioFile(Channel* c) return nullptr; } - -#ifdef TEST_SAMPLE -// deps: channel.cc audiofile.cc -// cflags: $(SNDFILE_CFLAGS) -// libs: $(SNDFILE_LIBS) -#include "test.h" - -TEST_BEGIN; - -Sample s; -InstrumentChannel c; -InstrumentChannel c2; -AudioFile a("test"); - -s.addAudioFile(&c, &a); -TEST_EQUAL(s.getAudioFile(&c), &a, "?"); -TEST_EQUAL(s.getAudioFile(&c2), nullptr, "?"); - -TEST_END; - -#endif /*TEST_SAMPLE*/ diff --git a/src/sample.h b/src/sample.h index 5b4f3b5..f00db13 100644 --- a/src/sample.h +++ b/src/sample.h @@ -32,34 +32,22 @@ #include "channel.h" #include "audiofile.h" -typedef std::map<Channel*, AudioFile*> AudioFiles; +using AudioFiles = std::map<Channel*, AudioFile*>; -class InstrumentParser; -class Sample -{ +class Sample { friend class InstrumentParser; friend class PowerList; - public: Sample(const std::string& name, float power); ~Sample(); - AudioFile* getAudioFile(InstrumentChannel* c); + AudioFile* getAudioFile(InstrumentChannel *instrument_channel); private: - void addAudioFile(InstrumentChannel* c, AudioFile* a); + void addAudioFile(InstrumentChannel* instrument_channel, + AudioFile* audio_file); std::string name; float power; AudioFiles audiofiles; }; - -/* - * <sample name="kick-r-1"> - * <audiofile channel="Alesis-3" file="samples/1-kick-r-Alesis-3.wav"/> - * <audiofile channel="Amb L-3" file="samples/1-kick-r-Amb L-3.wav"/> - * <audiofile channel="Amb R-3" file="samples/1-kick-r-Amb R-3.wav"/> - * <audiofile channel="Kick L-3" file="samples/1-kick-r-Kick L-3.wav"/> - * <audiofile channel="Kick R-3" file="samples/1-kick-r-Kick R-3.wav"/> - * </sample> - */ diff --git a/src/saxparser.cc b/src/saxparser.cc index e32143d..280e608 100644 --- a/src/saxparser.cc +++ b/src/saxparser.cc @@ -26,29 +26,30 @@ */ #include "saxparser.h" -#include <string.h> -#include <hugin.hpp> #include <sstream> #include <iostream> +#include <hugin.hpp> + SAXParser::SAXParser() { - p = XML_ParserCreate(nullptr); - if(!p) { + parser = XML_ParserCreate(nullptr); + if(!parser) + { ERR(sax, "Couldn't allocate memory for parser\n"); // throw Exception(...); TODO return; } - XML_SetUserData(p, this); - XML_UseParserAsHandlerArg(p); - XML_SetElementHandler(p, start_hndl, end_hndl); - XML_SetCharacterDataHandler(p, character_hndl); + XML_SetUserData(parser, this); + XML_UseParserAsHandlerArg(parser); + XML_SetElementHandler(parser, SAXParser::startHandler, SAXParser::endHandler); + XML_SetCharacterDataHandler(parser, SAXParser::characterHandler); } SAXParser::~SAXParser() { - XML_ParserFree(p); + XML_ParserFree(parser); } int SAXParser::parseFile(const std::string& filename) @@ -60,7 +61,8 @@ int SAXParser::parseFile(const std::string& filename) std::ifstream file(filename, std::ifstream::in); - if(!file.is_open()) { + if(!file.is_open()) + { return 1; } @@ -68,59 +70,63 @@ int SAXParser::parseFile(const std::string& filename) ss << file.rdbuf(); std::string str = ss.str(); - parseString(str, filename); - - return 0; + return parseString(str, filename); } -int SAXParser::parseString(const std::string& str, const std::string& xml_source_name) +int SAXParser::parseString(const std::string& str, + const std::string& xml_source_name) { DEBUG(sax, "parse(buffer %d bytes)\n", (int)str.length()); - if(!XML_Parse(p, str.c_str(), str.length(), true)) { - parseError(str, XML_ErrorString(XML_GetErrorCode(p)), - xml_source_name, (int)XML_GetCurrentLineNumber(p)); + if(!XML_Parse(parser, str.c_str(), str.length(), true)) + { + parseError(str, XML_ErrorString(XML_GetErrorCode(parser)), + xml_source_name, (int)XML_GetCurrentLineNumber(parser)); return 1; } return 0; } -void SAXParser::parseError(const std::string& buf, const std::string& error, const std::string& xml_source_name, std::size_t lineno) +void SAXParser::parseError(const std::string& buf, const std::string& error, + const std::string& xml_source_name, + std::size_t lineno) { - std::cerr << "SAXParser error trying to parse from source: " << xml_source_name << "\n"; + std::cerr << "SAXParser error trying to parse from source: " << + xml_source_name << "\n"; std::cerr << "At line " << lineno << ": " << error << "\n"; std::cerr << "Buffer " << buf.size() << " bytes: \n[\n"; std::cerr << buf; std::cerr << "\n]" << std::endl; } -void SAXParser::character_hndl(void* p, const XML_Char* s, int len) +void SAXParser::characterHandler(void* parser, const XML_Char* cData, int len) { - SAXParser* parser = (SAXParser*)XML_GetUserData(p); - std::string chars(s, len); - parser->characterData(chars); + SAXParser* sax_parser = (SAXParser*)XML_GetUserData(parser); + std::string chars(cData, len); + sax_parser->characterData(chars); } -void SAXParser::start_hndl(void* p, const char* el, const char** attr) +void SAXParser::startHandler(void* parser, const char* el, const char** attr) { - SAXParser* parser = (SAXParser*)XML_GetUserData(p); + SAXParser* sax_parser = (SAXParser*)XML_GetUserData(parser); // Convert to comfy C++ values... attr_t attributes; - while(*attr) { + while(*attr) + { std::string at_name = *attr++; std::string at_value = *attr++; attributes.emplace(at_name, at_value); } - parser->startTag(std::string(el), attributes); + sax_parser->startTag(std::string(el), attributes); } -void SAXParser::end_hndl(void* p, const char* el) +void SAXParser::endHandler(void* parser, const char* el) { - SAXParser* parser = (SAXParser*)XML_GetUserData(p); - parser->endTag(std::string(el)); + SAXParser* sax_parser = (SAXParser*)XML_GetUserData(parser); + sax_parser->endTag(std::string(el)); } diff --git a/src/saxparser.h b/src/saxparser.h index 92197d1..4b1a273 100644 --- a/src/saxparser.h +++ b/src/saxparser.h @@ -31,7 +31,8 @@ #include <expat.h> #include <fstream> -class SAXParser { +class SAXParser +{ public: SAXParser(); virtual ~SAXParser(); @@ -40,7 +41,8 @@ public: virtual int parseFile(const std::string& filename); //! Parses all the data in the buffer. - virtual int parseString(const std::string& str, const std::string& xml_source_name = ""); + virtual int parseString(const std::string& str, + const std::string& xml_source_name = ""); protected: using attr_t = std::unordered_map<std::string, std::string>; @@ -48,13 +50,16 @@ protected: virtual void characterData(const std::string& data) {} virtual void startTag(const std::string& name, const attr_t& attr) {} virtual void endTag(const std::string& name) {} - virtual void parseError(const std::string& buf, const std::string& error, const std::string& xml_source_name, std::size_t lineno); + virtual void parseError(const std::string& buf, + const std::string& error, + const std::string& xml_source_name, + std::size_t lineno); private: - XML_Parser p; + XML_Parser parser; std::string filename; - static void character_hndl(void* p, const XML_Char* s, int len); - static void start_hndl(void* p, const char* el, const char** attr); - static void end_hndl(void* p, const char* el); + static void characterHandler(void* parser, const XML_Char* cData, int len); + static void startHandler(void* parser, const char* el, const char** attr); + static void endHandler(void* parser, const char* el); }; diff --git a/src/semaphore.cc b/src/semaphore.cc index cd29bbf..6172251 100644 --- a/src/semaphore.cc +++ b/src/semaphore.cc @@ -27,87 +27,101 @@ #include "semaphore.h" #include <hugin.hpp> - #include <limits> +#include <assert.h> #ifdef WIN32 #include <windows.h> #else -// Make sure we don't include /this/ file... +// Make sure we don't include /this/ files header... #include <../include/semaphore.h> +#include <errno.h> +#include <stdio.h> #endif struct semaphore_private_t { #ifdef WIN32 - HANDLE semaphore; + HANDLE semaphore; #else - sem_t semaphore; + sem_t semaphore; #endif }; -Semaphore::Semaphore(const char *name) +Semaphore::Semaphore(std::size_t initial_count) { - this->name = name; - // DEBUG(semaphore, "Create [%s]\n", name); - - prv = new struct semaphore_private_t(); + prv = new struct semaphore_private_t(); #ifdef WIN32 - prv->semaphore = CreateSemaphore(NULL, // default security attributes - 0, // initial count - std::numeric_limits<LONG>::max(), - NULL); // unnamed semaphore + prv->semaphore = CreateSemaphore(nullptr, // default security attributes + initial_count, + std::numeric_limits<LONG>::max(), + nullptr); // unnamed semaphore #else - sem_init(&prv->semaphore, 0, 0); + const int pshared = 0; + sem_init(&prv->semaphore, pshared, initial_count); #endif } Semaphore::~Semaphore() { - // DEBUG(semaphore, "Delete [%s]\n", name); - #ifdef WIN32 - CloseHandle(prv->semaphore); + CloseHandle(prv->semaphore); #else - sem_destroy(&prv->semaphore); + sem_destroy(&prv->semaphore); #endif - delete prv; + delete prv; } void Semaphore::post() { - // DEBUG(semaphore, "Post [%s]\n", name); +#ifdef WIN32 + ReleaseSemaphore(prv->semaphore, 1, NULL); +#else + sem_post(&prv->semaphore); +#endif +} +bool Semaphore::wait(const std::chrono::milliseconds& timeout) +{ #ifdef WIN32 - ReleaseSemaphore(prv->semaphore, 1, NULL); + DWORD ret = WaitForSingleObject(prv->semaphore, timeout.count()); + if(ret == WAIT_TIMEOUT) + { + return false; + } + + assert(ret == WAIT_OBJECT_0); #else - sem_post(&prv->semaphore); + struct timespec t = { + // Whole seconds: + (time_t)(timeout.count() / 1000), + + // Remainder as nanoseconds: + (long)((timeout.count() - ((timeout.count() / 1000) * 1000)) * 1000000) + }; + + int ret = sem_timedwait(&prv->semaphore, &t); + if(ret < 0) + { + if(errno == ETIMEDOUT) + { + return false; + } + + perror("sem_timedwait()"); + assert(false); + } #endif + + return true; } void Semaphore::wait() { - // DEBUG(semaphore, "Wait [%s]\n", name); - #ifdef WIN32 - WaitForSingleObject(prv->semaphore, INFINITE); + WaitForSingleObject(prv->semaphore, INFINITE); #else - sem_wait(&prv->semaphore); + sem_wait(&prv->semaphore); #endif } - -#ifdef TEST_SEMAPHORE -//deps: -//cflags: -I.. $(PTHREAD_CFLAGS) -//libs: $(PTHREAD_LIBS) -#include <test.h> - -TEST_BEGIN; - -// TODO: Put some testcode here (see test.h for usable macros). -TEST_TRUE(false, "No tests yet!"); - -TEST_END; - -#endif/*TEST_SEMAPHORE*/ diff --git a/src/semaphore.h b/src/semaphore.h index 4464898..d5995cb 100644 --- a/src/semaphore.h +++ b/src/semaphore.h @@ -24,22 +24,26 @@ * along with DrumGizmo; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -#ifndef __PRACRO_SEMAPHORE_H__ -#define __PRACRO_SEMAPHORE_H__ +#pragma once + +#include <chrono> struct semaphore_private_t; -class Semaphore { +class Semaphore +{ public: - Semaphore(const char *name = ""); - ~Semaphore(); + Semaphore(std::size_t initial_count = 0); + ~Semaphore(); + + void post(); - void post(); - void wait(); + //! Lock semaphore with timeout. + //! \returns true if the semaphore was locked, false on timeout. + bool wait(const std::chrono::milliseconds& timeout); + + void wait(); private: struct semaphore_private_t *prv{nullptr}; - const char *name{nullptr}; }; - -#endif/*__PRACRO_SEMAPHORE_H__*/ diff --git a/src/settings.h b/src/settings.h index 74c432d..6b4e882 100644 --- a/src/settings.h +++ b/src/settings.h @@ -27,52 +27,54 @@ #pragma once #include <atomic> +#include <string> #include <cassert> -template <typename T> class SettingRef -{ -public: - SettingRef(std::atomic<T>& value) - : value{value} - , cache{} - { - // string isn't lock free either - assert((std::is_same<T, std::string>::value || value.is_lock_free())); - } - - bool hasChanged() - { - T tmp = cache; - cache.exchange(value); - return tmp == cache; - } +#include "atomic.h" +#include "notifier.h" - T getValue() const - { - return cache; - } - -private: - std::atomic<T>& value; - std::atomic<T> cache; +enum class LoadStatus : unsigned int +{ + Idle, + Loading, + Done, + Error }; +//! Engine settings struct Settings { - std::atomic<bool> enable_velocity_modifier; - std::atomic<float> velocity_modifier_falloff; - std::atomic<float> velocity_modifier_weight; + Atomic<std::string> drumkit_file; + Atomic<LoadStatus> drumkit_load_status{LoadStatus::Idle}; + + Atomic<std::string> midimap_file; + Atomic<LoadStatus> midimap_load_status{LoadStatus::Idle}; + + Atomic<bool> enable_velocity_modifier{true}; + Atomic<float> velocity_modifier_falloff{0.5f}; + Atomic<float> velocity_modifier_weight{0.25f}; - std::atomic<bool> enable_velocity_randomiser; - std::atomic<float> velocity_randomiser_weight; + Atomic<bool> enable_velocity_randomiser{false}; + Atomic<float> velocity_randomiser_weight{0.1f}; - std::atomic<int> samplerate; + Atomic<double> samplerate{44100.0}; - std::atomic<bool> enable_resampling; + Atomic<bool> enable_resampling{true}; + + Atomic<std::size_t> number_of_files; + Atomic<std::size_t> number_of_files_loaded; + Atomic<std::string> current_file; }; +//! Settings getter class. struct SettingsGetter { + SettingRef<std::string> drumkit_file; + SettingRef<LoadStatus> drumkit_load_status; + + SettingRef<std::string> midimap_file; + SettingRef<LoadStatus> midimap_load_status; + SettingRef<bool> enable_velocity_modifier; SettingRef<float> velocity_modifier_falloff; SettingRef<float> velocity_modifier_weight; @@ -80,48 +82,125 @@ struct SettingsGetter SettingRef<bool> enable_velocity_randomiser; SettingRef<float> velocity_randomiser_weight; - SettingRef<int> samplerate; + SettingRef<double> samplerate; SettingRef<bool> enable_resampling; + SettingRef<std::size_t> number_of_files; + SettingRef<std::size_t> number_of_files_loaded; + SettingRef<std::string> current_file; + SettingsGetter(Settings& settings) - : enable_velocity_modifier{settings.enable_velocity_modifier} + : drumkit_file(settings.drumkit_file) + , drumkit_load_status(settings.drumkit_load_status) + , midimap_file(settings.midimap_file) + , midimap_load_status(settings.midimap_load_status) + , enable_velocity_modifier{settings.enable_velocity_modifier} , velocity_modifier_falloff{settings.velocity_modifier_falloff} , velocity_modifier_weight{settings.velocity_modifier_weight} , enable_velocity_randomiser{settings.enable_velocity_randomiser} , velocity_randomiser_weight{settings.velocity_randomiser_weight} , samplerate{settings.samplerate} , enable_resampling{settings.enable_resampling} + , number_of_files{settings.number_of_files} + , number_of_files_loaded{settings.number_of_files_loaded} + , current_file{settings.current_file} { } }; +//! Settings change notifier class. +class SettingsNotifier +{ +public: + Notifier<std::string> drumkit_file; + Notifier<LoadStatus> drumkit_load_status; + + Notifier<std::string> midimap_file; + Notifier<LoadStatus> midimap_load_status; + + Notifier<bool> enable_velocity_modifier; + Notifier<float> velocity_modifier_falloff; + Notifier<float> velocity_modifier_weight; + + Notifier<bool> enable_velocity_randomiser; + Notifier<float> velocity_randomiser_weight; + + Notifier<double> samplerate; + + Notifier<bool> enable_resampling; + + Notifier<std::size_t> number_of_files; + Notifier<std::size_t> number_of_files_loaded; + Notifier<std::string> current_file; + + void evaluate() + { +#define EVAL(x) if(settings.x.hasChanged()) { x(settings.x.getValue()); } + + EVAL(drumkit_file); + EVAL(drumkit_load_status); + + EVAL(midimap_file); + EVAL(midimap_load_status); + + EVAL(enable_velocity_modifier); + EVAL(velocity_modifier_falloff); + EVAL(velocity_modifier_weight); + + EVAL(enable_velocity_randomiser); + EVAL(velocity_randomiser_weight); + + EVAL(samplerate); + + EVAL(enable_resampling); + + EVAL(number_of_files); + EVAL(number_of_files_loaded); + EVAL(current_file); + } + + SettingsNotifier(Settings& settings) + : settings(settings) + { + } + +private: + SettingsGetter settings; +}; + // lovely reminder: NO, GLOCKE. NOOOO!! /* enum class IntParams { - Foo = 0 + Foo = 0 }; -struct Settings { - std::array<std::atomic<int>, 5> ints; +struct Settings +{ + std::array<std::atomic<int>, 5> ints; - Settings() - : ints{} { - //get(IntParams::Foo).store(3); - } + Settings() + : ints{} + { + //get(IntParams::Foo).store(3); + } - std::atomic<int>& get(IntParams param) { - return ints[(size_t)param]; - } + std::atomic<int>& get(IntParams param) + { + return ints[(size_t)param]; + } }; -struct SettingsGetter { - std::vector<SettingRef<int>> ints; +struct SettingsGetter +{ + std::vector<SettingRef<int>> ints; - SettingsGetter(Settings& parent) { - for (auto& atomic: parent.ints) { - ints.emplace_back(atomic); - } - } + SettingsGetter(Settings& parent) + { + for(auto& atomic: parent.ints) + { + ints.emplace_back(atomic); + } + } }; */ diff --git a/src/syncedsettings.h b/src/syncedsettings.h new file mode 100644 index 0000000..0fe5efd --- /dev/null +++ b/src/syncedsettings.h @@ -0,0 +1,106 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * syncedsettings.h + * + * Thu Mar 31 09:23:27 CEST 2016 + * Copyright 2016 Christian Glöckner + * cgloeckner@freenet.de + ****************************************************************************/ + +/* + * 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 <mutex> + +template <typename T> class Group; + +template <typename T> class Accessor +{ +private: + std::lock_guard<std::mutex> lock; + +public: + Accessor(Group<T>& parent) + : lock{parent.mutex} + , data(parent.data) + { + } + + T& data; +}; + +template <typename T> class Group +{ +private: + friend class Accessor<T>; + + mutable std::mutex mutex; + T data; + +public: + Group() + : mutex{} + , data{} + { + } + + Group(Group<T> const& other) + : mutex{} + , data{} + { + std::lock_guard<std::mutex> lock{other.mutex}; + data = other.data; + } + + Group(Group<T>&& other) + : mutex{} + , data{} + { + std::lock_guard<std::mutex> lock{other.mutex}; + std::swap(data, other.data); + } + + Group<T>& operator=(const Group<T>& other) + { + if (*this != &other) + { + std::lock_guard<std::mutex> lock{mutex}; + std::lock_guard<std::mutex> lock2{other.mutex}; + data = other.data; + } + return *this; + } + + Group<T>& operator=(Group<T>&& other) + { + if (*this != &other) + { + std::lock_guard<std::mutex> lock{mutex}; + std::lock_guard<std::mutex> lock2{other.mutex}; + std::swap(data, other.data); + } + return *this; + } + + operator T() const + { + std::lock_guard<std::mutex> lock{mutex}; + return data; + } +}; |