1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
|
// Copyright 2016 David Robillard <d@drobilla.net>
// SPDX-License-Identifier: ISC
#include "lv2/atom/atom.h"
#include "lv2/urid/urid.h"
#include <stdarg.h>
#include <stdint.h>
#include <stdlib.h>
/** Entry in an array that serves as a dictionary of properties. */
typedef struct {
const char* uri;
LV2_URID urid;
LV2_Atom* value;
} StateMapItem;
/** Comparator for StateMapItems sorted by URID. */
static int
state_map_cmp(const void* a, const void* b)
{
const StateMapItem* ka = (const StateMapItem*)a;
const StateMapItem* kb = (const StateMapItem*)b;
if (ka->urid < kb->urid) {
return -1;
}
if (kb->urid < ka->urid) {
return 1;
}
return 0;
}
/** Helper macro for terse state map initialisation. */
#define STATE_MAP_INIT(type, ptr) \
(LV2_ATOM__##type), (sizeof(*(ptr)) - sizeof(LV2_Atom)), (ptr)
/**
Initialise a state map.
The variable parameters list must be NULL terminated, and is a sequence of
const char* uri, const char* type, uint32_t size, LV2_Atom* value. The
value must point to a valid atom that resides elsewhere, the state map is
only an index and does not contain actual state values. The macro
STATE_MAP_INIT can be used to make simpler code when state is composed of
standard atom types, for example:
struct Plugin {
LV2_URID_Map* map;
StateMapItem props[3];
// ...
};
state_map_init(
self->props, self->map, self->map->handle,
PLUG_URI "#gain", STATE_MAP_INIT(Float, &state->gain),
PLUG_URI "#offset", STATE_MAP_INIT(Int, &state->offset),
PLUG_URI "#file", STATE_MAP_INIT(Path, &state->file),
NULL);
*/
static void
state_map_init(
StateMapItem dict[],
LV2_URID_Map* map,
LV2_URID_Map_Handle handle,
/* const char* uri, const char* type, uint32_t size, LV2_Atom* value */...)
{
// Set dict entries from parameters
unsigned i = 0;
va_list args;
va_start(args, handle);
for (const char* uri = NULL; (uri = va_arg(args, const char*)); ++i) {
const char* type = va_arg(args, const char*);
const uint32_t size = va_arg(args, uint32_t);
LV2_Atom* const value = va_arg(args, LV2_Atom*);
dict[i].uri = uri;
dict[i].urid = map->map(map->handle, uri);
dict[i].value = value;
dict[i].value->size = size;
dict[i].value->type = map->map(map->handle, type);
}
va_end(args);
// Sort for fast lookup by URID by state_map_find()
qsort(dict, i, sizeof(StateMapItem), state_map_cmp);
}
/**
Retrieve an item from a state map by URID.
This takes O(lg(n)) time, and is useful for implementing generic property
access with little code, for example to respond to patch:Get messages for a
specific property.
*/
static StateMapItem*
state_map_find(StateMapItem dict[], uint32_t n_entries, LV2_URID urid)
{
const StateMapItem key = {NULL, urid, NULL};
return (StateMapItem*)bsearch(
&key, dict, n_entries, sizeof(StateMapItem), state_map_cmp);
}
|