gearmulator

Emulation of classic VA synths of the late 90s/2000s that are based on Motorola 56300 family DSPs
Log | Files | Refs | Submodules | README | LICENSE

datasource.cpp (5804B)


      1 #include "datasource.h"
      2 
      3 #include <algorithm>
      4 #include <sstream>
      5 #include <memory>
      6 
      7 #include "db.h"
      8 #include "patch.h"
      9 
     10 #include "baseLib/binarystream.h"
     11 
     12 namespace pluginLib::patchDB
     13 {
     14 	bool DataSource::createConsecutiveProgramNumbers()
     15 	{
     16 		if(patches.empty())
     17 			return false;
     18 
     19 		// note that this does NOT sort the patches member, it is a set that cannot be sorted, we only generate consecutive program numbers here
     20 
     21 		std::vector<PatchPtr> patchesVector(patches.begin(), patches.end());
     22 
     23 		sortByProgram(patchesVector);
     24 
     25 		return createConsecutiveProgramNumbers(patchesVector);
     26 	}
     27 
     28 	bool DataSource::createConsecutiveProgramNumbers(const std::vector<PatchPtr>& _patches)
     29 	{
     30 		bool dirty = false;
     31 		uint32_t program = 0;
     32 
     33 		for (const auto& patch : _patches)
     34 		{
     35 			const auto p = program++;
     36 
     37 			if(patch->program == p)
     38 				continue;
     39 
     40 			patch->program = p;
     41 			dirty = true;
     42 		}
     43 
     44 		return dirty;
     45 	}
     46 
     47 	bool DataSource::makeSpaceForNewPatches(const uint32_t _insertPosition, const uint32_t _count) const
     48 	{
     49 		bool dirty = true;
     50 
     51 		for (const auto& patch : patches)
     52 		{
     53 			if(patch->program >= _insertPosition)
     54 			{
     55 				patch->program += _count;
     56 				dirty = true;
     57 			}
     58 		}
     59 		return dirty;
     60 	}
     61 
     62 	std::pair<uint32_t, uint32_t> DataSource::getProgramNumberRange() const
     63 	{
     64 		if(patches.empty())
     65 			return {g_invalidProgram, g_invalidProgram};
     66 
     67 		uint32_t min = std::numeric_limits<uint32_t>::max();
     68 		uint32_t max = std::numeric_limits<uint32_t>::min();
     69 
     70 		for (const auto& patch : patches)
     71 		{
     72 			min = std::min(patch->program, min);
     73 			max = std::max(patch->program, max);
     74 		}
     75 
     76 		return {min, max};
     77 	}
     78 
     79 	uint32_t DataSource::getMaxProgramNumber() const
     80 	{
     81 		return getProgramNumberRange().second;
     82 	}
     83 
     84 	void DataSource::sortByProgram(std::vector<PatchPtr>& _patches)
     85 	{
     86 		std::sort(_patches.begin(), _patches.end(), [&](const PatchPtr& _a, const PatchPtr& _b)
     87 		{
     88 			return _a->program < _b->program;
     89 		});
     90 	}
     91 
     92 	bool DataSource::contains(const PatchPtr& _patch) const
     93 	{
     94 		return patches.find(_patch) != patches.end();
     95 	}
     96 
     97 	bool DataSource::movePatchesTo(const uint32_t _position, const std::vector<PatchPtr>& _patches)
     98 	{
     99 		std::vector<PatchPtr> patchesVec(patches.begin(), patches.end());
    100 		sortByProgram(patchesVec);
    101 
    102 		createConsecutiveProgramNumbers(patchesVec);
    103 
    104 		uint32_t targetPosition = _position;
    105 
    106 		// insert position has to be decremented by 1 for each patch that is reinserted that has a position less than the target position
    107 		for (const auto& patch : _patches)
    108 		{
    109 			if(patch->program < _position)
    110 				--targetPosition;
    111 		}
    112 
    113 		if(!remove(_patches))
    114 			return false;
    115 
    116 		patchesVec.assign(patches.begin(), patches.end());
    117 		sortByProgram(patchesVec);
    118 
    119 		if(targetPosition >= patchesVec.size())
    120 			patchesVec.insert(patchesVec.end(), _patches.begin(), _patches.end());
    121 		else
    122 			patchesVec.insert(patchesVec.begin() + targetPosition, _patches.begin(), _patches.end());
    123 
    124 		createConsecutiveProgramNumbers(patchesVec);
    125 		
    126 		for (const auto& patch : _patches)
    127 			patches.insert(patch);
    128 
    129 		return true;
    130 	}
    131 
    132 	bool DataSource::remove(const PatchPtr& _patch)
    133 	{
    134 		return patches.erase(_patch);
    135 	}
    136 
    137 	PatchPtr DataSource::getPatch(const PatchKey& _key) const
    138 	{
    139 		for (const auto& patch : patches)
    140 		{
    141 			if(*patch == _key)
    142 				return patch;
    143 		}
    144 		return {};
    145 	}
    146 
    147 	std::string DataSource::toString() const
    148 	{
    149 		std::stringstream ss;
    150 
    151 		ss << "type|" << patchDB::toString(type);
    152 		ss << "|name|" << name;
    153 		if (bank != g_invalidBank)
    154 			ss << "|bank|" << bank;
    155 //		if (program != g_invalidProgram)
    156 //			ss << "|prog|" << program;
    157 		return ss.str();
    158 	}
    159 
    160 	void DataSource::write(baseLib::BinaryStream& _outStream) const
    161 	{
    162 		baseLib::ChunkWriter cw(_outStream, chunks::g_datasource, 1);
    163 
    164 		_outStream.write(static_cast<uint8_t>(type));
    165 		_outStream.write(static_cast<uint8_t>(origin));
    166 		_outStream.write(name);
    167 		_outStream.write(bank);
    168 
    169 		_outStream.write(static_cast<uint32_t>(patches.size()));
    170 
    171 		for (const auto& patch : patches)
    172 			patch->write(_outStream);
    173 	}
    174 
    175 	bool DataSource::read(baseLib::BinaryStream& _inStream)
    176 	{
    177 		auto in = _inStream.tryReadChunk(chunks::g_datasource);
    178 		if(!in)
    179 			return false;
    180 
    181 		type = static_cast<SourceType>(in.read<uint8_t>());
    182 		origin = static_cast<DataSourceOrigin>(in.read<uint8_t>());
    183 		name = in.readString();
    184 		bank = in.read<uint32_t>();
    185 
    186 		const auto numPatches = in.read<uint32_t>();
    187 
    188 		for(uint32_t i=0; i<numPatches; ++i)
    189 		{
    190 			const auto patch = std::make_shared<Patch>();
    191 			if(!patch->read(in))
    192 				return false;
    193 
    194 			DB::assign(patch, patch->modifications);
    195 
    196 			patches.insert(patch);
    197 		}
    198 
    199 		return true;
    200 	}
    201 
    202 	DataSourceNode::DataSourceNode(const DataSource& _ds) : DataSource(_ds)
    203 	{
    204 	}
    205 
    206 	DataSourceNode::~DataSourceNode()
    207 	{
    208 		setParent(nullptr);
    209 		removeAllChildren();
    210 	}
    211 
    212 	void DataSourceNode::setParent(const DataSourceNodePtr& _parent)
    213 	{
    214 		if (getParent() == _parent)
    215 			return;
    216 
    217 		if(m_parent)
    218 		{
    219 			// we MUST NOT create a new ptr to this here as we may be called from our destructor, in which case there shouldn't be a pointer in there anyway
    220 			for(uint32_t i=0; i<static_cast<uint32_t>(m_parent->m_children.size()); ++i)
    221 			{
    222 				auto& child = m_parent->m_children[i];
    223 				auto ptr = child.lock();
    224 				if (ptr && ptr.get() == this)
    225 				{
    226 					m_parent->m_children.erase(m_parent->m_children.begin() + i);
    227 					break;
    228 				}
    229 			}
    230 		}
    231 
    232 		m_parent = _parent;
    233 
    234 		if(_parent)
    235 			_parent->m_children.emplace_back(shared_from_this());
    236 	}
    237 
    238 	bool DataSourceNode::isChildOf(const DataSourceNode* _ds) const
    239 	{
    240 		auto node = this;
    241 
    242 		while(node)
    243 		{
    244 			if (_ds == node)
    245 				return true;
    246 			node = node->m_parent.get();
    247 		}
    248 		return false;
    249 	}
    250 
    251 	void DataSourceNode::removeAllChildren()
    252 	{
    253 		while(!m_children.empty())
    254 		{
    255 			const auto& c = m_children.back().lock();
    256 			if (c)
    257 				c->setParent(nullptr);
    258 			else
    259 				m_children.pop_back();
    260 		}
    261 	}
    262 }