diff options
275 files changed, 149047 insertions, 0 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..8fa8402 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,2 @@ +include: + - local: 'gitlab-ci/generic.yml' @@ -0,0 +1,201 @@ + The Artistic License 2.0 + + Copyright (c) 2000-2006, The Perl Foundation. + + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +Preamble + +This license establishes the terms under which a given free software +Package may be copied, modified, distributed, and/or redistributed. +The intent is that the Copyright Holder maintains some artistic +control over the development of that Package while still keeping the +Package available as open source and free software. + +You are always permitted to make arrangements wholly outside of this +license directly with the Copyright Holder of a given Package. If the +terms of this license do not permit the full use that you propose to +make of the Package, you should contact the Copyright Holder and seek +a different licensing arrangement. + +Definitions + + "Copyright Holder" means the individual(s) or organization(s) + named in the copyright notice for the entire Package. + + "Contributor" means any party that has contributed code or other + material to the Package, in accordance with the Copyright Holder's + procedures. + + "You" and "your" means any person who would like to copy, + distribute, or modify the Package. + + "Package" means the collection of files distributed by the + Copyright Holder, and derivatives of that collection and/or of + those files. A given Package may consist of either the Standard + Version, or a Modified Version. + + "Distribute" means providing a copy of the Package or making it + accessible to anyone else, or in the case of a company or + organization, to others outside of your company or organization. + + "Distributor Fee" means any fee that you charge for Distributing + this Package or providing support for this Package to another + party. It does not mean licensing fees. + + "Standard Version" refers to the Package if it has not been + modified, or has been modified only in ways explicitly requested + by the Copyright Holder. + + "Modified Version" means the Package, if it has been changed, and + such changes were not explicitly requested by the Copyright + Holder. + + "Original License" means this Artistic License as Distributed with + the Standard Version of the Package, in its current version or as + it may be modified by The Perl Foundation in the future. + + "Source" form means the source code, documentation source, and + configuration files for the Package. + + "Compiled" form means the compiled bytecode, object code, binary, + or any other form resulting from mechanical transformation or + translation of the Source form. + + +Permission for Use and Modification Without Distribution + +(1) You are permitted to use the Standard Version and create and use +Modified Versions for any purpose without restriction, provided that +you do not Distribute the Modified Version. + + +Permissions for Redistribution of the Standard Version + +(2) You may Distribute verbatim copies of the Source form of the +Standard Version of this Package in any medium without restriction, +either gratis or for a Distributor Fee, provided that you duplicate +all of the original copyright notices and associated disclaimers. At +your discretion, such verbatim copies may or may not include a +Compiled form of the Package. + +(3) You may apply any bug fixes, portability changes, and other +modifications made available from the Copyright Holder. The resulting +Package will still be considered the Standard Version, and as such +will be subject to the Original License. + + +Distribution of Modified Versions of the Package as Source + +(4) You may Distribute your Modified Version as Source (either gratis +or for a Distributor Fee, and with or without a Compiled form of the +Modified Version) provided that you clearly document how it differs +from the Standard Version, including, but not limited to, documenting +any non-standard features, executables, or modules, and provided that +you do at least ONE of the following: + + (a) make the Modified Version available to the Copyright Holder + of the Standard Version, under the Original License, so that the + Copyright Holder may include your modifications in the Standard + Version. + + (b) ensure that installation of your Modified Version does not + prevent the user installing or running the Standard Version. In + addition, the Modified Version must bear a name that is different + from the name of the Standard Version. + + (c) allow anyone who receives a copy of the Modified Version to + make the Source form of the Modified Version available to others + under + + (i) the Original License or + + (ii) a license that permits the licensee to freely copy, + modify and redistribute the Modified Version using the same + licensing terms that apply to the copy that the licensee + received, and requires that the Source form of the Modified + Version, and of any works derived from it, be made freely + available in that license fees are prohibited but Distributor + Fees are allowed. + + +Distribution of Compiled Forms of the Standard Version +or Modified Versions without the Source + +(5) You may Distribute Compiled forms of the Standard Version without +the Source, provided that you include complete instructions on how to +get the Source of the Standard Version. Such instructions must be +valid at the time of your distribution. If these instructions, at any +time while you are carrying out such distribution, become invalid, you +must provide new instructions on demand or cease further distribution. +If you provide valid instructions or cease distribution within thirty +days after you become aware that the instructions are invalid, then +you do not forfeit any of your rights under this license. + +(6) You may Distribute a Modified Version in Compiled form without +the Source, provided that you comply with Section 4 with respect to +the Source of the Modified Version. + + +Aggregating or Linking the Package + +(7) You may aggregate the Package (either the Standard Version or +Modified Version) with other packages and Distribute the resulting +aggregation provided that you do not charge a licensing fee for the +Package. Distributor Fees are permitted, and licensing fees for other +components in the aggregation are permitted. The terms of this license +apply to the use and Distribution of the Standard or Modified Versions +as included in the aggregation. + +(8) You are permitted to link Modified and Standard Versions with +other works, to embed the Package in a larger work of your own, or to +build stand-alone binary or bytecode versions of applications that +include the Package, and Distribute the result without restriction, +provided the result does not expose a direct interface to the Package. + + +Items That are Not Considered Part of a Modified Version + +(9) Works (including, but not limited to, modules and scripts) that +merely extend or make use of the Package, do not, by themselves, cause +the Package to be a Modified Version. In addition, such works are not +considered parts of the Package itself, and are not subject to the +terms of this license. + + +General Provisions + +(10) Any use, modification, and distribution of the Standard or +Modified Versions is governed by this Artistic License. By using, +modifying or distributing the Package, you accept this license. Do not +use, modify, or distribute the Package, if you do not accept this +license. + +(11) If your Modified Version has been derived from a Modified +Version made by someone other than you, you are nevertheless required +to ensure that your Modified Version complies with the requirements of +this license. + +(12) This license does not grant you the right to use any trademark, +service mark, tradename, or logo of the Copyright Holder. + +(13) This license includes the non-exclusive, worldwide, +free-of-charge patent license to make, have made, use, offer to sell, +sell, import and otherwise transfer the Package with respect to any +patent claims licensable by the Copyright Holder that are necessarily +infringed by the Package. If you institute patent litigation +(including a cross-claim or counterclaim) against any party alleging +that the Package constitutes direct or contributory patent +infringement, then this Artistic License to you shall terminate on the +date that such litigation is filed. + +(14) Disclaimer of Warranty: +THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS +IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL +LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..f520ef0 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,60 @@ +# Changelog + +## [0.24.0] - 15 Jul 2020 + +### Added + +* support for GL double buffering + +## [0.22.0] - 13 Apr 2020 + +### Added + +* reporting of decimal note/controller numbers in midi inspector + +### Fixed + +* scrolling in atom inspector TTL preview + +### Changed + +* to build with pugl master + +## [0.20.0] - 13 Oct 2019 + +### Added + +* sherlock:matchAll as default filter URI in atom inspector +* filter buttons for sherlock:matchAll and time:Position in atom inspector + +### Changed + +* position of negate toggle in atom inspector + +### Fixed + +* filter logic in atom inspector + +## [0.18.0] - 15 Apr 2019 + +### Added + +* ui resize extension +* tracing to host's log for atom_inspector +* filtering by URID for atom_inspector + +### Changed + +* build system from CMake to meson +* ui checkboxes +* routing only OSC messages/bundles to ui +* style to always light color row after frame row +* put OSC arguments on separate rows + +### Fixed + +* automatic scaling on hiDPI displays +* end-of-line handling in turtle lexer +* atom item sizes reporting +* turtle pretty number configuration switching +* strobing shadowing when in non-following mode diff --git a/README.md b/README.md new file mode 100644 index 0000000..99dbbd0 --- /dev/null +++ b/README.md @@ -0,0 +1,91 @@ +## Sherlock + +### An investigative LV2 plugin bundle + +This plugin bundle contains plugins for visualizing LV2 atom, MIDI and +OSC events. + +Use them for monitoring and debugging of event signal flows inside plugin graphs. + +#### Build status + +[](https://gitlab.com/OpenMusicKontrollers/sherlock.lv2/commits/master) + +### Binaries + +For GNU/Linux (64-bit, 32-bit, armv7, arm64). + +To install the plugin bundle on your system, simply copy the __sherlock.lv2__ +folder out of the platform folder of the downloaded package into your +[LV2 path](http://lv2plug.in/pages/filesystem-hierarchy-standard.html). + +#### Stable release + +* [sherlock.lv2-0.24.0.zip](https://dl.open-music-kontrollers.ch/sherlock.lv2/stable/sherlock.lv2-0.24.0.zip) ([sig](https://dl.open-music-kontrollers.ch/sherlock.lv2/stable/sherlock.lv2-0.24.0.zip.sig)) + +#### Unstable (nightly) release + +* [sherlock.lv2-latest-unstable.zip](https://dl.open-music-kontrollers.ch/sherlock.lv2/unstable/sherlock.lv2-latest-unstable.zip) ([sig](https://dl.open-music-kontrollers.ch/sherlock.lv2/unstable/sherlock.lv2-latest-unstable.zip.sig)) + +### Sources + +#### Stable release + +* [sherlock.lv2-0.24.0.tar.xz](https://git.open-music-kontrollers.ch/lv2/sherlock.lv2/snapshot/sherlock.lv2-0.24.0.tar.xz) +([sig](https://git.open-music-kontrollers.ch/lv2/sherlock.lv2/snapshot/sherlock.lv2-0.24.0.tar.xz.asc)) + +#### Git repository + +* <https://git.open-music-kontrollers.ch/lv2/sherlock.lv2> + +### Packages + +* [ArchLinux](https://www.archlinux.org/packages/community/x86_64/sherlock.lv2/) + +### Bugs and feature requests + +* [Gitlab](https://gitlab.com/OpenMusicKontrollers/sherlock.lv2) +* [Github](https://github.com/OpenMusicKontrollers/sherlock.lv2) + +### Plugins + +#### Atom Inspector + + + +The _Atom Inspector_ is meant as a monitor/debug tool for LV2 plugin +and host authors. It captures all Atom events sent to its event input port +and presents them on its user interface for convenient nested browsing. + +#### MIDI Inspector + + + +The _MIDI Inspector_ is meant as a monitor/debug tool for LV2 plugin +and host authors. It captures all MIDI events sent to its event input port +and presents them on its user interface for convenient nested browsing. + +#### OSC Inspector + + + +The _OSC Inspector_ is meant as a monitor/debug tool for LV2 plugin +and host authors. It captures all OSC events sent to its event input port +and presents them on its user interface for convenient nested browsing. + +#### License + +Copyright (c) 2015-2020 Hanspeter Portner (dev@open-music-kontrollers.ch) + +This is free software: you can redistribute it and/or modify +it under the terms of the Artistic License 2.0 as published by +The Perl Foundation. + +This source is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +Artistic License 2.0 for more details. + +You should have received a copy of the Artistic License 2.0 +along the source as a COPYING file. If not, obtain it from +<http://www.perlfoundation.org/artistic_license_2_0>. @@ -0,0 +1 @@ +0.25.17 diff --git a/atom_inspector.c b/atom_inspector.c new file mode 100644 index 0000000..f332994 --- /dev/null +++ b/atom_inspector.c @@ -0,0 +1,341 @@ +/* + * Copyright (c) 2015-2020 Hanspeter Portner (dev@open-music-kontrollers.ch) + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the Artistic License 2.0 as published by + * The Perl Foundation. + * + * This source is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Artistic License 2.0 for more details. + * + * You should have received a copy of the Artistic License 2.0 + * along the source as a COPYING file. If not, obtain it from + * http://www.perlfoundation.org/artistic_license_2_0. + */ + +#include <stdio.h> +#include <stdlib.h> + +#include <sherlock.h> + +typedef struct _handle_t handle_t; + +struct _handle_t { + LV2_URID_Map *map; + LV2_URID_Unmap *unmap; + LV2_Log_Log *log; + LV2_Log_Logger logger; + + const LV2_Atom_Sequence *control; + craft_t through; + craft_t notify; + + LV2_URID time_position; + LV2_URID time_frame; + LV2_URID sherlock_matchAll; + + int64_t frame; + + PROPS_T(props, MAX_NPROPS); + state_t state; + state_t stash; +}; + +static LV2_Handle +instantiate(const LV2_Descriptor* descriptor, double rate __attribute__((unused)), + const char *bundle_path __attribute__((unused)), + const LV2_Feature *const *features) +{ + int i; + handle_t *handle = calloc(1, sizeof(handle_t)); + if(!handle) + return NULL; + + for(i=0; features[i]; i++) + { + if(!strcmp(features[i]->URI, LV2_URID__map)) + handle->map = features[i]->data; + else if(!strcmp(features[i]->URI, LV2_URID__unmap)) + handle->unmap = features[i]->data; + else if(!strcmp(features[i]->URI, LV2_LOG__log)) + handle->log = features[i]->data; + } + + if(!handle->map || !handle->unmap) + { + fprintf(stderr, "%s: Host does not support urid:(un)map\n", descriptor->URI); + free(handle); + return NULL; + } + + if(handle->log) + lv2_log_logger_init(&handle->logger, handle->map, handle->log); + + handle->time_position = handle->map->map(handle->map->handle, LV2_TIME__Position); + handle->time_frame = handle->map->map(handle->map->handle, LV2_TIME__frame); + handle->sherlock_matchAll = handle->map->map(handle->map->handle, SHERLOCK_URI"#matchAll"); + + lv2_atom_forge_init(&handle->through.forge, handle->map); + lv2_atom_forge_init(&handle->notify.forge, handle->map); + + if(!props_init(&handle->props, descriptor->URI, + defs, MAX_NPROPS, &handle->state, &handle->stash, + handle->map, handle)) + { + fprintf(stderr, "failed to allocate property structure\n"); + free(handle); + return NULL; + } + + return handle; +} + +static void +connect_port(LV2_Handle instance, uint32_t port, void *data) +{ + handle_t *handle = (handle_t *)instance; + + switch(port) + { + case 0: + handle->control = (const LV2_Atom_Sequence *)data; + break; + case 1: + handle->through.seq = (LV2_Atom_Sequence *)data; + break; + case 2: + handle->notify.seq = (LV2_Atom_Sequence *)data; + break; + default: + break; + } +} + +static void +run(LV2_Handle instance, uint32_t nsamples) +{ + handle_t *handle = (handle_t *)instance; + craft_t *through = &handle->through; + craft_t *notify = &handle->notify; + + uint32_t capacity = through->seq->atom.size; + lv2_atom_forge_set_buffer(&through->forge, through->buf, capacity); + through->ref = lv2_atom_forge_sequence_head(&through->forge, &through->frame[0], 0); + + capacity = notify->seq->atom.size; + lv2_atom_forge_set_buffer(¬ify->forge, notify->buf, capacity); + notify->ref = lv2_atom_forge_sequence_head(¬ify->forge, ¬ify->frame[0], 0); + + props_idle(&handle->props, ¬ify->forge, 0, ¬ify->ref); + + LV2_ATOM_SEQUENCE_FOREACH(handle->control, ev) + { + const LV2_Atom *atom = &ev->body; + const LV2_Atom_Object *obj = (const LV2_Atom_Object *)&ev->body; + const int64_t frames = ev->time.frames; + + if(handle->state.trace && handle->log) + { + if(lv2_atom_forge_is_object_type(&through->forge, atom->type)) + { + lv2_log_trace(&handle->logger, "%4"PRIi64", object, %s\n", ev->time.frames, + handle->unmap->unmap(handle->unmap->handle, obj->body.otype)); + //FIXME introspect object? + } + else if(atom->type == through->forge.Bool) + { + lv2_log_trace(&handle->logger, "%4"PRIi64", bool , %s\n", ev->time.frames, + ((const LV2_Atom_Bool *)atom)->body ? "true" : "false"); + } + else if(atom->type == through->forge.Int) + { + lv2_log_trace(&handle->logger, "%4"PRIi64", int32 , %"PRIi32"\n", ev->time.frames, + ((const LV2_Atom_Int *)atom)->body); + } + else if(atom->type == through->forge.Long) + { + lv2_log_trace(&handle->logger, "%4"PRIi64", int64 , %"PRIi64"\n", ev->time.frames, + ((const LV2_Atom_Long *)atom)->body); + } + else if(atom->type == through->forge.Float) + { + lv2_log_trace(&handle->logger, "%4"PRIi64", flt32 , %f\n", ev->time.frames, + ((const LV2_Atom_Float *)atom)->body); + } + else if(atom->type == through->forge.Double) + { + lv2_log_trace(&handle->logger, "%4"PRIi64", flt64 , %lf\n", ev->time.frames, + ((const LV2_Atom_Double *)atom)->body); + } + else if(atom->type == through->forge.String) + { + lv2_log_trace(&handle->logger, "%4"PRIi64", urid , %s\n", ev->time.frames, + handle->unmap->unmap(handle->unmap->handle, ((const LV2_Atom_URID *)atom)->body)); + } + else if(atom->type == through->forge.String) + { + lv2_log_trace(&handle->logger, "%4"PRIi64", string, %s\n", ev->time.frames, + (const char *)LV2_ATOM_BODY_CONST(atom)); + } + else if(atom->type == through->forge.URI) + { + lv2_log_trace(&handle->logger, "%4"PRIi64", uri , %s\n", ev->time.frames, + (const char *)LV2_ATOM_BODY_CONST(atom)); + } + else if(atom->type == through->forge.Path) + { + lv2_log_trace(&handle->logger, "%4"PRIi64", path , %s\n", ev->time.frames, + (const char *)LV2_ATOM_BODY_CONST(atom)); + } + //FIXME more types + else + { + lv2_log_trace(&handle->logger, "%4"PRIi64", %s\n", ev->time.frames, + handle->unmap->unmap(handle->unmap->handle, atom->type)); + } + } + + // copy all events to through port + if(through->ref) + through->ref = lv2_atom_forge_frame_time(&through->forge, frames); + if(through->ref) + through->ref = lv2_atom_forge_raw(&through->forge, &obj->atom, lv2_atom_total_size(&obj->atom)); + if(through->ref) + lv2_atom_forge_pad(&through->forge, obj->atom.size); + + if( !props_advance(&handle->props, ¬ify->forge, frames, obj, ¬ify->ref) + && lv2_atom_forge_is_object_type(¬ify->forge, obj->atom.type) + && (obj->body.otype == handle->time_position) ) + { + const LV2_Atom_Long *time_frame = NULL; + lv2_atom_object_get(obj, handle->time_frame, &time_frame, NULL); + if(time_frame) + handle->frame = time_frame->body - frames; + } + } + + if(through->ref) + lv2_atom_forge_pop(&through->forge, &through->frame[0]); + else + { + lv2_atom_sequence_clear(through->seq); + + if(handle->log) + lv2_log_trace(&handle->logger, "through buffer overflow\n"); + } + + bool has_event = notify->seq->atom.size > sizeof(LV2_Atom_Sequence_Body); + + if(notify->ref) + notify->ref = lv2_atom_forge_frame_time(¬ify->forge, nsamples-1); + if(notify->ref) + notify->ref = lv2_atom_forge_tuple(¬ify->forge, ¬ify->frame[1]); + if(notify->ref) + notify->ref = lv2_atom_forge_long(¬ify->forge, handle->frame); + if(notify->ref) + notify->ref = lv2_atom_forge_int(¬ify->forge, nsamples); + if(notify->ref) + notify->ref = lv2_atom_forge_sequence_head(¬ify->forge, ¬ify->frame[2], 0); + + // only serialize filtered events to UI + LV2_ATOM_SEQUENCE_FOREACH(handle->control, ev) + { + const LV2_Atom_Object *obj = (const LV2_Atom_Object *)&ev->body; + bool type_matches; + + if(handle->state.filter == handle->sherlock_matchAll) + { + type_matches = true; + } + else + { + type_matches = lv2_atom_forge_is_object_type(¬ify->forge, obj->atom.type) + ? (obj->body.otype == handle->state.filter) + : (obj->atom.type == handle->state.filter); + } + + if( (!handle->state.negate && type_matches) + || (handle->state.negate && !type_matches) ) + { + has_event = true; + if(notify->ref) + notify->ref = lv2_atom_forge_frame_time(¬ify->forge, ev->time.frames); + if(notify->ref) + notify->ref = lv2_atom_forge_write(¬ify->forge, &ev->body, sizeof(LV2_Atom) + ev->body.size); + } + } + + if(notify->ref) + lv2_atom_forge_pop(¬ify->forge, ¬ify->frame[2]); + if(notify->ref) + lv2_atom_forge_pop(¬ify->forge, ¬ify->frame[1]); + if(notify->ref) + lv2_atom_forge_pop(¬ify->forge, ¬ify->frame[0]); + else + { + lv2_atom_sequence_clear(notify->seq); + + if(handle->log) + lv2_log_trace(&handle->logger, "notify buffer overflow\n"); + } + + if(!has_event) // don't send anything + lv2_atom_sequence_clear(notify->seq); + + handle->frame += nsamples; +} + +static void +cleanup(LV2_Handle instance) +{ + handle_t *handle = (handle_t *)instance; + + free(handle); +} + +static LV2_State_Status +_state_save(LV2_Handle instance, LV2_State_Store_Function store, + LV2_State_Handle state, uint32_t flags, + const LV2_Feature *const *features) +{ + handle_t *handle = instance; + + return props_save(&handle->props, store, state, flags, features); +} + +static LV2_State_Status +_state_restore(LV2_Handle instance, LV2_State_Retrieve_Function retrieve, + LV2_State_Handle state, uint32_t flags, + const LV2_Feature *const *features) +{ + handle_t *handle = instance; + + return props_restore(&handle->props, retrieve, state, flags, features); +} + +static const LV2_State_Interface state_iface = { + .save = _state_save, + .restore = _state_restore +}; + +static const void* +extension_data(const char* uri) +{ + if(!strcmp(uri, LV2_STATE__interface)) + return &state_iface; + + return NULL; +} + +const LV2_Descriptor atom_inspector = { + .URI = SHERLOCK_ATOM_INSPECTOR_URI, + .instantiate = instantiate, + .connect_port = connect_port, + .activate = NULL, + .run = run, + .deactivate = NULL, + .cleanup = cleanup, + .extension_data = extension_data +}; diff --git a/atom_inspector_nk.c b/atom_inspector_nk.c new file mode 100644 index 0000000..ec628b8 --- /dev/null +++ b/atom_inspector_nk.c @@ -0,0 +1,472 @@ +/* + * Copyright (c) 2015-2020 Hanspeter Portner (dev@open-music-kontrollers.ch) + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the Artistic License 2.0 as published by + * The Perl Foundation. + * + * This source is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Artistic License 2.0 for more details. + * + * You should have received a copy of the Artistic License 2.0 + * along the source as a COPYING file. If not, obtain it from + * http://www.perlfoundation.org/artistic_license_2_0. + */ + +#include <ctype.h> +#include <inttypes.h> + +#include <sherlock.h> +#include <sherlock_nk.h> +#include <encoder.h> + +#ifdef Bool // hack for xlib +# undef Bool +#endif + +#define NS_RDF (const uint8_t*)"http://www.w3.org/1999/02/22-rdf-syntax-ns#" +#define NS_RDFS (const uint8_t*)"http://www.w3.org/2000/01/rdf-schema#" +#define NS_XSD (const uint8_t*)"http://www.w3.org/2001/XMLSchema#" +#define NS_OSC (const uint8_t*)"http://open-music-kontrollers.ch/lv2/osc#" +#define NS_XPRESS (const uint8_t*)"http://open-music-kontrollers.ch/lv2/xpress#" +#define NS_SPOD (const uint8_t*)"http://open-music-kontrollers.ch/lv2/synthpod#" +#define NS_CANVAS (const uint8_t*)"http://open-music-kontrollers.ch/lv2/canvas#" + +// copyied and adapted from libsratom +static inline char * +_sratom_to_turtle(Sratom* sratom, + LV2_URID_Unmap* unmap, + const char* base_uri, + const SerdNode* subject, + const SerdNode* predicate, + uint32_t type, + uint32_t size, + const void* body) +{ + SerdURI buri = SERD_URI_NULL; + SerdNode base = serd_node_new_uri_from_string((uint8_t *)(base_uri), NULL, &buri); + SerdEnv* env = serd_env_new(&base); + SerdChunk str = { NULL, 0 }; + + serd_env_set_prefix_from_strings(env, (const uint8_t *)"rdf", NS_RDF); + serd_env_set_prefix_from_strings(env, (const uint8_t *)"rdfs", NS_RDFS); + serd_env_set_prefix_from_strings(env, (const uint8_t *)"xsd", NS_XSD); + serd_env_set_prefix_from_strings(env, (const uint8_t *)"lv2", (const uint8_t *)LV2_CORE_PREFIX); + serd_env_set_prefix_from_strings(env, (const uint8_t *)"midi", (const uint8_t *)LV2_MIDI_PREFIX); + serd_env_set_prefix_from_strings(env, (const uint8_t *)"atom", (const uint8_t *)LV2_ATOM_PREFIX); + serd_env_set_prefix_from_strings(env, (const uint8_t *)"units", (const uint8_t *)LV2_UNITS_PREFIX); + serd_env_set_prefix_from_strings(env, (const uint8_t *)"ui", (const uint8_t *)LV2_UI_PREFIX); + serd_env_set_prefix_from_strings(env, (const uint8_t *)"time", (const uint8_t *)LV2_TIME_URI"#"); + serd_env_set_prefix_from_strings(env, (const uint8_t *)"patch", (const uint8_t *)LV2_PATCH_PREFIX); + serd_env_set_prefix_from_strings(env, (const uint8_t *)"state", (const uint8_t *)LV2_STATE_PREFIX); + + serd_env_set_prefix_from_strings(env, (const uint8_t *)"osc", NS_OSC); + serd_env_set_prefix_from_strings(env, (const uint8_t *)"xpress", NS_XPRESS); + serd_env_set_prefix_from_strings(env, (const uint8_t *)"spod", NS_SPOD); + serd_env_set_prefix_from_strings(env, (const uint8_t *)"canvas", NS_CANVAS); + + SerdWriter* writer = serd_writer_new( + SERD_TURTLE, + (SerdStyle)(SERD_STYLE_ABBREVIATED | + SERD_STYLE_RESOLVED | + SERD_STYLE_CURIED | + SERD_STYLE_ASCII), + env, &buri, serd_chunk_sink, &str); + + // Write @prefix directives + serd_env_foreach(env, + (SerdPrefixSink)serd_writer_set_prefix, + writer); + + sratom_set_sink(sratom, base_uri, + (SerdStatementSink)serd_writer_write_statement, + (SerdEndSink)serd_writer_end_anon, + writer); + sratom_write(sratom, unmap, SERD_EMPTY_S, + subject, predicate, type, size, body); + serd_writer_finish(writer); + + serd_writer_free(writer); + serd_env_free(env); + serd_node_free(&base); + return (char*)serd_chunk_sink_finish(&str); +} + +static void +_set_string(struct nk_str *str, uint32_t size, const char *body) +{ + nk_str_clear(str); + + // replace tab with 2 spaces + const char *end = body + size - 1; + const char *from = body; + for(const char *to = strchr(from, '\t'); + to && (to < end); + from = to + 1, to = strchr(from, '\t')) + { + nk_str_append_text_utf8(str, from, to-from); + nk_str_append_text_utf8(str, " ", 2); + } + nk_str_append_text_utf8(str, from, end-from); +} + +static inline void +_shadow(struct nk_context *ctx, bool *shadow) +{ + if(*shadow) + { + struct nk_style *style = &ctx->style; + const struct nk_vec2 group_padding = style->window.group_padding; + struct nk_command_buffer *canvas = nk_window_get_canvas(ctx); + + struct nk_rect b = nk_widget_bounds(ctx); + b.x -= group_padding.x; + b.w *= 10; + b.w += 5*group_padding.x; + nk_fill_rect(canvas, b, 0.f, nk_rgb(0x28, 0x28, 0x28)); + } + + *shadow = !*shadow; +} + +void +_atom_inspector_expose(struct nk_context *ctx, struct nk_rect wbounds, void *data) +{ + plughandle_t *handle = data; + + handle->dy = 20.f * _get_scale(handle); + const float widget_h = handle->dy; + struct nk_style *style = &ctx->style; + const struct nk_vec2 window_padding = style->window.padding; + const struct nk_vec2 group_padding = style->window.group_padding; + + style->selectable.normal.data.color.a = 0x0; + style->selectable.hover.data.color.a = 0x0; + + const char *window_name = "Sherlock"; + if(nk_begin(ctx, window_name, wbounds, NK_WINDOW_NO_SCROLLBAR)) + { + struct nk_panel *panel= nk_window_get_panel(ctx); + struct nk_command_buffer *canvas = nk_window_get_canvas(ctx); + + const float body_h = panel->bounds.h - 2*window_padding.y; + nk_layout_row_dynamic(ctx, body_h, 2); + if(nk_group_begin(ctx, "Left", NK_WINDOW_NO_SCROLLBAR)) + { + { + // has filter URID been updated meanwhile ? + if(handle->filter != handle->state.filter) + { + const char *uri = handle->unmap->unmap(handle->unmap->handle, handle->state.filter); + + if(uri) + { + strncpy(handle->filter_uri, uri, sizeof(handle->filter_uri) - 1); + } + else + { + handle->filter_uri[0] = '\0'; + } + + handle->filter = handle->state.filter; + } + + bool dirty = false; + + const float n = 4; + const float r0 = 1.f / n; + const float r1 = 0.1f / 3; + const float r2 = r0 - r1; + const float footer [5] = {r1+r2, r1+r2, r1+r2, r1, r2}; + nk_layout_row(ctx, NK_DYNAMIC, widget_h, 5, footer); + { + nk_label(ctx, "match:", NK_TEXT_LEFT); + + if(nk_button_label(ctx, "time")) + { + strncpy(handle->filter_uri, LV2_TIME__Position, sizeof(handle->filter_uri) - 1); + dirty = true; + } + + if(nk_button_label(ctx, "all")) + { + strncpy(handle->filter_uri, SHERLOCK_URI"#matchAll", sizeof(handle->filter_uri) - 1); + dirty = true; + } + + const int32_t state_negate = _check(ctx, handle->state.negate); + if(state_negate != handle->state.negate) + { + handle->state.negate = state_negate; + _set_bool(handle, handle->urid.negate, handle->state.negate); + } + nk_label(ctx, "negate", NK_TEXT_LEFT); + } + + nk_layout_row_dynamic(ctx, widget_h, 1); + { + const nk_flags flags = NK_EDIT_FIELD + | NK_EDIT_AUTO_SELECT + | NK_EDIT_SIG_ENTER; + //nk_edit_focus(ctx, flags); + nk_flags mode = nk_edit_string_zero_terminated(ctx, flags, handle->filter_uri, sizeof(handle->filter_uri) - 1, nk_filter_ascii); + if(mode & NK_EDIT_COMMITED) + { + if(strlen(handle->filter_uri) == 0) + { + strncpy(handle->filter_uri, SHERLOCK_URI"#matchAll", sizeof(handle->filter_uri) - 1); + } + dirty = true; + } + } + + if(dirty) + { + handle->state.filter = handle->map->map(handle->map->handle, handle->filter_uri); + _set_urid(handle, handle->urid.filter, handle->state.filter); + } + } + + const float content_h = nk_window_get_height(ctx) - 3*window_padding.y - 7*group_padding.y - 4*widget_h; + nk_layout_row_dynamic(ctx, content_h, 1); + nk_flags flags = NK_WINDOW_BORDER; + if(handle->state.follow) + { + flags |= NK_WINDOW_NO_SCROLLBAR; + } + else + { + handle->shadow = false; + } + struct nk_list_view lview; + if(nk_list_view_begin(ctx, &lview, "Events", flags, widget_h, NK_MIN(handle->n_item, MAX_LINES))) + { + if(handle->state.follow) + { + lview.end = NK_MAX(handle->n_item, 0); + lview.begin = NK_MAX(lview.end - lview.count, 0); + } + for(int l = lview.begin; (l < lview.end) && (l < handle->n_item); l++) + { + item_t *itm = handle->items[l]; + + switch(itm->type) + { + case ITEM_TYPE_NONE: + { + // skip, never reached + } break; + case ITEM_TYPE_FRAME: + { + nk_layout_row_dynamic(ctx, widget_h, 3); + { + struct nk_rect b = nk_widget_bounds(ctx); + b.x -= group_padding.x; + b.w *= 3; + b.w += 4*group_padding.x; + nk_fill_rect(canvas, b, 0.f, nk_rgb(0x18, 0x18, 0x18)); + } + + nk_labelf_colored(ctx, NK_TEXT_LEFT, orange, "@%"PRIi64, itm->frame.offset); + nk_labelf_colored(ctx, NK_TEXT_CENTERED, green, "-%"PRIu32"-", itm->frame.counter); + nk_labelf_colored(ctx, NK_TEXT_RIGHT, violet, "%"PRIi32, itm->frame.nsamples); + + handle->shadow = false; + } break; + + case ITEM_TYPE_EVENT: + { + LV2_Atom_Event *ev = &itm->event.ev; + const LV2_Atom *body = &ev->body; + const int64_t frames = ev->time.frames; + const char *uri = NULL; + if(lv2_atom_forge_is_object_type(&handle->forge, body->type)) + { + const LV2_Atom_Object *obj = (const LV2_Atom_Object *)body; + + if(obj->body.otype) + uri = handle->unmap->unmap(handle->unmap->handle, obj->body.otype); + else if(obj->body.id) + uri = handle->unmap->unmap(handle->unmap->handle, obj->body.id); + else + uri = "Unknown"; + } + else // not an object + { + uri = handle->unmap->unmap(handle->unmap->handle, body->type); + } + + const float entry [4] = {0.1, 0.65, 0.15, 0.1}; + nk_layout_row(ctx, NK_DYNAMIC, widget_h, 4, entry); + { + _shadow(ctx, &handle->shadow); + nk_labelf_colored(ctx, NK_TEXT_LEFT, yellow, "+%04"PRIi64, frames); + + if(nk_select_label(ctx, uri, NK_TEXT_LEFT, handle->selected == body)) + { + handle->ttl_dirty = handle->ttl_dirty + || (handle->selected != body); // has selection actually changed? + handle->selected = body; + } + + if(body->type == handle->forge.Bool) + { + const LV2_Atom_Bool *ref = (const LV2_Atom_Bool *)body; + nk_labelf_colored(ctx, NK_TEXT_RIGHT, violet, "%s", ref->body ? "true" : "false"); + } + else if(body->type == handle->forge.Int) + { + const LV2_Atom_Int *ref = (const LV2_Atom_Int *)body; + nk_labelf_colored(ctx, NK_TEXT_RIGHT, green, "%"PRIi32, ref->body); + } + else if(body->type == handle->forge.Long) + { + const LV2_Atom_Long *ref = (const LV2_Atom_Long *)body; + nk_labelf_colored(ctx, NK_TEXT_RIGHT, green, "%"PRIi64, ref->body); + } + else if(body->type == handle->forge.Float) + { + const LV2_Atom_Float *ref = (const LV2_Atom_Float *)body; + nk_labelf_colored(ctx, NK_TEXT_RIGHT, green, "%f", ref->body); + } + else if(body->type == handle->forge.Double) + { + const LV2_Atom_Double *ref = (const LV2_Atom_Double *)body; + nk_labelf_colored(ctx, NK_TEXT_RIGHT, green, "%lf", ref->body); + } + /* + else if(body->type == handle->forge.String) + { + nk_label_colored(ctx, LV2_ATOM_BODY_CONST(body), NK_TEXT_RIGHT, red); + } + else if(body->type == handle->forge.URI) + { + nk_label_colored(ctx, LV2_ATOM_BODY_CONST(body), NK_TEXT_RIGHT, yellow); + } + else if(body->type == handle->forge.URID) + { + const LV2_Atom_URID *urid = (const LV2_Atom_URID *)body; + const char *_uri = handle->unmap->unmap(handle->unmap->handle, urid->body); + nk_label_colored(ctx, _uri, NK_TEXT_RIGHT, yellow); + } + else if(body->type == handle->forge.Path) + { + nk_label_colored(ctx, LV2_ATOM_BODY_CONST(body), NK_TEXT_RIGHT, red); + } + else if(body->type == handle->forge.Literal) + { + nk_label_colored(ctx, LV2_ATOM_CONTENTS_CONST(LV2_Atom_Literal, body), NK_TEXT_RIGHT, red); + } + */ + else + { + nk_spacing(ctx, 1); + } + + nk_labelf_colored(ctx, NK_TEXT_RIGHT, blue, "%"PRIu32, body->size); + } + } break; + } + } + + nk_list_view_end(&lview); + } + + const float n = 4; + const float r0 = 1.f / n; + const float r1 = 0.1f / 3; + const float r2 = r0 - r1; + const float footer [8] = {r1, r2, r1, r2, r1, r2, r1, r2}; + nk_layout_row(ctx, NK_DYNAMIC, widget_h, 8, footer); + { + const int32_t state_overwrite = _check(ctx, handle->state.overwrite); + if(state_overwrite != handle->state.overwrite) + { + handle->state.overwrite = state_overwrite; + _set_bool(handle, handle->urid.overwrite, handle->state.overwrite); + } + nk_label(ctx, "overwrite", NK_TEXT_LEFT); + + const int32_t state_block = _check(ctx, handle->state.block); + if(state_block != handle->state.block) + { + handle->state.block = state_block; + _set_bool(handle, handle->urid.block, handle->state.block); + } + nk_label(ctx, "block", NK_TEXT_LEFT); + + const int32_t state_follow = _check(ctx, handle->state.follow); + if(state_follow != handle->state.follow) + { + handle->state.follow = state_follow; + _set_bool(handle, handle->urid.follow, handle->state.follow); + } + nk_label(ctx, "follow", NK_TEXT_LEFT); + + const int32_t state_pretty = _check(ctx, handle->state.pretty); + if(state_pretty != handle->state.pretty) + { + handle->state.pretty = state_pretty; + _set_bool(handle, handle->urid.pretty, handle->state.pretty); + + handle->ttl_dirty = true; + } + nk_label(ctx, "pretty", NK_TEXT_LEFT); + } + + const bool max_reached = handle->n_item >= MAX_LINES; + nk_layout_row_dynamic(ctx, widget_h, 2); + if(nk_button_symbol_label(ctx, + max_reached ? NK_SYMBOL_TRIANGLE_RIGHT: NK_SYMBOL_NONE, + "clear", NK_TEXT_LEFT)) + { + _clear(handle); + } + nk_label(ctx, "Sherlock.lv2: "SHERLOCK_VERSION, NK_TEXT_RIGHT); + + nk_group_end(ctx); + } + + if(nk_group_begin(ctx, "Right", NK_WINDOW_NO_SCROLLBAR)) + { + const LV2_Atom *atom = handle->selected; + if(handle->ttl_dirty && atom) + { + sratom_set_pretty_numbers(handle->sratom, handle->state.pretty); + + char *ttl = _sratom_to_turtle(handle->sratom, handle->unmap, + handle->base_uri, NULL, NULL, + atom->type, atom->size, LV2_ATOM_BODY_CONST(atom)); + if(ttl) + { + struct nk_str *str = &handle->editor.string; + const size_t len = strlen(ttl); + + _set_string(str, len, ttl); + + handle->editor.lexer.needs_refresh = 1; + + free(ttl); + } + + handle->ttl_dirty = false; + } + + const nk_flags flags = NK_EDIT_BOX; + int len = nk_str_len(&handle->editor.string); + + if(len > 0) //FIXME + { + const float content_h = nk_window_get_height(ctx) - 2*window_padding.y - 2*group_padding.y; + nk_layout_row_dynamic(ctx, content_h, 1); + const nk_flags mode = nk_edit_buffer(ctx, flags, &handle->editor, nk_filter_default); + (void)mode; + } + + nk_group_end(ctx); + } + } + nk_end(ctx); +} diff --git a/encoder.h b/encoder.h new file mode 100644 index 0000000..ebc999d --- /dev/null +++ b/encoder.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2015-2020 Hanspeter Portner (dev@open-music-kontrollers.ch) + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the Artistic License 2.0 as published by + * The Perl Foundation. + * + * This source is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Artistic License 2.0 for more details. + * + * You should have received a copy of the Artistic License 2.0 + * along the source as a COPYING file. If not, obtain it from + * http://www.perlfoundation.org/artistic_license_2_0. + */ + +#ifndef ENCODER_H +#define ENCODER_H + +#include "lv2/lv2plug.in/ns/extensions/ui/ui.h" + +#define NK_PUGL_API +#include "nk_pugl/nk_pugl.h" + +extern const struct nk_color cwhite; +extern const struct nk_color gray; +extern const struct nk_color yellow; +extern const struct nk_color magenta; +extern const struct nk_color green; +extern const struct nk_color blue; +extern const struct nk_color orange; +extern const struct nk_color violet; +extern const struct nk_color red; + +struct nk_token * +ttl_lex(void *data, const char *utf8, int len); + +#endif diff --git a/encoder.l b/encoder.l new file mode 100644 index 0000000..de0451f --- /dev/null +++ b/encoder.l @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2015-2020 Hanspeter Portner (dev@open-music-kontrollers.ch) + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the Artistic License 2.0 as published by + * The Perl Foundation. + * + * This source is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Artistic License 2.0 for more details. + * + * You should have received a copy of the Artistic License 2.0 + * along the source as a COPYING file. If not, obtain it from + * http://www.perlfoundation.org/artistic_license_2_0. + */ + +%{ +#include <stdio.h> +#include <string.h> + +#include <encoder.h> + +#define ful 0xff +#define one 0xbb +#define two 0x66 +#define non 0x0 +const struct nk_color cwhite = {.r = one, .g = one, .b = one, .a = ful}; +const struct nk_color gray = {.r = two, .g = two, .b = two, .a = ful}; +const struct nk_color yellow = {.r = one, .g = one, .b = non, .a = ful}; +const struct nk_color magenta = {.r = one, .g = two, .b = one, .a = ful}; +const struct nk_color green = {.r = non, .g = one, .b = non, .a = ful}; +const struct nk_color blue = {.r = non, .g = one, .b = one, .a = ful}; +const struct nk_color orange = {.r = one, .g = two, .b = non, .a = ful}; +const struct nk_color violet = {.r = two, .g = two, .b = one, .a = ful}; +const struct nk_color red = {.r = one, .g = non, .b = non, .a = ful}; + +enum { + TK_NONE, + TK_PREFIX, + TK_SUBJECT, + TK_PREDICATE, + TK_BOOL, + TK_NUMBER, + TK_URI_IN, + TK_URI_OUT, + TK_URI_ERR, + TK_STRING_IN, + TK_STRING_OUT, + TK_STRING_ERR, + TK_LONG_STRING_IN, + TK_LONG_STRING_OUT, + TK_WHITESPACE, + TK_RAW, + TK_EOL +}; + +%} + +%option reentrant noyywrap + +w [ \v\a\t]+ +name [_a-zA-Z@][_a-zA-Z0-9\.]* +n [0-9]+ +exp [Ee][+-]?{n} +number ({n}|{n}[.]{n}){exp}? +eol [\n\r] + +%x XSTRING +%x XLONG_STRING +%x XURI + +%% + +{w} return TK_WHITESPACE; +"<" BEGIN(XURI); return TK_URI_IN; +\"\"\" BEGIN(XLONG_STRING); return TK_LONG_STRING_IN; +\" BEGIN(XSTRING); return TK_STRING_IN; +{name}: return TK_SUBJECT; +"@prefix" return TK_PREFIX; +"a" return TK_PREFIX; +true return TK_BOOL; +false return TK_BOOL; +{name} return TK_PREDICATE; +{number} return TK_NUMBER; +{eol} return TK_RAW; +. return TK_RAW; + +<XURI> +{ + ">" BEGIN(0); return TK_URI_OUT; + {eol} BEGIN(0); return TK_URI_ERR; + . return TK_RAW; +} + +<XLONG_STRING> +{ + \"\"\" BEGIN(0); return TK_LONG_STRING_OUT; + {eol} return TK_EOL; + . return TK_RAW; +} + +<XSTRING> +{ + \\\" return TK_RAW; + \" BEGIN(0); return TK_STRING_OUT; + {eol} BEGIN(0); return TK_STRING_ERR; + . return TK_RAW; +} + +%% + +struct nk_token * +ttl_lex(void *data __attribute__((unused)), const char *utf8, int len) +{ + yyscan_t scanner; + YY_BUFFER_STATE buf; + + enclex_init(&scanner); + if(utf8) + { + buf = enc_scan_bytes(utf8, len, scanner); + } + else + { + enclex_destroy(scanner); + return NULL; + } + + struct nk_token *tokens = NULL; + int n_tokens = 0; + + const char *base = encget_text(scanner); + int offset0 = 0; + struct nk_color col0 = {0xff, 0xff, 0xff, 0xff}; + + for(int tok=enclex(scanner); tok; tok=enclex(scanner)) + { + const char *txt = encget_text(scanner); + const int offset1 = txt - base; + struct nk_color col1 = col0; + + switch(tok) + { + case TK_PREFIX: + col1 = blue; + break; + case TK_SUBJECT: + col1 = magenta; + break; + case TK_PREDICATE: + col1 = orange; + break; + case TK_BOOL: + col1 = violet; + break; + case TK_NUMBER: + col1 = green; + break; + case TK_URI_IN: + case TK_URI_OUT: + case TK_URI_ERR: + col1 = yellow; + break; + + case TK_STRING_IN: + case TK_STRING_OUT: + case TK_STRING_ERR: + case TK_LONG_STRING_IN: + case TK_LONG_STRING_OUT: + col1 = red; + break; + + case TK_NONE: + case TK_WHITESPACE: + col1 = cwhite; + break; + + case TK_EOL: + continue; + + case TK_RAW: + default: + // skip over + break; + } + + if(offset1) + { + tokens = realloc(tokens, (n_tokens + 1) * sizeof(struct nk_token)); + tokens[n_tokens].offset = offset1; + tokens[n_tokens++].color = col0; + } + + offset0 = offset1; + col0 = col1; + } + + tokens = realloc(tokens, (n_tokens + 1) * sizeof(struct nk_token)); + tokens[n_tokens].offset = len; + tokens[n_tokens++].color = (struct nk_color){0xff, 0xff, 0xff, 0xff}; + + enc_delete_buffer(buf, scanner); + enclex_destroy(scanner); + + // to please compiler + (void)offset0; + (void)input; + (void)yyunput; + + return tokens; +} diff --git a/generic.yml b/gitlab-ci/generic.yml index aca2fe2..aca2fe2 100644 --- a/generic.yml +++ b/gitlab-ci/generic.yml diff --git a/manifest.ttl.in b/manifest.ttl.in new file mode 100644 index 0000000..18b73f6 --- /dev/null +++ b/manifest.ttl.in @@ -0,0 +1,62 @@ +# Copyright (c) 2015-2020 Hanspeter Portner (dev@open-music-kontrollers.ch) +# +# This is free software: you can redistribute it and/or modify +# it under the terms of the Artistic License 2.0 as published by +# The Perl Foundation. +# +# This source is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# Artistic License 2.0 for more details. +# +# You should have received a copy of the Artistic License 2.0 +# along the source as a COPYING file. If not, obtain it from +# http://www.perlfoundation.org/artistic_license_2_0. + +@prefix lv2: <http://lv2plug.in/ns/lv2core#> . +@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> . +@prefix ui: <http://lv2plug.in/ns/extensions/ui#> . + +@prefix sherlock: <http://open-music-kontrollers.ch/lv2/sherlock#> . + +# Atom Inspector Plugin +sherlock:atom_inspector + a lv2:Plugin ; + lv2:minorVersion @MINOR_VERSION@ ; + lv2:microVersion @MICRO_VERSION@ ; + lv2:binary <sherlock@MODULE_SUFFIX@> ; + ui:ui sherlock:atom_inspector_4_nk ; + rdfs:seeAlso <sherlock.ttl> . + +sherlock:atom_inspector_4_nk + a ui:@UI_TYPE@ ; + ui:binary <sherlock_nk@MODULE_SUFFIX@> ; + rdfs:seeAlso <sherlock_ui.ttl> . + +# MIDI Inspector Plugin +sherlock:midi_inspector + a lv2:Plugin ; + lv2:minorVersion @MINOR_VERSION@ ; + lv2:microVersion @MICRO_VERSION@ ; + lv2:binary <sherlock@MODULE_SUFFIX@> ; + ui:ui sherlock:midi_inspector_4_nk ; + rdfs:seeAlso <sherlock.ttl> . + +sherlock:midi_inspector_4_nk + a ui:@UI_TYPE@ ; + ui:binary <sherlock_nk@MODULE_SUFFIX@> ; + rdfs:seeAlso <sherlock_ui.ttl> . + +# OSC Inspector Plugin +sherlock:osc_inspector + a lv2:Plugin ; + lv2:minorVersion @MINOR_VERSION@ ; + lv2:microVersion @MICRO_VERSION@ ; + lv2:binary <sherlock@MODULE_SUFFIX@> ; + ui:ui sherlock:osc_inspector_4_nk ; + rdfs:seeAlso <sherlock.ttl> . + +sherlock:osc_inspector_4_nk + a ui:@UI_TYPE@ ; + ui:binary <sherlock_nk@MODULE_SUFFIX@> ; + rdfs:seeAlso <sherlock_ui.ttl> . diff --git a/meson.build b/meson.build new file mode 100644 index 0000000..2c5f7df --- /dev/null +++ b/meson.build @@ -0,0 +1,139 @@ +project('sherlock.lv2', 'c', default_options : [ + 'buildtype=release', + 'warning_level=3', + 'werror=false', + 'b_lto=false', + 'c_std=gnu11']) + +nk_pugl = subproject('nk_pugl') + +lv2libdir = get_option('lv2libdir') + +inst_dir = join_paths(lv2libdir, meson.project_name()) + +nk_pugl_dep = nk_pugl.get_variable('nk_pugl_gl') +cousine_regular_ttf = nk_pugl.get_variable('cousine_regular_ttf') + +source_root = meson.source_root() +build_root = meson.build_root() + +static_link = meson.is_cross_build() + +cc = meson.get_compiler('c') + +m_dep = cc.find_library('m') +lv2_dep = dependency('lv2', version : '>=1.14.0') +sratom_dep = dependency('sratom-0', version : '>=0.6.0', static : static_link) + +dsp_deps = [m_dep, lv2_dep] +ui_deps = [m_dep, lv2_dep, sratom_dep, nk_pugl_dep] + +props_inc = include_directories('props.lv2') +osc_inc = include_directories('osc.lv2') +ser_inc = include_directories('ser_atom.lv2') +nk_pugl_inc = include_directories(join_paths('subprojects', 'nk_pugl')) +inc_dir = [props_inc, osc_inc, ser_inc, nk_pugl_inc] + +rawvers = run_command('cat', 'VERSION').stdout().strip() +version = rawvers.split('.') + +conf_data = configuration_data() +conf_data.set('MAJOR_VERSION', version[0]) +conf_data.set('MINOR_VERSION', version[1]) +conf_data.set('MICRO_VERSION', version[2]) + +add_project_arguments('-DSHERLOCK_VERSION="'+rawvers+'"', language : 'c') +add_project_arguments('-D_GNU_SOURCE', language : 'c') + +flex = find_program('flex') +lgen = generator(flex, + output : '@PLAINNAME@.c', + arguments : ['--prefix=enc', '-o', '@OUTPUT@', '@INPUT@']) + +lv2_validate = find_program('lv2_validate', native : true, required : false) +sord_validate = find_program('sord_validate', native : true, required : false) +lv2lint = find_program('lv2lint', required : false) + +lfiles = lgen.process('encoder.l') + +dsp_srcs = ['sherlock.c', + 'atom_inspector.c', + 'midi_inspector.c', + 'osc_inspector.c'] + +ui_srcs = ['sherlock_nk.c', + 'atom_inspector_nk.c', + 'midi_inspector_nk.c', + 'osc_inspector_nk.c', + lfiles] + +c_args = [ + '-fvisibility=hidden'] + +if host_machine.system() == 'windows' + conf_data.set('UI_TYPE', 'WindowsUI') +elif host_machine.system() == 'darwin' + conf_data.set('UI_TYPE', 'CocoaUI') +else + conf_data.set('UI_TYPE', 'X11UI') +endif + +mod = shared_module('sherlock', dsp_srcs, + c_args : c_args, + include_directories : inc_dir, + name_prefix : '', + dependencies : dsp_deps, + install : true, + install_dir : inst_dir) + +ui = shared_module('sherlock_nk', ui_srcs, + c_args : c_args, + include_directories : inc_dir, + name_prefix : '', + dependencies : ui_deps, + install : true, + install_dir : inst_dir) + +suffix = mod.full_path().strip().split('.')[-1] +conf_data.set('MODULE_SUFFIX', '.' + suffix) + +manifest_ttl = configure_file( + input : 'manifest.ttl.in', + output : 'manifest.ttl', + configuration : conf_data, + install : true, + install_dir : inst_dir) + +dsp_ttl = configure_file( + input : 'sherlock.ttl', + output : 'sherlock.ttl', + copy : true, + install : true, + install_dir : inst_dir) + +ui_ttl = configure_file( + input : 'sherlock_ui.ttl', + output : 'sherlock_ui.ttl', + copy : true, + install : true, + install_dir : inst_dir) + +configure_file( + input : cousine_regular_ttf, + output : 'Cousine-Regular.ttf', + copy : true, + install : true, + install_dir : inst_dir) + +if lv2_validate.found() and sord_validate.found() + test('LV2 validate', lv2_validate, + args : [manifest_ttl, dsp_ttl, ui_ttl]) +endif + +if lv2lint.found() + test('LV2 lint', lv2lint, + args : ['-Ewarn', '-I', join_paths(build_root, ''), + 'http://open-music-kontrollers.ch/lv2/sherlock#atom_inspector', + 'http://open-music-kontrollers.ch/lv2/sherlock#midi_inspector', + 'http://open-music-kontrollers.ch/lv2/sherlock#osc_inspector']) +endif diff --git a/meson_options.txt b/meson_options.txt new file mode 100644 index 0000000..8a007bd --- /dev/null +++ b/meson_options.txt @@ -0,0 +1,3 @@ +option('lv2libdir', + type : 'string', + value : 'lib/lv2') diff --git a/midi_inspector.c b/midi_inspector.c new file mode 100644 index 0000000..fc2fd75 --- /dev/null +++ b/midi_inspector.c @@ -0,0 +1,266 @@ +/* + * Copyright (c) 2015-2020 Hanspeter Portner (dev@open-music-kontrollers.ch) + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the Artistic License 2.0 as published by + * The Perl Foundation. + * + * This source is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Artistic License 2.0 for more details. + * + * You should have received a copy of the Artistic License 2.0 + * along the source as a COPYING file. If not, obtain it from + * http://www.perlfoundation.org/artistic_license_2_0. + */ + +#include <stdio.h> +#include <stdlib.h> + +#include <sherlock.h> + +#include "lv2/lv2plug.in/ns/ext/midi/midi.h" + +typedef struct _handle_t handle_t; + +struct _handle_t { + LV2_URID_Map *map; + LV2_URID_Unmap *unmap; + LV2_Log_Log *log; + LV2_Log_Logger logger; + + const LV2_Atom_Sequence *control; + craft_t through; + craft_t notify; + + LV2_URID time_position; + LV2_URID time_frame; + LV2_URID midi_event; + + int64_t frame; + + PROPS_T(props, MAX_NPROPS); + state_t state; + state_t stash; +}; + +static LV2_Handle +instantiate(const LV2_Descriptor* descriptor, double rate __attribute__((unused)), + const char *bundle_path __attribute__((unused)), + const LV2_Feature *const *features) +{ + int i; + handle_t *handle = calloc(1, sizeof(handle_t)); + if(!handle) + return NULL; + + for(i=0; features[i]; i++) + { + if(!strcmp(features[i]->URI, LV2_URID__map)) + handle->map = features[i]->data; + else if(!strcmp(features[i]->URI, LV2_URID__unmap)) + handle->unmap = features[i]->data; + else if(!strcmp(features[i]->URI, LV2_LOG__log)) + handle->log = features[i]->data; + } + + if(!handle->map || !handle->unmap) + { + fprintf(stderr, "%s: Host does not support urid:(un)map\n", descriptor->URI); + free(handle); + return NULL; + } + + if(handle->log) + lv2_log_logger_init(&handle->logger, handle->map, handle->log); + + handle->time_position = handle->map->map(handle->map->handle, LV2_TIME__Position); + handle->time_frame = handle->map->map(handle->map->handle, LV2_TIME__frame); + handle->midi_event = handle->map->map(handle->map->handle, LV2_MIDI__MidiEvent); + + lv2_atom_forge_init(&handle->through.forge, handle->map); + lv2_atom_forge_init(&handle->notify.forge, handle->map); + + if(!props_init(&handle->props, descriptor->URI, + defs, MAX_NPROPS, &handle->state, &handle->stash, + handle->map, handle)) + { + fprintf(stderr, "failed to allocate property structure\n"); + free(handle); + return NULL; + } + + return handle; +} + +static void +connect_port(LV2_Handle instance, uint32_t port, void *data) +{ + handle_t *handle = (handle_t *)instance; + + switch(port) + { + case 0: + handle->control = (const LV2_Atom_Sequence *)data; + break; + case 1: + handle->through.seq = (LV2_Atom_Sequence *)data; + break; + case 2: + handle->notify.seq = (LV2_Atom_Sequence *)data; + break; + default: + break; + } +} + +static void +run(LV2_Handle instance, uint32_t nsamples) +{ + handle_t *handle = (handle_t *)instance; + craft_t *through = &handle->through; + craft_t *notify = &handle->notify; + + uint32_t capacity = through->seq->atom.size; + lv2_atom_forge_set_buffer(&through->forge, through->buf, capacity); + through->ref = lv2_atom_forge_sequence_head(&through->forge, &through->frame[0], 0); + + capacity = notify->seq->atom.size; + lv2_atom_forge_set_buffer(¬ify->forge, notify->buf, capacity); + notify->ref = lv2_atom_forge_sequence_head(¬ify->forge, ¬ify->frame[0], 0); + + props_idle(&handle->props, ¬ify->forge, 0, ¬ify->ref); + + LV2_ATOM_SEQUENCE_FOREACH(handle->control, ev) + { + const LV2_Atom_Object *obj = (const LV2_Atom_Object *)&ev->body; + const int64_t frames = ev->time.frames; + + // copy all events to through port + if(through->ref) + through->ref = lv2_atom_forge_frame_time(&through->forge, frames); + if(through->ref) + through->ref = lv2_atom_forge_raw(&through->forge, &obj->atom, lv2_atom_total_size(&obj->atom)); + if(through->ref) + lv2_atom_forge_pad(&through->forge, obj->atom.size); + + if( !props_advance(&handle->props, ¬ify->forge, frames, obj, ¬ify->ref) + && lv2_atom_forge_is_object_type(¬ify->forge, obj->atom.type) + && (obj->body.otype == handle->time_position) ) + { + const LV2_Atom_Long *time_frame = NULL; + lv2_atom_object_get(obj, handle->time_frame, &time_frame, NULL); + if(time_frame) + handle->frame = time_frame->body - frames; + } + } + + if(through->ref) + lv2_atom_forge_pop(&through->forge, &through->frame[0]); + else + { + lv2_atom_sequence_clear(through->seq); + + if(handle->log) + lv2_log_trace(&handle->logger, "through buffer overflow\n"); + } + + bool has_event = notify->seq->atom.size > sizeof(LV2_Atom_Sequence_Body); + + if(notify->ref) + notify->ref = lv2_atom_forge_frame_time(¬ify->forge, nsamples-1); + if(notify->ref) + notify->ref = lv2_atom_forge_tuple(¬ify->forge, ¬ify->frame[1]); + if(notify->ref) + notify->ref = lv2_atom_forge_long(¬ify->forge, handle->frame); + if(notify->ref) + notify->ref = lv2_atom_forge_int(¬ify->forge, nsamples); + if(notify->ref) + notify->ref = lv2_atom_forge_sequence_head(¬ify->forge, ¬ify->frame[2], 0); + + // only serialize MIDI events to UI + LV2_ATOM_SEQUENCE_FOREACH(handle->control, ev) + { + if(ev->body.type == handle->midi_event) + { + has_event = true; + if(notify->ref) + notify->ref = lv2_atom_forge_frame_time(¬ify->forge, ev->time.frames); + if(notify->ref) + notify->ref = lv2_atom_forge_write(¬ify->forge, &ev->body, sizeof(LV2_Atom) + ev->body.size); + } + } + + if(notify->ref) + lv2_atom_forge_pop(¬ify->forge, ¬ify->frame[2]); + if(notify->ref) + lv2_atom_forge_pop(¬ify->forge, ¬ify->frame[1]); + if(notify->ref) + lv2_atom_forge_pop(¬ify->forge, ¬ify->frame[0]); + else + { + lv2_atom_sequence_clear(notify->seq); + + if(handle->log) + lv2_log_trace(&handle->logger, "notify buffer overflow\n"); + } + + if(!has_event) // don't send anything + lv2_atom_sequence_clear(notify->seq); + + handle->frame += nsamples; +} + +static void +cleanup(LV2_Handle instance) +{ + handle_t *handle = (handle_t *)instance; + + free(handle); +} + +static LV2_State_Status +_state_save(LV2_Handle instance, LV2_State_Store_Function store, + LV2_State_Handle state, uint32_t flags, + const LV2_Feature *const *features) +{ + handle_t *handle = instance; + + return props_save(&handle->props, store, state, flags, features); +} + +static LV2_State_Status +_state_restore(LV2_Handle instance, LV2_State_Retrieve_Function retrieve, + LV2_State_Handle state, uint32_t flags, + const LV2_Feature *const *features) +{ + handle_t *handle = instance; + + return props_restore(&handle->props, retrieve, state, flags, features); +} + +static const LV2_State_Interface state_iface = { + .save = _state_save, + .restore = _state_restore +}; + +static const void* +extension_data(const char* uri) +{ + if(!strcmp(uri, LV2_STATE__interface)) + return &state_iface; + + return NULL; +} + +const LV2_Descriptor midi_inspector = { + .URI = SHERLOCK_MIDI_INSPECTOR_URI, + .instantiate = instantiate, + .connect_port = connect_port, + .activate = NULL, + .run = run, + .deactivate = NULL, + .cleanup = cleanup, + .extension_data = extension_data +}; diff --git a/midi_inspector_nk.c b/midi_inspector_nk.c new file mode 100644 index 0000000..8877437 --- /dev/null +++ b/midi_inspector_nk.c @@ -0,0 +1,538 @@ +/* + * Copyright (c) 2015-2020 Hanspeter Portner (dev@open-music-kontrollers.ch) + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the Artistic License 2.0 as published by + * The Perl Foundation. + * + * This source is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Artistic License 2.0 for more details. + * + * You should have received a copy of the Artistic License 2.0 + * along the source as a COPYING file. If not, obtain it from + * http://www.perlfoundation.org/artistic_license_2_0. + */ + +#include <inttypes.h> + +#include <sherlock.h> +#include <sherlock_nk.h> +#include <encoder.h> + +typedef struct _midi_msg_t midi_msg_t; + +struct _midi_msg_t { + uint8_t type; + const char *key; +}; + +#define COMMANDS_NUM 18 +static const midi_msg_t commands [COMMANDS_NUM] = { + { LV2_MIDI_MSG_NOTE_OFF , "NoteOff" }, + { LV2_MIDI_MSG_NOTE_ON , "NoteOn" }, + { LV2_MIDI_MSG_NOTE_PRESSURE , "NotePressure" }, + { LV2_MIDI_MSG_CONTROLLER , "Controller" }, + { LV2_MIDI_MSG_PGM_CHANGE , "ProgramChange" }, + { LV2_MIDI_MSG_CHANNEL_PRESSURE , "ChannelPressure" }, + { LV2_MIDI_MSG_BENDER , "Bender" }, + { LV2_MIDI_MSG_SYSTEM_EXCLUSIVE , "SystemExclusive" }, + { LV2_MIDI_MSG_MTC_QUARTER , "QuarterFrame" }, + { LV2_MIDI_MSG_SONG_POS , "SongPosition" }, + { LV2_MIDI_MSG_SONG_SELECT , "SongSelect" }, + { LV2_MIDI_MSG_TUNE_REQUEST , "TuneRequest" }, + { LV2_MIDI_MSG_CLOCK , "Clock" }, + { LV2_MIDI_MSG_START , "Start" }, + { LV2_MIDI_MSG_CONTINUE , "Continue" }, + { LV2_MIDI_MSG_STOP , "Stop" }, + { LV2_MIDI_MSG_ACTIVE_SENSE , "ActiveSense" }, + { LV2_MIDI_MSG_RESET , "Reset" }, +}; + +#define CONTROLLERS_NUM 72 +static const midi_msg_t controllers [CONTROLLERS_NUM] = { + { LV2_MIDI_CTL_MSB_BANK , "BankSelection_MSB" }, + { LV2_MIDI_CTL_MSB_MODWHEEL , "Modulation_MSB" }, + { LV2_MIDI_CTL_MSB_BREATH , "Breath_MSB" }, + { LV2_MIDI_CTL_MSB_FOOT , "Foot_MSB" }, + { LV2_MIDI_CTL_MSB_PORTAMENTO_TIME , "PortamentoTime_MSB" }, + { LV2_MIDI_CTL_MSB_DATA_ENTRY , "DataEntry_MSB" }, + { LV2_MIDI_CTL_MSB_MAIN_VOLUME , "MainVolume_MSB" }, + { LV2_MIDI_CTL_MSB_BALANCE , "Balance_MSB" }, + { LV2_MIDI_CTL_MSB_PAN , "Panpot_MSB" }, + { LV2_MIDI_CTL_MSB_EXPRESSION , "Expression_MSB" }, + { LV2_MIDI_CTL_MSB_EFFECT1 , "Effect1_MSB" }, + { LV2_MIDI_CTL_MSB_EFFECT2 , "Effect2_MSB" }, + { LV2_MIDI_CTL_MSB_GENERAL_PURPOSE1 , "GeneralPurpose1_MSB" }, + { LV2_MIDI_CTL_MSB_GENERAL_PURPOSE2 , "GeneralPurpose2_MSB" }, + { LV2_MIDI_CTL_MSB_GENERAL_PURPOSE3 , "GeneralPurpose3_MSB" }, + { LV2_MIDI_CTL_MSB_GENERAL_PURPOSE4 , "GeneralPurpose4_MSB" }, + + { LV2_MIDI_CTL_LSB_BANK , "BankSelection_LSB" }, + { LV2_MIDI_CTL_LSB_MODWHEEL , "Modulation_LSB" }, + { LV2_MIDI_CTL_LSB_BREATH , "Breath_LSB" }, + { LV2_MIDI_CTL_LSB_FOOT , "Foot_LSB" }, + { LV2_MIDI_CTL_LSB_PORTAMENTO_TIME , "PortamentoTime_LSB" }, + { LV2_MIDI_CTL_LSB_DATA_ENTRY , "DataEntry_LSB" }, + { LV2_MIDI_CTL_LSB_MAIN_VOLUME , "MainVolume_LSB" }, + { LV2_MIDI_CTL_LSB_BALANCE , "Balance_LSB" }, + { LV2_MIDI_CTL_LSB_PAN , "Panpot_LSB" }, + { LV2_MIDI_CTL_LSB_EXPRESSION , "Expression_LSB" }, + { LV2_MIDI_CTL_LSB_EFFECT1 , "Effect1_LSB" }, + { LV2_MIDI_CTL_LSB_EFFECT2 , "Effect2_LSB" }, + { LV2_MIDI_CTL_LSB_GENERAL_PURPOSE1 , "GeneralPurpose1_LSB" }, + { LV2_MIDI_CTL_LSB_GENERAL_PURPOSE2 , "GeneralPurpose2_LSB" }, + { LV2_MIDI_CTL_LSB_GENERAL_PURPOSE3 , "GeneralPurpose3_LSB" }, + { LV2_MIDI_CTL_LSB_GENERAL_PURPOSE4 , "GeneralPurpose4_LSB" }, + + { LV2_MIDI_CTL_SUSTAIN , "SustainPedal" }, + { LV2_MIDI_CTL_PORTAMENTO , "Portamento" }, + { LV2_MIDI_CTL_SOSTENUTO , "Sostenuto" }, + { LV2_MIDI_CTL_SOFT_PEDAL , "SoftPedal" }, + { LV2_MIDI_CTL_LEGATO_FOOTSWITCH , "LegatoFootSwitch" }, + { LV2_MIDI_CTL_HOLD2 , "Hold2" }, + + { LV2_MIDI_CTL_SC1_SOUND_VARIATION , "SC1_SoundVariation" }, + { LV2_MIDI_CTL_SC2_TIMBRE , "SC2_Timbre" }, + { LV2_MIDI_CTL_SC3_RELEASE_TIME , "SC3_ReleaseTime" }, + { LV2_MIDI_CTL_SC4_ATTACK_TIME , "SC4_AttackTime" }, + { LV2_MIDI_CTL_SC5_BRIGHTNESS , "SC5_Brightness" }, + { LV2_MIDI_CTL_SC6 , "SC6" }, + { LV2_MIDI_CTL_SC7 , "SC7" }, + { LV2_MIDI_CTL_SC8 , "SC8" }, + { LV2_MIDI_CTL_SC9 , "SC9" }, + { LV2_MIDI_CTL_SC10 , "SC10" }, + + { LV2_MIDI_CTL_GENERAL_PURPOSE5 , "GeneralPurpose5" }, + { LV2_MIDI_CTL_GENERAL_PURPOSE6 , "GeneralPurpose6" }, + { LV2_MIDI_CTL_GENERAL_PURPOSE7 , "GeneralPurpose7" }, + { LV2_MIDI_CTL_GENERAL_PURPOSE8 , "GeneralPurpose8" }, + { LV2_MIDI_CTL_PORTAMENTO_CONTROL , "PortamentoControl" }, + + { LV2_MIDI_CTL_E1_REVERB_DEPTH , "E1_ReverbDepth" }, + { LV2_MIDI_CTL_E2_TREMOLO_DEPTH , "E2_TremoloDepth" }, + { LV2_MIDI_CTL_E3_CHORUS_DEPTH , "E3_ChorusDepth" }, + { LV2_MIDI_CTL_E4_DETUNE_DEPTH , "E4_DetuneDepth" }, + { LV2_MIDI_CTL_E5_PHASER_DEPTH , "E5_PhaserDepth" }, + + { LV2_MIDI_CTL_DATA_INCREMENT , "DataIncrement" }, + { LV2_MIDI_CTL_DATA_DECREMENT , "DataDecrement" }, + + { LV2_MIDI_CTL_NRPN_LSB , "NRPN_LSB" }, + { LV2_MIDI_CTL_NRPN_MSB , "NRPN_MSB" }, + + { LV2_MIDI_CTL_RPN_LSB , "RPN_LSB" }, + { LV2_MIDI_CTL_RPN_MSB , "RPN_MSB" }, + + { LV2_MIDI_CTL_ALL_SOUNDS_OFF , "AllSoundsOff" }, + { LV2_MIDI_CTL_RESET_CONTROLLERS , "ResetControllers" }, + { LV2_MIDI_CTL_LOCAL_CONTROL_SWITCH , "LocalControlSwitch" }, + { LV2_MIDI_CTL_ALL_NOTES_OFF , "AllNotesOff" }, + { LV2_MIDI_CTL_OMNI_OFF , "OmniOff" }, + { LV2_MIDI_CTL_OMNI_ON , "OmniOn" }, + { LV2_MIDI_CTL_MONO1 , "Mono1" }, + { LV2_MIDI_CTL_MONO2 , "Mono2" }, +}; + +#define TIMECODES_NUM 8 +static const midi_msg_t timecodes [TIMECODES_NUM] = { + { 0 , "FrameNumber_LSB" }, + { 1 , "FrameNumber_MSB" }, + { 2 , "Second_LSB" }, + { 3 , "Second_MSB" }, + { 4 , "Minute_LSB" }, + { 5 , "Minute_MSB" }, + { 6 , "Hour_LSB" }, + { 7 , "RateAndHour_MSB" }, +}; + +static int +_cmp_search(const void *itm1, const void *itm2) +{ + const midi_msg_t *msg1 = itm1; + const midi_msg_t *msg2 = itm2; + + if(msg1->type < msg2->type) + return -1; + else if(msg1->type > msg2->type) + return 1; + + return 0; +} + +static inline const midi_msg_t * +_search_command(uint8_t type) +{ + return bsearch(&type, commands, COMMANDS_NUM, sizeof(midi_msg_t), _cmp_search); +} + +static inline const midi_msg_t * +_search_controller(uint8_t type) +{ + return bsearch(&type, controllers, CONTROLLERS_NUM, sizeof(midi_msg_t), _cmp_search); +} + +static inline const midi_msg_t * +_search_timecode(uint8_t type) +{ + return bsearch(&type, timecodes, TIMECODES_NUM, sizeof(midi_msg_t), _cmp_search); +} + +static const char *keys [12] = { + "C", "C#", + "D", "D#", + "E", + "F", "F#", + "G", "G#", + "A", "A#", + "B" +}; + +static inline const char * +_note(uint8_t val, int8_t *octave) +{ + *octave = val / 12 - 1; + + return keys[val % 12]; +} + +static inline void +_shadow(struct nk_context *ctx, bool *shadow) +{ + if(*shadow) + { + struct nk_style *style = &ctx->style; + const struct nk_vec2 group_padding = style->window.group_padding; + struct nk_command_buffer *canvas = nk_window_get_canvas(ctx); + + struct nk_rect b = nk_widget_bounds(ctx); + b.x -= group_padding.x; + b.w *= 10; + b.w += 5*group_padding.x; + nk_fill_rect(canvas, b, 0.f, nk_rgb(0x28, 0x28, 0x28)); + } + + *shadow = !*shadow; +} + +void +_midi_inspector_expose(struct nk_context *ctx, struct nk_rect wbounds, void *data) +{ + plughandle_t *handle = data; + + handle->dy = 20.f * _get_scale(handle); + const float widget_h = handle->dy; + struct nk_style *style = &ctx->style; + const struct nk_vec2 window_padding = style->window.padding; + const struct nk_vec2 group_padding = style->window.group_padding; + + const char *window_name = "Sherlock"; + if(nk_begin(ctx, window_name, wbounds, NK_WINDOW_NO_SCROLLBAR)) + { + struct nk_panel *panel = nk_window_get_panel(ctx); + struct nk_command_buffer *canvas = nk_window_get_canvas(ctx); + + const float body_h = panel->bounds.h - 4*window_padding.y - 2*widget_h; + nk_layout_row_dynamic(ctx, body_h, 1); + nk_flags flags = NK_WINDOW_BORDER; + if(handle->state.follow) + { + flags |= NK_WINDOW_NO_SCROLLBAR; + } + else + { + handle->shadow = false; + } + struct nk_list_view lview; + if(nk_list_view_begin(ctx, &lview, "Events", flags, widget_h, NK_MIN(handle->n_item, MAX_LINES))) + { + if(handle->state.follow) + { + lview.end = NK_MAX(handle->n_item, 0); + lview.begin = NK_MAX(lview.end - lview.count, 0); + } + for(int l = lview.begin; (l < lview.end) && (l < handle->n_item); l++) + { + item_t *itm = handle->items[l]; + + switch(itm->type) + { + case ITEM_TYPE_NONE: + { + // skip, was sysex payload + } break; + case ITEM_TYPE_FRAME: + { + nk_layout_row_dynamic(ctx, widget_h, 3); + { + struct nk_rect b = nk_widget_bounds(ctx); + b.x -= group_padding.x; + b.w *= 3; + b.w += 4*group_padding.x; + nk_fill_rect(canvas, b, 0.f, nk_rgb(0x18, 0x18, 0x18)); + } + + nk_labelf_colored(ctx, NK_TEXT_LEFT, orange, "@%"PRIi64, itm->frame.offset); + nk_labelf_colored(ctx, NK_TEXT_CENTERED, green, "-%"PRIu32"-", itm->frame.counter); + nk_labelf_colored(ctx, NK_TEXT_RIGHT, violet, "%"PRIi32, itm->frame.nsamples); + + handle->shadow = false; + } break; + + case ITEM_TYPE_EVENT: + { + LV2_Atom_Event *ev = &itm->event.ev; + const LV2_Atom *body = &ev->body; + const int64_t frames = ev->time.frames; + const uint8_t *msg = LV2_ATOM_BODY_CONST(body); + const uint8_t cmd = (msg[0] & 0xf0) == 0xf0 + ? msg[0] + : msg[0] & 0xf0; + + const midi_msg_t *command_msg = _search_command(cmd); + const char *command_str = command_msg + ? command_msg->key + : "Unknown"; + + char tmp [16]; + nk_layout_row_begin(ctx, NK_DYNAMIC, widget_h, 7); + { + nk_layout_row_push(ctx, 0.1); + _shadow(ctx, &handle->shadow); + nk_labelf_colored(ctx, NK_TEXT_LEFT, yellow, "+%04"PRIi64, frames); + + nk_layout_row_push(ctx, 0.2); + const unsigned rem = body->size; + const unsigned to = rem >= 4 ? 4 : rem % 4; + for(unsigned i=0, ptr=0; i<to; i++, ptr+=3) + sprintf(&tmp[ptr], "%02"PRIX8" ", msg[i]); + tmp[to*3 - 1] = '\0'; + nk_label_colored(ctx, tmp, NK_TEXT_LEFT, cwhite); + + nk_layout_row_push(ctx, 0.2); + nk_label_colored(ctx, command_str, NK_TEXT_LEFT, magenta); + + switch(cmd) + { + case LV2_MIDI_MSG_NOTE_OFF: + // fall-through + case LV2_MIDI_MSG_NOTE_ON: + // fall-through + case LV2_MIDI_MSG_NOTE_PRESSURE: + { + nk_layout_row_push(ctx, 0.1); + nk_labelf_colored(ctx, NK_TEXT_RIGHT, cwhite, "Ch:%2"PRIu8, + (msg[0] & 0x0f) + 1); + + nk_layout_row_push(ctx, 0.2); + int8_t octave; + const char *key = _note(msg[1], &octave); + nk_labelf_colored(ctx, NK_TEXT_RIGHT, cwhite, "%s%+"PRIi8"=%3"PRIu8, + key, octave, msg[1]); + + nk_layout_row_push(ctx, 0.1); + nk_labelf_colored(ctx, NK_TEXT_RIGHT, cwhite, "%"PRIu8, msg[2]); + } break; + case LV2_MIDI_MSG_CONTROLLER: + { + nk_layout_row_push(ctx, 0.1); + nk_labelf_colored(ctx, NK_TEXT_RIGHT, cwhite, "Ch:%2"PRIu8, + (msg[0] & 0x0f) + 1); + + const midi_msg_t *controller_msg = _search_controller(msg[1]); + const char *controller_str = controller_msg + ? controller_msg->key + : "Unknown"; + nk_layout_row_push(ctx, 0.2); + nk_labelf_colored(ctx, NK_TEXT_RIGHT, cwhite, "%s=%3"PRIu8"", + controller_str, msg[1]); + + nk_layout_row_push(ctx, 0.1); + nk_labelf_colored(ctx, NK_TEXT_RIGHT, cwhite, "%"PRIu8, msg[2]); + } break; + case LV2_MIDI_MSG_PGM_CHANGE: + // fall-through + case LV2_MIDI_MSG_CHANNEL_PRESSURE: + { + nk_layout_row_push(ctx, 0.1); + nk_labelf_colored(ctx, NK_TEXT_RIGHT, cwhite, "Ch:%2"PRIu8, + (msg[0] & 0x0f) + 1); + + nk_layout_row_push(ctx, 0.2); + nk_labelf_colored(ctx, NK_TEXT_RIGHT, cwhite, "%"PRIu8, msg[1]); + + nk_layout_row_push(ctx, 0.1); + _empty(ctx); + } break; + case LV2_MIDI_MSG_BENDER: + { + const int16_t bender = (((int16_t)msg[2] << 7) | msg[1]) - 0x2000; + + nk_layout_row_push(ctx, 0.1); + nk_labelf_colored(ctx, NK_TEXT_RIGHT, cwhite, "Ch:%2"PRIu8, + (msg[0] & 0x0f) + 1); + + nk_layout_row_push(ctx, 0.2); + nk_labelf_colored(ctx, NK_TEXT_RIGHT, cwhite, "%"PRIi16, bender); + + nk_layout_row_push(ctx, 0.1); + _empty(ctx); + } break; + case LV2_MIDI_MSG_MTC_QUARTER: + { + const uint8_t msg_type = msg[1] >> 4; + const uint8_t msg_val = msg[1] & 0xf; + + nk_layout_row_push(ctx, 0.1); + _empty(ctx); + + const midi_msg_t *timecode_msg = _search_timecode(msg_type); + const char *timecode_str = timecode_msg + ? timecode_msg->key + : "Unknown"; + nk_layout_row_push(ctx, 0.2); + nk_label_colored(ctx, timecode_str, NK_TEXT_RIGHT, cwhite); + + nk_layout_row_push(ctx, 0.1); + nk_labelf_colored(ctx, NK_TEXT_RIGHT, cwhite, "%"PRIu8, msg_val); + } break; + case LV2_MIDI_MSG_SONG_POS: + { + const int16_t song_pos= (((int16_t)msg[2] << 7) | msg[1]); + + nk_layout_row_push(ctx, 0.1); + _empty(ctx); + + nk_layout_row_push(ctx, 0.2); + nk_labelf_colored(ctx, NK_TEXT_RIGHT, cwhite, "%"PRIu16, song_pos); + + nk_layout_row_push(ctx, 0.1); + _empty(ctx); + } break; + case LV2_MIDI_MSG_SONG_SELECT: + { + nk_layout_row_push(ctx, 0.1); + _empty(ctx); + + nk_layout_row_push(ctx, 0.2); + nk_labelf_colored(ctx, NK_TEXT_RIGHT, cwhite, "%"PRIu8, msg[1]); + + nk_layout_row_push(ctx, 0.1); + _empty(ctx); + } break; + case LV2_MIDI_MSG_SYSTEM_EXCLUSIVE: + // fall-throuh + case LV2_MIDI_MSG_TUNE_REQUEST: + // fall-throuh + case LV2_MIDI_MSG_CLOCK: + // fall-throuh + case LV2_MIDI_MSG_START: + // fall-throuh + case LV2_MIDI_MSG_CONTINUE: + // fall-throuh + case LV2_MIDI_MSG_STOP: + // fall-throuh + case LV2_MIDI_MSG_ACTIVE_SENSE: + // fall-throuh + case LV2_MIDI_MSG_RESET: + { + nk_layout_row_push(ctx, 0.1); + _empty(ctx); + + nk_layout_row_push(ctx, 0.2); + _empty(ctx); + + nk_layout_row_push(ctx, 0.1); + _empty(ctx); + } break; + } + + nk_layout_row_push(ctx, 0.1); + nk_labelf_colored(ctx, NK_TEXT_RIGHT, blue, "%"PRIu32, body->size); + } + nk_layout_row_end(ctx); + + for(unsigned j=4; j<body->size; j+=4) + { + nk_layout_row_begin(ctx, NK_DYNAMIC, widget_h, 7); + { + nk_layout_row_push(ctx, 0.1); + _shadow(ctx, &handle->shadow); + _empty(ctx); + + nk_layout_row_push(ctx, 0.2); + const unsigned rem = body->size - j; + const unsigned to = rem >= 4 ? 4 : rem % 4; + for(unsigned i=0, ptr=0; i<to; i++, ptr+=3) + sprintf(&tmp[ptr], "%02"PRIX8" ", msg[j+i]); + tmp[to*3 - 1] = '\0'; + nk_label_colored(ctx, tmp, NK_TEXT_LEFT, cwhite); + + nk_layout_row_push(ctx, 0.2); + _empty(ctx); + + nk_layout_row_push(ctx, 0.1); + _empty(ctx); + + nk_layout_row_push(ctx, 0.2); + _empty(ctx); + + nk_layout_row_push(ctx, 0.1); + _empty(ctx); + + nk_layout_row_push(ctx, 0.1); + _empty(ctx); + } + } + } break; + } + } + + nk_list_view_end(&lview); + } + + const float n = 3; + const float r0 = 1.f / n; + const float r1 = 0.1f / 3; + const float r2 = r0 - r1; + const float footer [6] = {r1, r2, r1, r2, r1, r2}; + nk_layout_row(ctx, NK_DYNAMIC, widget_h, 6, footer); + { + const int32_t state_overwrite = _check(ctx, handle->state.overwrite); + if(state_overwrite != handle->state.overwrite) + { + handle->state.overwrite = state_overwrite; + _set_bool(handle, handle->urid.overwrite, handle->state.overwrite); + } + nk_label(ctx, "overwrite", NK_TEXT_LEFT); + + const int32_t state_block = _check(ctx, handle->state.block); + if(state_block != handle->state.block) + { + handle->state.block = state_block; + _set_bool(handle, handle->urid.block, handle->state.block); + } + nk_label(ctx, "block", NK_TEXT_LEFT); + + const int32_t state_follow = _check(ctx, handle->state.follow); + if(state_follow != handle->state.follow) + { + handle->state.follow = state_follow; + _set_bool(handle, handle->urid.follow, handle->state.follow); + } + nk_label(ctx, "follow", NK_TEXT_LEFT); + } + + const bool max_reached = handle->n_item >= MAX_LINES; + nk_layout_row_dynamic(ctx, widget_h, 2); + if(nk_button_symbol_label(ctx, + max_reached ? NK_SYMBOL_TRIANGLE_RIGHT: NK_SYMBOL_NONE, + "clear", NK_TEXT_LEFT)) + { + _clear(handle); + } + nk_label(ctx, "Sherlock.lv2: "SHERLOCK_VERSION, NK_TEXT_RIGHT); + } + nk_end(ctx); +} diff --git a/osc.lv2/.gitlab-ci.yml b/osc.lv2/.gitlab-ci.yml new file mode 100644 index 0000000..f0e54dd --- /dev/null +++ b/osc.lv2/.gitlab-ci.yml @@ -0,0 +1,65 @@ +stages: + - test + +.variables_template: &variables_definition + variables: + BASE_NAME: "osc.lv2" + PKG_CONFIG_PATH: "/opt/lv2/lib/pkgconfig:/opt/${CI_BUILD_NAME}/lib/pkgconfig:/usr/lib/${CI_BUILD_NAME}/pkgconfig" + +.common_template: &common_definition + <<: *variables_definition + stage: test + +.build_template: &build_definition + <<: *common_definition + script: + - meson --cross-file "${CI_BUILD_NAME}" build + - ninja -C build + +.test_template: &test_definition + <<: *common_definition + script: + - meson --cross-file "${CI_BUILD_NAME}" build + - ninja -C build + - cd build + - meson test --verbose --wrap "${CI_BUILD_NAME}.wrap" + +.universal_linux_template: &universal_linux_definition + image: ventosus/universal-linux-gnu + <<: *test_definition + +.arm_linux_template: &arm_linux_definition + image: ventosus/arm-linux-gnueabihf + <<: *test_definition + +.universal_w64_template: &universal_w64_definition + image: ventosus/universal-w64-mingw32 + before_script: + - ln -s /usr/lib/gcc/i686-w64-mingw32/6.3-win32/libgcc_s_sjlj-1.dll /opt/i686-w64-mingw32/lib/libgcc_s_sjlj-1.dll + <<: *test_definition + +.universal_apple_template: &universal_apple_definition + image: ventosus/universal-apple-darwin + <<: *build_definition + +# building in docker +x86_64-linux-gnu: + <<: *universal_linux_definition + +i686-linux-gnu: + <<: *universal_linux_definition + +arm-linux-gnueabihf: + <<: *arm_linux_definition + +aarch64-linux-gnu: + <<: *arm_linux_definition + +x86_64-w64-mingw32: + <<: *universal_w64_definition + +i686-w64-mingw32: + <<: *universal_w64_definition + +universal-apple-darwin: + <<: *universal_apple_definition diff --git a/osc.lv2/COPYING b/osc.lv2/COPYING new file mode 100644 index 0000000..ddb9a46 --- /dev/null +++ b/osc.lv2/COPYING @@ -0,0 +1,201 @@ + The Artistic License 2.0 + + Copyright (c) 2000-2006, The Perl Foundation. + + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +Preamble + +This license establishes the terms under which a given free software +Package may be copied, modified, distributed, and/or redistributed. +The intent is that the Copyright Holder maintains some artistic +control over the development of that Package while still keeping the +Package available as open source and free software. + +You are always permitted to make arrangements wholly outside of this +license directly with the Copyright Holder of a given Package. If the +terms of this license do not permit the full use that you propose to +make of the Package, you should contact the Copyright Holder and seek +a different licensing arrangement. + +Definitions + + "Copyright Holder" means the individual(s) or organization(s) + named in the copyright notice for the entire Package. + + "Contributor" means any party that has contributed code or other + material to the Package, in accordance with the Copyright Holder's + procedures. + + "You" and "your" means any person who would like to copy, + distribute, or modify the Package. + + "Package" means the collection of files distributed by the + Copyright Holder, and derivatives of that collection and/or of + those files. A given Package may consist of either the Standard + Version, or a Modified Version. + + "Distribute" means providing a copy of the Package or making it + accessible to anyone else, or in the case of a company or + organization, to others outside of your company or organization. + + "Distributor Fee" means any fee that you charge for Distributing + this Package or providing support for this Package to another + party. It does not mean licensing fees. + + "Standard Version" refers to the Package if it has not been + modified, or has been modified only in ways explicitly requested + by the Copyright Holder. + + "Modified Version" means the Package, if it has been changed, and + such changes were not explicitly requested by the Copyright + Holder. + + "Original License" means this Artistic License as Distributed with + the Standard Version of the Package, in its current version or as + it may be modified by The Perl Foundation in the future. + + "Source" form means the source code, documentation source, and + configuration files for the Package. + + "Compiled" form means the compiled bytecode, object code, binary, + or any other form resulting from mechanical transformation or + translation of the Source form. + + +Permission for Use and Modification Without Distribution + +(1) You are permitted to use the Standard Version and create and use +Modified Versions for any purpose without restriction, provided that +you do not Distribute the Modified Version. + + +Permissions for Redistribution of the Standard Version + +(2) You may Distribute verbatim copies of the Source form of the +Standard Version of this Package in any medium without restriction, +either gratis or for a Distributor Fee, provided that you duplicate +all of the original copyright notices and associated disclaimers. At +your discretion, such verbatim copies may or may not include a +Compiled form of the Package. + +(3) You may apply any bug fixes, portability changes, and other +modifications made available from the Copyright Holder. The resulting +Package will still be considered the Standard Version, and as such +will be subject to the Original License. + + +Distribution of Modified Versions of the Package as Source + +(4) You may Distribute your Modified Version as Source (either gratis +or for a Distributor Fee, and with or without a Compiled form of the +Modified Version) provided that you clearly document how it differs +from the Standard Version, including, but not limited to, documenting +any non-standard features, executables, or modules, and provided that +you do at least ONE of the following: + + (a) make the Modified Version available to the Copyright Holder + of the Standard Version, under the Original License, so that the + Copyright Holder may include your modifications in the Standard + Version. + + (b) ensure that installation of your Modified Version does not + prevent the user installing or running the Standard Version. In + addition, the Modified Version must bear a name that is different + from the name of the Standard Version. + + (c) allow anyone who receives a copy of the Modified Version to + make the Source form of the Modified Version available to others + under + + (i) the Original License or + + (ii) a license that permits the licensee to freely copy, + modify and redistribute the Modified Version using the same + licensing terms that apply to the copy that the licensee + received, and requires that the Source form of the Modified + Version, and of any works derived from it, be made freely + available in that license fees are prohibited but Distributor + Fees are allowed. + + +Distribution of Compiled Forms of the Standard Version +or Modified Versions without the Source + +(5) You may Distribute Compiled forms of the Standard Version without +the Source, provided that you include complete instructions on how to +get the Source of the Standard Version. Such instructions must be +valid at the time of your distribution. If these instructions, at any +time while you are carrying out such distribution, become invalid, you +must provide new instructions on demand or cease further distribution. +If you provide valid instructions or cease distribution within thirty +days after you become aware that the instructions are invalid, then +you do not forfeit any of your rights under this license. + +(6) You may Distribute a Modified Version in Compiled form without +the Source, provided that you comply with Section 4 with respect to +the Source of the Modified Version. + + +Aggregating or Linking the Package + +(7) You may aggregate the Package (either the Standard Version or +Modified Version) with other packages and Distribute the resulting +aggregation provided that you do not charge a licensing fee for the +Package. Distributor Fees are permitted, and licensing fees for other +components in the aggregation are permitted. The terms of this license +apply to the use and Distribution of the Standard or Modified Versions +as included in the aggregation. + +(8) You are permitted to link Modified and Standard Versions with +other works, to embed the Package in a larger work of your own, or to +build stand-alone binary or bytecode versions of applications that +include the Package, and Distribute the result without restriction, +provided the result does not expose a direct interface to the Package. + + +Items That are Not Considered Part of a Modified Version + +(9) Works (including, but not limited to, modules and scripts) that +merely extend or make use of the Package, do not, by themselves, cause +the Package to be a Modified Version. In addition, such works are not +considered parts of the Package itself, and are not subject to the +terms of this license. + + +General Provisions + +(10) Any use, modification, and distribution of the Standard or +Modified Versions is governed by this Artistic License. By using, +modifying or distributing the Package, you accept this license. Do not +use, modify, or distribute the Package, if you do not accept this +license. + +(11) If your Modified Version has been derived from a Modified +Version made by someone other than you, you are nevertheless required +to ensure that your Modified Version complies with the requirements of +this license. + +(12) This license does not grant you the right to use any trademark, +service mark, tradename, or logo of the Copyright Holder. + +(13) This license includes the non-exclusive, worldwide, +free-of-charge patent license to make, have made, use, offer to sell, +sell, import and otherwise transfer the Package with respect to any +patent claims licensable by the Copyright Holder that are necessarily +infringed by the Package. If you institute patent litigation +(including a cross-claim or counterclaim) against any party alleging +that the Package constitutes direct or contributory patent +infringement, then this Artistic License to you shall terminate on the +date that such litigation is filed. + +(14) Disclaimer of Warranty: +THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS +IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL +LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/osc.lv2/README.md b/osc.lv2/README.md new file mode 100644 index 0000000..1a30571 --- /dev/null +++ b/osc.lv2/README.md @@ -0,0 +1,33 @@ +# osc.lv2 + +## Open Sound Control Extension for the LV2 Plugin Specification + +### Build Status + +[](https://gitlab.com/OpenMusicKontrollers/osc.lv2/commits/master) + +### Build / test + + git clone https://git.open-music-kontrollers.ch/lv2/osc.lv2 + cd osc.lv2 + meson build + cd build + ninja -j4 + ninja test + +### License + +Copyright (c) 2017 Hanspeter Portner (dev@open-music-kontrollers.ch) + +This is free software: you can redistribute it and/or modify +it under the terms of the Artistic License 2.0 as published by +The Perl Foundation. + +This source is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +Artistic License 2.0 for more details. + +You should have received a copy of the Artistic License 2.0 +along the source as a COPYING file. If not, obtain it from +<http://www.perlfoundation.org/artistic_license_2_0>. diff --git a/osc.lv2/VERSION b/osc.lv2/VERSION new file mode 100644 index 0000000..3170382 --- /dev/null +++ b/osc.lv2/VERSION @@ -0,0 +1 @@ +0.1.143 diff --git a/osc.lv2/lv2-osc.doap.ttl b/osc.lv2/lv2-osc.doap.ttl new file mode 100644 index 0000000..ef74f92 --- /dev/null +++ b/osc.lv2/lv2-osc.doap.ttl @@ -0,0 +1,40 @@ +# Copyright (c) 2015-2016 Hanspeter Portner (dev@open-music-kontrollers.ch) +# +# This is free software: you can redistribute it and/or modify +# it under the terms of the Artistic License 2.0 as published by +# The Perl Foundation. +# +# This source is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# Artistic License 2.0 for more details. +# +# You should have received a copy of the Artistic License 2.0 +# along the source as a COPYING file. If not, obtain it from +# http://www.perlfoundation.org/artistic_license_2_0. + +@prefix dcs: <http://ontologi.es/doap-changeset#> . +@prefix doap: <http://usefulinc.com/ns/doap#> . +@prefix foaf: <http://xmlns.com/foaf/0.1/> . +@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> . +@prefix lic: <http://opensource.org/licenses/> . +@prefix omk: <http://open-music-kontrollers.ch/ventosus#> . + +<http://open-music-kontrollers.ch/lv2/osc> + a doap:Project ; + doap:license lic:Artistic-2.0 ; + doap:name "LV2 OSC" ; + doap:shortdesc "A definition of atomified OSC." ; + doap:maintainer omk:me ; + doap:created "2015-06-19" ; + doap:developer omk:me ; + doap:release [ + doap:revision "1.0" ; + doap:created "2015-06-19" ; + dcs:blame omk:me ; + dcs:changeset [ + dcs:item [ + rdfs:label "Initial release." + ] + ] + ] . diff --git a/osc.lv2/manifest.ttl b/osc.lv2/manifest.ttl new file mode 100644 index 0000000..a2bbaf8 --- /dev/null +++ b/osc.lv2/manifest.ttl @@ -0,0 +1,23 @@ +# Copyright (c) 2015-2016 Hanspeter Portner (dev@open-music-kontrollers.ch) +# +# This is free software: you can redistribute it and/or modify +# it under the terms of the Artistic License 2.0 as published by +# The Perl Foundation. +# +# This source is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# Artistic License 2.0 for more details. +# +# You should have received a copy of the Artistic License 2.0 +# along the source as a COPYING file. If not, obtain it from +# http://www.perlfoundation.org/artistic_license_2_0. + +@prefix lv2: <http://lv2plug.in/ns/lv2core#> . +@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> . + +<http://open-music-kontrollers.ch/lv2/osc> + a lv2:Specification ; + lv2:minorVersion 1 ; + lv2:microVersion 0 ; + rdfs:seeAlso <osc.ttl> . diff --git a/osc.lv2/meson.build b/osc.lv2/meson.build new file mode 100644 index 0000000..750f0dc --- /dev/null +++ b/osc.lv2/meson.build @@ -0,0 +1,36 @@ +project('osc.lv2', 'c', default_options : [ + 'buildtype=release', + 'warning_level=3', + 'werror=true', + 'b_lto=false', + 'c_std=c11']) + +version = run_command('cat', 'VERSION').stdout().strip() + +add_project_arguments('-D_GNU_SOURCE', language : 'c') + +conf_data = configuration_data() +cc = meson.get_compiler('c') + +lv2_dep = dependency('lv2') +thread_dep = dependency('threads') +deps = [lv2_dep, thread_dep] + +c_args = [] + +if host_machine.system() == 'windows' + deps += cc.find_library('ws2_32') + c_args += '-Wno-error=format' + c_args += '-Wno-error=format-extra-args' +endif + +osc_test = executable('osc_test', + join_paths('test', 'osc_test.c'), + c_args : c_args, + dependencies : deps, + install : false) + +# FIXME start virautl serial pair before test +# socat -d -d pty,raw,echo=0 pty,raw,echo=0 +test('Test', osc_test, + timeout : 240) diff --git a/osc.lv2/osc.lv2/endian.h b/osc.lv2/osc.lv2/endian.h new file mode 100644 index 0000000..f310c51 --- /dev/null +++ b/osc.lv2/osc.lv2/endian.h @@ -0,0 +1,120 @@ +// "License": Public Domain +// I, Mathias Panzenböck, place this file hereby into the public domain. Use it at your own risk for whatever you like. +// In case there are jurisdictions that don't support putting things in the public domain you can also consider it to +// be "dual licensed" under the BSD, MIT and Apache licenses, if you want to. This code is trivial anyway. Consider it +// an example on how to get the endian conversion functions on different platforms. + +#ifndef PORTABLE_ENDIAN_H__ +#define PORTABLE_ENDIAN_H__ + +#if (defined(_WIN16) || defined(_WIN32) || defined(_WIN64)) && !defined(__WINDOWS__) + +# define __WINDOWS__ + +#endif + +#if defined(__linux__) || defined(__CYGWIN__) + +# include <endian.h> + +#elif defined(__APPLE__) + +# include <libkern/OSByteOrder.h> + +# define htobe16(x) OSSwapHostToBigInt16(x) +# define htole16(x) OSSwapHostToLittleInt16(x) +# define be16toh(x) OSSwapBigToHostInt16(x) +# define le16toh(x) OSSwapLittleToHostInt16(x) + +# define htobe32(x) OSSwapHostToBigInt32(x) +# define htole32(x) OSSwapHostToLittleInt32(x) +# define be32toh(x) OSSwapBigToHostInt32(x) +# define le32toh(x) OSSwapLittleToHostInt32(x) + +# define htobe64(x) OSSwapHostToBigInt64(x) +# define htole64(x) OSSwapHostToLittleInt64(x) +# define be64toh(x) OSSwapBigToHostInt64(x) +# define le64toh(x) OSSwapLittleToHostInt64(x) + +# define __BYTE_ORDER BYTE_ORDER +# define __BIG_ENDIAN BIG_ENDIAN +# define __LITTLE_ENDIAN LITTLE_ENDIAN +# define __PDP_ENDIAN PDP_ENDIAN + +#elif defined(__OpenBSD__) + +# include <sys/endian.h> + +#elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) || defined(__OpenBSD__) + +# include <sys/endian.h> + +#elif defined(__WINDOWS__) + +# include <winsock2.h> +# include <sys/param.h> + +# if BYTE_ORDER == LITTLE_ENDIAN + +# define htobe16(x) htons(x) +# define htole16(x) (x) +# define be16toh(x) ntohs(x) +# define le16toh(x) (x) + +# define htobe32(x) htonl(x) +# define htole32(x) (x) +# define be32toh(x) ntohl(x) +# define le32toh(x) (x) + +# ifndef htonll +static inline uint64_t htonll(uint64_t n) +{ + return (((uint64_t)htonl(n)) << 32) + htonl(n >> 32); +} +# endif + +# ifndef ntohll +# define ntohll htonll +# endif + +# define htobe64(x) htonll(x) +# define htole64(x) (x) +# define be64toh(x) ntohll(x) +# define le64toh(x) (x) + +# elif BYTE_ORDER == BIG_ENDIAN + + /* that would be xbox 360 */ +# define htobe16(x) (x) +# define htole16(x) __builtin_bswap16(x) +# define be16toh(x) (x) +# define le16toh(x) __builtin_bswap16(x) + +# define htobe32(x) (x) +# define htole32(x) __builtin_bswap32(x) +# define be32toh(x) (x) +# define le32toh(x) __builtin_bswap32(x) + +# define htobe64(x) (x) +# define htole64(x) __builtin_bswap64(x) +# define be64toh(x) (x) +# define le64toh(x) __builtin_bswap64(x) + +# else + +# error byte order not supported + +# endif + +# define __BYTE_ORDER BYTE_ORDER +# define __BIG_ENDIAN BIG_ENDIAN +# define __LITTLE_ENDIAN LITTLE_ENDIAN +# define __PDP_ENDIAN PDP_ENDIAN + +#else + +# error platform not supported + +#endif + +#endif diff --git a/osc.lv2/osc.lv2/forge.h b/osc.lv2/osc.lv2/forge.h new file mode 100644 index 0000000..6dc5fe7 --- /dev/null +++ b/osc.lv2/osc.lv2/forge.h @@ -0,0 +1,474 @@ +/* + * Copyright (c) 2015-2016 Hanspeter Portner (dev@open-music-kontrollers.ch) + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the Artistic License 2.0 as published by + * The Perl Foundation. + * + * This source is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Artistic License 2.0 for more details. + * + * You should have received a copy of the Artistic License 2.0 + * along the source as a COPYING file. If not, obtain it from + * http://www.perlfoundation.org/artistic_license_2_0. + */ + +#ifndef LV2_OSC_FORGE_H +#define LV2_OSC_FORGE_H + +#include <inttypes.h> + +#include <osc.lv2/osc.h> +#include <osc.lv2/util.h> +#include <osc.lv2/reader.h> + +#include <lv2/lv2plug.in/ns/ext/atom/forge.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define lv2_osc_forge_int(forge, osc_urid, val) \ + lv2_atom_forge_int((forge), (val)) + +#define lv2_osc_forge_float(forge, osc_urid, val) \ + lv2_atom_forge_float((forge), (val)) + +#define lv2_osc_forge_string(forge, osc_urid, val, len) \ + lv2_atom_forge_string((forge), (val), (len)) + +#define lv2_osc_forge_long(forge, osc_urid, val) \ + lv2_atom_forge_long((forge), (val)) + +#define lv2_osc_forge_double(forge, osc_urid, val) \ + lv2_atom_forge_double((forge), (val)) + +#define lv2_osc_forge_true(forge, osc_urid) \ + lv2_atom_forge_bool((forge), 1) + +#define lv2_osc_forge_false(forge, osc_urid) \ + lv2_atom_forge_bool((forge), 0) + +#define lv2_osc_forge_nil(forge, osc_urid) \ + lv2_atom_forge_literal((forge), "", 0, (osc_urid)->OSC_Nil, 0) + +#define lv2_osc_forge_impulse(forge, osc_urid) \ + lv2_atom_forge_literal((forge), "", 0, (osc_urid)->OSC_Impulse, 0) + +#define lv2_osc_forge_symbol(forge, osc_urid, val) \ + lv2_atom_forge_urid((forge), (val)) + +static inline LV2_Atom_Forge_Ref +lv2_osc_forge_chunk(LV2_Atom_Forge *forge, LV2_URID type, + const uint8_t *buf, uint32_t size) +{ + LV2_Atom_Forge_Ref ref; + + if( (ref = lv2_atom_forge_atom(forge, size, type)) + && (ref = lv2_atom_forge_raw(forge, buf, size)) ) + { + lv2_atom_forge_pad(forge, size); + return ref; + } + + return 0; +} + +static inline LV2_Atom_Forge_Ref +lv2_osc_forge_midi(LV2_Atom_Forge *forge, LV2_OSC_URID *osc_urid, + const uint8_t *buf, uint32_t size) +{ + assert(size <= 3); + return lv2_osc_forge_chunk(forge, osc_urid->MIDI_MidiEvent, buf, size); +} + +static inline LV2_Atom_Forge_Ref +lv2_osc_forge_blob(LV2_Atom_Forge* forge, LV2_OSC_URID *osc_urid, + const uint8_t *buf, uint32_t size) +{ + return lv2_osc_forge_chunk(forge, osc_urid->ATOM_Chunk, buf, size); +} + +static inline LV2_Atom_Forge_Ref +lv2_osc_forge_char(LV2_Atom_Forge* forge, LV2_OSC_URID *osc_urid, + char val) +{ + return lv2_atom_forge_literal(forge, &val, 1, osc_urid->OSC_Char, 0); +} + +static inline LV2_Atom_Forge_Ref +lv2_osc_forge_rgba(LV2_Atom_Forge* forge, LV2_OSC_URID *osc_urid, + uint8_t r, uint8_t g, uint8_t b, uint8_t a) +{ + char val [9]; + sprintf(val, "%02"PRIx8"%02"PRIx8"%02"PRIx8"%02"PRIx8, r, g, b, a); + return lv2_atom_forge_literal(forge, val, 8, osc_urid->OSC_RGBA, 0); +} + +static inline LV2_Atom_Forge_Ref +lv2_osc_forge_timetag(LV2_Atom_Forge *forge, LV2_OSC_URID *osc_urid, + const LV2_OSC_Timetag *timetag) +{ + LV2_Atom_Forge_Frame frame; + LV2_Atom_Forge_Ref ref; + + if( (ref = lv2_atom_forge_object(forge, &frame, 0, osc_urid->OSC_Timetag)) + && (ref = lv2_atom_forge_key(forge, osc_urid->OSC_timetagIntegral)) + && (ref = lv2_atom_forge_long(forge, timetag->integral)) + && (ref = lv2_atom_forge_key(forge, osc_urid->OSC_timetagFraction)) + && (ref = lv2_atom_forge_long(forge, timetag->fraction)) ) + { + lv2_atom_forge_pop(forge, &frame); + return ref; + } + + return 0; +} + +static inline LV2_Atom_Forge_Ref +lv2_osc_forge_bundle_head(LV2_Atom_Forge* forge, LV2_OSC_URID *osc_urid, + LV2_Atom_Forge_Frame frame [2], const LV2_OSC_Timetag *timetag) +{ + LV2_Atom_Forge_Ref ref; + + if( (ref = lv2_atom_forge_object(forge, &frame[0], 0, osc_urid->OSC_Bundle)) + && (ref = lv2_atom_forge_key(forge, osc_urid->OSC_bundleTimetag)) + && (ref = lv2_osc_forge_timetag(forge, osc_urid, timetag)) + && (ref = lv2_atom_forge_key(forge, osc_urid->OSC_bundleItems)) + && (ref = lv2_atom_forge_tuple(forge, &frame[1])) ) + { + return ref; + } + + return 0; +} + +/** + TODO +*/ +static inline LV2_Atom_Forge_Ref +lv2_osc_forge_message_head(LV2_Atom_Forge *forge, LV2_OSC_URID *osc_urid, + LV2_Atom_Forge_Frame frame [2], const char *path) +{ + assert(path); + + LV2_Atom_Forge_Ref ref; + if( (ref = lv2_atom_forge_object(forge, &frame[0], 0, osc_urid->OSC_Message)) + && (ref = lv2_atom_forge_key(forge, osc_urid->OSC_messagePath)) + && (ref = lv2_atom_forge_string(forge, path, strlen(path))) + && (ref = lv2_atom_forge_key(forge, osc_urid->OSC_messageArguments)) + && (ref = lv2_atom_forge_tuple(forge, &frame[1])) ) + { + return ref; + } + + return 0; +} + +/** + TODO +*/ +static inline void +lv2_osc_forge_pop(LV2_Atom_Forge *forge, LV2_Atom_Forge_Frame frame [2]) +{ + lv2_atom_forge_pop(forge, &frame[1]); // a LV2_Atom_Tuple + lv2_atom_forge_pop(forge, &frame[0]); // a LV2_Atom_Object +} + +static inline LV2_Atom_Forge_Ref +lv2_osc_forge_message_varlist(LV2_Atom_Forge *forge, LV2_OSC_URID *osc_urid, + const char *path, const char *fmt, va_list args) +{ + LV2_Atom_Forge_Frame frame [2]; + LV2_Atom_Forge_Ref ref; + + if(!lv2_osc_check_path(path) || !lv2_osc_check_fmt(fmt, 0)) + return 0; + if(!(ref = lv2_osc_forge_message_head(forge, osc_urid, frame, path))) + return 0; + + for(const char *type = fmt; *type; type++) + { + switch( (LV2_OSC_Type)*type) + { + case LV2_OSC_INT32: + { + if(!(ref = lv2_osc_forge_int(forge, osc_urid, va_arg(args, int32_t)))) + return 0; + break; + } + case LV2_OSC_FLOAT: + { + if(!(ref = lv2_osc_forge_float(forge, osc_urid, (float)va_arg(args, double)))) + return 0; + break; + } + case LV2_OSC_STRING: + { + const char *s = va_arg(args, const char *); + if(!s || !(ref = lv2_osc_forge_string(forge, osc_urid, s, strlen(s)))) + return 0; + break; + } + case LV2_OSC_BLOB: + { + const int32_t size = va_arg(args, int32_t); + const uint8_t *b = va_arg(args, const uint8_t *); + if(!b || !(ref = lv2_osc_forge_blob(forge, osc_urid, b, size))) + return 0; + break; + } + + case LV2_OSC_INT64: + { + if(!(ref = lv2_osc_forge_long(forge, osc_urid, va_arg(args, int64_t)))) + return 0; + break; + } + case LV2_OSC_DOUBLE: + { + if(!(ref = lv2_osc_forge_double(forge, osc_urid, va_arg(args, double)))) + return 0; + break; + } + case LV2_OSC_TIMETAG: + { + const LV2_OSC_Timetag timetag = { + .integral = va_arg(args, uint32_t), + .fraction = va_arg(args, uint32_t) + }; + if(!(ref = lv2_osc_forge_timetag(forge, osc_urid, &timetag))) + return 0; + break; + } + + case LV2_OSC_TRUE: + { + if(!(ref = lv2_osc_forge_true(forge, osc_urid))) + return 0; + break; + } + case LV2_OSC_FALSE: + { + if(!(ref = lv2_osc_forge_false(forge, osc_urid))) + return 0; + break; + } + case LV2_OSC_NIL: + { + if(!(ref = lv2_osc_forge_nil(forge, osc_urid))) + return 0; + break; + } + case LV2_OSC_IMPULSE: + { + if(!(ref = lv2_osc_forge_impulse(forge, osc_urid))) + return 0; + break; + } + + case LV2_OSC_SYMBOL: + { + if(!(ref = lv2_osc_forge_symbol(forge, osc_urid, va_arg(args, uint32_t)))) + return 0; + break; + } + case LV2_OSC_MIDI: + { + const int32_t size = va_arg(args, int32_t); + const uint8_t *m = va_arg(args, const uint8_t *); + if(!m || !(ref = lv2_osc_forge_midi(forge, osc_urid, m, size))) + return 0; + break; + } + case LV2_OSC_CHAR: + { + if(!(ref = lv2_osc_forge_char(forge, osc_urid, (char)va_arg(args, int)))) + return 0; + break; + } + case LV2_OSC_RGBA: + { + if(!(ref = lv2_osc_forge_rgba(forge, osc_urid, + (uint8_t)va_arg(args, unsigned), + (uint8_t)va_arg(args, unsigned), + (uint8_t)va_arg(args, unsigned), + (uint8_t)va_arg(args, unsigned)))) + return 0; + break; + } + } + } + + lv2_osc_forge_pop(forge, frame); + + return ref; +} + +static inline LV2_Atom_Forge_Ref +lv2_osc_forge_message_vararg(LV2_Atom_Forge *forge, LV2_OSC_URID *osc_urid, + const char *path, const char *fmt, ...) +{ + LV2_Atom_Forge_Ref ref; + va_list args; + + va_start(args, fmt); + + ref = lv2_osc_forge_message_varlist(forge, osc_urid, path, fmt, args); + + va_end(args); + + return ref; +} + +static inline LV2_Atom_Forge_Ref +lv2_osc_forge_packet(LV2_Atom_Forge *forge, LV2_OSC_URID *osc_urid, + LV2_URID_Map *map, const uint8_t *buf, size_t size) +{ + LV2_OSC_Reader reader; + LV2_Atom_Forge_Frame frame [2]; + LV2_Atom_Forge_Ref ref; + + lv2_osc_reader_initialize(&reader, buf, size); + + if(lv2_osc_reader_is_bundle(&reader)) + { + LV2_OSC_Item *itm = OSC_READER_BUNDLE_BEGIN(&reader, size); + + if(itm && (ref = lv2_osc_forge_bundle_head(forge, osc_urid, frame, + LV2_OSC_TIMETAG_CREATE(itm->timetag)))) + { + OSC_READER_BUNDLE_ITERATE(&reader, itm) + { + if(!(ref = lv2_osc_forge_packet(forge, osc_urid, map, itm->body, itm->size))) + return 0; + } + + lv2_osc_forge_pop(forge, frame); + + return ref; + } + } + else if(lv2_osc_reader_is_message(&reader)) + { + LV2_OSC_Arg *arg = OSC_READER_MESSAGE_BEGIN(&reader, size); + + if(arg && (ref = lv2_osc_forge_message_head(forge, osc_urid, frame, arg->path))) + { + OSC_READER_MESSAGE_ITERATE(&reader, arg) + { + switch( (LV2_OSC_Type)*arg->type) + { + case LV2_OSC_INT32: + { + if(!(ref = lv2_osc_forge_int(forge, osc_urid, arg->i))) + return 0; + break; + } + case LV2_OSC_FLOAT: + { + if(!(ref = lv2_osc_forge_float(forge, osc_urid, arg->f))) + return 0; + break; + } + case LV2_OSC_STRING: + { + if(!(ref = lv2_osc_forge_string(forge, osc_urid, arg->s, arg->size - 1))) + return 0; + break; + } + case LV2_OSC_BLOB: + { + if(!(ref = lv2_osc_forge_blob(forge, osc_urid, arg->b, arg->size))) + return 0; + break; + } + + case LV2_OSC_INT64: + { + if(!(ref = lv2_osc_forge_long(forge, osc_urid, arg->h))) + return 0; + break; + } + case LV2_OSC_DOUBLE: + { + if(!(ref = lv2_osc_forge_double(forge, osc_urid, arg->d))) + return 0; + break; + } + case LV2_OSC_TIMETAG: + { + if(!(ref = lv2_osc_forge_timetag(forge, osc_urid, LV2_OSC_TIMETAG_CREATE(arg->t)))) + return 0; + break; + } + + case LV2_OSC_TRUE: + { + if(!(ref = lv2_osc_forge_true(forge, osc_urid))) + return 0; + break; + } + case LV2_OSC_FALSE: + { + if(!(ref = lv2_osc_forge_false(forge, osc_urid))) + return 0; + break; + } + case LV2_OSC_NIL: + { + if(!(ref = lv2_osc_forge_nil(forge, osc_urid))) + return 0; + break; + } + case LV2_OSC_IMPULSE: + { + if(!(ref = lv2_osc_forge_impulse(forge, osc_urid))) + return 0; + break; + } + + case LV2_OSC_SYMBOL: + { + if(!(ref = lv2_osc_forge_symbol(forge, osc_urid, + map->map(map->handle, arg->S)))) + return 0; + break; + } + case LV2_OSC_MIDI: + { + if(!(ref = lv2_osc_forge_midi(forge, osc_urid, &arg->b[1], arg->size - 1))) + return 0; + break; + } + case LV2_OSC_CHAR: + { + if(!(ref = lv2_osc_forge_char(forge, osc_urid, arg->c))) + return 0; + break; + } + case LV2_OSC_RGBA: + { + if(!(ref = lv2_osc_forge_rgba(forge, osc_urid, arg->R, arg->G, arg->B, arg->A))) + return 0; + break; + } + } + } + + lv2_osc_forge_pop(forge, frame); + + return ref; + } + } + + return 0; +} + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // LV2_OSC_FORGE_H diff --git a/osc.lv2/osc.lv2/osc.h b/osc.lv2/osc.lv2/osc.h new file mode 100644 index 0000000..1ada68c --- /dev/null +++ b/osc.lv2/osc.lv2/osc.h @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2015-2016 Hanspeter Portner (dev@open-music-kontrollers.ch) + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the Artistic License 2.0 as published by + * The Perl Foundation. + * + * This source is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Artistic License 2.0 for more details. + * + * You should have received a copy of the Artistic License 2.0 + * along the source as a COPYING file. If not, obtain it from + * http://www.perlfoundation.org/artistic_license_2_0. + */ + +#ifndef LV2_OSC_H +#define LV2_OSC_H + +#include <stdint.h> + +#include <lv2/lv2plug.in/ns/ext/urid/urid.h> +#include <lv2/lv2plug.in/ns/ext/atom/atom.h> +#include <lv2/lv2plug.in/ns/ext/midi/midi.h> + +#define LV2_OSC_URI "http://open-music-kontrollers.ch/lv2/osc" +#define LV2_OSC_PREFIX LV2_OSC_URI "#" + +#define LV2_OSC__Event LV2_OSC_PREFIX "Event" // atom message type +#define LV2_OSC__schedule LV2_OSC_PREFIX "schedule" // feature + +#define LV2_OSC__Packet LV2_OSC_PREFIX "Packet" // atom object type + +#define LV2_OSC__Bundle LV2_OSC_PREFIX "Bundle" // atom object type +#define LV2_OSC__bundleTimetag LV2_OSC_PREFIX "bundleTimetag" // atom object property +#define LV2_OSC__bundleItems LV2_OSC_PREFIX "bundleItems" + +#define LV2_OSC__Message LV2_OSC_PREFIX "Message" // atom object type +#define LV2_OSC__messagePath LV2_OSC_PREFIX "messagePath" // atom object property +#define LV2_OSC__messageArguments LV2_OSC_PREFIX "messageArguments" // atom object property + +#define LV2_OSC__Timetag LV2_OSC_PREFIX "Timetag" // atom object type +#define LV2_OSC__timetagIntegral LV2_OSC_PREFIX "timetagIntegral" // atom object property +#define LV2_OSC__timetagFraction LV2_OSC_PREFIX "timetagFraction" // atom object property + +#define LV2_OSC__Nil LV2_OSC_PREFIX "Nil" // atom literal type +#define LV2_OSC__Impulse LV2_OSC_PREFIX "Impulse" // atom literal type +#define LV2_OSC__Char LV2_OSC_PREFIX "Char" // atom literal type +#define LV2_OSC__RGBA LV2_OSC_PREFIX "RGBA" // atom literal type + +#define LV2_OSC_PADDED_SIZE(size) ( ( (size_t)(size) + 3 ) & ( ~3 ) ) +#define LV2_OSC_IMMEDIATE 1ULL + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void *LV2_OSC_Schedule_Handle; + +typedef double (*LV2_OSC_Schedule_OSC2Frames)( + LV2_OSC_Schedule_Handle handle, + uint64_t timetag); + +typedef uint64_t (*LV2_OSC_Schedule_Frames2OSC)( + LV2_OSC_Schedule_Handle handle, + double frames); + +typedef struct _LV2_OSC_Schedule { + LV2_OSC_Schedule_Handle handle; + LV2_OSC_Schedule_OSC2Frames osc2frames; + LV2_OSC_Schedule_Frames2OSC frames2osc; +} LV2_OSC_Schedule; + +typedef enum LV2_OSC_Type { + LV2_OSC_INT32 = 'i', + LV2_OSC_FLOAT = 'f', + LV2_OSC_STRING = 's', + LV2_OSC_BLOB = 'b', + + LV2_OSC_TRUE = 'T', + LV2_OSC_FALSE = 'F', + LV2_OSC_NIL = 'N', + LV2_OSC_IMPULSE = 'I', + + LV2_OSC_INT64 = 'h', + LV2_OSC_DOUBLE = 'd', + LV2_OSC_TIMETAG = 't', + + LV2_OSC_SYMBOL = 'S', + LV2_OSC_CHAR = 'c', + LV2_OSC_MIDI = 'm', + LV2_OSC_RGBA = 'r' +} LV2_OSC_Type; + +union swap32_t { + uint32_t u; + + int32_t i; + float f; +}; + +union swap64_t { + uint64_t u; + + int64_t h; + uint64_t t; + double d; +}; + +typedef struct _LV2_OSC_Timetag { + uint32_t integral; + uint32_t fraction; +} LV2_OSC_Timetag; + +typedef struct _LV2_OSC_URID { + LV2_URID OSC_Packet; + + LV2_URID OSC_Bundle; + LV2_URID OSC_bundleTimetag; + LV2_URID OSC_bundleItems; + + LV2_URID OSC_Message; + LV2_URID OSC_messagePath; + LV2_URID OSC_messageArguments; + + LV2_URID OSC_Timetag; + LV2_URID OSC_timetagIntegral; + LV2_URID OSC_timetagFraction; + + LV2_URID OSC_Nil; + LV2_URID OSC_Impulse; + LV2_URID OSC_Char; + LV2_URID OSC_RGBA; + + LV2_URID MIDI_MidiEvent; + + LV2_URID ATOM_Int; + LV2_URID ATOM_Long; + LV2_URID ATOM_String; + LV2_URID ATOM_Literal; + LV2_URID ATOM_Float; + LV2_URID ATOM_Double; + LV2_URID ATOM_URID; + LV2_URID ATOM_Bool; + LV2_URID ATOM_Tuple; + LV2_URID ATOM_Object; + LV2_URID ATOM_Chunk; +} LV2_OSC_URID; + +static inline void +lv2_osc_urid_init(LV2_OSC_URID *osc_urid, LV2_URID_Map *map) +{ + osc_urid->OSC_Packet = map->map(map->handle, LV2_OSC__Packet); + + osc_urid->OSC_Bundle = map->map(map->handle, LV2_OSC__Bundle); + osc_urid->OSC_bundleTimetag = map->map(map->handle, LV2_OSC__bundleTimetag); + osc_urid->OSC_bundleItems = map->map(map->handle, LV2_OSC__bundleItems); + + osc_urid->OSC_Message = map->map(map->handle, LV2_OSC__Message); + osc_urid->OSC_messagePath = map->map(map->handle, LV2_OSC__messagePath); + osc_urid->OSC_messageArguments = map->map(map->handle, LV2_OSC__messageArguments); + + osc_urid->OSC_Timetag = map->map(map->handle, LV2_OSC__Timetag); + osc_urid->OSC_timetagIntegral = map->map(map->handle, LV2_OSC__timetagIntegral); + osc_urid->OSC_timetagFraction = map->map(map->handle, LV2_OSC__timetagFraction); + + osc_urid->OSC_Nil = map->map(map->handle, LV2_OSC__Nil); + osc_urid->OSC_Impulse = map->map(map->handle, LV2_OSC__Impulse); + osc_urid->OSC_Char = map->map(map->handle, LV2_OSC__Char); + osc_urid->OSC_RGBA = map->map(map->handle, LV2_OSC__RGBA); + + osc_urid->MIDI_MidiEvent = map->map(map->handle, LV2_MIDI__MidiEvent); + + osc_urid->ATOM_Int = map->map(map->handle, LV2_ATOM__Int); + osc_urid->ATOM_Long = map->map(map->handle, LV2_ATOM__Long); + osc_urid->ATOM_String = map->map(map->handle, LV2_ATOM__String); + osc_urid->ATOM_Literal = map->map(map->handle, LV2_ATOM__Literal); + osc_urid->ATOM_Float = map->map(map->handle, LV2_ATOM__Float); + osc_urid->ATOM_Double = map->map(map->handle, LV2_ATOM__Double); + osc_urid->ATOM_URID = map->map(map->handle, LV2_ATOM__URID); + osc_urid->ATOM_Bool = map->map(map->handle, LV2_ATOM__Bool); + osc_urid->ATOM_Tuple = map->map(map->handle, LV2_ATOM__Tuple); + osc_urid->ATOM_Object = map->map(map->handle, LV2_ATOM__Object); + osc_urid->ATOM_Chunk = map->map(map->handle, LV2_ATOM__Chunk); +} + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // LV2_OSC_H diff --git a/osc.lv2/osc.lv2/reader.h b/osc.lv2/osc.lv2/reader.h new file mode 100644 index 0000000..ae46dfa --- /dev/null +++ b/osc.lv2/osc.lv2/reader.h @@ -0,0 +1,629 @@ +/* + * Copyright (c) 2015-2016 Hanspeter Portner (dev@open-music-kontrollers.ch) + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the Artistic License 2.0 as published by + * The Perl Foundation. + * + * This source is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Artistic License 2.0 for more details. + * + * You should have received a copy of the Artistic License 2.0 + * along the source as a COPYING file. If not, obtain it from + * http://www.perlfoundation.org/artistic_license_2_0. + */ + +#ifndef LV2_OSC_READER_H +#define LV2_OSC_READER_H + +#include <stdbool.h> +#include <string.h> +#include <stdarg.h> + +#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; + const uint8_t *ptr; + const uint8_t *end; +}; + +struct _LV2_OSC_Item { + int32_t size; + const uint8_t *body; + + uint64_t timetag; + const uint8_t *end; +}; + +struct _LV2_OSC_Arg { + const char *type; + int32_t size; + union { + int32_t i; + float f; + const char *s; + const uint8_t *b; + + int64_t h; + double d; + uint64_t t; + + const uint8_t *m; + const char *S; + char c; + struct { + uint8_t R; + uint8_t G; + uint8_t B; + uint8_t A; + }; // anonymous RGBA struct + }; + + const char *path; + const uint8_t *end; +}; + +static inline void +lv2_osc_reader_initialize(LV2_OSC_Reader *reader, const uint8_t *buf, size_t size) +{ + reader->buf = buf; + reader->ptr = buf; + reader->end = buf + size; +} + +static inline bool +lv2_osc_reader_overflow(LV2_OSC_Reader *reader, size_t size) +{ + return reader->ptr + size > reader->end; +} + +static inline bool +lv2_osc_reader_be32toh(LV2_OSC_Reader *reader, union swap32_t *s32) +{ + if(lv2_osc_reader_overflow(reader, 4)) + return false; + + s32->u = *(const uint32_t *)reader->ptr; + s32->u = be32toh(s32->u); + reader->ptr += 4; + + return true; +} + +static inline bool +lv2_osc_reader_be64toh(LV2_OSC_Reader *reader, union swap64_t *s64) +{ + if(lv2_osc_reader_overflow(reader, 8)) + return false; + + s64->u = *(const uint64_t *)reader->ptr; + s64->u = be64toh(s64->u); + reader->ptr += 8; + + return true; +} + +static inline bool +lv2_osc_reader_get_int32(LV2_OSC_Reader *reader, int32_t *i) +{ + union swap32_t s32; + if(!lv2_osc_reader_be32toh(reader, &s32)) + return false; + + *i = s32.i; + + return true; +} + +static inline bool +lv2_osc_reader_get_float(LV2_OSC_Reader *reader, float *f) +{ + union swap32_t s32; + if(!lv2_osc_reader_be32toh(reader, &s32)) + return false; + + *f = s32.f; + + return true; +} + +static inline bool +lv2_osc_reader_get_int64(LV2_OSC_Reader *reader, int64_t *h) +{ + union swap64_t s64; + if(!lv2_osc_reader_be64toh(reader, &s64)) + return false; + + *h = s64.h; + + return true; +} + +static inline bool +lv2_osc_reader_get_timetag(LV2_OSC_Reader *reader, uint64_t *t) +{ + union swap64_t s64; + if(!lv2_osc_reader_be64toh(reader, &s64)) + return false; + + *t = s64.u; + + return true; +} + +static inline bool +lv2_osc_reader_get_double(LV2_OSC_Reader *reader, double *d) +{ + union swap64_t s64; + if(!lv2_osc_reader_be64toh(reader, &s64)) + return false; + + *d = s64.d; + + return true; +} + +static inline bool +lv2_osc_reader_get_string(LV2_OSC_Reader *reader, const char **s) +{ + const char *str = (const char *)reader->ptr; + const size_t padded = LV2_OSC_PADDED_SIZE(strlen(str) + 1); + if(lv2_osc_reader_overflow(reader, padded )) + return false; + + *s = str; + reader->ptr += padded; + + return true; +} + +static inline bool +lv2_osc_reader_get_symbol(LV2_OSC_Reader *reader, const char **S) +{ + return lv2_osc_reader_get_string(reader, S); +} + +static inline bool +lv2_osc_reader_get_midi(LV2_OSC_Reader *reader, const uint8_t **m) +{ + if(lv2_osc_reader_overflow(reader, 4)) + return false; + + *m = reader->ptr; + reader->ptr += 4; + + return true; +} + +static inline bool +lv2_osc_reader_get_blob(LV2_OSC_Reader *reader, int32_t *len, const uint8_t **body) +{ + if(!lv2_osc_reader_get_int32(reader, len)) + return false; + + const size_t padded = LV2_OSC_PADDED_SIZE(*len); + if(lv2_osc_reader_overflow(reader, padded)) + return false; + + *body = reader->ptr; + reader->ptr += padded; + + return true; +} + +static inline bool +lv2_osc_reader_get_rgba(LV2_OSC_Reader *reader, uint8_t *r, uint8_t *g, uint8_t *b, uint8_t *a) +{ + if(lv2_osc_reader_overflow(reader, 4)) + return false; + + *r = reader->ptr[0]; + *g = reader->ptr[1]; + *b = reader->ptr[2]; + *a = reader->ptr[3]; + reader->ptr += 4; + + return true; +} + +static inline bool +lv2_osc_reader_get_char(LV2_OSC_Reader *reader, char *c) +{ + int32_t i; + if(!lv2_osc_reader_get_int32(reader, &i)) + return false; + + *c = i; + + return true; +} + +static inline LV2_OSC_Item * +lv2_osc_reader_item_raw(LV2_OSC_Reader *reader, LV2_OSC_Item *itm) +{ + if(!lv2_osc_reader_get_int32(reader, &itm->size)) + return NULL; + + if(lv2_osc_reader_overflow(reader, itm->size)) + return NULL; + + itm->body = reader->ptr; + + return itm; +} + +static inline LV2_OSC_Item * +lv2_osc_reader_item_begin(LV2_OSC_Reader *reader, LV2_OSC_Item *itm, size_t len) +{ + if(lv2_osc_reader_overflow(reader, len)) + return NULL; + + itm->end = reader->ptr + len; + + if(lv2_osc_reader_overflow(reader, 16)) + return NULL; + + if(strncmp((const char *)reader->ptr, "#bundle", 8)) + return NULL; + reader->ptr += 8; + + if(!lv2_osc_reader_get_timetag(reader, &itm->timetag)) + return NULL; + + return lv2_osc_reader_item_raw(reader, itm); +} + +static inline bool +lv2_osc_reader_item_is_end(LV2_OSC_Reader *reader, LV2_OSC_Item *itm) +{ + return reader->ptr > itm->end; +} + +static inline LV2_OSC_Item * +lv2_osc_reader_item_next(LV2_OSC_Reader *reader, LV2_OSC_Item *itm) +{ + reader->ptr += itm->size; + + return lv2_osc_reader_item_raw(reader, itm); +} + +#define OSC_READER_BUNDLE_BEGIN(reader, len) \ + lv2_osc_reader_item_begin( \ + (reader), \ + &(LV2_OSC_Item){ .size = 0, .body = NULL, .timetag = 1ULL, .end = NULL }, \ + len) + +#define OSC_READER_BUNDLE_ITERATE(reader, itm) \ + for(itm = itm; \ + itm && !lv2_osc_reader_item_is_end((reader), (itm)); \ + itm = lv2_osc_reader_item_next((reader), (itm))) + +#define OSC_READER_BUNDLE_FOREACH(reader, itm, len) \ + for(LV2_OSC_Item *(itm) = OSC_READER_BUNDLE_BEGIN((reader), (len)); \ + itm && !lv2_osc_reader_item_is_end((reader), (itm)); \ + itm = lv2_osc_reader_item_next((reader), (itm))) + +static inline LV2_OSC_Arg * +lv2_osc_reader_arg_raw(LV2_OSC_Reader *reader, LV2_OSC_Arg *arg) +{ + switch( (LV2_OSC_Type)*arg->type) + { + case LV2_OSC_INT32: + { + if(!lv2_osc_reader_get_int32(reader, &arg->i)) + return NULL; + arg->size = 4; + + break; + } + case LV2_OSC_FLOAT: + { + if(!lv2_osc_reader_get_float(reader, &arg->f)) + return NULL; + arg->size = 4; + + break; + } + case LV2_OSC_STRING: + { + if(!lv2_osc_reader_get_string(reader, &arg->s)) + return NULL; + arg->size = strlen(arg->s) + 1; + + break; + } + case LV2_OSC_BLOB: + { + if(!lv2_osc_reader_get_blob(reader, &arg->size, &arg->b)) + return NULL; + //arg->size = arg->size; + + break; + } + + case LV2_OSC_TRUE: + case LV2_OSC_FALSE: + case LV2_OSC_NIL: + case LV2_OSC_IMPULSE: + break; + + case LV2_OSC_INT64: + { + if(!lv2_osc_reader_get_int64(reader, &arg->h)) + return NULL; + arg->size = 8; + + break; + } + case LV2_OSC_DOUBLE: + { + if(!lv2_osc_reader_get_double(reader, &arg->d)) + return NULL; + arg->size = 8; + + break; + } + case LV2_OSC_TIMETAG: + { + if(!lv2_osc_reader_get_timetag(reader, &arg->t)) + return NULL; + arg->size = 8; + + break; + } + + case LV2_OSC_MIDI: + { + if(!lv2_osc_reader_get_midi(reader, &arg->m)) + return NULL; + arg->size = 4; + + break; + } + case LV2_OSC_SYMBOL: + { + if(!lv2_osc_reader_get_symbol(reader, &arg->S)) + return NULL; + arg->size = strlen(arg->S) + 1; + + break; + } + case LV2_OSC_CHAR: + { + if(!lv2_osc_reader_get_char(reader, &arg->c)) + return NULL; + arg->size = 4; + + break; + } + case LV2_OSC_RGBA: + { + if(!lv2_osc_reader_get_rgba(reader, &arg->R, &arg->G, &arg->B, &arg->A)) + return NULL; + arg->size = 4; + + break; + } + } + + return arg; +} + +static inline LV2_OSC_Arg * +lv2_osc_reader_arg_begin(LV2_OSC_Reader *reader, LV2_OSC_Arg *arg, size_t len) +{ + if(lv2_osc_reader_overflow(reader, len)) + return NULL; + + arg->end = reader->ptr + len; + + if(!lv2_osc_reader_get_string(reader, &arg->path)) //TODO check for validity + return NULL; + + if(!lv2_osc_reader_get_string(reader, &arg->type)) //TODO check for validity + return NULL; + + if(*arg->type != ',') + return NULL; + + arg->type++; // skip ',' + + return lv2_osc_reader_arg_raw(reader, arg); +} + +static inline bool +lv2_osc_reader_arg_is_end(LV2_OSC_Reader *reader, LV2_OSC_Arg *arg) +{ + return (*arg->type == '\0') || (reader->ptr > arg->end); +} + +static inline LV2_OSC_Arg * +lv2_osc_reader_arg_next(LV2_OSC_Reader *reader, LV2_OSC_Arg *arg) +{ + arg->type++; + + return lv2_osc_reader_arg_raw(reader, arg); +} + +#define OSC_READER_MESSAGE_BEGIN(reader, len) \ + lv2_osc_reader_arg_begin( \ + (reader), \ + &(LV2_OSC_Arg){ .type = NULL, .size = 0, .path = NULL, .end = NULL }, \ + len) + +#define OSC_READER_MESSAGE_ITERATE(reader, arg) \ + for(arg = arg; \ + arg && !lv2_osc_reader_arg_is_end((reader), (arg)); \ + arg = lv2_osc_reader_arg_next((reader), (arg))) + +#define OSC_READER_MESSAGE_FOREACH(reader, arg, len) \ + for(LV2_OSC_Arg *(arg) = OSC_READER_MESSAGE_BEGIN((reader), (len)); \ + arg && !lv2_osc_reader_arg_is_end((reader), (arg)); \ + arg = lv2_osc_reader_arg_next((reader), (arg))) + +static inline bool +lv2_osc_reader_arg_varlist(LV2_OSC_Reader *reader, const char *fmt, va_list args) +{ + for(const char *type = fmt; *type; type++) + { + switch( (LV2_OSC_Type)*type) + { + case LV2_OSC_INT32: + if(!lv2_osc_reader_get_int32(reader, va_arg(args, int32_t *))) + return false; + break; + case LV2_OSC_FLOAT: + if(!lv2_osc_reader_get_float(reader, va_arg(args, float *))) + return false; + break; + case LV2_OSC_STRING: + if(!lv2_osc_reader_get_string(reader, va_arg(args, const char **))) + return false; + break; + case LV2_OSC_BLOB: + if(!lv2_osc_reader_get_blob(reader, va_arg(args, int32_t *), va_arg(args, const uint8_t **))) + return false; + break; + + case LV2_OSC_TRUE: + case LV2_OSC_FALSE: + case LV2_OSC_NIL: + case LV2_OSC_IMPULSE: + break; + + case LV2_OSC_INT64: + if(!lv2_osc_reader_get_int64(reader, va_arg(args, int64_t *))) + return false; + break; + case LV2_OSC_DOUBLE: + if(!lv2_osc_reader_get_double(reader, va_arg(args, double *))) + return false; + break; + case LV2_OSC_TIMETAG: + if(!lv2_osc_reader_get_timetag(reader, va_arg(args, uint64_t *))) + return false; + break; + + case LV2_OSC_MIDI: + if(!lv2_osc_reader_get_midi(reader, va_arg(args, const uint8_t **))) + return false; + break; + case LV2_OSC_SYMBOL: + if(!lv2_osc_reader_get_symbol(reader, va_arg(args, const char **))) + return false; + break; + case LV2_OSC_CHAR: + if(!lv2_osc_reader_get_char(reader, va_arg(args, char *))) + return false; + break; + case LV2_OSC_RGBA: + if(!lv2_osc_reader_get_rgba(reader, va_arg(args, uint8_t *), va_arg(args, uint8_t *), + va_arg(args, uint8_t *), va_arg(args, uint8_t *))) + return false; + break; + } + } + + return true; +} + +static inline bool +lv2_osc_reader_arg_vararg(LV2_OSC_Reader *reader, const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + + const bool res = lv2_osc_reader_arg_varlist(reader, fmt, args); + + va_end(args); + + return res; +} + +static inline bool +lv2_osc_reader_is_bundle(LV2_OSC_Reader *reader) +{ + return strncmp((const char *)reader->ptr, "#bundle", 8) == 0; +} + +static inline bool +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 char *pattern = strpbrk(from, "*?[]{}/"); + const bool has_pattern = pattern && (pattern[0] != '/'); + (void)has_pattern; //FIXME + + 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 + +#endif // LV2_OSC_READER_H diff --git a/osc.lv2/osc.lv2/stream.h b/osc.lv2/osc.lv2/stream.h new file mode 100644 index 0000000..47d338a --- /dev/null +++ b/osc.lv2/osc.lv2/stream.h @@ -0,0 +1,1433 @@ +/* + * Copyright (c) 2015-2016 Hanspeter Portner (dev@open-music-kontrollers.ch) + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the Artistic License 2.0 as published by + * The Perl Foundation. + * + * This source is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Artistic License 2.0 for more details. + * + * You should have received a copy of the Artistic License 2.0 + * along the source as a COPYING file. If not, obtain it from + * http://www.perlfoundation.org/artistic_license_2_0. + */ + +#ifndef LV2_OSC_STREAM_H +#define LV2_OSC_STREAM_H + +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> +#if !defined(_WIN32) +# include <arpa/inet.h> +# include <sys/socket.h> +# include <net/if.h> +# include <netinet/tcp.h> +# include <netinet/in.h> +# include <netdb.h> +# include <termios.h> +# include <limits.h> +#endif +#include <sys/types.h> +#include <fcntl.h> +#include <errno.h> +#include <unistd.h> +#include <poll.h> + +#include <osc.lv2/osc.h> + +#if !defined(LV2_OSC_STREAM_SNDBUF) +# define LV2_OSC_STREAM_SNDBUF 0x100000 // 1 M +#endif + +#if !defined(LV2_OSC_STREAM_RCVBUF) +# define LV2_OSC_STREAM_RCVBUF 0x100000 // 1 M +#endif + +#if !defined(LV2_OSC_STREAM_REQBUF) +# define LV2_OSC_STREAM_REQBUF 1024 +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void * +(*LV2_OSC_Stream_Write_Request)(void *data, size_t minimum, size_t *maximum); + +typedef void +(*LV2_OSC_Stream_Write_Advance)(void *data, size_t written); + +typedef const void * +(*LV2_OSC_Stream_Read_Request)(void *data, size_t *toread); + +typedef void +(*LV2_OSC_Stream_Read_Advance)(void *data); + +typedef struct _LV2_OSC_Address LV2_OSC_Address; +typedef struct _LV2_OSC_Driver LV2_OSC_Driver; +typedef struct _LV2_OSC_Stream LV2_OSC_Stream; + +struct _LV2_OSC_Address { + socklen_t len; + union { + struct sockaddr_in in4; + struct sockaddr_in6 in6; + }; +}; + +struct _LV2_OSC_Driver { + LV2_OSC_Stream_Write_Request write_req; + LV2_OSC_Stream_Write_Advance write_adv; + LV2_OSC_Stream_Read_Request read_req; + LV2_OSC_Stream_Read_Advance read_adv; +}; + +struct _LV2_OSC_Stream { + int socket_family; + int socket_type; + int protocol; + bool server; + bool slip; + bool serial; + bool connected; + int sock; + int fd; + LV2_OSC_Address self; + LV2_OSC_Address peer; + const LV2_OSC_Driver *driv; + void *data; + uint8_t tx_buf [0x4000]; + uint8_t rx_buf [0x4000]; + size_t rx_off; + char url [PATH_MAX]; +}; + +typedef enum _LV2_OSC_Enum { + LV2_OSC_NONE = 0x000000, + + LV2_OSC_SEND = 0x800000, + LV2_OSC_RECV = 0x400000, + LV2_OSC_CONN = 0x200000, + + LV2_OSC_ERR = 0x00ffff +} LV2_OSC_Enum; + +static const char *udp_prefix = "osc.udp://"; +static const char *tcp_prefix = "osc.tcp://"; +static const char *tcp_slip_prefix = "osc.slip.tcp://"; +static const char *tcp_prefix_prefix = "osc.prefix.tcp://"; +static const char *ser_prefix = "osc.serial://"; +//FIXME serial + + +static int +_lv2_osc_stream_interface_attribs(int fd, int speed) +{ + struct termios tty; + + if(tcgetattr(fd, &tty) < 0) + { + return -1; + } + + cfsetospeed(&tty, (speed_t)speed); + cfsetispeed(&tty, (speed_t)speed); + + tty.c_cflag |= (CLOCAL | CREAD); /* ignore modem controls */ + tty.c_cflag &= ~CSIZE; + tty.c_cflag |= CS8; /* 8-bit characters */ + tty.c_cflag &= ~PARENB; /* no parity bit */ + tty.c_cflag &= ~CSTOPB; /* only need 1 stop bit */ + tty.c_cflag &= ~CRTSCTS; /* no hardware flowcontrol */ + + /* setup for non-canonical mode */ + tty.c_iflag &= ~(IGNCR | ONLCR | IXON); + tty.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); + tty.c_oflag &= ~OPOST; + + /* fetch bytes as they become available */ + tty.c_cc[VMIN] = 0; + tty.c_cc[VTIME] = 0; + + if(tcsetattr(fd, TCSANOW, &tty) != 0) + { + return -1; + } + + return 0; +} + +#define LV2_OSC_STREAM_ERRNO(EV, ERRNO) ( (EV & (~LV2_OSC_ERR)) | (ERRNO) ) + +static void +_close_socket(int *fd) +{ + if(fd) + { + if(*fd >= 0) + { + close(*fd); + } + + *fd = -1; + } +} + +static int +lv2_osc_stream_deinit(LV2_OSC_Stream *stream) +{ + _close_socket(&stream->fd); + _close_socket(&stream->sock); + + return 0; +} + +static int +_lv2_osc_stream_reinit(LV2_OSC_Stream *stream) +{ + LV2_OSC_Enum ev = LV2_OSC_NONE; + lv2_osc_stream_deinit(stream); + + char *dup = strdup(stream->url); + if(!dup) + { + ev = LV2_OSC_STREAM_ERRNO(ev, ENOMEM); + goto fail; + } + + char *ptr = dup; + char *tmp; + + if(strncmp(ptr, udp_prefix, strlen(udp_prefix)) == 0) + { + stream->slip = false; + stream->socket_family = AF_INET; + stream->socket_type = SOCK_DGRAM; + stream->protocol = IPPROTO_UDP; + ptr += strlen(udp_prefix); + } + else if(strncmp(ptr, tcp_prefix, strlen(tcp_prefix)) == 0) + { + stream->slip = true; + stream->socket_family = AF_INET; + stream->socket_type = SOCK_STREAM; + stream->protocol = IPPROTO_TCP; + ptr += strlen(tcp_prefix); + } + else if(strncmp(ptr, tcp_slip_prefix, strlen(tcp_slip_prefix)) == 0) + { + stream->slip = true; + stream->socket_family = AF_INET; + stream->socket_type = SOCK_STREAM; + stream->protocol = IPPROTO_TCP; + ptr += strlen(tcp_slip_prefix); + } + else if(strncmp(ptr, tcp_prefix_prefix, strlen(tcp_prefix_prefix)) == 0) + { + stream->slip = false; + stream->socket_family = AF_INET; + stream->socket_type = SOCK_STREAM; + stream->protocol = IPPROTO_TCP; + ptr += strlen(tcp_prefix_prefix); + } + else if(strncmp(ptr, ser_prefix, strlen(ser_prefix)) == 0) + { + stream->slip = true; + stream->serial = true; + ptr += strlen(ser_prefix); + } + else + { + ev = LV2_OSC_STREAM_ERRNO(ev, ENOPROTOOPT); + goto fail; + } + + if(ptr[0] == '\0') + { + ev = LV2_OSC_STREAM_ERRNO(ev, EDESTADDRREQ); + goto fail; + } + + if(stream->serial) + { + stream->sock = open(ptr, O_RDWR | O_NOCTTY | O_NDELAY); + if(stream->sock < 0) + { + ev = LV2_OSC_STREAM_ERRNO(ev, errno); + goto fail; + } + + if(fcntl(stream->sock, F_SETFL, FNDELAY) == -1) //FIXME + { + ev = LV2_OSC_STREAM_ERRNO(ev, errno); + goto fail; + } + + if(_lv2_osc_stream_interface_attribs(stream->sock, B115200) == -1) + { + ev = LV2_OSC_STREAM_ERRNO(ev, errno); + goto fail; + } + + stream->connected = true; + } + else // !stream->serial + { + const char *node = NULL; + const char *iface = NULL; + const char *service = NULL; + + // optional IPv6 + if(ptr[0] == '[') + { + stream->socket_family = AF_INET6; + ++ptr; + } + + node = ptr; + + // optional IPv6 + if( (tmp = strchr(ptr, '%')) ) + { + if(stream->socket_family != AF_INET6) + { + ev = LV2_OSC_STREAM_ERRNO(ev, EPROTOTYPE); + goto fail; + } + + ptr = tmp; + ptr[0] = '\0'; + iface = ++ptr; + } + + // optional IPv6 + if( (tmp = strchr(ptr, ']')) ) + if(ptr) + { + if(stream->socket_family != AF_INET6) + { + ev = LV2_OSC_STREAM_ERRNO(ev, EDESTADDRREQ); + goto fail; + } + + ptr = tmp; + ptr[0] = '\0'; + ++ptr; + } + + // mandatory IPv4/6 + ptr = strchr(ptr, ':'); + if(!ptr) + { + ev = LV2_OSC_STREAM_ERRNO(ev, EDESTADDRREQ); + goto fail; + } + + ptr[0] = '\0'; + + service = ++ptr; + + if(strlen(node) == 0) + { + node = NULL; + stream->server = true; + } + + stream->sock = socket(stream->socket_family, stream->socket_type, + stream->protocol); + + if(stream->sock < 0) + { + ev = LV2_OSC_STREAM_ERRNO(ev, errno); + goto fail; + } + + if(fcntl(stream->sock, F_SETFL, O_NONBLOCK) == -1) + { + ev = LV2_OSC_STREAM_ERRNO(ev, errno); + goto fail; + } + + const int sendbuff = LV2_OSC_STREAM_SNDBUF; + const int recvbuff = LV2_OSC_STREAM_RCVBUF; + const int reuseaddr = 1; + + if(setsockopt(stream->sock, SOL_SOCKET, + SO_SNDBUF, &sendbuff, sizeof(sendbuff)) == -1) + { + ev = LV2_OSC_STREAM_ERRNO(ev, errno); + goto fail; + } + + if(setsockopt(stream->sock, SOL_SOCKET, + SO_RCVBUF, &recvbuff, sizeof(recvbuff)) == -1) + { + ev = LV2_OSC_STREAM_ERRNO(ev, errno); + goto fail; + } + + if(setsockopt(stream->sock, SOL_SOCKET, + SO_REUSEADDR, &reuseaddr, sizeof(reuseaddr)) == -1) + { + ev = LV2_OSC_STREAM_ERRNO(ev, errno); + goto fail; + } + + if(stream->socket_family == AF_INET) // IPv4 + { + if(stream->server) + { + // resolve self address + struct addrinfo hints; + memset(&hints, 0x0, sizeof(struct addrinfo)); + hints.ai_family = stream->socket_family; + hints.ai_socktype = stream->socket_type; + hints.ai_protocol = stream->protocol; + + struct addrinfo *res; + if(getaddrinfo(node, service, &hints, &res) != 0) + { + ev = LV2_OSC_STREAM_ERRNO(ev, errno); + goto fail; + } + if(res->ai_addrlen != sizeof(stream->peer.in4)) + { + ev = LV2_OSC_STREAM_ERRNO(ev, EPROTOTYPE); + goto fail; + } + + stream->self.len = res->ai_addrlen; + memcpy(&stream->self.in4, res->ai_addr, res->ai_addrlen); + stream->self.in4.sin_addr.s_addr = htonl(INADDR_ANY); + + freeaddrinfo(res); + + if(bind(stream->sock, (struct sockaddr *)&stream->self.in4, + stream->self.len) != 0) + { + ev = LV2_OSC_STREAM_ERRNO(ev, errno); + goto fail; + } + } + else // client + { + stream->self.len = sizeof(stream->self.in4); + stream->self.in4.sin_family = stream->socket_family; + stream->self.in4.sin_port = htons(0); + stream->self.in4.sin_addr.s_addr = htonl(INADDR_ANY); + + if(bind(stream->sock, (struct sockaddr *)&stream->self.in4, + stream->self.len) != 0) + { + ev = LV2_OSC_STREAM_ERRNO(ev, errno); + goto fail; + } + + // resolve peer address + struct addrinfo hints; + memset(&hints, 0x0, sizeof(struct addrinfo)); + hints.ai_family = stream->socket_family; + hints.ai_socktype = stream->socket_type; + hints.ai_protocol = stream->protocol; + + struct addrinfo *res; + if(getaddrinfo(node, service, &hints, &res) != 0) + { + ev = LV2_OSC_STREAM_ERRNO(ev, errno); + goto fail; + } + if(res->ai_addrlen != sizeof(stream->peer.in4)) + { + ev = LV2_OSC_STREAM_ERRNO(ev, EPROTOTYPE); + goto fail; + } + + stream->peer.len = res->ai_addrlen; + memcpy(&stream->peer.in4, res->ai_addr, res->ai_addrlen); + + freeaddrinfo(res); + } + + if(stream->socket_type == SOCK_DGRAM) + { + const int broadcast = 1; + + if(setsockopt(stream->sock, SOL_SOCKET, SO_BROADCAST, + &broadcast, sizeof(broadcast)) != 0) + { + ev = LV2_OSC_STREAM_ERRNO(ev, errno); + goto fail; + } + + //FIXME handle multicast + } + else if(stream->socket_type == SOCK_STREAM) + { + const int flag = 1; + + if(setsockopt(stream->sock, stream->protocol, + TCP_NODELAY, &flag, sizeof(flag)) != 0) + { + ev = LV2_OSC_STREAM_ERRNO(ev, errno); + goto fail; + } + + if(setsockopt(stream->sock, SOL_SOCKET, + SO_KEEPALIVE, &flag, sizeof(flag)) != 0) + { + ev = LV2_OSC_STREAM_ERRNO(ev, errno); + goto fail; + } + + if(stream->server) + { + if(listen(stream->sock, 1) != 0) + { + ev = LV2_OSC_STREAM_ERRNO(ev, errno); + goto fail; + } + } + else // client + { + if(connect(stream->sock, (struct sockaddr *)&stream->peer.in4, + stream->peer.len) == 0) + { + stream->connected = true; + } + } + } + else + { + ev = LV2_OSC_STREAM_ERRNO(ev, EPROTOTYPE); + goto fail; + } + } + else if(stream->socket_family == AF_INET6) // IPv6 + { + if(stream->server) + { + // resolve self address + struct addrinfo hints; + memset(&hints, 0x0, sizeof(struct addrinfo)); + hints.ai_family = stream->socket_family; + hints.ai_socktype = stream->socket_type; + hints.ai_protocol = stream->protocol; + + struct addrinfo *res; + if(getaddrinfo(node, service, &hints, &res) != 0) + { + ev = LV2_OSC_STREAM_ERRNO(ev, errno); + goto fail; + } + if(res->ai_addrlen != sizeof(stream->peer.in6)) + { + ev = LV2_OSC_STREAM_ERRNO(ev, EPROTOTYPE); + goto fail; + } + + stream->self.len = res->ai_addrlen; + memcpy(&stream->self.in6, res->ai_addr, res->ai_addrlen); + stream->self.in6.sin6_addr = in6addr_any; + if(iface) + { + stream->self.in6.sin6_scope_id = if_nametoindex(iface); + } + + freeaddrinfo(res); + + if(bind(stream->sock, (struct sockaddr *)&stream->self.in6, + stream->self.len) != 0) + { + ev = LV2_OSC_STREAM_ERRNO(ev, errno); + goto fail; + } + } + else // client + { + stream->self.len = sizeof(stream->self.in6); + stream->self.in6.sin6_family = stream->socket_family; + stream->self.in6.sin6_port = htons(0); + stream->self.in6.sin6_addr = in6addr_any; + if(iface) + { + stream->self.in6.sin6_scope_id = if_nametoindex(iface); + } + + if(bind(stream->sock, (struct sockaddr *)&stream->self.in6, + stream->self.len) != 0) + { + ev = LV2_OSC_STREAM_ERRNO(ev, errno); + goto fail; + } + + // resolve peer address + struct addrinfo hints; + memset(&hints, 0x0, sizeof(struct addrinfo)); + hints.ai_family = stream->socket_family; + hints.ai_socktype = stream->socket_type; + hints.ai_protocol = stream->protocol; + + struct addrinfo *res; + if(getaddrinfo(node, service, &hints, &res) != 0) + { + ev = LV2_OSC_STREAM_ERRNO(ev, errno); + goto fail; + } + if(res->ai_addrlen != sizeof(stream->peer.in6)) + { + ev = LV2_OSC_STREAM_ERRNO(ev, EPROTOTYPE); + goto fail; + } + + stream->peer.len = res->ai_addrlen; + memcpy(&stream->peer.in6, res->ai_addr, res->ai_addrlen); + + if(iface) + { + stream->peer.in6.sin6_scope_id = if_nametoindex(iface); + } + + freeaddrinfo(res); + } + + if(stream->socket_type == SOCK_DGRAM) + { + // nothing to do + } + else if(stream->socket_type == SOCK_STREAM) + { + const int flag = 1; + + if(setsockopt(stream->sock, stream->protocol, + TCP_NODELAY, &flag, sizeof(flag)) != 0) + { + ev = LV2_OSC_STREAM_ERRNO(ev, errno); + goto fail; + } + + if(setsockopt(stream->sock, SOL_SOCKET, + SO_KEEPALIVE, &flag, sizeof(flag)) != 0) + { + ev = LV2_OSC_STREAM_ERRNO(ev, errno); + goto fail; + } + + if(stream->server) + { + if(listen(stream->sock, 1) != 0) + { + ev = LV2_OSC_STREAM_ERRNO(ev, errno); + goto fail; + } + } + else // client + { + if(connect(stream->sock, (struct sockaddr *)&stream->peer.in6, + stream->peer.len) == 0) + { + stream->connected = true; + } + } + } + else + { + ev = LV2_OSC_STREAM_ERRNO(ev, EPROTOTYPE); + goto fail; + } + } + else + { + ev = LV2_OSC_STREAM_ERRNO(ev, EPROTOTYPE); + goto fail; + } + } + + free(dup); + + return ev; + +fail: + if(dup) + { + free(dup); + } + + _close_socket(&stream->sock); + + return ev; +} + +static int +lv2_osc_stream_init(LV2_OSC_Stream *stream, const char *url, + const LV2_OSC_Driver *driv, void *data) +{ + memset(stream, 0x0, sizeof(LV2_OSC_Stream)); + + strncpy(stream->url, url, sizeof(stream->url) - 1); + stream->driv = driv; + stream->data = data; + stream->sock = -1; + stream->fd = -1; + + return _lv2_osc_stream_reinit(stream); +} + +#define SLIP_END 0300 // 0xC0, 192, indicates end of packet +#define SLIP_ESC 0333 // 0xDB, 219, indicates byte stuffing +#define SLIP_END_REPLACE 0334 // 0xDC, 220, ESC ESC_END means END data byte +#define SLIP_ESC_REPLACE 0335 // 0xDD, 221, ESC ESC_ESC means ESC data byte + +// SLIP encoding +static size_t +lv2_osc_slip_encode_inline(uint8_t *dst, size_t len) +{ + if(len == 0) + return 0; + + const uint8_t *end = dst + len; + + // estimate new size + size_t size = 2; // double ended SLIP + for(const uint8_t *from=dst; from<end; from++, size++) + { + if( (*from == SLIP_END) || (*from == SLIP_ESC)) + size ++; + } + + // fast track if no escaping needed + if(size == len + 2) + { + memmove(dst+1, dst, len); + dst[0] = SLIP_END; + dst[size-1] = SLIP_END; + + return size; + } + + // slow track if some escaping needed + uint8_t *to = dst + size - 1; + *to-- = SLIP_END; + for(const uint8_t *from=end-1; from>=dst; from--) + { + if(*from == SLIP_END) + { + *to-- = SLIP_END_REPLACE; + *to-- = SLIP_ESC; + } + else if(*from == SLIP_ESC) + { + *to-- = SLIP_ESC_REPLACE; + *to-- = SLIP_ESC; + } + else + *to-- = *from; + } + *to-- = SLIP_END; + + return size; +} + +// SLIP decoding +static size_t +lv2_osc_slip_decode_inline(uint8_t *dst, size_t len, size_t *size) +{ + const uint8_t *src = dst; + const uint8_t *end = dst + len; + uint8_t *ptr = dst; + + bool whole = false; + + if( (src < end) && (*src == SLIP_END) ) + { + whole = true; + src++; + } + + while(src < end) + { + if(*src == SLIP_ESC) + { + if(src == end-1) + break; + + src++; + if(*src == SLIP_END_REPLACE) + *ptr++ = SLIP_END; + else if(*src == SLIP_ESC_REPLACE) + *ptr++ = SLIP_ESC; + src++; + } + else if(*src == SLIP_END) + { + src++; + + *size = whole ? ptr - dst : 0; + return src - dst; + } + else + { + *ptr++ = *src++; + } + } + + *size = 0; + return 0; +} + +static LV2_OSC_Enum +_lv2_osc_stream_run_udp(LV2_OSC_Stream *stream) +{ + LV2_OSC_Enum ev = LV2_OSC_NONE; + + // send everything + if(stream->peer.len) // has a peer + { + const uint8_t *buf; + size_t tosend; + + while( (buf = stream->driv->read_req(stream->data, &tosend)) ) + { + const ssize_t sent = sendto(stream->sock, buf, tosend, 0, + (struct sockaddr *)&stream->peer.in6, stream->peer.len); + + if(sent == -1) + { + if( (errno == EAGAIN) || (errno == EWOULDBLOCK) ) + { + // full queue + break; + } + + ev = LV2_OSC_STREAM_ERRNO(ev, errno); + break; + } + else if(sent != (ssize_t)tosend) + { + ev = LV2_OSC_STREAM_ERRNO(ev, EIO); + break; + } + + stream->driv->read_adv(stream->data); + ev |= LV2_OSC_SEND; + } + } + + // recv everything + { + uint8_t *buf; + size_t max_len; + + while( (buf = stream->driv->write_req(stream->data, + LV2_OSC_STREAM_REQBUF, &max_len)) ) + { + struct sockaddr_in6 in; + socklen_t in_len = sizeof(in); + + memset(&in, 0, in_len); + const ssize_t recvd = recvfrom(stream->sock, buf, max_len, 0, + (struct sockaddr *)&in, &in_len); + + if(recvd == -1) + { + if( (errno == EAGAIN) || (errno == EWOULDBLOCK) ) + { + // empty queue + break; + } + + ev = LV2_OSC_STREAM_ERRNO(ev, errno); + break; + } + else if(recvd == 0) + { + // peer has shut down + break; + } + + stream->peer.len = in_len; + memcpy(&stream->peer.in6, &in, in_len); + + stream->driv->write_adv(stream->data, recvd); + ev |= LV2_OSC_RECV; + } + } + + return ev; +} + +static LV2_OSC_Enum +_lv2_osc_stream_run_tcp(LV2_OSC_Stream *stream) +{ + LV2_OSC_Enum ev = LV2_OSC_NONE; + + // handle connections + if(!stream->connected) // no peer + { + if(stream->server) + { + stream->peer.len = sizeof(stream->peer.in6); + stream->fd = accept(stream->sock, (struct sockaddr *)&stream->peer.in6, + &stream->peer.len); + + if(stream->fd >= 0) + { + const int flag = 1; + const int sendbuff = LV2_OSC_STREAM_SNDBUF; + const int recvbuff = LV2_OSC_STREAM_RCVBUF; + + if(fcntl(stream->fd, F_SETFL, O_NONBLOCK) == -1) + { + ev = LV2_OSC_STREAM_ERRNO(ev, errno); + } + + if(setsockopt(stream->fd, stream->protocol, + TCP_NODELAY, &flag, sizeof(flag)) != 0) + { + ev = LV2_OSC_STREAM_ERRNO(ev, errno); + } + + if(setsockopt(stream->sock, SOL_SOCKET, + SO_KEEPALIVE, &flag, sizeof(flag)) != 0) + { + ev = LV2_OSC_STREAM_ERRNO(ev, errno); + } + + if(setsockopt(stream->fd, SOL_SOCKET, + SO_SNDBUF, &sendbuff, sizeof(sendbuff)) == -1) + { + ev = LV2_OSC_STREAM_ERRNO(ev, errno); + } + + if(setsockopt(stream->fd, SOL_SOCKET, + SO_RCVBUF, &recvbuff, sizeof(recvbuff)) == -1) + { + ev = LV2_OSC_STREAM_ERRNO(ev, errno); + } + + stream->connected = true; // orderly accept + } + else + { + //ev = LV2_OSC_STREAM_ERRNO(ev, errno); + } + } + else + { + if(stream->sock < 0) + { + ev = _lv2_osc_stream_reinit(stream); + } + + if(connect(stream->sock, (struct sockaddr *)&stream->peer.in6, + stream->peer.len) == 0) + { + stream->connected = true; // orderly (re)connect + } + else + { + //if(errno == EISCONN) + //{ + // _close_socket(&stream->sock); + //} + + //ev = LV2_OSC_STREAM_ERRNO(ev, errno); + } + } + } + + // send everything + if(stream->connected) + { + int *fd = stream->server + ? &stream->fd + : &stream->sock; + + if(*fd >= 0) + { + const uint8_t *buf; + size_t tosend; + + while( (buf = stream->driv->read_req(stream->data, &tosend)) ) + { + if(stream->slip) // SLIP framed + { + if(tosend <= sizeof(stream->tx_buf)) // check if there is enough memory + { + memcpy(stream->tx_buf, buf, tosend); + tosend = lv2_osc_slip_encode_inline(stream->tx_buf, tosend); + } + else + { + tosend = 0; + } + } + else // uint32_t prefix frames + { + const size_t nsize = tosend + sizeof(uint32_t); + + if(nsize <= sizeof(stream->tx_buf)) // check if there is enough memory + { + const uint32_t prefix = htonl(tosend); + + memcpy(stream->tx_buf, &prefix, sizeof(uint32_t)); + memcpy(stream->tx_buf + sizeof(uint32_t), buf, tosend); + tosend = nsize; + } + else + { + tosend = 0; + } + } + + const ssize_t sent = tosend + ? send(*fd, stream->tx_buf, tosend, 0) + : 0; + + if(sent == -1) + { + if( (errno == EAGAIN) || (errno == EWOULDBLOCK) ) + { + // empty queue + break; + } + + _close_socket(fd); + stream->connected = false; + ev = LV2_OSC_STREAM_ERRNO(ev, errno); + break; + } + else if(sent != (ssize_t)tosend) + { + ev = LV2_OSC_STREAM_ERRNO(ev, EIO); + break; + } + + stream->driv->read_adv(stream->data); + ev |= LV2_OSC_SEND; + } + } + } + + // recv everything + if(stream->connected) + { + int *fd = stream->server + ? &stream->fd + : &stream->sock; + + if(*fd >= 0) + { + if(stream->slip) // SLIP framed + { + while(true) + { + ssize_t recvd = recv(*fd, stream->rx_buf + stream->rx_off, + sizeof(stream->rx_buf) - stream->rx_off, 0); + + if(recvd == -1) + { + if( (errno == EAGAIN) || (errno == EWOULDBLOCK) ) + { + // empty queue + break; + } + + _close_socket(fd); + stream->connected = false; + ev = LV2_OSC_STREAM_ERRNO(ev, errno); + break; + } + else if(recvd == 0) + { + _close_socket(fd); + stream->connected = false; // orderly shutdown + break; + } + + uint8_t *ptr = stream->rx_buf; + recvd += stream->rx_off; + + while(recvd > 0) + { + size_t size; + size_t parsed = lv2_osc_slip_decode_inline(ptr, recvd, &size); + + if(size) // dispatch + { + uint8_t *buf; + + if( (buf = stream->driv->write_req(stream->data, size, NULL)) ) + { + memcpy(buf, ptr, size); + + stream->driv->write_adv(stream->data, size); + ev |= LV2_OSC_RECV; + } + else + { + parsed = 0; + ev = LV2_OSC_STREAM_ERRNO(ev, ENOMEM); + } + } + + if(parsed) + { + ptr += parsed; + recvd -= parsed; + } + else + { + break; + } + } + + if(recvd > 0) // is there remaining chunk for next call? + { + memmove(stream->rx_buf, ptr, recvd); + stream->rx_off = recvd; + } + else + { + stream->rx_off = 0; + } + + break; + } + } + else // uint32_t prefix frames + { + uint8_t *buf; + + while( (buf = stream->driv->write_req(stream->data, + LV2_OSC_STREAM_REQBUF, NULL)) ) + { + uint32_t prefix; + + ssize_t recvd = recv(*fd, &prefix, sizeof(uint32_t), 0); + if(recvd == sizeof(uint32_t)) + { + prefix = ntohl(prefix); //FIXME check prefix <= max_len + recvd = recv(*fd, buf, prefix, 0); + } + else if(recvd == -1) + { + if( (errno == EAGAIN) || (errno == EWOULDBLOCK) ) + { + // empty queue + break; + } + + _close_socket(fd); + stream->connected = false; + ev = LV2_OSC_STREAM_ERRNO(ev, errno); + break; + } + else if(recvd == 0) + { + _close_socket(fd); + stream->connected = false; // orderly shutdown + break; + } + + stream->driv->write_adv(stream->data, recvd); + ev |= LV2_OSC_RECV; + } + } + } + } + + if(stream->connected) + { + ev |= LV2_OSC_CONN; + } + + return ev; +} + +static LV2_OSC_Enum +_lv2_osc_stream_run_ser(LV2_OSC_Stream *stream) +{ + LV2_OSC_Enum ev = LV2_OSC_NONE; + + // send everything + { + const int fd = stream->sock; + + if(fd >= 0) + { + const uint8_t *buf; + size_t tosend; + + while( (buf = stream->driv->read_req(stream->data, &tosend)) ) + { + if(stream->slip) // SLIP framed + { + if(tosend <= sizeof(stream->tx_buf)) // check if there is enough memory + { + memcpy(stream->tx_buf, buf, tosend); + tosend = lv2_osc_slip_encode_inline(stream->tx_buf, tosend); + } + else + { + tosend = 0; + } + } + else // uint32_t prefix frames + { + const size_t nsize = tosend + sizeof(uint32_t); + + if(nsize <= sizeof(stream->tx_buf)) // check if there is enough memory + { + const uint32_t prefix = htonl(tosend); + + memcpy(stream->tx_buf, &prefix, sizeof(uint32_t)); + memcpy(stream->tx_buf + sizeof(uint32_t), buf, tosend); + tosend = nsize; + } + else + { + tosend = 0; + } + } + + const ssize_t sent = tosend + ? write(fd, stream->tx_buf, tosend) + : 0; + + if(sent == -1) + { + if( (errno == EAGAIN) || (errno == EWOULDBLOCK) ) + { + // empty queue + break; + } + + ev = LV2_OSC_STREAM_ERRNO(ev, errno); + break; + } + else if(sent != (ssize_t)tosend) + { + ev = LV2_OSC_STREAM_ERRNO(ev, EIO); + break; + } + + stream->driv->read_adv(stream->data); + ev |= LV2_OSC_SEND; + } + } + } + + // recv everything + { + const int fd = stream->sock; + + if(fd >= 0) + { + if(stream->slip) // SLIP framed + { + while(true) + { + ssize_t recvd = read(fd, stream->rx_buf + stream->rx_off, + sizeof(stream->rx_buf) - stream->rx_off); + + if(recvd == -1) + { + if( (errno == EAGAIN) || (errno == EWOULDBLOCK) ) + { + // empty queue + break; + } + + stream->connected = false; + ev = LV2_OSC_STREAM_ERRNO(ev, errno); + break; + } + else if(recvd == 0) + { + // orderly shutdown + break; + } + + uint8_t *ptr = stream->rx_buf; + recvd += stream->rx_off; + + while(recvd > 0) + { + size_t size; + size_t parsed = lv2_osc_slip_decode_inline(ptr, recvd, &size); + + if(size) // dispatch + { + uint8_t *buf; + + if( (buf = stream->driv->write_req(stream->data, size, NULL)) ) + { + memcpy(buf, ptr, size); + + stream->driv->write_adv(stream->data, size); + ev |= LV2_OSC_RECV; + } + else + { + parsed = 0; + ev = LV2_OSC_STREAM_ERRNO(ev, ENOMEM); + } + } + + if(parsed) + { + ptr += parsed; + recvd -= parsed; + } + else + { + break; + } + } + + if(recvd > 0) // is there remaining chunk for next call? + { + memmove(stream->rx_buf, ptr, recvd); + stream->rx_off = recvd; + } + else + { + stream->rx_off = 0; + } + + break; + } + } + else // uint32_t prefix frames + { + uint8_t *buf; + + while( (buf = stream->driv->write_req(stream->data, + LV2_OSC_STREAM_REQBUF, NULL)) ) + { + uint32_t prefix; + + ssize_t recvd = read(fd, &prefix, sizeof(uint32_t)); + if(recvd == sizeof(uint32_t)) + { + prefix = ntohl(prefix); //FIXME check prefix <= max_len + recvd = read(fd, buf, prefix); + } + else if(recvd == -1) + { + if( (errno == EAGAIN) || (errno == EWOULDBLOCK) ) + { + // empty queue + break; + } + + stream->connected = false; + ev = LV2_OSC_STREAM_ERRNO(ev, errno); + break; + } + else if(recvd == 0) + { + // orderly shutdown + break; + } + + stream->driv->write_adv(stream->data, recvd); + ev |= LV2_OSC_RECV; + } + } + } + } + + if(stream->connected) + { + ev |= LV2_OSC_CONN; + } + + return ev; +} + +static LV2_OSC_Enum +lv2_osc_stream_run(LV2_OSC_Stream *stream) +{ + LV2_OSC_Enum ev = LV2_OSC_NONE; + + switch(stream->socket_type) + { + case SOCK_DGRAM: + { + ev |= _lv2_osc_stream_run_udp(stream); + } break; + case SOCK_STREAM: + { + ev |= _lv2_osc_stream_run_tcp(stream); + } break; + default: + { + ev |= _lv2_osc_stream_run_ser(stream); + } break; + } + + return ev; +} + +static int +lv2_osc_stream_get_file_descriptors(LV2_OSC_Stream *stream, int fds [2]) +{ + if(!fds) + { + return 1; + } + + fds[0] = stream->sock; + fds[1] = stream->fd; + + return 0; +} + +static LV2_OSC_Enum +lv2_osc_stream_pollin(LV2_OSC_Stream *stream, int timeout_ms) +{ + int fd [2]; + + if(lv2_osc_stream_get_file_descriptors(stream, fd) != 0) + { + return LV2_OSC_STREAM_ERRNO(LV2_OSC_NONE, EBADF); + } + + struct pollfd fds [2] = { + [0] = { + .fd = fd[0], + .events = POLLIN, + .revents = 0 + }, + [1] = { + .fd = fd[1], + .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 + +#endif // LV2_OSC_STREAM_H diff --git a/osc.lv2/osc.lv2/util.h b/osc.lv2/osc.lv2/util.h new file mode 100644 index 0000000..3517618 --- /dev/null +++ b/osc.lv2/osc.lv2/util.h @@ -0,0 +1,631 @@ +/* + * Copyright (c) 2015-2016 Hanspeter Portner (dev@open-music-kontrollers.ch) + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the Artistic License 2.0 as published by + * The Perl Foundation. + * + * This source is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Artistic License 2.0 for more details. + * + * You should have received a copy of the Artistic License 2.0 + * along the source as a COPYING file. If not, obtain it from + * http://www.perlfoundation.org/artistic_license_2_0. + */ + +#ifndef LV2_OSC_UTIL_H +#define LV2_OSC_UTIL_H + +#include <assert.h> +#include <ctype.h> +#include <inttypes.h> +#include <stdio.h> +#include <stdlib.h> +#if !defined(_WIN32) +# include <fnmatch.h> +#endif + +#include <osc.lv2/osc.h> + +#include <lv2/lv2plug.in/ns/ext/atom/util.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __unused +# define __unused __attribute__((unused)) +#endif + +#undef LV2_ATOM_TUPLE_FOREACH // there is a bug in LV2 1.10.0 +#define LV2_ATOM_TUPLE_FOREACH(tuple, iter) \ + for (LV2_Atom* (iter) = lv2_atom_tuple_begin(tuple); \ + !lv2_atom_tuple_is_end(LV2_ATOM_BODY(tuple), (tuple)->atom.size, (iter)); \ + (iter) = lv2_atom_tuple_next(iter)) + +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 [] = { + ' ', '#', + '\0' +}; + +// allowed characters in OSC format string +static const char valid_format_chars [] = { + LV2_OSC_INT32, LV2_OSC_FLOAT, LV2_OSC_STRING, LV2_OSC_BLOB, + LV2_OSC_TRUE, LV2_OSC_FALSE, LV2_OSC_NIL, LV2_OSC_IMPULSE, + LV2_OSC_INT64, LV2_OSC_DOUBLE, LV2_OSC_TIMETAG, + LV2_OSC_SYMBOL, LV2_OSC_MIDI, + '\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 +*/ +static inline bool +lv2_osc_check_path(const char *path) +{ + assert(path); + + if(path[0] != '/') + return false; + + for(const char *ptr=path+1; *ptr!='\0'; ptr++) + if( (isprint(*ptr) == 0) || (strchr(invalid_path_chars, *ptr) != NULL) ) + return false; + + return true; +} + +/** + TODO +*/ +static inline bool +lv2_osc_check_fmt(const char *format, int offset) +{ + assert(format); + + if(offset && (format[0] != ',') ) + return false; + + for(const char *ptr=format+offset; *ptr!='\0'; ptr++) + if(strchr(valid_format_chars, *ptr) == NULL) + return false; + + return true; +} + +/** + TODO +*/ +static inline uint64_t +lv2_osc_timetag_parse(const LV2_OSC_Timetag *timetag) +{ + return ((uint64_t)timetag->integral << 32) | timetag->fraction; +} + +/** + TODO +*/ +static inline LV2_OSC_Timetag * +lv2_osc_timetag_create(LV2_OSC_Timetag *timetag, uint64_t tt) +{ + timetag->integral = tt >> 32; + timetag->fraction = tt & 0xffffffff; + + return timetag; +} + +#define LV2_OSC_TIMETAG_CREATE(tt) \ + lv2_osc_timetag_create(&(LV2_OSC_Timetag){.integral = 0, .fraction = 0}, (tt)) + +/** + TODO +*/ +static inline bool +lv2_osc_is_packet_type(LV2_OSC_URID *osc_urid, LV2_URID type) +{ + return type == osc_urid->OSC_Packet; +} + +/** + TODO +*/ +static inline bool +lv2_osc_is_bundle_type(LV2_OSC_URID *osc_urid, LV2_URID type) +{ + return type == osc_urid->OSC_Bundle; +} + +/** + TODO +*/ +static inline bool +lv2_osc_is_message_type(LV2_OSC_URID *osc_urid, LV2_URID type) +{ + return type == osc_urid->OSC_Message; +} + +/** + TODO +*/ +static inline bool +lv2_osc_is_message_or_bundle_type(LV2_OSC_URID *osc_urid, LV2_URID type) +{ + return lv2_osc_is_message_type(osc_urid, type) + || lv2_osc_is_bundle_type(osc_urid, type); +} + +static inline LV2_OSC_Type +lv2_osc_argument_type(LV2_OSC_URID *osc_urid, const LV2_Atom *atom) +{ + const LV2_Atom_Object *obj = (const LV2_Atom_Object *)atom; + + if(atom->type == osc_urid->ATOM_Int) + return LV2_OSC_INT32; + else if(atom->type == osc_urid->ATOM_Float) + return LV2_OSC_FLOAT; + else if(atom->type == osc_urid->ATOM_String) + return LV2_OSC_STRING; + else if(atom->type == osc_urid->ATOM_Chunk) + return LV2_OSC_BLOB; + + else if(atom->type == osc_urid->ATOM_Long) + return LV2_OSC_INT64; + else if(atom->type == osc_urid->ATOM_Double) + return LV2_OSC_DOUBLE; + else if( (atom->type == osc_urid->ATOM_Object) && (obj->body.otype == osc_urid->OSC_Timetag) ) + return LV2_OSC_TIMETAG; + + else if(atom->type == osc_urid->ATOM_Bool) + { + if(((const LV2_Atom_Bool *)atom)->body) + return LV2_OSC_TRUE; + else + return LV2_OSC_FALSE; + } + else if(atom->type == osc_urid->ATOM_Literal) + { + const LV2_Atom_Literal *lit = (const LV2_Atom_Literal *)atom; + if(lit->body.datatype == osc_urid->OSC_Nil) + return LV2_OSC_NIL; + else if(lit->body.datatype == osc_urid->OSC_Impulse) + return LV2_OSC_IMPULSE; + else if(lit->body.datatype == osc_urid->OSC_Char) + return LV2_OSC_CHAR; + else if(lit->body.datatype == osc_urid->OSC_RGBA) + return LV2_OSC_RGBA; + } + + else if(atom->type == osc_urid->ATOM_URID) + return LV2_OSC_SYMBOL; + else if(atom->type == osc_urid->MIDI_MidiEvent) + return LV2_OSC_MIDI; + + return '\0'; +} + +static inline const LV2_Atom * +lv2_osc_int32_get(LV2_OSC_URID *osc_urid __unused, const LV2_Atom *atom, + int32_t *i) +{ + assert(i); + *i = ((const LV2_Atom_Int *)atom)->body; + + return lv2_atom_tuple_next(atom); +} + +static inline const LV2_Atom * +lv2_osc_float_get(LV2_OSC_URID *osc_urid __unused, const LV2_Atom *atom, + float *f) +{ + assert(f); + *f = ((const LV2_Atom_Float *)atom)->body; + + return lv2_atom_tuple_next(atom); +} + +static inline const LV2_Atom * +lv2_osc_string_get(LV2_OSC_URID *osc_urid __unused, const LV2_Atom *atom, + const char **s) +{ + assert(s); + *s = LV2_ATOM_BODY_CONST(atom); + + return lv2_atom_tuple_next(atom); +} + +static inline const LV2_Atom * +lv2_osc_blob_get(LV2_OSC_URID *osc_urid __unused, const LV2_Atom *atom, + uint32_t *size, const uint8_t **b) +{ + assert(size && b); + *size = atom->size; + *b = LV2_ATOM_BODY_CONST(atom); + + return lv2_atom_tuple_next(atom); +} + +static inline const LV2_Atom * +lv2_osc_int64_get(LV2_OSC_URID *osc_urid __unused, const LV2_Atom *atom, + int64_t *h) +{ + assert(h); + *h = ((const LV2_Atom_Long *)atom)->body; + + return lv2_atom_tuple_next(atom); +} + +static inline const LV2_Atom * +lv2_osc_double_get(LV2_OSC_URID *osc_urid __unused, const LV2_Atom *atom, + double *d) +{ + assert(d); + *d = ((const LV2_Atom_Double *)atom)->body; + + return lv2_atom_tuple_next(atom); +} + +static inline const LV2_Atom * +lv2_osc_timetag_get(LV2_OSC_URID *osc_urid, const LV2_Atom *atom, + LV2_OSC_Timetag *timetag) +{ + assert(timetag); + + const LV2_Atom_Long *integral = NULL; + const LV2_Atom_Long *fraction = NULL; + + lv2_atom_object_get((const LV2_Atom_Object *)atom, + osc_urid->OSC_timetagIntegral, &integral, + osc_urid->OSC_timetagFraction, &fraction, + 0); + + if( integral && (integral->atom.type == osc_urid->ATOM_Long) + && fraction && (fraction->atom.type == osc_urid->ATOM_Long) ) + { + timetag->integral = integral->body; + timetag->fraction = fraction->body; + } + else + { + // set to immediate + timetag->integral = 0; + timetag->fraction = 1; + } + + return lv2_atom_tuple_next(atom); +} + +static inline const LV2_Atom * +lv2_osc_true_get(LV2_OSC_URID *osc_urid __unused, const LV2_Atom *atom) +{ + return lv2_atom_tuple_next(atom); +} + +static inline const LV2_Atom * +lv2_osc_false_get(LV2_OSC_URID *osc_urid __unused, const LV2_Atom *atom) +{ + return lv2_atom_tuple_next(atom); +} + +static inline const LV2_Atom * +lv2_osc_nil_get(LV2_OSC_URID *osc_urid __unused, const LV2_Atom *atom) +{ + return lv2_atom_tuple_next(atom); +} + +static inline const LV2_Atom * +lv2_osc_impulse_get(LV2_OSC_URID *osc_urid __unused, const LV2_Atom *atom) +{ + return lv2_atom_tuple_next(atom); +} + +static inline const LV2_Atom * +lv2_osc_symbol_get(LV2_OSC_URID *osc_urid __unused, const LV2_Atom *atom, + LV2_URID *S) +{ + assert(S); + *S = ((const LV2_Atom_URID *)atom)->body; + + return lv2_atom_tuple_next(atom); +} + +static inline const LV2_Atom * +lv2_osc_midi_get(LV2_OSC_URID *osc_urid __unused, const LV2_Atom *atom, + uint32_t *size, const uint8_t **m) +{ + assert(size && m); + *size = atom->size; + *m = LV2_ATOM_BODY_CONST(atom); + + return lv2_atom_tuple_next(atom); +} + +static inline const LV2_Atom * +lv2_osc_char_get(LV2_OSC_URID *osc_urid __unused, const LV2_Atom *atom, char *c) +{ + assert(c); + const char *str = LV2_ATOM_CONTENTS_CONST(LV2_Atom_Literal, atom); + *c = str[0]; + + return lv2_atom_tuple_next(atom); +} + +static inline const LV2_Atom * +lv2_osc_rgba_get(LV2_OSC_URID *osc_urid __unused, const LV2_Atom *atom, + uint8_t *r, uint8_t *g, uint8_t *b, uint8_t *a) +{ + assert(r && g && b && a); + const char *str = LV2_ATOM_CONTENTS_CONST(LV2_Atom_Literal, atom); + + uint8_t *key [4] = { + r, g, b, a + }; + + const char *pos = str; + char *endptr; + + for(unsigned count = 0; count < 4; count++, pos += 2) + { + char buf [5] = {'0', 'x', pos[0], pos[1], '\0'}; + + *key[count] = strtol(buf, &endptr, 16); + } + + return lv2_atom_tuple_next(atom); +} + +/** + TODO +*/ +static inline bool +lv2_osc_bundle_body_get(LV2_OSC_URID *osc_urid, uint32_t size, const LV2_Atom_Object_Body *body, + const LV2_Atom_Object **timetag, const LV2_Atom_Tuple **items) +{ + assert(timetag && items); + + *timetag = NULL; + *items = NULL; + + lv2_atom_object_body_get(size, body, + osc_urid->OSC_bundleTimetag, timetag, + osc_urid->OSC_bundleItems, items, + 0); + + if(!*timetag || ((*timetag)->atom.type != osc_urid->ATOM_Object) || ((*timetag)->body.otype != osc_urid->OSC_Timetag)) + return false; + if(!*items || ((*items)->atom.type != osc_urid->ATOM_Tuple)) + return false; + + return true; +} + +/** + TODO +*/ +static inline bool +lv2_osc_bundle_get(LV2_OSC_URID *osc_urid, const LV2_Atom_Object *obj, + const LV2_Atom_Object **timetag, const LV2_Atom_Tuple **items) +{ + return lv2_osc_bundle_body_get(osc_urid, obj->atom.size, &obj->body, + timetag, items); +} + +/** + TODO +*/ +static inline bool +lv2_osc_message_body_get(LV2_OSC_URID *osc_urid, uint32_t size, const LV2_Atom_Object_Body *body, + const LV2_Atom_String **path, const LV2_Atom_Tuple **arguments) +{ + assert(path && arguments); + + *path = NULL; + *arguments = NULL; + + lv2_atom_object_body_get(size, body, + osc_urid->OSC_messagePath, path, + osc_urid->OSC_messageArguments, arguments, + 0); + + if(!*path || ((*path)->atom.type != osc_urid->ATOM_String)) + return false; + // message without arguments is valid + if( *arguments && ((*arguments)->atom.type != osc_urid->ATOM_Tuple)) + return false; + + return true; +} + +/** + TODO +*/ +static inline bool +lv2_osc_message_get(LV2_OSC_URID *osc_urid, const LV2_Atom_Object *obj, + const LV2_Atom_String **path, const LV2_Atom_Tuple **arguments) +{ + return lv2_osc_message_body_get(osc_urid, obj->atom.size, &obj->body, + path, arguments); +} + +static inline bool +lv2_osc_body_unroll(LV2_OSC_URID *osc_urid, uint32_t size, const LV2_Atom_Object_Body *body, + LV2_OSC_Method method, void *data) +{ + if(body->otype == osc_urid->OSC_Bundle) + { + const LV2_Atom_Object *timetag = NULL; + const LV2_Atom_Tuple *items = NULL; + + if(!lv2_osc_bundle_body_get(osc_urid, size, body, &timetag, &items)) + return false; + + LV2_OSC_Timetag tt; + lv2_osc_timetag_get(osc_urid, &timetag->atom, &tt); + + LV2_ATOM_TUPLE_FOREACH(items, atom) + { + const LV2_Atom_Object *obj= (const LV2_Atom_Object *)atom; + + if(!lv2_osc_body_unroll(osc_urid, obj->atom.size, &obj->body, method, data)) + return false; + } + + return true; + } + else if(body->otype == osc_urid->OSC_Message) + { + const LV2_Atom_String *path = NULL; + const LV2_Atom_Tuple *arguments = NULL; + + if(!lv2_osc_message_body_get(osc_urid, size, body, &path, &arguments)) + return false; + + if(method) + method(LV2_ATOM_BODY_CONST(path), arguments, data); + + return true; + } + + return false; +} + +static inline bool +lv2_osc_unroll(LV2_OSC_URID *osc_urid, const LV2_Atom_Object *obj, + LV2_OSC_Method method, void *data) +{ + return lv2_osc_body_unroll(osc_urid, obj->atom.size, &obj->body, method, data); +} + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // LV2_OSC_UTIL_H diff --git a/osc.lv2/osc.lv2/writer.h b/osc.lv2/osc.lv2/writer.h new file mode 100644 index 0000000..037d44c --- /dev/null +++ b/osc.lv2/osc.lv2/writer.h @@ -0,0 +1,579 @@ +/* + * Copyright (c) 2015-2016 Hanspeter Portner (dev@open-music-kontrollers.ch) + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the Artistic License 2.0 as published by + * The Perl Foundation. + * + * This source is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Artistic License 2.0 for more details. + * + * You should have received a copy of the Artistic License 2.0 + * along the source as a COPYING file. If not, obtain it from + * http://www.perlfoundation.org/artistic_license_2_0. + */ + +#ifndef LV2_OSC_WRITER_H +#define LV2_OSC_WRITER_H + +#include <stdbool.h> +#include <string.h> + +#include <osc.lv2/osc.h> +#include <osc.lv2/util.h> +#include <osc.lv2/endian.h> + +#include <lv2/lv2plug.in/ns/ext/atom/util.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#undef LV2_ATOM_TUPLE_FOREACH // there is a bug in LV2 1.10.0 +#define LV2_ATOM_TUPLE_FOREACH(tuple, iter) \ + for (LV2_Atom* (iter) = lv2_atom_tuple_begin(tuple); \ + !lv2_atom_tuple_is_end(LV2_ATOM_BODY(tuple), (tuple)->atom.size, (iter)); \ + (iter) = lv2_atom_tuple_next(iter)) + +typedef struct _LV2_OSC_Writer LV2_OSC_Writer; +typedef struct _LV2_OSC_Writer_Frame LV2_OSC_Writer_Frame; + +struct _LV2_OSC_Writer { + uint8_t *buf; + uint8_t *ptr; + const uint8_t *end; +}; + +struct _LV2_OSC_Writer_Frame { + uint8_t *ref; +}; + +static inline void +lv2_osc_writer_initialize(LV2_OSC_Writer *writer, uint8_t *buf, size_t size) +{ + writer->buf = buf; + writer->ptr = buf; + writer->end = buf + size; +} + +static inline size_t +lv2_osc_writer_get_size(LV2_OSC_Writer *writer) +{ + if(writer->ptr > writer->buf) + return writer->ptr - writer->buf; + + return 0; +} + +static inline uint8_t * +lv2_osc_writer_finalize(LV2_OSC_Writer *writer, size_t *size) +{ + *size = lv2_osc_writer_get_size(writer); + + if(*size) + return writer->buf; + + return NULL; +} + +static inline bool +lv2_osc_writer_overflow(LV2_OSC_Writer *writer, size_t size) +{ + return writer->ptr + size >= writer->end; +} + +static inline bool +lv2_osc_writer_htobe32(LV2_OSC_Writer *writer, union swap32_t *s32) +{ + if(lv2_osc_writer_overflow(writer, 4)) + return false; + + s32->u = htobe32(s32->u); + *(uint32_t *)writer->ptr = s32->u; + writer->ptr += 4; + + return true; +} + +static inline bool +lv2_osc_writer_htobe64(LV2_OSC_Writer *writer, union swap64_t *s64) +{ + if(lv2_osc_writer_overflow(writer, 8)) + return false; + + s64->u = htobe64(s64->u); + *(uint64_t *)writer->ptr = s64->u; + writer->ptr += 8; + + return true; +} + +static inline bool +lv2_osc_writer_add_int32(LV2_OSC_Writer *writer, int32_t i) +{ + return lv2_osc_writer_htobe32(writer, &(union swap32_t){ .i = i }); +} + +static inline bool +lv2_osc_writer_add_float(LV2_OSC_Writer *writer, float f) +{ + return lv2_osc_writer_htobe32(writer, &(union swap32_t){ .f = f }); +} + +static inline bool +lv2_osc_writer_add_string(LV2_OSC_Writer *writer, const char *s) +{ + const size_t rawlen = strlen(s) + 1; + const size_t padded = LV2_OSC_PADDED_SIZE(rawlen); + if(lv2_osc_writer_overflow(writer, padded)) + return false; + + const uint32_t blank = 0; + memcpy(writer->ptr + padded - sizeof(uint32_t), &blank, sizeof(uint32_t)); + memcpy(writer->ptr, s, rawlen); + writer->ptr += padded; + + return true; +} + +static inline bool +lv2_osc_writer_add_symbol(LV2_OSC_Writer *writer, const char *S) +{ + return lv2_osc_writer_add_string(writer, S); +} + +static inline bool +lv2_osc_writer_add_int64(LV2_OSC_Writer *writer, int64_t h) +{ + return lv2_osc_writer_htobe64(writer, &(union swap64_t){ .h = h }); +} + +static inline bool +lv2_osc_writer_add_double(LV2_OSC_Writer *writer, double d) +{ + return lv2_osc_writer_htobe64(writer, &(union swap64_t){ .d = d }); +} + +static inline bool +lv2_osc_writer_add_timetag(LV2_OSC_Writer *writer, uint64_t u) +{ + return lv2_osc_writer_htobe64(writer, &(union swap64_t){ .u = u }); +} + +static inline bool +lv2_osc_writer_add_blob_inline(LV2_OSC_Writer *writer, int32_t len, uint8_t **body) +{ + const size_t len_padded = LV2_OSC_PADDED_SIZE(len); + const size_t size = 4 + len_padded; + if(lv2_osc_writer_overflow(writer, size)) + return false; + + if(!lv2_osc_writer_add_int32(writer, len)) + return false; + + *body = writer->ptr; + //memset(&writer->ptr[len], 0x0, len_padded - len); + writer->ptr += len_padded; + + return true; +} + +static inline bool +lv2_osc_writer_add_blob(LV2_OSC_Writer *writer, int32_t len, const uint8_t *body) +{ + uint8_t *dst; + if(!lv2_osc_writer_add_blob_inline(writer, len, &dst)) + return false; + + memcpy(dst, body, len); + + return true; +} + +static inline bool +lv2_osc_writer_add_midi_inline(LV2_OSC_Writer *writer, int32_t len, uint8_t **m) +{ + if( (len > 4) || lv2_osc_writer_overflow(writer, 4)) + return false; + + *m = writer->ptr; + //memset(&writer->ptr[len], 0x0, 4 - len); + writer->ptr += 4; + + return true; +} + +static inline bool +lv2_osc_writer_add_midi(LV2_OSC_Writer *writer, int32_t len, const uint8_t *m) +{ + uint8_t *dst; + if(!lv2_osc_writer_add_midi_inline(writer, len, &dst)) + return false; + + memcpy(dst, m, len); + + return true; +} + +static inline bool +lv2_osc_writer_add_rgba(LV2_OSC_Writer *writer, uint8_t r, uint8_t g, uint8_t b, uint8_t a) +{ + if(lv2_osc_writer_overflow(writer, 4)) + return false; + + writer->ptr[0] = r; + writer->ptr[1] = g; + writer->ptr[2] = b; + writer->ptr[3] = a; + writer->ptr += 4; + + return true; +} + +static inline bool +lv2_osc_writer_add_char(LV2_OSC_Writer *writer, char c) +{ + return lv2_osc_writer_add_int32(writer, (int32_t)c); +} + +static inline bool +lv2_osc_writer_push_bundle(LV2_OSC_Writer *writer, LV2_OSC_Writer_Frame *frame, uint64_t t) +{ + if(lv2_osc_writer_overflow(writer, 16)) + return false; + + frame->ref = writer->ptr; + + strncpy((char *)writer->ptr, "#bundle", 8); + writer->ptr += 8; + + return lv2_osc_writer_add_timetag(writer, t); +} + +static inline bool +lv2_osc_writer_pop_bundle(LV2_OSC_Writer *writer, LV2_OSC_Writer_Frame *frame) +{ + union swap32_t s32 = { .i = writer->ptr - frame->ref - 16}; + + if(s32.i <= 0) + { + writer->ptr = frame->ref; + return false; + } + + return true; +} + +static inline bool +lv2_osc_writer_push_item(LV2_OSC_Writer *writer, LV2_OSC_Writer_Frame *frame) +{ + if(lv2_osc_writer_overflow(writer, 4)) + return false; + + frame->ref = writer->ptr; + writer->ptr += 4; + + return true; +} + +static inline bool +lv2_osc_writer_pop_item(LV2_OSC_Writer *writer, LV2_OSC_Writer_Frame *frame) +{ + union swap32_t s32 = { .i = writer->ptr - frame->ref - 4}; + + if(s32.i <= 0) + { + writer->ptr = frame->ref; + return false; + } + + s32.u = htobe32(s32.u); + *(uint32_t *)frame->ref = s32.u; + + return true; +} + +static inline bool +lv2_osc_writer_add_path(LV2_OSC_Writer *writer, const char *path) +{ + return lv2_osc_writer_add_string(writer, path); +} + +static inline bool +lv2_osc_writer_add_format(LV2_OSC_Writer *writer, const char *fmt) +{ + const size_t rawlen = strlen(fmt) + 1; + const size_t padded = LV2_OSC_PADDED_SIZE(rawlen + 1); + if(lv2_osc_writer_overflow(writer, padded)) + return false; + + const uint32_t blank = 0; + memcpy(writer->ptr + padded - sizeof(uint32_t), &blank, sizeof(uint32_t)); + *writer->ptr++ = ','; + memcpy(writer->ptr, fmt, rawlen); + writer->ptr += padded - 1; + + return true; +} + +static inline bool +lv2_osc_writer_arg_varlist(LV2_OSC_Writer *writer, const char *fmt, va_list args) +{ + for(const char *type = fmt; *type; type++) + { + switch( (LV2_OSC_Type)*type) + { + case LV2_OSC_INT32: + if(!lv2_osc_writer_add_int32(writer, va_arg(args, int32_t))) + return false; + break; + case LV2_OSC_FLOAT: + if(!lv2_osc_writer_add_float(writer, (float)va_arg(args, double))) + return false; + break; + case LV2_OSC_STRING: + if(!lv2_osc_writer_add_string(writer, va_arg(args, const char *))) + return false; + break; + case LV2_OSC_BLOB: + { + const int32_t len = va_arg(args, int32_t); + if(!lv2_osc_writer_add_blob(writer, len, va_arg(args, const uint8_t *))) + return false; + } break; + + case LV2_OSC_TRUE: + case LV2_OSC_FALSE: + case LV2_OSC_NIL: + case LV2_OSC_IMPULSE: + break; + + case LV2_OSC_INT64: + if(!lv2_osc_writer_add_int64(writer, va_arg(args, int64_t))) + return false; + break; + case LV2_OSC_DOUBLE: + if(!lv2_osc_writer_add_double(writer, va_arg(args, double))) + return false; + break; + case LV2_OSC_TIMETAG: + if(!lv2_osc_writer_add_timetag(writer, va_arg(args, uint64_t))) + return false; + break; + + case LV2_OSC_MIDI: + { + const int32_t len = va_arg(args, int32_t); + if(!lv2_osc_writer_add_midi(writer, len, va_arg(args, const uint8_t *))) + return false; + } break; + case LV2_OSC_SYMBOL: + if(!lv2_osc_writer_add_symbol(writer, va_arg(args, const char *))) + return false; + break; + case LV2_OSC_CHAR: + if(!lv2_osc_writer_add_char(writer, va_arg(args, int))) + return false; + break; + case LV2_OSC_RGBA: + { + const uint8_t r = va_arg(args, unsigned); + const uint8_t g = va_arg(args, unsigned); + const uint8_t b = va_arg(args, unsigned); + const uint8_t a = va_arg(args, unsigned); + if(!lv2_osc_writer_add_rgba(writer, r, g, b, a)) + return false; + } break; + } + } + + return true; +} + +static inline bool +lv2_osc_writer_arg_vararg(LV2_OSC_Writer *writer, const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + + const bool res = lv2_osc_writer_arg_varlist(writer, fmt, args); + + va_end(args); + + return res; +} + +static inline bool +lv2_osc_writer_message_varlist(LV2_OSC_Writer *writer, const char *path, const char *fmt, va_list args) +{ + if(!lv2_osc_writer_add_path(writer, path)) + return false; + + if(!lv2_osc_writer_add_format(writer, fmt)) + return false; + + return lv2_osc_writer_arg_varlist(writer, fmt, args); +} + +static inline bool +lv2_osc_writer_message_vararg(LV2_OSC_Writer *writer, const char *path, const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + + const bool res = lv2_osc_writer_message_varlist(writer, path, fmt, args); + + va_end(args); + + return res; +} + +static inline bool +lv2_osc_writer_packet(LV2_OSC_Writer *writer, LV2_OSC_URID *osc_urid, + LV2_URID_Unmap *unmap, uint32_t size, const LV2_Atom_Object_Body *body) +{ + if(body->otype == osc_urid->OSC_Bundle) + { + const LV2_Atom_Object *timetag = NULL; + const LV2_Atom_Tuple *items = NULL; + + if(!lv2_osc_bundle_body_get(osc_urid, size, body, &timetag, &items)) + return false; + + LV2_OSC_Timetag tt; + LV2_OSC_Writer_Frame bndl = { .ref = 0 }; + + lv2_osc_timetag_get(osc_urid, &timetag->atom, &tt); + if(!lv2_osc_writer_push_bundle(writer, &bndl, lv2_osc_timetag_parse(&tt))) + return false; + + LV2_ATOM_TUPLE_FOREACH(items, atom) + { + const LV2_Atom_Object *obj= (const LV2_Atom_Object *)atom; + LV2_OSC_Writer_Frame itm = { .ref = 0 }; + + if( !lv2_osc_writer_push_item(writer, &itm) + || !lv2_osc_writer_packet(writer, osc_urid, unmap, obj->atom.size, &obj->body) + || !lv2_osc_writer_pop_item(writer, &itm) ) + { + return false; + } + } + + return lv2_osc_writer_pop_bundle(writer, &bndl); + } + else if(body->otype == osc_urid->OSC_Message) + { + const LV2_Atom_String *path = NULL; + const LV2_Atom_Tuple *arguments = NULL; + + if(lv2_osc_message_body_get(osc_urid, size, body, &path, &arguments)) + { + if(!lv2_osc_writer_add_path(writer, LV2_ATOM_BODY_CONST(path))) + return false; + + char fmt [128]; //TODO how big? + char *ptr = fmt; + LV2_ATOM_TUPLE_FOREACH(arguments, atom) + { + *ptr++ = lv2_osc_argument_type(osc_urid, atom); + } + *ptr = '\0'; + if(!lv2_osc_writer_add_format(writer, fmt)) + return false; + + LV2_ATOM_TUPLE_FOREACH(arguments, atom) + { + const LV2_Atom_Object *obj= (const LV2_Atom_Object *)atom; + + if(atom->type == osc_urid->ATOM_Int) + { + if(!lv2_osc_writer_add_int32(writer, ((const LV2_Atom_Int *)atom)->body)) + return false; + } + else if(atom->type == osc_urid->ATOM_Float) + { + if(!lv2_osc_writer_add_float(writer, ((const LV2_Atom_Float *)atom)->body)) + return false; + } + else if(atom->type == osc_urid->ATOM_String) + { + if(!lv2_osc_writer_add_string(writer, LV2_ATOM_BODY_CONST(atom))) + return false; + } + else if(atom->type == osc_urid->ATOM_Chunk) + { + if(!lv2_osc_writer_add_blob(writer, atom->size, LV2_ATOM_BODY_CONST(atom))) + return false; + } + + else if(atom->type == osc_urid->ATOM_Long) + { + if(!lv2_osc_writer_add_int64(writer, ((const LV2_Atom_Long *)atom)->body)) + return false; + } + else if(atom->type == osc_urid->ATOM_Double) + { + if(!lv2_osc_writer_add_double(writer, ((const LV2_Atom_Double *)atom)->body)) + return false; + } + else if( (atom->type == osc_urid->ATOM_Object) && (obj->body.otype == osc_urid->OSC_Timetag) ) + { + LV2_OSC_Timetag tt; + lv2_osc_timetag_get(osc_urid, &obj->atom, &tt); + if(!lv2_osc_writer_add_timetag(writer, lv2_osc_timetag_parse(&tt))) + return false; + } + + // there is nothing to do for: true, false, nil, impulse + + else if(atom->type == osc_urid->ATOM_URID) + { + const char *symbol = unmap->unmap(unmap->handle, ((const LV2_Atom_URID *)atom)->body); + if(!symbol || !lv2_osc_writer_add_symbol(writer, symbol)) + return false; + } + else if(atom->type == osc_urid->MIDI_MidiEvent) + { + uint8_t *m = NULL; + if(!lv2_osc_writer_add_midi_inline(writer, atom->size + 1, &m)) + return false; + m[0] = 0x0; // port + memcpy(&m[1], LV2_ATOM_BODY_CONST(atom), atom->size); + } + else if(atom->type == osc_urid->ATOM_Literal) + { + const LV2_Atom_Literal *lit = (LV2_Atom_Literal *)atom; + + if(lit->body.datatype == osc_urid->OSC_Char) + { + const char c = *(const char *)LV2_ATOM_CONTENTS_CONST(LV2_Atom_Literal, lit); + if(!lv2_osc_writer_add_char(writer, c)) + return false; + } + else if(lit->body.datatype == osc_urid->OSC_RGBA) + { + const char *rgba = LV2_ATOM_CONTENTS_CONST(LV2_Atom_Literal, atom); + uint8_t r, g, b, a; + if(sscanf(rgba, "%02"SCNx8"%02"SCNx8"%02"SCNx8"%02"SCNx8, &r, &g, &b, &a) != 4) + return false; + if(!lv2_osc_writer_add_rgba(writer, r, g, b, a)) + return false; + } + } + } + } + + return true; + } + + return false; +} + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // LV2_OSC_WRITER_H diff --git a/osc.lv2/osc.ttl b/osc.lv2/osc.ttl new file mode 100644 index 0000000..db4a048 --- /dev/null +++ b/osc.lv2/osc.ttl @@ -0,0 +1,42 @@ +# Copyright (c) 2015-2016 Hanspeter Portner (dev@open-music-kontrollers.ch) +# +# This is free software: you can redistribute it and/or modify +# it under the terms of the Artistic License 2.0 as published by +# The Perl Foundation. +# +# This source is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# Artistic License 2.0 for more details. +# +# You should have received a copy of the Artistic License 2.0 +# along the source as a COPYING file. If not, obtain it from +# http://www.perlfoundation.org/artistic_license_2_0. + +@prefix owl: <http://www.w3.org/2002/07/owl#> . +@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> . +@prefix xsd: <http://www.w3.org/2001/XMLSchema#> . +@prefix lv2: <http://lv2plug.in/ns/lv2core#> . +@prefix atom: <http://lv2plug.in/ns/ext/atom#> . +@prefix osc: <http://open-music-kontrollers.ch/lv2/osc#> . + +<http://open-music-kontrollers.ch/lv2/osc> + a owl:Ontology ; + rdfs:seeAlso <lv2_osc.h> , + <lv2-osc.doap.ttl> ; + lv2:documentation """ + <p>This specification defines event data types for OSC bundles and message. + To signal support for OSC events on an atom:AtomPort with an atom:bufferType + of atom:Sequence, plugin authors should add atom:supports osc:Event to + the plugin specification.</p> + """ . + +osc:schedule + a lv2:Feature . + +osc:Event + a rdfs:Class , + rdfs:Datatype ; + rdfs:subClassOf atom:Atom ; + owl:onDatatype xsd:hexBinary ; + rdfs:label "OSC Event (Bundle or Message)" . diff --git a/osc.lv2/test/osc_test.c b/osc.lv2/test/osc_test.c new file mode 100644 index 0000000..2c6a710 --- /dev/null +++ b/osc.lv2/test/osc_test.c @@ -0,0 +1,1373 @@ +#include <assert.h> +#include <string.h> +#include <stdio.h> +#include <pthread.h> +#include <time.h> + +#include <osc.lv2/osc.h> +#include <osc.lv2/reader.h> +#include <osc.lv2/writer.h> +#include <osc.lv2/forge.h> +#if !defined(_WIN32) +# include <osc.lv2/stream.h> +#endif + +#define BUF_SIZE 0x100000 +#define MAX_URIDS 512 + +typedef void (*test_t)(LV2_OSC_Writer *writer); +typedef struct _urid_t urid_t; +typedef struct _app_t app_t; + +struct _urid_t { + LV2_URID urid; + char *uri; +}; + +struct _app_t { + urid_t urids [MAX_URIDS]; + LV2_URID urid; +}; + +static app_t __app; +static uint8_t buf0 [BUF_SIZE]; +static uint8_t buf1 [BUF_SIZE]; +static uint8_t buf2 [BUF_SIZE]; +static const LV2_Atom_Object *obj2= (const LV2_Atom_Object *)buf2; + +const uint8_t raw_0 [] = { + '/', 0x0, 0x0, 0x0, + ',', 0x0, 0x0, 0x0 +}; + +const uint8_t raw_1 [] = { + '/', 'p', 'i', 'n', + 'g', 0x0, 0x0, 0x0, + ',', 'i', 'f', 's', + 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xc, + 0x40, 0x59, 0x99, 0x9a, + 'w', 'o', 'r', 'l', + 'd', 0x0, 0x0, 0x0 +}; + +const uint8_t raw_2 [] = { + '/', 'p', 'i', 'n', + 'g', 0x0, 0x0, 0x0, + ',', 'h', 'd', 'S', + 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xc, + 0x40, 0x0b, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, + 'h', 't', 't', 'p', + ':', '/', '/', 'e', + 'x', 'a', 'm', 'p', + 'l', 'e', '.', 'c', + 'o', 'm', 0x0, 0x0 +}; + +const uint8_t raw_3 [] = { + '/', 'p', 'i', 'n', + 'g', 0x0, 0x0, 0x0, + ',', 'T', 'F', 'N', + 'I', 0x0, 0x0, 0x0 +}; + +const uint8_t raw_4 [] = { + '/', 'm', 'i', 'd', + 'i', 0x0, 0x0, 0x0, + ',', 'm', 0x0, 0x0, + 0x0, 0x90, 24, 0x7f +}; + +const uint8_t raw_5 [] = { + '/', 'b', 'l', 'o', + 'b', 0x0, 0x0, 0x0, + ',', 'b', 0x0, 0x0, + 0x0, 0x0, 0x0, 0x6, + 0x1, 0x2, 0x3, 0x4, + 0x5, 0x6, 0x0, 0x0 +}; + +const uint8_t raw_6 [] = { + '#', 'b', 'u', 'n', + 'd', 'l', 'e', 0x0, + 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x1, + + 0x0, 0x0, 0x0, 0x8, + '/', 0x0, 0x0, 0x0, + ',', 0x0, 0x0, 0x0 +}; + +const uint8_t raw_7 [] = { + '#', 'b', 'u', 'n', + 'd', 'l', 'e', 0x0, + 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x1, + + 0x0, 0x0, 0x0, 0x1c, + '#', 'b', 'u', 'n', + 'd', 'l', 'e', 0x0, + 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x1, + + 0x0, 0x0, 0x0, 0x8, + '/', 0x0, 0x0, 0x0, + ',', 0x0, 0x0, 0x0, + + 0x0, 0x0, 0x0, 0x8, + '/', 0x0, 0x0, 0x0, + ',', 0x0, 0x0, 0x0 +}; + +const uint8_t raw_8 [] = { + '/', 'p', 'i', 'n', + 'g', 0x0, 0x0, 0x0, + ',', 't', 'c', 'r', + 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x1, + 0x0, 0x0, 0x0, 'o', + 0x1, 0x2, 0x3, 0x4 +}; + +static LV2_URID +_map(LV2_URID_Map_Handle instance, const char *uri) +{ + app_t *app = instance; + + urid_t *itm; + for(itm=app->urids; itm->urid; itm++) + { + if(!strcmp(itm->uri, uri)) + return itm->urid; + } + + assert(app->urid + 1 < MAX_URIDS); + + // create new + itm->urid = ++app->urid; + itm->uri = strdup(uri); + + return itm->urid; +} + +static const char * +_unmap(LV2_URID_Unmap_Handle instance, LV2_URID urid) +{ + app_t *app = instance; + + urid_t *itm; + for(itm=app->urids; itm->urid; itm++) + { + if(itm->urid == urid) + return itm->uri; + } + + // not found + return NULL; +} + +static LV2_URID_Map map = { + .handle = &__app, + .map = _map +}; + +static LV2_URID_Unmap unmap = { + .handle = &__app, + .unmap = _unmap +}; + +//#define DUMP +#if defined(DUMP) +static void +_dump(const uint8_t *src, const uint8_t *dst, size_t size) +{ + for(size_t i = 0; i < size; i++) + printf("%zu %02x %02x\n", i, src[i], dst[i]); + printf("\n"); +} +#endif + +static void +_clone(LV2_OSC_Reader *reader, LV2_OSC_Writer *writer, size_t size) +{ + if(lv2_osc_reader_is_bundle(reader)) + { + LV2_OSC_Item *itm = OSC_READER_BUNDLE_BEGIN(reader, size); + assert(itm); + + LV2_OSC_Writer_Frame frame_bndl = { .ref = 0 }; + assert(lv2_osc_writer_push_bundle(writer, &frame_bndl, itm->timetag)); + + OSC_READER_BUNDLE_ITERATE(reader, itm) + { + LV2_OSC_Reader reader2; + lv2_osc_reader_initialize(&reader2, itm->body, itm->size); + + LV2_OSC_Writer_Frame frame_itm = { .ref = 0 }; + assert(lv2_osc_writer_push_item(writer, &frame_itm)); + _clone(&reader2, writer, itm->size); + assert(lv2_osc_writer_pop_item(writer, &frame_itm)); + } + + assert(lv2_osc_writer_pop_bundle(writer, &frame_bndl)); + } + else if(lv2_osc_reader_is_message(reader)) + { + LV2_OSC_Arg *arg = OSC_READER_MESSAGE_BEGIN(reader, size); + assert(arg); + + assert(lv2_osc_writer_add_path(writer, arg->path)); + assert(lv2_osc_writer_add_format(writer, arg->type)); + + OSC_READER_MESSAGE_ITERATE(reader, arg) + { + switch((LV2_OSC_Type)*arg->type) + { + case LV2_OSC_INT32: + assert(lv2_osc_writer_add_int32(writer, arg->i)); + break; + case LV2_OSC_FLOAT: + assert(lv2_osc_writer_add_float(writer, arg->f)); + break; + case LV2_OSC_STRING: + assert(lv2_osc_writer_add_string(writer, arg->s)); + break; + case LV2_OSC_BLOB: + assert(lv2_osc_writer_add_blob(writer, arg->size, arg->b)); + break; + + case LV2_OSC_INT64: + assert(lv2_osc_writer_add_int64(writer, arg->h)); + break; + case LV2_OSC_DOUBLE: + assert(lv2_osc_writer_add_double(writer, arg->d)); + break; + case LV2_OSC_TIMETAG: + assert(lv2_osc_writer_add_timetag(writer, arg->t)); + break; + + case LV2_OSC_TRUE: + case LV2_OSC_FALSE: + case LV2_OSC_NIL: + case LV2_OSC_IMPULSE: + break; + + case LV2_OSC_MIDI: + assert(lv2_osc_writer_add_midi(writer, arg->size, arg->m)); + break; + case LV2_OSC_SYMBOL: + assert(lv2_osc_writer_add_symbol(writer, arg->S)); + break; + case LV2_OSC_CHAR: + assert(lv2_osc_writer_add_char(writer, arg->c)); + break; + case LV2_OSC_RGBA: + assert(lv2_osc_writer_add_rgba(writer, arg->R, arg->G, arg->B, arg->A)); + break; + } + } + } +} + +static void +_test_a(LV2_OSC_Writer *writer, const uint8_t *raw, size_t size) +{ + LV2_OSC_URID osc_urid; + lv2_osc_urid_init(&osc_urid, &map); + + // check writer against raw bytes + size_t len; + assert(lv2_osc_writer_finalize(writer, &len) == buf0); + assert(len == size); +#if defined(DUMP) + if(memcmp(raw, buf0, size) != 0) + _dump(raw, buf0, size); +#endif + assert(memcmp(raw, buf0, size) == 0); + + // check reader & writer + LV2_OSC_Reader reader; + lv2_osc_reader_initialize(&reader, buf0, size); + lv2_osc_writer_initialize(writer, buf1, BUF_SIZE); + _clone(&reader, writer, size); + + // check cloned against raw bytes + assert(lv2_osc_writer_finalize(writer, &len) == buf1); + assert(len == size); +#if defined(DUMP) + if(memcmp(raw, buf1, size) != 0) + _dump(raw, buf1, size); +#endif + assert(memcmp(raw, buf1, size) == 0); + + // check forge + LV2_Atom_Forge forge; + lv2_atom_forge_init(&forge, &map); + lv2_atom_forge_set_buffer(&forge, buf2, BUF_SIZE); + assert(lv2_osc_forge_packet(&forge, &osc_urid, &map, buf0, size)); + + // check deforge + lv2_osc_writer_initialize(writer, buf1, BUF_SIZE); + assert(lv2_osc_writer_packet(writer, &osc_urid, &unmap, obj2->atom.size, &obj2->body)); + + // check deforged against raw bytes + assert(lv2_osc_writer_finalize(writer, &len) == buf1); + assert(len == size); +#if defined(DUMP) + if(memcmp(raw, buf1, size) != 0) + _dump(raw, buf1, size); +#endif + assert(memcmp(raw, buf1, size) == 0); +} + +static void +test_0_a(LV2_OSC_Writer *writer) +{ + assert(lv2_osc_writer_message_vararg(writer, "/", "")); + _test_a(writer, raw_0, sizeof(raw_0)); +} + +static void +test_1_a(LV2_OSC_Writer *writer) +{ + assert(lv2_osc_writer_message_vararg(writer, "/ping", "ifs", + 12, 3.4f, "world")); + _test_a(writer, raw_1, sizeof(raw_1)); +} + +static void +test_2_a(LV2_OSC_Writer *writer) +{ + assert(lv2_osc_writer_message_vararg(writer, "/ping", "hdS", + (int64_t)12, (double)3.4, "http://example.com")); + _test_a(writer, raw_2, sizeof(raw_2)); +} + +static void +test_3_a(LV2_OSC_Writer *writer) +{ + assert(lv2_osc_writer_message_vararg(writer, "/ping", "TFNI")); + _test_a(writer, raw_3, sizeof(raw_3)); +} + +static void +test_4_a(LV2_OSC_Writer *writer) +{ + const uint8_t m [] = {0x00, 0x90, 24, 0x7f}; + const int32_t len = sizeof(m); + assert(lv2_osc_writer_message_vararg(writer, "/midi", "m", len, m)); + _test_a(writer, raw_4, sizeof(raw_4)); +} + +static void +test_5_a(LV2_OSC_Writer *writer) +{ + const uint8_t b [] = {0x1, 0x2, 0x3, 0x4, 0x5, 0x6}; + const int32_t len = sizeof(b); + assert(lv2_osc_writer_message_vararg(writer, "/blob", "b", len, b)); + _test_a(writer, raw_5, sizeof(raw_5)); +} + +static void +test_6_a(LV2_OSC_Writer *writer) +{ + LV2_OSC_Writer_Frame frame_bndl = { .ref = 0 }; + LV2_OSC_Writer_Frame frame_itm = { .ref = 0 }; + + assert(lv2_osc_writer_push_bundle(writer, &frame_bndl, LV2_OSC_IMMEDIATE)); + { + assert(lv2_osc_writer_push_item(writer, &frame_itm)); + { + assert(lv2_osc_writer_message_vararg(writer, "/", "")); + } + assert(lv2_osc_writer_pop_item(writer, &frame_itm)); + } + assert(lv2_osc_writer_pop_bundle(writer, &frame_bndl)); + + _test_a(writer, raw_6, sizeof(raw_6)); +} + +static void +test_7_a(LV2_OSC_Writer *writer) +{ + LV2_OSC_Writer_Frame frame_bndl[2] = { { .ref = 0 }, { .ref = 0 } }; + LV2_OSC_Writer_Frame frame_itm[2] = { { .ref = 0 }, { .ref = 0 } };; + + assert(lv2_osc_writer_push_bundle(writer, &frame_bndl[0], LV2_OSC_IMMEDIATE)); + { + assert(lv2_osc_writer_push_item(writer, &frame_itm[0])); + { + assert(lv2_osc_writer_push_bundle(writer, &frame_bndl[1], LV2_OSC_IMMEDIATE)); + { + assert(lv2_osc_writer_push_item(writer, &frame_itm[1])); + { + assert(lv2_osc_writer_message_vararg(writer, "/", "")); + } + assert(lv2_osc_writer_pop_item(writer, &frame_itm[1])); + } + assert(lv2_osc_writer_pop_bundle(writer, &frame_bndl[1])); + } + assert(lv2_osc_writer_pop_item(writer, &frame_itm[0])); + + assert(lv2_osc_writer_push_item(writer, &frame_itm[0])); + { + assert(lv2_osc_writer_message_vararg(writer, "/", "")); + } + assert(lv2_osc_writer_pop_item(writer, &frame_itm[0])); + } + assert(lv2_osc_writer_pop_bundle(writer, &frame_bndl[0])); + + _test_a(writer, raw_7, sizeof(raw_7)); +} + +static void +test_8_a(LV2_OSC_Writer *writer) +{ + assert(lv2_osc_writer_message_vararg(writer, "/ping", "tcr", + 1ULL, + 'o', + 0x1, 0x2, 0x3, 0x4)); + _test_a(writer, raw_8, sizeof(raw_8)); +} + +static test_t tests [] = { + test_0_a, + test_1_a, + test_2_a, + test_3_a, + test_4_a, + test_5_a, + test_6_a, + test_7_a, + test_8_a, + + NULL +} +; +static int +_run_tests() +{ + LV2_OSC_Writer writer; + + for(test_t *test=tests; *test; test++) + { + test_t cb = *test; + + memset(buf0, 0x0, BUF_SIZE); + memset(buf1, 0x0, BUF_SIZE); + + lv2_osc_writer_initialize(&writer, buf0, BUF_SIZE); + + cb(&writer); + } + + assert(unmap.unmap(unmap.handle, 0)== NULL); + + return 0; +} + +#if !defined(_WIN32) +typedef struct _item_t item_t; +typedef struct _stash_t stash_t; + +struct _item_t { + size_t size; + uint8_t buf []; +}; + +struct _stash_t { + size_t size; + item_t **items; + item_t *rsvd; +}; + +static uint8_t * +_stash_write_req(stash_t *stash, size_t minimum, size_t *maximum) +{ + if(!stash->rsvd || (stash->rsvd->size < minimum)) + { + const size_t sz = sizeof(item_t) + minimum; + stash->rsvd = realloc(stash->rsvd, sz); + assert(stash->rsvd); + stash->rsvd->size = minimum; + } + + if(maximum) + { + *maximum = stash->rsvd->size; + } + + return stash->rsvd->buf; +} + +static void +_stash_write_adv(stash_t *stash, size_t written) +{ + assert(stash->rsvd); + assert(stash->rsvd->size >= written); + stash->rsvd->size = written; + stash->size += 1; + stash->items = realloc(stash->items, sizeof(item_t *) * stash->size); + stash->items[stash->size - 1] = stash->rsvd; + stash->rsvd = NULL; +} + +static const uint8_t * +_stash_read_req(stash_t *stash, size_t *size) +{ + if(stash->size == 0) + { + if(size) + { + *size = 0; + } + + return NULL; + } + + item_t *item = stash->items[0]; + + if(size) + { + *size = item->size; + } + + return item->buf; +} + +static void +_stash_read_adv(stash_t *stash) +{ + assert(stash->size); + + free(stash->items[0]); + stash->size -= 1; + + for(unsigned i = 0; i < stash->size; i++) + { + stash->items[i] = stash->items[i+1]; + } + + stash->items = realloc(stash->items, sizeof(item_t *) * stash->size); +} + +static void * +_write_req(void *data, size_t minimum, size_t *maximum) +{ + stash_t *stash = data; + + return _stash_write_req(&stash[0], minimum, maximum); +} + +static void +_write_adv(void *data, size_t written) +{ + stash_t *stash = data; + + _stash_write_adv(&stash[0], written); +} + +static const void * +_read_req(void *data, size_t *toread) +{ + stash_t *stash = data; + + return _stash_read_req(&stash[1], toread); +} + +static void +_read_adv(void *data) +{ + stash_t *stash = data; + + _stash_read_adv(&stash[1]); +} + +static const LV2_OSC_Driver driv = { + .write_req = _write_req, + .write_adv = _write_adv, + .read_req = _read_req, + .read_adv = _read_adv +}; + +#define COUNT 128 + +typedef struct _pair_t pair_t; + +struct _pair_t { + const char *server; + const char *client; + bool lossy; +}; + +static void * +_thread_1(void *data) +{ + const pair_t *pair = data; + const char *uri = pair->server; + + LV2_OSC_Stream stream; + stash_t stash [2]; + uint8_t check [COUNT]; + + memset(&stream, 0x0, sizeof(stream)); + memset(stash, 0x0, sizeof(stash)); + memset(check, 0x0, sizeof(check)); + + assert(lv2_osc_stream_init(&stream, uri, &driv, stash) == 0); + + time_t t0 = time(NULL); + unsigned count = 0; + while(true) + { + const time_t t1 = time(NULL); + const LV2_OSC_Enum ev = lv2_osc_stream_run(&stream); + + if(ev & LV2_OSC_ERR) + { + fprintf(stderr, "%s: %s\n", __func__, strerror(ev & LV2_OSC_ERR)); + } + + if(ev & LV2_OSC_RECV) + { + const uint8_t *buf_rx; + size_t reat; + + while( (buf_rx = _stash_read_req(&stash[0], &reat)) ) + { + LV2_OSC_Reader reader; + + lv2_osc_reader_initialize(&reader, buf_rx, reat); + assert(lv2_osc_reader_is_message(&reader)); + + OSC_READER_MESSAGE_FOREACH(&reader, arg, reat) + { + assert(strcmp(arg->path, "/trip") == 0); + assert(*arg->type == 'i'); + assert(arg->size == sizeof(int32_t)); + assert(check[arg->i] == 0); + check[arg->i] = 1; + } + + count++; + + while(true) + { + // send back + uint8_t *buf_tx; + if( (buf_tx = _stash_write_req(&stash[1], reat, NULL)) ) + { + memcpy(buf_tx, buf_rx, reat); + + _stash_write_adv(&stash[1], reat); + break; + } + } + + _stash_read_adv(&stash[0]); + } + + t0 = t1; + } + + if(count >= COUNT) + { + break; + } + else if(pair->lossy && (difftime(t1, t0) >= 1.0) ) + { + fprintf(stderr, "%s: timeout: %i\n", __func__, count); + break; + } + } + + LV2_OSC_Enum ev; + do + { + ev = lv2_osc_stream_run(&stream); + + if(ev & LV2_OSC_ERR) + { + fprintf(stderr, "%s: %s\n", __func__, strerror(ev & LV2_OSC_ERR)); + } + } while( (ev & LV2_OSC_SEND) || (ev & LV2_OSC_CONN) ); + + assert(pair->lossy || (count == COUNT) ); + + assert(lv2_osc_stream_deinit(&stream) == 0); + + free(stash[0].rsvd); + while(stash[0].size) + { + _stash_read_adv(&stash[0]); + } + free(stash[0].items); + + free(stash[1].rsvd); + while(stash[1].size) + { + _stash_read_adv(&stash[1]); + } + free(stash[1].items); + + return NULL; +} + +static void * +_thread_2(void *data) +{ + const pair_t *pair = data; + const char *uri = pair->client; + + LV2_OSC_Stream stream; + stash_t stash [2]; + uint8_t check [COUNT]; + + memset(&stream, 0x0, sizeof(stream)); + memset(stash, 0x0, sizeof(stash)); + memset(check, 0x0, sizeof(check)); + + assert(lv2_osc_stream_init(&stream, uri, &driv, stash) == 0); + + unsigned count = 0; + for(int32_t i = 0; i < COUNT; i++) + { + LV2_OSC_Writer writer; + + while(true) + { + uint8_t *buf_tx; + size_t max; + if( (buf_tx = _stash_write_req(&stash[1], 1024, &max)) ) + { + size_t writ; + lv2_osc_writer_initialize(&writer, buf_tx, max); + assert(lv2_osc_writer_message_vararg(&writer, "/trip", "i", i)); + assert(lv2_osc_writer_finalize(&writer, &writ) == buf_tx); + assert(writ == 16); + assert(check[i] == 0); + check[i] = 1; + + _stash_write_adv(&stash[1], writ); + break; + } + } + + const LV2_OSC_Enum ev = lv2_osc_stream_run(&stream); + + if(ev & LV2_OSC_ERR) + { + fprintf(stderr, "%s: %s\n", __func__, strerror(ev & LV2_OSC_ERR)); + } + + if(ev & LV2_OSC_RECV) + { + const uint8_t *buf_rx; + size_t reat; + + while( (buf_rx = _stash_read_req(&stash[0], &reat)) ) + { + LV2_OSC_Reader reader; + + lv2_osc_reader_initialize(&reader, buf_rx, reat); + assert(lv2_osc_reader_is_message(&reader)); + + OSC_READER_MESSAGE_FOREACH(&reader, arg, reat) + { + assert(strcmp(arg->path, "/trip") == 0); + assert(*arg->type == 'i'); + assert(arg->size == sizeof(int32_t)); + assert(check[arg->i] == 1); + check[arg->i] = 2; + } + + count++; + + _stash_read_adv(&stash[0]); + } + } + } + + time_t t0 = time(NULL); + while(true) + { + const time_t t1 = time(NULL); + const LV2_OSC_Enum ev = lv2_osc_stream_run(&stream); + + if(ev & LV2_OSC_ERR) + { + fprintf(stderr, "%s: %s\n", __func__, strerror(ev & LV2_OSC_ERR)); + } + + if(ev & LV2_OSC_RECV) + { + const uint8_t *buf_rx; + size_t reat; + + while( (buf_rx = _stash_read_req(&stash[0], &reat)) ) + { + LV2_OSC_Reader reader; + + lv2_osc_reader_initialize(&reader, buf_rx, reat); + assert(lv2_osc_reader_is_message(&reader)); + + OSC_READER_MESSAGE_FOREACH(&reader, arg, reat) + { + assert(strcmp(arg->path, "/trip") == 0); + assert(*arg->type == 'i'); + assert(arg->size == sizeof(int32_t)); + assert(check[arg->i] == 1); + check[arg->i] = 2; + } + + count++; + + _stash_read_adv(&stash[0]); + } + + t0 = t1; + } + + if(count >= COUNT) + { + break; + } + else if(pair->lossy && (difftime(t1, t0) >= 1.0) ) + { + fprintf(stderr, "%s: timeout: %i\n", __func__, count); + break; + } + } + + assert(pair->lossy || (count == COUNT) ); + + assert(lv2_osc_stream_deinit(&stream) == 0); + + free(stash[0].rsvd); + while(stash[0].size) + { + _stash_read_adv(&stash[0]); + } + free(stash[0].items); + + free(stash[1].rsvd); + while(stash[1].size) + { + _stash_read_adv(&stash[1]); + } + free(stash[1].items); + + return NULL; +} + +static const pair_t pairs [] = { + { + .server = "osc.udp://:2222", + .client = "osc.udp://localhost:2222", + .lossy = true + }, + { + .server = "osc.udp://[]:3333", + .client = "osc.udp://[::1]:3333", + .lossy = true + }, + + { + .server = "osc.udp://:3344", + .client = "osc.udp://255.255.255.255:3344", + .lossy = true + }, + + { + .server = "osc.tcp://:4444", + .client = "osc.tcp://localhost:4444", + .lossy = false + }, + { + .server = "osc.tcp://[]:5555", + .client = "osc.tcp://[::1]:5555", + .lossy = false + }, + + { + .server = "osc.slip.tcp://:6666", + .client = "osc.slip.tcp://localhost:6666", + .lossy = false + }, + { + .server = "osc.slip.tcp://[]:7777", + .client = "osc.slip.tcp://[::1]:7777", + .lossy = false + }, + + { + .server = "osc.prefix.tcp://:8888", + .client = "osc.prefix.tcp://localhost:8888", + .lossy = false + }, + { + .server = "osc.prefix.tcp://[%lo]:9999", + .client = "osc.prefix.tcp://[::1%lo]:9999", + .lossy = false + }, + +#if 0 + { + .server = "osc.serial:///dev/pts/4", //FIXME baudrate + .client = "osc.serial:///dev/pts/5", + .lossy = false + }, +#endif + + { + .server = NULL, + .client = NULL, + .lossy = false + } +}; +#endif + +#if !defined(_WIN32) +static unsigned foo_sub_one = 0; +static unsigned foo_sub_two [2] = { 0, 0 }; +static unsigned foo = 0; +static unsigned bar = 0; + +static void +_one(const char *path, unsigned *flag) +{ + *flag += 1; + + if(!path) + { + return; + } + + assert(!strcmp(path, "/sub/one") + || !strcmp(path, "/*/one") + || !strcmp(path, "/s*/one") + || !strcmp(path, "/su*/one") + || !strcmp(path, "/sub*/one") + || !strcmp(path, "/sub/*") + || !strcmp(path, "/*sub/one") + || !strcmp(path, "/*s*u*b*/one") + || !strcmp(path, "/su[ab]/one") + || !strcmp(path, "/su[a-b]/[!a-np-z]ne") + || !strcmp(path, "/su[a-b]/one") + || !strcmp(path, "/s?b/?ne") + || !strcmp(path, "/s?*/?ne") + || !strcmp(path, "/s?*/*?e") + || !strcmp(path, "/sub/{one,two}")); +} + +static void +_two(const char *path, unsigned *flag) +{ + *flag += 1; + + if(!path) + { + return; + } + + assert(!strcmp(path, "/sub/two") + || !strcmp(path, "/sub/*") + || !strcmp(path, "/sub/{one,two}")); +} + +static void +_foo(const char *path, unsigned *flag) +{ + *flag += 1; + + if(!path) + { + return; + } + + assert(!strcmp(path, "/foo") + || !strcmp(path, "/{foo,bar}")); +} + +static void +_bar(const char *path, unsigned *flag) +{ + *flag += 1; + + if(!path) + { + return; + } + + assert(!strcmp(path, "/bar") + || !strcmp(path, "/{foo,bar}")); +} + +static void +_hook_one(const char *path, const LV2_Atom_Tuple *arguments __attribute__((unused)), + void *data) +{ + _one(path, data); +} + +static void +_hook_two(const char *path, const LV2_Atom_Tuple *arguments __attribute__((unused)), + void *data) +{ + _two(path, data); +} + +static void +_hook_foo(const char *path, const LV2_Atom_Tuple *arguments __attribute__((unused)), + void *data) +{ + _foo(path, data); +} + +static void +_hook_bar(const char *path, const LV2_Atom_Tuple *arguments __attribute__((unused)), + void *data) +{ + _bar(path, data); +} + +static LV2_OSC_Hook hook_sub [] = { + { .name = "one", .method = _hook_one, .data = &foo_sub_one }, + { .name = "two", .method = _hook_two, .data = &foo_sub_two[0] }, + { .name = "two", .method = _hook_two, .data = &foo_sub_two[1] }, + { .name = NULL } +}; + +static LV2_OSC_Hook hook_root [] = { + { .name = "foo", .method = _hook_foo, .data = &foo }, + { .name = "bar", .method = _hook_bar, .data = &bar }, + { .name = "sub", .hooks = hook_sub }, + { .name = NULL } +}; + +static LV2_OSC_Tree tree_sub [4]; + +static void +_branch_one(LV2_OSC_Reader *reader __attribute__((unused)), + LV2_OSC_Arg *arg __attribute__((unused)), + const LV2_OSC_Tree *tree __attribute__((unused)), + void *data __attribute__((unused))) +{ + _one(NULL, &foo_sub_one); +} + +static void +_branch_two(LV2_OSC_Reader *reader __attribute__((unused)), + LV2_OSC_Arg *arg __attribute__((unused)), + const LV2_OSC_Tree *tree __attribute__((unused)), + void *data __attribute__((unused))) +{ + const size_t idx = tree - &tree_sub[1]; + + _two(NULL, &foo_sub_two[idx]); +} + +static void +_branch_foo(LV2_OSC_Reader *reader __attribute__((unused)), + LV2_OSC_Arg *arg __attribute__((unused)), + const LV2_OSC_Tree *tree __attribute__((unused)), + void *data __attribute__((unused))) +{ + _foo(NULL, &foo); +} + +static void +_branch_bar(LV2_OSC_Reader *reader __attribute__((unused)), + LV2_OSC_Arg *arg __attribute__((unused)), + const LV2_OSC_Tree *tree __attribute__((unused)), + void *data __attribute__((unused))) +{ + _bar(NULL, &bar); +} + +static LV2_OSC_Tree tree_sub [] = { + { .name = "one", .branch = _branch_one }, + { .name = "two", .branch = _branch_two }, + { .name = "two", .branch = _branch_two }, + { .name = NULL } +}; + +static LV2_OSC_Tree tree_root [] = { + { .name = "foo", .branch = _branch_foo }, + { .name = "bar", .branch = _branch_bar }, + { .name = "sub", .trees = tree_sub }, + { .name = NULL } +}; + +static bool +_run_test_hooks_internal(const char *path) +{ + foo_sub_one = foo_sub_two[0] = foo_sub_two[1] = foo = bar = false; + + { + LV2_OSC_URID osc_urid; + LV2_Atom_Forge forge; + + lv2_osc_urid_init(&osc_urid, &map); + lv2_atom_forge_init(&forge, &map); + + lv2_atom_forge_set_buffer(&forge, buf0, BUF_SIZE); + assert(lv2_osc_forge_message_vararg(&forge, &osc_urid, path, "")); + + const LV2_Atom_Object *obj = (const LV2_Atom_Object *)buf0;; + assert(lv2_osc_unroll(&osc_urid, obj, lv2_osc_hooks, hook_root) == true); + } + + { + LV2_OSC_Writer writer; + LV2_OSC_Reader reader; + + lv2_osc_writer_initialize(&writer, buf1, BUF_SIZE); + assert(lv2_osc_writer_message_vararg(&writer, path, "") == true); + + size_t len; + const uint8_t *buf = lv2_osc_writer_finalize(&writer, &len); + assert(buf); + assert(len); + + lv2_osc_reader_initialize(&reader, buf, len); + lv2_osc_reader_match(&reader, len, tree_root, NULL); + } + + return true; +} + +static int +_run_test_hooks() +{ + { + assert(_run_test_hooks_internal("/nil") == true); + assert(foo == 0); + assert(bar == 0); + assert(foo_sub_one == 0); + assert(foo_sub_two[0] == 0); + assert(foo_sub_two[1] == 0); + } + + { + assert(_run_test_hooks_internal("/foo") == true); + assert(foo == 2); + assert(bar == 0); + assert(foo_sub_one == 0); + assert(foo_sub_two[0] == 0); + assert(foo_sub_two[1] == 0); + } + + { + assert(_run_test_hooks_internal("/bar") == true); + assert(foo == 0); + assert(bar == 2); + assert(foo_sub_one == 0); + assert(foo_sub_two[0] == 0); + assert(foo_sub_two[1] == 0); + } + + { + assert(_run_test_hooks_internal("/sub/nil") == true); + assert(foo == 0); + assert(bar == 0); + assert(foo_sub_one == 0); + assert(foo_sub_two[0] == 0); + assert(foo_sub_two[1] == 0); + } + + { + assert(_run_test_hooks_internal("/sub/one") == true); + assert(foo == 0); + assert(bar == 0); + assert(foo_sub_one == 2); + assert(foo_sub_two[0] == 0); + assert(foo_sub_two[1] == 0); + } + + { + assert(_run_test_hooks_internal("/sub/two") == true); + assert(foo == 0); + assert(bar == 0); + assert(foo_sub_one == 0); + assert(foo_sub_two[0] == 2); + assert(foo_sub_two[1] == 2); + } + + { + assert(_run_test_hooks_internal("/sub/*") == true); + assert(foo == 0); + assert(bar == 0); + assert(foo_sub_one == 2); + assert(foo_sub_two[0] == 2); + assert(foo_sub_two[1] == 2); + } + + { + assert(_run_test_hooks_internal("/*/one") == true); + assert(foo == 0); + assert(bar == 0); + assert(foo_sub_one == 2); + assert(foo_sub_two[0] == 0); + assert(foo_sub_two[1] == 0); + } + + { + assert(_run_test_hooks_internal("/s*/one") == true); + assert(foo == 0); + assert(bar == 0); + assert(foo_sub_one == 2); + assert(foo_sub_two[0] == 0); + assert(foo_sub_two[1] == 0); + } + + { + assert(_run_test_hooks_internal("/su*/one") == true); + assert(foo == 0); + assert(bar == 0); + assert(foo_sub_one == 2); + assert(foo_sub_two[0] == 0); + assert(foo_sub_two[1] == 0); + } + + { + assert(_run_test_hooks_internal("/sub*/one") == true); + assert(foo == 0); + assert(bar == 0); + assert(foo_sub_one == 2); + assert(foo_sub_two[0] == 0); + assert(foo_sub_two[1] == 0); + } + + { + assert(_run_test_hooks_internal("/*sub/one") == true); + assert(foo == 0); + assert(bar == 0); + assert(foo_sub_one == 2); + assert(foo_sub_two[0] == 0); + assert(foo_sub_two[1] == 0); + } + + { + assert(_run_test_hooks_internal("/*s*u*b*/one") == true); + assert(foo == 0); + assert(bar == 0); + assert(foo_sub_one == 2); + assert(foo_sub_two[0] == 0); + assert(foo_sub_two[1] == 0); + } + + { + assert(_run_test_hooks_internal("/su[ab]/one") == true); + assert(foo == 0); + assert(bar == 0); + assert(foo_sub_one == 2); + assert(foo_sub_two[0] == 0); + assert(foo_sub_two[1] == 0); + } + + { + assert(_run_test_hooks_internal("/su[a-b]/[!a-np-z]ne") == true); + assert(foo == 0); + assert(bar == 0); + assert(foo_sub_one == 2); + assert(foo_sub_two[0] == 0); + assert(foo_sub_two[1] == 0); + } + + { + assert(_run_test_hooks_internal("/su[!a-b]/one") == true); + assert(foo == 0); + assert(bar == 0); + assert(foo_sub_one == 0); + assert(foo_sub_two[0] == 0); + assert(foo_sub_two[1] == 0); + } + + { + assert(_run_test_hooks_internal("/s?b/?ne") == true); + assert(foo == 0); + assert(bar == 0); + assert(foo_sub_one == 2); + assert(foo_sub_two[0] == 0); + assert(foo_sub_two[1] == 0); + } + + { + assert(_run_test_hooks_internal("/s?*/*?e") == true); + assert(foo == 0); + assert(bar == 0); + assert(foo_sub_one == 2); + assert(foo_sub_two[0] == 0); + assert(foo_sub_two[1] == 0); + } + + { + assert(_run_test_hooks_internal("/{foo,bar}") == true); + assert(foo == 2); + assert(bar == 2); + assert(foo_sub_one == 0); + assert(foo_sub_two[0] == 0); + assert(foo_sub_two[1] == 0); + } + + { + assert(_run_test_hooks_internal("/sub/{one,two}") == true); + assert(foo == 0); + assert(bar == 0); + assert(foo_sub_one == 2); + assert(foo_sub_two[0] == 2); + assert(foo_sub_two[1] == 2); + } + + return 0; +} +#endif + +int +main(int argc __attribute__((unused)), char **argv __attribute__((unused))) +{ +#if !defined(_WIN32) + (void)lv2_osc_stream_pollin; //FIXME +#endif + + fprintf(stdout, "running main tests:\n"); + assert(_run_tests() == 0); + +#if !defined(_WIN32) + fprintf(stdout, "running hook tests:\n"); + assert(_run_test_hooks() == 0); +#else + (void)lv2_osc_hooks; //FIXME +#endif + +#if !defined(_WIN32) + for(const pair_t *pair = pairs; pair->server; pair++) + { + pthread_t thread_1; + pthread_t thread_2; + + fprintf(stdout, "running stream test: <%s> <%s> %i\n", + pair->server, pair->client, pair->lossy); + + assert(pthread_create(&thread_1, NULL, _thread_1, (void *)pair) == 0); + assert(pthread_create(&thread_2, NULL, _thread_2, (void *)pair) == 0); + + assert(pthread_join(thread_1, NULL) == 0); + assert(pthread_join(thread_2, NULL) == 0); + } +#endif + + for(unsigned i=0; i<__app.urid; i++) + { + urid_t *itm = &__app.urids[i]; + + free(itm->uri); + } + + return 0; +} diff --git a/osc_inspector.c b/osc_inspector.c new file mode 100644 index 0000000..634c7f2 --- /dev/null +++ b/osc_inspector.c @@ -0,0 +1,270 @@ +/* + * Copyright (c) 2015-2020 Hanspeter Portner (dev@open-music-kontrollers.ch) + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the Artistic License 2.0 as published by + * The Perl Foundation. + * + * This source is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Artistic License 2.0 for more details. + * + * You should have received a copy of the Artistic License 2.0 + * along the source as a COPYING file. If not, obtain it from + * http://www.perlfoundation.org/artistic_license_2_0. + */ + +#include <stdio.h> +#include <stdlib.h> + +#include <sherlock.h> + +#include <osc.lv2/util.h> + +typedef struct _handle_t handle_t; + +struct _handle_t { + LV2_URID_Map *map; + LV2_URID_Unmap *unmap; + LV2_Log_Log *log; + LV2_Log_Logger logger; + + const LV2_Atom_Sequence *control; + craft_t through; + craft_t notify; + + LV2_URID time_position; + LV2_URID time_frame; + + LV2_OSC_URID osc_urid; + + int64_t frame; + + PROPS_T(props, MAX_NPROPS); + state_t state; + state_t stash; +}; + +static LV2_Handle +instantiate(const LV2_Descriptor* descriptor, double rate __attribute__((unused)), + const char *bundle_path __attribute__((unused)), + const LV2_Feature *const *features) +{ + int i; + handle_t *handle = calloc(1, sizeof(handle_t)); + if(!handle) + return NULL; + + for(i=0; features[i]; i++) + { + if(!strcmp(features[i]->URI, LV2_URID__map)) + handle->map = features[i]->data; + else if(!strcmp(features[i]->URI, LV2_URID__unmap)) + handle->unmap = features[i]->data; + else if(!strcmp(features[i]->URI, LV2_LOG__log)) + handle->log = features[i]->data; + } + + if(!handle->map || !handle->unmap) + { + fprintf(stderr, "%s: Host does not support urid:(un)map\n", descriptor->URI); + free(handle); + return NULL; + } + + if(handle->log) + lv2_log_logger_init(&handle->logger, handle->map, handle->log); + + handle->time_position = handle->map->map(handle->map->handle, LV2_TIME__Position); + handle->time_frame = handle->map->map(handle->map->handle, LV2_TIME__frame); + lv2_osc_urid_init(&handle->osc_urid, handle->map); + + lv2_atom_forge_init(&handle->through.forge, handle->map); + lv2_atom_forge_init(&handle->notify.forge, handle->map); + + if(!props_init(&handle->props, descriptor->URI, + defs, MAX_NPROPS, &handle->state, &handle->stash, + handle->map, handle)) + { + fprintf(stderr, "failed to allocate property structure\n"); + free(handle); + return NULL; + } + + return handle; +} + +static void +connect_port(LV2_Handle instance, uint32_t port, void *data) +{ + handle_t *handle = (handle_t *)instance; + + switch(port) + { + case 0: + handle->control = (const LV2_Atom_Sequence *)data; + break; + case 1: + handle->through.seq = (LV2_Atom_Sequence *)data; + break; + case 2: + handle->notify.seq = (LV2_Atom_Sequence *)data; + break; + default: + break; + } +} + +static void +run(LV2_Handle instance, uint32_t nsamples) +{ + handle_t *handle = (handle_t *)instance; + craft_t *through = &handle->through; + craft_t *notify = &handle->notify; + + uint32_t capacity = through->seq->atom.size; + lv2_atom_forge_set_buffer(&through->forge, through->buf, capacity); + through->ref = lv2_atom_forge_sequence_head(&through->forge, &through->frame[0], 0); + + capacity = notify->seq->atom.size; + lv2_atom_forge_set_buffer(¬ify->forge, notify->buf, capacity); + notify->ref = lv2_atom_forge_sequence_head(¬ify->forge, ¬ify->frame[0], 0); + + props_idle(&handle->props, ¬ify->forge, 0, ¬ify->ref); + + LV2_ATOM_SEQUENCE_FOREACH(handle->control, ev) + { + const LV2_Atom_Object *obj = (const LV2_Atom_Object *)&ev->body; + const int64_t frames = ev->time.frames; + + // copy all events to through port + if(through->ref) + through->ref = lv2_atom_forge_frame_time(&through->forge, frames); + if(through->ref) + through->ref = lv2_atom_forge_raw(&through->forge, &obj->atom, lv2_atom_total_size(&obj->atom)); + if(through->ref) + lv2_atom_forge_pad(&through->forge, obj->atom.size); + + if( !props_advance(&handle->props, ¬ify->forge, frames, obj, ¬ify->ref) + && lv2_atom_forge_is_object_type(¬ify->forge, obj->atom.type) + && (obj->body.otype == handle->time_position) ) + { + const LV2_Atom_Long *time_frame = NULL; + lv2_atom_object_get(obj, handle->time_frame, &time_frame, NULL); + if(time_frame) + handle->frame = time_frame->body - frames; + } + } + + if(through->ref) + lv2_atom_forge_pop(&through->forge, &through->frame[0]); + else + { + lv2_atom_sequence_clear(through->seq); + + if(handle->log) + lv2_log_trace(&handle->logger, "through buffer overflow\n"); + } + + bool has_event = notify->seq->atom.size > sizeof(LV2_Atom_Sequence_Body); + + if(notify->ref) + notify->ref = lv2_atom_forge_frame_time(¬ify->forge, nsamples-1); + if(notify->ref) + notify->ref = lv2_atom_forge_tuple(¬ify->forge, ¬ify->frame[1]); + if(notify->ref) + notify->ref = lv2_atom_forge_long(¬ify->forge, handle->frame); + if(notify->ref) + notify->ref = lv2_atom_forge_int(¬ify->forge, nsamples); + if(notify->ref) + notify->ref = lv2_atom_forge_sequence_head(¬ify->forge, ¬ify->frame[2], 0); + + // only serialize OSC events to UI + LV2_ATOM_SEQUENCE_FOREACH(handle->control, ev) + { + const LV2_Atom_Object *obj = (const LV2_Atom_Object *)&ev->body; + + if( lv2_atom_forge_is_object_type(¬ify->forge, obj->atom.type) + && lv2_osc_is_message_or_bundle_type(&handle->osc_urid, obj->body.otype) ) + { + has_event = true; + if(notify->ref) + notify->ref = lv2_atom_forge_frame_time(¬ify->forge, ev->time.frames); + if(notify->ref) + notify->ref = lv2_atom_forge_write(¬ify->forge, &ev->body, sizeof(LV2_Atom) + ev->body.size); + } + } + + if(notify->ref) + lv2_atom_forge_pop(¬ify->forge, ¬ify->frame[2]); + if(notify->ref) + lv2_atom_forge_pop(¬ify->forge, ¬ify->frame[1]); + if(notify->ref) + lv2_atom_forge_pop(¬ify->forge, ¬ify->frame[0]); + else + { + lv2_atom_sequence_clear(notify->seq); + + if(handle->log) + lv2_log_trace(&handle->logger, "notify buffer overflow\n"); + } + + if(!has_event) // don't send anything + lv2_atom_sequence_clear(notify->seq); + + handle->frame += nsamples; +} + +static void +cleanup(LV2_Handle instance) +{ + handle_t *handle = (handle_t *)instance; + + free(handle); +} + +static LV2_State_Status +_state_save(LV2_Handle instance, LV2_State_Store_Function store, + LV2_State_Handle state, uint32_t flags, + const LV2_Feature *const *features) +{ + handle_t *handle = instance; + + return props_save(&handle->props, store, state, flags, features); +} + +static LV2_State_Status +_state_restore(LV2_Handle instance, LV2_State_Retrieve_Function retrieve, + LV2_State_Handle state, uint32_t flags, + const LV2_Feature *const *features) +{ + handle_t *handle = instance; + + return props_restore(&handle->props, retrieve, state, flags, features); +} + +static const LV2_State_Interface state_iface = { + .save = _state_save, + .restore = _state_restore +}; + +static const void* +extension_data(const char* uri) +{ + if(!strcmp(uri, LV2_STATE__interface)) + return &state_iface; + + return NULL; +} + +const LV2_Descriptor osc_inspector = { + .URI = SHERLOCK_OSC_INSPECTOR_URI, + .instantiate = instantiate, + .connect_port = connect_port, + .activate = NULL, + .run = run, + .deactivate = NULL, + .cleanup = cleanup, + .extension_data = extension_data +}; diff --git a/osc_inspector_nk.c b/osc_inspector_nk.c new file mode 100644 index 0000000..0f9623c --- /dev/null +++ b/osc_inspector_nk.c @@ -0,0 +1,446 @@ +/* + * Copyright (c) 2015-2020 Hanspeter Portner (dev@open-music-kontrollers.ch) + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the Artistic License 2.0 as published by + * The Perl Foundation. + * + * This source is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Artistic License 2.0 for more details. + * + * You should have received a copy of the Artistic License 2.0 + * along the source as a COPYING file. If not, obtain it from + * http://www.perlfoundation.org/artistic_license_2_0. + */ + +#include <time.h> +#include <math.h> +#include <inttypes.h> + +#include <sherlock.h> +#include <sherlock_nk.h> +#include <encoder.h> + +#include <osc.lv2/util.h> + +typedef struct _mem_t mem_t; + +struct _mem_t { + size_t size; + char *buf; +}; + +static inline void +_shadow(struct nk_context *ctx, bool *shadow) +{ + if(*shadow) + { + struct nk_style *style = &ctx->style; + const struct nk_vec2 group_padding = style->window.group_padding; + struct nk_command_buffer *canvas = nk_window_get_canvas(ctx); + + struct nk_rect b = nk_widget_bounds(ctx); + b.x -= group_padding.x; + b.w *= 10; + b.w += 5*group_padding.x; + nk_fill_rect(canvas, b, 0.f, nk_rgb(0x28, 0x28, 0x28)); + } + + *shadow = !*shadow; +} + +static inline void +_mem_printf(mem_t *mem, const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + + char *src; + if(vasprintf(&src, fmt, args) != -1) + { + const size_t sz = strlen(src); + + mem->buf = realloc(mem->buf, mem->size + sz); + if(mem->buf) + { + char *dst = mem->buf + mem->size - 1; + + strncpy(dst, src, sz + 1); + mem->size += sz; + } + else + mem->size = 0; + + free(src); + } + + va_end(args); +} + +static void +_osc_timetag(mem_t *mem, LV2_OSC_Timetag *tt) +{ + if(tt->integral <= 1UL) + { + _mem_printf(mem, "t : %s", "immediate"); + } + else + { + const uint32_t us = floor(tt->fraction * 0x1p-32 * 1e6); + const time_t ttime = tt->integral - 0x83aa7e80; + const struct tm *ltime = localtime(&ttime); + + char tmp [32]; + if(strftime(tmp, 32, "%d-%b-%Y %T", ltime)) + _mem_printf(mem, "t : %s.%06"PRIu32, tmp, us); + } +} + +static void +_osc_argument(plughandle_t *handle, struct nk_context *ctx, const LV2_Atom *arg, + const char *path, bool first) +{ + const LV2_OSC_Type type = lv2_osc_argument_type(&handle->osc_urid, arg); + + mem_t mem = { + .size = 1, + .buf = calloc(1, sizeof(char)) + }; + + switch(type) + { + case LV2_OSC_INT32: + { + int32_t i; + lv2_osc_int32_get(&handle->osc_urid, arg, &i); + _mem_printf(&mem, "i : %"PRIi32, i); + } break; + case LV2_OSC_FLOAT: + { + float f; + lv2_osc_float_get(&handle->osc_urid, arg, &f); + _mem_printf(&mem, "f : %f", f); + } break; + case LV2_OSC_STRING: + { + const char *s; + lv2_osc_string_get(&handle->osc_urid, arg, &s); + _mem_printf(&mem, "s : %s", s); + } break; + case LV2_OSC_BLOB: + { + uint32_t sz; + const uint8_t *b; + lv2_osc_blob_get(&handle->osc_urid, arg, &sz, &b); + _mem_printf(&mem, "b : (%"PRIu32") ", sz); + for(unsigned i=0; i<sz; i++) + _mem_printf(&mem, "%02"PRIx8, b[i]); + } break; + + case LV2_OSC_TRUE: + { + _mem_printf(&mem, "T : true"); + } break; + case LV2_OSC_FALSE: + { + _mem_printf(&mem, "F : false"); + } break; + case LV2_OSC_NIL: + { + _mem_printf(&mem, "N : nil"); + } break; + case LV2_OSC_IMPULSE: + { + _mem_printf(&mem, "I : impulse"); + } break; + + case LV2_OSC_INT64: + { + int64_t h; + lv2_osc_int64_get(&handle->osc_urid, arg, &h); + _mem_printf(&mem, "h : %"PRIi64, h); + } break; + case LV2_OSC_DOUBLE: + { + double d; + lv2_osc_double_get(&handle->osc_urid, arg, &d); + _mem_printf(&mem, "d : %lf", d); + } break; + case LV2_OSC_TIMETAG: + { + LV2_OSC_Timetag tt; + lv2_osc_timetag_get(&handle->osc_urid, arg, &tt); + _osc_timetag(&mem, &tt); + } break; + + case LV2_OSC_SYMBOL: + { + LV2_URID S; + lv2_osc_symbol_get(&handle->osc_urid, arg, &S); + _mem_printf(&mem, "S : %s", handle->unmap->unmap(handle->unmap->handle, S)); + } break; + case LV2_OSC_CHAR: + { + char c; + lv2_osc_char_get(&handle->osc_urid, arg, &c); + _mem_printf(&mem, "c : %c", c); + } break; + case LV2_OSC_RGBA: + { + uint8_t r [4]; + lv2_osc_rgba_get(&handle->osc_urid, arg, r+0, r+1, r+2, r+3); + _mem_printf(&mem, "r : "); + for(unsigned i=0; i<4; i++) + _mem_printf(&mem, "%02"PRIx8, r[i]); + } break; + case LV2_OSC_MIDI: + { + uint32_t sz; + const uint8_t *m; + lv2_osc_midi_get(&handle->osc_urid, arg, &sz, &m); + _mem_printf(&mem, "m : (%"PRIu32") ", sz); + for(unsigned i=0; i<sz; i++) + _mem_printf(&mem, "%02"PRIx8, m[i]); + } break; + } + + if(!first) + { + _shadow(ctx, &handle->shadow); + _empty(ctx); + } + + if(first) + { + nk_label_colored(ctx, path, NK_TEXT_LEFT, magenta); + } + else + { + _empty(ctx); + } + + if(mem.buf) + { + nk_label_colored(ctx, mem.buf, NK_TEXT_LEFT, cwhite); + free(mem.buf); + } + else + { + _empty(ctx); + } + + nk_labelf_colored(ctx, NK_TEXT_RIGHT, blue, "%"PRIu32, arg->size); +} + +static void +_osc_message(plughandle_t *handle, struct nk_context *ctx, const LV2_Atom_Object *obj) +{ + const LV2_Atom_String *path = NULL; + const LV2_Atom_Tuple *args = NULL; + lv2_osc_message_get(&handle->osc_urid, obj, &path, &args); + + bool first = true; + LV2_ATOM_TUPLE_FOREACH(args, arg) + { + _osc_argument(handle, ctx, arg, LV2_ATOM_BODY_CONST(path), first); + + if(first) + first = false; + } +} + +static void +_osc_packet(plughandle_t *handle, struct nk_context *ctx, int64_t frames, + const LV2_Atom_Object *obj, float offset); + +static void +_osc_bundle(plughandle_t *handle, struct nk_context *ctx, const LV2_Atom_Object *obj, float offset) +{ + const LV2_Atom_Object *timetag = NULL; + const LV2_Atom_Tuple *items = NULL; + lv2_osc_bundle_get(&handle->osc_urid, obj, &timetag, &items); + + // format bundle timestamp + LV2_OSC_Timetag tt; + lv2_osc_timetag_get(&handle->osc_urid, &timetag->atom, &tt); + + mem_t mem = { + .size = 1, + .buf = calloc(1, sizeof(char)) + }; + + nk_label_colored(ctx, "#bundle", NK_TEXT_LEFT, red); + + _osc_timetag(&mem, &tt); + if(mem.buf) + { + nk_label_colored(ctx, mem.buf, NK_TEXT_LEFT, cwhite); + free(mem.buf); + } + else + { + _empty(ctx); + } + + nk_labelf_colored(ctx, NK_TEXT_RIGHT, blue, "%"PRIu32, obj->atom.size); + + LV2_ATOM_TUPLE_FOREACH(items, item) + { + _osc_packet(handle, ctx, -1, (const LV2_Atom_Object *)item, offset + 0.025); + } +} + +static void +_osc_packet(plughandle_t *handle, struct nk_context *ctx, int64_t frames, + const LV2_Atom_Object *obj, float offset) +{ + const float widget_h = handle->dy; + + const float ratios [4] = {offset, 0.3f - offset, 0.6f, 0.1f}; + nk_layout_row(ctx, NK_DYNAMIC, widget_h, 4, ratios); + + _shadow(ctx, &handle->shadow); + if(frames >= 0) + { + nk_labelf_colored(ctx, NK_TEXT_LEFT, yellow, "+%04"PRIi64, frames); + } + else + { + _empty(ctx); + } + + if(lv2_osc_is_message_type(&handle->osc_urid, obj->body.otype)) + { + _osc_message(handle, ctx, obj); + } + else if(lv2_osc_is_bundle_type(&handle->osc_urid, obj->body.otype)) + { + _osc_bundle(handle, ctx, obj, offset); + } +} + +void +_osc_inspector_expose(struct nk_context *ctx, struct nk_rect wbounds, void *data) +{ + plughandle_t *handle = data; + + handle->dy = 20.f * _get_scale(handle); + const float widget_h = handle->dy; + struct nk_style *style = &ctx->style; + const struct nk_vec2 window_padding = style->window.padding; + const struct nk_vec2 group_padding = style->window.group_padding; + + const char *window_name = "Sherlock"; + if(nk_begin(ctx, window_name, wbounds, NK_WINDOW_NO_SCROLLBAR)) + { + struct nk_panel *panel = nk_window_get_panel(ctx); + struct nk_command_buffer *canvas = nk_window_get_canvas(ctx); + + const float body_h = panel->bounds.h - 4*window_padding.y - 2*widget_h; + nk_layout_row_dynamic(ctx, body_h, 1); + nk_flags flags = NK_WINDOW_BORDER; + if(handle->state.follow) + { + flags |= NK_WINDOW_NO_SCROLLBAR; + } + else + { + handle->shadow = false; + } + struct nk_list_view lview; + if(nk_list_view_begin(ctx, &lview, "Events", flags, widget_h, NK_MIN(handle->n_item, MAX_LINES))) + { + if(handle->state.follow) + { + lview.end = NK_MAX(handle->n_item, 0); + lview.begin = NK_MAX(lview.end - lview.count, 0); + } + for(int l = lview.begin; (l < lview.end) && (l < handle->n_item); l++) + { + item_t *itm = handle->items[l]; + + switch(itm->type) + { + case ITEM_TYPE_NONE: + { + // skip, was bundle payload + } break; + case ITEM_TYPE_FRAME: + { + nk_layout_row_dynamic(ctx, widget_h, 3); + { + struct nk_rect b = nk_widget_bounds(ctx); + b.x -= group_padding.x; + b.w *= 3; + b.w += 4*group_padding.x; + nk_fill_rect(canvas, b, 0.f, nk_rgb(0x18, 0x18, 0x18)); + } + + nk_labelf_colored(ctx, NK_TEXT_LEFT, orange, "@%"PRIi64, itm->frame.offset); + nk_labelf_colored(ctx, NK_TEXT_CENTERED, green, "-%"PRIu32"-", itm->frame.counter); + nk_labelf_colored(ctx, NK_TEXT_RIGHT, violet, "%"PRIi32, itm->frame.nsamples); + + handle->shadow = false; + } break; + + case ITEM_TYPE_EVENT: + { + LV2_Atom_Event *ev = &itm->event.ev; + const LV2_Atom_Object *obj = (const LV2_Atom_Object *)&ev->body; + const int64_t frames = ev->time.frames; + const float offset = 0.1; + + _osc_packet(handle, ctx, frames, obj, offset); + } break; + } + } + + nk_list_view_end(&lview); + } + + const float n = 3; + const float r0 = 1.f / n; + const float r1 = 0.1f / 3; + const float r2 = r0 - r1; + const float footer [6] = {r1, r2, r1, r2, r1, r2}; + nk_layout_row(ctx, NK_DYNAMIC, widget_h, 6, footer); + { + const int32_t state_overwrite = _check(ctx, handle->state.overwrite); + if(state_overwrite != handle->state.overwrite) + { + handle->state.overwrite = state_overwrite; + _set_bool(handle, handle->urid.overwrite, handle->state.overwrite); + } + nk_label(ctx, "overwrite", NK_TEXT_LEFT); + + const int32_t state_block = _check(ctx, handle->state.block); + if(state_block != handle->state.block) + { + handle->state.block = state_block; + _set_bool(handle, handle->urid.block, handle->state.block); + } + nk_label(ctx, "block", NK_TEXT_LEFT); + + const int32_t state_follow = _check(ctx, handle->state.follow); + if(state_follow != handle->state.follow) + { + handle->state.follow = state_follow; + _set_bool(handle, handle->urid.follow, handle->state.follow); + } + nk_label(ctx, "follow", NK_TEXT_LEFT); + } + + const bool max_reached = handle->n_item >= MAX_LINES; + nk_layout_row_dynamic(ctx, widget_h, 2); + if(nk_button_symbol_label(ctx, + max_reached ? NK_SYMBOL_TRIANGLE_RIGHT: NK_SYMBOL_NONE, + "clear", NK_TEXT_LEFT)) + { + _clear(handle); + } + nk_label(ctx, "Sherlock.lv2: "SHERLOCK_VERSION, NK_TEXT_RIGHT); + } + nk_end(ctx); +} diff --git a/props.lv2/.gitlab-ci.yml b/props.lv2/.gitlab-ci.yml new file mode 100644 index 0000000..dd2bcb6 --- /dev/null +++ b/props.lv2/.gitlab-ci.yml @@ -0,0 +1,75 @@ +stages: + - build + - test + - deploy + +.variables_template: &variables_definition + variables: + BASE_NAME: "props.lv2" + PKG_CONFIG_PATH: "/opt/lv2/lib/pkgconfig:/opt/${CI_BUILD_NAME}/lib/pkgconfig" + +.common_template: &common_definition + <<: *variables_definition + stage: build + artifacts: + name: "${BASE_NAME}-$(cat VERSION)-${CI_BUILD_NAME}" + paths: + - "${BASE_NAME}-$(cat VERSION)/" + +.build_template: &build_definition + <<: *common_definition + script: + - mkdir build + - pushd build + - cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=${CI_PROJECT_DIR} -DPLUGIN_DEST="${BASE_NAME}-$(cat ../VERSION)/${CI_BUILD_NAME}/${BASE_NAME}" -DCMAKE_CI_BUILD_NAME=${CI_BUILD_NAME} .. + - cmake .. # needed for darwin + - make + - make install + +.universal_linux_template: &universal_linux_definition + image: ventosus/universal-linux-gnu + <<: *build_definition + +.arm_linux_template: &arm_linux_definition + image: ventosus/arm-linux-gnueabihf + <<: *build_definition + +.universal_w64_template: &universal_w64_definition + image: ventosus/universal-w64-mingw32 + <<: *build_definition + +.universal_apple_template: &universal_apple_definition + image: ventosus/universal-apple-darwin + <<: *build_definition + +# building in docker +x86_64-linux-gnu: + <<: *universal_linux_definition + +i686-linux-gnu: + <<: *universal_linux_definition + +arm-linux-gnueabihf: + <<: *arm_linux_definition + +aarch64-linux-gnu: + <<: *arm_linux_definition + +x86_64-w64-mingw32: + <<: *universal_w64_definition + +i686-w64-mingw32: + <<: *universal_w64_definition + +universal-apple-darwin: + <<: *universal_apple_definition + +pack: + <<: *variables_definition + stage: deploy + script: + - echo 'packing up...' + artifacts: + name: "${BASE_NAME}-$(cat VERSION)" + paths: + - "${BASE_NAME}-$(cat VERSION)/" diff --git a/props.lv2/COPYING b/props.lv2/COPYING new file mode 100644 index 0000000..ddb9a46 --- /dev/null +++ b/props.lv2/COPYING @@ -0,0 +1,201 @@ + The Artistic License 2.0 + + Copyright (c) 2000-2006, The Perl Foundation. + + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +Preamble + +This license establishes the terms under which a given free software +Package may be copied, modified, distributed, and/or redistributed. +The intent is that the Copyright Holder maintains some artistic +control over the development of that Package while still keeping the +Package available as open source and free software. + +You are always permitted to make arrangements wholly outside of this +license directly with the Copyright Holder of a given Package. If the +terms of this license do not permit the full use that you propose to +make of the Package, you should contact the Copyright Holder and seek +a different licensing arrangement. + +Definitions + + "Copyright Holder" means the individual(s) or organization(s) + named in the copyright notice for the entire Package. + + "Contributor" means any party that has contributed code or other + material to the Package, in accordance with the Copyright Holder's + procedures. + + "You" and "your" means any person who would like to copy, + distribute, or modify the Package. + + "Package" means the collection of files distributed by the + Copyright Holder, and derivatives of that collection and/or of + those files. A given Package may consist of either the Standard + Version, or a Modified Version. + + "Distribute" means providing a copy of the Package or making it + accessible to anyone else, or in the case of a company or + organization, to others outside of your company or organization. + + "Distributor Fee" means any fee that you charge for Distributing + this Package or providing support for this Package to another + party. It does not mean licensing fees. + + "Standard Version" refers to the Package if it has not been + modified, or has been modified only in ways explicitly requested + by the Copyright Holder. + + "Modified Version" means the Package, if it has been changed, and + such changes were not explicitly requested by the Copyright + Holder. + + "Original License" means this Artistic License as Distributed with + the Standard Version of the Package, in its current version or as + it may be modified by The Perl Foundation in the future. + + "Source" form means the source code, documentation source, and + configuration files for the Package. + + "Compiled" form means the compiled bytecode, object code, binary, + or any other form resulting from mechanical transformation or + translation of the Source form. + + +Permission for Use and Modification Without Distribution + +(1) You are permitted to use the Standard Version and create and use +Modified Versions for any purpose without restriction, provided that +you do not Distribute the Modified Version. + + +Permissions for Redistribution of the Standard Version + +(2) You may Distribute verbatim copies of the Source form of the +Standard Version of this Package in any medium without restriction, +either gratis or for a Distributor Fee, provided that you duplicate +all of the original copyright notices and associated disclaimers. At +your discretion, such verbatim copies may or may not include a +Compiled form of the Package. + +(3) You may apply any bug fixes, portability changes, and other +modifications made available from the Copyright Holder. The resulting +Package will still be considered the Standard Version, and as such +will be subject to the Original License. + + +Distribution of Modified Versions of the Package as Source + +(4) You may Distribute your Modified Version as Source (either gratis +or for a Distributor Fee, and with or without a Compiled form of the +Modified Version) provided that you clearly document how it differs +from the Standard Version, including, but not limited to, documenting +any non-standard features, executables, or modules, and provided that +you do at least ONE of the following: + + (a) make the Modified Version available to the Copyright Holder + of the Standard Version, under the Original License, so that the + Copyright Holder may include your modifications in the Standard + Version. + + (b) ensure that installation of your Modified Version does not + prevent the user installing or running the Standard Version. In + addition, the Modified Version must bear a name that is different + from the name of the Standard Version. + + (c) allow anyone who receives a copy of the Modified Version to + make the Source form of the Modified Version available to others + under + + (i) the Original License or + + (ii) a license that permits the licensee to freely copy, + modify and redistribute the Modified Version using the same + licensing terms that apply to the copy that the licensee + received, and requires that the Source form of the Modified + Version, and of any works derived from it, be made freely + available in that license fees are prohibited but Distributor + Fees are allowed. + + +Distribution of Compiled Forms of the Standard Version +or Modified Versions without the Source + +(5) You may Distribute Compiled forms of the Standard Version without +the Source, provided that you include complete instructions on how to +get the Source of the Standard Version. Such instructions must be +valid at the time of your distribution. If these instructions, at any +time while you are carrying out such distribution, become invalid, you +must provide new instructions on demand or cease further distribution. +If you provide valid instructions or cease distribution within thirty +days after you become aware that the instructions are invalid, then +you do not forfeit any of your rights under this license. + +(6) You may Distribute a Modified Version in Compiled form without +the Source, provided that you comply with Section 4 with respect to +the Source of the Modified Version. + + +Aggregating or Linking the Package + +(7) You may aggregate the Package (either the Standard Version or +Modified Version) with other packages and Distribute the resulting +aggregation provided that you do not charge a licensing fee for the +Package. Distributor Fees are permitted, and licensing fees for other +components in the aggregation are permitted. The terms of this license +apply to the use and Distribution of the Standard or Modified Versions +as included in the aggregation. + +(8) You are permitted to link Modified and Standard Versions with +other works, to embed the Package in a larger work of your own, or to +build stand-alone binary or bytecode versions of applications that +include the Package, and Distribute the result without restriction, +provided the result does not expose a direct interface to the Package. + + +Items That are Not Considered Part of a Modified Version + +(9) Works (including, but not limited to, modules and scripts) that +merely extend or make use of the Package, do not, by themselves, cause +the Package to be a Modified Version. In addition, such works are not +considered parts of the Package itself, and are not subject to the +terms of this license. + + +General Provisions + +(10) Any use, modification, and distribution of the Standard or +Modified Versions is governed by this Artistic License. By using, +modifying or distributing the Package, you accept this license. Do not +use, modify, or distribute the Package, if you do not accept this +license. + +(11) If your Modified Version has been derived from a Modified +Version made by someone other than you, you are nevertheless required +to ensure that your Modified Version complies with the requirements of +this license. + +(12) This license does not grant you the right to use any trademark, +service mark, tradename, or logo of the Copyright Holder. + +(13) This license includes the non-exclusive, worldwide, +free-of-charge patent license to make, have made, use, offer to sell, +sell, import and otherwise transfer the Package with respect to any +patent claims licensable by the Copyright Holder that are necessarily +infringed by the Package. If you institute patent litigation +(including a cross-claim or counterclaim) against any party alleging +that the Package constitutes direct or contributory patent +infringement, then this Artistic License to you shall terminate on the +date that such litigation is filed. + +(14) Disclaimer of Warranty: +THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS +IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL +LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/props.lv2/README.md b/props.lv2/README.md new file mode 100644 index 0000000..08466d2 --- /dev/null +++ b/props.lv2/README.md @@ -0,0 +1,20 @@ +# Props.lv2 + +## Utility header for property based LV2 plugins + +### License + +Copyright (c) 2015 Hanspeter Portner (dev@open-music-kontrollers.ch) + +This is free software: you can redistribute it and/or modify +it under the terms of the Artistic License 2.0 as published by +The Perl Foundation. + +This source is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +Artistic License 2.0 for more details. + +You should have received a copy of the Artistic License 2.0 +along the source as a COPYING file. If not, obtain it from +<http://www.perlfoundation.org/artistic_license_2_0>. diff --git a/props.lv2/VERSION b/props.lv2/VERSION new file mode 100644 index 0000000..eac5392 --- /dev/null +++ b/props.lv2/VERSION @@ -0,0 +1 @@ +0.1.139 diff --git a/props.lv2/meson.build b/props.lv2/meson.build new file mode 100644 index 0000000..d354d89 --- /dev/null +++ b/props.lv2/meson.build @@ -0,0 +1,82 @@ +project('props.lv2', 'c', default_options : [ + 'buildtype=release', + 'warning_level=3', + 'werror=false', + 'b_lto=false', + 'c_std=c11']) + +add_project_arguments('-D_GNU_SOURCE', language : 'c') + +conf_data = configuration_data() +cc = meson.get_compiler('c') + +cp = find_program('cp') +lv2_validate = find_program('lv2_validate', native : true, required : false) +sord_validate = find_program('sord_validate', native : true, required : false) +lv2lint = find_program('lv2lint', required : false) +clone = [cp, '@INPUT@', '@OUTPUT@'] + +m_dep = cc.find_library('m') +lv2_dep = dependency('lv2', version : '>=1.14.0') + +inc_dir = [] + +inst_dir = join_paths(get_option('libdir'), 'lv2', meson.project_name()) + +dsp_srcs = [join_paths('test', 'props.c')] + +c_args = ['-fvisibility=hidden', + '-ffast-math'] + +mod = shared_module('props', dsp_srcs, + c_args : c_args, + include_directories : inc_dir, + name_prefix : '', + dependencies : [m_dep, lv2_dep], + install : true, + install_dir : inst_dir) + +version = run_command('cat', 'VERSION').stdout().strip().split('.') +conf_data.set('MAJOR_VERSION', version[0]) +conf_data.set('MINOR_VERSION', version[1]) +conf_data.set('MICRO_VERSION', version[2]) + +suffix = mod.full_path().strip().split('.')[-1] +conf_data.set('MODULE_SUFFIX', '.' + suffix) + +manifest_ttl = configure_file( + input : join_paths('test', 'manifest.ttl.in'), output : 'manifest.ttl', + configuration : conf_data, + install : true, + install_dir : inst_dir) +dsp_ttl = custom_target('props_ttl', + input : join_paths('test', 'props.ttl'), + output : 'props.ttl', + command : clone, + install : true, + install_dir : inst_dir) +custom_target('chunk_bin', + input : join_paths('test', 'chunk.bin'), + output : 'chunk.bin', + command : clone, + install : true, + install_dir : inst_dir) + +props_test = executable('props_test', + join_paths('test', 'props_test.c'), + c_args : c_args, + install : false) + +test('Test', props_test, + timeout : 240) + +if lv2_validate.found() and sord_validate.found() + test('LV2 validate', lv2_validate, + args : [manifest_ttl, dsp_ttl]) +endif + +if lv2lint.found() + test('LV2 lint', lv2lint, + args : ['-Ewarn', + 'http://open-music-kontrollers.ch/lv2/props#test']) +endif diff --git a/props.lv2/props.h b/props.lv2/props.h new file mode 100644 index 0000000..1d1cb64 --- /dev/null +++ b/props.lv2/props.h @@ -0,0 +1,1031 @@ +/* + * Copyright (c) 2015 Hanspeter Portner (dev@open-music-kontrollers.ch) + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the Artistic License 2.0 as published by + * The Perl Foundation. + * + * This source is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Artistic License 2.0 for more details. + * + * You should have received a copy of the Artistic License 2.0 + * along the source as a COPYING file. If not, obtain it from + * http://www.perlfoundation.org/artistic_license_2_0. + */ + +#ifndef _LV2_PROPS_H_ +#define _LV2_PROPS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdlib.h> +#include <stdatomic.h> +#include <stdio.h> + +#include <lv2/lv2plug.in/ns/lv2core/lv2.h> +#include <lv2/lv2plug.in/ns/ext/urid/urid.h> +#include <lv2/lv2plug.in/ns/ext/atom/atom.h> +#include <lv2/lv2plug.in/ns/ext/atom/forge.h> +#include <lv2/lv2plug.in/ns/ext/patch/patch.h> +#include <lv2/lv2plug.in/ns/ext/state/state.h> + +/***************************************************************************** + * API START + *****************************************************************************/ + +// structures +typedef struct _props_def_t props_def_t; +typedef struct _props_impl_t props_impl_t; +typedef struct _props_t props_t; + +// function callbacks +typedef void (*props_event_cb_t)( + void *data, + int64_t frames, + props_impl_t *impl); + +struct _props_def_t { + const char *property; + const char *type; + const char *access; + size_t offset; + bool hidden; + + uint32_t max_size; + props_event_cb_t event_cb; +}; + +struct _props_impl_t { + LV2_URID property; + LV2_URID type; + LV2_URID access; + + struct { + uint32_t size; + void *body; + } value; + struct { + uint32_t size; + void *body; + } stash; + + const props_def_t *def; + + atomic_int state; + bool stashing; +}; + +struct _props_t { + struct { + LV2_URID subject; + + LV2_URID patch_get; + LV2_URID patch_set; + LV2_URID patch_put; + LV2_URID patch_patch; + LV2_URID patch_wildcard; + LV2_URID patch_add; + LV2_URID patch_remove; + LV2_URID patch_subject; + LV2_URID patch_body; + LV2_URID patch_property; + LV2_URID patch_value; + LV2_URID patch_writable; + LV2_URID patch_readable; + LV2_URID patch_sequence; + LV2_URID patch_error; + LV2_URID patch_ack; + + LV2_URID atom_int; + LV2_URID atom_long; + LV2_URID atom_float; + LV2_URID atom_double; + LV2_URID atom_bool; + LV2_URID atom_urid; + LV2_URID atom_path; + LV2_URID atom_literal; + LV2_URID atom_vector; + LV2_URID atom_object; + LV2_URID atom_sequence; + + LV2_URID state_StateChanged; + } urid; + + void *data; + + bool stashing; + atomic_bool restoring; + + uint32_t max_size; + + unsigned nimpls; + props_impl_t impls [1]; +}; + +#define PROPS_T(PROPS, MAX_NIMPLS) \ + props_t (PROPS); \ + props_impl_t _impls [MAX_NIMPLS] + +// rt-safe +static inline int +props_init(props_t *props, const char *subject, + const props_def_t *defs, int nimpls, + void *value_base, void *stash_base, + LV2_URID_Map *map, void *data); + +// rt-safe +static inline void +props_idle(props_t *props, LV2_Atom_Forge *forge, uint32_t frames, + LV2_Atom_Forge_Ref *ref); + +// rt-safe +static inline int +props_advance(props_t *props, LV2_Atom_Forge *forge, uint32_t frames, + const LV2_Atom_Object *obj, LV2_Atom_Forge_Ref *ref); + +// rt-safe +static inline void +props_set(props_t *props, LV2_Atom_Forge *forge, uint32_t frames, + LV2_URID property, LV2_Atom_Forge_Ref *ref); + +// rt-safe +static inline void +props_get(props_t *props, LV2_Atom_Forge *forge, uint32_t frames, + LV2_URID property, LV2_Atom_Forge_Ref *ref); + +// rt-safe +static inline void +props_stash(props_t *props, LV2_URID property); + +// rt-safe +static inline LV2_URID +props_map(props_t *props, const char *property); + +// rt-safe +static inline const char * +props_unmap(props_t *props, LV2_URID property); + +// non-rt +static inline LV2_State_Status +props_save(props_t *props, LV2_State_Store_Function store, + LV2_State_Handle state, uint32_t flags, const LV2_Feature *const *features); + +// non-rt +static inline LV2_State_Status +props_restore(props_t *props, LV2_State_Retrieve_Function retrieve, + LV2_State_Handle state, uint32_t flags, const LV2_Feature *const *features); + +/***************************************************************************** + * API END + *****************************************************************************/ + +// enumerations +typedef enum _props_state_t { + PROP_STATE_NONE = 0, + PROP_STATE_LOCK = 1, + PROP_STATE_RESTORE = 2 +} props_state_t; + +static inline void +_props_impl_spin_lock(props_impl_t *impl, int from, int to) +{ + int expected = from; + const int desired = to; + + while(!atomic_compare_exchange_strong_explicit(&impl->state, &expected, desired, + memory_order_acquire, memory_order_acquire)) + { + // spin + } +} + +static inline bool +_props_impl_try_lock(props_impl_t *impl, int from, int to) +{ + int expected = from; + const int desired = to; + + return atomic_compare_exchange_strong_explicit(&impl->state, &expected, desired, + memory_order_acquire, memory_order_acquire); +} + +static inline void +_props_impl_unlock(props_impl_t *impl, int to) +{ + atomic_store_explicit(&impl->state, to, memory_order_release); +} + +static inline bool +_props_restoring_get(props_t *props) +{ + return atomic_exchange_explicit(&props->restoring, false, memory_order_acquire); +} + +static inline void +_props_restoring_set(props_t *props) +{ + atomic_store_explicit(&props->restoring, true, memory_order_release); +} + +static inline void +_props_qsort(props_impl_t *A, int n) +{ + if(n < 2) + return; + + const props_impl_t *p = A; + + int i = -1; + int j = n; + + while(true) + { + do { + i += 1; + } while(A[i].property < p->property); + + do { + j -= 1; + } while(A[j].property > p->property); + + if(i >= j) + break; + + const props_impl_t tmp = A[i]; + A[i] = A[j]; + A[j] = tmp; + } + + _props_qsort(A, j + 1); + _props_qsort(A + j + 1, n - j - 1); +} + +static inline props_impl_t * +_props_impl_get(props_t *props, LV2_URID property) +{ + props_impl_t *base = props->impls; + + for(int N = props->nimpls, half; N > 1; N -= half) + { + half = N/2; + props_impl_t *dst = &base[half]; + base = (dst->property > property) ? base : dst; + } + + return (base->property == property) ? base : NULL; +} + +static inline LV2_Atom_Forge_Ref +_props_patch_set(props_t *props, LV2_Atom_Forge *forge, uint32_t frames, + props_impl_t *impl, int32_t sequence_num) +{ + LV2_Atom_Forge_Frame obj_frame; + + LV2_Atom_Forge_Ref ref = lv2_atom_forge_frame_time(forge, frames); + + if(ref) + ref = lv2_atom_forge_object(forge, &obj_frame, 0, props->urid.patch_set); + { + if(props->urid.subject) // is optional + { + if(ref) + ref = lv2_atom_forge_key(forge, props->urid.patch_subject); + if(ref) + ref = lv2_atom_forge_urid(forge, props->urid.subject); + } + + if(sequence_num) // is optional + { + if(ref) + ref = lv2_atom_forge_key(forge, props->urid.patch_sequence); + if(ref) + ref = lv2_atom_forge_int(forge, sequence_num); + } + + if(ref) + ref = lv2_atom_forge_key(forge, props->urid.patch_property); + if(ref) + ref = lv2_atom_forge_urid(forge, impl->property); + + if(ref) + lv2_atom_forge_key(forge, props->urid.patch_value); + if(ref) + ref = lv2_atom_forge_atom(forge, impl->value.size, impl->type); + if(ref) + ref = lv2_atom_forge_write(forge, impl->value.body, impl->value.size); + } + if(ref) + lv2_atom_forge_pop(forge, &obj_frame); + + if(ref) + ref = lv2_atom_forge_frame_time(forge, frames); + if(ref) + ref = lv2_atom_forge_object(forge, &obj_frame, 0, props->urid.state_StateChanged); + if(ref) + lv2_atom_forge_pop(forge, &obj_frame); + + return ref; +} + +static inline LV2_Atom_Forge_Ref +_props_patch_get(props_t *props, LV2_Atom_Forge *forge, uint32_t frames, + props_impl_t *impl, int32_t sequence_num) +{ + LV2_Atom_Forge_Frame obj_frame; + + LV2_Atom_Forge_Ref ref = lv2_atom_forge_frame_time(forge, frames); + + if(ref) + ref = lv2_atom_forge_object(forge, &obj_frame, 0, props->urid.patch_get); + { + if(props->urid.subject) // is optional + { + if(ref) + ref = lv2_atom_forge_key(forge, props->urid.patch_subject); + if(ref) + ref = lv2_atom_forge_urid(forge, props->urid.subject); + } + + if(sequence_num) // is optional + { + if(ref) + ref = lv2_atom_forge_key(forge, props->urid.patch_sequence); + if(ref) + ref = lv2_atom_forge_int(forge, sequence_num); + } + + if(ref) + ref = lv2_atom_forge_key(forge, props->urid.patch_property); + if(ref) + ref = lv2_atom_forge_urid(forge, impl->property); + } + if(ref) + lv2_atom_forge_pop(forge, &obj_frame); + + return ref; +} + +static inline LV2_Atom_Forge_Ref +_props_patch_error(props_t *props, LV2_Atom_Forge *forge, uint32_t frames, + int32_t sequence_num) +{ + LV2_Atom_Forge_Frame obj_frame; + + LV2_Atom_Forge_Ref ref = lv2_atom_forge_frame_time(forge, frames); + + if(ref) + ref = lv2_atom_forge_object(forge, &obj_frame, 0, props->urid.patch_error); + { + if(ref) + ref = lv2_atom_forge_key(forge, props->urid.patch_sequence); + if(ref) + ref = lv2_atom_forge_int(forge, sequence_num); + } + if(ref) + lv2_atom_forge_pop(forge, &obj_frame); + + return ref; +} + +static inline LV2_Atom_Forge_Ref +_props_patch_ack(props_t *props, LV2_Atom_Forge *forge, uint32_t frames, + int32_t sequence_num) +{ + LV2_Atom_Forge_Frame obj_frame; + + LV2_Atom_Forge_Ref ref = lv2_atom_forge_frame_time(forge, frames); + + if(ref) + ref = lv2_atom_forge_object(forge, &obj_frame, 0, props->urid.patch_ack); + { + if(ref) + ref = lv2_atom_forge_key(forge, props->urid.patch_sequence); + if(ref) + ref = lv2_atom_forge_int(forge, sequence_num); + } + if(ref) + lv2_atom_forge_pop(forge, &obj_frame); + + return ref; +} + +static inline void +_props_impl_stash(props_t *props, props_impl_t *impl) +{ + if(_props_impl_try_lock(impl, PROP_STATE_NONE, PROP_STATE_LOCK)) + { + impl->stashing = false; + impl->stash.size = impl->value.size; + memcpy(impl->stash.body, impl->value.body, impl->value.size); + + _props_impl_unlock(impl, PROP_STATE_NONE); + } + else + { + impl->stashing = true; // try again later + props->stashing = true; + } +} + +static inline void +_props_impl_restore(props_t *props, LV2_Atom_Forge *forge, uint32_t frames, + props_impl_t *impl, LV2_Atom_Forge_Ref *ref) +{ + if(_props_impl_try_lock(impl, PROP_STATE_RESTORE, PROP_STATE_LOCK)) + { + impl->stashing = false; // makes no sense to stash a recently restored value + impl->value.size = impl->stash.size; + memcpy(impl->value.body, impl->stash.body, impl->stash.size); + + _props_impl_unlock(impl, PROP_STATE_NONE); + + if(*ref && !impl->def->hidden) + *ref = _props_patch_set(props, forge, frames, impl, 0); + + const props_def_t *def = impl->def; + if(def->event_cb) + def->event_cb(props->data, 0, impl); + } +} + +static inline void +_props_impl_set(props_t *props, props_impl_t *impl, LV2_URID type, + uint32_t size, const void *body) +{ + if( (impl->type == type) + && ( (impl->def->max_size == 0) || (size <= impl->def->max_size)) ) + { + impl->value.size = size; + memcpy(impl->value.body, body, size); + + _props_impl_stash(props, impl); + } +} + +static inline int +_props_impl_init(props_t *props, props_impl_t *impl, const props_def_t *def, + void *value_base, void *stash_base, LV2_URID_Map *map) +{ + if(!def->property || !def->type) + return 0; + + const LV2_URID type = map->map(map->handle, def->type); + const LV2_URID property = map->map(map->handle, def->property); + const LV2_URID access = def->access + ? map->map(map->handle, def->access) + : map->map(map->handle, LV2_PATCH__writable); + + if(!type || !property || !access) + return 0; + + impl->property = property; + impl->access = access; + impl->def = def; + impl->value.body = (uint8_t *)value_base + def->offset; + impl->stash.body = (uint8_t *)stash_base + def->offset; + + uint32_t size; + if( (type == props->urid.atom_int) + || (type == props->urid.atom_float) + || (type == props->urid.atom_bool) + || (type == props->urid.atom_urid) ) + { + size = 4; + } + else if((type == props->urid.atom_long) + || (type == props->urid.atom_double) ) + { + size = 8; + } + else if(type == props->urid.atom_literal) + { + size = sizeof(LV2_Atom_Literal_Body); + } + else if(type == props->urid.atom_vector) + { + size = sizeof(LV2_Atom_Vector_Body); + } + else if(type == props->urid.atom_object) + { + size = sizeof(LV2_Atom_Object_Body); + } + else if(type == props->urid.atom_sequence) + { + size = sizeof(LV2_Atom_Sequence_Body); + } + else + { + size = 0; // assume everything else as having size 0 + } + + impl->type = type; + impl->value.size = size; + impl->stash.size = size; + + atomic_init(&impl->state, PROP_STATE_NONE); + + // update maximal value size + const uint32_t max_size = def->max_size + ? def->max_size + : size; + + if(max_size > props->max_size) + { + props->max_size = max_size; + } + + return 1; +} + +static inline int +props_init(props_t *props, const char *subject, + const props_def_t *defs, int nimpls, + void *value_base, void *stash_base, + LV2_URID_Map *map, void *data) +{ + if(!props || !defs || !value_base || !stash_base || !map) + return 0; + + props->nimpls = nimpls; + props->data = data; + + props->urid.subject = subject ? map->map(map->handle, subject) : 0; + + props->urid.patch_get = map->map(map->handle, LV2_PATCH__Get); + props->urid.patch_set = map->map(map->handle, LV2_PATCH__Set); + props->urid.patch_put = map->map(map->handle, LV2_PATCH__Put); + props->urid.patch_patch = map->map(map->handle, LV2_PATCH__Patch); + props->urid.patch_wildcard = map->map(map->handle, LV2_PATCH__wildcard); + props->urid.patch_add = map->map(map->handle, LV2_PATCH__add); + props->urid.patch_remove = map->map(map->handle, LV2_PATCH__remove); + props->urid.patch_subject = map->map(map->handle, LV2_PATCH__subject); + props->urid.patch_body = map->map(map->handle, LV2_PATCH__body); + props->urid.patch_property = map->map(map->handle, LV2_PATCH__property); + props->urid.patch_value = map->map(map->handle, LV2_PATCH__value); + props->urid.patch_writable = map->map(map->handle, LV2_PATCH__writable); + props->urid.patch_readable = map->map(map->handle, LV2_PATCH__readable); + props->urid.patch_sequence = map->map(map->handle, LV2_PATCH__sequenceNumber); + props->urid.patch_ack = map->map(map->handle, LV2_PATCH__Ack); + props->urid.patch_error = map->map(map->handle, LV2_PATCH__Error); + + props->urid.atom_int = map->map(map->handle, LV2_ATOM__Int); + props->urid.atom_long = map->map(map->handle, LV2_ATOM__Long); + props->urid.atom_float = map->map(map->handle, LV2_ATOM__Float); + props->urid.atom_double = map->map(map->handle, LV2_ATOM__Double); + props->urid.atom_bool = map->map(map->handle, LV2_ATOM__Bool); + props->urid.atom_urid = map->map(map->handle, LV2_ATOM__URID); + props->urid.atom_path = map->map(map->handle, LV2_ATOM__Path); + props->urid.atom_literal = map->map(map->handle, LV2_ATOM__Literal); + props->urid.atom_vector = map->map(map->handle, LV2_ATOM__Vector); + props->urid.atom_object = map->map(map->handle, LV2_ATOM__Object); + props->urid.atom_sequence = map->map(map->handle, LV2_ATOM__Sequence); + + props->urid.state_StateChanged = map->map(map->handle, LV2_STATE__StateChanged); + + atomic_init(&props->restoring, false); + + int status = 1; + for(unsigned i = 0; i < props->nimpls; i++) + { + props_impl_t *impl = &props->impls[i]; + + status = status + && _props_impl_init(props, impl, &defs[i], value_base, stash_base, map); + } + + _props_qsort(props->impls, props->nimpls); + + return status; +} + +static inline void +props_idle(props_t *props, LV2_Atom_Forge *forge, uint32_t frames, + LV2_Atom_Forge_Ref *ref) +{ + if(_props_restoring_get(props)) + { + for(unsigned i = 0; i < props->nimpls; i++) + { + props_impl_t *impl = &props->impls[i]; + + _props_impl_restore(props, forge, frames, impl, ref); + } + } + + if(props->stashing) + { + props->stashing = false; + + for(unsigned i = 0; i < props->nimpls; i++) + { + props_impl_t *impl = &props->impls[i]; + + if(impl->stashing) + _props_impl_stash(props, impl); + } + } +} + +static inline int +props_advance(props_t *props, LV2_Atom_Forge *forge, uint32_t frames, + const LV2_Atom_Object *obj, LV2_Atom_Forge_Ref *ref) +{ + if(!lv2_atom_forge_is_object_type(forge, obj->atom.type)) + { + return 0; + } + + if(obj->body.otype == props->urid.patch_get) + { + const LV2_Atom_URID *subject = NULL; + const LV2_Atom_URID *property = NULL; + const LV2_Atom_Int *sequence = NULL; + + lv2_atom_object_get(obj, + props->urid.patch_subject, &subject, + props->urid.patch_property, &property, + props->urid.patch_sequence, &sequence, + 0); + + // check for a matching optional subject + if( (subject && props->urid.subject) + && ( (subject->atom.type != props->urid.atom_urid) + || (subject->body != props->urid.subject) ) ) + { + return 0; + } + + int32_t sequence_num = 0; + if(sequence && (sequence->atom.type == props->urid.atom_int)) + { + sequence_num = sequence->body; + } + + if(!property) + { + for(unsigned i = 0; i < props->nimpls; i++) + { + props_impl_t *impl = &props->impls[i]; + + if(*ref && !impl->def->hidden) + *ref = _props_patch_set(props, forge, frames, impl, sequence_num); + } + + return 1; + } + else if(property->atom.type == props->urid.atom_urid) + { + props_impl_t *impl = _props_impl_get(props, property->body); + + if(impl) + { + if(*ref && !impl->def->hidden) + *ref = _props_patch_set(props, forge, frames, impl, sequence_num); + + return 1; + } + else if(sequence_num) + { + if(*ref) + *ref = _props_patch_error(props, forge, frames, sequence_num); + } + } + else if(sequence_num) + { + if(*ref) + *ref = _props_patch_error(props, forge, frames, sequence_num); + } + } + else if(obj->body.otype == props->urid.patch_set) + { + const LV2_Atom_URID *subject = NULL; + const LV2_Atom_URID *property = NULL; + const LV2_Atom_Int *sequence = NULL; + const LV2_Atom *value = NULL; + + lv2_atom_object_get(obj, + props->urid.patch_subject, &subject, + props->urid.patch_property, &property, + props->urid.patch_sequence, &sequence, + props->urid.patch_value, &value, + 0); + + // check for a matching optional subject + if( (subject && props->urid.subject) + && ( (subject->atom.type != props->urid.atom_urid) + || (subject->body != props->urid.subject) ) ) + { + return 0; + } + + int32_t sequence_num = 0; + if(sequence && (sequence->atom.type == props->urid.atom_int)) + { + sequence_num = sequence->body; + } + + if(!property || (property->atom.type != props->urid.atom_urid) || !value) + { + if(sequence_num) + { + if(ref) + *ref = _props_patch_error(props, forge, frames, sequence_num); + } + + return 0; + } + + props_impl_t *impl = _props_impl_get(props, property->body); + if(impl) + { + _props_impl_set(props, impl, value->type, value->size, + LV2_ATOM_BODY_CONST(value)); + + // send on (e.g. to UI) + if(*ref && !impl->def->hidden) + *ref = _props_patch_set(props, forge, frames, impl, sequence_num); + + const props_def_t *def = impl->def; + if(def->event_cb) + def->event_cb(props->data, frames, impl); + + if(sequence_num) + { + if(*ref) + *ref = _props_patch_ack(props, forge, frames, sequence_num); + } + + return 1; + } + else if(sequence_num) + { + if(*ref) + *ref = _props_patch_error(props, forge, frames, sequence_num); + } + } + else if(obj->body.otype == props->urid.patch_put) + { + const LV2_Atom_URID *subject = NULL; + const LV2_Atom_Int *sequence = NULL; + const LV2_Atom_Object *body = NULL; + + lv2_atom_object_get(obj, + props->urid.patch_subject, &subject, + props->urid.patch_sequence, &sequence, + props->urid.patch_body, &body, + 0); + + // check for a matching optional subject + if( (subject && props->urid.subject) + && ( (subject->atom.type != props->urid.atom_urid) + || (subject->body != props->urid.subject) ) ) + { + return 0; + } + + int32_t sequence_num = 0; + if(sequence && (sequence->atom.type == props->urid.atom_int)) + { + sequence_num = sequence->body; + } + + if(!body || !lv2_atom_forge_is_object_type(forge, body->atom.type)) + { + if(sequence_num) + { + if(*ref) + *ref = _props_patch_error(props, forge, frames, sequence_num); + } + + return 0; + } + + LV2_ATOM_OBJECT_FOREACH(body, prop) + { + const LV2_URID property = prop->key; + const LV2_Atom *value = &prop->value; + + props_impl_t *impl = _props_impl_get(props, property); + if(impl) + { + _props_impl_set(props, impl, value->type, value->size, + LV2_ATOM_BODY_CONST(value)); + + // send on (e.g. to UI) + if(*ref && !impl->def->hidden) + *ref = _props_patch_set(props, forge, frames, impl, sequence_num); + + const props_def_t *def = impl->def; + if(def->event_cb) + def->event_cb(props->data, frames, impl); + } + } + + if(sequence_num) + { + if(*ref) + *ref = _props_patch_ack(props, forge, frames, sequence_num); + } + + return 1; + } + + return 0; // did not handle a patch event +} + +static inline void +props_set(props_t *props, LV2_Atom_Forge *forge, uint32_t frames, + LV2_URID property, LV2_Atom_Forge_Ref *ref) +{ + props_impl_t *impl = _props_impl_get(props, property); + + if(impl) + { + _props_impl_stash(props, impl); + + if(*ref && !impl->def->hidden) //TODO use patch:sequenceNumber + *ref = _props_patch_set(props, forge, frames, impl, 0); + } +} + +static inline void +props_get(props_t *props, LV2_Atom_Forge *forge, uint32_t frames, + LV2_URID property, LV2_Atom_Forge_Ref *ref) +{ + props_impl_t *impl = _props_impl_get(props, property); + + if(impl) + { + if(*ref && !impl->def->hidden) //TODO use patch:sequenceNumber + *ref = _props_patch_get(props, forge, frames, impl, 0); + } +} + +static inline void +props_stash(props_t *props, LV2_URID property) +{ + props_impl_t *impl = _props_impl_get(props, property); + + if(impl) + _props_impl_stash(props, impl); +} + +static inline LV2_URID +props_map(props_t *props, const char *uri) +{ + for(unsigned i = 0; i < props->nimpls; i++) + { + props_impl_t *impl = &props->impls[i]; + + if(!strcmp(impl->def->property, uri)) + return impl->property; + } + + return 0; +} + +static inline const char * +props_unmap(props_t *props, LV2_URID property) +{ + props_impl_t *impl = _props_impl_get(props, property); + + if(impl) + return impl->def->property; + + return NULL; +} + +static inline LV2_State_Status +props_save(props_t *props, LV2_State_Store_Function store, + LV2_State_Handle state, uint32_t flags, const LV2_Feature *const *features) +{ + const LV2_State_Map_Path *map_path = NULL; + + // set POD flag if not already set by host + flags |= LV2_STATE_IS_POD; + + for(unsigned i = 0; features[i]; i++) + { + if(!strcmp(features[i]->URI, LV2_STATE__mapPath)) + { + map_path = features[i]->data; + break; + } + } + + void *body = malloc(props->max_size); // create memory to store widest value + if(body) + { + for(unsigned i = 0; i < props->nimpls; i++) + { + props_impl_t *impl = &props->impls[i]; + + if(impl->access == props->urid.patch_readable) + continue; // skip read-only, as it makes no sense to restore them + + _props_impl_spin_lock(impl, PROP_STATE_NONE, PROP_STATE_LOCK); + + // create temporary copy of value, store() may well be blocking + const uint32_t size = impl->stash.size; + memcpy(body, impl->stash.body, size); + + _props_impl_unlock(impl, PROP_STATE_NONE); + + if( map_path && (impl->type == props->urid.atom_path) ) + { + const char *path = strstr(body, "file://") + ? (char *)body + 7 // skip "file://" + : (char *)body; + char *abstract = map_path->abstract_path(map_path->handle, path); + if(abstract) + { + const uint32_t sz = strlen(abstract) + 1; + store(state, impl->property, abstract, sz, impl->type, flags); + + free(abstract); + } + } + else // !Path + { + store(state, impl->property, body, size, impl->type, flags); + } + } + + free(body); + } + + return LV2_STATE_SUCCESS; +} + +static inline LV2_State_Status +props_restore(props_t *props, LV2_State_Retrieve_Function retrieve, + LV2_State_Handle state, uint32_t flags __attribute__((unused)), + const LV2_Feature *const *features) +{ + const LV2_State_Map_Path *map_path = NULL; + + for(unsigned i = 0; features[i]; i++) + { + if(!strcmp(features[i]->URI, LV2_STATE__mapPath)) + map_path = features[i]->data; + } + + for(unsigned i = 0; i < props->nimpls; i++) + { + props_impl_t *impl = &props->impls[i]; + + if(impl->access == props->urid.patch_readable) + continue; // skip read-only, as it makes no sense to restore them + + size_t size; + uint32_t type; + uint32_t _flags; + const void *body = retrieve(state, impl->property, &size, &type, &_flags); + + if( body + && (type == impl->type) + && ( (impl->def->max_size == 0) || (size <= impl->def->max_size) ) ) + { + if(map_path && (type == props->urid.atom_path) ) + { + char *absolute = map_path->absolute_path(map_path->handle, body); + if(absolute) + { + const uint32_t sz = strlen(absolute) + 1; + + _props_impl_spin_lock(impl, PROP_STATE_NONE, PROP_STATE_LOCK); + + impl->stash.size = sz; + memcpy(impl->stash.body, absolute, sz); + + _props_impl_unlock(impl, PROP_STATE_RESTORE); + + free(absolute); + } + } + else // !Path + { + _props_impl_spin_lock(impl, PROP_STATE_NONE, PROP_STATE_LOCK); + + impl->stash.size = size; + memcpy(impl->stash.body, body, size); + + _props_impl_unlock(impl, PROP_STATE_RESTORE); + } + } + } + + _props_restoring_set(props); + + return LV2_STATE_SUCCESS; +} + +#ifdef __cplusplus +} +#endif + +#endif // _LV2_PROPS_H_ diff --git a/props.lv2/test/chunk.bin b/props.lv2/test/chunk.bin Binary files differnew file mode 100644 index 0000000..b66efb8 --- /dev/null +++ b/props.lv2/test/chunk.bin diff --git a/props.lv2/test/manifest.ttl.in b/props.lv2/test/manifest.ttl.in new file mode 100644 index 0000000..0ecc313 --- /dev/null +++ b/props.lv2/test/manifest.ttl.in @@ -0,0 +1,28 @@ +# Copyright (c) 2015 Hanspeter Portner (dev@open-music-kontrollers.ch) +# +# This is free software: you can redistribute it and/or modify +# it under the terms of the Artistic License 2.0 as published by +# The Perl Foundation. +# +# This source is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# Artistic License 2.0 for more details. +# +# You should have received a copy of the Artistic License 2.0 +# along the source as a COPYING file. If not, obtain it from +# http://www.perlfoundation.org/artistic_license_2_0. + +@prefix lv2: <http://lv2plug.in/ns/lv2core#> . +@prefix owl: <http://www.w3.org/2002/07/owl#> . +@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> . + +@prefix props: <http://open-music-kontrollers.ch/lv2/props#> . + +# Orbit Looper +props:test + a lv2:Plugin ; + lv2:minorVersion @MINOR_VERSION@ ; + lv2:microVersion @MICRO_VERSION@ ; + lv2:binary <props@MODULE_SUFFIX@> ; + rdfs:seeAlso <props.ttl> . diff --git a/props.lv2/test/props.c b/props.lv2/test/props.c new file mode 100644 index 0000000..590c519 --- /dev/null +++ b/props.lv2/test/props.c @@ -0,0 +1,323 @@ +/* + * Copyright (c) 2015 Hanspeter Portner (dev@open-music-kontrollers.ch) + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the Artistic License 2.0 as published by + * The Perl Foundation. + * + * This source is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Artistic License 2.0 for more details. + * + * You should have received a copy of the Artistic License 2.0 + * along the source as a COPYING file. If not, obtain it from + * http://www.perlfoundation.org/artistic_license_2_0. + */ + +#include <stdio.h> + +#include <props.h> + +#include <lv2/lv2plug.in/ns/ext/log/log.h> +#include <lv2/lv2plug.in/ns/ext/log/logger.h> + +#define PROPS_PREFIX "http://open-music-kontrollers.ch/lv2/props#" +#define PROPS_TEST_URI PROPS_PREFIX"test" + +#define MAX_NPROPS 7 +#define MAX_STRLEN 256 + +typedef struct _plugstate_t plugstate_t; +typedef struct _plughandle_t plughandle_t; + +struct _plugstate_t { + int32_t val1; + int64_t val2; + float val3; + double val4; + char val5 [MAX_STRLEN]; + char val6 [MAX_STRLEN]; + uint8_t val7 [MAX_STRLEN]; +}; + +struct _plughandle_t { + LV2_URID_Map *map; + LV2_Log_Log *log; + LV2_Log_Logger logger; + LV2_Atom_Forge forge; + LV2_Atom_Forge_Ref ref; + + PROPS_T(props, MAX_NPROPS); + plugstate_t state; + plugstate_t stash; + + struct { + LV2_URID val2; + LV2_URID val4; + } urid; + + const LV2_Atom_Sequence *event_in; + LV2_Atom_Sequence *event_out; +}; + +static void +_intercept(void *data, int64_t frames __attribute__((unused)), props_impl_t *impl) +{ + plughandle_t *handle = data; + + lv2_log_trace(&handle->logger, "SET : %s\n", impl->def->property); +} + +static void +_intercept_stat1(void *data, int64_t frames, props_impl_t *impl) +{ + plughandle_t *handle = data; + + _intercept(data, frames, impl); + + handle->state.val2 = handle->state.val1 * 2; + + props_set(&handle->props, &handle->forge, frames, handle->urid.val2, &handle->ref); +} + +static void +_intercept_stat3(void *data, int64_t frames, props_impl_t *impl) +{ + plughandle_t *handle = data; + + _intercept(data, frames, impl); + + handle->state.val4 = handle->state.val3 * 2; + + props_set(&handle->props, &handle->forge, frames, handle->urid.val4, &handle->ref); +} + +static void +_intercept_stat6(void *data, int64_t frames, props_impl_t *impl) +{ + plughandle_t *handle = data; + + _intercept(data, frames, impl); + + const char *path = strstr(handle->state.val6, "file://") + ? handle->state.val6 + 7 // skip "file://" + : handle->state.val6; + FILE *f = fopen(path, "wb"); // create empty file + if(f) + fclose(f); +} + +static const props_def_t defs [MAX_NPROPS] = { + { + .property = PROPS_PREFIX"statInt", + .offset = offsetof(plugstate_t, val1), + .type = LV2_ATOM__Int, + .event_cb = _intercept_stat1, + }, + { + .property = PROPS_PREFIX"statLong", + .access = LV2_PATCH__readable, + .offset = offsetof(plugstate_t, val2), + .type = LV2_ATOM__Long, + .event_cb = _intercept, + }, + { + .property = PROPS_PREFIX"statFloat", + .offset = offsetof(plugstate_t, val3), + .type = LV2_ATOM__Float, + .event_cb = _intercept_stat3, + }, + { + .property = PROPS_PREFIX"statDouble", + .access = LV2_PATCH__readable, + .offset = offsetof(plugstate_t, val4), + .type = LV2_ATOM__Double, + .event_cb = _intercept, + }, + { + .property = PROPS_PREFIX"statString", + .offset = offsetof(plugstate_t, val5), + .type = LV2_ATOM__String, + .event_cb = _intercept, + .max_size = MAX_STRLEN // strlen + }, + { + .property = PROPS_PREFIX"statPath", + .offset = offsetof(plugstate_t, val6), + .type = LV2_ATOM__Path, + .event_cb = _intercept_stat6, + .max_size = MAX_STRLEN // strlen + }, + { + .property = PROPS_PREFIX"statChunk", + .offset = offsetof(plugstate_t, val7), + .type = LV2_ATOM__Chunk, + .event_cb = _intercept, + .max_size = MAX_STRLEN // strlen + } +}; + +static LV2_Handle +instantiate(const LV2_Descriptor* descriptor, + double rate __attribute__((unused)), + const char *bundle_path __attribute__((unused)), + const LV2_Feature *const *features) +{ + plughandle_t *handle = calloc(1, sizeof(plughandle_t)); + if(!handle) + return NULL; + + for(unsigned i=0; features[i]; i++) + { + if(!strcmp(features[i]->URI, LV2_URID__map)) + handle->map = features[i]->data; + else if(!strcmp(features[i]->URI, LV2_LOG__log)) + handle->log = features[i]->data; + } + + if(!handle->map) + { + fprintf(stderr, + "%s: Host does not support urid:map\n", descriptor->URI); + free(handle); + return NULL; + } + if(!handle->log) + { + fprintf(stderr, + "%s: Host does not support log:log\n", descriptor->URI); + free(handle); + return NULL; + } + + lv2_log_logger_init(&handle->logger, handle->map, handle->log); + lv2_atom_forge_init(&handle->forge, handle->map); + + if(!props_init(&handle->props, descriptor->URI, + defs, MAX_NPROPS, &handle->state, &handle->stash, + handle->map, handle)) + { + lv2_log_error(&handle->logger, "failed to initialize property structure\n"); + free(handle); + return NULL; + } + + handle->urid.val2 = props_map(&handle->props, PROPS_PREFIX"statLong"); + handle->urid.val4 = props_map(&handle->props, PROPS_PREFIX"statDouble"); + + return handle; +} + +static void +connect_port(LV2_Handle instance, uint32_t port, void *data) +{ + plughandle_t *handle = (plughandle_t *)instance; + + switch(port) + { + case 0: + handle->event_in = (const LV2_Atom_Sequence *)data; + break; + case 1: + handle->event_out = (LV2_Atom_Sequence *)data; + break; + default: + break; + } +} + +static void +run(LV2_Handle instance, uint32_t nsamples __attribute__((unused))) +{ + plughandle_t *handle = instance; + + uint32_t capacity = handle->event_out->atom.size; + LV2_Atom_Forge_Frame frame; + lv2_atom_forge_set_buffer(&handle->forge, (uint8_t *)handle->event_out, capacity); + handle->ref = lv2_atom_forge_sequence_head(&handle->forge, &frame, 0); + + props_idle(&handle->props, &handle->forge, 0, &handle->ref); + + LV2_ATOM_SEQUENCE_FOREACH(handle->event_in, ev) + { + const LV2_Atom_Object *obj = (const LV2_Atom_Object *)&ev->body; + + if(handle->ref) + props_advance(&handle->props, &handle->forge, ev->time.frames, obj, &handle->ref); + } + + if(handle->ref) + lv2_atom_forge_pop(&handle->forge, &frame); + else + lv2_atom_sequence_clear(handle->event_out); +} + +static void +cleanup(LV2_Handle instance) +{ + plughandle_t *handle = instance; + + free(handle); +} + +static LV2_State_Status +_state_save(LV2_Handle instance, LV2_State_Store_Function store, + LV2_State_Handle state, uint32_t flags, + const LV2_Feature *const *features) +{ + plughandle_t *handle = (plughandle_t *)instance; + + return props_save(&handle->props, store, state, flags, features); +} + +static LV2_State_Status +_state_restore(LV2_Handle instance, LV2_State_Retrieve_Function retrieve, + LV2_State_Handle state, uint32_t flags, + const LV2_Feature *const *features) +{ + plughandle_t *handle = (plughandle_t *)instance; + + return props_restore(&handle->props, retrieve, state, flags, features); +} + +LV2_State_Interface state_iface = { + .save = _state_save, + .restore = _state_restore +}; + +static const void * +extension_data(const char *uri) +{ + if(!strcmp(uri, LV2_STATE__interface)) + return &state_iface; + return NULL; +} + +const LV2_Descriptor props_test = { + .URI = PROPS_TEST_URI, + .instantiate = instantiate, + .connect_port = connect_port, + .activate = NULL, + .run = run, + .deactivate = NULL, + .cleanup = cleanup, + .extension_data = extension_data +}; + +#ifdef _WIN32 +__declspec(dllexport) +#else +__attribute__((visibility("default"))) +#endif +const LV2_Descriptor* +lv2_descriptor(uint32_t index) +{ + switch(index) + { + case 0: + return &props_test; + default: + return NULL; + } +} diff --git a/props.lv2/test/props.ttl b/props.lv2/test/props.ttl new file mode 100644 index 0000000..cd4d107 --- /dev/null +++ b/props.lv2/test/props.ttl @@ -0,0 +1,152 @@ +# Copyright (c) 2015 Hanspeter Portner (dev@open-music-kontrollers.ch) +# +# This is free software: you can redistribute it and/or modify +# it under the terms of the Artistic License 2.0 as published by +# The Perl Foundation. +# +# This source is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# Artistic License 2.0 for more details. +# +# You should have received a copy of the Artistic License 2.0 +# along the source as a COPYING file. If not, obtain it from +# http://www.perlfoundation.org/artistic_license_2_0. + +@prefix owl: <http://www.w3.org/2002/07/owl#> . +@prefix foaf: <http://xmlns.com/foaf/0.1/> . +@prefix doap: <http://usefulinc.com/ns/doap#> . +@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> . +@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> . +@prefix lv2: <http://lv2plug.in/ns/lv2core#> . +@prefix atom: <http://lv2plug.in/ns/ext/atom#> . +@prefix urid: <http://lv2plug.in/ns/ext/urid#> . +@prefix state: <http://lv2plug.in/ns/ext/state#> . +@prefix patch: <http://lv2plug.in/ns/ext/patch#> . +@prefix log: <http://lv2plug.in/ns/ext/log#> . +@prefix units: <http://lv2plug.in/ns/extensions/units#> . +@prefix xsd: <http://www.w3.org/2001/XMLSchema#> . + +@prefix lic: <http://opensource.org/licenses/> . +@prefix omk: <http://open-music-kontrollers.ch/ventosus#> . +@prefix proj: <http://open-music-kontrollers.ch/lv2/> . +@prefix props: <http://open-music-kontrollers.ch/lv2/props#> . + +# Maintainer +omk:me + a foaf:Person ; + foaf:name "Hanspeter Portner" ; + foaf:mbox <mailto:dev@open-music-kontrollers.ch> ; + foaf:homepage <http://open-music-kontrollers.ch> . + +# Project +proj:props + a doap:Project ; + doap:maintainer omk:me ; + doap:name "Props Bundle" . + +props:statInt + a lv2:Parameter ; + rdfs:range atom:Int ; + rdfs:label "statInt" ; + rdfs:comment "This is a 32-bit integer" ; + units:unit units:hz ; + lv2:minimum 0 ; + lv2:maximum 10 . + +props:statLong + a lv2:Parameter ; + rdfs:range atom:Long ; + rdfs:label "statLong" ; + rdfs:comment "This is a 64-bit integer" ; + units:unit units:khz ; + lv2:minimum 0 ; + lv2:maximum 20 . + +props:statFloat + a lv2:Parameter ; + rdfs:range atom:Float ; + rdfs:label "statFloat" ; + rdfs:comment "This is a 32-bit float" ; + units:unit units:mhz ; + lv2:minimum -0.5 ; + lv2:maximum 0.5 . + +props:statDouble + a lv2:Parameter ; + rdfs:range atom:Double ; + rdfs:label "statDouble" ; + rdfs:comment "This is a 64-bit double" ; + units:unit units:db ; + lv2:minimum -1.0 ; + lv2:maximum 1.0 . + +props:statString + a lv2:Parameter ; + rdfs:range atom:String ; + rdfs:label "statString" ; + rdfs:comment "This is a string" . + +props:statPath + a lv2:Parameter ; + rdfs:range atom:Path ; + rdfs:label "statPath" ; + rdfs:comment "This is a path" . + +props:statChunk + a lv2:Parameter ; + rdfs:range atom:Chunk; + rdfs:label "statChunk" ; + rdfs:comment "This is a chunk" . + +# Looper Test +props:test + a lv2:Plugin , + lv2:ConverterPlugin ; + doap:name "Props Test" ; + doap:license lic:Artistic-2.0 ; + lv2:project proj:props ; + lv2:requiredFeature urid:map, log:log, state:loadDefaultState ; + lv2:optionalFeature lv2:isLive, lv2:hardRTCapable, state:threadSafeRestore ; + lv2:extensionData state:interface ; + + lv2:port [ + # sink event port + a lv2:InputPort , + atom:AtomPort ; + atom:bufferType atom:Sequence ; + atom:supports patch:Message ; + lv2:index 0 ; + lv2:symbol "event_in" ; + lv2:name "Event Input" ; + lv2:designation lv2:control ; + ] , [ + # source event port + a lv2:OutputPort , + atom:AtomPort ; + atom:bufferType atom:Sequence ; + atom:supports patch:Message ; + lv2:index 1 ; + lv2:symbol "event_out" ; + lv2:name "Event Output" ; + lv2:designation lv2:control ; + ] ; + + patch:writable + props:statInt , + props:statFloat , + props:statString , + props:statPath , + props:statChunk ; + + patch:readable + props:statLong , + props:statDouble ; + + state:state [ + props:statInt 4 ; + props:statFloat "0.4"^^xsd:float ; + props:statString "Hello world" ; + props:statPath <> ; + props:statChunk "AQIDBAUGBw=="^^xsd:base64Binary ; + ] . diff --git a/props.lv2/test/props_test.c b/props.lv2/test/props_test.c new file mode 100644 index 0000000..69f3b3f --- /dev/null +++ b/props.lv2/test/props_test.c @@ -0,0 +1,647 @@ +/* + * Copyright (c) 2015 Hanspeter Portner (dev@open-music-kontrollers.ch) + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the Artistic License 2.0 as published by + * The Perl Foundation. + * + * This source is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Artistic License 2.0 for more details. + * + * You should have received a copy of the Artistic License 2.0 + * along the source as a COPYING file. If not, obtain it from + * http://www.perlfoundation.org/artistic_license_2_0. + */ + +#include <assert.h> + +#include <props.h> + +#define MAX_URIDS 512 +#define STR_SIZE 32 +#define CHUNK_SIZE 16 +#define VEC_SIZE 13 + +#define PROPS_PREFIX "http://open-music-kontrollers.ch/lv2/props#" +#define PROPS_TEST_URI PROPS_PREFIX"test" + +typedef struct _plugstate_t plugstate_t; +typedef struct _urid_t urid_t; +typedef struct _handle_t handle_t; +typedef void (*test_t)(handle_t *handle); +typedef void *(*ser_atom_realloc_t)(void *data, void *buf, size_t size); +typedef void (*ser_atom_free_t)(void *data, void *buf); + +typedef struct _ser_atom_t ser_atom_t; + +struct _plugstate_t { + int32_t b32; + int32_t i32; + int64_t i64; + float f32; + double f64; + uint32_t urid; + char str [STR_SIZE]; + char uri [STR_SIZE]; + char path [STR_SIZE]; + uint8_t chunk [CHUNK_SIZE]; + LV2_Atom_Literal_Body lit; + char lit_body [STR_SIZE]; + LV2_Atom_Vector_Body vec; + int32_t vec_body [VEC_SIZE]; + LV2_Atom_Object_Body obj; //FIXME + LV2_Atom_Sequence_Body seq; //FIXME +}; + +struct _urid_t { + LV2_URID urid; + char *uri; +}; + +enum { + PROP_b32 = 0, + PROP_i32, + PROP_i64, + PROP_f32, + PROP_f64, + PROP_urid, + PROP_str, + PROP_uri, + PROP_path, + PROP_chunk, + PROP_lit, + PROP_vec, + PROP_obj, + PROP_seq, + + MAX_NPROPS +}; + +struct _handle_t { + PROPS_T(props, MAX_NPROPS); + plugstate_t state; + plugstate_t stash; + + LV2_URID_Map map; + + urid_t urids [MAX_URIDS]; + LV2_URID urid; +}; + +struct _ser_atom_t { + ser_atom_realloc_t realloc; + ser_atom_free_t free; + void *data; + + size_t size; + size_t offset; + union { + uint8_t *buf; + LV2_Atom *atom; + }; +}; + +static LV2_Atom_Forge_Ref +_ser_atom_sink(LV2_Atom_Forge_Sink_Handle handle, const void *buf, + uint32_t size) +{ + ser_atom_t *ser = handle; + const size_t needed = ser->offset + size; + + while(needed > ser->size) + { + const size_t augmented = ser->size + ? ser->size << 1 + : 1024; + uint8_t *grown = ser->realloc(ser->data, ser->buf, augmented); + if(!grown) // out-of-memory + { + return 0; + } + + ser->buf = grown; + ser->size = augmented; + } + + const LV2_Atom_Forge_Ref ref = ser->offset + 1; + memcpy(&ser->buf[ser->offset], buf, size); + ser->offset += size; + + return ref; +} + +static LV2_Atom * +_ser_atom_deref(LV2_Atom_Forge_Sink_Handle handle, LV2_Atom_Forge_Ref ref) +{ + ser_atom_t *ser = handle; + + if(!ref) // invalid reference + { + return NULL; + } + + const size_t offset = ref - 1; + return (LV2_Atom *)&ser->buf[offset]; +} + +static void * +_ser_atom_realloc(void *data, void *buf, size_t size) +{ + (void)data; + + return realloc(buf, size); +} + +static void +_ser_atom_free(void *data, void *buf) +{ + (void)data; + + free(buf); +} + +static int +ser_atom_deinit(ser_atom_t *ser) +{ + if(!ser) + { + return -1; + } + + if(ser->buf) + { + ser->free(ser->data, ser->buf); + } + + ser->size = 0; + ser->offset = 0; + ser->buf = NULL; + + return 0; +} + +static int +ser_atom_funcs(ser_atom_t *ser, ser_atom_realloc_t realloc, + ser_atom_free_t free, void *data) +{ + if(!ser || !realloc || !free || ser_atom_deinit(ser)) + { + return -1; + } + + ser->realloc = realloc; + ser->free = free; + ser->data = data; + + return 0; +} + +static int +ser_atom_init(ser_atom_t *ser) +{ + if(!ser) + { + return -1; + } + + ser->size = 0; + ser->offset = 0; + ser->buf = NULL; + + return ser_atom_funcs(ser, _ser_atom_realloc, _ser_atom_free, NULL); +} + +#if 0 +static int +ser_atom_reset(ser_atom_t *ser, LV2_Atom_Forge *forge) +{ + if(!ser || !forge) + { + return -1; + } + + lv2_atom_forge_set_sink(forge, _ser_atom_sink, _ser_atom_deref, ser); + + ser->offset = 0; + + return 0; +} +#endif + +static LV2_Atom * +ser_atom_get(ser_atom_t *ser) +{ + if(!ser) + { + return NULL; + } + + return ser->atom; +} + +static LV2_URID +_map(LV2_URID_Map_Handle instance, const char *uri) +{ + handle_t *handle = instance; + + urid_t *itm; + for(itm=handle->urids; itm->urid; itm++) + { + if(!strcmp(itm->uri, uri)) + return itm->urid; + } + + assert(handle->urid + 1 < MAX_URIDS); + + // create new + itm->urid = ++handle->urid; + itm->uri = strdup(uri); + + return itm->urid; +} + +static const props_def_t defs [MAX_NPROPS] = { + [PROP_b32] = { + .property = PROPS_PREFIX"b32", + .offset = offsetof(plugstate_t, b32), + .type = LV2_ATOM__Bool + }, + [PROP_i32] = { + .property = PROPS_PREFIX"i32", + .offset = offsetof(plugstate_t, i32), + .type = LV2_ATOM__Int + }, + [PROP_i64] = { + .property = PROPS_PREFIX"i64", + .offset = offsetof(plugstate_t, i64), + .type = LV2_ATOM__Long + }, + [PROP_f32] = { + .property = PROPS_PREFIX"f32", + .offset = offsetof(plugstate_t, f32), + .type = LV2_ATOM__Float + }, + [PROP_f64] = { + .property = PROPS_PREFIX"f64", + .offset = offsetof(plugstate_t, f64), + .type = LV2_ATOM__Double + }, + [PROP_urid] = { + .property = PROPS_PREFIX"urid", + .offset = offsetof(plugstate_t, urid), + .type = LV2_ATOM__URID + }, + [PROP_str] = { + .property = PROPS_PREFIX"str", + .offset = offsetof(plugstate_t, str), + .type = LV2_ATOM__String, + .max_size = STR_SIZE + }, + [PROP_uri] = { + .property = PROPS_PREFIX"uri", + .offset = offsetof(plugstate_t, uri), + .type = LV2_ATOM__URI, + .max_size = STR_SIZE + }, + [PROP_path] = { + .property = PROPS_PREFIX"path", + .offset = offsetof(plugstate_t, path), + .type = LV2_ATOM__Path, + .max_size = STR_SIZE + }, + [PROP_chunk] = { + .property = PROPS_PREFIX"chunk", + .offset = offsetof(plugstate_t, chunk), + .type = LV2_ATOM__Chunk, + .max_size = CHUNK_SIZE + }, + [PROP_lit] = { + .property = PROPS_PREFIX"lit", + .offset = offsetof(plugstate_t, lit), + .type = LV2_ATOM__Literal, + .max_size = sizeof(LV2_Atom_Literal_Body) + STR_SIZE + }, + [PROP_vec] = { + .property = PROPS_PREFIX"vec", + .offset = offsetof(plugstate_t, vec), + .type = LV2_ATOM__Literal, + .max_size = sizeof(LV2_Atom_Vector_Body) + VEC_SIZE*sizeof(int32_t) + }, + [PROP_obj] = { + .property = PROPS_PREFIX"obj", + .offset = offsetof(plugstate_t, obj), + .type = LV2_ATOM__Object, + .max_size = sizeof(LV2_Atom_Object_Body) + 0 //FIXME + }, + [PROP_seq] = { + .property = PROPS_PREFIX"seq", + .offset = offsetof(plugstate_t, seq), + .type = LV2_ATOM__Sequence, + .max_size = sizeof(LV2_Atom_Sequence_Body) + 0 //FIXME + } +}; + +static void +_test_1(handle_t *handle) +{ + assert(handle); + + props_t *props = &handle->props; + plugstate_t *state = &handle->state; + plugstate_t *stash = &handle->stash; + LV2_URID_Map *map = &handle->map; + + for(unsigned i = 0; i < MAX_NPROPS; i++) + { + const props_def_t *def = &defs[i]; + + const LV2_URID property = props_map(props, def->property); + assert(property != 0); + assert(property == map->map(map->handle, def->property)); + + assert(strcmp(props_unmap(props, property), def->property) == 0); + + props_impl_t *impl = _props_impl_get(props, property); + assert(impl); + + const LV2_URID type = map->map(map->handle, def->type); + const LV2_URID access = map->map(map->handle, def->access + ? def->access : LV2_PATCH__writable); + + assert(impl->property == property); + assert(impl->type == type); + assert(impl->access == access); + + assert(impl->def == def); + + assert(atomic_load(&impl->state) == PROP_STATE_NONE); + assert(impl->stashing == false); + + switch(i) + { + case PROP_b32: + { + assert(impl->value.size == sizeof(state->b32)); + assert(impl->value.body == &state->b32); + + assert(impl->stash.size == sizeof(stash->b32)); + assert(impl->stash.body == &stash->b32); + } break; + case PROP_i32: + { + assert(impl->value.size == sizeof(state->i32)); + assert(impl->value.body == &state->i32); + + assert(impl->stash.size == sizeof(stash->i32)); + assert(impl->stash.body == &stash->i32); + } break; + case PROP_i64: + { + assert(impl->value.size == sizeof(state->i64)); + assert(impl->value.body == &state->i64); + + assert(impl->stash.size == sizeof(stash->i64)); + assert(impl->stash.body == &stash->i64); + } break; + case PROP_f32: + { + assert(impl->value.size == sizeof(state->f32)); + assert(impl->value.body == &state->f32); + + assert(impl->stash.size == sizeof(stash->f32)); + assert(impl->stash.body == &stash->f32); + } break; + case PROP_f64: + { + assert(impl->value.size == sizeof(state->f64)); + assert(impl->value.body == &state->f64); + + assert(impl->stash.size == sizeof(stash->f64)); + assert(impl->stash.body == &stash->f64); + } break; + case PROP_urid: + { + assert(impl->value.size == sizeof(state->urid)); + assert(impl->value.body == &state->urid); + + assert(impl->stash.size == sizeof(stash->urid)); + assert(impl->stash.body == &stash->urid); + } break; + case PROP_str: + { + assert(impl->value.size == 0); + assert(impl->value.body == &state->str); + + assert(impl->stash.size == 0); + assert(impl->stash.body == &stash->str); + } break; + case PROP_uri: + { + assert(impl->value.size == 0); + assert(impl->value.body == &state->uri); + + assert(impl->stash.size == 0); + assert(impl->stash.body == &stash->uri); + } break; + case PROP_path: + { + assert(impl->value.size == 0); + assert(impl->value.body == &state->path); + + assert(impl->stash.size == 0); + assert(impl->stash.body == &stash->path); + } break; + case PROP_chunk: + { + assert(impl->value.size == 0); + assert(impl->value.body == &state->chunk); + + assert(impl->stash.size == 0); + assert(impl->stash.body == &stash->chunk); + } break; + case PROP_lit: + { + assert(impl->value.size == sizeof(state->lit)); + assert(impl->value.body == &state->lit); + + assert(impl->stash.size == sizeof(stash->lit)); + assert(impl->stash.body == &stash->lit); + } break; + case PROP_vec: + { + assert(impl->value.size == sizeof(state->vec)); + assert(impl->value.body == &state->vec); + + assert(impl->stash.size == sizeof(stash->vec)); + assert(impl->stash.body == &stash->vec); + } break; + case PROP_obj: + { + assert(impl->value.size == sizeof(state->obj)); + assert(impl->value.body == &state->obj); + + assert(impl->stash.size == sizeof(stash->obj)); + assert(impl->stash.body == &stash->obj); + } break; + case PROP_seq: + { + assert(impl->value.size == sizeof(state->seq)); + assert(impl->value.body == &state->seq); + + assert(impl->stash.size == sizeof(stash->seq)); + assert(impl->stash.body == &stash->seq); + } break; + default: + { + assert(false); + } break; + } + } +} + +static void +_test_2(handle_t *handle) +{ + assert(handle); + + props_t *props = &handle->props; + plugstate_t *state = &handle->state; + plugstate_t *stash = &handle->stash; + LV2_URID_Map *map = &handle->map; + + LV2_Atom_Forge forge; + LV2_Atom_Forge_Frame frame; + LV2_Atom_Forge_Ref ref; + ser_atom_t ser; + + lv2_atom_forge_init(&forge, map); + assert(ser_atom_init(&ser) == 0); + + lv2_atom_forge_set_sink(&forge, _ser_atom_sink, _ser_atom_deref, &ser); + + ref = lv2_atom_forge_sequence_head(&forge, &frame, 0); + assert(ref); + + props_idle(props, &forge, 0, &ref); + assert(ref); + + const LV2_URID property = props_map(props, defs[0].property); + assert(property); + + state->b32 = true; + + props_set(props, &forge, 1, property, &ref); + assert(ref); + + state->b32 = false; + + lv2_atom_forge_pop(&forge, &frame); + + const LV2_Atom_Sequence *seq = (const LV2_Atom_Sequence *)ser_atom_get(&ser); + assert(seq); + + unsigned nevs = 0; + LV2_ATOM_SEQUENCE_FOREACH(seq, ev) + { + const LV2_Atom *atom = &ev->body; + + assert(ev->time.frames == 1); + assert(atom->type == forge.Object); + + const LV2_Atom_Object *obj = (const LV2_Atom_Object *)atom; + assert(obj->body.id == 0); + + if(obj->body.otype == props->urid.state_StateChanged) + { + continue; + } + + assert(obj->body.otype == props->urid.patch_set); + + unsigned nprops = 0; + LV2_ATOM_OBJECT_FOREACH(obj, prop) + { + assert(prop->context == 0); + + if(prop->key == props->urid.patch_subject) + { + const LV2_Atom_URID *val = (const LV2_Atom_URID *)&prop->value; + + assert(val->atom.type == forge.URID); + assert(val->atom.size == sizeof(uint32_t)); + assert(val->body == props->urid.subject); + + nprops |= 0x1; + } + else if(prop->key == props->urid.patch_property) + { + const LV2_Atom_URID *val = (const LV2_Atom_URID *)&prop->value; + + assert(val->atom.type == forge.URID); + assert(val->atom.size == sizeof(uint32_t)); + assert(val->body == property); + + nprops |= 0x2; + } + else if(prop->key == props->urid.patch_value) + { + const LV2_Atom_Bool *val = (const LV2_Atom_Bool *)&prop->value; + + assert(val->atom.type == forge.Bool); + assert(val->atom.size == sizeof(int32_t)); + assert(val->body == true); + + nprops |= 0x4; + } + else + { + assert(false); + } + } + assert(nprops == 0x7); + + assert(props_advance(props, &forge, ev->time.frames, obj, &ref) == 1); + + assert(state->b32 == true); + assert(stash->b32 == true); + + nevs |= 0x1; + } + assert(nevs == 0x1); + + assert(ser_atom_deinit(&ser) == 0); +} + +static const test_t tests [] = { + _test_1, + _test_2, + NULL +}; + +int +main(int argc __attribute__((unused)), char **argv __attribute__((unused))) +{ + static handle_t handle; + + for(const test_t *test = tests; *test; test++) + { + memset(&handle, 0, sizeof(handle)); + + handle.map.handle = &handle; + handle.map.map = _map; + + assert(props_init(&handle.props, PROPS_PREFIX"subj", defs, MAX_NPROPS, + &handle.state, &handle.stash, &handle.map, NULL) == 1); + + (*test)(&handle); + } + + for(urid_t *itm=handle.urids; itm->urid; itm++) + { + free(itm->uri); + } + + return 0; +} diff --git a/screenshots/screenshot_1.png b/screenshots/screenshot_1.png Binary files differnew file mode 100644 index 0000000..abcdba9 --- /dev/null +++ b/screenshots/screenshot_1.png diff --git a/screenshots/screenshot_2.png b/screenshots/screenshot_2.png Binary files differnew file mode 100644 index 0000000..940385f --- /dev/null +++ b/screenshots/screenshot_2.png diff --git a/screenshots/screenshot_3.png b/screenshots/screenshot_3.png Binary files differnew file mode 100644 index 0000000..d44b890 --- /dev/null +++ b/screenshots/screenshot_3.png diff --git a/ser_atom.lv2/COPYING b/ser_atom.lv2/COPYING new file mode 100644 index 0000000..ddb9a46 --- /dev/null +++ b/ser_atom.lv2/COPYING @@ -0,0 +1,201 @@ + The Artistic License 2.0 + + Copyright (c) 2000-2006, The Perl Foundation. + + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +Preamble + +This license establishes the terms under which a given free software +Package may be copied, modified, distributed, and/or redistributed. +The intent is that the Copyright Holder maintains some artistic +control over the development of that Package while still keeping the +Package available as open source and free software. + +You are always permitted to make arrangements wholly outside of this +license directly with the Copyright Holder of a given Package. If the +terms of this license do not permit the full use that you propose to +make of the Package, you should contact the Copyright Holder and seek +a different licensing arrangement. + +Definitions + + "Copyright Holder" means the individual(s) or organization(s) + named in the copyright notice for the entire Package. + + "Contributor" means any party that has contributed code or other + material to the Package, in accordance with the Copyright Holder's + procedures. + + "You" and "your" means any person who would like to copy, + distribute, or modify the Package. + + "Package" means the collection of files distributed by the + Copyright Holder, and derivatives of that collection and/or of + those files. A given Package may consist of either the Standard + Version, or a Modified Version. + + "Distribute" means providing a copy of the Package or making it + accessible to anyone else, or in the case of a company or + organization, to others outside of your company or organization. + + "Distributor Fee" means any fee that you charge for Distributing + this Package or providing support for this Package to another + party. It does not mean licensing fees. + + "Standard Version" refers to the Package if it has not been + modified, or has been modified only in ways explicitly requested + by the Copyright Holder. + + "Modified Version" means the Package, if it has been changed, and + such changes were not explicitly requested by the Copyright + Holder. + + "Original License" means this Artistic License as Distributed with + the Standard Version of the Package, in its current version or as + it may be modified by The Perl Foundation in the future. + + "Source" form means the source code, documentation source, and + configuration files for the Package. + + "Compiled" form means the compiled bytecode, object code, binary, + or any other form resulting from mechanical transformation or + translation of the Source form. + + +Permission for Use and Modification Without Distribution + +(1) You are permitted to use the Standard Version and create and use +Modified Versions for any purpose without restriction, provided that +you do not Distribute the Modified Version. + + +Permissions for Redistribution of the Standard Version + +(2) You may Distribute verbatim copies of the Source form of the +Standard Version of this Package in any medium without restriction, +either gratis or for a Distributor Fee, provided that you duplicate +all of the original copyright notices and associated disclaimers. At +your discretion, such verbatim copies may or may not include a +Compiled form of the Package. + +(3) You may apply any bug fixes, portability changes, and other +modifications made available from the Copyright Holder. The resulting +Package will still be considered the Standard Version, and as such +will be subject to the Original License. + + +Distribution of Modified Versions of the Package as Source + +(4) You may Distribute your Modified Version as Source (either gratis +or for a Distributor Fee, and with or without a Compiled form of the +Modified Version) provided that you clearly document how it differs +from the Standard Version, including, but not limited to, documenting +any non-standard features, executables, or modules, and provided that +you do at least ONE of the following: + + (a) make the Modified Version available to the Copyright Holder + of the Standard Version, under the Original License, so that the + Copyright Holder may include your modifications in the Standard + Version. + + (b) ensure that installation of your Modified Version does not + prevent the user installing or running the Standard Version. In + addition, the Modified Version must bear a name that is different + from the name of the Standard Version. + + (c) allow anyone who receives a copy of the Modified Version to + make the Source form of the Modified Version available to others + under + + (i) the Original License or + + (ii) a license that permits the licensee to freely copy, + modify and redistribute the Modified Version using the same + licensing terms that apply to the copy that the licensee + received, and requires that the Source form of the Modified + Version, and of any works derived from it, be made freely + available in that license fees are prohibited but Distributor + Fees are allowed. + + +Distribution of Compiled Forms of the Standard Version +or Modified Versions without the Source + +(5) You may Distribute Compiled forms of the Standard Version without +the Source, provided that you include complete instructions on how to +get the Source of the Standard Version. Such instructions must be +valid at the time of your distribution. If these instructions, at any +time while you are carrying out such distribution, become invalid, you +must provide new instructions on demand or cease further distribution. +If you provide valid instructions or cease distribution within thirty +days after you become aware that the instructions are invalid, then +you do not forfeit any of your rights under this license. + +(6) You may Distribute a Modified Version in Compiled form without +the Source, provided that you comply with Section 4 with respect to +the Source of the Modified Version. + + +Aggregating or Linking the Package + +(7) You may aggregate the Package (either the Standard Version or +Modified Version) with other packages and Distribute the resulting +aggregation provided that you do not charge a licensing fee for the +Package. Distributor Fees are permitted, and licensing fees for other +components in the aggregation are permitted. The terms of this license +apply to the use and Distribution of the Standard or Modified Versions +as included in the aggregation. + +(8) You are permitted to link Modified and Standard Versions with +other works, to embed the Package in a larger work of your own, or to +build stand-alone binary or bytecode versions of applications that +include the Package, and Distribute the result without restriction, +provided the result does not expose a direct interface to the Package. + + +Items That are Not Considered Part of a Modified Version + +(9) Works (including, but not limited to, modules and scripts) that +merely extend or make use of the Package, do not, by themselves, cause +the Package to be a Modified Version. In addition, such works are not +considered parts of the Package itself, and are not subject to the +terms of this license. + + +General Provisions + +(10) Any use, modification, and distribution of the Standard or +Modified Versions is governed by this Artistic License. By using, +modifying or distributing the Package, you accept this license. Do not +use, modify, or distribute the Package, if you do not accept this +license. + +(11) If your Modified Version has been derived from a Modified +Version made by someone other than you, you are nevertheless required +to ensure that your Modified Version complies with the requirements of +this license. + +(12) This license does not grant you the right to use any trademark, +service mark, tradename, or logo of the Copyright Holder. + +(13) This license includes the non-exclusive, worldwide, +free-of-charge patent license to make, have made, use, offer to sell, +sell, import and otherwise transfer the Package with respect to any +patent claims licensable by the Copyright Holder that are necessarily +infringed by the Package. If you institute patent litigation +(including a cross-claim or counterclaim) against any party alleging +that the Package constitutes direct or contributory patent +infringement, then this Artistic License to you shall terminate on the +date that such litigation is filed. + +(14) Disclaimer of Warranty: +THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS +IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL +LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/ser_atom.lv2/README.md b/ser_atom.lv2/README.md new file mode 100644 index 0000000..21efd1b --- /dev/null +++ b/ser_atom.lv2/README.md @@ -0,0 +1,24 @@ +# ser_atom.lv2 + +## General purpose LV2 atom forge serializer + +### Reference + +* <http://lv2plug.in/ns/ext/urid> + +### License + +Copyright (c) 2018 Hanspeter Portner (dev@open-music-kontrollers.ch) + +This is free software: you can redistribute it and/or modify +it under the terms of the Artistic License 2.0 as published by +The Perl Foundation. + +This source is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +Artistic License 2.0 for more details. + +You should have received a copy of the Artistic License 2.0 +along the source as a COPYING file. If not, obtain it from +<http://www.perlfoundation.org/artistic_license_2_0>. diff --git a/ser_atom.lv2/ser_atom.lv2/ser_atom.h b/ser_atom.lv2/ser_atom.lv2/ser_atom.h new file mode 100644 index 0000000..7357e65 --- /dev/null +++ b/ser_atom.lv2/ser_atom.lv2/ser_atom.h @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2018 Hanspeter Portner (dev@open-music-kontrollers.ch) + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the Artistic License 2.0 as published by + * The Perl Foundation. + * + * This source is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Artistic License 2.0 for more details. + * + * You should have received a copy of the Artistic License 2.0 + * along the source as a COPYING file. If not, obtain it from + * http://www.perlfoundation.org/artistic_license_2_0. + */ + +#ifndef _SER_ATOM_H +#define _SER_ATOM_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdbool.h> +#include <stdint.h> +#include <stdatomic.h> +#include <stdlib.h> +#include <string.h> + +#include <lv2/lv2plug.in/ns/ext/atom/forge.h> + +#ifndef SER_ATOM_API +# define SER_ATOM_API static +#endif + +typedef void *(*ser_atom_realloc_t)(void *data, void *buf, size_t size); +typedef void (*ser_atom_free_t)(void *data, void *buf); + +typedef struct _ser_atom_t ser_atom_t; + +SER_ATOM_API int +ser_atom_init(ser_atom_t *ser); + +SER_ATOM_API int +ser_atom_funcs(ser_atom_t *ser, ser_atom_realloc_t realloc, + ser_atom_free_t free, void *data); + +SER_ATOM_API int +ser_atom_reset(ser_atom_t *ser, LV2_Atom_Forge *forge); + +SER_ATOM_API LV2_Atom * +ser_atom_get(ser_atom_t *ser); + +SER_ATOM_API int +ser_atom_deinit(ser_atom_t *ser); + +#ifdef SER_ATOM_IMPLEMENTATION + +struct _ser_atom_t { + ser_atom_realloc_t realloc; + ser_atom_free_t free; + void *data; + + size_t size; + size_t offset; + union { + uint8_t *buf; + LV2_Atom *atom; + }; +}; + +static LV2_Atom_Forge_Ref +_ser_atom_sink(LV2_Atom_Forge_Sink_Handle handle, const void *buf, + uint32_t size) +{ + ser_atom_t *ser = handle; + const size_t needed = ser->offset + size; + + while(needed > ser->size) + { + const size_t augmented = ser->size + ? ser->size << 1 + : 1024; + uint8_t *grown = ser->realloc(ser->data, ser->buf, augmented); + if(!grown) // out-of-memory + { + return 0; + } + + ser->buf = grown; + ser->size = augmented; + } + + const LV2_Atom_Forge_Ref ref = ser->offset + 1; + memcpy(&ser->buf[ser->offset], buf, size); + ser->offset += size; + + return ref; +} + +static LV2_Atom * +_ser_atom_deref(LV2_Atom_Forge_Sink_Handle handle, LV2_Atom_Forge_Ref ref) +{ + ser_atom_t *ser = handle; + + if(!ref) // invalid reference + { + return NULL; + } + + const size_t offset = ref - 1; + return (LV2_Atom *)&ser->buf[offset]; +} + +static void * +_ser_atom_realloc(void *data, void *buf, size_t size) +{ + (void)data; + + return realloc(buf, size); +} + +static void +_ser_atom_free(void *data, void *buf) +{ + (void)data; + + free(buf); +} + +SER_ATOM_API int +ser_atom_funcs(ser_atom_t *ser, ser_atom_realloc_t realloc, + ser_atom_free_t free, void *data) +{ + if(!ser || !realloc || !free || ser_atom_deinit(ser)) + { + return -1; + } + + ser->realloc = realloc; + ser->free = free; + ser->data = data; + + return 0; +} + +SER_ATOM_API int +ser_atom_init(ser_atom_t *ser) +{ + if(!ser) + { + return -1; + } + + ser->size = 0; + ser->offset = 0; + ser->buf = NULL; + + return ser_atom_funcs(ser, _ser_atom_realloc, _ser_atom_free, NULL); +} + +SER_ATOM_API int +ser_atom_reset(ser_atom_t *ser, LV2_Atom_Forge *forge) +{ + if(!ser || !forge) + { + return -1; + } + + lv2_atom_forge_set_sink(forge, _ser_atom_sink, _ser_atom_deref, ser); + + ser->offset = 0; + + return 0; +} + +SER_ATOM_API LV2_Atom * +ser_atom_get(ser_atom_t *ser) +{ + if(!ser) + { + return NULL; + } + + return ser->atom; +} + +SER_ATOM_API int +ser_atom_deinit(ser_atom_t *ser) +{ + if(!ser) + { + return -1; + } + + if(ser->buf) + { + ser->free(ser->data, ser->buf); + } + + ser->size = 0; + ser->offset = 0; + ser->buf = NULL; + + return 0; +} + +#endif // SER_ATOM_IMPLEMENTATION + +#ifdef __cplusplus +} +#endif + +#endif //_SER_ATOM_H diff --git a/ser_atom.lv2/test/Makefile b/ser_atom.lv2/test/Makefile new file mode 100644 index 0000000..95a84de --- /dev/null +++ b/ser_atom.lv2/test/Makefile @@ -0,0 +1,13 @@ +CC ?= gcc +C_FLAGS ?= -I../ -Wall -Wextra -Wpedantic $(shell pkg-config --cflags lv2) \ + -fprofile-arcs -ftest-coverage + +all: ser_atom_test + +ser_atom_test: ser_atom_test.c ../ser_atom.lv2/ser_atom.h + $(CC) -std=c11 -g -o $@ $< $(C_FLAGS) + valgrind ./$@ + gcov $< + +clean: + rm -f ser_atom_test *.gcov *.gc* diff --git a/ser_atom.lv2/test/ser_atom_test.c b/ser_atom.lv2/test/ser_atom_test.c new file mode 100644 index 0000000..00898f0 --- /dev/null +++ b/ser_atom.lv2/test/ser_atom_test.c @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2018 Hanspeter Portner (dev@open-music-kontrollers.ch) + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the Artistic License 2.0 as published by + * The Perl Foundation. + * + * This source is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Artistic License 2.0 for more details. + * + * You should have received a copy of the Artistic License 2.0 + * along the source as a COPYING file. If not, obtain it from + * http://www.perlfoundation.org/artistic_license_2_0. + */ + +#include <assert.h> +#include <inttypes.h> +#include <stdio.h> + +#define SER_ATOM_IMPLEMENTATION +#include <ser_atom.lv2/ser_atom.h> + +#define MAX_ITEMS 0x100000 + +static uint32_t +_map(void *data, const char *uri) +{ + (void)uri; + + uint32_t *urid = data; + + return ++(*urid); +} + +static void * +_realloc(void *data, void *buf, size_t size) +{ + (void)data; + (void)buf; + (void)size; + + return NULL; +} + +static void +_free(void *data, void *buf) +{ + (void)data; + (void)buf; +} + +int +main(int argc, char **argv) +{ + (void)argc; + (void)argv; + + ser_atom_t ser; + LV2_Atom_Forge forge; + + uint32_t urid = 0; + LV2_URID_Map map = { + .handle = &urid, + .map = _map + }; + + lv2_atom_forge_init(&forge, &map); + + assert(ser_atom_init(NULL) != 0); + assert(ser_atom_init(&ser) == 0); + + assert(ser.size == 0); + assert(ser.offset == 0); + assert(ser.buf == NULL); + + assert(ser_atom_funcs(NULL, NULL, NULL, NULL) != 0); + assert(ser_atom_funcs(&ser, _realloc, _free, NULL) == 0); + assert(ser_atom_reset(&ser, &forge) == 0); + assert(lv2_atom_forge_bool(&forge, true) == 0); + _free(NULL, NULL); + + assert(ser_atom_init(&ser) == 0); + + assert(ser.realloc == _ser_atom_realloc); + assert(ser.free == _ser_atom_free); + assert(ser.data == NULL); + + assert(ser.size == 0); + assert(ser.offset == 0); + assert(ser.buf == NULL); + + assert(ser_atom_reset(NULL, &forge) != 0); + assert(ser_atom_reset(&ser, NULL) != 0); + assert(ser_atom_reset(NULL, NULL) != 0); + assert(ser_atom_reset(&ser, &forge) == 0); + + LV2_Atom_Forge_Frame frame; + int64_t i; + + assert(lv2_atom_forge_tuple(&forge, &frame) != 0); + for(i = 0; i < MAX_ITEMS; i++) + { + assert(lv2_atom_forge_long(&forge, i) != 0); + } + lv2_atom_forge_pop(&forge, &frame); + + i = 0; + LV2_ATOM_TUPLE_FOREACH((const LV2_Atom_Tuple *)ser.buf, atom) + { + assert(atom->size == sizeof(int64_t)); + assert(atom->type == forge.Long); + + const int64_t *i64 = LV2_ATOM_BODY_CONST(atom); + assert(*i64 == i++); + } + + const size_t tot_size = MAX_ITEMS*sizeof(LV2_Atom_Long) + sizeof(LV2_Atom_Tuple); + assert(ser.offset == tot_size); + assert(ser.size >= tot_size); + + assert(lv2_atom_forge_deref(&forge, 0) == NULL); + + assert(ser_atom_get(NULL) == NULL); + assert(ser_atom_get(&ser) == ser.atom); + + assert(ser_atom_deinit(NULL) != 0); + assert(ser_atom_deinit(&ser) == 0); + + assert(ser.size == 0); + assert(ser.offset == 0); + assert(ser.buf == NULL); + + return 0; +} diff --git a/sherlock.c b/sherlock.c new file mode 100644 index 0000000..fdbf705 --- /dev/null +++ b/sherlock.c @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2015-2020 Hanspeter Portner (dev@open-music-kontrollers.ch) + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the Artistic License 2.0 as published by + * The Perl Foundation. + * + * This source is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Artistic License 2.0 for more details. + * + * You should have received a copy of the Artistic License 2.0 + * along the source as a COPYING file. If not, obtain it from + * http://www.perlfoundation.org/artistic_license_2_0. + */ + +#include <sherlock.h> + +#ifdef _WIN32 +__declspec(dllexport) +#else +__attribute__((visibility("default"))) +#endif +const LV2_Descriptor* +lv2_descriptor(uint32_t index) +{ + switch(index) + { + case 0: + return &atom_inspector; + case 1: + return &midi_inspector; + case 2: + return &osc_inspector; + default: + return NULL; + } +} diff --git a/sherlock.h b/sherlock.h new file mode 100644 index 0000000..db0eb45 --- /dev/null +++ b/sherlock.h @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2015-2020 Hanspeter Portner (dev@open-music-kontrollers.ch) + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the Artistic License 2.0 as published by + * The Perl Foundation. + * + * This source is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Artistic License 2.0 for more details. + * + * You should have received a copy of the Artistic License 2.0 + * along the source as a COPYING file. If not, obtain it from + * http://www.perlfoundation.org/artistic_license_2_0. + */ + +#ifndef _SHERLOCK_LV2_H +#define _SHERLOCK_LV2_H + +#include <stdint.h> +#include <inttypes.h> + +#include "lv2/lv2plug.in/ns/ext/atom/atom.h" +#include "lv2/lv2plug.in/ns/ext/atom/forge.h" +#include "lv2/lv2plug.in/ns/ext/midi/midi.h" +#include "lv2/lv2plug.in/ns/ext/time/time.h" +#include "lv2/lv2plug.in/ns/ext/urid/urid.h" +#include "lv2/lv2plug.in/ns/ext/time/time.h" +#include "lv2/lv2plug.in/ns/ext/patch/patch.h" +#include "lv2/lv2plug.in/ns/ext/log/log.h" +#include "lv2/lv2plug.in/ns/ext/log/logger.h" +#include "lv2/lv2plug.in/ns/extensions/units/units.h" +#include "lv2/lv2plug.in/ns/extensions/ui/ui.h" +#include "lv2/lv2plug.in/ns/lv2core/lv2.h" + +#include <stdio.h> +#include <props.h> + +#define SHERLOCK_URI "http://open-music-kontrollers.ch/lv2/sherlock" + +#define SHERLOCK_ATOM_INSPECTOR_URI SHERLOCK_URI"#atom_inspector" +#define SHERLOCK_ATOM_INSPECTOR_NK_URI SHERLOCK_URI"#atom_inspector_4_nk" + +#define SHERLOCK_MIDI_INSPECTOR_URI SHERLOCK_URI"#midi_inspector" +#define SHERLOCK_MIDI_INSPECTOR_NK_URI SHERLOCK_URI"#midi_inspector_4_nk" + +#define SHERLOCK_OSC_INSPECTOR_URI SHERLOCK_URI"#osc_inspector" +#define SHERLOCK_OSC_INSPECTOR_NK_URI SHERLOCK_URI"#osc_inspector_4_nk" + +extern const LV2_Descriptor atom_inspector; +extern const LV2_Descriptor midi_inspector; +extern const LV2_Descriptor osc_inspector; + +typedef struct _position_t position_t; +typedef struct _state_t state_t; +typedef struct _craft_t craft_t; + +struct _position_t { + uint64_t offset; + uint32_t nsamples; +}; + +struct _state_t { + int32_t overwrite; + int32_t block; + int32_t follow; + int32_t pretty; + int32_t trace; + uint32_t filter; + int32_t negate; +}; + +struct _craft_t { + LV2_Atom_Forge forge; + LV2_Atom_Forge_Frame frame [3]; + LV2_Atom_Forge_Ref ref; + union { + LV2_Atom_Sequence *seq; + uint8_t *buf; + }; +}; + +#define MAX_NPROPS 7 + +static const props_def_t defs [MAX_NPROPS] = { + { + .property = SHERLOCK_URI"#overwrite", + .offset = offsetof(state_t, overwrite), + .type = LV2_ATOM__Bool, + }, + { + .property = SHERLOCK_URI"#block", + .offset = offsetof(state_t, block), + .type = LV2_ATOM__Bool, + }, + { + .property = SHERLOCK_URI"#follow", + .offset = offsetof(state_t, follow), + .type = LV2_ATOM__Bool, + }, + { + .property = SHERLOCK_URI"#pretty", + .offset = offsetof(state_t, pretty), + .type = LV2_ATOM__Bool, + }, + { + .property = SHERLOCK_URI"#trace", + .offset = offsetof(state_t, trace), + .type = LV2_ATOM__Bool, + }, + { + .property = SHERLOCK_URI"#filter", + .offset = offsetof(state_t, filter), + .type = LV2_ATOM__URID, + }, + { + .property = SHERLOCK_URI"#negate", + .offset = offsetof(state_t, negate), + .type = LV2_ATOM__Bool, + } +}; + +// there is a bug in LV2 <= 0.10 +#if defined(LV2_ATOM_TUPLE_FOREACH) +# undef LV2_ATOM_TUPLE_FOREACH +# define LV2_ATOM_TUPLE_FOREACH(tuple, iter) \ + for (LV2_Atom* (iter) = lv2_atom_tuple_begin(tuple); \ + !lv2_atom_tuple_is_end(LV2_ATOM_BODY(tuple), (tuple)->atom.size, (iter)); \ + (iter) = lv2_atom_tuple_next(iter)) +#endif + +#endif // _SHERLOCK_LV2_H diff --git a/sherlock.ttl b/sherlock.ttl new file mode 100644 index 0000000..35fb464 --- /dev/null +++ b/sherlock.ttl @@ -0,0 +1,281 @@ +# Copyright (c) 2015-2020 Hanspeter Portner (dev@open-music-kontrollers.ch) +# +# This is free software: you can redistribute it and/or modify +# it under the terms of the Artistic License 2.0 as published by +# The Perl Foundation. +# +# This source is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# Artistic License 2.0 for more details. +# +# You should have received a copy of the Artistic License 2.0 +# along the source as a COPYING file. If not, obtain it from +# http://www.perlfoundation.org/artistic_license_2_0. + +@prefix foaf: <http://xmlns.com/foaf/0.1/> . +@prefix doap: <http://usefulinc.com/ns/doap#> . +@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> . +@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> . +@prefix lv2: <http://lv2plug.in/ns/lv2core#> . +@prefix atom: <http://lv2plug.in/ns/ext/atom#> . +@prefix midi: <http://lv2plug.in/ns/ext/midi#> . +@prefix time: <http://lv2plug.in/ns/ext/time#> . +@prefix urid: <http://lv2plug.in/ns/ext/urid#> . +@prefix patch: <http://lv2plug.in/ns/ext/patch#> . +@prefix state: <http://lv2plug.in/ns/ext/state#> . +@prefix log: <http://lv2plug.in/ns/ext/log#> . + +@prefix xpress: <http://open-music-kontrollers.ch/lv2/xpress#> . +@prefix osc: <http://open-music-kontrollers.ch/lv2/osc#> . +@prefix lic: <http://opensource.org/licenses/> . +@prefix omk: <http://open-music-kontrollers.ch/ventosus#> . +@prefix proj: <http://open-music-kontrollers.ch/lv2/> . +@prefix sherlock: <http://open-music-kontrollers.ch/lv2/sherlock#> . + +osc:Event + a rdfs:Class ; + rdfs:subClassOf atom:Object ; + rdfs:label "OSC Event (Bundle or Message)" . + +xpress:Message + a rdfs:Class , + rdfs:Datatype ; + rdfs:subClassOf atom:Atom . + +# Maintainer +omk:me + a foaf:Person ; + foaf:name "Hanspeter Portner" ; + foaf:mbox <mailto:dev@open-music-kontrollers.ch> ; + foaf:homepage <http://open-music-kontrollers.ch> . + +# Project +proj:sherlock + a doap:Project ; + doap:maintainer omk:me ; + doap:name "Sherlock Bundle" . + +sherlock:overwrite + a lv2:Parameter ; + rdfs:label "Overwrite" ; + rdfs:comment "Overwrite buffer when maximum number of events reached" ; + rdfs:range atom:Bool . + +sherlock:block + a lv2:Parameter ; + rdfs:label "Block" ; + rdfs:comment "Block addition of newly received events" ; + rdfs:range atom:Bool . + +sherlock:follow + a lv2:Parameter ; + rdfs:label "Follow" ; + rdfs:comment "Automatically scroll to and show last added event" ; + rdfs:range atom:Bool . + +sherlock:pretty + a lv2:Parameter ; + rdfs:label "Pretty" ; + rdfs:comment "Toggle whether to pretty print or not" ; + rdfs:range atom:Bool . + +sherlock:trace + a lv2:Parameter ; + rdfs:label "Trace" ; + rdfs:comment "Toggle whether to show trace output on console" ; + rdfs:range atom:Bool . + +sherlock:filter + a lv2:Parameter ; + rdfs:label "Match" ; + rdfs:comment "Match events according to type or object type" ; + rdfs:range atom:URI . + +sherlock:negate + a lv2:Parameter ; + rdfs:label "Negate" ; + rdfs:comment "Toggle negation of filter" ; + rdfs:range atom:Bool . + +# Atom Inspector Plugin +sherlock:atom_inspector + a lv2:Plugin, + lv2:AnalyserPlugin ; + doap:name "Sherlock Atom Inspector" ; + doap:license lic:Artistic-2.0 ; + lv2:project proj:sherlock ; + lv2:optionalFeature lv2:isLive, lv2:hardRTCapable, state:threadSafeRestore, log:log ; + lv2:requiredFeature urid:map, urid:unmap, state:loadDefaultState ; + lv2:extensionData state:interface ; + + lv2:port [ + # input event port + a lv2:InputPort , + atom:AtomPort ; + atom:bufferType atom:Sequence ; + atom:supports midi:MidiEvent , + time:Position , + patch:Message , + osc:Event , + xpress:Message ; + lv2:index 0 ; + lv2:symbol "control" ; + lv2:name "Control" ; + lv2:designation lv2:control ; + ] , [ + # output event port + a lv2:OutputPort , + atom:AtomPort ; + atom:bufferType atom:Sequence ; + atom:supports midi:MidiEvent , + time:Position , + patch:Message , + osc:Event , + xpress:Message ; + lv2:index 1 ; + lv2:symbol "through" ; + lv2:name "Through" ; + ] , [ + # output notify port + a lv2:OutputPort , + atom:AtomPort ; + atom:bufferType atom:Sequence ; + atom:supports atom:Sequence , + patch:Message ; + lv2:index 2 ; + lv2:symbol "notify" ; + lv2:name "Notify" ; + lv2:designation lv2:control ; + ] ; + + patch:writable + sherlock:overwrite , + sherlock:block , + sherlock:follow , + sherlock:pretty , + sherlock:trace , + sherlock:filter , + sherlock:negate ; + + state:state [ + sherlock:overwrite true ; + sherlock:block false ; + sherlock:follow true ; + sherlock:pretty true ; + sherlock:trace false ; + sherlock:filter sherlock:matchAll ; + sherlock:negate false ; + ] . + +# MIDI Inspector Plugin +sherlock:midi_inspector + a lv2:Plugin, + lv2:AnalyserPlugin ; + doap:name "Sherlock MIDI Inspector" ; + doap:license lic:Artistic-2.0 ; + lv2:project proj:sherlock ; + lv2:optionalFeature lv2:isLive, lv2:hardRTCapable, state:threadSafeRestore, log:log ; + lv2:requiredFeature urid:map, urid:unmap, state:loadDefaultState ; + lv2:extensionData state:interface ; + + lv2:port [ + # input event port + a lv2:InputPort , + atom:AtomPort ; + atom:bufferType atom:Sequence ; + atom:supports midi:MidiEvent , + time:Position , + patch:Message ; + lv2:index 0 ; + lv2:symbol "control" ; + lv2:name "Control" ; + lv2:designation lv2:control ; + ] , [ + # output event port + a lv2:OutputPort , + atom:AtomPort ; + atom:bufferType atom:Sequence ; + atom:supports midi:MidiEvent ; + lv2:index 1 ; + lv2:symbol "through" ; + lv2:name "Through" ; + ] , [ + # output notify port + a lv2:OutputPort , + atom:AtomPort ; + atom:bufferType atom:Sequence ; + atom:supports atom:Sequence , + patch:Message ; + lv2:index 2 ; + lv2:symbol "notify" ; + lv2:name "Notify" ; + lv2:designation lv2:control ; + ] ; + + patch:writable + sherlock:overwrite , + sherlock:block , + sherlock:follow ; + + state:state [ + sherlock:overwrite true ; + sherlock:block false ; + sherlock:follow true ; + ] . + +# OSC Inspector Plugin +sherlock:osc_inspector + a lv2:Plugin, + lv2:AnalyserPlugin ; + doap:name "Sherlock OSC Inspector" ; + doap:license lic:Artistic-2.0 ; + lv2:project proj:sherlock ; + lv2:optionalFeature lv2:isLive, lv2:hardRTCapable, state:threadSafeRestore, log:log ; + lv2:requiredFeature urid:map, urid:unmap, state:loadDefaultState ; + lv2:extensionData state:interface ; + + lv2:port [ + # input event port + a lv2:InputPort , + atom:AtomPort ; + atom:bufferType atom:Sequence ; + atom:supports osc:Event , + time:Position , + patch:Message ; + lv2:index 0 ; + lv2:symbol "control" ; + lv2:name "Control" ; + lv2:designation lv2:control ; + ] , [ + # output event port + a lv2:OutputPort , + atom:AtomPort ; + atom:bufferType atom:Sequence ; + atom:supports osc:Event ; + lv2:index 1 ; + lv2:symbol "through" ; + lv2:name "Through" ; + ] , [ + # output notify port + a lv2:OutputPort , + atom:AtomPort ; + atom:bufferType atom:Sequence ; + atom:supports atom:Sequence , + patch:Message ; + lv2:index 2 ; + lv2:symbol "notify" ; + lv2:name "Notify" ; + lv2:designation lv2:control ; + ] ; + + patch:writable + sherlock:overwrite , + sherlock:block , + sherlock:follow ; + + state:state [ + sherlock:overwrite true ; + sherlock:block false ; + sherlock:follow true ; + ] . diff --git a/sherlock_nk.c b/sherlock_nk.c new file mode 100644 index 0000000..05d1b08 --- /dev/null +++ b/sherlock_nk.c @@ -0,0 +1,681 @@ +/* + * Copyright (c) 2015-2020 Hanspeter Portner (dev@open-music-kontrollers.ch) + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the Artistic License 2.0 as published by + * The Perl Foundation. + * + * This source is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Artistic License 2.0 for more details. + * + * You should have received a copy of the Artistic License 2.0 + * along the source as a COPYING file. If not, obtain it from + * http://www.perlfoundation.org/artistic_license_2_0. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <math.h> +#include <time.h> +#include <limits.h> + +#include <sherlock.h> +#include <osc.lv2/util.h> + +#define SER_ATOM_IMPLEMENTATION +#include <ser_atom.lv2/ser_atom.h> + +#include <encoder.h> + +#define NK_PUGL_IMPLEMENTATION +#include <sherlock_nk.h> + +static inline void +_discover(plughandle_t *handle) +{ + ser_atom_t ser; + + if(ser_atom_init(&ser) == 0) + { + LV2_Atom_Forge_Frame frame; + + ser_atom_reset(&ser, &handle->forge); + lv2_atom_forge_object(&handle->forge, &frame, 0, handle->props.urid.patch_get); + lv2_atom_forge_pop(&handle->forge, &frame); + + handle->write_function(handle->controller, 0, lv2_atom_total_size(ser_atom_get(&ser)), + handle->event_transfer, ser_atom_get(&ser)); + + ser_atom_deinit(&ser); + } +} + +void +_set_bool(plughandle_t *handle, LV2_URID property, int32_t val) +{ + ser_atom_t ser; + + if(ser_atom_init(&ser) == 0) + { + LV2_Atom_Forge_Frame frame; + + ser_atom_reset(&ser, &handle->forge); + lv2_atom_forge_object(&handle->forge, &frame, 0, handle->props.urid.patch_set); + lv2_atom_forge_key(&handle->forge, handle->props.urid.patch_property); + lv2_atom_forge_urid(&handle->forge, property); + + lv2_atom_forge_key(&handle->forge, handle->props.urid.patch_value); + lv2_atom_forge_bool(&handle->forge, val); + + lv2_atom_forge_pop(&handle->forge, &frame); + + handle->write_function(handle->controller, 0, lv2_atom_total_size(ser_atom_get(&ser)), + handle->event_transfer, ser_atom_get(&ser)); + + ser_atom_deinit(&ser); + } +} + +void +_set_urid(plughandle_t *handle, LV2_URID property, uint32_t val) +{ + ser_atom_t ser; + + if(ser_atom_init(&ser) == 0) + { + LV2_Atom_Forge_Frame frame; + + ser_atom_reset(&ser, &handle->forge); + lv2_atom_forge_object(&handle->forge, &frame, 0, handle->props.urid.patch_set); + lv2_atom_forge_key(&handle->forge, handle->props.urid.patch_property); + lv2_atom_forge_urid(&handle->forge, property); + + lv2_atom_forge_key(&handle->forge, handle->props.urid.patch_value); + lv2_atom_forge_urid(&handle->forge, val); + + lv2_atom_forge_pop(&handle->forge, &frame); + + handle->write_function(handle->controller, 0, lv2_atom_total_size(ser_atom_get(&ser)), + handle->event_transfer, ser_atom_get(&ser)); + + ser_atom_deinit(&ser); + } +} + +void +_ruler(struct nk_context *ctx, float line_thickness, struct nk_color color) +{ + struct nk_rect bounds = nk_layout_space_bounds(ctx); + const enum nk_widget_layout_states states = nk_widget(&bounds, ctx); + + if(states != NK_WIDGET_INVALID) + { + struct nk_command_buffer *canv= nk_window_get_canvas(ctx); + const float x0 = bounds.x; + const float y0 = bounds.y + bounds.h/2; + const float x1 = bounds.x + bounds.w; + const float y1 = y0; + + nk_stroke_line(canv, x0, y0, x1, y1, line_thickness, color); + } +} + +void +_empty(struct nk_context *ctx) +{ + nk_spacing(ctx, 1); +} + +static void +_clear_items(plughandle_t *handle) +{ + if(handle->items) + { + for(int i = 0; i < handle->n_item; i++) + { + item_t *itm = handle->items[i]; + + if(itm) + free(itm); + } + + free(handle->items); + handle->items = NULL; + } + + handle->n_item = 0; +} + +static item_t * +_append_item(plughandle_t *handle, item_type_t type, size_t sz) +{ + handle->items = realloc(handle->items, (handle->n_item + 1)*sizeof(item_t *)); + handle->items[handle->n_item] = malloc(sizeof(item_t) + sz); + + item_t *itm = handle->items[handle->n_item]; + itm->type = type; + + handle->n_item += 1; + + return itm; +} + +void +_clear(plughandle_t *handle) +{ + _clear_items(handle); + struct nk_str *str = &handle->editor.string; + nk_str_clear(str); + handle->selected = NULL; + handle->counter = 1; +} + +void +_post_redisplay(plughandle_t *handle) +{ + nk_pugl_post_redisplay(&handle->win); +} + +float +_get_scale (plughandle_t *handle) +{ + return nk_pugl_get_scale(&handle->win); +} + +static int +_dial_bool(struct nk_context *ctx, int32_t *val, struct nk_color color, bool editable) +{ + const int32_t tmp = *val; + struct nk_rect bounds; + const bool left_mouse_click_in_cursor = nk_widget_is_mouse_clicked(ctx, NK_BUTTON_LEFT); + const enum nk_widget_layout_states layout_states = nk_widget(&bounds, ctx); + + if(layout_states != NK_WIDGET_INVALID) + { + enum nk_widget_states states = NK_WIDGET_STATE_INACTIVE; + struct nk_input *in = (ctx->current->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; + + if(in && editable) + { + bool mouse_has_scrolled = false; + + if(left_mouse_click_in_cursor) + { + states = NK_WIDGET_STATE_ACTIVED; + } + else if(nk_input_is_mouse_hovering_rect(in, bounds)) + { + if(in->mouse.scroll_delta.y != 0.f) // has scrolling + { + mouse_has_scrolled = true; + in->mouse.scroll_delta.y = 0.f; + } + + states = NK_WIDGET_STATE_HOVER; + } + + if(left_mouse_click_in_cursor || mouse_has_scrolled) + { + *val = !*val; + } + } + + const struct nk_style_item *fg = NULL; + + switch(states) + { + case NK_WIDGET_STATE_HOVER: + { + fg = &ctx->style.progress.cursor_hover; + } break; + case NK_WIDGET_STATE_ACTIVED: + { + fg = &ctx->style.progress.cursor_active; + } break; + default: + { + fg = &ctx->style.progress.cursor_normal; + } break; + } + + struct nk_color fg_color = fg->data.color; + + fg_color.r = (int)fg_color.r * color.r / 0xff; + fg_color.g = (int)fg_color.g * color.g / 0xff; + fg_color.b = (int)fg_color.b * color.b / 0xff; + fg_color.a = (int)fg_color.a * color.a / 0xff; + + struct nk_command_buffer *canv= nk_window_get_canvas(ctx); + const float w2 = bounds.w/2; + const float h2 = bounds.h/2; + const float r1 = NK_MIN(w2, h2); + const float r2 = r1 / 2; + const float cx = bounds.x + w2; + const float cy = bounds.y + h2; + + nk_stroke_arc(canv, cx, cy, r2 - 0, 0.f, 2*M_PI, 2.f, fg_color); + if(*val) + nk_fill_arc(canv, cx, cy, r2 - 2, 0.f, 2*M_PI, fg_color); + } + + return tmp != *val; +} + +int32_t +_check(struct nk_context *ctx, int32_t state) +{ + _dial_bool(ctx, &state, nk_rgb(0xff, 0xff, 0xff), true); + + return state; +} + +static LV2UI_Handle +instantiate(const LV2UI_Descriptor *descriptor __attribute__((unused)), + const char *plugin_uri, const char *bundle_path __attribute__((unused)), + LV2UI_Write_Function write_function, LV2UI_Controller controller, + LV2UI_Widget *widget, const LV2_Feature *const *features) +{ + plughandle_t *handle = calloc(1, sizeof(plughandle_t)); + if(!handle) + return NULL; + + void *parent = NULL; + LV2UI_Resize *host_resize = NULL; + for(int i=0; features[i]; i++) + { + if(!strcmp(features[i]->URI, LV2_URID__map)) + handle->map = features[i]->data; + else if(!strcmp(features[i]->URI, LV2_URID__unmap)) + handle->unmap = features[i]->data; + else if(!strcmp(features[i]->URI, LV2_UI__parent)) + parent = features[i]->data; + else if(!strcmp(features[i]->URI, LV2_UI__resize)) + host_resize = features[i]->data; + } + + if(!handle->map || !handle->unmap) + { + fprintf(stderr, "LV2 URID extension not supported\n"); + free(handle); + return NULL; + } + if(!parent) + { + free(handle); + return NULL; + } + + handle->event_transfer = handle->map->map(handle->map->handle, LV2_ATOM__eventTransfer); + lv2_atom_forge_init(&handle->forge, handle->map); + lv2_osc_urid_init(&handle->osc_urid, handle->map); + + handle->write_function = write_function; + handle->controller = controller; + + if(!props_init(&handle->props, plugin_uri, + defs, MAX_NPROPS, &handle->state, &handle->stash, + handle->map, handle)) + { + fprintf(stderr, "failed to allocate property structure\n"); + free(handle); + return NULL; + } + + handle->urid.overwrite = props_map(&handle->props, SHERLOCK_URI"#overwrite"); + handle->urid.block = props_map(&handle->props, SHERLOCK_URI"#block"); + handle->urid.follow = props_map(&handle->props, SHERLOCK_URI"#follow"); + handle->urid.pretty = props_map(&handle->props, SHERLOCK_URI"#pretty"); + handle->urid.trace = props_map(&handle->props, SHERLOCK_URI"#trace"); + handle->urid.filter = props_map(&handle->props, SHERLOCK_URI"#filter"); + handle->urid.negate = props_map(&handle->props, SHERLOCK_URI"#negate"); + + nk_pugl_config_t *cfg = &handle->win.cfg; + cfg->height = 700; + cfg->resizable = true; + cfg->ignore = false; + cfg->class = "sherlock_inspector"; + cfg->title = "Sherlock Inspector"; + cfg->parent = (intptr_t)parent; + cfg->host_resize = host_resize; + cfg->data = handle; + if(!strcmp(plugin_uri, SHERLOCK_MIDI_INSPECTOR_URI)) + { + handle->type = SHERLOCK_MIDI_INSPECTOR, + cfg->width = 600; + cfg->expose = _midi_inspector_expose; + } + else if(!strcmp(plugin_uri, SHERLOCK_ATOM_INSPECTOR_URI)) + { + handle->type = SHERLOCK_ATOM_INSPECTOR, + cfg->width = 1200; + cfg->expose = _atom_inspector_expose; + } + else if(!strcmp(plugin_uri, SHERLOCK_OSC_INSPECTOR_URI)) + { + handle->type = SHERLOCK_OSC_INSPECTOR, + cfg->width = 600; + cfg->expose = _osc_inspector_expose; + } + + if(asprintf(&cfg->font.face, "%sCousine-Regular.ttf", bundle_path) == -1) + cfg->font.face= NULL; + cfg->font.size = 13; + + *(intptr_t *)widget = nk_pugl_init(&handle->win); + nk_pugl_show(&handle->win); + + _clear(handle); + _discover(handle); + + nk_textedit_init_default(&handle->editor); + handle->editor.lexer.lex = ttl_lex; + handle->editor.lexer.data = NULL; + + handle->sratom = sratom_new(handle->map); + sratom_set_pretty_numbers(handle->sratom, handle->state.pretty); + handle->base_uri = "file:///tmp/base"; + + return handle; +} + +static void +cleanup(LV2UI_Handle instance) +{ + plughandle_t *handle = instance; + + sratom_free(handle->sratom); + + _clear_items(handle); + nk_textedit_free(&handle->editor); + + if(handle->editor.lexer.tokens) + free(handle->editor.lexer.tokens); + + if(handle->win.cfg.font.face) + free(handle->win.cfg.font.face); + nk_pugl_hide(&handle->win); + nk_pugl_shutdown(&handle->win); + + free(handle); +} + +static void +_osc_bundle(plughandle_t *handle, const LV2_Atom_Object *obj); + +static void +_osc_message(plughandle_t *handle, const LV2_Atom_Object *obj) +{ + const LV2_Atom_String *path = NULL; + const LV2_Atom_Tuple *args = NULL; + lv2_osc_message_get(&handle->osc_urid, obj, &path, &args); + + bool first = true; + + LV2_ATOM_TUPLE_FOREACH(args, arg) + { + if(first) + { + first = false; + } + else + { + _append_item(handle, ITEM_TYPE_NONE, 0); + } + } +} + +static void +_osc_packet(plughandle_t *handle, const LV2_Atom_Object *obj) +{ + if(lv2_osc_is_message_type(&handle->osc_urid, obj->body.otype)) + { + _append_item(handle, ITEM_TYPE_NONE, 0); + _osc_message(handle, obj); + } + else if(lv2_osc_is_bundle_type(&handle->osc_urid, obj->body.otype)) + { + _append_item(handle, ITEM_TYPE_NONE, 0); + _osc_bundle(handle, obj); + } +} + +static void +_osc_bundle(plughandle_t *handle, const LV2_Atom_Object *obj) +{ + const LV2_Atom_Object *timetag = NULL; + const LV2_Atom_Tuple *items = NULL; + lv2_osc_bundle_get(&handle->osc_urid, obj, &timetag, &items); + + LV2_ATOM_TUPLE_FOREACH(items, item) + { + _osc_packet(handle, (const LV2_Atom_Object *)item); + } +} + +static void +port_event(LV2UI_Handle instance, uint32_t i, uint32_t size __attribute__((unused)), + uint32_t urid, const void *buf) +{ + plughandle_t *handle = instance; + + if(urid != handle->event_transfer) + return; + + switch(i) + { + case 0: + case 2: + { + const LV2_Atom_Tuple *tup = buf; + + if(tup->atom.type != handle->forge.Tuple) + { + ser_atom_t ser; + + if(ser_atom_init(&ser) == 0) + { + LV2_Atom_Forge_Frame frame; + + ser_atom_reset(&ser, &handle->forge); + LV2_Atom_Forge_Ref ref = lv2_atom_forge_sequence_head(&handle->forge, &frame, 0); + + if(props_advance(&handle->props, &handle->forge, 0, buf, &ref)) + { + nk_pugl_post_redisplay(&handle->win); + } + + lv2_atom_forge_pop(&handle->forge, &frame); + + ser_atom_deinit(&ser); + } + + break; + } + + const LV2_Atom_Long *offset = NULL; + const LV2_Atom_Int *nsamples = NULL; + const LV2_Atom_Sequence *seq = NULL; + + unsigned k = 0; + LV2_ATOM_TUPLE_FOREACH(tup, item) + { + switch(k) + { + case 0: + { + if(item->type == handle->forge.Long) + offset = (const LV2_Atom_Long *)item; + } break; + case 1: + { + if(item->type == handle->forge.Int) + nsamples = (const LV2_Atom_Int *)item; + } break; + case 2: + { + if(item->type == handle->forge.Sequence) + seq = (const LV2_Atom_Sequence *)item; + } break; + } + + k++; + } + + const bool overflow = handle->n_item > MAX_LINES; + + if(!offset || !nsamples || !seq || (seq->atom.size <= sizeof(LV2_Atom_Sequence_Body)) ) + { + break; + } + + if(overflow && handle->state.overwrite) + { + _clear(handle); + } + + if(overflow || handle->state.block) + { + break; + } + + // append frame + { + item_t *itm = _append_item(handle, ITEM_TYPE_FRAME, 0); + itm->frame.offset = offset->body; + itm->frame.counter = handle->counter++; + itm->frame.nsamples = nsamples->body; + } + + LV2_ATOM_SEQUENCE_FOREACH(seq, ev) + { + const size_t ev_sz = sizeof(LV2_Atom_Event) + ev->body.size; + item_t *itm = _append_item(handle, ITEM_TYPE_EVENT, ev_sz); + memcpy(&itm->event.ev, ev, ev_sz); + + switch(handle->type) + { + case SHERLOCK_ATOM_INSPECTOR: + { + if(handle->state.follow) + { + handle->selected = &itm->event.ev.body; + handle->ttl_dirty = true; + } + } break; + case SHERLOCK_OSC_INSPECTOR: + { + const LV2_Atom_Object *obj = (const LV2_Atom_Object *)&ev->body; + + // bundles may span over multiple lines + if(lv2_osc_is_bundle_type(&handle->osc_urid, obj->body.otype)) + { + _osc_bundle(handle, obj); + } + else + { + _osc_message(handle, obj); + } + } break; + case SHERLOCK_MIDI_INSPECTOR: + { + const uint8_t *msg = LV2_ATOM_BODY_CONST(&ev->body); + + // sysex messages may span over multiple lines + if( (msg[0] == LV2_MIDI_MSG_SYSTEM_EXCLUSIVE) && (ev->body.size > 4) ) + { + for(uint32_t j = 4; j < ev->body.size; j += 4) + _append_item(handle, ITEM_TYPE_NONE, 0); // place holder + } + } break; + } + } + + nk_pugl_post_redisplay(&handle->win); + + break; + } + } +} + +static int +_idle(LV2UI_Handle instance) +{ + plughandle_t *handle = instance; + + return nk_pugl_process_events(&handle->win); +} + +static const LV2UI_Idle_Interface idle_ext = { + .idle = _idle +}; + +static int +_resize(LV2UI_Handle instance, int width, int height) +{ + plughandle_t *handle = instance; + + return nk_pugl_resize(&handle->win, width, height); +} + +static const LV2UI_Resize resize_ext = { + .ui_resize = _resize +}; + +static const void * +extension_data(const char *uri) +{ + if(!strcmp(uri, LV2_UI__idleInterface)) + return &idle_ext; + else if(!strcmp(uri, LV2_UI__resize)) + return &resize_ext; + + return NULL; +} + +const LV2UI_Descriptor midi_inspector_nk = { + .URI = SHERLOCK_MIDI_INSPECTOR_NK_URI, + .instantiate = instantiate, + .cleanup = cleanup, + .port_event = port_event, + .extension_data = extension_data +}; + +const LV2UI_Descriptor atom_inspector_nk = { + .URI = SHERLOCK_ATOM_INSPECTOR_NK_URI, + .instantiate = instantiate, + .cleanup = cleanup, + .port_event = port_event, + .extension_data = extension_data +}; + +const LV2UI_Descriptor osc_inspector_nk = { + .URI = SHERLOCK_OSC_INSPECTOR_NK_URI, + .instantiate = instantiate, + .cleanup = cleanup, + .port_event = port_event, + .extension_data = extension_data +}; + +#ifdef _WIN32 +__declspec(dllexport) +#else +__attribute__((visibility("default"))) +#endif +const LV2UI_Descriptor* +lv2ui_descriptor(uint32_t index) +{ + switch(index) + { + case 0: + return &midi_inspector_nk; + case 1: + return &atom_inspector_nk; + case 2: + return &osc_inspector_nk; + + default: + return NULL; + } +} diff --git a/sherlock_nk.h b/sherlock_nk.h new file mode 100644 index 0000000..5a222ca --- /dev/null +++ b/sherlock_nk.h @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2015-2020 Hanspeter Portner (dev@open-music-kontrollers.ch) + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the Artistic License 2.0 as published by + * The Perl Foundation. + * + * This source is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Artistic License 2.0 for more details. + * + * You should have received a copy of the Artistic License 2.0 + * along the source as a COPYING file. If not, obtain it from + * http://www.perlfoundation.org/artistic_license_2_0. + */ + +#ifndef _SHERLOCK_NK_H +#define _SHERLOCK_NK_H + +#define NK_PUGL_API +#include "nk_pugl/nk_pugl.h" + +#include <osc.lv2/osc.h> +#include <sratom/sratom.h> + +#define MAX_LINES 2048 + +typedef struct _item_t item_t; +typedef struct _plughandle_t plughandle_t; + +typedef enum _item_type_t { + ITEM_TYPE_NONE, + ITEM_TYPE_FRAME, + ITEM_TYPE_EVENT +} item_type_t; + +struct _item_t { + item_type_t type; + + union { + struct { + int64_t offset; + uint32_t counter; + int32_t nsamples; + } frame; + + struct { + LV2_Atom_Event ev; + uint8_t body [0]; + } event; + }; +}; + +typedef enum _plugin_type_t { + SHERLOCK_ATOM_INSPECTOR, + SHERLOCK_MIDI_INSPECTOR, + SHERLOCK_OSC_INSPECTOR +} plugin_type_t; + +struct _plughandle_t { + LV2UI_Write_Function write_function; + LV2UI_Controller controller; + + LV2_URID_Map *map; + LV2_URID_Unmap *unmap; + LV2_Atom_Forge forge; + LV2_Atom_Forge_Frame frame; + LV2_URID event_transfer; + LV2_OSC_URID osc_urid; + + PROPS_T(props, MAX_NPROPS); + struct { + LV2_URID overwrite; + LV2_URID block; + LV2_URID follow; + LV2_URID pretty; + LV2_URID trace; + LV2_URID filter; + LV2_URID negate; + } urid; + state_t state; + state_t stash; + + nk_pugl_window_t win; + + bool ttl_dirty; + const LV2_Atom *selected; + struct nk_text_edit editor; + + Sratom *sratom; + const char *base_uri; + + float dy; + + uint32_t counter; + int n_item; + item_t **items; + + bool shadow; + plugin_type_t type; + + char filter_uri [1024]; + LV2_URID filter; +}; + +extern const char *max_items [5]; +extern const int32_t max_values [5]; + +void +_midi_inspector_expose(struct nk_context *ctx, struct nk_rect wbounds, void *data); + +void +_atom_inspector_expose(struct nk_context *ctx, struct nk_rect wbounds, void *data); + +void +_osc_inspector_expose(struct nk_context *ctx, struct nk_rect wbounds, void *data); + +void +_empty(struct nk_context *ctx); + +void +_set_bool(plughandle_t *handle, LV2_URID property, int32_t val); + +void +_set_urid(plughandle_t *handle, LV2_URID property, uint32_t val); + +void +_clear(plughandle_t *handle); + +void +_ruler(struct nk_context *ctx, float line_thickness, struct nk_color color); + +void +_post_redisplay(plughandle_t *handle); + +float +_get_scale(plughandle_t *handle); + +int32_t +_check(struct nk_context *ctx, int32_t state); + +#endif // _SHERLOCK_NK_H diff --git a/sherlock_ui.ttl b/sherlock_ui.ttl new file mode 100644 index 0000000..5e735f3 --- /dev/null +++ b/sherlock_ui.ttl @@ -0,0 +1,62 @@ +# Copyright (c) 2015-2020 Hanspeter Portner (dev@open-music-kontrollers.ch) +# +# This is free software: you can redistribute it and/or modify +# it under the terms of the Artistic License 2.0 as published by +# The Perl Foundation. +# +# This source is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# Artistic License 2.0 for more details. +# +# You should have received a copy of the Artistic License 2.0 +# along the source as a COPYING file. If not, obtain it from +# http://www.perlfoundation.org/artistic_license_2_0. + +@prefix lv2: <http://lv2plug.in/ns/lv2core#> . +@prefix ui: <http://lv2plug.in/ns/extensions/ui#> . +@prefix atom: <http://lv2plug.in/ns/ext/atom#> . +@prefix ui: <http://lv2plug.in/ns/extensions/ui#> . +@prefix urid: <http://lv2plug.in/ns/ext/urid#> . +@prefix patch: <http://lv2plug.in/ns/ext/patch#> . + +@prefix sherlock: <http://open-music-kontrollers.ch/lv2/sherlock#> . + +# Atom Inspector UI +sherlock:atom_inspector_4_nk + ui:portNotification [ + ui:plugin sherlock:atom_inspector ; + lv2:symbol "notify" ; + ui:notifyType patch:Message , + atom:Tuple ; + ui:protocol atom:eventTransfer + ] ; + lv2:extensionData ui:idleInterface, ui:resize ; + lv2:optionalFeature ui:resize ; + lv2:requiredFeature ui:idleInterface, urid:map, urid:unmap . + +# MIDI Inspector UI +sherlock:midi_inspector_4_nk + ui:portNotification [ + ui:plugin sherlock:midi_inspector ; + lv2:symbol "notify" ; + ui:notifyType patch:Message , + atom:Tuple ; + ui:protocol atom:eventTransfer + ] ; + lv2:extensionData ui:idleInterface, ui:resize ; + lv2:optionalFeature ui:resize ; + lv2:requiredFeature ui:idleInterface, urid:map, urid:unmap . + +# OSC Inspector UI +sherlock:osc_inspector_4_nk + ui:portNotification [ + ui:plugin sherlock:osc_inspector ; + lv2:symbol "notify" ; + ui:notifyType patch:Message , + atom:Tuple ; + ui:protocol atom:eventTransfer + ] ; + lv2:extensionData ui:idleInterface, ui:resize ; + lv2:optionalFeature ui:resize ; + lv2:requiredFeature ui:idleInterface, urid:map, urid:unmap . diff --git a/subprojects/nk_pugl/.gitlab-ci.yml b/subprojects/nk_pugl/.gitlab-ci.yml new file mode 100644 index 0000000..e289a04 --- /dev/null +++ b/subprojects/nk_pugl/.gitlab-ci.yml @@ -0,0 +1,94 @@ +stages: + - build + - deploy + +.variables_template: &variables_definition + variables: + BASE_NAME: "nk_pugl" + PKG_CONFIG_PATH: "/opt/lv2/lib/pkgconfig:/opt/${CI_BUILD_NAME}/lib/pkgconfig:/usr/lib/${CI_BUILD_NAME}/pkgconfig" + +.common_template: &common_definition + <<: *variables_definition + stage: build + artifacts: + name: "${BASE_NAME}-$(cat VERSION)-${CI_BUILD_NAME}" + paths: + - "${BASE_NAME}-$(cat VERSION)/" + +.build_template: &build_definition + <<: *common_definition + script: + - meson -Dbuild-examples=true --prefix="/" --libdir="lib" --cross-file "${CI_BUILD_NAME}" build + - sed -i -e '/framework/s/-Wl,-O1//g' -e '/framework/s/-Wl,--start-group//g' -e '/framework/s/-Wl,--end-group//g' build/build.ninja + - ninja -C build + - DESTDIR="${CI_PROJECT_DIR}/${BASE_NAME}-$(cat VERSION)/${CI_BUILD_NAME}" ninja -C build install + +.analyze_template: &analyze_definition + <<: *common_definition + script: + - meson -Dbuild-examples=true --prefix="/" --libdir="lib" --cross-file "${CI_BUILD_NAME}" build + - sed -i -e '/framework/s/-Wl,-O1//g' -e '/framework/s/-Wl,--start-group//g' -e '/framework/s/-Wl,--end-group//g' build/build.ninja + - ninja -C build + - DESTDIR="${CI_PROJECT_DIR}/${BASE_NAME}-$(cat VERSION)/${CI_BUILD_NAME}" ninja -C build install + + - CC=clang CXX=clang++ meson -Dbuild-examples=true --prefix="/" --libdir="lib" --cross-file "${CI_BUILD_NAME}" clang + - ninja -C clang + + - scan-build --status-bugs meson -Dbuild-examples=true --prefix="/" --libdir="lib" --cross-file "${CI_BUILD_NAME}" scanbuild + - scan-build --status-bugs ninja -C scanbuild + +.universal_linux_template: &universal_linux_definition + image: ventosus/universal-linux-gnu + <<: *analyze_definition + +.arm_linux_template: &arm_linux_definition + image: ventosus/arm-linux-gnueabihf + <<: *build_definition + +.universal_w64_template: &universal_w64_definition + image: ventosus/universal-w64-mingw32 + <<: *build_definition + +.universal_apple_template: &universal_apple_definition + image: ventosus/universal-apple-darwin + <<: *build_definition + +# building in docker +x86_64-linux-gnu: + before_script: + - apt-get install -y libglu1-mesa-dev libevdev-dev + <<: *universal_linux_definition + +i686-linux-gnu: + before_script: + - apt-get install -y libglu1-mesa-dev:i386 libevdev-dev:i386 + <<: *universal_linux_definition + +arm-linux-gnueabihf: + before_script: + - apt-get install -y libglu1-mesa-dev:armhf libevdev-dev:armhf + <<: *arm_linux_definition + +aarch64-linux-gnu: + before_script: + - apt-get install -y libglu1-mesa-dev:arm64 libevdev-dev:arm64 + <<: *arm_linux_definition + +x86_64-w64-mingw32: + <<: *universal_w64_definition + +i686-w64-mingw32: + <<: *universal_w64_definition + +universal-apple-darwin: + <<: *universal_apple_definition + +pack: + <<: *variables_definition + stage: deploy + script: + - echo 'packing up...' + artifacts: + name: "${BASE_NAME}-$(cat VERSION)" + paths: + - "${BASE_NAME}-$(cat VERSION)/" diff --git a/subprojects/nk_pugl/COPYING b/subprojects/nk_pugl/COPYING new file mode 100644 index 0000000..ddb9a46 --- /dev/null +++ b/subprojects/nk_pugl/COPYING @@ -0,0 +1,201 @@ + The Artistic License 2.0 + + Copyright (c) 2000-2006, The Perl Foundation. + + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +Preamble + +This license establishes the terms under which a given free software +Package may be copied, modified, distributed, and/or redistributed. +The intent is that the Copyright Holder maintains some artistic +control over the development of that Package while still keeping the +Package available as open source and free software. + +You are always permitted to make arrangements wholly outside of this +license directly with the Copyright Holder of a given Package. If the +terms of this license do not permit the full use that you propose to +make of the Package, you should contact the Copyright Holder and seek +a different licensing arrangement. + +Definitions + + "Copyright Holder" means the individual(s) or organization(s) + named in the copyright notice for the entire Package. + + "Contributor" means any party that has contributed code or other + material to the Package, in accordance with the Copyright Holder's + procedures. + + "You" and "your" means any person who would like to copy, + distribute, or modify the Package. + + "Package" means the collection of files distributed by the + Copyright Holder, and derivatives of that collection and/or of + those files. A given Package may consist of either the Standard + Version, or a Modified Version. + + "Distribute" means providing a copy of the Package or making it + accessible to anyone else, or in the case of a company or + organization, to others outside of your company or organization. + + "Distributor Fee" means any fee that you charge for Distributing + this Package or providing support for this Package to another + party. It does not mean licensing fees. + + "Standard Version" refers to the Package if it has not been + modified, or has been modified only in ways explicitly requested + by the Copyright Holder. + + "Modified Version" means the Package, if it has been changed, and + such changes were not explicitly requested by the Copyright + Holder. + + "Original License" means this Artistic License as Distributed with + the Standard Version of the Package, in its current version or as + it may be modified by The Perl Foundation in the future. + + "Source" form means the source code, documentation source, and + configuration files for the Package. + + "Compiled" form means the compiled bytecode, object code, binary, + or any other form resulting from mechanical transformation or + translation of the Source form. + + +Permission for Use and Modification Without Distribution + +(1) You are permitted to use the Standard Version and create and use +Modified Versions for any purpose without restriction, provided that +you do not Distribute the Modified Version. + + +Permissions for Redistribution of the Standard Version + +(2) You may Distribute verbatim copies of the Source form of the +Standard Version of this Package in any medium without restriction, +either gratis or for a Distributor Fee, provided that you duplicate +all of the original copyright notices and associated disclaimers. At +your discretion, such verbatim copies may or may not include a +Compiled form of the Package. + +(3) You may apply any bug fixes, portability changes, and other +modifications made available from the Copyright Holder. The resulting +Package will still be considered the Standard Version, and as such +will be subject to the Original License. + + +Distribution of Modified Versions of the Package as Source + +(4) You may Distribute your Modified Version as Source (either gratis +or for a Distributor Fee, and with or without a Compiled form of the +Modified Version) provided that you clearly document how it differs +from the Standard Version, including, but not limited to, documenting +any non-standard features, executables, or modules, and provided that +you do at least ONE of the following: + + (a) make the Modified Version available to the Copyright Holder + of the Standard Version, under the Original License, so that the + Copyright Holder may include your modifications in the Standard + Version. + + (b) ensure that installation of your Modified Version does not + prevent the user installing or running the Standard Version. In + addition, the Modified Version must bear a name that is different + from the name of the Standard Version. + + (c) allow anyone who receives a copy of the Modified Version to + make the Source form of the Modified Version available to others + under + + (i) the Original License or + + (ii) a license that permits the licensee to freely copy, + modify and redistribute the Modified Version using the same + licensing terms that apply to the copy that the licensee + received, and requires that the Source form of the Modified + Version, and of any works derived from it, be made freely + available in that license fees are prohibited but Distributor + Fees are allowed. + + +Distribution of Compiled Forms of the Standard Version +or Modified Versions without the Source + +(5) You may Distribute Compiled forms of the Standard Version without +the Source, provided that you include complete instructions on how to +get the Source of the Standard Version. Such instructions must be +valid at the time of your distribution. If these instructions, at any +time while you are carrying out such distribution, become invalid, you +must provide new instructions on demand or cease further distribution. +If you provide valid instructions or cease distribution within thirty +days after you become aware that the instructions are invalid, then +you do not forfeit any of your rights under this license. + +(6) You may Distribute a Modified Version in Compiled form without +the Source, provided that you comply with Section 4 with respect to +the Source of the Modified Version. + + +Aggregating or Linking the Package + +(7) You may aggregate the Package (either the Standard Version or +Modified Version) with other packages and Distribute the resulting +aggregation provided that you do not charge a licensing fee for the +Package. Distributor Fees are permitted, and licensing fees for other +components in the aggregation are permitted. The terms of this license +apply to the use and Distribution of the Standard or Modified Versions +as included in the aggregation. + +(8) You are permitted to link Modified and Standard Versions with +other works, to embed the Package in a larger work of your own, or to +build stand-alone binary or bytecode versions of applications that +include the Package, and Distribute the result without restriction, +provided the result does not expose a direct interface to the Package. + + +Items That are Not Considered Part of a Modified Version + +(9) Works (including, but not limited to, modules and scripts) that +merely extend or make use of the Package, do not, by themselves, cause +the Package to be a Modified Version. In addition, such works are not +considered parts of the Package itself, and are not subject to the +terms of this license. + + +General Provisions + +(10) Any use, modification, and distribution of the Standard or +Modified Versions is governed by this Artistic License. By using, +modifying or distributing the Package, you accept this license. Do not +use, modify, or distribute the Package, if you do not accept this +license. + +(11) If your Modified Version has been derived from a Modified +Version made by someone other than you, you are nevertheless required +to ensure that your Modified Version complies with the requirements of +this license. + +(12) This license does not grant you the right to use any trademark, +service mark, tradename, or logo of the Copyright Holder. + +(13) This license includes the non-exclusive, worldwide, +free-of-charge patent license to make, have made, use, offer to sell, +sell, import and otherwise transfer the Package with respect to any +patent claims licensable by the Copyright Holder that are necessarily +infringed by the Package. If you institute patent litigation +(including a cross-claim or counterclaim) against any party alleging +that the Package constitutes direct or contributory patent +infringement, then this Artistic License to you shall terminate on the +date that such litigation is filed. + +(14) Disclaimer of Warranty: +THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS +IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL +LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/subprojects/nk_pugl/VERSION b/subprojects/nk_pugl/VERSION new file mode 100644 index 0000000..010fbfb --- /dev/null +++ b/subprojects/nk_pugl/VERSION @@ -0,0 +1 @@ +0.1.149 diff --git a/subprojects/nk_pugl/example/example.c b/subprojects/nk_pugl/example/example.c new file mode 100644 index 0000000..1c505da --- /dev/null +++ b/subprojects/nk_pugl/example/example.c @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2016-2020 Hanspeter Portner (dev@open-music-kontrollers.ch) + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the Artistic License 2.0 as published by + * The Perl Foundation. + * + * This source is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Artistic License 2.0 for more details. + * + * You should have received a copy of the Artistic License 2.0 + * along the source as a COPYING file. If not, obtain it from + * http://www.perlfoundation.org/artistic_license_2_0. + */ + +#include <unistd.h> +#include <signal.h> +#include <time.h> +#include <limits.h> + +#define LEN NK_LEN +#define MAX NK_MAX + +#define NK_PUGL_IMPLEMENTATION +#include <nk_pugl/nk_pugl.h> + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#include "nuklear/demo/overview.c" +#pragma GCC diagnostic pop + +static volatile sig_atomic_t done = 0; + +static void +_sigint(int signum __attribute__((unused))) +{ + done = 1; +} + +static void +_expose(struct nk_context *ctx, struct nk_rect wbounds __attribute__((unused)), + void *data __attribute__((unused))) +{ + overview(ctx); +} + +int +main(int argc __attribute__((unused)), char **argv __attribute__((unused))) +{ + static nk_pugl_window_t win; + nk_pugl_config_t *cfg = &win.cfg; + + cfg->width = 1280; + cfg->height = 720; + cfg->resizable = true; + cfg->parent = 0; + cfg->threads = false; + cfg->ignore = false; + cfg->class = "nk_pugl_example"; + cfg->title = "Nk Pugl Example"; + cfg->expose = _expose; + cfg->data = NULL; + cfg->font.face = "./Cousine-Regular.ttf"; + cfg->font.size = 13; + + signal(SIGTERM, _sigint); + signal(SIGINT, _sigint); +#if !defined(_WIN32) + signal(SIGQUIT, _sigint); + signal(SIGKILL, _sigint); +#endif + + const intptr_t widget = nk_pugl_init(&win); + if(!widget) + { + return 1; + } + + nk_pugl_show(&win); + +#if !defined(_WIN32) && !defined(__APPLE__) + struct timespec tm; + clock_gettime(CLOCK_MONOTONIC, &tm); +#endif + + while(!done) + { +#if !defined(_WIN32) && !defined(__APPLE__) + if(clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &tm, NULL) != 0) + { + continue; + } + +#define NANOS 1000000000 + tm.tv_nsec += NANOS / 25; + while(tm.tv_nsec >= NANOS) + { + tm.tv_sec += 1; + tm.tv_nsec -= NANOS; + } +#undef NANOS +#else + usleep(1000000 / 25); +#endif + + done = nk_pugl_process_events(&win); + } + + nk_pugl_hide(&win); + + nk_pugl_shutdown(&win); + + return 0; +} diff --git a/subprojects/nk_pugl/glew-2.1.0/GL/eglew.h b/subprojects/nk_pugl/glew-2.1.0/GL/eglew.h new file mode 100644 index 0000000..4670147 --- /dev/null +++ b/subprojects/nk_pugl/glew-2.1.0/GL/eglew.h @@ -0,0 +1,2618 @@ +/* +** The OpenGL Extension Wrangler Library +** Copyright (C) 2008-2017, Nigel Stewart <nigels[]users sourceforge net> +** Copyright (C) 2002-2008, Milan Ikits <milan ikits[]ieee org> +** Copyright (C) 2002-2008, Marcelo E. Magallon <mmagallo[]debian org> +** Copyright (C) 2002, Lev Povalahev +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are met: +** +** * Redistributions of source code must retain the above copyright notice, +** this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright notice, +** this list of conditions and the following disclaimer in the documentation +** and/or other materials provided with the distribution. +** * The name of the author may be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +** CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +** ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +** THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* + * Mesa 3-D graphics library + * Version: 7.0 + * + * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* +** Copyright (c) 2007 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be included +** in all copies or substantial portions of the Materials. +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ + +#ifndef __eglew_h__ +#define __eglew_h__ +#define __EGLEW_H__ + +#ifdef __eglext_h_ +#error eglext.h included before eglew.h +#endif + +#if defined(__egl_h_) +#error egl.h included before eglew.h +#endif + +#define __eglext_h_ + +#define __egl_h_ + +#ifndef EGLAPIENTRY +#define EGLAPIENTRY +#endif +#ifndef EGLAPI +#define EGLAPI extern +#endif + +/* EGL Types */ +#include <sys/types.h> + +#include <KHR/khrplatform.h> +#include <EGL/eglplatform.h> + +#include <GL/glew.h> + +#ifdef __cplusplus +extern "C" { +#endif + +typedef int32_t EGLint; + +typedef unsigned int EGLBoolean; +typedef void *EGLDisplay; +typedef void *EGLConfig; +typedef void *EGLSurface; +typedef void *EGLContext; +typedef void (*__eglMustCastToProperFunctionPointerType)(void); + +typedef unsigned int EGLenum; +typedef void *EGLClientBuffer; + +typedef void *EGLSync; +typedef intptr_t EGLAttrib; +typedef khronos_utime_nanoseconds_t EGLTime; +typedef void *EGLImage; + +typedef void *EGLSyncKHR; +typedef intptr_t EGLAttribKHR; +typedef void *EGLLabelKHR; +typedef void *EGLObjectKHR; +typedef void (EGLAPIENTRY *EGLDEBUGPROCKHR)(EGLenum error,const char *command,EGLint messageType,EGLLabelKHR threadLabel,EGLLabelKHR objectLabel,const char* message); +typedef khronos_utime_nanoseconds_t EGLTimeKHR; +typedef void *EGLImageKHR; +typedef void *EGLStreamKHR; +typedef khronos_uint64_t EGLuint64KHR; +typedef int EGLNativeFileDescriptorKHR; +typedef khronos_ssize_t EGLsizeiANDROID; +typedef void (*EGLSetBlobFuncANDROID) (const void *key, EGLsizeiANDROID keySize, const void *value, EGLsizeiANDROID valueSize); +typedef EGLsizeiANDROID (*EGLGetBlobFuncANDROID) (const void *key, EGLsizeiANDROID keySize, void *value, EGLsizeiANDROID valueSize); +typedef void *EGLDeviceEXT; +typedef void *EGLOutputLayerEXT; +typedef void *EGLOutputPortEXT; +typedef void *EGLSyncNV; +typedef khronos_utime_nanoseconds_t EGLTimeNV; +typedef khronos_utime_nanoseconds_t EGLuint64NV; +typedef khronos_stime_nanoseconds_t EGLnsecsANDROID; + +struct EGLClientPixmapHI; + +#define EGL_DONT_CARE ((EGLint)-1) + +#define EGL_NO_CONTEXT ((EGLContext)0) +#define EGL_NO_DISPLAY ((EGLDisplay)0) +#define EGL_NO_IMAGE ((EGLImage)0) +#define EGL_NO_SURFACE ((EGLSurface)0) +#define EGL_NO_SYNC ((EGLSync)0) + +#define EGL_UNKNOWN ((EGLint)-1) + +#define EGL_DEFAULT_DISPLAY ((EGLNativeDisplayType)0) + +EGLAPI __eglMustCastToProperFunctionPointerType EGLAPIENTRY eglGetProcAddress (const char *procname); +/* ---------------------------- EGL_VERSION_1_0 ---------------------------- */ + +#ifndef EGL_VERSION_1_0 +#define EGL_VERSION_1_0 1 + +#define EGL_FALSE 0 +#define EGL_PBUFFER_BIT 0x0001 +#define EGL_TRUE 1 +#define EGL_PIXMAP_BIT 0x0002 +#define EGL_WINDOW_BIT 0x0004 +#define EGL_SUCCESS 0x3000 +#define EGL_NOT_INITIALIZED 0x3001 +#define EGL_BAD_ACCESS 0x3002 +#define EGL_BAD_ALLOC 0x3003 +#define EGL_BAD_ATTRIBUTE 0x3004 +#define EGL_BAD_CONFIG 0x3005 +#define EGL_BAD_CONTEXT 0x3006 +#define EGL_BAD_CURRENT_SURFACE 0x3007 +#define EGL_BAD_DISPLAY 0x3008 +#define EGL_BAD_MATCH 0x3009 +#define EGL_BAD_NATIVE_PIXMAP 0x300A +#define EGL_BAD_NATIVE_WINDOW 0x300B +#define EGL_BAD_PARAMETER 0x300C +#define EGL_BAD_SURFACE 0x300D +#define EGL_BUFFER_SIZE 0x3020 +#define EGL_ALPHA_SIZE 0x3021 +#define EGL_BLUE_SIZE 0x3022 +#define EGL_GREEN_SIZE 0x3023 +#define EGL_RED_SIZE 0x3024 +#define EGL_DEPTH_SIZE 0x3025 +#define EGL_STENCIL_SIZE 0x3026 +#define EGL_CONFIG_CAVEAT 0x3027 +#define EGL_CONFIG_ID 0x3028 +#define EGL_LEVEL 0x3029 +#define EGL_MAX_PBUFFER_HEIGHT 0x302A +#define EGL_MAX_PBUFFER_PIXELS 0x302B +#define EGL_MAX_PBUFFER_WIDTH 0x302C +#define EGL_NATIVE_RENDERABLE 0x302D +#define EGL_NATIVE_VISUAL_ID 0x302E +#define EGL_NATIVE_VISUAL_TYPE 0x302F +#define EGL_SAMPLES 0x3031 +#define EGL_SAMPLE_BUFFERS 0x3032 +#define EGL_SURFACE_TYPE 0x3033 +#define EGL_TRANSPARENT_TYPE 0x3034 +#define EGL_TRANSPARENT_BLUE_VALUE 0x3035 +#define EGL_TRANSPARENT_GREEN_VALUE 0x3036 +#define EGL_TRANSPARENT_RED_VALUE 0x3037 +#define EGL_NONE 0x3038 +#define EGL_SLOW_CONFIG 0x3050 +#define EGL_NON_CONFORMANT_CONFIG 0x3051 +#define EGL_TRANSPARENT_RGB 0x3052 +#define EGL_VENDOR 0x3053 +#define EGL_VERSION 0x3054 +#define EGL_EXTENSIONS 0x3055 +#define EGL_HEIGHT 0x3056 +#define EGL_WIDTH 0x3057 +#define EGL_LARGEST_PBUFFER 0x3058 +#define EGL_DRAW 0x3059 +#define EGL_READ 0x305A +#define EGL_CORE_NATIVE_ENGINE 0x305B + +typedef EGLBoolean ( * PFNEGLCHOOSECONFIGPROC) (EGLDisplay dpy, const EGLint * attrib_list, EGLConfig * configs, EGLint config_size, EGLint * num_config); +typedef EGLBoolean ( * PFNEGLCOPYBUFFERSPROC) (EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target); +typedef EGLContext ( * PFNEGLCREATECONTEXTPROC) (EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint * attrib_list); +typedef EGLSurface ( * PFNEGLCREATEPBUFFERSURFACEPROC) (EGLDisplay dpy, EGLConfig config, const EGLint * attrib_list); +typedef EGLSurface ( * PFNEGLCREATEPIXMAPSURFACEPROC) (EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint * attrib_list); +typedef EGLSurface ( * PFNEGLCREATEWINDOWSURFACEPROC) (EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint * attrib_list); +typedef EGLBoolean ( * PFNEGLDESTROYCONTEXTPROC) (EGLDisplay dpy, EGLContext ctx); +typedef EGLBoolean ( * PFNEGLDESTROYSURFACEPROC) (EGLDisplay dpy, EGLSurface surface); +typedef EGLBoolean ( * PFNEGLGETCONFIGATTRIBPROC) (EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint * value); +typedef EGLBoolean ( * PFNEGLGETCONFIGSPROC) (EGLDisplay dpy, EGLConfig * configs, EGLint config_size, EGLint * num_config); +typedef EGLDisplay ( * PFNEGLGETCURRENTDISPLAYPROC) ( void ); +typedef EGLSurface ( * PFNEGLGETCURRENTSURFACEPROC) (EGLint readdraw); +typedef EGLDisplay ( * PFNEGLGETDISPLAYPROC) (EGLNativeDisplayType display_id); +typedef EGLint ( * PFNEGLGETERRORPROC) ( void ); +typedef EGLBoolean ( * PFNEGLINITIALIZEPROC) (EGLDisplay dpy, EGLint * major, EGLint * minor); +typedef EGLBoolean ( * PFNEGLMAKECURRENTPROC) (EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx); +typedef EGLBoolean ( * PFNEGLQUERYCONTEXTPROC) (EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint * value); +typedef const char * ( * PFNEGLQUERYSTRINGPROC) (EGLDisplay dpy, EGLint name); +typedef EGLBoolean ( * PFNEGLQUERYSURFACEPROC) (EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint * value); +typedef EGLBoolean ( * PFNEGLSWAPBUFFERSPROC) (EGLDisplay dpy, EGLSurface surface); +typedef EGLBoolean ( * PFNEGLTERMINATEPROC) (EGLDisplay dpy); +typedef EGLBoolean ( * PFNEGLWAITGLPROC) ( void ); +typedef EGLBoolean ( * PFNEGLWAITNATIVEPROC) (EGLint engine); + +#define eglChooseConfig EGLEW_GET_FUN(__eglewChooseConfig) +#define eglCopyBuffers EGLEW_GET_FUN(__eglewCopyBuffers) +#define eglCreateContext EGLEW_GET_FUN(__eglewCreateContext) +#define eglCreatePbufferSurface EGLEW_GET_FUN(__eglewCreatePbufferSurface) +#define eglCreatePixmapSurface EGLEW_GET_FUN(__eglewCreatePixmapSurface) +#define eglCreateWindowSurface EGLEW_GET_FUN(__eglewCreateWindowSurface) +#define eglDestroyContext EGLEW_GET_FUN(__eglewDestroyContext) +#define eglDestroySurface EGLEW_GET_FUN(__eglewDestroySurface) +#define eglGetConfigAttrib EGLEW_GET_FUN(__eglewGetConfigAttrib) +#define eglGetConfigs EGLEW_GET_FUN(__eglewGetConfigs) +#define eglGetCurrentDisplay EGLEW_GET_FUN(__eglewGetCurrentDisplay) +#define eglGetCurrentSurface EGLEW_GET_FUN(__eglewGetCurrentSurface) +#define eglGetDisplay EGLEW_GET_FUN(__eglewGetDisplay) +#define eglGetError EGLEW_GET_FUN(__eglewGetError) +#define eglInitialize EGLEW_GET_FUN(__eglewInitialize) +#define eglMakeCurrent EGLEW_GET_FUN(__eglewMakeCurrent) +#define eglQueryContext EGLEW_GET_FUN(__eglewQueryContext) +#define eglQueryString EGLEW_GET_FUN(__eglewQueryString) +#define eglQuerySurface EGLEW_GET_FUN(__eglewQuerySurface) +#define eglSwapBuffers EGLEW_GET_FUN(__eglewSwapBuffers) +#define eglTerminate EGLEW_GET_FUN(__eglewTerminate) +#define eglWaitGL EGLEW_GET_FUN(__eglewWaitGL) +#define eglWaitNative EGLEW_GET_FUN(__eglewWaitNative) + +#define EGLEW_VERSION_1_0 EGLEW_GET_VAR(__EGLEW_VERSION_1_0) + +#endif /* EGL_VERSION_1_0 */ + +/* ---------------------------- EGL_VERSION_1_1 ---------------------------- */ + +#ifndef EGL_VERSION_1_1 +#define EGL_VERSION_1_1 1 + +#define EGL_CONTEXT_LOST 0x300E +#define EGL_BIND_TO_TEXTURE_RGB 0x3039 +#define EGL_BIND_TO_TEXTURE_RGBA 0x303A +#define EGL_MIN_SWAP_INTERVAL 0x303B +#define EGL_MAX_SWAP_INTERVAL 0x303C +#define EGL_NO_TEXTURE 0x305C +#define EGL_TEXTURE_RGB 0x305D +#define EGL_TEXTURE_RGBA 0x305E +#define EGL_TEXTURE_2D 0x305F +#define EGL_TEXTURE_FORMAT 0x3080 +#define EGL_TEXTURE_TARGET 0x3081 +#define EGL_MIPMAP_TEXTURE 0x3082 +#define EGL_MIPMAP_LEVEL 0x3083 +#define EGL_BACK_BUFFER 0x3084 + +typedef EGLBoolean ( * PFNEGLBINDTEXIMAGEPROC) (EGLDisplay dpy, EGLSurface surface, EGLint buffer); +typedef EGLBoolean ( * PFNEGLRELEASETEXIMAGEPROC) (EGLDisplay dpy, EGLSurface surface, EGLint buffer); +typedef EGLBoolean ( * PFNEGLSURFACEATTRIBPROC) (EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value); +typedef EGLBoolean ( * PFNEGLSWAPINTERVALPROC) (EGLDisplay dpy, EGLint interval); + +#define eglBindTexImage EGLEW_GET_FUN(__eglewBindTexImage) +#define eglReleaseTexImage EGLEW_GET_FUN(__eglewReleaseTexImage) +#define eglSurfaceAttrib EGLEW_GET_FUN(__eglewSurfaceAttrib) +#define eglSwapInterval EGLEW_GET_FUN(__eglewSwapInterval) + +#define EGLEW_VERSION_1_1 EGLEW_GET_VAR(__EGLEW_VERSION_1_1) + +#endif /* EGL_VERSION_1_1 */ + +/* ---------------------------- EGL_VERSION_1_2 ---------------------------- */ + +#ifndef EGL_VERSION_1_2 +#define EGL_VERSION_1_2 1 + +#define EGL_OPENGL_ES_BIT 0x0001 +#define EGL_OPENVG_BIT 0x0002 +#define EGL_LUMINANCE_SIZE 0x303D +#define EGL_ALPHA_MASK_SIZE 0x303E +#define EGL_COLOR_BUFFER_TYPE 0x303F +#define EGL_RENDERABLE_TYPE 0x3040 +#define EGL_SINGLE_BUFFER 0x3085 +#define EGL_RENDER_BUFFER 0x3086 +#define EGL_COLORSPACE 0x3087 +#define EGL_ALPHA_FORMAT 0x3088 +#define EGL_COLORSPACE_LINEAR 0x308A +#define EGL_ALPHA_FORMAT_NONPRE 0x308B +#define EGL_ALPHA_FORMAT_PRE 0x308C +#define EGL_CLIENT_APIS 0x308D +#define EGL_RGB_BUFFER 0x308E +#define EGL_LUMINANCE_BUFFER 0x308F +#define EGL_HORIZONTAL_RESOLUTION 0x3090 +#define EGL_VERTICAL_RESOLUTION 0x3091 +#define EGL_PIXEL_ASPECT_RATIO 0x3092 +#define EGL_SWAP_BEHAVIOR 0x3093 +#define EGL_BUFFER_PRESERVED 0x3094 +#define EGL_BUFFER_DESTROYED 0x3095 +#define EGL_OPENVG_IMAGE 0x3096 +#define EGL_CONTEXT_CLIENT_TYPE 0x3097 +#define EGL_OPENGL_ES_API 0x30A0 +#define EGL_OPENVG_API 0x30A1 +#define EGL_DISPLAY_SCALING 10000 + +typedef EGLBoolean ( * PFNEGLBINDAPIPROC) (EGLenum api); +typedef EGLSurface ( * PFNEGLCREATEPBUFFERFROMCLIENTBUFFERPROC) (EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint * attrib_list); +typedef EGLenum ( * PFNEGLQUERYAPIPROC) ( void ); +typedef EGLBoolean ( * PFNEGLRELEASETHREADPROC) ( void ); +typedef EGLBoolean ( * PFNEGLWAITCLIENTPROC) ( void ); + +#define eglBindAPI EGLEW_GET_FUN(__eglewBindAPI) +#define eglCreatePbufferFromClientBuffer EGLEW_GET_FUN(__eglewCreatePbufferFromClientBuffer) +#define eglQueryAPI EGLEW_GET_FUN(__eglewQueryAPI) +#define eglReleaseThread EGLEW_GET_FUN(__eglewReleaseThread) +#define eglWaitClient EGLEW_GET_FUN(__eglewWaitClient) + +#define EGLEW_VERSION_1_2 EGLEW_GET_VAR(__EGLEW_VERSION_1_2) + +#endif /* EGL_VERSION_1_2 */ + +/* ---------------------------- EGL_VERSION_1_3 ---------------------------- */ + +#ifndef EGL_VERSION_1_3 +#define EGL_VERSION_1_3 1 + +#define EGL_OPENGL_ES2_BIT 0x0004 +#define EGL_VG_COLORSPACE_LINEAR_BIT 0x0020 +#define EGL_VG_ALPHA_FORMAT_PRE_BIT 0x0040 +#define EGL_MATCH_NATIVE_PIXMAP 0x3041 +#define EGL_CONFORMANT 0x3042 +#define EGL_VG_COLORSPACE 0x3087 +#define EGL_VG_ALPHA_FORMAT 0x3088 +#define EGL_VG_COLORSPACE_LINEAR 0x308A +#define EGL_VG_ALPHA_FORMAT_NONPRE 0x308B +#define EGL_VG_ALPHA_FORMAT_PRE 0x308C +#define EGL_CONTEXT_CLIENT_VERSION 0x3098 + +#define EGLEW_VERSION_1_3 EGLEW_GET_VAR(__EGLEW_VERSION_1_3) + +#endif /* EGL_VERSION_1_3 */ + +/* ---------------------------- EGL_VERSION_1_4 ---------------------------- */ + +#ifndef EGL_VERSION_1_4 +#define EGL_VERSION_1_4 1 + +#define EGL_OPENGL_BIT 0x0008 +#define EGL_MULTISAMPLE_RESOLVE_BOX_BIT 0x0200 +#define EGL_SWAP_BEHAVIOR_PRESERVED_BIT 0x0400 +#define EGL_MULTISAMPLE_RESOLVE 0x3099 +#define EGL_MULTISAMPLE_RESOLVE_DEFAULT 0x309A +#define EGL_MULTISAMPLE_RESOLVE_BOX 0x309B +#define EGL_OPENGL_API 0x30A2 + +typedef EGLContext ( * PFNEGLGETCURRENTCONTEXTPROC) ( void ); + +#define eglGetCurrentContext EGLEW_GET_FUN(__eglewGetCurrentContext) + +#define EGLEW_VERSION_1_4 EGLEW_GET_VAR(__EGLEW_VERSION_1_4) + +#endif /* EGL_VERSION_1_4 */ + +/* ---------------------------- EGL_VERSION_1_5 ---------------------------- */ + +#ifndef EGL_VERSION_1_5 +#define EGL_VERSION_1_5 1 + +#define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT 0x00000001 +#define EGL_SYNC_FLUSH_COMMANDS_BIT 0x0001 +#define EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT 0x00000002 +#define EGL_OPENGL_ES3_BIT 0x00000040 +#define EGL_GL_COLORSPACE_SRGB 0x3089 +#define EGL_GL_COLORSPACE_LINEAR 0x308A +#define EGL_CONTEXT_MAJOR_VERSION 0x3098 +#define EGL_CL_EVENT_HANDLE 0x309C +#define EGL_GL_COLORSPACE 0x309D +#define EGL_GL_TEXTURE_2D 0x30B1 +#define EGL_GL_TEXTURE_3D 0x30B2 +#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x30B3 +#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x30B4 +#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x30B5 +#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x30B6 +#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x30B7 +#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x30B8 +#define EGL_GL_RENDERBUFFER 0x30B9 +#define EGL_GL_TEXTURE_LEVEL 0x30BC +#define EGL_GL_TEXTURE_ZOFFSET 0x30BD +#define EGL_IMAGE_PRESERVED 0x30D2 +#define EGL_SYNC_PRIOR_COMMANDS_COMPLETE 0x30F0 +#define EGL_SYNC_STATUS 0x30F1 +#define EGL_SIGNALED 0x30F2 +#define EGL_UNSIGNALED 0x30F3 +#define EGL_TIMEOUT_EXPIRED 0x30F5 +#define EGL_CONDITION_SATISFIED 0x30F6 +#define EGL_SYNC_TYPE 0x30F7 +#define EGL_SYNC_CONDITION 0x30F8 +#define EGL_SYNC_FENCE 0x30F9 +#define EGL_CONTEXT_MINOR_VERSION 0x30FB +#define EGL_CONTEXT_OPENGL_PROFILE_MASK 0x30FD +#define EGL_SYNC_CL_EVENT 0x30FE +#define EGL_SYNC_CL_EVENT_COMPLETE 0x30FF +#define EGL_CONTEXT_OPENGL_DEBUG 0x31B0 +#define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE 0x31B1 +#define EGL_CONTEXT_OPENGL_ROBUST_ACCESS 0x31B2 +#define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY 0x31BD +#define EGL_NO_RESET_NOTIFICATION 0x31BE +#define EGL_LOSE_CONTEXT_ON_RESET 0x31BF +#define EGL_FOREVER 0xFFFFFFFFFFFFFFFF + +typedef EGLint ( * PFNEGLCLIENTWAITSYNCPROC) (EGLDisplay dpy, EGLSync sync, EGLint flags, EGLTime timeout); +typedef EGLImage ( * PFNEGLCREATEIMAGEPROC) (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLAttrib * attrib_list); +typedef EGLSurface ( * PFNEGLCREATEPLATFORMPIXMAPSURFACEPROC) (EGLDisplay dpy, EGLConfig config, void * native_pixmap, const EGLAttrib * attrib_list); +typedef EGLSurface ( * PFNEGLCREATEPLATFORMWINDOWSURFACEPROC) (EGLDisplay dpy, EGLConfig config, void * native_window, const EGLAttrib * attrib_list); +typedef EGLSync ( * PFNEGLCREATESYNCPROC) (EGLDisplay dpy, EGLenum type, const EGLAttrib * attrib_list); +typedef EGLBoolean ( * PFNEGLDESTROYIMAGEPROC) (EGLDisplay dpy, EGLImage image); +typedef EGLBoolean ( * PFNEGLDESTROYSYNCPROC) (EGLDisplay dpy, EGLSync sync); +typedef EGLDisplay ( * PFNEGLGETPLATFORMDISPLAYPROC) (EGLenum platform, void * native_display, const EGLAttrib * attrib_list); +typedef EGLBoolean ( * PFNEGLGETSYNCATTRIBPROC) (EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLAttrib * value); +typedef EGLBoolean ( * PFNEGLWAITSYNCPROC) (EGLDisplay dpy, EGLSync sync, EGLint flags); + +#define eglClientWaitSync EGLEW_GET_FUN(__eglewClientWaitSync) +#define eglCreateImage EGLEW_GET_FUN(__eglewCreateImage) +#define eglCreatePlatformPixmapSurface EGLEW_GET_FUN(__eglewCreatePlatformPixmapSurface) +#define eglCreatePlatformWindowSurface EGLEW_GET_FUN(__eglewCreatePlatformWindowSurface) +#define eglCreateSync EGLEW_GET_FUN(__eglewCreateSync) +#define eglDestroyImage EGLEW_GET_FUN(__eglewDestroyImage) +#define eglDestroySync EGLEW_GET_FUN(__eglewDestroySync) +#define eglGetPlatformDisplay EGLEW_GET_FUN(__eglewGetPlatformDisplay) +#define eglGetSyncAttrib EGLEW_GET_FUN(__eglewGetSyncAttrib) +#define eglWaitSync EGLEW_GET_FUN(__eglewWaitSync) + +#define EGLEW_VERSION_1_5 EGLEW_GET_VAR(__EGLEW_VERSION_1_5) + +#endif /* EGL_VERSION_1_5 */ + +/* ------------------------- EGL_ANDROID_blob_cache ------------------------ */ + +#ifndef EGL_ANDROID_blob_cache +#define EGL_ANDROID_blob_cache 1 + +typedef void ( * PFNEGLSETBLOBCACHEFUNCSANDROIDPROC) (EGLDisplay dpy, EGLSetBlobFuncANDROID set, EGLGetBlobFuncANDROID get); + +#define eglSetBlobCacheFuncsANDROID EGLEW_GET_FUN(__eglewSetBlobCacheFuncsANDROID) + +#define EGLEW_ANDROID_blob_cache EGLEW_GET_VAR(__EGLEW_ANDROID_blob_cache) + +#endif /* EGL_ANDROID_blob_cache */ + +/* ---------------- EGL_ANDROID_create_native_client_buffer ---------------- */ + +#ifndef EGL_ANDROID_create_native_client_buffer +#define EGL_ANDROID_create_native_client_buffer 1 + +#define EGL_NATIVE_BUFFER_USAGE_PROTECTED_BIT_ANDROID 0x00000001 +#define EGL_NATIVE_BUFFER_USAGE_RENDERBUFFER_BIT_ANDROID 0x00000002 +#define EGL_NATIVE_BUFFER_USAGE_TEXTURE_BIT_ANDROID 0x00000004 +#define EGL_NATIVE_BUFFER_USAGE_ANDROID 0x3143 + +typedef EGLClientBuffer ( * PFNEGLCREATENATIVECLIENTBUFFERANDROIDPROC) (const EGLint * attrib_list); + +#define eglCreateNativeClientBufferANDROID EGLEW_GET_FUN(__eglewCreateNativeClientBufferANDROID) + +#define EGLEW_ANDROID_create_native_client_buffer EGLEW_GET_VAR(__EGLEW_ANDROID_create_native_client_buffer) + +#endif /* EGL_ANDROID_create_native_client_buffer */ + +/* --------------------- EGL_ANDROID_framebuffer_target -------------------- */ + +#ifndef EGL_ANDROID_framebuffer_target +#define EGL_ANDROID_framebuffer_target 1 + +#define EGL_FRAMEBUFFER_TARGET_ANDROID 0x3147 + +#define EGLEW_ANDROID_framebuffer_target EGLEW_GET_VAR(__EGLEW_ANDROID_framebuffer_target) + +#endif /* EGL_ANDROID_framebuffer_target */ + +/* ----------------- EGL_ANDROID_front_buffer_auto_refresh ----------------- */ + +#ifndef EGL_ANDROID_front_buffer_auto_refresh +#define EGL_ANDROID_front_buffer_auto_refresh 1 + +#define EGL_FRONT_BUFFER_AUTO_REFRESH_ANDROID 0x314C + +#define EGLEW_ANDROID_front_buffer_auto_refresh EGLEW_GET_VAR(__EGLEW_ANDROID_front_buffer_auto_refresh) + +#endif /* EGL_ANDROID_front_buffer_auto_refresh */ + +/* -------------------- EGL_ANDROID_image_native_buffer -------------------- */ + +#ifndef EGL_ANDROID_image_native_buffer +#define EGL_ANDROID_image_native_buffer 1 + +#define EGL_NATIVE_BUFFER_ANDROID 0x3140 + +#define EGLEW_ANDROID_image_native_buffer EGLEW_GET_VAR(__EGLEW_ANDROID_image_native_buffer) + +#endif /* EGL_ANDROID_image_native_buffer */ + +/* --------------------- EGL_ANDROID_native_fence_sync --------------------- */ + +#ifndef EGL_ANDROID_native_fence_sync +#define EGL_ANDROID_native_fence_sync 1 + +#define EGL_SYNC_NATIVE_FENCE_ANDROID 0x3144 +#define EGL_SYNC_NATIVE_FENCE_FD_ANDROID 0x3145 +#define EGL_SYNC_NATIVE_FENCE_SIGNALED_ANDROID 0x3146 + +typedef EGLint ( * PFNEGLDUPNATIVEFENCEFDANDROIDPROC) (EGLDisplay dpy, EGLSyncKHR sync); + +#define eglDupNativeFenceFDANDROID EGLEW_GET_FUN(__eglewDupNativeFenceFDANDROID) + +#define EGLEW_ANDROID_native_fence_sync EGLEW_GET_VAR(__EGLEW_ANDROID_native_fence_sync) + +#endif /* EGL_ANDROID_native_fence_sync */ + +/* --------------------- EGL_ANDROID_presentation_time --------------------- */ + +#ifndef EGL_ANDROID_presentation_time +#define EGL_ANDROID_presentation_time 1 + +typedef EGLBoolean ( * PFNEGLPRESENTATIONTIMEANDROIDPROC) (EGLDisplay dpy, EGLSurface surface, EGLnsecsANDROID time); + +#define eglPresentationTimeANDROID EGLEW_GET_FUN(__eglewPresentationTimeANDROID) + +#define EGLEW_ANDROID_presentation_time EGLEW_GET_VAR(__EGLEW_ANDROID_presentation_time) + +#endif /* EGL_ANDROID_presentation_time */ + +/* ------------------------- EGL_ANDROID_recordable ------------------------ */ + +#ifndef EGL_ANDROID_recordable +#define EGL_ANDROID_recordable 1 + +#define EGL_RECORDABLE_ANDROID 0x3142 + +#define EGLEW_ANDROID_recordable EGLEW_GET_VAR(__EGLEW_ANDROID_recordable) + +#endif /* EGL_ANDROID_recordable */ + +/* ---------------- EGL_ANGLE_d3d_share_handle_client_buffer --------------- */ + +#ifndef EGL_ANGLE_d3d_share_handle_client_buffer +#define EGL_ANGLE_d3d_share_handle_client_buffer 1 + +#define EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE 0x3200 + +#define EGLEW_ANGLE_d3d_share_handle_client_buffer EGLEW_GET_VAR(__EGLEW_ANGLE_d3d_share_handle_client_buffer) + +#endif /* EGL_ANGLE_d3d_share_handle_client_buffer */ + +/* -------------------------- EGL_ANGLE_device_d3d ------------------------- */ + +#ifndef EGL_ANGLE_device_d3d +#define EGL_ANGLE_device_d3d 1 + +#define EGL_D3D9_DEVICE_ANGLE 0x33A0 +#define EGL_D3D11_DEVICE_ANGLE 0x33A1 + +#define EGLEW_ANGLE_device_d3d EGLEW_GET_VAR(__EGLEW_ANGLE_device_d3d) + +#endif /* EGL_ANGLE_device_d3d */ + +/* -------------------- EGL_ANGLE_query_surface_pointer -------------------- */ + +#ifndef EGL_ANGLE_query_surface_pointer +#define EGL_ANGLE_query_surface_pointer 1 + +typedef EGLBoolean ( * PFNEGLQUERYSURFACEPOINTERANGLEPROC) (EGLDisplay dpy, EGLSurface surface, EGLint attribute, void ** value); + +#define eglQuerySurfacePointerANGLE EGLEW_GET_FUN(__eglewQuerySurfacePointerANGLE) + +#define EGLEW_ANGLE_query_surface_pointer EGLEW_GET_VAR(__EGLEW_ANGLE_query_surface_pointer) + +#endif /* EGL_ANGLE_query_surface_pointer */ + +/* ------------- EGL_ANGLE_surface_d3d_texture_2d_share_handle ------------- */ + +#ifndef EGL_ANGLE_surface_d3d_texture_2d_share_handle +#define EGL_ANGLE_surface_d3d_texture_2d_share_handle 1 + +#define EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE 0x3200 + +#define EGLEW_ANGLE_surface_d3d_texture_2d_share_handle EGLEW_GET_VAR(__EGLEW_ANGLE_surface_d3d_texture_2d_share_handle) + +#endif /* EGL_ANGLE_surface_d3d_texture_2d_share_handle */ + +/* ---------------------- EGL_ANGLE_window_fixed_size ---------------------- */ + +#ifndef EGL_ANGLE_window_fixed_size +#define EGL_ANGLE_window_fixed_size 1 + +#define EGL_FIXED_SIZE_ANGLE 0x3201 + +#define EGLEW_ANGLE_window_fixed_size EGLEW_GET_VAR(__EGLEW_ANGLE_window_fixed_size) + +#endif /* EGL_ANGLE_window_fixed_size */ + +/* --------------------- EGL_ARM_implicit_external_sync -------------------- */ + +#ifndef EGL_ARM_implicit_external_sync +#define EGL_ARM_implicit_external_sync 1 + +#define EGL_SYNC_PRIOR_COMMANDS_IMPLICIT_EXTERNAL_ARM 0x328A + +#define EGLEW_ARM_implicit_external_sync EGLEW_GET_VAR(__EGLEW_ARM_implicit_external_sync) + +#endif /* EGL_ARM_implicit_external_sync */ + +/* ------------------- EGL_ARM_pixmap_multisample_discard ------------------ */ + +#ifndef EGL_ARM_pixmap_multisample_discard +#define EGL_ARM_pixmap_multisample_discard 1 + +#define EGL_DISCARD_SAMPLES_ARM 0x3286 + +#define EGLEW_ARM_pixmap_multisample_discard EGLEW_GET_VAR(__EGLEW_ARM_pixmap_multisample_discard) + +#endif /* EGL_ARM_pixmap_multisample_discard */ + +/* --------------------------- EGL_EXT_buffer_age -------------------------- */ + +#ifndef EGL_EXT_buffer_age +#define EGL_EXT_buffer_age 1 + +#define EGL_BUFFER_AGE_EXT 0x313D + +#define EGLEW_EXT_buffer_age EGLEW_GET_VAR(__EGLEW_EXT_buffer_age) + +#endif /* EGL_EXT_buffer_age */ + +/* ----------------------- EGL_EXT_client_extensions ----------------------- */ + +#ifndef EGL_EXT_client_extensions +#define EGL_EXT_client_extensions 1 + +#define EGLEW_EXT_client_extensions EGLEW_GET_VAR(__EGLEW_EXT_client_extensions) + +#endif /* EGL_EXT_client_extensions */ + +/* ------------------- EGL_EXT_create_context_robustness ------------------- */ + +#ifndef EGL_EXT_create_context_robustness +#define EGL_EXT_create_context_robustness 1 + +#define EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT 0x30BF +#define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT 0x3138 +#define EGL_NO_RESET_NOTIFICATION_EXT 0x31BE +#define EGL_LOSE_CONTEXT_ON_RESET_EXT 0x31BF + +#define EGLEW_EXT_create_context_robustness EGLEW_GET_VAR(__EGLEW_EXT_create_context_robustness) + +#endif /* EGL_EXT_create_context_robustness */ + +/* -------------------------- EGL_EXT_device_base -------------------------- */ + +#ifndef EGL_EXT_device_base +#define EGL_EXT_device_base 1 + +#define EGL_BAD_DEVICE_EXT 0x322B +#define EGL_DEVICE_EXT 0x322C + +#define EGLEW_EXT_device_base EGLEW_GET_VAR(__EGLEW_EXT_device_base) + +#endif /* EGL_EXT_device_base */ + +/* --------------------------- EGL_EXT_device_drm -------------------------- */ + +#ifndef EGL_EXT_device_drm +#define EGL_EXT_device_drm 1 + +#define EGL_DRM_DEVICE_FILE_EXT 0x3233 + +#define EGLEW_EXT_device_drm EGLEW_GET_VAR(__EGLEW_EXT_device_drm) + +#endif /* EGL_EXT_device_drm */ + +/* ----------------------- EGL_EXT_device_enumeration ---------------------- */ + +#ifndef EGL_EXT_device_enumeration +#define EGL_EXT_device_enumeration 1 + +typedef EGLBoolean ( * PFNEGLQUERYDEVICESEXTPROC) (EGLint max_devices, EGLDeviceEXT * devices, EGLint * num_devices); + +#define eglQueryDevicesEXT EGLEW_GET_FUN(__eglewQueryDevicesEXT) + +#define EGLEW_EXT_device_enumeration EGLEW_GET_VAR(__EGLEW_EXT_device_enumeration) + +#endif /* EGL_EXT_device_enumeration */ + +/* ------------------------- EGL_EXT_device_openwf ------------------------- */ + +#ifndef EGL_EXT_device_openwf +#define EGL_EXT_device_openwf 1 + +#define EGL_OPENWF_DEVICE_ID_EXT 0x3237 + +#define EGLEW_EXT_device_openwf EGLEW_GET_VAR(__EGLEW_EXT_device_openwf) + +#endif /* EGL_EXT_device_openwf */ + +/* -------------------------- EGL_EXT_device_query ------------------------- */ + +#ifndef EGL_EXT_device_query +#define EGL_EXT_device_query 1 + +#define EGL_BAD_DEVICE_EXT 0x322B +#define EGL_DEVICE_EXT 0x322C + +typedef EGLBoolean ( * PFNEGLQUERYDEVICEATTRIBEXTPROC) (EGLDeviceEXT device, EGLint attribute, EGLAttrib * value); +typedef const char * ( * PFNEGLQUERYDEVICESTRINGEXTPROC) (EGLDeviceEXT device, EGLint name); +typedef EGLBoolean ( * PFNEGLQUERYDISPLAYATTRIBEXTPROC) (EGLDisplay dpy, EGLint attribute, EGLAttrib * value); + +#define eglQueryDeviceAttribEXT EGLEW_GET_FUN(__eglewQueryDeviceAttribEXT) +#define eglQueryDeviceStringEXT EGLEW_GET_FUN(__eglewQueryDeviceStringEXT) +#define eglQueryDisplayAttribEXT EGLEW_GET_FUN(__eglewQueryDisplayAttribEXT) + +#define EGLEW_EXT_device_query EGLEW_GET_VAR(__EGLEW_EXT_device_query) + +#endif /* EGL_EXT_device_query */ + +/* ------------------ EGL_EXT_gl_colorspace_bt2020_linear ------------------ */ + +#ifndef EGL_EXT_gl_colorspace_bt2020_linear +#define EGL_EXT_gl_colorspace_bt2020_linear 1 + +#define EGL_GL_COLORSPACE_BT2020_LINEAR_EXT 0x333F + +#define EGLEW_EXT_gl_colorspace_bt2020_linear EGLEW_GET_VAR(__EGLEW_EXT_gl_colorspace_bt2020_linear) + +#endif /* EGL_EXT_gl_colorspace_bt2020_linear */ + +/* -------------------- EGL_EXT_gl_colorspace_bt2020_pq -------------------- */ + +#ifndef EGL_EXT_gl_colorspace_bt2020_pq +#define EGL_EXT_gl_colorspace_bt2020_pq 1 + +#define EGL_GL_COLORSPACE_BT2020_PQ_EXT 0x3340 + +#define EGLEW_EXT_gl_colorspace_bt2020_pq EGLEW_GET_VAR(__EGLEW_EXT_gl_colorspace_bt2020_pq) + +#endif /* EGL_EXT_gl_colorspace_bt2020_pq */ + +/* ------------------- EGL_EXT_gl_colorspace_scrgb_linear ------------------ */ + +#ifndef EGL_EXT_gl_colorspace_scrgb_linear +#define EGL_EXT_gl_colorspace_scrgb_linear 1 + +#define EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT 0x3350 + +#define EGLEW_EXT_gl_colorspace_scrgb_linear EGLEW_GET_VAR(__EGLEW_EXT_gl_colorspace_scrgb_linear) + +#endif /* EGL_EXT_gl_colorspace_scrgb_linear */ + +/* ---------------------- EGL_EXT_image_dma_buf_import --------------------- */ + +#ifndef EGL_EXT_image_dma_buf_import +#define EGL_EXT_image_dma_buf_import 1 + +#define EGL_LINUX_DMA_BUF_EXT 0x3270 +#define EGL_LINUX_DRM_FOURCC_EXT 0x3271 +#define EGL_DMA_BUF_PLANE0_FD_EXT 0x3272 +#define EGL_DMA_BUF_PLANE0_OFFSET_EXT 0x3273 +#define EGL_DMA_BUF_PLANE0_PITCH_EXT 0x3274 +#define EGL_DMA_BUF_PLANE1_FD_EXT 0x3275 +#define EGL_DMA_BUF_PLANE1_OFFSET_EXT 0x3276 +#define EGL_DMA_BUF_PLANE1_PITCH_EXT 0x3277 +#define EGL_DMA_BUF_PLANE2_FD_EXT 0x3278 +#define EGL_DMA_BUF_PLANE2_OFFSET_EXT 0x3279 +#define EGL_DMA_BUF_PLANE2_PITCH_EXT 0x327A +#define EGL_YUV_COLOR_SPACE_HINT_EXT 0x327B +#define EGL_SAMPLE_RANGE_HINT_EXT 0x327C +#define EGL_YUV_CHROMA_HORIZONTAL_SITING_HINT_EXT 0x327D +#define EGL_YUV_CHROMA_VERTICAL_SITING_HINT_EXT 0x327E +#define EGL_ITU_REC601_EXT 0x327F +#define EGL_ITU_REC709_EXT 0x3280 +#define EGL_ITU_REC2020_EXT 0x3281 +#define EGL_YUV_FULL_RANGE_EXT 0x3282 +#define EGL_YUV_NARROW_RANGE_EXT 0x3283 +#define EGL_YUV_CHROMA_SITING_0_EXT 0x3284 +#define EGL_YUV_CHROMA_SITING_0_5_EXT 0x3285 + +#define EGLEW_EXT_image_dma_buf_import EGLEW_GET_VAR(__EGLEW_EXT_image_dma_buf_import) + +#endif /* EGL_EXT_image_dma_buf_import */ + +/* ----------------- EGL_EXT_image_dma_buf_import_modifiers ---------------- */ + +#ifndef EGL_EXT_image_dma_buf_import_modifiers +#define EGL_EXT_image_dma_buf_import_modifiers 1 + +#define EGL_DMA_BUF_PLANE3_FD_EXT 0x3440 +#define EGL_DMA_BUF_PLANE3_OFFSET_EXT 0x3441 +#define EGL_DMA_BUF_PLANE3_PITCH_EXT 0x3442 +#define EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT 0x3443 +#define EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT 0x3444 +#define EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT 0x3445 +#define EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT 0x3446 +#define EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT 0x3447 +#define EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT 0x3448 +#define EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT 0x3449 +#define EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT 0x344A + +typedef EGLBoolean ( * PFNEGLQUERYDMABUFFORMATSEXTPROC) (EGLDisplay dpy, EGLint max_formats, EGLint *formats, EGLint *num_formats); +typedef EGLBoolean ( * PFNEGLQUERYDMABUFMODIFIERSEXTPROC) (EGLDisplay dpy, EGLint format, EGLint max_modifiers, EGLuint64KHR *modifiers, EGLBoolean *external_only, EGLint *num_modifiers); + +#define eglQueryDmaBufFormatsEXT EGLEW_GET_FUN(__eglewQueryDmaBufFormatsEXT) +#define eglQueryDmaBufModifiersEXT EGLEW_GET_FUN(__eglewQueryDmaBufModifiersEXT) + +#define EGLEW_EXT_image_dma_buf_import_modifiers EGLEW_GET_VAR(__EGLEW_EXT_image_dma_buf_import_modifiers) + +#endif /* EGL_EXT_image_dma_buf_import_modifiers */ + +/* ------------------------ EGL_EXT_multiview_window ----------------------- */ + +#ifndef EGL_EXT_multiview_window +#define EGL_EXT_multiview_window 1 + +#define EGL_MULTIVIEW_VIEW_COUNT_EXT 0x3134 + +#define EGLEW_EXT_multiview_window EGLEW_GET_VAR(__EGLEW_EXT_multiview_window) + +#endif /* EGL_EXT_multiview_window */ + +/* -------------------------- EGL_EXT_output_base -------------------------- */ + +#ifndef EGL_EXT_output_base +#define EGL_EXT_output_base 1 + +#define EGL_BAD_OUTPUT_LAYER_EXT 0x322D +#define EGL_BAD_OUTPUT_PORT_EXT 0x322E +#define EGL_SWAP_INTERVAL_EXT 0x322F + +typedef EGLBoolean ( * PFNEGLGETOUTPUTLAYERSEXTPROC) (EGLDisplay dpy, const EGLAttrib * attrib_list, EGLOutputLayerEXT * layers, EGLint max_layers, EGLint * num_layers); +typedef EGLBoolean ( * PFNEGLGETOUTPUTPORTSEXTPROC) (EGLDisplay dpy, const EGLAttrib * attrib_list, EGLOutputPortEXT * ports, EGLint max_ports, EGLint * num_ports); +typedef EGLBoolean ( * PFNEGLOUTPUTLAYERATTRIBEXTPROC) (EGLDisplay dpy, EGLOutputLayerEXT layer, EGLint attribute, EGLAttrib value); +typedef EGLBoolean ( * PFNEGLOUTPUTPORTATTRIBEXTPROC) (EGLDisplay dpy, EGLOutputPortEXT port, EGLint attribute, EGLAttrib value); +typedef EGLBoolean ( * PFNEGLQUERYOUTPUTLAYERATTRIBEXTPROC) (EGLDisplay dpy, EGLOutputLayerEXT layer, EGLint attribute, EGLAttrib * value); +typedef const char * ( * PFNEGLQUERYOUTPUTLAYERSTRINGEXTPROC) (EGLDisplay dpy, EGLOutputLayerEXT layer, EGLint name); +typedef EGLBoolean ( * PFNEGLQUERYOUTPUTPORTATTRIBEXTPROC) (EGLDisplay dpy, EGLOutputPortEXT port, EGLint attribute, EGLAttrib * value); +typedef const char * ( * PFNEGLQUERYOUTPUTPORTSTRINGEXTPROC) (EGLDisplay dpy, EGLOutputPortEXT port, EGLint name); + +#define eglGetOutputLayersEXT EGLEW_GET_FUN(__eglewGetOutputLayersEXT) +#define eglGetOutputPortsEXT EGLEW_GET_FUN(__eglewGetOutputPortsEXT) +#define eglOutputLayerAttribEXT EGLEW_GET_FUN(__eglewOutputLayerAttribEXT) +#define eglOutputPortAttribEXT EGLEW_GET_FUN(__eglewOutputPortAttribEXT) +#define eglQueryOutputLayerAttribEXT EGLEW_GET_FUN(__eglewQueryOutputLayerAttribEXT) +#define eglQueryOutputLayerStringEXT EGLEW_GET_FUN(__eglewQueryOutputLayerStringEXT) +#define eglQueryOutputPortAttribEXT EGLEW_GET_FUN(__eglewQueryOutputPortAttribEXT) +#define eglQueryOutputPortStringEXT EGLEW_GET_FUN(__eglewQueryOutputPortStringEXT) + +#define EGLEW_EXT_output_base EGLEW_GET_VAR(__EGLEW_EXT_output_base) + +#endif /* EGL_EXT_output_base */ + +/* --------------------------- EGL_EXT_output_drm -------------------------- */ + +#ifndef EGL_EXT_output_drm +#define EGL_EXT_output_drm 1 + +#define EGL_DRM_CRTC_EXT 0x3234 +#define EGL_DRM_PLANE_EXT 0x3235 +#define EGL_DRM_CONNECTOR_EXT 0x3236 + +#define EGLEW_EXT_output_drm EGLEW_GET_VAR(__EGLEW_EXT_output_drm) + +#endif /* EGL_EXT_output_drm */ + +/* ------------------------- EGL_EXT_output_openwf ------------------------- */ + +#ifndef EGL_EXT_output_openwf +#define EGL_EXT_output_openwf 1 + +#define EGL_OPENWF_PIPELINE_ID_EXT 0x3238 +#define EGL_OPENWF_PORT_ID_EXT 0x3239 + +#define EGLEW_EXT_output_openwf EGLEW_GET_VAR(__EGLEW_EXT_output_openwf) + +#endif /* EGL_EXT_output_openwf */ + +/* ----------------------- EGL_EXT_pixel_format_float ---------------------- */ + +#ifndef EGL_EXT_pixel_format_float +#define EGL_EXT_pixel_format_float 1 + +#define EGL_COLOR_COMPONENT_TYPE_EXT 0x3339 +#define EGL_COLOR_COMPONENT_TYPE_FIXED_EXT 0x333A +#define EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT 0x333B + +#define EGLEW_EXT_pixel_format_float EGLEW_GET_VAR(__EGLEW_EXT_pixel_format_float) + +#endif /* EGL_EXT_pixel_format_float */ + +/* ------------------------- EGL_EXT_platform_base ------------------------- */ + +#ifndef EGL_EXT_platform_base +#define EGL_EXT_platform_base 1 + +typedef EGLSurface ( * PFNEGLCREATEPLATFORMPIXMAPSURFACEEXTPROC) (EGLDisplay dpy, EGLConfig config, void * native_pixmap, const EGLint * attrib_list); +typedef EGLSurface ( * PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC) (EGLDisplay dpy, EGLConfig config, void * native_window, const EGLint * attrib_list); +typedef EGLDisplay ( * PFNEGLGETPLATFORMDISPLAYEXTPROC) (EGLenum platform, void * native_display, const EGLint * attrib_list); + +#define eglCreatePlatformPixmapSurfaceEXT EGLEW_GET_FUN(__eglewCreatePlatformPixmapSurfaceEXT) +#define eglCreatePlatformWindowSurfaceEXT EGLEW_GET_FUN(__eglewCreatePlatformWindowSurfaceEXT) +#define eglGetPlatformDisplayEXT EGLEW_GET_FUN(__eglewGetPlatformDisplayEXT) + +#define EGLEW_EXT_platform_base EGLEW_GET_VAR(__EGLEW_EXT_platform_base) + +#endif /* EGL_EXT_platform_base */ + +/* ------------------------ EGL_EXT_platform_device ------------------------ */ + +#ifndef EGL_EXT_platform_device +#define EGL_EXT_platform_device 1 + +#define EGL_PLATFORM_DEVICE_EXT 0x313F + +#define EGLEW_EXT_platform_device EGLEW_GET_VAR(__EGLEW_EXT_platform_device) + +#endif /* EGL_EXT_platform_device */ + +/* ------------------------ EGL_EXT_platform_wayland ----------------------- */ + +#ifndef EGL_EXT_platform_wayland +#define EGL_EXT_platform_wayland 1 + +#define EGL_PLATFORM_WAYLAND_EXT 0x31D8 + +#define EGLEW_EXT_platform_wayland EGLEW_GET_VAR(__EGLEW_EXT_platform_wayland) + +#endif /* EGL_EXT_platform_wayland */ + +/* -------------------------- EGL_EXT_platform_x11 ------------------------- */ + +#ifndef EGL_EXT_platform_x11 +#define EGL_EXT_platform_x11 1 + +#define EGL_PLATFORM_X11_EXT 0x31D5 +#define EGL_PLATFORM_X11_SCREEN_EXT 0x31D6 + +#define EGLEW_EXT_platform_x11 EGLEW_GET_VAR(__EGLEW_EXT_platform_x11) + +#endif /* EGL_EXT_platform_x11 */ + +/* ----------------------- EGL_EXT_protected_content ----------------------- */ + +#ifndef EGL_EXT_protected_content +#define EGL_EXT_protected_content 1 + +#define EGL_PROTECTED_CONTENT_EXT 0x32C0 + +#define EGLEW_EXT_protected_content EGLEW_GET_VAR(__EGLEW_EXT_protected_content) + +#endif /* EGL_EXT_protected_content */ + +/* ----------------------- EGL_EXT_protected_surface ----------------------- */ + +#ifndef EGL_EXT_protected_surface +#define EGL_EXT_protected_surface 1 + +#define EGL_PROTECTED_CONTENT_EXT 0x32C0 + +#define EGLEW_EXT_protected_surface EGLEW_GET_VAR(__EGLEW_EXT_protected_surface) + +#endif /* EGL_EXT_protected_surface */ + +/* ------------------- EGL_EXT_stream_consumer_egloutput ------------------- */ + +#ifndef EGL_EXT_stream_consumer_egloutput +#define EGL_EXT_stream_consumer_egloutput 1 + +typedef EGLBoolean ( * PFNEGLSTREAMCONSUMEROUTPUTEXTPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLOutputLayerEXT layer); + +#define eglStreamConsumerOutputEXT EGLEW_GET_FUN(__eglewStreamConsumerOutputEXT) + +#define EGLEW_EXT_stream_consumer_egloutput EGLEW_GET_VAR(__EGLEW_EXT_stream_consumer_egloutput) + +#endif /* EGL_EXT_stream_consumer_egloutput */ + +/* ------------------- EGL_EXT_surface_SMPTE2086_metadata ------------------ */ + +#ifndef EGL_EXT_surface_SMPTE2086_metadata +#define EGL_EXT_surface_SMPTE2086_metadata 1 + +#define EGL_SMPTE2086_DISPLAY_PRIMARY_RX_EXT 0x3341 +#define EGL_SMPTE2086_DISPLAY_PRIMARY_RY_EXT 0x3342 +#define EGL_SMPTE2086_DISPLAY_PRIMARY_GX_EXT 0x3343 +#define EGL_SMPTE2086_DISPLAY_PRIMARY_GY_EXT 0x3344 +#define EGL_SMPTE2086_DISPLAY_PRIMARY_BX_EXT 0x3345 +#define EGL_SMPTE2086_DISPLAY_PRIMARY_BY_EXT 0x3346 +#define EGL_SMPTE2086_WHITE_POINT_X_EXT 0x3347 +#define EGL_SMPTE2086_WHITE_POINT_Y_EXT 0x3348 +#define EGL_SMPTE2086_MAX_LUMINANCE_EXT 0x3349 +#define EGL_SMPTE2086_MIN_LUMINANCE_EXT 0x334A + +#define EGLEW_EXT_surface_SMPTE2086_metadata EGLEW_GET_VAR(__EGLEW_EXT_surface_SMPTE2086_metadata) + +#endif /* EGL_EXT_surface_SMPTE2086_metadata */ + +/* -------------------- EGL_EXT_swap_buffers_with_damage ------------------- */ + +#ifndef EGL_EXT_swap_buffers_with_damage +#define EGL_EXT_swap_buffers_with_damage 1 + +typedef EGLBoolean ( * PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC) (EGLDisplay dpy, EGLSurface surface, EGLint * rects, EGLint n_rects); + +#define eglSwapBuffersWithDamageEXT EGLEW_GET_FUN(__eglewSwapBuffersWithDamageEXT) + +#define EGLEW_EXT_swap_buffers_with_damage EGLEW_GET_VAR(__EGLEW_EXT_swap_buffers_with_damage) + +#endif /* EGL_EXT_swap_buffers_with_damage */ + +/* -------------------------- EGL_EXT_yuv_surface -------------------------- */ + +#ifndef EGL_EXT_yuv_surface +#define EGL_EXT_yuv_surface 1 + +#define EGL_YUV_BUFFER_EXT 0x3300 +#define EGL_YUV_ORDER_EXT 0x3301 +#define EGL_YUV_ORDER_YUV_EXT 0x3302 +#define EGL_YUV_ORDER_YVU_EXT 0x3303 +#define EGL_YUV_ORDER_YUYV_EXT 0x3304 +#define EGL_YUV_ORDER_UYVY_EXT 0x3305 +#define EGL_YUV_ORDER_YVYU_EXT 0x3306 +#define EGL_YUV_ORDER_VYUY_EXT 0x3307 +#define EGL_YUV_ORDER_AYUV_EXT 0x3308 +#define EGL_YUV_CSC_STANDARD_EXT 0x330A +#define EGL_YUV_CSC_STANDARD_601_EXT 0x330B +#define EGL_YUV_CSC_STANDARD_709_EXT 0x330C +#define EGL_YUV_CSC_STANDARD_2020_EXT 0x330D +#define EGL_YUV_NUMBER_OF_PLANES_EXT 0x3311 +#define EGL_YUV_SUBSAMPLE_EXT 0x3312 +#define EGL_YUV_SUBSAMPLE_4_2_0_EXT 0x3313 +#define EGL_YUV_SUBSAMPLE_4_2_2_EXT 0x3314 +#define EGL_YUV_SUBSAMPLE_4_4_4_EXT 0x3315 +#define EGL_YUV_DEPTH_RANGE_EXT 0x3317 +#define EGL_YUV_DEPTH_RANGE_LIMITED_EXT 0x3318 +#define EGL_YUV_DEPTH_RANGE_FULL_EXT 0x3319 +#define EGL_YUV_PLANE_BPP_EXT 0x331A +#define EGL_YUV_PLANE_BPP_0_EXT 0x331B +#define EGL_YUV_PLANE_BPP_8_EXT 0x331C +#define EGL_YUV_PLANE_BPP_10_EXT 0x331D + +#define EGLEW_EXT_yuv_surface EGLEW_GET_VAR(__EGLEW_EXT_yuv_surface) + +#endif /* EGL_EXT_yuv_surface */ + +/* -------------------------- EGL_HI_clientpixmap -------------------------- */ + +#ifndef EGL_HI_clientpixmap +#define EGL_HI_clientpixmap 1 + +#define EGL_CLIENT_PIXMAP_POINTER_HI 0x8F74 + +typedef EGLSurface ( * PFNEGLCREATEPIXMAPSURFACEHIPROC) (EGLDisplay dpy, EGLConfig config, struct EGLClientPixmapHI * pixmap); + +#define eglCreatePixmapSurfaceHI EGLEW_GET_FUN(__eglewCreatePixmapSurfaceHI) + +#define EGLEW_HI_clientpixmap EGLEW_GET_VAR(__EGLEW_HI_clientpixmap) + +#endif /* EGL_HI_clientpixmap */ + +/* -------------------------- EGL_HI_colorformats -------------------------- */ + +#ifndef EGL_HI_colorformats +#define EGL_HI_colorformats 1 + +#define EGL_COLOR_FORMAT_HI 0x8F70 +#define EGL_COLOR_RGB_HI 0x8F71 +#define EGL_COLOR_RGBA_HI 0x8F72 +#define EGL_COLOR_ARGB_HI 0x8F73 + +#define EGLEW_HI_colorformats EGLEW_GET_VAR(__EGLEW_HI_colorformats) + +#endif /* EGL_HI_colorformats */ + +/* ------------------------ EGL_IMG_context_priority ----------------------- */ + +#ifndef EGL_IMG_context_priority +#define EGL_IMG_context_priority 1 + +#define EGL_CONTEXT_PRIORITY_LEVEL_IMG 0x3100 +#define EGL_CONTEXT_PRIORITY_HIGH_IMG 0x3101 +#define EGL_CONTEXT_PRIORITY_MEDIUM_IMG 0x3102 +#define EGL_CONTEXT_PRIORITY_LOW_IMG 0x3103 + +#define EGLEW_IMG_context_priority EGLEW_GET_VAR(__EGLEW_IMG_context_priority) + +#endif /* EGL_IMG_context_priority */ + +/* ---------------------- EGL_IMG_image_plane_attribs ---------------------- */ + +#ifndef EGL_IMG_image_plane_attribs +#define EGL_IMG_image_plane_attribs 1 + +#define EGL_NATIVE_BUFFER_MULTIPLANE_SEPARATE_IMG 0x3105 +#define EGL_NATIVE_BUFFER_PLANE_OFFSET_IMG 0x3106 + +#define EGLEW_IMG_image_plane_attribs EGLEW_GET_VAR(__EGLEW_IMG_image_plane_attribs) + +#endif /* EGL_IMG_image_plane_attribs */ + +/* ---------------------------- EGL_KHR_cl_event --------------------------- */ + +#ifndef EGL_KHR_cl_event +#define EGL_KHR_cl_event 1 + +#define EGL_CL_EVENT_HANDLE_KHR 0x309C +#define EGL_SYNC_CL_EVENT_KHR 0x30FE +#define EGL_SYNC_CL_EVENT_COMPLETE_KHR 0x30FF + +#define EGLEW_KHR_cl_event EGLEW_GET_VAR(__EGLEW_KHR_cl_event) + +#endif /* EGL_KHR_cl_event */ + +/* --------------------------- EGL_KHR_cl_event2 --------------------------- */ + +#ifndef EGL_KHR_cl_event2 +#define EGL_KHR_cl_event2 1 + +#define EGL_CL_EVENT_HANDLE_KHR 0x309C +#define EGL_SYNC_CL_EVENT_KHR 0x30FE +#define EGL_SYNC_CL_EVENT_COMPLETE_KHR 0x30FF + +typedef EGLSyncKHR ( * PFNEGLCREATESYNC64KHRPROC) (EGLDisplay dpy, EGLenum type, const EGLAttribKHR * attrib_list); + +#define eglCreateSync64KHR EGLEW_GET_FUN(__eglewCreateSync64KHR) + +#define EGLEW_KHR_cl_event2 EGLEW_GET_VAR(__EGLEW_KHR_cl_event2) + +#endif /* EGL_KHR_cl_event2 */ + +/* ----------------- EGL_KHR_client_get_all_proc_addresses ----------------- */ + +#ifndef EGL_KHR_client_get_all_proc_addresses +#define EGL_KHR_client_get_all_proc_addresses 1 + +#define EGLEW_KHR_client_get_all_proc_addresses EGLEW_GET_VAR(__EGLEW_KHR_client_get_all_proc_addresses) + +#endif /* EGL_KHR_client_get_all_proc_addresses */ + +/* ------------------------- EGL_KHR_config_attribs ------------------------ */ + +#ifndef EGL_KHR_config_attribs +#define EGL_KHR_config_attribs 1 + +#define EGL_VG_COLORSPACE_LINEAR_BIT_KHR 0x0020 +#define EGL_VG_ALPHA_FORMAT_PRE_BIT_KHR 0x0040 +#define EGL_CONFORMANT_KHR 0x3042 + +#define EGLEW_KHR_config_attribs EGLEW_GET_VAR(__EGLEW_KHR_config_attribs) + +#endif /* EGL_KHR_config_attribs */ + +/* --------------------- EGL_KHR_context_flush_control --------------------- */ + +#ifndef EGL_KHR_context_flush_control +#define EGL_KHR_context_flush_control 1 + +#define EGL_CONTEXT_RELEASE_BEHAVIOR_NONE_KHR 0 +#define EGL_CONTEXT_RELEASE_BEHAVIOR_KHR 0x2097 +#define EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR 0x2098 + +#define EGLEW_KHR_context_flush_control EGLEW_GET_VAR(__EGLEW_KHR_context_flush_control) + +#endif /* EGL_KHR_context_flush_control */ + +/* ------------------------- EGL_KHR_create_context ------------------------ */ + +#ifndef EGL_KHR_create_context +#define EGL_KHR_create_context 1 + +#define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR 0x00000001 +#define EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR 0x00000001 +#define EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR 0x00000002 +#define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR 0x00000002 +#define EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR 0x00000004 +#define EGL_OPENGL_ES3_BIT 0x00000040 +#define EGL_OPENGL_ES3_BIT_KHR 0x00000040 +#define EGL_CONTEXT_MAJOR_VERSION_KHR 0x3098 +#define EGL_CONTEXT_MINOR_VERSION_KHR 0x30FB +#define EGL_CONTEXT_FLAGS_KHR 0x30FC +#define EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR 0x30FD +#define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR 0x31BD +#define EGL_NO_RESET_NOTIFICATION_KHR 0x31BE +#define EGL_LOSE_CONTEXT_ON_RESET_KHR 0x31BF + +#define EGLEW_KHR_create_context EGLEW_GET_VAR(__EGLEW_KHR_create_context) + +#endif /* EGL_KHR_create_context */ + +/* -------------------- EGL_KHR_create_context_no_error -------------------- */ + +#ifndef EGL_KHR_create_context_no_error +#define EGL_KHR_create_context_no_error 1 + +#define EGL_CONTEXT_OPENGL_NO_ERROR_KHR 0x31B3 + +#define EGLEW_KHR_create_context_no_error EGLEW_GET_VAR(__EGLEW_KHR_create_context_no_error) + +#endif /* EGL_KHR_create_context_no_error */ + +/* ----------------------------- EGL_KHR_debug ----------------------------- */ + +#ifndef EGL_KHR_debug +#define EGL_KHR_debug 1 + +#define EGL_OBJECT_THREAD_KHR 0x33B0 +#define EGL_OBJECT_DISPLAY_KHR 0x33B1 +#define EGL_OBJECT_CONTEXT_KHR 0x33B2 +#define EGL_OBJECT_SURFACE_KHR 0x33B3 +#define EGL_OBJECT_IMAGE_KHR 0x33B4 +#define EGL_OBJECT_SYNC_KHR 0x33B5 +#define EGL_OBJECT_STREAM_KHR 0x33B6 +#define EGL_DEBUG_CALLBACK_KHR 0x33B8 +#define EGL_DEBUG_MSG_CRITICAL_KHR 0x33B9 +#define EGL_DEBUG_MSG_ERROR_KHR 0x33BA +#define EGL_DEBUG_MSG_WARN_KHR 0x33BB +#define EGL_DEBUG_MSG_INFO_KHR 0x33BC + +typedef EGLint ( * PFNEGLDEBUGMESSAGECONTROLKHRPROC) (EGLDEBUGPROCKHR callback, const EGLAttrib * attrib_list); +typedef EGLint ( * PFNEGLLABELOBJECTKHRPROC) (EGLDisplay display, EGLenum objectType, EGLObjectKHR object, EGLLabelKHR label); +typedef EGLBoolean ( * PFNEGLQUERYDEBUGKHRPROC) (EGLint attribute, EGLAttrib * value); + +#define eglDebugMessageControlKHR EGLEW_GET_FUN(__eglewDebugMessageControlKHR) +#define eglLabelObjectKHR EGLEW_GET_FUN(__eglewLabelObjectKHR) +#define eglQueryDebugKHR EGLEW_GET_FUN(__eglewQueryDebugKHR) + +#define EGLEW_KHR_debug EGLEW_GET_VAR(__EGLEW_KHR_debug) + +#endif /* EGL_KHR_debug */ + +/* --------------------------- EGL_KHR_fence_sync -------------------------- */ + +#ifndef EGL_KHR_fence_sync +#define EGL_KHR_fence_sync 1 + +#define EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR 0x30F0 +#define EGL_SYNC_CONDITION_KHR 0x30F8 +#define EGL_SYNC_FENCE_KHR 0x30F9 + +#define EGLEW_KHR_fence_sync EGLEW_GET_VAR(__EGLEW_KHR_fence_sync) + +#endif /* EGL_KHR_fence_sync */ + +/* --------------------- EGL_KHR_get_all_proc_addresses -------------------- */ + +#ifndef EGL_KHR_get_all_proc_addresses +#define EGL_KHR_get_all_proc_addresses 1 + +#define EGLEW_KHR_get_all_proc_addresses EGLEW_GET_VAR(__EGLEW_KHR_get_all_proc_addresses) + +#endif /* EGL_KHR_get_all_proc_addresses */ + +/* ------------------------- EGL_KHR_gl_colorspace ------------------------- */ + +#ifndef EGL_KHR_gl_colorspace +#define EGL_KHR_gl_colorspace 1 + +#define EGL_GL_COLORSPACE_SRGB_KHR 0x3089 +#define EGL_GL_COLORSPACE_LINEAR_KHR 0x308A +#define EGL_GL_COLORSPACE_KHR 0x309D + +#define EGLEW_KHR_gl_colorspace EGLEW_GET_VAR(__EGLEW_KHR_gl_colorspace) + +#endif /* EGL_KHR_gl_colorspace */ + +/* --------------------- EGL_KHR_gl_renderbuffer_image --------------------- */ + +#ifndef EGL_KHR_gl_renderbuffer_image +#define EGL_KHR_gl_renderbuffer_image 1 + +#define EGL_GL_RENDERBUFFER_KHR 0x30B9 + +#define EGLEW_KHR_gl_renderbuffer_image EGLEW_GET_VAR(__EGLEW_KHR_gl_renderbuffer_image) + +#endif /* EGL_KHR_gl_renderbuffer_image */ + +/* ---------------------- EGL_KHR_gl_texture_2D_image ---------------------- */ + +#ifndef EGL_KHR_gl_texture_2D_image +#define EGL_KHR_gl_texture_2D_image 1 + +#define EGL_GL_TEXTURE_2D_KHR 0x30B1 +#define EGL_GL_TEXTURE_LEVEL_KHR 0x30BC + +#define EGLEW_KHR_gl_texture_2D_image EGLEW_GET_VAR(__EGLEW_KHR_gl_texture_2D_image) + +#endif /* EGL_KHR_gl_texture_2D_image */ + +/* ---------------------- EGL_KHR_gl_texture_3D_image ---------------------- */ + +#ifndef EGL_KHR_gl_texture_3D_image +#define EGL_KHR_gl_texture_3D_image 1 + +#define EGL_GL_TEXTURE_3D_KHR 0x30B2 +#define EGL_GL_TEXTURE_ZOFFSET_KHR 0x30BD + +#define EGLEW_KHR_gl_texture_3D_image EGLEW_GET_VAR(__EGLEW_KHR_gl_texture_3D_image) + +#endif /* EGL_KHR_gl_texture_3D_image */ + +/* -------------------- EGL_KHR_gl_texture_cubemap_image ------------------- */ + +#ifndef EGL_KHR_gl_texture_cubemap_image +#define EGL_KHR_gl_texture_cubemap_image 1 + +#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR 0x30B3 +#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X_KHR 0x30B4 +#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y_KHR 0x30B5 +#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_KHR 0x30B6 +#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z_KHR 0x30B7 +#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_KHR 0x30B8 + +#define EGLEW_KHR_gl_texture_cubemap_image EGLEW_GET_VAR(__EGLEW_KHR_gl_texture_cubemap_image) + +#endif /* EGL_KHR_gl_texture_cubemap_image */ + +/* ----------------------------- EGL_KHR_image ----------------------------- */ + +#ifndef EGL_KHR_image +#define EGL_KHR_image 1 + +#define EGL_NATIVE_PIXMAP_KHR 0x30B0 + +typedef EGLImageKHR ( * PFNEGLCREATEIMAGEKHRPROC) (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint * attrib_list); +typedef EGLBoolean ( * PFNEGLDESTROYIMAGEKHRPROC) (EGLDisplay dpy, EGLImageKHR image); + +#define eglCreateImageKHR EGLEW_GET_FUN(__eglewCreateImageKHR) +#define eglDestroyImageKHR EGLEW_GET_FUN(__eglewDestroyImageKHR) + +#define EGLEW_KHR_image EGLEW_GET_VAR(__EGLEW_KHR_image) + +#endif /* EGL_KHR_image */ + +/* --------------------------- EGL_KHR_image_base -------------------------- */ + +#ifndef EGL_KHR_image_base +#define EGL_KHR_image_base 1 + +#define EGL_IMAGE_PRESERVED_KHR 0x30D2 + +#define EGLEW_KHR_image_base EGLEW_GET_VAR(__EGLEW_KHR_image_base) + +#endif /* EGL_KHR_image_base */ + +/* -------------------------- EGL_KHR_image_pixmap ------------------------- */ + +#ifndef EGL_KHR_image_pixmap +#define EGL_KHR_image_pixmap 1 + +#define EGL_NATIVE_PIXMAP_KHR 0x30B0 + +#define EGLEW_KHR_image_pixmap EGLEW_GET_VAR(__EGLEW_KHR_image_pixmap) + +#endif /* EGL_KHR_image_pixmap */ + +/* -------------------------- EGL_KHR_lock_surface ------------------------- */ + +#ifndef EGL_KHR_lock_surface +#define EGL_KHR_lock_surface 1 + +#define EGL_READ_SURFACE_BIT_KHR 0x0001 +#define EGL_WRITE_SURFACE_BIT_KHR 0x0002 +#define EGL_LOCK_SURFACE_BIT_KHR 0x0080 +#define EGL_OPTIMAL_FORMAT_BIT_KHR 0x0100 +#define EGL_MATCH_FORMAT_KHR 0x3043 +#define EGL_FORMAT_RGB_565_EXACT_KHR 0x30C0 +#define EGL_FORMAT_RGB_565_KHR 0x30C1 +#define EGL_FORMAT_RGBA_8888_EXACT_KHR 0x30C2 +#define EGL_FORMAT_RGBA_8888_KHR 0x30C3 +#define EGL_MAP_PRESERVE_PIXELS_KHR 0x30C4 +#define EGL_LOCK_USAGE_HINT_KHR 0x30C5 +#define EGL_BITMAP_POINTER_KHR 0x30C6 +#define EGL_BITMAP_PITCH_KHR 0x30C7 +#define EGL_BITMAP_ORIGIN_KHR 0x30C8 +#define EGL_BITMAP_PIXEL_RED_OFFSET_KHR 0x30C9 +#define EGL_BITMAP_PIXEL_GREEN_OFFSET_KHR 0x30CA +#define EGL_BITMAP_PIXEL_BLUE_OFFSET_KHR 0x30CB +#define EGL_BITMAP_PIXEL_ALPHA_OFFSET_KHR 0x30CC +#define EGL_BITMAP_PIXEL_LUMINANCE_OFFSET_KHR 0x30CD +#define EGL_LOWER_LEFT_KHR 0x30CE +#define EGL_UPPER_LEFT_KHR 0x30CF + +typedef EGLBoolean ( * PFNEGLLOCKSURFACEKHRPROC) (EGLDisplay dpy, EGLSurface surface, const EGLint * attrib_list); +typedef EGLBoolean ( * PFNEGLUNLOCKSURFACEKHRPROC) (EGLDisplay dpy, EGLSurface surface); + +#define eglLockSurfaceKHR EGLEW_GET_FUN(__eglewLockSurfaceKHR) +#define eglUnlockSurfaceKHR EGLEW_GET_FUN(__eglewUnlockSurfaceKHR) + +#define EGLEW_KHR_lock_surface EGLEW_GET_VAR(__EGLEW_KHR_lock_surface) + +#endif /* EGL_KHR_lock_surface */ + +/* ------------------------- EGL_KHR_lock_surface2 ------------------------- */ + +#ifndef EGL_KHR_lock_surface2 +#define EGL_KHR_lock_surface2 1 + +#define EGL_BITMAP_PIXEL_SIZE_KHR 0x3110 + +#define EGLEW_KHR_lock_surface2 EGLEW_GET_VAR(__EGLEW_KHR_lock_surface2) + +#endif /* EGL_KHR_lock_surface2 */ + +/* ------------------------- EGL_KHR_lock_surface3 ------------------------- */ + +#ifndef EGL_KHR_lock_surface3 +#define EGL_KHR_lock_surface3 1 + +#define EGL_READ_SURFACE_BIT_KHR 0x0001 +#define EGL_WRITE_SURFACE_BIT_KHR 0x0002 +#define EGL_LOCK_SURFACE_BIT_KHR 0x0080 +#define EGL_OPTIMAL_FORMAT_BIT_KHR 0x0100 +#define EGL_MATCH_FORMAT_KHR 0x3043 +#define EGL_FORMAT_RGB_565_EXACT_KHR 0x30C0 +#define EGL_FORMAT_RGB_565_KHR 0x30C1 +#define EGL_FORMAT_RGBA_8888_EXACT_KHR 0x30C2 +#define EGL_FORMAT_RGBA_8888_KHR 0x30C3 +#define EGL_MAP_PRESERVE_PIXELS_KHR 0x30C4 +#define EGL_LOCK_USAGE_HINT_KHR 0x30C5 +#define EGL_BITMAP_POINTER_KHR 0x30C6 +#define EGL_BITMAP_PITCH_KHR 0x30C7 +#define EGL_BITMAP_ORIGIN_KHR 0x30C8 +#define EGL_BITMAP_PIXEL_RED_OFFSET_KHR 0x30C9 +#define EGL_BITMAP_PIXEL_GREEN_OFFSET_KHR 0x30CA +#define EGL_BITMAP_PIXEL_BLUE_OFFSET_KHR 0x30CB +#define EGL_BITMAP_PIXEL_ALPHA_OFFSET_KHR 0x30CC +#define EGL_BITMAP_PIXEL_LUMINANCE_OFFSET_KHR 0x30CD +#define EGL_LOWER_LEFT_KHR 0x30CE +#define EGL_UPPER_LEFT_KHR 0x30CF +#define EGL_BITMAP_PIXEL_SIZE_KHR 0x3110 + +typedef EGLBoolean ( * PFNEGLQUERYSURFACE64KHRPROC) (EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLAttribKHR * value); + +#define eglQuerySurface64KHR EGLEW_GET_FUN(__eglewQuerySurface64KHR) + +#define EGLEW_KHR_lock_surface3 EGLEW_GET_VAR(__EGLEW_KHR_lock_surface3) + +#endif /* EGL_KHR_lock_surface3 */ + +/* --------------------- EGL_KHR_mutable_render_buffer --------------------- */ + +#ifndef EGL_KHR_mutable_render_buffer +#define EGL_KHR_mutable_render_buffer 1 + +#define EGL_MUTABLE_RENDER_BUFFER_BIT_KHR 0x1000 + +#define EGLEW_KHR_mutable_render_buffer EGLEW_GET_VAR(__EGLEW_KHR_mutable_render_buffer) + +#endif /* EGL_KHR_mutable_render_buffer */ + +/* ----------------------- EGL_KHR_no_config_context ----------------------- */ + +#ifndef EGL_KHR_no_config_context +#define EGL_KHR_no_config_context 1 + +#define EGLEW_KHR_no_config_context EGLEW_GET_VAR(__EGLEW_KHR_no_config_context) + +#endif /* EGL_KHR_no_config_context */ + +/* ------------------------- EGL_KHR_partial_update ------------------------ */ + +#ifndef EGL_KHR_partial_update +#define EGL_KHR_partial_update 1 + +#define EGL_BUFFER_AGE_KHR 0x313D + +typedef EGLBoolean ( * PFNEGLSETDAMAGEREGIONKHRPROC) (EGLDisplay dpy, EGLSurface surface, EGLint * rects, EGLint n_rects); + +#define eglSetDamageRegionKHR EGLEW_GET_FUN(__eglewSetDamageRegionKHR) + +#define EGLEW_KHR_partial_update EGLEW_GET_VAR(__EGLEW_KHR_partial_update) + +#endif /* EGL_KHR_partial_update */ + +/* ------------------------ EGL_KHR_platform_android ----------------------- */ + +#ifndef EGL_KHR_platform_android +#define EGL_KHR_platform_android 1 + +#define EGL_PLATFORM_ANDROID_KHR 0x3141 + +#define EGLEW_KHR_platform_android EGLEW_GET_VAR(__EGLEW_KHR_platform_android) + +#endif /* EGL_KHR_platform_android */ + +/* -------------------------- EGL_KHR_platform_gbm ------------------------- */ + +#ifndef EGL_KHR_platform_gbm +#define EGL_KHR_platform_gbm 1 + +#define EGL_PLATFORM_GBM_KHR 0x31D7 + +#define EGLEW_KHR_platform_gbm EGLEW_GET_VAR(__EGLEW_KHR_platform_gbm) + +#endif /* EGL_KHR_platform_gbm */ + +/* ------------------------ EGL_KHR_platform_wayland ----------------------- */ + +#ifndef EGL_KHR_platform_wayland +#define EGL_KHR_platform_wayland 1 + +#define EGL_PLATFORM_WAYLAND_KHR 0x31D8 + +#define EGLEW_KHR_platform_wayland EGLEW_GET_VAR(__EGLEW_KHR_platform_wayland) + +#endif /* EGL_KHR_platform_wayland */ + +/* -------------------------- EGL_KHR_platform_x11 ------------------------- */ + +#ifndef EGL_KHR_platform_x11 +#define EGL_KHR_platform_x11 1 + +#define EGL_PLATFORM_X11_KHR 0x31D5 +#define EGL_PLATFORM_X11_SCREEN_KHR 0x31D6 + +#define EGLEW_KHR_platform_x11 EGLEW_GET_VAR(__EGLEW_KHR_platform_x11) + +#endif /* EGL_KHR_platform_x11 */ + +/* ------------------------- EGL_KHR_reusable_sync ------------------------- */ + +#ifndef EGL_KHR_reusable_sync +#define EGL_KHR_reusable_sync 1 + +#define EGL_SYNC_FLUSH_COMMANDS_BIT_KHR 0x0001 +#define EGL_SYNC_STATUS_KHR 0x30F1 +#define EGL_SIGNALED_KHR 0x30F2 +#define EGL_UNSIGNALED_KHR 0x30F3 +#define EGL_TIMEOUT_EXPIRED_KHR 0x30F5 +#define EGL_CONDITION_SATISFIED_KHR 0x30F6 +#define EGL_SYNC_TYPE_KHR 0x30F7 +#define EGL_SYNC_REUSABLE_KHR 0x30FA +#define EGL_FOREVER_KHR 0xFFFFFFFFFFFFFFFF + +typedef EGLint ( * PFNEGLCLIENTWAITSYNCKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout); +typedef EGLSyncKHR ( * PFNEGLCREATESYNCKHRPROC) (EGLDisplay dpy, EGLenum type, const EGLint * attrib_list); +typedef EGLBoolean ( * PFNEGLDESTROYSYNCKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync); +typedef EGLBoolean ( * PFNEGLGETSYNCATTRIBKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint * value); +typedef EGLBoolean ( * PFNEGLSIGNALSYNCKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode); + +#define eglClientWaitSyncKHR EGLEW_GET_FUN(__eglewClientWaitSyncKHR) +#define eglCreateSyncKHR EGLEW_GET_FUN(__eglewCreateSyncKHR) +#define eglDestroySyncKHR EGLEW_GET_FUN(__eglewDestroySyncKHR) +#define eglGetSyncAttribKHR EGLEW_GET_FUN(__eglewGetSyncAttribKHR) +#define eglSignalSyncKHR EGLEW_GET_FUN(__eglewSignalSyncKHR) + +#define EGLEW_KHR_reusable_sync EGLEW_GET_VAR(__EGLEW_KHR_reusable_sync) + +#endif /* EGL_KHR_reusable_sync */ + +/* ----------------------------- EGL_KHR_stream ---------------------------- */ + +#ifndef EGL_KHR_stream +#define EGL_KHR_stream 1 + +#define EGL_CONSUMER_LATENCY_USEC_KHR 0x3210 +#define EGL_PRODUCER_FRAME_KHR 0x3212 +#define EGL_CONSUMER_FRAME_KHR 0x3213 +#define EGL_STREAM_STATE_KHR 0x3214 +#define EGL_STREAM_STATE_CREATED_KHR 0x3215 +#define EGL_STREAM_STATE_CONNECTING_KHR 0x3216 +#define EGL_STREAM_STATE_EMPTY_KHR 0x3217 +#define EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR 0x3218 +#define EGL_STREAM_STATE_OLD_FRAME_AVAILABLE_KHR 0x3219 +#define EGL_STREAM_STATE_DISCONNECTED_KHR 0x321A +#define EGL_BAD_STREAM_KHR 0x321B +#define EGL_BAD_STATE_KHR 0x321C + +typedef EGLStreamKHR ( * PFNEGLCREATESTREAMKHRPROC) (EGLDisplay dpy, const EGLint * attrib_list); +typedef EGLBoolean ( * PFNEGLDESTROYSTREAMKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream); +typedef EGLBoolean ( * PFNEGLQUERYSTREAMKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLint * value); +typedef EGLBoolean ( * PFNEGLQUERYSTREAMU64KHRPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLuint64KHR * value); +typedef EGLBoolean ( * PFNEGLSTREAMATTRIBKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLint value); + +#define eglCreateStreamKHR EGLEW_GET_FUN(__eglewCreateStreamKHR) +#define eglDestroyStreamKHR EGLEW_GET_FUN(__eglewDestroyStreamKHR) +#define eglQueryStreamKHR EGLEW_GET_FUN(__eglewQueryStreamKHR) +#define eglQueryStreamu64KHR EGLEW_GET_FUN(__eglewQueryStreamu64KHR) +#define eglStreamAttribKHR EGLEW_GET_FUN(__eglewStreamAttribKHR) + +#define EGLEW_KHR_stream EGLEW_GET_VAR(__EGLEW_KHR_stream) + +#endif /* EGL_KHR_stream */ + +/* ------------------------- EGL_KHR_stream_attrib ------------------------- */ + +#ifndef EGL_KHR_stream_attrib +#define EGL_KHR_stream_attrib 1 + +#define EGL_CONSUMER_LATENCY_USEC_KHR 0x3210 +#define EGL_STREAM_STATE_KHR 0x3214 +#define EGL_STREAM_STATE_CREATED_KHR 0x3215 +#define EGL_STREAM_STATE_CONNECTING_KHR 0x3216 + +typedef EGLStreamKHR ( * PFNEGLCREATESTREAMATTRIBKHRPROC) (EGLDisplay dpy, const EGLAttrib * attrib_list); +typedef EGLBoolean ( * PFNEGLQUERYSTREAMATTRIBKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLAttrib * value); +typedef EGLBoolean ( * PFNEGLSETSTREAMATTRIBKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLAttrib value); +typedef EGLBoolean ( * PFNEGLSTREAMCONSUMERACQUIREATTRIBKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream, const EGLAttrib * attrib_list); +typedef EGLBoolean ( * PFNEGLSTREAMCONSUMERRELEASEATTRIBKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream, const EGLAttrib * attrib_list); + +#define eglCreateStreamAttribKHR EGLEW_GET_FUN(__eglewCreateStreamAttribKHR) +#define eglQueryStreamAttribKHR EGLEW_GET_FUN(__eglewQueryStreamAttribKHR) +#define eglSetStreamAttribKHR EGLEW_GET_FUN(__eglewSetStreamAttribKHR) +#define eglStreamConsumerAcquireAttribKHR EGLEW_GET_FUN(__eglewStreamConsumerAcquireAttribKHR) +#define eglStreamConsumerReleaseAttribKHR EGLEW_GET_FUN(__eglewStreamConsumerReleaseAttribKHR) + +#define EGLEW_KHR_stream_attrib EGLEW_GET_VAR(__EGLEW_KHR_stream_attrib) + +#endif /* EGL_KHR_stream_attrib */ + +/* ------------------- EGL_KHR_stream_consumer_gltexture ------------------- */ + +#ifndef EGL_KHR_stream_consumer_gltexture +#define EGL_KHR_stream_consumer_gltexture 1 + +#define EGL_CONSUMER_ACQUIRE_TIMEOUT_USEC_KHR 0x321E + +typedef EGLBoolean ( * PFNEGLSTREAMCONSUMERACQUIREKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream); +typedef EGLBoolean ( * PFNEGLSTREAMCONSUMERGLTEXTUREEXTERNALKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream); +typedef EGLBoolean ( * PFNEGLSTREAMCONSUMERRELEASEKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream); + +#define eglStreamConsumerAcquireKHR EGLEW_GET_FUN(__eglewStreamConsumerAcquireKHR) +#define eglStreamConsumerGLTextureExternalKHR EGLEW_GET_FUN(__eglewStreamConsumerGLTextureExternalKHR) +#define eglStreamConsumerReleaseKHR EGLEW_GET_FUN(__eglewStreamConsumerReleaseKHR) + +#define EGLEW_KHR_stream_consumer_gltexture EGLEW_GET_VAR(__EGLEW_KHR_stream_consumer_gltexture) + +#endif /* EGL_KHR_stream_consumer_gltexture */ + +/* -------------------- EGL_KHR_stream_cross_process_fd -------------------- */ + +#ifndef EGL_KHR_stream_cross_process_fd +#define EGL_KHR_stream_cross_process_fd 1 + +typedef EGLStreamKHR ( * PFNEGLCREATESTREAMFROMFILEDESCRIPTORKHRPROC) (EGLDisplay dpy, EGLNativeFileDescriptorKHR file_descriptor); +typedef EGLNativeFileDescriptorKHR ( * PFNEGLGETSTREAMFILEDESCRIPTORKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream); + +#define eglCreateStreamFromFileDescriptorKHR EGLEW_GET_FUN(__eglewCreateStreamFromFileDescriptorKHR) +#define eglGetStreamFileDescriptorKHR EGLEW_GET_FUN(__eglewGetStreamFileDescriptorKHR) + +#define EGLEW_KHR_stream_cross_process_fd EGLEW_GET_VAR(__EGLEW_KHR_stream_cross_process_fd) + +#endif /* EGL_KHR_stream_cross_process_fd */ + +/* -------------------------- EGL_KHR_stream_fifo -------------------------- */ + +#ifndef EGL_KHR_stream_fifo +#define EGL_KHR_stream_fifo 1 + +#define EGL_STREAM_FIFO_LENGTH_KHR 0x31FC +#define EGL_STREAM_TIME_NOW_KHR 0x31FD +#define EGL_STREAM_TIME_CONSUMER_KHR 0x31FE +#define EGL_STREAM_TIME_PRODUCER_KHR 0x31FF + +typedef EGLBoolean ( * PFNEGLQUERYSTREAMTIMEKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLTimeKHR * value); + +#define eglQueryStreamTimeKHR EGLEW_GET_FUN(__eglewQueryStreamTimeKHR) + +#define EGLEW_KHR_stream_fifo EGLEW_GET_VAR(__EGLEW_KHR_stream_fifo) + +#endif /* EGL_KHR_stream_fifo */ + +/* ----------------- EGL_KHR_stream_producer_aldatalocator ----------------- */ + +#ifndef EGL_KHR_stream_producer_aldatalocator +#define EGL_KHR_stream_producer_aldatalocator 1 + +#define EGLEW_KHR_stream_producer_aldatalocator EGLEW_GET_VAR(__EGLEW_KHR_stream_producer_aldatalocator) + +#endif /* EGL_KHR_stream_producer_aldatalocator */ + +/* ------------------- EGL_KHR_stream_producer_eglsurface ------------------ */ + +#ifndef EGL_KHR_stream_producer_eglsurface +#define EGL_KHR_stream_producer_eglsurface 1 + +#define EGL_STREAM_BIT_KHR 0x0800 + +typedef EGLSurface ( * PFNEGLCREATESTREAMPRODUCERSURFACEKHRPROC) (EGLDisplay dpy, EGLConfig config, EGLStreamKHR stream, const EGLint * attrib_list); + +#define eglCreateStreamProducerSurfaceKHR EGLEW_GET_FUN(__eglewCreateStreamProducerSurfaceKHR) + +#define EGLEW_KHR_stream_producer_eglsurface EGLEW_GET_VAR(__EGLEW_KHR_stream_producer_eglsurface) + +#endif /* EGL_KHR_stream_producer_eglsurface */ + +/* ---------------------- EGL_KHR_surfaceless_context ---------------------- */ + +#ifndef EGL_KHR_surfaceless_context +#define EGL_KHR_surfaceless_context 1 + +#define EGLEW_KHR_surfaceless_context EGLEW_GET_VAR(__EGLEW_KHR_surfaceless_context) + +#endif /* EGL_KHR_surfaceless_context */ + +/* -------------------- EGL_KHR_swap_buffers_with_damage ------------------- */ + +#ifndef EGL_KHR_swap_buffers_with_damage +#define EGL_KHR_swap_buffers_with_damage 1 + +typedef EGLBoolean ( * PFNEGLSWAPBUFFERSWITHDAMAGEKHRPROC) (EGLDisplay dpy, EGLSurface surface, EGLint * rects, EGLint n_rects); + +#define eglSwapBuffersWithDamageKHR EGLEW_GET_FUN(__eglewSwapBuffersWithDamageKHR) + +#define EGLEW_KHR_swap_buffers_with_damage EGLEW_GET_VAR(__EGLEW_KHR_swap_buffers_with_damage) + +#endif /* EGL_KHR_swap_buffers_with_damage */ + +/* ------------------------ EGL_KHR_vg_parent_image ------------------------ */ + +#ifndef EGL_KHR_vg_parent_image +#define EGL_KHR_vg_parent_image 1 + +#define EGL_VG_PARENT_IMAGE_KHR 0x30BA + +#define EGLEW_KHR_vg_parent_image EGLEW_GET_VAR(__EGLEW_KHR_vg_parent_image) + +#endif /* EGL_KHR_vg_parent_image */ + +/* --------------------------- EGL_KHR_wait_sync --------------------------- */ + +#ifndef EGL_KHR_wait_sync +#define EGL_KHR_wait_sync 1 + +typedef EGLint ( * PFNEGLWAITSYNCKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync, EGLint flags); + +#define eglWaitSyncKHR EGLEW_GET_FUN(__eglewWaitSyncKHR) + +#define EGLEW_KHR_wait_sync EGLEW_GET_VAR(__EGLEW_KHR_wait_sync) + +#endif /* EGL_KHR_wait_sync */ + +/* --------------------------- EGL_MESA_drm_image -------------------------- */ + +#ifndef EGL_MESA_drm_image +#define EGL_MESA_drm_image 1 + +#define EGL_DRM_BUFFER_USE_SCANOUT_MESA 0x00000001 +#define EGL_DRM_BUFFER_USE_SHARE_MESA 0x00000002 +#define EGL_DRM_BUFFER_FORMAT_MESA 0x31D0 +#define EGL_DRM_BUFFER_USE_MESA 0x31D1 +#define EGL_DRM_BUFFER_FORMAT_ARGB32_MESA 0x31D2 +#define EGL_DRM_BUFFER_MESA 0x31D3 +#define EGL_DRM_BUFFER_STRIDE_MESA 0x31D4 + +typedef EGLImageKHR ( * PFNEGLCREATEDRMIMAGEMESAPROC) (EGLDisplay dpy, const EGLint * attrib_list); +typedef EGLBoolean ( * PFNEGLEXPORTDRMIMAGEMESAPROC) (EGLDisplay dpy, EGLImageKHR image, EGLint * name, EGLint * handle, EGLint * stride); + +#define eglCreateDRMImageMESA EGLEW_GET_FUN(__eglewCreateDRMImageMESA) +#define eglExportDRMImageMESA EGLEW_GET_FUN(__eglewExportDRMImageMESA) + +#define EGLEW_MESA_drm_image EGLEW_GET_VAR(__EGLEW_MESA_drm_image) + +#endif /* EGL_MESA_drm_image */ + +/* --------------------- EGL_MESA_image_dma_buf_export --------------------- */ + +#ifndef EGL_MESA_image_dma_buf_export +#define EGL_MESA_image_dma_buf_export 1 + +typedef EGLBoolean ( * PFNEGLEXPORTDMABUFIMAGEMESAPROC) (EGLDisplay dpy, EGLImageKHR image, int * fds, EGLint * strides, EGLint * offsets); +typedef EGLBoolean ( * PFNEGLEXPORTDMABUFIMAGEQUERYMESAPROC) (EGLDisplay dpy, EGLImageKHR image, int * fourcc, int * num_planes, EGLuint64KHR * modifiers); + +#define eglExportDMABUFImageMESA EGLEW_GET_FUN(__eglewExportDMABUFImageMESA) +#define eglExportDMABUFImageQueryMESA EGLEW_GET_FUN(__eglewExportDMABUFImageQueryMESA) + +#define EGLEW_MESA_image_dma_buf_export EGLEW_GET_VAR(__EGLEW_MESA_image_dma_buf_export) + +#endif /* EGL_MESA_image_dma_buf_export */ + +/* ------------------------- EGL_MESA_platform_gbm ------------------------- */ + +#ifndef EGL_MESA_platform_gbm +#define EGL_MESA_platform_gbm 1 + +#define EGL_PLATFORM_GBM_MESA 0x31D7 + +#define EGLEW_MESA_platform_gbm EGLEW_GET_VAR(__EGLEW_MESA_platform_gbm) + +#endif /* EGL_MESA_platform_gbm */ + +/* --------------------- EGL_MESA_platform_surfaceless --------------------- */ + +#ifndef EGL_MESA_platform_surfaceless +#define EGL_MESA_platform_surfaceless 1 + +#define EGL_PLATFORM_SURFACELESS_MESA 0x31DD + +#define EGLEW_MESA_platform_surfaceless EGLEW_GET_VAR(__EGLEW_MESA_platform_surfaceless) + +#endif /* EGL_MESA_platform_surfaceless */ + +/* -------------------------- EGL_NOK_swap_region -------------------------- */ + +#ifndef EGL_NOK_swap_region +#define EGL_NOK_swap_region 1 + +typedef EGLBoolean ( * PFNEGLSWAPBUFFERSREGIONNOKPROC) (EGLDisplay dpy, EGLSurface surface, EGLint numRects, const EGLint * rects); + +#define eglSwapBuffersRegionNOK EGLEW_GET_FUN(__eglewSwapBuffersRegionNOK) + +#define EGLEW_NOK_swap_region EGLEW_GET_VAR(__EGLEW_NOK_swap_region) + +#endif /* EGL_NOK_swap_region */ + +/* -------------------------- EGL_NOK_swap_region2 ------------------------- */ + +#ifndef EGL_NOK_swap_region2 +#define EGL_NOK_swap_region2 1 + +typedef EGLBoolean ( * PFNEGLSWAPBUFFERSREGION2NOKPROC) (EGLDisplay dpy, EGLSurface surface, EGLint numRects, const EGLint * rects); + +#define eglSwapBuffersRegion2NOK EGLEW_GET_FUN(__eglewSwapBuffersRegion2NOK) + +#define EGLEW_NOK_swap_region2 EGLEW_GET_VAR(__EGLEW_NOK_swap_region2) + +#endif /* EGL_NOK_swap_region2 */ + +/* ---------------------- EGL_NOK_texture_from_pixmap ---------------------- */ + +#ifndef EGL_NOK_texture_from_pixmap +#define EGL_NOK_texture_from_pixmap 1 + +#define EGL_Y_INVERTED_NOK 0x307F + +#define EGLEW_NOK_texture_from_pixmap EGLEW_GET_VAR(__EGLEW_NOK_texture_from_pixmap) + +#endif /* EGL_NOK_texture_from_pixmap */ + +/* ------------------------ EGL_NV_3dvision_surface ------------------------ */ + +#ifndef EGL_NV_3dvision_surface +#define EGL_NV_3dvision_surface 1 + +#define EGL_AUTO_STEREO_NV 0x3136 + +#define EGLEW_NV_3dvision_surface EGLEW_GET_VAR(__EGLEW_NV_3dvision_surface) + +#endif /* EGL_NV_3dvision_surface */ + +/* ------------------------- EGL_NV_coverage_sample ------------------------ */ + +#ifndef EGL_NV_coverage_sample +#define EGL_NV_coverage_sample 1 + +#define EGL_COVERAGE_BUFFERS_NV 0x30E0 +#define EGL_COVERAGE_SAMPLES_NV 0x30E1 + +#define EGLEW_NV_coverage_sample EGLEW_GET_VAR(__EGLEW_NV_coverage_sample) + +#endif /* EGL_NV_coverage_sample */ + +/* --------------------- EGL_NV_coverage_sample_resolve -------------------- */ + +#ifndef EGL_NV_coverage_sample_resolve +#define EGL_NV_coverage_sample_resolve 1 + +#define EGL_COVERAGE_SAMPLE_RESOLVE_NV 0x3131 +#define EGL_COVERAGE_SAMPLE_RESOLVE_DEFAULT_NV 0x3132 +#define EGL_COVERAGE_SAMPLE_RESOLVE_NONE_NV 0x3133 + +#define EGLEW_NV_coverage_sample_resolve EGLEW_GET_VAR(__EGLEW_NV_coverage_sample_resolve) + +#endif /* EGL_NV_coverage_sample_resolve */ + +/* --------------------------- EGL_NV_cuda_event --------------------------- */ + +#ifndef EGL_NV_cuda_event +#define EGL_NV_cuda_event 1 + +#define EGL_CUDA_EVENT_HANDLE_NV 0x323B +#define EGL_SYNC_CUDA_EVENT_NV 0x323C +#define EGL_SYNC_CUDA_EVENT_COMPLETE_NV 0x323D + +#define EGLEW_NV_cuda_event EGLEW_GET_VAR(__EGLEW_NV_cuda_event) + +#endif /* EGL_NV_cuda_event */ + +/* ------------------------- EGL_NV_depth_nonlinear ------------------------ */ + +#ifndef EGL_NV_depth_nonlinear +#define EGL_NV_depth_nonlinear 1 + +#define EGL_DEPTH_ENCODING_NONE_NV 0 +#define EGL_DEPTH_ENCODING_NV 0x30E2 +#define EGL_DEPTH_ENCODING_NONLINEAR_NV 0x30E3 + +#define EGLEW_NV_depth_nonlinear EGLEW_GET_VAR(__EGLEW_NV_depth_nonlinear) + +#endif /* EGL_NV_depth_nonlinear */ + +/* --------------------------- EGL_NV_device_cuda -------------------------- */ + +#ifndef EGL_NV_device_cuda +#define EGL_NV_device_cuda 1 + +#define EGL_CUDA_DEVICE_NV 0x323A + +#define EGLEW_NV_device_cuda EGLEW_GET_VAR(__EGLEW_NV_device_cuda) + +#endif /* EGL_NV_device_cuda */ + +/* -------------------------- EGL_NV_native_query -------------------------- */ + +#ifndef EGL_NV_native_query +#define EGL_NV_native_query 1 + +typedef EGLBoolean ( * PFNEGLQUERYNATIVEDISPLAYNVPROC) (EGLDisplay dpy, EGLNativeDisplayType * display_id); +typedef EGLBoolean ( * PFNEGLQUERYNATIVEPIXMAPNVPROC) (EGLDisplay dpy, EGLSurface surf, EGLNativePixmapType * pixmap); +typedef EGLBoolean ( * PFNEGLQUERYNATIVEWINDOWNVPROC) (EGLDisplay dpy, EGLSurface surf, EGLNativeWindowType * window); + +#define eglQueryNativeDisplayNV EGLEW_GET_FUN(__eglewQueryNativeDisplayNV) +#define eglQueryNativePixmapNV EGLEW_GET_FUN(__eglewQueryNativePixmapNV) +#define eglQueryNativeWindowNV EGLEW_GET_FUN(__eglewQueryNativeWindowNV) + +#define EGLEW_NV_native_query EGLEW_GET_VAR(__EGLEW_NV_native_query) + +#endif /* EGL_NV_native_query */ + +/* ---------------------- EGL_NV_post_convert_rounding --------------------- */ + +#ifndef EGL_NV_post_convert_rounding +#define EGL_NV_post_convert_rounding 1 + +#define EGLEW_NV_post_convert_rounding EGLEW_GET_VAR(__EGLEW_NV_post_convert_rounding) + +#endif /* EGL_NV_post_convert_rounding */ + +/* ------------------------- EGL_NV_post_sub_buffer ------------------------ */ + +#ifndef EGL_NV_post_sub_buffer +#define EGL_NV_post_sub_buffer 1 + +#define EGL_POST_SUB_BUFFER_SUPPORTED_NV 0x30BE + +typedef EGLBoolean ( * PFNEGLPOSTSUBBUFFERNVPROC) (EGLDisplay dpy, EGLSurface surface, EGLint x, EGLint y, EGLint width, EGLint height); + +#define eglPostSubBufferNV EGLEW_GET_FUN(__eglewPostSubBufferNV) + +#define EGLEW_NV_post_sub_buffer EGLEW_GET_VAR(__EGLEW_NV_post_sub_buffer) + +#endif /* EGL_NV_post_sub_buffer */ + +/* ------------------ EGL_NV_robustness_video_memory_purge ----------------- */ + +#ifndef EGL_NV_robustness_video_memory_purge +#define EGL_NV_robustness_video_memory_purge 1 + +#define EGL_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV 0x334C + +#define EGLEW_NV_robustness_video_memory_purge EGLEW_GET_VAR(__EGLEW_NV_robustness_video_memory_purge) + +#endif /* EGL_NV_robustness_video_memory_purge */ + +/* ------------------ EGL_NV_stream_consumer_gltexture_yuv ----------------- */ + +#ifndef EGL_NV_stream_consumer_gltexture_yuv +#define EGL_NV_stream_consumer_gltexture_yuv 1 + +#define EGL_YUV_BUFFER_EXT 0x3300 +#define EGL_YUV_NUMBER_OF_PLANES_EXT 0x3311 +#define EGL_YUV_PLANE0_TEXTURE_UNIT_NV 0x332C +#define EGL_YUV_PLANE1_TEXTURE_UNIT_NV 0x332D +#define EGL_YUV_PLANE2_TEXTURE_UNIT_NV 0x332E + +typedef EGLBoolean ( * PFNEGLSTREAMCONSUMERGLTEXTUREEXTERNALATTRIBSNVPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLAttrib *attrib_list); + +#define eglStreamConsumerGLTextureExternalAttribsNV EGLEW_GET_FUN(__eglewStreamConsumerGLTextureExternalAttribsNV) + +#define EGLEW_NV_stream_consumer_gltexture_yuv EGLEW_GET_VAR(__EGLEW_NV_stream_consumer_gltexture_yuv) + +#endif /* EGL_NV_stream_consumer_gltexture_yuv */ + +/* ---------------------- EGL_NV_stream_cross_display ---------------------- */ + +#ifndef EGL_NV_stream_cross_display +#define EGL_NV_stream_cross_display 1 + +#define EGL_STREAM_CROSS_DISPLAY_NV 0x334E + +#define EGLEW_NV_stream_cross_display EGLEW_GET_VAR(__EGLEW_NV_stream_cross_display) + +#endif /* EGL_NV_stream_cross_display */ + +/* ----------------------- EGL_NV_stream_cross_object ---------------------- */ + +#ifndef EGL_NV_stream_cross_object +#define EGL_NV_stream_cross_object 1 + +#define EGL_STREAM_CROSS_OBJECT_NV 0x334D + +#define EGLEW_NV_stream_cross_object EGLEW_GET_VAR(__EGLEW_NV_stream_cross_object) + +#endif /* EGL_NV_stream_cross_object */ + +/* --------------------- EGL_NV_stream_cross_partition --------------------- */ + +#ifndef EGL_NV_stream_cross_partition +#define EGL_NV_stream_cross_partition 1 + +#define EGL_STREAM_CROSS_PARTITION_NV 0x323F + +#define EGLEW_NV_stream_cross_partition EGLEW_GET_VAR(__EGLEW_NV_stream_cross_partition) + +#endif /* EGL_NV_stream_cross_partition */ + +/* ---------------------- EGL_NV_stream_cross_process ---------------------- */ + +#ifndef EGL_NV_stream_cross_process +#define EGL_NV_stream_cross_process 1 + +#define EGL_STREAM_CROSS_PROCESS_NV 0x3245 + +#define EGLEW_NV_stream_cross_process EGLEW_GET_VAR(__EGLEW_NV_stream_cross_process) + +#endif /* EGL_NV_stream_cross_process */ + +/* ----------------------- EGL_NV_stream_cross_system ---------------------- */ + +#ifndef EGL_NV_stream_cross_system +#define EGL_NV_stream_cross_system 1 + +#define EGL_STREAM_CROSS_SYSTEM_NV 0x334F + +#define EGLEW_NV_stream_cross_system EGLEW_GET_VAR(__EGLEW_NV_stream_cross_system) + +#endif /* EGL_NV_stream_cross_system */ + +/* ------------------------ EGL_NV_stream_fifo_next ------------------------ */ + +#ifndef EGL_NV_stream_fifo_next +#define EGL_NV_stream_fifo_next 1 + +#define EGL_PENDING_FRAME_NV 0x3329 +#define EGL_STREAM_TIME_PENDING_NV 0x332A + +#define EGLEW_NV_stream_fifo_next EGLEW_GET_VAR(__EGLEW_NV_stream_fifo_next) + +#endif /* EGL_NV_stream_fifo_next */ + +/* --------------------- EGL_NV_stream_fifo_synchronous -------------------- */ + +#ifndef EGL_NV_stream_fifo_synchronous +#define EGL_NV_stream_fifo_synchronous 1 + +#define EGL_STREAM_FIFO_SYNCHRONOUS_NV 0x3336 + +#define EGLEW_NV_stream_fifo_synchronous EGLEW_GET_VAR(__EGLEW_NV_stream_fifo_synchronous) + +#endif /* EGL_NV_stream_fifo_synchronous */ + +/* ----------------------- EGL_NV_stream_frame_limits ---------------------- */ + +#ifndef EGL_NV_stream_frame_limits +#define EGL_NV_stream_frame_limits 1 + +#define EGL_PRODUCER_MAX_FRAME_HINT_NV 0x3337 +#define EGL_CONSUMER_MAX_FRAME_HINT_NV 0x3338 + +#define EGLEW_NV_stream_frame_limits EGLEW_GET_VAR(__EGLEW_NV_stream_frame_limits) + +#endif /* EGL_NV_stream_frame_limits */ + +/* ------------------------- EGL_NV_stream_metadata ------------------------ */ + +#ifndef EGL_NV_stream_metadata +#define EGL_NV_stream_metadata 1 + +#define EGL_MAX_STREAM_METADATA_BLOCKS_NV 0x3250 +#define EGL_MAX_STREAM_METADATA_BLOCK_SIZE_NV 0x3251 +#define EGL_MAX_STREAM_METADATA_TOTAL_SIZE_NV 0x3252 +#define EGL_PRODUCER_METADATA_NV 0x3253 +#define EGL_CONSUMER_METADATA_NV 0x3254 +#define EGL_METADATA0_SIZE_NV 0x3255 +#define EGL_METADATA1_SIZE_NV 0x3256 +#define EGL_METADATA2_SIZE_NV 0x3257 +#define EGL_METADATA3_SIZE_NV 0x3258 +#define EGL_METADATA0_TYPE_NV 0x3259 +#define EGL_METADATA1_TYPE_NV 0x325A +#define EGL_METADATA2_TYPE_NV 0x325B +#define EGL_METADATA3_TYPE_NV 0x325C +#define EGL_PENDING_METADATA_NV 0x3328 + +typedef EGLBoolean ( * PFNEGLQUERYDISPLAYATTRIBNVPROC) (EGLDisplay dpy, EGLint attribute, EGLAttrib * value); +typedef EGLBoolean ( * PFNEGLQUERYSTREAMMETADATANVPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLenum name, EGLint n, EGLint offset, EGLint size, void * data); +typedef EGLBoolean ( * PFNEGLSETSTREAMMETADATANVPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLint n, EGLint offset, EGLint size, const void * data); + +#define eglQueryDisplayAttribNV EGLEW_GET_FUN(__eglewQueryDisplayAttribNV) +#define eglQueryStreamMetadataNV EGLEW_GET_FUN(__eglewQueryStreamMetadataNV) +#define eglSetStreamMetadataNV EGLEW_GET_FUN(__eglewSetStreamMetadataNV) + +#define EGLEW_NV_stream_metadata EGLEW_GET_VAR(__EGLEW_NV_stream_metadata) + +#endif /* EGL_NV_stream_metadata */ + +/* -------------------------- EGL_NV_stream_remote ------------------------- */ + +#ifndef EGL_NV_stream_remote +#define EGL_NV_stream_remote 1 + +#define EGL_STREAM_STATE_INITIALIZING_NV 0x3240 +#define EGL_STREAM_TYPE_NV 0x3241 +#define EGL_STREAM_PROTOCOL_NV 0x3242 +#define EGL_STREAM_ENDPOINT_NV 0x3243 +#define EGL_STREAM_LOCAL_NV 0x3244 +#define EGL_STREAM_PROTOCOL_FD_NV 0x3246 +#define EGL_STREAM_PRODUCER_NV 0x3247 +#define EGL_STREAM_CONSUMER_NV 0x3248 + +#define EGLEW_NV_stream_remote EGLEW_GET_VAR(__EGLEW_NV_stream_remote) + +#endif /* EGL_NV_stream_remote */ + +/* -------------------------- EGL_NV_stream_reset -------------------------- */ + +#ifndef EGL_NV_stream_reset +#define EGL_NV_stream_reset 1 + +#define EGL_SUPPORT_RESET_NV 0x3334 +#define EGL_SUPPORT_REUSE_NV 0x3335 + +typedef EGLBoolean ( * PFNEGLRESETSTREAMNVPROC) (EGLDisplay dpy, EGLStreamKHR stream); + +#define eglResetStreamNV EGLEW_GET_FUN(__eglewResetStreamNV) + +#define EGLEW_NV_stream_reset EGLEW_GET_VAR(__EGLEW_NV_stream_reset) + +#endif /* EGL_NV_stream_reset */ + +/* -------------------------- EGL_NV_stream_socket ------------------------- */ + +#ifndef EGL_NV_stream_socket +#define EGL_NV_stream_socket 1 + +#define EGL_STREAM_PROTOCOL_SOCKET_NV 0x324B +#define EGL_SOCKET_HANDLE_NV 0x324C +#define EGL_SOCKET_TYPE_NV 0x324D + +#define EGLEW_NV_stream_socket EGLEW_GET_VAR(__EGLEW_NV_stream_socket) + +#endif /* EGL_NV_stream_socket */ + +/* ----------------------- EGL_NV_stream_socket_inet ----------------------- */ + +#ifndef EGL_NV_stream_socket_inet +#define EGL_NV_stream_socket_inet 1 + +#define EGL_SOCKET_TYPE_INET_NV 0x324F + +#define EGLEW_NV_stream_socket_inet EGLEW_GET_VAR(__EGLEW_NV_stream_socket_inet) + +#endif /* EGL_NV_stream_socket_inet */ + +/* ----------------------- EGL_NV_stream_socket_unix ----------------------- */ + +#ifndef EGL_NV_stream_socket_unix +#define EGL_NV_stream_socket_unix 1 + +#define EGL_SOCKET_TYPE_UNIX_NV 0x324E + +#define EGLEW_NV_stream_socket_unix EGLEW_GET_VAR(__EGLEW_NV_stream_socket_unix) + +#endif /* EGL_NV_stream_socket_unix */ + +/* --------------------------- EGL_NV_stream_sync -------------------------- */ + +#ifndef EGL_NV_stream_sync +#define EGL_NV_stream_sync 1 + +#define EGL_SYNC_TYPE_KHR 0x30F7 +#define EGL_SYNC_NEW_FRAME_NV 0x321F + +typedef EGLSyncKHR ( * PFNEGLCREATESTREAMSYNCNVPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLenum type, const EGLint * attrib_list); + +#define eglCreateStreamSyncNV EGLEW_GET_FUN(__eglewCreateStreamSyncNV) + +#define EGLEW_NV_stream_sync EGLEW_GET_VAR(__EGLEW_NV_stream_sync) + +#endif /* EGL_NV_stream_sync */ + +/* ------------------------------ EGL_NV_sync ------------------------------ */ + +#ifndef EGL_NV_sync +#define EGL_NV_sync 1 + +#define EGL_SYNC_FLUSH_COMMANDS_BIT_NV 0x0001 +#define EGL_SYNC_PRIOR_COMMANDS_COMPLETE_NV 0x30E6 +#define EGL_SYNC_STATUS_NV 0x30E7 +#define EGL_SIGNALED_NV 0x30E8 +#define EGL_UNSIGNALED_NV 0x30E9 +#define EGL_ALREADY_SIGNALED_NV 0x30EA +#define EGL_TIMEOUT_EXPIRED_NV 0x30EB +#define EGL_CONDITION_SATISFIED_NV 0x30EC +#define EGL_SYNC_TYPE_NV 0x30ED +#define EGL_SYNC_CONDITION_NV 0x30EE +#define EGL_SYNC_FENCE_NV 0x30EF +#define EGL_FOREVER_NV 0xFFFFFFFFFFFFFFFF + +typedef EGLint ( * PFNEGLCLIENTWAITSYNCNVPROC) (EGLSyncNV sync, EGLint flags, EGLTimeNV timeout); +typedef EGLSyncNV ( * PFNEGLCREATEFENCESYNCNVPROC) (EGLDisplay dpy, EGLenum condition, const EGLint * attrib_list); +typedef EGLBoolean ( * PFNEGLDESTROYSYNCNVPROC) (EGLSyncNV sync); +typedef EGLBoolean ( * PFNEGLFENCENVPROC) (EGLSyncNV sync); +typedef EGLBoolean ( * PFNEGLGETSYNCATTRIBNVPROC) (EGLSyncNV sync, EGLint attribute, EGLint * value); +typedef EGLBoolean ( * PFNEGLSIGNALSYNCNVPROC) (EGLSyncNV sync, EGLenum mode); + +#define eglClientWaitSyncNV EGLEW_GET_FUN(__eglewClientWaitSyncNV) +#define eglCreateFenceSyncNV EGLEW_GET_FUN(__eglewCreateFenceSyncNV) +#define eglDestroySyncNV EGLEW_GET_FUN(__eglewDestroySyncNV) +#define eglFenceNV EGLEW_GET_FUN(__eglewFenceNV) +#define eglGetSyncAttribNV EGLEW_GET_FUN(__eglewGetSyncAttribNV) +#define eglSignalSyncNV EGLEW_GET_FUN(__eglewSignalSyncNV) + +#define EGLEW_NV_sync EGLEW_GET_VAR(__EGLEW_NV_sync) + +#endif /* EGL_NV_sync */ + +/* --------------------------- EGL_NV_system_time -------------------------- */ + +#ifndef EGL_NV_system_time +#define EGL_NV_system_time 1 + +typedef EGLuint64NV ( * PFNEGLGETSYSTEMTIMEFREQUENCYNVPROC) ( void ); +typedef EGLuint64NV ( * PFNEGLGETSYSTEMTIMENVPROC) ( void ); + +#define eglGetSystemTimeFrequencyNV EGLEW_GET_FUN(__eglewGetSystemTimeFrequencyNV) +#define eglGetSystemTimeNV EGLEW_GET_FUN(__eglewGetSystemTimeNV) + +#define EGLEW_NV_system_time EGLEW_GET_VAR(__EGLEW_NV_system_time) + +#endif /* EGL_NV_system_time */ + +/* --------------------- EGL_TIZEN_image_native_buffer --------------------- */ + +#ifndef EGL_TIZEN_image_native_buffer +#define EGL_TIZEN_image_native_buffer 1 + +#define EGL_NATIVE_BUFFER_TIZEN 0x32A0 + +#define EGLEW_TIZEN_image_native_buffer EGLEW_GET_VAR(__EGLEW_TIZEN_image_native_buffer) + +#endif /* EGL_TIZEN_image_native_buffer */ + +/* --------------------- EGL_TIZEN_image_native_surface -------------------- */ + +#ifndef EGL_TIZEN_image_native_surface +#define EGL_TIZEN_image_native_surface 1 + +#define EGL_NATIVE_SURFACE_TIZEN 0x32A1 + +#define EGLEW_TIZEN_image_native_surface EGLEW_GET_VAR(__EGLEW_TIZEN_image_native_surface) + +#endif /* EGL_TIZEN_image_native_surface */ + +/* ------------------------------------------------------------------------- */ + +#define EGLEW_FUN_EXPORT GLEW_FUN_EXPORT +#define EGLEW_VAR_EXPORT GLEW_VAR_EXPORT + +EGLEW_FUN_EXPORT PFNEGLCHOOSECONFIGPROC __eglewChooseConfig; +EGLEW_FUN_EXPORT PFNEGLCOPYBUFFERSPROC __eglewCopyBuffers; +EGLEW_FUN_EXPORT PFNEGLCREATECONTEXTPROC __eglewCreateContext; +EGLEW_FUN_EXPORT PFNEGLCREATEPBUFFERSURFACEPROC __eglewCreatePbufferSurface; +EGLEW_FUN_EXPORT PFNEGLCREATEPIXMAPSURFACEPROC __eglewCreatePixmapSurface; +EGLEW_FUN_EXPORT PFNEGLCREATEWINDOWSURFACEPROC __eglewCreateWindowSurface; +EGLEW_FUN_EXPORT PFNEGLDESTROYCONTEXTPROC __eglewDestroyContext; +EGLEW_FUN_EXPORT PFNEGLDESTROYSURFACEPROC __eglewDestroySurface; +EGLEW_FUN_EXPORT PFNEGLGETCONFIGATTRIBPROC __eglewGetConfigAttrib; +EGLEW_FUN_EXPORT PFNEGLGETCONFIGSPROC __eglewGetConfigs; +EGLEW_FUN_EXPORT PFNEGLGETCURRENTDISPLAYPROC __eglewGetCurrentDisplay; +EGLEW_FUN_EXPORT PFNEGLGETCURRENTSURFACEPROC __eglewGetCurrentSurface; +EGLEW_FUN_EXPORT PFNEGLGETDISPLAYPROC __eglewGetDisplay; +EGLEW_FUN_EXPORT PFNEGLGETERRORPROC __eglewGetError; +EGLEW_FUN_EXPORT PFNEGLINITIALIZEPROC __eglewInitialize; +EGLEW_FUN_EXPORT PFNEGLMAKECURRENTPROC __eglewMakeCurrent; +EGLEW_FUN_EXPORT PFNEGLQUERYCONTEXTPROC __eglewQueryContext; +EGLEW_FUN_EXPORT PFNEGLQUERYSTRINGPROC __eglewQueryString; +EGLEW_FUN_EXPORT PFNEGLQUERYSURFACEPROC __eglewQuerySurface; +EGLEW_FUN_EXPORT PFNEGLSWAPBUFFERSPROC __eglewSwapBuffers; +EGLEW_FUN_EXPORT PFNEGLTERMINATEPROC __eglewTerminate; +EGLEW_FUN_EXPORT PFNEGLWAITGLPROC __eglewWaitGL; +EGLEW_FUN_EXPORT PFNEGLWAITNATIVEPROC __eglewWaitNative; + +EGLEW_FUN_EXPORT PFNEGLBINDTEXIMAGEPROC __eglewBindTexImage; +EGLEW_FUN_EXPORT PFNEGLRELEASETEXIMAGEPROC __eglewReleaseTexImage; +EGLEW_FUN_EXPORT PFNEGLSURFACEATTRIBPROC __eglewSurfaceAttrib; +EGLEW_FUN_EXPORT PFNEGLSWAPINTERVALPROC __eglewSwapInterval; + +EGLEW_FUN_EXPORT PFNEGLBINDAPIPROC __eglewBindAPI; +EGLEW_FUN_EXPORT PFNEGLCREATEPBUFFERFROMCLIENTBUFFERPROC __eglewCreatePbufferFromClientBuffer; +EGLEW_FUN_EXPORT PFNEGLQUERYAPIPROC __eglewQueryAPI; +EGLEW_FUN_EXPORT PFNEGLRELEASETHREADPROC __eglewReleaseThread; +EGLEW_FUN_EXPORT PFNEGLWAITCLIENTPROC __eglewWaitClient; + +EGLEW_FUN_EXPORT PFNEGLGETCURRENTCONTEXTPROC __eglewGetCurrentContext; + +EGLEW_FUN_EXPORT PFNEGLCLIENTWAITSYNCPROC __eglewClientWaitSync; +EGLEW_FUN_EXPORT PFNEGLCREATEIMAGEPROC __eglewCreateImage; +EGLEW_FUN_EXPORT PFNEGLCREATEPLATFORMPIXMAPSURFACEPROC __eglewCreatePlatformPixmapSurface; +EGLEW_FUN_EXPORT PFNEGLCREATEPLATFORMWINDOWSURFACEPROC __eglewCreatePlatformWindowSurface; +EGLEW_FUN_EXPORT PFNEGLCREATESYNCPROC __eglewCreateSync; +EGLEW_FUN_EXPORT PFNEGLDESTROYIMAGEPROC __eglewDestroyImage; +EGLEW_FUN_EXPORT PFNEGLDESTROYSYNCPROC __eglewDestroySync; +EGLEW_FUN_EXPORT PFNEGLGETPLATFORMDISPLAYPROC __eglewGetPlatformDisplay; +EGLEW_FUN_EXPORT PFNEGLGETSYNCATTRIBPROC __eglewGetSyncAttrib; +EGLEW_FUN_EXPORT PFNEGLWAITSYNCPROC __eglewWaitSync; + +EGLEW_FUN_EXPORT PFNEGLSETBLOBCACHEFUNCSANDROIDPROC __eglewSetBlobCacheFuncsANDROID; + +EGLEW_FUN_EXPORT PFNEGLCREATENATIVECLIENTBUFFERANDROIDPROC __eglewCreateNativeClientBufferANDROID; + +EGLEW_FUN_EXPORT PFNEGLDUPNATIVEFENCEFDANDROIDPROC __eglewDupNativeFenceFDANDROID; + +EGLEW_FUN_EXPORT PFNEGLPRESENTATIONTIMEANDROIDPROC __eglewPresentationTimeANDROID; + +EGLEW_FUN_EXPORT PFNEGLQUERYSURFACEPOINTERANGLEPROC __eglewQuerySurfacePointerANGLE; + +EGLEW_FUN_EXPORT PFNEGLQUERYDEVICESEXTPROC __eglewQueryDevicesEXT; + +EGLEW_FUN_EXPORT PFNEGLQUERYDEVICEATTRIBEXTPROC __eglewQueryDeviceAttribEXT; +EGLEW_FUN_EXPORT PFNEGLQUERYDEVICESTRINGEXTPROC __eglewQueryDeviceStringEXT; +EGLEW_FUN_EXPORT PFNEGLQUERYDISPLAYATTRIBEXTPROC __eglewQueryDisplayAttribEXT; + +EGLEW_FUN_EXPORT PFNEGLQUERYDMABUFFORMATSEXTPROC __eglewQueryDmaBufFormatsEXT; +EGLEW_FUN_EXPORT PFNEGLQUERYDMABUFMODIFIERSEXTPROC __eglewQueryDmaBufModifiersEXT; + +EGLEW_FUN_EXPORT PFNEGLGETOUTPUTLAYERSEXTPROC __eglewGetOutputLayersEXT; +EGLEW_FUN_EXPORT PFNEGLGETOUTPUTPORTSEXTPROC __eglewGetOutputPortsEXT; +EGLEW_FUN_EXPORT PFNEGLOUTPUTLAYERATTRIBEXTPROC __eglewOutputLayerAttribEXT; +EGLEW_FUN_EXPORT PFNEGLOUTPUTPORTATTRIBEXTPROC __eglewOutputPortAttribEXT; +EGLEW_FUN_EXPORT PFNEGLQUERYOUTPUTLAYERATTRIBEXTPROC __eglewQueryOutputLayerAttribEXT; +EGLEW_FUN_EXPORT PFNEGLQUERYOUTPUTLAYERSTRINGEXTPROC __eglewQueryOutputLayerStringEXT; +EGLEW_FUN_EXPORT PFNEGLQUERYOUTPUTPORTATTRIBEXTPROC __eglewQueryOutputPortAttribEXT; +EGLEW_FUN_EXPORT PFNEGLQUERYOUTPUTPORTSTRINGEXTPROC __eglewQueryOutputPortStringEXT; + +EGLEW_FUN_EXPORT PFNEGLCREATEPLATFORMPIXMAPSURFACEEXTPROC __eglewCreatePlatformPixmapSurfaceEXT; +EGLEW_FUN_EXPORT PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC __eglewCreatePlatformWindowSurfaceEXT; +EGLEW_FUN_EXPORT PFNEGLGETPLATFORMDISPLAYEXTPROC __eglewGetPlatformDisplayEXT; + +EGLEW_FUN_EXPORT PFNEGLSTREAMCONSUMEROUTPUTEXTPROC __eglewStreamConsumerOutputEXT; + +EGLEW_FUN_EXPORT PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC __eglewSwapBuffersWithDamageEXT; + +EGLEW_FUN_EXPORT PFNEGLCREATEPIXMAPSURFACEHIPROC __eglewCreatePixmapSurfaceHI; + +EGLEW_FUN_EXPORT PFNEGLCREATESYNC64KHRPROC __eglewCreateSync64KHR; + +EGLEW_FUN_EXPORT PFNEGLDEBUGMESSAGECONTROLKHRPROC __eglewDebugMessageControlKHR; +EGLEW_FUN_EXPORT PFNEGLLABELOBJECTKHRPROC __eglewLabelObjectKHR; +EGLEW_FUN_EXPORT PFNEGLQUERYDEBUGKHRPROC __eglewQueryDebugKHR; + +EGLEW_FUN_EXPORT PFNEGLCREATEIMAGEKHRPROC __eglewCreateImageKHR; +EGLEW_FUN_EXPORT PFNEGLDESTROYIMAGEKHRPROC __eglewDestroyImageKHR; + +EGLEW_FUN_EXPORT PFNEGLLOCKSURFACEKHRPROC __eglewLockSurfaceKHR; +EGLEW_FUN_EXPORT PFNEGLUNLOCKSURFACEKHRPROC __eglewUnlockSurfaceKHR; + +EGLEW_FUN_EXPORT PFNEGLQUERYSURFACE64KHRPROC __eglewQuerySurface64KHR; + +EGLEW_FUN_EXPORT PFNEGLSETDAMAGEREGIONKHRPROC __eglewSetDamageRegionKHR; + +EGLEW_FUN_EXPORT PFNEGLCLIENTWAITSYNCKHRPROC __eglewClientWaitSyncKHR; +EGLEW_FUN_EXPORT PFNEGLCREATESYNCKHRPROC __eglewCreateSyncKHR; +EGLEW_FUN_EXPORT PFNEGLDESTROYSYNCKHRPROC __eglewDestroySyncKHR; +EGLEW_FUN_EXPORT PFNEGLGETSYNCATTRIBKHRPROC __eglewGetSyncAttribKHR; +EGLEW_FUN_EXPORT PFNEGLSIGNALSYNCKHRPROC __eglewSignalSyncKHR; + +EGLEW_FUN_EXPORT PFNEGLCREATESTREAMKHRPROC __eglewCreateStreamKHR; +EGLEW_FUN_EXPORT PFNEGLDESTROYSTREAMKHRPROC __eglewDestroyStreamKHR; +EGLEW_FUN_EXPORT PFNEGLQUERYSTREAMKHRPROC __eglewQueryStreamKHR; +EGLEW_FUN_EXPORT PFNEGLQUERYSTREAMU64KHRPROC __eglewQueryStreamu64KHR; +EGLEW_FUN_EXPORT PFNEGLSTREAMATTRIBKHRPROC __eglewStreamAttribKHR; + +EGLEW_FUN_EXPORT PFNEGLCREATESTREAMATTRIBKHRPROC __eglewCreateStreamAttribKHR; +EGLEW_FUN_EXPORT PFNEGLQUERYSTREAMATTRIBKHRPROC __eglewQueryStreamAttribKHR; +EGLEW_FUN_EXPORT PFNEGLSETSTREAMATTRIBKHRPROC __eglewSetStreamAttribKHR; +EGLEW_FUN_EXPORT PFNEGLSTREAMCONSUMERACQUIREATTRIBKHRPROC __eglewStreamConsumerAcquireAttribKHR; +EGLEW_FUN_EXPORT PFNEGLSTREAMCONSUMERRELEASEATTRIBKHRPROC __eglewStreamConsumerReleaseAttribKHR; + +EGLEW_FUN_EXPORT PFNEGLSTREAMCONSUMERACQUIREKHRPROC __eglewStreamConsumerAcquireKHR; +EGLEW_FUN_EXPORT PFNEGLSTREAMCONSUMERGLTEXTUREEXTERNALKHRPROC __eglewStreamConsumerGLTextureExternalKHR; +EGLEW_FUN_EXPORT PFNEGLSTREAMCONSUMERRELEASEKHRPROC __eglewStreamConsumerReleaseKHR; + +EGLEW_FUN_EXPORT PFNEGLCREATESTREAMFROMFILEDESCRIPTORKHRPROC __eglewCreateStreamFromFileDescriptorKHR; +EGLEW_FUN_EXPORT PFNEGLGETSTREAMFILEDESCRIPTORKHRPROC __eglewGetStreamFileDescriptorKHR; + +EGLEW_FUN_EXPORT PFNEGLQUERYSTREAMTIMEKHRPROC __eglewQueryStreamTimeKHR; + +EGLEW_FUN_EXPORT PFNEGLCREATESTREAMPRODUCERSURFACEKHRPROC __eglewCreateStreamProducerSurfaceKHR; + +EGLEW_FUN_EXPORT PFNEGLSWAPBUFFERSWITHDAMAGEKHRPROC __eglewSwapBuffersWithDamageKHR; + +EGLEW_FUN_EXPORT PFNEGLWAITSYNCKHRPROC __eglewWaitSyncKHR; + +EGLEW_FUN_EXPORT PFNEGLCREATEDRMIMAGEMESAPROC __eglewCreateDRMImageMESA; +EGLEW_FUN_EXPORT PFNEGLEXPORTDRMIMAGEMESAPROC __eglewExportDRMImageMESA; + +EGLEW_FUN_EXPORT PFNEGLEXPORTDMABUFIMAGEMESAPROC __eglewExportDMABUFImageMESA; +EGLEW_FUN_EXPORT PFNEGLEXPORTDMABUFIMAGEQUERYMESAPROC __eglewExportDMABUFImageQueryMESA; + +EGLEW_FUN_EXPORT PFNEGLSWAPBUFFERSREGIONNOKPROC __eglewSwapBuffersRegionNOK; + +EGLEW_FUN_EXPORT PFNEGLSWAPBUFFERSREGION2NOKPROC __eglewSwapBuffersRegion2NOK; + +EGLEW_FUN_EXPORT PFNEGLQUERYNATIVEDISPLAYNVPROC __eglewQueryNativeDisplayNV; +EGLEW_FUN_EXPORT PFNEGLQUERYNATIVEPIXMAPNVPROC __eglewQueryNativePixmapNV; +EGLEW_FUN_EXPORT PFNEGLQUERYNATIVEWINDOWNVPROC __eglewQueryNativeWindowNV; + +EGLEW_FUN_EXPORT PFNEGLPOSTSUBBUFFERNVPROC __eglewPostSubBufferNV; + +EGLEW_FUN_EXPORT PFNEGLSTREAMCONSUMERGLTEXTUREEXTERNALATTRIBSNVPROC __eglewStreamConsumerGLTextureExternalAttribsNV; + +EGLEW_FUN_EXPORT PFNEGLQUERYDISPLAYATTRIBNVPROC __eglewQueryDisplayAttribNV; +EGLEW_FUN_EXPORT PFNEGLQUERYSTREAMMETADATANVPROC __eglewQueryStreamMetadataNV; +EGLEW_FUN_EXPORT PFNEGLSETSTREAMMETADATANVPROC __eglewSetStreamMetadataNV; + +EGLEW_FUN_EXPORT PFNEGLRESETSTREAMNVPROC __eglewResetStreamNV; + +EGLEW_FUN_EXPORT PFNEGLCREATESTREAMSYNCNVPROC __eglewCreateStreamSyncNV; + +EGLEW_FUN_EXPORT PFNEGLCLIENTWAITSYNCNVPROC __eglewClientWaitSyncNV; +EGLEW_FUN_EXPORT PFNEGLCREATEFENCESYNCNVPROC __eglewCreateFenceSyncNV; +EGLEW_FUN_EXPORT PFNEGLDESTROYSYNCNVPROC __eglewDestroySyncNV; +EGLEW_FUN_EXPORT PFNEGLFENCENVPROC __eglewFenceNV; +EGLEW_FUN_EXPORT PFNEGLGETSYNCATTRIBNVPROC __eglewGetSyncAttribNV; +EGLEW_FUN_EXPORT PFNEGLSIGNALSYNCNVPROC __eglewSignalSyncNV; + +EGLEW_FUN_EXPORT PFNEGLGETSYSTEMTIMEFREQUENCYNVPROC __eglewGetSystemTimeFrequencyNV; +EGLEW_FUN_EXPORT PFNEGLGETSYSTEMTIMENVPROC __eglewGetSystemTimeNV; +EGLEW_VAR_EXPORT GLboolean __EGLEW_VERSION_1_0; +EGLEW_VAR_EXPORT GLboolean __EGLEW_VERSION_1_1; +EGLEW_VAR_EXPORT GLboolean __EGLEW_VERSION_1_2; +EGLEW_VAR_EXPORT GLboolean __EGLEW_VERSION_1_3; +EGLEW_VAR_EXPORT GLboolean __EGLEW_VERSION_1_4; +EGLEW_VAR_EXPORT GLboolean __EGLEW_VERSION_1_5; +EGLEW_VAR_EXPORT GLboolean __EGLEW_ANDROID_blob_cache; +EGLEW_VAR_EXPORT GLboolean __EGLEW_ANDROID_create_native_client_buffer; +EGLEW_VAR_EXPORT GLboolean __EGLEW_ANDROID_framebuffer_target; +EGLEW_VAR_EXPORT GLboolean __EGLEW_ANDROID_front_buffer_auto_refresh; +EGLEW_VAR_EXPORT GLboolean __EGLEW_ANDROID_image_native_buffer; +EGLEW_VAR_EXPORT GLboolean __EGLEW_ANDROID_native_fence_sync; +EGLEW_VAR_EXPORT GLboolean __EGLEW_ANDROID_presentation_time; +EGLEW_VAR_EXPORT GLboolean __EGLEW_ANDROID_recordable; +EGLEW_VAR_EXPORT GLboolean __EGLEW_ANGLE_d3d_share_handle_client_buffer; +EGLEW_VAR_EXPORT GLboolean __EGLEW_ANGLE_device_d3d; +EGLEW_VAR_EXPORT GLboolean __EGLEW_ANGLE_query_surface_pointer; +EGLEW_VAR_EXPORT GLboolean __EGLEW_ANGLE_surface_d3d_texture_2d_share_handle; +EGLEW_VAR_EXPORT GLboolean __EGLEW_ANGLE_window_fixed_size; +EGLEW_VAR_EXPORT GLboolean __EGLEW_ARM_implicit_external_sync; +EGLEW_VAR_EXPORT GLboolean __EGLEW_ARM_pixmap_multisample_discard; +EGLEW_VAR_EXPORT GLboolean __EGLEW_EXT_buffer_age; +EGLEW_VAR_EXPORT GLboolean __EGLEW_EXT_client_extensions; +EGLEW_VAR_EXPORT GLboolean __EGLEW_EXT_create_context_robustness; +EGLEW_VAR_EXPORT GLboolean __EGLEW_EXT_device_base; +EGLEW_VAR_EXPORT GLboolean __EGLEW_EXT_device_drm; +EGLEW_VAR_EXPORT GLboolean __EGLEW_EXT_device_enumeration; +EGLEW_VAR_EXPORT GLboolean __EGLEW_EXT_device_openwf; +EGLEW_VAR_EXPORT GLboolean __EGLEW_EXT_device_query; +EGLEW_VAR_EXPORT GLboolean __EGLEW_EXT_gl_colorspace_bt2020_linear; +EGLEW_VAR_EXPORT GLboolean __EGLEW_EXT_gl_colorspace_bt2020_pq; +EGLEW_VAR_EXPORT GLboolean __EGLEW_EXT_gl_colorspace_scrgb_linear; +EGLEW_VAR_EXPORT GLboolean __EGLEW_EXT_image_dma_buf_import; +EGLEW_VAR_EXPORT GLboolean __EGLEW_EXT_image_dma_buf_import_modifiers; +EGLEW_VAR_EXPORT GLboolean __EGLEW_EXT_multiview_window; +EGLEW_VAR_EXPORT GLboolean __EGLEW_EXT_output_base; +EGLEW_VAR_EXPORT GLboolean __EGLEW_EXT_output_drm; +EGLEW_VAR_EXPORT GLboolean __EGLEW_EXT_output_openwf; +EGLEW_VAR_EXPORT GLboolean __EGLEW_EXT_pixel_format_float; +EGLEW_VAR_EXPORT GLboolean __EGLEW_EXT_platform_base; +EGLEW_VAR_EXPORT GLboolean __EGLEW_EXT_platform_device; +EGLEW_VAR_EXPORT GLboolean __EGLEW_EXT_platform_wayland; +EGLEW_VAR_EXPORT GLboolean __EGLEW_EXT_platform_x11; +EGLEW_VAR_EXPORT GLboolean __EGLEW_EXT_protected_content; +EGLEW_VAR_EXPORT GLboolean __EGLEW_EXT_protected_surface; +EGLEW_VAR_EXPORT GLboolean __EGLEW_EXT_stream_consumer_egloutput; +EGLEW_VAR_EXPORT GLboolean __EGLEW_EXT_surface_SMPTE2086_metadata; +EGLEW_VAR_EXPORT GLboolean __EGLEW_EXT_swap_buffers_with_damage; +EGLEW_VAR_EXPORT GLboolean __EGLEW_EXT_yuv_surface; +EGLEW_VAR_EXPORT GLboolean __EGLEW_HI_clientpixmap; +EGLEW_VAR_EXPORT GLboolean __EGLEW_HI_colorformats; +EGLEW_VAR_EXPORT GLboolean __EGLEW_IMG_context_priority; +EGLEW_VAR_EXPORT GLboolean __EGLEW_IMG_image_plane_attribs; +EGLEW_VAR_EXPORT GLboolean __EGLEW_KHR_cl_event; +EGLEW_VAR_EXPORT GLboolean __EGLEW_KHR_cl_event2; +EGLEW_VAR_EXPORT GLboolean __EGLEW_KHR_client_get_all_proc_addresses; +EGLEW_VAR_EXPORT GLboolean __EGLEW_KHR_config_attribs; +EGLEW_VAR_EXPORT GLboolean __EGLEW_KHR_context_flush_control; +EGLEW_VAR_EXPORT GLboolean __EGLEW_KHR_create_context; +EGLEW_VAR_EXPORT GLboolean __EGLEW_KHR_create_context_no_error; +EGLEW_VAR_EXPORT GLboolean __EGLEW_KHR_debug; +EGLEW_VAR_EXPORT GLboolean __EGLEW_KHR_fence_sync; +EGLEW_VAR_EXPORT GLboolean __EGLEW_KHR_get_all_proc_addresses; +EGLEW_VAR_EXPORT GLboolean __EGLEW_KHR_gl_colorspace; +EGLEW_VAR_EXPORT GLboolean __EGLEW_KHR_gl_renderbuffer_image; +EGLEW_VAR_EXPORT GLboolean __EGLEW_KHR_gl_texture_2D_image; +EGLEW_VAR_EXPORT GLboolean __EGLEW_KHR_gl_texture_3D_image; +EGLEW_VAR_EXPORT GLboolean __EGLEW_KHR_gl_texture_cubemap_image; +EGLEW_VAR_EXPORT GLboolean __EGLEW_KHR_image; +EGLEW_VAR_EXPORT GLboolean __EGLEW_KHR_image_base; +EGLEW_VAR_EXPORT GLboolean __EGLEW_KHR_image_pixmap; +EGLEW_VAR_EXPORT GLboolean __EGLEW_KHR_lock_surface; +EGLEW_VAR_EXPORT GLboolean __EGLEW_KHR_lock_surface2; +EGLEW_VAR_EXPORT GLboolean __EGLEW_KHR_lock_surface3; +EGLEW_VAR_EXPORT GLboolean __EGLEW_KHR_mutable_render_buffer; +EGLEW_VAR_EXPORT GLboolean __EGLEW_KHR_no_config_context; +EGLEW_VAR_EXPORT GLboolean __EGLEW_KHR_partial_update; +EGLEW_VAR_EXPORT GLboolean __EGLEW_KHR_platform_android; +EGLEW_VAR_EXPORT GLboolean __EGLEW_KHR_platform_gbm; +EGLEW_VAR_EXPORT GLboolean __EGLEW_KHR_platform_wayland; +EGLEW_VAR_EXPORT GLboolean __EGLEW_KHR_platform_x11; +EGLEW_VAR_EXPORT GLboolean __EGLEW_KHR_reusable_sync; +EGLEW_VAR_EXPORT GLboolean __EGLEW_KHR_stream; +EGLEW_VAR_EXPORT GLboolean __EGLEW_KHR_stream_attrib; +EGLEW_VAR_EXPORT GLboolean __EGLEW_KHR_stream_consumer_gltexture; +EGLEW_VAR_EXPORT GLboolean __EGLEW_KHR_stream_cross_process_fd; +EGLEW_VAR_EXPORT GLboolean __EGLEW_KHR_stream_fifo; +EGLEW_VAR_EXPORT GLboolean __EGLEW_KHR_stream_producer_aldatalocator; +EGLEW_VAR_EXPORT GLboolean __EGLEW_KHR_stream_producer_eglsurface; +EGLEW_VAR_EXPORT GLboolean __EGLEW_KHR_surfaceless_context; +EGLEW_VAR_EXPORT GLboolean __EGLEW_KHR_swap_buffers_with_damage; +EGLEW_VAR_EXPORT GLboolean __EGLEW_KHR_vg_parent_image; +EGLEW_VAR_EXPORT GLboolean __EGLEW_KHR_wait_sync; +EGLEW_VAR_EXPORT GLboolean __EGLEW_MESA_drm_image; +EGLEW_VAR_EXPORT GLboolean __EGLEW_MESA_image_dma_buf_export; +EGLEW_VAR_EXPORT GLboolean __EGLEW_MESA_platform_gbm; +EGLEW_VAR_EXPORT GLboolean __EGLEW_MESA_platform_surfaceless; +EGLEW_VAR_EXPORT GLboolean __EGLEW_NOK_swap_region; +EGLEW_VAR_EXPORT GLboolean __EGLEW_NOK_swap_region2; +EGLEW_VAR_EXPORT GLboolean __EGLEW_NOK_texture_from_pixmap; +EGLEW_VAR_EXPORT GLboolean __EGLEW_NV_3dvision_surface; +EGLEW_VAR_EXPORT GLboolean __EGLEW_NV_coverage_sample; +EGLEW_VAR_EXPORT GLboolean __EGLEW_NV_coverage_sample_resolve; +EGLEW_VAR_EXPORT GLboolean __EGLEW_NV_cuda_event; +EGLEW_VAR_EXPORT GLboolean __EGLEW_NV_depth_nonlinear; +EGLEW_VAR_EXPORT GLboolean __EGLEW_NV_device_cuda; +EGLEW_VAR_EXPORT GLboolean __EGLEW_NV_native_query; +EGLEW_VAR_EXPORT GLboolean __EGLEW_NV_post_convert_rounding; +EGLEW_VAR_EXPORT GLboolean __EGLEW_NV_post_sub_buffer; +EGLEW_VAR_EXPORT GLboolean __EGLEW_NV_robustness_video_memory_purge; +EGLEW_VAR_EXPORT GLboolean __EGLEW_NV_stream_consumer_gltexture_yuv; +EGLEW_VAR_EXPORT GLboolean __EGLEW_NV_stream_cross_display; +EGLEW_VAR_EXPORT GLboolean __EGLEW_NV_stream_cross_object; +EGLEW_VAR_EXPORT GLboolean __EGLEW_NV_stream_cross_partition; +EGLEW_VAR_EXPORT GLboolean __EGLEW_NV_stream_cross_process; +EGLEW_VAR_EXPORT GLboolean __EGLEW_NV_stream_cross_system; +EGLEW_VAR_EXPORT GLboolean __EGLEW_NV_stream_fifo_next; +EGLEW_VAR_EXPORT GLboolean __EGLEW_NV_stream_fifo_synchronous; +EGLEW_VAR_EXPORT GLboolean __EGLEW_NV_stream_frame_limits; +EGLEW_VAR_EXPORT GLboolean __EGLEW_NV_stream_metadata; +EGLEW_VAR_EXPORT GLboolean __EGLEW_NV_stream_remote; +EGLEW_VAR_EXPORT GLboolean __EGLEW_NV_stream_reset; +EGLEW_VAR_EXPORT GLboolean __EGLEW_NV_stream_socket; +EGLEW_VAR_EXPORT GLboolean __EGLEW_NV_stream_socket_inet; +EGLEW_VAR_EXPORT GLboolean __EGLEW_NV_stream_socket_unix; +EGLEW_VAR_EXPORT GLboolean __EGLEW_NV_stream_sync; +EGLEW_VAR_EXPORT GLboolean __EGLEW_NV_sync; +EGLEW_VAR_EXPORT GLboolean __EGLEW_NV_system_time; +EGLEW_VAR_EXPORT GLboolean __EGLEW_TIZEN_image_native_buffer; +EGLEW_VAR_EXPORT GLboolean __EGLEW_TIZEN_image_native_surface; +/* ------------------------------------------------------------------------ */ + +GLEWAPI GLenum GLEWAPIENTRY eglewInit (EGLDisplay display); +GLEWAPI GLboolean GLEWAPIENTRY eglewIsSupported (const char *name); + +#define EGLEW_GET_VAR(x) (*(const GLboolean*)&x) +#define EGLEW_GET_FUN(x) x + +GLEWAPI GLboolean GLEWAPIENTRY eglewGetExtension (const char *name); + +#ifdef __cplusplus +} +#endif + +#endif /* __eglew_h__ */ diff --git a/subprojects/nk_pugl/glew-2.1.0/GL/glew.h b/subprojects/nk_pugl/glew-2.1.0/GL/glew.h new file mode 100644 index 0000000..b5b6987 --- /dev/null +++ b/subprojects/nk_pugl/glew-2.1.0/GL/glew.h @@ -0,0 +1,23686 @@ +/* +** The OpenGL Extension Wrangler Library +** Copyright (C) 2008-2017, Nigel Stewart <nigels[]users sourceforge net> +** Copyright (C) 2002-2008, Milan Ikits <milan ikits[]ieee org> +** Copyright (C) 2002-2008, Marcelo E. Magallon <mmagallo[]debian org> +** Copyright (C) 2002, Lev Povalahev +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are met: +** +** * Redistributions of source code must retain the above copyright notice, +** this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright notice, +** this list of conditions and the following disclaimer in the documentation +** and/or other materials provided with the distribution. +** * The name of the author may be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +** CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +** ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +** THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* + * Mesa 3-D graphics library + * Version: 7.0 + * + * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* +** Copyright (c) 2007 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be included +** in all copies or substantial portions of the Materials. +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ + +#ifndef __glew_h__ +#define __glew_h__ +#define __GLEW_H__ + +#if defined(__gl_h_) || defined(__GL_H__) || defined(_GL_H) || defined(__X_GL_H) +#error gl.h included before glew.h +#endif +#if defined(__gl2_h_) +#error gl2.h included before glew.h +#endif +#if defined(__gltypes_h_) +#error gltypes.h included before glew.h +#endif +#if defined(__REGAL_H__) +#error Regal.h included before glew.h +#endif +#if defined(__glext_h_) || defined(__GLEXT_H_) +#error glext.h included before glew.h +#endif +#if defined(__gl_ATI_h_) +#error glATI.h included before glew.h +#endif + +#define __gl_h_ +#define __gl2_h_ +#define __GL_H__ +#define _GL_H +#define __gltypes_h_ +#define __REGAL_H__ +#define __X_GL_H +#define __glext_h_ +#define __GLEXT_H_ +#define __gl_ATI_h_ + +#if defined(_WIN32) + +/* + * GLEW does not include <windows.h> to avoid name space pollution. + * GL needs GLAPI and GLAPIENTRY, GLU needs APIENTRY, CALLBACK, and wchar_t + * defined properly. + */ +/* <windef.h> and <gl.h>*/ +#ifdef APIENTRY +# ifndef GLAPIENTRY +# define GLAPIENTRY APIENTRY +# endif +# ifndef GLEWAPIENTRY +# define GLEWAPIENTRY APIENTRY +# endif +#else +#define GLEW_APIENTRY_DEFINED +# if defined(__MINGW32__) || defined(__CYGWIN__) || (_MSC_VER >= 800) || defined(_STDCALL_SUPPORTED) || defined(__BORLANDC__) +# define APIENTRY __stdcall +# ifndef GLAPIENTRY +# define GLAPIENTRY __stdcall +# endif +# ifndef GLEWAPIENTRY +# define GLEWAPIENTRY __stdcall +# endif +# else +# define APIENTRY +# endif +#endif +#ifndef GLAPI +# if defined(__MINGW32__) || defined(__CYGWIN__) +# define GLAPI extern +# endif +#endif +/* <winnt.h> */ +#ifndef CALLBACK +#define GLEW_CALLBACK_DEFINED +# if defined(__MINGW32__) || defined(__CYGWIN__) +# define CALLBACK __attribute__ ((__stdcall__)) +# elif (defined(_M_MRX000) || defined(_M_IX86) || defined(_M_ALPHA) || defined(_M_PPC)) && !defined(MIDL_PASS) +# define CALLBACK __stdcall +# else +# define CALLBACK +# endif +#endif +/* <wingdi.h> and <winnt.h> */ +#ifndef WINGDIAPI +#define GLEW_WINGDIAPI_DEFINED +#define WINGDIAPI __declspec(dllimport) +#endif +/* <ctype.h> */ +#if (defined(_MSC_VER) || defined(__BORLANDC__)) && !defined(_WCHAR_T_DEFINED) +typedef unsigned short wchar_t; +# define _WCHAR_T_DEFINED +#endif +/* <stddef.h> */ +#if !defined(_W64) +# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && defined(_MSC_VER) && _MSC_VER >= 1300 +# define _W64 __w64 +# else +# define _W64 +# endif +#endif +#if !defined(_PTRDIFF_T_DEFINED) && !defined(_PTRDIFF_T_) && !defined(__MINGW64__) +# ifdef _WIN64 +typedef __int64 ptrdiff_t; +# else +typedef _W64 int ptrdiff_t; +# endif +# define _PTRDIFF_T_DEFINED +# define _PTRDIFF_T_ +#endif + +#ifndef GLAPI +# if defined(__MINGW32__) || defined(__CYGWIN__) +# define GLAPI extern +# else +# define GLAPI WINGDIAPI +# endif +#endif + +/* + * GLEW_STATIC is defined for static library. + * GLEW_BUILD is defined for building the DLL library. + */ + +#ifdef GLEW_STATIC +# define GLEWAPI extern +#else +# ifdef GLEW_BUILD +# define GLEWAPI extern __declspec(dllexport) +# else +# define GLEWAPI extern __declspec(dllimport) +# endif +#endif + +#else /* _UNIX */ + +/* + * Needed for ptrdiff_t in turn needed by VBO. This is defined by ISO + * C. On my system, this amounts to _3 lines_ of included code, all of + * them pretty much harmless. If you know of a way of detecting 32 vs + * 64 _targets_ at compile time you are free to replace this with + * something that's portable. For now, _this_ is the portable solution. + * (mem, 2004-01-04) + */ + +#include <stddef.h> + +/* SGI MIPSPro doesn't like stdint.h in C++ mode */ +/* ID: 3376260 Solaris 9 has inttypes.h, but not stdint.h */ + +#if (defined(__sgi) || defined(__sun)) && !defined(__GNUC__) +#include <inttypes.h> +#else +#include <stdint.h> +#endif + +#define GLEW_APIENTRY_DEFINED +#define APIENTRY + +/* + * GLEW_STATIC is defined for static library. + */ + +#ifdef GLEW_STATIC +# define GLEWAPI extern +#else +# if defined(__GNUC__) && __GNUC__>=4 +# define GLEWAPI extern __attribute__ ((visibility("default"))) +# elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) +# define GLEWAPI extern __global +# else +# define GLEWAPI extern +# endif +#endif + +/* <glu.h> */ +#ifndef GLAPI +#define GLAPI extern +#endif + +#endif /* _WIN32 */ + +#ifndef GLAPIENTRY +#define GLAPIENTRY +#endif + +#ifndef GLEWAPIENTRY +#define GLEWAPIENTRY +#endif + +#define GLEW_VAR_EXPORT GLEWAPI +#define GLEW_FUN_EXPORT GLEWAPI + +#ifdef __cplusplus +extern "C" { +#endif + +/* ----------------------------- GL_VERSION_1_1 ---------------------------- */ + +#ifndef GL_VERSION_1_1 +#define GL_VERSION_1_1 1 + +typedef unsigned int GLenum; +typedef unsigned int GLbitfield; +typedef unsigned int GLuint; +typedef int GLint; +typedef int GLsizei; +typedef unsigned char GLboolean; +typedef signed char GLbyte; +typedef short GLshort; +typedef unsigned char GLubyte; +typedef unsigned short GLushort; +typedef unsigned long GLulong; +typedef float GLfloat; +typedef float GLclampf; +typedef double GLdouble; +typedef double GLclampd; +typedef void GLvoid; +#if defined(_MSC_VER) && _MSC_VER < 1400 +typedef __int64 GLint64EXT; +typedef unsigned __int64 GLuint64EXT; +#elif defined(_MSC_VER) || defined(__BORLANDC__) +typedef signed long long GLint64EXT; +typedef unsigned long long GLuint64EXT; +#else +# if defined(__MINGW32__) || defined(__CYGWIN__) +#include <inttypes.h> +# endif +typedef int64_t GLint64EXT; +typedef uint64_t GLuint64EXT; +#endif +typedef GLint64EXT GLint64; +typedef GLuint64EXT GLuint64; +typedef struct __GLsync *GLsync; + +typedef char GLchar; + +#define GL_ZERO 0 +#define GL_FALSE 0 +#define GL_LOGIC_OP 0x0BF1 +#define GL_NONE 0 +#define GL_TEXTURE_COMPONENTS 0x1003 +#define GL_NO_ERROR 0 +#define GL_POINTS 0x0000 +#define GL_CURRENT_BIT 0x00000001 +#define GL_TRUE 1 +#define GL_ONE 1 +#define GL_CLIENT_PIXEL_STORE_BIT 0x00000001 +#define GL_LINES 0x0001 +#define GL_LINE_LOOP 0x0002 +#define GL_POINT_BIT 0x00000002 +#define GL_CLIENT_VERTEX_ARRAY_BIT 0x00000002 +#define GL_LINE_STRIP 0x0003 +#define GL_LINE_BIT 0x00000004 +#define GL_TRIANGLES 0x0004 +#define GL_TRIANGLE_STRIP 0x0005 +#define GL_TRIANGLE_FAN 0x0006 +#define GL_QUADS 0x0007 +#define GL_QUAD_STRIP 0x0008 +#define GL_POLYGON_BIT 0x00000008 +#define GL_POLYGON 0x0009 +#define GL_POLYGON_STIPPLE_BIT 0x00000010 +#define GL_PIXEL_MODE_BIT 0x00000020 +#define GL_LIGHTING_BIT 0x00000040 +#define GL_FOG_BIT 0x00000080 +#define GL_DEPTH_BUFFER_BIT 0x00000100 +#define GL_ACCUM 0x0100 +#define GL_LOAD 0x0101 +#define GL_RETURN 0x0102 +#define GL_MULT 0x0103 +#define GL_ADD 0x0104 +#define GL_NEVER 0x0200 +#define GL_ACCUM_BUFFER_BIT 0x00000200 +#define GL_LESS 0x0201 +#define GL_EQUAL 0x0202 +#define GL_LEQUAL 0x0203 +#define GL_GREATER 0x0204 +#define GL_NOTEQUAL 0x0205 +#define GL_GEQUAL 0x0206 +#define GL_ALWAYS 0x0207 +#define GL_SRC_COLOR 0x0300 +#define GL_ONE_MINUS_SRC_COLOR 0x0301 +#define GL_SRC_ALPHA 0x0302 +#define GL_ONE_MINUS_SRC_ALPHA 0x0303 +#define GL_DST_ALPHA 0x0304 +#define GL_ONE_MINUS_DST_ALPHA 0x0305 +#define GL_DST_COLOR 0x0306 +#define GL_ONE_MINUS_DST_COLOR 0x0307 +#define GL_SRC_ALPHA_SATURATE 0x0308 +#define GL_STENCIL_BUFFER_BIT 0x00000400 +#define GL_FRONT_LEFT 0x0400 +#define GL_FRONT_RIGHT 0x0401 +#define GL_BACK_LEFT 0x0402 +#define GL_BACK_RIGHT 0x0403 +#define GL_FRONT 0x0404 +#define GL_BACK 0x0405 +#define GL_LEFT 0x0406 +#define GL_RIGHT 0x0407 +#define GL_FRONT_AND_BACK 0x0408 +#define GL_AUX0 0x0409 +#define GL_AUX1 0x040A +#define GL_AUX2 0x040B +#define GL_AUX3 0x040C +#define GL_INVALID_ENUM 0x0500 +#define GL_INVALID_VALUE 0x0501 +#define GL_INVALID_OPERATION 0x0502 +#define GL_STACK_OVERFLOW 0x0503 +#define GL_STACK_UNDERFLOW 0x0504 +#define GL_OUT_OF_MEMORY 0x0505 +#define GL_2D 0x0600 +#define GL_3D 0x0601 +#define GL_3D_COLOR 0x0602 +#define GL_3D_COLOR_TEXTURE 0x0603 +#define GL_4D_COLOR_TEXTURE 0x0604 +#define GL_PASS_THROUGH_TOKEN 0x0700 +#define GL_POINT_TOKEN 0x0701 +#define GL_LINE_TOKEN 0x0702 +#define GL_POLYGON_TOKEN 0x0703 +#define GL_BITMAP_TOKEN 0x0704 +#define GL_DRAW_PIXEL_TOKEN 0x0705 +#define GL_COPY_PIXEL_TOKEN 0x0706 +#define GL_LINE_RESET_TOKEN 0x0707 +#define GL_EXP 0x0800 +#define GL_VIEWPORT_BIT 0x00000800 +#define GL_EXP2 0x0801 +#define GL_CW 0x0900 +#define GL_CCW 0x0901 +#define GL_COEFF 0x0A00 +#define GL_ORDER 0x0A01 +#define GL_DOMAIN 0x0A02 +#define GL_CURRENT_COLOR 0x0B00 +#define GL_CURRENT_INDEX 0x0B01 +#define GL_CURRENT_NORMAL 0x0B02 +#define GL_CURRENT_TEXTURE_COORDS 0x0B03 +#define GL_CURRENT_RASTER_COLOR 0x0B04 +#define GL_CURRENT_RASTER_INDEX 0x0B05 +#define GL_CURRENT_RASTER_TEXTURE_COORDS 0x0B06 +#define GL_CURRENT_RASTER_POSITION 0x0B07 +#define GL_CURRENT_RASTER_POSITION_VALID 0x0B08 +#define GL_CURRENT_RASTER_DISTANCE 0x0B09 +#define GL_POINT_SMOOTH 0x0B10 +#define GL_POINT_SIZE 0x0B11 +#define GL_POINT_SIZE_RANGE 0x0B12 +#define GL_POINT_SIZE_GRANULARITY 0x0B13 +#define GL_LINE_SMOOTH 0x0B20 +#define GL_LINE_WIDTH 0x0B21 +#define GL_LINE_WIDTH_RANGE 0x0B22 +#define GL_LINE_WIDTH_GRANULARITY 0x0B23 +#define GL_LINE_STIPPLE 0x0B24 +#define GL_LINE_STIPPLE_PATTERN 0x0B25 +#define GL_LINE_STIPPLE_REPEAT 0x0B26 +#define GL_LIST_MODE 0x0B30 +#define GL_MAX_LIST_NESTING 0x0B31 +#define GL_LIST_BASE 0x0B32 +#define GL_LIST_INDEX 0x0B33 +#define GL_POLYGON_MODE 0x0B40 +#define GL_POLYGON_SMOOTH 0x0B41 +#define GL_POLYGON_STIPPLE 0x0B42 +#define GL_EDGE_FLAG 0x0B43 +#define GL_CULL_FACE 0x0B44 +#define GL_CULL_FACE_MODE 0x0B45 +#define GL_FRONT_FACE 0x0B46 +#define GL_LIGHTING 0x0B50 +#define GL_LIGHT_MODEL_LOCAL_VIEWER 0x0B51 +#define GL_LIGHT_MODEL_TWO_SIDE 0x0B52 +#define GL_LIGHT_MODEL_AMBIENT 0x0B53 +#define GL_SHADE_MODEL 0x0B54 +#define GL_COLOR_MATERIAL_FACE 0x0B55 +#define GL_COLOR_MATERIAL_PARAMETER 0x0B56 +#define GL_COLOR_MATERIAL 0x0B57 +#define GL_FOG 0x0B60 +#define GL_FOG_INDEX 0x0B61 +#define GL_FOG_DENSITY 0x0B62 +#define GL_FOG_START 0x0B63 +#define GL_FOG_END 0x0B64 +#define GL_FOG_MODE 0x0B65 +#define GL_FOG_COLOR 0x0B66 +#define GL_DEPTH_RANGE 0x0B70 +#define GL_DEPTH_TEST 0x0B71 +#define GL_DEPTH_WRITEMASK 0x0B72 +#define GL_DEPTH_CLEAR_VALUE 0x0B73 +#define GL_DEPTH_FUNC 0x0B74 +#define GL_ACCUM_CLEAR_VALUE 0x0B80 +#define GL_STENCIL_TEST 0x0B90 +#define GL_STENCIL_CLEAR_VALUE 0x0B91 +#define GL_STENCIL_FUNC 0x0B92 +#define GL_STENCIL_VALUE_MASK 0x0B93 +#define GL_STENCIL_FAIL 0x0B94 +#define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95 +#define GL_STENCIL_PASS_DEPTH_PASS 0x0B96 +#define GL_STENCIL_REF 0x0B97 +#define GL_STENCIL_WRITEMASK 0x0B98 +#define GL_MATRIX_MODE 0x0BA0 +#define GL_NORMALIZE 0x0BA1 +#define GL_VIEWPORT 0x0BA2 +#define GL_MODELVIEW_STACK_DEPTH 0x0BA3 +#define GL_PROJECTION_STACK_DEPTH 0x0BA4 +#define GL_TEXTURE_STACK_DEPTH 0x0BA5 +#define GL_MODELVIEW_MATRIX 0x0BA6 +#define GL_PROJECTION_MATRIX 0x0BA7 +#define GL_TEXTURE_MATRIX 0x0BA8 +#define GL_ATTRIB_STACK_DEPTH 0x0BB0 +#define GL_CLIENT_ATTRIB_STACK_DEPTH 0x0BB1 +#define GL_ALPHA_TEST 0x0BC0 +#define GL_ALPHA_TEST_FUNC 0x0BC1 +#define GL_ALPHA_TEST_REF 0x0BC2 +#define GL_DITHER 0x0BD0 +#define GL_BLEND_DST 0x0BE0 +#define GL_BLEND_SRC 0x0BE1 +#define GL_BLEND 0x0BE2 +#define GL_LOGIC_OP_MODE 0x0BF0 +#define GL_INDEX_LOGIC_OP 0x0BF1 +#define GL_COLOR_LOGIC_OP 0x0BF2 +#define GL_AUX_BUFFERS 0x0C00 +#define GL_DRAW_BUFFER 0x0C01 +#define GL_READ_BUFFER 0x0C02 +#define GL_SCISSOR_BOX 0x0C10 +#define GL_SCISSOR_TEST 0x0C11 +#define GL_INDEX_CLEAR_VALUE 0x0C20 +#define GL_INDEX_WRITEMASK 0x0C21 +#define GL_COLOR_CLEAR_VALUE 0x0C22 +#define GL_COLOR_WRITEMASK 0x0C23 +#define GL_INDEX_MODE 0x0C30 +#define GL_RGBA_MODE 0x0C31 +#define GL_DOUBLEBUFFER 0x0C32 +#define GL_STEREO 0x0C33 +#define GL_RENDER_MODE 0x0C40 +#define GL_PERSPECTIVE_CORRECTION_HINT 0x0C50 +#define GL_POINT_SMOOTH_HINT 0x0C51 +#define GL_LINE_SMOOTH_HINT 0x0C52 +#define GL_POLYGON_SMOOTH_HINT 0x0C53 +#define GL_FOG_HINT 0x0C54 +#define GL_TEXTURE_GEN_S 0x0C60 +#define GL_TEXTURE_GEN_T 0x0C61 +#define GL_TEXTURE_GEN_R 0x0C62 +#define GL_TEXTURE_GEN_Q 0x0C63 +#define GL_PIXEL_MAP_I_TO_I 0x0C70 +#define GL_PIXEL_MAP_S_TO_S 0x0C71 +#define GL_PIXEL_MAP_I_TO_R 0x0C72 +#define GL_PIXEL_MAP_I_TO_G 0x0C73 +#define GL_PIXEL_MAP_I_TO_B 0x0C74 +#define GL_PIXEL_MAP_I_TO_A 0x0C75 +#define GL_PIXEL_MAP_R_TO_R 0x0C76 +#define GL_PIXEL_MAP_G_TO_G 0x0C77 +#define GL_PIXEL_MAP_B_TO_B 0x0C78 +#define GL_PIXEL_MAP_A_TO_A 0x0C79 +#define GL_PIXEL_MAP_I_TO_I_SIZE 0x0CB0 +#define GL_PIXEL_MAP_S_TO_S_SIZE 0x0CB1 +#define GL_PIXEL_MAP_I_TO_R_SIZE 0x0CB2 +#define GL_PIXEL_MAP_I_TO_G_SIZE 0x0CB3 +#define GL_PIXEL_MAP_I_TO_B_SIZE 0x0CB4 +#define GL_PIXEL_MAP_I_TO_A_SIZE 0x0CB5 +#define GL_PIXEL_MAP_R_TO_R_SIZE 0x0CB6 +#define GL_PIXEL_MAP_G_TO_G_SIZE 0x0CB7 +#define GL_PIXEL_MAP_B_TO_B_SIZE 0x0CB8 +#define GL_PIXEL_MAP_A_TO_A_SIZE 0x0CB9 +#define GL_UNPACK_SWAP_BYTES 0x0CF0 +#define GL_UNPACK_LSB_FIRST 0x0CF1 +#define GL_UNPACK_ROW_LENGTH 0x0CF2 +#define GL_UNPACK_SKIP_ROWS 0x0CF3 +#define GL_UNPACK_SKIP_PIXELS 0x0CF4 +#define GL_UNPACK_ALIGNMENT 0x0CF5 +#define GL_PACK_SWAP_BYTES 0x0D00 +#define GL_PACK_LSB_FIRST 0x0D01 +#define GL_PACK_ROW_LENGTH 0x0D02 +#define GL_PACK_SKIP_ROWS 0x0D03 +#define GL_PACK_SKIP_PIXELS 0x0D04 +#define GL_PACK_ALIGNMENT 0x0D05 +#define GL_MAP_COLOR 0x0D10 +#define GL_MAP_STENCIL 0x0D11 +#define GL_INDEX_SHIFT 0x0D12 +#define GL_INDEX_OFFSET 0x0D13 +#define GL_RED_SCALE 0x0D14 +#define GL_RED_BIAS 0x0D15 +#define GL_ZOOM_X 0x0D16 +#define GL_ZOOM_Y 0x0D17 +#define GL_GREEN_SCALE 0x0D18 +#define GL_GREEN_BIAS 0x0D19 +#define GL_BLUE_SCALE 0x0D1A +#define GL_BLUE_BIAS 0x0D1B +#define GL_ALPHA_SCALE 0x0D1C +#define GL_ALPHA_BIAS 0x0D1D +#define GL_DEPTH_SCALE 0x0D1E +#define GL_DEPTH_BIAS 0x0D1F +#define GL_MAX_EVAL_ORDER 0x0D30 +#define GL_MAX_LIGHTS 0x0D31 +#define GL_MAX_CLIP_PLANES 0x0D32 +#define GL_MAX_TEXTURE_SIZE 0x0D33 +#define GL_MAX_PIXEL_MAP_TABLE 0x0D34 +#define GL_MAX_ATTRIB_STACK_DEPTH 0x0D35 +#define GL_MAX_MODELVIEW_STACK_DEPTH 0x0D36 +#define GL_MAX_NAME_STACK_DEPTH 0x0D37 +#define GL_MAX_PROJECTION_STACK_DEPTH 0x0D38 +#define GL_MAX_TEXTURE_STACK_DEPTH 0x0D39 +#define GL_MAX_VIEWPORT_DIMS 0x0D3A +#define GL_MAX_CLIENT_ATTRIB_STACK_DEPTH 0x0D3B +#define GL_SUBPIXEL_BITS 0x0D50 +#define GL_INDEX_BITS 0x0D51 +#define GL_RED_BITS 0x0D52 +#define GL_GREEN_BITS 0x0D53 +#define GL_BLUE_BITS 0x0D54 +#define GL_ALPHA_BITS 0x0D55 +#define GL_DEPTH_BITS 0x0D56 +#define GL_STENCIL_BITS 0x0D57 +#define GL_ACCUM_RED_BITS 0x0D58 +#define GL_ACCUM_GREEN_BITS 0x0D59 +#define GL_ACCUM_BLUE_BITS 0x0D5A +#define GL_ACCUM_ALPHA_BITS 0x0D5B +#define GL_NAME_STACK_DEPTH 0x0D70 +#define GL_AUTO_NORMAL 0x0D80 +#define GL_MAP1_COLOR_4 0x0D90 +#define GL_MAP1_INDEX 0x0D91 +#define GL_MAP1_NORMAL 0x0D92 +#define GL_MAP1_TEXTURE_COORD_1 0x0D93 +#define GL_MAP1_TEXTURE_COORD_2 0x0D94 +#define GL_MAP1_TEXTURE_COORD_3 0x0D95 +#define GL_MAP1_TEXTURE_COORD_4 0x0D96 +#define GL_MAP1_VERTEX_3 0x0D97 +#define GL_MAP1_VERTEX_4 0x0D98 +#define GL_MAP2_COLOR_4 0x0DB0 +#define GL_MAP2_INDEX 0x0DB1 +#define GL_MAP2_NORMAL 0x0DB2 +#define GL_MAP2_TEXTURE_COORD_1 0x0DB3 +#define GL_MAP2_TEXTURE_COORD_2 0x0DB4 +#define GL_MAP2_TEXTURE_COORD_3 0x0DB5 +#define GL_MAP2_TEXTURE_COORD_4 0x0DB6 +#define GL_MAP2_VERTEX_3 0x0DB7 +#define GL_MAP2_VERTEX_4 0x0DB8 +#define GL_MAP1_GRID_DOMAIN 0x0DD0 +#define GL_MAP1_GRID_SEGMENTS 0x0DD1 +#define GL_MAP2_GRID_DOMAIN 0x0DD2 +#define GL_MAP2_GRID_SEGMENTS 0x0DD3 +#define GL_TEXTURE_1D 0x0DE0 +#define GL_TEXTURE_2D 0x0DE1 +#define GL_FEEDBACK_BUFFER_POINTER 0x0DF0 +#define GL_FEEDBACK_BUFFER_SIZE 0x0DF1 +#define GL_FEEDBACK_BUFFER_TYPE 0x0DF2 +#define GL_SELECTION_BUFFER_POINTER 0x0DF3 +#define GL_SELECTION_BUFFER_SIZE 0x0DF4 +#define GL_TEXTURE_WIDTH 0x1000 +#define GL_TRANSFORM_BIT 0x00001000 +#define GL_TEXTURE_HEIGHT 0x1001 +#define GL_TEXTURE_INTERNAL_FORMAT 0x1003 +#define GL_TEXTURE_BORDER_COLOR 0x1004 +#define GL_TEXTURE_BORDER 0x1005 +#define GL_DONT_CARE 0x1100 +#define GL_FASTEST 0x1101 +#define GL_NICEST 0x1102 +#define GL_AMBIENT 0x1200 +#define GL_DIFFUSE 0x1201 +#define GL_SPECULAR 0x1202 +#define GL_POSITION 0x1203 +#define GL_SPOT_DIRECTION 0x1204 +#define GL_SPOT_EXPONENT 0x1205 +#define GL_SPOT_CUTOFF 0x1206 +#define GL_CONSTANT_ATTENUATION 0x1207 +#define GL_LINEAR_ATTENUATION 0x1208 +#define GL_QUADRATIC_ATTENUATION 0x1209 +#define GL_COMPILE 0x1300 +#define GL_COMPILE_AND_EXECUTE 0x1301 +#define GL_BYTE 0x1400 +#define GL_UNSIGNED_BYTE 0x1401 +#define GL_SHORT 0x1402 +#define GL_UNSIGNED_SHORT 0x1403 +#define GL_INT 0x1404 +#define GL_UNSIGNED_INT 0x1405 +#define GL_FLOAT 0x1406 +#define GL_2_BYTES 0x1407 +#define GL_3_BYTES 0x1408 +#define GL_4_BYTES 0x1409 +#define GL_DOUBLE 0x140A +#define GL_CLEAR 0x1500 +#define GL_AND 0x1501 +#define GL_AND_REVERSE 0x1502 +#define GL_COPY 0x1503 +#define GL_AND_INVERTED 0x1504 +#define GL_NOOP 0x1505 +#define GL_XOR 0x1506 +#define GL_OR 0x1507 +#define GL_NOR 0x1508 +#define GL_EQUIV 0x1509 +#define GL_INVERT 0x150A +#define GL_OR_REVERSE 0x150B +#define GL_COPY_INVERTED 0x150C +#define GL_OR_INVERTED 0x150D +#define GL_NAND 0x150E +#define GL_SET 0x150F +#define GL_EMISSION 0x1600 +#define GL_SHININESS 0x1601 +#define GL_AMBIENT_AND_DIFFUSE 0x1602 +#define GL_COLOR_INDEXES 0x1603 +#define GL_MODELVIEW 0x1700 +#define GL_PROJECTION 0x1701 +#define GL_TEXTURE 0x1702 +#define GL_COLOR 0x1800 +#define GL_DEPTH 0x1801 +#define GL_STENCIL 0x1802 +#define GL_COLOR_INDEX 0x1900 +#define GL_STENCIL_INDEX 0x1901 +#define GL_DEPTH_COMPONENT 0x1902 +#define GL_RED 0x1903 +#define GL_GREEN 0x1904 +#define GL_BLUE 0x1905 +#define GL_ALPHA 0x1906 +#define GL_RGB 0x1907 +#define GL_RGBA 0x1908 +#define GL_LUMINANCE 0x1909 +#define GL_LUMINANCE_ALPHA 0x190A +#define GL_BITMAP 0x1A00 +#define GL_POINT 0x1B00 +#define GL_LINE 0x1B01 +#define GL_FILL 0x1B02 +#define GL_RENDER 0x1C00 +#define GL_FEEDBACK 0x1C01 +#define GL_SELECT 0x1C02 +#define GL_FLAT 0x1D00 +#define GL_SMOOTH 0x1D01 +#define GL_KEEP 0x1E00 +#define GL_REPLACE 0x1E01 +#define GL_INCR 0x1E02 +#define GL_DECR 0x1E03 +#define GL_VENDOR 0x1F00 +#define GL_RENDERER 0x1F01 +#define GL_VERSION 0x1F02 +#define GL_EXTENSIONS 0x1F03 +#define GL_S 0x2000 +#define GL_ENABLE_BIT 0x00002000 +#define GL_T 0x2001 +#define GL_R 0x2002 +#define GL_Q 0x2003 +#define GL_MODULATE 0x2100 +#define GL_DECAL 0x2101 +#define GL_TEXTURE_ENV_MODE 0x2200 +#define GL_TEXTURE_ENV_COLOR 0x2201 +#define GL_TEXTURE_ENV 0x2300 +#define GL_EYE_LINEAR 0x2400 +#define GL_OBJECT_LINEAR 0x2401 +#define GL_SPHERE_MAP 0x2402 +#define GL_TEXTURE_GEN_MODE 0x2500 +#define GL_OBJECT_PLANE 0x2501 +#define GL_EYE_PLANE 0x2502 +#define GL_NEAREST 0x2600 +#define GL_LINEAR 0x2601 +#define GL_NEAREST_MIPMAP_NEAREST 0x2700 +#define GL_LINEAR_MIPMAP_NEAREST 0x2701 +#define GL_NEAREST_MIPMAP_LINEAR 0x2702 +#define GL_LINEAR_MIPMAP_LINEAR 0x2703 +#define GL_TEXTURE_MAG_FILTER 0x2800 +#define GL_TEXTURE_MIN_FILTER 0x2801 +#define GL_TEXTURE_WRAP_S 0x2802 +#define GL_TEXTURE_WRAP_T 0x2803 +#define GL_CLAMP 0x2900 +#define GL_REPEAT 0x2901 +#define GL_POLYGON_OFFSET_UNITS 0x2A00 +#define GL_POLYGON_OFFSET_POINT 0x2A01 +#define GL_POLYGON_OFFSET_LINE 0x2A02 +#define GL_R3_G3_B2 0x2A10 +#define GL_V2F 0x2A20 +#define GL_V3F 0x2A21 +#define GL_C4UB_V2F 0x2A22 +#define GL_C4UB_V3F 0x2A23 +#define GL_C3F_V3F 0x2A24 +#define GL_N3F_V3F 0x2A25 +#define GL_C4F_N3F_V3F 0x2A26 +#define GL_T2F_V3F 0x2A27 +#define GL_T4F_V4F 0x2A28 +#define GL_T2F_C |