-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathrt.h
208 lines (182 loc) · 8.42 KB
/
rt.h
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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
/*
Calf Box, an open source musical instrument.
Copyright (C) 2010-2013 Krzysztof Foltman
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CBOX_RT_H
#define CBOX_RT_H
#include <stdint.h>
#include "cmd.h"
#include "dom.h"
#include "fifo.h"
#include "ioenv.h"
#include "midi.h"
#include "mididest.h"
#define RT_CMD_QUEUE_ITEMS 1024
#define RT_MAX_COST_PER_CALL 100
struct cbox_instruments;
struct cbox_scene;
struct cbox_io;
struct cbox_midi_pattern;
struct cbox_song;
struct cbox_rt_cmd_instance;
struct cbox_rt_cmd_definition
{
int (*prepare)(void *user_data); // non-zero to skip the whole thing
int (*execute)(void *user_data); // returns cost
void (*cleanup)(void *user_data);
};
CBOX_EXTERN_CLASS(cbox_rt)
struct cbox_rt
{
CBOX_OBJECT_HEADER()
struct cbox_io *io;
struct cbox_io_callbacks *cbs;
struct cbox_fifo *rb_execute, *rb_cleanup;
struct cbox_command_target cmd_target;
int started, disconnected;
struct cbox_io_env io_env;
struct cbox_engine *engine;
};
extern struct cbox_rt *cbox_rt_new(struct cbox_document *doc);
extern void cbox_rt_set_io(struct cbox_rt *rt, struct cbox_io *io);
extern void cbox_rt_set_offline(struct cbox_rt *rt, int sample_rate, int buffer_size);
extern void cbox_rt_start(struct cbox_rt *rt, struct cbox_command_target *fb);
extern void cbox_rt_handle_cmd_queue(struct cbox_rt *rt);
// This one should be called from RT thread process function to execute the queued RT commands
extern void cbox_rt_handle_rt_commands(struct cbox_rt *rt);
extern void cbox_rt_stop(struct cbox_rt *rt);
// Those are for calling from the main thread. I will add a RT-thread version later.
extern void cbox_rt_execute_cmd_sync(struct cbox_rt *rt, struct cbox_rt_cmd_definition *cmd, void *user_data);
extern int cbox_rt_execute_cmd_async(struct cbox_rt *rt, struct cbox_rt_cmd_definition *cmd, void *user_data);
extern void *cbox_rt_swap_pointers(struct cbox_rt *rt, void **ptr, void *new_value);
extern void cbox_rt_swap_pointers_into(struct cbox_rt *rt, void **ptr, void *new_value, void **old_value_ptr);
extern void *cbox_rt_swap_pointers_and_update_count(struct cbox_rt *rt, void **ptr, void *new_value, uint32_t *pcount, uint32_t new_count);
extern void cbox_rt_array_insert(struct cbox_rt *rt, void ***ptr, uint32_t *pcount, int index, void *new_value);
extern void *cbox_rt_array_remove(struct cbox_rt *rt, void ***ptr, uint32_t *pcount, int index);
extern gboolean cbox_rt_array_remove_by_value(struct cbox_rt *rt, void ***ptr, uint32_t *pcount, void *value_to_remove);
extern struct cbox_midi_merger *cbox_rt_get_midi_output(struct cbox_rt *rt, struct cbox_uuid *uuid);
///////////////////////////////////////////////////////////////////////////////
#define GET_RT_FROM_cbox_rt(ptr) (ptr)
#define RT_FUNC_ARG_MEMBER(type, name) type name;
#define RT_FUNC_ARG_LIST(type, name) , type name
#define RT_FUNC_ARG_PASS(type, name) _args.name = name;
#define RT_FUNC_ARG_PASS2(type, name) , _args.name
#define RT_FUNC_ARG_PASS3(type, name) , _args->name
#define RT_FUNC_ARG_PASS4(type, name) , name
#define RT_FUNC_ARG_PASS5(type, name) _args->name = name;
#define DEFINE_RT_FUNC(restype, objtype, argname, name) \
struct rt_function_args_##name { \
struct objtype *_obj; \
restype _result; \
name##_args(RT_FUNC_ARG_MEMBER) \
}; \
static restype RT_IMPL_##name(struct objtype *_obj, int *_cost name##_args(RT_FUNC_ARG_LIST)); \
int exec_##name(void *user_data) { \
int cost = 1; \
struct rt_function_args_##name *_args = user_data;\
_args->_result = RT_IMPL_##name(_args->_obj, &cost name##_args(RT_FUNC_ARG_PASS3)); \
return cost; \
} \
restype name(struct objtype *_obj name##_args(RT_FUNC_ARG_LIST)) \
{ \
struct cbox_rt *rt = GET_RT_FROM_##objtype(_obj); \
if (rt) { \
struct rt_function_args_##name _args; \
static struct cbox_rt_cmd_definition _cmd = { .prepare = NULL, .execute = exec_##name, .cleanup = NULL }; \
_args._obj = _obj; \
name##_args(RT_FUNC_ARG_PASS) \
cbox_rt_execute_cmd_sync(rt, &_cmd, &_args); \
return _args._result; \
} else { \
int cost; \
restype _result; \
do { \
cost = 1; \
_result = RT_IMPL_##name(_obj, &cost name##_args(RT_FUNC_ARG_PASS4)); \
} while(!cost); \
return _result; \
} \
} \
restype RT_IMPL_##name(struct objtype *argname, int *_cost name##_args(RT_FUNC_ARG_LIST))
#define DEFINE_RT_VOID_FUNC(objtype, argname, name) \
struct rt_function_args_##name { \
struct objtype *_obj; \
name##_args(RT_FUNC_ARG_MEMBER) \
}; \
static void RT_IMPL_##name(struct objtype *_obj, int *_cost name##_args(RT_FUNC_ARG_LIST)); \
int exec_##name(void *user_data) { \
int cost = 1; \
struct rt_function_args_##name *_args = user_data;\
RT_IMPL_##name(_args->_obj, &cost name##_args(RT_FUNC_ARG_PASS3)); \
return cost; \
} \
void name(struct objtype *_obj name##_args(RT_FUNC_ARG_LIST)) \
{ \
struct cbox_rt *rt = GET_RT_FROM_##objtype(_obj); \
if (rt) { \
struct rt_function_args_##name _args = { ._obj = _obj }; \
static struct cbox_rt_cmd_definition _cmd = { .prepare = NULL, .execute = exec_##name, .cleanup = NULL }; \
name##_args(RT_FUNC_ARG_PASS) \
cbox_rt_execute_cmd_sync(rt, &_cmd, &_args); \
} else { \
int cost; \
do { \
cost = 1; \
RT_IMPL_##name(_obj, &cost name##_args(RT_FUNC_ARG_PASS4)); \
} while(!cost); \
} \
} \
void RT_IMPL_##name(struct objtype *argname, int *_cost name##_args(RT_FUNC_ARG_LIST))
#define DEFINE_ASYNC_RT_FUNC(objtype, argname, name) \
struct rt_function_args_##name { \
struct objtype *_obj; \
name##_args(RT_FUNC_ARG_MEMBER) \
}; \
static void RT_IMPL_##name(struct objtype *_obj, int *_cost name##_args(RT_FUNC_ARG_LIST)); \
static int prepare_##name(void *user_data); \
static void cleanup_##name(void *user_data); \
static int exec_##name(void *user_data) { \
int cost = 1; \
struct rt_function_args_##name *_args = user_data;\
RT_IMPL_##name(_args->_obj, &cost name##_args(RT_FUNC_ARG_PASS3)); \
return cost; \
} \
void name(struct objtype *_obj name##_args(RT_FUNC_ARG_LIST)) \
{ \
struct cbox_rt *rt = GET_RT_FROM_##objtype(_obj); \
struct rt_function_args_##name *_args = malloc(sizeof(struct rt_function_args_##name)); \
_args->_obj = _obj; \
name##_args(RT_FUNC_ARG_PASS5) \
static struct cbox_rt_cmd_definition _cmd = { .prepare = prepare_##name, .execute = exec_##name, .cleanup = cleanup_##name }; \
if (cbox_rt_execute_cmd_async(rt, &_cmd, _args)) \
free(_args); \
} \
void RT_IMPL_##name(struct objtype *argname, int *_cost name##_args(RT_FUNC_ARG_LIST))
#define ASYNC_PREPARE_FUNC(objtype, argname, name) \
static int PREPARE_IMPL_##name(struct objtype *argname, struct rt_function_args_##name *args); \
int prepare_##name(void *user_data) {\
struct rt_function_args_##name *_args = user_data;\
return PREPARE_IMPL_##name(_args->_obj, _args); \
} \
int PREPARE_IMPL_##name(struct objtype *argname, struct rt_function_args_##name *args)
#define ASYNC_CLEANUP_FUNC(objtype, argname, name) \
static void CLEANUP_IMPL_##name(struct objtype *argname, struct rt_function_args_##name *args); \
void cleanup_##name(void *user_data) {\
struct rt_function_args_##name *_args = user_data;\
CLEANUP_IMPL_##name(_args->_obj, _args); \
free(_args); \
} \
void CLEANUP_IMPL_##name(struct objtype *argname, struct rt_function_args_##name *args)
#define RT_CALL_AGAIN_LATER() ((*_cost) = 0)
#define RT_SET_COST(n) ((*_cost) = (n))
#endif