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

remoteDevice.cpp (7091B)


      1 #include "remoteDevice.h"
      2 
      3 #include "udpClient.h"
      4 
      5 #include "bridgeLib/types.h"
      6 
      7 #include "dsp56kEmu/logging.h"
      8 
      9 #include "networkLib/tcpClient.h"
     10 #include "networkLib/tcpStream.h"
     11 
     12 #include "synthLib/deviceException.h"
     13 
     14 #include "deviceConnection.h"
     15 
     16 #include <condition_variable>
     17 
     18 #include "baseLib/filesystem.h"
     19 
     20 #include "networkLib/exception.h"
     21 #include "networkLib/logging.h"
     22 
     23 namespace bridgeClient
     24 {
     25 	static constexpr uint32_t g_udpTimeout = 5;	// seconds
     26 	static constexpr uint32_t g_tcpTimeout = 5;	// seconds
     27 
     28 	RemoteDevice::RemoteDevice(const synthLib::DeviceCreateParams& _params, bridgeLib::PluginDesc&& _desc, const std::string& _host/* = {}*/, uint32_t _port/* = 0*/) : Device(_params), m_pluginDesc(std::move(_desc))
     29 	{
     30 		getDeviceCreateParams().romHash = baseLib::MD5(getDeviceCreateParams().romData);
     31 		getDeviceCreateParams().romName = baseLib::filesystem::getFilenameWithoutPath(getDeviceCreateParams().romName);
     32 
     33 		m_pluginDesc.protocolVersion = bridgeLib::g_protocolVersion;
     34 		createConnection(_host, _port);
     35 	}
     36 
     37 	RemoteDevice::~RemoteDevice()
     38 	{
     39 		m_connection.reset();
     40 	}
     41 
     42 	float RemoteDevice::getSamplerate() const
     43 	{
     44 		return m_deviceDesc.samplerate;
     45 	}
     46 
     47 	bool RemoteDevice::isValid() const
     48 	{
     49 		return m_valid;
     50 	}
     51 
     52 	bool RemoteDevice::getState(std::vector<uint8_t>& _state, const synthLib::StateType _type)
     53 	{
     54 		return safeCall([&]
     55 		{
     56 			return m_connection->getDeviceState(_state, _type);
     57 		}, [&]
     58 		{
     59 			// if there is no valid connection anymore attempt to grab the latest state that was sent
     60 			if(!m_connection)
     61 				return;
     62 			auto& state = static_cast<bridgeLib::TcpConnection*>(m_connection.get())->getDeviceState();
     63 			_state.insert(_state.end(), state.state.begin(), state.state.end());
     64 		});
     65 	}
     66 
     67 	bool RemoteDevice::setState(const std::vector<uint8_t>& _state, const synthLib::StateType _type)
     68 	{
     69 		if(!isValid())
     70 			return false;
     71 		return m_connection->setDeviceState(_state, _type);
     72 	}
     73 
     74 	uint32_t RemoteDevice::getChannelCountIn()
     75 	{
     76 		return m_deviceDesc.inChannels;
     77 	}
     78 
     79 	uint32_t RemoteDevice::getChannelCountOut()
     80 	{
     81 		return m_deviceDesc.outChannels;
     82 	}
     83 
     84 	bool RemoteDevice::setDspClockPercent(const uint32_t _percent)
     85 	{
     86 		return safeCall([&]
     87 		{
     88 			m_connection->setDspClockPercent(_percent);
     89 			return true;
     90 		});
     91 	}
     92 
     93 	uint32_t RemoteDevice::getDspClockPercent() const
     94 	{
     95 		return m_deviceDesc.dspClockPercent;
     96 	}
     97 
     98 	uint64_t RemoteDevice::getDspClockHz() const
     99 	{
    100 		return m_deviceDesc.dspClockHz;
    101 	}
    102 
    103 	uint32_t RemoteDevice::getInternalLatencyInputToOutput() const
    104 	{
    105 		return m_deviceDesc.latencyInToOut;
    106 	}
    107 
    108 	uint32_t RemoteDevice::getInternalLatencyMidiToOutput() const
    109 	{
    110 		return m_deviceDesc.latencyMidiToOut;
    111 	}
    112 
    113 	void RemoteDevice::getPreferredSamplerates(std::vector<float>& _dst) const
    114 	{
    115 		_dst = m_deviceDesc.preferredSamplerates;
    116 	}
    117 
    118 	void RemoteDevice::getSupportedSamplerates(std::vector<float>& _dst) const
    119 	{
    120 		_dst = m_deviceDesc.supportedSamplerates;
    121 	}
    122 
    123 	bool RemoteDevice::setSamplerate(const float _samplerate)
    124 	{
    125 		return safeCall([&]
    126 		{
    127 			m_connection->setSamplerate(_samplerate);
    128 			return true;
    129 		});
    130 	}
    131 
    132 	bool RemoteDevice::setStateFromUnknownCustomData(const std::vector<uint8_t>& _state)
    133 	{
    134 		return safeCall([&]
    135 		{
    136 			m_connection->setStateFromUnknownCustomData(_state);
    137 			return true;
    138 		});
    139 	} 
    140 
    141 	void RemoteDevice::onBootFinished(const bridgeLib::DeviceDesc& _desc)
    142 	{
    143 		{
    144 			std::unique_lock lock(m_cvWaitMutex);
    145 			m_deviceDesc = _desc;
    146 		}
    147 		m_cvWait.notify_one();
    148 	}
    149 
    150 	void RemoteDevice::onDisconnect()
    151 	{
    152 		{
    153 			std::unique_lock lock(m_cvWaitMutex);
    154 			m_valid = false;
    155 		}
    156 		m_cvWait.notify_one();
    157 	}
    158 
    159 	void RemoteDevice::readMidiOut(std::vector<synthLib::SMidiEvent>& _midiOut)
    160 	{
    161 		safeCall([&]
    162 		{
    163 			m_connection->readMidiOut(_midiOut);
    164 			return true;
    165 		});
    166 	}
    167 
    168 	void RemoteDevice::processAudio(const synthLib::TAudioInputs& _inputs, const synthLib::TAudioOutputs& _outputs, const size_t _samples)
    169 	{
    170 		safeCall([&]
    171 		{
    172 			return m_connection->processAudio(_inputs, _outputs, static_cast<uint32_t>(_samples), getExtraLatencySamples());
    173 		});
    174 	}
    175 
    176 	bool RemoteDevice::sendMidi(const synthLib::SMidiEvent& _ev, std::vector<synthLib::SMidiEvent>& _response)
    177 	{
    178 		return safeCall([&]
    179 		{
    180 			return m_connection->send(_ev);
    181 		});
    182 	}
    183 
    184 	bool RemoteDevice::safeCall(const std::function<bool()>& _func, const std::function<void()>& _onFail/* = [] {}*/)
    185 	{
    186 		if(!isValid())
    187 		{
    188 			_onFail();
    189 			return false;
    190 		}
    191 
    192 		try
    193 		{
    194 			if(!_func())
    195 			{
    196 				onDisconnect();
    197 				_onFail();
    198 			}
    199 		}
    200 		catch(networkLib::NetException& e)
    201 		{
    202 			LOG(e.what());
    203 			onDisconnect();
    204 			_onFail();
    205 		}
    206 		return true;
    207 	}
    208 
    209 	void RemoteDevice::createConnection(const std::string& _host, uint32_t _port)
    210 	{
    211 		// wait for UDP connection up to 5 seconds
    212 		bridgeLib::ServerInfo si;
    213 		std::string host = _host;
    214 
    215 		if(_host.empty() || !_port)
    216 		{
    217 			UdpClient udpClient(m_pluginDesc, [&](const std::string& _hostname, const bridgeLib::ServerInfo& _si, const bridgeLib::Error& _err)
    218 			{
    219 				if(_err.code != bridgeLib::ErrorCode::Ok)
    220 					return;
    221 				{
    222 					std::unique_lock lock(m_cvWaitMutex);
    223 					si = _si;
    224 					host = _hostname;
    225 					LOG("Found server "<< _hostname << ':' << si.portTcp);
    226 				}
    227 				m_cvWait.notify_one();
    228 			});
    229 
    230 			std::unique_lock lockCv(m_cvWaitMutex);
    231 			if(!m_cvWait.wait_for(lockCv, std::chrono::seconds(g_udpTimeout), [&si]
    232 			{
    233 				return si.protocolVersion == bridgeLib::g_protocolVersion;
    234 			}))
    235 			{
    236 				throw synthLib::DeviceException(synthLib::DeviceError::RemoteUdpConnectFailed, "No server found");
    237 			}
    238 		}
    239 		else
    240 		{
    241 			si.portTcp = _port;
    242 		}
    243 
    244 		// wait for TCP connection for another 5 seconds
    245 		std::unique_ptr<networkLib::TcpStream> stream;
    246 
    247 		LOG("Connecting to "<< host << ':' << si.portTcp);
    248 
    249 		networkLib::TcpClient client(host, si.portTcp,[&](std::unique_ptr<networkLib::TcpStream> _tcpStream)
    250 		{
    251 			{
    252 				std::unique_lock lock(m_cvWaitMutex);
    253 				stream = std::move(_tcpStream);
    254 			}
    255 			m_cvWait.notify_one();
    256 		});
    257 
    258 		{
    259 			std::unique_lock lockCv(m_cvWaitMutex);
    260 			if(!m_cvWait.wait_for(lockCv, std::chrono::seconds(g_tcpTimeout), [&stream]
    261 			{
    262 				return stream.get() && stream->isValid();
    263 			}))
    264 			{
    265 				throw synthLib::DeviceException(synthLib::DeviceError::RemoteTcpConnectFailed, "Failed to connect to " + host + ':' + std::to_string(si.portTcp));
    266 			}
    267 		}
    268 
    269 		// we are connected. Wait for device info as long as the connection is alive. The server will either
    270 		// close it if the requirements are not fulfilled (plugin not existing on server) or will eventually
    271 		// send device info after the device has bene opened on the server
    272 		m_connection.reset(new DeviceConnection(*this, std::move(stream)));
    273 
    274 		std::unique_lock lockCv(m_cvWaitMutex);
    275 		m_cvWait.wait(lockCv, [this]()
    276 		{
    277 			// continue waiting if the connection is still active but we didn't receive a device desc yet
    278 			return !m_connection->isValid() || m_deviceDesc.outChannels > 0;
    279 		});
    280 
    281 		if(!m_connection->isValid() || m_deviceDesc.outChannels == 0)
    282 			throw synthLib::DeviceException(synthLib::DeviceError::RemoteTcpConnectFailed);
    283 
    284 		m_valid = true;
    285 
    286 		LOG("Connection established successfully");
    287 	}
    288 }