diff options
| -rw-r--r-- | plugin/drumgizmo_plugin.cc | 13 | ||||
| -rw-r--r-- | src/audioinputenginemidi.cc | 51 | ||||
| -rw-r--r-- | src/midimapparser.cc | 3 | ||||
| -rw-r--r-- | src/midimapper.cc | 24 | ||||
| -rw-r--r-- | src/midimapper.h | 16 | ||||
| -rw-r--r-- | test/Makefile.am | 17 | ||||
| -rw-r--r-- | test/dgreftest/midiinputengine.cc | 17 | ||||
| -rw-r--r-- | test/midimapparsertest.cc | 44 | ||||
| -rw-r--r-- | test/midimappertest.cc | 140 | 
9 files changed, 257 insertions, 68 deletions
| diff --git a/plugin/drumgizmo_plugin.cc b/plugin/drumgizmo_plugin.cc index 82c0ee9..7960763 100644 --- a/plugin/drumgizmo_plugin.cc +++ b/plugin/drumgizmo_plugin.cc @@ -410,7 +410,18 @@ bool DrumGizmoPlugin::Input::loadMidiMap(const std::string& file,  	bool result = AudioInputEngineMidi::loadMidiMap(file, i);  	std::vector<std::pair<int, std::string>> midnam; -	const auto& map = mmap.getMap(); +	const auto& midimap = mmap.getMap(); +	std::map<int, std::string> map; +	for(const auto& entry : midimap) +	{ +		// in case of multiple instruments mapped to one note, use '/' as separator +		if(!map[entry.note_id].empty()) +		{ +			map[entry.note_id] += "/"; +		} +		map[entry.note_id] += entry.instrument_name; +	} +  	midnam.reserve(map.size());  	for(const auto& m : map)  	{ diff --git a/src/audioinputenginemidi.cc b/src/audioinputenginemidi.cc index 8732d8d..69aeeb6 100644 --- a/src/audioinputenginemidi.cc +++ b/src/audioinputenginemidi.cc @@ -117,32 +117,35 @@ void AudioInputEngineMidi::processNote(const std::uint8_t* midi_buffer,  	auto key = midi_buffer[1];  	auto velocity = midi_buffer[2];  	auto instrument_idx = mmap.lookup(key); - -	switch(midi_buffer[0] & NoteMask) +	auto instruments = mmap.lookup(key); +	for(const auto& instrument_idx : instruments)  	{ -	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}); -		} -		break; - -	case NoteAftertouch: -		if(velocity > 0 && instrument_idx != -1) +		switch(midi_buffer[0] & NoteMask)  		{ -			events.push_back({EventType::Choke, (std::size_t)instrument_idx, -			                  offset, .0f}); +		case NoteOff: +			// Ignore for now +			break; + +		case NoteOn: +			if(velocity != 0) +			{ +				// 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}); +			} +			break; + +		case NoteAftertouch: +			if(velocity > 0) +			{ +				events.push_back({EventType::Choke, (std::size_t)instrument_idx, +				                  offset, .0f}); +			} +			break; + +		default: +			break;  		} -		break; - -	default: -		break;  	}  } diff --git a/src/midimapparser.cc b/src/midimapparser.cc index 059dfec..363e1d5 100644 --- a/src/midimapparser.cc +++ b/src/midimapparser.cc @@ -50,7 +50,8 @@ bool MidiMapParser::parseFile(const std::string& filename)  			continue;  		} -		midimap[note] = instr; +		MidimapEntry entry{note, instr}; +		midimap.push_back(entry);  	}  	return true; diff --git a/src/midimapper.cc b/src/midimapper.cc index 9593aae..b9316c5 100644 --- a/src/midimapper.cc +++ b/src/midimapper.cc @@ -26,23 +26,25 @@   */  #include "midimapper.h" -int MidiMapper::lookup(int note) +std::vector<int> MidiMapper::lookup(int note_id)  { -	std::lock_guard<std::mutex> guard(mutex); +	std::vector<int> instruments; -	auto midimap_it = midimap.find(note); -	if(midimap_it == midimap.end()) -	{ -		return -1; -	} +	std::lock_guard<std::mutex> guard(mutex); -	auto instrmap_it = instrmap.find(midimap_it->second); -	if(instrmap_it == instrmap.end()) +	for(const auto& map_entry : midimap)  	{ -		return -1; +		if(map_entry.note_id == note_id) +		{ +			auto instrmap_it = instrmap.find(map_entry.instrument_name); +			if(instrmap_it != instrmap.end()) +			{ +				instruments.push_back(instrmap_it->second); +			} +		}  	} -	return instrmap_it->second; +	return instruments;  }  void MidiMapper::swap(instrmap_t& instrmap, midimap_t& midimap) diff --git a/src/midimapper.h b/src/midimapper.h index 4673e33..94781d4 100644 --- a/src/midimapper.h +++ b/src/midimapper.h @@ -29,16 +29,22 @@  #include <map>  #include <string>  #include <mutex> +#include <vector> -typedef std::map<int, std::string> midimap_t; -typedef std::map<std::string, int> instrmap_t; +struct MidimapEntry +{ +	int note_id; +	std::string instrument_name; +}; + +using midimap_t = std::vector<MidimapEntry>; +using instrmap_t = std::map<std::string, int>;  class MidiMapper  {  public: -	//! Lookup note in map and return its index. -	//! \returns -1 if not found or the note index. -	int lookup(int note); +	//! Lookup note in map and returns the corresponding instrument index list. +	std::vector<int> lookup(int note_id);  	//! Set new map sets.  	void swap(instrmap_t& instrmap, midimap_t& midimap); diff --git a/test/Makefile.am b/test/Makefile.am index 6d62314..6441fd3 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 +	eventsdstest powermaptest midimappertest  if WITH_NLS  TESTS += translationtest @@ -335,6 +335,21 @@ powermaptest_SOURCES = \  	powermaptest.cc \  	uunit/uunit.cc +midimappertest_CXXFLAGS = \ +	-I$(top_srcdir)/test/uunit -DOUTPUT=\"midimappertest\" \ +	$(DEBUG_FLAGS) \ +	-I$(top_srcdir)/src \ +	-I$(top_srcdir)/hugin \ +	-I$(top_srcdir)/pugixml/src +midimappertest_LDFLAGS = +midimappertest_SOURCES = \ +	$(top_srcdir)/hugin/hugin.c \ +	$(top_srcdir)/src/midimapper.cc \ +	$(top_srcdir)/pugixml/src/pugixml.cpp \ +	scopedfile.cc \ +	midimappertest.cc \ +	uunit/uunit.cc +  RES = \  	$(top_srcdir)/test/locale/da.mo diff --git a/test/dgreftest/midiinputengine.cc b/test/dgreftest/midiinputengine.cc index ca223da..dbffec9 100644 --- a/test/dgreftest/midiinputengine.cc +++ b/test/dgreftest/midiinputengine.cc @@ -155,16 +155,15 @@ 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]; -				events.emplace_back(); -				auto& event = events.back(); -				event.type = EventType::OnSet; -				size_t evpos = current_event->time_seconds * (samplerate / speed); -				event.offset = evpos - pos; - -				int i = mmap.lookup(key); -				if(i != -1) +				auto instruments = mmap.lookup(key); +				for(const auto& instrument_idx : instruments)  				{ -					event.instrument = i; +					events.emplace_back(); +					auto& event = events.back(); +					event.type = EventType::OnSet; +					size_t evpos = current_event->time_seconds * (samplerate / speed); +					event.offset = evpos - pos; +					event.instrument = instrument_idx;  					event.velocity = velocity / 127.0;  				}  			} diff --git a/test/midimapparsertest.cc b/test/midimapparsertest.cc index eb4d6d5..3e77c44 100644 --- a/test/midimapparsertest.cc +++ b/test/midimapparsertest.cc @@ -36,8 +36,8 @@ class MidimapParserTest  public:  	MidimapParserTest()  	{ -		uUNIT_TEST(MidimapParserTest::test); -		uUNIT_TEST(MidimapParserTest::invalid); +		uTEST(MidimapParserTest::test); +		uTEST(MidimapParserTest::invalid);  	}  	void test() @@ -49,23 +49,35 @@ public:  			"	<map note=\"60\" instr=\"Crash_left_whisker\"/>\n" \  			"	<map note=\"55\" instr=\"Crash_right_tip\"/>\n" \  			"	<map note=\"62\" instr=\"Crash_right_whisker\"/>\n" \ +			"	<map note=\"62\" instr=\"Hihat_closed\"/>\n" \  			"	<map note=\"56\" instr=\"Hihat_closed\"/>\n" \  			"</midimap>");  		MidiMapParser parser; -		uUNIT_ASSERT(parser.parseFile(scoped_file.filename())); - -		uUNIT_ASSERT(parser.midimap.find(54) != parser.midimap.end()); -		uUNIT_ASSERT(parser.midimap.find(60) != parser.midimap.end()); -		uUNIT_ASSERT(parser.midimap.find(55) != parser.midimap.end()); -		uUNIT_ASSERT(parser.midimap.find(62) != parser.midimap.end()); -		uUNIT_ASSERT(parser.midimap.find(56) != parser.midimap.end()); - -		uUNIT_ASSERT_EQUAL(std::string("Crash_left_tip"), parser.midimap[54]); -		uUNIT_ASSERT_EQUAL(std::string("Crash_left_whisker"), parser.midimap[60]); -		uUNIT_ASSERT_EQUAL(std::string("Crash_right_tip"), parser.midimap[55]); -		uUNIT_ASSERT_EQUAL(std::string("Crash_right_whisker"), parser.midimap[62]); -		uUNIT_ASSERT_EQUAL(std::string("Hihat_closed"), parser.midimap[56]); +		uASSERT(parser.parseFile(scoped_file.filename())); + +		const auto& midimap = parser.midimap; +		uASSERT_EQUAL(6u, midimap.size()); + +		uASSERT_EQUAL(54, midimap[0].note_id); +		uASSERT_EQUAL(std::string("Crash_left_tip"), midimap[0].instrument_name); + +		uASSERT_EQUAL(60, midimap[1].note_id); +		uASSERT_EQUAL(std::string("Crash_left_whisker"), midimap[1].instrument_name); + +		uASSERT_EQUAL(55, midimap[2].note_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(std::string("Crash_right_whisker"), midimap[3].instrument_name); + +		uASSERT_EQUAL(62, midimap[4].note_id); +		uASSERT_EQUAL(std::string("Hihat_closed"), midimap[4].instrument_name); + +		uASSERT_EQUAL(56, midimap[5].note_id); +		uASSERT_EQUAL(std::string("Hihat_closed"), midimap[5].instrument_name);  	}  	void invalid() @@ -81,7 +93,7 @@ public:  			"</midimap>");  		MidiMapParser parser; -		uUNIT_ASSERT(!parser.parseFile(scoped_file.filename())); +		uASSERT(!parser.parseFile(scoped_file.filename()));  	}  }; diff --git a/test/midimappertest.cc b/test/midimappertest.cc new file mode 100644 index 0000000..703c646 --- /dev/null +++ b/test/midimappertest.cc @@ -0,0 +1,140 @@ +/* -*- Mode: c++ -*- */ +/*************************************************************************** + *            midimappertest.cc + * + *  Sun Aug 8 09:55:13 CEST 2021 + *  Copyright 2021 Bent Bisballe Nyeng + *  deva@aasimon.org + ****************************************************************************/ + +/* + *  This file is part of DrumGizmo. + * + *  DrumGizmo is free software; you can redistribute it and/or modify + *  it under the terms of the GNU Lesser General Public License as published by + *  the Free Software Foundation; either version 3 of the License, or + *  (at your option) any later version. + * + *  DrumGizmo is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU Lesser General Public License for more details. + * + *  You should have received a copy of the GNU Lesser General Public License + *  along with DrumGizmo; if not, write to the Free Software + *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA. */ +#include <uunit.h> + +#include <algorithm> + +#include <midimapper.h> + +#include "scopedfile.h" + +class MidiMapperTest +	: public uUnit +{ +public: +	MidiMapperTest() +	{ +		uTEST(MidiMapperTest::test); +		uTEST(MidiMapperTest::exceptional); +	} + +	void test() +	{ +		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" }, +		}; + +		instrmap_t instrmap +		{ +			{ "Crash_left_tip", 0 }, +			{ "Crash_left_whisker", 1 }, +			{ "Crash_right_tip", 2 }, +			{ "Crash_right_whisker", 3 }, +			{ "Hihat_closed", 4 }, +		}; + +		MidiMapper mapper; +		mapper.swap(instrmap, midimap); + +		{ +			auto is = mapper.lookup(54); +			uASSERT_EQUAL(1u, is.size()); +			uASSERT_EQUAL(0, is[0]); +		} + +		{ +			auto is = mapper.lookup(60); +			uASSERT_EQUAL(1u, is.size()); +			uASSERT_EQUAL(1, is[0]); +		} + +		{ +			auto is = mapper.lookup(55); +			uASSERT_EQUAL(1u, is.size()); +			uASSERT_EQUAL(2, is[0]); +		} + +		{ +			auto is = mapper.lookup(62); +			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)); +			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]); +		} +	} + +	void exceptional() +	{ +		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" }, +		}; + +		instrmap_t instrmap +		{ +			{ "Crash_left_tip", 0 }, +			{ "Crash_left_whisker", 1 }, +			{ "Crash_right_tip", 2 }, +			{ "Crash_right_whisker", 3 }, +			{ "Hihat_closed", 4 }, +		}; + +		MidiMapper mapper; +		mapper.swap(instrmap, midimap); + +		// no such note id +		{ +			auto is = mapper.lookup(42); +			uASSERT_EQUAL(0u, is.size()); +		} + +		// no such instrument +		{ +			auto is = mapper.lookup(60); +			uASSERT_EQUAL(0u, is.size()); +		} +	} +}; + +// Registers the fixture into the 'registry' +static MidiMapperTest test; | 
