summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drumgizmo/drumgizmoc.cc12
-rw-r--r--plugin/Makefile.mingw32.in1
-rw-r--r--src/DGDOM.h1
-rw-r--r--src/Makefile.am2
-rw-r--r--src/audioinputenginemidi.cc56
-rw-r--r--src/audioinputenginemidi.h2
-rw-r--r--src/dgxmlparser.cc16
-rw-r--r--src/domloader.cc1
-rw-r--r--src/event.h9
-rw-r--r--src/inputprocessor.cc5
-rw-r--r--src/instrument.cc5
-rw-r--r--src/instrument.h3
-rw-r--r--src/positionfilter.cc48
-rw-r--r--src/positionfilter.h52
-rw-r--r--src/sample.cc9
-rw-r--r--src/sample.h5
-rw-r--r--src/sample_selection.cc17
-rw-r--r--src/sample_selection.h2
-rw-r--r--src/settings.h12
19 files changed, 226 insertions, 32 deletions
diff --git a/drumgizmo/drumgizmoc.cc b/drumgizmo/drumgizmoc.cc
index 8eba4c9..b906c8a 100644
--- a/drumgizmo/drumgizmoc.cc
+++ b/drumgizmo/drumgizmoc.cc
@@ -139,6 +139,8 @@ static std::string arguments()
"Sample selection parameters:\n"
" close: The importance given to choosing a sample close to\n"
" the actual velocity value (after humanization). [0,1]\n"
+ " position: The importance given to choosing a sample close to\n"
+ " the actual position value (after humanization). [0,1]\n"
" diverse: The importance given to choosing samples\n"
" which haven't been played recently. [0,1]\n"
" random: The amount of randomness added. [0,1]\n"
@@ -617,6 +619,16 @@ int main(int argc, char* argv[])
}
settings.sample_selection_f_close.store(val);
}
+ else if(token.key == "position")
+ {
+ auto val = atof_nol(token.value.data());
+ if(val < 0 || val > 1)
+ {
+ std::cerr << "position range is [0, 1].\n";
+ return 1;
+ }
+ settings.sample_selection_f_position.store(val);
+ }
else if(token.key == "diverse")
{
auto val = atof_nol(token.value.data());
diff --git a/plugin/Makefile.mingw32.in b/plugin/Makefile.mingw32.in
index ad47bcc..1b8c848 100644
--- a/plugin/Makefile.mingw32.in
+++ b/plugin/Makefile.mingw32.in
@@ -49,6 +49,7 @@ DG_SRC = \
@top_srcdir@/src/thread.cc \
@top_srcdir@/src/translation.cc \
@top_srcdir@/src/velocityfilter.cc \
+ @top_srcdir@/src/positionfilter.cc \
@top_srcdir@/src/versionstr.cc
DG_CFLAGS = -I@top_srcdir@ -I@top_srcdir@/src \
-I@top_srcdir@/zita-resampler/libs \
diff --git a/src/DGDOM.h b/src/DGDOM.h
index 474b29c..a03f0ef 100644
--- a/src/DGDOM.h
+++ b/src/DGDOM.h
@@ -59,6 +59,7 @@ struct SampleDOM
{
std::string name;
double power; // >= v2.0 only
+ double position; // >=v2.0 only
bool normalized; // >= v2.0 only
std::vector<AudioFileDOM> audiofiles;
};
diff --git a/src/Makefile.am b/src/Makefile.am
index b656f48..3e691b1 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -75,6 +75,7 @@ libdg_la_SOURCES = \
staminafilter.cc \
thread.cc \
velocityfilter.cc \
+ positionfilter.cc \
versionstr.cc
EXTRA_DIST = \
@@ -138,5 +139,6 @@ EXTRA_DIST = \
thread.h \
translation.h \
velocityfilter.h \
+ positionfilter.h \
versionstr.h \
zrwrapper.h
diff --git a/src/audioinputenginemidi.cc b/src/audioinputenginemidi.cc
index ce3ce18..f6fedd6 100644
--- a/src/audioinputenginemidi.cc
+++ b/src/audioinputenginemidi.cc
@@ -100,9 +100,13 @@ bool AudioInputEngineMidi::isValid() const
static const std::uint8_t NoteOff = 0x80;
static const std::uint8_t NoteOn = 0x90;
static const std::uint8_t NoteAftertouch = 0xA0;
+static const std::uint8_t ControlChange = 0xB0;
// Note type mask:
-static int const NoteMask = 0xF0;
+static const std::uint8_t TypeMask = 0xF0;
+
+// See:
+// https://www.midi.org/specifications-old/item/table-1-summary-of-midi-message
void AudioInputEngineMidi::processNote(const std::uint8_t* midi_buffer,
std::size_t midi_buffer_length,
@@ -114,35 +118,59 @@ void AudioInputEngineMidi::processNote(const std::uint8_t* midi_buffer,
return;
}
- auto key = midi_buffer[1];
- auto velocity = midi_buffer[2];
- auto instrument_idx = mmap.lookup(key);
-
- switch(midi_buffer[0] & NoteMask)
+ switch(midi_buffer[0] & TypeMask)
{
case NoteOff:
// Ignore for now
break;
case NoteOn:
- if(velocity != 0 && instrument_idx != -1)
{
- // maps velocities to [.5/127, 126.5/127]
- auto centered_velocity = (velocity-.5f)/127.0f;
- events.push_back({EventType::OnSet, (std::size_t)instrument_idx,
- offset, centered_velocity});
+ auto key = midi_buffer[1];
+ auto velocity = midi_buffer[2];
+ auto instrument_idx = mmap.lookup(key);
+ if(velocity != 0 && instrument_idx != -1)
+ {
+ // maps velocities to [.5/127, 126.5/127]
+ auto centered_velocity = (velocity-.5f)/127.0f;
+ events.push_back({ EventType::OnSet, (std::size_t)instrument_idx,
+ offset, centered_velocity, positional_information });
+ }
}
break;
case NoteAftertouch:
- if(velocity == 0 && instrument_idx != -1)
{
- events.push_back({EventType::Choke, (std::size_t)instrument_idx,
- offset, .0f});
+ auto key = midi_buffer[1];
+ auto velocity = midi_buffer[2];
+ auto instrument_idx = mmap.lookup(key);
+ if(velocity == 0 && instrument_idx != -1)
+ {
+ events.push_back({ EventType::Choke, (std::size_t)instrument_idx,
+ offset, .0f, .0f });
+ }
+ }
+ break;
+
+ case ControlChange:
+ {
+ auto controller_number = midi_buffer[1];
+ auto value = midi_buffer[2];
+ if(controller_number == 16) // positional information
+ {
+ // Store value for use in next NoteOn event.
+ positional_information = value / 127.0f;
+
+ // Return here to prevent reset of cached positional information.
+ return;
+ }
}
break;
default:
break;
}
+
+ // Clear cached positional information.
+ positional_information = 0.0f;
}
diff --git a/src/audioinputenginemidi.h b/src/audioinputenginemidi.h
index 8da7bd2..12efd66 100644
--- a/src/audioinputenginemidi.h
+++ b/src/audioinputenginemidi.h
@@ -70,4 +70,6 @@ private:
bool is_valid;
ConfigFile refs;
+
+ float positional_information{0.0f};
};
diff --git a/src/dgxmlparser.cc b/src/dgxmlparser.cc
index 0d3cdcd..bd9af66 100644
--- a/src/dgxmlparser.cc
+++ b/src/dgxmlparser.cc
@@ -358,9 +358,19 @@ bool parseInstrumentFile(const std::string& filename, InstrumentDOM& dom, LogFun
}
else
{
- res &= attrcpy(dom.samples.back().power, sample, "power", logger, filename);
- dom.samples.back().normalized = false;
- res &= attrcpy(dom.samples.back().normalized, sample, "normalized", logger, filename, true);
+ res &= attrcpy(dom.samples.back().power, sample, "power",
+ logger, filename);
+
+ dom.samples.back().position = 0.0; // optional - defaults to 0
+ res &= attrcpy(dom.samples.back().position, sample, "position",
+ logger, filename, true);
+ // Clamp to [0; 1] range.
+ dom.samples.back().position =
+ std::min(1.0, std::max(dom.samples.back().position, 0.0));
+
+ dom.samples.back().normalized = false; // optional - defaults to false
+ res &= attrcpy(dom.samples.back().normalized, sample, "normalized",
+ logger, filename, true);
}
for(pugi::xml_node audiofile: sample.children("audiofile"))
diff --git a/src/domloader.cc b/src/domloader.cc
index c78ed75..5d411bd 100644
--- a/src/domloader.cc
+++ b/src/domloader.cc
@@ -99,6 +99,7 @@ bool DOMLoader::loadDom(const std::string& basepath,
for(const auto& sampledom : instrumentdom.samples)
{
auto sample = new Sample(sampledom.name, sampledom.power,
+ sampledom.position,
sampledom.normalized);
for(const auto& audiofiledom : sampledom.audiofiles)
{
diff --git a/src/event.h b/src/event.h
index 737fb18..5780cc9 100644
--- a/src/event.h
+++ b/src/event.h
@@ -39,8 +39,9 @@ enum class EventType
//! POD datatype for input event transport.
struct event_t
{
- EventType type; //!< The type of the event.
- std::size_t instrument; //!< The instrument number.
- std::size_t offset; //!< The offset position in the input buffer
- float velocity; //!< The velocity if the type is a note on [0; 1]
+ EventType type; //!< The type of the event.
+ std::size_t instrument; //!< The instrument number.
+ std::size_t offset; //!< The offset position in the input buffer
+ float velocity; //!< The velocity if the type is a note on [0; 1]
+ float position; //!< The position of the note. 0 := center, 1 := rim
};
diff --git a/src/inputprocessor.cc b/src/inputprocessor.cc
index 4bafb1d..a883286 100644
--- a/src/inputprocessor.cc
+++ b/src/inputprocessor.cc
@@ -36,6 +36,7 @@
#include "powermapfilter.h"
#include "staminafilter.h"
#include "velocityfilter.h"
+#include "positionfilter.h"
#include "cpp11fix.h"
@@ -93,6 +94,7 @@ InputProcessor::InputProcessor(Settings& settings,
filters.emplace_back(std::make_unique<StaminaFilter>(settings));
filters.emplace_back(std::make_unique<LatencyFilter>(settings, random));
filters.emplace_back(std::make_unique<VelocityFilter>(settings, random));
+ filters.emplace_back(std::make_unique<PositionFilter>(settings, random));
filters.emplace_back(std::make_unique<Reporter>(settings, original_velocity));
}
@@ -244,7 +246,8 @@ bool InputProcessor::processOnset(event_t& event, std::size_t pos,
auto const power_min = instr->getMinPower();
float const power_span = power_max - power_min;
float const instrument_level = power_min + event.velocity*power_span;
- const auto sample = instr->sample(instrument_level, event.offset + pos);
+ // FIXME: bad variable naming of parameters
+ const auto sample = instr->sample(instrument_level, event.position, event.offset + pos);
if(sample == nullptr)
{
diff --git a/src/instrument.cc b/src/instrument.cc
index b7bcdd9..ac6aa28 100644
--- a/src/instrument.cc
+++ b/src/instrument.cc
@@ -54,12 +54,13 @@ bool Instrument::isValid() const
return this == magic;
}
-const Sample* Instrument::sample(level_t level, size_t pos)
+// FIXME: very bad variable naming of parameters
+const Sample* Instrument::sample(level_t level, float position , std::size_t pos)
{
if(version >= VersionStr("2.0"))
{
// Version 2.0
- return sample_selection.get(level * mod, pos);
+ return sample_selection.get(level * mod, position, pos);
}
else
{
diff --git a/src/instrument.h b/src/instrument.h
index c06ccdc..89918de 100644
--- a/src/instrument.h
+++ b/src/instrument.h
@@ -49,7 +49,8 @@ public:
Instrument(Settings& settings, Random& rand);
~Instrument();
- const Sample* sample(level_t level, size_t pos);
+ // FIXME: variable naming
+ const Sample* sample(level_t level, float position, std::size_t pos);
std::size_t getID() const;
const std::string& getName() const;
diff --git a/src/positionfilter.cc b/src/positionfilter.cc
new file mode 100644
index 0000000..8d2f987
--- /dev/null
+++ b/src/positionfilter.cc
@@ -0,0 +1,48 @@
+/* -*- Mode: c++ -*- */
+/***************************************************************************
+ * positionfilter.cc
+ *
+ * Sat 13 Feb 2021 12:46:41 CET
+ * Copyright 2019 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 "positionfilter.h"
+
+#include "random.h"
+#include "settings.h"
+
+PositionFilter::PositionFilter(Settings& settings, Random& random)
+ : settings(settings), random(random)
+{
+}
+
+bool PositionFilter::filter(event_t& event, size_t pos)
+{
+ if (settings.enable_velocity_modifier.load())
+ {
+ float mean = event.position;
+ float stddev = settings.position_stddev.load();
+ // the 30.0f were determined empirically
+ event.position = random.normalDistribution(mean, stddev / 30.0f); // FIXME: right magic value?
+ }
+
+ return true;
+}
diff --git a/src/positionfilter.h b/src/positionfilter.h
new file mode 100644
index 0000000..ac989f6
--- /dev/null
+++ b/src/positionfilter.h
@@ -0,0 +1,52 @@
+/* -*- Mode: c++ -*- */
+/***************************************************************************
+ * positionfilter.h
+ *
+ * Sat 13 Feb 2021 12:46:41 CET
+ * Copyright 2019 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.
+ */
+#pragma once
+
+#include <cstddef>
+#include <map>
+#include <utility>
+
+#include "inputfilter.h"
+#include "instrument.h"
+
+struct Settings;
+class Random;
+
+class PositionFilter
+ : public InputFilter
+{
+public:
+ PositionFilter(Settings& settings, Random& random);
+
+ bool filter(event_t& event, std::size_t pos) override;
+
+ // Note getLatency not overloaded because this filter doesn't add latency.
+
+private:
+ Settings& settings;
+ Random& random;
+};
diff --git a/src/sample.cc b/src/sample.cc
index 9af2c08..2c59f5e 100644
--- a/src/sample.cc
+++ b/src/sample.cc
@@ -28,9 +28,11 @@
#include <sndfile.h>
-Sample::Sample(const std::string& name, double power, bool normalized)
+Sample::Sample(const std::string& name, double power, double position,
+ bool normalized)
: name{name}
, power{power}
+ , position{position}
, normalized(normalized)
, audiofiles{}
{
@@ -69,6 +71,11 @@ double Sample::getPower() const
return power;
}
+double Sample::getPosition() const
+{
+ return position;
+}
+
bool Sample::getNormalized() const
{
return normalized;
diff --git a/src/sample.h b/src/sample.h
index 6c31b6b..b13f624 100644
--- a/src/sample.h
+++ b/src/sample.h
@@ -37,12 +37,14 @@ using AudioFiles = std::map<const InstrumentChannel*, AudioFile*>;
class Sample
{
public:
- Sample(const std::string& name, double power, bool normalized = false);
+ Sample(const std::string& name, double power, double position,
+ bool normalized = false);
~Sample();
AudioFile* getAudioFile(const Channel& channel) const;
double getPower() const;
+ double getPosition() const;
bool getNormalized() const;
private:
@@ -55,6 +57,7 @@ private:
std::string name;
double power;
+ double position{0.0};
bool normalized;
AudioFiles audiofiles;
};
diff --git a/src/sample_selection.cc b/src/sample_selection.cc
index 7267faf..0ff2c51 100644
--- a/src/sample_selection.cc
+++ b/src/sample_selection.cc
@@ -54,7 +54,9 @@ void SampleSelection::finalise()
last.assign(powerlist.getPowerListItems().size(), 0);
}
-const Sample* SampleSelection::get(level_t level, std::size_t pos)
+// FIXME: For the position, weird hacks via the powerlist are necessary. Refactor!
+// FIXME: bad variable naming
+const Sample* SampleSelection::get(level_t level, float position, std::size_t pos)
{
const auto& samples = powerlist.getPowerListItems();
if(!samples.size())
@@ -64,14 +66,17 @@ const Sample* SampleSelection::get(level_t level, std::size_t pos)
std::size_t index_opt = 0;
float power_opt{0.f};
+ float pos_opt{0.f};
float value_opt{std::numeric_limits<float>::max()};
// the following three values are mostly for debugging
- float random_opt = 0.;
float close_opt = 0.;
+ float closepos_opt = 0.;
+ float random_opt = 0.;
float diverse_opt = 0.;
// Note the magic values in front of the settings factors.
const float f_close = 4.*settings.sample_selection_f_close.load();
+ const float f_position = 1000.*settings.sample_selection_f_position.load(); // FIXME: huge factor for now
const float f_diverse = (1./2.)*settings.sample_selection_f_diverse.load();
const float f_random = (1./3.)*settings.sample_selection_f_random.load();
@@ -137,22 +142,26 @@ const Sample* SampleSelection::get(level_t level, std::size_t pos)
auto random = rand.floatInRange(0.,1.);
auto close = (samples[current_index].power - level)/power_range;
auto diverse = 1./(1. + (float)(pos - last[current_index])/settings.samplerate);
- auto value = f_close*pow2(close) + f_diverse*diverse + f_random*random;
+ auto closepos = samples[current_index].sample->getPosition() - position;
+ // note that the value below for close and closepos is actually the weighted squared l2 distance in 2d
+ auto value = f_close*pow2(close) + f_position*pow2(closepos) + f_diverse*diverse + f_random*random;
if (value < value_opt)
{
index_opt = current_index;
power_opt = samples[current_index].power;
+ pos_opt = samples[current_index].sample->getPosition();
value_opt = value;
random_opt = random;
close_opt = close;
diverse_opt = diverse;
+ closepos_opt = closepos;
}
++count;
}
while (up_value_lb <= value_opt || down_value_lb <= value_opt);
- DEBUG(rand, "Chose sample with index: %d, value: %f, power %f, random: %f, close: %f, diverse: %f, count: %d", (int)index_opt, value_opt, power_opt, random_opt, close_opt, diverse_opt, (int)count);
+ DEBUG(rand, "Chose sample with index: %d, value: %f, power: %f, position: %f, random: %f, close: %f, diverse: %f, closepos: %f, count: %d", (int)index_opt, value_opt, power_opt, pos_opt, random_opt, close_opt, diverse_opt, closepos_opt, (int)count);
last[index_opt] = pos;
return samples[index_opt].sample;
diff --git a/src/sample_selection.h b/src/sample_selection.h
index 8da4e0d..1f6b290 100644
--- a/src/sample_selection.h
+++ b/src/sample_selection.h
@@ -40,7 +40,7 @@ public:
SampleSelection(Settings& settings, Random& rand, const PowerList& powerlist);
void finalise();
- const Sample* get(level_t level, std::size_t pos);
+ const Sample* get(level_t level, float position, std::size_t pos);
private:
Settings& settings;
diff --git a/src/settings.h b/src/settings.h
index fb93d79..5c2e4ee 100644
--- a/src/settings.h
+++ b/src/settings.h
@@ -76,13 +76,17 @@ struct Settings
static float constexpr velocity_modifier_falloff_default = 0.5f;
static float constexpr velocity_modifier_weight_default = 0.25f;
static float constexpr velocity_stddev_default = .45f;
+ static float constexpr position_stddev_default = 0.f; // FIXME: set to something sensible
static float constexpr sample_selection_f_close_default = .85f;
+ static float constexpr sample_selection_f_position_default = 1.f;
static float constexpr sample_selection_f_diverse_default = .16f;
static float constexpr sample_selection_f_random_default = .07f;
Atomic<float> velocity_modifier_falloff{velocity_modifier_falloff_default};
Atomic<float> velocity_modifier_weight{velocity_modifier_weight_default};
Atomic<float> velocity_stddev{velocity_stddev_default};
+ Atomic<float> position_stddev{position_stddev_default};
Atomic<float> sample_selection_f_close{sample_selection_f_close_default};
+ Atomic<float> sample_selection_f_position{sample_selection_f_position_default};
Atomic<float> sample_selection_f_diverse{sample_selection_f_diverse_default};
Atomic<float> sample_selection_f_random{sample_selection_f_random_default};
@@ -200,7 +204,9 @@ struct SettingsGetter
SettingRef<float> velocity_modifier_falloff;
SettingRef<float> velocity_modifier_weight;
SettingRef<float> velocity_stddev;
+ SettingRef<float> position_stddev;
SettingRef<float> sample_selection_f_close;
+ SettingRef<float> sample_selection_f_position;
SettingRef<float> sample_selection_f_diverse;
SettingRef<float> sample_selection_f_random;
@@ -275,7 +281,9 @@ struct SettingsGetter
, velocity_modifier_falloff{settings.velocity_modifier_falloff}
, velocity_modifier_weight{settings.velocity_modifier_weight}
, velocity_stddev{settings.velocity_stddev}
+ , position_stddev{settings.position_stddev}
, sample_selection_f_close{settings.sample_selection_f_close}
+ , sample_selection_f_position{settings.sample_selection_f_position}
, sample_selection_f_diverse{settings.sample_selection_f_diverse}
, sample_selection_f_random{settings.sample_selection_f_random}
, sample_selection_retry_count(settings.sample_selection_retry_count)
@@ -345,7 +353,9 @@ public:
Notifier<float> velocity_modifier_falloff;
Notifier<float> velocity_modifier_weight;
Notifier<float> velocity_stddev;
+ Notifier<float> position_stddev;
Notifier<float> sample_selection_f_close;
+ Notifier<float> sample_selection_f_position;
Notifier<float> sample_selection_f_diverse;
Notifier<float> sample_selection_f_random;
Notifier<std::size_t> sample_selection_retry_count;
@@ -424,7 +434,9 @@ public:
EVAL(velocity_modifier_falloff);
EVAL(velocity_modifier_weight);
EVAL(velocity_stddev);
+ EVAL(position_stddev);
EVAL(sample_selection_f_close);
+ EVAL(sample_selection_f_position);
EVAL(sample_selection_f_diverse);
EVAL(sample_selection_f_random);
EVAL(sample_selection_retry_count);