You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

509 lines
18KB

  1. #ifndef MODULE_OSCCV_HPP
  2. #define MODULE_OSCCV_HPP
  3. #include "rack.hpp"
  4. using namespace rack;
  5. #include "trowaSoft.hpp"
  6. #include "dsp/digital.hpp"
  7. #include "trowaSoftUtilities.hpp"
  8. #include "TSOSCCommunicator.hpp"
  9. #include <thread> // std::thread
  10. #include <mutex>
  11. #include <string>
  12. #include <queue>
  13. #include "../lib/oscpack/osc/OscOutboundPacketStream.h"
  14. #include "../lib/oscpack/ip/UdpSocket.h"
  15. #include "../lib/oscpack/osc/OscReceivedElements.h"
  16. #include "../lib/oscpack/osc/OscPacketListener.h"
  17. // Model for trowa OSC2CV
  18. extern Model* modelOscCV;
  19. #define TROWA_OSSCV_SHOW_ADV_CH_CONFIG 1 // Flag to showing advanced config or hiding it (while it is not finished)
  20. #define TROWA_OSCCV_DEFAULT_NUM_CHANNELS 8 // Default number of channels
  21. #define TROWA_OSCCV_NUM_PORTS_PER_INPUT 2 // Each input port should have a trigger input and actual value input.
  22. #define TROWA_OSCCV_DEFAULT_NAMESPACE "trowacv" // Default namespace for this module (should not be the same as the sequencers)
  23. #define TROWA_OSCCV_MAX_VOLTAGE 10.0 // Max output voltage
  24. #define TROWA_OSCCV_MIN_VOLTAGE -10.0 // Min output voltage
  25. #define TROWA_OSCCV_VAL_BUFFER_SIZE 512 // Buffer size for value history
  26. #define TROWA_OSCCV_TRIGGER_ON_V 10.0 // Trigger on/high output voltage
  27. #define TROWA_OSCCV_TRIGGER_OFF_V 0.0 // Trigger off/low output voltage
  28. #define TROWA_OSCCV_MIDI_VALUE_MIN_V -5 // -5v : Midi Value 0 (C-1)
  29. #define TROWA_OSCCV_MIDI_VALUE_MAX_V 5.58333 // +5.5833v : Midi Value 127
  30. #define TROWA_OSCCV_MIDI_VALUE_MIN 0 // Midi value 0
  31. #define TROWA_OSCCV_MIDI_VALUE_MAX 127 // Midi value 127
  32. #define TROWA_OSCCV_DEFAULT_SEND_HZ 100 // If no trigger input, bang out OSC when val changes this many times per second.
  33. #define TROWA_OSCCV_NUM_LIGHTS_PER_CHANNEL 2
  34. // A channel for OSC.
  35. struct TSOSCCVChannel {
  36. // Base param ids for the channel
  37. enum BaseParamIds {
  38. CH_SHOW_CONFIG,
  39. CH_NUM_PARAMS
  40. };
  41. // Path for this channel. Must start with '/'.
  42. std::string path;
  43. // The value
  44. float val = 0.0;
  45. // The translated value
  46. float translatedVal = 0.0;
  47. //// The last value we SENT over OSC (for tracking changes).
  48. //float lastVal = -20.0;
  49. //// The last translated value we SENT over OSC (for tracking changes).
  50. //float lastTranslatedVal = -20.0;
  51. uint32_t uintVal = 0;
  52. //uint32_t lastUintVal = 0;
  53. // Channel number (1-based)
  54. int channelNum;
  55. // What our parameter type should be. We can't really translate strings to voltage, so that is not available.
  56. enum ArgDataType : int {
  57. OscFloat = 1,
  58. OscInt = 2,
  59. OscBool = 3,
  60. // An OSC Midi message -- Not sure what actually supports this natively.
  61. OscMidi = 20
  62. };
  63. ArgDataType dataType = ArgDataType::OscFloat;
  64. // Message received.
  65. //float msgReceived = 0.0;
  66. // Value buffer
  67. float valBuffer[TROWA_OSCCV_VAL_BUFFER_SIZE] = { 0.0 };
  68. // Value buffer current index to insert into.
  69. int valBuffIx = 0;
  70. // The frame index.
  71. int frameIx = 0;
  72. // Show channel configuration for this channel.
  73. SchmittTrigger showChannelConfigTrigger;
  74. /// TODO: Configuration for conversion & use the conversion stuff.
  75. /// TODO: Eventually allow strings? Basically user would have to enumerate and we should have an index into the array of strings.
  76. // Min Rack input or output voltage
  77. float minVoltage = TROWA_OSCCV_MIN_VOLTAGE;
  78. // Max Rack input or output voltage
  79. float maxVoltage = TROWA_OSCCV_MAX_VOLTAGE;
  80. // Min OSC input or output value.
  81. float minOscVal = 0;
  82. // Max OSC input or output value.
  83. float maxOscVal = 127;
  84. // If we should translate between the min and max values.
  85. bool convertVals = false;
  86. std::mutex mutPath;
  87. TSOSCCVChannel()
  88. {
  89. return;
  90. }
  91. TSOSCCVChannel(int chNum, std::string path) : TSOSCCVChannel()
  92. {
  93. this->channelNum = chNum;
  94. this->path = path;
  95. initialize();
  96. return;
  97. }
  98. virtual void initialize() {
  99. this->convertVals = false;
  100. this->val = 0.0;
  101. this->translatedVal = getValOSC2CV();
  102. this->dataType = ArgDataType::OscFloat;
  103. // Min Rack input or output voltage
  104. minVoltage = TROWA_OSCCV_MIDI_VALUE_MIN_V;
  105. // Max Rack input or output voltage
  106. maxVoltage = TROWA_OSCCV_MIDI_VALUE_MAX_V;
  107. // Min OSC input or output value.
  108. minOscVal = 0;
  109. // Max OSC input or output value.
  110. maxOscVal = 127;
  111. for (int i = 0; i < TROWA_OSCCV_VAL_BUFFER_SIZE; i++)
  112. {
  113. valBuffer[i] = 0.0f;
  114. }
  115. valBuffIx = 0;
  116. convertVals = false;
  117. return;
  118. } // end initialize()
  119. // Get the value translated from OSC to CV voltage.
  120. float getValOSC2CV() {
  121. float tVal = val;
  122. if (convertVals) {
  123. tVal = rescale(val, minOscVal, maxOscVal, minVoltage, maxVoltage);
  124. }
  125. return tVal;
  126. }
  127. // Get the value translated from CV voltage to OSC value.
  128. float getValCV2OSC() {
  129. float tVal = val;
  130. if (convertVals) {
  131. tVal = rescale(val, minVoltage, maxVoltage, minOscVal, maxOscVal);
  132. switch (this->dataType)
  133. {
  134. case TSOSCCVChannel::ArgDataType::OscInt:
  135. tVal = static_cast<float>(static_cast<int>(tVal));
  136. break;
  137. case TSOSCCVChannel::ArgDataType::OscBool:
  138. tVal = static_cast<float>(static_cast<bool>(tVal));
  139. break;
  140. case TSOSCCVChannel::ArgDataType::OscFloat:
  141. default:
  142. break;
  143. }
  144. }
  145. return tVal;
  146. }
  147. void setOSCInValue(float oscVal) {
  148. val = oscVal;
  149. translatedVal = getValOSC2CV();
  150. return;
  151. }
  152. void addValToBuffer(float buffVal);
  153. void setValue(float newVal) {
  154. val = newVal;
  155. if (convertVals)
  156. translatedVal = getValCV2OSC();
  157. addValToBuffer(newVal);
  158. return;
  159. }
  160. void setPath(std::string path)
  161. {
  162. std::lock_guard<std::mutex> lock(mutPath);
  163. if (path[0] != '/')
  164. this->path = "/" + path;
  165. else
  166. this->path = path;
  167. return;
  168. }
  169. std::string getPath() {
  170. std::lock_guard<std::mutex> lock(mutPath);
  171. return path;
  172. }
  173. //--------------------------------------------------------
  174. // serialize()
  175. // @returns : The channel json node.
  176. //--------------------------------------------------------
  177. virtual json_t* serialize();
  178. //--------------------------------------------------------
  179. // deserialize()
  180. // @rootJ : (IN) The channel json node.
  181. //--------------------------------------------------------
  182. virtual void deserialize(json_t* rootJ);
  183. };
  184. // Channel specifically for CV Input -> OSC.
  185. // Extra stuff for knowing when to send output.
  186. struct TSOSCCVInputChannel : TSOSCCVChannel {
  187. // The last value we SENT over OSC (for tracking changes).
  188. float lastVal = -20.0;
  189. // The last translated value we SENT over OSC (for tracking changes).
  190. float lastTranslatedVal = -20.0;
  191. // If trigger is not set up (input type channel), how much input change is needed to send a message out.
  192. float channelSensitivity = 0.05f;
  193. // If we should send. Working value for module.
  194. bool doSend = false;
  195. TSOSCCVInputChannel() : TSOSCCVChannel()
  196. {
  197. return;
  198. }
  199. TSOSCCVInputChannel(int chNum, std::string path)
  200. {
  201. this->channelNum = chNum;
  202. this->path = path;
  203. this->initialize();
  204. return;
  205. }
  206. void initialize() override {
  207. this->lastVal = -20.0;
  208. this->lastTranslatedVal = -20.0;
  209. channelSensitivity = 0.05f;
  210. TSOSCCVChannel::initialize();
  211. doSend = false;
  212. return;
  213. } // end initialize()
  214. //--------------------------------------------------------
  215. // serialize()
  216. // @returns : The channel json node.
  217. //--------------------------------------------------------
  218. json_t* serialize() override;
  219. //--------------------------------------------------------
  220. // deserialize()
  221. // @rootJ : (IN) The channel json node.
  222. //--------------------------------------------------------
  223. void deserialize(json_t* rootJ) override;
  224. };
  225. struct TSOSCCVSimpleMessage {
  226. // Channel Number (1-N)
  227. int channelNum;
  228. float rxVal;
  229. uint32_t uintRxVal;
  230. TSOSCCVSimpleMessage(int chNum, float recvVal)
  231. {
  232. channelNum = chNum;
  233. rxVal = recvVal;
  234. }
  235. TSOSCCVSimpleMessage(int chNum, float recvVal, uint32_t uintVal)
  236. {
  237. channelNum = chNum;
  238. rxVal = recvVal;
  239. uintRxVal = uintVal;
  240. }
  241. };
  242. class TSOSCCVSimpleMsgListener;
  243. //===============================================================================
  244. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  245. // oscCV
  246. // OSC <=> CV (Open Sound Control <=> Control Voltage)
  247. // Generic input port -> osc message (on change or on trigger)
  248. // Generic osc message -> output port (on receive)
  249. // Received messages can only have 1 argument (or only 1 will be parsed and used anyway).
  250. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  251. //===============================================================================
  252. struct oscCV : Module {
  253. // User control parameters
  254. enum ParamIds {
  255. OSC_SAVE_CONF_PARAM, // ENABLE and Save the configuration for OSC
  256. OSC_DISABLE_PARAM, // Disable OSC (ignore config values)
  257. OSC_SHOW_CONF_PARAM, // Configure OSC toggle
  258. OSC_SHOW_ADV_CONF_PARAM, // [TBI] Advanced configuration
  259. OSC_ADV_CONF_NEXT_PARAM, // [TBI] Advanced configuration Next >
  260. OSC_ADV_CONF_PREV_PARAM, // [TBI] Advanced configuration < Prev
  261. OSC_ADV_CONF_BACK_PARAM, // [TBI] Advanced configuration Back
  262. OSC_AUTO_RECONNECT_PARAM, // Automatically reconnect (if connection is active as of save) on re-load.
  263. OSC_CH_SAVE_PARAM, // Channel: Save changes and go back to main config.
  264. OSC_CH_CANCEL_PARAM, // Channel: Save changes and go back to main config.
  265. OSC_CH_OSC_DATATYPE_PARAM, // Channel: OSC data type.
  266. OSC_CH_TRANSLATE_VALS_PARAM, // Channel: Flag to translate/massage values
  267. OSC_CH_MIN_CV_VOLT_PARAM, // Channel: Minimum CV Voltage
  268. OSC_CH_MAX_CV_VOLT_PARAM, // Channel: Maximum CV Voltage
  269. OSC_CH_MIN_OSC_VAL_PARAM, // Channel: Minimum OSC Value
  270. OSC_CH_MAX_OSC_VAL_PARAM, // Channel: Maximum OSC Value
  271. OSC_CH_SEND_FREQ_PARAM, // [TBI] Channel [INPUT->OSC only]: Send frequency (if trigger not active)
  272. OSC_CH_SEND_THRESHOLD_PARAM, // [TBI] Channell [INPUT->OSC only]: CV value change needed to trigger send (if trigger not active)
  273. CH_PARAM_START,
  274. NUM_PARAMS = CH_PARAM_START // Add #channels * 2 to this
  275. };
  276. enum InputIds {
  277. CH_INPUT_START,
  278. NUM_INPUTS = CH_INPUT_START // Add # channels *2 to this
  279. };
  280. enum OutputIds {
  281. CH_OUTPUT_START,
  282. NUM_OUTPUTS = CH_OUTPUT_START // Add # channels*2 to this Determined by # of channels
  283. };
  284. enum LightIds {
  285. OSC_CONFIGURE_LIGHT, // The light for configuring OSC.
  286. OSC_ENABLED_LIGHT, // Light for OSC enabled and currently running/active.
  287. OSC_CH_TRANSLATE_LIGHT, // Light for Channel Translate enabled.
  288. CH_LIGHT_START,
  289. NUM_LIGHTS = CH_LIGHT_START // Add # channels *2 to this
  290. };
  291. // Flag for doing Input Rack CV -> OSC.
  292. bool doCVPort2OSC = true;
  293. // Flag for Input OSC -> Rack CV
  294. bool doOSC2CVPort = true;
  295. // Number of channels we have
  296. int numberChannels = TROWA_OSCCV_DEFAULT_NUM_CHANNELS;
  297. // Input CV (from Rack) ==> Needs to be output to OSC
  298. TSOSCCVInputChannel* inputChannels = NULL;
  299. // Input OSC (from External) ==> Needs to be translated to Rack output port CV
  300. TSOSCCVChannel* outputChannels = NULL;
  301. PulseGenerator* pulseGens = NULL;
  302. // The received messages.
  303. std::queue<TSOSCCVSimpleMessage> rxMsgQueue;
  304. SchmittTrigger* inputTriggers;
  305. int oscId;
  306. /// TODO: OSC members should be dumped into an OSC base class....
  307. // Mutex for osc messaging.
  308. std::mutex oscMutex;
  309. // Current OSC IP address and port settings.
  310. TSOSCConnectionInfo currentOSCSettings = { OSC_ADDRESS_DEF, OSC_OUTPORT_DEF , OSC_INPORT_DEF };
  311. // OSC Configure trigger
  312. SchmittTrigger oscConfigTrigger;
  313. SchmittTrigger oscConnectTrigger;
  314. // Show the OSC configuration screen or not.
  315. bool oscShowConfigurationScreen = false;
  316. float sendDt = 0.0f;
  317. int sendFrequency_Hz = TROWA_OSCCV_DEFAULT_SEND_HZ;
  318. // Flag to reconnect at load. IFF true and oscInitialized is also true.
  319. bool oscReconnectAtLoad = false;
  320. // Flag if OSC objects have been initialized
  321. bool oscInitialized = false;
  322. // If there is an osc error.
  323. bool oscError = false;
  324. // OSC output buffer.
  325. char* oscBuffer = NULL;
  326. // OSC namespace to use. Without the '/'.
  327. std::string oscNamespace = TROWA_OSCCV_DEFAULT_NAMESPACE;
  328. // Sending OSC socket
  329. UdpTransmitSocket* oscTxSocket = NULL;
  330. // OSC message listener
  331. TSOSCCVSimpleMsgListener* oscListener = NULL;
  332. // Receiving OSC socket
  333. UdpListeningReceiveSocket* oscRxSocket = NULL;
  334. // The OSC listener thread
  335. std::thread oscListenerThread;
  336. // Prev step that was last turned off (when going to a new step).
  337. int oscLastPrevStepUpdated = TROWA_INDEX_UNDEFINED;
  338. // Settings for new OSC.
  339. TSOSCInfo oscNewSettings = { OSC_ADDRESS_DEF, OSC_OUTPORT_DEF , OSC_INPORT_DEF };
  340. // OSC Mode action (i.e. Enable, Disable)
  341. enum OSCAction {
  342. None,
  343. Disable,
  344. Enable
  345. };
  346. // Flag for our module to either enable or disable osc.
  347. OSCAction oscCurrentAction = OSCAction::None;
  348. // If this has it controls configured.
  349. bool isInitialized = false;
  350. const float lightLambda = 0.005f;
  351. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  352. // oscCV()
  353. // Create a module with numChannels.
  354. // @numChannels: (IN) Number of input and output 'channels'. Each channel has two CV's.
  355. // @cv2osc: (IN) True to do CV to OSC out.
  356. // @osc2cv: (IN) True to do OSC to CV out.
  357. // At least one of those flags should be true.
  358. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  359. oscCV(int numChannels, bool cv2osc, bool osc2cv);
  360. oscCV() : oscCV(TROWA_OSCCV_DEFAULT_NUM_CHANNELS, true, true) {
  361. return;
  362. }
  363. ~oscCV();
  364. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  365. // initializeChannels(void)
  366. // Set channels to default values.
  367. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  368. void initialChannels() {
  369. for (int i = 0; i < numberChannels; i++)
  370. {
  371. if (doCVPort2OSC) {
  372. inputChannels[i].channelNum = i + 1;
  373. inputChannels[i].path = "/ch/" + std::to_string(i + 1);
  374. inputChannels[i].initialize();
  375. }
  376. if (doOSC2CVPort) {
  377. outputChannels[i].channelNum = i + 1;
  378. outputChannels[i].path = "/ch/" + std::to_string(i + 1);
  379. outputChannels[i].initialize();
  380. }
  381. }
  382. return;
  383. }
  384. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  385. // initOSC()
  386. // @ipAddres : (IN) The ip address of the OSC client / server.
  387. // @outputPort : (IN) The Tx port.
  388. // @inputPort : (IN) The Rx port.
  389. // Initialize OSC on the given ip and ports.
  390. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  391. void initOSC(const char* ipAddress, int outputPort, int inputPort);
  392. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  393. // Clean up OSC.
  394. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  395. void cleanupOSC();
  396. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  397. // setOscNamespace()
  398. // @oscNamespace : (IN) The namespace (without /).
  399. // Set the OSC namespace (thread safe-ish).
  400. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  401. void setOscNamespace(std::string oscNamespace);
  402. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  403. // step(void)
  404. // Process.
  405. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  406. void step() override;
  407. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  408. // reset(void)
  409. // Initialize values.
  410. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  411. void reset() override;
  412. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  413. // toJson(void)
  414. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  415. json_t *toJson() override;
  416. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  417. // fromJson(void)
  418. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  419. void fromJson(json_t *rootJ) override;
  420. };
  421. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  422. // Listener for OSC incoming messages.
  423. // Currently each module must have its own listener object & slave thread since I'm not 100% sure about the threading in Rack (if we could keep
  424. // one thread alive throughout the deaths of other modules). This way, its easy to clean up (when module dies, it kills its slave listener thread)
  425. // instead of tracking how many modules are still alive and using OSC.
  426. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  427. class TSOSCCVSimpleMsgListener : public osc::OscPacketListener {
  428. public:
  429. // Pointer to OSC module with a message queue to dump into.
  430. oscCV * oscModule;
  431. // OSC namespace to use. Currently, if message doesn't have this namespace, we will ignore it. In future, maybe one listener can feed multiple modules with different namespaces?
  432. std::string oscNamespace;
  433. // Instantiate a listener.
  434. TSOSCCVSimpleMsgListener();
  435. // Instantiate a listener.
  436. TSOSCCVSimpleMsgListener(std::string oscNs, oscCV* oscModule)
  437. {
  438. this->oscModule = oscModule;
  439. if (oscNs.length() > 0 && oscNs.at(0) != '/')
  440. this->oscNamespace = "/" + oscNs;
  441. else
  442. this->oscNamespace = oscNs;
  443. }
  444. void setNamespace(std::string oscNs)
  445. {
  446. //debug("Listener.setNamespace(): %s, first char is %c.", oscNs.c_str(), oscNs.at(0));
  447. std::lock_guard<std::mutex> lock(mutExNamespace);
  448. if (oscNs.length() > 0 && oscNs.at(0) != '/')
  449. this->oscNamespace = "/" + oscNs;
  450. else
  451. this->oscNamespace = oscNs;
  452. return;
  453. }
  454. protected:
  455. // Mutex for setting the namespace.
  456. std::mutex mutExNamespace;
  457. //--------------------------------------------------------------------------------------------------------------------------------------------
  458. // ProcessMessage()
  459. // @rxMsg : (IN) The received message from the OSC library.
  460. // @remoteEndPoint: (IN) The remove end point (sender).
  461. // Handler for receiving messages from the OSC library. Taken from their example listener.
  462. // Should create a generic TSExternalControlMessage for our trowaSoft sequencers and dump it in the module instance's queue.
  463. //--------------------------------------------------------------------------------------------------------------------------------------------
  464. virtual void ProcessMessage(const osc::ReceivedMessage& rxMsg, const IpEndpointName& remoteEndpoint) override;
  465. };
  466. #endif // !MODULE_OSCCV_HPP