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

weGraph.cpp (6669B)


      1 #include "weGraph.h"
      2 
      3 #include "xtWaveEditor.h"
      4 
      5 #include "dsp56kEmu/fastmath.h"
      6 
      7 namespace xtJucePlugin
      8 {
      9 	Graph::Graph(WaveEditor& _editor) : m_editor(_editor), m_data(_editor.getGraphData())
     10 	{
     11 		m_onDataChanged.set(m_data.onChanged, [this]()
     12 		{
     13 			onSourceChanged();
     14 		});
     15 	}
     16 
     17 	void Graph::paint(juce::Graphics& g)
     18 	{
     19 		g.fillAll(findColour(juce::TreeView::ColourIds::backgroundColourId));
     20 
     21 		paint(getData(), getDataSize(),g, 0, 0, getWidth(), getHeight());
     22 	}
     23 
     24 	void Graph::parentHierarchyChanged()
     25 	{
     26 		juce::Component::parentHierarchyChanged();
     27 
     28 		const auto* parent = getParentComponent();
     29 		if(!parent)
     30 			return;
     31 
     32 		setSize(parent->getWidth(), parent->getHeight());
     33 	}
     34 
     35 	void Graph::paint(const float* _data, const size_t _size, juce::Graphics& _g, const int _x, const int _y, const int _width, const int _height) const
     36 	{
     37 		const auto& style = m_editor.getStyle();
     38 
     39 		const float scaleX = static_cast<float>(_width)  / static_cast<float>(_size);
     40 		const float scaleY = static_cast<float>(_height);
     41 
     42 		const float x = static_cast<float>(_x) + scaleX * 0.5f;
     43 		const float y = static_cast<float>(_y);
     44 
     45 		const float h = static_cast<float>(_height);
     46 
     47 		for(uint32_t i=0; i<_size; ++i)
     48 		{
     49 			const auto x0 = static_cast<float>(i ? (i - 1) : i) * scaleX + x;
     50 			const auto x1 = static_cast<float>(i    ) * scaleX + x;
     51 
     52 			const auto y0 = h - (normalize(_data[i ? (i - 1) : i])) * scaleY + y - 1;
     53 			const auto y1 = h - (normalize(_data[i    ])) * scaleY + y - 1;
     54 
     55 			if(i)
     56 			{
     57 				_g.setColour(juce::Colour(style.colGraphLine));
     58 				_g.drawLine(x0, y0, x1, y1, style.graphLineThickness);
     59 			}
     60 
     61 			if(m_highlightedIndices.find(i) != m_highlightedIndices.end())
     62 			{
     63 				_g.setColour(style.colGraphLineHighlighted);
     64 				const auto s = style.graphPointSizeHighlighted;
     65 				_g.fillEllipse(x1 - s * 0.5f, y1 - s * 0.5f, s, s);
     66 			}
     67 			else
     68 			{
     69 				_g.setColour(style.colGraphLine);
     70 				const auto s = style.graphPointSize;
     71 				_g.fillEllipse(x1 - s * 0.5f, y1 - s * 0.5f, s, s);
     72 			}
     73 		}
     74 	}
     75 
     76 	bool Graph::updateHoveredIndex(const juce::MouseEvent& _e)
     77 	{
     78 		const auto index = mouseToIndex(_e);
     79 		if(!isValidIndex(index))
     80 		{
     81 			setHoveredIndex(InvalidIndex);
     82 			return false;
     83 		}
     84 		setHoveredIndex(static_cast<uint32_t>(index));
     85 		return true;
     86 	}
     87 
     88 	void Graph::mouseDown(const juce::MouseEvent& _e)
     89 	{
     90 		Component::mouseDown(_e);
     91 
     92 		if (_e.mods.isPopupMenu())
     93 		{
     94 			m_editor.openGraphPopupMenu(*this, _e);
     95 			return;
     96 		}
     97 
     98 		setLastMouseEvent(_e);
     99 		const auto i = mouseToIndex(_e);
    100 		if(isValidIndex(i))
    101 			modifyValue(static_cast<uint32_t>(i), mouseToUnnormalizedValue(_e));
    102 	}
    103 
    104 	void Graph::mouseMove(const juce::MouseEvent& _e)
    105 	{
    106 		Component::mouseMove(_e);
    107 
    108 		if (_e.mods.isPopupMenu())
    109 			return;
    110 
    111 		updateHoveredIndex(_e);
    112 	}
    113 
    114 	void Graph::mouseEnter(const juce::MouseEvent& _e)
    115 	{
    116 		Component::mouseEnter(_e);
    117 		updateHoveredIndex(_e);
    118 	}
    119 
    120 	void Graph::mouseExit(const juce::MouseEvent& _e)
    121 	{
    122 		Component::mouseExit(_e);
    123 		setHoveredIndex(InvalidIndex);
    124 	}
    125 
    126 	void Graph::mouseDrag(const juce::MouseEvent& _e)
    127 	{
    128 		Component::mouseDrag(_e);
    129 
    130 		if (_e.mods.isPopupMenu())
    131 			return;
    132 
    133 		if(!_e.mods.isShiftDown())
    134 		{
    135 			updateHoveredIndex(_e);
    136 
    137 			if(m_lastMouseEvent)
    138 			{
    139 				modifyValuesForRange(*m_lastMouseEvent, _e);
    140 			}
    141 			else if(isValidIndex(m_hoveredIndex))
    142 			{
    143 				modifyValue(m_hoveredIndex, mouseToUnnormalizedValue(_e));
    144 			}
    145 		}
    146 		else
    147 		{
    148 			if(isValidIndex(m_hoveredIndex))
    149 				modifyValue(m_hoveredIndex, mouseToUnnormalizedValue(_e));
    150 		}
    151 
    152 		setLastMouseEvent(_e);
    153 	}
    154 
    155 	int32_t Graph::mouseToIndex(const juce::MouseEvent& _e) const
    156 	{
    157 		return _e.x * static_cast<int32_t>(getDataSize()) / (int32_t)getWidth();
    158 	}
    159 
    160 	float Graph::mouseToNormalizedValue(const juce::MouseEvent& _e) const
    161 	{
    162 		const auto v = 1.0f - static_cast<float>(_e.y) / static_cast<float>(getHeight() - 1);
    163 		return dsp56k::clamp(v, 0.0f, 1.0f);
    164 	}
    165 
    166 	float Graph::mouseToUnnormalizedValue(const juce::MouseEvent& _e) const
    167 	{
    168 		return unnormalize(mouseToNormalizedValue(_e));
    169 	}
    170 
    171 	const juce::MouseEvent* Graph::lastMouseEvent() const
    172 	{
    173 		return m_lastMouseEvent.get();
    174 	}
    175 
    176 	bool Graph::isInterestedInDragSource(const SourceDetails& _dragSourceDetails)
    177 	{
    178 		return false;
    179 	}
    180 
    181 	void Graph::itemDropped(const SourceDetails& _dragSourceDetails)
    182 	{
    183 	}
    184 
    185 	bool Graph::isInterestedInFileDrag(const juce::StringArray& _files)
    186 	{
    187 		if (_files.size() != 1)
    188 			return false;
    189 		return _files[0].endsWithIgnoreCase(".wav");
    190 	}
    191 
    192 	void Graph::filesDropped(const juce::StringArray& _files, int _x, int _y)
    193 	{
    194 		if (_files.size() != 1)
    195 			return;
    196 		if (auto res = m_editor.importWaveFile(_files[0].toStdString()))
    197 			m_editor.getGraphData().set(*res);
    198 	}
    199 
    200 	void Graph::onSourceChanged()
    201 	{
    202 		repaint();
    203 	}
    204 
    205 	void Graph::onHoveredIndexChanged(const uint32_t _index)
    206 	{
    207 		if(_index == InvalidIndex)
    208 		{
    209 			if(!m_highlightedIndices.empty())
    210 				m_highlightedIndices.clear();
    211 
    212 			onHighlightedIndicesChanged(m_highlightedIndices);
    213 		}
    214 
    215 		setHighlightedIndices({_index});
    216 	}
    217 
    218 	void Graph::onHighlightedIndicesChanged(const std::set<uint32_t>& _indices)
    219 	{
    220 		repaint();
    221 	}
    222 
    223 	void Graph::setHighlightedIndices(const std::set<uint32_t>& _indices)
    224 	{
    225 		bool changed = false;
    226 
    227 		for (auto existing : m_highlightedIndices)
    228 		{
    229 			if(_indices.find(existing) == _indices.end())
    230 			{
    231 				changed = true;
    232 				break;
    233 			}
    234 		}
    235 
    236 		if(!changed)
    237 		{
    238 			for (uint32_t newIndex : _indices)
    239 			{
    240 				if(m_highlightedIndices.find(newIndex) == m_highlightedIndices.end())
    241 				{
    242 					changed = true;
    243 					break;
    244 				}
    245 			}
    246 		}
    247 
    248 		if(!changed)
    249 			return;
    250 
    251 		m_highlightedIndices = _indices;
    252 
    253 		onHighlightedIndicesChanged(m_highlightedIndices);
    254 	}
    255 
    256 	void Graph::modifyValue(uint32_t _index, float _unnormalizedValue)
    257 	{
    258 	}
    259 
    260 	void Graph::setHoveredIndex(uint32_t _index)
    261 	{
    262 		if(_index == m_hoveredIndex)
    263 			return;
    264 		m_hoveredIndex = _index;
    265 		onHoveredIndexChanged(m_hoveredIndex);
    266 	}
    267 
    268 	void Graph::setLastMouseEvent(const juce::MouseEvent& _e)
    269 	{
    270 		m_lastMouseEvent = std::make_unique<juce::MouseEvent>(_e);
    271 	}
    272 
    273 	void Graph::modifyValuesForRange(const juce::MouseEvent& _a, const juce::MouseEvent& _b)
    274 	{
    275 		auto indexA = mouseToIndex(_a);
    276 		auto indexB = mouseToIndex(_b);
    277 
    278 		auto valueA = mouseToUnnormalizedValue(_a);
    279 		auto valueB = mouseToUnnormalizedValue(_b);
    280 
    281 		if(indexA > indexB)
    282 		{
    283 			std::swap(indexA, indexB);
    284 			std::swap(valueA, valueB);
    285 		}
    286 
    287 		const auto count = indexB - indexA + 1;
    288 
    289 		const auto valueDiff = valueB - valueA;
    290 		const auto factor = valueDiff / static_cast<float>(count);
    291 
    292 		auto v = valueA;
    293 
    294 		for(auto i = indexA; i <= indexB; ++i)
    295 		{
    296 			if(i < 0)
    297 				continue;
    298 
    299 			if(i >= static_cast<int32_t>(getDataSize()))
    300 				return;
    301 
    302 			modifyValue(i, v);
    303 			v += factor;
    304 		}
    305 	}
    306 }