summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSander Vocke <sandervocke@gmail.com>2024-07-25 09:09:35 +0200
committerSander Vocke <sandervocke@gmail.com>2024-07-25 11:06:32 +0200
commit624aafbc9cde2b9e83c7c278e44f19ab9e3bc9fc (patch)
treef6e2ef7329b32e4601326012221e0b5ce64a0367
parent019d478818950f7880d2c0f80d8fc8f963e9736b (diff)
Support curve maps in midi map file
-rw-r--r--plugin/Makefile.mingw32.in3
-rw-r--r--plugingui/powerwidget.cc1
-rw-r--r--plugingui/powerwidget.h4
-rw-r--r--src/Makefile.am6
-rw-r--r--src/audioinputenginemidi.cc73
-rw-r--r--src/curvemap.cc (renamed from src/powermap.cc)87
-rw-r--r--src/curvemap.h (renamed from src/powermap.h)65
-rw-r--r--src/midimapparser.cc24
-rw-r--r--src/midimapper.cc56
-rw-r--r--src/midimapper.h20
-rw-r--r--src/parsecurvemap.cc60
-rw-r--r--src/parsecurvemap.h (renamed from test/powermaptest.cc)36
-rw-r--r--src/powermapfilter.h4
-rw-r--r--test/Makefile.am17
-rw-r--r--test/curvemaptest.cc237
-rw-r--r--test/dgreftest/midiinputengine.cc13
-rw-r--r--test/midimapparsertest.cc50
-rw-r--r--test/midimappertest.cc77
-rw-r--r--test/translationtest_resource_data.cc72
-rwxr-xr-xtools/add_file4
20 files changed, 735 insertions, 174 deletions
diff --git a/plugin/Makefile.mingw32.in b/plugin/Makefile.mingw32.in
index ad47bcc..e932b9b 100644
--- a/plugin/Makefile.mingw32.in
+++ b/plugin/Makefile.mingw32.in
@@ -39,7 +39,8 @@ DG_SRC = \
@top_srcdir@/src/midimapper.cc \
@top_srcdir@/src/path.cc \
@top_srcdir@/src/powerlist.cc \
- @top_srcdir@/src/powermap.cc \
+ @top_srcdir@/src/curvemap.cc \
+ @top_srcdir@/src/parsecurvemap.cc \
@top_srcdir@/src/powermapfilter.cc \
@top_srcdir@/src/random.cc \
@top_srcdir@/src/sample.cc \
diff --git a/plugingui/powerwidget.cc b/plugingui/powerwidget.cc
index 9be0c48..db37561 100644
--- a/plugingui/powerwidget.cc
+++ b/plugingui/powerwidget.cc
@@ -31,7 +31,6 @@
#include <notifier.h>
#include <settings.h>
-#include <powermap.h>
#include <hugin.hpp>
#include <cmath>
diff --git a/plugingui/powerwidget.h b/plugingui/powerwidget.h
index 3a7bb8e..3d09e6b 100644
--- a/plugingui/powerwidget.h
+++ b/plugingui/powerwidget.h
@@ -34,7 +34,7 @@
#include <dggui/label.h>
#include <dggui/font.h>
-#include <powermap.h>
+#include <curvemap.h>
struct Settings;
class SettingsNotifier;
@@ -75,7 +75,7 @@ private:
virtual void mouseLeaveEvent() override;
private:
- Powermap power_map;
+ CurveMap power_map;
void parameterChangedFloat(float);
void parameterChangedBool(bool);
diff --git a/src/Makefile.am b/src/Makefile.am
index a8bdb59..9c83aab 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -67,7 +67,8 @@ libdg_la_SOURCES = \
$(top_srcdir)/src/midimapper.cc \
$(top_srcdir)/src/path.cc \
$(top_srcdir)/src/powerlist.cc \
- $(top_srcdir)/src/powermap.cc \
+ $(top_srcdir)/src/curvemap.cc \
+ $(top_srcdir)/src/parsecurvemap.cc \
$(top_srcdir)/src/powermapfilter.cc \
$(top_srcdir)/src/random.cc \
$(top_srcdir)/src/sample.cc \
@@ -126,7 +127,8 @@ EXTRA_DIST = \
path.h \
platform.h \
powerlist.h \
- powermap.h \
+ curvemap.h \
+ parsecurvemap.h \
powermapfilter.h \
random.h \
range.h \
diff --git a/src/audioinputenginemidi.cc b/src/audioinputenginemidi.cc
index 2e794f4..f0e79ed 100644
--- a/src/audioinputenginemidi.cc
+++ b/src/audioinputenginemidi.cc
@@ -108,42 +108,57 @@ void AudioInputEngineMidi::processNote(const std::uint8_t* midi_buffer,
return;
}
- auto key = midi_buffer[1]; // NOLINT - span
- auto velocity = midi_buffer[2]; // NOLINT - span
- auto instrument_idx = mmap.lookup(key);
- auto instruments = mmap.lookup(key);
- for(const auto& instrument_idx : instruments)
+ switch(midi_buffer[0] & NoteMask) // NOLINT - span
{
- switch(midi_buffer[0] & NoteMask) // NOLINT - span
- {
- case NoteOff:
- // Ignore for now
- break;
+ case NoteOff:
+ // Ignore for now
+ break;
- case NoteOn:
- if(velocity != 0)
+ case NoteOn:
+ {
+ auto key = midi_buffer[1]; // NOLINT - span
+ auto velocity = midi_buffer[2]; // NOLINT - span
+ auto map_entries = mmap.lookup(key);
+ for(const auto& entry : map_entries)
{
- constexpr float lower_offset{0.5f};
- constexpr float midi_velocity_max{127.0f};
- // maps velocities to [.5/127, 126.5/127]
- assert(velocity <= 127); // MIDI only support up to 127
- auto centered_velocity =
- (static_cast<float>(velocity) - lower_offset) / midi_velocity_max;
- events.push_back({EventType::OnSet, (std::size_t)instrument_idx,
- offset, centered_velocity});
+ auto instrument_idx = mmap.lookup_instrument(entry.instrument_name);
+ if(instrument_idx >= 0 && velocity != 0)
+ {
+ constexpr float lower_offset{0.5f};
+ constexpr float midi_velocity_max{127.0f};
+ // maps velocities to [.5/127, 126.5/127]
+ assert(velocity <= 127); // MIDI only support up to 127
+ auto centered_velocity =
+ (static_cast<float>(velocity) - lower_offset) / midi_velocity_max;
+ if (entry.maybe_curve_map)
+ {
+ centered_velocity = entry.maybe_curve_map->map(centered_velocity);
+ }
+ events.push_back({EventType::OnSet, (std::size_t)instrument_idx,
+ offset, centered_velocity});
+ }
}
- break;
+ }
+ break;
- case NoteAftertouch:
- if(velocity > 0)
+ case NoteAftertouch:
+ {
+ auto key = midi_buffer[1]; // NOLINT - span
+ auto velocity = midi_buffer[2]; // NOLINT - span
+ auto map_entries = mmap.lookup(key);
+ for(const auto& entry : map_entries)
{
- events.push_back({EventType::Choke, (std::size_t)instrument_idx,
- offset, .0f});
+ auto instrument_idx = mmap.lookup_instrument(entry.instrument_name);
+ if(instrument_idx >= 0 && velocity > 0)
+ {
+ events.push_back({EventType::Choke, (std::size_t)instrument_idx,
+ offset, .0f});
+ }
}
- break;
-
- default:
- break;
}
+ break;
+
+ default:
+ break;
}
}
diff --git a/src/powermap.cc b/src/curvemap.cc
index 2bb45b7..858c7b8 100644
--- a/src/powermap.cc
+++ b/src/curvemap.cc
@@ -24,7 +24,7 @@
* along with DrumGizmo; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-#include "powermap.h"
+#include "curvemap.h"
#include <cassert>
#include <cmath>
@@ -32,31 +32,31 @@
namespace
{
-using Power = Powermap::Power;
-using PowerPair = Powermap::PowerPair;
+using CurveValue = CurveMap::CurveValue;
+using CurveValuePair = CurveMap::CurveValuePair;
-Power h00(Power x)
+CurveValue h00(CurveValue x)
{
return (1 + 2 * x) * pow(1 - x, 2);
}
-Power h10(Power x)
+CurveValue h10(CurveValue x)
{
return x * pow(1 - x, 2);
}
-Power h01(Power x)
+CurveValue h01(CurveValue x)
{
return x * x * (3 - 2 * x);
}
-Power h11(Power x)
+CurveValue h11(CurveValue x)
{
return x * x * (x - 1);
}
-Power computeValue(const Power x, const PowerPair& P0, const PowerPair& P1,
- const Power m0, const Power m1)
+CurveValue computeValue(const CurveValue x, const CurveValuePair& P0, const CurveValuePair& P1,
+ const CurveValue m0, const CurveValue m1)
{
const auto x0 = P0.in;
const auto x1 = P1.in;
@@ -74,21 +74,25 @@ Power computeValue(const Power x, const PowerPair& P0, const PowerPair& P1,
} // end anonymous namespace
-Powermap::Powermap()
+CurveMap::CurveMap()
{
reset();
}
-Power Powermap::map(Power in)
+CurveValue CurveMap::map(CurveValue in)
{
assert(in >= 0. && in <= 1.);
+ if (invert)
+ {
+ in = 1.0 - in;
+ }
if (spline_needs_update)
{
updateSpline();
}
- Power out;
+ CurveValue out;
if (in < fixed[0].in)
{
out = shelf ? fixed[0].out
@@ -113,18 +117,19 @@ Power Powermap::map(Power in)
return out;
}
-void Powermap::reset()
+void CurveMap::reset()
{
setFixed0({eps, eps});
setFixed1({.5, .5});
setFixed2({1 - eps, 1 - eps});
// FIXME: better false?
shelf = true;
+ invert = false;
updateSpline();
}
-void Powermap::setFixed0(PowerPair new_value)
+void CurveMap::setFixed0(CurveValuePair new_value)
{
if (fixed[0] != new_value)
{
@@ -134,7 +139,7 @@ void Powermap::setFixed0(PowerPair new_value)
}
}
-void Powermap::setFixed1(PowerPair new_value)
+void CurveMap::setFixed1(CurveValuePair new_value)
{
if (fixed[1] != new_value)
{
@@ -144,7 +149,7 @@ void Powermap::setFixed1(PowerPair new_value)
}
}
-void Powermap::setFixed2(PowerPair new_value)
+void CurveMap::setFixed2(CurveValuePair new_value)
{
if (fixed[2] != new_value)
{
@@ -154,7 +159,12 @@ void Powermap::setFixed2(PowerPair new_value)
}
}
-void Powermap::setShelf(bool enable)
+void CurveMap::setInvert(bool enable)
+{
+ invert = enable;
+}
+
+void CurveMap::setShelf(bool enable)
{
if (shelf != enable)
{
@@ -163,34 +173,42 @@ void Powermap::setShelf(bool enable)
}
}
-PowerPair Powermap::getFixed0() const
+CurveValuePair CurveMap::getFixed0() const
{
return fixed[0];
}
-PowerPair Powermap::getFixed1() const
+CurveValuePair CurveMap::getFixed1() const
{
return fixed[1];
}
-PowerPair Powermap::getFixed2() const
+CurveValuePair CurveMap::getFixed2() const
{
return fixed[2];
}
+bool CurveMap::getInvert() const {
+ return invert;
+}
+
+bool CurveMap::getShelf() const {
+ return shelf;
+}
+
// This mostly followes the wikipedia article for monotone cubic splines:
// https://en.wikipedia.org/wiki/Monotone_cubic_interpolation
-void Powermap::updateSpline()
+void CurveMap::updateSpline()
{
assert(0. <= fixed[0].in && fixed[0].in < fixed[1].in &&
fixed[1].in < fixed[2].in && fixed[2].in <= 1.);
assert(0. <= fixed[0].out && fixed[0].out <= fixed[1].out &&
fixed[1].out <= fixed[2].out && fixed[2].out <= 1.);
- Powers X = shelf ? Powers{fixed[0].in, fixed[1].in, fixed[2].in}
- : Powers{0., fixed[0].in, fixed[1].in, fixed[2].in, 1.};
- Powers Y = shelf ? Powers{fixed[0].out, fixed[1].out, fixed[2].out}
- : Powers{0., fixed[0].out, fixed[1].out, fixed[2].out, 1.};
+ CurveValues X = shelf ? CurveValues{fixed[0].in, fixed[1].in, fixed[2].in}
+ : CurveValues{0., fixed[0].in, fixed[1].in, fixed[2].in, 1.};
+ CurveValues Y = shelf ? CurveValues{fixed[0].out, fixed[1].out, fixed[2].out}
+ : CurveValues{0., fixed[0].out, fixed[1].out, fixed[2].out, 1.};
auto slopes = calcSlopes(X, Y);
@@ -215,12 +233,12 @@ void Powermap::updateSpline()
// This follows the monotone cubic spline algorithm of Steffen, from:
// "A Simple Method for Monotonic Interpolation in One Dimension"
-std::vector<float> Powermap::calcSlopes(const Powers& X, const Powers& Y)
+std::vector<float> CurveMap::calcSlopes(const CurveValues& X, const CurveValues& Y)
{
- Powers m(X.size());
+ CurveValues m(X.size());
- Powers d(X.size() - 1);
- Powers h(X.size() - 1);
+ CurveValues d(X.size() - 1);
+ CurveValues h(X.size() - 1);
for (std::size_t i = 0; i < d.size(); ++i)
{
h[i] = X[i + 1] - X[i];
@@ -245,7 +263,16 @@ std::vector<float> Powermap::calcSlopes(const Powers& X, const Powers& Y)
return m;
}
-Power Powermap::clamp(Power in, Power min, Power max) const
+CurveValue CurveMap::clamp(CurveValue in, CurveValue min, CurveValue max) const
{
return std::max(min, std::min(in, max));
}
+
+bool CurveMap::operator==(const CurveMap& other) const
+{
+ return getFixed0() == other.getFixed0() &&
+ getFixed1() == other.getFixed1() &&
+ getFixed2() == other.getFixed2() &&
+ getShelf() == other.getShelf() &&
+ getInvert() == other.getInvert();
+}
diff --git a/src/powermap.h b/src/curvemap.h
index 3a406cc..c058bab 100644
--- a/src/powermap.h
+++ b/src/curvemap.h
@@ -1,6 +1,6 @@
/* -*- Mode: c++ -*- */
/***************************************************************************
- * powermap.h
+ * curvemap.h
*
* Fri Apr 17 23:06:12 CEST 2020
* Copyright 2020 André Nusser
@@ -29,48 +29,71 @@
#include <array>
#include <vector>
-class Powermap
+class CurveMapTestAccessor;
+
+class CurveMap
{
+ friend class CurveMapTestAccessor;
public:
- using Power = float;
- using Powers = std::vector<Power>;
- struct PowerPair
+ using CurveValue = float;
+ using CurveValues = std::vector<CurveValue>;
+
+ bool operator==(const CurveMap& other) const;
+
+ struct CurveValuePair
{
- Power in;
- Power out;
+ CurveValue in;
+ CurveValue out;
- bool operator!=(const PowerPair& other)
+ bool operator==(const CurveValuePair& other)
+ {
+ return in == other.in || out == other.out;
+ }
+ bool operator!=(const CurveValuePair& other)
{
- return in != other.in || out != other.out;
+ return !(*this == other);
}
};
- Powermap();
+ CurveMap();
- Power map(Power in);
+ CurveValue map(CurveValue in);
void reset();
- void setFixed0(PowerPair new_value);
- void setFixed1(PowerPair new_value);
- void setFixed2(PowerPair new_value);
+ void setFixed0(CurveValuePair new_value);
+ void setFixed1(CurveValuePair new_value);
+ void setFixed2(CurveValuePair new_value);
void setShelf(bool enable);
- PowerPair getFixed0() const;
- PowerPair getFixed1() const;
- PowerPair getFixed2() const;
+ //! If enabled, inversion inverts (1 - x) the input value before mapping
+ //! it through the curve.
+ void setInvert(bool enable);
+
+ CurveValuePair getFixed0() const;
+ CurveValuePair getFixed1() const;
+ CurveValuePair getFixed2() const;
+ bool getShelf() const;
+ bool getInvert() const;
private:
// input parameters (state of this class)
- std::array<PowerPair, 3> fixed;
+ std::array<CurveValuePair, 3> fixed;
bool shelf;
+ bool invert;
// spline parameters (deterministically computed from the input parameters)
bool spline_needs_update;
std::array<float, 5> m;
- const Power eps = 1e-4;
+ static constexpr CurveValue eps = 1e-4;
void updateSpline();
- std::vector<float> calcSlopes(const Powers& X, const Powers& P);
+ std::vector<float> calcSlopes(const CurveValues& X, const CurveValues& P);
+
+ CurveValue clamp(CurveValue in, CurveValue min, CurveValue max) const;
+};
- Power clamp(Power in, Power min, Power max) const;
+class CurveMapTestAccessor
+{
+public:
+ static constexpr CurveMap::CurveValue eps = CurveMap::eps;
};
diff --git a/src/midimapparser.cc b/src/midimapparser.cc
index 363e1d5..70dfbc0 100644
--- a/src/midimapparser.cc
+++ b/src/midimapparser.cc
@@ -25,10 +25,13 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
#include "midimapparser.h"
+#include "parsecurvemap.h"
#include <pugixml.hpp>
#include <hugin.hpp>
+#include <cpp11fix.h>
+
bool MidiMapParser::parseFile(const std::string& filename)
{
pugi::xml_document doc;
@@ -42,15 +45,26 @@ bool MidiMapParser::parseFile(const std::string& filename)
pugi::xml_node midimap_node = doc.child("midimap");
for(pugi::xml_node map_node : midimap_node.children("map"))
{
- constexpr int bad_value = 10000;
- auto note = map_node.attribute("note").as_int(bad_value);
- auto instr = map_node.attribute("instr").as_string();
- if(std::string(instr) == "" || note == bad_value)
+ constexpr int default_int = 10000;
+ auto note = map_node.attribute("note").as_int(default_int);
+ auto instr = std::string(map_node.attribute("instr").as_string());
+
+ std::unique_ptr<CurveMap> maybe_curve;
+ auto maybe_curve_node = map_node.child("curve");
+ if (maybe_curve_node) {
+ CurveMap curve;
+ if (parse_curve_map (maybe_curve_node, curve)) {
+ maybe_curve = std::make_unique<CurveMap>();
+ *maybe_curve = curve;
+ }
+ }
+
+ if(std::string(instr) == "" || note == default_int)
{
continue;
}
- MidimapEntry entry{note, instr};
+ MidimapEntry entry(note, instr, maybe_curve.get());
midimap.push_back(entry);
}
diff --git a/src/midimapper.cc b/src/midimapper.cc
index 345ce2f..8b44dde 100644
--- a/src/midimapper.cc
+++ b/src/midimapper.cc
@@ -25,26 +25,64 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
#include "midimapper.h"
+#include <set>
-std::vector<int> MidiMapper::lookup(int note_id)
+#include <cpp11fix.h>
+
+MidimapEntry::MidimapEntry(int note_id,
+ std::string instrument_name,
+ CurveMap *maybe_curve_map) :
+ note_id(note_id)
+ , instrument_name(instrument_name)
+{
+ if (maybe_curve_map)
+ {
+ this->maybe_curve_map = std::make_unique<CurveMap>(*maybe_curve_map);
+ }
+}
+
+MidimapEntry::MidimapEntry(const MidimapEntry& other)
+{
+ *this = other;
+}
+
+MidimapEntry &MidimapEntry::operator=(const MidimapEntry& other)
+{
+ note_id = other.note_id;
+ instrument_name = other.instrument_name;
+ if (other.maybe_curve_map)
+ {
+ maybe_curve_map = std::make_unique<CurveMap>(*other.maybe_curve_map);
+ }
+
+ return *this;
+}
+
+int MidiMapper::lookup_instrument(std::string name) {
+ const std::lock_guard<std::mutex> guard(mutex);
+ auto instrmap_it = instrmap.find(name);
+ if(instrmap_it != instrmap.end())
+ {
+ return instrmap_it->second;
+ }
+ return -1;
+}
+
+std::vector<MidimapEntry> MidiMapper::lookup(int note_id)
{
- std::vector<int> instruments;
+ std::vector<MidimapEntry> rval;
const std::lock_guard<std::mutex> guard(mutex);
for(const auto& map_entry : midimap)
{
- if(map_entry.note_id == note_id)
+ if(note_id == map_entry.note_id)
{
- auto instrmap_it = instrmap.find(map_entry.instrument_name);
- if(instrmap_it != instrmap.end())
- {
- instruments.push_back(instrmap_it->second);
- }
+ rval.push_back(map_entry);
}
}
- return instruments;
+ return rval;
}
void MidiMapper::swap(instrmap_t& instrmap, midimap_t& midimap)
diff --git a/src/midimapper.h b/src/midimapper.h
index 94781d4..ee1e8d0 100644
--- a/src/midimapper.h
+++ b/src/midimapper.h
@@ -30,11 +30,24 @@
#include <string>
#include <mutex>
#include <vector>
+#include <memory>
+
+#include "curvemap.h"
struct MidimapEntry
{
int note_id;
std::string instrument_name;
+
+ //! An optional curve map which will map the given velocity
+ //! or CC value to a new value.
+ std::unique_ptr<CurveMap> maybe_curve_map;
+
+ MidimapEntry &operator=(const MidimapEntry& other);
+ MidimapEntry(const MidimapEntry& other);
+ MidimapEntry(int note_id,
+ std::string instrument_name,
+ CurveMap *maybe_curve_map = nullptr);
};
using midimap_t = std::vector<MidimapEntry>;
@@ -43,8 +56,11 @@ using instrmap_t = std::map<std::string, int>;
class MidiMapper
{
public:
- //! Lookup note in map and returns the corresponding instrument index list.
- std::vector<int> lookup(int note_id);
+ //! Lookup midi map entries matching the given note.
+ std::vector<MidimapEntry> lookup(int note_id);
+
+ //! Lookup instrument by name.
+ int lookup_instrument(std::string name);
//! Set new map sets.
void swap(instrmap_t& instrmap, midimap_t& midimap);
diff --git a/src/parsecurvemap.cc b/src/parsecurvemap.cc
new file mode 100644
index 0000000..f6862e1
--- /dev/null
+++ b/src/parsecurvemap.cc
@@ -0,0 +1,60 @@
+/* -*- Mode: c++ -*- */
+/***************************************************************************
+ * parsecurvemap.cc
+ *
+ * Wed Jul 24 12:55:00 CEST 2024
+ * Copyright 2024 Sander Vocke
+ *
+ ****************************************************************************/
+
+/*
+ * 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 "parsecurvemap.h"
+
+bool parse_curve_map(pugi::xml_node curvemap_node, CurveMap &out)
+{
+ CurveMap rval;
+
+ if(curvemap_node.attribute("shelf")) {
+ rval.setShelf(curvemap_node.attribute("shelf").as_bool(true));
+ }
+ if(curvemap_node.attribute("invert")) {
+ rval.setInvert(curvemap_node.attribute("invert").as_bool(false));
+ }
+ if(curvemap_node.attribute("in2") && curvemap_node.attribute("out2")) {
+ rval.setFixed2( CurveMap::CurveValuePair{
+ curvemap_node.attribute("in2").as_float(0.0f),
+ curvemap_node.attribute("out2").as_float(0.0f)
+ });
+ }
+ if(curvemap_node.attribute("in1") && curvemap_node.attribute("out1")) {
+ rval.setFixed1( CurveMap::CurveValuePair{
+ curvemap_node.attribute("in1").as_float(0.0f),
+ curvemap_node.attribute("out1").as_float(0.0f)
+ });
+ }
+ if(curvemap_node.attribute("in0") && curvemap_node.attribute("out0")) {
+ rval.setFixed0( CurveMap::CurveValuePair{
+ curvemap_node.attribute("in0").as_float(0.0f),
+ curvemap_node.attribute("out0").as_float(0.0f)
+ });
+ }
+
+ out = rval;
+ return true;
+} \ No newline at end of file
diff --git a/test/powermaptest.cc b/src/parsecurvemap.h
index bef5bdc..a6f0429 100644
--- a/test/powermaptest.cc
+++ b/src/parsecurvemap.h
@@ -1,10 +1,10 @@
/* -*- Mode: c++ -*- */
/***************************************************************************
- * powermaptest.cc
+ * parsecurvemap.h
+ *
+ * Wed Jul 24 12:55:00 CEST 2024
+ * Copyright 2024 Sander Vocke
*
- * Sun Apr 19 23:23:37 CEST 2020
- * Copyright 2020 André Nusser
- * andre.nusser@googlemail.com
****************************************************************************/
/*
@@ -24,28 +24,10 @@
* along with DrumGizmo; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-#include <uunit.h>
-
-#include "../src/powermap.h"
-
-class test_powermaptest
- : public uUnit
-{
-public:
- test_powermaptest()
- {
- uUNIT_TEST(test_powermaptest::check_values);
- }
-
- void check_values()
- {
- Powermap powermap;
+#pragma once
- // TODO
- // std::cout << powermap.map(.8) << std::endl;
- // uUNIT_ASSERT_EQUAL(powermap.map(.8), .8);
- }
-};
+#include <pugixml.hpp>
+#include "curvemap.h"
-// Registers the fixture into the 'registry'
-static test_powermaptest test;
+// Returns true if success (out is replaced), false if failure (out unchanged)
+bool parse_curve_map(pugi::xml_node curvemap_node, CurveMap &out); \ No newline at end of file
diff --git a/src/powermapfilter.h b/src/powermapfilter.h
index 263f809..b9dfe5b 100644
--- a/src/powermapfilter.h
+++ b/src/powermapfilter.h
@@ -27,7 +27,7 @@
#pragma once
#include "inputfilter.h"
-#include "powermap.h"
+#include "curvemap.h"
struct Settings;
@@ -43,5 +43,5 @@ public:
private:
Settings& settings;
- Powermap powermap;
+ CurveMap powermap;
};
diff --git a/test/Makefile.am b/test/Makefile.am
index 15ceb7d..5550816 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -8,7 +8,7 @@ TESTS = resource enginetest paintertest configfile audiocache \
randomtest atomictest syncedsettingstest imagecachetest \
semaphoretest drumkitcreatortest bytesizeparsertest notifiertest \
dgxmlparsertest domloadertest configparsertest midimapparsertest \
- eventsdstest powermaptest midimappertest
+ eventsdstest curvemaptest midimappertest
if WITH_NLS
TESTS += translationtest
@@ -314,6 +314,9 @@ midimapparsertest_LDFLAGS =
midimapparsertest_SOURCES = \
$(top_srcdir)/hugin/hugin.c \
$(top_srcdir)/src/midimapparser.cc \
+ $(top_srcdir)/src/curvemap.cc \
+ $(top_srcdir)/src/parsecurvemap.cc \
+ $(top_srcdir)/src/midimapper.cc \
$(top_srcdir)/pugixml/src/pugixml.cpp \
scopedfile.cc \
midimapparsertest.cc \
@@ -329,14 +332,14 @@ eventsdstest_SOURCES = \
eventsdstest.cc \
uunit/uunit.cc
-powermaptest_CXXFLAGS = \
- -I$(top_srcdir)/test/uunit -DOUTPUT=\"powermaptest\" \
+curvemaptest_CXXFLAGS = \
+ -I$(top_srcdir)/test/uunit -DOUTPUT=\"curvemaptest\" \
$(DEBUG_FLAGS) \
-I$(top_srcdir)/src
-powermaptest_LDFLAGS =
-powermaptest_SOURCES = \
- $(top_srcdir)/src/powermap.cc \
- powermaptest.cc \
+curvemaptest_LDFLAGS =
+curvemaptest_SOURCES = \
+ $(top_srcdir)/src/curvemap.cc \
+ curvemaptest.cc \
uunit/uunit.cc
midimappertest_CXXFLAGS = \
diff --git a/test/curvemaptest.cc b/test/curvemaptest.cc
new file mode 100644
index 0000000..8bbfa10
--- /dev/null
+++ b/test/curvemaptest.cc
@@ -0,0 +1,237 @@
+/* -*- Mode: c++ -*- */
+/***************************************************************************
+ * curvemaptest.cc
+ *
+ * Sun Apr 19 23:23:37 CEST 2020
+ * Copyright 2020 André Nusser
+ * andre.nusser@googlemail.com
+ ****************************************************************************/
+
+/*
+ * 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 <uunit.h>
+#include <map>
+
+#include "../src/curvemap.h"
+#include <iostream>
+#include <iomanip>
+
+class test_curvemaptest
+ : public uUnit
+{
+public:
+ test_curvemaptest()
+ {
+ uUNIT_TEST(test_curvemaptest::check_default);
+ uUNIT_TEST(test_curvemaptest::check_default_invert);
+ uUNIT_TEST(test_curvemaptest::check_default_disabled_shelf);
+ uUNIT_TEST(test_curvemaptest::check_default_disabled_shelf_invert);
+ uUNIT_TEST(test_curvemaptest::check_fixed1_075_025);
+ uUNIT_TEST(test_curvemaptest::check_fixed1_075_025_invert);
+ uUNIT_TEST(test_curvemaptest::check_shelf_060);
+ uUNIT_TEST(test_curvemaptest::check_shelf_060_invert);
+ // uUNIT_TEST(test_curvemaptest::check_fixed0_075_025_invert);
+ }
+
+ static constexpr auto eps = CurveMapTestAccessor::eps;
+
+ const std::map<double, double> default_map = {
+ {0.0, eps},
+ {eps, eps},
+ {0.1, 0.1},
+ {0.2, 0.2},
+ {0.3, 0.3},
+ {0.4, 0.4},
+ {0.5, 0.5},
+ {0.6, 0.6},
+ {0.7, 0.7},
+ {0.8, 0.8},
+ {0.9, 0.9},
+ {1.0 - eps, 1.0 - eps},
+ {1.0, 1.0 - eps}
+ };
+
+ const std::map<double, double> identity_map = {
+ {0.0, 0.0},
+ {0.1, 0.1},
+ {0.2, 0.2},
+ {0.3, 0.3},
+ {0.4, 0.4},
+ {0.5, 0.5},
+ {0.6, 0.6},
+ {0.7, 0.7},
+ {0.8, 0.8},
+ {0.9, 0.9},
+ {1.0, 1.0}
+ };
+
+ const std::map<double, double> fixed1_075_025_map = {
+ {0.0, eps},
+ {eps, eps},
+ {0, 0.0001},
+ {0.1, 0.0295469705015421},
+ {0.2, 0.0536915548145771},
+ {0.3, 0.0760560110211372},
+ {0.4, 0.100195862352848},
+ {0.5, 0.129666686058044},
+ {0.6, 0.168024003505707},
+ {0.7, 0.218823373317719},
+ {0.8, 0.325357049703598},
+ {0.9, 0.64416378736496},
+ {1.0 - eps, 1.0 - eps},
+ {1.0, 1.0 - eps}
+ };
+
+ const std::map<double, double> shelf_060_map = {
+ {0.0, eps},
+ {eps, eps},
+ {0.1, 0.1},
+ {0.2, 0.2},
+ {0.3, 0.3},
+ {0.4, 0.4},
+ {0.5, 0.5},
+ {0.6, 0.6},
+ {0.7, 0.6},
+ {0.8, 0.6},
+ {0.9, 0.6},
+ {1.0, 0.6}
+ };
+
+ void check_default()
+ {
+ auto dataset = this->default_map;
+
+ CurveMap map;
+
+ for (auto& entry : dataset) {
+ auto in = entry.first;
+ auto expect = entry.second;
+ uASSERT_EQUAL(expect, map.map(in));
+ }
+ }
+
+ void check_default_invert()
+ {
+ auto dataset = this->default_map;
+
+ CurveMap map;
+ map.setInvert(true);
+
+ for (auto& entry : dataset) {
+ auto in = 1.0 - entry.first;
+ auto expect = entry.second;
+ uASSERT_EQUAL(expect, map.map(in));
+ }
+ }
+
+ void check_default_disabled_shelf()
+ {
+ auto dataset = this->identity_map;
+
+ CurveMap map;
+ map.setShelf(false);
+ map.setFixed2({0.6, 0.6});
+
+ for (auto& entry : dataset) {
+ auto in = entry.first;
+ auto expect = entry.second;
+ // std::cout << "{" << in << ", " << std::setprecision (15) << map.map(in) << "}," << std::endl; // FIXME
+ uASSERT_EQUAL(expect, map.map(in));
+ }
+ }
+
+ void check_default_disabled_shelf_invert()
+ {
+ auto dataset = this->identity_map;
+
+ CurveMap map;
+ map.setShelf(false);
+ map.setFixed2({0.6, 0.6});
+ map.setInvert(true);
+
+ for (auto& entry : dataset) {
+ auto in = 1.0 - entry.first;
+ auto expect = entry.second;
+ uASSERT_EQUAL(expect, map.map(in));
+ }
+ }
+
+ void check_fixed1_075_025()
+ {
+ auto dataset = this->fixed1_075_025_map;
+
+ CurveMap map;
+ map.setFixed1({0.75, 0.25});
+
+ for (auto& entry : dataset) {
+ auto in = entry.first;
+ auto expect = entry.second;
+ // std::cout << "{" << in << ", " << std::setprecision (15) << map.map(in) << "}," << std::endl; // FIXME
+ uASSERT_EQUAL(expect, map.map(in));
+ }
+ }
+
+ void check_fixed1_075_025_invert()
+ {
+ auto dataset = this->fixed1_075_025_map;
+
+ CurveMap map;
+ map.setFixed1({0.75, 0.25});
+ map.setInvert(true);
+
+ for (auto& entry : dataset) {
+ auto in = 1.0 - entry.first;
+ auto expect = entry.second;
+ uASSERT_EQUAL(expect, map.map(in));
+ }
+ }
+
+ void check_shelf_060()
+ {
+ auto dataset = this->shelf_060_map;
+
+ CurveMap map;
+ map.setFixed2({0.6, 0.6});
+ map.setShelf(true);
+
+ for (auto& entry : dataset) {
+ auto in = entry.first;
+ auto expect = entry.second;
+ uASSERT_EQUAL(expect, map.map(in));
+ }
+ }
+
+ void check_shelf_060_invert()
+ {
+ auto dataset = this->shelf_060_map;
+
+ CurveMap map;
+ map.setFixed2({0.6, 0.6});
+ map.setShelf(true);
+ map.setInvert(true);
+
+ for (auto& entry : dataset) {
+ auto in = 1.0 - entry.first;
+ auto expect = entry.second;
+ uASSERT_EQUAL(expect, map.map(in));
+ }
+ }
+};
+
+// Registers the fixture into the 'registry'
+static test_curvemaptest test;
diff --git a/test/dgreftest/midiinputengine.cc b/test/dgreftest/midiinputengine.cc
index dbffec9..4827e5f 100644
--- a/test/dgreftest/midiinputengine.cc
+++ b/test/dgreftest/midiinputengine.cc
@@ -155,9 +155,14 @@ void MidifileInputEngine::run(size_t pos, size_t len, std::vector<event_t>& even
int key = current_event->midi_buffer[1];
int velocity = current_event->midi_buffer[2];
- auto instruments = mmap.lookup(key);
- for(const auto& instrument_idx : instruments)
+ auto entries = mmap.lookup(key);
+ for(const auto& entry : entries)
{
+ auto instrument_idx = mmap.lookup_instrument(entry.instrument_name);
+ if (instrument_idx < 0)
+ {
+ continue;
+ }
events.emplace_back();
auto& event = events.back();
event.type = EventType::OnSet;
@@ -165,6 +170,10 @@ void MidifileInputEngine::run(size_t pos, size_t len, std::vector<event_t>& even
event.offset = evpos - pos;
event.instrument = instrument_idx;
event.velocity = velocity / 127.0;
+ if (entry.maybe_curve_map)
+ {
+ event.velocity = entry.maybe_curve_map->map(event.velocity);
+ }
}
}
}
diff --git a/test/midimapparsertest.cc b/test/midimapparsertest.cc
index 3e77c44..0b892e9 100644
--- a/test/midimapparsertest.cc
+++ b/test/midimapparsertest.cc
@@ -27,6 +27,7 @@
#include <uunit.h>
#include <midimapparser.h>
+#include <curvemap.h>
#include "scopedfile.h"
@@ -36,11 +37,12 @@ class MidimapParserTest
public:
MidimapParserTest()
{
- uTEST(MidimapParserTest::test);
- uTEST(MidimapParserTest::invalid);
+ uTEST(MidimapParserTest::test_basic);
+ uTEST(MidimapParserTest::test_curve);
+ uTEST(MidimapParserTest::test_invalid);
}
- void test()
+ void test_basic()
{
ScopedFile scoped_file(
"<?xml version='1.0' encoding='UTF-8'?>\n" \
@@ -80,7 +82,47 @@ public:
uASSERT_EQUAL(std::string("Hihat_closed"), midimap[5].instrument_name);
}
- void invalid()
+ void test_curve()
+ {
+ ScopedFile scoped_file(
+ "<?xml version='1.0' encoding='UTF-8'?>\n" \
+ "<midimap>\n" \
+ " <map note=\"56\" instr=\"Hihat_closed\"/>\n" \
+ " <map note=\"40\" instr=\"Kick\">\n" \
+ " <curve in0=\"0.1\" out0=\"0.2\" in1=\"0.5\" out1=\"0.6\" in2=\"0.8\" out2=\"0.9\" invert=\"true\" shelf=\"false\"/>\n" \
+ " </map>\n" \
+ " <map note=\"41\" instr=\"Snare\">\n" \
+ " <curve/>\n" \
+ " </map>\n" \
+ "</midimap>");
+
+ MidiMapParser parser;
+ uASSERT(parser.parseFile(scoped_file.filename()));
+
+ const auto& midimap = parser.midimap;
+ uASSERT_EQUAL(3u, midimap.size());
+
+ uASSERT_EQUAL(56, midimap[0].note_id);
+ uASSERT(!midimap[0].maybe_curve_map);
+
+ uASSERT_EQUAL(40, midimap[1].note_id);
+ uASSERT(midimap[1].maybe_curve_map.get());
+ uASSERT_EQUAL(true, midimap[1].maybe_curve_map->getInvert());
+ uASSERT_EQUAL(false, midimap[1].maybe_curve_map->getShelf());
+ uASSERT_EQUAL(0.1, midimap[1].maybe_curve_map->getFixed0().in);
+ uASSERT_EQUAL(0.2, midimap[1].maybe_curve_map->getFixed0().out);
+ uASSERT_EQUAL(0.5, midimap[1].maybe_curve_map->getFixed1().in);
+ uASSERT_EQUAL(0.6, midimap[1].maybe_curve_map->getFixed1().out);
+ uASSERT_EQUAL(0.8, midimap[1].maybe_curve_map->getFixed2().in);
+ uASSERT_EQUAL(0.9, midimap[1].maybe_curve_map->getFixed2().out);
+
+ uASSERT_EQUAL(41, midimap[2].note_id);
+ CurveMap reference_map;
+ uASSERT(midimap[2].maybe_curve_map.get());
+ uASSERT(reference_map == *midimap[2].maybe_curve_map);
+ }
+
+ void test_invalid()
{
ScopedFile scoped_file(
"<?xml version='1.0' encoding='UTF-8'?>\n" \
diff --git a/test/midimappertest.cc b/test/midimappertest.cc
index 703c646..bf80266 100644
--- a/test/midimappertest.cc
+++ b/test/midimappertest.cc
@@ -26,6 +26,7 @@
#include <uunit.h>
#include <algorithm>
+#include <vector>
#include <midimapper.h>
@@ -45,12 +46,12 @@ public:
{
midimap_t midimap
{
- { 54, "Crash_left_tip" },
- { 60, "Crash_left_whisker" },
- { 55, "Crash_right_tip" },
- { 62, "Crash_right_whisker" },
- { 62, "Hihat_closed" },
- { 56, "Hihat_closed" },
+ MidimapEntry(54, "Crash_left_tip"),
+ MidimapEntry(60, "Crash_left_whisker"),
+ MidimapEntry(55, "Crash_right_tip"),
+ MidimapEntry(62, "Crash_right_whisker"),
+ MidimapEntry(62, "Hihat_closed"),
+ MidimapEntry(56, "Hihat_closed"),
};
instrmap_t instrmap
@@ -66,35 +67,48 @@ public:
mapper.swap(instrmap, midimap);
{
- auto is = mapper.lookup(54);
- uASSERT_EQUAL(1u, is.size());
- uASSERT_EQUAL(0, is[0]);
+ auto es = mapper.lookup(54);
+ uASSERT_EQUAL(1u, es.size());
+
+ auto i = mapper.lookup_instrument(es[0].instrument_name);
+ uASSERT_EQUAL(0, i);
}
{
- auto is = mapper.lookup(60);
- uASSERT_EQUAL(1u, is.size());
- uASSERT_EQUAL(1, is[0]);
+ auto es = mapper.lookup(60);
+ uASSERT_EQUAL(1u, es.size());
+
+ auto i = mapper.lookup_instrument(es[0].instrument_name);
+ uASSERT_EQUAL(1, i);
}
{
- auto is = mapper.lookup(55);
- uASSERT_EQUAL(1u, is.size());
- uASSERT_EQUAL(2, is[0]);
+ auto es = mapper.lookup(55);
+ uASSERT_EQUAL(1u, es.size());
+
+ auto i = mapper.lookup_instrument(es[0].instrument_name);
+ uASSERT_EQUAL(2, i);
}
{
- auto is = mapper.lookup(62);
- uASSERT_EQUAL(2u, is.size());
+ auto es = mapper.lookup(62);
+ uASSERT_EQUAL(2u, es.size());
+
+ std::vector<int> is;
+ is.push_back(mapper.lookup_instrument(es[0].instrument_name));
+ is.push_back(mapper.lookup_instrument(es[1].instrument_name));
+
// We don't care about the order, so just count the instances
uASSERT_EQUAL(1u, std::count(is.begin(), is.end(), 3));
uASSERT_EQUAL(1u, std::count(is.begin(), is.end(), 4));
}
{
- auto is = mapper.lookup(56);
- uASSERT_EQUAL(1u, is.size());
- uASSERT_EQUAL(4, is[0]);
+ auto es = mapper.lookup(56);
+ uASSERT_EQUAL(1u, es.size());
+
+ auto i = mapper.lookup_instrument(es[0].instrument_name);
+ uASSERT_EQUAL(4, i);
}
}
@@ -102,12 +116,12 @@ public:
{
midimap_t midimap
{
- { 54, "Crash_left_tip" },
- { 60, "Crash_left_whisker_MISSING" },
- { 55, "Crash_right_tip" },
- { 62, "Crash_right_whisker" },
- { 62, "Hihat_closed" },
- { 56, "Hihat_closed" },
+ MidimapEntry(54, "Crash_left_tip" ),
+ MidimapEntry(60, "Crash_left_whisker_MISSING" ),
+ MidimapEntry(55, "Crash_right_tip" ),
+ MidimapEntry(62, "Crash_right_whisker" ),
+ MidimapEntry(62, "Hihat_closed" ),
+ MidimapEntry(56, "Hihat_closed" ),
};
instrmap_t instrmap
@@ -124,14 +138,17 @@ public:
// no such note id
{
- auto is = mapper.lookup(42);
- uASSERT_EQUAL(0u, is.size());
+ auto es = mapper.lookup(42);
+ uASSERT_EQUAL(0u, es.size());
}
// no such instrument
{
- auto is = mapper.lookup(60);
- uASSERT_EQUAL(0u, is.size());
+ auto es = mapper.lookup(60);
+ uASSERT_EQUAL(1u, es.size());
+
+ auto is = mapper.lookup_instrument(es[0].instrument_name);
+ uASSERT_EQUAL(-1, is);
}
}
};
diff --git a/test/translationtest_resource_data.cc b/test/translationtest_resource_data.cc
new file mode 100644
index 0000000..7e25737
--- /dev/null
+++ b/test/translationtest_resource_data.cc
@@ -0,0 +1,72 @@
+/* This file is autogenerated by rcgen. Do not modify! */
+#include <dggui/resource_data.h>
+
+const rc_data_t rc_dataX[] =
+{
+ {
+ ":locale/da.mo", 948,
+ "\336\22\4\225\0\0\0\0\15\0\0\0\34\0\0\0"
+ "\204\0\0\0\21\0\0\0\354\0\0\0\0\0\0\0"
+ "\60\1\0\0\5\0\0\0\61\1\0\0\15\0\0\0"
+ "\67\1\0\0\16\0\0\0\105\1\0\0\13\0\0\0"
+ "\124\1\0\0\7\0\0\0\140\1\0\0\4\0\0\0"
+ "\150\1\0\0\12\0\0\0\155\1\0\0\20\0\0\0"
+ "\170\1\0\0\6\0\0\0\211\1\0\0\20\0\0\0"
+ "\220\1\0\0\22\0\0\0\241\1\0\0\12\0\0\0"
+ "\264\1\0\0\141\1\0\0\277\1\0\0\2\0\0\0"
+ "\41\3\0\0\17\0\0\0\44\3\0\0\16\0\0\0"
+ "\64\3\0\0\1\0\0\0\103\3\0\0\11\0\0\0"
+ "\105\3\0\0\11\0\0\0\117\3\0\0\12\0\0\0"
+ "\131\3\0\0\21\0\0\0\144\3\0\0\10\0\0\0"
+ "\166\3\0\0\17\0\0\0\177\3\0\0\26\0\0\0"
+ "\217\3\0\0\15\0\0\0\246\3\0\0\1\0\0\0"
+ "\14\0\0\0\0\0\0\0\15\0\0\0\11\0\0\0"
+ "\0\0\0\0\5\0\0\0\0\0\0\0\7\0\0\0"
+ "\2\0\0\0\12\0\0\0\0\0\0\0\3\0\0\0"
+ "\10\0\0\0\6\0\0\0\13\0\0\0\4\0\0\0"
+ "\0\101\142\157\165\164\0\102\154\145\145\144\40\103\157\156"
+ "\164\162\157\154\0\104\151\163\153\40\123\164\162\145\141\155"
+ "\151\156\147\0\104\162\165\155\107\151\172\155\157\40\166\0"
+ "\104\162\165\155\153\151\164\0\115\141\151\156\0\122\145\163"
+ "\141\155\160\154\151\156\147\0\123\141\155\160\154\145\40\123"
+ "\145\154\145\143\164\151\157\156\0\123\164\141\164\165\163\0"
+ "\124\151\155\151\156\147\40\110\165\155\141\156\151\172\145\162"
+ "\0\126\145\154\157\143\151\164\171\40\110\165\155\141\156\151"
+ "\172\145\162\0\126\151\163\165\141\154\151\172\145\162\0\120"
+ "\162\157\152\145\143\164\55\111\144\55\126\145\162\163\151\157"
+ "\156\72\40\144\162\165\155\147\151\172\155\157\40\60\56\71"
+ "\56\61\67\12\122\145\160\157\162\164\55\115\163\147\151\144"
+ "\55\102\165\147\163\55\124\157\72\40\12\120\117\124\55\103"
+ "\162\145\141\164\151\157\156\55\104\141\164\145\72\40\62\60"
+ "\61\71\55\60\71\55\61\63\40\62\61\72\60\67\53\60"
+ "\62\60\60\12\120\117\55\122\145\166\151\163\151\157\156\55"
+ "\104\141\164\145\72\40\62\60\61\71\55\60\71\55\61\63"
+ "\40\61\71\72\64\62\53\60\62\60\60\12\114\141\163\164"
+ "\55\124\162\141\156\163\154\141\164\157\162\72\40\101\165\164"
+ "\157\155\141\164\151\143\141\154\154\171\40\147\145\156\145\162"
+ "\141\164\145\144\12\114\141\156\147\165\141\147\145\55\124\145"
+ "\141\155\72\40\156\157\156\145\12\114\141\156\147\165\141\147"
+ "\145\72\40\144\141\12\115\111\115\105\55\126\145\162\163\151"
+ "\157\156\72\40\61\56\60\12\103\157\156\164\145\156\164\55"
+ "\124\171\160\145\72\40\164\145\170\164\57\160\154\141\151\156"
+ "\73\40\143\150\141\162\163\145\164\75\111\123\117\55\70\70"
+ "\65\71\55\61\12\103\157\156\164\145\156\164\55\124\162\141"
+ "\156\163\146\145\162\55\105\156\143\157\144\151\156\147\72\40"
+ "\70\142\151\164\12\120\154\165\162\141\154\55\106\157\162\155"
+ "\163\72\40\156\160\154\165\162\141\154\163\75\62\73\40\160"
+ "\154\165\162\141\154\75\50\156\40\41\75\40\61\51\73\12"
+ "\0\117\155\0\117\166\145\162\150\370\162\40\153\157\156\164"
+ "\162\157\154\0\104\151\163\153\40\163\164\162\145\141\155\151"
+ "\156\147\0\130\0\124\162\157\155\155\145\163\346\164\0\110"
+ "\157\166\145\144\146\141\156\145\0\122\145\163\141\155\160\154"
+ "\151\156\147\0\114\171\144\142\151\144\40\165\144\166\346\154"
+ "\147\145\154\163\145\0\124\151\154\163\164\141\156\144\0\124"
+ "\151\144\163\150\165\155\141\156\151\163\141\164\157\162\0\123"
+ "\154\141\147\163\164\171\162\153\145\40\150\165\155\141\156\151"
+ "\163\141\164\157\162\0\126\151\163\165\141\154\151\163\145\162"
+ "\151\156\147\0"
+ },
+ { "", 0, 0 }
+};
+
+const rc_data_t* rc_data = rc_dataX;
diff --git a/tools/add_file b/tools/add_file
index a704029..be232fb 100755
--- a/tools/add_file
+++ b/tools/add_file
@@ -26,6 +26,10 @@ function allfile() {
then
NAME="Goran Mekić"; EMAIL="meka@tilda.center"
fi
+ if [ "$USER" == "savo" ]
+ then
+ NAME="Sander Vocke"; EMAIL="sandervocke@gmail.com"
+ fi
echo "/* -*- Mode: c++ -*- */" > $1;
echo "/***************************************************************************" >> $1;