diff options
| author | Bent Bisballe Nyeng <deva@aasimon.org> | 2019-01-27 17:02:40 +0100 | 
|---|---|---|
| committer | Bent Bisballe Nyeng <deva@aasimon.org> | 2019-01-27 17:02:40 +0100 | 
| commit | 2aae9799e1d96d827ad156aeafa549deabd51e5d (patch) | |
| tree | 707fb2798cd3b9304fc4af690b557efc9d98a1a8 | |
| parent | 053b723adf3948d18f025efed9450d837359edd9 (diff) | |
Re-instate instrument v1.0 support.
| -rw-r--r-- | drumgizmo/Makefile.am | 18 | ||||
| -rw-r--r-- | drumgizmo/dgvalidator.cc | 90 | ||||
| -rw-r--r-- | src/DGDOM.h | 20 | ||||
| -rw-r--r-- | src/dgxmlparser.cc | 46 | ||||
| -rw-r--r-- | src/domloader.cc | 29 | ||||
| -rw-r--r-- | src/inputprocessor.cc | 4 | ||||
| -rw-r--r-- | src/instrument.cc | 39 | ||||
| -rw-r--r-- | src/instrument.h | 7 | ||||
| -rw-r--r-- | src/rangemap.h | 98 | ||||
| -rw-r--r-- | src/sample.cc | 6 | ||||
| -rw-r--r-- | src/sample.h | 8 | 
11 files changed, 339 insertions, 26 deletions
| diff --git a/drumgizmo/Makefile.am b/drumgizmo/Makefile.am index 5455726..40bddc9 100644 --- a/drumgizmo/Makefile.am +++ b/drumgizmo/Makefile.am @@ -2,7 +2,7 @@ DISTDIRS = input output  if ENABLE_CLI -bin_PROGRAMS = drumgizmo +bin_PROGRAMS = drumgizmo dgvalidator  drumgizmo_LDADD = $(JACK_LIBS) $(top_srcdir)/src/libdg.la @@ -101,4 +101,20 @@ EXTRA_DIST = \  	output/oss.h \  	output/wavfile.h +dgvalidator_LDADD = $(JACK_LIBS) $(top_srcdir)/src/libdg.la + +dgvalidator_LDFLAGS = + +dgvalidator_CXXFLAGS = \ +	-I$(top_srcdir)/src -I$(top_srcdir)/getoptpp \ +	-I$(top_srcdir)/hugin -DWITH_HUG_MUTEX -DWITH_HUG_FILTER \ +	$(SSEFLAGS) + +dgvalidator_CFLAGS = -DWITH_HUG_MUTEX -DWITH_HUG_FILTER + +dgvalidator_SOURCES = \ +	dgvalidator.cc \ +	$(top_srcdir)/hugin/hugin.c \ +	$(top_srcdir)/hugin/hugin_filter.c +  endif # ENABLE_CLI diff --git a/drumgizmo/dgvalidator.cc b/drumgizmo/dgvalidator.cc new file mode 100644 index 0000000..d0cef8d --- /dev/null +++ b/drumgizmo/dgvalidator.cc @@ -0,0 +1,90 @@ +/* -*- Mode: c++ -*- */ +/*************************************************************************** + *            dgvalidator.cc + * + *  Sun Jan 27 10:44:44 CET 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. + */ +#include <dgxmlparser.h> +#include <path.h> +#include <domloader.h> +#include <random.h> +#include <settings.h> +#include <drumkit.h> + +#include <string> +#include <hugin.hpp> + +int main(int argc, char* argv[]) +{ +	std::string edited_filename = argv[1]; +	DrumkitDOM drumkitdom; +	std::vector<InstrumentDOM> instrumentdoms; +	std::string path = getPath(edited_filename); +	bool parseerror = false; +	bool ret = parseDrumkitFile(edited_filename, drumkitdom); +	if(!ret) +	{ +		WARN(drumkitloader, "Drumkit file parser error: '%s'", +		     edited_filename.data()); +	} + +	parseerror |= !ret; + +	for(const auto& ref : drumkitdom.instruments) +	{ +		instrumentdoms.emplace_back(); +		bool ret = parseInstrumentFile(path + "/" + ref.file, instrumentdoms.back()); +		if(!ret) +		{ +			WARN(drumkitloader, "Instrument file parser error: '%s'", +			     edited_filename.data()); +		} + +		parseerror |= !ret; +	} + +	if(parseerror) +	{ +		return 1; +	} + +	Settings settings; +	Random rand; +	DrumKit kit; + +	DOMLoader domloader(settings, rand); +	ret = domloader.loadDom(path, drumkitdom, instrumentdoms, kit); +	if(!ret) +	{ +		WARN(drumkitloader, "DOMLoader error"); +		return 1; +	} +	parseerror |= !ret; +	if(parseerror) +	{ +		ERR(drumgizmo, "Drumkit parser failed: %s\n", edited_filename.c_str()); +		return 1; +	} + +	return 0; +} diff --git a/src/DGDOM.h b/src/DGDOM.h index df03515..933c250 100644 --- a/src/DGDOM.h +++ b/src/DGDOM.h @@ -31,6 +31,21 @@  #include "channel.h" +// v1.0 velocity groups + +struct SampleRefDOM +{ +	double probability; +	std::string name; +}; + +struct VelocityDOM +{ +	double upper; +	double lower; +	std::vector<SampleRefDOM> samplerefs; +}; +  // Instrument DOM:  struct AudioFileDOM @@ -43,7 +58,7 @@ struct AudioFileDOM  struct SampleDOM  {  	std::string name; -	double power; +	double power; // >= v2.0 only  	std::vector<AudioFileDOM> audiofiles;  }; @@ -60,6 +75,9 @@ struct InstrumentDOM  	std::string description;  	std::vector<SampleDOM> samples;  	std::vector<InstrumentChannelDOM> instrument_channels; + +	// v1.0 only +	std::vector<VelocityDOM> velocities;  }; diff --git a/src/dgxmlparser.cc b/src/dgxmlparser.cc index 9d3249e..fc5dbb9 100644 --- a/src/dgxmlparser.cc +++ b/src/dgxmlparser.cc @@ -179,20 +179,56 @@ bool parseInstrumentFile(const std::string& filename, InstrumentDOM& dom)  		res &= attrcpy(dom.instrument_channels.back().main, channel, "main", true);  	} +	INFO(dgxmlparser, "XML version: %s\n", dom.version.data()); +  	pugi::xml_node samples = instrument.child("samples");  	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().power, sample, "power"); + +		// Power only part of >= v2.0 instruments. +		if(dom.version == "1.0") +		{ +			dom.samples.back().power = 0.0; +		} +		else +		{ +			res &= attrcpy(dom.samples.back().power, sample, "power"); +		}  		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"); -			res &= attrcpy(dom.samples.back().audiofiles.back().file, audiofile, "file"); -			dom.samples.back().audiofiles.back().filechannel = 1; // Defaults to channel 1 in mono (1-based) -			res &= attrcpy(dom.samples.back().audiofiles.back().filechannel, audiofile, "filechannel", true); +			res &= attrcpy(dom.samples.back().audiofiles.back().instrument_channel, +			               audiofile, "channel"); +			res &= attrcpy(dom.samples.back().audiofiles.back().file, +				               audiofile, "file"); +			// 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); +		} +	} + +	// Velocity groups are only part of v1.0 instruments. +	if(dom.version == "1.0") +	{ +		pugi::xml_node velocities = instrument.child("velocities"); +		for(pugi::xml_node velocity: velocities.children("velocity")) +		{ +			dom.velocities.emplace_back(); + +			res &= attrcpy(dom.velocities.back().lower, velocity, "lower"); +			res &= attrcpy(dom.velocities.back().upper, velocity, "upper"); +			for(pugi::xml_node sampleref: velocity.children("sampleref")) +			{ +				dom.velocities.back().samplerefs.emplace_back(); +				res &= attrcpy(dom.velocities.back().samplerefs.back().probability, +				               sampleref, "probability"); +				res &= attrcpy(dom.velocities.back().samplerefs.back().name, +				               sampleref, "name"); +			}  		}  	} diff --git a/src/domloader.cc b/src/domloader.cc index 663ef75..8a133fa 100644 --- a/src/domloader.cc +++ b/src/domloader.cc @@ -165,6 +165,35 @@ bool DOMLoader::loadDom(const std::string& basepath,  				}  			} +			if(instrument->version == VersionStr(1,0,0)) +			{ +				// Version 1.0 use velocity groups +				for(auto& velocity : instrumentdom.velocities) +				{ +					for(const auto& sampleref : velocity.samplerefs) +					{ +						bool found_sample{false}; +						for(const auto& sample : instrument->samplelist) +						{ +							// TODO: What should be done with the probability?? +							if(sample->name == sampleref.name) +							{ +								instrument->addSample(velocity.lower, velocity.upper, sample); +								found_sample = true; +								break; +							} +						} +						if(!found_sample) +						{ +							ERR(kitparser, +							    "Missing sample '%s' from sampleref in instrument '%s'\n", +							    sampleref.name.data(), instrument->getName().data()); +							return false; +						} +					} +				} +			} +  			instrument->finalise();  			// Transfer ownership to the DrumKit object. diff --git a/src/inputprocessor.cc b/src/inputprocessor.cc index c004933..1570afe 100644 --- a/src/inputprocessor.cc +++ b/src/inputprocessor.cc @@ -147,7 +147,7 @@ bool InputProcessor::processOnset(event_t& event,  		}  	} -	Sample* sample = instr->sample(event.velocity, event.offset + pos); +	const auto sample = instr->sample(event.velocity, event.offset + pos);  	if(sample == nullptr)  	{ @@ -162,7 +162,7 @@ bool InputProcessor::processOnset(event_t& event,  	for(Channel& ch: kit.channels)  	{ -		AudioFile* af = sample->getAudioFile(ch); +		const auto af = sample->getAudioFile(ch);  		if(af == nullptr || !af->isValid())  		{  			//DEBUG(inputprocessor, "Missing AudioFile.\n"); diff --git a/src/instrument.cc b/src/instrument.cc index 05ac17d..29619d8 100644 --- a/src/instrument.cc +++ b/src/instrument.cc @@ -54,21 +54,44 @@ bool Instrument::isValid() const  	return this == magic;  } -Sample* Instrument::sample(level_t level, size_t pos) +const Sample* Instrument::sample(level_t level, size_t pos)  { -	return powerlist.get(level * mod); +	if(version >= VersionStr("2.0")) +	{ +		// Version 2.0 +		return powerlist.get(level * mod); +	} +	else +	{ +		// Version 1.0 +		auto s = samples.get(level * mod); +		if(s.size() == 0) +		{ +			return nullptr; +		} + +		return rand.choose(s); +	} +} + +void Instrument::addSample(level_t a, level_t b, const Sample* s) +{ +	samples.insert(a, b, s);  }  void Instrument::finalise()  { -	std::vector<Sample*>::iterator s = samplelist.begin(); -	while(s != samplelist.end()) +	if(version >= VersionStr("2.0"))  	{ -		powerlist.add(*s); -		s++; +		std::vector<Sample*>::iterator s = samplelist.begin(); +		while(s != samplelist.end()) +		{ +			powerlist.add(*s); +			s++; +		} + +		powerlist.finalise();  	} - -	powerlist.finalise();  }  const std::string& Instrument::getName() const diff --git a/src/instrument.h b/src/instrument.h index ff33d6e..6e59681 100644 --- a/src/instrument.h +++ b/src/instrument.h @@ -31,6 +31,7 @@  #include <memory>  #include <deque> +#include "rangemap.h" // for v1.0 kits  #include "powerlist.h"  #include "sample.h" @@ -45,7 +46,7 @@ public:  	Instrument(Settings& settings, Random& rand);  	~Instrument(); -	Sample* sample(level_t level, size_t pos); +	const Sample* sample(level_t level, size_t pos);  	const std::string& getName() const;  	const std::string& getDescription() const; @@ -84,7 +85,9 @@ private:  	VersionStr version; -	void addSample(level_t a, level_t b, Sample* s); +	RangeMap<level_t, const Sample*> samples; + +	void addSample(level_t a, level_t b, const Sample* s);  	void finalise(); ///< Signal instrument that no more samples will be added.  	std::vector<Sample*> samplelist; diff --git a/src/rangemap.h b/src/rangemap.h new file mode 100644 index 0000000..e53cbe8 --- /dev/null +++ b/src/rangemap.h @@ -0,0 +1,98 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + *            rangemap.h + * + *  Wed Sep 22 19:17:49 CEST 2010 + *  Copyright 2010 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 <vector> +#include <map> + +template <typename T1, typename T2> class RangeMap +{ +public: +	void insert(T1 from, T1 to, T2 value); +	std::vector<T2> get(T1 from, T1 to); +	std::vector<T2> get(T1 at); + +private: +	friend class InstrumentParserTest; +	std::multimap<std::pair<T1, T1>, T2> values; +}; + +template <typename T1, typename T2> +void RangeMap<T1, T2>::insert(T1 from, T1 to, T2 value) +{ +	if(from < to) +	{ +		values.insert(std::make_pair(std::make_pair(from, to), value)); +	} +	else +	{ +		values.insert(std::make_pair(std::make_pair(to, from), value)); +	} +} + +template <typename T1, typename T2> +std::vector<T2> RangeMap<T1, T2>::get(T1 from, T1 to) +{ +	std::vector<T2> res; + +	typename std::multimap<std::pair<T1, T1>, T2>::iterator i = values.begin(); +	while(i != values.end()) +	{ +		T1 a = i->first.first; +		T1 b = i->first.second; +		if((from >= a && to <= b) ||             // inside +		    (from <= a && to >= b) ||            // containing +		    (from <= a && to >= a && to <= b) || // overlapping lower +		    (from >= a && from <= b && to >= b)  // overlapping upper +		    ) +		{ +			res.push_back(i->second); +		} +		i++; +	} + +	return res; +} + +template <typename T1, typename T2> std::vector<T2> RangeMap<T1, T2>::get(T1 at) +{ +	std::vector<T2> res; + +	typename std::multimap<std::pair<T1, T1>, T2>::iterator i = values.begin(); +	while(i != values.end()) +	{ +		T1 a = i->first.first; +		T1 b = i->first.second; +		if(at >= a && at <= b) +		{ +			res.push_back(i->second); +		} +		i++; +	} + +	return res; +} diff --git a/src/sample.cc b/src/sample.cc index c1795e8..4d0443d 100644 --- a/src/sample.cc +++ b/src/sample.cc @@ -28,7 +28,7 @@  #include <sndfile.h> -Sample::Sample(const std::string& name, float power) +Sample::Sample(const std::string& name, double power)  	: name{name}  	, power{power}  	, audiofiles{} @@ -44,7 +44,7 @@ void Sample::addAudioFile(InstrumentChannel* c, AudioFile* a)  	audiofiles[c] = a;  } -AudioFile* Sample::getAudioFile(const Channel& channel) +AudioFile* Sample::getAudioFile(const Channel& channel) const  {  	/*  	if(audiofiles.find(c) == audiofiles.end()) return nullptr; @@ -63,7 +63,7 @@ AudioFile* Sample::getAudioFile(const Channel& channel)  	return nullptr;  } -float Sample::getPower() const +double Sample::getPower() const  {  	return power;  } diff --git a/src/sample.h b/src/sample.h index 5e41e9e..48f94ac 100644 --- a/src/sample.h +++ b/src/sample.h @@ -37,12 +37,12 @@ using AudioFiles = std::map<const InstrumentChannel*, AudioFile*>;  class Sample  {  public: -	Sample(const std::string& name, float power); +	Sample(const std::string& name, double power);  	~Sample(); -	AudioFile* getAudioFile(const Channel& channel); +	AudioFile* getAudioFile(const Channel& channel) const; -	float getPower() const; +	double getPower() const;  private:  	friend class DOMLoader; @@ -55,6 +55,6 @@ private:  	                  AudioFile* audio_file);  	std::string name; -	float power; +	double power;  	AudioFiles audiofiles;  }; | 
