aboutsummaryrefslogtreecommitdiff
path: root/osc.lv2/osc.lv2
diff options
context:
space:
mode:
authorHanspeter Portner <dev@open-music-kontrollers.ch>2020-06-29 22:26:19 +0200
committerHanspeter Portner <dev@open-music-kontrollers.ch>2020-06-29 22:26:19 +0200
commit55515223a0b051b40ff775aaaca8debe81d1271c (patch)
tree1b35028e75b5bd56f5bb15f3bac4a91809cd4028 /osc.lv2/osc.lv2
parentbb682a80101fca64278059755419ae389edffa6e (diff)
parent126c7d37fe01ca0957d71c0e92f05bac19daf927 (diff)
downloadsynthpod-55515223a0b051b40ff775aaaca8debe81d1271c.tar.xz
Merge commit '126c7d37fe01ca0957d71c0e92f05bac19daf927'
Diffstat (limited to 'osc.lv2/osc.lv2')
-rw-r--r--osc.lv2/osc.lv2/reader.h55
-rw-r--r--osc.lv2/osc.lv2/stream.h35
-rw-r--r--osc.lv2/osc.lv2/util.h126
3 files changed, 215 insertions, 1 deletions
diff --git a/osc.lv2/osc.lv2/reader.h b/osc.lv2/osc.lv2/reader.h
index 8e0ae459..7a8456b5 100644
--- a/osc.lv2/osc.lv2/reader.h
+++ b/osc.lv2/osc.lv2/reader.h
@@ -24,14 +24,25 @@
#include <osc.lv2/osc.h>
#include <osc.lv2/endian.h>
+#include <osc.lv2/util.h>
#ifdef __cplusplus
extern "C" {
#endif
+
+typedef struct _LV2_OSC_Tree LV2_OSC_Tree;
typedef struct _LV2_OSC_Reader LV2_OSC_Reader;
typedef struct _LV2_OSC_Item LV2_OSC_Item;
typedef struct _LV2_OSC_Arg LV2_OSC_Arg;
+typedef void (*LV2_OSC_Branch)(LV2_OSC_Reader *reader, LV2_OSC_Arg *arg,
+ const LV2_OSC_Tree *tree, void *data);
+
+struct _LV2_OSC_Tree {
+ const char *name;
+ const LV2_OSC_Tree *trees;
+ LV2_OSC_Branch branch;
+};
struct _LV2_OSC_Reader {
const uint8_t *buf;
@@ -564,6 +575,50 @@ lv2_osc_reader_is_message(LV2_OSC_Reader *reader)
return reader->ptr[0] == '/'; //FIXME check path
}
+static inline void
+_lv2_osc_trees_internal(LV2_OSC_Reader *reader, const char *path, const char *from,
+ LV2_OSC_Arg *arg, const LV2_OSC_Tree *trees, void *data)
+{
+ const char *ptr = strchr(from, '/');
+
+ const size_t len = ptr
+ ? (size_t)(ptr - from)
+ : strlen(from);
+
+ for(const LV2_OSC_Tree *tree = trees; tree && tree->name; tree++)
+ {
+ if(lv2_osc_pattern_match(from, tree->name, len))
+ {
+ if(tree->trees && ptr)
+ {
+ if(tree->branch)
+ {
+ LV2_OSC_Reader reader_clone = *reader;
+ tree->branch(&reader_clone, arg, tree, data);
+ }
+
+ _lv2_osc_trees_internal(reader, path, &ptr[1], arg, tree->trees, data);
+ }
+ else if(tree->branch && !ptr)
+ {
+ LV2_OSC_Reader reader_clone = *reader;
+ tree->branch(&reader_clone, arg, tree, data);
+ }
+ }
+ }
+}
+
+static inline void
+lv2_osc_reader_match(LV2_OSC_Reader *reader, size_t len,
+ const LV2_OSC_Tree *trees, void *data)
+{
+ LV2_OSC_Arg *arg = OSC_READER_MESSAGE_BEGIN(reader, len);
+ const char *path = arg->path;
+ const char *from = &path[1];
+
+ _lv2_osc_trees_internal(reader, path, from, arg, trees, data);
+}
+
#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/osc.lv2/osc.lv2/stream.h b/osc.lv2/osc.lv2/stream.h
index a86c2309..c1339c0d 100644
--- a/osc.lv2/osc.lv2/stream.h
+++ b/osc.lv2/osc.lv2/stream.h
@@ -19,6 +19,7 @@
#define LV2_OSC_STREAM_H
#include <stdbool.h>
+#include <stdlib.h>
#include <string.h>
#if !defined(_WIN32)
# include <arpa/inet.h>
@@ -34,6 +35,7 @@
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
+#include <poll.h>
#include <osc.lv2/osc.h>
@@ -665,7 +667,7 @@ lv2_osc_stream_init(LV2_OSC_Stream *stream, const char *url,
{
memset(stream, 0x0, sizeof(LV2_OSC_Stream));
- strncpy(stream->url, url, sizeof(stream->url));
+ strncpy(stream->url, url, sizeof(stream->url) - 1);
stream->driv = driv;
stream->data = data;
stream->sock = -1;
@@ -1372,6 +1374,37 @@ lv2_osc_stream_run(LV2_OSC_Stream *stream)
return ev;
}
+static LV2_OSC_Enum
+lv2_osc_stream_pollin(LV2_OSC_Stream *stream, int timeout_ms)
+{
+ struct pollfd fds [2] = {
+ [0] = {
+ .fd = stream->sock,
+ .events = POLLIN,
+ .revents = 0
+ },
+ [1] = {
+ .fd = stream->fd,
+ .events = POLLIN,
+ .revents = 0
+ }
+ };
+
+ const int res = poll(fds, 2, timeout_ms);
+ if(res < 0)
+ {
+ return LV2_OSC_STREAM_ERRNO(LV2_OSC_NONE, errno);
+ }
+
+#if 0
+ fprintf(stderr, "++ %i: %i %i %i %i\n", res,
+ fds[0].fd, (int)fds[0].revents,
+ fds[1].fd, (int)fds[1].revents);
+#endif
+
+ return lv2_osc_stream_run(stream);
+}
+
#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/osc.lv2/osc.lv2/util.h b/osc.lv2/osc.lv2/util.h
index 195bb867..35176181 100644
--- a/osc.lv2/osc.lv2/util.h
+++ b/osc.lv2/osc.lv2/util.h
@@ -23,6 +23,9 @@
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
+#if !defined(_WIN32)
+# include <fnmatch.h>
+#endif
#include <osc.lv2/osc.h>
@@ -45,6 +48,15 @@ extern "C" {
typedef void (*LV2_OSC_Method)(const char *path,
const LV2_Atom_Tuple *arguments, void *data);
+typedef struct _LV2_OSC_Hook LV2_OSC_Hook;
+
+struct _LV2_OSC_Hook {
+ const char *name;
+ const LV2_OSC_Hook *hooks;
+ LV2_OSC_Method method;
+ void *data;
+};
+
// characters not allowed in OSC path string
static const char invalid_path_chars [] = {
' ', '#',
@@ -60,6 +72,120 @@ static const char valid_format_chars [] = {
'\0'
};
+static bool
+lv2_osc_pattern_match(const char *from, const char *name, size_t len)
+{
+#if !defined(_WIN32)
+ size_t nbrace = 0;
+
+# if defined(FNM_EXTMATCH)
+ // count opening curly braces
+ for(size_t i = 0; i < len; i++)
+ {
+ if(from[i] == '{')
+ {
+ nbrace++;
+ }
+ }
+# endif
+
+ // allocate temporary pattern buffer
+ char *pattern = alloca(len + nbrace + 1);
+
+ if(!pattern)
+ {
+ return false;
+ }
+
+# if defined(FNM_EXTMATCH)
+ // convert {x,y} to @(x|y) for extended fnmatch
+ if(nbrace)
+ {
+ char *ptr = pattern;
+
+ for(size_t i = 0; i < len; i++)
+ {
+ switch(from[i])
+ {
+ case '{':
+ {
+ *ptr++ = '@';
+ *ptr++ = '(';
+ } break;
+ case ',':
+ {
+ *ptr++ = '|';
+ } break;
+ case '}':
+ {
+ *ptr++ = ')';
+ } break;
+ default:
+ {
+ *ptr++ = from[i];
+ } break;
+ }
+ }
+ }
+ else
+# endif
+ {
+ memcpy(pattern, from, len);
+ }
+
+ // terminate pattern string with null terminator
+ pattern[len + nbrace] = '\0';
+
+# if defined(FNM_EXTMATCH)
+ return fnmatch(pattern, name, FNM_NOESCAPE | FNM_EXTMATCH) == 0 ? true : false;
+# else
+ return fnmatch(pattern, name, FNM_NOESCAPE) == 0 ? true : false;
+# endif
+#else
+ return strncmp(from, name, len) == 0 ? true : false;
+#endif
+}
+
+static void
+_lv2_osc_hooks_internal(const char *path, const char *from,
+ const LV2_Atom_Tuple *arguments, const LV2_OSC_Hook *hooks)
+{
+ const char *ptr = strchr(from, '/');
+
+ const size_t len = ptr
+ ? (size_t)(ptr - from)
+ : strlen(from);
+
+ for(const LV2_OSC_Hook *hook = hooks; hook && hook->name; hook++)
+ {
+ if(lv2_osc_pattern_match(from, hook->name, len))
+ {
+ if(hook->hooks && ptr)
+ {
+ from = &ptr[1];
+
+ _lv2_osc_hooks_internal(path, from, arguments, hook->hooks);
+ }
+ else if(hook->method && !ptr)
+ {
+ hook->method(path, arguments, hook->data);
+ }
+ }
+ }
+}
+
+/**
+ TODO
+*/
+static void
+lv2_osc_hooks(const char *path, const LV2_Atom_Tuple *arguments, void *data)
+{
+ const LV2_OSC_Hook *hooks = data;
+ const char *from = &path[1];
+
+ _lv2_osc_hooks_internal(path, from, arguments, hooks);
+}
+
/**
TODO
*/