summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drumgizmo/Makefile.am18
-rw-r--r--drumgizmo/dgvalidator.cc90
-rw-r--r--src/DGDOM.h20
-rw-r--r--src/dgxmlparser.cc46
-rw-r--r--src/domloader.cc29
-rw-r--r--src/inputprocessor.cc4
-rw-r--r--src/instrument.cc39
-rw-r--r--src/instrument.h7
-rw-r--r--src/rangemap.h98
-rw-r--r--src/sample.cc6
-rw-r--r--src/sample.h8
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;
};