1 /*
2 * Copyright (c) 2015-2016 Hanspeter Portner (dev@open-music-kontrollers.ch)
3 *
4 * This is free software: you can redistribute it and/or modify
5 * it under the terms of the Artistic License 2.0 as published by
6 * The Perl Foundation.
7 *
8 * This source is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * Artistic License 2.0 for more details.
12 *
13 * You should have received a copy of the Artistic License 2.0
14 * along the source as a COPYING file. If not, obtain it from
15 * http://www.perlfoundation.org/artistic_license_2_0.
16 */
17
18 #ifndef _SYNTHPOD_APP_PRIVATE_H
19 #define _SYNTHPOD_APP_PRIVATE_H
20
21 #include <limits.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <stdatomic.h>
25 #include <ctype.h> // isspace
26 #include <math.h>
27 #include <semaphore.h>
28 #include <pthread.h>
29
30 #include <synthpod_app.h>
31 #include <synthpod_private.h>
32
33 #include <sratom/sratom.h>
34 #include <varchunk.h>
35
36 #include <lv2_extensions.h> // ardour's inline display
37
38 #define CROSS_CLOCK_IMPLEMENTATION
39 #include <cross_clock/cross_clock.h>
40
41 #define XSD_PREFIX "http://www.w3.org/2001/XMLSchema#"
42 #define RDF_PREFIX "http://www.w3.org/1999/02/22-rdf-syntax-ns#"
43 #define RDFS_PREFIX "http://www.w3.org/2000/01/rdf-schema#"
44 #define SPOD_PREFIX "http://open-music-kontrollers.ch/lv2/synthpod#"
45
46 #define URN_UUID_LENGTH 46
47
48 #define NUM_FEATURES 17
49 #define MAX_SOURCES 32 // TODO how many?
50 #define MAX_MODS 512 // TODO how many?
51 #define MAX_SLAVES 7 // e.g. 8-core machines
52 #define MAX_AUTOMATIONS 64
53 #define ALIAS_MAX 32
54
55 typedef enum _job_type_request_t job_type_request_t;
56 typedef enum _job_type_reply_t job_type_reply_t;
57 typedef enum _blocking_state_t blocking_state_t;
58 typedef enum _silencing_state_t silencing_state_t;
59 typedef enum _ramp_state_t ramp_state_t;
60 typedef enum _auto_type_t auto_type_t;
61
62 typedef char urn_uuid_t [URN_UUID_LENGTH];
63 typedef struct _dsp_slave_t dsp_slave_t;
64 typedef struct _dsp_client_t dsp_client_t;
65 typedef struct _dsp_master_t dsp_master_t;
66
67 typedef struct _mod_worker_t mod_worker_t;
68 typedef struct _midi_auto_t midi_auto_t;
69 typedef struct _osc_auto_t osc_auto_t;
70 typedef struct _auto_t auto_t;
71 typedef struct _mod_t mod_t;
72 typedef struct _port_t port_t;
73 typedef struct _job_t job_t;
74 typedef struct _source_t source_t;
75 typedef struct _pool_t pool_t;
76 typedef struct _port_driver_t port_driver_t;
77 typedef struct _app_prof_t app_prof_t;
78 typedef struct _mod_prof_t mod_prof_t;
79
80 typedef void (*port_multiplex_cb_t) (sp_app_t *app, port_t *port, uint32_t nsamples);
81 typedef void (*port_transfer_cb_t) (sp_app_t *app, port_t *port, uint32_t nsamples);
82
83 enum _silencing_state_t {
84 SILENCING_STATE_RUN = 0,
85 SILENCING_STATE_BLOCK,
86 SILENCING_STATE_WAIT
87 };
88
89 enum _blocking_state_t {
90 BLOCKING_STATE_RUN = 0,
91 BLOCKING_STATE_DRAIN,
92 BLOCKING_STATE_BLOCK,
93 BLOCKING_STATE_WAIT,
94 };
95
96 static const bool advance_ui [] = {
97 [BLOCKING_STATE_RUN] = true,
98 [BLOCKING_STATE_DRAIN] = false,
99 [BLOCKING_STATE_BLOCK] = true,
100 [BLOCKING_STATE_WAIT] = false
101 };
102
103 static const bool advance_work [] = {
104 [BLOCKING_STATE_RUN] = true,
105 [BLOCKING_STATE_DRAIN] = true,
106 [BLOCKING_STATE_BLOCK] = true,
107 [BLOCKING_STATE_WAIT] = true
108 };
109
110 enum _ramp_state_t {
111 RAMP_STATE_NONE = 0,
112 RAMP_STATE_UP,
113 RAMP_STATE_DOWN,
114 RAMP_STATE_DOWN_DEL,
115 RAMP_STATE_DOWN_DRAIN,
116 RAMP_STATE_DOWN_DISABLE,
117 };
118
119 enum _job_type_request_t {
120 JOB_TYPE_REQUEST_MODULE_SUPPORTED,
121 JOB_TYPE_REQUEST_MODULE_ADD,
122 JOB_TYPE_REQUEST_MODULE_DEL,
123 JOB_TYPE_REQUEST_MODULE_REINSTANTIATE,
124 JOB_TYPE_REQUEST_PRESET_LOAD,
125 JOB_TYPE_REQUEST_PRESET_SAVE,
126 JOB_TYPE_REQUEST_BUNDLE_LOAD,
127 JOB_TYPE_REQUEST_BUNDLE_SAVE,
128 JOB_TYPE_REQUEST_DRAIN
129 };
130
131 enum _job_type_reply_t {
132 JOB_TYPE_REPLY_MODULE_SUPPORTED,
133 JOB_TYPE_REPLY_MODULE_ADD,
134 JOB_TYPE_REPLY_MODULE_DEL,
135 JOB_TYPE_REPLY_MODULE_REINSTANTIATE,
136 JOB_TYPE_REPLY_PRESET_LOAD,
137 JOB_TYPE_REPLY_PRESET_SAVE,
138 JOB_TYPE_REPLY_BUNDLE_LOAD,
139 JOB_TYPE_REPLY_BUNDLE_SAVE,
140 JOB_TYPE_REPLY_DRAIN
141 };
142
143 struct _dsp_slave_t {
144 dsp_master_t *dsp_master;
145 sem_t sem;
146 pthread_t thread;
147 };
148
149 struct _dsp_client_t {
150 atomic_int ref_count;
151 unsigned num_sinks;
152 unsigned num_sources;
153 dsp_client_t *sinks [64]; //FIXME
154
155 #if defined(USE_DYNAMIC_PARALLELIZER)
156 unsigned weight;
157 #else
158 int count;
159 unsigned mark;
160 #endif
161 };
162
163 struct _dsp_master_t {
164 dsp_slave_t dsp_slaves [MAX_SLAVES];
165 atomic_bool kill;
166 atomic_bool emergency_exit;
167 sem_t sem;
168 unsigned concurrent;
169 unsigned num_slaves;
170 uint32_t nsamples;
171 };
172
173 struct _job_t {
174 union {
175 job_type_request_t request;
176 job_type_reply_t reply;
177 };
178 union {
179 mod_t *mod;
180 int32_t status;
181 };
182 LV2_URID urn;
183 };
184
185 struct _pool_t {
186 size_t size;
187 void *buf;
188 };
189
190 struct _app_prof_t {
191 struct timespec t0;
192 struct timespec t1;
193 unsigned sum;
194 unsigned min;
195 unsigned max;
196 unsigned count;
197 };
198
199 struct _mod_prof_t {
200 unsigned sum;
201 unsigned min;
202 unsigned max;
203 };
204
205 struct _mod_worker_t {
206 sem_t sem;
207 pthread_t thread;
208 atomic_bool kill;
209 varchunk_t *app_to_worker;
210 varchunk_t *state_to_worker;
211 varchunk_t *app_from_worker;
212 };
213
214 enum _auto_type_t {
215 AUTO_TYPE_NONE = 0,
216 AUTO_TYPE_MIDI,
217 AUTO_TYPE_OSC
218 };
219
220 struct _midi_auto_t {
221 int8_t channel;
222 int8_t controller;
223 };
224
225 struct _osc_auto_t {
226 char path [128]; //TODO how big?
227 };
228
229 struct _auto_t {
230 auto_type_t type;
231 uint32_t index;
232 LV2_URID property;
233 LV2_URID range;
234
235 int src_enabled;
236 int snk_enabled;
237
238 double a;
239 double b;
240 double c;
241 double d;
242
243 double mul;
244 double add;
245
246 bool sync;
247 bool learning;
248
249 union {
250 midi_auto_t midi;
251 osc_auto_t osc;
252 };
253 };
254
255 struct _mod_t {
256 sp_app_t *app;
257 int32_t uid;
258 urn_uuid_t urn_uri;
259 LV2_URID urn;
260 LV2_URID visible;
261 bool disabled;
262
263 bool delete_request;
264 bool needs_bypassing;
265 bool bypassed;
266
267 // worker
268 struct {
269 const LV2_Worker_Interface *iface;
270 LV2_Worker_Schedule schedule;
271 } worker;
272
273 mod_worker_t mod_worker;
274
275 LV2_Worker_Schedule state_worker;
276 LV2_Feature state_feature_list [1];
277 LV2_Feature *state_features [2];
278
279 // system_port
280 bool system_ports;
281
282 // log
283 LV2_Log_Log log;
284
285 // make_path
286 LV2_State_Make_Path make_path;
287
288 struct {
289 const LV2_Inline_Display_Interface *iface;
290 const LV2_Inline_Display_Image_Surface *surf;
291 LV2_Inline_Display queue_draw;
292 atomic_bool draw_queued;
293 atomic_flag lock;
294 bool subscribed;
295 uint32_t counter;
296 uint32_t threshold;
297 } idisp;
298
299 // opts
300 struct {
301 LV2_Options_Option options [7];
302 const LV2_Options_Interface *iface;
303 } opts;
304
305 // state
306 struct {
307 const LV2_State_Interface *iface;
308 } state;
309
310 // features
311 LV2_Feature feature_list [NUM_FEATURES];
312 const LV2_Feature *features [NUM_FEATURES + 1];
313
314 // self
315 const LilvPlugin *plug;
316 LV2_URID plug_urid;
317 LilvInstance *inst;
318 LV2_Handle handle;
319 LilvNodes *presets;
320 char *uri_str;
321
322 // ports
323 unsigned num_ports;
324 port_t *ports;
325
326 pool_t pools [PORT_TYPE_NUM];
327 mod_prof_t prof;
328
329 dsp_client_t dsp_client;
330
331 struct {
332 float x;
333 float y;
334 } pos;
335
336 char alias [ALIAS_MAX];
337 LV2_URID ui;
338 auto_t automations [MAX_AUTOMATIONS];
339 };
340
341 struct _port_driver_t {
342 port_multiplex_cb_t multiplex;
343 port_transfer_cb_t transfer;
344 bool sparse_update;
345 };
346
347 struct _source_t {
348 port_t *port;
349 float gain;
350 struct {
351 float x;
352 float y;
353 } pos;
354
355 // ramping
356 struct {
357 int can;
358 int samples;
359 ramp_state_t state;
360 float value;
361 } ramp;
362 };
363
364 typedef struct _connectable_t connectable_t;
365 typedef struct _control_port_t control_port_t;
366 typedef struct _audio_port_t audio_port_t;
367 typedef struct _cv_port_t cv_port_t;
368 typedef struct _atom_port_t atom_port_t;
369
370 struct _connectable_t {
371 int num_sources;
372 source_t sources [MAX_SOURCES];
373 };
374
375 struct _control_port_t {
376 bool is_integer;
377 bool is_toggled;
378
379 float dflt;
380 float min;
381 float max;
382 float range;
383 float range_1;
384 float last;
385 int32_t i32;
386 float f32;
387 bool auto_dirty;
388
389 float stash;
390 bool stashing;
391 atomic_flag lock;
392 };
393
394 struct _audio_port_t {
395 connectable_t connectable;
396 float last;
397 };
398
399 struct _cv_port_t {
400 connectable_t connectable;
401 float last;
402 };
403
404 struct _atom_port_t {
405 connectable_t connectable;
406 port_buffer_type_t buffer_type; // none, sequence
407 bool patchable; // support patch:Message
408 };
409
410 struct _port_t {
411 mod_t *mod;
412
413 uint32_t index;
414 const char *symbol;
415
416 size_t size;
417 void *base;
418
419 port_type_t type; // audio, CV, control, atom
420 port_direction_t direction; // input, output
421 LV2_URID protocol; // floatProtocol, peakProtocol, atomTransfer, eventTransfer
422 const port_driver_t *driver;
423
424 int subscriptions; // subsriptions reference counter
425
426 // system_port iface
427 struct {
428 system_port_t type;
429 void *data;
430 } sys;
431
432 union {
433 control_port_t control;
434 audio_port_t audio;
435 cv_port_t cv;
436 atom_port_t atom;
437 };
438 };
439
440 struct _sp_app_t {
441 sp_app_driver_t *driver;
442 void *data;
443
444 atomic_bool dirty;
445
446 blocking_state_t block_state;
447 silencing_state_t silence_state;
448 bool load_bundle;
449
450 struct {
451 const char *home;
452 } dir;
453
454 int embedded;
455 LilvWorld *world;
456 const LilvPlugins *plugs;
457
458 reg_t regs;
459 LV2_Atom_Forge forge;
460
461 unsigned num_mods;
462 mod_t *mods [MAX_MODS];
463
464 sp_app_system_source_t system_sources [64]; //FIXME, how many?
465 sp_app_system_sink_t system_sinks [64]; //FIXME, how many?
466
467 LV2_State_Make_Path make_path;
468 LV2_State_Map_Path map_path;
469 LV2_Feature state_feature_list [2];
470 LV2_Feature *state_features [3];
471 #pragma GCC diagnostic push
472 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
473 LV2_URI_Map_Feature uri_to_id;
474 #pragma GCC diagnostic pop
475
476 char *bundle_path;
477 char *bundle_filename;
478 LV2_URID bundle_urn; //FIXME use this instead of bundle_path
479
480 struct {
481 unsigned period_cnt;
482 unsigned bound;
483 unsigned counter;
484 } fps;
485
486 int ramp_samples;
487
488 Sratom *sratom;
489 app_prof_t prof;
490
491 int32_t ncols;
492 int32_t nrows;
493 float nleft;
494
495 dsp_master_t dsp_master;
496
497 LV2_OSC_URID osc_urid;
498
499 cross_clock_t clk_mono;
500 cross_clock_t clk_real;
501
502 struct {
503 float x;
504 float y;
505 } pos;
506
507 int32_t column_enabled;
508 int32_t row_enabled;
509 };
510
511 extern const port_driver_t control_port_driver;
512 extern const port_driver_t audio_port_driver;
513 extern const port_driver_t cv_port_driver;
514 extern const port_driver_t atom_port_driver;
515 extern const port_driver_t seq_port_driver;
516
517 #define PORT_BASE_ALIGNED(PORT) ASSUME_ALIGNED((PORT)->base)
518 #define PORT_SIZE(PORT) ((PORT)->size)
519
520 /*
521 * Debug
522 */
523 int __attribute__((format(printf, 2, 3)))
524 sp_app_log_error(sp_app_t *app, const char *fmt, ...);
525
526 int __attribute__((format(printf, 2, 3)))
527 sp_app_log_note(sp_app_t *app, const char *fmt, ...);
528
529 int __attribute__((format(printf, 2, 3)))
530 sp_app_log_warning(sp_app_t *app, const char *fmt, ...);
531
532 int __attribute__((format(printf, 2, 3)))
533 sp_app_log_trace(sp_app_t *app, const char *fmt, ...);
534
535 /*
536 * UI
537 */
538 static inline void *
__sp_app_to_ui_request(sp_app_t * app,size_t minimum,size_t * maximum)539 __sp_app_to_ui_request(sp_app_t *app, size_t minimum, size_t *maximum)
540 {
541 if(app->driver->to_ui_request)
542 return app->driver->to_ui_request(minimum, maximum, app->data);
543
544 sp_app_log_trace(app, "%s: failed to request buffer\n", __func__);
545 return NULL;
546 }
547 #define _sp_app_to_ui_request(APP, MINIMUM) \
548 ASSUME_ALIGNED(__sp_app_to_ui_request((APP), (MINIMUM), NULL))
549 #define _sp_app_to_ui_request_max(APP, MINIMUM, MAXIMUM) \
550 ASSUME_ALIGNED(__sp_app_to_ui_request((APP), (MINIMUM), (MAXIMUM)))
551
552 static inline void
_sp_app_to_ui_advance(sp_app_t * app,size_t written)553 _sp_app_to_ui_advance(sp_app_t *app, size_t written)
554 {
555 if(app->driver->to_ui_advance)
556 app->driver->to_ui_advance(written, app->data);
557 else
558 sp_app_log_trace(app, "%s: failed to advance buffer\n", __func__);
559 }
560
561 static inline LV2_Atom *
_sp_app_to_ui_request_atom(sp_app_t * app)562 _sp_app_to_ui_request_atom(sp_app_t *app)
563 {
564 size_t maximum;
565 LV2_Atom *atom = _sp_app_to_ui_request_max(app, 4096, &maximum); //FIXME what should minimum be?
566
567 if(atom)
568 lv2_atom_forge_set_buffer(&app->forge, (uint8_t *)atom, maximum);
569 else
570 sp_app_log_trace(app, "%s: failed to request atom\n", __func__);
571
572 return atom;
573 }
574
575 static inline void
_sp_app_to_ui_advance_atom(sp_app_t * app,const LV2_Atom * atom)576 _sp_app_to_ui_advance_atom(sp_app_t *app, const LV2_Atom *atom)
577 {
578 _sp_app_to_ui_advance(app, lv2_atom_total_size(atom));
579 }
580
581 static inline void
_sp_app_to_ui_overflow(sp_app_t * app)582 _sp_app_to_ui_overflow(sp_app_t *app)
583 {
584 sp_app_log_trace(app, "%s: buffer overflow\n", __func__);
585 }
586
587 static inline LV2_Atom *
_sp_request_atom(sp_app_t * app,sp_to_request_t req,void * data)588 _sp_request_atom(sp_app_t *app, sp_to_request_t req, void *data)
589 {
590 size_t maximum;
591 LV2_Atom *atom = req(4096, &maximum, data); //FIXME what should minimum be?
592
593 if(atom)
594 lv2_atom_forge_set_buffer(&app->forge, (uint8_t *)atom, maximum);
595 else
596 sp_app_log_trace(app, "%s: failed to request atom\n", __func__);
597
598 return atom;
599 }
600
601 static inline void
_sp_advance_atom(sp_app_t * app,const LV2_Atom * atom,sp_to_advance_t adv,void * data)602 _sp_advance_atom(sp_app_t *app, const LV2_Atom *atom, sp_to_advance_t adv, void *data)
603 {
604 adv(lv2_atom_total_size(atom), data);
605 }
606
607 /*
608 * Worker
609 */
610
611 static inline void *
__sp_app_to_worker_request(sp_app_t * app,size_t minimum,size_t * maximum)612 __sp_app_to_worker_request(sp_app_t *app, size_t minimum, size_t *maximum)
613 {
614 if(app->driver->to_worker_request)
615 return app->driver->to_worker_request(minimum, maximum, app->data);
616
617 sp_app_log_trace(app, "%s: failed to request buffer\n", __func__);
618 return NULL;
619 }
620 #define _sp_app_to_worker_request(APP, MINIMUM) \
621 ASSUME_ALIGNED(__sp_app_to_worker_request((APP), (MINIMUM), NULL))
622 #define _sp_app_to_worker_request_max(APP, MINIMUM, MAXIMUM) \
623 ASSUME_ALIGNED(__sp_app_to_worker_request((APP), (MINIMUM), (MAXIMUM)))
624
625 static inline void
_sp_app_to_worker_advance(sp_app_t * app,size_t written)626 _sp_app_to_worker_advance(sp_app_t *app, size_t written)
627 {
628 if(app->driver->to_worker_advance)
629 app->driver->to_worker_advance(written, app->data);
630 else
631 sp_app_log_trace(app, "%s: failed to advance buffer\n", __func__);
632 }
633
634 void
635 _sp_app_order(sp_app_t *app);
636
637 void
638 _sp_app_reset(sp_app_t *app);
639
640 void
641 _sp_app_populate(sp_app_t *app);
642
643 /*
644 * State
645 */
646 void
647 _sp_app_state_preset_restore(sp_app_t *app, mod_t *mod, LilvState *const state,
648 bool async);
649
650 int
651 _sp_app_state_preset_load(sp_app_t *app, mod_t *mod, const char *uri, bool async);
652
653 LilvState *
654 _sp_app_state_preset_create(sp_app_t *app, mod_t *mod, const char *bndl);
655
656 int
657 _sp_app_state_preset_save(sp_app_t *app, mod_t *mod, const char *target);
658
659 int
660 _sp_app_state_bundle_save(sp_app_t *app, const char *bundle_path);
661
662 int
663 _sp_app_state_bundle_load(sp_app_t *app, const char *bundle_path);
664
665 /*
666 * Mod
667 */
668 mod_t *
669 _sp_app_mod_add(sp_app_t *app, const char *uri, LV2_URID urn);
670
671 void
672 _sp_app_mod_eject(sp_app_t *app, mod_t *mod);
673
674 int
675 _sp_app_mod_del(sp_app_t *app, mod_t *mod);
676
677 mod_t *
678 _sp_app_mod_get_by_uid(sp_app_t *app, int32_t uid);
679
680 void
681 _sp_app_mod_reinitialize(mod_t *mod);
682
683 LV2_Worker_Status
684 _sp_app_mod_worker_work_sync(mod_t *mod, size_t size, const void *payload);
685
686 void
687 _sp_app_mod_queue_draw(mod_t *mod);
688
689 void
690 _sp_app_mod_reinstantiate(sp_app_t *app, mod_t *mod);
691
692 /*
693 * Port
694 */
695 void
696 _dsp_master_reorder(sp_app_t *app);
697
698 void
699 _sp_app_port_disconnect(sp_app_t *app, port_t *src_port, port_t *snk_port);
700
701 int
702 _sp_app_port_disconnect_request(sp_app_t *app, port_t *src_port, port_t *snk_port,
703 ramp_state_t ramp_state);
704
705 bool
706 _sp_app_port_connected(port_t *src_port, port_t *snk_port, float gain);
707
708 int
709 _sp_app_port_connect(sp_app_t *app, port_t *src_port, port_t *snk_port, float gain);
710
711 int
712 _sp_app_port_silence_request(sp_app_t *app, port_t *src_port, port_t *snk_port,
713 ramp_state_t ramp_state);
714
715 void
716 _sp_app_port_control_stash(port_t *port);
717
718 int
719 _sp_app_port_desilence(sp_app_t *app, port_t *src_port, port_t *snk_port);
720
721 connectable_t *
722 _sp_app_port_connectable(port_t *src_port);
723
724 static inline void
_sp_app_port_spin_lock(control_port_t * control)725 _sp_app_port_spin_lock(control_port_t *control)
726 {
727 while(atomic_flag_test_and_set_explicit(&control->lock, memory_order_acquire))
728 {
729 // spin
730 }
731 }
732
733 static inline bool
_sp_app_port_try_lock(control_port_t * control)734 _sp_app_port_try_lock(control_port_t *control)
735 {
736 return atomic_flag_test_and_set_explicit(&control->lock, memory_order_acquire) == false;
737 }
738
739 static inline void
_sp_app_port_unlock(control_port_t * control)740 _sp_app_port_unlock(control_port_t *control)
741 {
742 atomic_flag_clear_explicit(&control->lock, memory_order_release);
743 }
744
745 /*
746 * Ui
747 */
748 void
749 _sp_app_ui_set_modlist(sp_app_t *app, LV2_URID subj, int32_t seqn);
750
751 void
752 _connection_list_add(sp_app_t *app, const LV2_Atom_Object *obj);
753
754 void
755 _node_list_add(sp_app_t *app, const LV2_Atom_Object *obj);
756
757 void
758 _automation_refresh_mul_add(auto_t *automation);
759
760 void
761 _automation_list_add(sp_app_t *app, const LV2_Atom_Object *obj);
762
763 LV2_Atom_Forge_Ref
764 _sp_app_forge_midi_automation(sp_app_t *app, LV2_Atom_Forge_Frame *frame,
765 mod_t *mod, port_t *port, const auto_t *automation);
766
767 LV2_Atom_Forge_Ref
768 _sp_app_forge_osc_automation(sp_app_t *app, LV2_Atom_Forge_Frame *frame,
769 mod_t *mod, port_t *port, const auto_t *automation);
770
771 #endif
772