Audio plugin host https://kx.studio/carla
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.

ports.h 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497
  1. /*
  2. * Copyright (c) 2012 Mark McCurry
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a
  5. * copy of this software and associated documentation files (the "Software"),
  6. * to deal in the Software without restriction, including without limitation
  7. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8. * and/or sell copies of the Software, and to permit persons to whom the
  9. * Software is furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice (including the next
  12. * paragraph) shall be included in all copies or substantial portions of the
  13. * Software.
  14. *
  15. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  16. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  17. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  18. * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  19. * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  20. * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  22. * DEALINGS IN THE SOFTWARE.
  23. */
  24. /**
  25. * @file ports.h
  26. * Collection of functions for ports.
  27. * This includes dispatchin, reading metadata etc.
  28. */
  29. #ifndef RTOSC_PORTS
  30. #define RTOSC_PORTS
  31. #include <vector>
  32. #include <functional>
  33. #include <initializer_list>
  34. #include <rtosc/rtosc.h>
  35. #include <rtosc/rtosc-version.h>
  36. #include <cstring>
  37. #include <cctype>
  38. #include <cstdlib>
  39. #include <cstdio>
  40. #include <string>
  41. namespace rtosc {
  42. //First define all types
  43. typedef const char *msg_t;
  44. struct Port;
  45. struct Ports;
  46. //! data object for the dispatch routine
  47. struct RtData
  48. {
  49. RtData(void);
  50. /**
  51. * Location of where the dispatch routine is currently being called.
  52. * If non-NULL, the dispatch routine will update the port name here while
  53. * walking through the Ports tree
  54. */
  55. char *loc;
  56. size_t loc_size;
  57. void *obj; //!< runtime object to dispatch this object to
  58. int matches; //!< number of matches returned from dispatch routine
  59. const Port *port; //!< dispatch will write the matching port's pointer here
  60. //! @brief Will be set to point to the full OSC message in case of
  61. //! a base dispatch
  62. const char *message;
  63. int idx[16];
  64. void push_index(int ind);
  65. void pop_index(void);
  66. virtual void replyArray(const char *path, const char *args,
  67. rtosc_arg_t *vals);
  68. virtual void reply(const char *path, const char *args, ...);
  69. //!Reply if information has been requested
  70. virtual void reply(const char *msg);
  71. virtual void chain(const char *path, const char *args, ...);
  72. //!Bypass message to some kind of backend if the message can not be handled
  73. virtual void chain(const char *msg);
  74. virtual void chainArray(const char *path, const char *args,
  75. rtosc_arg_t *vals);
  76. //!Transmit initialization/change of a value to all listeners
  77. virtual void broadcast(const char *path, const char *args, ...);
  78. virtual void broadcast(const char *msg);
  79. virtual void broadcastArray(const char *path, const char *args,
  80. rtosc_arg_t *vals);
  81. virtual void forward(const char *rational=NULL);
  82. };
  83. /**
  84. * Port in rtosc dispatching hierarchy
  85. */
  86. struct Port {
  87. const char *name; //!< Pattern for messages to match
  88. const char *metadata;//!< Statically accessable data about port
  89. const Ports *ports; //!< Pointer to further ports
  90. std::function<void(msg_t, RtData&)> cb;//!< Callback for matching functions
  91. class MetaIterator
  92. {
  93. public:
  94. MetaIterator(const char *str);
  95. //A bit odd to return yourself, but it seems to work for this
  96. //context
  97. const MetaIterator& operator*(void) const {return *this;}
  98. const MetaIterator* operator->(void) const {return this;}
  99. bool operator==(MetaIterator a) {return title == a.title;}
  100. bool operator!=(MetaIterator a) {return title != a.title;}
  101. MetaIterator& operator++(void);
  102. operator bool() const;
  103. const char *title;
  104. const char *value;
  105. };
  106. class MetaContainer
  107. {
  108. public:
  109. MetaContainer(const char *str_);
  110. MetaIterator begin(void) const;
  111. MetaIterator end(void) const;
  112. MetaIterator find(const char *str) const;
  113. size_t length(void) const;
  114. //!Return the key to the value @p str, or NULL if the key is
  115. //!invalid or if there's no value for that key.
  116. const char *operator[](const char *str) const;
  117. const char *str_ptr;
  118. };
  119. MetaContainer meta(void) const
  120. {
  121. if(metadata && *metadata == ':')
  122. return MetaContainer(metadata+1);
  123. else
  124. return MetaContainer(metadata);
  125. }
  126. };
  127. /**
  128. * Ports - a dispatchable collection of Port entries
  129. *
  130. * This structure makes it somewhat easier to perform actions on collections of
  131. * port entries and it is responsible for the dispatching of OSC messages to
  132. * their respective ports.
  133. * That said, it is a very simple structure, which uses a stl container to store
  134. * all data in a simple dispatch table.
  135. * All methods post-initialization are RT safe (assuming callbacks are RT safe)
  136. */
  137. struct Ports
  138. {
  139. std::vector<Port> ports;
  140. std::function<void(msg_t, RtData&)> default_handler;
  141. typedef std::vector<Port>::const_iterator itr_t;
  142. /**Forwards to builtin container*/
  143. itr_t begin() const {return ports.begin();}
  144. /**Forwards to builtin container*/
  145. itr_t end() const {return ports.end();}
  146. /**Forwards to builtin container*/
  147. size_t size() const {return ports.size();}
  148. /**Forwards to builtin container*/
  149. const Port &operator[](unsigned i) const {return ports[i];}
  150. Ports(std::initializer_list<Port> l);
  151. ~Ports(void);
  152. Ports(const Ports&) = delete;
  153. /**
  154. * Dispatches message to all matching ports.
  155. * This uses simple pattern matching available in rtosc::match.
  156. *
  157. * @param m A valid OSC message. Note that the address part shall not
  158. * contain any type specifier.
  159. * @param d The RtData object shall contain a path buffer (or null), the length of
  160. * the buffer, a pointer to data. It must also contain the location
  161. * if an answer is being expected.
  162. * @param base_dispatch Whether the OSC path is to be interpreted as a full
  163. * OSC path beginning at the root
  164. */
  165. void dispatch(const char *m, RtData &d, bool base_dispatch=false) const;
  166. /**
  167. * Retrieve local port by name
  168. * TODO implement full matching
  169. */
  170. const Port *operator[](const char *name) const;
  171. /**
  172. * Find the best match for a given path
  173. *
  174. * @parameter path partial OSC path
  175. * @returns first path prefixed by the argument
  176. *
  177. * Example usage:
  178. * @code
  179. * Ports p = {{"foo",0,0,dummy_method},
  180. * {"flam",0,0,dummy_method},
  181. * {"bar",0,0,dummy_method}};
  182. * p.apropos("/b")->name;//bar
  183. * p.apropos("/f")->name;//foo
  184. * p.apropos("/fl")->name;//flam
  185. * p.apropos("/gg");//NULL
  186. * @endcode
  187. */
  188. const Port *apropos(const char *path) const;
  189. /**
  190. * Collapse path with parent path identifiers "/.."
  191. *
  192. * e.g. /foo/bar/../baz => /foo/baz
  193. */
  194. static char *collapsePath(char *p);
  195. protected:
  196. void refreshMagic(void);
  197. private:
  198. //Performance hacks
  199. class Port_Matcher *impl;
  200. unsigned elms;
  201. };
  202. struct ClonePort
  203. {
  204. const char *name;
  205. std::function<void(msg_t, RtData&)> cb;
  206. };
  207. struct ClonePorts:public Ports
  208. {
  209. ClonePorts(const Ports &p,
  210. std::initializer_list<ClonePort> c);
  211. };
  212. struct MergePorts:public Ports
  213. {
  214. MergePorts(std::initializer_list<const Ports*> c);
  215. };
  216. /**
  217. * Return a port's default value
  218. *
  219. * Returns the default value of a given port, if any exists, as a string.
  220. * For the parameters, see the overloaded function.
  221. * @note The recursive parameter should never be specified.
  222. * @return The default value(s), pretty-printed, or NULL if there is no
  223. * valid default annotation
  224. */
  225. const char* get_default_value(const char* port_name, const Ports& ports,
  226. void* runtime, const Port* port_hint = NULL,
  227. int32_t idx = -1, int recursive = 1);
  228. /**
  229. * Return a port's default value
  230. *
  231. * Returns the default value of a given port, if any exists, as an array of
  232. * rtosc_arg_vals . The values in the resulting array are being canonicalized,
  233. * i.e. mapped values are being converted to integers; see
  234. * canonicalize_arg_vals() .
  235. *
  236. * @param port_name the port's OSC path.
  237. * @param port_args the port's arguments, e.g. '::i:c:S'
  238. * @param ports the ports where @a portname is to be searched
  239. * @param runtime object holding @a ports . Optional. Helps finding
  240. * default values dependent on others, such as presets.
  241. * @param port_hint The port itself corresponding to portname (including
  242. * the args). If not specified, will be found using @p portname .
  243. * @param idx If the port is an array (using the '#' notation), this specifies
  244. * the index required for the default value
  245. * @param n Size of the output parameter @res . This size can not be known,
  246. * so you should provide a large enough array.
  247. * @param res The output parameter for the argument values.
  248. * @param strbuf String buffer for storing pretty printed strings and blobs.
  249. * @param strbufsize Size of @p strbuf
  250. * @return The actual number of aruments written to @p res (can be smaller
  251. * than @p n) or -1 if there is no valid default annotation
  252. */
  253. int get_default_value(const char* port_name, const char *port_args,
  254. const Ports& ports,
  255. void* runtime, const Port* port_hint,
  256. int32_t idx,
  257. size_t n, rtosc_arg_val_t* res,
  258. char *strbuf, size_t strbufsize);
  259. /**
  260. * Return a string list of all changed values
  261. *
  262. * Return a human readable list of the value that changed
  263. * corresponding to the rDefault macro
  264. * @param ports The static ports structure
  265. * @param runtime The runtime object
  266. * @return The list of ports and their changed values, linewise
  267. */
  268. std::string get_changed_values(const Ports& ports, void* runtime);
  269. //! Class to modify messages loaded from savefiles.
  270. //! Objects of this class shall be passed to savefile loading routines. You can
  271. //! inherit to change the behaviour, e.g. to modify or discard such messages.
  272. class savefile_dispatcher_t
  273. {
  274. const Ports* ports;
  275. void* runtime;
  276. char loc[1024];
  277. protected:
  278. enum proceed {
  279. abort = -2, //!< the message shall lead to abort the savefile loading
  280. discard = -1 //!< the message shall not be dispatched
  281. };
  282. enum dependency_t {
  283. no_dependencies, //! default values don't depend on others
  284. has_dependencies, //! default values do depend on others
  285. not_specified //! it's not know which of the other enum values fit
  286. };
  287. rtosc_version rtosc_filever, //!< rtosc versinon savefile was written with
  288. rtosc_curver, //!< rtosc version of this library
  289. app_filever, //!< app version savefile was written with
  290. app_curver; //!< current app version
  291. //! call this to dispatch a message
  292. void operator()(const char* msg);
  293. static int default_response(size_t nargs, bool first_round,
  294. dependency_t dependency);
  295. private:
  296. //! callback for when a message shall be dispatched
  297. //! implement this if you need to change a message
  298. virtual int on_dispatch(size_t portname_max, char* portname,
  299. size_t maxargs, size_t nargs,
  300. rtosc_arg_val_t* args,
  301. bool round2, dependency_t dependency);
  302. friend int dispatch_printed_messages(const char* messages,
  303. const Ports& ports, void* runtime,
  304. savefile_dispatcher_t *dispatcher);
  305. friend int load_from_file(const char* file_content,
  306. const Ports& ports, void* runtime,
  307. const char* appname,
  308. rtosc_version appver,
  309. savefile_dispatcher_t* dispatcher);
  310. };
  311. /**
  312. * Scan OSC messages from human readable format and dispatch them.
  313. * @param messages The OSC messages, whitespace-separated
  314. * @param ports The static ports structure
  315. * @param runtime The runtime object
  316. * @param dispatcher Object to modify messages prior to dispatching, or NULL.
  317. * You can overwrite its virtual functions, and you should specify any of the
  318. * version structs if needed. All other members shall not be initialized.
  319. * @return The number of messages read, or, if there was a read error,
  320. * the number of bytes read until the read error occured minus one
  321. */
  322. int dispatch_printed_messages(const char* messages,
  323. const Ports& ports, void* runtime,
  324. savefile_dispatcher_t *dispatcher = NULL);
  325. /**
  326. * Return a savefile containing all values that differ from the default values.
  327. * @param ports The static ports structure
  328. * @param runtime The runtime object
  329. * @param appname Name of the application calling this function
  330. * @param appver Version of the application calling this function
  331. * @return The resulting savefile as an std::sting
  332. */
  333. std::string save_to_file(const Ports& ports, void* runtime,
  334. const char* appname, rtosc_version appver);
  335. /**
  336. * Read save file and dispatch contained parameters.
  337. * @param file_content The file as a C string
  338. * @param ports The static ports structure
  339. * @param runtime The runtime object
  340. * @param appname Name of the application calling this function; must
  341. * match the file's application name
  342. * @param appver Version of the application calling this function
  343. * @param dispatcher Modifier for the messages; NULL if no modifiers are needed
  344. * @return The number of messages read, or, if there was a read error,
  345. * the negated number of bytes read until the read error occured minus one
  346. */
  347. int load_from_file(const char* file_content,
  348. const Ports& ports, void* runtime,
  349. const char* appname,
  350. rtosc_version appver,
  351. savefile_dispatcher_t* dispatcher = NULL);
  352. /**
  353. * Convert given argument values to their canonical representation.
  354. *
  355. * The ports first (or-wise) argument types are defined as canonical.
  356. * E.g. if passing two 'S' argument values, the
  357. * port could be `portname::ii:cc:SS` or `portname::ii:t`.
  358. *
  359. * @param av The input and output argument values
  360. * @param n The size of @p av
  361. * @param port_args The port arguments string, e.g. `::i:c:s`. The first
  362. * non-colon letter sequence marks the canonical types
  363. * @param meta The port's metadata container
  364. * @return The number of argument values that should have need conversion,
  365. * but failed, e.g. because of values missing in rMap.
  366. */
  367. int canonicalize_arg_vals(rtosc_arg_val_t* av, size_t n,
  368. const char* port_args, Port::MetaContainer meta);
  369. /**
  370. * Convert each of the given arguments to their mapped symbol, if possible.
  371. * @param av The input and output argument values
  372. * @param n The size of @p av
  373. * @param meta The port's metadata container
  374. */
  375. void map_arg_vals(rtosc_arg_val_t* av, size_t n,
  376. Port::MetaContainer meta);
  377. /*********************
  378. * Port walking code *
  379. *********************/
  380. //typedef std::function<void(const Port*,const char*)> port_walker_t;
  381. /**
  382. * Function pointer type for port walking.
  383. *
  384. * accepts:
  385. * - the currently walked port
  386. * - the port's absolute location
  387. * - the part of the location which makes up the port; this is usually the
  388. * location's substring after the last slash, but it can also contain multiple
  389. * slashes
  390. * - the port's base, i.e. it's parent Ports struct
  391. * - the custom data supplied to walk_ports
  392. * - the runtime object (which may be NULL if not known)
  393. */
  394. typedef void(*port_walker_t)(const Port*,const char*,const char*,
  395. const Ports&,void*,void*);
  396. /**
  397. * Call a function on all ports and subports.
  398. * @param base The base port of traversing
  399. * @param name_buffer Buffer which will be filled with the port name; must be
  400. * reset to zero over the full length!
  401. * @param buffer_size Size of name_buffer
  402. * @param data Data that should be available in the callback
  403. * @param walker Callback function
  404. */
  405. void walk_ports(const Ports *base,
  406. char *name_buffer,
  407. size_t buffer_size,
  408. void *data,
  409. port_walker_t walker,
  410. void *runtime = NULL);
  411. /**
  412. * Return the index with value @p value from the metadata's enumeration.
  413. * @param meta The metadata
  414. * @param value The value to search the key for
  415. * @return The first key holding value, or `std::numeric_limits<int>::min()`
  416. * if none was found
  417. */
  418. int enum_key(Port::MetaContainer meta, const char* value);
  419. /*********************
  420. * Port Dumping code *
  421. *********************/
  422. struct OscDocFormatter
  423. {
  424. const Ports *p;
  425. std::string prog_name;
  426. std::string uri;
  427. std::string doc_origin;
  428. std::string author_first;
  429. std::string author_last;
  430. //TODO extend this some more
  431. };
  432. std::ostream &operator<<(std::ostream &o, OscDocFormatter &formatter);
  433. };
  434. #endif