summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSander Vocke <sandervocke@gmail.com>2024-07-23 12:22:30 +0200
committerSander Vocke <sandervocke@gmail.com>2024-07-23 12:22:30 +0200
commit23f625be77c925569dfea8700103aff89d513b50 (patch)
treee9e794b31b3314bafc856c8da9c6eb0733e10eb7
parentddd12cae8a21eba52a4d8fae9dced18878e0e055 (diff)
Add openness CC control for hi-hats.distance_openness
-rw-r--r--drumgizmo/drumgizmoc.cc12
-rw-r--r--drumgizmo/input/jackmidi.cc6
-rw-r--r--plugin/drumgizmo_plugin.cc7
-rw-r--r--src/DGDOM.h5
-rw-r--r--src/audioinputenginemidi.cc54
-rw-r--r--src/audioinputenginemidi.h5
-rw-r--r--src/dgxmlparser.cc27
-rw-r--r--src/domloader.cc1
-rw-r--r--src/drumgizmo.cc2
-rw-r--r--src/engineevent.h1
-rw-r--r--src/inputprocessor.cc6
-rw-r--r--src/instrument.cc4
-rw-r--r--src/instrument.h2
-rw-r--r--src/instrumentstate.h13
-rw-r--r--src/midimapparser.cc46
-rw-r--r--src/midimapper.cc48
-rw-r--r--src/midimapper.h37
-rw-r--r--src/sample.cc8
-rw-r--r--src/sample.h4
-rw-r--r--src/sample_selection.cc15
-rw-r--r--src/sample_selection.h2
-rw-r--r--src/settings.h14
-rw-r--r--test/dgreftest/midiinputengine.cc4
-rw-r--r--test/midimapparsertest.cc12
-rw-r--r--test/midimappertest.cc21
-rwxr-xr-xtest/uitests/powerwidgettestbin0 -> 4232712 bytes
26 files changed, 274 insertions, 82 deletions
diff --git a/drumgizmo/drumgizmoc.cc b/drumgizmo/drumgizmoc.cc
index 62b527e..44bbbbb 100644
--- a/drumgizmo/drumgizmoc.cc
+++ b/drumgizmo/drumgizmoc.cc
@@ -139,6 +139,8 @@ static std::string arguments()
" 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"
+ " openness: The importance given to choosing a sample close to\n"
+ " the actual openness 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"
@@ -627,6 +629,16 @@ int main(int argc, char* argv[])
}
settings.sample_selection_f_position.store(val);
}
+ else if(token.key == "openness")
+ {
+ auto val = atof_nol(token.value.data());
+ if(val < 0 || val > 1)
+ {
+ std::cerr << "openness range is [0, 1].\n";
+ return 1;
+ }
+ settings.sample_selection_f_openness.store(val);
+ }
else if(token.key == "diverse")
{
auto val = atof_nol(token.value.data());
diff --git a/drumgizmo/input/jackmidi.cc b/drumgizmo/input/jackmidi.cc
index 7081bf1..d64e8c4 100644
--- a/drumgizmo/input/jackmidi.cc
+++ b/drumgizmo/input/jackmidi.cc
@@ -3,7 +3,7 @@
* jackmidi.cc
*
* Mo 25. Jan 11:26:06 CET 2016
- * Copyright 2016 Christian Glöckner
+ * Copyright 2016 Christian Gl�ckner
* cgloeckner@freenet.de
****************************************************************************/
@@ -50,7 +50,7 @@ bool JackMidiInputEngine::init(const Instruments& instruments)
{
if(!loadMidiMap(midimap_file, instruments))
{
- std::cerr << "[MidifileInputEngine] Failed to parse midimap '"
+ std::cerr << "[JackMidiInputEngine] Failed to parse midimap '"
<< midimap_file << "'\n";
return false;
}
@@ -114,7 +114,7 @@ void JackMidiInputEngine::process(jack_nframes_t num_frames)
// It might not be though in case the system is under heavy load.
// Make room for both the new and old events to make sure we don't throw
// anything away.
- events.reserve(events.size() + num_events);
+ // FIXME events.reserve(events.size() + num_events);
for(jack_nframes_t i = 0; i < num_events; ++i)
{
diff --git a/plugin/drumgizmo_plugin.cc b/plugin/drumgizmo_plugin.cc
index 7960763..b07f43f 100644
--- a/plugin/drumgizmo_plugin.cc
+++ b/plugin/drumgizmo_plugin.cc
@@ -404,6 +404,7 @@ bool DrumGizmoPlugin::Input::isFreewheeling() const
return plugin.getFreeWheel();
}
+// TODO what is going on here
bool DrumGizmoPlugin::Input::loadMidiMap(const std::string& file,
const Instruments& i)
{
@@ -415,11 +416,11 @@ bool DrumGizmoPlugin::Input::loadMidiMap(const std::string& file,
for(const auto& entry : midimap)
{
// in case of multiple instruments mapped to one note, use '/' as separator
- if(!map[entry.note_id].empty())
+ if(!map[entry.from_id].empty())
{
- map[entry.note_id] += "/";
+ map[entry.from_id] += "/";
}
- map[entry.note_id] += entry.instrument_name;
+ map[entry.from_id] += entry.instrument_name;
}
midnam.reserve(map.size());
diff --git a/src/DGDOM.h b/src/DGDOM.h
index a03f0ef..3626848 100644
--- a/src/DGDOM.h
+++ b/src/DGDOM.h
@@ -58,8 +58,9 @@ struct AudioFileDOM
struct SampleDOM
{
std::string name;
- double power; // >= v2.0 only
- double position; // >=v2.0 only
+ double power; // >= v2.0 only
+ double position; // >= v3.0 only
+ double openness; // >= v3.0 only
bool normalized; // >= v2.0 only
std::vector<AudioFileDOM> audiofiles;
};
diff --git a/src/audioinputenginemidi.cc b/src/audioinputenginemidi.cc
index 240acc3..dd31bc9 100644
--- a/src/audioinputenginemidi.cc
+++ b/src/audioinputenginemidi.cc
@@ -26,6 +26,7 @@
*/
#include "audioinputenginemidi.h"
+#include "instrument.h"
#include "midimapparser.h"
#include <cassert>
@@ -70,6 +71,7 @@ bool AudioInputEngineMidi::loadMidiMap(const std::string& midimap_file,
for(size_t i = 0; i < instruments.size(); i++)
{
instrmap[instruments[i]->getName()] = static_cast<int>(i);
+ instrument_states[i] = InstrumentState{};
}
mmap.swap(instrmap, midimap_parser.midimap);
@@ -119,7 +121,8 @@ void AudioInputEngineMidi::processNote(const std::uint8_t* midi_buffer,
{
auto key = midi_buffer[1]; // NOLINT - span
auto velocity = midi_buffer[2]; // NOLINT - span
- auto instruments = mmap.lookup(key);
+ auto map_entries = mmap.lookup(key, MapFrom::Note, MapTo::PlayInstrument);
+ auto instruments = mmap.lookup_instruments(map_entries);
for(const auto& instrument_idx : instruments)
{
if(velocity != 0)
@@ -130,8 +133,16 @@ void AudioInputEngineMidi::processNote(const std::uint8_t* midi_buffer,
assert(velocity <= 127); // MIDI only support up to 127
auto centered_velocity =
(static_cast<float>(velocity) - lower_offset) / midi_velocity_max;
+ float position = 0.0f;
+ float openness = 0.0f; // TODO
+ auto instr_it = instrument_states.find(instrument_idx);
+ if(instr_it != instrument_states.end())
+ {
+ position = instr_it->second.position;
+ openness = instr_it->second.openness;
+ }
events.push_back({EventType::OnSet, (std::size_t)instrument_idx,
- offset, centered_velocity, positional_information});
+ offset, centered_velocity, position, openness});
}
}
}
@@ -141,13 +152,14 @@ void AudioInputEngineMidi::processNote(const std::uint8_t* midi_buffer,
{
auto key = midi_buffer[1]; // NOLINT - span
auto velocity = midi_buffer[2]; // NOLINT - span
- auto instruments = mmap.lookup(key);
+ auto map_entries = mmap.lookup(key, MapFrom::Note, MapTo::PlayInstrument);
+ auto instruments = mmap.lookup_instruments(map_entries);
for(const auto& instrument_idx : instruments)
{
if(velocity > 0)
{
events.push_back({EventType::Choke, (std::size_t)instrument_idx,
- offset, .0f, .0f});
+ offset, .0f, .0f, .0f});
}
}
}
@@ -157,17 +169,33 @@ void AudioInputEngineMidi::processNote(const std::uint8_t* midi_buffer,
{
auto controller_number = midi_buffer[1]; // NOLINT - span
auto value = midi_buffer[2]; // NOLINT - span
- 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;
+ // TODO: cross-map from cc to play, etc.
+ auto map_entries = mmap.lookup(controller_number,
+ MapFrom::CC,
+ MapTo::InstrumentState);
+ for(const auto& entry : map_entries)
+ {
+ auto instrument_idx = mmap.lookup_instrument(entry.instrument_name);
+ if (instrument_idx >= 0) {
+ auto state_it = instrument_states.find(instrument_idx);
+ if (state_it != instrument_states.end()) {
+ InstrumentState &state = state_it->second;
+ auto const max = (float) entry.state_max;
+ auto const min = (float) entry.state_min;
+ auto const in_clamped = std::min(std::max((float)value, std::min(min, max)), std::max(min, max));
+ float fvalue = (in_clamped - min) / (max - min);
+ if (entry.maybe_instrument_state_kind == InstrumentStateKind::Openness) {
+ state_it->second.openness = fvalue;
+ }
+ else if (entry.maybe_instrument_state_kind == InstrumentStateKind::Position) {
+ state_it->second.position = fvalue;
+ }
+ }
+ }
}
+
+ // TODO: the old version deleted the position cache(s) here
}
}
-
- // Clear cached positional information.
- positional_information = 0.0f;
}
diff --git a/src/audioinputenginemidi.h b/src/audioinputenginemidi.h
index 28da538..e045785 100644
--- a/src/audioinputenginemidi.h
+++ b/src/audioinputenginemidi.h
@@ -27,11 +27,13 @@
#pragma once
#include <string>
+#include <map>
#include "audioinputengine.h"
#include "midimapper.h"
#include "instrument.h"
#include "configfile.h"
+#include "instrumentstate.h"
class AudioInputEngineMidi
: public AudioInputEngine
@@ -65,12 +67,11 @@ public:
protected:
MidiMapper mmap;
+ std::map<int, InstrumentState> instrument_states;
private:
std::string midimap;
bool is_valid{false};
ConfigFile refs{REFSFILE};
-
- float positional_information{0.0f};
};
diff --git a/src/dgxmlparser.cc b/src/dgxmlparser.cc
index bd9af66..29cb8f2 100644
--- a/src/dgxmlparser.cc
+++ b/src/dgxmlparser.cc
@@ -351,26 +351,33 @@ bool parseInstrumentFile(const std::string& filename, InstrumentDOM& dom, LogFun
dom.samples.emplace_back();
res &= attrcpy(dom.samples.back().name, sample, "name", logger, filename);
- // Power only part of >= v2.0 instruments.
- if(dom.version == "1.0")
- {
- dom.samples.back().power = 0.0;
- }
- else
+ // Power and normalized sample support only part of >= v2.0 instruments.
+ dom.samples.back().power = 0.0;
+ dom.samples.back().normalized = false; // optional - defaults to false
+ if(dom.version != "1.0")
{
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().normalized, sample, "normalized",
+ logger, filename, true);
+ }
+
+ // Position and openness support only part of >= v3.0 instruments.
+ dom.samples.back().position = 0.0; // optional - defaults to 0
+ dom.samples.back().openness = 0.0; // optional - defaults to 0
+ if(dom.version != "1.0" && dom.version != "2.0")
+ {
+ // Get and clamp to [0; 1] range.
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",
+ res &= attrcpy(dom.samples.back().openness, sample, "openness",
logger, filename, true);
+ dom.samples.back().openness =
+ std::min(1.0, std::max(dom.samples.back().openness, 0.0));
}
for(pugi::xml_node audiofile: sample.children("audiofile"))
diff --git a/src/domloader.cc b/src/domloader.cc
index 5d411bd..aab7906 100644
--- a/src/domloader.cc
+++ b/src/domloader.cc
@@ -100,6 +100,7 @@ bool DOMLoader::loadDom(const std::string& basepath,
{
auto sample = new Sample(sampledom.name, sampledom.power,
sampledom.position,
+ sampledom.openness,
sampledom.normalized);
for(const auto& audiofiledom : sampledom.audiofiles)
{
diff --git a/src/drumgizmo.cc b/src/drumgizmo.cc
index 85624ca..0c298d4 100644
--- a/src/drumgizmo.cc
+++ b/src/drumgizmo.cc
@@ -26,11 +26,9 @@
*/
#include "drumgizmo.h"
-#include <cmath>
#include <cstdio>
#include <cassert>
#include <cstring>
-#include <mutex>
#include "audiotypes.h"
#include <config.h>
diff --git a/src/engineevent.h b/src/engineevent.h
index bf2b712..d8930d2 100644
--- a/src/engineevent.h
+++ b/src/engineevent.h
@@ -44,4 +44,5 @@ struct event_t
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
+ float openness; //!< The openness of the instrument. 0 := closed, 1 := open
};
diff --git a/src/inputprocessor.cc b/src/inputprocessor.cc
index fa3498c..30ead8a 100644
--- a/src/inputprocessor.cc
+++ b/src/inputprocessor.cc
@@ -3,7 +3,7 @@
* inputprocessor.cc
*
* Sat Apr 23 20:39:30 CEST 2016
- * Copyright 2016 André Nusser
+ * Copyright 2016 Andr� Nusser
* andre.nusser@googlemail.com
****************************************************************************/
@@ -37,7 +37,6 @@
#include "staminafilter.h"
#include "velocityfilter.h"
#include "positionfilter.h"
-
#include "cpp11fix.h"
class VelocityStorer
@@ -254,7 +253,8 @@ bool InputProcessor::processOnset(event_t& event, std::size_t pos,
float const power_span = power_max - power_min;
float const instrument_level = power_min + event.velocity*power_span;
// FIXME: bad variable naming of parameters
- const auto sample = instr->sample(instrument_level, event.position, event.offset + pos);
+ // FIXME: filter for openness?
+ const auto sample = instr->sample(instrument_level, event.position, event.openness, event.offset + pos);
if(sample == nullptr)
{
diff --git a/src/instrument.cc b/src/instrument.cc
index ac6aa28..59e5980 100644
--- a/src/instrument.cc
+++ b/src/instrument.cc
@@ -55,12 +55,12 @@ bool Instrument::isValid() const
}
// FIXME: very bad variable naming of parameters
-const Sample* Instrument::sample(level_t level, float position , std::size_t pos)
+const Sample* Instrument::sample(level_t level, float position , float openness, std::size_t pos)
{
if(version >= VersionStr("2.0"))
{
// Version 2.0
- return sample_selection.get(level * mod, position, pos);
+ return sample_selection.get(level * mod, position, openness, pos);
}
else
{
diff --git a/src/instrument.h b/src/instrument.h
index 89918de..7f767da 100644
--- a/src/instrument.h
+++ b/src/instrument.h
@@ -50,7 +50,7 @@ public:
~Instrument();
// FIXME: variable naming
- const Sample* sample(level_t level, float position, std::size_t pos);
+ const Sample* sample(level_t level, float position, float openness, std::size_t pos);
std::size_t getID() const;
const std::string& getName() const;
diff --git a/src/instrumentstate.h b/src/instrumentstate.h
new file mode 100644
index 0000000..8be4581
--- /dev/null
+++ b/src/instrumentstate.h
@@ -0,0 +1,13 @@
+#pragma once
+
+//! Tracks the MIDI state of an instrument during play.
+struct InstrumentState {
+
+ // Physical position applied to the next hit.
+ // 0.0-1.0, where 0.0 is the middle and 1.0 is closest to the rim.
+ float position = 0.0;
+
+ // Openness (typically for a hi-hat).
+ // 0.0-1.0, where 0.0 is closed and 1.0 is fully open.
+ float openness = 0.0;
+}; \ No newline at end of file
diff --git a/src/midimapparser.cc b/src/midimapparser.cc
index 363e1d5..198f002 100644
--- a/src/midimapparser.cc
+++ b/src/midimapparser.cc
@@ -42,16 +42,46 @@ 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 cc = map_node.attribute("cc").as_int(default_int);
+ auto instr = std::string(map_node.attribute("instr").as_string());
+ auto control_min = map_node.attribute("min").as_int(default_int);
+ auto control_max = map_node.attribute("max").as_int(default_int);
+ auto control_str = std::string(map_node.attribute("control").as_string());
+ auto control = (control_str == "openness" ? InstrumentStateKind::Openness :
+ control_str == "position" ? InstrumentStateKind::Position :
+ InstrumentStateKind::None);
+
+ bool is_conflict = (note != default_int && cc != default_int);
+ bool is_note_play_instrument =
+ (!is_conflict && instr != "" && note != default_int);
+ bool is_cc_control =
+ (!is_conflict && instr != "" && control != InstrumentStateKind::None && cc != default_int);
+
+ if (is_note_play_instrument)
{
- continue;
+ midimap.push_back(MidimapEntry {
+ MapFrom::Note,
+ MapTo::PlayInstrument,
+ note,
+ instr,
+ InstrumentStateKind::None,
+ 0, 0
+ });
+ }
+ else if (is_cc_control)
+ {
+ midimap.push_back(MidimapEntry {
+ MapFrom::CC,
+ MapTo::InstrumentState,
+ cc,
+ instr,
+ control,
+ (control_min != default_int) ? (uint8_t)control_min : (uint8_t)0,
+ (control_max != default_int) ? (uint8_t)control_max : (uint8_t)127
+ });
}
-
- MidimapEntry entry{note, instr};
- midimap.push_back(entry);
}
return true;
diff --git a/src/midimapper.cc b/src/midimapper.cc
index 345ce2f..5f81e70 100644
--- a/src/midimapper.cc
+++ b/src/midimapper.cc
@@ -25,26 +25,56 @@
* 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)
+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<int> MidiMapper::lookup_instruments(std::vector<MidimapEntry> const& entries) {
+ const std::lock_guard<std::mutex> guard(mutex);
+ std::set<int> rval;
+ for(const auto& entry : entries)
+ {
+ auto it = instrmap.find(entry.instrument_name);
+ if (it != instrmap.end()) {
+ rval.insert(it->second);
+ }
+ }
+ return std::vector<int>(rval.begin(), rval.end());
+}
+
+std::vector<MidimapEntry> MidiMapper::lookup(
+ int from_id,
+ MapFrom from_kind,
+ MapTo to_kind,
+ InstrumentStateKind state_kind)
{
- 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)
+ bool match = true;
+ match = match && (from_id == map_entry.from_id || from_id == -1);
+ match = match && (from_kind == MapFrom::None || from_kind == map_entry.from_kind);
+ match = match && (to_kind == MapTo::None || to_kind == map_entry.to_kind);
+ match = match && (state_kind == InstrumentStateKind::None || state_kind == map_entry.maybe_instrument_state_kind);
+
+ if(match)
{
- 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..45a2a8a 100644
--- a/src/midimapper.h
+++ b/src/midimapper.h
@@ -31,10 +31,33 @@
#include <mutex>
#include <vector>
+enum class MapFrom {
+ Note,
+ CC,
+ None
+};
+
+enum class MapTo {
+ PlayInstrument,
+ InstrumentState,
+ None
+};
+
+enum class InstrumentStateKind {
+ Position,
+ Openness,
+ None
+};
+
struct MidimapEntry
{
- int note_id;
+ MapFrom from_kind;
+ MapTo to_kind;
+ int from_id; // note or CC number
std::string instrument_name;
+ InstrumentStateKind maybe_instrument_state_kind;
+ uint8_t state_min; // cc value mapping to state 0.0
+ uint8_t state_max; // cc value mapping to state 1.0
};
using midimap_t = std::vector<MidimapEntry>;
@@ -43,8 +66,16 @@ 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 query.
+ std::vector<MidimapEntry> lookup(
+ int from_id = -1, // note or cc #. -1 matches all notes/cc's
+ MapFrom from_kind = MapFrom::None, // None will return both CC and note maps
+ MapTo to_kind = MapTo::None, // None will return both instrument hits and controls
+ InstrumentStateKind state_kind = InstrumentStateKind::None // None maps all state control kinds
+ );
+
+ int lookup_instrument(std::string name);
+ std::vector<int> lookup_instruments(std::vector<MidimapEntry> const& entries);
//! Set new map sets.
void swap(instrmap_t& instrmap, midimap_t& midimap);
diff --git a/src/sample.cc b/src/sample.cc
index 2c59f5e..d40315d 100644
--- a/src/sample.cc
+++ b/src/sample.cc
@@ -29,10 +29,11 @@
#include <sndfile.h>
Sample::Sample(const std::string& name, double power, double position,
- bool normalized)
+ double openness, bool normalized)
: name{name}
, power{power}
, position{position}
+ , openness{openness}
, normalized(normalized)
, audiofiles{}
{
@@ -76,6 +77,11 @@ double Sample::getPosition() const
return position;
}
+double Sample::getOpenness() const
+{
+ return openness;
+}
+
bool Sample::getNormalized() const
{
return normalized;
diff --git a/src/sample.h b/src/sample.h
index b13f624..2c43cfc 100644
--- a/src/sample.h
+++ b/src/sample.h
@@ -38,13 +38,14 @@ class Sample
{
public:
Sample(const std::string& name, double power, double position,
- bool normalized = false);
+ double openness, bool normalized = false);
~Sample();
AudioFile* getAudioFile(const Channel& channel) const;
double getPower() const;
double getPosition() const;
+ double getOpenness() const;
bool getNormalized() const;
private:
@@ -58,6 +59,7 @@ private:
std::string name;
double power;
double position{0.0};
+ double openness{0.0};
bool normalized;
AudioFiles audiofiles;
};
diff --git a/src/sample_selection.cc b/src/sample_selection.cc
index eb13e55..57ef4fe 100644
--- a/src/sample_selection.cc
+++ b/src/sample_selection.cc
@@ -56,7 +56,7 @@ void SampleSelection::finalise()
// 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 Sample* SampleSelection::get(level_t level, float position, float openness, std::size_t pos)
{
const auto& samples = powerlist.getPowerListItems();
if(!samples.size())
@@ -67,6 +67,7 @@ const Sample* SampleSelection::get(level_t level, float position, std::size_t po
std::size_t index_opt = 0;
float power_opt{0.f};
float pos_opt{0.f};
+ float openness_opt{0.f};
float value_opt{std::numeric_limits<float>::max()};
// the following three values are mostly for debugging
float close_opt = 0.;
@@ -77,6 +78,7 @@ const Sample* SampleSelection::get(level_t level, float position, std::size_t po
// 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_openness = 1000.*settings.sample_selection_f_openness.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();
@@ -142,14 +144,21 @@ const Sample* SampleSelection::get(level_t level, float position, std::size_t po
auto close = (samples[current_index].power - level)/power_range;
auto diverse = 1./(1. + (float)(pos - last[current_index])/settings.samplerate);
auto closepos = samples[current_index].sample->getPosition() - position;
+ auto closeopenness = samples[current_index].sample->getOpenness() - openness;
// 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;
+ auto value =
+ f_close*pow2(close)
+ + f_position*pow2(closepos)
+ + f_openness*pow2(closeopenness)
+ + 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();
+ openness_opt = samples[current_index].sample->getOpenness();
value_opt = value;
random_opt = random;
close_opt = close;
@@ -160,7 +169,7 @@ const Sample* SampleSelection::get(level_t level, float position, std::size_t po
}
while (up_value_lb <= value_opt || down_value_lb <= value_opt);
- 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);
+ DEBUG(rand, "Chose sample with index: %d, value: %f, power: %f, position: %f, openness: %f, random: %f, close: %f, diverse: %f, closepos: %f, count: %d", (int)index_opt, value_opt, power_opt, pos_opt, openness_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 1f6b290..8d7d247 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, float position, std::size_t pos);
+ const Sample* get(level_t level, float position, float openness, std::size_t pos);
private:
Settings& settings;
diff --git a/src/settings.h b/src/settings.h
index 5c2e4ee..d45514b 100644
--- a/src/settings.h
+++ b/src/settings.h
@@ -3,7 +3,7 @@
* settings.h
*
* Tue Mar 22 10:59:46 CET 2016
- * Copyright 2016 Christian Glöckner
+ * Copyright 2016 Christian Gl�ckner
* cgloeckner@freenet.de
****************************************************************************/
@@ -77,16 +77,20 @@ struct Settings
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 openness_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_openness_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> openness_stddev{openness_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_openness{sample_selection_f_openness_default};
Atomic<float> sample_selection_f_diverse{sample_selection_f_diverse_default};
Atomic<float> sample_selection_f_random{sample_selection_f_random_default};
@@ -205,8 +209,10 @@ struct SettingsGetter
SettingRef<float> velocity_modifier_weight;
SettingRef<float> velocity_stddev;
SettingRef<float> position_stddev;
+ SettingRef<float> openness_stddev;
SettingRef<float> sample_selection_f_close;
SettingRef<float> sample_selection_f_position;
+ SettingRef<float> sample_selection_f_openness;
SettingRef<float> sample_selection_f_diverse;
SettingRef<float> sample_selection_f_random;
@@ -282,8 +288,10 @@ struct SettingsGetter
, velocity_modifier_weight{settings.velocity_modifier_weight}
, velocity_stddev{settings.velocity_stddev}
, position_stddev{settings.position_stddev}
+ , openness_stddev{settings.openness_stddev}
, sample_selection_f_close{settings.sample_selection_f_close}
, sample_selection_f_position{settings.sample_selection_f_position}
+ , sample_selection_f_openness{settings.sample_selection_f_openness}
, 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)
@@ -354,8 +362,10 @@ public:
Notifier<float> velocity_modifier_weight;
Notifier<float> velocity_stddev;
Notifier<float> position_stddev;
+ Notifier<float> openness_stddev;
Notifier<float> sample_selection_f_close;
Notifier<float> sample_selection_f_position;
+ Notifier<float> sample_selection_f_openness;
Notifier<float> sample_selection_f_diverse;
Notifier<float> sample_selection_f_random;
Notifier<std::size_t> sample_selection_retry_count;
@@ -435,8 +445,10 @@ public:
EVAL(velocity_modifier_weight);
EVAL(velocity_stddev);
EVAL(position_stddev);
+ EVAL(openness_stddev)
EVAL(sample_selection_f_close);
EVAL(sample_selection_f_position);
+ EVAL(sample_selection_f_openness);
EVAL(sample_selection_f_diverse);
EVAL(sample_selection_f_random);
EVAL(sample_selection_retry_count);
diff --git a/test/dgreftest/midiinputengine.cc b/test/dgreftest/midiinputengine.cc
index dbffec9..6cab307 100644
--- a/test/dgreftest/midiinputengine.cc
+++ b/test/dgreftest/midiinputengine.cc
@@ -143,6 +143,7 @@ void MidifileInputEngine::run(size_t pos, size_t len, std::vector<event_t>& even
current_event = smf_get_next_event(smf);
}
+ // TODO: handle CC
while(current_event && current_event->time_seconds < current_max_time)
{
if(!smf_event_is_metadata(current_event))
@@ -155,7 +156,8 @@ 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);
+ auto entries = mmap.lookup(key, MapFrom::Note, MapTo::PlayInstrument);
+ auto instruments = mmap.lookup_instruments(entries);
for(const auto& instrument_idx : instruments)
{
events.emplace_back();
diff --git a/test/midimapparsertest.cc b/test/midimapparsertest.cc
index 3e77c44..7ec95fb 100644
--- a/test/midimapparsertest.cc
+++ b/test/midimapparsertest.cc
@@ -59,24 +59,24 @@ public:
const auto& midimap = parser.midimap;
uASSERT_EQUAL(6u, midimap.size());
- uASSERT_EQUAL(54, midimap[0].note_id);
+ uASSERT_EQUAL(54, midimap[0].from_id);
uASSERT_EQUAL(std::string("Crash_left_tip"), midimap[0].instrument_name);
- uASSERT_EQUAL(60, midimap[1].note_id);
+ uASSERT_EQUAL(60, midimap[1].from_id);
uASSERT_EQUAL(std::string("Crash_left_whisker"), midimap[1].instrument_name);
- uASSERT_EQUAL(55, midimap[2].note_id);
+ uASSERT_EQUAL(55, midimap[2].from_id);
uASSERT_EQUAL(std::string("Crash_right_tip"), midimap[2].instrument_name);
// These next two note numbers are intentionally the same and trigger two
// different instruments:
- uASSERT_EQUAL(62, midimap[3].note_id);
+ uASSERT_EQUAL(62, midimap[3].from_id);
uASSERT_EQUAL(std::string("Crash_right_whisker"), midimap[3].instrument_name);
- uASSERT_EQUAL(62, midimap[4].note_id);
+ uASSERT_EQUAL(62, midimap[4].from_id);
uASSERT_EQUAL(std::string("Hihat_closed"), midimap[4].instrument_name);
- uASSERT_EQUAL(56, midimap[5].note_id);
+ uASSERT_EQUAL(56, midimap[5].from_id);
uASSERT_EQUAL(std::string("Hihat_closed"), midimap[5].instrument_name);
}
diff --git a/test/midimappertest.cc b/test/midimappertest.cc
index 703c646..e8f02db 100644
--- a/test/midimappertest.cc
+++ b/test/midimappertest.cc
@@ -66,25 +66,29 @@ public:
mapper.swap(instrmap, midimap);
{
- auto is = mapper.lookup(54);
+ auto is = mapper.lookup_instruments(
+ mapper.lookup(54, MapFrom::Note, MapTo::PlayInstrument));
uASSERT_EQUAL(1u, is.size());
uASSERT_EQUAL(0, is[0]);
}
{
- auto is = mapper.lookup(60);
+ auto is = mapper.lookup_instruments(
+ mapper.lookup(60, MapFrom::Note, MapTo::PlayInstrument));
uASSERT_EQUAL(1u, is.size());
uASSERT_EQUAL(1, is[0]);
}
{
- auto is = mapper.lookup(55);
+ auto is = mapper.lookup_instruments(
+ mapper.lookup(55, MapFrom::Note, MapTo::PlayInstrument));
uASSERT_EQUAL(1u, is.size());
uASSERT_EQUAL(2, is[0]);
}
{
- auto is = mapper.lookup(62);
+ auto is = mapper.lookup_instruments(
+ mapper.lookup(62, MapFrom::Note, MapTo::PlayInstrument));
uASSERT_EQUAL(2u, is.size());
// We don't care about the order, so just count the instances
uASSERT_EQUAL(1u, std::count(is.begin(), is.end(), 3));
@@ -92,7 +96,8 @@ public:
}
{
- auto is = mapper.lookup(56);
+ auto is = mapper.lookup_instruments(
+ mapper.lookup(56, MapFrom::Note, MapTo::PlayInstrument));
uASSERT_EQUAL(1u, is.size());
uASSERT_EQUAL(4, is[0]);
}
@@ -124,13 +129,15 @@ public:
// no such note id
{
- auto is = mapper.lookup(42);
+ auto is = mapper.lookup_instruments(
+ mapper.lookup(42, MapFrom::Note, MapTo::PlayInstrument));
uASSERT_EQUAL(0u, is.size());
}
// no such instrument
{
- auto is = mapper.lookup(60);
+ auto is = mapper.lookup_instruments(
+ mapper.lookup(60, MapFrom::Note, MapTo::PlayInstrument));
uASSERT_EQUAL(0u, is.size());
}
}
diff --git a/test/uitests/powerwidgettest b/test/uitests/powerwidgettest
new file mode 100755
index 0000000..264a526
--- /dev/null
+++ b/test/uitests/powerwidgettest
Binary files differ