From 23f625be77c925569dfea8700103aff89d513b50 Mon Sep 17 00:00:00 2001 From: Sander Vocke Date: Tue, 23 Jul 2024 12:22:30 +0200 Subject: Add openness CC control for hi-hats. --- drumgizmo/drumgizmoc.cc | 12 +++++++++ drumgizmo/input/jackmidi.cc | 6 ++--- plugin/drumgizmo_plugin.cc | 7 ++--- src/DGDOM.h | 5 ++-- src/audioinputenginemidi.cc | 54 +++++++++++++++++++++++++++++--------- src/audioinputenginemidi.h | 5 ++-- src/dgxmlparser.cc | 27 ++++++++++++------- src/domloader.cc | 1 + src/drumgizmo.cc | 2 -- src/engineevent.h | 1 + src/inputprocessor.cc | 6 ++--- src/instrument.cc | 4 +-- src/instrument.h | 2 +- src/instrumentstate.h | 13 +++++++++ src/midimapparser.cc | 46 ++++++++++++++++++++++++++------ src/midimapper.cc | 48 ++++++++++++++++++++++++++------- src/midimapper.h | 37 +++++++++++++++++++++++--- src/sample.cc | 8 +++++- src/sample.h | 4 ++- src/sample_selection.cc | 15 ++++++++--- src/sample_selection.h | 2 +- src/settings.h | 14 +++++++++- test/dgreftest/midiinputengine.cc | 4 ++- test/midimapparsertest.cc | 12 ++++----- test/midimappertest.cc | 21 ++++++++++----- test/uitests/powerwidgettest | Bin 0 -> 4232712 bytes 26 files changed, 274 insertions(+), 82 deletions(-) create mode 100644 src/instrumentstate.h create mode 100755 test/uitests/powerwidgettest 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 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 @@ -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(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(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 +#include #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 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 #include #include #include -#include #include "audiotypes.h" #include 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 -std::vector MidiMapper::lookup(int note_id) +int MidiMapper::lookup_instrument(std::string name) { + const std::lock_guard guard(mutex); + auto instrmap_it = instrmap.find(name); + if(instrmap_it != instrmap.end()) + { + return instrmap_it->second; + } + return -1; +} + +std::vector MidiMapper::lookup_instruments(std::vector const& entries) { + const std::lock_guard guard(mutex); + std::set rval; + for(const auto& entry : entries) + { + auto it = instrmap.find(entry.instrument_name); + if (it != instrmap.end()) { + rval.insert(it->second); + } + } + return std::vector(rval.begin(), rval.end()); +} + +std::vector MidiMapper::lookup( + int from_id, + MapFrom from_kind, + MapTo to_kind, + InstrumentStateKind state_kind) { - std::vector instruments; + std::vector rval; const std::lock_guard 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 #include +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; @@ -43,8 +66,16 @@ using instrmap_t = std::map; class MidiMapper { public: - //! Lookup note in map and returns the corresponding instrument index list. - std::vector lookup(int note_id); + //! Lookup midi map entries matching the given query. + std::vector 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 lookup_instruments(std::vector 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 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::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 velocity_modifier_falloff{velocity_modifier_falloff_default}; Atomic velocity_modifier_weight{velocity_modifier_weight_default}; Atomic velocity_stddev{velocity_stddev_default}; Atomic position_stddev{position_stddev_default}; + Atomic openness_stddev{openness_stddev_default}; Atomic sample_selection_f_close{sample_selection_f_close_default}; Atomic sample_selection_f_position{sample_selection_f_position_default}; + Atomic sample_selection_f_openness{sample_selection_f_openness_default}; Atomic sample_selection_f_diverse{sample_selection_f_diverse_default}; Atomic sample_selection_f_random{sample_selection_f_random_default}; @@ -205,8 +209,10 @@ struct SettingsGetter SettingRef velocity_modifier_weight; SettingRef velocity_stddev; SettingRef position_stddev; + SettingRef openness_stddev; SettingRef sample_selection_f_close; SettingRef sample_selection_f_position; + SettingRef sample_selection_f_openness; SettingRef sample_selection_f_diverse; SettingRef 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 velocity_modifier_weight; Notifier velocity_stddev; Notifier position_stddev; + Notifier openness_stddev; Notifier sample_selection_f_close; Notifier sample_selection_f_position; + Notifier sample_selection_f_openness; Notifier sample_selection_f_diverse; Notifier sample_selection_f_random; Notifier 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& 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& 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 Binary files /dev/null and b/test/uitests/powerwidgettest differ -- cgit v1.2.3