LiVES  3.2.0
effects-weed.c
Go to the documentation of this file.
1 // effects-weed.c
2 // LiVES (lives-exe)
3 // (c) G. Finch 2005 - 2020 (salsaman+lives@gmail.com)
4 // Released under the GPL 3 or later
5 // see file ../COPYING for licensing details
6 
7 #include <dlfcn.h>
8 
9 #ifdef __cplusplus
10 #if defined(HAVE_OPENCV) || defined(HAVE_OPENCV4)
11 #ifdef HAVE_OPENCV4
12 #include "opencv4/opencv2/core/core.hpp"
13 #else
14 #include "opencv2/core/core.hpp"
15 #endif
16 using namespace cv;
17 #endif
18 #endif
19 
20 #include "main.h"
21 #include "effects.h"
22 
23 #include "weed-effects-utils.h"
24 
26 
27 #include "callbacks.h"
28 #include "rte_window.h"
29 #include "resample.h"
30 #include "audio.h"
31 #include "ce_thumbs.h"
32 #include "paramwindow.h"
33 
35 
36 static int our_plugin_id = 0;
37 static weed_plant_t *expected_hi = NULL, *expected_pi = NULL;
38 static boolean suspect = FALSE;
39 static char *fxname;
40 static int ncbcalls = 0;
41 
42 static boolean fx_inited = FALSE;
43 
44 struct _procvals {
45  weed_process_f procfunc;
46  weed_plant_t *inst;
47  weed_timecode_t tc;
48  weed_error_t ret;
49  char padding[DEF_ALIGN - ((sizeof(weed_process_f) - sizeof(weed_plant_t *)
50  - sizeof(weed_timecode_t) - sizeof(weed_error_t)) % DEF_ALIGN)];
51 };
52 
53 static weed_plantptr_t statsplant = NULL;
54 
55 static int load_compound_fx(void);
56 
57 
58 #if 0
59 LIVES_LOCAL_INLINE int weed_inst_refs_count(weed_plant_t *inst) {
60  int error;
61  if (!inst) return -1;
62  if (!weed_plant_has_leaf(inst, WEED_LEAF_HOST_REFS)) return 0;
63  return weed_get_int_value(inst, WEED_LEAF_HOST_REFS, &error);
64 }
65 #endif
66 
68 LIVES_GLOBAL_INLINE weed_error_t weed_leaf_copy_or_delete(weed_layer_t *dlayer, const char *key, weed_layer_t *slayer) {
69  if (!weed_plant_has_leaf(slayer, key)) return weed_leaf_delete(dlayer, key);
70  else return weed_leaf_copy(dlayer, key, slayer, key);
71 }
72 
73 
75 #ifdef DEBUG_FILTER_MUTEXES
76  int retval;
77  g_print("trylock of %d\n", key);
78 #endif
79  if (key < 0 || key >= FX_KEYS_MAX) {
80  if (key != -1) {
81  char *msg = lives_strdup_printf("attempted lock of bad fx key %d", key);
82  LIVES_ERROR(msg);
83  lives_free(msg);
84  }
85  return 0;
86  }
87 #ifdef DEBUG_FILTER_MUTEXES
88  retval = pthread_mutex_trylock(&mainw->fx_mutex[key]);
89  g_print("trylock of %d returned %d\n", key, retval);
90  return retval;
91 #endif
92  return pthread_mutex_trylock(&mainw->fx_mutex[key]);
93 }
94 
95 #ifndef DEBUG_FILTER_MUTEXES
97  int ret = filter_mutex_trylock(key);
99  /* if (ret != 0 && !mainw->is_exiting) { */
100  /* /\* char *msg = lives_strdup_printf("attempted double lock of fx key %d, err was %d", key, ret); *\/ */
101  /* /\* LIVES_ERROR(msg); *\/ */
102  /* /\* lives_free(msg); *\/ */
103  /* } */
104  return ret;
105 }
106 
107 
109  if (key >= 0 && key < FX_KEYS_MAX) {
110  int ret = pthread_mutex_unlock(&mainw->fx_mutex[key]);
111  if (ret != 0 && !mainw->is_exiting) {
112  char *msg = lives_strdup_printf("attempted double unlock of fx key %d, err was %d", key, ret);
113  LIVES_ERROR(msg);
114  lives_free(msg);
115  }
116  return ret;
117  } else {
118  if (key != -1) {
119  char *msg = lives_strdup_printf("attempted unlock of bad fx key %d", key);
120  LIVES_ERROR(msg);
121  lives_free(msg);
122  }
123  }
124  return 0;
125 }
126 #endif
127 
128 
130 // filter library functions
131 
132 int num_compound_fx(weed_plant_t *plant) {
133  weed_plant_t *filter;
134 
135  if (WEED_PLANT_IS_FILTER_INSTANCE(plant)) filter = weed_instance_get_filter(plant, TRUE);
136  else filter = plant;
137 
138  if (!weed_plant_has_leaf(filter, WEED_LEAF_HOST_FILTER_LIST)) return 1;
139  return weed_leaf_num_elements(filter, WEED_LEAF_HOST_FILTER_LIST);
140 }
141 
142 
143 boolean has_non_alpha_palette(weed_plant_t *ctmpl, weed_plant_t *filter) {
144  int *plist;
145  int npals = 0;
146  register int i;
147 
148  plist = weed_chantmpl_get_palette_list(filter, ctmpl, &npals);
149  if (!plist) return TRUE;
150  for (i = 0; i < npals; i++) {
151  if (plist[i] == WEED_PALETTE_END) break;
152  if (!weed_palette_is_alpha(plist[i])) {
153  lives_free(plist);
154  return TRUE;
155  }
156  }
157  lives_free(plist);
158  return FALSE;
159 }
160 
161 
162 boolean has_alpha_palette(weed_plant_t *ctmpl, weed_plant_t *filter) {
163  int *plist;
164  int npals = 0;
165  register int i;
166 
167  plist = weed_chantmpl_get_palette_list(filter, ctmpl, &npals);
168  for (i = 0; i < npals; i++) {
169  if (weed_palette_is_alpha(plist[i])) {
170  if (palette == WEED_PALETTE_NONE) continue;
171  lives_free(plist);
172  return TRUE;
173  }
174  }
175  lives_free(plist);
176  return FALSE;
177 }
178 
179 
180 weed_plant_t *weed_instance_get_filter(weed_plant_t *inst, boolean get_compound_parent) {
181  if (get_compound_parent &&
182  (weed_plant_has_leaf(inst, WEED_LEAF_HOST_COMPOUND_CLASS)))
183  return weed_get_plantptr_value(inst, WEED_LEAF_HOST_COMPOUND_CLASS, NULL);
184  return weed_get_plantptr_value(inst, WEED_LEAF_FILTER_CLASS, NULL);
185 }
186 
187 
188 static boolean all_outs_alpha(weed_plant_t *filt, boolean ign_opt) {
189  // check (mandatory) output chans, see if any are non-alpha
190  int nouts;
191  weed_plant_t **ctmpls = weed_filter_get_out_chantmpls(filt, &nouts);
192  if (!nouts) return FALSE;
193  if (!ctmpls[0]) {
194  lives_freep((void **)&ctmpls);
195  return FALSE;
196  }
197  for (int i = 0; i < nouts; i++) {
198  if (ign_opt && weed_chantmpl_is_optional(ctmpls[i])) continue;
199  if (has_non_alpha_palette(ctmpls[i], filt)) {
200  lives_free(ctmpls);
201  return FALSE;
202  }
203  }
204  lives_freep((void **)&ctmpls);
205  return TRUE;
206 }
207 
208 
209 static boolean all_ins_alpha(weed_plant_t *filt, boolean ign_opt) {
210  // check mandatory input chans, see if any are non-alpha
211  // if there are no mandatory inputs, we check optional (even if ign_opt is TRUE)
212  boolean has_mandatory_in = FALSE;
213  int nins;
214  weed_plant_t **ctmpls = weed_filter_get_in_chantmpls(filt, &nins);
215  if (nins == 0) return FALSE;
216  if (!ctmpls[0]) {
217  lives_free(ctmpls);
218  return FALSE;
219  }
220  for (int i = 0; i < nins; i++) {
221  if (ign_opt && weed_chantmpl_is_optional(ctmpls[i])) continue;
222  has_mandatory_in = TRUE;
223  if (has_non_alpha_palette(ctmpls[i], filt)) {
224  lives_free(ctmpls);
225  return FALSE;
226  }
227  }
228  if (!has_mandatory_in) {
229  for (int i = 0; i < nins; i++) {
230  if (has_non_alpha_palette(ctmpls[i], filt)) {
231  lives_free(ctmpls);
232  return FALSE;
233  }
234  }
235  lives_free(ctmpls);
236  return TRUE;
237  }
238  lives_free(ctmpls);
239  return FALSE;
240 }
241 
242 
243 lives_fx_cat_t weed_filter_categorise(weed_plant_t *pl, int in_channels, int out_channels) {
244  weed_plant_t *filt = pl;
245 
246  boolean has_out_params = FALSE;
247  boolean has_in_params = FALSE;
248  boolean all_out_alpha = TRUE;
249  boolean all_in_alpha = TRUE;
250  boolean has_in_alpha = FALSE;
251 
252  int filter_flags;
253 
255 
256  all_out_alpha = all_outs_alpha(filt, TRUE);
257  all_in_alpha = all_ins_alpha(filt, TRUE);
258 
259  filter_flags = weed_get_int_value(filt, WEED_LEAF_FLAGS, NULL);
260  if (weed_plant_has_leaf(filt, WEED_LEAF_OUT_PARAMETER_TEMPLATES)) has_out_params = TRUE;
261  if (weed_plant_has_leaf(filt, WEED_LEAF_IN_PARAMETER_TEMPLATES)) has_in_params = TRUE;
262  if (filter_flags & WEED_FILTER_IS_CONVERTER) return LIVES_FX_CAT_CONVERTER;
263  if (in_channels == 0 && out_channels > 0 && all_out_alpha) return LIVES_FX_CAT_DATA_GENERATOR;
264  if (in_channels == 0 && out_channels > 0) {
266  else if (has_video_chans_out(filt, TRUE)) return LIVES_FX_CAT_AV_GENERATOR;
267  else return LIVES_FX_CAT_AUDIO_GENERATOR;
268  }
269  if (out_channels >= 1 && in_channels >= 1 && (all_in_alpha || has_in_alpha) && !all_out_alpha)
271  if (out_channels >= 1 && all_out_alpha) return LIVES_FX_CAT_ANALYSER;
272  if (out_channels > 1) return LIVES_FX_CAT_SPLITTER;
273 
274  if (in_channels > 2 && out_channels == 1) {
276  }
277  if (in_channels == 2 && out_channels == 1) return LIVES_FX_CAT_TRANSITION;
278  if (in_channels == 1 && out_channels == 1 && !(has_video_chans_in(filt, TRUE)) &&
280  if (in_channels == 1 && out_channels == 1) return LIVES_FX_CAT_EFFECT;
281  if (in_channels > 0 && out_channels == 0 && has_out_params) return LIVES_FX_CAT_ANALYSER;
282  if (in_channels > 0 && out_channels == 0) return LIVES_FX_CAT_TAP;
283  if (in_channels == 0 && out_channels == 0 && has_out_params && has_in_params) return LIVES_FX_CAT_DATA_PROCESSOR;
284  if (in_channels == 0 && out_channels == 0 && has_out_params) return LIVES_FX_CAT_DATA_SOURCE;
285  if (in_channels == 0 && out_channels == 0) return LIVES_FX_CAT_UTILITY;
286  return LIVES_FX_CAT_NONE;
287 }
288 
289 
290 lives_fx_cat_t weed_filter_subcategorise(weed_plant_t *pl, lives_fx_cat_t category, boolean count_opt) {
291  weed_plant_t *filt = pl;
292  boolean has_video_chansi;
293 
295 
296  if (category == LIVES_FX_CAT_COMPOSITOR) count_opt = TRUE;
297 
298  has_video_chansi = has_video_chans_in(filt, count_opt);
299 
300  if (category == LIVES_FX_CAT_TRANSITION) {
301  if (get_transition_param(filt, FALSE) != -1) {
302  if (!has_video_chansi) return LIVES_FX_CAT_AUDIO_TRANSITION;
304  }
306  }
307 
308  if (category == LIVES_FX_CAT_COMPOSITOR && !has_video_chansi) return LIVES_FX_CAT_AUDIO_MIXER;
309  if (category == LIVES_FX_CAT_EFFECT && !has_video_chansi) return LIVES_FX_CAT_AUDIO_EFFECT;
310  if (category == LIVES_FX_CAT_CONVERTER && !has_video_chansi) return LIVES_FX_CAT_AUDIO_VOL;
311 
312  if (category == LIVES_FX_CAT_ANALYSER) {
313  if (!has_video_chansi) return LIVES_FX_CAT_AUDIO_ANALYSER;
315  }
316 
317  return LIVES_FX_CAT_NONE;
318 }
319 
320 
321 int num_alpha_channels(weed_plant_t *filter, boolean out) {
322  // get number of alpha channels (in or out) for filter; including optional
323  weed_plant_t **ctmpls;
324  int count = 0, nchans;
325  register int i;
326 
327  if (out) {
328  ctmpls = weed_filter_get_out_chantmpls(filter, &nchans);
329  if (!ctmpls) return FALSE;
330  for (i = 0; i < nchans; i++) {
331  if (has_non_alpha_palette(ctmpls[i], filter)) continue;
332  count++;
333  }
334  } else {
335  ctmpls = weed_filter_get_in_chantmpls(filter, &nchans);
336  if (!ctmpls) return FALSE;
337  for (i = 0; i < nchans; i++) {
338  if (has_non_alpha_palette(ctmpls[i], filter)) continue;
339  count++;
340  }
341  }
342  lives_freep((void **)&ctmpls);
343  return count;
344 }
345 
346 
348 
349 #define MAX_WEED_INSTANCES 65536
350 
351 // store keys so we now eg, which rte mask entry to xor when deiniting
352 static int fg_generator_key;
353 static int bg_generator_key;
354 
355 // store modes too
356 static int fg_generator_mode;
357 static int bg_generator_mode;
358 
359 // generators to start on playback, because of a problem in libvisual
360 // - we must start generators after starting audio
361 static int bg_gen_to_start;
362 static int fg_gen_to_start;
363 
364 // store the clip, this can sometimes get lost
365 static int fg_generator_clip;
366 
368 
369 static weed_plant_t **weed_filters; // array of filter_classes
370 
371 static LiVESList *weed_fx_sorted_list;
372 
373 // each 'hotkey' controls n instances, selectable as 'modes' or banks
374 static weed_plant_t **key_to_instance[FX_KEYS_MAX];
375 static weed_plant_t **key_to_instance_copy[FX_KEYS_MAX]; // copy for preview during rendering
376 
377 static int *key_to_fx[FX_KEYS_MAX];
378 static int key_modes[FX_KEYS_MAX];
379 
380 static int num_weed_filters;
381 
382 
383 typedef struct {
384  char *string;
385  int32_t hash;
386 } lives_hashentry;
387 
388 #define NHASH_TYPES 8
389 
390 typedef lives_hashentry lives_hashjoint[NHASH_TYPES];
391 
392 // 0 is TF, 1 is TT, 2 is FF, 3 is FT // then possibly repeated with spaces substituted with '_'
393 static lives_hashjoint *hashnames;
394 
395 // per key/mode parameter defaults
396 // *INDENT-OFF*
398 // *INDENT-ON*
399 
401 
402 static weed_plant_t *init_events[FX_KEYS_MAX_VIRTUAL];
403 static void **pchains[FX_KEYS_MAX]; // parameter changes, used during recording (not for rendering)
404 static void *filter_map[FX_KEYS_MAX + 2];
405 static int next_free_key;
406 
408 
409 
411  // this is called during multitrack rendering.
412  // We are rendering, but we want to display the current frame in the preview window
413  // thus we backup our rendering instances, apply the current frame instances, and then restore the rendering instances
414  register int i;
415 
416  for (i = FX_KEYS_MAX_VIRTUAL; i < FX_KEYS_MAX; i++) {
417  key_to_instance_copy[i][0] = key_to_instance[i][0];
418  key_to_instance[i][0] = NULL;
419  }
420 }
421 
422 
424  register int i;
425  for (i = FX_KEYS_MAX_VIRTUAL; i < FX_KEYS_MAX; i++) {
426  key_to_instance[i][0] = key_to_instance_copy[i][0];
427  }
428 }
429 
430 
431 static char *weed_filter_get_type(weed_plant_t *filter, boolean getsub, boolean format) {
432  // return value should be lives_free'd after use
433  char *tmp1, *tmp2, *ret;
435  enabled_in_channels(filter, TRUE),
436  enabled_out_channels(filter, TRUE));
437 
438  lives_fx_cat_t sub = weed_filter_subcategorise(filter, cat, FALSE);
439 
440  if (!getsub || sub == LIVES_FX_CAT_NONE)
441  return lives_fx_cat_to_text(cat, FALSE);
442 
443  tmp1 = lives_fx_cat_to_text(cat, FALSE);
444  tmp2 = lives_fx_cat_to_text(sub, FALSE);
445 
446  if (format) ret = lives_strdup_printf("%s (%s)", tmp1, tmp2);
447  else {
448  if (cat == LIVES_FX_CAT_TRANSITION) ret = lives_strdup_printf("%s - %s", tmp1, tmp2);
449  else ret = lives_strdup_printf("%s", tmp2);
450  }
451 
452  lives_free(tmp1);
453  lives_free(tmp2);
454 
455  return ret;
456 }
457 
458 
459 void update_host_info(weed_plant_t *hinfo) {
460  // set "host_audio_plugin" in the host_info
461  switch (prefs->audio_player) {
462  case AUD_PLAYER_SOX:
463  weed_set_string_value(hinfo, WEED_LEAF_HOST_AUDIO_PLAYER, AUDIO_PLAYER_SOX);
464  break;
465  case AUD_PLAYER_JACK:
466  weed_set_string_value(hinfo, WEED_LEAF_HOST_AUDIO_PLAYER, AUDIO_PLAYER_JACK);
467  break;
468  case AUD_PLAYER_PULSE:
469  weed_set_string_value(hinfo, WEED_LEAF_HOST_AUDIO_PLAYER, AUDIO_PLAYER_PULSE);
470  break;
471  case AUD_PLAYER_NONE:
472  weed_set_string_value(hinfo, WEED_LEAF_HOST_AUDIO_PLAYER, AUDIO_PLAYER_NONE);
473  break;
474  }
475 }
476 
477 
479  // update host_info for all loaded filters
480  // we should call this when any of the relevant data changes
481  // (for now it's just the audio player)
482  weed_plant_t *filter, *hinfo, *pinfo;
483  int i;
484  for (i = 0; i < num_weed_filters; i++) {
485  filter = weed_filters[i];
486  hinfo = weed_get_plantptr_value(filter, WEED_LEAF_HOST_INFO, NULL);
487  if (!hinfo) {
488  pinfo = weed_get_plantptr_value(filter, WEED_LEAF_PLUGIN_INFO, NULL);
489  if (pinfo)
490  hinfo = weed_get_plantptr_value(pinfo, WEED_LEAF_HOST_INFO, NULL);
491  }
492  if (hinfo && WEED_PLANT_IS_HOST_INFO(hinfo)) update_host_info(hinfo);
493  }
494 }
495 
496 
497 static weed_plant_t *get_enabled_channel_inner(weed_plant_t *inst, int which, boolean is_in, boolean audio_only) {
498  // plant is a filter_instance
499  // "which" starts at 0
500  weed_plant_t **channels = NULL;
501  weed_plant_t *retval, *ctmpl = NULL;
502 
503  int nchans = 3;
504 
505  int i = 0;
506 
507  if (!WEED_PLANT_IS_FILTER_INSTANCE(inst)) return NULL;
508 
509  if (is_in) {
510  channels = weed_instance_get_in_channels(inst, &nchans);
511  } else {
512  channels = weed_instance_get_out_channels(inst, &nchans);
513  }
514 
515  if (!nchans) return NULL;
516 
517  while (1) {
518  if (weed_get_boolean_value(channels[i], WEED_LEAF_DISABLED, NULL) == WEED_FALSE) {
519  if (audio_only) ctmpl = weed_channel_get_template(channels[i]);
520  if (!audio_only || (audio_only && weed_chantmpl_is_audio(ctmpl) == WEED_TRUE)) {
521  which--;
522  }
523  }
524  if (which < 0) break;
525  if (++i >= nchans) {
526  lives_free(channels);
527  return NULL;
528  }
529  }
530  retval = channels[i];
531  lives_freep((void **)&channels);
532  return retval;
533 }
534 
535 
536 weed_plant_t *get_enabled_channel(weed_plant_t *inst, int which, boolean is_in) {
537  // count audio and video channels
538  return get_enabled_channel_inner(inst, which, is_in, FALSE);
539 }
540 
541 
542 weed_plant_t *get_enabled_audio_channel(weed_plant_t *inst, int which, boolean is_in) {
543  // count only audio channels
544  return get_enabled_channel_inner(inst, which, is_in, TRUE);
545 }
546 
547 
548 weed_plant_t *get_mandatory_channel(weed_plant_t *filter, int which, boolean is_in) {
549  // plant is a filter_class
550  // "which" starts at 0
551  weed_plant_t **ctmpls;
552  weed_plant_t *retval;
553  register int i = 0;
554 
555  if (!WEED_PLANT_IS_FILTER_CLASS(filter)) return NULL;
556 
557  if (is_in) ctmpls = weed_filter_get_in_chantmpls(filter, NULL);
558  else ctmpls = weed_filter_get_out_chantmpls(filter, NULL);
559 
560  if (!ctmpls) return NULL;
561  while (which > -1) {
562  if (!weed_chantmpl_is_optional(ctmpls[i])) which--;
563  i++;
564  }
565  retval = ctmpls[i - 1];
566  lives_free(ctmpls);
567  return retval;
568 }
569 
570 
571 LIVES_GLOBAL_INLINE boolean weed_instance_is_resizer(weed_plant_t *inst) {
572  weed_plant_t *ftmpl = weed_instance_get_filter(inst, TRUE);
573  return weed_filter_is_resizer(ftmpl);
574 }
575 
576 
577 boolean is_audio_channel_in(weed_plant_t *inst, int chnum) {
578  int nchans = 0;
579  weed_plant_t **in_chans;
580  weed_plant_t *ctmpl;
581 
582  in_chans = weed_instance_get_in_channels(inst, &nchans);
583  if (nchans <= chnum) {
584  lives_freep((void **)&in_chans);
585  return FALSE;
586  }
587 
588  ctmpl = weed_channel_get_template(in_chans[chnum]);
589  lives_free(in_chans);
590 
591  return (weed_chantmpl_is_audio(ctmpl) == WEED_TRUE);
592 }
593 
594 
595 weed_plant_t *get_audio_channel_in(weed_plant_t *inst, int achnum) {
596  // get nth audio channel in (not counting video channels)
597  int nchans = 0;
598  weed_plant_t **in_chans;
599  weed_plant_t *ctmpl, *achan;
600 
601  in_chans = weed_instance_get_in_channels(inst, &nchans);
602  if (!in_chans) return NULL;
603 
604  for (register int i = 0; i < nchans; i++) {
605  ctmpl = weed_channel_get_template(in_chans[i]);
606  if (weed_chantmpl_is_audio(ctmpl)) {
607  if (achnum-- == 0) {
608  achan = in_chans[i];
609  lives_free(in_chans);
610  return achan;
611  }
612  }
613  }
614 
615  lives_freep((void **)&in_chans);
616  return NULL;
617 }
618 
619 
620 boolean has_video_chans_in(weed_plant_t *filter, boolean count_opt) {
621  // TODO: we should probably distinguish between enabled and disabled optional channels
622  int nchans = 0;
623  weed_plant_t **in_ctmpls;
624 
625  in_ctmpls = weed_filter_get_in_chantmpls(filter, &nchans);
626  if (!in_ctmpls) return FALSE;
627 
628  for (register int i = 0; i < nchans; i++) {
629  if (!count_opt && weed_chantmpl_is_optional(in_ctmpls[i])) continue;
630  if (weed_chantmpl_is_audio(in_ctmpls[i])) continue;
631  lives_free(in_ctmpls);
632  return TRUE;
633  }
634  lives_freep((void **)&in_ctmpls);
635 
636  return FALSE;
637 }
638 
639 
640 boolean has_audio_chans_in(weed_plant_t *filter, boolean count_opt) {
641  int nchans = 0;
642  weed_plant_t **in_ctmpls = weed_filter_get_in_chantmpls(filter, &nchans);
643  if (!in_ctmpls) return FALSE;
644  for (int i = 0; i < nchans; i++) {
645  if (!count_opt && weed_chantmpl_is_optional(in_ctmpls[i])) continue;
646  if (weed_chantmpl_is_audio(in_ctmpls[i])) {
647  lives_free(in_ctmpls);
648  return TRUE;
649  }
650  }
651  lives_freep((void **)&in_ctmpls);
652  return FALSE;
653 }
654 
655 
656 boolean is_audio_channel_out(weed_plant_t *inst, int chnum) {
657  weed_plant_t **out_chans;
658  weed_plant_t *ctmpl;
659  int nchans = 0;
660 
661  out_chans = weed_instance_get_in_channels(inst, &nchans);
662  if (nchans <= chnum) {
663  lives_freep((void **)&out_chans);
664  return FALSE;
665  }
666  ctmpl = weed_channel_get_template(out_chans[chnum]);
667  lives_free(out_chans);
668 
669  if (weed_chantmpl_is_audio(ctmpl) == WEED_TRUE) {
670  return TRUE;
671  }
672  return FALSE;
673 }
674 
675 
676 boolean has_video_chans_out(weed_plant_t *filter, boolean count_opt) {
677  weed_plant_t **out_ctmpls;
678  int nchans = 0;
679 
680  out_ctmpls = weed_filter_get_out_chantmpls(filter, &nchans);
681  if (!out_ctmpls) return FALSE;
682 
683  for (int i = 0; i < nchans; i++) {
684  if (!count_opt && weed_chantmpl_is_optional(out_ctmpls[i])) continue;
685  if (weed_chantmpl_is_audio(out_ctmpls[i]) == WEED_TRUE) continue;
686  lives_free(out_ctmpls);
687  return TRUE;
688  }
689  lives_freep((void **)&out_ctmpls);
690 
691  return FALSE;
692 }
693 
694 
695 boolean has_audio_chans_out(weed_plant_t *filter, boolean count_opt) {
696  weed_plant_t **out_ctmpls;
697  int nchans = 0;
698 
699  out_ctmpls = weed_filter_get_out_chantmpls(filter, &nchans);
700  if (!out_ctmpls) return FALSE;
701 
702  for (int i = 0; i < nchans; i++) {
703  if (!count_opt && weed_chantmpl_is_optional(out_ctmpls[i])) continue;
704  if (weed_chantmpl_is_audio(out_ctmpls[i]) == WEED_FALSE) continue;
705  lives_free(out_ctmpls);
706  return TRUE;
707  }
708  lives_freep((void **)&out_ctmpls);
709 
710  return FALSE;
711 }
712 
713 
714 boolean is_pure_audio(weed_plant_t *plant, boolean count_opt) {
715  weed_plant_t *filter = plant;
716  if (WEED_PLANT_IS_FILTER_INSTANCE(plant)) filter = weed_instance_get_filter(plant, FALSE);
717 
718  if ((has_audio_chans_in(filter, count_opt) || has_audio_chans_out(filter, count_opt)) &&
719  !has_video_chans_in(filter, count_opt) && !has_video_chans_out(filter, count_opt)) return TRUE;
720  return FALSE;
721 }
722 
723 
724 boolean weed_parameter_has_variable_elements_strict(weed_plant_t *inst, weed_plant_t *ptmpl) {
726  weed_plant_t **chans, *ctmpl;
727  int flags = weed_get_int_value(ptmpl, WEED_LEAF_FLAGS, NULL);
728  int nchans;
729 
730  if (flags & WEED_PARAMETER_VARIABLE_SIZE) return TRUE;
731 
732  if (!inst) return FALSE;
733 
734  if (!(flags & WEED_PARAMETER_VALUE_PER_CHANNEL)) return FALSE;
735 
736  if ((nchans = weed_leaf_num_elements(inst, WEED_LEAF_IN_CHANNELS)) == 0)
737  return FALSE;
738 
739  chans = weed_get_plantptr_array(inst, WEED_LEAF_IN_CHANNELS, NULL);
740 
741  for (int i = 0; i < nchans; i++) {
742  if (weed_get_boolean_value(chans[i], WEED_LEAF_DISABLED, NULL) == WEED_TRUE) continue; //ignore disabled channels
743  ctmpl = weed_get_plantptr_value(chans[i], WEED_LEAF_TEMPLATE, NULL);
744  if (weed_plant_has_leaf(ctmpl, WEED_LEAF_MAX_REPEATS) && weed_get_int_value(ctmpl, WEED_LEAF_MAX_REPEATS, NULL) != 1) {
745  lives_free(chans);
746  return TRUE;
747  }
748  }
749 
750  lives_freep((void **)&chans);
751  return FALSE;
752 }
753 
754 
779 static void create_filter_map(uint64_t rteval) {
780  int count = 0, i;
781  weed_plant_t *inst;
782 
783  for (i = 0; i < FX_KEYS_MAX_VIRTUAL; i++) {
784  if (rteval & (GU641 << i) && (inst = weed_instance_obtain(i, key_modes[i])) != NULL) {
785  if (enabled_in_channels(inst, FALSE) > 0) {
786  filter_map[count++] = init_events[i];
787  }
788  weed_instance_unref(inst);
789  }
790  }
791  filter_map[count] = NULL;
792 }
793 
794 
803 weed_plant_t *add_filter_deinit_events(weed_plant_t *event_list) {
804  // should be called with mainw->event_list_mutex unlocked !
805  int i;
806  boolean needs_filter_map = FALSE;
807  weed_timecode_t last_tc = 0;
808 
809  if (event_list) last_tc = get_event_timecode(get_last_event(event_list));
810 
811  for (i = 0; i < FX_KEYS_MAX_VIRTUAL; i++) {
812  if (init_events[i]) {
813  event_list = append_filter_deinit_event(event_list, last_tc, init_events[i], pchains[i]);
814  init_events[i] = NULL;
815  // no freep !
816  if (pchains[i]) lives_free(pchains[i]);
817  pchains[i] = NULL;
818  needs_filter_map = TRUE;
819  }
820  }
821 
823  create_filter_map(mainw->rte);
824  if (needs_filter_map) {
825  pthread_mutex_lock(&mainw->event_list_mutex);
826  event_list = append_filter_map_event(event_list, last_tc, filter_map);
827  pthread_mutex_unlock(&mainw->event_list_mutex);
828  }
829  return event_list;
830 }
831 
832 
839 weed_plant_t *add_filter_init_events(weed_plant_t *event_list, weed_timecode_t tc) {
840  int i;
841  weed_plant_t *inst;
842  int fx_idx, ntracks;
843 
844  for (i = 0; i < FX_KEYS_MAX_VIRTUAL; i++) {
845  if ((inst = weed_instance_obtain(i, key_modes[i])) != NULL) {
846  if (enabled_in_channels(inst, FALSE) > 0) {
847  event_list = append_filter_init_event(event_list, tc, (fx_idx = key_to_fx[i][key_modes[i]]), -1, i, inst);
848  init_events[i] = get_last_event(event_list);
849  ntracks = weed_leaf_num_elements(init_events[i], WEED_LEAF_IN_TRACKS);
850  pchains[i] = filter_init_add_pchanges(event_list, inst, init_events[i], ntracks, 0);
851  }
852  weed_instance_unref(inst);
853  }
854  }
856  create_filter_map(mainw->rte);
857  if (filter_map[0]) event_list = append_filter_map_event(event_list, tc, filter_map);
858  return event_list;
859 }
860 
861 
868 int best_palette_match(int *palette_list, int num_palettes, int palette) {
869  int best_palette = palette_list[0];
870  boolean has_alpha, is_rgb, is_alpha, is_yuv, mismatch;
871 
872  if (palette == best_palette) return palette;
873 
874  has_alpha = weed_palette_has_alpha(palette);
875  is_rgb = weed_palette_is_rgb(palette);
876  is_alpha = weed_palette_is_alpha(palette);
877  is_yuv = !is_alpha && !is_rgb;
878 
879  for (int i = 0; (num_palettes > 0 && i < num_palettes) || (num_palettes <= 0 && palette_list[i] != WEED_PALETTE_END); i++) {
880  if (palette_list[i] == palette) {
882  return palette;
883  }
884 
885  if ((weed_palette_is_rgb(best_palette) && !is_rgb) || (weed_palette_is_alpha(best_palette) && !is_alpha)
886  || (weed_palette_is_yuv(best_palette) && !is_yuv)) mismatch = TRUE;
887  else mismatch = FALSE;
888 
889  switch (palette_list[i]) {
890  case WEED_PALETTE_RGB24:
891  case WEED_PALETTE_BGR24:
892  if (palette == WEED_PALETTE_RGB24 || palette == WEED_PALETTE_BGR24) return palette_list[i];
893 
894  if ((is_rgb || mismatch) && (!weed_palette_has_alpha(palette) || best_palette == WEED_PALETTE_RGBAFLOAT ||
895  best_palette == WEED_PALETTE_RGBFLOAT)
896  && !(best_palette == WEED_PALETTE_RGB24 || best_palette == WEED_PALETTE_BGR24))
897  best_palette = palette_list[i];
898  break;
899  case WEED_PALETTE_RGBA32:
900  case WEED_PALETTE_BGRA32:
901  if (palette == WEED_PALETTE_RGBA32 || palette == WEED_PALETTE_BGRA32) best_palette = palette_list[i];
902  case WEED_PALETTE_ARGB32:
903  if ((is_rgb || mismatch) && (has_alpha || best_palette == WEED_PALETTE_RGBFLOAT
904  || best_palette == WEED_PALETTE_RGBAFLOAT)
905  && best_palette != WEED_PALETTE_RGBA32
906  && !(palette == WEED_PALETTE_ARGB32 && best_palette == WEED_PALETTE_BGRA32))
907  best_palette = palette_list[i];
908  break;
909  case WEED_PALETTE_RGBAFLOAT:
910  if ((is_rgb || mismatch) && best_palette == WEED_PALETTE_RGBFLOAT && has_alpha)
911  best_palette = WEED_PALETTE_RGBAFLOAT;
912  break;
913  case WEED_PALETTE_RGBFLOAT:
914  if ((is_rgb || mismatch) && best_palette == WEED_PALETTE_RGBAFLOAT && !has_alpha)
915  best_palette = WEED_PALETTE_RGBFLOAT;
916  break;
917  // yuv
918  case WEED_PALETTE_YUVA4444P:
919  if (is_yuv && has_alpha) return WEED_PALETTE_YUVA4444P;
920  if ((mismatch || is_yuv)
921  && (has_alpha || (best_palette != WEED_PALETTE_YUV444P && best_palette != WEED_PALETTE_YUV888)))
922  best_palette = WEED_PALETTE_YUVA4444P;
923  break;
924  case WEED_PALETTE_YUV444P:
925  if (is_yuv && !has_alpha) return WEED_PALETTE_YUV444P;
926  if ((mismatch || is_yuv)
927  && (!has_alpha || (best_palette != WEED_PALETTE_YUVA4444P && best_palette != WEED_PALETTE_YUVA8888)))
928  best_palette = WEED_PALETTE_YUV444P;
929  break;
930  case WEED_PALETTE_YUVA8888:
931  if ((mismatch || is_yuv) && (has_alpha || (best_palette != WEED_PALETTE_YUV444P && best_palette != WEED_PALETTE_YUV888)))
932  best_palette = WEED_PALETTE_YUVA8888;
933  break;
934  case WEED_PALETTE_YUV888:
935  if ((mismatch || is_yuv)
936  && (!has_alpha || (best_palette != WEED_PALETTE_YUVA4444P && best_palette != WEED_PALETTE_YUVA8888)))
937  best_palette = WEED_PALETTE_YUV888;
938  break;
939  case WEED_PALETTE_YUV422P:
940  case WEED_PALETTE_UYVY:
941  case WEED_PALETTE_YUYV:
942  if ((mismatch || is_yuv) && (best_palette != WEED_PALETTE_YUVA4444P && best_palette != WEED_PALETTE_YUV444P
943  && best_palette != WEED_PALETTE_YUVA8888 && best_palette != WEED_PALETTE_YUV888))
944  best_palette = palette_list[i];
945  break;
946  case WEED_PALETTE_YUV420P:
947  case WEED_PALETTE_YVU420P:
948  if ((mismatch || is_yuv) && (best_palette == WEED_PALETTE_YUV411 || weed_palette_is_alpha(best_palette)))
949  best_palette = palette_list[i];
950  break;
951  default:
952  if (weed_palette_is_alpha(best_palette)) {
953  if (palette_list[i] == WEED_PALETTE_YUV411 && !is_alpha) best_palette = WEED_PALETTE_A8;
954  if (palette_list[i] == WEED_PALETTE_A8) best_palette = WEED_PALETTE_A8;
955  if (palette_list[i] == WEED_PALETTE_A1 && (best_palette != WEED_PALETTE_A8))
956  best_palette = WEED_PALETTE_A1;
957  }
958  break;
959  }
960  }
961 
962 #ifdef DEBUG_PALETTES
963  lives_printerr("Debug: best palette for %d is %d\n", palette, best_palette);
964 #endif
965 
966  return best_palette;
967 }
968 
969 
970 static boolean get_fixed_channel_size(weed_plant_t *template, int *width, int *height) {
971  weed_size_t nwidths = weed_leaf_num_elements(template, WEED_LEAF_WIDTH);
972  weed_size_t nheights = weed_leaf_num_elements(template, WEED_LEAF_HEIGHT);
973  int *heights, *widths;
974  int defined = 0;
975  int oheight = 0, owidth = 0;
976  int i;
977  if (!width || nwidths == 0) defined++;
978  else {
979  if (nwidths == 1) {
980  *width = weed_get_int_value(template, WEED_LEAF_WIDTH, NULL);
981  defined++;
982  }
983  }
984 
985  if (!height || nheights == 0) defined++;
986  else {
987  if (nheights == 1) {
988  *height = weed_get_int_value(template, WEED_LEAF_HEIGHT, NULL);
989  defined++;
990  }
991  }
992  if (defined == 2) return TRUE;
993 
995  if (nwidths != nheights) {
997  return FALSE;
998  }
999 
1000  widths = weed_get_int_array(template, WEED_LEAF_WIDTH, NULL);
1001  heights = weed_get_int_array(template, WEED_LEAF_HEIGHT, NULL);
1002 
1003  if (width) owidth = *width;
1004  if (height) oheight = *height;
1005 
1006  for (i = 0; i < nwidths; i++) {
1007  defined = 0;
1008  // these should be in ascending order, so we'll just quit when both values are greater
1009  if (!width) defined++;
1010  else {
1011  *width = widths[i];
1012  if (*width >= owidth) defined++;
1013  }
1014  if (!height) defined++;
1015  else {
1016  *height = heights[i];
1017  if (*height >= oheight) defined++;
1018  }
1019  if (defined == 2) return TRUE;
1020  }
1021  return FALSE;
1022 }
1023 
1024 
1025 #define MIN_CHAN_WIDTH 4
1026 #define MIN_CHAN_HEIGHT 4
1027 
1028 #define MAX_CHAN_WIDTH 16384
1029 #define MAX_CHAN_HEIGHT 16384
1030 
1046 static void set_channel_size(weed_plant_t *filter, weed_plant_t *channel, int width, int height) {
1047  weed_plant_t *chantmpl = weed_channel_get_template(channel);
1048  boolean check_ctmpl = FALSE;
1049  int max, min;
1050  int filter_flags = weed_filter_get_flags(filter);
1051 
1052  if (width < MIN_CHAN_WIDTH) width = MIN_CHAN_WIDTH;
1053  if (width > MAX_CHAN_WIDTH) width = MAX_CHAN_WIDTH;
1054  if (height < MIN_CHAN_HEIGHT) height = MIN_CHAN_HEIGHT;
1055  if (height > MAX_CHAN_HEIGHT) height = MAX_CHAN_HEIGHT;
1056 
1057  if (filter_flags & WEED_FILTER_CHANNEL_SIZES_MAY_VARY) {
1058  check_ctmpl = TRUE;
1059  }
1060 
1061  if (check_ctmpl && weed_plant_has_leaf(chantmpl, WEED_LEAF_WIDTH)) {
1062  get_fixed_channel_size(chantmpl, &width, &height);
1063  } else {
1064  if (weed_plant_has_leaf(filter, WEED_LEAF_WIDTH)) {
1065  get_fixed_channel_size(filter, &width, &height);
1066  } else {
1067  if (weed_plant_has_leaf(chantmpl, WEED_LEAF_HOST_WIDTH)) {
1068  width = weed_get_int_value(chantmpl, WEED_LEAF_HOST_WIDTH, NULL);
1069  }
1070  if (weed_plant_has_leaf(filter, WEED_LEAF_HSTEP)) {
1071  width = ALIGN_CEIL(width, weed_get_int_value(filter, WEED_LEAF_HSTEP, NULL));
1072  }
1073  if (width < MIN_CHAN_WIDTH) width = MIN_CHAN_WIDTH;
1074  if (width > MAX_CHAN_WIDTH) width = MAX_CHAN_WIDTH;
1075  if (check_ctmpl && weed_plant_has_leaf(chantmpl, WEED_LEAF_MAXWIDTH)) {
1076  max = weed_get_int_value(chantmpl, WEED_LEAF_MAXWIDTH, NULL);
1077  if (max > 0 && width > max) width = max;
1078  } else if (weed_plant_has_leaf(filter, WEED_LEAF_MAXWIDTH)) {
1079  max = weed_get_int_value(filter, WEED_LEAF_MAXWIDTH, NULL);
1080  if (width > max) width = max;
1081  }
1082  if (check_ctmpl && weed_plant_has_leaf(chantmpl, WEED_LEAF_MINWIDTH)) {
1083  min = weed_get_int_value(chantmpl, WEED_LEAF_MINWIDTH, NULL);
1084  if (min > 0 && width < min) width = min;
1085  } else if (weed_plant_has_leaf(filter, WEED_LEAF_MINWIDTH)) {
1086  min = weed_get_int_value(filter, WEED_LEAF_MINWIDTH, NULL);
1087  if (width < min) width = min;
1088  }
1089  }
1090  }
1091 
1092  if (width < MIN_CHAN_WIDTH) width = MIN_CHAN_WIDTH;
1093  if (width > MAX_CHAN_WIDTH) width = MAX_CHAN_WIDTH;
1094 
1095  width = (width >> 1) << 1;
1096  weed_set_int_value(channel, WEED_LEAF_WIDTH, width);
1097 
1098  if (check_ctmpl && weed_plant_has_leaf(chantmpl, WEED_LEAF_HEIGHT)) {
1099  get_fixed_channel_size(chantmpl, &width, &height);
1100  } else {
1101  if (weed_plant_has_leaf(filter, WEED_LEAF_HEIGHT)) {
1102  get_fixed_channel_size(filter, &width, &height);
1103  } else {
1104  if (weed_plant_has_leaf(chantmpl, WEED_LEAF_HOST_HEIGHT)) {
1105  height = weed_get_int_value(chantmpl, WEED_LEAF_HOST_HEIGHT, NULL);
1106  }
1107  if (weed_plant_has_leaf(filter, WEED_LEAF_VSTEP)) {
1108  height = ALIGN_CEIL(height, weed_get_int_value(filter, WEED_LEAF_VSTEP, NULL));
1109  }
1110  if (height < MIN_CHAN_HEIGHT) height = MIN_CHAN_HEIGHT;
1111  if (height > MAX_CHAN_HEIGHT) height = MAX_CHAN_HEIGHT;
1112  if (check_ctmpl && weed_plant_has_leaf(chantmpl, WEED_LEAF_MAXHEIGHT)) {
1113  max = weed_get_int_value(chantmpl, WEED_LEAF_MAXHEIGHT, NULL);
1114  if (max > 0 && height > max) height = max;
1115  } else if (weed_plant_has_leaf(filter, WEED_LEAF_MAXHEIGHT)) {
1116  max = weed_get_int_value(filter, WEED_LEAF_MAXHEIGHT, NULL);
1117  if (height > max) height = max;
1118  }
1119  if (check_ctmpl && weed_plant_has_leaf(chantmpl, WEED_LEAF_MINHEIGHT)) {
1120  min = weed_get_int_value(chantmpl, WEED_LEAF_MINHEIGHT, NULL);
1121  if (min > 0 && height < min) height = min;
1122  } else if (weed_plant_has_leaf(filter, WEED_LEAF_MINHEIGHT)) {
1123  min = weed_get_int_value(filter, WEED_LEAF_MINHEIGHT, NULL);
1124  if (height < min) height = min;
1125  }
1126  }
1127  }
1128 
1129  if (height < MIN_CHAN_HEIGHT) height = MIN_CHAN_HEIGHT;
1130  if (height > MAX_CHAN_HEIGHT) height = MAX_CHAN_HEIGHT;
1131  height = (height >> 1) << 1;
1132  weed_set_int_value(channel, WEED_LEAF_HEIGHT, height);
1133 }
1134 
1135 
1136 int weed_flagset_array_count(weed_plant_t **array, boolean set_readonly) {
1137  register int i;
1138  for (i = 0; array[i]; i++) {
1139  if (set_readonly) weed_add_plant_flags(array[i], WEED_FLAG_IMMUTABLE | WEED_FLAG_UNDELETABLE, "plugin_");
1140  }
1141  return i;
1142 }
1143 
1144 
1148 char *cd_to_plugin_dir(weed_plant_t *filter) {
1149  weed_plant_t *plugin_info;
1150  char *ppath;
1151  char *ret;
1152  if (WEED_PLANT_IS_PLUGIN_INFO(filter)) plugin_info = filter; // on shutdown the filters are freed.
1153  else plugin_info = weed_get_plantptr_value(filter, WEED_LEAF_PLUGIN_INFO, NULL);
1154  ppath = weed_get_string_value(plugin_info, WEED_LEAF_HOST_PLUGIN_PATH, NULL);
1155  ret = lives_get_current_dir();
1156  // allow this to fail -it's not that important - it just means any plugin data files wont be found
1157  // besides, we dont want to show warnings at 50 fps
1158  lives_chdir(ppath, TRUE);
1159  lives_free(ppath);
1160  return ret;
1161 }
1162 
1163 
1164 LIVES_GLOBAL_INLINE weed_plant_t *get_next_compound_inst(weed_plant_t *inst) {
1165  return weed_get_plantptr_value(inst, WEED_LEAF_HOST_NEXT_INSTANCE, NULL);
1166 }
1167 
1168 
1169 lives_filter_error_t weed_reinit_effect(weed_plant_t *inst, boolean reinit_compound) {
1170  // call with filter_mutex unlocked
1171  weed_plant_t *filter, *orig_inst = inst;
1172  lives_filter_error_t filter_error = FILTER_SUCCESS;
1173  char *cwd;
1174  boolean deinit_first = FALSE;
1175  weed_error_t retval;
1176  int key = -1;
1177 
1178  weed_instance_ref(inst);
1179 
1180  if (weed_plant_has_leaf(inst, WEED_LEAF_HOST_KEY)) key = weed_get_int_value(inst, WEED_LEAF_HOST_KEY, NULL);
1181 
1182  if (key != -1) {
1183  weed_plant_t *gui;
1184  filter_mutex_lock(key);
1185  gui = weed_instance_get_gui(inst, FALSE);
1186  if (weed_get_int_value(gui, WEED_LEAF_EASE_OUT, NULL) > 0) {
1187  // plugin is easing, so we need to deinit it
1188  uint64_t new_rte = GU641 << (key);
1189  if (mainw->rte & new_rte) mainw->rte ^= new_rte;
1190  // WEED_LEAF_EASE_OUT exists, so it'll get deinited right away
1191  weed_deinit_effect(key);
1192  weed_instance_unref(inst);
1193  filter_mutex_unlock(key);
1195  }
1196  }
1197 
1198  mainw->blend_palette = WEED_PALETTE_END;
1199 
1200 reinit:
1201 
1202  filter = weed_instance_get_filter(inst, FALSE);
1203 
1204  if (weed_get_boolean_value(inst, WEED_LEAF_HOST_INITED, NULL) == WEED_TRUE) deinit_first = TRUE;
1205 
1206  if (deinit_first) {
1207  weed_call_deinit_func(inst);
1208  }
1209 
1210  if (weed_plant_has_leaf(filter, WEED_LEAF_INIT_FUNC)) {
1211  weed_init_f init_func = (weed_init_f)weed_get_funcptr_value(filter, WEED_LEAF_INIT_FUNC, NULL);
1212  cwd = cd_to_plugin_dir(filter);
1213  if (init_func) {
1214  lives_rfx_t *rfx;
1215  retval = (*init_func)(inst);
1216  if (fx_dialog[1]
1217  || (mainw->multitrack && mainw->multitrack->current_rfx
1218  && mainw->multitrack->poly_state == POLY_PARAMS)) {
1219  // redraw GUI if necessary
1220  if (fx_dialog[1]) rfx = fx_dialog[1]->rfx;
1221  else rfx = mainw->multitrack->current_rfx;
1222  if (rfx->source_type == LIVES_RFX_SOURCE_WEED && rfx->source == inst) {
1223  // update any text params with focus
1224  if (mainw->textwidget_focus && LIVES_IS_WIDGET_OBJECT(mainw->textwidget_focus)) {
1225  // make sure text widgets are updated if they activate the default
1226  LiVESWidget *textwidget =
1227  (LiVESWidget *)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(mainw->textwidget_focus), TEXTWIDGET_KEY);
1228  weed_set_boolean_value(inst, WEED_LEAF_HOST_REINITING, WEED_TRUE);
1229  after_param_text_changed(textwidget, rfx);
1230  weed_leaf_delete(inst, WEED_LEAF_HOST_REINITING);
1231  mainw->textwidget_focus = NULL;
1232  }
1233 
1234  // do updates from "gui"
1235  //rfx_params_free(rfx);
1236  //lives_freep((void **)&rfx->params);
1237  if (rfx->num_params > 0 && !rfx->params)
1238  rfx->params = weed_params_to_rfx(rfx->num_params, inst, FALSE);
1239  if (fx_dialog[1]) {
1240  int keyw = fx_dialog[1]->key;
1241  int modew = fx_dialog[1]->mode;
1242  update_widget_vis(NULL, keyw, modew);
1243  } else update_widget_vis(rfx, -1, -1);
1244  filter_error = FILTER_INFO_REDRAWN;
1245  }
1246  }
1247 
1248  if (retval != WEED_SUCCESS) {
1249  weed_instance_unref(orig_inst);
1250  lives_chdir(cwd, FALSE);
1251  lives_free(cwd);
1252  if (key != -1) filter_mutex_unlock(key);
1254  }
1255 
1256  // need to set this before calling deinit
1257  weed_set_boolean_value(inst, WEED_LEAF_HOST_INITED, WEED_TRUE);
1258  }
1259  if (!deinit_first) {
1260  weed_call_deinit_func(inst);
1261  }
1262 
1263  lives_chdir(cwd, FALSE);
1264  lives_free(cwd);
1265  if (filter_error != FILTER_INFO_REDRAWN) filter_error = FILTER_INFO_REINITED;
1266  }
1267 
1268  if (deinit_first) {
1269  weed_set_boolean_value(inst, WEED_LEAF_HOST_INITED, WEED_TRUE);
1270  weed_set_boolean_value(inst, WEED_LEAF_HOST_UNUSED, WEED_TRUE);
1271  } else {
1272  weed_set_boolean_value(inst, WEED_LEAF_HOST_INITED, WEED_FALSE);
1273  weed_leaf_delete(inst, WEED_LEAF_HOST_UNUSED);
1274  }
1275 
1276  if (reinit_compound) {
1277  inst = get_next_compound_inst(inst);
1278  if (inst) goto reinit;
1279  }
1280 
1281  if (key != -1) filter_mutex_unlock(key);
1282  weed_instance_unref(orig_inst);
1283  mainw->blend_palette = WEED_PALETTE_END;
1284  return filter_error;
1285 }
1286 
1287 
1288 void weed_reinit_all(void) {
1289  // reinit all effects on playback start
1290  lives_filter_error_t retval;
1291  weed_plant_t *instance, *last_inst, *next_inst;
1292  register int i;
1293 
1294  for (i = 0; i < FX_KEYS_MAX_VIRTUAL; i++) {
1295  if (rte_key_valid(i + 1, TRUE)) {
1296  if (rte_key_is_enabled(1 + i)) {
1297  mainw->osc_block = TRUE;
1298  if ((instance = weed_instance_obtain(i, key_modes[i])) == NULL) {
1299  mainw->osc_block = FALSE;
1300  continue;
1301  }
1302  last_inst = instance;
1303 
1304  // ignore video generators
1305  while ((next_inst = get_next_compound_inst(last_inst)) != NULL) last_inst = next_inst;
1306  if (enabled_in_channels(instance, FALSE) == 0 && enabled_out_channels(last_inst, FALSE) > 0 &&
1307  !is_pure_audio(last_inst, FALSE)) {
1308  weed_instance_unref(instance);
1309  continue;
1310  }
1311  if ((retval = weed_reinit_effect(instance, FALSE)) == FILTER_ERROR_COULD_NOT_REINIT) {
1312  weed_instance_unref(instance);
1313  continue;
1314  }
1315  weed_instance_unref(instance);
1316  }
1317  }
1318  }
1319 
1320  mainw->osc_block = FALSE;
1321 }
1322 
1323 
1324 static void *thread_process_func(void *arg) {
1325  struct _procvals *procvals = (struct _procvals *)arg;
1326  procvals->ret = (*procvals->procfunc)(procvals->inst, procvals->tc);
1327  return NULL;
1328 }
1329 
1330 
1331 #define SLICE_ALIGN 2
1332 
1333 static lives_filter_error_t process_func_threaded(weed_plant_t *inst, weed_timecode_t tc) {
1334  // split output(s) into horizontal slices
1335  struct _procvals *procvals;
1336  lives_thread_t *dthreads = NULL;
1337  weed_plant_t **xinst = NULL;
1338  weed_plant_t **xchannels, *xchan;
1339  weed_plant_t *filter = weed_instance_get_filter(inst, FALSE);
1340  weed_error_t retval;
1341  int nchannels;
1342  int pal;
1343  double vrt;
1344 
1345  weed_plant_t **out_channels = weed_get_plantptr_array_counted(inst, WEED_LEAF_OUT_CHANNELS, &nchannels);
1346  boolean plugin_invalid = FALSE;
1347  boolean filter_invalid = FALSE;
1348  boolean needs_reinit = FALSE;
1349 
1350  int vstep = SLICE_ALIGN, minh;
1351  int slices, slices_per_thread, to_use;
1352  int heights[2], *xheights;
1353  int offset = 0;
1354  int dheight, height, xheight = 0, cheight;
1355  int nthreads = 0;
1356 
1357  int i, j;
1358 
1359  weed_process_f process_func = (weed_process_f)weed_get_funcptr_value(filter, WEED_LEAF_PROCESS_FUNC, NULL);
1360 
1361  filter = weed_instance_get_filter(inst, TRUE);
1362  if (weed_plant_has_leaf(filter, WEED_LEAF_VSTEP)) {
1363  minh = weed_get_int_value(filter, WEED_LEAF_VSTEP, NULL);
1364  if (minh > vstep) vstep = minh;
1365  }
1366 
1367  for (i = 0; i < nchannels; i++) {
1369  height = weed_channel_get_height(out_channels[i]);
1370  pal = weed_channel_get_palette(out_channels[i]);
1371 
1372  for (j = 0; j < weed_palette_get_nplanes(pal); j++) {
1374  cheight = height * vrt;
1375  if (xheight == 0 || cheight < xheight) xheight = cheight;
1376  }
1377  }
1378 
1379  if (xheight % vstep != 0) return FILTER_ERROR_DONT_THREAD;
1380 
1381  // slices = min height / step
1382  slices = xheight / vstep;
1383  slices_per_thread = ALIGN_CEIL(slices, prefs->nfx_threads) / prefs->nfx_threads;
1384 
1385  to_use = ALIGN_CEIL(slices, slices_per_thread) / slices_per_thread;
1386  if (--to_use < 1) return FILTER_ERROR_DONT_THREAD;
1387 
1388  procvals = (struct _procvals *)lives_calloc(to_use, sizeof(struct _procvals));
1389  procvals->ret = WEED_SUCCESS;
1390  xinst = (weed_plant_t **)lives_calloc(to_use, sizeof(weed_plant_t *));
1391  dthreads = (lives_thread_t *)lives_calloc(to_use - 1, sizeof(lives_thread_t));
1392 
1393  for (i = 0; i < nchannels; i++) {
1394  heights[1] = height = weed_get_int_value(out_channels[i], WEED_LEAF_HEIGHT, NULL);
1395  slices = height / vstep;
1396  slices_per_thread = CEIL((double)slices / (double)to_use, 1.);
1397  dheight = slices_per_thread * vstep;
1398  heights[0] = dheight;
1399  weed_set_int_value(out_channels[i], WEED_LEAF_OFFSET, 0);
1400  weed_set_int_array(out_channels[i], WEED_LEAF_HEIGHT, 2, heights);
1401  }
1402 
1403  for (j = 0; j < to_use; j++) {
1404  // each thread needs its own copy of the output channels, so it can have its own WEED_LEAF_OFFSET and WEED_LEAF_HEIGHT
1405  // therefore it also needs its own copy of inst
1406  // but note that WEED_LEAF_PIXEL_DATA always points to the same memory buffer(s)
1407  // this is good also because it avoids concurrency problems with updating inst leaves
1408  // one of the threads (in this case the last one) will get the original inst so it can update values
1409  if (j < to_use - 1) {
1410  pthread_mutex_lock(&mainw->instance_ref_mutex);
1411  xinst[j] = weed_plant_copy(inst);
1412  pthread_mutex_unlock(&mainw->instance_ref_mutex);
1413  xchannels = (weed_plant_t **)lives_calloc(nchannels, sizeof(weed_plant_t *));
1414  } else {
1415  xinst[j] = inst;
1416  xchannels = NULL;
1417  }
1418 
1419  for (i = 0; i < nchannels; i++) {
1420  if (j < to_use - 1) {
1421  xchan = xchannels[i] = weed_plant_copy(out_channels[i]);
1422  } else {
1423  xchan = out_channels[i];
1424  }
1425  xheights = weed_get_int_array(out_channels[i], WEED_LEAF_HEIGHT, NULL);
1426  height = xheights[1];
1427  dheight = xheights[0];
1428  offset = dheight * j;
1429  if ((height - offset) < dheight) dheight = height - offset;
1430  xheights[0] = dheight;
1431  weed_set_int_value(xchan, WEED_LEAF_OFFSET, offset);
1432  weed_set_int_array(xchan, WEED_LEAF_HEIGHT, 2, xheights);
1433  lives_free(xheights);
1434  }
1435 
1436  if (j < to_use - 1) {
1437  weed_set_plantptr_array(xinst[j], WEED_LEAF_OUT_CHANNELS, nchannels, xchannels);
1438  }
1439  lives_freep((void **)&xchannels);
1440 
1441  procvals[j].procfunc = process_func;
1442  procvals[j].inst = xinst[j];
1443  procvals[j].tc = tc; // use same timecode for all slices
1444 
1445  if (j < to_use - 1) {
1446  // start a thread for processing
1447  lives_thread_create(&dthreads[j], LIVES_THRDATTR_NONE, thread_process_func, &procvals[j]);
1448  nthreads++; // actual number of threads used
1449  } else {
1451  (*thread_process_func)(&procvals[j]);
1452  retval = procvals[j].ret;
1453  if (retval == WEED_ERROR_PLUGIN_INVALID) plugin_invalid = TRUE;
1454  if (retval == WEED_ERROR_FILTER_INVALID) filter_invalid = TRUE;
1455  if (retval == WEED_ERROR_REINIT_NEEDED) needs_reinit = TRUE;
1456  }
1457  }
1458 
1459  // wait for threads to finish
1460  for (j = 0; j < nthreads; j++) {
1461  lives_thread_join(dthreads[j], NULL);
1462  retval = procvals[j].ret;
1463  if (retval == WEED_ERROR_PLUGIN_INVALID) plugin_invalid = TRUE;
1464  if (retval == WEED_ERROR_FILTER_INVALID) filter_invalid = TRUE;
1465  if (retval == WEED_ERROR_REINIT_NEEDED) needs_reinit = TRUE;
1466 
1467  xchannels = weed_get_plantptr_array(xinst[j], WEED_LEAF_OUT_CHANNELS, NULL);
1468  for (i = 0; i < nchannels; i++) {
1469  weed_plant_free(xchannels[i]);
1470  }
1471  lives_freep((void **)&xchannels);
1472  weed_plant_free(xinst[j]);
1473  }
1474 
1475  for (i = 0; i < nchannels; i++) {
1476  // reset the channel heights
1477  xheights = weed_get_int_array(out_channels[i], WEED_LEAF_HEIGHT, NULL);
1478  weed_set_int_value(out_channels[i], WEED_LEAF_HEIGHT, xheights[1]);
1479  lives_free(xheights);
1480  weed_leaf_delete(out_channels[i], WEED_LEAF_OFFSET);
1481  }
1482 
1483  lives_freep((void **)&procvals);
1484  lives_freep((void **)&xinst);
1485  lives_freep((void **)&dthreads);
1486  lives_freep((void **)&out_channels);
1487  weed_leaf_delete(inst, WEED_LEAF_HOST_UNUSED);
1488 
1489  if (plugin_invalid) return FILTER_ERROR_INVALID_PLUGIN;
1490  if (filter_invalid) return FILTER_ERROR_INVALID_FILTER;
1491  if (needs_reinit) return FILTER_ERROR_NEEDS_REINIT; // TODO...
1492  return FILTER_SUCCESS;
1493 }
1494 
1495 
1496 static lives_filter_error_t check_cconx(weed_plant_t *inst, int nchans, boolean *needs_reinit) {
1497  weed_plant_t **in_channels;
1498 
1499  // we stored original key/mode to use here
1500  if (weed_plant_has_leaf(inst, WEED_LEAF_HOST_KEY)) {
1501  // pull from alpha chain
1502  int key = weed_get_int_value(inst, WEED_LEAF_HOST_KEY, NULL), mode;
1503  if (weed_plant_has_leaf(inst, WEED_LEAF_HOST_MODE)) {
1504  mode = weed_get_int_value(inst, WEED_LEAF_HOST_MODE, NULL);
1505  } else mode = key_modes[key];
1506 
1507  // need to do this AFTER setting in-channel size
1508  if (mainw->cconx) {
1509  // chain any alpha channels
1510  if (cconx_chain_data(key, mode)) *needs_reinit = TRUE;
1511  }
1512  }
1513 
1514  // make sure we have pixel_data for all mandatory in alpha channels (from alpha chains)
1515  // if not, if the ctmpl is optnl mark as host_temp_disabled; else return with error
1516 
1517  in_channels = weed_get_plantptr_array(inst, WEED_LEAF_IN_CHANNELS, NULL);
1518 
1519  for (int i = 0; i < nchans; i++) {
1520  if (!weed_palette_is_alpha(weed_get_int_value(in_channels[i], WEED_LEAF_CURRENT_PALETTE, NULL))) continue;
1521 
1522  if (weed_plant_has_leaf(in_channels[i], WEED_LEAF_HOST_INTERNAL_CONNECTION)) {
1523  if (cconx_chain_data_internal(in_channels[i])) *needs_reinit = TRUE;
1524  }
1525 
1526  if (!weed_get_voidptr_value(in_channels[i], WEED_LEAF_PIXEL_DATA, NULL)) {
1527  weed_plant_t *chantmpl = weed_get_plantptr_value(in_channels[i], WEED_LEAF_TEMPLATE, NULL);
1528  if (weed_plant_has_leaf(chantmpl, WEED_LEAF_MAX_REPEATS) || (weed_chantmpl_is_optional(chantmpl)))
1529  if (weed_get_boolean_value(in_channels[i], WEED_LEAF_DISABLED, NULL) == WEED_FALSE)
1530  weed_set_boolean_value(in_channels[i], WEED_LEAF_HOST_TEMP_DISABLED, WEED_TRUE);
1531  else weed_set_boolean_value(in_channels[i], WEED_LEAF_HOST_TEMP_DISABLED, WEED_FALSE);
1532  // WEED_LEAF_DISABLED will serve instead
1533  else {
1534  lives_freep((void **)&in_channels);
1536  }
1537  }
1538  }
1539 
1540  lives_freep((void **)&in_channels);
1541  return FILTER_SUCCESS;
1542 }
1543 
1544 
1585 lives_filter_error_t weed_apply_instance(weed_plant_t *inst, weed_plant_t *init_event, weed_plant_t **layers,
1586  int opwidth, int opheight, weed_timecode_t tc) {
1587  // filter_mutex should be unlocked
1588 
1589  void *pdata;
1590 
1591  weed_plant_t **in_channels = NULL, **out_channels = NULL, *channel, *chantmpl;
1592  weed_plant_t **in_ctmpls;
1593  weed_plant_t *def_channel = NULL;
1594  weed_plant_t *filter = weed_instance_get_filter(inst, FALSE);
1595  weed_layer_t *layer = NULL, *orig_layer = NULL;
1596 
1597  int *in_tracks, *out_tracks;
1598  int *rowstrides;
1599  int *palettes;
1600  int *channel_rows;
1601  int *mand;
1603 
1604  short pb_quality = prefs->pb_quality;
1605 
1606  boolean rowstrides_changed;
1607  boolean needs_reinit = FALSE, inplace = FALSE;
1608  boolean all_out_alpha = TRUE; //,all_in_alpha=FALSE;
1609  boolean is_converter = FALSE, pvary = FALSE, svary = FALSE;
1610  boolean resized = FALSE, letterboxed = FALSE;
1611  boolean letterbox = FALSE;
1612 
1613  int num_palettes, num_in_tracks = 0, num_out_tracks;
1614  int inwidth, inheight, inpalette, outpalette, opalette, channel_flags, filter_flags = 0;
1615  int palette, cpalette, def_palette = 0;
1616  int outwidth, outheight;
1617  int numplanes = 0, width, height, xwidth, xheight;
1618  int nchr;
1619  int maxinwidth = 4, maxinheight = 4, mininwidth = -1, mininheight = -1;
1620  int iclamping, isampling, isubspace;
1621  int clip = -1;
1622  frames_t frame;
1623  int num_ctmpl, num_inc, num_outc;
1624  int osubspace = -1, osampling = -1, oclamping = -1;
1625  int num_in_alpha = 0, num_out_alpha = 0;
1626  int nmandout = 0;
1627  int lcount = 0;
1628  int key = -1;
1629  int i, j, k;
1630 
1631  if (prefs->dev_show_timing)
1632  g_printerr("apply inst @ %f\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
1633 
1634  if (weed_get_boolean_value(inst, WEED_LEAF_HOST_INITED, NULL) == WEED_FALSE) needs_reinit = TRUE;
1635 
1636  if (LIVES_IS_RENDERING) pb_quality = PB_QUALITY_HIGH;
1637 
1638  // TODO - check if inited, if not return with error (check also for filters with no init_func)
1639 
1641  if (pb_quality == PB_QUALITY_HIGH) {
1642  if (opwidth > 0)
1643  maxinwidth = opwidth;
1644  if (opheight > 0)
1645  maxinheight = opheight;
1646  }
1647 
1648  out_channels = weed_get_plantptr_array(inst, WEED_LEAF_OUT_CHANNELS, NULL);
1649 
1650  if (!out_channels && (mainw->preview || mainw->is_rendering) && num_compound_fx(inst) == 1) {
1652  lives_freep((void **)&out_channels);
1653  return retval;
1654  }
1655 
1656  filter_flags = weed_get_int_value(filter, WEED_LEAF_FLAGS, NULL);
1657  if (weed_plant_has_leaf(inst, WEED_LEAF_HOST_KEY)) key = weed_get_int_value(inst, WEED_LEAF_HOST_KEY, NULL);
1658 
1659  if (is_pure_audio(filter, TRUE)) {
1661  lives_freep((void **)&out_channels);
1662  return FILTER_ERROR_IS_AUDIO;
1663  }
1664 
1665  in_channels = weed_get_plantptr_array(inst, WEED_LEAF_IN_CHANNELS, NULL);
1666 
1667  // here, in_tracks and out_tracks map our layers to in_channels and out_channels in the filter
1668  if (!in_channels || !has_video_chans_in(filter, TRUE) || all_ins_alpha(filter, TRUE)) {
1669  if ((!out_channels && weed_plant_has_leaf(inst, WEED_LEAF_OUT_PARAMETERS)) ||
1670  (all_outs_alpha(filter, TRUE))) {
1672  for (i = 0; (channel = get_enabled_channel(inst, i, FALSE)) != NULL; i++) {
1673  pdata = weed_get_voidptr_value(channel, WEED_LEAF_PIXEL_DATA, NULL);
1674 
1675  if (!pdata) {
1676  width = DEF_FRAME_HSIZE_43S_UNSCALED; // TODO: default size for new alpha only channels
1677  height = DEF_FRAME_VSIZE_43S_UNSCALED; // TODO: default size for new alpha only channels
1678 
1679  weed_set_int_value(channel, WEED_LEAF_WIDTH, width);
1680  weed_set_int_value(channel, WEED_LEAF_HEIGHT, height);
1681 
1682  set_channel_size(filter, channel, width, height);
1683 
1684  if (weed_plant_has_leaf(filter, WEED_LEAF_ALIGNMENT_HINT)) {
1685  int rowstride_alignment_hint = weed_get_int_value(filter, WEED_LEAF_ALIGNMENT_HINT, NULL);
1686  if (rowstride_alignment_hint > ALIGN_DEF)
1687  THREADVAR(rowstride_alignment_hint) = rowstride_alignment_hint;
1688  }
1689 
1690  // this will look at width, height, current_palette, and create an empty pixel_data and set rowstrides
1691  // and update width and height if necessary
1692  if (!create_empty_pixel_data(channel, FALSE, TRUE)) {
1693  retval = FILTER_ERROR_MEMORY_ERROR;
1694  goto done_video;
1695  }
1696  }
1697  }
1698 
1699  // TODO - this is more complex, as we have to check the entire chain of fx
1700 
1703  retval = run_process_func(inst, tc, key);
1704 
1705  lives_freep((void **)&in_channels);
1706  return retval;
1707  }
1708  lives_freep((void **)&in_channels);
1709  lives_freep((void **)&out_channels);
1711  }
1712 
1713  if (!get_enabled_channel(inst, 0, TRUE)) {
1715  lives_freep((void **)&in_channels);
1716  lives_freep((void **)&out_channels);
1718  }
1719 
1720  if (!init_event) {
1721  num_in_tracks = enabled_in_channels(inst, FALSE);
1722  in_tracks = (int *)lives_calloc(2, sizint);
1723  in_tracks[1] = 1;
1724  num_out_tracks = enabled_out_channels(inst, FALSE);
1725  out_tracks = (int *)lives_calloc(1, sizint);
1726  } else {
1727  in_tracks = weed_get_int_array_counted(init_event, WEED_LEAF_IN_TRACKS, &num_in_tracks);
1728  out_tracks = weed_get_int_array_counted(init_event, WEED_LEAF_OUT_TRACKS, &num_out_tracks);
1729  }
1730 
1733  num_inc = weed_leaf_num_elements(inst, WEED_LEAF_IN_CHANNELS);
1734 
1735  for (i = 0; i < num_inc; i++) {
1736  if (weed_palette_is_alpha(weed_get_int_value(in_channels[i], WEED_LEAF_CURRENT_PALETTE, NULL)) &&
1737  weed_get_boolean_value(in_channels[i], WEED_LEAF_DISABLED, NULL) == WEED_FALSE)
1738  num_in_alpha++;
1739  }
1740 
1741  num_inc -= num_in_alpha;
1742 
1743  retval = check_cconx(inst, num_inc + num_in_alpha, &needs_reinit);
1744  if (retval != FILTER_SUCCESS) {
1745  goto done_video;
1746  }
1747 
1748  if (num_in_tracks > num_inc) num_in_tracks = num_inc; // for example, compound fx
1749 
1751  if (num_inc > num_in_tracks) {
1752  for (i = num_in_tracks; i < num_inc + num_in_alpha; i++) {
1753  if (!weed_palette_is_alpha(weed_channel_get_palette(in_channels[i]))) {
1754  if (weed_get_boolean_value(in_channels[i], WEED_LEAF_DISABLED, NULL) == WEED_FALSE)
1755  weed_set_boolean_value(in_channels[i], WEED_LEAF_HOST_TEMP_DISABLED, WEED_TRUE);
1756  else weed_set_boolean_value(in_channels[i], WEED_LEAF_HOST_TEMP_DISABLED, WEED_FALSE);
1757  }
1758  }
1759  }
1760 
1761  // count the actual layers fed in
1762  while (layers[lcount]) lcount++;
1763 
1764  for (k = i = 0; i < num_in_tracks; i++) {
1765  if (in_tracks[i] < 0) {
1766  retval = FILTER_ERROR_INVALID_TRACK; // probably audio
1767  goto done_video;
1768  }
1769 
1770  while (weed_palette_is_alpha(weed_channel_get_palette(in_channels[k]))) k++;
1771 
1772  channel = in_channels[k];
1773  weed_set_boolean_value(channel, WEED_LEAF_HOST_TEMP_DISABLED, WEED_FALSE);
1774 
1775  if (in_tracks[i] >= lcount) {
1778  for (j = k; j < num_in_tracks + num_in_alpha; j++) {
1779  if (weed_palette_is_alpha(weed_channel_get_palette(in_channels[j]))) continue;
1780  channel = in_channels[j];
1781  chantmpl = weed_get_plantptr_value(channel, WEED_LEAF_TEMPLATE, NULL);
1782  if (weed_plant_has_leaf(chantmpl, WEED_LEAF_MAX_REPEATS) || (weed_chantmpl_is_optional(chantmpl)))
1783  if (weed_get_boolean_value(channel, WEED_LEAF_DISABLED, NULL) == WEED_FALSE)
1784  weed_set_boolean_value(channel, WEED_LEAF_HOST_TEMP_DISABLED, WEED_TRUE);
1785  else weed_set_boolean_value(channel, WEED_LEAF_HOST_TEMP_DISABLED, WEED_FALSE);
1786  else {
1787  retval = FILTER_ERROR_MISSING_LAYER;
1788  goto done_video;
1789  }
1790  }
1791  break;
1792  }
1793  layer = layers[in_tracks[i]];
1794 
1795  if (!weed_get_voidptr_value(layer, WEED_LEAF_PIXEL_DATA, NULL)) {
1797  if (prefs->dev_show_timing)
1798  g_printerr("fx clr pre @ %f\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
1799  check_layer_ready(layer);
1800  if (prefs->dev_show_timing)
1801  g_printerr("fx clr post @ %f\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
1802  frame = weed_get_int_value(layer, WEED_LEAF_FRAME, NULL);
1803  if (frame == 0) {
1805  channel = in_channels[k];
1806  chantmpl = weed_get_plantptr_value(channel, WEED_LEAF_TEMPLATE, NULL);
1807  if (weed_plant_has_leaf(chantmpl, WEED_LEAF_MAX_REPEATS) || (weed_chantmpl_is_optional(chantmpl))) {
1808  if (weed_get_boolean_value(channel, WEED_LEAF_DISABLED, NULL) == WEED_FALSE)
1809  weed_set_boolean_value(channel, WEED_LEAF_HOST_TEMP_DISABLED, WEED_TRUE);
1810  } else {
1811  weed_set_boolean_value(channel, WEED_LEAF_HOST_TEMP_DISABLED, WEED_FALSE);
1812  retval = FILTER_ERROR_BLANK_FRAME;
1813  goto done_video;
1814  // *INDENT-OFF*
1815  }}}
1816  k++;
1817  }
1818  // *INDENT-ON*
1819 
1822  in_ctmpls = weed_get_plantptr_array_counted(filter, WEED_LEAF_IN_CHANNEL_TEMPLATES, &num_ctmpl);
1823  mand = (int *)lives_calloc(num_ctmpl, sizint);
1824 
1825  for (i = 0; i < num_inc + num_in_alpha; i++) {
1827  if (weed_get_boolean_value(in_channels[i], WEED_LEAF_DISABLED, NULL) == WEED_TRUE ||
1828  weed_get_boolean_value(in_channels[i], WEED_LEAF_HOST_TEMP_DISABLED, NULL) == WEED_TRUE) continue;
1829  chantmpl = weed_channel_get_template(in_channels[i]);
1830  for (j = 0; j < num_ctmpl; j++) {
1832  if (chantmpl == in_ctmpls[j]) {
1833  mand[j] = 1;
1834  break;
1835  }
1836  }
1837  }
1838 
1839  for (j = 0; j < num_ctmpl; j++) {
1841  if (mand[j] == 0 && !weed_chantmpl_is_optional(in_ctmpls[j])) {
1842  lives_freep((void **)&in_ctmpls);
1843  lives_freep((void **)&mand);
1844  retval = FILTER_ERROR_MISSING_LAYER;
1845  goto done_video;
1846  }
1847  }
1848 
1849  lives_freep((void **)&in_ctmpls);
1850  lives_freep((void **)&mand);
1851 
1853 
1854  num_outc = weed_leaf_num_elements(inst, WEED_LEAF_OUT_CHANNELS);
1855 
1856  for (i = 0; i < num_outc; i++) {
1857  if (weed_palette_is_alpha(weed_channel_get_palette(out_channels[i]))) {
1858  if (weed_get_boolean_value(out_channels[i], WEED_LEAF_DISABLED, NULL) == WEED_FALSE)
1859  num_out_alpha++;
1860  } else {
1861  if (weed_get_boolean_value(out_channels[i], WEED_LEAF_DISABLED, NULL) == WEED_FALSE &&
1862  weed_get_boolean_value(out_channels[i], WEED_LEAF_HOST_TEMP_DISABLED, NULL) == WEED_FALSE) {
1863  nmandout++;
1864  }
1865  }
1866  }
1867 
1868  if (!init_event || num_compound_fx(inst) > 1) num_out_tracks -= num_out_alpha;
1869 
1870  if (num_out_tracks < 0) num_out_tracks = 0;
1871 
1872  if (nmandout > num_out_tracks) {
1875  // - needs more investigation if it is still happening
1877  }
1878 
1879  // pull frames for tracks
1880 
1881  for (i = 0; i < num_out_tracks + num_out_alpha; i++) {
1882  if (i >= num_outc) continue; // for compound filters, num_out_tracks may not be valid
1883  channel = out_channels[i];
1884  palette = weed_channel_get_palette(channel);
1885  if (weed_palette_is_alpha(palette)) continue;
1886  if (weed_get_boolean_value(channel, WEED_LEAF_DISABLED, NULL) == WEED_TRUE ||
1887  weed_get_boolean_value(channel, WEED_LEAF_HOST_TEMP_DISABLED, NULL) == WEED_TRUE) continue;
1888  all_out_alpha = FALSE;
1889  }
1890 
1891  for (j = i = 0; i < num_in_tracks; i++) {
1892  if (weed_palette_is_alpha(weed_channel_get_palette(in_channels[j]))) continue;
1893  if (weed_get_boolean_value(in_channels[j], WEED_LEAF_DISABLED, NULL) == WEED_TRUE ||
1894  weed_get_boolean_value(in_channels[j], WEED_LEAF_HOST_TEMP_DISABLED, NULL) == WEED_TRUE) {
1895  j++;
1896  continue;
1897  }
1898  layer = layers[in_tracks[i]];
1899  clip = weed_get_int_value(layer, WEED_LEAF_CLIP, NULL);
1900 
1901  if (!weed_layer_get_pixel_data_packed(layer)) {
1902  //check_layer_ready(layer);
1903  /* /// wait for thread to pull layer pixel_data */
1904  if (!is_layer_ready(layer)) {
1905 #define FX_WAIT_LIM 10000 // microseconds * 10
1906  if (prefs->dev_show_timing)
1907  g_printerr("fx clr2 pre @ %f\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
1908  for (register int tt = 0; tt < FX_WAIT_LIM && !is_layer_ready(layer); tt++) {
1909  lives_nanosleep(10000);
1910  }
1911  if (prefs->dev_show_timing)
1912  g_printerr("fx clr2 post @ %f\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
1913  if (!is_layer_ready(layer)) {
1914  retval = FILTER_ERROR_MISSING_FRAME;
1915  goto done_video;
1916  }
1917  if (!weed_layer_get_pixel_data_packed(layer)) {
1918  retval = FILTER_ERROR_MISSING_FRAME;
1919  goto done_video;
1920  }
1921  }
1922  }
1923  // we apply only transitions and compositors to the scrap file
1924  if (clip == mainw->scrap_file && num_in_tracks <= 1 && num_out_tracks <= 1) {
1925  retval = FILTER_ERROR_IS_SCRAP_FILE;
1926  goto done_video;
1927  }
1928  // use comparative widths - in RGB(A) pixels
1930  inwidth = weed_layer_get_width_pixels(layer);
1931  inheight = weed_layer_get_height(layer);
1932 
1933  if (filter_flags & WEED_FILTER_CHANNEL_SIZES_MAY_VARY) svary = TRUE;
1934  if (filter_flags & WEED_FILTER_IS_CONVERTER) is_converter = TRUE;
1935 
1936  if (maxinwidth == 4 && inwidth > 4) maxinwidth = inwidth;
1937  if (maxinheight == 4 && inheight > 4) maxinheight = inheight;
1938 
1940  letterbox = TRUE;
1941 
1942  if (!svary) {
1943  if (letterbox) {
1949  // otherwise, we will aspect ratio it to fit the max size. Since we know at least one of the dimensions was
1950  // within the current bounds (otherwise it would engulf), we will end up with 2 edges touching and two letterboxed
1951  if (inwidth >= maxinwidth && inheight >= maxinheight) {
1952  maxinwidth = inwidth;
1953  maxinheight = inheight;
1954  }
1955  } else {
1956  if (inwidth > maxinwidth) maxinwidth = inwidth;
1957  if (inheight > maxinheight) maxinheight = inheight;
1958  }
1959  if (prefs->pb_quality == PB_QUALITY_LOW) {
1960  // for low quality we pick the smallest dimensions
1961  if (mininwidth == -1 || inwidth < mininwidth) mininwidth = inwidth;
1962  if (mininheight == -1 || inheight < mininheight) mininheight = inheight;
1963  }
1964  }
1965  j++;
1966  }
1967 
1968  if (!svary || prefs->pb_quality == PB_QUALITY_LOW || !is_converter) {
1969  switch (pb_quality) {
1970  case PB_QUALITY_HIGH:
1971  if (maxinwidth > opwidth) opwidth = maxinwidth;
1972  if (maxinheight > opheight) opheight = maxinheight;
1973  break;
1974  case PB_QUALITY_MED:
1975  if (!mainw->multitrack) {
1976  if (maxinwidth > opwidth || maxinheight > opheight) {
1977  calc_maxspect(opwidth, opheight, &maxinwidth, &maxinheight);
1978  opwidth = maxinwidth;
1979  opheight = maxinheight;
1980  } else {
1981  calc_maxspect(maxinwidth, maxinheight, &opwidth, &opheight);
1982  }
1983  } else {
1984  if (maxinwidth > opwidth) maxinwidth = opwidth;
1985  if (maxinheight > opheight) maxinheight = opheight;
1986  opwidth = maxinwidth;
1987  opheight = maxinheight;
1988  }
1989  break;
1990  default:
1991  // PB_QUALITY_LOW
1992  if (!mainw->multitrack) {
1993  if (mininwidth < opwidth || mininheight < opheight) {
1994  calc_maxspect(mininwidth, mininheight, &opwidth, &opheight);
1995  } else {
1996  calc_maxspect(opwidth, opheight, &mininwidth, &mininheight);
1997  opwidth = mininwidth;
1998  opheight = mininheight;
1999  }
2000  } else {
2001  if (mininwidth < opwidth) opwidth = mininwidth;
2002  if (mininheight < opheight) opheight = mininheight;
2003  }
2004  break;
2005  }
2006  }
2007 
2008  opwidth = (opwidth >> 1) << 1;
2009  opheight = (opheight >> 1) << 1;
2010 
2011  if (pb_quality < PB_QUALITY_HIGH && mainw->multitrack && prefs->letterbox_mt) {
2012  calc_midspect(cfile->hsize, cfile->vsize, &opwidth, &opheight);
2013  }
2014 
2018  for (k = i = 0; k < num_inc + num_in_alpha; k++) {
2019  int owidth, oheight;
2020 
2021  channel = get_enabled_channel(inst, k, TRUE);
2022  if (!channel) break;
2023 
2024  if (weed_get_boolean_value(channel, WEED_LEAF_HOST_TEMP_DISABLED, NULL) == WEED_TRUE) continue;
2025 
2026  if (!def_channel) def_channel = channel;
2027 
2033  if (!svary && def_channel != channel && (weed_channel_get_width(def_channel) != weed_channel_get_width(channel)
2034  || weed_channel_get_width(def_channel) != weed_channel_get_width(channel))) {
2036  goto done_video;
2037  }
2038  continue;
2039  }
2040 
2041  layer = layers[in_tracks[i]];
2042 
2043  // values in pixels
2044  width = opwidth;
2045  height = opheight;
2046 
2047  if (svary) {
2050  if (is_converter || def_channel != channel) {
2052  inwidth = weed_get_int_value(layer, WEED_LEAF_WIDTH, NULL);
2053  inheight = weed_get_int_value(layer, WEED_LEAF_HEIGHT, NULL);
2055  height = inheight;
2056  }
2057  }
2058 
2059  cpalette = weed_channel_get_palette(channel);
2060  width /= weed_palette_get_pixels_per_macropixel(cpalette); // convert width to channel macropixels
2061 
2063  owidth = weed_channel_get_width(channel);
2064  oheight = weed_channel_get_height(channel);
2065 
2066  chantmpl = weed_channel_get_template(channel);
2067  channel_flags = weed_chantmpl_get_flags(chantmpl);
2068 
2069  if (owidth != width || oheight != height) {
2070  set_channel_size(filter, channel, width, height);
2071  opwidth = weed_channel_get_width(channel);
2072  opheight = weed_channel_get_height(channel);
2073  if (channel_flags & WEED_CHANNEL_REINIT_ON_SIZE_CHANGE) {
2074  boolean oneeds_reinit = needs_reinit;
2075  needs_reinit = TRUE;
2076  if (channel_flags & WEED_CHANNEL_NEEDS_NATURAL_SIZE) {
2077  int *nsizes = weed_get_int_array(channel, WEED_LEAF_NATURAL_SIZE, NULL);
2078  if (nsizes) {
2079  int *lnsizes;
2080  if (prefs->dev_show_timing)
2081  g_printerr("nsw pre2 @ %f\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
2082  lives_nanosleep_until_nonzero(weed_plant_has_leaf(layer, WEED_LEAF_NATURAL_SIZE));
2083  if (prefs->dev_show_timing)
2084  g_printerr("nsw post2 @ %f\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
2085  lnsizes = weed_get_int_array(layer, WEED_LEAF_NATURAL_SIZE, NULL);
2086  if (nsizes[0] == lnsizes[0] && nsizes[1] == lnsizes[1]) needs_reinit = oneeds_reinit;
2087  lives_free(lnsizes);
2088  lives_free(nsizes);
2089  }
2090  }
2091  }
2092  }
2093  if (prefs->dev_show_timing)
2094  g_printerr("nsw pre @ %f\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
2095  if (channel_flags & WEED_CHANNEL_NEEDS_NATURAL_SIZE) {
2096  lives_nanosleep_until_nonzero(weed_plant_has_leaf(layer, WEED_LEAF_NATURAL_SIZE));
2097  weed_leaf_dup(channel, layer, WEED_LEAF_NATURAL_SIZE);
2098  }
2099  if (prefs->dev_show_timing)
2100  g_printerr("nsw post @ %f\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
2101  i++;
2102  }
2103 
2104  if (!def_channel) {
2105  retval = FILTER_ERROR_NO_IN_CHANNELS;
2106  goto done_video;
2107  }
2108 
2139  for (i = 0; i < num_in_tracks; i++) {
2140  int tgamma = WEED_GAMMA_UNKNOWN;
2141  if (i > 0) def_palette = weed_channel_get_palette(def_channel);
2142 
2143  channel = get_enabled_channel(inst, i, TRUE);
2144  if (channel) {
2145  chantmpl = weed_channel_get_template(channel);
2146  channel_flags = weed_chantmpl_get_flags(chantmpl);
2147  }
2148 
2149  //channel = get_enabled_channel(inst, i, TRUE);
2150  if (weed_get_boolean_value(channel, WEED_LEAF_HOST_TEMP_DISABLED, NULL) == WEED_TRUE) continue;
2151 
2152  inpalette = weed_channel_get_palette(channel);
2153  if (weed_palette_is_alpha(inpalette)) continue;
2154 
2155  if (prefs->dev_show_timing)
2156  g_printerr("clrfx pre @ %f\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
2157  layer = layers[in_tracks[i]];
2158  check_layer_ready(layer);
2159  if (prefs->dev_show_timing)
2160  g_printerr("clrfx post @ %f\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
2161 
2162  cpalette = opalette = weed_layer_get_palette(layer);
2163  if (weed_palette_is_alpha(opalette)) continue;
2164 
2165  chantmpl = weed_channel_get_template(channel);
2166  channel_flags |= weed_chantmpl_get_flags(chantmpl);
2167 
2168  if (filter_flags & WEED_FILTER_PALETTES_MAY_VARY) {
2169  pvary = TRUE;
2170  } else if (i > 0) opalette = weed_channel_get_palette(def_channel);
2171 
2172  if ((channel_flags & WEED_CHANNEL_REINIT_ON_PALETTE_CHANGE)
2173  || ((channel_flags & WEED_CHANNEL_REINIT_ON_ROWSTRIDES_CHANGE)
2175  if (!needs_reinit && weed_get_boolean_value(inst, WEED_LEAF_HOST_UNUSED, NULL) == WEED_FALSE)
2177  opalette = inpalette;
2178  else {
2179  int clip = weed_get_int_value(layer, WEED_LEAF_CLIP, NULL);
2180  if (clip == 0 || IS_NORMAL_CLIP(clip)) {
2181  if (!weed_palette_is_rgb(opalette))
2182  opalette = (weed_palette_has_alpha(opalette) ? WEED_PALETTE_RGBA32 : WEED_PALETTE_RGB24);
2183  needs_reinit = TRUE;
2184  // *INDENT-OFF*
2185  }}}
2186  // *INDENT-ON*
2187 
2188  if (opalette != inpalette) {
2190  palettes = weed_chantmpl_get_palette_list(filter, chantmpl, &num_palettes);
2191  palette = best_palette_match(palettes, num_palettes, opalette);
2192  if (i > 0 && !pvary && palette != def_palette) {
2193  lives_freep((void **)&palettes);
2194  lives_freep((void **)&rowstrides);
2195  retval = FILTER_ERROR_TEMPLATE_MISMATCH; // plugin author messed up...
2196  goto done_video;
2197  }
2198 
2199  if (palette != inpalette) {
2200  if (channel_flags & WEED_CHANNEL_REINIT_ON_PALETTE_CHANGE) needs_reinit = TRUE;
2201  }
2202  lives_freep((void **)&palettes);
2203  opalette = palette;
2204  }
2205 
2206  if (weed_palette_is_yuv(opalette)) {
2208  weed_channel_get_palette_yuv(channel, &iclamping, &isampling, &isubspace);
2209 
2210  if (!needs_reinit && (channel_flags & WEED_CHANNEL_REINIT_ON_PALETTE_CHANGE) != 0
2211  && weed_get_boolean_value(inst, WEED_LEAF_HOST_UNUSED, NULL) == WEED_FALSE) {
2213  oclamping = iclamping;
2214  osampling = isampling;
2215  osubspace = isubspace;
2216  } else {
2217  if (i > 0 && !pvary) {
2218  weed_channel_get_palette_yuv(def_channel, &oclamping, &osampling, &osubspace);
2219  } else {
2220  // cpalette is layer palette here
2221  if ((i == 0 || pvary) && weed_palette_is_yuv(cpalette)) {
2222  oclamping = weed_get_int_value(layer, WEED_LEAF_YUV_CLAMPING, NULL);
2223  } else {
2224  if (i > 0)
2225  oclamping = weed_get_int_value(def_channel, WEED_LEAF_YUV_CLAMPING, NULL);
2226  else
2227  oclamping = WEED_YUV_CLAMPING_UNCLAMPED;
2228  }
2229  if (pvary && weed_plant_has_leaf(chantmpl, WEED_LEAF_YUV_CLAMPING)) {
2230  oclamping = weed_get_int_value(chantmpl, WEED_LEAF_YUV_CLAMPING, NULL);
2231  } else {
2232  if (weed_plant_has_leaf(filter, WEED_LEAF_YUV_CLAMPING)) {
2233  oclamping = weed_get_int_value(filter, WEED_LEAF_YUV_CLAMPING, NULL);
2234  }
2235  }
2236 
2237  // cpalette is layer palette here
2238  if (weed_palette_is_yuv(cpalette)) {
2239  // cant convert YUV <-> YUV sampling yet
2240  osampling = weed_get_int_value(layer, WEED_LEAF_YUV_SAMPLING, NULL);
2241  } else {
2242  if (i > 0)
2243  osampling = weed_get_int_value(def_channel, WEED_LEAF_YUV_SAMPLING, NULL);
2244  else
2245  osampling = WEED_YUV_SAMPLING_DEFAULT;
2246  if (pvary && weed_plant_has_leaf(chantmpl, WEED_LEAF_YUV_SAMPLING)) {
2247  osampling = weed_get_int_value(chantmpl, WEED_LEAF_YUV_SAMPLING, NULL);
2248  } else if (weed_plant_has_leaf(filter, WEED_LEAF_YUV_SAMPLING)) {
2249  osampling = weed_get_int_value(filter, WEED_LEAF_YUV_SAMPLING, NULL);
2250  }
2251  }
2252 
2253  // cpalette is layer palette here
2254  if (weed_palette_is_yuv(cpalette)) {
2255  // cant convert YUV <-> YUV subspace yet
2256  osubspace = weed_get_int_value(layer, WEED_LEAF_YUV_SUBSPACE, NULL);
2257  } else {
2258  if (i > 0)
2259  osubspace = weed_get_int_value(def_channel, WEED_LEAF_YUV_SUBSPACE, NULL);
2260  else
2261  osampling = WEED_YUV_SUBSPACE_YUV;
2262  if (pvary && weed_plant_has_leaf(chantmpl, WEED_LEAF_YUV_SUBSPACE)) {
2263  osubspace = weed_get_int_value(chantmpl, WEED_LEAF_YUV_SUBSPACE, NULL);
2264  } else {
2265  if (weed_plant_has_leaf(filter, WEED_LEAF_YUV_SUBSPACE)) {
2266  osubspace = weed_get_int_value(filter, WEED_LEAF_YUV_SUBSPACE, NULL);
2267  } else
2268  osubspace = WEED_YUV_SUBSPACE_YUV;
2269  }
2270  }
2271  }
2272 
2273  if (channel_flags & WEED_CHANNEL_REINIT_ON_PALETTE_CHANGE) {
2274  if (oclamping != iclamping || isampling != osampling || isubspace != osubspace) {
2275  // we need to reinit due to yuv changes, see if we can switch to RGB
2276  if ((i == 0 || pvary) && IS_NORMAL_CLIP(clip)) {
2277  if (!weed_palette_is_rgb(opalette)) opalette = (weed_palette_has_alpha(opalette) ? WEED_PALETTE_RGBA32
2278  : WEED_PALETTE_RGB24);
2279  if (opalette != palette) {
2281  palettes = weed_chantmpl_get_palette_list(filter, chantmpl, &num_palettes);
2282  opalette = best_palette_match(palettes, num_palettes, opalette);
2283  }
2284  }
2285  needs_reinit = TRUE;
2286  // *INDENT-OFF*
2287  }}}}
2288  // *INDENT-ON*
2289 
2290  orig_layer = NULL;
2291 
2292  // cpalette is layer palette here, opalette is now channel palette
2293  if (cpalette != opalette || (weed_palette_is_yuv(opalette) && weed_palette_is_yuv(cpalette)
2294  && weed_get_int_value(layer, WEED_LEAF_YUV_CLAMPING, NULL) != oclamping)) {
2295  if (all_out_alpha && (weed_palette_is_lower_quality(opalette, cpalette) ||
2296  (weed_palette_is_rgb(inpalette) &&
2297  !weed_palette_is_rgb(cpalette)) ||
2298  (weed_palette_is_rgb(cpalette) &&
2299  !weed_palette_is_rgb(inpalette)))) {
2302  orig_layer = layer;
2303  layer = weed_layer_copy(NULL, orig_layer);
2304  weed_set_plantptr_value(orig_layer, WEED_LEAF_DUPLICATE, layer);
2305  }
2306  }
2307 
2309 
2313 
2314  width = opwidth;
2315  height = opheight;
2316 
2317  xwidth = inwidth = weed_layer_get_width_pixels(layer);
2318  xheight = inheight = weed_layer_get_height(layer);
2319 
2320  resized = FALSE;
2321  letterboxed = FALSE;
2322 
2323  // we are comparing the macropixel sizes which is fine because that won't change
2324  // regardless of the channel / layer palette, but for resize_layer we need the pixel size,
2325  // which will be width * pixels_per_macropixel of the original channel palette, which is the divisor we used when
2326  // setting the channel width. resize_layer() will handle conversion of the macropixel sizes between layer palette
2327  // and opalette
2328  if ((!svary && (inwidth != width || inheight != height))
2329  || (svary && (inwidth > width || inheight > height || letterbox))) {
2330  short interp = get_interp_value(pb_quality, TRUE);
2331  if (letterbox && !orig_layer) {
2332  // if we are letterboxing, as well as letterboxing the final output in the player, we will also letterbox each layer into its channel
2333  // if we only have 1 layer this is irrelevant since the channel size == layer size, (or in high quality, channel size == player size,
2336  // the same size, which was set by largest / smallest engulfing channel. [unless the filter set WEED_FILTER_SIZES_MAY_VARY]
2337  // Depending on the quality setting, this may be the largest or the smallest.
2338  // thus one layer / channel will fill the image, whilst all others may get letterboxed
2339  // another alternative would be to resize all of the layers, and ignore letterboxing for the intermediate stages,
2341  // to all layers
2342  int lbvals[4];
2343  calc_maxspect(width, height, &xwidth, &xheight);
2344 
2345  if (xwidth != width || height != xheight) {
2346  if (!letterbox_layer(layer, width, height, xwidth, xheight, interp, opalette, oclamping)) {
2348  goto done_video;
2349  }
2350  resized = TRUE;
2351  lbvals[0] = (width - xwidth) >> 1;
2352  lbvals[1] = (height - xheight) >> 1;
2353  lbvals[2] = xwidth;
2354  lbvals[3] = xheight;
2355  weed_set_int_array(channel, WEED_LEAF_INNER_SIZE, 4, lbvals);
2356  if (!mainw->multitrack && i > 0 && mainw->blend_palette == WEED_PALETTE_END) {
2358  &mainw->blend_subspace);
2359  mainw->blend_width = xwidth;
2360  mainw->blend_height = xheight;
2362  }
2363  }
2364  }
2365  if (!resized) {
2366  if (weed_plant_has_leaf(channel, WEED_LEAF_INNER_SIZE))
2367  weed_leaf_delete(channel, WEED_LEAF_INNER_SIZE);
2368  if (!resize_layer(layer, width, height, interp, opalette, oclamping)) {
2370  goto done_video;
2371  }
2372 
2373  if (!mainw->multitrack && i > 0 && mainw->blend_palette == WEED_PALETTE_END) {
2375  &mainw->blend_subspace);
2376  mainw->blend_width = width;
2377  mainw->blend_height = height;
2379  }
2380  }
2381  } else {
2382  if (weed_plant_has_leaf(channel, WEED_LEAF_INNER_SIZE))
2383  weed_leaf_delete(channel, WEED_LEAF_INNER_SIZE);
2384  }
2385 
2386  // check palette again in case it changed during resize
2387  cpalette = weed_layer_get_palette(layer);
2388 
2389  if (prefs->apply_gamma && weed_palette_is_rgb(opalette)) {
2390  // apply gamma conversion if plugin requested it
2391  if (filter_flags & WEED_FILTER_PREF_LINEAR_GAMMA)
2392  tgamma = WEED_GAMMA_LINEAR;
2393  else
2394  tgamma = cfile->gamma_type;
2395  }
2396 
2397  if (cpalette != opalette) {
2398  if (prefs->dev_show_timing)
2399  g_printerr("clpal1 pre @ %f\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
2400  if (!convert_layer_palette_full(layer, opalette, oclamping, osampling, osubspace, tgamma)) {
2402  goto done_video;
2403  }
2404  if (prefs->dev_show_timing)
2405  g_printerr("clpal1 post @ %f\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
2406  }
2407 
2409  // at this stage we still haven't updated values in the channel, except for width and height
2410  channel_rows = weed_channel_get_rowstrides(channel, &nchr);
2411 
2412  // check layer rowstrides against previous settings
2413  rowstrides = weed_layer_get_rowstrides(layer, &numplanes);
2414  rowstrides_changed = rowstrides_differ(numplanes, rowstrides, nchr, channel_rows);
2415  lives_free(channel_rows);
2416  lives_free(rowstrides);
2417 
2418  if (rowstrides_changed && (channel_flags & WEED_CHANNEL_REINIT_ON_ROWSTRIDES_CHANGE))
2419  needs_reinit = TRUE;
2420 
2421  if (tgamma != WEED_GAMMA_UNKNOWN) {
2422  if (prefs->dev_show_timing)
2423  g_printerr("gamma1 pre @ %f\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
2424  if (letterboxed)
2425  gamma_convert_sub_layer(tgamma, 1.0, layer, (width - xwidth) / 2, (height - xheight) / 2,
2426  xwidth, xheight, TRUE);
2427  else
2428  gamma_convert_layer(tgamma, layer);
2429  if (prefs->dev_show_timing)
2430  g_printerr("gamma1 post @ %f\n", lives_get_current_ticks() / TICKS_PER_SECOND_DBL);
2431  }
2432 
2435 
2437  // width, height, rowstrides, current palette, pixel_data,
2438  // YUV_*, etc.
2439  if (!weed_layer_copy((weed_layer_t *)channel, layer)) {
2440  retval = FILTER_ERROR_COPYING_FAILED;
2441  goto done_video;
2442  }
2443  if (!resized) {
2444  if (!mainw->multitrack && i > 0 && mainw->blend_palette == WEED_PALETTE_END) {
2446  &mainw->blend_subspace);
2450  }
2451  }
2452  }
2453 
2455 
2458  for (i = 0; i < num_out_tracks + num_out_alpha; i++) {
2460 
2461  channel = get_enabled_channel(inst, i, FALSE);
2462  if (!channel) break; // compound fx
2463 
2464  inpalette = weed_channel_get_palette(channel);
2465 
2466  if (!weed_palette_is_alpha(inpalette) && out_tracks[i] < 0) {
2467  retval = FILTER_ERROR_INVALID_TRACK; // probably audio
2468  goto done_video;
2469  }
2470 
2471  chantmpl = weed_channel_get_template(channel);
2472  channel_flags = weed_chantmpl_get_flags(chantmpl);
2473 
2475  rowstrides = weed_channel_get_rowstrides(channel, &numplanes);
2476  outwidth = weed_channel_get_width(channel);
2477  outheight = weed_channel_get_height(channel);
2478  outpalette = weed_channel_get_palette_yuv(channel, &oclamping, &osampling, &osubspace);
2479 
2481  weed_set_int64_value(channel, WEED_LEAF_TIMECODE, tc);
2482 
2483  // check for INPLACE. According to the spec we can make outputs other than the first inplace, but we'll skip that for now
2484  if (i == 0 &&
2487  || (in_tracks && out_tracks && in_tracks[0] == out_tracks[0]))) {
2488  if (channel_flags & WEED_CHANNEL_CAN_DO_INPLACE) {
2489  if (!(weed_palette_is_alpha(outpalette) &&
2490  weed_get_boolean_value(channel, WEED_LEAF_HOST_ORIG_PDATA, NULL) == WEED_TRUE)) {
2492  palettes = weed_chantmpl_get_palette_list(filter, chantmpl, &num_palettes);
2493  palette = weed_channel_get_palette(def_channel);
2494  if (best_palette_match(palettes, num_palettes, palette) == palette) {
2495  if (!weed_layer_copy(channel, def_channel)) {
2496  retval = FILTER_ERROR_COPYING_FAILED;
2497  goto done_video;
2498  }
2499  inplace = TRUE;
2500  } else {
2501  lives_freep((void **)&rowstrides);
2502  retval = FILTER_ERROR_TEMPLATE_MISMATCH; // plugin author messed up...
2503  goto done_video;
2504  }
2506  // protect our in / out channel from being freed()
2507  weed_set_boolean_value(channel, WEED_LEAF_HOST_ORIG_PDATA, WEED_TRUE);
2508  }
2509  lives_freep((void **)&palettes);
2510  weed_set_boolean_value(channel, WEED_LEAF_HOST_INPLACE, WEED_TRUE);
2511  }
2512  }
2513  }
2514 
2515  if (!inplace) {
2519  palette = weed_channel_get_palette(def_channel);
2520  if (palette != outpalette) {
2521  // palette change needed; try to change channel palette
2522  palettes = weed_chantmpl_get_palette_list(filter, chantmpl, &num_palettes);
2523  if ((outpalette = best_palette_match(palettes, num_palettes, palette)) == palette) {
2524  weed_set_int_value(channel, WEED_LEAF_CURRENT_PALETTE, palette);
2525  } else {
2526  lives_freep((void **)&palettes);
2527  lives_freep((void **)&rowstrides);
2529  goto done_video;
2530  }
2531  lives_freep((void **)&palettes);
2532  }
2533 
2534  weed_leaf_copy_or_delete(channel, WEED_LEAF_YUV_CLAMPING, def_channel);
2535  weed_leaf_copy_or_delete(channel, WEED_LEAF_YUV_SAMPLING, def_channel);
2536  weed_leaf_copy_or_delete(channel, WEED_LEAF_YUV_SUBSPACE, def_channel);
2537 
2538  if (svary && is_converter) {
2541  width = weed_get_int_value(chantmpl, WEED_LEAF_HOST_WIDTH, NULL);
2543  height = weed_get_int_value(chantmpl, WEED_LEAF_HOST_HEIGHT, NULL);
2544  } else {
2545  // NB. in future if we add more out channels, if (svary) this should be the ith in_channel.
2546  width = weed_channel_get_width(def_channel);
2547  height = weed_channel_get_height(def_channel);
2548  }
2549 
2550  set_channel_size(filter, channel, width, height);
2551 
2552  if (weed_plant_has_leaf(filter, WEED_LEAF_ALIGNMENT_HINT)) {
2553  int rowstride_alignment_hint = weed_get_int_value(filter, WEED_LEAF_ALIGNMENT_HINT, NULL);
2554  if (rowstride_alignment_hint > ALIGN_DEF) {
2555  THREADVAR(rowstride_alignment_hint) = rowstride_alignment_hint;
2556  }
2557  }
2558 
2559  // this will look at width, height, current_palette, and create an empty pixel_data and set rowstrides
2560  // and update width and height if necessary
2561  if (!create_empty_pixel_data(channel, FALSE, TRUE)) {
2562  retval = FILTER_ERROR_MEMORY_ERROR;
2563  goto done_video;
2564  }
2565  if (filter_flags & WEED_FILTER_PREF_LINEAR_GAMMA)
2566  weed_channel_set_gamma_type(channel, WEED_GAMMA_LINEAR);
2567  else {
2569  weed_channel_set_gamma_type(channel, cfile->gamma_type);
2570  }
2571 
2572  weed_set_boolean_value(channel, WEED_LEAF_HOST_INPLACE, WEED_FALSE);
2573  // end of (!inplace)
2574  }
2575 
2577 
2578  channel_rows = weed_channel_get_rowstrides(channel, &nchr);
2579  palette = weed_channel_get_palette_yuv(channel, &iclamping, &isampling, &isubspace);
2580 
2581  rowstrides_changed = rowstrides_differ(nchr, channel_rows, numplanes, rowstrides);
2582 
2583  lives_freep((void **)&channel_rows);
2584  lives_freep((void **)&rowstrides);
2585 
2586  width = weed_channel_get_width(channel);
2587  height = weed_channel_get_height(channel);
2588 
2589  if ((rowstrides_changed && (channel_flags & WEED_CHANNEL_REINIT_ON_ROWSTRIDES_CHANGE))) needs_reinit = TRUE;
2590 
2591  if ((outwidth != width || outheight != height) && (channel_flags & WEED_CHANNEL_REINIT_ON_SIZE_CHANGE))
2592  needs_reinit = TRUE;
2593 
2594  if (palette != inpalette || (weed_palette_is_yuv(palette)
2595  && (oclamping != iclamping || osampling != isampling || osubspace != isubspace)))
2596  if (channel_flags & WEED_CHANNEL_REINIT_ON_PALETTE_CHANGE) needs_reinit = TRUE;
2597  }
2598 
2600 
2601  if (needs_reinit) {
2602  if ((retval = weed_reinit_effect(inst, FALSE)) == FILTER_ERROR_COULD_NOT_REINIT) {
2603  goto done_video;
2604  }
2605  }
2606 
2607  if (prefs->apply_gamma) {
2608  // do gamma correction of any RGB(A) parameters
2609  gamma_conv_params(((filter_flags & WEED_FILTER_PREF_LINEAR_GAMMA))
2610  ? WEED_GAMMA_LINEAR : WEED_GAMMA_SRGB, inst, TRUE);
2611  gamma_conv_params(((filter_flags & WEED_FILTER_PREF_LINEAR_GAMMA))
2612  ? WEED_GAMMA_LINEAR : WEED_GAMMA_SRGB, inst, FALSE);
2613  }
2614 
2616  weed_set_double_value(inst, WEED_LEAF_FPS, cfile->pb_fps);
2617 
2618  //...finally we are ready to apply the filter
2619 
2620  // TODO - better error handling
2621  //...finally we are ready to apply the filter
2622  retval = run_process_func(inst, tc, key);
2623 
2627  gamma_conv_params(WEED_GAMMA_SRGB, inst, TRUE);
2628  gamma_conv_params(WEED_GAMMA_SRGB, inst, FALSE);
2629 
2630  if (retval == FILTER_ERROR_INVALID_PLUGIN) {
2631  goto done_video;
2632  }
2633 
2634  if (retval == WEED_ERROR_REINIT_NEEDED) {
2635  needs_reinit = TRUE;
2636  }
2637 
2638  for (k = 0; k < num_inc + num_in_alpha; k++) {
2639  channel = get_enabled_channel(inst, k, TRUE);
2641  // free pdata for all alpha in channels, unless orig pdata was passed from a prior fx
2642  layer = layers[in_tracks[k]];
2643  weed_layer_pixel_data_free(channel);
2644  if (!weed_channel_get_pixel_data(channel)) {
2645  weed_layer_t *dupe = weed_get_plantptr_value(layers[in_tracks[i]], WEED_LEAF_DUPLICATE, NULL);
2646  if (dupe) weed_layer_nullify_pixel_data(dupe);
2647  else weed_layer_nullify_pixel_data(layer);
2648  }
2649  }
2650  }
2651 
2652  // now we write our out channels back to layers, leaving the palettes and sizes unchanged
2653 
2654  for (i = k = 0; k < num_out_tracks + num_out_alpha; k++) {
2655  channel = get_enabled_channel(inst, k, FALSE);
2656  if (!channel) break; // compound fx
2657 
2658  layer = layers[out_tracks[i]];
2659  weed_set_boolean_value(layer, "letterboxed", letterbox);
2660 
2661  if (weed_get_boolean_value(channel, WEED_LEAF_HOST_INPLACE, NULL) == WEED_TRUE) continue;
2662 
2664  // out chan data for alpha is freed after all fx proc - in case we need for in chans
2665  continue;
2666  }
2667 
2668  // free any existing pixel_data, we will replace it with the channel data
2670 
2671  if (!weed_layer_copy(layer, channel)) {
2672  retval = FILTER_ERROR_COPYING_FAILED;
2673  goto done_video;
2674  }
2675  i++;
2676  }
2677 
2678  if (needs_reinit) {
2679  retval = FILTER_ERROR_NEEDS_REINIT;
2680  }
2681 
2682  for (i = 0; i < num_inc + num_in_alpha; i++) {
2683  if (weed_get_boolean_value(in_channels[i], WEED_LEAF_HOST_TEMP_DISABLED, NULL) == WEED_TRUE) {
2684  weed_set_boolean_value(in_channels[i], WEED_LEAF_DISABLED, WEED_FALSE);
2685  weed_set_boolean_value(in_channels[i], WEED_LEAF_HOST_TEMP_DISABLED, WEED_FALSE);
2686  }
2687  }
2688 
2689 done_video:
2690 
2691  for (i = 0; i < num_in_tracks; i++) {
2692  weed_plant_t *dupe;
2693  layer = layers[in_tracks[i]];
2694  check_layer_ready(layer);
2695  dupe = weed_get_plantptr_value(layer, WEED_LEAF_DUPLICATE, NULL);
2696  if (dupe) {
2697  weed_layer_free(dupe);
2698  weed_leaf_delete(layer, WEED_LEAF_DUPLICATE);
2699  }
2700  }
2701 
2702  lives_freep((void **)&in_tracks);
2703  lives_freep((void **)&out_tracks);
2704  lives_freep((void **)&in_channels);
2705  lives_freep((void **)&out_channels);
2706 
2707  return retval;
2708 }
2709 
2710 
2711 static lives_filter_error_t enable_disable_channels(weed_plant_t *inst, boolean is_in, int *tracks, int num_tracks,
2712  int nbtracks,
2713  weed_plant_t **layers) {
2714  // handle case where in_channels > than num layers
2715  // either we temporarily disable the channel, or we can't apply the filter
2716  weed_plant_t *filter = weed_instance_get_filter(inst, FALSE);
2717  weed_plant_t *channel, **channels, *chantmpl, **ctmpls = NULL, *layer;
2718  int maxcheck = num_tracks, i, j, num_ctmpls, num_channels;
2719  void **pixdata = NULL;
2720  boolean *mand;
2721 
2722  if (is_in)
2723  channels = weed_get_plantptr_array_counted(inst, WEED_LEAF_IN_CHANNELS, &num_channels);
2724  else
2725  channels = weed_get_plantptr_array_counted(inst, WEED_LEAF_OUT_CHANNELS, &num_channels);
2726 
2727  if (num_tracks > num_channels) maxcheck = num_tracks = num_channels;
2728  if (num_channels > num_tracks) maxcheck = num_channels;
2729 
2730  for (i = 0; i < maxcheck; i++) {
2731  channel = channels[i];
2732  weed_set_boolean_value(channel, WEED_LEAF_HOST_TEMP_DISABLED, WEED_FALSE);
2733 
2734  // skip disabled channels for now
2735  if (weed_channel_is_disabled(channel)) continue;
2736  if (i < num_tracks) layer = layers[tracks[i] + nbtracks];
2737  else layer = NULL;
2738 
2739  if (!layer || ((weed_layer_is_audio(layer) && !weed_layer_get_audio_data(layer, NULL)) ||
2740  (weed_layer_is_video(layer) && (pixdata = weed_layer_get_pixel_data(layer, NULL)) == NULL))) {
2741  // if the layer data is NULL and it maps to a repeating channel, then disable the channel temporarily
2742  chantmpl = weed_channel_get_template(channel);
2743  if (weed_chantmpl_get_max_repeats(chantmpl) != 1) {
2744  if (!weed_channel_is_disabled(channel)) {
2745  weed_set_boolean_value(channel, WEED_LEAF_HOST_TEMP_DISABLED, WEED_TRUE);
2746  } else weed_set_boolean_value(channel, WEED_LEAF_HOST_TEMP_DISABLED, WEED_FALSE);
2747  } else {
2748  lives_free(channels);
2749  lives_freep((void **)&pixdata);
2750  lives_freep((void **)&ctmpls);
2752  }
2753  }
2754  }
2755 
2756  lives_freep((void **)&pixdata);
2757 
2758  // ensure all chantmpls not marked "optional" have at least one corresponding enabled channel
2759  // e.g. we could have disabled all channels from a template with "max_repeats" that is not also "optional"
2760  if (is_in) ctmpls = weed_filter_get_in_chantmpls(filter, &num_ctmpls);
2761  else ctmpls = weed_filter_get_out_chantmpls(filter, &num_ctmpls);
2762 
2763  if (num_ctmpls > 0) {
2764  // step through all the active channels and mark the template as fulfilled
2765  mand = (int *)lives_calloc(num_ctmpls, sizint);
2766  for (i = 0; i < num_channels; i++) {
2767  if (weed_channel_is_disabled(channels[i]) ||
2768  weed_get_boolean_value(channels[i], WEED_LEAF_HOST_TEMP_DISABLED, NULL) == WEED_TRUE) continue;
2769  chantmpl = weed_channel_get_template(channels[i]);
2770  for (j = 0; j < num_ctmpls; j++) {
2771  if (chantmpl == ctmpls[j]) {
2772  mand[j] = TRUE;
2773  break;
2774  }
2775  }
2776  }
2777 
2778  for (j = 0; j < num_ctmpls; j++) if (mand[j] == FALSE && (!weed_chantmpl_is_optional(ctmpls[j]))) {
2779  lives_freep((void **)&ctmpls);
2780  lives_freep((void **)&mand);
2781  lives_free(channels);
2782  lives_freep((void **)&ctmpls);
2784  }
2785  lives_freep((void **)&ctmpls);
2786  lives_freep((void **)&mand);
2787  } else {
2788  lives_free(channels);
2789  lives_freep((void **)&ctmpls);
2791  }
2792 
2793  lives_freep((void **)&ctmpls);
2794  lives_free(channels);
2795  return FILTER_SUCCESS;
2796 }
2797 
2798 
2799 lives_filter_error_t run_process_func(weed_plant_t *instance, weed_timecode_t tc, int key) {
2800  weed_plant_t *filter = weed_instance_get_filter(instance, FALSE);
2801  weed_process_f process_func;
2803  boolean did_thread = FALSE;
2804  int filter_flags = weed_get_int_value(filter, WEED_LEAF_FLAGS, NULL);
2805 #ifdef PLMEMCHECK
2806  int npl;
2807  weed_plant_t *och = weed_instance_get_out_channels(instance, &npl);
2808  if (och)
2809  weed_mem_chkreg(wee_channel_get_pdt, rs, ht, npl);
2810 #endif
2811 
2812  // see if we can multithread
2813  if ((prefs->nfx_threads = future_prefs->nfx_threads) > 1 &&
2814  filter_flags & WEED_FILTER_HINT_MAY_THREAD) {
2815  weed_plant_t **out_channels = weed_instance_get_out_channels(instance, NULL);
2816  if (key == -1 || !filter_mutex_trylock(key)) {
2817  retval = process_func_threaded(instance, tc);
2818  if (key != -1) filter_mutex_unlock(key);
2819  } else retval = FILTER_ERROR_INVALID_PLUGIN;
2820  lives_free(out_channels);
2821  if (retval != FILTER_ERROR_DONT_THREAD) did_thread = TRUE;
2822  }
2823  if (!did_thread) {
2824  // normal single threaded version
2825  process_func = (weed_process_f)weed_get_funcptr_value(filter, WEED_LEAF_PROCESS_FUNC, NULL);
2826  if (process_func && (key == -1 || !filter_mutex_trylock(key))) {
2827  weed_error_t ret = (*process_func)(instance, tc);
2828  if (key != -1) filter_mutex_unlock(key);
2829  if (ret == WEED_ERROR_PLUGIN_INVALID) retval = FILTER_ERROR_INVALID_PLUGIN;
2830  } else retval = FILTER_ERROR_INVALID_PLUGIN;
2831  weed_leaf_delete(instance, WEED_LEAF_HOST_UNUSED);
2832  }
2833 #ifdef PLMEMCHECK
2834  weed_mem_chkreg(NULL, NULL, 0, 0);
2835 #endif
2836  return retval;
2837 }
2838 
2839 
2842 
2845 static lives_filter_error_t weed_apply_audio_instance_inner(weed_plant_t *inst, weed_plant_t *init_event,
2846  weed_plant_t **layers, weed_timecode_t tc, int nbtracks) {
2847  // filter_mutex MUST be unlocked
2848 
2849  // TODO - handle the following:
2850  // input audio_channels are mono, but the plugin NEEDS stereo; we should duplicate the audio.
2851 
2852  // TODO - handle plugin return errors better, eg. NEEDS_REINIT
2853 
2854  int *in_tracks = NULL, *out_tracks = NULL;
2855 
2856  weed_layer_t *layer;
2857  weed_plant_t **in_channels = NULL, **out_channels = NULL, *channel, *chantmpl;
2858 
2859  float **adata;
2860 
2862 
2863  int channel_flags;
2864  int num_in_tracks, num_out_tracks;
2865 
2866  int num_inc;
2867  int key = -1;
2868 
2869  int nchans = 0;
2870  int nsamps = 0;
2871 
2872  register int i, j;
2873 
2874  if (weed_plant_has_leaf(inst, WEED_LEAF_HOST_KEY)) key = weed_get_int_value(inst, WEED_LEAF_HOST_KEY, NULL);
2875 
2876  if (!get_enabled_channel(inst, 0, TRUE)) {
2877  // we process generators elsewhere
2879  }
2880 
2881  if (!init_event) {
2882  num_in_tracks = enabled_in_channels(inst, FALSE);
2883  in_tracks = (int *)lives_calloc(2, sizint);
2884  in_tracks[1] = 1;
2885  if (!get_enabled_channel(inst, 0, FALSE)) num_out_tracks = 0;
2886  else {
2887  num_out_tracks = 1;
2888  out_tracks = (int *)lives_calloc(1, sizint);
2889  }
2890  } else {
2891  in_tracks = weed_get_int_array_counted(init_event, WEED_LEAF_IN_TRACKS, &num_in_tracks);
2892  out_tracks = weed_get_int_array_counted(init_event, WEED_LEAF_OUT_TRACKS, &num_out_tracks);
2893  }
2894 
2895  in_channels = weed_instance_get_in_channels(inst, &num_inc);
2896  if (num_in_tracks > num_inc) num_in_tracks = num_inc;
2897 
2898  for (i = 0; i < num_in_tracks; i++) {
2899  layer = layers[in_tracks[i] + nbtracks];
2900  channel = get_enabled_channel(inst, i, TRUE);
2901 
2902  if (weed_get_boolean_value(channel, WEED_LEAF_HOST_TEMP_DISABLED, NULL) == WEED_TRUE) continue;
2903 
2904  weed_set_int64_value(channel, WEED_LEAF_TIMECODE, tc);
2905  weed_leaf_dup(channel, layer, WEED_LEAF_AUDIO_DATA_LENGTH);
2906  weed_leaf_dup(channel, layer, WEED_LEAF_AUDIO_RATE);
2907  weed_leaf_dup(channel, layer, WEED_LEAF_AUDIO_CHANNELS);
2908 
2909  /* g_print("setting ad for channel %d from layer %d. val %p, eg %f \n", i, in_tracks[i] + nbtracks, weed_get_voidptr_value(layer, "audio_data", NULL), ((float *)(weed_get_voidptr_value(layer, "audio_data", NULL)))[0]); */
2910  weed_leaf_dup(channel, layer, WEED_LEAF_AUDIO_DATA);
2911  /* g_print("setting afterval %p, eg %f \n", weed_get_voidptr_value(channel, "audio_data", NULL), ((float *)(weed_get_voidptr_value(channel, "audio_data", NULL)))[0]); */
2912  }
2913 
2914  // set up our out channels
2915  for (i = 0; i < num_out_tracks; i++) {
2916  weed_plant_t *inchan;
2917 
2918  if (out_tracks[i] != in_tracks[i]) {
2919  retval = FILTER_ERROR_INVALID_TRACK; // we dont do swapping around of audio tracks
2920  goto done_audio;
2921  }
2922 
2923  channel = get_enabled_channel(inst, i, FALSE);
2924  inchan = get_enabled_channel(inst, i, TRUE);
2925  layer = layers[out_tracks[i] + nbtracks];
2926 
2927  weed_set_int64_value(channel, WEED_LEAF_TIMECODE, tc);
2928  chantmpl = weed_channel_get_template(channel);
2929  channel_flags = weed_chantmpl_get_flags(chantmpl);
2930 
2933  if ((channel_flags & WEED_CHANNEL_CAN_DO_INPLACE)
2935  && weed_channel_get_naudchans(channel) == weed_channel_get_naudchans(inchan)) {
2936  weed_set_boolean_value(layer, WEED_LEAF_HOST_INPLACE, WEED_TRUE);
2937  weed_leaf_dup(channel, inchan, WEED_LEAF_AUDIO_DATA);
2938  /* g_print("setting dfff ad for channel %p from chan %p, eg %f \n", weed_get_voidptr_value(channel, "audio_data", NULL), weed_get_voidptr_value(inchan, "audio_data", NULL), ((float *)(weed_get_voidptr_value(layer, "audio_data", NULL)))[0]); */
2939  } else {
2940  nchans = weed_layer_get_naudchans(layer);
2941  adata = (float **)lives_calloc(nchans, sizeof(float *));
2942  nsamps = weed_layer_get_audio_length(layer);
2943  for (i = 0; i < nchans; i++) {
2944  adata[i] = lives_calloc(nsamps, sizeof(float));
2945  if (!adata[i]) {
2946  for (--i; i > 0; i--) lives_free(adata[i]);
2947  lives_free(adata);
2948  retval = FILTER_ERROR_MEMORY_ERROR;
2949  goto done_audio;
2950  }
2951  }
2952  weed_set_boolean_value(layer, WEED_LEAF_HOST_INPLACE, WEED_FALSE);
2953  weed_set_voidptr_array(channel, WEED_LEAF_AUDIO_DATA, nchans, (void **)adata);
2954  lives_free(adata);
2955  }
2956 
2957  weed_leaf_dup(channel, layer, WEED_LEAF_AUDIO_DATA_LENGTH);
2958  weed_leaf_dup(channel, layer, WEED_LEAF_AUDIO_RATE);
2959  weed_leaf_dup(channel, layer, WEED_LEAF_AUDIO_CHANNELS);
2960  }
2961 
2962  if (CURRENT_CLIP_IS_VALID) weed_set_double_value(inst, WEED_LEAF_FPS, cfile->pb_fps);
2963 
2964  //...finally we are ready to apply the filter
2965  retval = run_process_func(inst, tc, key);
2966 
2967  if (retval == FILTER_ERROR_INVALID_PLUGIN) {
2968  retval = FILTER_ERROR_INVALID_PLUGIN;
2969  goto done_audio;
2970  }
2971 
2972  // TODO - handle process errors (e.g. WEED_ERROR_PLUGIN_INVALID)
2973 
2974  // now we write our out channels back to layers
2975  for (i = 0; i < num_out_tracks; i++) {
2976  channel = get_enabled_channel(inst, i, FALSE);
2977  layer = layers[out_tracks[i] + nbtracks];
2978  if (weed_plant_has_leaf(channel, WEED_LEAF_AUDIO_DATA)) {
2980  if (weed_get_boolean_value(layer, WEED_LEAF_HOST_INPLACE, NULL) == WEED_FALSE
2981  && weed_get_boolean_value(layer, WEED_LEAF_HOST_KEEP_ADATA, NULL) == WEED_FALSE) {
2982  adata = (float **)weed_get_voidptr_array_counted(layer, WEED_LEAF_AUDIO_DATA, &nchans);
2983  for (j = 0; j < nchans; j++) lives_freep((void **)&adata[j]);
2984  lives_freep((void **)&adata);
2985  }
2986  weed_leaf_copy(layer, WEED_LEAF_AUDIO_DATA, channel, WEED_LEAF_AUDIO_DATA);
2987  /* g_print("setting 333dfff %d op layer for channel %p from chan %p, eg %f \n", in_tracks[i] + nbtracks, weed_get_voidptr_value(layer, "audio_data", NULL), weed_get_voidptr_value(channel, "audio_data", NULL), ((float *)(weed_get_voidptr_value(layer, "audio_data", NULL)))[0]); */
2988  }
2989  }
2990  for (i = 0; i < num_inc; i++) {
2991  if (weed_get_boolean_value(in_channels[i], WEED_LEAF_HOST_TEMP_DISABLED, NULL) == WEED_TRUE) {
2992  weed_set_boolean_value(in_channels[i], WEED_LEAF_HOST_TEMP_DISABLED, WEED_FALSE);
2993  }
2994  }
2995 
2996 done_audio:
2997  lives_freep((void **)&in_tracks);
2998  lives_freep((void **)&out_tracks);
2999  lives_freep((void **)&in_channels);
3000  lives_freep((void **)&out_channels);
3001 
3002  return retval;
3003 }
3004 
3005 
3031 lives_filter_error_t weed_apply_audio_instance(weed_plant_t *init_event, weed_layer_t **layers, int nbtracks, int nchans,
3032  int64_t nsamps, double arate, weed_timecode_t tc, double * vis) {
3033  lives_filter_error_t retval = FILTER_SUCCESS, retval2;
3034 
3035  weed_plant_t **in_channels = NULL, **out_channels = NULL;
3036 
3037  weed_plant_t *instance = NULL, *orig_inst, *filter;
3038  weed_plant_t *channel = NULL;
3039  weed_plant_t *ctmpl;
3040 
3041  int *in_tracks = NULL, *out_tracks = NULL;
3042 
3043  boolean needs_reinit = FALSE;
3044  boolean was_init_event = FALSE;
3045 
3046  int flags = 0, cflags;
3047  int key = -1;
3048  boolean rvary = FALSE, lvary = FALSE;
3049 
3050  int ntracks = 1;
3051  int numinchans = 0, numoutchans = 0, xnchans, xxnchans, xrate;
3052 
3053  register int i;
3054 
3055  // caller passes an init_event from event list, or an instance (for realtime mode)
3056 
3057  if (WEED_PLANT_IS_FILTER_INSTANCE(init_event)) {
3058  // for realtime, we pass a single instance instead of init_event
3059 
3060  instance = init_event; // needs to be refcounted
3061 
3062  in_channels = weed_get_plantptr_array(instance, WEED_LEAF_IN_CHANNELS, NULL);
3063  out_channels = weed_get_plantptr_array(instance, WEED_LEAF_OUT_CHANNELS, NULL);
3064 
3065  if (!in_channels) {
3066  if (!out_channels && weed_plant_has_leaf(instance, WEED_LEAF_OUT_PARAMETERS)) {
3067  // plugin has no in channels and no out channels, but if it has out paramters then it must be a data processing module
3068 
3069  // if the data feeds into audio effects then we run it now, otherwise we will run it during the video cycle
3071 
3072  // otherwise we just run the process_func() and return
3073 
3074  if (CURRENT_CLIP_IS_VALID) weed_set_double_value(instance, WEED_LEAF_FPS, cfile->pb_fps);
3075  retval = run_process_func(instance, tc, key);
3076  return retval;
3077  }
3078  lives_free(out_channels);
3080  }
3081 
3082  lives_free(in_channels);
3083  lives_free(out_channels);
3084  in_channels = out_channels = NULL;
3085 
3086  // set init_event to NULL before passing it to the inner function
3087  init_event = NULL;
3088 
3089  in_tracks = (int *)lives_calloc(1, sizint);
3090  out_tracks = (int *)lives_calloc(1, sizint);
3091  } else {
3092  // when processing an event list, we pass an init_event
3093  was_init_event = TRUE;
3094  if (weed_plant_has_leaf(init_event, WEED_LEAF_HOST_TAG)) {
3095  char *keystr = weed_get_string_value(init_event, WEED_LEAF_HOST_TAG, NULL);
3096  key = atoi(keystr);
3097  lives_freep((void **)&keystr);
3098  } else return FILTER_ERROR_INVALID_INIT_EVENT;
3099 
3100  in_tracks = weed_get_int_array_counted(init_event, WEED_LEAF_IN_TRACKS, &ntracks);
3101 
3102  if (weed_plant_has_leaf(init_event, WEED_LEAF_OUT_TRACKS))
3103  out_tracks = weed_get_int_array(init_event, WEED_LEAF_OUT_TRACKS, NULL);
3104 
3105  // check instance exists, and interpolate parameters
3106 
3107  if (rte_key_valid(key + 1, FALSE)) {
3108  if ((instance = weed_instance_obtain(key, key_modes[key])) == NULL) {
3109  lives_freep((void **)&in_tracks);
3110  lives_freep((void **)&out_tracks);
3112  }
3113  if (mainw->pchains && mainw->pchains[key]) {
3115  if (!interpolate_params(instance, mainw->pchains[key], tc)) {
3116  weed_instance_unref(instance);
3117  lives_freep((void **)&in_tracks);
3118  lives_freep((void **)&out_tracks);
3120  }
3121  }
3122  } else {
3123  lives_freep((void **)&in_tracks);
3124  lives_freep((void **)&out_tracks);
3126  }
3127  }
3128 
3129  orig_inst = instance;
3130 
3131 audinst1:
3132  lives_freep((void **)&in_channels);
3133  lives_freep((void **)&out_channels);
3134 
3135  in_channels = weed_get_plantptr_array_counted(instance, WEED_LEAF_IN_CHANNELS, &numinchans);
3136  out_channels = weed_get_plantptr_array_counted(instance, WEED_LEAF_OUT_CHANNELS, &numoutchans);
3137 
3138  retval = enable_disable_channels(instance, TRUE, in_tracks, ntracks, nbtracks, layers);
3139  // in theory we should check out channels also, but for now we only load audio filters with one mandatory out
3140 
3141  if (retval != FILTER_SUCCESS) goto audret1;
3142 
3143  filter = weed_instance_get_filter(instance, FALSE);
3144  flags = weed_filter_get_flags(filter);
3145 
3146  if (flags & WEED_FILTER_AUDIO_RATES_MAY_VARY) rvary = TRUE;
3147  if (flags & WEED_FILTER_CHANNEL_LAYOUTS_MAY_VARY) lvary = TRUE;
3148 
3149  if (vis && vis[0] < 0. && in_tracks[0] <= -nbtracks) {
3151  if (numinchans == 1 && numoutchans == 1 && !(flags & WEED_FILTER_IS_CONVERTER)) {
3152  retval = FILTER_ERROR_IS_SCRAP_FILE;
3153  goto audret1;
3154  }
3155  }
3156 
3157  for (i = 0; i < numinchans; i++) {
3158  if ((channel = in_channels[i]) == NULL) continue;
3159  if (weed_channel_is_disabled(channel) ||
3160  weed_get_boolean_value(channel, WEED_LEAF_HOST_TEMP_DISABLED, NULL) == WEED_TRUE) continue;
3161 
3162  xnchans = nchans; // preferred value
3163  ctmpl = weed_channel_get_template(channel);
3164  cflags = weed_chantmpl_get_flags(ctmpl);
3165  // TODO ** - can be list
3166  if (lvary && weed_plant_has_leaf(ctmpl, WEED_LEAF_AUDIO_CHANNELS))
3167  xnchans = weed_get_int_value(ctmpl, WEED_LEAF_AUDIO_CHANNELS, NULL);
3168  else if (weed_plant_has_leaf(filter, WEED_LEAF_MAX_AUDIO_CHANNELS)) {
3169  xxnchans = weed_get_int_value(filter, WEED_LEAF_MAX_AUDIO_CHANNELS, NULL);
3170  if (xxnchans > 0 && xxnchans < nchans) xnchans = xxnchans;
3171  }
3172  if (xnchans != nchans) {
3174  goto audret1;
3175  }
3176  if (weed_get_int_value(channel, WEED_LEAF_AUDIO_CHANNELS, NULL) != nchans
3177  && (cflags & WEED_CHANNEL_REINIT_ON_LAYOUT_CHANGE))
3178  needs_reinit = TRUE;
3179  else weed_set_int_value(channel, WEED_LEAF_AUDIO_CHANNELS, nchans);
3180 
3181  //if ((weed_plant_has_leaf(ctmpl, WEED_LEAF_AUDIO_CHANNEL_LAYOUT) {
3182  // TODO - check layouts if present, make sure it supports mono / stereo
3183 
3184  xrate = arate;
3185  // TODO : can be list
3186  if (rvary && weed_plant_has_leaf(ctmpl, WEED_LEAF_AUDIO_RATE))
3187  xrate = weed_get_int_value(ctmpl, WEED_LEAF_AUDIO_RATE, NULL);
3188  else if (weed_plant_has_leaf(filter, WEED_LEAF_AUDIO_RATE))
3189  xrate = weed_get_int_value(filter, WEED_LEAF_AUDIO_RATE, NULL);
3190  if (arate != xrate) {
3191  // TODO - resample
3193  goto audret1;
3194  }
3195 
3196  if (weed_get_int_value(channel, WEED_LEAF_AUDIO_RATE, NULL) != arate) {
3197  if (cflags & WEED_CHANNEL_REINIT_ON_RATE_CHANGE) {
3198  needs_reinit = TRUE;
3199  }
3200  }
3201 
3202  weed_set_int_value(channel, WEED_LEAF_AUDIO_RATE, arate);
3203  }
3204 
3205  for (i = 0; i < numoutchans; i++) {
3206  if ((channel = out_channels[i]) == NULL) continue;
3207  if (weed_channel_is_disabled(channel) ||
3208  weed_get_boolean_value(channel, WEED_LEAF_HOST_TEMP_DISABLED, NULL) == WEED_TRUE) continue;
3209  xnchans = nchans; // preferred value
3210  ctmpl = weed_channel_get_template(channel);
3211  cflags = weed_chantmpl_get_flags(ctmpl);
3212  // TODO ** - can be list
3213  if (lvary && weed_plant_has_leaf(ctmpl, WEED_LEAF_AUDIO_CHANNELS))
3214  xnchans = weed_get_int_value(ctmpl, WEED_LEAF_AUDIO_CHANNELS, NULL);
3215  else if (weed_plant_has_leaf(filter, WEED_LEAF_MAX_AUDIO_CHANNELS)) {
3216  xxnchans = weed_get_int_value(filter, WEED_LEAF_MAX_AUDIO_CHANNELS, NULL);
3217  if (xxnchans > 0 && xxnchans < nchans) xnchans = xxnchans;
3218  }
3219  if (xnchans != nchans) {
3221  goto audret1;
3222  }
3223  if (weed_get_int_value(channel, WEED_LEAF_AUDIO_CHANNELS, NULL) != nchans
3224  && (cflags & WEED_CHANNEL_REINIT_ON_LAYOUT_CHANGE))
3225  needs_reinit = TRUE;
3226  else weed_set_int_value(channel, WEED_LEAF_AUDIO_CHANNELS, nchans);
3227 
3228  //if ((weed_plant_has_leaf(ctmpl, WEED_LEAF_AUDIO_CHANNEL_LAYOUT) {
3229  // TODO - check layouts if present, make sure it supports mono / stereo
3230 
3231  xrate = arate;
3232  // TODO : can be list
3233  if (rvary && weed_plant_has_leaf(ctmpl, WEED_LEAF_AUDIO_RATE))
3234  xrate = weed_get_int_value(ctmpl, WEED_LEAF_AUDIO_RATE, NULL);
3235  else if (weed_plant_has_leaf(filter, WEED_LEAF_AUDIO_RATE))
3236  xrate = weed_get_int_value(filter, WEED_LEAF_AUDIO_RATE, NULL);
3237  if (arate != xrate) {
3238  // TODO - resample
3240  goto audret1;
3241  }
3242 
3243  if (weed_get_int_value(channel, WEED_LEAF_AUDIO_RATE, NULL) != arate) {
3244  if (cflags & WEED_CHANNEL_REINIT_ON_RATE_CHANGE) {
3245  needs_reinit = TRUE;
3246  }
3247  }
3248 
3249  weed_set_int_value(channel, WEED_LEAF_AUDIO_RATE, arate);
3250  }
3251 
3252  if (needs_reinit) {
3253  // - deinit inst
3254  // mutex locked
3255  if (key != -1) filter_mutex_lock(key);
3256  weed_call_deinit_func(instance);
3257  if (key != -1) filter_mutex_unlock(key);
3258 
3259  // - init inst
3260  if (weed_plant_has_leaf(filter, WEED_LEAF_INIT_FUNC)) {
3261  weed_init_f init_func = (weed_init_f)weed_get_funcptr_value(filter, WEED_LEAF_INIT_FUNC, NULL);
3262  if (init_func) {
3263  char *cwd = cd_to_plugin_dir(filter);
3264  if ((*init_func)(instance) != WEED_SUCCESS) {
3265  key_to_instance[key][key_modes[key]] = NULL;
3266  lives_chdir(cwd, FALSE);
3267  lives_free(cwd);
3268  lives_freep((void **)&in_channels);
3269  lives_freep((void **)&out_channels);
3271  goto audret1;
3272  }
3273  lives_chdir(cwd, FALSE);
3274  lives_free(cwd);
3275  }
3276  }
3277  weed_set_boolean_value(instance, WEED_LEAF_HOST_INITED, WEED_TRUE);
3278  weed_set_boolean_value(instance, WEED_LEAF_HOST_UNUSED, WEED_TRUE);
3279  retval = FILTER_INFO_REINITED;
3280  }
3281 
3282  // apply visibility mask to volume values
3283  if (vis && (flags & WEED_FILTER_IS_CONVERTER)) {
3284  int vmaster = get_master_vol_param(filter, FALSE);
3285  if (vmaster != -1) {
3286  int nvals;
3287  weed_plant_t **in_params = weed_instance_get_in_params(instance, NULL);
3288  double *fvols = weed_get_double_array_counted(in_params[vmaster], WEED_LEAF_VALUE, &nvals);
3289  for (i = 0; i < nvals; i++) {
3290  fvols[i] = fvols[i] * vis[in_tracks[i] + nbtracks];
3291  if (vis[in_tracks[i] + nbtracks] < 0.) fvols[i] = -fvols[i];
3292  }
3293  if (!filter_mutex_trylock(key)) {
3294  weed_set_double_array(in_params[vmaster], WEED_LEAF_VALUE, nvals, fvols);
3295  filter_mutex_unlock(key);
3296  //set_copy_to(instance, vmaster, TRUE);
3297  }
3298  lives_freep((void **)&fvols);
3299  lives_freep((void **)&in_params);
3300  }
3301  }
3302 
3303  retval2 = weed_apply_audio_instance_inner(instance, init_event, layers, tc, nbtracks);
3304  if (retval == FILTER_SUCCESS) retval = retval2;
3305 
3306  if (retval2 == FILTER_SUCCESS && was_init_event) {
3307  // handle compound filters
3308  if ((instance = get_next_compound_inst(instance)) != NULL) goto audinst1;
3309  }
3310 
3311  // TODO - handle invalid, needs_reinit etc.
3312 
3313  if (was_init_event) weed_instance_unref(orig_inst);
3314 
3315 audret1:
3316  lives_freep((void **)&in_channels);
3317  lives_freep((void **)&out_channels);
3318 
3319  lives_freep((void **)&in_tracks);
3320  lives_freep((void **)&out_tracks);
3321 
3322  return retval;
3323 }
3324 
3325 
3346 static void weed_apply_filter_map(weed_plant_t **layers, weed_plant_t *filter_map, weed_timecode_t tc, void ***pchains) {
3347  weed_plant_t *instance, *orig_inst;
3348  weed_plant_t *init_event;
3349  lives_filter_error_t retval;
3350 
3351  char *keystr;
3352 
3353  void **init_events;
3354 
3355  weed_error_t filter_error;
3356  int key, num_inst;
3357 
3358  boolean needs_reinit;
3359 
3360  if (!filter_map || !weed_plant_has_leaf(filter_map, WEED_LEAF_INIT_EVENTS) ||
3361  !weed_get_voidptr_value(filter_map, WEED_LEAF_INIT_EVENTS, NULL)) return;
3362 
3363  init_events = weed_get_voidptr_array_counted(filter_map, WEED_LEAF_INIT_EVENTS, &num_inst);
3364 
3365  for (int i = 0; i < num_inst; i++) {
3366  init_event = (weed_plant_t *)init_events[i];
3367 
3368  if (weed_plant_has_leaf(init_event, WEED_LEAF_HOST_TAG)) {
3369  keystr = weed_get_string_value(init_event, WEED_LEAF_HOST_TAG, NULL);
3370  key = atoi(keystr);
3371  lives_free(keystr);
3372  if (rte_key_valid(key + 1, FALSE)) {
3373  if ((instance = weed_instance_obtain(key, key_modes[key])) == NULL) continue;
3374 
3375  if (is_pure_audio(instance, FALSE)) {
3376  weed_instance_unref(instance);
3377  continue; // audio effects are applied in the audio renderer
3378  }
3379 
3380  orig_inst = instance;
3381 
3382  if (!LIVES_IS_PLAYING && mainw->multitrack && mainw->multitrack->current_rfx
3383  && mainw->multitrack->current_rfx->source
3384  && (mainw->multitrack->solo_inst || instance == mainw->multitrack->current_rfx->source)) {
3385  if (instance == mainw->multitrack->current_rfx->source) {
3386  void **pchain = mt_get_pchain();
3387  // interpolation can be switched of by setting mainw->no_interp
3388  if (!mainw->no_interp && pchain) {
3389  interpolate_params(instance, pchain, tc); // interpolate parameters for preview
3390  }
3391  } else {
3392  if (mainw->multitrack->solo_inst) {
3393  weed_instance_unref(instance);
3394  continue;
3395  }
3396  }
3397  } else {
3398  int idx;
3399  char *filter_hash;
3400  boolean is_valid = FALSE;
3401  if (!weed_plant_has_leaf(init_events[i], WEED_LEAF_OUT_TRACKS)
3402  || !weed_plant_has_leaf(init_events[i], WEED_LEAF_IN_TRACKS)) continue;
3403  if (mainw->multitrack && mainw->multitrack->solo_inst && mainw->multitrack->init_event
3404  && !LIVES_IS_PLAYING && mainw->multitrack->init_event != init_events[i]) continue;
3405  filter_hash = weed_get_string_value(init_events[i], WEED_LEAF_FILTER, NULL);
3406  if ((idx = weed_get_idx_for_hashname(filter_hash, TRUE)) != -1) {
3407  weed_plant_t *filter = get_weed_filter(idx);
3408  if (has_video_chans_in(filter, FALSE) && has_video_chans_out(filter, FALSE)) {
3409  int nintracks, *in_tracks = weed_get_int_array_counted(init_events[i], WEED_LEAF_IN_TRACKS, &nintracks);
3410  for (register int j = 0; j < nintracks; j++) {
3411  if (j >= mainw->num_tracks) break;
3412  if (mainw->active_track_list[in_tracks[j]] > 0) {
3413  is_valid = TRUE;
3414  break;
3415  }
3416  }
3417  lives_free(in_tracks);
3418  }
3419  }
3420  lives_free(filter_hash);
3422  if (!is_valid) continue;
3423 
3424  if (pchains && pchains[key]) {
3425  interpolate_params(instance, pchains[key], tc); // interpolate parameters during playback
3426  }
3427  }
3428  /*
3429  // might be needed for multitrack ???
3430  if (mainw->pconx!=NULL) {
3431  int key=i;
3432  int mode=key_modes[i];
3433  if (weed_plant_has_leaf(instance,WEED_LEAF_HOST_MODE)) {
3434  key=weed_get_int_value(instance,WEED_LEAF_HOST_KEY,&error);
3435  mode=weed_get_int_value(instance,WEED_LEAF_HOST_MODE,&error);
3436  }
3437  // chain any data pipelines
3438  pconx_chain_data(key,mode);
3439  }*/
3440 
3441 apply_inst2:
3442 
3443  if (weed_plant_has_leaf(instance, WEED_LEAF_HOST_NEXT_INSTANCE)) {
3444  // chain any internal data pipelines for compound fx
3445  needs_reinit = pconx_chain_data_internal(instance);
3446  if (needs_reinit) {
3447  if ((retval = weed_reinit_effect(instance, FALSE)) == FILTER_ERROR_COULD_NOT_REINIT) {
3448  weed_instance_unref(orig_inst);
3449  if (!LIVES_IS_PLAYING && mainw->multitrack && mainw->multitrack->solo_inst &&
3450  orig_inst == mainw->multitrack->solo_inst) break;
3451  continue;
3452  }
3453  }
3454  }
3455 
3456  //if (LIVES_IS_PLAYING)
3457  filter_error = weed_apply_instance(instance, init_event, layers, mainw->pwidth, mainw->pheight, tc);
3458 
3459  //filter_error = weed_apply_instance(instance, init_event, layers, 0, 0, tc);
3460 
3461  if (filter_error == WEED_SUCCESS && (instance = get_next_compound_inst(instance)) != NULL) goto apply_inst2;
3462  if (filter_error == WEED_ERROR_REINIT_NEEDED) {
3463  if ((retval = weed_reinit_effect(instance, FALSE)) == FILTER_ERROR_COULD_NOT_REINIT) {
3464  weed_instance_unref(orig_inst);
3465  if (!LIVES_IS_PLAYING && mainw->multitrack && mainw->multitrack->solo_inst &&
3466  orig_inst == mainw->multitrack->solo_inst) break;
3467  continue;
3468  }
3469  }
3470  //if (filter_error!=FILTER_SUCCESS) lives_printerr("Render error was %d\n",filter_error);
3471  if (!LIVES_IS_PLAYING && mainw->multitrack && mainw->multitrack->solo_inst &&
3472  orig_inst == mainw->multitrack->solo_inst) {
3473  weed_instance_unref(orig_inst);
3474  break;
3475  }
3476  weed_instance_unref(orig_inst);
3477  }
3478  }
3479  }
3480  lives_freep((void **)&init_events);
3481 }
3482 
3483 
3484 weed_plant_t *weed_apply_effects(weed_plant_t **layers, weed_plant_t *filter_map, weed_timecode_t tc,
3485  int opwidth, int opheight, void ***pchains) {
3486  // given a stack of layers, a filter map, a timecode and possibly paramater chains
3487  // apply the effects in the filter map, and return a single layer as the result
3488 
3489  // if all goes wrong we return a blank 4x4 RGB24 layer (TODO - return a NULL ?)
3490 
3491  // returned layer can be of any width,height,palette
3492  // caller should free all input layers, WEED_LEAF_PIXEL_DATA of all non-returned layers is free()d here
3493 
3494  weed_plant_t *filter, *instance, *orig_inst, *instance2, *layer;
3495  lives_filter_error_t filter_error;
3496 
3497  boolean needs_reinit;
3498 
3499  int output = -1;
3500  int clip;
3501  int easeval = 0;
3502 
3503  int i;
3504 
3505  if (mainw->is_rendering && !(mainw->proc_ptr && mainw->preview)) {
3506  // rendering from multitrack
3507  if (filter_map && layers[0]) {
3508  weed_apply_filter_map(layers, filter_map, tc, pchains);
3509  }
3510  }
3511 
3512  // free playback: we will have here only one or two layers, and no filter_map.
3513  // Effects are applied in key order, in tracks are 0 and 1, out track is 0
3514  else {
3515  weed_plant_t *gui;
3516  for (i = 0; i < FX_KEYS_MAX_VIRTUAL; i++) {
3517  if (rte_key_valid(i + 1, TRUE)) {
3518  if (!(rte_key_is_enabled(1 + i))) {
3519  // if anything is connected to ACTIVATE, the fx may be activated
3520  pconx_chain_data(i, key_modes[i], FALSE);
3521  }
3522  if (rte_key_is_enabled(1 + i)) {
3523  mainw->osc_block = TRUE;
3524  if ((instance = weed_instance_obtain(i, key_modes[i])) == NULL) {
3525  mainw->osc_block = FALSE;
3526  continue;
3527  }
3528  filter = weed_instance_get_filter(instance, TRUE);
3529 
3530  if (is_pure_audio(filter, TRUE)) {
3531  weed_instance_unref(instance);
3532  continue;
3533  }
3534  gui = weed_instance_get_gui(instance, FALSE);
3535  if (weed_get_int_value(gui, WEED_LEAF_EASE_OUT, NULL) > 0) {
3536  // if the plugin is easing out, check if it finished
3537  if (!weed_plant_has_leaf(instance, WEED_LEAF_AUTO_EASING)) { // if auto_Easing then we'll deinit it on the event_list
3538  if (!weed_get_int_value(gui, WEED_LEAF_EASE_OUT_FRAMES, NULL)) {
3539  // easing finished, deinit it
3540  uint64_t new_rte = GU641 << (i);
3541  // record
3542  if (init_events[i]) {
3543  // if we are recording, mark the number of frames to ease out
3544  // we'll need to repeat the same process during preview / rendering
3545  // - when we hit the init_event, we'll find the deinit, then work back x frames and mark easing start
3546  weed_set_int_value(init_events[i], WEED_LEAF_EASE_OUT,
3547  weed_get_int_value(instance, WEED_LEAF_EASE_OUT, NULL));
3548  }
3549  weed_instance_unref(instance);
3550  filter_mutex_lock(i);
3551  weed_deinit_effect(i);
3552  if (mainw->rte & new_rte) {
3553  mainw->rte ^= new_rte;
3554  if (rte_window) rtew_set_keych(i, FALSE);
3556  }
3558  continue;
3559  // *INDENT-OFF*
3560  }}}
3561  // *INDENT-ON*
3562 
3563  if (mainw->pchains && mainw->pchains[i]) {
3564  if (!filter_mutex_trylock(i)) {
3565  interpolate_params(instance, mainw->pchains[i], tc); // interpolate parameters during preview
3567  }
3568  }
3569  //filter = weed_instance_get_filter(instance, TRUE);
3570 
3571  // TODO *** enable this, and apply pconx to audio gens in audio.c
3572  if (!is_pure_audio(filter, TRUE)) {
3573  if (mainw->pconx && !(mainw->preview || mainw->is_rendering)) {
3574  // chain any data pipelines
3575  needs_reinit = pconx_chain_data(i, key_modes[i], FALSE);
3576 
3577  // if anything is connected to ACTIVATE, the fx may be activated
3578  if ((instance2 = weed_instance_obtain(i, key_modes[i])) == NULL) {
3579  weed_instance_unref(instance);
3580  continue;
3581  }
3582  weed_instance_unref(instance);
3583  instance = instance2;
3584  if (needs_reinit) {
3585  if ((filter_error = weed_reinit_effect(instance, FALSE)) == FILTER_ERROR_COULD_NOT_REINIT) {
3586  weed_instance_unref(instance);
3587  continue;
3588  // *INDENT-OFF*
3589  }}}}
3590  // *INDENT-ON*
3591 
3592  orig_inst = instance;
3593 
3594 apply_inst3:
3595 
3596  if (weed_plant_has_leaf(instance, WEED_LEAF_HOST_NEXT_INSTANCE)) {
3597  // chain any internal data pipelines for compound fx
3598  needs_reinit = pconx_chain_data_internal(instance);
3599  if (needs_reinit) {
3600  if ((filter_error = weed_reinit_effect(instance, FALSE)) == FILTER_ERROR_COULD_NOT_REINIT) {
3601  weed_instance_unref(instance);
3602  continue;
3603  // *INDENT-OFF*
3604  }}}
3605  // *INDENT-ON*
3606 
3607  filter_error = weed_apply_instance(instance, NULL, layers, opwidth, opheight, tc);
3608 
3609  if (easeval > 0 && !weed_plant_has_leaf(orig_inst, WEED_LEAF_AUTO_EASING)) {
3610  // if the plugin is supposed to be easing out, make sure it is really
3611  weed_plant_t *gui = weed_instance_get_gui(orig_inst, FALSE);
3612  if (gui) {
3613  int xeaseval = weed_get_int_value(gui, WEED_LEAF_EASE_OUT_FRAMES, NULL), myeaseval;
3614  myeaseval = weed_get_int_value(instance, WEED_LEAF_HOST_EASE_OUT_COUNT, NULL);
3615  if (xeaseval > myeaseval) {
3616  uint64_t new_rte = GU641 << (i);
3617  filter_mutex_lock(i);
3618  weed_instance_unref(orig_inst);
3619  if (mainw->rte & new_rte) {
3620  mainw->rte ^= new_rte;
3621  if (rte_window) rtew_set_keych(i, FALSE);
3623  }
3624  weed_deinit_effect(i);
3626  continue;
3627  }
3628  // count how many frames to ease out
3629  weed_set_int_value(instance, WEED_LEAF_HOST_EASE_OUT_COUNT,
3630  weed_get_int_value(instance, WEED_LEAF_HOST_EASE_OUT_COUNT, NULL) + 1);
3631  }
3632  }
3633  if (filter_error == FILTER_ERROR_NEEDS_REINIT) {
3634  // TODO...
3635  }
3636  if (filter_error == FILTER_INFO_REINITED)
3637  update_widget_vis(NULL, i, key_modes[i]);
3638  //#define DEBUG_RTE
3639 #ifdef DEBUG_RTE
3640  if (filter_error != FILTER_SUCCESS) lives_printerr("Render error was %d\n", filter_error);
3641 #endif
3642  if (filter_error == FILTER_SUCCESS && (instance = get_next_compound_inst(instance))) goto apply_inst3;
3643 
3644  if (mainw->pconx && (filter_error == FILTER_SUCCESS || filter_error == FILTER_INFO_REINITED
3645  || filter_error == FILTER_INFO_REDRAWN)) {
3646  pconx_chain_data_omc(orig_inst, i, key_modes[i]);
3647  }
3648  weed_instance_unref(orig_inst);
3649  // *INDENT-OFF*
3650  }}}}
3651  // *INDENT-ON*
3652 
3653  // TODO - set mainw->vpp->play_params from connected out params and out alphas
3654 
3655  if (!mainw->is_rendering) {
3656  mainw->osc_block = FALSE;
3657  }
3658 
3659  // caller should free all layers, but here we will free all other pixel_data
3660 
3661  for (i = 0; layers[i]; i++) {
3662  if (layers[i] == mainw->blend_layer) mainw->blend_layer = NULL;
3663 
3664  if ((mainw->multitrack && i == mainw->multitrack->preview_layer) || ((!mainw->multitrack ||
3665  mainw->multitrack->preview_layer < 0) &&
3666  ((weed_get_voidptr_value(layers[i], WEED_LEAF_PIXEL_DATA, NULL)) ||
3667  (weed_get_int_value(layers[i], WEED_LEAF_FRAME, NULL) != 0 &&
3668  (LIVES_IS_PLAYING || !mainw->multitrack || !mainw->multitrack->current_rfx ||
3669  (!mainw->multitrack->init_event || tc < get_event_timecode(mainw->multitrack->init_event) ||
3670  (mainw->multitrack->init_event == mainw->multitrack->avol_init_event) ||
3671  tc > get_event_timecode(weed_get_plantptr_value
3672  (mainw->multitrack->init_event, WEED_LEAF_DEINIT_EVENT, NULL)))))))) {
3673  if (output != -1 || weed_get_int_value(layers[i], WEED_LEAF_CLIP, NULL) == -1) {
3674  if (!weed_plant_has_leaf(layers[i], WEED_LEAF_PIXEL_DATA)) continue;
3675  check_layer_ready(layers[i]);
3676  weed_layer_pixel_data_free(layers[i]);
3677  } else output = i;
3678  } else {
3679  if (!weed_plant_has_leaf(layers[i], WEED_LEAF_PIXEL_DATA)) continue;
3680  check_layer_ready(layers[i]);
3681  weed_layer_pixel_data_free(layers[i]);
3682  }
3683  }
3684 
3685  if (output == -1) {
3686  // blank frame - e.g. for multitrack
3687  return create_blank_layer(NULL, NULL, opwidth, opheight, WEED_PALETTE_END);
3688  }
3689 
3690  layer = layers[output];
3691  clip = weed_get_int_value(layer, WEED_LEAF_CLIP, NULL);
3692 
3693  // frame is pulled uneffected here. TODO: Try to pull at target output palette
3694  if (!weed_get_voidptr_value(layer, WEED_LEAF_PIXEL_DATA, NULL)) {
3695  check_layer_ready(layer);
3696  if (!pull_frame_at_size(layer, get_image_ext_for_type(mainw->files[clip]->img_type), tc, opwidth, opheight,
3697  WEED_PALETTE_END)) {
3698  char *msg = lives_strdup_printf("weed_apply_effects created empty pixel_data at tc %ld, map was %p, clip = %d, frame = %d",
3699  tc, filter_map, clip, weed_get_int_value(layer, WEED_LEAF_FRAME, NULL));
3700  LIVES_WARN(msg);
3701  lives_free(msg);
3702  create_blank_layer(layer, get_image_ext_for_type(mainw->files[clip]->img_type), opwidth, opheight, WEED_PALETTE_END);
3703  }
3704  }
3705  return layer;
3706 }
3707 
3708 
3709 void weed_apply_audio_effects(weed_plant_t *filter_map, weed_layer_t **layers, int nbtracks, int nchans, int64_t nsamps,
3710  double arate, weed_timecode_t tc, double * vis) {
3711  int i, num_inst, error;
3712  void **init_events;
3713  weed_plant_t *init_event, *filter;
3714  char *fhash;
3715 
3716  // this is called during rendering - we will have previously received a
3717  // filter_map event and now we apply this to audio (abuf)
3718  // abuf will be a NULL terminated array of float audio
3719 
3720  // the results of abuf[0] and abuf[1] (for stereo) will be written to fileno
3721  if (!filter_map || !weed_plant_has_leaf(filter_map, WEED_LEAF_INIT_EVENTS) ||
3722  !weed_get_voidptr_value(filter_map, WEED_LEAF_INIT_EVENTS, NULL)) {
3723  return;
3724  }
3726  init_events = weed_get_voidptr_array_counted(filter_map, WEED_LEAF_INIT_EVENTS, &num_inst);
3727  for (i = 0; i < num_inst; i++) {
3728  init_event = (weed_plant_t *)init_events[i];
3729  fhash = weed_get_string_value(init_event, WEED_LEAF_FILTER, &error);
3731  lives_freep((void **)&fhash);
3732  if (has_audio_chans_in(filter, FALSE) && !has_video_chans_in(filter, FALSE) && !has_video_chans_out(filter, FALSE) &&
3733  has_audio_chans_out(filter, FALSE)) {
3734  weed_apply_audio_instance(init_event, layers, nbtracks, nchans, nsamps, arate, tc, vis);
3735  }
3736  // TODO *** - also run any pure data processing filters which feed into audio filters
3737  }
3738  lives_freep((void **)&init_events);
3739  mainw->pchains = NULL;
3740 }
3741 
3742 
3743 void weed_apply_audio_effects_rt(weed_layer_t *alayer, weed_timecode_t tc, boolean analysers_only, boolean is_audio_thread) {
3744  weed_plant_t *instance, *filter, *orig_inst, *new_inst;
3745  lives_filter_error_t filter_error;
3746  weed_layer_t *layers[1];
3747  boolean needs_reinit;
3748  int nsamps, arate, nchans;
3749 
3750  // free playback: apply any audio filters or analysers (but not generators)
3751  // Effects are applied in key order
3752 
3753  if (!alayer) return;
3754 
3755  nchans = weed_layer_get_naudchans(alayer);
3756  arate = weed_layer_get_audio_rate(alayer);
3757  nsamps = weed_layer_get_audio_length(alayer);
3758 
3759  for (int i = 0; i < FX_KEYS_MAX_VIRTUAL; i++) {
3760  if (rte_key_valid(i + 1, TRUE)) {
3761  if (!(rte_key_is_enabled(1 + i))) {
3762  // if anything is connected to ACTIVATE, the fx may be activated
3763  if (is_audio_thread) pconx_chain_data(i, key_modes[i], TRUE);
3764  }
3765  if (rte_key_is_enabled(1 + i)) {
3766  mainw->osc_block = TRUE;
3767 
3768  if ((orig_inst = instance = weed_instance_obtain(i, key_modes[i])) == NULL) {
3769  mainw->osc_block = FALSE;
3770  continue;
3771  }
3772 
3773  filter = weed_instance_get_filter(instance, FALSE);
3774 
3775  if (!has_audio_chans_in(filter, FALSE) || has_video_chans_in(filter, FALSE) || has_video_chans_out(filter, FALSE)) {
3776  weed_instance_unref(instance);
3777  mainw->osc_block = FALSE;
3778  continue;
3779  }
3780 
3781  if (analysers_only && has_audio_chans_out(filter, FALSE)) {
3782  weed_instance_unref(instance);
3783  continue;
3784  }
3785 
3786  if (mainw->pchains && mainw->pchains[i]) {
3787  if (!filter_mutex_trylock(i)) {
3788  interpolate_params(instance, mainw->pchains[i], tc); // interpolate parameters during preview
3790  }
3791  }
3792  if (mainw->pconx && is_audio_thread) {
3793  // chain any data pipelines
3794 
3795  needs_reinit = pconx_chain_data(i, key_modes[i], TRUE);
3796 
3797  // if anything is connected to ACTIVATE, the fx may be deactivated
3798  if ((new_inst = weed_instance_obtain(i, key_modes[i])) == NULL) {
3799  weed_instance_unref(instance);
3800  mainw->osc_block = FALSE;
3801  continue;
3802  }
3803 
3804  weed_instance_unref(instance);
3805  instance = new_inst;
3806 
3807  if (needs_reinit) {
3808  if ((filter_error = weed_reinit_effect(instance, FALSE)) == FILTER_ERROR_COULD_NOT_REINIT) {
3809  weed_instance_unref(instance);
3810  continue;
3811  // *INDENT-OFF*
3812  }}}
3813  // *INDENT-ON*
3814 
3815  orig_inst = instance;
3816 
3817 apply_audio_inst2:
3818 
3819  if (weed_plant_has_leaf(instance, WEED_LEAF_HOST_NEXT_INSTANCE)) {
3820  // chain any internal data pipelines for compound fx
3821  needs_reinit = pconx_chain_data_internal(instance);
3822  if (needs_reinit) {
3823  if ((filter_error = weed_reinit_effect(instance, FALSE)) == FILTER_ERROR_COULD_NOT_REINIT) {
3824  weed_instance_unref(instance);
3825  continue;
3826  }
3827  }
3828  }
3829 
3830  layers[0] = alayer;
3831  // will unref instance
3832  filter_error = weed_apply_audio_instance(instance, layers, 0, nchans, nsamps, arate, tc, NULL);
3833 
3834  if (filter_error == FILTER_SUCCESS && (instance = get_next_compound_inst(instance))) {
3835  goto apply_audio_inst2;
3836  }
3837  if (filter_error == FILTER_ERROR_NEEDS_REINIT) {
3838  // TODO...
3839  }
3840 
3841  weed_instance_unref(orig_inst);
3842 
3843  if (filter_error == FILTER_INFO_REINITED) update_widget_vis(NULL, i, key_modes[i]); // redraw our paramwindow
3844 #ifdef DEBUG_RTE
3845  if (filter_error != FILTER_SUCCESS) lives_printerr("Render error was %d\n", filter_error);
3846 #endif
3847  mainw->osc_block = FALSE;
3848 
3849  if (mainw->pconx && (filter_error == FILTER_SUCCESS || filter_error == FILTER_INFO_REINITED
3850  || filter_error == FILTER_INFO_REDRAWN)) {
3851  pconx_chain_data_omc((instance = weed_instance_obtain(i, key_modes[i])), i, key_modes[i]);
3852  weed_instance_unref(instance);
3853  // *INDENT-OFF*
3854  }}}}
3855  // *INDENT-ON*
3856 }
3857 
3858 
3859 boolean has_audio_filters(lives_af_t af_type) {
3860  // do we have any active audio filters (excluding audio generators) ?
3861  // called from audio thread during playback
3862  weed_plant_t *filter;
3863  int idx;
3864  register int i;
3865 
3866  if (af_type == AF_TYPE_A && mainw->audio_frame_buffer) return TRUE;
3867 
3868  for (i = 0; i < FX_KEYS_MAX_VIRTUAL; i++) {
3869  if (rte_key_valid(i + 1, TRUE)) {
3870  if (rte_key_is_enabled(1 + i)) {
3871  idx = key_to_fx[i][key_modes[i]];
3872  filter = weed_filters[idx];
3873  if (has_audio_chans_in(filter, FALSE) && !has_video_chans_in(filter, FALSE) && !has_video_chans_out(filter, FALSE)) {
3874  if ((af_type == AF_TYPE_A && has_audio_chans_out(filter, FALSE)) || // check for analysers only
3875  (af_type == AF_TYPE_NONA && !has_audio_chans_out(filter, FALSE))) // check for non-analysers only
3876  continue;
3877  return TRUE;
3878  // *INDENT-OFF*
3879  }}}}
3880  // *INDENT-ON*
3881 
3882  return FALSE;
3883 }
3884 
3885 
3886 boolean has_video_filters(boolean analysers_only) {
3887  // do we have any active video filters (excluding generators) ?
3888  weed_plant_t *filter;
3889  int idx;
3890  register int i;
3891 
3892  for (i = 0; i < FX_KEYS_MAX_VIRTUAL; i++) {
3893  if (rte_key_valid(i + 1, TRUE)) {
3894  if (rte_key_is_enabled(1 + i)) {
3895  idx = key_to_fx[i][key_modes[i]];
3896  filter = weed_filters[idx];
3897  if (has_video_chans_in(filter, FALSE)) {
3898  if (analysers_only && has_video_chans_out(filter, FALSE)) continue;
3899  return TRUE;
3900  // *INDENT-OFF*
3901  }}}}
3902  // *INDENT-ON*
3903 
3904  return FALSE;
3905 }
3906 
3907 
3909 
3910 static int check_weed_plugin_info(weed_plant_t *plugin_info) {
3911  // verify the plugin_info returned from the plugin
3912  // TODO - print descriptive errors
3913  if (!weed_plant_has_leaf(plugin_info, WEED_LEAF_HOST_INFO)) return -1;
3914  if (!weed_plant_has_leaf(plugin_info, WEED_LEAF_VERSION)) return -2;
3915  if (!weed_plant_has_leaf(plugin_info, WEED_LEAF_FILTERS)) return -3;
3916  return weed_leaf_num_elements(plugin_info, WEED_LEAF_FILTERS);
3917 }
3918 
3919 
3920 int num_in_params(weed_plant_t *plant, boolean skip_hidden, boolean skip_internal) {
3921  weed_plant_t **params = NULL;
3922 
3923  weed_plant_t *param;
3924 
3925  int counted = 0;
3926  int num_params, i;
3927  boolean is_template = (WEED_PLANT_IS_FILTER_CLASS(plant));
3928 
3929 nip1:
3930 
3931  if (is_template) {
3932  if (!(params = weed_get_plantptr_array_counted(plant, WEED_LEAF_IN_PARAMETER_TEMPLATES, &num_params))) return 0;
3933  } else {
3934  if (!(params = weed_get_plantptr_array_counted(plant, WEED_LEAF_IN_PARAMETERS, &num_params))) goto nip1done;
3935  }
3936 
3937  if (!skip_hidden && !skip_internal) {
3938  counted += num_params;
3939  goto nip1done;
3940  }
3941 
3942  for (i = 0; i < num_params; i++) {
3943  if (skip_hidden && is_hidden_param(plant, i)) continue;
3944  param = params[i];
3945  if (skip_internal && weed_plant_has_leaf(param, WEED_LEAF_HOST_INTERNAL_CONNECTION)) continue;
3946  counted++;
3947  }
3948 
3949 nip1done:
3950 
3951  lives_freep((void **)&params);
3952 
3953  // TODO: should be skip_internal or !skip_internal ?
3954  if (!is_template && skip_internal && (plant = get_next_compound_inst(plant)) != NULL) goto nip1;
3955 
3956  return counted;
3957 }
3958 
3959 
3960 int num_out_params(weed_plant_t *plant) {
3961  int num_params, error;
3962  boolean is_template = (WEED_PLANT_IS_FILTER_CLASS(plant));
3963 
3964  if (is_template) {
3965  if (!weed_plant_has_leaf(plant, WEED_LEAF_OUT_PARAMETER_TEMPLATES) ||
3966  !weed_get_plantptr_value(plant, WEED_LEAF_OUT_PARAMETER_TEMPLATES, &error)) return 0;
3967  num_params = weed_leaf_num_elements(plant, WEED_LEAF_OUT_PARAMETER_TEMPLATES);
3968  } else {
3969  if (!weed_plant_has_leaf(plant, WEED_LEAF_OUT_PARAMETERS)) return 0;
3970  if (!weed_get_plantptr_value(plant, WEED_LEAF_OUT_PARAMETERS, &error)) return 0;
3971  num_params = weed_leaf_num_elements(plant, WEED_LEAF_OUT_PARAMETERS);
3972  }
3973  return num_params;
3974 }
3975 
3976 boolean has_usable_palette(weed_plant_t *chantmpl) {
3977  int palette = weed_get_int_value(chantmpl, WEED_LEAF_CURRENT_PALETTE, NULL);
3978  // currently only integer RGB palettes are usable
3979  if (palette == 5 || palette == 6) return FALSE;
3980  if (palette > 0 && palette <= 7) return TRUE;
3981  return FALSE;
3982 }
3983 
3984 
3985 int enabled_in_channels(weed_plant_t *plant, boolean count_repeats) {
3986  // count number of non-disabled in channels (video and/or audio) for a filter or instance
3987 
3988  // NOTE: for instances, we do not count optional audio channels, even if they are enabled
3989 
3990  weed_plant_t **channels = NULL;
3991  weed_plant_t *filter;
3992  boolean is_template = WEED_PLANT_IS_FILTER_CLASS(plant);
3993  int enabled = 0;
3994  int num_channels;
3995 
3996  register int i;
3997 
3998  if (is_template) {
3999  filter = plant;
4000  if (!weed_plant_has_leaf(plant, WEED_LEAF_IN_CHANNEL_TEMPLATES)) return 0;
4001  channels = weed_get_plantptr_array_counted(plant, WEED_LEAF_IN_CHANNEL_TEMPLATES, &num_channels);
4002  } else {
4003  filter = weed_instance_get_filter(plant, TRUE);
4004  if (!weed_plant_has_leaf(plant, WEED_LEAF_IN_CHANNELS)) return 0;
4005  channels = weed_get_plantptr_array_counted(plant, WEED_LEAF_IN_CHANNELS, &num_channels);
4006  }
4007 
4008  for (i = 0; i < num_channels; i++) {
4009  if (!is_template) {
4010  weed_plant_t *ctmpl = weed_get_plantptr_value(channels[i], WEED_LEAF_TEMPLATE, NULL);
4011  if (weed_chantmpl_is_audio(ctmpl) == WEED_TRUE) {
4012  if (weed_chantmpl_is_optional(ctmpl)) continue;
4013  }
4014  if (weed_get_boolean_value(channels[i], WEED_LEAF_DISABLED, NULL) == WEED_FALSE) enabled++;
4015  } else {
4016  // skip alpha channels
4017  if (mainw->multitrack && !has_non_alpha_palette(channels[i], filter)) continue;
4018  if (weed_get_boolean_value(channels[i], WEED_LEAF_HOST_DISABLED, NULL) == WEED_FALSE) enabled++;
4019  }
4020 
4021  if (count_repeats) {
4022  // count repeated channels
4023  weed_plant_t *chantmpl;
4024  int repeats;
4025  if (is_template) chantmpl = channels[i];
4026  else chantmpl = weed_get_plantptr_value(channels[i], WEED_LEAF_TEMPLATE, NULL);
4027  if (weed_plant_has_leaf(channels[i], WEED_LEAF_MAX_REPEATS)) {
4028  if (weed_get_boolean_value(channels[i], WEED_LEAF_DISABLED, NULL) == WEED_TRUE &&
4029  !has_usable_palette(chantmpl)) continue; // channel was disabled because palette is unusable
4030  repeats = weed_get_int_value(channels[i], WEED_LEAF_MAX_REPEATS, NULL) - 1;
4031  if (repeats == -1) repeats = 1000000;
4032  enabled += repeats;
4033  }
4034  }
4035  }
4036 
4037  if (channels) lives_freep((void **)&channels);
4038 
4039  return enabled;
4040 }
4041 
4042 
4043 int enabled_out_channels(weed_plant_t *plant, boolean count_repeats) {
4044  weed_plant_t **channels = NULL;
4045  int enabled = 0;
4046  int num_channels, i;
4047  boolean is_template = WEED_PLANT_IS_FILTER_CLASS(plant);
4048 
4049  if (is_template) {
4050  channels = weed_get_plantptr_array_counted(plant, WEED_LEAF_OUT_CHANNEL_TEMPLATES, &num_channels);
4051  } else {
4052  channels = weed_get_plantptr_array_counted(plant, WEED_LEAF_OUT_CHANNELS, &num_channels);
4053  }
4054 
4055  for (i = 0; i < num_channels; i++) {
4056  if (!is_template) {
4057  if (weed_get_boolean_value(channels[i], WEED_LEAF_DISABLED, NULL) == WEED_FALSE) enabled++;
4058  } else {
4059  if (weed_get_boolean_value(channels[i], WEED_LEAF_HOST_DISABLED, NULL) == WEED_FALSE) enabled++;
4060  }
4061  if (count_repeats) {
4062  // count repeated channels
4063  weed_plant_t *chantmpl;
4064  int repeats;
4065  if (is_template) chantmpl = channels[i];
4066  else chantmpl = weed_get_plantptr_value(channels[i], WEED_LEAF_TEMPLATE, NULL);
4067  if (weed_plant_has_leaf(channels[i], WEED_LEAF_MAX_REPEATS)) {
4068  if (weed_get_boolean_value(channels[i], WEED_LEAF_DISABLED, NULL) == WEED_TRUE &&
4069  !has_usable_palette(chantmpl)) continue; // channel was disabled because palette is unusable
4070  repeats = weed_get_int_value(channels[i], WEED_LEAF_MAX_REPEATS, NULL) - 1;
4071  if (repeats == -1) repeats = 1000000;
4072  enabled += repeats;
4073  // *INDENT-OFF*
4074  }}}
4075  // *INDENT-ON*
4076 
4077  if (channels) lives_freep((void **)&channels);
4078 
4079  return enabled;
4080 }
4081 
4082 
4084 
4085 static int min_audio_chans(weed_plant_t *plant) {
4086  int *ents;
4087  int ne;
4088  int minas = 1, i;
4089  ents = weed_get_int_array_counted(plant, WEED_LEAF_AUDIO_CHANNELS, &ne);
4090  if (ne == 0) return 1;
4091  for (i = 0; i < ne; i++) {
4092  if (minas == 1 || (ents[i] > 0 && ents[i] < minas)) minas = ents[i];
4093  if (minas == 1) {
4094  lives_free(ents);
4095  return 1;
4096  }
4097  }
4098  lives_free(ents);
4099  return minas;
4100 }
4101 
4102 
4103 static int check_for_lives(weed_plant_t *filter, int filter_idx) {
4104  // for LiVES, currently:
4105  // all filters must take 0, 1 or 2 mandatory/optional inputs and provide
4106  // 1 mandatory output (audio or video) or >1 optional (video only) outputs (for now)
4107 
4108  // or 1 or more mandatory alpha outputs (analysers)
4109 
4110  // filters can also have 1 mandatory input and no outputs and out parameters
4111  // (video analyzer)
4112 
4113  // they may have no outs provided they have out parameters (data sources or processors)
4114 
4115  // all channels used must support a limited range of palettes (for now)
4116 
4117  // filters can now have any number of mandatory in alphas, the effect will not be run unless the channels are filled
4118  // (by chaining to output of another fx)
4119  weed_plant_t **array = NULL;
4120 
4121  int chans_in_mand = 0; // number of mandatory channels
4122  int chans_in_opt_max = 0; // number of usable (by LiVES) optional channels
4123  int chans_out_mand = 0;
4124  int chans_out_opt_max = 0;
4125  int achans_in_mand = 0, achans_out_mand = 0;
4126 
4127  boolean is_audio = FALSE;
4128  boolean has_out_params = FALSE;
4129  boolean all_out_alpha = TRUE;
4130  boolean hidden = FALSE;
4131  boolean cvary = FALSE, pvary = FALSE;
4132 
4133  int flags = 0;
4134  int num_elements, i;
4135  int naudins = 0, naudouts = 0;
4136  int filter_achans = 0;
4137  int ctachans;
4138  //g_print("checking %s\n", weed_filter_get_name(filter));
4139  // TODO - check seed types
4140  if (!weed_plant_has_leaf(filter, WEED_LEAF_NAME)) return 1;
4141  if (!weed_plant_has_leaf(filter, WEED_LEAF_AUTHOR)) return 2;
4142  if (!weed_plant_has_leaf(filter, WEED_LEAF_VERSION)) return 3;
4143  if (!weed_plant_has_leaf(filter, WEED_LEAF_PROCESS_FUNC)) return 4;
4144 
4145  flags = weed_filter_get_flags(filter);
4146 
4147  // for now we will only load realtime effects
4148  if (flags & WEED_FILTER_NON_REALTIME) return 5;
4149  if (flags & WEED_FILTER_CHANNEL_LAYOUTS_MAY_VARY) cvary = TRUE;
4150  if (flags & WEED_FILTER_PALETTES_MAY_VARY) pvary = TRUE;
4151 
4152  // count number of mandatory and optional in_channels
4153  array = weed_filter_get_in_chantmpls(filter, &num_elements);
4154 
4155  for (i = 0; i < num_elements; i++) {
4156  if (!weed_plant_has_leaf(array[i], WEED_LEAF_NAME)) {
4157  lives_freep((void **)&array);
4158  return 6;
4159  }
4160 
4161  if (weed_chantmpl_is_audio(array[i]) == WEED_TRUE) {
4163  if (filter_achans == 0) {
4164  filter_achans = min_audio_chans(filter);
4165  }
4166  // filter set nothing, or set a bad n umber but channels may vary
4167  // we're ok if the total number of mandatory non repeaters is <= 2
4168  if (!weed_chantmpl_is_optional(array[i])) {
4169  if (!cvary && (ctachans = min_audio_chans(array[i])) > 0)
4170  naudins += ctachans;
4171  else naudins += filter_achans;
4172  if (naudins > 2) {
4173  if (!prefs->vj_mode) {
4174  // currently we only handle mono and stereo audio filters
4175  char *filtname = weed_filter_get_name(filter);
4176  char *pkgstring = weed_filter_get_package_name(filter);
4177  char *msg, *pkstr;
4178  if (pkgstring) pkstr = lives_strdup_printf(" from package %s ", pkgstring);
4179  else pkstr = lives_strdup("");
4180  msg = lives_strdup_printf("Cannot use filter %s%s\n"
4181  "as it requires at least %d input audio channels\n",
4182  filtname, pkstr, naudins);
4183  lives_free(filtname); lives_free(pkstr); lives_free(pkgstring);
4184  LIVES_INFO(msg);
4185  lives_free(msg);
4186  }
4187  lives_freep((void **)&array);
4188  return 7;
4189  }
4190  }
4191  is_audio = TRUE;
4192  }
4193 
4194  if (!is_audio) {
4195  if (!weed_plant_has_leaf(filter, WEED_LEAF_PALETTE_LIST)) {
4196  if (!pvary || !weed_plant_has_leaf(array[i], WEED_LEAF_PALETTE_LIST)) {
4197  lives_freep((void **)&array);
4198  return 16;
4199  }
4200  } else {
4201  if (!weed_plant_has_leaf(array[i], WEED_LEAF_PALETTE_LIST))
4202  weed_leaf_copy(array[i], WEED_LEAF_PALETTE_LIST, filter, WEED_LEAF_PALETTE_LIST);
4203  }
4204  }
4205 
4206  if (weed_chantmpl_is_optional(array[i])) {
4207  // is optional
4208  chans_in_opt_max++;
4209  weed_set_boolean_value(array[i], WEED_LEAF_HOST_DISABLED, WEED_TRUE);
4210  } else {
4211  if (has_non_alpha_palette(array[i], filter)) {
4212  if (!is_audio) chans_in_mand++;
4213  else achans_in_mand++;
4214  // *INDENT-OFF*
4215  }}}
4216  // *INDENT-ON*
4217 
4218  if (num_elements > 0) lives_freep((void **)&array);
4219  if (chans_in_mand > 2) {
4220  // currently we only handle mono and stereo audio filters
4221  if (!prefs->vj_mode) {
4222  char *filtname = weed_filter_get_name(filter);
4223  char *pkgstring = weed_filter_get_package_name(filter);
4224  char *msg, *pkstr;
4225  lives_freep((void **)&array);
4226  if (pkgstring) pkstr = lives_strdup_printf(" from package %s ", pkgstring);
4227  else pkstr = lives_strdup("");
4228  msg = lives_strdup_printf("Cannot use filter %s%s\n"
4229  "as it requires at least %d input video channels\n",
4230  filtname, pkstr, chans_in_mand);
4231  lives_free(filtname); lives_free(pkstr); lives_free(pkgstring);
4232  LIVES_INFO(msg);
4233  lives_free(msg);
4234  }
4235  return 8; // we dont handle mixers yet...
4236  }
4237  if (achans_in_mand > 0 && chans_in_mand > 0) return 13; // can't yet handle effects that need both audio and video
4238 
4239  // count number of mandatory and optional out_channels
4240  array = weed_filter_get_out_chantmpls(filter, &num_elements);
4241 
4242  for (i = 0; i < num_elements; i++) {
4243  if (!weed_plant_has_leaf(array[i], WEED_LEAF_NAME)) {
4244  lives_freep((void **)&array);
4245  return 6;
4246  }
4247 
4248  if (weed_chantmpl_is_audio(array[i]) == WEED_TRUE) {
4249  if (!weed_chantmpl_is_optional(array[i])) {
4250  if (!cvary && (ctachans = min_audio_chans(array[i])) > 0)
4251  naudouts += ctachans;
4252  else naudouts += filter_achans;
4253  if (naudouts > 2) {
4254  // currently we only handle mono and stereo audio filters
4255  lives_freep((void **)&array);
4256  return 7;
4257  }
4258  }
4259  is_audio = TRUE;
4260  if (naudins == 1 && naudouts == 2) {
4261  // converting mono to stereo cannot be done like that
4262  lives_freep((void **)&array);
4263  return 7;
4264  }
4265  is_audio = TRUE;
4266  }
4267 
4268  if (!is_audio) {
4269  if (!weed_plant_has_leaf(filter, WEED_LEAF_PALETTE_LIST)) {
4270  if (!pvary || !weed_plant_has_leaf(array[i], WEED_LEAF_PALETTE_LIST)) {
4271  lives_freep((void **)&array);
4272  return 16;
4273  }
4274  } else {
4275  if (!weed_plant_has_leaf(array[i], WEED_LEAF_PALETTE_LIST))
4276  weed_leaf_copy(array[i], WEED_LEAF_PALETTE_LIST, filter, WEED_LEAF_PALETTE_LIST);
4277  }
4278  }
4279 
4280  if (weed_chantmpl_is_optional(array[i])) {
4281  // is optional
4282  chans_out_opt_max++;
4283  weed_set_boolean_value(array[i], WEED_LEAF_HOST_DISABLED, WEED_TRUE);
4284  } else {
4285  // is mandatory
4286  if (!is_audio) {
4287  chans_out_mand++;
4288  if (has_non_alpha_palette(array[i], filter)) all_out_alpha = FALSE;
4289  } else achans_out_mand++;
4290  }
4291  }
4292 
4293  if (num_elements > 0) lives_freep((void **)&array);
4294  if (weed_plant_has_leaf(filter, WEED_LEAF_OUT_PARAMETER_TEMPLATES)) has_out_params = TRUE;
4295 
4296  if ((chans_out_mand > 1 && !all_out_alpha) || ((chans_out_mand + chans_out_opt_max + achans_out_mand < 1)
4297  && (!has_out_params))) {
4298  return 11;
4299  }
4300  if (achans_out_mand > 1 || (achans_out_mand == 1 && chans_out_mand > 0)) return 14;
4301  if (achans_in_mand >= 1 && achans_out_mand == 0 && !(has_out_params)) return 15;
4302 
4303  weed_add_plant_flags(filter, WEED_FLAG_IMMUTABLE | WEED_FLAG_UNDELETABLE, "plugin_");
4304  if (weed_plant_has_leaf(filter, WEED_LEAF_GUI)) {
4305  weed_plant_t *gui = weed_get_plantptr_value(filter, WEED_LEAF_GUI, NULL);
4306  weed_add_plant_flags(gui, WEED_FLAG_IMMUTABLE | WEED_FLAG_UNDELETABLE, "plugin_");
4307  if (weed_get_boolean_value(gui, WEED_LEAF_HIDDEN, NULL) == WEED_TRUE) {
4308  hidden = TRUE;
4309  }
4310  }
4311 
4312  if (hidden || (flags & WEED_FILTER_IS_CONVERTER)) {
4313  if (is_audio) {
4314  weed_set_boolean_value(filter, WEED_LEAF_HOST_MENU_HIDE, WEED_TRUE);
4315  if (enabled_in_channels(filter, TRUE) >= 1000000) {
4316  // this is a candidate for audio volume
4318  cand->list = lives_list_append(cand->list, LIVES_INT_TO_POINTER(filter_idx));
4319  cand->delegate = 0;
4320  }
4321  } else {
4322  weed_set_boolean_value(filter, WEED_LEAF_HOST_MENU_HIDE, WEED_TRUE);
4323  if (chans_in_mand == 1 && chans_out_mand == 1) {
4324  if ((flags & WEED_FILTER_IS_CONVERTER) && (flags & WEED_FILTER_CHANNEL_SIZES_MAY_VARY)) {
4325  // this is a candidate for resize
4327  cand->list = lives_list_append(cand->list, LIVES_INT_TO_POINTER(filter_idx));
4328  cand->delegate = 0;
4329  // *INDENT-OFF*
4330  }}}}
4331  // *INDENT-ON*
4332 
4333  return 0;
4334 }
4335 
4336 
4337 // Weed function overrides /////////////////
4338 
4339 weed_error_t weed_plant_free_host(weed_plant_t *plant) {
4340  // delete even undeletable plants
4341  weed_error_t err;
4342  if (!plant) return WEED_ERROR_NOSUCH_PLANT;
4343  err = _weed_plant_free(plant);
4344  if (err == WEED_ERROR_UNDELETABLE) {
4345  weed_clear_plant_flags(plant, WEED_FLAG_UNDELETABLE, NULL);
4346  return _weed_plant_free(plant);
4347  }
4348  return err;
4349 }
4350 
4351 
4352 /* weed_plant_t *weed_plant_new_host(int type) { */
4353 /* return _weed_plant_new(type); */
4354 /* } */
4355 
4356 
4357 weed_error_t weed_leaf_delete_host(weed_plant_t *plant, const char *key) {
4358  // delete even undeletable leaves
4359  weed_error_t err;
4360  if (!plant) return WEED_ERROR_NOSUCH_PLANT;
4361  err = _weed_leaf_delete(plant, key);
4362  if (err == WEED_ERROR_UNDELETABLE) {
4363  weed_leaf_clear_flagbits(plant, key, WEED_FLAG_UNDELETABLE);
4364  err = _weed_leaf_delete(plant, key);
4365  if (err != WEED_SUCCESS) abort();
4366  }
4367  return err;
4368 }
4369 
4370 
4371 weed_error_t weed_leaf_set_host(weed_plant_t *plant, const char *key, uint32_t seed_type,
4372  weed_size_t num_elems, void *values) {
4373  // change even immutable leaves
4374  weed_error_t err;
4375 
4376  if (!plant) return WEED_ERROR_NOSUCH_PLANT;
4377 
4378  do {
4379  err = _weed_leaf_set(plant, key, seed_type, num_elems, values);
4380  } while (err == WEED_ERROR_CONCURRENCY);
4381  if (err == WEED_ERROR_IMMUTABLE) {
4382  int32_t flags = weed_leaf_get_flags(plant, key);
4383  flags ^= WEED_FLAG_IMMUTABLE;
4384  weed_leaf_set_flags(plant, key, flags);
4385  err = _weed_leaf_set(plant, key, seed_type, num_elems, values);
4386  flags |= WEED_FLAG_IMMUTABLE;
4387  weed_leaf_set_flags(plant, key, flags);
4388  }
4389  return err;
4390 }
4391 
4392 
4393 /* weed_error_t weed_leaf_set_plugin(weed_plant_t *plant, const char *key, uint32_t seed_type, weed_size_t num_elems, void *values) { */
4394 /* fprintf(stderr, "pl setting %s\n", key); */
4395 /* return _weed_leaf_set(plant, key, seed_type, num_elems, values); */
4396 /* } */
4397 
4398 static void upd_statsplant(const char *key) {
4399  int freq;
4400  if (mainw->is_exiting) return;
4401  if (!statsplant) statsplant = weed_plant_new(0);
4402  _weed_leaf_get(statsplant, key, WEED_SEED_INT, &freq);
4403  _weed_leaf_set(statsplant, key, WEED_SEED_INT, 1, &freq);
4404 }
4405 
4406 
4407 // memory profiling for plugins
4408 
4409 void *lives_monitor_malloc(size_t size) {
4410  void *p = malloc(size);
4411  fprintf(stderr, "plugin mallocing %ld bytes, got ptr %p\n", size, p);
4412  if (size == 1024) break_me("monitor_malloc");
4413  return NULL;
4414 }
4415 
4416 
4417 void lives_monitor_free(void *p) {
4418  //fprintf(stderr, "plugin freeing ptr ptr %p\n", p);
4419 }
4420 
4421 
4422 weed_error_t weed_leaf_set_monitor(weed_plant_t *plant, const char *key, uint32_t seed_type, weed_size_t num_elems,
4423  void *values) {
4424  weed_error_t err;
4425  err = _weed_leaf_set(plant, key, seed_type, num_elems, values);
4426  g_print("PL setting %s in type %d\n", key, weed_plant_get_type(plant));
4427 
4428  if (WEED_PLANT_IS_GUI(plant) && !strcmp(key, WEED_LEAF_FLAGS)) g_print("Err was %d\n", err);
4429  return err;
4430 }
4431 
4432 
4433 weed_error_t weed_leaf_get_monitor(weed_plant_t *plant, const char *key, int32_t idx, void *value) {
4434  // plugins can be monitored for example
4435  weed_error_t err = _weed_leaf_get(plant, key, idx, value);
4436  // and simulating bugs...
4437  /* if (!strcmp(key, WEED_LEAF_WIDTH) && value) { */
4438  /* int *ww = (int *)value; */
4439  /* *ww -= 100; */
4440  /* } */
4441  upd_statsplant(key);
4442  return err;
4443 }
4444 
4445 #if 0
4446 static void **dta = NULL;
4447 static int *rws = NULL;
4448 static int ht = 0;
4449 static int npls = 0;
4450 
4451 void weed_mem_chkreg(void **data, int *rs, int height, int nplanes) {
4452  dta = data;
4453  rws = rs;
4454  ht = height;
4455  npls = npanes
4456 }
4457 
4458 
4459 void *lives_memcpy_monitor(void *d, const void *s, size_t sz) {
4460  if (dta) {
4461  for (int i = 0; i < npls; i++) {
4462  void *end = dta[i] + rws[i] * ht;
4463  if (d > end && d - end < 8) fprintf(stderr, "pl overwrite\n");
4464  }
4465  return lives_memcpy(d, s, sz);
4466  }
4467 }
4468 #endif
4469 
4470 weed_size_t weed_leaf_num_elements_monitor(weed_plant_t *plant, const char *key) {
4471  upd_statsplant(key);
4472  return _weed_leaf_num_elements(plant, key);
4473 }
4474 
4475 
4476 void show_weed_stats(weed_plant_t *statsplant) {
4477  LiVESList *freq = NULL, *sorted = NULL, *list;
4478  char **leaves;
4479  int val, i, added = 0, min, lmin = 0;
4480  weed_size_t nleaves;
4481 
4482  if (!statsplant) return;
4483  leaves = weed_plant_list_leaves(statsplant, &nleaves);
4485  for (i = 0; i < nleaves; i++) {
4486  int f = weed_get_int_value(statsplant, leaves[i], NULL);
4487  freq = lives_list_prepend(freq, LIVES_INT_TO_POINTER(f));
4488  //g_print("added %s with freq %d\n", leaves[i], f);
4489  }
4490  while (added < nleaves) {
4491  min = LIVES_MAXINT32;
4492  for (list = freq; list; list = list->next) {
4493  val = LIVES_POINTER_TO_INT(list->data);
4494  if (val < min && val > lmin) min = val;
4495  }
4496  //g_print("next min was %d\n", min);
4497  i = nleaves - 1;
4498  for (list = freq; list; list = list->next) {
4499  val = LIVES_POINTER_TO_INT(list->data);
4500  if (val == min) {
4501  //g_print("prep. %d %s\n", i, leaves[i]);
4502  sorted = lives_list_prepend(sorted, LIVES_INT_TO_POINTER(i));
4503  if (++added == nleaves) break;
4504  }
4505  i--;
4506  }
4507  if (min == lmin) break;
4508  lmin = min;
4509  }
4510  for (list = sorted; list; list = list->next) {
4511  val = LIVES_POINTER_TO_INT(list->data);
4512  g_print("STATS: %s : %d\n", leaves[val], weed_get_int_value(statsplant, leaves[val], NULL));
4513  free(leaves[val]);
4514  }
4515  free(leaves);
4516  lives_list_free(freq);
4517  lives_list_free(sorted);
4518  weed_plant_free(statsplant);
4519 }
4520 
4521 
4522 weed_plant_t *host_info_cb(weed_plant_t *xhost_info, void *data) {
4523  // if the plugin called weed_boostrap during its weed_setup() as we requested, then we will end up here
4524  // from weed_bootstrap()
4525  int id = LIVES_POINTER_TO_INT(data);
4526 
4527  int lib_weed_version = 0;
4528  int lib_filter_version = 0;
4529 
4530  if (id == 100) {
4531  // the openGL plugin
4532  our_plugin_id = 100;
4533  fxname = NULL;
4534  }
4535 
4536  suspect = TRUE;
4537 
4538  ncbcalls++;
4539  if (id != 100 && ncbcalls > 1) {
4540  return NULL;
4541  }
4542 
4543  if (!xhost_info) {
4544  return NULL;
4545  }
4546 
4547  expected_hi = xhost_info;
4548 
4549  if (id == our_plugin_id) {
4550  // GOOD !
4551  // plugin called weed_bootstrap as requested
4552  //g_print("plugin called weed_bootstrap, and we assigned it ID %d\n", our_plugin_id);
4553  weed_set_int_value(xhost_info, WEED_LEAF_HOST_IDENTIFIER, id);
4554  weed_set_boolean_value(xhost_info, WEED_LEAF_HOST_SUSPICIOUS, WEED_FALSE);
4555  suspect = FALSE;
4556  } else {
4557  weed_set_int_value(xhost_info, WEED_LEAF_HOST_IDENTIFIER, 0);
4558  weed_set_boolean_value(xhost_info, WEED_LEAF_HOST_SUSPICIOUS, WEED_TRUE);
4559  }
4560 
4561  // we can do cool stuff here !
4562 
4563  if (!suspect) {
4564  // let's check the versions the library is using...
4565  if (weed_plant_has_leaf(xhost_info, WEED_LEAF_WEED_ABI_VERSION)) {
4566  lib_weed_version = weed_get_int_value(xhost_info, WEED_LEAF_WEED_ABI_VERSION, NULL);
4567 
4568  // this allows us to load plugins compiled with older versions of the lib
4569  // we must not set it any higher than it is though
4570  // this is redundant really, since we already checked before calling weed_init()
4571  if (lib_weed_version > weed_abi_version)
4572  weed_set_int_value(xhost_info, WEED_LEAF_WEED_ABI_VERSION, weed_abi_version);
4573  }
4574  if (weed_plant_has_leaf(xhost_info, WEED_LEAF_FILTER_API_VERSION)) {
4575  lib_filter_version = weed_get_int_value(xhost_info, WEED_LEAF_FILTER_API_VERSION, NULL);
4576  if (lib_filter_version > WEED_FILTER_API_VERSION)
4577  weed_set_int_value(xhost_info, WEED_LEAF_FILTER_API_VERSION, WEED_FILTER_API_VERSION);
4578  }
4579  }
4580 
4581  if (weed_plant_has_leaf(xhost_info, WEED_LEAF_PLUGIN_INFO)) {
4582  // let's check the versions the plugin supports
4583  weed_plant_t *plugin_info = weed_get_plantptr_value(xhost_info, WEED_LEAF_PLUGIN_INFO, NULL);
4584  int pl_max_weed_abi, pl_max_filter_api;
4585  if (plugin_info) {
4586  expected_pi = plugin_info;
4587  // we don't need to bother with min versions, the lib will check for us
4588  /* if (weed_plant_has_leaf(plugin_info, WEED_LEAF_MIN_WEED_ABI_VERSION)) { */
4589  /* pl_min_weed_api = weed_get_int_value(plugin_info, WEED_LEAF_MIN_WEED_ABI_VERSION, NULL); */
4590  /* } */
4591  if (weed_plant_has_leaf(plugin_info, WEED_LEAF_MAX_WEED_ABI_VERSION)) {
4592  pl_max_weed_abi = weed_get_int_value(plugin_info, WEED_LEAF_MAX_WEED_ABI_VERSION, NULL);
4593  // we can support all versions back to 110
4594  if (pl_max_weed_abi < weed_abi_version && pl_max_weed_abi >= 110) {
4595  weed_set_int_value(xhost_info, WEED_LEAF_WEED_ABI_VERSION, pl_max_weed_abi);
4596  }
4597  }
4598  // we don't need to bother with min versions, the lib will check for us
4599  /* if (weed_plant_has_leaf(plugin_info, WEED_LEAF_MIN_WEED_API_VERSION)) { */
4600  /* pl_min_filter_api = weed_get_int_value(plugin_info, WEED_LEAF_MIN_FILTER_API_VERSION, NULL); */
4601  /* } */
4602  if (weed_plant_has_leaf(plugin_info, WEED_LEAF_MAX_WEED_API_VERSION)) {
4603  pl_max_filter_api = weed_get_int_value(plugin_info, WEED_LEAF_MAX_FILTER_API_VERSION, NULL);
4604  // we can support all versions back to 110
4605  if (pl_max_filter_api < WEED_FILTER_API_VERSION && pl_max_filter_api >= 110) {
4606  weed_set_int_value(xhost_info, WEED_LEAF_FILTER_API_VERSION, pl_max_filter_api);
4607  // *INDENT-OFF*
4608  }}}}
4609  // *INDENT-ON*
4610 
4611  // fprintf(stderr, "API versions %d %d / %d %d : %d %d\n", lib_weed_version, lib_filter_version,
4612  //pl_min_weed_api, pl_max_weed_api, pl_min_filter_api, pl_max_filter_api);
4613 
4614 #ifndef USE_STD_MEMFUNCS
4615  // let's override some plugin functions...
4616  if (id == 100) {
4617  weed_set_funcptr_value(xhost_info, WEED_LEAF_MALLOC_FUNC, (weed_funcptr_t)_ext_malloc);
4618  weed_set_funcptr_value(xhost_info, WEED_LEAF_FREE_FUNC, (weed_funcptr_t)_ext_free);
4619  weed_set_funcptr_value(xhost_info, WEED_LEAF_REALLOC_FUNC, (weed_funcptr_t)_ext_realloc);
4620  weed_set_funcptr_value(xhost_info, WEED_LEAF_CALLOC_FUNC, (weed_funcptr_t)_ext_calloc);
4621  } else {
4622  weed_set_funcptr_value(xhost_info, WEED_LEAF_MALLOC_FUNC, (weed_funcptr_t)lives_malloc);
4623  weed_set_funcptr_value(xhost_info, WEED_LEAF_FREE_FUNC, (weed_funcptr_t)lives_free);
4624  weed_set_funcptr_value(xhost_info, WEED_LEAF_REALLOC_FUNC, (weed_funcptr_t)lives_realloc);
4625  weed_set_funcptr_value(xhost_info, WEED_LEAF_CALLOC_FUNC, (weed_funcptr_t)lives_calloc);
4626  }
4627  //weed_set_funcptr_value(xhost_info, WEED_LEAF_MEMCPY_FUNC, (weed_funcptr_t)lives_memcpy_monitor);
4628  weed_set_funcptr_value(xhost_info, WEED_LEAF_MEMCPY_FUNC, (weed_funcptr_t)lives_memcpy);
4629  weed_set_funcptr_value(xhost_info, WEED_LEAF_MEMSET_FUNC, (weed_funcptr_t)lives_memset);
4630  weed_set_funcptr_value(xhost_info, WEED_LEAF_MEMMOVE_FUNC, (weed_funcptr_t)lives_memmove);
4631 #endif
4632  //weed_set_funcptr_value(xhost_info, WEED_LEAF_MALLOC_FUNC, (weed_funcptr_t)monitor_malloc);
4633  //weed_set_funcptr_value(xhost_info, WEED_LEAF_FREE_FUNC, (weed_funcptr_t)monitor_free);
4634 
4635  // since we redefined weed_leaf_set, weed_leaf_delete and weed_plant_free for ourselves,
4636  // we need to reset the plugin versions, since it will inherit ours by default when calling setup_func()
4637 
4638  weed_set_funcptr_value(xhost_info, WEED_LEAF_SET_FUNC, (weed_funcptr_t)_weed_leaf_set);
4639  weed_set_funcptr_value(xhost_info, WEED_LEAF_DELETE_FUNC, (weed_funcptr_t)_weed_leaf_delete);
4640  weed_set_funcptr_value(xhost_info, WEED_PLANT_FREE_FUNC, (weed_funcptr_t)_weed_plant_free);
4641  //weed_set_funcptr_value(xhost_info, WEED_LEAF_NUM_ELEMENTS_FUNC, (weed_funcptr_t)_weed_leaf_num_elements);
4642 
4643  weed_set_string_value(xhost_info, WEED_LEAF_HOST_NAME, "LiVES");
4644  weed_set_string_value(xhost_info, WEED_LEAF_HOST_VERSION, LiVES_VERSION);
4645 
4646  weed_set_string_value(xhost_info, WEED_LEAF_LAYOUT_SCHEMES, "rfx");
4647 
4648  weed_set_int_value(xhost_info, WEED_LEAF_FLAGS, WEED_HOST_SUPPORTS_LINEAR_GAMMA
4649  | WEED_HOST_SUPPORTS_PREMULTIPLIED_ALPHA);
4650 
4651  if (fxname && !strcmp(fxname, "projectM")) {
4652  // weed_set_funcptr_value(xhost_info, WEED_LEAF_SET_FUNC, (weed_funcptr_t)weed_leaf_set_monitor);
4653  //weed_set_int_value(xhost_info, WEED_LEAF_VERBOSITY, WEED_VERBOSITY_DEBUG);
4654  } else
4655  weed_set_int_value(xhost_info, WEED_LEAF_VERBOSITY, WEED_VERBOSITY_WARN);
4656 
4657  update_host_info(xhost_info);
4658  return xhost_info;
4659 }
4660 
4661 
4663 
4664 static void gen_hashnames(int i, int j) {
4665  hashnames[i][0].string = NULL;
4666  hashnames[i][0].string = make_weed_hashname(j, TRUE, FALSE, 0, FALSE);
4667  hashnames[i][0].hash = lives_string_hash(hashnames[i][0].string);
4668  hashnames[i][1].string = NULL;
4669  hashnames[i][1].string = make_weed_hashname(j, TRUE, TRUE, 0, FALSE); // full dupes
4670  hashnames[i][1].hash = lives_string_hash(hashnames[i][1].string);
4671  hashnames[i][2].string = NULL;
4672  hashnames[i][2].string = make_weed_hashname(j, FALSE, FALSE, 0, FALSE); // partial pdupes
4673  hashnames[i][2].hash = lives_string_hash(hashnames[i][2].string);
4674  hashnames[i][3].string = NULL;
4675  hashnames[i][3].string = make_weed_hashname(j, FALSE, TRUE, 0, FALSE);
4676  hashnames[i][3].hash = lives_string_hash(hashnames[i][3].string);
4677 
4678  hashnames[i][4].string = NULL;
4679  hashnames[i][4].string = make_weed_hashname(j, TRUE, FALSE, 0, TRUE);
4680  hashnames[i][4].hash = lives_string_hash(hashnames[i][4].string);
4681  hashnames[i][5].string = NULL;
4682  hashnames[i][5].string = make_weed_hashname(j, TRUE, TRUE, 0, TRUE); // full dupes
4683  hashnames[i][5].hash = lives_string_hash(hashnames[i][5].string);
4684  hashnames[i][6].string = NULL;
4685  hashnames[i][6].string = make_weed_hashname(j, FALSE, FALSE, 0, TRUE); // partial pdupes
4686  hashnames[i][6].hash = lives_string_hash(hashnames[i][6].string);
4687  hashnames[i][7].string = NULL;
4688  hashnames[i][7].string = make_weed_hashname(j, FALSE, TRUE, 0, TRUE);
4689  hashnames[i][7].hash = lives_string_hash(hashnames[i][7].string);
4690 }
4691 
4692 
4693 static void load_weed_plugin(char *plugin_name, char *plugin_path, char *dir) {
4694 #if defined TEST_ISOL && defined LM_ID_NEWLM
4695  static Lmid_t lmid = LM_ID_NEWLM;
4696  static boolean have_lmid = FALSE;
4697  Lmid_t new_lmid;
4698 #endif
4699  weed_setup_f setup_fn;
4700  weed_plant_t *plugin_info = NULL, **filters = NULL, *filter = NULL;
4701  weed_plant_t *host_info;
4702  void *handle;
4703  int dlflags = RTLD_NOW | RTLD_LOCAL;
4704  int reason, idx = num_weed_filters;
4705  int filters_in_plugin, fnum, j;
4706 
4707  char cwd[PATH_MAX];
4708 
4709  // filters which can cause a segfault
4710  const char *frei0r_blacklist[] = {"Timeout indicator", NULL};
4711  const char *ladspa_blacklist[] = {"Mag's Notch Filter", "Identity (Control)", "Signal Branch (IC)",
4712  "Signal Product (ICIC)", "Signal Difference (ICMC)",
4713  "Signal Sum (ICIC)", "Signal Ratio (NCDC)",
4714  NULL
4715  };
4716 
4717  char *pwd, *tmp, *msg, *filtname;
4718  char *filter_name = NULL, *package_name = NULL;
4719  boolean blacklisted;
4720  boolean none_valid = TRUE;
4721 
4722  register int i;
4723 
4724 #ifdef RTLD_DEEPBIND
4725  dlflags |= RTLD_DEEPBIND;
4726 #endif
4727 
4728  pwd = getcwd(cwd, PATH_MAX);
4729  THREADVAR(chdir_failed) = FALSE;
4730 
4731  // walk list and create fx structures
4732  //#define DEBUG_WEED
4733 #ifdef DEBUG_WEED
4734  lives_printerr("Checking plugin %s\n", plugin_path);
4735 #endif
4736 
4737 #if defined TEST_ISOL && defined LM_ID_NEWLM
4738  if (!have_lmid) {
4739  handle = dlmopen(LM_ID_NEWLM, plugin_path, dlflags);
4740  } else {
4741  handle = dlmopen(lmid, plugin_path, dlflags);
4742  }
4743  if (handle) {
4744  dlerror(); // clear existing errors
4745  if (!have_lmid) {
4746  have_lmid = TRUE;
4747  dlinfo(handle, RTLD_DI_LMID, &new_lmid);
4748  dlerror(); // clear existing errors
4749  lmid = new_lmid;
4750  }
4751  }
4752 #else
4753  if ((handle = dlopen(plugin_path, dlflags))) {
4754  dlerror(); // clear existing errors
4755  }
4756 #endif
4757  else {
4758  msg = lives_strdup_printf(_("Unable to load plugin %s\nError was: %s\n"), plugin_path, dlerror());
4759  LIVES_WARN(msg);
4760  lives_free(msg);
4761  return;
4762  }
4763  if ((setup_fn = (weed_setup_f)dlsym(handle, "weed_setup")) == NULL) {
4764  msg = lives_strdup_printf(_("Error: plugin %s has no weed_setup() function.\n"), plugin_path);
4765  LIVES_ERROR(msg);
4766  lives_free(msg);
4767  return;
4768  }
4769 
4770  // here we call the plugin's setup_fn, passing in our bootstrap function
4771  // the plugin will call our bootstrap function to get the correct versions of the core weed functions
4772  // and bootstrap itself
4773 
4774  // if we use the plugin, we must not free the plugin_info, since the plugin has a reference to this
4775 
4776  // chdir to plugin dir, in case it needs to load data
4777 
4778  // set a callback so we can adjust plugin functions (provided the plugin calls weed_bootstrap as we request)
4779  host_info = NULL;
4780  our_plugin_id = 0;
4781  do {
4782  our_plugin_id = (int)((lives_random() * lives_random()) & 0xFFFF);
4783  } while (our_plugin_id == 0);
4784 
4785  weed_set_host_info_callback(host_info_cb, LIVES_INT_TO_POINTER(our_plugin_id));
4786 
4787  lives_chdir(dir, TRUE);
4788  suspect = TRUE;
4789  expected_hi = expected_pi = NULL;
4790  ncbcalls = 0;
4791  fxname = strip_ext(plugin_name);
4792 
4793  plugin_info = (*setup_fn)(weed_bootstrap);
4794 
4795  if (!plugin_info || (filters_in_plugin = check_weed_plugin_info(plugin_info)) < 1) {
4796  msg = lives_strdup_printf(_("No usable filters found in plugin:\n%s\n"), plugin_path);
4797  LIVES_INFO(msg);
4798  lives_free(msg);
4799  if (plugin_info) weed_plant_free(plugin_info);
4800  dlclose(handle);
4801  lives_chdir(pwd, FALSE);
4802  lives_freep((void **)&fxname);
4803  return;
4804  }
4805 
4806  lives_freep((void **)&fxname);
4807 
4808  if (expected_pi && plugin_info != expected_pi) suspect = TRUE;
4809  if (weed_plant_has_leaf(plugin_info, WEED_LEAF_HOST_INFO)) {
4810  host_info = weed_get_plantptr_value(plugin_info, WEED_LEAF_HOST_INFO, NULL);
4811  if (!host_info || host_info != expected_hi) {
4812  // filter switched the host_info...very naughty
4813  if (host_info) weed_plant_free(host_info);
4814  msg = lives_strdup_printf("Badly behaved plugin (%s)\n", plugin_path);
4815  LIVES_WARN(msg);
4816  lives_free(msg);
4817  if (plugin_info) weed_plant_free(plugin_info);
4818  dlclose(handle);
4819  lives_chdir(pwd, FALSE);
4820  return;
4821  }
4822  if (weed_plant_has_leaf(host_info, WEED_LEAF_PLUGIN_INFO)) {
4823  weed_plant_t *pi = weed_get_plantptr_value(host_info, WEED_LEAF_PLUGIN_INFO, NULL);
4824  if (!pi || pi != plugin_info) {
4825  // filter switched the plugin_info...very naughty
4826  msg = lives_strdup_printf("Badly behaved plugin - %s %p %p %p %p\n",
4827  plugin_path, pi, plugin_info, host_info, expected_hi);
4828  LIVES_WARN(msg);
4829  lives_free(msg);
4830  if (pi) weed_plant_free(pi);
4831  if (host_info) weed_plant_free(host_info);
4832  if (plugin_info) weed_plant_free(plugin_info);
4833  dlclose(handle);
4834  lives_chdir(pwd, FALSE);
4835  return;
4836  }
4837  } else {
4838  suspect = TRUE;
4839  weed_set_plantptr_value(host_info, WEED_LEAF_PLUGIN_INFO, plugin_info);
4840  }
4841  } else {
4842  if (suspect || !expected_hi) {
4843  msg = lives_strdup_printf("Badly behaved plugin: %s\n", plugin_path);
4844  LIVES_WARN(msg);
4845  lives_free(msg);
4846  if (host_info) weed_plant_free(host_info);
4847  if (plugin_info) weed_plant_free(plugin_info);
4848  dlclose(handle);
4849  lives_chdir(pwd, FALSE);
4850  return;
4851  }
4852  host_info = expected_hi;
4853  suspect = TRUE;
4854  weed_set_plantptr_value(plugin_info, WEED_LEAF_HOST_INFO, expected_hi);
4855  }
4856  if (!suspect) {
4857  weed_set_boolean_value(plugin_info, WEED_LEAF_HOST_SUSPICIOUS, WEED_FALSE);
4858  weed_set_boolean_value(host_info, WEED_LEAF_HOST_SUSPICIOUS, WEED_FALSE);
4859  } else {
4860  weed_set_boolean_value(plugin_info, WEED_LEAF_HOST_SUSPICIOUS, WEED_TRUE);
4861  weed_set_boolean_value(host_info, WEED_LEAF_HOST_SUSPICIOUS, WEED_TRUE);
4862  }
4863  weed_set_voidptr_value(plugin_info, WEED_LEAF_HOST_HANDLE, handle);
4864  weed_set_string_value(plugin_info, WEED_LEAF_HOST_PLUGIN_NAME, plugin_name); // for hashname
4865  weed_set_string_value(plugin_info, WEED_LEAF_HOST_PLUGIN_PATH, dir);
4866  weed_add_plant_flags(plugin_info, WEED_FLAG_IMMUTABLE | WEED_FLAG_UNDELETABLE, "plugin_");
4867 
4868  filters = weed_get_plantptr_array(plugin_info, WEED_LEAF_FILTERS, NULL);
4869 
4870  if (weed_plant_has_leaf(plugin_info, WEED_LEAF_PACKAGE_NAME)) {
4871  package_name = lives_strdup_printf("%s: ", (tmp = weed_get_string_value(plugin_info,
4872  WEED_LEAF_PACKAGE_NAME, NULL)));
4873  lives_free(tmp);
4874  } else package_name = lives_strdup("");
4875 
4876  for (fnum = 0; fnum < filters_in_plugin; fnum++) {
4877  filter = filters[fnum];
4878  blacklisted = FALSE;
4879 
4880  if (!filter) {
4881  msg = lives_strdup_printf(_("Plugin %s returned an empty filter !"), plugin_path);
4882  LIVES_WARN(msg);
4883  lives_free(msg);
4884  continue;
4885  }
4886 
4887  filtname = weed_filter_get_name(filter);
4888  blacklisted = FALSE;
4889 
4890  if (!strcmp(package_name, "Frei0r: ")) {
4891  for (i = 0; frei0r_blacklist[i]; i++) {
4892  if (!strcmp(filtname, frei0r_blacklist[i])) {
4893  blacklisted = TRUE;
4894  break;
4895  // *INDENT-OFF*
4896  }}}
4897  // *INDENT-ON*
4898 
4899  if (!strcmp(package_name, "LADSPA: ")) {
4900  for (i = 0; ladspa_blacklist[i]; i++) {
4901  if (!strcmp(filtname, ladspa_blacklist[i])) {
4902  blacklisted = TRUE;
4903  break;
4904  // *INDENT-OFF*
4905  }}}
4906  // *INDENT-ON*
4907 
4908  if (blacklisted) {
4909  if (!prefs->vj_mode) {
4910  msg = lives_strdup_printf(_("%sskipping blacklisted filter %s\n"), package_name, filtname);
4911  fprintf(stderr, "%s", msg);
4912  lives_free(msg);
4913  }
4914  continue;
4915  }
4916 
4917  filter_name = lives_strdup_printf("%s%s:", package_name, filtname);
4918  lives_free(filtname);
4919 
4920  // add value returned in host_info_cb
4921  if (host_info) weed_set_plantptr_value(filter, WEED_LEAF_HOST_INFO, host_info);
4922 
4923  if (!(reason = check_for_lives(filter, idx))) {
4924  boolean dup = FALSE;
4925  none_valid = FALSE;
4926  num_weed_filters++;
4927  weed_filters = (weed_plant_t **)lives_realloc(weed_filters, num_weed_filters * sizeof(weed_plant_t *));
4928  weed_filters[idx] = filter;
4929 
4930  hashnames = (lives_hashjoint *)lives_realloc(hashnames, num_weed_filters * sizeof(lives_hashjoint));
4931  gen_hashnames(idx, idx);
4932 
4933  for (i = 0; i < idx; i++) {
4934  if (hashnames[idx][1].hash == hashnames[i][1].hash
4935  && !lives_utf8_strcasecmp(hashnames[idx][1].string, hashnames[i][1].string)) {
4936  // skip dups
4937  if (!prefs->vj_mode) {
4938  msg = lives_strdup_printf(_("Found duplicate plugin %s"), hashnames[idx][1].string);
4939  LIVES_INFO(msg);
4940  lives_free(msg);
4941  }
4942  for (j = 0; j < NHASH_TYPES; j ++) {
4943  lives_freep((void **)&hashnames[idx][j].string);
4944  }
4945  num_weed_filters--;
4946  weed_filters = (weed_plant_t **)lives_realloc(weed_filters, num_weed_filters * sizeof(weed_plant_t *));
4947  hashnames = (lives_hashjoint *)lives_realloc(hashnames, num_weed_filters * sizeof(lives_hashjoint));
4948  lives_freep((void **)&filter_name);
4949  dup = TRUE;
4950  break;
4951  }
4952 
4953  if (hashnames[i][2].hash == hashnames[idx][2].hash
4954  && !lives_utf8_strcasecmp(hashnames[i][2].string, hashnames[idx][2].string)) {
4955  //g_print("partial dupe: %s and %s\n",phashnames[phashes-1],phashnames[i-oidx-1]);
4956  // found a partial match: author and/or version differ
4957  // hide oldder version from menus
4958  if (weed_get_int_value(filter, WEED_LEAF_VERSION, NULL) <
4959  weed_get_int_value(weed_filters[i], WEED_LEAF_VERSION, NULL)) {
4960  weed_set_boolean_value(filter, WEED_LEAF_HOST_MENU_HIDE, WEED_TRUE);
4961  } else {
4962  weed_set_boolean_value(weed_filters[i], WEED_LEAF_HOST_MENU_HIDE, WEED_TRUE);
4963  }
4964  break;
4965  }
4966  }
4967 
4968  if (dup) continue;
4969  idx++;
4970  if (prefs->show_splash) {
4971  msg = lives_strdup_printf((tmp = _("Loaded filter %s in plugin %s")), filter_name, plugin_name);
4972  lives_free(tmp);
4974  lives_free(msg);
4975  }
4976  } else {
4977 #ifdef DEBUG_WEED
4978  lives_printerr("Unsuitable filter \"%s\" in plugin \"%s\", reason code %d\n",
4979  filter_name, plugin_name, reason);
4980 #endif
4981  }
4982  lives_freep((void **)&filter_name);
4983  }
4984 
4985  if (none_valid && plugin_info) {
4986  host_info = weed_get_plantptr_value(plugin_info, WEED_LEAF_HOST_INFO, NULL);
4987  if (host_info) weed_plant_free(host_info);
4988  weed_plant_free(plugin_info);
4989  }
4990 
4991  lives_freep((void **)&filters);
4992  lives_free(package_name);
4993  if (THREADVAR(chdir_failed)) {
4994  char *dirs = (_("Some plugin directories"));
4995  do_chdir_failed_error(dirs);
4996  lives_free(dirs);
4997  }
4998 
4999  lives_chdir(pwd, FALSE);
5000 
5001  // TODO - add any rendered effects to fx submenu
5002 }
5003 
5004 
5005 static void make_fx_defs_menu(int num_weed_compounds) {
5006  weed_plant_t *filter;
5007 
5008  LiVESWidget *menuitem, *menu = mainw->rte_defs;
5009  LiVESWidget *pkg_menu;
5010  LiVESWidget *pkg_submenu = NULL;
5011 
5012  LiVESList *menu_list = NULL;
5013  LiVESList *pkg_menu_list = NULL;
5014  LiVESList *compound_list = NULL;
5015 
5016  char *string, *filter_type, *filter_name;
5017  char *pkg = NULL, *pkgstring;
5018  boolean hidden;
5019  register int i;
5020 
5021  weed_fx_sorted_list = NULL;
5022 
5023  // menu entries for vj/set defs
5024  for (i = 0; i < num_weed_filters; i++) {
5025  filter = weed_filters[i];
5026 
5027  if (weed_filter_hints_unstable(filter) && !prefs->show_dev_opts && !prefs->unstable_fx) continue;
5028  filter_name = weed_filter_idx_get_name(i, FALSE, FALSE);
5029 
5030  // skip hidden filters
5031  if (weed_get_boolean_value(filter, WEED_LEAF_HOST_MENU_HIDE, NULL) == WEED_TRUE ||
5032  (num_in_params(filter, TRUE, TRUE) == 0 && !(!has_video_chans_in(filter, FALSE) && has_video_chans_out(filter, FALSE))) ||
5033  (enabled_in_channels(filter, TRUE) > 2 && enabled_out_channels(filter, TRUE) > 0))
5034  hidden = TRUE;
5035  else hidden = FALSE;
5036 
5037  pkgstring = weed_filter_get_package_name(filter);
5038 
5039  if (pkgstring) {
5040  // new package
5041  if (pkg && strcmp(pkg, pkgstring)) {
5042  pkg_menu_list = add_sorted_list_to_menu(LIVES_MENU(menu), pkg_menu_list);
5043  lives_list_free(pkg_menu_list);
5044  pkg_menu_list = NULL;
5045  menu = mainw->rte_defs;
5046  lives_freep((void **)&pkg);
5047  }
5048 
5049  if (!pkg) {
5050  pkg = pkgstring;
5051  /* TRANSLATORS: example " - LADSPA plugins -" */
5052  pkgstring = lives_strdup_printf(_(" - %s plugins -"), pkg);
5053  // create new submenu
5054 
5056  pkg_menu = lives_standard_menu_item_new_with_label(pkgstring);
5058  lives_container_add(LIVES_CONTAINER(mainw->rte_defs), pkg_menu);
5059 
5060  pkg_submenu = lives_menu_new();
5061  lives_menu_item_set_submenu(LIVES_MENU_ITEM(pkg_menu), pkg_submenu);
5062 
5063  if (palette->style & STYLE_1) {
5064  lives_widget_set_bg_color(pkg_submenu, LIVES_WIDGET_STATE_NORMAL, &palette->menu_and_bars);
5065  lives_widget_set_fg_color(pkg_submenu, LIVES_WIDGET_STATE_NORMAL, &palette->menu_and_bars_fore);
5066  }
5067 
5068  lives_widget_show(pkg_menu);
5069  lives_widget_show(pkg_submenu);
5070  lives_free(pkgstring);
5071 
5072  // add to submenu
5073  menu = pkg_submenu;
5074  }
5075  } else {
5076  pkg_menu_list = add_sorted_list_to_menu(LIVES_MENU(menu), pkg_menu_list);
5077  lives_list_free(pkg_menu_list);
5078  pkg_menu_list = NULL;
5079  lives_freep((void **)&pkg);
5080  menu = mainw->rte_defs;
5081  }
5082  filter_type = weed_filter_get_type(filter, TRUE, FALSE);
5083  string = lives_strdup_printf("%s (%s)", filter_name, filter_type);
5084 
5086  menuitem = lives_standard_menu_item_new_with_label(string);
5088  lives_free(string);
5089  lives_free(filter_type);
5090 
5091  lives_widget_object_set_data(LIVES_WIDGET_OBJECT(menuitem), HIDDEN_KEY, LIVES_INT_TO_POINTER((int)hidden));
5092  lives_widget_object_set_data(LIVES_WIDGET_OBJECT(menuitem), SECLIST_KEY, &weed_fx_sorted_list);
5093  lives_widget_object_set_data(LIVES_WIDGET_OBJECT(menuitem), SECLIST_VAL_KEY, LIVES_INT_TO_POINTER(i));
5094 
5095  if (pkg) pkg_menu_list = lives_list_prepend(pkg_menu_list, (livespointer)menuitem);
5096  else {
5097  if (i >= num_weed_filters - num_weed_compounds) compound_list = lives_list_prepend(compound_list, (livespointer)menuitem);
5098  else menu_list = lives_list_prepend(menu_list, (livespointer)menuitem);
5099  }
5100 
5101  lives_signal_connect(LIVES_GUI_OBJECT(menuitem), LIVES_WIDGET_ACTIVATE_SIGNAL,
5102  LIVES_GUI_CALLBACK(rte_set_defs_activate), LIVES_INT_TO_POINTER(i));
5103 
5104  lives_freep((void **)&filter_name);
5105  }
5106 
5107  if (pkg) {
5108  pkg_menu_list = add_sorted_list_to_menu(LIVES_MENU(menu), pkg_menu_list);
5109  lives_list_free(pkg_menu_list);
5110  lives_free(pkg);
5111  }
5112  menu_list = add_sorted_list_to_menu(LIVES_MENU(mainw->rte_defs), menu_list);
5113  lives_list_free(menu_list);
5114  compound_list = add_sorted_list_to_menu(LIVES_MENU(mainw->rte_defs), compound_list);
5115  lives_list_free(compound_list);
5116 }
5117 
5118 
5119 void weed_load_all(void) {
5120  // get list of plugins from directory and create our fx
5121  LiVESList *weed_plugin_list, *weed_plugin_sublist;
5122  char **dirs;
5123  char *subdir_path, *subdir_name, *plugin_path, *plugin_name;
5124  int max_modes = prefs->max_modes_per_key;
5125  int numdirs, ncompounds;
5126  int i, j;
5127 
5128  num_weed_filters = 0;
5129 
5130  weed_filters = NULL;
5131  hashnames = NULL;
5132 
5134 
5135 #ifdef DEBUG_WEED
5136  lives_printerr("In weed init\n");
5137 #endif
5138 
5139  fg_gen_to_start = fg_generator_key = fg_generator_clip = fg_generator_mode = -1;
5140  bg_gen_to_start = bg_generator_key = bg_generator_mode = -1;
5141 
5142  for (i = 0; i < FX_KEYS_MAX; i++) {
5143  if (i == FX_KEYS_MAX_VIRTUAL) max_modes = 1;
5144 
5145  key_to_instance[i] = (weed_plant_t **)lives_calloc(max_modes, sizeof(weed_plant_t *));
5146 
5147  key_to_instance_copy[i] = (weed_plant_t **)lives_calloc(1, sizeof(weed_plant_t *));
5148 
5149  key_to_fx[i] = (int *)lives_calloc(max_modes, sizint);
5150 
5151  if (i < FX_KEYS_MAX_VIRTUAL)
5152  // *INDENT-OFF*
5153  key_defaults[i] = (weed_plant_t ***)lives_calloc(max_modes, sizeof(weed_plant_t **));
5154  // *INDENT-ON*
5155 
5156  key_modes[i] = 0; // current active mode of each key
5157  filter_map[i] = NULL; // maps effects in order of application for multitrack rendering
5158  for (j = 0; j < max_modes; j++) key_to_fx[i][j] = -1;
5159  }
5160 
5161  filter_map[FX_KEYS_MAX + 1] = NULL;
5162 
5163  for (i = 0; i < FX_KEYS_MAX_VIRTUAL; i++) {
5164  pchains[i] = NULL;
5165  init_events[i] = NULL;
5166  }
5167 
5168  next_free_key = FX_KEYS_MAX_VIRTUAL;
5169 
5171 
5172  // first we parse the weed_plugin_path
5173 #ifndef IS_MINGW
5174  numdirs = get_token_count(prefs->weed_plugin_path, ':');
5175  dirs = lives_strsplit(prefs->weed_plugin_path, ":", numdirs);
5176 #else
5177  numdirs = get_token_count(prefs->weed_plugin_path, ';');
5178  dirs = lives_strsplit(prefs->weed_plugin_path, ";", numdirs);
5179 #endif
5181 
5182  for (i = 0; i < numdirs; i++) {
5183  // get list of all files
5184  LiVESList *list = weed_plugin_list = get_plugin_list(PLUGIN_EFFECTS_WEED, TRUE, dirs[i], NULL);
5185 
5186  // parse twice, first we get the plugins, then 1 level of subdirs
5187  while (list) {
5188  LiVESList *listnext = list->next;
5190  plugin_name = (char *)list->data;
5191  if (!lives_strncmp(plugin_name + lives_strlen(plugin_name) - strlen(DLL_NAME) - 1, "." DLL_NAME, strlen(DLL_NAME) + 1)) {
5192  plugin_path = lives_build_filename(dirs[i], plugin_name, NULL);
5193  load_weed_plugin(plugin_name, plugin_path, dirs[i]);
5194  lives_freep((void **)&plugin_name);
5195  lives_free(plugin_path);
5196  list->data = NULL;
5197  if (list->prev) list->prev->next = listnext;
5198  else weed_plugin_list = listnext;
5199  if (listnext) listnext->prev = list->prev;
5200  list->prev = list->next = NULL;
5201  lives_list_free(list);
5202  }
5203  list = listnext;
5205  }
5206 
5207  // get 1 level of subdirs
5208  for (list = weed_plugin_list; list; list = list->next) {
5210  subdir_name = (char *)list->data;
5211  subdir_path = lives_build_filename(dirs[i], subdir_name, NULL);
5212  if (!lives_file_test(subdir_path, LIVES_FILE_TEST_IS_DIR) || !strcmp(subdir_name, "icons") || !strcmp(subdir_name, "data")) {
5213  lives_free(subdir_path);
5214  continue;
5215  }
5216 
5217  for (LiVESList *list2 = weed_plugin_sublist = get_plugin_list(PLUGIN_EFFECTS_WEED, TRUE, subdir_path, DLL_NAME);
5218  list2; list2 = list2 ->next) {
5219  plugin_name = (char *)list2->data;
5220  plugin_path = lives_build_filename(subdir_path, plugin_name, NULL);
5221  load_weed_plugin(plugin_name, plugin_path, subdir_path);
5222  lives_free(plugin_path);
5223  }
5224  lives_list_free_all(&weed_plugin_sublist);
5225  lives_freep((void **)&subdir_path);
5227  }
5228  lives_list_free_all(&weed_plugin_list);
5229  }
5230 
5231  lives_strfreev(dirs);
5232 
5233  d_print(_("Successfully loaded %d Weed filters\n"), num_weed_filters);
5234 
5236  ncompounds = load_compound_fx();
5238  make_fx_defs_menu(ncompounds);
5240  weed_fx_sorted_list = lives_list_reverse(weed_fx_sorted_list);
5241  fx_inited = TRUE;
5242 }
5243 
5244 
5245 static void weed_plant_free_if_not_in_list(weed_plant_t *plant, LiVESList **freed_ptrs) {
5247  if (freed_ptrs) {
5248  LiVESList *list = *freed_ptrs;
5249  while (list) {
5250  if (plant == (weed_plant_t *)list->data) return;
5251  list = list->next;
5252  }
5253  *freed_ptrs = lives_list_prepend(*freed_ptrs, (livespointer)plant);
5254  }
5255  weed_plant_free(plant);
5256 }
5257 
5258 
5259 static void weed_filter_free(weed_plant_t *filter, LiVESList **freed_ptrs) {
5260  int nitems, i;
5261  weed_plant_t **plants, *gui;
5262  boolean is_compound = FALSE;
5263 
5264  if (num_compound_fx(filter) > 1) is_compound = TRUE;
5265 
5266  // free in_param_templates
5267  plants = weed_get_plantptr_array_counted(filter, WEED_LEAF_IN_PARAMETER_TEMPLATES, &nitems);
5268  if (nitems > 0) {
5269  for (i = 0; i < nitems; i++) {
5270  if (weed_plant_has_leaf(plants[i], WEED_LEAF_GUI)) {
5271  gui = (weed_get_plantptr_value(plants[i], WEED_LEAF_GUI, NULL));
5272  weed_plant_free_if_not_in_list(gui, freed_ptrs);
5273  }
5274  weed_plant_free_if_not_in_list(plants[i], freed_ptrs);
5275  }
5276  lives_freep((void **)&plants);
5277  }
5278 
5279  if (is_compound) {
5280  weed_plant_free(filter);
5281  return;
5282  }
5283 
5284  // free in_channel_templates
5285  if (weed_plant_has_leaf(filter, WEED_LEAF_IN_CHANNEL_TEMPLATES)) {
5286  plants = weed_get_plantptr_array_counted(filter, WEED_LEAF_IN_CHANNEL_TEMPLATES, &nitems);
5287  if (nitems > 0) {
5288  for (i = 0; i < nitems; i++) weed_plant_free_if_not_in_list(plants[i], freed_ptrs);
5289  lives_freep((void **)&plants);
5290  }
5291  }
5292 
5293  // free out_channel_templates
5294  if (weed_plant_has_leaf(filter, WEED_LEAF_OUT_CHANNEL_TEMPLATES)) {
5295  plants = weed_get_plantptr_array_counted(filter, WEED_LEAF_OUT_CHANNEL_TEMPLATES, &nitems);
5296  if (nitems > 0) {
5297  for (i = 0; i < nitems; i++) weed_plant_free_if_not_in_list(plants[i], freed_ptrs);
5298  lives_freep((void **)&plants);
5299  }
5300  }
5301 
5302  // free out_param_templates
5303  plants = weed_get_plantptr_array_counted(filter, WEED_LEAF_OUT_PARAMETER_TEMPLATES, &nitems);
5304  if (nitems > 0) {
5306  for (i = 0; i < nitems; i++) {
5307  if (weed_plant_has_leaf(plants[i], WEED_LEAF_GUI))
5308  weed_plant_free(weed_get_plantptr_value(plants[i], WEED_LEAF_GUI, NULL));
5309  weed_plant_free_if_not_in_list(plants[i], freed_ptrs);
5310  }
5311  lives_freep((void **)&plants);
5312  }
5313 
5314  // free gui
5315  if (weed_plant_has_leaf(filter, WEED_LEAF_GUI))
5316  weed_plant_free_if_not_in_list(weed_get_plantptr_value(filter, WEED_LEAF_GUI, NULL), freed_ptrs);
5317 
5318  // free filter
5319  weed_plant_free(filter);
5320 }
5321 
5322 
5323 static weed_plant_t *create_compound_filter(char *plugin_name, int nfilts, int *filts) {
5324  weed_plant_t *filter = weed_plant_new(WEED_PLANT_FILTER_CLASS), *xfilter, *gui;
5325  weed_plant_t **in_params = NULL, **out_params = NULL, **params;
5326  weed_plant_t **in_chans, **out_chans;
5327 
5328  char *tmp;
5329 
5330  double tgfps = -1., tfps;
5331 
5332  int count, xcount, error, nvals;
5333  int txparam = -1, tparam, txvolm = -1, tvolm;
5334 
5335  register int i, j, x;
5336 
5337  weed_set_int_array(filter, WEED_LEAF_HOST_FILTER_LIST, nfilts, filts);
5338 
5339  // create parameter templates - concatenate all sub filters
5340  count = xcount = 0;
5341 
5342  for (i = 0; i < nfilts; i++) {
5343  xfilter = weed_filters[filts[i]];
5344 
5345  if (weed_plant_has_leaf(xfilter, WEED_LEAF_PREFERRED_FPS)) {
5346  tfps = weed_get_double_value(xfilter, WEED_LEAF_PREFERRED_FPS, &error);
5347  if (tgfps == -1.) tgfps = tfps;
5348  else if (tgfps != tfps) {
5349  if (!prefs->vj_mode) {
5350  d_print((tmp = lives_strdup_printf(_("Invalid compound effect %s - has conflicting target_fps\n"), plugin_name)));
5351  LIVES_ERROR(tmp);
5352  lives_free(tmp);
5353  }
5354  return NULL;
5355  }
5356  }
5357 
5358  // in_parameter templates are copy-by-value, since we may set a different default/host_default value, and a different gui
5359 
5360  // everything else - filter classes, out_param templates and channels are copy by ref.
5361 
5362  if (weed_plant_has_leaf(xfilter, WEED_LEAF_IN_PARAMETER_TEMPLATES)) {
5363  tparam = get_transition_param(xfilter, FALSE);
5364 
5365  // TODO *** - ignore transtion params if they are connected to themselves
5366 
5367  if (tparam != -1) {
5368  if (txparam != -1) {
5369  if (!prefs->vj_mode) {
5370  d_print((tmp = lives_strdup_printf(_("Invalid compound effect %s - has multiple transition parameters\n"),
5371  plugin_name)));
5372  LIVES_ERROR(tmp);
5373  lives_free(tmp);
5374  }
5375  return NULL;
5376  }
5377  txparam = tparam;
5378  }
5379 
5380  tvolm = get_master_vol_param(xfilter, FALSE);
5381 
5382  // TODO *** - ignore master vol params if they are connected to themselves
5383 
5384  if (tvolm != -1) {
5385  if (txvolm != -1) {
5386  if (!prefs->vj_mode) {
5387  d_print((tmp = lives_strdup_printf(_("Invalid compound effect %s - has multiple master volume parameters\n"),
5388  plugin_name)));
5389  LIVES_ERROR(tmp);
5390  lives_free(tmp);
5391  }
5392  return NULL;
5393  }
5394  txvolm = tvolm;
5395  }
5396 
5397  params = weed_get_plantptr_array_counted(xfilter, WEED_LEAF_IN_PARAMETER_TEMPLATES, &nvals);
5398  count += nvals;
5399 
5400  in_params = (weed_plant_t **)lives_realloc(in_params, count * sizeof(weed_plant_t *));
5401  x = 0;
5402 
5403  for (j = xcount; j < count; j++) {
5404  in_params[j] = weed_plant_copy(params[x]);
5405  gui = weed_get_plantptr_value(params[x], WEED_LEAF_GUI, &error);
5406  if (gui) weed_set_plantptr_value(in_params[j], WEED_LEAF_GUI, weed_plant_copy(gui));
5407 
5408  if (x == tparam) {
5409  weed_set_boolean_value(in_params[j], WEED_LEAF_IS_TRANSITION, WEED_TRUE);
5410  } else if (weed_plant_has_leaf(in_params[j], WEED_LEAF_IS_TRANSITION))
5411  weed_leaf_delete(in_params[j], WEED_LEAF_IS_TRANSITION);
5412 
5413  if (x == tvolm) {
5414  weed_set_boolean_value(in_params[j], WEED_LEAF_IS_VOLUME_MASTER, WEED_TRUE);
5415  } else if (weed_plant_has_leaf(in_params[j], WEED_LEAF_IS_VOLUME_MASTER))
5416  weed_leaf_delete(in_params[j], WEED_LEAF_IS_VOLUME_MASTER);
5417 
5418  x++;
5419  }
5420  lives_free(params);
5421  xcount = count;
5422  }
5423  }
5424 
5425  if (tgfps != -1.) weed_set_double_value(filter, WEED_LEAF_PREFERRED_FPS, tgfps);
5426 
5427  if (count > 0) {
5428  weed_set_plantptr_array(filter, WEED_LEAF_IN_PARAMETER_TEMPLATES, count, in_params);
5429  lives_free(in_params);
5430  }
5431 
5432  count = xcount = 0;
5433 
5434  for (i = 0; i < nfilts; i++) {
5435  xfilter = weed_filters[filts[i]];
5436  if (weed_plant_has_leaf(xfilter, WEED_LEAF_OUT_PARAMETER_TEMPLATES)) {
5437  params = weed_get_plantptr_array_counted(xfilter, WEED_LEAF_OUT_PARAMETER_TEMPLATES, &nvals);
5438  count += nvals;
5439 
5440  out_params = (weed_plant_t **)lives_realloc(out_params, count * sizeof(weed_plant_t *));
5441  x = 0;
5442 
5443  for (j = xcount; j < count; j++) {
5444  out_params[j] = params[x++];
5445  }
5446  if (params) lives_free(params);
5447  xcount = count;
5448  }
5449  }
5450 
5451  if (count > 0) {
5452  weed_set_plantptr_array(filter, WEED_LEAF_OUT_PARAMETER_TEMPLATES, count, out_params);
5453  lives_free(out_params);
5454  }
5455 
5456  // use in channels from first filter
5457 
5458  xfilter = weed_filters[filts[0]];
5459  if (weed_plant_has_leaf(xfilter, WEED_LEAF_IN_CHANNEL_TEMPLATES)) {
5460  in_chans = weed_get_plantptr_array_counted(xfilter, WEED_LEAF_IN_CHANNEL_TEMPLATES, &count);
5461  weed_set_plantptr_array(filter, WEED_LEAF_IN_CHANNEL_TEMPLATES, count, in_chans);
5462  lives_free(in_chans);
5463  }
5464 
5465  // use out channels from last filter
5466 
5467  xfilter = weed_filters[filts[nfilts - 1]];
5468  if (weed_plant_has_leaf(xfilter, WEED_LEAF_OUT_CHANNEL_TEMPLATES)) {
5469  out_chans = weed_get_plantptr_array_counted(xfilter, WEED_LEAF_OUT_CHANNEL_TEMPLATES, &count);
5470  weed_set_plantptr_array(filter, WEED_LEAF_OUT_CHANNEL_TEMPLATES, count, out_chans);
5471  lives_free(out_chans);
5472  }
5473 
5474  return filter;
5475 }
5476 
5477 
5478 static void load_compound_plugin(char *plugin_name, char *plugin_path) {
5479  FILE *cpdfile;
5480 
5481  weed_plant_t *filter = NULL, *ptmpl, *iptmpl, *xfilter;
5482  char buff[16384];
5483  char **array, **svals;
5484  char *author = NULL, *tmp, *key;
5485  int *filters = NULL, *ivals;
5486  double *dvals;
5487  int xvals[4];
5488 
5489  boolean ok = TRUE, autoscale;
5490  int stage = 0, nfilts = 0, fnum, line = 0, version = 0;
5491  int qvals = 1, ntok, xfilt, xfilt2;
5492  int xconx = 0;
5493  int nparams, nchans, pnum, pnum2, xpnum2, cnum, cnum2, ptype, pptype, pcspace, pflags;
5494  int error;
5495 
5496  register int i;
5497 
5498  if ((cpdfile = fopen(plugin_path, "r"))) {
5499  while (fgets(buff, 16384, cpdfile)) {
5500  line++;
5501  lives_strstrip(buff);
5502  if (!(*buff)) {
5503  if (++stage == 5) break;
5504  if (stage == 2) {
5505  if (nfilts < 2) {
5506  if (!prefs->vj_mode) {
5507  d_print((tmp = lives_strdup_printf(_("Invalid compound effect %s - must have >1 sub filters\n"), plugin_name)));
5508  LIVES_ERROR(tmp);
5509  lives_free(tmp);
5510  }
5511  ok = FALSE;
5512  break;
5513  }
5514  filter = create_compound_filter(plugin_name, nfilts, filters);
5515  if (!filter) break;
5516  }
5517  continue;
5518  }
5519  switch (stage) {
5520  case 0:
5521  if (line == 1) author = lives_strdup(buff);
5522  if (line == 2) version = atoi(buff);
5523  break;
5524  case 1:
5525  // add filters
5526  fnum = weed_get_idx_for_hashname(buff, TRUE);
5527  if (fnum == -1) {
5528  if (!prefs->vj_mode) {
5529  d_print((tmp = lives_strdup_printf(_("Invalid effect %s found in compound effect %s, line %d\n"),
5530  buff, plugin_name, line)));
5531  LIVES_INFO(tmp);
5532  lives_free(tmp);
5533  }
5534  ok = FALSE;
5535  break;
5536  }
5537  filters = (int *)lives_realloc(filters, ++nfilts * sizeof(int));
5538  filters[nfilts - 1] = fnum;
5539  break;
5540  case 2:
5541  // override defaults: format is i|p|d0|d1|...|dn
5542  // NOTE: for obvious reasons, | may not be used inside string defaults
5543  ntok = get_token_count(buff, '|');
5544 
5545  if (ntok < 2) {
5546  if (!prefs->vj_mode) {
5547  d_print((tmp = lives_strdup_printf(_("Invalid default found in compound effect %s, line %d\n"), plugin_name, line)));
5548  LIVES_ERROR(tmp);
5549  lives_free(tmp);
5550  }
5551  ok = FALSE;
5552  break;
5553  }
5554 
5555  array = lives_strsplit(buff, "|", ntok);
5556 
5557  xfilt = atoi(array[0]); // sub filter number
5558  if (xfilt < 0 || xfilt >= nfilts) {
5559  if (!prefs->vj_mode) {
5560  d_print((tmp = lives_strdup_printf(_("Invalid filter %d for defaults found in compound effect %s, line %d\n"),
5561  xfilt, plugin_name, line)));
5562  LIVES_ERROR(tmp);
5563  lives_free(tmp);
5564  }
5565  ok = FALSE;
5566  lives_strfreev(array);
5567  break;
5568  }
5569  xfilter = get_weed_filter(filters[xfilt]);
5570 
5571  nparams = num_in_params(xfilter, FALSE, FALSE);
5572 
5573  pnum = atoi(array[1]);
5574 
5575  if (pnum >= nparams) {
5576  if (!prefs->vj_mode) {
5577  d_print((tmp = lives_strdup_printf(_("Invalid param %d for defaults found in compound effect %s, line %d\n"),
5578  pnum, plugin_name, line)));
5579  LIVES_ERROR(tmp);
5580  lives_free(tmp);
5581  }
5582  ok = FALSE;
5583  lives_strfreev(array);
5584  break;
5585  }
5586 
5587  // get pnum for compound filter
5588  for (i = 0; i < xfilt; i++) pnum += num_in_params(get_weed_filter(filters[i]), FALSE, FALSE);
5589 
5590  ptmpl = weed_filter_in_paramtmpl(filter, pnum, FALSE);
5591 
5592  ptype = weed_leaf_seed_type(ptmpl, WEED_LEAF_DEFAULT);
5593  pflags = weed_get_int_value(ptmpl, WEED_LEAF_FLAGS, &error);
5594  pptype = weed_paramtmpl_get_type(ptmpl);
5595 
5596  if (pptype == WEED_PARAM_COLOR) {
5597  pcspace = weed_get_int_value(ptmpl, WEED_LEAF_COLORSPACE, &error);
5598  qvals = 3;
5599  if (pcspace == WEED_COLORSPACE_RGBA) qvals = 4;
5600  }
5601 
5602  ntok -= 2;
5603 
5604  if ((ntok != weed_leaf_num_elements(ptmpl, WEED_LEAF_DEFAULT) && !(pflags & WEED_PARAMETER_VARIABLE_SIZE)) ||
5605  ntok % qvals != 0) {
5606  if (!prefs->vj_mode) {
5607  d_print((tmp = lives_strdup_printf(_("Invalid number of values for defaults found in compound effect %s, line %d\n"),
5608  plugin_name, line)));
5609  LIVES_ERROR(tmp);
5610  lives_free(tmp);
5611  }
5612  ok = FALSE;
5613  lives_strfreev(array);
5614  break;
5615  }
5616 
5617  // TODO - for INT and DOUBLE, check if default is within min/max bounds
5618 
5619  switch (ptype) {
5620  case WEED_SEED_INT:
5621  ivals = (int *)lives_malloc(ntok * sizint);
5622  for (i = 0; i < ntok; i++) {
5623  ivals[i] = atoi(array[i + 2]);
5624  }
5625  weed_set_int_array(ptmpl, WEED_LEAF_DEFAULT, ntok, ivals);
5626  lives_free(ivals);
5627  break;
5628  case WEED_SEED_DOUBLE:
5629  dvals = (double *)lives_malloc(ntok * sizdbl);
5630  for (i = 0; i < ntok; i++) {
5631  dvals[i] = strtod(array[i + 2], NULL);
5632  }
5633  weed_set_double_array(ptmpl, WEED_LEAF_DEFAULT, ntok, dvals);
5634  lives_free(dvals);
5635  break;
5636  case WEED_SEED_BOOLEAN:
5637  ivals = (int *)lives_malloc(ntok * sizint);
5638  for (i = 0; i < ntok; i++) {
5639  ivals[i] = atoi(array[i + 2]);
5640 
5641  if (ivals[i] != WEED_TRUE && ivals[i] != WEED_FALSE) {
5642  lives_free(ivals);
5643  if (!prefs->vj_mode) {
5644  d_print((tmp = lives_strdup_printf(_("Invalid non-boolean value for defaults found in compound effect %s, "
5645  "line %d\n"), pnum, plugin_name, line)));
5646  LIVES_ERROR(tmp);
5647  lives_free(tmp);
5648  }
5649  ok = FALSE;
5650  lives_strfreev(array);
5651  break;
5652  }
5653 
5654  }
5655  weed_set_boolean_array(ptmpl, WEED_LEAF_DEFAULT, ntok, ivals);
5656  lives_free(ivals);
5657  break;
5658  default: // string
5659  svals = (char **)lives_malloc(ntok * sizeof(char *));
5660  for (i = 0; i < ntok; i++) {
5661  svals[i] = lives_strdup(array[i + 2]);
5662  }
5663  weed_set_string_array(ptmpl, WEED_LEAF_DEFAULT, ntok, svals);
5664  for (i = 0; i < ntok; i++) {
5665  lives_free(svals[i]);
5666  }
5667  lives_free(svals);
5668  break;
5669  }
5670  lives_strfreev(array);
5671  break;
5672  case 3:
5673  // link params: format is f0|p0|autoscale|f1|p1
5674 
5675  ntok = get_token_count(buff, '|');
5676 
5677  if (ntok != 5) {
5678  if (!prefs->vj_mode) {
5679  d_print((tmp = lives_strdup_printf(_("Invalid param link found in compound effect %s, line %d\n"),
5680  plugin_name, line)));
5681  LIVES_ERROR(tmp);
5682  lives_free(tmp);
5683  }
5684  ok = FALSE;
5685  break;
5686  }
5687 
5688  array = lives_strsplit(buff, "|", ntok);
5689 
5690  xfilt = atoi(array[0]); // sub filter number
5691  if (xfilt < -1 || xfilt >= nfilts) {
5692  if (!prefs->vj_mode) {
5693  d_print((tmp = lives_strdup_printf(_("Invalid out filter %d for link params found in compound effect %s, line %d\n"),
5694  xfilt, plugin_name, line)));
5695  LIVES_ERROR(tmp);
5696  lives_free(tmp);
5697  }
5698  ok = FALSE;
5699  lives_strfreev(array);
5700  break;
5701  }
5702 
5703  pnum = atoi(array[1]);
5704 
5705  if (xfilt > -1) {
5706  xfilter = get_weed_filter(filters[xfilt]);
5707 
5708  if (weed_plant_has_leaf(xfilter, WEED_LEAF_OUT_PARAMETER_TEMPLATES))
5709  nparams = weed_leaf_num_elements(xfilter, WEED_LEAF_OUT_PARAMETER_TEMPLATES);
5710  else nparams = 0;
5711 
5712  if (pnum >= nparams) {
5713  if (!prefs->vj_mode) {
5714  d_print((tmp = lives_strdup_printf(_("Invalid out param %d for link params found in compound effect %s, line %d\n"),
5715  pnum, plugin_name, line)));
5716  LIVES_ERROR(tmp);
5717  lives_free(tmp);
5718  }
5719  ok = FALSE;
5720  lives_strfreev(array);
5721  break;
5722  }
5723  }
5724 
5725  autoscale = atoi(array[2]);
5726 
5727  if (autoscale != WEED_TRUE && autoscale != WEED_FALSE) {
5728  if (!prefs->vj_mode) {
5729  d_print((tmp = lives_strdup_printf(_("Invalid non-boolean value for autoscale found in compound effect %s, "
5730  "line %d\n"), pnum, plugin_name, line)));
5731  LIVES_ERROR(tmp);
5732  lives_free(tmp);
5733  }
5734  ok = FALSE;
5735  lives_strfreev(array);
5736  break;
5737  }
5738 
5739  xfilt2 = atoi(array[3]); // sub filter number
5740  if (xfilt >= nfilts) {
5741  if (!prefs->vj_mode) {
5742  d_print((tmp = lives_strdup_printf(_("Invalid in filter %d for link params found in compound effect %s, line %d\n"),
5743  xfilt2, plugin_name, line)));
5744  LIVES_ERROR(tmp);
5745  lives_free(tmp);
5746  }
5747  ok = FALSE;
5748  lives_strfreev(array);
5749  break;
5750  }
5751  xfilter = get_weed_filter(filters[xfilt2]);
5752 
5753  nparams = num_in_params(xfilter, FALSE, FALSE);
5754 
5755  pnum2 = atoi(array[4]);
5756 
5757  if (pnum2 >= nparams) {
5758  if (!prefs->vj_mode) {
5759  d_print((tmp = lives_strdup_printf(_("Invalid in param %d for link params found in compound effect %s, line %d\n"),
5760  pnum2, plugin_name, line)));
5761  LIVES_ERROR(tmp);
5762  lives_free(tmp);
5763  }
5764  ok = FALSE;
5765  lives_strfreev(array);
5766  break;
5767  }
5768 
5769  // calc xpnum2
5770  xpnum2 = pnum2;
5771  for (i = 0; i < xfilt2; i++) xpnum2 += num_in_params(get_weed_filter(filters[i]), FALSE, FALSE);
5772 
5773  // must get paramtmpl here from filter (not xfilter)
5774  iptmpl = weed_filter_in_paramtmpl(filter, xpnum2, FALSE);
5775 
5776  xvals[0] = xfilt;
5777  xvals[1] = pnum;
5778 
5779  weed_set_int_array(iptmpl, WEED_LEAF_HOST_INTERNAL_CONNECTION, 2, xvals);
5780  if (autoscale == WEED_TRUE) weed_set_boolean_value(iptmpl,
5782 
5783  lives_strfreev(array);
5784  break;
5785  case 4:
5786  // link alpha channels: format is f0|c0|f1|c1
5787  ntok = get_token_count(buff, '|');
5788 
5789  if (ntok != 4) {
5790  if (!prefs->vj_mode) {
5791  d_print((tmp = lives_strdup_printf(_("Invalid channel link found in compound effect %s, line %d\n"),
5792  plugin_name, line)));
5793  LIVES_ERROR(tmp);
5794  lives_free(tmp);
5795  }
5796  ok = FALSE;
5797  break;
5798  }
5799 
5800  array = lives_strsplit(buff, "|", ntok);
5801 
5802  xfilt = atoi(array[0]); // sub filter number
5803  if (xfilt < 0 || xfilt >= nfilts) {
5804  if (!prefs->vj_mode) {
5805  d_print((tmp = lives_strdup_printf(_("Invalid out filter %d for link channels found in compound effect %s, "
5806  "line %d\n"), xfilt, plugin_name, line)));
5807  LIVES_ERROR(tmp);
5808  lives_free(tmp);
5809  }
5810  ok = FALSE;
5811  lives_strfreev(array);
5812  break;
5813  }
5814  xfilter = get_weed_filter(filters[xfilt]);
5815 
5816  nchans = 0;
5817  if (weed_plant_has_leaf(xfilter, WEED_LEAF_OUT_CHANNEL_TEMPLATES)) {
5818  nchans = weed_leaf_num_elements(xfilter, WEED_LEAF_OUT_CHANNEL_TEMPLATES);
5819  if (!weed_get_plantptr_value(xfilter, WEED_LEAF_OUT_CHANNEL_TEMPLATES, &error)) nchans = 0;
5820  }
5821 
5822  cnum = atoi(array[1]);
5823 
5824  if (cnum >= nchans) {
5825  if (!prefs->vj_mode) {
5826  d_print((tmp = lives_strdup_printf(_("Invalid out channel %d for link params found in compound effect %s, line %d\n"),
5827  cnum, plugin_name, line)));
5828  LIVES_ERROR(tmp);
5829  lives_free(tmp);
5830  }
5831  ok = FALSE;
5832  lives_strfreev(array);
5833  break;
5834  }
5835 
5836  xfilt2 = atoi(array[2]); // sub filter number
5837  if (xfilt2 <= xfilt || xfilt >= nfilts) {
5838  if (!prefs->vj_mode) {
5839  d_print((tmp = lives_strdup_printf(_("Invalid in filter %d for link channels found in compound effect %s, line %d\n"),
5840  xfilt2, plugin_name, line)));
5841  LIVES_ERROR(tmp);
5842  lives_free(tmp);
5843  }
5844  ok = FALSE;
5845  lives_strfreev(array);
5846  break;
5847  }
5848  xfilter = get_weed_filter(filters[xfilt2]);
5849 
5850  nchans = 0;
5851  if (weed_plant_has_leaf(xfilter, WEED_LEAF_IN_CHANNEL_TEMPLATES)) {
5852  nchans = weed_leaf_num_elements(xfilter, WEED_LEAF_IN_CHANNEL_TEMPLATES);
5853  if (!weed_get_plantptr_value(xfilter, WEED_LEAF_IN_CHANNEL_TEMPLATES, &error)) nchans = 0;
5854  }
5855 
5856  cnum2 = atoi(array[3]);
5857 
5858  if (cnum2 >= nchans) {
5859  if (!prefs->vj_mode) {
5860  d_print((tmp = lives_strdup_printf(_("Invalid in channel %d for link params found in compound effect %s, line %d\n"),
5861  cnum2, plugin_name, line)));
5862  LIVES_ERROR(tmp);
5863  lives_free(tmp);
5864  }
5865  ok = FALSE;
5866  lives_strfreev(array);
5867  break;
5868  }
5869 
5870  xvals[0] = xfilt;
5871  xvals[1] = cnum;
5872  xvals[2] = xfilt2;
5873  xvals[3] = cnum2;
5874 
5875  // unlike with in_param_templates, which are copy by value, in_channel_templates are copy by ref.
5876  // so we need to add some extra leaves to the compound filter to note channel connections
5877  // - we will link the actual channels when we create an instance from the filter
5879  weed_set_int_array(filter, key, 4, xvals);
5880  lives_free(key);
5881 
5882  lives_strfreev(array);
5883  break;
5884  default:
5885  break;
5886  }
5887  if (!ok) {
5888  if (filter) weed_filter_free(filter, NULL);
5889  filter = NULL;
5890  break;
5891  }
5892  }
5893  fclose(cpdfile);
5894  }
5895 
5896  if (filter) {
5897  int idx;
5898  char *filter_name = lives_strdup_printf(_("Compound:%s"), plugin_name);
5899  weed_set_string_value(filter, WEED_LEAF_NAME, filter_name);
5900 
5901  weed_set_string_value(filter, WEED_LEAF_AUTHOR, author);
5902  weed_set_int_value(filter, WEED_LEAF_VERSION, version);
5903  idx = num_weed_filters++;
5904 
5905  weed_filters = (weed_plant_t **)lives_realloc(weed_filters, num_weed_filters * sizeof(weed_plant_t *));
5906  weed_filters[idx] = filter;
5907  hashnames = (lives_hashjoint *)lives_realloc(hashnames, num_weed_filters * sizeof(lives_hashjoint));
5908  gen_hashnames(idx, idx);
5909  lives_free(filter_name);
5910  }
5911 
5912  if (author) lives_free(author);
5913  if (filters) lives_free(filters);
5914 }
5915 
5916 
5917 static int load_compound_fx(void) {
5918  LiVESList *compound_plugin_list;
5919 
5920  int plugin_idx, onum_filters = num_weed_filters;
5921 
5922  char *lives_compound_plugin_path, *plugin_name, *plugin_path;
5923 
5925 
5926  lives_compound_plugin_path = lives_build_path(prefs->config_datadir, PLUGIN_COMPOUND_EFFECTS_CUSTOM, NULL);
5927  compound_plugin_list = get_plugin_list(PLUGIN_COMPOUND_EFFECTS_CUSTOM, TRUE, lives_compound_plugin_path, NULL);
5928 
5929  for (plugin_idx = 0; plugin_idx < lives_list_length(compound_plugin_list); plugin_idx++) {
5930  plugin_name = (char *)lives_list_nth_data(compound_plugin_list, plugin_idx);
5931  plugin_path = lives_build_path(lives_compound_plugin_path, plugin_name, NULL);
5932  load_compound_plugin(plugin_name, plugin_path);
5933  lives_free(plugin_path);
5935  }
5936 
5937  lives_list_free_all(&compound_plugin_list);
5938 
5940  lives_free(lives_compound_plugin_path);
5941 
5942  lives_compound_plugin_path = lives_build_path(prefs->prefix_dir, PLUGIN_COMPOUND_DIR,
5944  compound_plugin_list = get_plugin_list(PLUGIN_COMPOUND_EFFECTS_BUILTIN, TRUE, lives_compound_plugin_path, NULL);
5945 
5946  for (plugin_idx = 0; plugin_idx < lives_list_length(compound_plugin_list); plugin_idx++) {
5947  plugin_name = (char *)lives_list_nth_data(compound_plugin_list, plugin_idx);
5948  plugin_path = lives_build_path(lives_compound_plugin_path, plugin_name, NULL);
5949  load_compound_plugin(plugin_name, plugin_path);
5950  lives_free(plugin_path);
5952  }
5953 
5954  lives_list_free_all(&compound_plugin_list);
5955 
5956  if (num_weed_filters > onum_filters) {
5957  d_print(_("Successfully loaded %d compound filters\n"), num_weed_filters - onum_filters);
5958  }
5959 
5960  lives_free(lives_compound_plugin_path);
5962  return num_weed_filters - onum_filters;
5963 }
5964 
5965 
5966 void weed_unload_all(void) {
5967  weed_plant_t *filter, *plugin_info, *host_info;
5968  LiVESList *pinfo = NULL, *list, *freed_plants = NULL, *hostinfo_ptrs = NULL;
5969 
5970  int error;
5971 
5972  register int i, j;
5973 
5974  if (!fx_inited) return;
5975 
5976  mainw->num_tr_applied = 0;
5978 
5979  for (i = 0; i < FX_KEYS_MAX_VIRTUAL; i++) {
5980  for (j = 0; j < prefs->max_modes_per_key; j++) {
5981  if (key_defaults[i][j]) free_key_defaults(i, j);
5982  }
5984  }
5985 
5986  THREADVAR(chdir_failed) = FALSE;
5987 
5988  for (i = 0; i < num_weed_filters; i++) {
5989  filter = weed_filters[i];
5990  plugin_info = weed_get_plantptr_value(filter, WEED_LEAF_PLUGIN_INFO, &error);
5991  if (!plugin_info) {
5992  weed_filter_free(filter, &freed_plants);
5993  lives_list_free(freed_plants);
5994  freed_plants = NULL;
5995  continue;
5996  }
5997  freed_plants = weed_get_voidptr_value(plugin_info, WEED_LEAF_FREED_PLANTS, NULL);
5998  weed_filter_free(filter, &freed_plants);
5999  if (!pinfo || lives_list_index(pinfo, plugin_info) == -1) {
6000  pinfo = lives_list_append(pinfo, plugin_info);
6001  weed_set_voidptr_value(plugin_info, WEED_LEAF_FREED_PLANTS, (void *)freed_plants);
6002  }
6003  freed_plants = NULL;
6004  }
6005 
6006  list = pinfo;
6007 
6008  while (pinfo) {
6009  // We need to free ALL the filters for a plugin before calling desetup and dlclose.
6010  // Otherwise we will end doing this on an unloaded plugin !
6011  plugin_info = (weed_plant_t *)pinfo->data;
6012  if (plugin_info) {
6013  void *handle = weed_get_voidptr_value(plugin_info, WEED_LEAF_HOST_HANDLE, &error);
6014  if (handle && prefs->startup_phase == 0) {
6015  weed_desetup_f desetup_fn;
6016  if ((desetup_fn = (weed_desetup_f)dlsym(handle, "weed_desetup")) != NULL) {
6017  char *cwd = cd_to_plugin_dir(plugin_info);
6018  // call weed_desetup()
6019  (*desetup_fn)();
6020  lives_chdir(cwd, FALSE);
6021  lives_free(cwd);
6022  }
6023  dlclose(handle);
6025  }
6026  freed_plants = weed_get_voidptr_value(plugin_info, WEED_LEAF_FREED_PLANTS, NULL);
6027  if (freed_plants) {
6028  lives_list_free(freed_plants);
6029  freed_plants = NULL;
6030  }
6031  host_info = weed_get_plantptr_value((weed_plant_t *)pinfo->data, WEED_LEAF_HOST_INFO, &error);
6032  weed_plant_free_if_not_in_list(host_info, &hostinfo_ptrs);
6033  weed_plant_free(plugin_info);
6034  }
6035  pinfo = pinfo->next;
6036  }
6037 
6038  if (list) lives_list_free(list);
6039  if (hostinfo_ptrs) lives_list_free(hostinfo_ptrs);
6040 
6041  for (i = 0; i < num_weed_filters; i++) {
6042  for (j = 0; j < NHASH_TYPES; j ++) {
6043  if (hashnames[i][j].string) lives_free(hashnames[i][j].string);
6044  }
6045  }
6046 
6047  if (hashnames) lives_free(hashnames);
6048  if (weed_filters) lives_free(weed_filters);
6049 
6050  lives_list_free(weed_fx_sorted_list);
6051 
6052  for (i = 0; i < FX_KEYS_MAX; i++) {
6053  lives_free(key_to_fx[i]);
6054  lives_free(key_to_instance[i]);
6055  lives_free(key_to_instance_copy[i]);
6056  }
6057 
6059 
6060  if (THREADVAR(chdir_failed)) {
6061  char *dirs = (_("Some plugin directories"));
6062  do_chdir_failed_error(dirs);
6063  lives_free(dirs);
6064  }
6065 }
6066 
6067 
6068 static void weed_in_channels_free(weed_plant_t *inst) {
6069  int num_channels;
6070  weed_plant_t **channels = weed_instance_get_in_channels(inst, &num_channels);
6071  if (num_channels > 0) {
6072  for (int i = 0; i < num_channels; i++) {
6073  if (channels[i]) {
6075  else weed_plant_free(channels[i]);
6076  }
6077  }
6078  }
6079  lives_free(channels);
6080 }
6081 
6082 
6083 static void weed_out_channels_free(weed_plant_t *inst) {
6084  int num_channels;
6085  weed_plant_t **channels = weed_instance_get_out_channels(inst, &num_channels);
6086  if (num_channels > 0) {
6087  for (int i = 0; i < num_channels; i++) {
6088  if (channels[i]) {
6090  else weed_plant_free(channels[i]);
6091  }
6092  }
6093  }
6094  lives_free(channels);
6095 }
6096 
6097 
6098 static void weed_channels_free(weed_plant_t *inst) {
6099  weed_in_channels_free(inst);
6100  weed_out_channels_free(inst);
6101 }
6102 
6103 
6104 static void weed_gui_free(weed_plant_t *plant) {
6105  weed_plant_t *gui = weed_get_plantptr_value(plant, WEED_LEAF_GUI, NULL);
6106  if (gui) weed_plant_free(gui);
6107 }
6108 
6109 
6110 void weed_in_params_free(weed_plant_t **parameters, int num_parameters) {
6111  for (int i = 0; i < num_parameters; i++) {
6112  if (parameters[i]) {
6113  if (parameters[i] == mainw->rte_textparm) mainw->rte_textparm = NULL;
6114  weed_gui_free(parameters[i]);
6115  weed_plant_free(parameters[i]);
6116  }
6117  }
6118 }
6119 
6120 
6121 void weed_in_parameters_free(weed_plant_t *inst) {
6122  int num_parameters;
6123  weed_plant_t **parameters = weed_instance_get_in_params(inst, &num_parameters);
6124  if (num_parameters > 0) {
6125  weed_in_params_free(parameters, num_parameters);
6126  weed_leaf_delete(inst, WEED_LEAF_IN_PARAMETERS);
6127  }
6128  lives_free(parameters);
6129 }
6130 
6131 
6132 static void weed_out_parameters_free(weed_plant_t *inst) {
6133  int num_parameters;
6134  weed_plant_t **parameters = weed_instance_get_out_params(inst, &num_parameters);
6135  if (num_parameters > 0) {
6136  for (int i = 0; i < num_parameters; i++) {
6137  if (parameters[i]) weed_plant_free(parameters[i]);
6138  }
6139  weed_leaf_delete(inst, WEED_LEAF_OUT_PARAMETERS);
6140  }
6141  lives_free(parameters);
6142 }
6143 
6144 
6145 static void weed_parameters_free(weed_plant_t *inst) {
6147  weed_out_parameters_free(inst);
6148 }
6149 
6150 
6151 static void lives_free_instance(weed_plant_t *inst) {
6152  weed_channels_free(inst);
6153  weed_parameters_free(inst);
6154  weed_plant_free(inst);
6155 }
6156 
6157 
6159  // return new refcount
6160  // return value of -1 indicates the instance was freed
6161  // -2 if the inst was NULL
6162  int nrefs;
6163  if (!inst) return -2;
6164 
6165  pthread_mutex_lock(&mainw->instance_ref_mutex);
6166  nrefs = weed_get_int_value(inst, WEED_LEAF_HOST_REFS, NULL) - 1;
6167 
6168  if (nrefs <= -1) {
6169  char *msg;
6170  pthread_mutex_unlock(&mainw->instance_ref_mutex);
6171  if (weed_plant_has_leaf(inst, WEED_LEAF_HOST_REFS)) {
6172  msg = lives_strdup_printf("unref of filter instance (%p) with nrefs == %d\n", inst, nrefs);
6173  LIVES_ERROR(msg);
6174  break_me("invalid filt inst unref");
6175  }
6176  return nrefs;
6177  }
6178  weed_set_int_value(inst, WEED_LEAF_HOST_REFS, nrefs);
6179  pthread_mutex_unlock(&mainw->instance_ref_mutex);
6180 
6181 #ifdef DEBUG_REFCOUNT
6182  g_print("unref %p, nrefs==%d\n", inst, nrefs);
6183 #endif
6184  if (nrefs == -1) {
6185 #ifdef DEBUG_REFCOUNT
6186  g_print("FREE %p\n", inst);
6187 #endif
6188  lives_free_instance(inst);
6189  }
6190  return nrefs;
6191 }
6192 
6193 
6194 int _weed_instance_ref(weed_plant_t *inst) {
6195  // return refcount after the operation
6196  // or 0 if the inst was NULL
6197  int nrefs;
6198 
6199  if (!inst) return 0;
6200 
6201  pthread_mutex_lock(&mainw->instance_ref_mutex);
6202  nrefs = weed_get_int_value(inst, WEED_LEAF_HOST_REFS, NULL);
6203  weed_set_int_value(inst, WEED_LEAF_HOST_REFS, ++nrefs);
6204 #ifdef DEBUG_REFCOUNT
6205  g_print("ref %p, nrefs==%d\n", inst, nrefs);
6206 #endif
6207  pthread_mutex_unlock(&mainw->instance_ref_mutex);
6208  return nrefs;
6209 }
6210 
6211 
6212 weed_plant_t *_weed_instance_obtain(int line, char *file, int key, int mode) {
6213  // does not create the instance, but adds a ref to an existing one
6214  // caller MUST call weed_instance_unref() when instance is no longer needed
6215  weed_plant_t *instance;
6216 
6217  if (mode < 0 || mode > rte_key_getmaxmode(key + 1)) return NULL;
6218  pthread_mutex_lock(&mainw->instance_ref_mutex);
6219  instance = key_to_instance[key][mode];
6220 #ifdef DEBUG_REFCOUNT
6221  if (instance) g_print("wio %p at line %d in file %s\n", instance, line, file);
6222 #endif
6223  if (instance) _weed_instance_ref(instance);
6224  pthread_mutex_unlock(&mainw->instance_ref_mutex);
6225  return instance;
6226 }
6227 
6228 
6229 #ifndef DEBUG_REFCOUNT
6230 LIVES_GLOBAL_INLINE int weed_instance_ref(weed_plant_t *inst) {
6231  return _weed_instance_ref(inst);
6232 }
6233 
6234 LIVES_GLOBAL_INLINE int weed_instance_unref(weed_plant_t *inst) {
6235  return _weed_instance_unref(inst);
6236 }
6237 
6238 LIVES_GLOBAL_INLINE weed_plant_t *weed_instance_obtain(int key, int mode) {
6239  return _weed_instance_obtain(0, NULL, key, mode);
6240 }
6241 #endif
6242 
6249 static weed_plant_t **weed_channels_create(weed_plant_t *filter, boolean in) {
6250  weed_plant_t **channels, **chantmpls;
6251  int num_channels;
6252  int i, j;
6253  int ccount = 0;
6254  int num_repeats;
6255  int flags;
6256  boolean pvary = FALSE;
6257 
6258  if (in) chantmpls = weed_filter_get_in_chantmpls(filter, &num_channels);
6259  else chantmpls = weed_filter_get_out_chantmpls(filter, &num_channels);
6260 
6261  for (i = 0; i < num_channels; i++) {
6262  if (weed_plant_has_leaf(chantmpls[i], WEED_LEAF_HOST_REPEATS))
6263  num_repeats = weed_get_int_value(chantmpls[i], WEED_LEAF_HOST_REPEATS, NULL);
6264  else num_repeats = 1;
6265  ccount += num_repeats;
6266  }
6267 
6268  channels = (weed_plant_t **)lives_calloc((ccount + 1), sizeof(weed_plant_t *));
6269 
6270  flags = weed_filter_get_flags(filter);
6271  if (flags & WEED_FILTER_PALETTES_MAY_VARY) {
6272  pvary = TRUE;
6273  }
6274 
6275  ccount = 0;
6276 
6277  for (i = 0; i < num_channels; i++) {
6278  if (weed_plant_has_leaf(chantmpls[i], WEED_LEAF_HOST_REPEATS))
6279  num_repeats = weed_get_int_value(chantmpls[i], WEED_LEAF_HOST_REPEATS, NULL);
6280  else num_repeats = 1;
6281  for (j = 0; j < num_repeats; j++) {
6283  channels[ccount] = weed_plant_new(WEED_PLANT_CHANNEL);
6284  weed_set_plantptr_value(channels[ccount], WEED_LEAF_TEMPLATE, chantmpls[i]);
6285  if (weed_chantmpl_is_audio(chantmpls[i]) == WEED_FALSE) {
6286  int rah = ALIGN_DEF, nplanes, width, n, pal;
6287  int rs[4];
6288  weed_set_voidptr_value(channels[ccount], WEED_LEAF_PIXEL_DATA, NULL);
6289  set_channel_size(filter, channels[ccount], DEF_GEN_WIDTH, DEF_GEN_HEIGHT);
6290  pal = WEED_PALETTE_END;
6291  if (pvary) pal = weed_get_int_value(chantmpls[i], WEED_LEAF_PALETTE_LIST, NULL);
6292  if (pal == WEED_PALETTE_NONE) pal = weed_get_int_value(filter, WEED_LEAF_PALETTE_LIST, NULL);
6293  weed_set_int_value(channels[ccount], WEED_LEAF_CURRENT_PALETTE, pal);
6294  if (weed_plant_has_leaf(filter, WEED_LEAF_ALIGNMENT_HINT)) {
6295  rah = weed_get_int_value(filter, WEED_LEAF_ALIGNMENT_HINT, NULL);
6296  }
6297  nplanes = weed_palette_get_nplanes(pal);
6298  width = weed_channel_get_width(channels[ccount]) * (weed_palette_get_bits_per_macropixel(pal) >> 3);
6299  for (n = 0; n < weed_palette_get_nplanes(pal); n++) {
6300  rs[n] = ALIGN_CEIL(width * weed_palette_get_plane_ratio_horizontal(pal, n), rah);
6301  }
6302  weed_set_int_array(channels[ccount], WEED_LEAF_ROWSTRIDES, nplanes, rs);
6303  }
6304  if (weed_plant_has_leaf(chantmpls[i], WEED_LEAF_HOST_DISABLED)) {
6305  weed_set_boolean_value(channels[ccount], WEED_LEAF_DISABLED,
6306  weed_get_boolean_value(chantmpls[i], WEED_LEAF_HOST_DISABLED, NULL));
6307  }
6308  weed_add_plant_flags(channels[ccount], WEED_FLAG_UNDELETABLE | WEED_FLAG_IMMUTABLE, "plugin_");
6309  ccount++;
6310  }
6311  }
6312  channels[ccount] = NULL;
6313  lives_free(chantmpls);
6314  return channels;
6315 }
6316 
6317 
6318 weed_plant_t **weed_params_create(weed_plant_t *filter, boolean in) {
6319  // return set of parameters with default/host_default values
6320  // in==TRUE create in parameters for filter
6321  // in==FALSE create out parameters for filter
6322 
6323  weed_plant_t **params, **paramtmpls;
6324  int num_params;
6325 
6326  if (in) paramtmpls = weed_filter_get_in_paramtmpls(filter, &num_params);
6327  else paramtmpls = weed_filter_get_out_paramtmpls(filter, &num_params);
6328  if (num_params == 0) return NULL;
6329 
6330  params = (weed_plant_t **)lives_malloc((num_params + 1) * sizeof(weed_plant_t *));
6331 
6332  for (int i = 0; i < num_params; i++) {
6333  params[i] = weed_plant_new(WEED_PLANT_PARAMETER);
6334  weed_set_plantptr_value(params[i], WEED_LEAF_TEMPLATE, paramtmpls[i]);
6335  if (in && !weed_paramtmpl_value_irrelevant(paramtmpls[i])) {
6336  if (weed_plant_has_leaf(paramtmpls[i], WEED_LEAF_HOST_DEFAULT)) {
6337  weed_leaf_copy(params[i], WEED_LEAF_VALUE, paramtmpls[i], WEED_LEAF_HOST_DEFAULT);
6338  } else weed_leaf_copy(params[i], WEED_LEAF_VALUE, paramtmpls[i], WEED_LEAF_DEFAULT);
6339  weed_add_plant_flags(params[i], WEED_FLAG_UNDELETABLE | WEED_FLAG_IMMUTABLE, "plugin_");
6340  } else {
6341  weed_leaf_copy(params[i], WEED_LEAF_VALUE, paramtmpls[i], WEED_LEAF_DEFAULT);
6342  }
6343  }
6344  params[num_params] = NULL;
6345  lives_free(paramtmpls);
6346 
6347  return params;
6348 }
6349 
6350 
6351 static void set_default_channel_sizes(weed_plant_t *filter, weed_plant_t **in_channels, weed_plant_t **out_channels) {
6352  // set some reasonable default channel sizes when we first init the effect
6353  weed_plant_t *channel, *chantmpl;
6354  boolean has_aud_in_chans = FALSE;
6355  int width, height;
6356 
6357  register int i;
6358 
6359  // ignore filters with no in/out channels (e.g. data processors)
6360  if ((!in_channels || !in_channels[0]) && (!out_channels || !out_channels[0])) return;
6361 
6362  for (i = 0; in_channels && in_channels[i] &&
6363  !(weed_plant_has_leaf(in_channels[i], WEED_LEAF_DISABLED) &&
6364  weed_get_boolean_value(in_channels[i], WEED_LEAF_DISABLED, NULL) == WEED_TRUE); i++) {
6365  channel = in_channels[i];
6366  chantmpl = weed_get_plantptr_value(channel, WEED_LEAF_TEMPLATE, NULL);
6367  if (weed_chantmpl_is_audio(chantmpl) == WEED_FALSE) {
6368  set_channel_size(filter, channel, 320, 240);
6369  } else {
6370  if (mainw->current_file == -1) {
6371  weed_set_int_value(channel, WEED_LEAF_AUDIO_CHANNELS, DEFAULT_AUDIO_CHANS);
6372  weed_set_int_value(channel, WEED_LEAF_AUDIO_RATE, DEFAULT_AUDIO_RATE);
6373  } else {
6374  weed_set_int_value(channel, WEED_LEAF_AUDIO_CHANNELS, cfile->achans);
6375  weed_set_int_value(channel, WEED_LEAF_AUDIO_RATE, cfile->arate);
6376  }
6377  weed_set_int_value(channel, WEED_LEAF_AUDIO_DATA_LENGTH, 0);
6378  weed_set_voidptr_value(channel, WEED_LEAF_AUDIO_DATA, NULL);
6379  has_aud_in_chans = TRUE;
6380  }
6381  }
6382 
6383  for (i = 0; out_channels && out_channels[i]; i++) {
6384  channel = out_channels[i];
6385  chantmpl = weed_channel_get_template(channel);
6386  if (weed_chantmpl_is_audio(chantmpl) == WEED_FALSE) {
6387  width = DEF_FRAME_HSIZE_UNSCALED;
6388  height = DEF_FRAME_VSIZE_UNSCALED;
6389  set_channel_size(filter, channel, width, height);
6390  } else {
6391  if (mainw->current_file == -1 || !has_aud_in_chans) {
6392  weed_set_int_value(channel, WEED_LEAF_AUDIO_CHANNELS, DEFAULT_AUDIO_CHANS);
6393  weed_set_int_value(channel, WEED_LEAF_AUDIO_RATE, DEFAULT_AUDIO_RATE);
6394  } else {
6395  weed_set_int_value(channel, WEED_LEAF_AUDIO_CHANNELS, cfile->achans);
6396  weed_set_int_value(channel, WEED_LEAF_AUDIO_RATE, cfile->arate);
6397  }
6398  weed_set_int_value(channel, WEED_LEAF_AUDIO_DATA_LENGTH, 0);
6399  weed_set_voidptr_value(channel, WEED_LEAF_AUDIO_DATA, NULL);
6400  }
6401  }
6402 }
6403 
6404 
6405 static weed_plant_t *weed_create_instance(weed_plant_t *filter, weed_plant_t **inc, weed_plant_t **outc,
6406  weed_plant_t **inp, weed_plant_t **outp) {
6407  // here we create a new filter_instance from the ingredients:
6408  // filter_class, in_channels, out_channels, in_parameters, out_parameters
6409  weed_plant_t *inst = weed_plant_new(WEED_PLANT_FILTER_INSTANCE);
6410 
6411  int flags = WEED_FLAG_IMMUTABLE | WEED_FLAG_UNDELETABLE, n;
6412 
6413  weed_set_plantptr_value(inst, WEED_LEAF_FILTER_CLASS, filter);
6414  if (inc) weed_set_plantptr_array(inst, WEED_LEAF_IN_CHANNELS, weed_flagset_array_count(inc, TRUE), inc);
6415  if (outc) weed_set_plantptr_array(inst, WEED_LEAF_OUT_CHANNELS, weed_flagset_array_count(outc, TRUE), outc);
6416  if (inp) weed_set_plantptr_array(inst, WEED_LEAF_IN_PARAMETERS, weed_flagset_array_count(inp, TRUE), inp);
6417  if (outp) {
6418  weed_set_plantptr_array(inst, WEED_LEAF_OUT_PARAMETERS, (n = weed_flagset_array_count(outp, TRUE)), outp);
6419  for (int i = 0; i < n; i++) {
6420  // allow plugins to set out_param WEED_LEAF_VALUE
6421  weed_leaf_set_flags(outp[i], WEED_LEAF_VALUE, (weed_leaf_get_flags(outp[i], WEED_LEAF_VALUE) | flags) ^ flags);
6422  }
6423  }
6424 
6425  weed_set_boolean_value(inst, WEED_LEAF_HOST_INITED, WEED_FALSE);
6426  weed_add_plant_flags(inst, WEED_FLAG_IMMUTABLE | WEED_FLAG_UNDELETABLE, "plugin_");
6427  return inst;
6428 }
6429 
6430 
6431 void add_param_connections(weed_plant_t *inst) {
6432  weed_plant_t **in_ptmpls, **outp;
6433  weed_plant_t *iparam, *oparam, *first_inst = inst, *filter = weed_instance_get_filter(inst, TRUE);
6434  int *xvals;
6435  int nptmpls, error;
6436 
6437  register int i;
6438 
6439  in_ptmpls = weed_get_plantptr_array_counted(filter, WEED_LEAF_IN_PARAMETER_TEMPLATES, &nptmpls);
6440  if (!in_ptmpls) return;
6441 
6442  for (i = 0; i < nptmpls; i++) {
6443  if (weed_plant_has_leaf(in_ptmpls[i], WEED_LEAF_HOST_INTERNAL_CONNECTION)) {
6444  xvals = weed_get_int_array(in_ptmpls[i], WEED_LEAF_HOST_INTERNAL_CONNECTION, &error);
6445 
6446  iparam = weed_inst_in_param(first_inst, i, FALSE, FALSE);
6447 
6448  if (xvals[0] > -1) {
6449  inst = first_inst;
6450  while (--xvals[0] >= 0) inst = get_next_compound_inst(inst);
6451 
6452  outp = weed_get_plantptr_array(inst, WEED_LEAF_OUT_PARAMETERS, &error);
6453  oparam = outp[xvals[1]];
6454  lives_free(outp);
6455  } else oparam = iparam; // just hide the parameter, but don't pull a value
6456 
6457  weed_set_plantptr_value(iparam, WEED_LEAF_HOST_INTERNAL_CONNECTION, oparam);
6458 
6459  if (weed_plant_has_leaf(in_ptmpls[i], WEED_LEAF_HOST_INTERNAL_CONNECTION_AUTOSCALE) &&
6460  weed_get_boolean_value(in_ptmpls[i], WEED_LEAF_HOST_INTERNAL_CONNECTION_AUTOSCALE, &error) == WEED_TRUE)
6461  weed_set_boolean_value(iparam, WEED_LEAF_HOST_INTERNAL_CONNECTION_AUTOSCALE, WEED_TRUE);
6462  lives_free(xvals);
6463  }
6464  }
6465  lives_free(in_ptmpls);
6466 }
6467 
6468 
6469 weed_plant_t *weed_instance_from_filter(weed_plant_t *filter) {
6470  // return an instance from a filter, with the (first if compound) instance refcounted
6471  // caller should call weed_instance_unref() when done
6472  weed_plant_t **inc = NULL, **outc = NULL, **inp = NULL, **outp = NULL, **xinp;
6473 
6474  weed_plant_t *last_inst = NULL, *first_inst = NULL, *inst, *ofilter = filter;
6475  weed_plant_t *ochan = NULL;
6476 
6477  int *filters = NULL, *xvals;
6478 
6479  char *key;
6480 
6481  int nfilters, ninpar = 0, error;
6482 
6483  int xcnumx = 0, x, poffset = 0;
6484 
6485  int i, j;
6486 
6487  if ((nfilters = num_compound_fx(filter)) > 1) {
6488  filters = weed_get_int_array(filter, WEED_LEAF_HOST_FILTER_LIST, NULL);
6489  }
6490 
6491  inp = weed_params_create(filter, TRUE);
6492 
6493  for (i = 0; i < nfilters; i++) {
6494  if (filters) {
6495  filter = weed_filters[filters[i]];
6496  }
6497 
6498  // create channels from channel_templates
6499  inc = weed_channels_create(filter, TRUE);
6500  outc = weed_channels_create(filter, FALSE);
6501 
6502  set_default_channel_sizes(filter, inc, outc); // we set the initial channel sizes to some reasonable defaults
6503 
6504  // create parameters from parameter_templates
6505  outp = weed_params_create(filter, FALSE);
6506 
6507  if (nfilters == 1) xinp = inp;
6508  else {
6509  // for a compound filter, assign only the params which belong to the instance
6510  if (ninpar == 0) xinp = NULL;
6511  else {
6512  xinp = (weed_plant_t **)lives_malloc((ninpar + 1) * sizeof(weed_plant_t *));
6513  x = 0;
6514  for (j = poffset; j < poffset + ninpar; j++) xinp[x++] = inp[j];
6515  xinp[x] = NULL;
6516  poffset += ninpar;
6517  }
6518  }
6519 
6520  if (i == 0) pthread_mutex_lock(&mainw->instance_ref_mutex);
6521  inst = weed_create_instance(filter, inc, outc, xinp, outp);
6522 
6523  if (i == 0) {
6524  weed_instance_ref(inst);
6525  pthread_mutex_unlock(&mainw->instance_ref_mutex);
6526  }
6527 
6528  if (filters) weed_set_plantptr_value(inst, WEED_LEAF_HOST_COMPOUND_CLASS, ofilter);
6529 
6530  if (i > 0) {
6531  weed_set_plantptr_value(last_inst, WEED_LEAF_HOST_NEXT_INSTANCE, inst);
6532  } else first_inst = inst;
6533 
6534  last_inst = inst;
6535 
6536  lives_freep((void **)&inc);
6537  lives_freep((void **)&outc);
6538  lives_freep((void **)&outp);
6539  if (xinp != inp) lives_freep((void **)&xinp);
6540 
6541  /* for (j = 0; j < ninpar; j++) { */
6542  /* // copy param values if that was set up */
6543  /* set_copy_to(inst, j, TRUE); */
6544  /* } */
6545  }
6546 
6547  lives_freep((void **)&inp);
6548 
6549  if (filters) {
6550  lives_free(filters);
6551 
6552  // for compound fx, add param and channel connections
6553  filter = ofilter;
6554 
6555  // add param connections
6556  add_param_connections(first_inst);
6557 
6558  while (1) {
6559  // add channel connections
6561  if (weed_plant_has_leaf(filter, key)) {
6562  xvals = weed_get_int_array(filter, key, &error);
6563 
6564  inst = first_inst;
6565  while (1) {
6566  if (xvals[0]-- == 0) {
6567  // got the out instance
6568  outc = weed_get_plantptr_array(inst, WEED_LEAF_OUT_CHANNELS, &error);
6569  ochan = outc[xvals[1]];
6570  lives_freep((void **)&outc);
6571  }
6572  if (xvals[2]-- == 0) {
6573  // got the in instance
6574  inc = weed_get_plantptr_array(inst, WEED_LEAF_IN_CHANNELS, &error);
6575  weed_set_plantptr_value(inc[xvals[3]], WEED_LEAF_HOST_INTERNAL_CONNECTION, ochan);
6576  lives_freep((void **)&inc);
6577  break;
6578  }
6579 
6580  inst = get_next_compound_inst(inst);
6581  }
6582 
6583  lives_free(xvals);
6584  lives_free(key);
6585  } else {
6586  lives_free(key);
6587  break;
6588  }
6589  }
6590  }
6591 
6592  return first_inst;
6593 }
6594 
6595 
6596 boolean weed_init_effect(int hotkey) {
6597  // mainw->osc_block should be set to TRUE before calling this function !
6598  // filter_mutex MUST be locked, on FALSE return is unlocked
6599  weed_plant_t *filter, *gui;
6600  weed_plant_t *new_instance, *inst;
6601  weed_plant_t *event_list;
6602  weed_error_t error;
6603 
6604  boolean fg_modeswitch = FALSE, is_trans = FALSE, gen_start = FALSE, is_modeswitch = FALSE;
6605  boolean all_out_alpha;
6606  boolean is_gen = FALSE;
6607  boolean is_audio_gen = FALSE;
6608 
6609  int num_tr_applied;
6610  int rte_keys = mainw->rte_keys;
6611  int inc_count, outc_count;
6612  int ntracks;
6613  int idx;
6614  int playing_file = mainw->playing_file;
6615 
6616  mainw->error = FALSE;
6617 
6618  if (hotkey < 0) {
6619  is_modeswitch = TRUE;
6620  hotkey = -hotkey - 1;
6621  }
6622 
6623  if (hotkey == fg_generator_key) {
6624  fg_modeswitch = TRUE;
6625  }
6626 
6627  if (hotkey >= FX_KEYS_MAX) {
6628  mainw->error = TRUE;
6629  return FALSE;
6630  }
6631 
6632  if (!rte_key_valid(hotkey + 1, FALSE)) {
6633  mainw->error = TRUE;
6634  return FALSE;
6635  }
6636 
6637  idx = key_to_fx[hotkey][key_modes[hotkey]];
6638  filter = weed_filters[idx];
6639 
6640  inc_count = enabled_in_channels(filter, FALSE);
6641  outc_count = enabled_out_channels(filter, FALSE);
6642 
6643  if (all_ins_alpha(filter, TRUE)) inc_count = 0;
6644 
6645  if (inc_count == 0) is_gen = TRUE;
6646 
6647  // check first if it is an audio generator
6648 
6649  if ((is_gen || (has_audio_chans_in(filter, FALSE) && !has_video_chans_in(filter, TRUE)))
6650  && has_audio_chans_out(filter, FALSE) && !has_video_chans_out(filter, TRUE)) {
6652  // audio fx only with realtime players
6653  char *fxname = weed_filter_idx_get_name(idx, FALSE, FALSE);
6654  d_print(_("Effect %s cannot be used with this audio player.\n"), fxname);
6655  lives_free(fxname);
6656  mainw->error = TRUE;
6657  filter_mutex_unlock(hotkey);
6658  return FALSE;
6659  }
6660 
6661  if (is_gen) {
6662  if (mainw->agen_key != 0) {
6663  // we had an existing audio gen running - stop that one first
6664  int agen_key = mainw->agen_key - 1;
6665  boolean needs_unlock = FALSE;
6666  if (!filter_mutex_trylock(agen_key)) {
6667  needs_unlock = TRUE;
6668  }
6669 
6670  weed_deinit_effect(agen_key);
6671 
6672  pthread_mutex_lock(&mainw->event_list_mutex);
6673  if ((rte_key_is_enabled(1 + agen_key))) {
6674  // need to do this in case starting another audio gen caused us to come here
6675  mainw->rte ^= (GU641 << agen_key);
6676  pthread_mutex_unlock(&mainw->event_list_mutex);
6677  if (rte_window && !mainw->is_rendering && !mainw->multitrack) {
6678  rtew_set_keych(agen_key, FALSE);
6679  }
6680  if (mainw->ce_thumbs) ce_thumbs_set_keych(agen_key, FALSE);
6681  } else pthread_mutex_unlock(&mainw->event_list_mutex);
6682  if (needs_unlock) filter_mutex_unlock(agen_key);
6683  }
6684  is_audio_gen = TRUE;
6685  }
6686  }
6687 
6688  // if outputs are all alpha it is not a true (video/audio generating) generator
6689  all_out_alpha = all_outs_alpha(filter, TRUE);
6690 
6691  // TODO - block template channel changes
6692  // we must stop any old generators
6693 
6694  if (hotkey < FX_KEYS_MAX_VIRTUAL) {
6695  if (!all_out_alpha && is_gen && outc_count > 0 && hotkey != fg_generator_key && mainw->num_tr_applied > 0 &&
6697  mainw->files[mainw->blend_file] &&
6698  mainw->files[mainw->blend_file]->clip_type == CLIP_TYPE_GENERATOR && !is_audio_gen) {
6700  if (bg_gen_to_start == -1) {
6701  weed_generator_end((weed_plant_t *)mainw->files[mainw->blend_file]->ext_src);
6702  }
6703 
6704  bg_gen_to_start = bg_generator_key = bg_generator_mode = -1;
6705  mainw->blend_file = -1;
6706  }
6707 
6708  if (CURRENT_CLIP_IS_VALID && cfile->clip_type == CLIP_TYPE_GENERATOR &&
6709  (fg_modeswitch || (is_gen && outc_count > 0 && mainw->num_tr_applied == 0)) && !is_audio_gen && !all_out_alpha) {
6710  if (mainw->is_processing || mainw->preview) {
6711  mainw->error = TRUE;
6712  filter_mutex_unlock(hotkey);
6713  return FALSE; // stopping fg gen will cause clip to switch
6714  }
6715  if (LIVES_IS_PLAYING && mainw->whentostop == STOP_ON_VID_END && !is_gen) {
6716  // stop on vid end, and the playing generator stopped
6718  } else {
6721  weed_generator_end((weed_plant_t *)cfile->ext_src);
6722  fg_generator_key = fg_generator_clip = fg_generator_mode = -1;
6723  if (CURRENT_CLIP_IS_VALID && (cfile->achans == 0 || cfile->frames > 0)) {
6724  // in case we switched to bg clip, and bg clip was gen
6725  // otherwise we will get killed in generator_start
6726  mainw->current_file = -1;
6727  // *INDENT-OFF*
6728  }}}}
6729  // *INDENT-ON*
6730 
6731  if (hotkey < FX_KEYS_MAX_VIRTUAL) {
6732  if (inc_count == 2) {
6733  mainw->num_tr_applied++; // increase trans count
6736  }
6738  if (mainw->num_tr_applied == 1 && !is_modeswitch) {
6740  }
6741  } else if (is_gen && outc_count > 0 && !is_audio_gen && !all_out_alpha) {
6742  // aha - a generator
6743  if (!LIVES_IS_PLAYING) {
6744  // if we are not playing, we will postpone creating the instance
6745  // this is a workaround for a problem in libvisual
6746  fg_gen_to_start = hotkey;
6747  fg_generator_key = hotkey;
6748  fg_generator_mode = key_modes[hotkey];
6749  gen_start = TRUE;
6750  } else if (!fg_modeswitch && mainw->num_tr_applied == 0 && (mainw->is_processing || mainw->preview)) {
6751  mainw->error = TRUE;
6752  filter_mutex_unlock(hotkey);
6753  return FALSE;
6754  }
6755  }
6756  }
6757  // TODO - unblock template channel changes
6758 
6759  // if the param window is already open, use instance from there
6760  if (fx_dialog[1] && fx_dialog[1]->key == hotkey && fx_dialog[1]->mode == key_modes[hotkey]) {
6761  lives_rfx_t *rfx = fx_dialog[1]->rfx;
6762  new_instance = (weed_plant_t *)rfx->source;
6763  // add a ref since we will remove one below, the param window should already have a ref
6764  weed_instance_ref(new_instance);
6765  update_widget_vis(NULL, hotkey, key_modes[hotkey]); // redraw our paramwindow
6766  } else {
6767  new_instance = weed_instance_from_filter(filter); //adds a ref
6768  // if it is a key effect, set key defaults
6769  if (hotkey < FX_KEYS_MAX_VIRTUAL && key_defaults[hotkey][key_modes[hotkey]]) {
6770  // TODO - handle compound fx
6771  filter_mutex_unlock(hotkey);
6772  weed_reinit_effect(new_instance, FALSE);
6773  filter_mutex_lock(hotkey);
6774  apply_key_defaults(new_instance, hotkey, key_modes[hotkey]);
6775  filter_mutex_unlock(hotkey);
6776  weed_reinit_effect(new_instance, FALSE);
6777  filter_mutex_lock(hotkey);
6778  }
6779  }
6780 
6781  // record the key so we know whose parameters to record later
6782  weed_set_int_value(new_instance, WEED_LEAF_HOST_KEY, hotkey);
6783 
6784  inst = new_instance;
6785 
6786  gui = weed_instance_get_gui(inst, FALSE);
6787  if (gui && weed_get_int_value(gui, WEED_LEAF_EASE_OUT, NULL)) {
6788  weed_leaf_delete(gui, WEED_LEAF_EASE_OUT);
6789  }
6790  weed_leaf_delete(inst, WEED_LEAF_HOST_EASE_OUT_COUNT);
6791  weed_leaf_delete(inst, WEED_LEAF_AUTO_EASING);
6792 
6793  if (weed_plant_has_leaf(filter, WEED_LEAF_HOST_FPS))
6794  weed_leaf_copy(inst, WEED_LEAF_TARGET_FPS, filter, WEED_LEAF_HOST_FPS);
6795  else if (weed_plant_has_leaf(filter, WEED_LEAF_PREFERRED_FPS))
6796  weed_leaf_copy(inst, WEED_LEAF_TARGET_FPS, filter, WEED_LEAF_PREFERRED_FPS);
6797 
6798  while (weed_plant_has_leaf(inst, WEED_LEAF_HOST_NEXT_INSTANCE)) {
6799  // handle compound fx
6800  inst = weed_get_plantptr_value(inst, WEED_LEAF_HOST_NEXT_INSTANCE, &error);
6801  weed_set_int_value(inst, WEED_LEAF_HOST_KEY, hotkey);
6802  }
6803  inst = new_instance;
6804 
6805  if (!gen_start) {
6806  weed_plant_t *inst, *next_inst = NULL;
6807  inst = new_instance;
6808 
6809 start1:
6810 
6811  filter = weed_instance_get_filter(inst, FALSE);
6812 
6813  if (weed_plant_has_leaf(filter, WEED_LEAF_INIT_FUNC)) {
6814  weed_init_f init_func;
6815  char *cwd = cd_to_plugin_dir(filter), *tmp;
6816  init_func = (weed_init_f)weed_get_funcptr_value(filter, WEED_LEAF_INIT_FUNC, NULL);
6817  if (init_func && (error = (*init_func)(inst)) != WEED_SUCCESS) {
6818  char *filter_name;
6819  filter = weed_filters[idx];
6820  filter_name = weed_get_string_value(filter, WEED_LEAF_NAME, NULL);
6821  d_print(_("Failed to start instance %s, (%s)\n"), filter_name, (tmp = weed_error_to_text(error)));
6822  lives_free(tmp);
6823  lives_free(filter_name);
6824  key_to_instance[hotkey][key_modes[hotkey]] = NULL;
6825 
6826 deinit2:
6827 
6828  if (weed_plant_has_leaf(inst, WEED_LEAF_HOST_NEXT_INSTANCE))
6829  next_inst = weed_get_plantptr_value(inst, WEED_LEAF_HOST_NEXT_INSTANCE, &error);
6830  else next_inst = NULL;
6831 
6832  weed_call_deinit_func(inst);
6833 
6834  if (next_inst && weed_get_boolean_value(next_inst, WEED_LEAF_HOST_INITED, &error) == WEED_TRUE) {
6835  // handle compound fx
6836  inst = next_inst;
6837  goto deinit2;
6838  }
6839 
6840  inst = new_instance;
6841 
6842  if (hotkey < FX_KEYS_MAX_VIRTUAL) {
6843  if (is_trans) {
6844  // TODO: - do we need this ? is_trans is always FALSE !
6845  mainw->num_tr_applied--;
6846  if (mainw->num_tr_applied == 0) {
6850  // *INDENT-OFF*
6851  }}}}
6852  // *INDENT-ON*
6853 
6854  weed_instance_unref(inst);
6855  lives_chdir(cwd, FALSE);
6856  lives_free(cwd);
6857  if (is_audio_gen) mainw->agen_needs_reinit = FALSE;
6858  mainw->error = TRUE;
6859  filter_mutex_unlock(hotkey);
6860  return FALSE;
6861  }
6862  lives_chdir(cwd, FALSE);
6863  lives_free(cwd);
6864  }
6865 
6866  weed_set_boolean_value(inst, WEED_LEAF_HOST_INITED, WEED_TRUE);
6867  weed_set_boolean_value(inst, WEED_LEAF_HOST_UNUSED, WEED_TRUE);
6868 
6869  if ((inst = get_next_compound_inst(inst)) != NULL) goto start1;
6870 
6871  inst = new_instance;
6872  filter = weed_filters[idx];
6873  }
6874 
6875  if (is_gen && outc_count > 0 && !is_audio_gen && !all_out_alpha) {
6876  // generator start
6877  if (mainw->num_tr_applied > 0 && !fg_modeswitch && mainw->current_file > -1 && LIVES_IS_PLAYING) {
6878  // transition is on, make into bg clip
6879  bg_generator_key = hotkey;
6880  bg_generator_mode = key_modes[hotkey];
6881  } else {
6882  // no transition, make fg (or kb was grabbed for fg generator)
6883  fg_generator_key = hotkey;
6884  fg_generator_mode = key_modes[hotkey];
6885  }
6886 
6887  // start the generator and maybe start playing
6888  num_tr_applied = mainw->num_tr_applied;
6889  if (fg_modeswitch) mainw->num_tr_applied = 0; // force to fg
6890 
6891  key_to_instance[hotkey][key_modes[hotkey]] = inst;
6892  // enable param recording, in case the instance was obtained from a param window
6893  if (weed_plant_has_leaf(inst, WEED_LEAF_HOST_NORECORD)) weed_leaf_delete(inst, WEED_LEAF_HOST_NORECORD);
6894 
6895  error = weed_generator_start(inst, hotkey);
6896  if (error != 0) {
6897  int weed_error;
6898  char *filter_name;
6899  filter_mutex_lock(hotkey);
6900  weed_call_deinit_func(inst);
6901  weed_instance_unref(inst);
6902  weed_instance_unref(inst);
6903  if (error != 2) {
6904  filter_name = weed_get_string_value(filter, WEED_LEAF_NAME, &weed_error);
6905  d_print(_("Unable to start generator %s (error code: %d)\n"), filter_name, error);
6906  lives_free(filter_name);
6907  } else mainw->error = TRUE;
6908  if (mainw->num_tr_applied && mainw->current_file > -1) {
6909  bg_gen_to_start = bg_generator_key = bg_generator_mode = -1;
6910  } else {
6911  fg_generator_key = fg_generator_clip = fg_generator_mode = -1;
6912  }
6913  if (fg_modeswitch) mainw->num_tr_applied = num_tr_applied;
6914  key_to_instance[hotkey][key_modes[hotkey]] = NULL;
6915  filter_mutex_unlock(hotkey);
6916  if (!mainw->multitrack) {
6917  if (!LIVES_IS_PLAYING) {
6919  }
6920  }
6921  return FALSE;
6922  }
6923 
6924  if (playing_file == -1 && mainw->gen_started_play) {
6925  return TRUE;
6926  }
6927 
6928  // weed_generator_start can change the instance
6929  //inst = weed_instance_obtain(hotkey, key_modes[hotkey]);/////
6930 
6931  // TODO - problem if modeswitch triggers playback
6932  // hence we do not allow mixing of generators and non-gens on the same key
6933  if (fg_modeswitch) mainw->num_tr_applied = num_tr_applied;
6934  if (fg_generator_key != -1) {
6935  pthread_mutex_lock(&mainw->event_list_mutex);
6936  mainw->rte |= (GU641 << fg_generator_key);
6937  pthread_mutex_unlock(&mainw->event_list_mutex);
6939  }
6940  if (bg_generator_key != -1 && !fg_modeswitch) {
6941  pthread_mutex_lock(&mainw->event_list_mutex);
6942  mainw->rte |= (GU641 << bg_generator_key);
6943  pthread_mutex_unlock(&mainw->event_list_mutex);
6944  if (hotkey < prefs->rte_keys_virtual) {
6945  if (rte_window && !mainw->is_rendering && !mainw->multitrack) {
6946  rtew_set_keych(bg_generator_key, TRUE);
6947  }
6948  if (mainw->ce_thumbs) ce_thumbs_set_keych(bg_generator_key, TRUE);
6949  }
6950  }
6951  }
6952 
6953  if (rte_keys == hotkey) {
6954  mainw->rte_keys = rte_keys;
6956  }
6957 
6958  // need to do this *before* calling append_filter_map_event
6959  key_to_instance[hotkey][key_modes[hotkey]] = inst;
6960 
6961  // enable param recording, in case the instance was obtained from a param window
6962  if (weed_plant_has_leaf(inst, WEED_LEAF_HOST_NORECORD)) weed_leaf_delete(inst, WEED_LEAF_HOST_NORECORD);
6963 
6964  if (mainw->record && !mainw->record_paused && LIVES_IS_PLAYING && (prefs->rec_opts & REC_EFFECTS) && !is_gen) {
6965  ticks_t actual_ticks = mainw->startticks;
6966  uint64_t rteval, new_rte;
6967  pthread_mutex_lock(&mainw->event_list_mutex);
6968  event_list = append_filter_init_event(mainw->event_list, actual_ticks, idx, -1, hotkey, inst);
6969  if (!mainw->event_list) mainw->event_list = event_list;
6970  init_events[hotkey] = get_last_event(mainw->event_list);
6971  ntracks = weed_leaf_num_elements(init_events[hotkey], WEED_LEAF_IN_TRACKS);
6972  pchains[hotkey] = filter_init_add_pchanges(mainw->event_list, inst, init_events[hotkey], ntracks, 0);
6973  rteval = mainw->rte;
6974  new_rte = GU641 << (hotkey);
6975  if (!(rteval & new_rte)) rteval |= new_rte;
6976  create_filter_map(rteval); // we create filter_map event_t * array with ordered effects
6977  mainw->event_list = append_filter_map_event(mainw->event_list, actual_ticks, filter_map);
6978  pthread_mutex_unlock(&mainw->event_list_mutex);
6979  }
6980 
6981  weed_instance_unref(inst); // release the ref we added earlier
6982 
6983  if (is_audio_gen) {
6984  mainw->agen_key = hotkey + 1;
6986 
6987  if (mainw->playing_file > 0) {
6990 #ifdef ENABLE_JACK
6991  if (mainw->jackd_read && mainw->jackd_read->in_use &&
6992  (mainw->jackd_read->playing_file == -1 || mainw->jackd_read->playing_file == mainw->ascrap_file)) {
6993  // if playing external audio, switch over to internal for an audio gen
6994  jack_time_reset(mainw->jackd, mainw->currticks);
6995  // close the reader
6996  jack_rec_audio_end(!prefs->perm_audio_reader, FALSE);
6997  }
6998  if (mainw->jackd && (!mainw->jackd_read || !mainw->jackd_read->in_use)) {
6999  // enable writer
7000  mainw->jackd->in_use = TRUE;
7001  }
7002 #endif
7003  }
7005 #ifdef HAVE_PULSE_AUDIO
7006  if (mainw->pulsed_read && mainw->pulsed_read->in_use &&
7007  (mainw->pulsed_read->playing_file == -1 || mainw->pulsed_read->playing_file == mainw->ascrap_file)) {
7008  // if playing external audio, switch over to internal for an audio gen
7009  ticks_t audio_ticks = lives_pulse_get_time(mainw->pulsed_read);
7010  if (audio_ticks == -1) {
7012  return mainw->cancelled;
7013  }
7014  pa_time_reset(mainw->pulsed, -audio_ticks);
7015  pulse_rec_audio_end(!prefs->perm_audio_reader, FALSE);
7016  pulse_driver_uncork(mainw->pulsed);
7017  }
7018  if (mainw->pulsed && (!mainw->pulsed_read || !mainw->pulsed_read->in_use)) {
7019  mainw->pulsed->in_use = TRUE;
7020  }
7021 #endif
7022  }
7023 
7025  (prefs->rec_opts & REC_AUDIO)) {
7026  // if recording audio, open ascrap file and add audio event
7027  mainw->record = FALSE;
7028  on_record_perf_activate(NULL, NULL);
7030  mainw->record = TRUE;
7032 #ifdef ENABLE_JACK
7033  jack_time_reset(mainw->jackd, lives_jack_get_time(mainw->jackd_read));
7034  mainw->jackd->in_use = TRUE;
7035 #endif
7036  // *INDENT-OFF*
7037  }}}}
7038  // *INDENT-ON*
7039 
7040  return TRUE;
7041 }
7042 
7043 
7044 weed_error_t weed_call_init_func(weed_plant_t *inst) {
7045  weed_plant_t *filter;
7046  weed_error_t error = WEED_SUCCESS;
7047 
7048  weed_instance_ref(inst);
7049 
7050  filter = weed_instance_get_filter(inst, FALSE);
7051  if (weed_plant_has_leaf(filter, WEED_LEAF_INIT_FUNC)) {
7052  weed_init_f init_func = (weed_init_f)weed_get_funcptr_value(filter, WEED_LEAF_INIT_FUNC, NULL);
7053  if (init_func) {
7054  char *cwd = cd_to_plugin_dir(filter);
7055  error = (*init_func)(inst);
7056  lives_chdir(cwd, FALSE);
7057  lives_free(cwd);
7058  }
7059  }
7060  weed_set_boolean_value(inst, WEED_LEAF_HOST_INITED, WEED_TRUE);
7061  weed_set_boolean_value(inst, WEED_LEAF_HOST_UNUSED, WEED_TRUE);
7062  weed_instance_unref(inst);
7063  return error;
7064 }
7065 
7066 
7067 weed_error_t weed_call_deinit_func(weed_plant_t *instance) {
7068  // filter_mutex MUST be locked
7069  weed_plant_t *filter;
7070  weed_error_t error = WEED_SUCCESS;
7071 
7072  weed_instance_ref(instance);
7073 
7074  filter = weed_instance_get_filter(instance, FALSE);
7075  if (weed_get_boolean_value(instance, WEED_LEAF_HOST_INITED, NULL) == WEED_FALSE) {
7076  weed_instance_unref(instance);
7077  return 1;
7078  }
7079  if (weed_plant_has_leaf(filter, WEED_LEAF_DEINIT_FUNC)) {
7080  weed_deinit_f deinit_func = (weed_deinit_f)weed_get_funcptr_value(filter, WEED_LEAF_DEINIT_FUNC, NULL);
7081  if (deinit_func) {
7082  char *cwd = cd_to_plugin_dir(filter);
7083  error = (*deinit_func)(instance);
7084  lives_chdir(cwd, FALSE);
7085  lives_free(cwd);
7086  }
7087  }
7088  weed_set_boolean_value(instance, WEED_LEAF_HOST_INITED, WEED_FALSE);
7089  weed_instance_unref(instance);
7090  return error;
7091 }
7092 
7093 
7094 boolean weed_deinit_effect(int hotkey) {
7095  // hotkey is 0 based
7096  // mainw->osc_block should be set before calling this function !
7097  // caller should also handle mainw->rte
7098 
7099  // filter_mutex_lock(hotkey) must be be called before entering
7100 
7101  weed_plant_t *instance, *inst, *last_inst, *next_inst, *filter, *gui;
7102 
7103  boolean is_modeswitch = FALSE;
7104  boolean was_transition = FALSE;
7105  boolean is_audio_gen = FALSE;
7106  boolean is_video_gen = FALSE;
7107  int num_in_chans, num_out_chans;
7108 
7109  int error;
7110  int easing;
7111 
7112  int needs_unlock = -1;
7113 
7114  if (hotkey < 0) {
7115  is_modeswitch = TRUE;
7116  hotkey = -hotkey - 1;
7117  }
7118 
7119  if (hotkey >= FX_KEYS_MAX) return FALSE;
7120 
7121  // adds a ref
7122  if (!(instance = weed_instance_obtain(hotkey, key_modes[hotkey]))) return TRUE;
7123 
7124  if (LIVES_IS_PLAYING && hotkey < FX_KEYS_MAX_VIRTUAL) {
7125  if (prefs->allow_easing) {
7126  // if it's a user key and the plugin supports easing out, we'll do that instead
7127  weed_plant_t *gui = weed_instance_get_gui(instance, FALSE);
7128  if (!weed_plant_has_leaf(gui, WEED_LEAF_EASE_OUT)) {
7129  uint64_t new_rte = GU641 << (hotkey);
7130  if (mainw->rte & new_rte) {
7131  if ((easing = weed_get_int_value(gui, WEED_LEAF_EASE_OUT_FRAMES, NULL))) {
7132  int myease = cfile->pb_fps * 2.;
7133  if (easing < myease) {
7134  weed_set_int_value(gui, WEED_LEAF_EASE_OUT, myease);
7135  weed_set_int_value(instance, WEED_LEAF_HOST_EASE_OUT_COUNT, myease);
7136  weed_instance_unref(instance);
7137  return FALSE;
7138  // *INDENT-OFF*
7139  }}}}}}
7140  // *INDENT-ON*
7141  mainw->blend_palette = WEED_PALETTE_END;
7142 
7143  // disable param recording, in case the instance is still attached to a param window
7144  weed_set_boolean_value(instance, WEED_LEAF_HOST_NORECORD, WEED_TRUE);
7145 
7146  num_in_chans = enabled_in_channels(instance, FALSE);
7147 
7148  gui = weed_instance_get_gui(instance, FALSE);
7149  if (gui && weed_get_int_value(gui, WEED_LEAF_EASE_OUT, NULL)) {
7150  weed_leaf_delete(gui, WEED_LEAF_EASE_OUT);
7151  }
7152  weed_leaf_delete(instance, WEED_LEAF_HOST_EASE_OUT_COUNT);
7153  weed_leaf_delete(instance, WEED_LEAF_AUTO_EASING);
7154 
7155  // handle compound fx
7156  last_inst = instance;
7157  while (weed_plant_has_leaf(last_inst, WEED_LEAF_HOST_NEXT_INSTANCE)) last_inst = weed_get_plantptr_value(last_inst,
7159  num_out_chans = enabled_out_channels(last_inst, FALSE);
7160 
7161  if (hotkey + 1 == mainw->agen_key) is_audio_gen = TRUE;
7162  else if (num_in_chans == 0) is_video_gen = TRUE;
7163 
7164  filter = weed_instance_get_filter(instance, TRUE);
7165  if ((is_video_gen || all_ins_alpha(filter, TRUE)) && num_out_chans > 0 && !all_outs_alpha(filter, TRUE)) {
7166  weed_instance_unref(instance); // remove ref from weed instance obtain
7168  if (LIVES_IS_PLAYING && mainw->whentostop == STOP_ON_VID_END && (hotkey != bg_generator_key)) {
7169  mainw->cancelled = CANCEL_GENERATOR_END; // will be unreffed on pb end
7170  } else {
7171  weed_generator_end(instance); // removes 1 ref
7172  }
7173  return TRUE;
7174  }
7175 
7176  if (is_audio_gen) {
7177  // is audio generator
7178  // wait for current processing to finish
7179  mainw->agen_key = 0;
7180  mainw->agen_samps_count = 0;
7181 
7182  // for external audio, switch back to reading
7183 
7184  if (mainw->playing_file > 0 && prefs->audio_src == AUDIO_SRC_EXT) {
7185 #ifdef ENABLE_JACK
7187  if (!mainw->jackd_read || !mainw->jackd_read->in_use) {
7188  mainw->jackd->in_use = FALSE; // deactivate writer
7189  jack_rec_audio_to_clip(-1, 0, RECA_MONITOR); //activate reader
7190  jack_time_reset(mainw->jackd_read, lives_jack_get_time(mainw->jackd)); // ensure time continues monotonically
7191  if (mainw->record) mainw->jackd_read->playing_file = mainw->ascrap_file; // if recording, continue to write to ascrap file
7192  mainw->jackd_read->is_paused = FALSE;
7193  mainw->jackd_read->in_use = TRUE;
7194  if (mainw->jackd) {
7195  mainw->jackd->playing_file = -1;
7196  }
7197  }
7198  }
7199 #endif
7200 #ifdef HAVE_PULSE_AUDIO
7202  if (!mainw->pulsed_read || !mainw->pulsed_read->in_use) {
7203  if (mainw->pulsed) mainw->pulsed->in_use = FALSE; // deactivate writer
7204  pulse_rec_audio_to_clip(-1, 0, RECA_MONITOR); //activate reader
7205  if (mainw->pulsed) {
7206  ticks_t audio_ticks = lives_pulse_get_time(mainw->pulsed_read);
7207  if (audio_ticks == -1) {
7209  weed_instance_unref(instance); // remove ref from weed instance obtain
7210  return TRUE;
7211  }
7212  pa_time_reset(mainw->pulsed_read, -audio_ticks); // ensure time continues monotonically
7213  pulse_driver_uncork(mainw->pulsed_read);
7214  if (mainw->pulsed) {
7215  pulse_driver_cork(mainw->pulsed);
7216  mainw->pulsed->playing_file = -1;
7217  }
7218  }
7219  if (mainw->record) mainw->pulsed_read->playing_file = mainw->ascrap_file; // if recording, continue to write to ascrap file
7220  mainw->pulsed_read->is_paused = FALSE;
7221  mainw->pulsed_read->in_use = TRUE;
7222  }
7223  }
7224 #endif
7225  } else if (mainw->playing_file > 0) {
7226  // for internal, continue where we should
7229  else {
7230  if (mainw->pre_src_audio_file == -1) {
7231  // audio doesn't follow clip switches and we were playing this...
7233  } else {
7234 #ifdef HAVE_PULSE_AUDIO
7236  if (mainw->pulsed) mainw->pulsed->playing_file = mainw->pre_src_audio_file;
7237  if (mainw->record && !mainw->record_paused && (prefs->rec_opts & REC_AUDIO)) {
7238  pulse_get_rec_avals(mainw->pulsed);
7239  }
7240  }
7241 #endif
7242 #ifdef ENABLE_JACK
7244  if (mainw->jackd) mainw->jackd->playing_file = mainw->pre_src_audio_file;
7245  if (mainw->record && !mainw->record_paused && (prefs->rec_opts & REC_AUDIO)) {
7246  jack_get_rec_avals(mainw->jackd);
7247  }
7248  }
7249 #endif
7250  // *INDENT-OFF*
7251  }}}}}
7252  // *INDENT-ON*
7253 
7254  if (!filter_mutex_trylock(hotkey)) {
7255  // should fail, but just in case
7256  needs_unlock = hotkey;
7257  }
7258  key_to_instance[hotkey][key_modes[hotkey]] = NULL;
7259  if (needs_unlock != -1) {
7260  filter_mutex_unlock(needs_unlock);
7261  needs_unlock = -1;
7262  }
7263 
7264  if (hotkey < FX_KEYS_MAX_VIRTUAL) {
7265  if (mainw->whentostop == STOP_ON_VID_END && mainw->current_file > -1 &&
7266  (cfile->frames == 0 || (mainw->loop && cfile->achans > 0 && !mainw->is_rendering && (mainw->audio_end / cfile->fps)
7267  < MAX(cfile->laudio_time, cfile->raudio_time)))) mainw->whentostop = STOP_ON_AUD_END;
7268 
7269  if (num_in_chans == 2) {
7270  was_transition = TRUE;
7271  mainw->num_tr_applied--;
7272  if (mainw->num_tr_applied == 0) {
7276  // *INDENT-OFF*
7277  }}}}
7278  // *INDENT-ON*
7279  inst = instance;
7280 
7281 deinit3:
7282 
7283  if (weed_plant_has_leaf(inst, WEED_LEAF_HOST_NEXT_INSTANCE))
7284  next_inst = weed_get_plantptr_value(inst, WEED_LEAF_HOST_NEXT_INSTANCE,
7285  &error);
7286  else next_inst = NULL;
7287 
7288  weed_call_deinit_func(inst);
7289  weed_instance_unref(inst); // remove ref from weed_instance_obtain
7290  weed_instance_unref(inst); // free if no other refs
7291 
7292  if (next_inst) {
7293  // handle compound fx
7294  inst = next_inst;
7295  weed_instance_ref(inst); // proxy for weed_instance_obtain
7296  goto deinit3;
7297  }
7298 
7299  // if the param window is already open, show any reinits now
7300  if (fx_dialog[1] && fx_dialog[1]->key == hotkey && fx_dialog[1]->mode == key_modes[hotkey]) {
7301  update_widget_vis(NULL, hotkey, key_modes[hotkey]); // redraw our paramwindow
7302  }
7303 
7304  if (was_transition && !is_modeswitch) {
7305  if (mainw->num_tr_applied < 1) {
7306  if (CURRENT_CLIP_IS_VALID && mainw->effort > 0) {
7307  reset_effort();
7308  }
7309  if (bg_gen_to_start != -1) bg_gen_to_start = -1;
7312  // all transitions off, so end the bg generator
7313  // lock the filter mutex if it's not locked
7314  if (!filter_mutex_trylock(bg_generator_key)) {
7315  needs_unlock = bg_generator_key; // will get reset to -1
7316  }
7317  weed_deinit_effect(bg_generator_key);
7318  if (needs_unlock != -1) {
7319  filter_mutex_unlock(needs_unlock);
7320  needs_unlock = -1;
7321  }
7322  }
7323  mainw->blend_file = -1;
7324  }
7325  }
7326  if (mainw->record && !mainw->record_paused && LIVES_IS_PLAYING && init_events[hotkey] &&
7327  (prefs->rec_opts & REC_EFFECTS) && num_in_chans > 0) {
7328  uint64_t rteval, new_rte;
7329  //ticks_t actual_ticks = mainw->clock_ticks;//lives_get_current_playback_ticks(mainw->origsecs, mainw->orignsecs, NULL);
7330  ticks_t actual_ticks = mainw->startticks;
7331  pthread_mutex_lock(&mainw->event_list_mutex);
7332  mainw->event_list = append_filter_deinit_event(mainw->event_list, actual_ticks, init_events[hotkey], pchains[hotkey]);
7333  init_events[hotkey] = NULL;
7334  if (pchains[hotkey]) lives_free(pchains[hotkey]);
7335  pchains[hotkey] = NULL;
7336  rteval = mainw->rte;
7337  new_rte = GU641 << (hotkey);
7338  if (rteval & new_rte) {
7339  rteval ^= new_rte;
7340  if (rte_window) rtew_set_keych(hotkey, FALSE);
7341  if (mainw->ce_thumbs) ce_thumbs_set_keych(hotkey, FALSE);
7342  }
7343  create_filter_map(rteval); // we create filter_map event_t * array with ordered effects
7344  mainw->event_list = append_filter_map_event(mainw->event_list, actual_ticks, filter_map);
7345  pthread_mutex_unlock(&mainw->event_list_mutex);
7346  }
7347  return TRUE;
7348 }
7349 
7350 
7359  register int i;
7360 
7361  for (i = FX_KEYS_MAX_VIRTUAL; i < FX_KEYS_MAX; i++) {
7362  if (key_to_instance[i][0]) {
7363  // no mutex needed since we are rendering
7364  weed_deinit_effect(i);
7365  if (mainw->multitrack && mainw->multitrack->is_rendering && pchains[i]) {
7366  lives_free(pchains[i]);
7367  pchains[i] = NULL;
7368  // *INDENT-OFF*
7369  }}}
7370  // *INDENT-ON*
7371 }
7372 
7373 
7382  weed_plant_t *instance;
7383  register int i;
7384 
7385  for (i = 0; i < FX_KEYS_MAX_VIRTUAL; i++) {
7386  if ((instance = key_to_instance[i][key_modes[i]]) != NULL) {
7387  weed_plant_t *gui = weed_instance_get_gui(instance, FALSE);
7388  if (weed_plant_has_leaf(gui, WEED_LEAF_EASE_OUT)) {
7389  // no mutex needed since we are rendering. and since we arent playing it will get deinited now
7390  weed_deinit_effect(i);
7393  // *INDENT-OFF*
7394  }}}
7395  // *INDENT-ON*
7396 }
7397 
7398 
7404 void weed_deinit_all(boolean shutdown) {
7405  int i;
7406  weed_plant_t *instance;
7407 
7408  mainw->osc_block = TRUE;
7409  if (rte_window) {
7410  rtew_set_keygr(-1);
7411  }
7412 
7413  mainw->rte_keys = -1;
7415  if (!LIVES_IS_PLAYING) bg_gen_to_start = bg_generator_key = bg_generator_mode = -1;
7416 
7417  for (i = 0; i < FX_KEYS_MAX_VIRTUAL; i++) {
7418  if (!shutdown) {
7419  // maintain braces because of #DEBUG_FILTER_MUTEXES
7420  if (LIVES_IS_PLAYING && !shutdown && i >= FX_KEYS_PHYSICAL) {
7421  // meta-physical keys only shutdown through the interface or via easter-egg keys...
7422  mainw->osc_block = FALSE;
7423  return;
7424  }
7425  filter_mutex_lock(i);
7426  } else {
7427  // on shutdown, another thread might be deadlocked on this
7428  // so we will unlock it after
7430  }
7431  if ((rte_key_is_enabled(1 + i))) {
7432  if ((instance = weed_instance_obtain(i, key_modes[i])) != NULL) {
7433  if (shutdown || !LIVES_IS_PLAYING || mainw->current_file == -1 || cfile->ext_src != instance) {
7434  if (rte_window) rtew_set_keych(i, FALSE);
7436  weed_deinit_effect(i);
7437  pthread_mutex_lock(&mainw->event_list_mutex);
7438  mainw->rte ^= (GU641 << i);
7439  pthread_mutex_unlock(&mainw->event_list_mutex);
7440  } else weed_instance_unref(instance);
7441  }
7442  }
7444  }
7445 
7446  mainw->osc_block = FALSE;
7447 }
7448 
7449 
7458 static int register_audio_channels(int nchannels) {
7460  mainw->afbuffer_clients = 0;
7461  return -1;
7462  }
7463  if (nchannels <= 0) return mainw->afbuffer_clients;
7464  pthread_mutex_lock(&mainw->abuf_frame_mutex);
7465  if (mainw->afbuffer_clients == 0) {
7468  }
7469  mainw->afbuffer_clients += nchannels;
7470  pthread_mutex_unlock(&mainw->abuf_frame_mutex);
7471  return mainw->afbuffer_clients;
7472 }
7473 
7474 
7475 static int unregister_audio_channels(int nchannels) {
7476  if (!mainw->audio_frame_buffer) {
7477  mainw->afbuffer_clients = 0;
7478  return -1;
7479  }
7480 
7481  mainw->afbuffer_clients -= nchannels;
7482  if (mainw->afbuffer_clients <= 0) {
7483  int i;
7484  // lock out the audio thread
7485  pthread_mutex_lock(&mainw->abuf_frame_mutex);
7486  for (i = 0; i < 2; i++) {
7487  if (mainw->afb[i]) {
7489  lives_free(mainw->afb[i]);
7490  mainw->afb[i] = NULL;
7491  }
7492  }
7493  mainw->audio_frame_buffer = NULL;
7494  pthread_mutex_unlock(&mainw->abuf_frame_mutex);
7495  }
7496  return mainw->afbuffer_clients;
7497 }
7498 
7499 
7500 static boolean fill_audio_channel(weed_plant_t *filter, weed_plant_t *achan) {
7501  // this is for filter instances with mixed audio / video inputs/outputs
7502  // uneffected audio is buffered by the audio thread; here we copy / convert it to a video effect's audio channel
7503  // purely audio filters run in the audio thread
7504 
7505  static lives_audio_buf_t *audbuf;
7506 
7507  if (achan) {
7508  weed_set_int_value(achan, WEED_LEAF_AUDIO_DATA_LENGTH, 0);
7509  weed_set_voidptr_value(achan, WEED_LEAF_AUDIO_DATA, NULL);
7510  }
7511 
7513  // no audio has been buffered
7514  return FALSE;
7515  }
7516 
7517  // lock the buffers
7518 
7519  if (mainw->afbuffer_clients_read == 0) {
7521  // cast away the (volatile)
7522  pthread_mutex_lock(&mainw->abuf_frame_mutex);
7524  if (audbuf == mainw->afb[0]) mainw->audio_frame_buffer = mainw->afb[1];
7525  else mainw->audio_frame_buffer = mainw->afb[0];
7526  pthread_mutex_unlock(&mainw->abuf_frame_mutex);
7527  }
7528 
7529  // push read buffer to channel
7530  if (achan && audbuf) {
7531  // convert audio to format requested, and copy it to the audio channel data
7532  push_audio_to_channel(filter, achan, audbuf);
7533  }
7534 
7536  // all clients have read the data, now we can free it
7537  free_audio_frame_buffer(audbuf);
7539  }
7540 
7541  return TRUE;
7542 }
7543 
7544 
7545 int check_filter_chain_palettes(boolean is_bg, int *palette_list, int npals) {
7546  register int i;
7547  int palette = WEED_PALETTE_END;
7548 
7549  if (mainw->rte) {
7550  for (i = 0; i < FX_KEYS_MAX_VIRTUAL; i++) {
7551  if (palette != WEED_PALETTE_END) break;
7552  if (rte_key_is_enabled(1 + i)) {
7553  weed_plant_t *instance;
7554  if (i == fg_generator_key) continue;
7555  if ((instance = weed_instance_obtain(i, key_modes[i])) != NULL) {
7556  if (is_bg && enabled_in_channels(instance, FALSE) < 2) continue;
7557  weed_plant_t *filter = weed_instance_get_filter(instance, TRUE);
7558  weed_plant_t *channel = get_enabled_channel(instance, (is_bg ? 1 : 0), TRUE);
7559  if (channel) {
7560  int nvals;
7561  weed_plant_t *chantmpl = weed_channel_get_template(channel);
7562  int *plist = weed_chantmpl_get_palette_list(filter, chantmpl, &nvals);
7563  for (int j = 0; j < nvals; j++) {
7564  if (plist[j] == WEED_PALETTE_END) break;
7565  else for (int k = 0; k < npals; k++) {
7566  if (palette_list[k] == WEED_PALETTE_END) break;
7567  if (palette_list[k] == plist[j]) {
7568  palette = plist[j];
7569  break;
7570  // *INDENT-OFF*
7571  }}
7572  if (palette != WEED_PALETTE_END) break;
7573  }
7574  lives_free(plist);
7575  }
7576  weed_instance_unref(instance);
7577  }}}
7578  // *INDENT-ON*
7579 
7580  if (palette == WEED_PALETTE_END) {
7582  for (i = 0; i < npals; i++) {
7583  if (palette_list[i] == mainw->vpp->palette) {
7584  palette = palette_list[i];
7585  break;
7586  // *INDENT-OFF*
7587  }}}}}
7588  // *INDENT-ON*
7589 
7590  if (palette == WEED_PALETTE_END) {
7591  for (i = 0; i < npals; i++) {
7592  if (weed_palette_is_pixbuf_palette(palette_list[i])) break;
7593  }
7594  }
7595  if (palette == WEED_PALETTE_END) {
7596  for (i = 0; i < npals; i++) {
7597  if (weed_palette_is_rgb(palette_list[i])) break;
7598  }
7599  }
7600  if (palette == WEED_PALETTE_END) palette = palette_list[0];
7601  return palette;
7602 }
7603 
7605 // special handling for generators (sources)
7606 
7607 weed_plant_t *weed_layer_create_from_generator(weed_plant_t *inst, weed_timecode_t tc, int clipno) {
7608  weed_plant_t *channel, **out_channels;
7609  weed_plant_t *filter;
7610  weed_plant_t *chantmpl;
7611  weed_plant_t *achan;
7612  weed_process_f process_func;
7613  int *palette_list;
7614  int *rowstrides;
7615  lives_filter_error_t retval;
7616  weed_error_t ret;
7617  int npals;
7618  int num_channels;
7619  int npl, npl2;
7620  int palette, opalette;
7621  int filter_flags = 0, channel_flags;
7622  int num_in_alpha = 0;
7623  int width, height, xwidth, xheight;
7624  int reinits = 0;
7625 
7626  int i;
7627 
7628  boolean did_thread = FALSE;
7629  boolean needs_reinit = FALSE;
7630  boolean can_change = FALSE;
7631  boolean is_bg = TRUE;
7632  char *cwd;
7633 
7634  if (!inst) return NULL;
7635 
7636  weed_instance_ref(inst);
7637 
7638  out_channels = weed_get_plantptr_array_counted(inst, WEED_LEAF_OUT_CHANNELS, &num_channels);
7639  if (num_channels == 0) {
7640  weed_instance_unref(inst);
7641  return NULL;
7642  }
7643 
7644  if ((channel = get_enabled_channel(inst, 0, FALSE)) == NULL) {
7645  lives_free(out_channels);
7646  weed_instance_unref(inst);
7647  return NULL;
7648  }
7649 
7650  filter = weed_instance_get_filter(inst, FALSE);
7651  filter_flags = weed_filter_get_flags(filter);
7652  chantmpl = weed_channel_get_template(channel);
7653  palette_list = weed_chantmpl_get_palette_list(filter, chantmpl, &npals);
7654  palette = WEED_PALETTE_END;
7655 
7656  if (clipno == mainw->current_file) is_bg = FALSE;
7657 
7658  /*
7659  - just as with normal filters,
7660  - if the channel template flags have WEED_FILTER_REINIT_ON_PALETTE_CHANGE, then we want to minimise palette changes,
7661  in this case because reinit may disrupt the output flow from the generator, causing unnecessary visual changes.
7662  thus unless forced to, we will leave the palette as is. However as with filters,
7663  There are two points where we can voluntariily alter the palette:
7664  when the instance has just been inited (since it would be reset anyway)
7665  and if we are going to reinit anyway due to some other factor (e.g size change).
7666 
7667  when setting the palette we will consider the following:
7668  - if there are no filters active then look at the player palette. If the player can change palettes then find the best pair.
7669  else
7670  - if the gen. is fg, check the filters to be applied, If 1st filter has reinit on pal. change then try to match its palette
7671  - otherwise check the longest running palette, ie. intersection of gen. palette(s), filter_n palettes, filter_n+1 pal. list untiil
7672  either the intersection of our remaing palettes with filter palettes is the empty set. or we pass all palettes,
7673  then take intersection with player. Any filters with reinit on pal. change, we first try the current palette, if that doesnt work then
7674  we check its full palette list as we will be forced to reinit it.
7675  - if it is bg we will use mainw->blend_palette
7676  TODO: we should finde the transition where the gen. joins, and work backwards and forwards from there
7677 
7678 
7679  IF the template has WEED_FILTER_REINIT_ON_ROWSTRIDES_CHANGE or WEED_FILTER_REINIT_ON_SIZE_CHANGE
7680  then similar rules apply for those values
7681  */
7682 
7684  // unless it says reinit on palette change. Then as with normal filters we only change after an init / reinit
7685 
7686 matchvals:
7687 
7688  if (needs_reinit || weed_get_boolean_value(inst, WEED_LEAF_HOST_UNUSED, NULL) == WEED_TRUE)
7689  can_change = TRUE;
7690 
7691  needs_reinit = FALSE;
7692 
7693  channel = get_enabled_channel(inst, 0, FALSE);
7694  chantmpl = weed_channel_get_template(channel);
7695  channel_flags = weed_chantmpl_get_flags(chantmpl);
7696 
7697  opalette = weed_channel_get_palette(channel);
7698  if (can_change || !((channel_flags & WEED_CHANNEL_REINIT_ON_PALETTE_CHANGE))) {
7699  palette = check_filter_chain_palettes(is_bg, palette_list, npals);
7700  if (palette != WEED_PALETTE_END) {
7701  if (palette != opalette && !((channel_flags & WEED_CHANNEL_REINIT_ON_ROWSTRIDES_CHANGE) && pixel_size(palette)
7702  != pixel_size(opalette))) {
7704  }
7705  }
7706  }
7707 
7708  if (weed_plant_has_leaf(inst, WEED_LEAF_IN_CHANNELS)) {
7709  int num_inc;
7710  weed_plant_t **in_channels = weed_get_plantptr_array_counted(inst, WEED_LEAF_IN_CHANNELS, &num_inc);
7711  for (i = 0; i < num_inc; i++) {
7712  if (weed_palette_is_alpha(weed_channel_get_palette(in_channels[i])) &&
7713  weed_get_boolean_value(in_channels[i], WEED_LEAF_DISABLED, NULL) == WEED_FALSE) {
7714  num_in_alpha++;
7715  }
7716  lives_freep((void **)&in_channels);
7717  }
7718  }
7719 
7720  if (num_in_alpha > 0) {
7721  // if we have mandatory alpha ins, make sure they are filled
7722  retval = check_cconx(inst, num_in_alpha, &needs_reinit);
7723  if (retval != FILTER_SUCCESS) {
7724  lives_free(out_channels);
7725  weed_instance_unref(inst);
7726  return channel;
7727  }
7728  }
7729 
7730  xwidth = width = weed_channel_get_width(channel);
7731  //cpalette = weed_channel_get_palette(channel);
7732  //xwidth = width /= weed_palette_get_pixels_per_macropixel(cpalette); // convert width to channel macropixels (????)
7733  xheight = height = weed_channel_get_height(channel);
7734 
7735  if (can_change || (!(channel_flags & WEED_CHANNEL_REINIT_ON_ROWSTRIDES_CHANGE) && !(channel_flags
7736  & WEED_CHANNEL_REINIT_ON_SIZE_CHANGE))) {
7737  // if it's in the bg, and letterboxing, set size to the fg clip
7738  // or if it's fg or bg and we are playing high quality
7739  if (mainw->num_tr_applied > 0 && !num_in_alpha) {
7741  && mainw->files[mainw->blend_file]->ext_src == inst) {
7742  boolean is_lbox = FALSE;
7743  int lb_width = mainw->files[mainw->playing_file]->hsize;
7744  int lb_height = mainw->files[mainw->playing_file]->vsize;
7745  if ((mainw->multitrack && !mainw->multitrack->is_rendering && prefs->letterbox_mt)
7747  boolean can_resize = FALSE;
7748  int opwidth, opheight;
7749  get_player_size(&opwidth, &opheight);
7750  if (mainw->ext_playback && (mainw->vpp->capabilities & VPP_CAN_RESIZE) != 0) can_resize = TRUE;
7751  get_letterbox_sizes(&opwidth, &opheight, &lb_width, &lb_height, can_resize);
7752  is_lbox = TRUE;
7753  }
7754  if (is_lbox || (prefs->pb_quality == PB_QUALITY_HIGH && (lb_width > width || lb_height > height))) {
7755  xwidth = lb_width;
7756  xheight = lb_height;
7757  }
7758  }
7759  } else {
7762  || mainw->files[mainw->blend_file]->vsize > height)) {
7763  xwidth = mainw->files[mainw->blend_file]->hsize;
7764  xheight = mainw->files[mainw->blend_file]->vsize;
7765  }
7766  }
7767  }
7768 
7769  if (xwidth * xheight == 0) {
7770  if (weed_plant_has_leaf(chantmpl, WEED_LEAF_HOST_WIDTH)) {
7771  xwidth = weed_get_int_value(chantmpl, WEED_LEAF_HOST_WIDTH, NULL);
7772  } else xwidth = DEF_GEN_WIDTH;
7773  if (weed_plant_has_leaf(chantmpl, WEED_LEAF_HOST_HEIGHT)) {
7774  xheight = weed_get_int_value(chantmpl, WEED_LEAF_HOST_HEIGHT, NULL);
7775  } else xheight = DEF_GEN_HEIGHT;
7776  }
7777 
7778  rowstrides = weed_channel_get_rowstrides(channel, &npl);
7779 
7780  if (weed_plant_has_leaf(filter, WEED_LEAF_ALIGNMENT_HINT)) {
7781  int rowstride_alignment_hint = weed_get_int_value(filter, WEED_LEAF_ALIGNMENT_HINT, NULL);
7782  if (rowstride_alignment_hint > ALIGN_DEF) {
7783  THREADVAR(rowstride_alignment_hint) = rowstride_alignment_hint;
7784  }
7785  }
7786 
7788  for (i = 0; (channel = get_enabled_channel(inst, i, FALSE)); i++) {
7789  if (xwidth != weed_channel_get_width(channel) ||
7790  xheight != weed_channel_get_height(channel)) {
7791  int nplanes;
7792  void **pd = weed_channel_get_pixel_data_planar(channel, &nplanes);
7793  for (int j = 0; j < nplanes; j++) lives_free(pd[j]);
7794  lives_free(pd);
7795  weed_set_voidptr_value(channel, WEED_LEAF_PIXEL_DATA, NULL);
7796  set_channel_size(filter, channel, xwidth, xheight);
7797  }
7798  }
7799 
7800  channel = get_enabled_channel(inst, 0, FALSE);
7801 
7802  if (!create_empty_pixel_data(channel, FALSE, TRUE)) return NULL;
7803 
7805  xwidth = width;
7806  xheight = height;
7807 
7808  width = weed_channel_get_width(channel);
7809  //cpalette = weed_channel_get_palette(channel);
7810  //width /= weed_palette_get_pixels_per_macropixel(cpalette); // convert width to channel macropixels
7811  height = weed_channel_get_height(channel);
7812 
7813  if (xwidth != width || xheight != height) {
7814  if (channel_flags & WEED_CHANNEL_REINIT_ON_SIZE_CHANGE) {
7815  needs_reinit = TRUE;
7816  }
7817  }
7818 
7819  if (!needs_reinit && (channel_flags & WEED_CHANNEL_REINIT_ON_ROWSTRIDES_CHANGE)) {
7820  int *rowstrides2 = weed_channel_get_rowstrides(channel, &npl2);
7821  if (rowstrides_differ(npl, rowstrides, npl2, rowstrides2))
7822  needs_reinit = TRUE;
7823  lives_free(rowstrides2);
7824  }
7825  lives_free(rowstrides);
7826 
7827  if (filter_flags & WEED_FILTER_PREF_LINEAR_GAMMA)
7828  weed_channel_set_gamma_type(channel, WEED_GAMMA_LINEAR);
7829  else
7830  weed_channel_set_gamma_type(channel, cfile->gamma_type);
7831 
7832  if (needs_reinit) {
7833  if ((retval = weed_reinit_effect(inst, FALSE)) == FILTER_ERROR_COULD_NOT_REINIT) {
7834  lives_free(out_channels);
7835  weed_instance_unref(inst);
7836  return NULL;
7837  }
7838  goto matchvals;
7839  }
7840 
7841  if (i == 0 && mainw->current_file == mainw->playing_file) {
7842  cfile->hsize = width;
7843  cfile->vsize = height;
7844  set_main_title(cfile->file_name, 0);
7845  }
7846 
7847  // if we have an optional audio channel, we can push audio to it
7848  if ((achan = get_enabled_audio_channel(inst, 0, TRUE)) != NULL) {
7849  fill_audio_channel(filter, achan);
7850  }
7851 
7853  < weed_get_double_value(inst, WEED_LEAF_TARGET_FPS, NULL))
7854  weed_set_double_value(inst, WEED_LEAF_TARGET_FPS, mainw->inst_fps);
7855  else {
7856  if (weed_plant_has_leaf(filter, WEED_LEAF_HOST_FPS))
7857  weed_leaf_copy(inst, WEED_LEAF_TARGET_FPS, filter, WEED_LEAF_HOST_FPS);
7858  else if (weed_plant_has_leaf(filter, WEED_LEAF_PREFERRED_FPS))
7859  weed_leaf_copy(inst, WEED_LEAF_TARGET_FPS, filter, WEED_LEAF_PREFERRED_FPS);
7860  }
7861 
7862  if (CURRENT_CLIP_IS_VALID) weed_set_double_value(inst, WEED_LEAF_FPS, mainw->inst_fps);
7863 
7864  cwd = cd_to_plugin_dir(filter);
7865 
7866 procfunc1:
7867  // cannot lock the filter here as we may be multithreading
7868  if (filter_flags & WEED_FILTER_HINT_MAY_THREAD) {
7869  retval = process_func_threaded(inst, tc);
7870  if (retval != FILTER_ERROR_DONT_THREAD) did_thread = TRUE;
7871  }
7872  if (!did_thread) {
7873  // normal single threaded version
7874  process_func = (weed_process_f)weed_get_funcptr_value(filter, WEED_LEAF_PROCESS_FUNC, NULL);
7875  if (process_func)
7876  ret = (*process_func)(inst, tc);
7877  }
7878  lives_free(out_channels);
7879 
7880  //if (weed_palette_has_alpha(palette)) lives_layer_set_opaque(channel);
7881 
7882  if (achan) {
7883  int nachans;
7884  float **abuf = weed_channel_get_audio_data(achan, &nachans);
7885  for (i = 0; i < nachans; i++) lives_freep((void **)&abuf[i]);
7886  lives_freep((void **)&abuf);
7887  }
7888 
7889  if (ret == WEED_ERROR_REINIT_NEEDED) {
7890  if (reinits == 1) {
7891  weed_instance_unref(inst);
7892  return channel;
7893  }
7894  if ((retval = weed_reinit_effect(inst, FALSE)) == FILTER_ERROR_COULD_NOT_REINIT) {
7895  weed_instance_unref(inst);
7896  return channel;
7897  }
7898  reinits = 1;
7899  goto procfunc1;
7900  }
7901 
7902  weed_instance_unref(inst);
7903 
7904  lives_chdir(cwd, FALSE);
7905  lives_free(cwd);
7906 
7907  return channel;
7908 }
7909 
7910 
7911 int weed_generator_start(weed_plant_t *inst, int key) {
7912  // key here is zero based
7913  // make an "ephemeral clip"
7914 
7915  // cf. yuv4mpeg.c
7916  // start "playing" but receive frames from a plugin
7917 
7918  // filter_mutex MUST be locked, on FALSE return is unlocked
7919 
7920  weed_plant_t **out_channels, *channel, *filter, *achan;
7921  char *filter_name;
7922  int error, num_channels;
7923  int old_file = mainw->current_file, blend_file = mainw->blend_file;
7924  int palette;
7925 
7926  // create a virtual clip
7927  int new_file = 0;
7928  boolean is_bg = FALSE;
7929 
7930  //weed_instance_ref(inst);
7931  //filter_mutex_lock(key);
7932 
7934 
7935  if (CURRENT_CLIP_IS_VALID && cfile->clip_type == CLIP_TYPE_GENERATOR && mainw->num_tr_applied == 0) {
7936  close_current_file(0);
7937  old_file = -1;
7938  }
7939 
7940  if (mainw->is_processing && !mainw->preview) {
7941  filter_mutex_unlock(key);
7942  return 1;
7943  }
7944 
7945  if ((mainw->preview || (CURRENT_CLIP_IS_VALID && cfile->opening)) &&
7946  (mainw->num_tr_applied == 0 || mainw->blend_file == -1 || mainw->blend_file == mainw->current_file)) {
7947  filter_mutex_unlock(key);
7948  return 2;
7949  }
7950 
7952 
7953  if (old_file != -1 && mainw->blend_file != -1 && mainw->blend_file != mainw->current_file &&
7957  weed_generator_end((weed_plant_t *)mainw->files[mainw->blend_file]->ext_src);
7959  }
7960 
7961  // old_file can also be -1 if we are doing a fg_modeswitch
7962  if (old_file > -1 && LIVES_IS_PLAYING && mainw->num_tr_applied > 0) is_bg = TRUE;
7963 
7964  filter = weed_instance_get_filter(inst, FALSE);
7965  filter_name = weed_get_string_value(filter, WEED_LEAF_NAME, &error);
7966 
7968  // audio clip - we will init the generator as fg video in the same clip
7969  // otherwise known as "showoff mode"
7970  cfile->frames = 1;
7971  cfile->start = cfile->end = 1;
7972  cfile->clip_type = CLIP_TYPE_GENERATOR;
7973  cfile->frameno = 1;
7974  mainw->play_start = mainw->play_end = 1;
7976  } else {
7977  if (!create_cfile(-1, filter_name, TRUE)) {
7978  filter_mutex_unlock(key);
7979  return 3;
7980  }
7981 
7982  cfile->clip_type = CLIP_TYPE_GENERATOR;
7983 
7984  lives_snprintf(cfile->type, 40, "generator:%s", filter_name);
7985  lives_snprintf(cfile->file_name, PATH_MAX, "generator: %s", filter_name);
7986  lives_snprintf(cfile->name, CLIP_NAME_MAXLEN, "generator: %s", filter_name);
7987  lives_free(filter_name);
7988 
7989  // open as a clip with 1 frame
7990  cfile->start = cfile->end = cfile->frames = 1;
7991  }
7992 
7993  new_file = mainw->current_file;
7994  cfile->ext_src = inst;
7995  cfile->ext_src_type = LIVES_EXT_SRC_FILTER;
7996 
7997  if (is_bg) {
8000  }
8001 
8002  if (!is_bg || old_file == -1 || old_file == new_file) fg_generator_clip = new_file;
8003 
8004  if (weed_plant_has_leaf(filter, WEED_LEAF_HOST_FPS))
8005  cfile->pb_fps = cfile->fps = weed_get_double_value(filter, WEED_LEAF_HOST_FPS, &error);
8006  else if (weed_plant_has_leaf(filter, WEED_LEAF_PREFERRED_FPS))
8007  cfile->pb_fps = cfile->fps = weed_get_double_value(filter, WEED_LEAF_PREFERRED_FPS, &error);
8008  else {
8009  cfile->pb_fps = cfile->fps = prefs->default_fps;
8010  }
8011 
8012  out_channels = weed_get_plantptr_array_counted(inst, WEED_LEAF_OUT_CHANNELS, &num_channels);
8013  if (num_channels == 0) {
8014  filter_mutex_unlock(key);
8015  cfile->ext_src = NULL;
8016  cfile->ext_src_type = LIVES_EXT_SRC_NONE;
8018  return 4;
8019  }
8020 
8021  if (!(channel = get_enabled_channel(inst, 0, FALSE))) {
8022  lives_free(out_channels);
8023  filter_mutex_unlock(key);
8024  cfile->ext_src = NULL;
8025  cfile->ext_src_type = LIVES_EXT_SRC_NONE;
8027  return 5;
8028  }
8029  lives_free(out_channels);
8030 
8031  cfile->hsize = weed_get_int_value(channel, WEED_LEAF_WIDTH, &error);
8032  cfile->vsize = weed_get_int_value(channel, WEED_LEAF_HEIGHT, &error);
8033 
8034  palette = weed_get_int_value(channel, WEED_LEAF_CURRENT_PALETTE, &error);
8035  if (palette == WEED_PALETTE_RGBA32 || palette == WEED_PALETTE_ARGB32 || palette == WEED_PALETTE_BGRA32) cfile->bpp = 32;
8036  else cfile->bpp = 24;
8037 
8038  cfile->opening = FALSE;
8039  mainw->proc_ptr = NULL;
8040 
8041  // if the generator has an optional audio in channel, enable it: TODO - make this configurable
8042  if ((achan = get_audio_channel_in(inst, 0)) != NULL) {
8043  if (weed_plant_has_leaf(achan, WEED_LEAF_DISABLED)) weed_leaf_delete(achan, WEED_LEAF_DISABLED);
8044  register_audio_channels(1);
8045  }
8046 
8047  // if not playing, start playing
8048  if (!LIVES_IS_PLAYING) {
8049  uint64_t new_rte;
8050 
8051  if (!is_bg || old_file == -1 || old_file == new_file) {
8052  switch_to_file((mainw->current_file = old_file), new_file);
8053  set_main_title(cfile->file_name, 0);
8054  mainw->play_start = 1;
8055  mainw->play_end = INT_MAX;
8056  if (is_bg) {
8058  if (old_file != -1) mainw->current_file = old_file;
8059  }
8060  } else {
8062  mainw->current_file = old_file;
8063  mainw->play_start = cfile->start;
8064  mainw->play_end = cfile->end;
8065  mainw->playing_sel = FALSE;
8066  }
8067 
8068  new_rte = GU641 << key;
8069  pthread_mutex_lock(&mainw->event_list_mutex);
8070  if (!(mainw->rte & new_rte)) mainw->rte |= new_rte;
8071  pthread_mutex_unlock(&mainw->event_list_mutex);
8072 
8074  if (rte_window) rtew_set_keych(key, TRUE);
8075  if (mainw->ce_thumbs) {
8076  ce_thumbs_set_keych(key, TRUE);
8077 
8078  // if effect was auto (from ACTIVATE data connection), leave all param boxes
8079  // otherwise, remove any which are not "pinned"
8081  }
8082  filter_mutex_unlock(key);
8083 
8084  weed_instance_unref(inst); // release ref from weed_instance_from_filter, normally we would do this on return
8085 
8086  if (mainw->play_window) {
8088  }
8090 
8092  else {
8093  on_playall_activate(NULL, NULL);
8094  // need to set this after playback ends; this stops the key from being activated (again) in effects.c
8095  // also stops the (now defunct instance being unreffed)
8097  }
8098  return 0;
8099  } else {
8100  // already playing
8101 
8102  if (old_file != -1 && mainw->files[old_file]) {
8103  if (IS_NORMAL_CLIP(old_file)) mainw->pre_src_file = old_file;
8104  mainw->current_file = old_file;
8105  }
8106 
8107  if (!is_bg || old_file == -1 || old_file == new_file) {
8108  //if (mainw->current_file == -1) mainw->current_file = new_file;
8109 
8110  if (new_file != old_file) {
8111  mainw->new_clip = new_file;
8112 
8113  /* filter_mutex_unlock(key); // else we get stuck pulling a frame */
8114  /* do_quick_switch(new_file); */
8115  /* filter_mutex_lock(key); */
8116  /* mainw->force_show = TRUE; */
8117 
8118  // switch audio clip
8119  /* if (is_realtime_aplayer(prefs->audio_player) && (prefs->audio_opts & AUDIO_OPTS_FOLLOW_CLIPS) */
8120  /* && !mainw->is_rendering && (mainw->preview || !(mainw->agen_key != 0 || prefs->audio_src == AUDIO_SRC_EXT))) { */
8121  /* switch_audio_clip(new_file, TRUE); */
8122  /* } */
8123 
8125  if (!is_bg && IS_VALID_CLIP(blend_file)) mainw->blend_file = blend_file;
8126  mainw->new_blend_file = -1;
8127  } else {
8129  resize(1);
8131  }
8132  //if (old_file==-1) mainw->whentostop=STOP_ON_VID_END;
8133  } else {
8134  if (mainw->current_file == -1) {
8135  /* mainw->current_file = new_file; */
8136  /* if (is_realtime_aplayer(prefs->audio_player) && (prefs->audio_opts & AUDIO_OPTS_FOLLOW_CLIPS) */
8137  /* && !mainw->is_rendering && (mainw->preview || !(mainw->agen_key != 0 || prefs->audio_src == AUDIO_SRC_EXT))) { */
8138  /* switch_audio_clip(new_file, TRUE); */
8139  /* } */
8140  } else mainw->blend_file = new_file;
8144  }
8146  }
8147 
8148  filter_mutex_unlock(key);
8149 
8150  return 0;
8151 }
8152 
8153 
8154 void wge_inner(weed_plant_t *inst) {
8155  weed_plant_t *next_inst = NULL;
8156  // called from weed_generator_end() below and also called directly after playback ends
8157 
8158  // during playback, MUST call this with filter_mutex locked
8159 
8160  // unrefs inst 1 times
8161 
8162  if (weed_plant_has_leaf(inst, WEED_LEAF_HOST_KEY)) {
8163  int error;
8164  int key = weed_get_int_value(inst, WEED_LEAF_HOST_KEY, &error);
8165  key_to_instance[key][key_modes[key]] = NULL;
8166  }
8167 
8168  while (inst) {
8169  next_inst = get_next_compound_inst(inst);
8170  weed_call_deinit_func(inst);
8171  inst = next_inst;
8172  }
8173 }
8174 
8175 
8176 void weed_generator_end(weed_plant_t *inst) {
8177  // generator has stopped for one of the following reasons:
8178  // efect was de-inited; clip (bg/fg) was changed; playback stopped with fg
8179 
8180  // during playback, MUST be called with filter_mutex locked
8181 
8183  boolean is_bg = FALSE;
8184  boolean clip_switched = mainw->clip_switched;
8185  int current_file = mainw->current_file, pre_src_file = mainw->pre_src_file;
8186 
8188 
8189  if (!inst) {
8190  LIVES_WARN("inst was NULL !");
8191  }
8192 
8193  if (mainw->blend_file != -1 && mainw->blend_file != current_file && mainw->files[mainw->blend_file] &&
8194  mainw->files[mainw->blend_file]->ext_src == inst) is_bg = TRUE;
8196 
8197  if (LIVES_IS_PLAYING && !is_bg && mainw->whentostop == STOP_ON_VID_END) {
8198  // we will close the file after playback stops
8199  // and also unref the instance
8201  return;
8202  }
8203 
8206  if (rte_window && !mainw->is_rendering && !mainw->multitrack) {
8207  // update real time effects window if we are showing it
8208  if (!is_bg) {
8209  rtew_set_keych(fg_generator_key, FALSE);
8210  } else {
8211  rtew_set_keych(bg_generator_key, FALSE);
8212  }
8213  }
8214 
8215  if (mainw->ce_thumbs) {
8216  // update ce_thumbs window if we are showing it
8217  if (!is_bg) {
8218  ce_thumbs_set_keych(fg_generator_key, FALSE);
8219  } else {
8220  ce_thumbs_set_keych(bg_generator_key, FALSE);
8221  }
8222  }
8223 
8224  if (inst && get_audio_channel_in(inst, 0)) {
8225  unregister_audio_channels(1);
8226  }
8227 
8228  if (is_bg) {
8230  key_to_instance[bg_generator_key][bg_generator_mode] = NULL;
8231  pthread_mutex_lock(&mainw->event_list_mutex);
8232  if (rte_key_is_enabled(1 + bg_generator_key)) mainw->rte ^= (GU641 << bg_generator_key);
8233  pthread_mutex_unlock(&mainw->event_list_mutex);
8234  bg_gen_to_start = bg_generator_key = bg_generator_mode = -1;
8235  pre_src_file = mainw->pre_src_file;
8237  } else {
8239  key_to_instance[fg_generator_key][fg_generator_mode] = NULL;
8240  pthread_mutex_lock(&mainw->event_list_mutex);
8241  if (rte_key_is_enabled(1 + fg_generator_key)) mainw->rte ^= (GU641 << fg_generator_key);
8242  pthread_mutex_unlock(&mainw->event_list_mutex);
8243  fg_gen_to_start = fg_generator_key = fg_generator_clip = fg_generator_mode = -1;
8245  }
8246 
8247  if (inst) wge_inner(inst); // removes 1 ref
8248 
8249  // if the param window is already open, show any reinits now
8250  if (fx_dialog[1]) {
8251  if (is_bg) update_widget_vis(NULL, bg_generator_key, bg_generator_mode); // redraw our paramwindow
8252  else update_widget_vis(NULL, fg_generator_key, fg_generator_mode); // redraw our paramwindow
8253  }
8254 
8255  if (!is_bg && cfile->achans > 0 && cfile->clip_type == CLIP_TYPE_GENERATOR) {
8256  // we started playing from an audio clip
8257  cfile->frames = cfile->start = cfile->end = 0;
8258  cfile->ext_src = NULL;
8259  cfile->ext_src_type = LIVES_EXT_SRC_NONE;
8260  cfile->clip_type = CLIP_TYPE_DISK;
8261  cfile->hsize = cfile->vsize = 0;
8262  cfile->pb_fps = cfile->fps = prefs->default_fps;
8263  return;
8264  }
8265 
8273  if (is_bg) {
8277  mainw->new_blend_file = -1;
8278  // close generator file and switch to original file if possible
8279  if (!cfile || cfile->clip_type != CLIP_TYPE_GENERATOR) {
8280  break_me("close non-gen file");
8281  LIVES_WARN("Close non-generator file 2");
8283  } else {
8284  cfile->ext_src = NULL;
8285  cfile->ext_src_type = LIVES_EXT_SRC_NONE;
8287  }
8289  } else {
8290  // close generator file and switch to original file if possible
8291  if (!cfile || cfile->clip_type != CLIP_TYPE_GENERATOR) {
8292  LIVES_WARN("Close non-generator file 1");
8293  } else {
8294  cfile->ext_src = NULL;
8295  cfile->ext_src_type = LIVES_EXT_SRC_NONE;
8296  if (cfile->achans == 0) {
8297  current_file = mainw->current_file;
8299  if (LIVES_IS_PLAYING) {
8301  mainw->current_file = current_file;
8302  }
8303  }
8304  }
8305  if (mainw->current_file == current_file) mainw->clip_switched = clip_switched;
8306  }
8307 
8308  if (is_bg) {
8309  mainw->current_file = current_file;
8310  mainw->pre_src_file = pre_src_file;
8311  mainw->whentostop = wts;
8312  }
8313 
8315 }
8316 
8317 
8318 void weed_bg_generator_end(weed_plant_t *inst) {
8319  // when we stop with a bg generator we want it to be restarted next time
8320  // i.e we will need a new clip for it
8321  int bg_gen_key = bg_generator_key;
8322 
8323  // filter_mutex unlocked
8324 
8326  weed_instance_ref(inst);
8327  weed_generator_end(inst); // unrefs inst
8328  bg_gen_to_start = bg_gen_key;
8329 }
8330 
8331 
8333  // init generators on pb. We have to do this after audio startup
8334  // filter_mutex unlocked
8335  weed_plant_t *inst = NULL, *filter;
8336  weed_plant_t *next_inst = NULL, *orig_inst;
8337 
8338  char *filter_name;
8339 
8340  weed_error_t error = WEED_SUCCESS;
8341 
8342  int bgs = bg_gen_to_start;
8343  boolean was_started = FALSE;
8344 
8345  if (mainw->is_rendering) return TRUE;
8346 
8347  if (fg_gen_to_start == bg_gen_to_start) bg_gen_to_start = -1;
8348 
8349  if (cfile->frames == 0 && fg_gen_to_start == -1 && bg_gen_to_start != -1) {
8350  fg_gen_to_start = bg_gen_to_start;
8351  bg_gen_to_start = -1;
8352  }
8353 
8354  mainw->osc_block = TRUE;
8355 
8356  if (fg_gen_to_start != -1) {
8357  filter_mutex_lock(fg_gen_to_start);
8358  // check is still gen
8359 
8360  if (enabled_in_channels(weed_filters[key_to_fx[fg_gen_to_start][key_modes[fg_gen_to_start]]], FALSE) == 0) {
8361  orig_inst = inst = weed_instance_obtain(fg_gen_to_start, key_modes[fg_gen_to_start]);
8362 
8363  if (inst) {
8364 geninit1:
8365 
8366  filter = weed_instance_get_filter(inst, FALSE);
8367  if (weed_plant_has_leaf(filter, WEED_LEAF_INIT_FUNC)) {
8368  weed_init_f init_func = (weed_init_f)weed_get_funcptr_value(filter, WEED_LEAF_INIT_FUNC, NULL);
8369  if (init_func) {
8370  char *cwd = cd_to_plugin_dir(filter);
8371  error = (*init_func)(inst);
8372  lives_chdir(cwd, FALSE);
8373  lives_free(cwd);
8374  }
8375  }
8376 
8377  if (error != WEED_SUCCESS) {
8378  weed_plant_t *oldinst = inst;
8379  orig_inst = inst = weed_instance_obtain(fg_gen_to_start, key_modes[fg_gen_to_start]);
8380  weed_instance_unref(oldinst);
8381  key_to_instance[fg_gen_to_start][key_modes[fg_gen_to_start]] = NULL;
8382  if (inst) {
8383  char *tmp;
8384  filter = weed_instance_get_filter(inst, TRUE);
8385  filter_name = weed_get_string_value(filter, WEED_LEAF_NAME, NULL);
8386  d_print(_("Failed to start generator %s (%s)\n"), filter_name,
8387  (tmp = lives_strdup(weed_error_to_text(error))));
8388  lives_free(tmp);
8389  lives_free(filter_name);
8390 
8391 deinit4:
8392  next_inst = get_next_compound_inst(inst);
8393 
8394  weed_call_deinit_func(inst);
8395 
8396  if (next_inst) {
8397  // handle compound fx
8398  inst = next_inst;
8399  if (weed_get_boolean_value(inst, WEED_LEAF_HOST_INITED, &error) == WEED_TRUE) goto deinit4;
8400  }
8401  }
8402 
8403  // unref twice to destroy
8404  weed_instance_unref(orig_inst);
8405  weed_instance_unref(orig_inst);
8406 
8407  filter_mutex_unlock(fg_gen_to_start);
8408  fg_gen_to_start = -1;
8409  cfile->ext_src = NULL;
8410  cfile->ext_src_type = LIVES_EXT_SRC_NONE;
8411  mainw->osc_block = FALSE;
8412  return FALSE;
8413  }
8414 
8415  weed_set_boolean_value(inst, WEED_LEAF_HOST_INITED, WEED_TRUE);
8416  weed_set_boolean_value(inst, WEED_LEAF_HOST_UNUSED, WEED_TRUE);
8417 
8418  if (weed_plant_has_leaf(inst, WEED_LEAF_HOST_NEXT_INSTANCE)) {
8419  inst = weed_get_plantptr_value(inst, WEED_LEAF_HOST_NEXT_INSTANCE, &error);
8420  goto geninit1;
8421  }
8422 
8423  inst = orig_inst;
8424 
8425  if (weed_plant_has_leaf(filter, WEED_LEAF_PREFERRED_FPS)) {
8426  int current_file = mainw->current_file;
8427  mainw->current_file = fg_generator_clip;
8428  cfile->fps = weed_get_double_value(filter, WEED_LEAF_PREFERRED_FPS, &error);
8429  set_main_title(cfile->file_name, 0);
8430  lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_pb_fps), cfile->fps);
8431  mainw->current_file = current_file;
8432  }
8433 
8435  cfile->ext_src = inst;
8436  cfile->ext_src_type = LIVES_EXT_SRC_FILTER;
8437  weed_instance_unref(inst);
8438  }
8439  }
8440 
8441  filter_mutex_unlock(fg_gen_to_start);
8442  fg_gen_to_start = -1;
8443  }
8444 
8445  inst = NULL;
8446 
8447  if (bg_gen_to_start != -1) {
8448  filter_mutex_lock(bg_gen_to_start);
8449 
8450  // check is still gen
8451  if (mainw->num_tr_applied > 0
8452  && enabled_in_channels(weed_filters[key_to_fx[bg_gen_to_start][key_modes[bg_gen_to_start]]], FALSE) == 0) {
8453  if ((inst = weed_instance_obtain(bg_gen_to_start, key_modes[bg_gen_to_start])) == NULL) {
8454  // restart bg generator
8455  if (!weed_init_effect(bg_gen_to_start)) {
8456  mainw->osc_block = FALSE;
8457  filter_mutex_unlock(bg_gen_to_start);
8458  return TRUE;
8459  }
8460  was_started = TRUE;
8461  }
8462 
8463  if (!inst) inst = weed_instance_obtain(bgs, key_modes[bgs]);
8464 
8465  orig_inst = inst;
8466 
8467  if (!inst) {
8468  // 2nd playback
8469  int playing_file = mainw->playing_file;
8470  mainw->playing_file = -100; //kludge to stop playing a second time
8471  if (!weed_init_effect(bg_gen_to_start)) {
8472  filter_mutex_unlock(bg_gen_to_start);
8473  error++;
8474  }
8475  mainw->playing_file = playing_file;
8476  orig_inst = weed_instance_obtain(bg_gen_to_start, key_modes[bg_gen_to_start]);
8477  } else {
8478  if (!was_started) {
8479  orig_inst = inst;
8480 genstart2:
8481 
8482  // TODO - error check
8483  weed_call_init_func(inst);
8484 
8485  // handle compound fx
8486  if (weed_plant_has_leaf(inst, WEED_LEAF_HOST_NEXT_INSTANCE)) {
8487  inst = weed_get_plantptr_value(inst, WEED_LEAF_HOST_NEXT_INSTANCE, &error);
8488  goto genstart2;
8489  }
8490  }
8491  }
8492 
8493  inst = orig_inst;
8494 
8495  if (error != WEED_SUCCESS) {
8496 undoit:
8497  key_to_instance[bg_gen_to_start][key_modes[bg_gen_to_start]] = NULL;
8498  if (inst) {
8499  char *tmp;
8500  filter = weed_instance_get_filter(inst, TRUE);
8501  filter_name = weed_get_string_value(filter, WEED_LEAF_NAME, NULL);
8502  d_print(_("Failed to start generator %s, (%s)\n"), filter_name, (tmp = lives_strdup(weed_error_to_text(error))));
8503  lives_free(tmp);
8504  lives_free(filter_name);
8505 
8506 deinit5:
8507 
8508  if (weed_plant_has_leaf(inst, WEED_LEAF_HOST_NEXT_INSTANCE))
8509  next_inst = weed_get_plantptr_value(inst, WEED_LEAF_HOST_NEXT_INSTANCE,
8510  &error);
8511  else next_inst = NULL;
8512 
8513  weed_call_deinit_func(inst);
8514  weed_instance_unref(inst);
8515  weed_instance_unref(inst);
8516 
8517  if (next_inst) {
8518  // handle compound fx
8519  inst = next_inst;
8520  weed_instance_ref(inst);
8521  goto deinit5;
8522  }
8523  }
8524 
8525  mainw->blend_file = -1;
8526  pthread_mutex_lock(&mainw->event_list_mutex);
8527  if (rte_key_is_enabled(1 + ABS(bg_gen_to_start))) mainw->rte ^= (GU641 << ABS(bg_gen_to_start));
8528  pthread_mutex_unlock(&mainw->event_list_mutex);
8529  mainw->osc_block = FALSE;
8530  filter_mutex_unlock(bg_gen_to_start);
8531  bg_gen_to_start = -1;
8532  return FALSE;
8533  }
8534 
8536  || (mainw->files[mainw->blend_file]->frames > 0
8538  int current_file = mainw->current_file;
8539 
8540  filter = weed_instance_get_filter(inst, TRUE);
8541  filter_name = weed_get_string_value(filter, WEED_LEAF_NAME, NULL);
8542  if (!create_cfile(-1, filter_name, TRUE)) {
8543  mainw->current_file = current_file;
8544  goto undoit;
8545  }
8546 
8547  cfile->clip_type = CLIP_TYPE_GENERATOR;
8548 
8549  lives_snprintf(cfile->type, 40, "generator:%s", filter_name);
8550  lives_snprintf(cfile->file_name, PATH_MAX, "generator: %s", filter_name);
8551  lives_snprintf(cfile->name, CLIP_NAME_MAXLEN, "generator: %s", filter_name);
8552  lives_free(filter_name);
8553 
8554  // open as a clip with 1 frame
8555  cfile->start = cfile->end = cfile->frames = 1;
8557  mainw->files[mainw->blend_file]->ext_src = inst;
8559  mainw->current_file = current_file;
8560  }
8561  }
8562  filter_mutex_unlock(bg_gen_to_start);
8563  }
8564 
8565  orig_inst = inst;
8566 
8567 setgui1:
8568 
8569  // handle compound fx
8570  if (inst && weed_plant_has_leaf(inst, WEED_LEAF_HOST_NEXT_INSTANCE)) {
8571  inst = weed_get_plantptr_value(inst, WEED_LEAF_HOST_NEXT_INSTANCE, &error);
8572  goto setgui1;
8573  }
8574 
8575  if (orig_inst) weed_instance_unref(orig_inst);
8576  bg_gen_to_start = -1;
8577  mainw->osc_block = FALSE;
8578 
8579  return TRUE;
8580 }
8581 
8583 // weed parameter functions
8584 
8587 boolean is_hidden_param(weed_plant_t *plant, int i) {
8588  // find out if in_param i is visible or not for plant. Plant can be an instance or a filter
8589  weed_plant_t **wtmpls;
8590  weed_plant_t *filter, *pgui = NULL;
8591  weed_plant_t *wtmpl;
8592  boolean visible = TRUE;
8593  int num_params = 0;
8594 
8595  if (WEED_PLANT_IS_FILTER_INSTANCE(plant)) {
8596  weed_plant_t *param = weed_inst_in_param(plant, i, FALSE, FALSE);
8597  if (param) {
8598  if (weed_param_is_hidden(param, WEED_FALSE) == WEED_TRUE) {
8599  return TRUE;
8600  }
8601  pgui = weed_param_get_gui(param, FALSE);
8602  }
8603  filter = weed_instance_get_filter(plant, TRUE);
8604  } else filter = plant;
8605 
8606  wtmpls = weed_filter_get_in_paramtmpls(filter, &num_params);
8607 
8608  if (i >= num_params) {
8609  lives_free(wtmpls);
8610  return TRUE;
8611  }
8612 
8613  wtmpl = wtmpls[i];
8614  if (!wtmpl) {
8615  lives_free(wtmpls);
8616  return TRUE;
8617  }
8618 
8619  // hide internally connected parameters for compound fx
8620  if (weed_plant_has_leaf(wtmpl, WEED_LEAF_HOST_INTERNAL_CONNECTION)) {
8621  lives_free(wtmpls);
8622  return TRUE;
8623  }
8624 
8626  if ((weed_plant_has_leaf(wtmpl, WEED_LEAF_COPY_VALUE_TO))
8627  || (pgui && weed_plant_has_leaf(pgui, WEED_LEAF_COPY_VALUE_TO))) {
8628  int copyto = -1;
8629  int flags2 = 0, param_type, param_type2;
8630  weed_plant_t *wtmpl2;
8631  if (weed_plant_has_leaf(wtmpl, WEED_LEAF_COPY_VALUE_TO))
8632  copyto = weed_get_int_value(wtmpl, WEED_LEAF_COPY_VALUE_TO, NULL);
8633  if (pgui && weed_plant_has_leaf(pgui, WEED_LEAF_COPY_VALUE_TO))
8634  copyto = weed_get_int_value(pgui, WEED_LEAF_COPY_VALUE_TO, NULL);
8635  if (copyto == i || copyto < 0) copyto = -1;
8636  if (copyto > -1) {
8637  visible = FALSE;
8638  wtmpl2 = wtmpls[copyto];
8639  flags2 = weed_paramtmpl_get_flags(wtmpl2);
8640  param_type = weed_paramtmpl_get_type(wtmpl);
8641  param_type2 = weed_paramtmpl_get_type(wtmpl2);
8642  if (param_type == param_type2
8643  && ((flags2 & WEED_PARAMETER_VARIABLE_SIZE)
8644  || (flags2 & WEED_PARAMETER_VALUE_PER_CHANNEL)
8645  || weed_leaf_num_elements(wtmpl, WEED_LEAF_DEFAULT)
8646  == weed_leaf_num_elements(wtmpl2, WEED_LEAF_DEFAULT))) {
8647  visible = TRUE;
8648  }
8649  }
8650  }
8651  lives_free(wtmpls);
8652  return !visible;
8653 }
8654 
8655 
8656 int get_transition_param(weed_plant_t *filter, boolean skip_internal) {
8657  int num_params, count = 0;
8658  weed_plant_t **in_ptmpls = weed_filter_get_in_paramtmpls(filter, &num_params);
8659  if (num_params == 0) return -1;
8660  for (int i = 0; i < num_params; i++) {
8661  if (skip_internal && weed_plant_has_leaf(in_ptmpls[i], WEED_LEAF_HOST_INTERNAL_CONNECTION)) continue;
8662  if (weed_get_boolean_value(in_ptmpls[i], WEED_LEAF_IS_TRANSITION, NULL) == WEED_TRUE) {
8663  lives_free(in_ptmpls);
8664  return count;
8665  }
8666  count++;
8667  }
8668  lives_free(in_ptmpls);
8669  return -1;
8670 }
8671 
8672 
8673 int get_master_vol_param(weed_plant_t *filter, boolean skip_internal) {
8674  int error, num_params, i, count = 0;
8675  weed_plant_t **in_ptmpls;
8676 
8677  in_ptmpls = weed_get_plantptr_array_counted(filter, WEED_LEAF_IN_PARAMETER_TEMPLATES, &num_params);
8678  if (num_params == 0) return -1;
8679  for (i = 0; i < num_params; i++) {
8680  if (skip_internal && weed_plant_has_leaf(in_ptmpls[i], WEED_LEAF_HOST_INTERNAL_CONNECTION)) continue;
8681  if (weed_plant_has_leaf(in_ptmpls[i], WEED_LEAF_IS_VOLUME_MASTER) &&
8682  weed_get_boolean_value(in_ptmpls[i], WEED_LEAF_IS_VOLUME_MASTER, &error) == WEED_TRUE) {
8683  lives_free(in_ptmpls);
8684  return count;
8685  }
8686  count++;
8687  }
8688  lives_free(in_ptmpls);
8689  return -1;
8690 }
8691 
8692 
8693 boolean is_perchannel_multiw(weed_plant_t *param) {
8694  // updated for weed spec 1.1
8695  int error;
8696  int flags = 0;
8697  weed_plant_t *ptmpl;
8698  if (WEED_PLANT_IS_PARAMETER(param)) ptmpl = weed_get_plantptr_value(param, WEED_LEAF_TEMPLATE, &error);
8699  else ptmpl = param;
8700  if (weed_plant_has_leaf(ptmpl, WEED_LEAF_FLAGS)) flags = weed_get_int_value(ptmpl, WEED_LEAF_FLAGS, &error);
8701  if (flags & WEED_PARAMETER_VALUE_PER_CHANNEL) return TRUE;
8702  return FALSE;
8703 }
8704 
8705 
8706 boolean has_perchannel_multiw(weed_plant_t *filter) {
8707  int nptmpl, i;
8708  weed_plant_t **ptmpls = weed_get_plantptr_array_counted(filter, WEED_LEAF_IN_PARAMETER_TEMPLATES, &nptmpl);
8709 
8710  if (nptmpl == 0) return FALSE;
8711 
8712  for (i = 0; i < nptmpl; i++) {
8713  if (is_perchannel_multiw(ptmpls[i])) {
8714  lives_free(ptmpls);
8715  return TRUE;
8716  }
8717  }
8718 
8719  lives_free(ptmpls);
8720  return FALSE;
8721 }
8722 
8723 
8724 weed_plant_t *weed_inst_in_param(weed_plant_t *inst, int param_num, boolean skip_hidden, boolean skip_internal) {
8725  weed_plant_t **in_params;
8726  weed_plant_t *param;
8727  int error, num_params;
8728 
8729  do {
8730  if (!weed_plant_has_leaf(inst, WEED_LEAF_IN_PARAMETERS)) continue; // has no in_parameters
8731 
8732  num_params = weed_leaf_num_elements(inst, WEED_LEAF_IN_PARAMETERS);
8733 
8734  if (!skip_hidden && !skip_internal) {
8735  if (num_params > param_num) {
8736  in_params = weed_get_plantptr_array(inst, WEED_LEAF_IN_PARAMETERS, &error);
8737  param = in_params[param_num];
8738  lives_free(in_params);
8739  return param;
8740  }
8741  param_num -= num_params;
8742  }
8743 
8744  else {
8745  int count = 0;
8746  register int i;
8747 
8748  in_params = weed_get_plantptr_array(inst, WEED_LEAF_IN_PARAMETERS, &error);
8749 
8750  for (i = 0; i < num_params; i++) {
8751  param = in_params[i];
8752  if ((!skip_hidden || !is_hidden_param(inst, i)) && (!skip_internal
8753  || !weed_plant_has_leaf(param, WEED_LEAF_HOST_INTERNAL_CONNECTION))) {
8754  if (count == param_num) {
8755  lives_free(in_params);
8756  return param;
8757  }
8758  count++;
8759  }
8760  }
8761  param_num -= count;
8762  lives_free(in_params);
8763  }
8764  } while (weed_plant_has_leaf(inst, WEED_LEAF_HOST_NEXT_INSTANCE) &&
8765  (inst = weed_get_plantptr_value(inst, WEED_LEAF_HOST_NEXT_INSTANCE, &error)) != NULL);
8766 
8767  return NULL;
8768 }
8769 
8770 
8771 weed_plant_t *weed_inst_out_param(weed_plant_t *inst, int param_num) {
8772  weed_plant_t **out_params;
8773  weed_plant_t *param;
8774  int error, num_params;
8775 
8776  do {
8777  if (!weed_plant_has_leaf(inst, WEED_LEAF_OUT_PARAMETERS)) continue; // has no out_parameters
8778 
8779  num_params = weed_leaf_num_elements(inst, WEED_LEAF_OUT_PARAMETERS);
8780 
8781  if (num_params > param_num) {
8782  out_params = weed_get_plantptr_array(inst, WEED_LEAF_OUT_PARAMETERS, &error);
8783  param = out_params[param_num];
8784  lives_free(out_params);
8785  return param;
8786  }
8787  param_num -= num_params;
8788  } while (weed_plant_has_leaf(inst, WEED_LEAF_HOST_NEXT_INSTANCE) &&
8789  (inst = weed_get_plantptr_value(inst, WEED_LEAF_HOST_NEXT_INSTANCE, &error)) != NULL);
8790 
8791  return NULL;
8792 }
8793 
8794 
8795 weed_plant_t *weed_filter_in_paramtmpl(weed_plant_t *filter, int param_num, boolean skip_internal) {
8796  weed_plant_t **in_params;
8797  weed_plant_t *ptmpl;
8798  int num_params;
8799 
8800  int count = 0;
8801  register int i;
8802 
8803  in_params = weed_get_plantptr_array_counted(filter, WEED_LEAF_IN_PARAMETER_TEMPLATES, &num_params);
8804  if (num_params <= param_num) {
8805  lives_freep((void **)&in_params);
8806  return NULL; // invalid parameter number
8807  }
8808 
8809  if (!skip_internal) {
8810  ptmpl = in_params[param_num];
8811  lives_free(in_params);
8812  return ptmpl;
8813  }
8814 
8815  for (i = 0; i < num_params; i++) {
8816  ptmpl = in_params[i];
8817  if (!weed_plant_has_leaf(ptmpl, WEED_LEAF_HOST_INTERNAL_CONNECTION)) {
8818  if (count == param_num) {
8819  lives_free(in_params);
8820  return ptmpl;
8821  }
8822  count++;
8823  }
8824  }
8825 
8826  lives_free(in_params);
8827  return NULL;
8828 }
8829 
8830 
8831 weed_plant_t *weed_filter_out_paramtmpl(weed_plant_t *filter, int param_num) {
8832  weed_plant_t **out_params;
8833  weed_plant_t *ptmpl;
8834  int error, num_params;
8835 
8836  if (!weed_plant_has_leaf(filter, WEED_LEAF_OUT_PARAMETER_TEMPLATES)) return NULL; // has no out_parameters
8837 
8838  num_params = weed_leaf_num_elements(filter, WEED_LEAF_OUT_PARAMETER_TEMPLATES);
8839 
8840  if (num_params <= param_num) return NULL; // invalid parameter number
8841 
8842  out_params = weed_get_plantptr_array(filter, WEED_LEAF_OUT_PARAMETER_TEMPLATES, &error);
8843 
8844  ptmpl = out_params[param_num];
8845  lives_free(out_params);
8846  return ptmpl;
8847 }
8848 
8849 
8850 int get_nth_simple_param(weed_plant_t *plant, int pnum) {
8851  // return the number of the nth "simple" parameter
8852  // we define "simple" as - must be single valued int or float, must not be hidden
8853 
8854  // -1 is returned if no such parameter is found
8855 
8856  weed_plant_t **in_ptmpls;
8857  weed_plant_t *tparamtmpl;
8858  weed_plant_t *gui;
8859  int i, ptype, flags, nparams;
8860 
8861  if (WEED_PLANT_IS_FILTER_INSTANCE(plant)) plant = weed_instance_get_filter(plant, TRUE);
8862 
8863  if (!weed_plant_has_leaf(plant, WEED_LEAF_IN_PARAMETER_TEMPLATES)) return -1;
8864 
8865  in_ptmpls = weed_get_plantptr_array_counted(plant, WEED_LEAF_IN_PARAMETER_TEMPLATES, &nparams);
8866 
8867  for (i = 0; i < nparams; i++) {
8868  tparamtmpl = in_ptmpls[i];
8869  gui = weed_paramtmpl_get_gui(tparamtmpl, FALSE);
8870 
8871  ptype = weed_paramtmpl_get_type(tparamtmpl);
8872 
8873  if (gui && ptype == WEED_PARAM_INTEGER && weed_plant_has_leaf(gui, WEED_LEAF_CHOICES)) continue;
8874 
8875  flags = weed_paramtmpl_get_flags(tparamtmpl);
8876 
8877  if ((ptype == WEED_PARAM_INTEGER || ptype == WEED_PARAM_FLOAT)
8878  && flags == 0 && weed_leaf_num_elements(tparamtmpl, WEED_LEAF_DEFAULT) == 1 &&
8879  !is_hidden_param(plant, i)) {
8880  if (pnum == 0) {
8881  lives_free(in_ptmpls);
8882  return i;
8883  }
8884  pnum--;
8885  }
8886  }
8887  lives_free(in_ptmpls);
8888  return -1;
8889 }
8890 
8891 
8892 int count_simple_params(weed_plant_t *plant) {
8893  int i, ptype, flags, nparams, count = 0;
8894  weed_plant_t **in_ptmpls;
8895  weed_plant_t *tparamtmpl;
8896 
8897  if (WEED_PLANT_IS_FILTER_INSTANCE(plant)) plant = weed_instance_get_filter(plant, TRUE);
8898 
8899  if (!weed_plant_has_leaf(plant, WEED_LEAF_IN_PARAMETER_TEMPLATES)) return count;
8900 
8901  in_ptmpls = weed_get_plantptr_array_counted(plant, WEED_LEAF_IN_PARAMETER_TEMPLATES, &nparams);
8902 
8903  for (i = 0; i < nparams; i++) {
8904  tparamtmpl = in_ptmpls[i];
8905  ptype = weed_paramtmpl_get_type(tparamtmpl);
8906  flags = weed_paramtmpl_get_flags(tparamtmpl);
8907  if ((ptype == WEED_PARAM_INTEGER || ptype == WEED_PARAM_FLOAT)
8908  && flags == 0 && weed_leaf_num_elements(tparamtmpl, WEED_LEAF_DEFAULT) == 1 &&
8909  !is_hidden_param(plant, i)) {
8910  count++;
8911  }
8912  }
8913  lives_free(in_ptmpls);
8914  return count;
8915 }
8916 
8917 
8918 int set_copy_to(weed_plant_t *inst, int pnum, lives_rfx_t *rfx, boolean update) {
8919  // if we update a plugin in_parameter, evaluate any "copy_value_to"
8920  // filter_mutex MUST be unlocked
8921  weed_plant_t *paramtmpl;
8922  weed_plant_t *pgui, *in_param2;
8923  weed_plant_t *in_param = weed_inst_in_param(inst, pnum, FALSE, FALSE); // use this here in case of compound fx
8924  int copyto = -1;
8925  int key = -1;
8926  int param_type, param_type2;
8927 
8928  if (!in_param) return -1;
8929 
8930  pgui = weed_param_get_gui(in_param, FALSE);
8931  paramtmpl = weed_param_get_template(in_param);
8932 
8933  if (pgui && weed_plant_has_leaf(pgui, WEED_LEAF_COPY_VALUE_TO)) {
8934  copyto = weed_get_int_value(pgui, WEED_LEAF_COPY_VALUE_TO, NULL);
8935  if (copyto == pnum || copyto < 0) return -1;
8936  }
8937 
8938  if (copyto == -1 && weed_plant_has_leaf(paramtmpl, WEED_LEAF_COPY_VALUE_TO))
8939  copyto = weed_get_int_value(paramtmpl, WEED_LEAF_COPY_VALUE_TO, NULL);
8940  if (copyto == pnum || copyto < 0) return -1;
8941 
8942  if (copyto >= rfx->num_params) return -1;
8943 
8944  if (rfx->params[copyto].change_blocked) return -1;
8945 
8946  param_type = weed_param_get_type(in_param);
8947  in_param2 = weed_inst_in_param(inst, copyto, FALSE, FALSE); // use this here in case of compound fx
8948  if (!in_param2) return -1;
8949  if (weed_plant_has_leaf(in_param2, WEED_LEAF_HOST_INTERNAL_CONNECTION)) return -1;
8950  param_type2 = weed_param_get_type(in_param2);
8951 
8953  if (!(param_type == param_type2 && (!weed_param_has_variable_size(in_param) || weed_param_has_variable_size(in_param2))
8955  || weed_param_has_value_perchannel(in_param2)))) return -1;
8956 
8957  if (update) {
8958  weed_plant_t *paramtmpl2 = weed_param_get_template(in_param2);
8959  int flags = weed_paramtmpl_get_flags(paramtmpl2);
8960 
8961  if (weed_plant_has_leaf(inst, WEED_LEAF_HOST_KEY)) {
8962  key = weed_get_int_value(inst, WEED_LEAF_HOST_KEY, NULL);
8963  filter_mutex_lock(key);
8964  }
8965  if (flags & WEED_PARAMETER_VALUE_PER_CHANNEL) {
8966  int *ign_array;
8967  int nvals = weed_leaf_num_elements(in_param2, WEED_LEAF_VALUE);
8968  int vsize = 1;
8969  if (param_type2 == WEED_PARAM_COLOR) {
8970  int cspace = weed_get_int_value(paramtmpl2, WEED_LEAF_COLORSPACE, NULL);
8971  if (cspace == WEED_COLORSPACE_RGB) vsize = 3;
8972  else vsize = 4;
8973  }
8974  weed_leaf_copy(paramtmpl2, "host_new_def_backup", paramtmpl2, WEED_LEAF_NEW_DEFAULT);
8975  weed_leaf_copy(in_param2, "host_value_backup", in_param2, WEED_LEAF_VALUE);
8976  weed_leaf_copy(paramtmpl2, WEED_LEAF_NEW_DEFAULT, in_param, WEED_LEAF_VALUE);
8977  fill_param_vals_to(in_param2, paramtmpl2, nvals / vsize);
8978  ign_array = weed_get_boolean_array(in_param2, WEED_LEAF_IGNORE, NULL);
8979  for (int i = 0; i < nvals; i += vsize) {
8980  if (!weed_leaf_elements_equate(in_param2, WEED_LEAF_VALUE, in_param2, "host_value_backup", i))
8981  ign_array[i] = WEED_FALSE;
8982  else
8983  ign_array[i] = WEED_TRUE;
8984  }
8985  weed_set_boolean_array(in_param2, WEED_LEAF_IGNORE, nvals / vsize, ign_array);
8986  weed_leaf_delete(in_param2, "host_value_backup");
8987  weed_leaf_copy(paramtmpl2, WEED_LEAF_NEW_DEFAULT, paramtmpl2, "host_new_def_backup");
8988  weed_leaf_delete(paramtmpl2, "host_new_def_backup");
8989  lives_freep((void **)&ign_array);
8990  } else {
8991  weed_leaf_copy(in_param2, WEED_LEAF_VALUE, in_param, WEED_LEAF_VALUE);
8992  if (key != -1)
8993  filter_mutex_unlock(key);
8994  }
8995  }
8996  return copyto;
8997 }
8998 
8999 
9000 void rec_param_change(weed_plant_t *inst, int pnum) {
9001  // should be called with event_list_mutex unlocked !
9002  ticks_t actual_ticks;
9003  weed_plant_t *in_param;
9004  int key;
9005  int error;
9006 
9007  weed_instance_ref(inst);
9008 
9009  // do not record changes for the floating fx dialog box (rte window params)
9010  if (weed_plant_has_leaf(inst, WEED_LEAF_HOST_NORECORD)
9011  && weed_get_boolean_value(inst, WEED_LEAF_HOST_NORECORD, &error)) {
9012  weed_instance_unref(inst);
9013  return;
9014  }
9015 
9016  // do not record changes for generators - those get recorded to scrap_file or ascrap_file
9017  if (enabled_in_channels(inst, FALSE) == 0) {
9018  weed_instance_unref(inst);
9019  return;
9020  }
9021 
9022  //actual_ticks = mainw->clock_ticks;//lives_get_current_playback_ticks(mainw->origsecs, mainw->orignsecs, NULL);
9023  actual_ticks = mainw->startticks;
9024 
9025  pthread_mutex_lock(&mainw->event_list_mutex);
9026  key = weed_get_int_value(inst, WEED_LEAF_HOST_KEY, &error);
9027 
9028  in_param = weed_inst_in_param(inst, pnum, FALSE, FALSE);
9029 
9030  mainw->event_list = append_param_change_event(mainw->event_list, actual_ticks, pnum, in_param, init_events[key], pchains[key]);
9031  pthread_mutex_unlock(&mainw->event_list_mutex);
9032 
9033  weed_instance_unref(inst);
9034 }
9035 
9036 #define KEYSCALE 255.
9037 
9038 
9039 void weed_set_blend_factor(int hotkey) {
9040  weed_plant_t *inst, *in_param, *paramtmpl;
9041 
9042  LiVESList *list = NULL;
9043 
9044  weed_plant_t **in_params;
9045 
9046  double vald, mind, maxd;
9047 
9048  int vali, mini, maxi;
9049  int param_type, pnum, inc_count;
9050 
9051  if (hotkey < 0) return;
9052 
9053  filter_mutex_lock(hotkey);
9054 
9055  inst = weed_instance_obtain(hotkey, key_modes[hotkey]);
9056 
9057  if (!inst) {
9058  filter_mutex_unlock(hotkey);
9059  return;
9060  }
9061 
9062  pnum = get_nth_simple_param(inst, 0);
9063 
9064  if (pnum == -1) {
9065  weed_instance_unref(inst);
9066  filter_mutex_unlock(hotkey);
9067  return;
9068  }
9069 
9070  in_params = weed_get_plantptr_array(inst, WEED_LEAF_IN_PARAMETERS, NULL);
9071  in_param = in_params[pnum];
9072  lives_free(in_params);
9073 
9074  paramtmpl = weed_param_get_template(in_param);
9075  param_type = weed_paramtmpl_get_type(paramtmpl);
9076 
9077  inc_count = enabled_in_channels(inst, FALSE);
9078 
9079  /* filter_mutex_unlock(hotkey); */
9080  /* // record old value */
9081  /* //copyto = set_copy_to(inst, pnum, FALSE); */
9082  /* filter_mutex_lock(hotkey); */
9083 
9084  if (mainw->record && !mainw->record_paused && LIVES_IS_PLAYING && (prefs->rec_opts & REC_EFFECTS) && inc_count > 0) {
9085  //pthread_mutex_lock(&mainw->event_list_mutex);
9086  rec_param_change(inst, pnum);
9087  /* if (copyto > -1) { */
9088  /* rec_param_change(inst, copyto); */
9089  /* } */
9090  //pthread_mutex_unlock(&mainw->event_list_mutex);
9091  }
9092 
9093  if (weed_param_does_wrap(in_param)) {
9094  if (mainw->blend_factor >= 256.) mainw->blend_factor -= 256.;
9095  else if (mainw->blend_factor <= -1.) mainw->blend_factor += 256.;
9096  } else {
9097  if (mainw->blend_factor < 0.) mainw->blend_factor = 0.;
9098  else if (mainw->blend_factor > 255.) mainw->blend_factor = 255.;
9099  }
9100 
9101  switch (param_type) {
9102  case WEED_PARAM_INTEGER:
9103  vali = weed_get_int_value(in_param, WEED_LEAF_VALUE, NULL);
9104  mini = weed_get_int_value(paramtmpl, WEED_LEAF_MIN, NULL);
9105  maxi = weed_get_int_value(paramtmpl, WEED_LEAF_MAX, NULL);
9106 
9107  weed_set_int_value(in_param, WEED_LEAF_VALUE, (int)((double)mini +
9108  (mainw->blend_factor / KEYSCALE * (double)(maxi - mini)) + .5));
9109 
9110  vali = weed_get_int_value(in_param, WEED_LEAF_VALUE, NULL);
9111 
9112  list = lives_list_append(list, lives_strdup_printf("%d", vali));
9113  list = lives_list_append(list, lives_strdup_printf("%d", mini));
9114  list = lives_list_append(list, lives_strdup_printf("%d", maxi));
9115  update_pwindow(hotkey, pnum, list);
9116  if (mainw->ce_thumbs) ce_thumbs_update_params(hotkey, pnum, list);
9117  lives_list_free_all(&list);
9118 
9119  break;
9120  case WEED_PARAM_FLOAT:
9121  vald = weed_get_double_value(in_param, WEED_LEAF_VALUE, NULL);
9122  mind = weed_get_double_value(paramtmpl, WEED_LEAF_MIN, NULL);
9123  maxd = weed_get_double_value(paramtmpl, WEED_LEAF_MAX, NULL);
9124 
9125  weed_set_double_value(in_param, WEED_LEAF_VALUE, mind + (mainw->blend_factor / KEYSCALE * (maxd - mind)));
9126  vald = weed_get_double_value(in_param, WEED_LEAF_VALUE, NULL);
9127 
9128  list = lives_list_append(list, lives_strdup_printf("%.4f", vald));
9129  list = lives_list_append(list, lives_strdup_printf("%.4f", mind));
9130  list = lives_list_append(list, lives_strdup_printf("%.4f", maxd));
9131  update_pwindow(hotkey, pnum, list);
9132  if (mainw->ce_thumbs) ce_thumbs_update_params(hotkey, pnum, list);
9133  lives_list_free_all(&list);
9134 
9135  break;
9136  case WEED_PARAM_SWITCH:
9137  vali = !!(int)mainw->blend_factor;
9138  weed_set_boolean_value(in_param, WEED_LEAF_VALUE, vali);
9139  vali = weed_get_boolean_value(in_param, WEED_LEAF_VALUE, NULL);
9140  mainw->blend_factor = (double)vali;
9141 
9142  list = lives_list_append(list, lives_strdup_printf("%d", vali));
9143  update_pwindow(hotkey, pnum, list);
9144  if (mainw->ce_thumbs) ce_thumbs_update_params(hotkey, pnum, list);
9145  lives_list_free_all(&list);
9146 
9147  break;
9148  default:
9149  break;
9150  }
9151 
9152  /* filter_mutex_unlock(hotkey); */
9153  /* set_copy_to(inst, pnum, TRUE); */
9154  /* filter_mutex_lock(hotkey); */
9155 
9156  if (mainw->record && !mainw->record_paused && LIVES_IS_PLAYING && (prefs->rec_opts & REC_EFFECTS) && inc_count > 0) {
9157  //pthread_mutex_lock(&mainw->event_list_mutex);
9158  rec_param_change(inst, pnum);
9159  /* if (copyto > -1) { */
9160  /* rec_param_change(inst, copyto); */
9161  /* } */
9162  //pthread_mutex_unlock(&mainw->event_list_mutex);
9163  }
9164  weed_instance_unref(inst);
9165  filter_mutex_unlock(hotkey);
9166 }
9167 
9168 
9169 int weed_get_blend_factor(int hotkey) {
9170  // filter mutex MUST be locked
9171 
9172  weed_plant_t *inst, **in_params, *in_param, *paramtmpl;
9173  int vali, mini, maxi;
9174  double vald, mind, maxd;
9175  int weed_ptype;
9176  int i;
9177 
9178  if (hotkey < 0) return 0;
9179  inst = weed_instance_obtain(hotkey, key_modes[hotkey]);
9180 
9181  if (!inst) return 0;
9182 
9183  i = get_nth_simple_param(inst, 0);
9184 
9185  if (i == -1) {
9186  weed_instance_unref(inst);
9187  return 0;
9188  }
9189 
9190  in_params = weed_get_plantptr_array(inst, WEED_LEAF_IN_PARAMETERS, NULL);
9191  in_param = in_params[i];
9192 
9193  paramtmpl = weed_param_get_template(in_param);
9194  weed_ptype = weed_paramtmpl_get_type(paramtmpl);
9195 
9196  switch (weed_ptype) {
9197  case WEED_PARAM_INTEGER:
9198  vali = weed_get_int_value(in_param, WEED_LEAF_VALUE, NULL);
9199  mini = weed_get_int_value(paramtmpl, WEED_LEAF_MIN, NULL);
9200  maxi = weed_get_int_value(paramtmpl, WEED_LEAF_MAX, NULL);
9201  lives_free(in_params);
9202  weed_instance_unref(inst);
9203  return (double)(vali - mini) / (double)(maxi - mini) * KEYSCALE;
9204  case WEED_PARAM_FLOAT:
9205  vald = weed_get_double_value(in_param, WEED_LEAF_VALUE, NULL);
9206  mind = weed_get_double_value(paramtmpl, WEED_LEAF_MIN, NULL);
9207  maxd = weed_get_double_value(paramtmpl, WEED_LEAF_MAX, NULL);
9208  lives_free(in_params);
9209  weed_instance_unref(inst);
9210  return (vald - mind) / (maxd - mind) * KEYSCALE;
9211  case WEED_PARAM_SWITCH:
9212  vali = weed_get_boolean_value(in_param, WEED_LEAF_VALUE, NULL);
9213  lives_free(in_params);
9214  weed_instance_unref(inst);
9215  return vali;
9216  default:
9217  lives_free(in_params);
9218  weed_instance_unref(inst);
9219  }
9220 
9221  return 0;
9222 }
9223 
9224 
9225 weed_plant_t *get_new_inst_for_keymode(int key, int mode) {
9226  // key is 0 based
9227  weed_plant_t *inst;
9228  if ((inst = weed_instance_obtain(key, mode)) != NULL) {
9229  if (weed_plant_has_leaf(inst, WEED_LEAF_HOST_MODE)) {
9230  if (weed_get_int_value(inst, WEED_LEAF_HOST_KEY, NULL) == key
9231  && weed_get_int_value(inst, WEED_LEAF_HOST_MODE, NULL) == mode) {
9232  return inst;
9233  }
9234  }
9235  weed_instance_unref(inst);
9236  }
9237 
9238  for (int i = FX_KEYS_MAX_VIRTUAL; i < FX_KEYS_MAX; i++) {
9239  if ((inst = weed_instance_obtain(i, key_modes[i])) == NULL) {
9240  continue;
9241  }
9242  if (weed_plant_has_leaf(inst, WEED_LEAF_HOST_MODE)) {
9243  if (weed_get_int_value(inst, WEED_LEAF_HOST_KEY, NULL) == key
9244  && weed_get_int_value(inst, WEED_LEAF_HOST_MODE, NULL) == mode) {
9245  return inst;
9246  }
9247  }
9248  weed_instance_unref(inst);
9249  }
9250 
9251  return NULL;
9252 }
9253 
9254 
9256 
9257 LIVES_INLINE char *weed_instance_get_type(weed_plant_t *inst, boolean getsub) {
9258  // return value should be free'd after use
9259  weed_plant_t *filter = weed_instance_get_filter(inst, TRUE);
9260  return weed_filter_get_type(filter, getsub, TRUE);
9261 }
9262 
9263 
9264 char *rte_keymode_get_type(int key, int mode) {
9265  // return value should be free'd after use
9266  char *type = lives_strdup("");
9267  weed_plant_t *filter, *inst;
9268  int idx;
9269 
9270  key--;
9271  if (!rte_keymode_valid(key + 1, mode, TRUE)) return type;
9272 
9273  if ((idx = key_to_fx[key][mode]) == -1) return type;
9274  if ((filter = weed_filters[idx]) == NULL) return type;
9275 
9276  lives_free(type);
9277 
9278  mainw->osc_block = TRUE;
9279 
9280  if ((inst = key_to_instance[key][mode]) != NULL) {
9281  // return details for instance
9282  type = weed_instance_get_type(inst, TRUE);
9283  } else type = weed_filter_get_type(filter, TRUE, TRUE);
9284 
9285  mainw->osc_block = FALSE;
9286  return type;
9287 }
9288 
9289 
9291  weed_plant_t *filter;
9292  int idx;
9293  lives_fx_cat_t cat;
9294 
9295  key--;
9296  if (!rte_keymode_valid(key + 1, mode, TRUE)) return LIVES_FX_CAT_NONE;
9297 
9298  if ((idx = key_to_fx[key][mode]) == -1) return LIVES_FX_CAT_NONE;
9299  if ((filter = weed_filters[idx]) == NULL) return LIVES_FX_CAT_NONE;
9300 
9301  else cat = weed_filter_categorise(filter,
9302  enabled_in_channels(filter, FALSE),
9303  enabled_out_channels(filter, FALSE));
9304 
9305  return cat;
9306 }
9307 
9308 
9310 
9312  // 0 based
9313  int i, free_key;
9314  free_key = next_free_key;
9315  for (i = free_key + 1; i < FX_KEYS_MAX; i++) {
9316  if (key_to_fx[i][0] == -1) {
9317  next_free_key = i;
9318  break;
9319  }
9320  }
9321  if (i == FX_KEYS_MAX) next_free_key = -1;
9322  return free_key;
9323 }
9324 
9325 
9326 boolean weed_delete_effectkey(int key, int mode) {
9327  // delete the effect binding for key/mode and move higher numbered slots down
9328  // also moves the active mode if applicable
9329  // returns FALSE if there was no effect bound to key/mode
9330 
9331  char *tmp;
9332 
9333  boolean was_started = FALSE;
9334 
9335  int oldkeymode = key_modes[--key];
9336  int orig_mode = mode;
9337  int modekey = key;
9338 
9339  if (key_to_fx[key][mode] == -1) return FALSE;
9340 
9341  filter_mutex_lock(key);
9342  if (key < FX_KEYS_MAX_VIRTUAL) free_key_defaults(key, mode);
9343 
9344  for (; mode < (key < FX_KEYS_MAX_VIRTUAL ? prefs->max_modes_per_key : 1); mode++) {
9345  mainw->osc_block = TRUE;
9346  if (key >= FX_KEYS_MAX_VIRTUAL || mode == prefs->max_modes_per_key - 1 || key_to_fx[key][mode + 1] == -1) {
9347  if (key_to_instance[key][mode]) {
9348  was_started = TRUE;
9349  if (key_modes[key] == mode) modekey = -key - 1;
9350  else key_modes[key] = mode;
9351  weed_deinit_effect(modekey);
9352  key_modes[key] = oldkeymode;
9353  }
9354 
9355  key_to_fx[key][mode] = -1;
9356 
9357  if (mode == orig_mode && key_modes[key] == mode) {
9358  key_modes[key] = 0;
9359  if (was_started) {
9360  if (key_to_fx[key][0] != -1) {
9361  if (!weed_init_effect(modekey)) {
9362  // TODO
9363  filter_mutex_lock(key);
9364  }
9365  } else {
9366  pthread_mutex_lock(&mainw->event_list_mutex);
9367  if (rte_key_is_enabled(1 + key)) mainw->rte ^= (GU641 << key);
9368  pthread_mutex_unlock(&mainw->event_list_mutex);
9369  }
9370  }
9371  }
9372 
9373  break; // quit the loop
9374  } else if (key < FX_KEYS_MAX_VIRTUAL) {
9375  filter_mutex_unlock(key);
9376  rte_switch_keymode(key + 1, mode, (tmp = make_weed_hashname
9377  (key_to_fx[key][mode + 1], TRUE, FALSE, 0, FALSE)));
9378  lives_free(tmp);
9379  filter_mutex_lock(key);
9380  key_defaults[key][mode] = key_defaults[key][mode + 1];
9381  key_defaults[key][mode + 1] = NULL;
9382  }
9383  }
9384 
9385  if (key >= FX_KEYS_MAX_VIRTUAL && key < next_free_key) next_free_key = key;
9386 
9387  mainw->osc_block = FALSE;
9388  if (key_modes[key] > orig_mode) key_modes[key]--;
9389  filter_mutex_unlock(key);
9390 
9391  return TRUE;
9392 }
9393 
9394 
9396 
9397 boolean rte_key_valid(int key, boolean is_userkey) {
9398  // key is 1 based
9399  key--;
9400 
9401  if (key < 0 || (is_userkey && key >= FX_KEYS_MAX_VIRTUAL) || key >= FX_KEYS_MAX) return FALSE;
9402  if (key_to_fx[key][key_modes[key]] == -1) return FALSE;
9403  return TRUE;
9404 }
9405 
9406 
9407 boolean rte_keymode_valid(int key, int mode, boolean is_userkey) {
9408  // key is 1 based
9409  if (key < 1 || (is_userkey && key > FX_KEYS_MAX_VIRTUAL) || key > FX_KEYS_MAX || mode < 0 ||
9410  mode >= (key < FX_KEYS_MAX_VIRTUAL ? prefs->max_modes_per_key : 1)) return FALSE;
9411  if (key_to_fx[--key][mode] == -1) return FALSE;
9412  return TRUE;
9413 }
9414 
9415 
9416 int rte_keymode_get_filter_idx(int key, int mode) {
9417  // key is 1 based
9418  if (key < 1 || key > FX_KEYS_MAX || mode < 0 ||
9419  mode >= (key < FX_KEYS_MAX_VIRTUAL ? prefs->max_modes_per_key : 1)) return -1;
9420  return (key_to_fx[--key][mode]);
9421 }
9422 
9423 
9424 int rte_key_getmode(int key) {
9425  // get current active mode for an rte key
9426  // key is 1 based
9427 
9428  if (key < 1 || key > FX_KEYS_MAX) return -1;
9429  return key_modes[--key];
9430 }
9431 
9432 
9433 int rte_key_getmaxmode(int key) {
9434  // gets the highest mode with filter mapped for a key
9435  // not to be confused with rte_get_modespk() which returns the maximum possible
9436 
9437  register int i;
9438 
9439  if (key < 1 || key > FX_KEYS_MAX) return -1;
9440 
9441  key--;
9442 
9443  for (i = 0; i < (key < FX_KEYS_MAX_VIRTUAL ? prefs->max_modes_per_key : 1); i++) {
9444  if (key_to_fx[key][i] == -1) return --i;
9445  }
9446  return --i;
9447 }
9448 
9449 
9450 weed_plant_t *rte_keymode_get_instance(int key, int mode) {
9451  weed_plant_t *inst;
9452 
9453  key--;
9454  if (!rte_keymode_valid(key + 1, mode, FALSE)) return NULL;
9455  mainw->osc_block = TRUE;
9456  if ((inst = weed_instance_obtain(key, mode)) == NULL) {
9457  mainw->osc_block = FALSE;
9458  return NULL;
9459  }
9460  mainw->osc_block = FALSE;
9461  return inst;
9462 }
9463 
9464 
9465 weed_plant_t *rte_keymode_get_filter(int key, int mode) {
9466  // key is 1 based
9467  key--;
9468  if (!rte_keymode_valid(key + 1, mode, FALSE)) return NULL;
9469  return weed_filters[key_to_fx[key][mode]];
9470 }
9471 
9472 
9473 #define MAX_AUTHOR_LEN 10
9474 
9475 char *weed_filter_idx_get_name(int idx, boolean add_subcats, boolean add_notes) {
9476  // return value should be free'd after use
9477  weed_plant_t *filter;
9478  char *filter_name, *tmp;
9479 
9480  if (idx == -1) return lives_strdup("");
9481  if ((filter = weed_filters[idx]) == NULL) return lives_strdup("");
9482 
9483  filter_name = weed_filter_get_name(filter);
9484 
9485  if (add_subcats) {
9487  enabled_in_channels(filter, TRUE),
9488  enabled_out_channels(filter, TRUE));
9489  lives_fx_cat_t sub = weed_filter_subcategorise(filter, cat, FALSE);
9490  if (sub != LIVES_FX_CAT_NONE) {
9491  tmp = lives_strdup_printf("%s (%s)", filter_name, lives_fx_cat_to_text(sub, FALSE));
9492  lives_free(filter_name);
9493  filter_name = tmp;
9494  }
9495  }
9496 
9497  if (add_notes) {
9498  // if it's unstable add that
9499  if (weed_filter_hints_unstable(filter)) {
9500  tmp = lives_strdup_printf(_("%s [unstable]"), filter_name);
9501  lives_free(filter_name);
9502  filter_name = tmp;
9503  }
9504  }
9505 
9506  return filter_name;
9507 }
9508 
9509 
9511  // return value should be free'd after use
9512  weed_plant_t *filter;
9513  if (idx == -1) return NULL;
9514  if (!(filter = weed_filters[idx])) return NULL;
9515  return weed_filter_get_package_name(filter);
9516 }
9517 
9518 
9519 char *weed_instance_get_filter_name(weed_plant_t *inst, boolean get_compound_parent) {
9520  // return value should be lives_free'd after use
9521  weed_plant_t *filter;
9522  char *filter_name;
9523 
9524  if (!inst) return lives_strdup("");
9525  filter = weed_instance_get_filter(inst, get_compound_parent);
9526  filter_name = weed_get_string_value(filter, WEED_LEAF_NAME, NULL);
9527  return filter_name;
9528 }
9529 
9530 
9531 char *rte_keymode_get_filter_name(int key, int mode, boolean add_notes) {
9532  // return value should be lives_free'd after use
9533  // key is 1 based
9534  key--;
9535  if (!rte_keymode_valid(key + 1, mode, TRUE)) return lives_strdup("");
9536  return (weed_filter_idx_get_name(key_to_fx[key][mode], FALSE, add_notes));
9537 }
9538 
9539 
9540 char *rte_keymode_get_plugin_name(int key, int mode) {
9541  // return value should be lives_free'd after use
9542  // key is 1 based
9543  weed_plant_t *filter, *plugin_info;
9544  char *name;
9545 
9546  key--;
9547  if (!rte_keymode_valid(key + 1, mode, TRUE)) return lives_strdup("");
9548 
9549  filter = weed_filters[key_to_fx[key][mode]];
9550  plugin_info = weed_get_plantptr_value(filter, WEED_LEAF_PLUGIN_INFO, NULL);
9551  name = weed_get_string_value(plugin_info, WEED_LEAF_HOST_PLUGIN_NAME, NULL);
9552  return name;
9553 }
9554 
9555 
9557  return bg_generator_key;
9558 }
9559 
9561  return fg_generator_key;
9562 }
9563 
9565  return bg_generator_mode;
9566 }
9567 
9569  return fg_generator_mode;
9570 }
9571 
9579 weed_plant_t *get_textparm(void) {
9580  weed_plant_t *inst, **in_params, *ptmpl, *ret;
9581 
9582  int key = mainw->rte_keys, mode, i, ptype;
9583 
9584  if (key == -1) return NULL;
9585 
9586  mode = rte_key_getmode(key + 1);
9587 
9588  if ((inst = weed_instance_obtain(key, mode))) {
9589  int nparms;
9590 
9591  in_params = weed_get_plantptr_array_counted(inst, WEED_LEAF_IN_PARAMETERS, &nparms);
9592  if (nparms == 0) {
9593  weed_instance_unref(inst);
9594  return NULL;
9595  }
9596 
9597  for (i = 0; i < nparms; i++) {
9598  ptmpl = weed_param_get_template(in_params[i]);
9599  ptype = weed_paramtmpl_get_type(ptmpl);
9600 
9601  if (ptype == WEED_PARAM_TEXT) {
9602  ret = in_params[i];
9603  weed_set_int_value(ret, WEED_LEAF_HOST_IDX, i);
9604  weed_set_plantptr_value(ret, WEED_LEAF_HOST_INSTANCE, inst);
9605  lives_free(in_params);
9606  weed_instance_unref(inst);
9607  return ret;
9608  }
9609  }
9610 
9611  lives_free(in_params);
9612  weed_instance_unref(inst);
9613  }
9614 
9615  return NULL;
9616 }
9617 
9626 boolean rte_key_setmode(int key, int newmode) {
9627  weed_plant_t *inst, *last_inst;
9628  int oldmode;
9629  int blend_file;
9630  lives_whentostop_t whentostop = mainw->whentostop;
9631  int real_key;
9632 
9633  if (key == 0) {
9634  if ((key = mainw->rte_keys) == -1) return FALSE;
9635  } else key--;
9636 
9637  filter_mutex_lock(key);
9638 
9639  real_key = key;
9640 
9641  oldmode = key_modes[key];
9642 
9643  if (key_to_fx[key][0] == -1) {
9644  filter_mutex_unlock(key);
9645  return FALSE; // nothing is mapped to effect key
9646  }
9647 
9648  if (newmode == -1) {
9649  // cycle forwards
9650  if (oldmode == prefs->max_modes_per_key - 1 || key_to_fx[key][oldmode + 1] == -1) {
9651  newmode = 0;
9652  } else {
9653  newmode = key_modes[key] + 1;
9654  }
9655  }
9656 
9657  if (newmode == -2) {
9658  // cycle backwards
9659  newmode = key_modes[key] - 1;
9660  if (newmode < 0) {
9661  for (newmode = prefs->max_modes_per_key - 1; newmode >= 0; newmode--) {
9662  if (key_to_fx[key][newmode] != -1) break;
9663  }
9664  }
9665  }
9666 
9667  if (newmode < 0 || newmode > rte_key_getmaxmode(key + 1)) {
9668  filter_mutex_unlock(key);
9669  return FALSE;
9670  }
9671 
9672  if (key_to_fx[key][newmode] == -1) {
9673  filter_mutex_unlock(key);
9674  return FALSE;
9675  }
9676 
9677  if (rte_window) rtew_set_mode_radio(key, newmode);
9678  if (mainw->ce_thumbs) ce_thumbs_set_mode_combo(key, newmode);
9679 
9680  mainw->osc_block = TRUE;
9681  mainw->blend_palette = WEED_PALETTE_END;
9682 
9683  // TODO - block template channel changes
9684 
9685  if ((inst = weed_instance_obtain(key, oldmode)) != NULL) { // adds a ref
9686  if (enabled_in_channels(inst, FALSE) == 2 && enabled_in_channels(weed_filters[key_to_fx[key][newmode]], FALSE) == 2) {
9687  // transition --> transition, allow any bg generators to survive
9688  key = -key - 1;
9689  }
9690  }
9691 
9692  if (oldmode != newmode) {
9693  blend_file = mainw->blend_file;
9694 
9695  if (inst) {
9696  // handle compound fx
9697  last_inst = inst;
9698  while (get_next_compound_inst(last_inst)) last_inst = get_next_compound_inst(last_inst);
9699  }
9700 
9701  if (inst && (enabled_in_channels(inst, FALSE) > 0 || enabled_out_channels(last_inst, FALSE) == 0 ||
9702  is_pure_audio(inst, FALSE))) {
9703  // not a (video or video/audio) generator
9704  weed_deinit_effect(key);
9705  } else if (enabled_in_channels(weed_filters[key_to_fx[key][newmode]], FALSE) == 0 &&
9706  has_video_chans_out(weed_filters[key_to_fx[key][newmode]], TRUE))
9707  mainw->whentostop = NEVER_STOP; // when gen->gen, dont stop pb
9708 
9709  key_modes[real_key] = newmode;
9710 
9711  mainw->blend_file = blend_file;
9712 
9713  if (inst) {
9714  if (!weed_init_effect(key)) {
9715  weed_instance_unref(inst);
9716  // TODO - unblock template channel changes
9717  mainw->whentostop = whentostop;
9718  key = real_key;
9719  pthread_mutex_lock(&mainw->event_list_mutex);
9720  if (rte_key_is_enabled(1 + key)) mainw->rte ^= (GU641 << key);
9721  pthread_mutex_unlock(&mainw->event_list_mutex);
9722  mainw->osc_block = FALSE;
9723  return FALSE;
9724  }
9725  weed_instance_unref(inst);
9726  if (mainw->ce_thumbs) ce_thumbs_add_param_box(real_key, TRUE);
9727  }
9728  // TODO - unblock template channel changes
9729  mainw->whentostop = whentostop;
9730  }
9731 
9732  filter_mutex_unlock(real_key);
9733  mainw->osc_block = FALSE;
9734  return TRUE;
9735 }
9736 
9737 
9747 int weed_add_effectkey_by_idx(int key, int idx) {
9748  boolean has_gen = FALSE;
9749  boolean has_non_gen = FALSE;
9750 
9751  int i;
9752 
9753  if (idx == -1) return -1;
9754 
9755  key--;
9756 
9757  for (i = 0; i < prefs->max_modes_per_key; i++) {
9758  if (key_to_fx[key][i] != -1) {
9759  if (enabled_in_channels(weed_filters[key_to_fx[key][i]], FALSE) == 0
9760  && has_video_chans_out(weed_filters[key_to_fx[key][i]], TRUE))
9761  has_gen = TRUE;
9762  else has_non_gen = TRUE;
9763  } else {
9764  if ((enabled_in_channels(weed_filters[idx], FALSE) == 0 && has_non_gen &&
9765  !all_outs_alpha(weed_filters[idx], TRUE) && has_video_chans_out(weed_filters[idx], TRUE)) ||
9766  (enabled_in_channels(weed_filters[idx], FALSE) > 0 && has_gen)) return -2;
9767  key_to_fx[key][i] = idx;
9768  if (rte_window && !mainw->is_rendering && !mainw->multitrack) {
9769  // if rte window is visible add to combo box
9770  char *tmp;
9771  rtew_combo_set_text(key, i, (tmp = rte_keymode_get_filter_name(key + 1, i, FALSE)));
9772  lives_free(tmp);
9773 
9774  // set in ce_thumb combos
9776  }
9777  return i;
9778  }
9779  }
9780  return -3;
9781 }
9782 
9783 
9784 int weed_add_effectkey(int key, const char *hashname, boolean fullname) {
9785  // add a filter_class by hashname to an effect_key
9786  int idx = weed_get_idx_for_hashname(hashname, fullname);
9787  return weed_add_effectkey_by_idx(key, idx);
9788 }
9789 
9790 
9791 int rte_switch_keymode(int key, int mode, const char *hashname) {
9792  // this is called when we switch the filter_class bound to an effect_key/mode
9793  // filter mutex unlocked
9794  weed_plant_t *inst;
9795  int oldkeymode = key_modes[--key];
9796  int id = weed_get_idx_for_hashname(hashname, TRUE), tid;
9797  boolean osc_block;
9798  boolean has_gen = FALSE, has_non_gen = FALSE;
9799 
9800  int test = (mode == 0 ? 1 : 0);
9801 
9802  // effect not found
9803  if (id == -1) return -1;
9804 
9805  filter_mutex_lock(key);
9806 
9807  if ((tid = key_to_fx[key][test]) != -1) {
9808  if (enabled_in_channels(weed_filters[tid], FALSE) == 0 && has_video_chans_out(weed_filters[tid], TRUE)) has_gen = TRUE;
9809  else has_non_gen = TRUE;
9810  }
9811 
9812  if ((enabled_in_channels(weed_filters[id], FALSE) == 0 && has_video_chans_out(weed_filters[id], TRUE) &&
9813  !all_outs_alpha(weed_filters[id], TRUE) && has_non_gen) ||
9814  (enabled_in_channels(weed_filters[id], FALSE) > 0 && has_gen)) {
9815  filter_mutex_unlock(key);
9816  return -2;
9817  }
9818 
9819  osc_block = mainw->osc_block;
9820  mainw->osc_block = TRUE;
9821 
9822  // must be done before switching the key_to_fx, as we need to know number of in_parameter_templates
9823  if (key_defaults[key][mode]) free_key_defaults(key, mode);
9824 
9825  if ((inst = weed_instance_obtain(key, mode)) != NULL) {
9826  key_modes[key] = mode;
9827  weed_deinit_effect(-key - 1); // set is_modeswitch
9828  key_to_fx[key][mode] = id;
9829  if (!weed_init_effect(-key - 1)) {
9830  // TODO
9831  filter_mutex_lock(key);
9832  }
9833  key_modes[key] = oldkeymode;
9834  weed_instance_unref(inst);
9835  } else key_to_fx[key][mode] = id;
9836 
9837  filter_mutex_unlock(key);
9838  mainw->osc_block = osc_block;
9839 
9840  return 0;
9841 }
9842 
9843 
9844 void rte_swap_fg_bg(void) {
9845  int key = fg_generator_key;
9846  int mode = fg_generator_mode;
9847  mainw->blend_palette = WEED_PALETTE_END;
9848 
9849  if (key != -1) {
9850  fg_generator_clip = -1;
9851  }
9852  fg_generator_key = bg_generator_key;
9853  fg_generator_mode = bg_generator_mode;
9854  if (fg_generator_key != -1) {
9855  fg_generator_clip = mainw->current_file;
9856  }
9857  bg_generator_key = key;
9858  bg_generator_mode = mode;
9859 }
9860 
9861 
9862 LIVES_GLOBAL_INLINE int weed_get_sorted_filter(int i) {return LIVES_POINTER_TO_INT(lives_list_nth_data(weed_fx_sorted_list, i));}
9863 
9864 
9865 LiVESList *weed_get_all_names(lives_fx_list_t list_type) {
9866  // remember to free list (list + data) after use, if non-NULL
9867  LiVESList *list = NULL;
9868  char *filter_name, *hashname, *string;
9869  int i, error;
9870 
9871  for (i = 0; i < num_weed_filters; i++) {
9872  int sorted = weed_get_sorted_filter(i);
9873  weed_plant_t *filter = weed_filters[sorted];
9874  filter_name = weed_get_string_value(filter, WEED_LEAF_NAME, &error);
9875  switch (list_type) {
9876  case FX_LIST_NAME:
9877  // just name
9878  string = lives_strdup(filter_name);
9879  list = lives_list_append(list, (livespointer)string);
9880  break;
9881  case FX_LIST_EXTENDED_NAME: {
9882  // name + author (if dupe) + subcat + observations
9883  string = weed_filter_idx_get_name(sorted, TRUE, TRUE);
9884  list = lives_list_append(list, (livespointer)string);
9885  }
9886  break;
9887  case FX_LIST_HASHNAME:
9888  // hashnames - authors and not extra_authors
9889  hashname = lives_strdup(hashnames[sorted][0].string);
9890  list = lives_list_append(list, (livespointer)hashname);
9891  break;
9892  }
9893  lives_free(filter_name);
9894  }
9895  return list;
9896 }
9897 
9898 
9899 int rte_get_numfilters(void) {return num_weed_filters;}
9900 
9901 
9903 // parameter interpolation
9904 
9913 void fill_param_vals_to(weed_plant_t *param, weed_plant_t *paramtmpl, int index) {
9914  int i, ptype;
9915  int num_vals = weed_leaf_num_elements(param, WEED_LEAF_VALUE);
9916  int new_defi, *valis, *nvalis;
9917  double new_defd, *valds, *nvalds;
9918  char *new_defs, **valss, **nvalss;
9919  int cspace;
9920  int *colsis, *coli;
9921  int vcount;
9922  double *colsds, *cold;
9923 
9924  ptype = weed_paramtmpl_get_type(paramtmpl);
9925  vcount = num_vals;
9926  if (index >= vcount) vcount = ++index;
9927 
9928  switch (ptype) {
9929  case WEED_PARAM_INTEGER:
9930  if (vcount > num_vals) {
9931  new_defi = weed_get_int_value(paramtmpl, WEED_LEAF_NEW_DEFAULT, NULL);
9932  valis = weed_get_int_array(param, WEED_LEAF_VALUE, NULL);
9933  nvalis = (int *)lives_malloc(vcount * sizint);
9934  for (i = 0; i < vcount; i++) {
9935  if (i < num_vals && i < index) nvalis[i] = valis[i];
9936  else if (i <= num_vals && i > index) nvalis[i] = valis[i - 1];
9937  else nvalis[i] = new_defi;
9938  }
9939  weed_set_int_array(param, WEED_LEAF_VALUE, vcount, nvalis);
9940  lives_freep((void **)&valis);
9941  lives_freep((void **)&nvalis);
9942  }
9943  break;
9944  case WEED_PARAM_FLOAT:
9945  if (vcount > num_vals) {
9946  new_defd = weed_get_double_value(paramtmpl, WEED_LEAF_NEW_DEFAULT, NULL);
9947  valds = weed_get_double_array(param, WEED_LEAF_VALUE, NULL);
9948  nvalds = (double *)lives_malloc(vcount * sizdbl);
9949  for (i = 0; i < vcount; i++) {
9950  if (i < num_vals && i < index) nvalds[i] = valds[i];
9951  else if (i <= num_vals && i > index) nvalds[i] = valds[i - 1];
9952  else nvalds[i] = new_defd;
9953  }
9954  weed_set_double_array(param, WEED_LEAF_VALUE, vcount, nvalds);
9955 
9956  lives_freep((void **)&valds);
9957  lives_freep((void **)&nvalds);
9958  }
9959  break;
9960  case WEED_PARAM_SWITCH:
9961  if (vcount > num_vals) {
9962  new_defi = weed_get_boolean_value(paramtmpl, WEED_LEAF_NEW_DEFAULT, NULL);
9963  valis = weed_get_boolean_array(param, WEED_LEAF_VALUE, NULL);
9964  nvalis = (int *)lives_malloc(vcount * sizint);
9965  for (i = 0; i < vcount; i++) {
9966  if (i < num_vals && i < index) nvalis[i] = valis[i];
9967  else if (i <= num_vals && i > index) nvalis[i] = valis[i - 1];
9968  else nvalis[i] = new_defi;
9969  }
9970  weed_set_boolean_array(param, WEED_LEAF_VALUE, vcount, nvalis);
9971  lives_freep((void **)&valis);
9972  lives_freep((void **)&nvalis);
9973  }
9974  break;
9975  case WEED_PARAM_TEXT:
9976  if (vcount > num_vals) {
9977  new_defs = weed_get_string_value(paramtmpl, WEED_LEAF_NEW_DEFAULT, NULL);
9978  valss = weed_get_string_array(param, WEED_LEAF_VALUE, NULL);
9979  nvalss = (char **)lives_malloc(vcount * sizeof(char *));
9980  for (i = 0; i < vcount; i++) {
9981  if (i < num_vals && i < index) nvalss[i] = valss[i];
9982  else if (i <= num_vals && i > index) nvalss[i] = valss[i - 1];
9983  else nvalss[i] = new_defs;
9984  }
9985  weed_set_string_array(param, WEED_LEAF_VALUE, vcount, nvalss);
9986 
9987  for (i = 0; i < index; i++) {
9988  lives_freep((void **)&nvalss[i]);
9989  }
9990 
9991  lives_freep((void **)&valss);
9992  lives_freep((void **)&nvalss);
9993  }
9994  break;
9995  case WEED_PARAM_COLOR:
9996  cspace = weed_get_int_value(paramtmpl, WEED_LEAF_COLORSPACE, NULL);
9997  switch (cspace) {
9998  case WEED_COLORSPACE_RGB:
9999  num_vals /= 3;
10000  vcount = num_vals;
10001  index--;
10002  if (index >= vcount) vcount = ++index;
10003  vcount *= 3;
10004  if (weed_leaf_seed_type(paramtmpl, WEED_LEAF_NEW_DEFAULT) == WEED_SEED_INT) {
10005  colsis = weed_get_int_array(param, WEED_LEAF_VALUE, NULL);
10006  if (weed_leaf_num_elements(paramtmpl, WEED_LEAF_NEW_DEFAULT) == 1) {
10007  coli = (int *)lives_malloc(3 * sizint);
10008  coli[0] = coli[1] = coli[2] = weed_get_int_value(paramtmpl, WEED_LEAF_NEW_DEFAULT, NULL);
10009  } else coli = weed_get_int_array(paramtmpl, WEED_LEAF_NEW_DEFAULT, NULL);
10010  valis = weed_get_int_array(param, WEED_LEAF_VALUE, NULL);
10011  nvalis = (int *)lives_malloc(vcount * sizint);
10012  for (i = 0; i < vcount; i += 3) {
10013  if (i < num_vals && i < index) {
10014  nvalis[i] = valis[i];
10015  nvalis[i + 1] = valis[i + 1];
10016  nvalis[i + 2] = valis[i + 2];
10017  } else if (i <= num_vals && i > index) {
10018  nvalis[i] = valis[i - 3];
10019  nvalis[i + 1] = valis[i - 2];
10020  nvalis[i + 2] = valis[i - 1];
10021  } else {
10022  nvalis[i] = coli[0];
10023  nvalis[i + 1] = coli[1];
10024  nvalis[i + 2] = coli[2];
10025  }
10026  }
10027  weed_set_int_array(param, WEED_LEAF_VALUE, vcount, nvalis);
10028  lives_freep((void **)&valis);
10029  lives_freep((void **)&colsis);
10030  lives_freep((void **)&nvalis);
10031  } else {
10032  colsds = weed_get_double_array(param, WEED_LEAF_VALUE, NULL);
10033  if (weed_leaf_num_elements(paramtmpl, WEED_LEAF_NEW_DEFAULT) == 1) {
10034  cold = (double *)lives_malloc(3 * sizdbl);
10035  cold[0] = cold[1] = cold[2] = weed_get_double_value(paramtmpl, WEED_LEAF_NEW_DEFAULT, NULL);
10036  } else cold = weed_get_double_array(paramtmpl, WEED_LEAF_NEW_DEFAULT, NULL);
10037  valds = weed_get_double_array(param, WEED_LEAF_VALUE, NULL);
10038  nvalds = (double *)lives_malloc(vcount * sizdbl);
10039  for (i = 0; i < vcount; i += 3) {
10040  if (i < num_vals && i < index) {
10041  nvalds[i] = valds[i];
10042  nvalds[i + 1] = valds[i + 1];
10043  nvalds[i + 2] = valds[i + 2];
10044  } else if (i <= num_vals && i > index) {
10045  nvalds[i] = valds[i - 3];
10046  nvalds[i + 1] = valds[i - 2];
10047  nvalds[i + 2] = valds[i - 1];
10048  } else {
10049  nvalds[i] = cold[0];
10050  nvalds[i + 1] = cold[1];
10051  nvalds[i + 2] = cold[2];
10052  }
10053  }
10054  weed_set_double_array(param, WEED_LEAF_VALUE, vcount, nvalds);
10055  lives_freep((void **)&valds);
10056  lives_freep((void **)&colsds);
10057  lives_freep((void **)&nvalds);
10058  }
10059  vcount /= 3;
10060  }
10061  break;
10062  }
10063 
10064  if (is_perchannel_multiw(param)) {
10065  int num_vals;
10066  int *ign_array = weed_get_boolean_array_counted(param, WEED_LEAF_IGNORE, &num_vals);
10067  if (vcount > num_vals) {
10068  ign_array = (int *)lives_realloc(ign_array, vcount * sizint);
10069  for (i = num_vals; i < vcount; i++) {
10070  ign_array[i] = WEED_TRUE;
10071  }
10072  weed_set_boolean_array(param, WEED_LEAF_IGNORE, vcount, ign_array);
10073  }
10074  lives_freep((void **)&ign_array);
10075  }
10076 }
10077 
10078 
10079 static int get_default_element_int(weed_plant_t *param, int idx, int mpy, int add) {
10080  int *valsi, val;
10081  int error;
10082  weed_plant_t *ptmpl = weed_get_plantptr_value(param, WEED_LEAF_TEMPLATE, &error);
10083 
10084  if (!weed_paramtmpl_value_irrelevant(ptmpl) && weed_plant_has_leaf(ptmpl, WEED_LEAF_HOST_DEFAULT) &&
10085  weed_leaf_num_elements(ptmpl, WEED_LEAF_HOST_DEFAULT) > idx * mpy + add) {
10086  valsi = weed_get_int_array(ptmpl, WEED_LEAF_HOST_DEFAULT, &error);
10087  val = valsi[idx * mpy + add];
10088  lives_free(valsi);
10089  return val;
10090  }
10091  if (weed_plant_has_leaf(ptmpl, WEED_LEAF_DEFAULT)
10092  && weed_leaf_num_elements(ptmpl, WEED_LEAF_DEFAULT) > idx * mpy + add) {
10093  valsi = weed_get_int_array(ptmpl, WEED_LEAF_DEFAULT, &error);
10094  val = valsi[idx * mpy + add];
10095  lives_free(valsi);
10096  return val;
10097  }
10098  if (weed_leaf_num_elements(ptmpl, WEED_LEAF_NEW_DEFAULT) == mpy) {
10099  valsi = weed_get_int_array(ptmpl, WEED_LEAF_DEFAULT, &error);
10100  val = valsi[add];
10101  lives_free(valsi);
10102  return val;
10103  }
10104  return weed_get_int_value(ptmpl, WEED_LEAF_NEW_DEFAULT, &error);
10105 }
10106 
10107 
10108 static double get_default_element_double(weed_plant_t *param, int idx, int mpy, int add) {
10109  double *valsd, val;
10110  int error;
10111  weed_plant_t *ptmpl = weed_get_plantptr_value(param, WEED_LEAF_TEMPLATE, &error);
10112 
10113  if (!weed_paramtmpl_value_irrelevant(ptmpl) && weed_plant_has_leaf(ptmpl, WEED_LEAF_HOST_DEFAULT) &&
10114  weed_leaf_num_elements(ptmpl, WEED_LEAF_HOST_DEFAULT) > idx * mpy + add) {
10115  valsd = weed_get_double_array(ptmpl, WEED_LEAF_HOST_DEFAULT, &error);
10116  val = valsd[idx * mpy + add];
10117  lives_free(valsd);
10118  return val;
10119  }
10120  if (weed_plant_has_leaf(ptmpl, WEED_LEAF_DEFAULT)
10121  && weed_leaf_num_elements(ptmpl, WEED_LEAF_DEFAULT) > idx * mpy + add) {
10122  valsd = weed_get_double_array(ptmpl, WEED_LEAF_DEFAULT, &error);
10123  val = valsd[idx * mpy + add];
10124  lives_free(valsd);
10125  return val;
10126  }
10127  if (weed_leaf_num_elements(ptmpl, WEED_LEAF_NEW_DEFAULT) == mpy) {
10128  valsd = weed_get_double_array(ptmpl, WEED_LEAF_DEFAULT, &error);
10129  val = valsd[add];
10130  lives_free(valsd);
10131  return val;
10132  }
10133  return weed_get_double_value(ptmpl, WEED_LEAF_NEW_DEFAULT, &error);
10134 }
10135 
10136 
10137 static int get_default_element_bool(weed_plant_t *param, int idx) {
10138  int *valsi, val;
10139  int error;
10140  weed_plant_t *ptmpl = weed_get_plantptr_value(param, WEED_LEAF_TEMPLATE, &error);
10141 
10142  if (!weed_paramtmpl_value_irrelevant(ptmpl) && weed_plant_has_leaf(ptmpl, WEED_LEAF_HOST_DEFAULT) &&
10143  weed_leaf_num_elements(ptmpl, WEED_LEAF_HOST_DEFAULT) > idx) {
10144  valsi = weed_get_boolean_array(ptmpl, WEED_LEAF_HOST_DEFAULT, &error);
10145  val = valsi[idx];
10146  lives_free(valsi);
10147  return val;
10148  }
10149  if (weed_plant_has_leaf(ptmpl, WEED_LEAF_DEFAULT) && weed_leaf_num_elements(ptmpl, WEED_LEAF_DEFAULT) > idx) {
10150  valsi = weed_get_boolean_array(ptmpl, WEED_LEAF_DEFAULT, &error);
10151  val = valsi[idx];
10152  lives_free(valsi);
10153  return val;
10154  }
10155  return weed_get_boolean_value(ptmpl, WEED_LEAF_NEW_DEFAULT, &error);
10156 }
10157 
10158 
10159 static char *get_default_element_string(weed_plant_t *param, int idx) {
10160  char **valss, *val, *val2;
10161  int error, i;
10162  int numvals;
10163  weed_plant_t *ptmpl = weed_get_plantptr_value(param, WEED_LEAF_TEMPLATE, &error);
10164 
10165  if (!weed_paramtmpl_value_irrelevant(ptmpl) && weed_plant_has_leaf(ptmpl, WEED_LEAF_HOST_DEFAULT) &&
10166  (numvals = weed_leaf_num_elements(ptmpl, WEED_LEAF_HOST_DEFAULT)) > idx) {
10167  valss = weed_get_string_array(ptmpl, WEED_LEAF_HOST_DEFAULT, &error);
10168  val = lives_strdup(valss[idx]);
10169  for (i = 0; i < numvals; i++) lives_free(valss[i]);
10170  lives_free(valss);
10171  return val;
10172  }
10173  if (weed_plant_has_leaf(ptmpl, WEED_LEAF_DEFAULT) && (numvals = weed_leaf_num_elements(ptmpl, WEED_LEAF_DEFAULT)) > idx) {
10174  valss = weed_get_string_array(ptmpl, WEED_LEAF_DEFAULT, &error);
10175  val = lives_strdup(valss[idx]);
10176  for (i = 0; i < numvals; i++) lives_free(valss[i]);
10177  lives_free(valss);
10178  return val;
10179  }
10180  val = weed_get_string_value(ptmpl, WEED_LEAF_NEW_DEFAULT, &error);
10181  val2 = lives_strdup(val);
10182  lives_free(val);
10183  return val2;
10184 }
10185 
10186 
10187 boolean interpolate_param(weed_plant_t *param, void *pchain, weed_timecode_t tc) {
10188  // return FALSE if param has no "value"
10189  // - this can happen during realtime audio processing, if the effect is inited, but no "value" has been set yet
10190  // filter_mutex should be locked for the key during realtime processing
10191 
10192  weed_plant_t *pchange = (weed_plant_t *)pchain, *last_pchange = NULL;
10193  weed_plant_t *wtmpl;
10194  weed_timecode_t tc_diff = 0, tc_diff2;
10195  void **lpc, **npc;
10196  char **valss, **nvalss;
10197  double *last_valuesd, *next_valuesd;
10198  double *valds = NULL, *nvalds, last_valued;
10199  double last_valuedr, last_valuedg, last_valuedb, last_valueda;
10200  int *last_valuesi, *next_valuesi;
10201  int *valis = NULL, *nvalis, last_valuei;
10202  int last_valueir, last_valueig, last_valueib, last_valueia;
10203  int *ign, num_ign = 0;
10204  int ptype, cspace = 0;
10205  int got_npc, num_values, xnum, num_pvals, k, j;
10206 
10207  if (!pchange) return TRUE;
10208  if ((num_values = weed_leaf_num_elements(param, WEED_LEAF_VALUE)) == 0) return FALSE;
10209  if (weed_param_value_irrelevant(param)) return TRUE;
10210 
10211  while (pchange && get_event_timecode(pchange) <= tc) {
10212  last_pchange = pchange;
10213  pchange = (weed_plant_t *)weed_get_voidptr_value(pchange, WEED_LEAF_NEXT_CHANGE, NULL);
10214  }
10215 
10216  wtmpl = weed_param_get_template(param);
10217 
10218  if ((num_pvals = weed_leaf_num_elements((weed_plant_t *)pchain, WEED_LEAF_VALUE)) > num_values)
10219  num_values = num_pvals; // init a multivalued param
10220 
10221  lpc = (void **)lives_calloc(num_values, sizeof(void *));
10222  npc = (void **)lives_calloc(num_values, sizeof(void *));
10223 
10224  if (num_values == 1) {
10225  lpc[0] = last_pchange;
10226  npc[0] = pchange;
10227  } else {
10228  pchange = (weed_plant_t *)pchain;
10229 
10230  while (pchange) {
10231  num_pvals = weed_leaf_num_elements(pchange, WEED_LEAF_VALUE);
10232  if (num_pvals > num_values) num_pvals = num_values;
10233  if (weed_plant_has_leaf(pchange, WEED_LEAF_IGNORE)) {
10234  ign = weed_get_boolean_array_counted(pchange, WEED_LEAF_IGNORE, &num_ign);
10235  } else ign = NULL;
10236  if (get_event_timecode(pchange) <= tc) {
10237  for (j = 0; j < num_pvals; j++) if (!ign || j >= num_ign || ign[j] == WEED_FALSE) lpc[j] = pchange;
10238  } else {
10239  for (j = 0; j < num_pvals; j++) {
10240  if (!npc[j] && (!ign || j >= num_ign || ign[j] == WEED_FALSE)) npc[j] = pchange;
10241  }
10242  got_npc = 0;
10243  for (j = 0; j < num_values; j++) {
10244  if (npc[j]) got_npc++;
10245  }
10246  if (got_npc == num_values) {
10247  lives_freep((void **)&ign);
10248  break;
10249  }
10250  }
10251  pchange = (weed_plant_t *)weed_get_voidptr_value(pchange, WEED_LEAF_NEXT_CHANGE, NULL);
10252  lives_freep((void **)&ign);
10253  }
10254  }
10255 
10256  ptype = weed_paramtmpl_get_type(wtmpl);
10257  switch (ptype) {
10258  case WEED_PARAM_FLOAT:
10259  valds = (double *)lives_malloc(num_values * (sizeof(double)));
10260  break;
10261  case WEED_PARAM_COLOR:
10262  cspace = weed_get_int_value(wtmpl, WEED_LEAF_COLORSPACE, NULL);
10263  switch (cspace) {
10264  case WEED_COLORSPACE_RGB:
10265  if (!(num_values & 3)) return TRUE;
10266  if (weed_leaf_seed_type(wtmpl, WEED_LEAF_DEFAULT) == WEED_SEED_INT) {
10267  valis = (int *)lives_malloc(num_values * sizint);
10268  } else {
10269  valds = (double *)lives_malloc(num_values * (sizeof(double)));
10270  }
10271  break;
10272  case WEED_COLORSPACE_RGBA:
10273  if (num_values & 3) return TRUE;
10274  if (weed_leaf_seed_type(wtmpl, WEED_LEAF_DEFAULT) == WEED_SEED_INT) {
10275  valis = (int *)lives_malloc(num_values * sizint);
10276  } else {
10277  valds = (double *)lives_malloc(num_values * (sizeof(double)));
10278  }
10279  break;
10280  }
10281  break;
10282  case WEED_PARAM_SWITCH:
10283  case WEED_PARAM_INTEGER:
10284  valis = (int *)lives_malloc(num_values * sizint);
10285  break;
10286  }
10287 
10288  for (j = 0; j < num_values; j++) {
10289  // must interpolate - we use linear interpolation
10290  if (!lpc[j] && !npc[j]) continue;
10291  if (lpc[j] && npc[j]) tc_diff = weed_get_int64_value((weed_plant_t *)npc[j], WEED_LEAF_TIMECODE, NULL) -
10292  weed_get_int64_value((weed_plant_t *)lpc[j], WEED_LEAF_TIMECODE, NULL);
10293  switch (ptype) {
10294  case WEED_PARAM_FLOAT:
10295  if (!lpc[j]) {
10296  // before first change
10297  valds[j] = get_default_element_double(param, j, 1, 0);
10298  continue;
10299  }
10300  if (!npc[j]) {
10301  // after last change
10302  xnum = weed_leaf_num_elements((weed_plant_t *)lpc[j], WEED_LEAF_VALUE);
10303  if (xnum > j) {
10304  nvalds = weed_get_double_array((weed_plant_t *)lpc[j], WEED_LEAF_VALUE, NULL);
10305  valds[j] = nvalds[j];
10306  lives_free(nvalds);
10307  } else valds[j] = get_default_element_double(param, j, 1, 0);
10308  continue;
10309  }
10310 
10311  next_valuesd = weed_get_double_array((weed_plant_t *)npc[j], WEED_LEAF_VALUE, NULL);
10312  last_valuesd = weed_get_double_array_counted((weed_plant_t *)lpc[j], WEED_LEAF_VALUE, &xnum);
10313  if (xnum > j) last_valued = last_valuesd[j];
10314  else last_valued = get_default_element_double(param, j, 1, 0);
10315 
10316  valds[j] = last_valued + (double)(next_valuesd[j] - last_valued) / (double)(tc_diff / TICKS_PER_SECOND_DBL) *
10317  (double)((tc - weed_get_int64_value((weed_plant_t *)lpc[j], WEED_LEAF_TIMECODE, NULL)) / TICKS_PER_SECOND_DBL);
10318 
10319  lives_free(last_valuesd);
10320  lives_free(next_valuesd);
10321  break;
10322  case WEED_PARAM_COLOR:
10323  if (num_values != weed_leaf_num_elements(last_pchange, WEED_LEAF_VALUE)) break; // no interp possible
10324 
10325  switch (cspace) {
10326  case WEED_COLORSPACE_RGB:
10327  k = j * 3;
10328  if (weed_leaf_seed_type(wtmpl, WEED_LEAF_DEFAULT) == WEED_SEED_INT) {
10329  if (!lpc[j]) {
10330  // before first change
10331  valis[k] = get_default_element_int(param, j, 3, 0);
10332  valis[k + 1] = get_default_element_int(param, j, 3, 1);
10333  valis[k + 2] = get_default_element_int(param, j, 3, 2);
10334  j += 3;
10335  continue;
10336  }
10337  if (!npc[j]) {
10338  // after last change
10339  xnum = weed_leaf_num_elements((weed_plant_t *)lpc[j], WEED_LEAF_VALUE);
10340  if (xnum > k) {
10341  nvalis = weed_get_int_array((weed_plant_t *)lpc[j], WEED_LEAF_VALUE, NULL);
10342  valis[k] = nvalis[k];
10343  valis[k + 1] = nvalis[k + 1];
10344  valis[k + 2] = nvalis[k + 2];
10345  lives_free(nvalis);
10346  } else {
10347  valis[k] = get_default_element_int(param, j, 3, 0);
10348  valis[k + 1] = get_default_element_int(param, j, 3, 1);
10349  valis[k + 2] = get_default_element_int(param, j, 3, 2);
10350  }
10351  j += 3;
10352  continue;
10353  }
10354 
10355  next_valuesi = weed_get_int_array((weed_plant_t *)npc[j], WEED_LEAF_VALUE, NULL);
10356  last_valuesi = weed_get_int_array_counted((weed_plant_t *)lpc[j], WEED_LEAF_VALUE, &xnum);
10357  if (xnum > k) {
10358  last_valueir = last_valuesi[k];
10359  last_valueig = last_valuesi[k + 1];
10360  last_valueib = last_valuesi[k + 2];
10361  } else {
10362  last_valueir = get_default_element_int(param, j, 3, 0);
10363  last_valueig = get_default_element_int(param, j, 3, 1);
10364  last_valueib = get_default_element_int(param, j, 3, 2);
10365  }
10366 
10367  if (!next_valuesi) continue; // can happen if we recorded a param change
10368 
10369  valis[k] = last_valueir + (next_valuesi[k] - last_valueir) / (tc_diff / TICKS_PER_SECOND_DBL) *
10370  ((tc_diff2 = (tc - weed_get_int64_value((weed_plant_t *)lpc[j],
10371  WEED_LEAF_TIMECODE, NULL))) / TICKS_PER_SECOND_DBL) + .5;
10372  valis[k + 1] = last_valueig + (next_valuesi[k + 1] - last_valueig) / (tc_diff / TICKS_PER_SECOND_DBL) *
10373  (tc_diff2 / TICKS_PER_SECOND_DBL) + .5;
10374  valis[k + 2] = last_valueib + (next_valuesi[k + 2] - last_valueib) / (tc_diff / TICKS_PER_SECOND_DBL) *
10375  (tc_diff2 / TICKS_PER_SECOND_DBL) + .5;
10376 
10377  lives_free(last_valuesi);
10378  lives_free(next_valuesi);
10379  } else {
10380  if (!lpc[j]) {
10381  // before first change
10382  valds[k] = get_default_element_double(param, j, 3, 0);
10383  valds[k + 1] = get_default_element_double(param, j, 3, 1);
10384  valds[k + 2] = get_default_element_double(param, j, 3, 2);
10385  j += 3;
10386  continue;
10387  }
10388  if (!npc[j]) {
10389  // after last change
10390  xnum = weed_leaf_num_elements((weed_plant_t *)lpc[j], WEED_LEAF_VALUE);
10391  if (xnum > k) {
10392  nvalds = weed_get_double_array((weed_plant_t *)lpc[j], WEED_LEAF_VALUE, NULL);
10393  valds[k] = nvalds[k];
10394  valds[k + 1] = nvalds[k + 1];
10395  valds[k + 2] = nvalds[k + 2];
10396  lives_free(nvalds);
10397  } else {
10398  valds[k] = get_default_element_double(param, j, 3, 0);
10399  valds[k + 1] = get_default_element_double(param, j, 3, 1);
10400  valds[k + 2] = get_default_element_double(param, j, 3, 2);
10401  }
10402  j += 3;
10403  continue;
10404  }
10405 
10406  next_valuesd = weed_get_double_array((weed_plant_t *)npc[j], WEED_LEAF_VALUE, NULL);
10407  last_valuesd = weed_get_double_array_counted((weed_plant_t *)lpc[j], WEED_LEAF_VALUE, &xnum);
10408  if (xnum > k) {
10409  last_valuedr = last_valuesd[k];
10410  last_valuedg = last_valuesd[k + 1];
10411  last_valuedb = last_valuesd[k + 2];
10412  } else {
10413  last_valuedr = get_default_element_double(param, j, 3, 0);
10414  last_valuedg = get_default_element_double(param, j, 3, 1);
10415  last_valuedb = get_default_element_double(param, j, 3, 2);
10416  }
10417  valds[k] = last_valuedr + (next_valuesd[k] - last_valuedr) / (tc_diff / TICKS_PER_SECOND_DBL) *
10418  ((tc_diff2 = (tc - weed_get_int64_value((weed_plant_t *)lpc[j],
10419  WEED_LEAF_TIMECODE, NULL))) / TICKS_PER_SECOND_DBL);
10420  valds[k + 1] = last_valuedg + (next_valuesd[k + 1] - last_valuedg) / (tc_diff / TICKS_PER_SECOND_DBL) *
10421  (tc_diff2 / TICKS_PER_SECOND_DBL) + .5;
10422  valds[k + 2] = last_valuedb + (next_valuesd[k + 2] - last_valuedb) / (tc_diff / TICKS_PER_SECOND_DBL) *
10423  (tc_diff2 / TICKS_PER_SECOND_DBL) + .5;
10424 
10425  lives_free(last_valuesd);
10426  lives_free(next_valuesd);
10427  }
10428  j += 3;
10429  break;
10430  case WEED_COLORSPACE_RGBA:
10431  k = j * 4;
10432  if (weed_leaf_seed_type(wtmpl, WEED_LEAF_DEFAULT) == WEED_SEED_INT) {
10433  if (!lpc[j]) {
10434  // before first change
10435  valis[k] = get_default_element_int(param, j, 4, 0);
10436  valis[k + 1] = get_default_element_int(param, j, 4, 1);
10437  valis[k + 2] = get_default_element_int(param, j, 4, 2);
10438  valis[k + 3] = get_default_element_int(param, j, 4, 3);
10439  j += 4;
10440  continue;
10441  }
10442  if (!npc[j]) {
10443  // after last change
10444  xnum = weed_leaf_num_elements((weed_plant_t *)lpc[j], WEED_LEAF_VALUE);
10445  if (xnum > k) {
10446  nvalis = weed_get_int_array((weed_plant_t *)lpc[j], WEED_LEAF_VALUE, NULL);
10447  valis[k] = nvalis[k];
10448  valis[k + 1] = nvalis[k + 1];
10449  valis[k + 2] = nvalis[k + 2];
10450  valis[k + 3] = nvalis[k + 3];
10451  lives_free(nvalis);
10452  } else {
10453  valis[k] = get_default_element_int(param, j, 4, 0);
10454  valis[k + 1] = get_default_element_int(param, j, 4, 1);
10455  valis[k + 2] = get_default_element_int(param, j, 4, 2);
10456  valis[k + 3] = get_default_element_int(param, j, 4, 3);
10457  }
10458  j += 4;
10459  continue;
10460  }
10461 
10462  next_valuesi = weed_get_int_array((weed_plant_t *)npc[j], WEED_LEAF_VALUE, NULL);
10463  last_valuesi = weed_get_int_array_counted((weed_plant_t *)lpc[j], WEED_LEAF_VALUE, &xnum);
10464  if (xnum > k) {
10465  last_valueir = last_valuesi[k];
10466  last_valueig = last_valuesi[k + 1];
10467  last_valueib = last_valuesi[k + 2];
10468  last_valueia = last_valuesi[k + 3];
10469  } else {
10470  last_valueir = get_default_element_int(param, j, 4, 0);
10471  last_valueig = get_default_element_int(param, j, 4, 1);
10472  last_valueib = get_default_element_int(param, j, 4, 2);
10473  last_valueia = get_default_element_int(param, j, 4, 3);
10474  }
10475 
10476  if (!next_valuesi) continue; // can happen if we recorded a param change
10477 
10478  valis[k] = last_valueir + (next_valuesi[k] - last_valueir) / (tc_diff / TICKS_PER_SECOND_DBL) *
10479  ((tc_diff2 = (tc - weed_get_int64_value((weed_plant_t *)lpc[j],
10480  WEED_LEAF_TIMECODE, NULL))) / TICKS_PER_SECOND_DBL) + .5;
10481  valis[k + 1] = last_valueig + (next_valuesi[k + 1] - last_valueig) / (tc_diff / TICKS_PER_SECOND_DBL) *
10482  (tc_diff2 / TICKS_PER_SECOND_DBL) + .5;
10483  valis[k + 2] = last_valueib + (next_valuesi[k + 2] - last_valueib) / (tc_diff / TICKS_PER_SECOND_DBL) *
10484  (tc_diff2 / TICKS_PER_SECOND_DBL) + .5;
10485  valis[k + 3] = last_valueia + (next_valuesi[k + 3] - last_valueia) / (tc_diff / TICKS_PER_SECOND_DBL) *
10486  (tc_diff2 / TICKS_PER_SECOND_DBL) + .5;
10487 
10488  lives_free(last_valuesi);
10489  lives_free(next_valuesi);
10490  } else {
10491  if (!lpc[j]) {
10492  // before first change
10493  valds[k] = get_default_element_double(param, j, 4, 0);
10494  valds[k + 1] = get_default_element_double(param, j, 4, 1);
10495  valds[k + 2] = get_default_element_double(param, j, 4, 2);
10496  valds[k + 3] = get_default_element_double(param, j, 4, 3);
10497  j += 4;
10498  continue;
10499  }
10500  if (!npc[j]) {
10501  // after last change
10502  xnum = weed_leaf_num_elements((weed_plant_t *)lpc[j], WEED_LEAF_VALUE);
10503  if (xnum > k) {
10504  nvalds = weed_get_double_array((weed_plant_t *)lpc[j], WEED_LEAF_VALUE, NULL);
10505  valds[k] = nvalds[k];
10506  valds[k + 1] = nvalds[k + 1];
10507  valds[k + 2] = nvalds[k + 2];
10508  valds[k + 3] = nvalds[k + 3];
10509  lives_free(nvalds);
10510  } else {
10511  valds[k] = get_default_element_double(param, j, 4, 0);
10512  valds[k + 1] = get_default_element_double(param, j, 4, 1);
10513  valds[k + 2] = get_default_element_double(param, j, 4, 2);
10514  valds[k + 3] = get_default_element_double(param, j, 4, 3);
10515  }
10516  j += 4;
10517  continue;
10518  }
10519 
10520  next_valuesd = weed_get_double_array((weed_plant_t *)npc[j], WEED_LEAF_VALUE, NULL);
10521  last_valuesd = weed_get_double_array_counted((weed_plant_t *)lpc[j], WEED_LEAF_VALUE, &xnum);
10522  if (xnum > k) {
10523  last_valuedr = last_valuesd[k];
10524  last_valuedg = last_valuesd[k + 1];
10525  last_valuedb = last_valuesd[k + 2];
10526  last_valueda = last_valuesd[k + 3];
10527  } else {
10528  last_valuedr = get_default_element_double(param, j, 4, 0);
10529  last_valuedg = get_default_element_double(param, j, 4, 1);
10530  last_valuedb = get_default_element_double(param, j, 4, 2);
10531  last_valueda = get_default_element_double(param, j, 4, 3);
10532  }
10533  valds[k] = last_valuedr + (next_valuesd[k] - last_valuedr) / (tc_diff / TICKS_PER_SECOND_DBL) *
10534  ((tc_diff2 = (tc - weed_get_int64_value((weed_plant_t *)lpc[j],
10535  WEED_LEAF_TIMECODE, NULL))) / TICKS_PER_SECOND_DBL);
10536  valds[k + 1] = last_valuedg + (next_valuesd[k + 1] - last_valuedg) / (tc_diff / TICKS_PER_SECOND_DBL) *
10537  (tc_diff2 / TICKS_PER_SECOND_DBL) + .5;
10538  valds[k + 2] = last_valuedb + (next_valuesd[k + 2] - last_valuedb) / (tc_diff / TICKS_PER_SECOND_DBL) *
10539  (tc_diff2 / TICKS_PER_SECOND_DBL) + .5;
10540  valds[k + 3] = last_valueda + (next_valuesd[k + 3] - last_valuedb) / (tc_diff / TICKS_PER_SECOND_DBL) *
10541  (tc_diff2 / TICKS_PER_SECOND_DBL) + .5;
10542 
10543  lives_free(last_valuesd);
10544  lives_free(next_valuesd);
10545  }
10546  j += 4;
10547  break;
10548  } // cspace
10549  break; // color
10550  case WEED_PARAM_INTEGER:
10551  if (weed_param_get_nchoices(param) > 0) {
10552  // no interpolation
10553  if (npc[j] && get_event_timecode((weed_plant_t *)npc[j]) == tc) {
10554  nvalis = weed_get_int_array((weed_plant_t *)npc[j], WEED_LEAF_VALUE, NULL);
10555  valis[j] = nvalis[j];
10556  lives_free(nvalis);
10557  continue;
10558  } else {
10559  // use last_pchange value
10560  xnum = weed_leaf_num_elements((weed_plant_t *)lpc[j], WEED_LEAF_VALUE);
10561  if (xnum > j) {
10562  nvalis = weed_get_int_array((weed_plant_t *)lpc[j], WEED_LEAF_VALUE, NULL);
10563  valis[j] = nvalis[j];
10564  lives_free(nvalis);
10565  } else valis[j] = get_default_element_int(param, j, 1, 0);
10566  continue;
10567  }
10568  } else {
10569  if (!lpc[j]) {
10570  // before first change
10571  valis[j] = get_default_element_int(param, j, 1, 0);
10572  continue;
10573  }
10574  if (!npc[j]) {
10575  // after last change
10576  xnum = weed_leaf_num_elements((weed_plant_t *)lpc[j], WEED_LEAF_VALUE);
10577  if (xnum > j) {
10578  nvalis = weed_get_int_array((weed_plant_t *)lpc[j], WEED_LEAF_VALUE, NULL);
10579  valis[j] = nvalis[j];
10580  lives_free(nvalis);
10581  } else valis[j] = get_default_element_int(param, j, 1, 0);
10582  continue;
10583  }
10584 
10585  next_valuesi = weed_get_int_array((weed_plant_t *)npc[j], WEED_LEAF_VALUE, NULL);
10586  last_valuesi = weed_get_int_array_counted((weed_plant_t *)lpc[j], WEED_LEAF_VALUE, &xnum);
10587  if (xnum > j) last_valuei = last_valuesi[j];
10588  else last_valuei = get_default_element_int(param, j, 1, 0);
10589 
10590  valis[j] = last_valuei + (next_valuesi[j] - last_valuei) / (tc_diff / TICKS_PER_SECOND_DBL) *
10591  ((tc - weed_get_int64_value((weed_plant_t *)lpc[j], WEED_LEAF_TIMECODE, NULL)) / TICKS_PER_SECOND_DBL) + .5;
10592  lives_free(last_valuesi);
10593  lives_free(next_valuesi);
10594  break;
10595  }
10596  case WEED_PARAM_SWITCH:
10597  // no interpolation
10598  if (npc[j] && get_event_timecode((weed_plant_t *)npc[j]) == tc) {
10599  nvalis = weed_get_boolean_array((weed_plant_t *)npc[j], WEED_LEAF_VALUE, NULL);
10600  valis[j] = nvalis[j];
10601  lives_free(nvalis);
10602  continue;
10603  } else {
10604  // use last_pchange value
10605  xnum = weed_leaf_num_elements((weed_plant_t *)lpc[j], WEED_LEAF_VALUE);
10606  if (xnum > j) {
10607  nvalis = weed_get_boolean_array((weed_plant_t *)lpc[j], WEED_LEAF_VALUE, NULL);
10608  valis[j] = nvalis[j];
10609  lives_free(nvalis);
10610  } else valis[j] = get_default_element_bool(param, j);
10611  continue;
10612  }
10613  break;
10614  case WEED_PARAM_TEXT:
10615  // no interpolation
10616  valss = weed_get_string_array(param, WEED_LEAF_VALUE, NULL);
10617  if (npc[j] && get_event_timecode((weed_plant_t *)npc[j]) == tc) {
10618  nvalss = weed_get_string_array((weed_plant_t *)npc[j], WEED_LEAF_VALUE, NULL);
10619  valss[j] = lives_strdup(nvalss[j]);
10620  for (k = 0; k < num_values; k++) lives_free(nvalss[k]);
10621  lives_free(nvalss);
10622  weed_set_string_array(param, WEED_LEAF_VALUE, num_values, valss);
10623  for (k = 0; k < num_values; k++) lives_free(valss[k]);
10624  lives_free(valss);
10625  continue;
10626  } else {
10627  // use last_pchange value
10628  xnum = weed_leaf_num_elements((weed_plant_t *)lpc[j], WEED_LEAF_VALUE);
10629  if (xnum > j) {
10630  nvalss = weed_get_string_array((weed_plant_t *)lpc[j], WEED_LEAF_VALUE, NULL);
10631  valss[j] = lives_strdup(nvalss[j]);
10632  for (k = 0; k < xnum; k++) lives_free(nvalss[k]);
10633  lives_free(nvalss);
10634  } else valss[j] = get_default_element_string(param, j);
10635  weed_set_string_array(param, WEED_LEAF_VALUE, num_values, valss);
10636  for (k = 0; k < num_values; k++) lives_free(valss[k]);
10637  lives_free(valss);
10638  continue;
10639  }
10640  break;
10641  } // parameter ptype
10642  } // j
10643 
10644  switch (ptype) {
10645  case WEED_PARAM_FLOAT:
10646  weed_set_double_array(param, WEED_LEAF_VALUE, num_values, valds);
10647  lives_free(valds);
10648  break;
10649  case WEED_PARAM_COLOR:
10650  switch (cspace) {
10651  case WEED_COLORSPACE_RGB:
10652  if (weed_leaf_seed_type(wtmpl, WEED_LEAF_DEFAULT) == WEED_SEED_INT) {
10653  weed_set_int_array(param, WEED_LEAF_VALUE, num_values, valis);
10654  lives_free(valis);
10655  } else {
10656  weed_set_double_array(param, WEED_LEAF_VALUE, num_values, valds);
10657  lives_free(valds);
10658  }
10659  break;
10660  }
10661  break;
10662  case WEED_PARAM_INTEGER:
10663  weed_set_int_array(param, WEED_LEAF_VALUE, num_values, valis);
10664  lives_free(valis);
10665  break;
10666  case WEED_PARAM_SWITCH:
10667  weed_set_boolean_array(param, WEED_LEAF_VALUE, num_values, valis);
10668  lives_free(valis);
10669  break;
10670  }
10671 
10672  lives_free(npc);
10673  lives_free(lpc);
10674  return TRUE;
10675 }
10676 
10684 boolean interpolate_params(weed_plant_t *inst, void **pchains, weed_timecode_t tc) {
10685  weed_plant_t **in_params;
10686  void *pchain;
10687  int num_params, offset = 0;
10688 
10689  do {
10690  if (!pchains || (in_params = weed_instance_get_in_params(inst, &num_params)) == NULL) continue;
10691  for (int i = offset; i < offset + num_params; i++) {
10692  if (!is_hidden_param(inst, i - offset)) {
10693  pchain = pchains[i];
10694  if (pchain && WEED_PLANT_IS_EVENT((weed_plant_t *)pchain)
10695  && WEED_EVENT_IS_PARAM_CHANGE((weed_plant_t *)pchain)) {
10696  if (weed_param_value_irrelevant(in_params[i - offset])) continue;
10697  if (!interpolate_param(in_params[i - offset], pchain, tc)) {
10698  lives_free(in_params);
10699  return FALSE; // FALSE if param is not ready
10700  // *INDENT-OFF*
10701  }}}}
10702  // *INDENT-ON*
10703  offset += num_params;
10704  lives_free(in_params);
10705  } while ((inst = weed_get_plantptr_value(inst, WEED_LEAF_HOST_NEXT_INSTANCE, NULL)) != NULL);
10706 
10707  return TRUE;
10708 }
10709 
10710 
10713 
10730 char *make_weed_hashname(int filter_idx, boolean fullname, boolean use_extra_authors, char sep, boolean subs) {
10731  weed_plant_t *filter, *plugin_info;
10732 
10733  char plugin_fname[PATH_MAX];
10734  char *plugin_name, *filter_name, *filter_author, *filter_version, *hashname, *filename;
10735  char xsep[2];
10736  boolean use_micro = FALSE;
10737  int version;
10738  int type = 0;
10739 
10740  if (filter_idx < 0 || filter_idx >= num_weed_filters) return lives_strdup("");
10741 
10742  if (!fullname) type += 2;
10743  if (use_extra_authors) type++;
10744 
10745  if (sep != 0) {
10746  fullname = TRUE;
10747  use_extra_authors = FALSE;
10748  xsep[0] = sep;
10749  xsep[1] = 0;
10750  } else {
10751  xsep[0] = xsep[1] = 0;
10752  if (hashnames[filter_idx][type].string)
10753  return lives_strdup(hashnames[filter_idx][type].string);
10754  }
10755 
10756  filter = weed_filters[filter_idx];
10757 
10758  if (sep == 0 && hashnames[filter_idx][type].string) {
10759  return lives_strdup(hashnames[filter_idx][type].string);
10760  }
10761  if (weed_plant_has_leaf(filter, WEED_LEAF_PLUGIN_INFO)) {
10762  plugin_info = weed_get_plantptr_value(filter, WEED_LEAF_PLUGIN_INFO, NULL);
10763  if (weed_plant_has_leaf(plugin_info, WEED_LEAF_PACKAGE_NAME)) {
10764  filename = weed_get_string_value(plugin_info, WEED_LEAF_PACKAGE_NAME, NULL);
10765  } else {
10766  plugin_name = weed_get_string_value(plugin_info, WEED_LEAF_HOST_PLUGIN_NAME, NULL);
10767  lives_snprintf(plugin_fname, PATH_MAX, "%s", plugin_name);
10768  lives_free(plugin_name);
10769  get_filename(plugin_fname, TRUE);
10770  // should we really use utf-8 here ? (needs checking)
10771  filename = F2U8(plugin_fname);
10772  }
10773  } else {
10774  return lives_strdup("");
10775  }
10776  filter_name = weed_filter_get_name(filter);
10777 
10778  if (fullname) {
10779  if (!use_extra_authors || !weed_plant_has_leaf(filter, WEED_LEAF_EXTRA_AUTHORS))
10780  filter_author = weed_get_string_value(filter, WEED_LEAF_AUTHOR, NULL);
10781  else
10782  filter_author = weed_get_string_value(filter, WEED_LEAF_EXTRA_AUTHORS, NULL);
10783 
10784  version = weed_get_int_value(filter, WEED_LEAF_VERSION, NULL);
10785 
10786  if (*xsep) {
10787  hashname = lives_strconcat(filename, xsep, filter_name, xsep, filter_author, NULL);
10788  } else {
10789  if (use_micro) {
10790  int micro_version = weed_get_int_value(filter, WEED_LEAF_MICRO_VERSION, NULL);
10791  filter_version = lives_strdup_printf("%d.%d", version, micro_version);
10792  } else {
10793  filter_version = lives_strdup_printf("%d", version);
10794  }
10795  hashname = lives_strconcat(filename, filter_name, filter_author, filter_version, NULL);
10796  lives_free(filter_version);
10797  }
10798  lives_free(filter_author);
10799  } else {
10800  hashname = lives_strconcat(filename, filter_name, NULL);
10801  }
10802  lives_free(filter_name);
10803  lives_free(filename);
10804 
10805  if (subs) {
10806  char *xhashname = subst(hashname, " ", "_");
10807  if (lives_strcmp(xhashname, hashname)) {
10808  lives_free(hashname);
10809  return xhashname;
10810  }
10811  lives_free(hashname);
10812  lives_free(xhashname);
10813  return NULL;
10814  }
10815 
10816  //g_print("added filter %s\n",hashname);
10817  return hashname;
10818 }
10819 
10820 
10821 static char *fix_hashnames(const char *old) {
10822  const char *alterations[4] = {"frei0rFrei0r: ", "lapdspaLADSPA: ", "libvisuallibvisual: ", NULL};
10823  const char *replacements[4] = {"Frei0r", "LADSPA", "libvisual", NULL};
10824  char *hashname_new = NULL;
10825  int i = 0;
10826  while (alterations[i]) {
10827  if (strstr(old, alterations[i])) {
10828  hashname_new = subst(old, alterations[i], replacements[i]);
10829  break;
10830  }
10831  i++;
10832  }
10833  if (hashname_new) {
10834  return hashname_new;
10835  }
10836  return lives_strdup(old);
10837 }
10838 
10839 
10840 int weed_get_idx_for_hashname(const char *hashname, boolean fullname) {
10841  int32_t numhash;
10842  char *xhashname = fix_hashnames(hashname);
10843  int type = 0;
10844  register int i;
10845 
10846  if (!fullname) type = 2;
10847 
10848  numhash = lives_string_hash(xhashname);
10849 
10850  for (i = 0; i < num_weed_filters; i++) {
10851  if (numhash == hashnames[i][type].hash) {
10852  if (!lives_utf8_strcasecmp(xhashname, hashnames[i][type].string)) {
10853  lives_free(xhashname);
10854  return i;
10855  }
10856  }
10857  }
10858 
10859  type += 4;
10860 
10861  if (hashnames && hashnames[0][type].string) {
10862  for (i = 0; i < num_weed_filters; i++) {
10863  if (numhash == hashnames[i][type].hash) {
10864  if (!lives_utf8_strcasecmp(xhashname, hashnames[i][type].string)) {
10865  lives_free(xhashname);
10866  return i;
10867  // *INDENT-OFF*
10868  }}}}
10869  // *INDENT-ON*
10870 
10871  if (fullname) {
10872  type = 1;
10873  for (i = 0; i < num_weed_filters; i++) {
10874  if (numhash == hashnames[i][type].hash) {
10875  if (!lives_utf8_strcasecmp(xhashname, hashnames[i][type].string)) {
10876  lives_free(xhashname);
10877  return i;
10878  // *INDENT-OFF*
10879  }}}}
10880  // *INDENT-ON*
10881 
10882  lives_free(xhashname);
10883  return -1;
10884 }
10885 
10886 
10887 static boolean check_match(weed_plant_t *filter, const char *pkg, const char *fxname, const char *auth, int version) {
10888  // perform template matching for a filter, see weed_get_indices_from_template()
10889  weed_plant_t *plugin_info;
10890 
10891  char plugin_fname[PATH_MAX];
10892  char *plugin_name, *filter_name, *filter_author;
10893 
10894  int filter_version;
10895 
10896  if (pkg && *pkg) {
10897  char *filename;
10898 
10899  if (weed_plant_has_leaf(filter, WEED_LEAF_PLUGIN_INFO)) {
10900  plugin_info = weed_get_plantptr_value(filter, WEED_LEAF_PLUGIN_INFO, NULL);
10901  if (weed_plant_has_leaf(plugin_info, WEED_LEAF_PACKAGE_NAME)) {
10902  filename = weed_get_string_value(plugin_info, WEED_LEAF_HOST_PLUGIN_NAME, NULL);
10903  } else {
10904  plugin_name = weed_get_string_value(plugin_info, WEED_LEAF_HOST_PLUGIN_NAME, NULL);
10905  lives_snprintf(plugin_fname, PATH_MAX, "%s", plugin_name);
10906  lives_freep((void **)&plugin_name);
10907  get_filename(plugin_fname, TRUE);
10908  filename = F2U8(plugin_fname);
10909  }
10910  } else {
10911  return FALSE;
10912  }
10913 
10914  if (lives_utf8_strcasecmp(pkg, filename)) {
10915  lives_freep((void **)&filename);
10916  return FALSE;
10917  }
10918  lives_freep((void **)&filename);
10919  }
10920 
10921  if (fxname && *fxname) {
10922  filter_name = weed_get_string_value(filter, WEED_LEAF_NAME, NULL);
10923  if (lives_utf8_strcasecmp(fxname, filter_name)) {
10924  lives_freep((void **)&filter_name);
10925  return FALSE;
10926  }
10927  lives_freep((void **)&filter_name);
10928  }
10929 
10930  if (auth && *auth) {
10931  filter_author = weed_get_string_value(filter, WEED_LEAF_AUTHOR, NULL);
10932  if (lives_utf8_strcasecmp(auth, filter_author)) {
10933  lives_freep((void **)&filter_author);
10934  return FALSE;
10935  }
10936  lives_freep((void **)&filter_author);
10937  }
10938 
10939  if (version > 0) {
10940  filter_version = weed_get_int_value(filter, WEED_LEAF_VERSION, NULL);
10941  if (version != filter_version) return FALSE;
10942  }
10943 
10944  return TRUE;
10945 }
10946 
10947 
10958 int *weed_get_indices_from_template(const char *pkg, const char *fxname, const char *auth, int version) {
10959  weed_plant_t *filter;
10960  int *rvals;
10961 
10962  int count = 1, count2 = 0;
10963 
10964  register int i;
10965 
10966  // count number of return values
10967  for (i = 0; i < num_weed_filters; i++) {
10968  filter = weed_filters[i];
10969 
10970  if (check_match(filter, pkg, fxname, auth, version)) {
10971  count++;
10972  }
10973  }
10974 
10975  // allocate storage space
10976  rvals = (int *)lives_malloc(count * sizint);
10977 
10978  // get return values
10979  for (i = 0; count2 < count - 1; i++) {
10980  filter = weed_filters[i];
10981 
10982  if (check_match(filter, pkg, fxname, auth, version)) {
10983  rvals[count2++] = i;
10984  }
10985  }
10986 
10987  // end-of-array indicator
10988  rvals[count2] = -1;
10989 
10990  return rvals;
10991 }
10992 
10993 
10994 int weed_filter_highest_version(const char *pkg, const char *fxname, const char *auth, int *xversion) {
10995  int *allversions = weed_get_indices_from_template(pkg, fxname, auth, 0);
10996  int highestv = 0, version, i = 0, hidx = -1;
10997  char *hash;
10998  while ((version = allversions[i] != -1)) {
10999  if (version > highestv) {
11000  highestv = version;
11001  }
11002  i++;
11003  }
11004 
11005  lives_free(allversions);
11006  if (xversion) *xversion = highestv;
11007  hash = lives_strdup_printf("%s%s%s%d", pkg, fxname, auth, highestv);
11008  hidx = weed_get_idx_for_hashname(hash, TRUE);
11009  lives_free(hash);
11010  return hidx;
11011 }
11012 
11013 
11014 weed_plant_t *get_weed_filter(int idx) {
11015  if (idx > -1 && idx < num_weed_filters) return weed_filters[idx];
11016  return NULL;
11017 }
11018 
11019 
11037 static size_t weed_leaf_serialise(int fd, weed_plant_t *plant, const char *key, boolean write_all, unsigned char **mem) {
11038  void *value = NULL, *valuer = NULL;
11039 
11040  size_t totsize = 0;
11041 
11042  weed_size_t vlen;
11043  weed_size_t keylen = (weed_size_t)lives_strlen(key);
11044 
11045  int st, ne;
11046  int j;
11047 
11048  // write errors will be checked for by the calling function
11049 
11050  if (write_all) {
11051  // write byte length of key, followed by key in utf-8
11052  if (!mem) {
11053  lives_write_le_buffered(fd, &keylen, 4, TRUE);
11054  lives_write_buffered(fd, key, (size_t)keylen, TRUE);
11055  } else {
11056  lives_memcpy(*mem, &keylen, 4);
11057  *mem += 4;
11058  lives_memcpy(*mem, key, (size_t)keylen);
11059  *mem += keylen;
11060  }
11061  totsize += 4 + keylen;
11062  }
11063 
11064  // write seed type and number of elements
11065  st = weed_leaf_seed_type(plant, key);
11066  if (!mem && st == WEED_SEED_PLANTPTR) st = WEED_SEED_VOIDPTR;
11067 
11068  if (!mem) lives_write_le_buffered(fd, &st, 4, TRUE);
11069  else {
11070  lives_memcpy(*mem, &st, 4);
11071  *mem += 4;
11072  }
11073  ne = weed_leaf_num_elements(plant, key);
11074  if (!mem) lives_write_le_buffered(fd, &ne, 4, TRUE);
11075  else {
11076  lives_memcpy(*mem, &ne, 4);
11077  *mem += 4;
11078  }
11079 
11080  totsize += 8;
11081 
11082  // for pixel_data we do special handling
11083  // older LiVES versions wrote the bytesize (4 bytes, then the data
11084  if (!mem && !lives_strcmp(key, WEED_LEAF_PIXEL_DATA)) {
11085  weed_layer_t *layer = (weed_layer_t *)plant;
11086  int nplanes;
11087  int *rowstrides = weed_layer_get_rowstrides(layer, &nplanes);
11088  int pal = weed_layer_get_palette(layer);
11089  int width = weed_layer_get_width(layer);
11090  int height = weed_layer_get_height(layer);
11091  int ival = 0;
11092  boolean contig = FALSE;
11093  size_t padding = 0;
11094  size_t pdsize = 0;
11095 
11096  uint8_t **pixel_data = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11103  lives_write_le_buffered(fd, &ival, 4, TRUE);
11104  ival = 0x44454557;
11105  lives_write_le_buffered(fd, &ival, 4, TRUE);
11106  ival = 1;
11107  lives_write_le_buffered(fd, &ival, 4, TRUE);
11108  lives_write_le_buffered(fd, &nplanes, 4, TRUE);
11109  lives_write_le_buffered(fd, &pal, 4, TRUE);
11110  lives_write_le_buffered(fd, &width, 4, TRUE);
11111  lives_write_le_buffered(fd, &height, 4, TRUE);
11112 
11113  totsize += 28;
11114 
11115  if (weed_get_boolean_value(layer, WEED_LEAF_HOST_PIXEL_DATA_CONTIGUOUS, NULL) == WEED_TRUE) {
11116  contig = TRUE;
11117  }
11118  padding = 0;
11119  for (j = 0; j < nplanes; j++) {
11120  vlen = (weed_size_t)((double)height * weed_palette_get_plane_ratio_vertical(pal, j) * (double)rowstrides[j]);
11121  if (contig && j < nplanes - 1) padding = pixel_data[j + 1] - pixel_data[j] - vlen;
11122  vlen += padding;
11123  lives_write_le_buffered(fd, &rowstrides[j], 4, TRUE);
11124  lives_write_le_buffered(fd, &vlen, 8, TRUE);
11125  pdsize += vlen;
11126  totsize += 12;
11127  }
11128  if (!contig) {
11129  for (j = 0; j < nplanes; j++) {
11130  vlen = (weed_size_t)((double)height * weed_palette_get_plane_ratio_vertical(pal, j) * (double)rowstrides[j]);
11131  lives_write_buffered(fd, (const char *)pixel_data[j], vlen, TRUE);
11132  totsize += vlen;
11133  }
11134  } else {
11135  lives_write_buffered(fd, (const char *)pixel_data[0], pdsize, TRUE);
11136  totsize += pdsize;
11137  }
11138  lives_free(rowstrides);
11139  lives_free(pixel_data);
11140  } else {
11141  // for each element, write the data size followed by the data
11142  for (j = 0; j < ne; j++) {
11143  vlen = (weed_size_t)weed_leaf_element_size(plant, key, j);
11144  if (!mem && vlen == 0) {
11145  // we need to do this because NULL pointers return a size of 0, and older versions of LiVES
11146  // expected to always read 8 bytes for a void *
11147  if (st > 64) vlen = 8;
11148  }
11149  if (st != WEED_SEED_STRING) {
11150  if (vlen == 0) value = NULL;
11151  else {
11152  value = lives_malloc((size_t)vlen);
11153  weed_leaf_get(plant, key, j, value);
11154  }
11155  } else {
11156  // need to create a buffer to receive the string + terminating NULL
11157  value = lives_malloc((size_t)(vlen + 1));
11158  // weed_leaf_get() will assume it's a pointer to a variable of the correct type, and fill in the value
11159  weed_leaf_get(plant, key, j, &value);
11160  }
11161 
11162  if (!mem && weed_leaf_seed_type(plant, key) > 64) {
11163  // save voidptr as 64 bit
11164  valuer = (uint64_t *)lives_malloc(sizeof(uint64_t));
11165 
11166  // 'valuer' is a void * (size 8). and 'value' is void * (of whatever size)
11167  // but we can cast 'value' to a (void **),
11168  // and then we can dereference it and cast that value to a uint64, and store the result in valuer
11169  *((uint64_t *)valuer) = (uint64_t)(*((void **)value));
11170  vlen = sizeof(uint64_t);
11171  } else valuer = value;
11172 
11173  if (!mem) {
11174  lives_write_le_buffered(fd, &vlen, 4, TRUE);
11175  if (st != WEED_SEED_STRING) {
11176  lives_write_le_buffered(fd, valuer, (size_t)vlen, TRUE);
11177  } else lives_write_buffered(fd, (const char *)valuer, (size_t)vlen, TRUE);
11178  } else {
11179  lives_memcpy(*mem, &vlen, 4);
11180  *mem += 4;
11181  if (vlen > 0) {
11182  lives_memcpy(*mem, value, (size_t)vlen);
11183  *mem += vlen;
11184  }
11185  }
11186  if (valuer != value) lives_freep((void **)&valuer);
11187  totsize += 4 + vlen;
11188  lives_freep((void **)&value);
11189  }
11190  }
11191 
11192  // write errors should be checked for by the calling function
11193 
11194  return totsize;
11195 }
11196 
11197 
11198 size_t weed_plant_serialise(int fd, weed_plant_t *plant, unsigned char **mem) {
11199  // serialise an entire plant
11200  //
11201  // write errors should be checked for by the calling function
11202 
11203  // returns the bytesize of the serialised plant
11204 
11205  size_t totsize = 0;
11206  weed_size_t nleaves;
11207  char **proplist = weed_plant_list_leaves(plant, &nleaves);
11208  char *prop;
11209  int i = (int)nleaves;
11210  int pd_needed = 0, pd_reqs = 0;
11211 
11212  if (WEED_IS_LAYER(plant)) pd_needed = 1;
11213 
11214  if (!mem) lives_write_le_buffered(fd, &i, 4, TRUE); // write number of leaves
11215  else {
11216  lives_memcpy(*mem, &i, 4);
11217  *mem += 4;
11218  }
11219 
11220  totsize += 4;
11221 
11222  // serialise the "type" leaf first, so that we know this is a new plant when deserialising
11223  totsize += weed_leaf_serialise(fd, plant, WEED_LEAF_TYPE, TRUE, mem);
11224  lives_free(proplist[0]);
11225 
11226  for (i = 1; (prop = proplist[i]); i++) {
11227  // write each leaf and key
11228  if (pd_needed > 0) {
11229  // write pal, height, rowstrides before pixel_data.
11230  if (!lives_strcmp(prop, WEED_LEAF_PIXEL_DATA)) {
11231  if (pd_reqs > 3) pd_needed = 0;
11232  else {
11233  ++pd_needed;
11234  lives_free(prop);
11235  continue;
11236  }
11237  } else {
11238  if (pd_reqs < 4 && (!strcmp(prop, WEED_LEAF_WIDTH) || !strcmp(prop, WEED_LEAF_HEIGHT)
11239  || !lives_strcmp(prop, WEED_LEAF_CURRENT_PALETTE)
11240  || !strcmp(prop, WEED_LEAF_ROWSTRIDES))) {
11241  if (++pd_reqs == 4 && pd_needed > 1) {
11242  totsize += weed_leaf_serialise(fd, plant, prop, TRUE, mem);
11243  lives_free(prop);
11244  totsize += weed_leaf_serialise(fd, plant, WEED_LEAF_PIXEL_DATA, TRUE, mem);
11245  pd_needed = 0;
11246  continue;
11247  // *INDENT-OFF*
11248  }}}}
11249  // *INDENT-ON*
11250 
11251  totsize += weed_leaf_serialise(fd, plant, prop, TRUE, mem);
11252  lives_free(prop);
11253  }
11254  lives_freep((void **)&proplist);
11255  return totsize;
11256 }
11257 
11258 
11259 static int32_t weed_plant_mutate(weed_plantptr_t plant, int32_t newtype) {
11260  // beware of mutant plants....
11261  int32_t flags = weed_leaf_get_flags(plant, WEED_LEAF_TYPE);
11262  // clear the default flags to allow the "type" leaf to be altered
11263  weed_leaf_set_flags(plant, WEED_LEAF_TYPE, flags & ~(WEED_FLAG_IMMUTABLE));
11264  weed_set_int_value(plant, WEED_LEAF_TYPE, newtype);
11265  // lock the "type" leaf again so it cannot be altered accidentally
11266  weed_leaf_set_flags(plant, WEED_LEAF_TYPE, WEED_FLAG_IMMUTABLE);
11267  return weed_plant_get_type(plant);
11268 }
11269 
11270 
11271 #define REALIGN_MAX (40 * 1024 * 1024)
11272 #define MAX_FRAME_SIZE MILLIONS(100)
11273 #define MAX_FRAME_SIZE64 3019898880
11274 
11275 static int realign_typeleaf(int fd, weed_plant_t *plant) {
11276  uint8_t buff[12];
11277  const char XMATCH[8] = {4, 0, 0, 0, 't', 'y', 'p', 'e'};
11278  int type, nl;
11279  register uint64_t count = REALIGN_MAX;
11280  register int len;
11281 
11282  if (lives_read_buffered(fd, buff, 12, TRUE) < 12) return 0;
11283  for (len = 8; len > 0; len--) {
11284  if (!memcmp((void *)(buff + 12 - len), (void *)(XMATCH + 8 - len), len)) break;
11285  }
11286  if (len == 8) len--;
11287 
11288  while (--count != 0) {
11289  if (buff[11] == XMATCH[len]) {
11290  len++;
11291  if (len == 8) {
11292  nl = (uint32_t)((buff[3] << 24) + (buff[2] << 16) + (buff[1] << 8) + buff[0]);
11293  // skip st, ne, valsize
11294  if (lives_read_buffered(fd, buff, 12, TRUE) < 12) return 0;
11295  if (lives_read_le_buffered(fd, &type, 4, TRUE) < 4) return 0;
11296  weed_plant_mutate(plant, type);
11297  return nl;
11298  }
11299  } else {
11300  if (len > 0) {
11301  len = 0;
11302  continue;
11303  }
11304  }
11305  lives_memmove(buff + 7 - len, buff + 8 - len, len + 4);
11306  if (lives_read_buffered(fd, &buff[11], 1, TRUE) < 1) return 0;
11307  }
11308  return 0;
11309 }
11310 
11335 static int weed_leaf_deserialise(int fd, weed_plant_t *plant, const char *key, unsigned char **mem,
11336  boolean check_key) {
11337  void **values = NULL;
11338 
11339  ssize_t bytes;
11340 
11341  int32_t *ints;
11342  double *dubs;
11343  int64_t *int64s;
11344 
11345  weed_size_t len;
11346  weed_size_t vlen;
11347  //weed_size_t vlen64;
11348  weed_size_t vlen64_tot = 0;
11349 
11350  char *mykey = NULL;
11351  char *msg;
11352 
11353  boolean check_ptrs = FALSE;
11354  int32_t st; // seed type
11355  int32_t ne; // num elems
11356  int32_t type = 0;
11357  int error;
11358 
11359  int i, j;
11360 
11361  if (!key && check_key) {
11362  check_ptrs = TRUE;
11363  check_key = FALSE;
11364  }
11365 
11366  if (!key || check_key) {
11367  // key length
11368  if (!mem) {
11369  if (lives_read_le_buffered(fd, &len, 4, TRUE) < 4) {
11370  return -4;
11371  }
11372  } else {
11373  lives_memcpy(&len, *mem, 4);
11374  *mem += 4;
11375  }
11376 
11377  if (check_key && len != lives_strlen(key)) {
11378  if (prefs->show_dev_opts)
11379  g_print("len for %s was %d\n", key, len);
11380  return -9;
11381  }
11382  if (len > MAX_WEED_STRLEN) return -10;
11383 
11384  mykey = (char *)lives_malloc((size_t)len + 1);
11385  if (!mykey) return -5;
11386 
11387  // read key
11388  if (!mem) {
11389  if (lives_read_buffered(fd, mykey, (size_t)len, TRUE) < len) {
11390  type = -4;
11391  goto done;
11392  }
11393  } else {
11394  lives_memcpy(mykey, *mem, (size_t)len);
11395  *mem += len;
11396  }
11397  lives_memset(mykey + (size_t)len, 0, 1);
11398  //g_print("got key %s\n", mykey);
11399  if (check_key && lives_strcmp(mykey, key)) {
11400  type = -1;
11401  goto done;
11402  }
11403 
11404  if (!key) key = mykey;
11405  else {
11406  lives_freep((void **)&mykey);
11407  }
11408  }
11409 
11410  if (!mem) {
11411  if (lives_read_le_buffered(fd, &st, 4, TRUE) < 4) {
11412  type = -4;
11413  goto done;
11414  }
11415  } else {
11416  lives_memcpy(&st, *mem, 4);
11417  *mem += 4;
11418  }
11419  if (st < 64 && (st != WEED_SEED_INT && st != WEED_SEED_BOOLEAN && st != WEED_SEED_DOUBLE && st != WEED_SEED_INT64 &&
11420  st != WEED_SEED_STRING && st != WEED_SEED_VOIDPTR && st != WEED_SEED_PLANTPTR)) {
11421  if (prefs->show_dev_opts) {
11422  g_printerr("unknown seed type %d %s\n", st, mykey);
11423  break_me("ink. seed type in w.l. deser");
11424  }
11425  type = -6;
11426  goto done;
11427  }
11428 
11429  if (check_key && !strcmp(key, WEED_LEAF_TYPE)) {
11430  // for the WEED_LEAF_TYPE leaf perform some extra checks
11431  if (st != WEED_SEED_INT) {
11432  type = -2;
11433  goto done;
11434  }
11435  }
11436 
11437  if (!mem) {
11438  if (lives_read_le_buffered(fd, &ne, 4, TRUE) < 4) {
11439  type = -4;
11440  goto done;
11441  }
11442  } else {
11443  lives_memcpy(&ne, *mem, 4);
11444  *mem += 4;
11445  }
11446  if (ne > MAX_WEED_ELEMENTS) {
11447  type = -11;
11448  goto done;
11449  }
11450 
11451  if (!lives_strcmp(key, WEED_LEAF_PIXEL_DATA)) {
11452  //g_print("ne was %d\n", ne);
11453  if (ne > 4) {
11454  // max planes is 4 (YUVA4444P)
11455  for (j = ne ; j >= 0; lives_freep((void **)&values[j--]));
11456  values = NULL;
11457  type = -11;
11458  goto done;
11459  }
11460  }
11461  if (ne > 0) {
11462  values = (void **)lives_malloc(ne * sizeof(void *));
11463  if (!values) {
11464  type = -5;
11465  goto done;
11466  }
11467  } else values = NULL;
11468 
11469  if (check_key && !strcmp(key, WEED_LEAF_TYPE)) {
11470  // for the WEED_LEAF_TYPE leaf perform some extra checks
11471  if (ne != 1) {
11472  type = -3;
11473  goto done;
11474  }
11475  }
11476 
11477  // for pixel_data we do special handling
11478  if (!mem && !lives_strcmp(key, WEED_LEAF_PIXEL_DATA)) {
11479  int width, height, pal = 0, *rs = NULL, nplanes = ne;
11480  height = weed_layer_get_height(plant);
11481  if (height > 0) {
11482  width = weed_layer_get_width(plant);
11483  if (width > 0) {
11484  pal = weed_layer_get_palette(plant);
11485  if (pal > 0) {
11486  rs = weed_layer_get_rowstrides(plant, &nplanes); {
11487  if (nplanes != ne) {
11488  LIVES_WARN("Invalid planes in retrieved layer");
11489  // *INDENT-OFF*
11490  }}}}}
11491  // *INDENT-ON*
11492 
11493  for (j = 0; j < ne; j++) {
11494  bytes = lives_read_le_buffered(fd, &vlen, 4, TRUE);
11495  if (bytes < 4) {
11496  for (--j; j >= 0; lives_freep((void **)&values[j--]));
11497  values = NULL;
11498  type = -4;
11499  goto done;
11500  }
11501 
11502  if (j == 0 && vlen == 0) {
11503  int id;
11504  bytes = lives_read_le_buffered(fd, &id, 4, TRUE);
11505  if (id == 0x44454557) {
11506  weed_layer_t *layer = (weed_layer_t *)plant;
11507  int ver;
11508  uint64_t *vlen64 = lives_calloc(nplanes, 8);
11509  //size_t vlen64_tot = 0;
11510  int *rs = lives_calloc(nplanes, sizint);
11511 
11512  bytes = lives_read_le_buffered(fd, &ver, 4, TRUE);
11513  bytes = lives_read_le_buffered(fd, &nplanes, 4, TRUE);
11514  bytes = lives_read_le_buffered(fd, &pal, 4, TRUE);
11515  weed_layer_set_palette(layer, pal);
11516  bytes = lives_read_le_buffered(fd, &width, 4, TRUE);
11517  bytes = lives_read_le_buffered(fd, &height, 4, TRUE);
11518  weed_layer_set_size(layer, width, height);
11519  vlen64 = lives_calloc(nplanes, 8);
11520  rs = lives_calloc(nplanes, 4);
11521  for (int p = 0; p < nplanes; p++) {
11522  bytes = lives_read_le_buffered(fd, &rs[p], 4, TRUE);
11523  bytes = lives_read_le_buffered(fd, &vlen64[p], 8, TRUE);
11524  vlen64_tot += vlen64[p];
11525  }
11526 
11527  if (vlen64_tot > MAX_FRAME_SIZE64) {
11528  values = NULL;
11529  type = -11;
11530  lives_free(rs);
11531  lives_free(vlen64);
11532  goto done;
11533  }
11534 
11535  weed_layer_set_rowstrides(layer, rs, nplanes);
11536 
11537  lives_free(rs);
11538 
11539  values[0] = lives_calloc(ALIGN_CEIL(vlen64_tot + EXTRA_BYTES, 16) / 16, 16);
11540 
11541  if (!values[0]) {
11542  msg = lives_strdup_printf("Could not allocate %d bytes for deserialised frame", vlen);
11543  LIVES_ERROR(msg);
11544  lives_free(msg);
11545  lives_free(vlen64);
11546  weed_set_voidptr_value(plant, WEED_LEAF_PIXEL_DATA, NULL);
11547  type = -5;
11548  goto done;
11549  }
11550 
11551  if (lives_read_buffered(fd, values[0], vlen64_tot, TRUE) != vlen64_tot) {
11553  lives_free(values[0]);
11554  lives_free(values);
11555  values = NULL;
11556  lives_free(vlen64);
11557  type = -4;
11558  goto done;
11559  }
11560  for (i = 1; i < nplanes; i++) {
11561  values[i] = values[i - 1] + vlen64[i];
11562  }
11563  if (nplanes > 1)
11564  weed_set_boolean_value(plant, WEED_LEAF_HOST_PIXEL_DATA_CONTIGUOUS, WEED_TRUE);
11565  lives_free(vlen64);
11566  } else {
11568  values = NULL;
11569  type = -12;
11570  goto done;
11571  }
11572  } else {
11573  //g_print("vlen was %d\n", vlen);
11574  if (vlen > MAX_FRAME_SIZE) {
11575  for (--j; j >= 0; lives_freep((void **)&values[j--]));
11576  values = NULL;
11577  type = -11;
11578  goto done;
11579  }
11580  if (rs && vlen != rs[j] * height * weed_palette_get_plane_ratio_vertical(pal, j)) {
11581  int xrs, xw, xh, psize = pixel_size(pal);
11582  xrs = vlen / height;
11583  xw = xrs / psize;
11584  xh = vlen / xrs;
11585 
11586  LIVES_WARN("invalid frame size recovering layer");
11587  msg = lives_strdup_printf(" for plane %d, size is %d. Should be %d. Will adjust rs to %d, width to %d "
11588  "and height to %d\n", j, vlen, rs[j] * height, xrs, xw, xh);
11589  LIVES_WARN(msg);
11590  lives_free(msg);
11593  rs[j] = xrs;
11594  weed_layer_set_rowstrides(plant, rs, nplanes);
11595  }
11596 
11597  values[j] = lives_calloc(ALIGN_CEIL(vlen + EXTRA_BYTES, 16) / 16, 16);
11598  if (!values[j]) {
11599  msg = lives_strdup_printf("Could not allocate %d bytes for deserialised frame", vlen);
11600  LIVES_ERROR(msg);
11601  lives_free(msg);
11602  for (--j; j >= 0; j--) lives_free(values[j]);
11603  weed_set_voidptr_value(plant, WEED_LEAF_PIXEL_DATA, NULL);
11604  type = -5;
11605  goto done;
11606  }
11607  if (lives_read_buffered(fd, values[j], vlen, TRUE) != vlen) {
11608 
11609 
11610  }
11611  if (j >= nplanes) lives_free(values[j]);
11612  }
11613  }
11614  if (plant) {
11615  weed_set_voidptr_array(plant, WEED_LEAF_PIXEL_DATA, nplanes, values);
11616  while (nplanes != 0) values[--nplanes] = NULL;
11617  }
11618  goto done;
11619  } else {
11620  for (i = 0; i < ne; i++) {
11621  if (!mem) {
11622  bytes = lives_read_le_buffered(fd, &vlen, 4, TRUE);
11623  if (bytes < 4) {
11624  for (--i; i >= 0; lives_freep((void **)&values[i--]));
11625  values = NULL;
11626  type = -4;
11627  goto done;
11628  }
11629  } else {
11630  lives_memcpy(&vlen, *mem, 4);
11631  *mem += 4;
11632  }
11633 
11634  if (st == WEED_SEED_STRING) {
11635  if (vlen > MAX_WEED_STRLEN) {
11636  for (--i; i >= 0; lives_freep((void **)&values[i--]));
11637  values = NULL;
11638  type = -11;
11639  goto done;
11640  }
11641  values[i] = lives_malloc((size_t)vlen + 1);
11642  } else {
11643  if (vlen == 0) {
11644  if (st >= 64) {
11645  values[i] = NULL;
11646  } else {
11647  values = NULL;
11648  type = -4;
11649  goto done;
11650  }
11651  } else values[i] = lives_malloc((size_t)vlen);
11652  }
11653  if (vlen > 0) {
11654  if (!mem) {
11655  if (st != WEED_SEED_STRING)
11656  bytes = lives_read_le_buffered(fd, values[i], vlen, TRUE);
11657  else
11658  bytes = lives_read_buffered(fd, values[i], vlen, TRUE);
11659  if (bytes < vlen) {
11660  for (--i; i >= 0; lives_freep((void **)&values[i--]));
11661  values = NULL;
11662  type = -4;
11663  goto done;
11664  }
11665  } else {
11666  lives_memcpy(values[i], *mem, vlen);
11667  *mem += vlen;
11668  }
11669  }
11670  if (st == WEED_SEED_STRING) {
11671  lives_memset((char *)values[i] + vlen, 0, 1);
11672  }
11673  }
11674  }
11675 
11676  if (!strcmp(key, WEED_LEAF_TYPE)) {
11677  type = *(int32_t *)(values[0]);
11678  if (type < 0) return -8;
11679  }
11680  if (plant) {
11681  if (!values) {
11682  weed_leaf_set(plant, key, st, 0, NULL);
11683  } else {
11684  switch (st) {
11685  case WEED_SEED_INT:
11686  // fallthrough
11687  case WEED_SEED_BOOLEAN:
11688  ints = (int32_t *)lives_malloc(ne * 4);
11689  for (j = 0; j < ne; j++) ints[j] = *(int32_t *)values[j];
11690  if (!strcmp(key, WEED_LEAF_TYPE)) {
11691  if (weed_plant_has_leaf(plant, WEED_LEAF_TYPE)) {
11692  type = weed_get_int_value(plant, WEED_LEAF_TYPE, &error);
11693  if (type == WEED_PLANT_UNKNOWN) {
11694  type = weed_plant_mutate(plant, *ints);
11695  } else {
11696  if (*ints != type) {
11697  msg = lives_strdup_printf("Type mismatch in deserialization: expected %d, got %d\n",
11698  type, *ints);
11699  lives_free(ints);
11700  LIVES_ERROR(msg);
11701  lives_free(msg);
11702  type = -7;
11703  goto done;
11704  }
11705  // type already OK
11706  }
11707  } else {
11708  weed_leaf_set(plant, key, st, ne, (void *)ints);
11709  }
11710  } else {
11711  weed_leaf_set(plant, key, st, ne, (void *)ints);
11712  }
11713  lives_freep((void **)&ints);
11714  break;
11715  case WEED_SEED_DOUBLE:
11716  dubs = (double *)lives_malloc(ne * sizdbl);
11717  for (j = 0; j < ne; j++) dubs[j] = *(double *)values[j];
11718  weed_leaf_set(plant, key, st, ne, (void *)dubs);
11719  lives_freep((void **)&dubs);
11720  break;
11721  case WEED_SEED_INT64:
11722  int64s = (int64_t *)lives_malloc(ne * 8);
11723  for (j = 0; j < ne; j++) int64s[j] = *(int64_t *)values[j];
11724  weed_leaf_set(plant, key, st, ne, (void *)int64s);
11725  lives_freep((void **)&int64s);
11726  break;
11727  case WEED_SEED_STRING:
11728  weed_leaf_set(plant, key, st, ne, (void *)values);
11729  break;
11730  default:
11731  if (plant) {
11732  boolean add_leaf = TRUE;
11733  if (check_ptrs) {
11734  switch (weed_plant_get_type(plant)) {
11735  case WEED_PLANT_LAYER:
11736  if (lives_strcmp(key, WEED_LEAF_PIXEL_DATA)) {
11737  add_leaf = FALSE;
11738  }
11739  break;
11740  default: break;
11741  }
11742  }
11743  if (add_leaf) {
11744  if (!mem && prefs->force64bit) {
11745  // force pointers to uint64_t
11746  uint64_t *voids = (uint64_t *)lives_malloc(ne * sizeof(uint64_t));
11747  for (j = 0; j < ne; j++) voids[j] = (uint64_t)(*(void **)values[j]);
11748  weed_leaf_set(plant, key, WEED_SEED_INT64, ne, (void *)voids);
11749  lives_freep((void **)&voids);
11750  } else {
11751  void **voids = (void **)lives_malloc(ne * sizeof(void *));
11752  for (j = 0; j < ne; j++) voids[j] = values[j];
11753  weed_leaf_set(plant, key, st, ne, (void *)voids);
11754  lives_freep((void **)&voids);
11755  // *INDENT-OFF*
11756  }}}}}}
11757  // *INDENT-ON*
11758 
11759 done:
11760 
11761  if (values) {
11762  for (i = 0; i < ne; i++) lives_freep((void **)&values[i]);
11763  lives_freep((void **)&values);
11764  }
11765  lives_freep((void **)&mykey);
11766  return type;
11767 }
11768 
11769 
11770 weed_plant_t *weed_plant_deserialise(int fd, unsigned char **mem, weed_plant_t *plant) {
11771  // if plant is NULL we create a new one
11772  // deserialise a plant from file fd or mem
11773  int numleaves;
11774  ssize_t bytes;
11775  int err;
11776  int32_t type = WEED_PLANT_UNKNOWN;
11777  boolean newd = FALSE, retried = FALSE;
11778  boolean block_unk_ptrs = FALSE;
11779  int bugfd = -1;
11780 
11781 realign:
11782 
11783  // caller should clear and check THREADVAR(read_failed)
11784  if (!mem) {
11785  if (fd == bugfd) {
11786  if (!plant) {
11787  // create a new plant with type unknown
11788  plant = weed_plant_new(WEED_PLANT_UNKNOWN);
11789  newd = TRUE;
11790  }
11791  numleaves = realign_typeleaf(fd, plant);
11792  if (numleaves == 0 || (type = weed_plant_get_type(plant)) <= 0) {
11793  if (newd) weed_plant_free(plant);
11794  return NULL;
11795  }
11796  bugfd = -1;
11797  } else {
11798  if ((bytes = lives_read_le_buffered(fd, &numleaves, 4, TRUE)) < 4) {
11799  bugfd = -1;
11800  return NULL;
11801  }
11802  }
11803  } else {
11804  lives_memcpy(&numleaves, *mem, 4);
11805  *mem += 4;
11806  }
11807 
11808  if (!plant) {
11809  // create a new plant with type unknown
11810  plant = weed_plant_new(type);
11811  newd = TRUE;
11812  }
11813 
11814  if (type == WEED_PLANT_UNKNOWN) {
11815  if ((type = weed_leaf_deserialise(fd, plant, WEED_LEAF_TYPE, mem, TRUE)) <= 0) {
11816  // check the WEED_LEAF_TYPE leaf first
11817  if (type != -5) { // all except malloc error
11818  char *badfname = filename_from_fd(NULL, fd);
11819  char *msg = lives_strdup_printf("Data mismatch (%d) reading from\n%s", type, badfname ? badfname : "unknown file");
11820  LIVES_ERROR(msg);
11821  lives_free(msg);
11822  bugfd = fd;
11823  }
11824  if (newd) {
11825  weed_plant_free(plant);
11826  plant = NULL;
11827  }
11828  if (bugfd == fd && !retried) {
11829  retried = TRUE;
11830  goto realign;
11831  }
11832  return NULL;
11833  }
11834  }
11835 
11836  numleaves--;
11837 
11840  if (type == WEED_PLANT_LAYER) block_unk_ptrs = TRUE;
11841 
11842  while (numleaves--) {
11843  if ((err = weed_leaf_deserialise(fd, plant, NULL, mem, block_unk_ptrs)) != 0) {
11844  if (err != -5) { // all except malloc error
11845  char *badfname = filename_from_fd(NULL, fd);
11846  char *msg = lives_strdup_printf("Data mismatch (%d) reading from\n%s", err, badfname ? badfname : "unknown file");
11847  LIVES_ERROR(msg);
11848  lives_free(msg);
11849  bugfd = fd;
11850  }
11851  if (newd) {
11852  weed_plant_free(plant);
11853  plant = NULL;
11854  }
11855  if (bugfd == fd && !retried) {
11856  retried = TRUE;
11857  goto realign;
11858  }
11859  return NULL;
11860  }
11861  }
11862 
11863  if ((type = weed_get_plant_type(plant)) == WEED_PLANT_UNKNOWN) {
11864  //g_print("badplant was %d\n", type);
11865  if (newd) weed_plant_free(plant);
11866  return NULL;
11867  }
11868  //g_print("goodplant %p\n", plant);
11869  bugfd = -1;
11870  return plant;
11871 }
11872 
11873 
11874 boolean write_filter_defaults(int fd, int idx) {
11875  // return FALSE on write error
11876  char *hashname;
11877  weed_plant_t *filter = weed_filters[idx], **ptmpls;
11878  int num_params;
11879  int i;
11880  boolean wrote_hashname = FALSE;
11881  size_t vlen;
11882  int ntowrite = 0;
11883 
11884  ptmpls = weed_get_plantptr_array(filter, WEED_LEAF_IN_PARAMETER_TEMPLATES, &num_params);
11885  if (!ptmpls) return TRUE;
11886 
11887  for (i = 0; i < num_params; i++) {
11888  if (weed_plant_has_leaf(ptmpls[i], WEED_LEAF_HOST_DEFAULT)) {
11889  ntowrite++;
11890  }
11891  }
11892 
11893  for (i = 0; i < num_params; i++) {
11894  if (weed_plant_has_leaf(ptmpls[i], WEED_LEAF_HOST_DEFAULT)) {
11895  if (!wrote_hashname) {
11896  hashname = make_weed_hashname(idx, TRUE, FALSE, 0, FALSE);
11897  vlen = lives_strlen(hashname);
11898 
11899  lives_write_le_buffered(fd, &vlen, 4, TRUE);
11900  lives_write_buffered(fd, hashname, vlen, TRUE);
11901  lives_freep((void **)&hashname);
11902  wrote_hashname = TRUE;
11903  lives_write_le_buffered(fd, &ntowrite, 4, TRUE);
11904  }
11905  lives_write_le_buffered(fd, &i, 4, TRUE);
11906  weed_leaf_serialise(fd, ptmpls[i], WEED_LEAF_HOST_DEFAULT, FALSE, NULL);
11907  }
11908  }
11909  if (wrote_hashname) lives_write_buffered(fd, "\n", 1, TRUE);
11910 
11911  lives_freep((void **)&ptmpls);
11912 
11913  if (THREADVAR(write_failed) == fd + 1) {
11914  THREADVAR(write_failed) = 0;
11915  return FALSE;
11916  }
11917  return TRUE;
11918 }
11919 
11920 
11921 boolean read_filter_defaults(int fd) {
11922  weed_plant_t *filter, **ptmpls;
11923  void *buf = NULL;
11924 
11925  size_t vlen;
11926 
11927  int vleni, vlenz;
11928  int i, pnum;
11929  int num_params = 0;
11930  int ntoread;
11931  boolean read_failed = FALSE;
11932  boolean found = FALSE;
11933 
11934  char *tmp;
11935 
11936 
11937  while (1) {
11938  if (lives_read_le_buffered(fd, &vleni, 4, TRUE) < 4) {
11939  break;
11940  }
11941 
11942  // some files erroneously used a vlen of 8
11943  if (lives_read_le_buffered(fd, &vlenz, 4, TRUE) < 4) {
11944  break;
11945  }
11946 
11947  vlen = (size_t)vleni;
11948 
11949  if (capable->byte_order == LIVES_BIG_ENDIAN && prefs->bigendbug) {
11950  if (vleni == 0 && vlenz != 0) vlen = (size_t)vlenz;
11951  } else {
11952  if (vlenz != 0) {
11953  if (lives_lseek_buffered_rdonly(fd, -4) < 0) return FALSE;
11954  }
11955  }
11956 
11957  if (vlen > MAX_WEED_STRLEN) return FALSE;
11958 
11959  buf = lives_malloc(vlen + 1);
11960  if (lives_read_buffered(fd, buf, vlen, TRUE) < vlen) break;
11961 
11962  lives_memset((char *)buf + vlen, 0, 1);
11963  for (i = 0; i < num_weed_filters; i++) {
11964  if (!lives_strcmp((char *)buf, (tmp = make_weed_hashname(i, TRUE, FALSE, 0, FALSE)))) {
11965  lives_free(tmp);
11966  found = TRUE;
11967  break;
11968  }
11969  lives_free(tmp);
11970  }
11971  if (!found) {
11972  for (i = 0; i < num_weed_filters; i++) {
11973  if (!lives_strcmp((char *)buf, (tmp = make_weed_hashname(i, TRUE, TRUE, 0, FALSE)))) {
11974  lives_free(tmp);
11975  break;
11976  }
11977  lives_free(tmp);
11978  }
11979  }
11980 
11981  lives_freep((void **)&buf);
11982 
11983  ptmpls = NULL;
11984 
11985  if (i < num_weed_filters) {
11986  filter = weed_filters[i];
11987  ptmpls = weed_get_plantptr_array_counted(filter, WEED_LEAF_IN_PARAMETER_TEMPLATES, &num_params);
11988  } else num_params = 0;
11989 
11990  if (lives_read_le_buffered(fd, &ntoread, 4, TRUE) < 4) {
11991  if (ptmpls) lives_free(ptmpls);
11992  break;
11993  }
11994 
11995  for (i = 0; i < ntoread; i++) {
11996  if (lives_read_le_buffered(fd, &pnum, 4, TRUE) < 4) {
11997  if (ptmpls) lives_free(ptmpls);
11998  break;
11999  }
12000 
12001  if (pnum < num_params) {
12002  if (weed_leaf_deserialise(fd, ptmpls[pnum], WEED_LEAF_HOST_DEFAULT, NULL, FALSE) < 0) {
12003  }
12004  } else {
12005  weed_plant_t *dummyplant = weed_plant_new(WEED_PLANT_UNKNOWN);
12006  if (weed_leaf_deserialise(fd, dummyplant, WEED_LEAF_HOST_DEFAULT, NULL, FALSE) < 0) {
12007  weed_plant_free(dummyplant);
12008  read_failed = TRUE;
12009  break;
12010  }
12011  }
12012  if (ptmpls && weed_paramtmpl_value_irrelevant(ptmpls[pnum]))
12013  weed_leaf_delete(ptmpls[pnum], WEED_LEAF_HOST_DEFAULT);
12014  }
12015  if (read_failed) {
12016  if (ptmpls) lives_free(ptmpls);
12017  break;
12018  }
12019 
12020  buf = lives_malloc(strlen("\n"));
12021  lives_read_buffered(fd, buf, strlen("\n"), TRUE);
12022  lives_free(buf);
12023  if (ptmpls) lives_free(ptmpls);
12024  if (THREADVAR(read_failed) == fd + 1) {
12025  break;
12026  }
12027  }
12028 
12029  if (THREADVAR(read_failed) == fd + 1) {
12030  THREADVAR(read_failed) = 0;
12031  return FALSE;
12032  }
12033 
12034  return TRUE;
12035 }
12036 
12037 
12038 boolean write_generator_sizes(int fd, int idx) {
12039  // TODO - handle optional channels
12040  // return FALSE on write error
12041  char *hashname;
12042  weed_plant_t *filter, **ctmpls;
12043  int num_channels;
12044  int i;
12045  size_t vlen;
12046  boolean wrote_hashname = FALSE;
12047 
12048  num_channels = enabled_in_channels(weed_filters[idx], FALSE);
12049  if (num_channels != 0) return TRUE;
12050 
12051  filter = weed_filters[idx];
12052 
12053  ctmpls = weed_get_plantptr_array_counted(filter, WEED_LEAF_OUT_CHANNEL_TEMPLATES, &num_channels);
12054  if (num_channels == 0) return TRUE;
12055 
12056  for (i = 0; i < num_channels; i++) {
12057  if (weed_plant_has_leaf(ctmpls[i], WEED_LEAF_HOST_WIDTH) || weed_plant_has_leaf(ctmpls[i], WEED_LEAF_HOST_HEIGHT) ||
12058  (!wrote_hashname && weed_plant_has_leaf(filter, WEED_LEAF_HOST_FPS))) {
12059  if (!wrote_hashname) {
12060  hashname = make_weed_hashname(idx, TRUE, FALSE, 0, FALSE);
12061  vlen = lives_strlen(hashname);
12062  lives_write_le_buffered(fd, &vlen, 4, TRUE);
12063  lives_write_buffered(fd, hashname, vlen, TRUE);
12064  lives_free(hashname);
12065  wrote_hashname = TRUE;
12066  if (weed_plant_has_leaf(filter, WEED_LEAF_HOST_FPS)) {
12067  int j = -1;
12068  lives_write_le_buffered(fd, &j, 4, TRUE);
12069  weed_leaf_serialise(fd, filter, WEED_LEAF_HOST_FPS, FALSE, NULL);
12070  }
12071  }
12072 
12073  lives_write_le_buffered(fd, &i, 4, TRUE);
12074  if (weed_plant_has_leaf(ctmpls[i], WEED_LEAF_HOST_WIDTH)) weed_leaf_serialise(fd, ctmpls[i],
12075  WEED_LEAF_HOST_WIDTH, FALSE, NULL);
12076  else weed_leaf_serialise(fd, ctmpls[i], WEED_LEAF_WIDTH, FALSE, NULL);
12077  if (weed_plant_has_leaf(ctmpls[i], WEED_LEAF_HOST_HEIGHT)) weed_leaf_serialise(fd, ctmpls[i],
12078  WEED_LEAF_HOST_HEIGHT, FALSE, NULL);
12079  else weed_leaf_serialise(fd, ctmpls[i], WEED_LEAF_HEIGHT, FALSE, NULL);
12080  }
12081  }
12082  if (wrote_hashname) lives_write_buffered(fd, "\n", 1, TRUE);
12083 
12084  if (THREADVAR(write_failed) == fd + 1) {
12085  THREADVAR(write_failed) = 0;
12086  return FALSE;
12087  }
12088  return TRUE;
12089 }
12090 
12091 
12092 boolean read_generator_sizes(int fd) {
12093  weed_plant_t *filter, **ctmpls;
12094  ssize_t bytes;
12095  size_t vlen;
12096 
12097  char *buf;
12098  char *tmp;
12099 
12100  boolean found = FALSE;
12101  boolean ready;
12102 
12103  int vleni, vlenz;
12104  int i, num_chans = 0, cnum;
12105 
12106  while (1) {
12107  if (lives_read_le_buffered(fd, &vleni, 4, TRUE) < 4) {
12108  break;
12109  }
12110 
12111  // some files erroneously used a vlen of 8
12112  if (lives_read_le_buffered(fd, &vlenz, 4, TRUE) < 4) {
12113  break;
12114  }
12115 
12116  vlen = (size_t)vleni;
12117 
12118  if (capable->byte_order == LIVES_BIG_ENDIAN && prefs->bigendbug) {
12119  if (vleni == 0 && vlenz != 0) vlen = (size_t)vlenz;
12120  } else {
12121  if (vlenz != 0) {
12122  if (lives_lseek_buffered_rdonly(fd, -4) < 0) {
12123  return FALSE;
12124  }
12125  }
12126  }
12127 
12128  if (vlen > MAX_WEED_STRLEN) {
12129  return FALSE;
12130  }
12131 
12132  buf = (char *)lives_malloc(vlen + 1);
12133 
12134  bytes = lives_read_buffered(fd, buf, vlen, TRUE);
12135  if (bytes < vlen) {
12136  break;
12137  }
12138  lives_memset((char *)buf + vlen, 0, 1);
12139 
12140  for (i = 0; i < num_weed_filters; i++) {
12141  if (!lives_strcmp(buf, (tmp = make_weed_hashname(i, TRUE, FALSE, 0, FALSE)))) {
12142  lives_free(tmp);
12143  found = TRUE;
12144  break;
12145  }
12146  lives_free(tmp);
12147  }
12148  if (!found) {
12149  for (i = 0; i < num_weed_filters; i++) {
12150  if (!lives_strcmp(buf, (tmp = make_weed_hashname(i, TRUE, TRUE, 0, FALSE)))) {
12151  lives_free(tmp);
12152  break;
12153  }
12154  lives_free(tmp);
12155  }
12156  }
12157 
12158  lives_free(buf);
12159  ctmpls = NULL;
12160 
12161  ready = FALSE;
12162  filter = NULL;
12163  if (i < num_weed_filters) {
12164  filter = weed_filters[i];
12165  ctmpls = weed_get_plantptr_array_counted(filter, WEED_LEAF_OUT_CHANNEL_TEMPLATES, &num_chans);
12166  }
12167  while (!ready) {
12168  ready = TRUE;
12169  bytes = lives_read_le_buffered(fd, &cnum, 4, TRUE);
12170  if (bytes < 4) {
12171  break;
12172  }
12173  if (!filter) {
12174  // we still need to read past the values even if we didn't find the filter
12175  if (cnum == -1) {
12176  if (weed_leaf_deserialise(fd, NULL, WEED_LEAF_HOST_FPS, NULL, FALSE) < 0) break;
12177  ready = FALSE;
12178  } else {
12179  if (weed_leaf_deserialise(fd, NULL, WEED_LEAF_HOST_WIDTH, NULL, FALSE) < 0) break;
12180  if (weed_leaf_deserialise(fd, NULL, WEED_LEAF_HOST_HEIGHT, NULL, FALSE) < 0) break;
12181  }
12182  } else {
12183  if (cnum < num_chans && cnum >= 0) {
12184  if (weed_leaf_deserialise(fd, ctmpls[cnum], WEED_LEAF_HOST_WIDTH, NULL, FALSE) < 0) break;
12185  if (weed_leaf_deserialise(fd, ctmpls[cnum], WEED_LEAF_HOST_HEIGHT, NULL, FALSE) < 0) break;
12186  if (weed_get_int_value(ctmpls[cnum], WEED_LEAF_HOST_WIDTH, NULL) == 0)
12187  weed_set_int_value(ctmpls[cnum], WEED_LEAF_HOST_WIDTH, DEF_GEN_WIDTH);
12188  if (weed_get_int_value(ctmpls[cnum], WEED_LEAF_HOST_HEIGHT, NULL) == 0)
12189  weed_set_int_value(ctmpls[cnum], WEED_LEAF_HOST_HEIGHT, DEF_GEN_HEIGHT);
12190  } else if (cnum == -1) {
12191  if (weed_leaf_deserialise(fd, filter, WEED_LEAF_HOST_FPS, NULL, FALSE) < 0) break;
12192  ready = FALSE;
12193  }
12194  }
12195  }
12196 
12197  lives_freep((void **)&ctmpls);
12198 
12199  if (THREADVAR(read_failed) == fd + 1) {
12200  break;
12201  }
12202  buf = (char *)lives_malloc(strlen("\n"));
12203  lives_read_buffered(fd, buf, strlen("\n"), TRUE);
12204  lives_free(buf);
12205 
12206  if (THREADVAR(read_failed) == fd + 1) {
12207  break;
12208  }
12209  }
12210 
12211  if (THREADVAR(read_failed) == fd + 1) {
12212  THREADVAR(read_failed) = 0;
12213  return FALSE;
12214  }
12215  return TRUE;
12216 }
12217 
12218 
12220  if (!mainw->clip_index) {
12221  mainw->clip_index = (int *)lives_malloc(sizint);
12222  mainw->clip_index[0] = -1;
12223  }
12224  if (!mainw->frame_index) {
12225  mainw->frame_index = (int64_t *)lives_malloc(8);
12226  mainw->frame_index[0] = 0;
12227  }
12228 }
12229 
12230 // key/mode parameter defaults
12231 
12232 boolean read_key_defaults(int fd, int nparams, int key, int mode, int ver) {
12233  // read default param values for key/mode from file
12234 
12235  // if key < 0 we just read past the bytes in the file
12236 
12237  // return FALSE on EOF
12238 
12239  int i, j, nvals, nigns;
12240  int idx;
12241  ssize_t bytes;
12242  weed_plant_t *filter;
12243  int xnparams = 0, maxparams = nparams;
12244  weed_plant_t **key_defs;
12245  weed_timecode_t tc;
12246 
12247  int ret = 0;
12248 
12249  if (key >= 0) {
12250  idx = key_to_fx[key][mode];
12251  filter = weed_filters[idx];
12252  maxparams = xnparams = num_in_params(filter, FALSE, FALSE);
12253  }
12254 
12255  if (xnparams > maxparams) maxparams = xnparams;
12256  if (!maxparams) return FALSE;
12257 
12258  key_defs = (weed_plant_t **)lives_calloc(maxparams, sizeof(weed_plant_t *));
12259 
12260  for (i = 0; i < nparams; i++) {
12261  if (key < 0 || i < xnparams) {
12262  key_defs[i] = weed_plant_new(WEED_PLANT_PARAMETER);
12263  }
12264  if (ver > 1) {
12265  // for future - read nvals
12266  bytes = lives_read_le_buffered(fd, &nvals, 4, TRUE);
12267  if (bytes < 4) {
12268  goto err123;
12269  }
12270  if (!nvals) return TRUE;
12271  bytes = lives_read_le_buffered(fd, &tc, 8, TRUE);
12272  if (bytes < sizeof(weed_timecode_t)) {
12273  goto err123;
12274  }
12275  // read n ints (booleans)
12276  bytes = lives_read_le_buffered(fd, &nigns, 4, TRUE);
12277  if (bytes < 4) {
12278  goto err123;
12279  }
12280  if (nigns > 0) {
12281  int *igns = (int *)lives_malloc(nigns * 4);
12282  for (j = 0; j < nigns; j++) {
12283  bytes = lives_read_le_buffered(fd, &igns[j], 4, TRUE);
12284  if (bytes < 4) {
12285  goto err123;
12286  }
12287  }
12288  lives_free(igns);
12289  }
12290  }
12291 
12292  if (weed_leaf_deserialise(fd, key_defs[i], WEED_LEAF_VALUE, NULL, FALSE) < 0) goto err123;
12293 
12294  if (ver > 1) {
12295  for (j = 0; j < nvals; j++) {
12296  // for future - read timecodes
12297  weed_plant_t *plant = weed_plant_new(WEED_PLANT_PARAMETER);
12298  bytes = lives_read_le_buffered(fd, &tc, 8, TRUE);
12299  if (bytes < 8) {
12300  goto err123;
12301  }
12302  // read n ints (booleans)
12303  bytes = lives_read_le_buffered(fd, &nigns, 4, TRUE);
12304  if (bytes < 4) {
12305  goto err123;
12306  }
12307  if (nigns > 0) {
12308  int *igns = (int *)lives_malloc(nigns * 4);
12309  for (j = 0; j < nigns; j++) {
12310  bytes = lives_read_le_buffered(fd, &igns[j], 4, TRUE);
12311  if (bytes < 4) {
12312  goto err123;
12313  }
12314  }
12315  // discard excess values
12316  ret = weed_leaf_deserialise(fd, plant, WEED_LEAF_VALUE, NULL, FALSE);
12317  weed_plant_free(plant);
12318  if (ret < 0) goto err123;
12319  // *INDENT-OFF*
12320  }}}}
12321  // *INDENT-ON*
12322 
12323  if (key >= 0) key_defaults[key][mode] = key_defs;
12324 
12325 err123:
12326  if (key < 0) {
12327  for (i = 0; i < nparams; i++) {
12328  if (key_defs[i]) weed_plant_free(key_defs[i]);
12329  }
12330  lives_free(key_defs);
12331  }
12332 
12333  if (ret < 0 || THREADVAR(read_failed) == fd + 1) {
12334  THREADVAR(read_failed) = 0;
12335  return FALSE;
12336  }
12337 
12338  return TRUE;
12339 }
12340 
12341 
12342 void apply_key_defaults(weed_plant_t *inst, int key, int mode) {
12343  // call with filter_mutex locked
12344  // apply key/mode param defaults to a filter instance
12345  weed_plant_t **defs, **params;
12346  weed_plant_t *filter = weed_instance_get_filter(inst, TRUE);
12347  int nparams = num_in_params(filter, FALSE, FALSE);
12348  register int i, j = 0;
12349 
12350  if (nparams == 0) return;
12351 
12352  defs = key_defaults[key][mode];
12353  if (!defs) return;
12354 
12355  do {
12356  params = weed_get_plantptr_array(inst, WEED_LEAF_IN_PARAMETERS, NULL);
12357  nparams = num_in_params(inst, FALSE, FALSE);
12358 
12359  for (i = 0; i < nparams; i++) {
12360  if (!is_hidden_param(inst, i))
12361  weed_leaf_dup(params[i], defs[j], WEED_LEAF_VALUE);
12362  j++;
12363  }
12364  lives_free(params);
12365  } while (weed_get_plantptr_value(inst, WEED_LEAF_HOST_NEXT_INSTANCE, NULL));
12366 }
12367 
12368 
12369 void write_key_defaults(int fd, int key, int mode) {
12370  // save key/mode param defaults to file
12371  // caller should check for write errors
12372 
12373  weed_plant_t *filter;
12374  weed_plant_t **key_defs;
12375  int nparams = 0;
12376 
12377  if ((key_defs = key_defaults[key][mode]) == NULL) {
12378  lives_write_le_buffered(fd, &nparams, 4, TRUE);
12379  return;
12380  }
12381 
12382  filter = weed_filters[key_to_fx[key][mode]];
12383  nparams = num_in_params(filter, FALSE, FALSE);
12384  lives_write_le_buffered(fd, &nparams, 4, TRUE);
12385 
12386  for (int i = 0; i < nparams; i++) {
12387  if (THREADVAR(write_failed) == fd + 1) {
12388  THREADVAR(write_failed) = 0;
12389  break;
12390  }
12391  weed_leaf_serialise(fd, key_defs[i], WEED_LEAF_VALUE, FALSE, NULL);
12392  }
12393 }
12394 
12395 
12396 void free_key_defaults(int key, int mode) {
12397  // free key/mode param defaults
12398  weed_plant_t *filter;
12399  weed_plant_t **key_defs;
12400  int nparams;
12401 
12402  if (key >= FX_KEYS_MAX_VIRTUAL || mode >= prefs->max_modes_per_key) return;
12403 
12404  key_defs = key_defaults[key][mode];
12405 
12406  if (!key_defs) return;
12407 
12408  filter = weed_filters[key_to_fx[key][mode]];
12409  nparams = num_in_params(filter, FALSE, FALSE);
12410 
12411  for (int i = 0; i < nparams; i++) if (key_defs[i]) weed_plant_free(key_defs[i]);
12412 
12413  lives_free(key_defaults[key][mode]);
12414  key_defaults[key][mode] = NULL;
12415 }
12416 
12417 
12418 void set_key_defaults(weed_plant_t *inst, int key, int mode) {
12419  // copy key/mode param defaults from an instance
12420  weed_plant_t **key_defs, **params;
12421  weed_plant_t *filter = weed_instance_get_filter(inst, TRUE);
12422  int i = -1;
12423  int nparams, poffset = 0;
12424 
12425  if (key_defaults[key][mode]) free_key_defaults(key, mode);
12426 
12427  nparams = num_in_params(filter, FALSE, FALSE);
12428  if (nparams == 0) return;
12429 
12430  key_defs = (weed_plant_t **)lives_malloc(nparams * sizeof(weed_plant_t *));
12431 
12432  do {
12433  nparams = num_in_params(inst, FALSE, FALSE);
12434  if (nparams > 0) {
12435  int last = nparams + poffset - 1;
12436  params = weed_get_plantptr_array(inst, WEED_LEAF_IN_PARAMETERS, NULL);
12437  while (i < last) {
12438  key_defs[++i] = weed_plant_new(WEED_PLANT_PARAMETER);
12439  weed_leaf_dup(key_defs[i], params[i - poffset], WEED_LEAF_VALUE);
12440  }
12441  lives_free(params);
12442  poffset = ++last;
12443  }
12444  } while ((inst = weed_get_plantptr_value(inst, WEED_LEAF_HOST_NEXT_INSTANCE, NULL)));
12445 
12446  key_defaults[key][mode] = key_defs;
12447 }
12448 
12449 
12450 boolean has_key_defaults(void) {
12451  // check if any key/mode has default parameters set
12452  for (int i = 0; i < prefs->rte_keys_virtual; i++) {
12453  for (int j = 0; j < prefs->max_modes_per_key; j++) {
12454  if (key_defaults[i][j]) return TRUE;
12455  }
12456  }
12457  return FALSE;
12458 }
12459 
12460 
weed_inst_out_param
weed_plant_t * weed_inst_out_param(weed_plant_t *inst, int param_num)
Definition: effects-weed.c:8771
weed_channel_get_naudchans
WEED_GLOBAL_INLINE int weed_channel_get_naudchans(weed_plant_t *channel)
Definition: weed-effects-utils.c:498
_vid_playback_plugin::palette
int palette
width in pixels, but converted to macropixels for the player
Definition: plugins.h:181
lives_freep
boolean lives_freep(void **ptr)
Definition: utils.c:1411
LIVES_GLOBAL_INLINE
#define LIVES_GLOBAL_INLINE
Definition: main.h:239
mainwindow::jackd
void * jackd
jack audio player / transport
Definition: mainwindow.h:1453
weed-effects-utils.h
mainwindow::blend_factor
double blend_factor
keyboard control parameter
Definition: mainwindow.h:872
append_filter_deinit_event
weed_plant_t * append_filter_deinit_event(weed_plant_t *event_list, weed_timecode_t tc, void *init_event, void **pchain)
Definition: events.c:2882
pconx_chain_data_omc
int pconx_chain_data_omc(weed_plant_t *inst, int okey, int omode)
Definition: effects-data.c:1323
mainwindow::instance_ref_mutex
pthread_mutex_t instance_ref_mutex
refcounting for instances
Definition: mainwindow.h:1504
MAX_CHAN_HEIGHT
#define MAX_CHAN_HEIGHT
Definition: effects-weed.c:1029
mainwindow::rte_textparm
weed_plant_t * rte_textparm
send keyboard input to this paramter (usually NULL)
Definition: mainwindow.h:1589
weed_apply_audio_effects
void weed_apply_audio_effects(weed_plant_t *filter_map, weed_layer_t **layers, int nbtracks, int nchans, int64_t nsamps, double arate, weed_timecode_t tc, double *vis)
Definition: effects-weed.c:3709
mainwindow::gen_started_play
boolean gen_started_play
Definition: mainwindow.h:1694
LIVES_FX_CAT_AUDIO_MIXER
@ LIVES_FX_CAT_AUDIO_MIXER
Definition: effects.h:29
mainwindow::startticks
volatile ticks_t startticks
effective ticks when current frame was (should have been) displayed
Definition: mainwindow.h:997
LIVES_IS_PLAYING
#define LIVES_IS_PLAYING
Definition: main.h:840
LIVES_LOCAL_INLINE
#define LIVES_LOCAL_INLINE
Definition: main.h:246
KEYSCALE
#define KEYSCALE
Definition: effects-weed.c:9036
get_plugin_list
LiVESList * get_plugin_list(const char *plugin_type, boolean allow_nonex, const char *plugdir, const char *filter_ext)
Definition: plugins.c:115
lives_signal_connect
ulong lives_signal_connect(LiVESWidget *, const char *signal_name, ulong funcptr, livespointer data)
WEED_LEAF_INIT_EVENTS
#define WEED_LEAF_INIT_EVENTS
Definition: events.h:55
_weed_instance_unref
LIVES_GLOBAL_INLINE int _weed_instance_unref(weed_plant_t *inst)
Definition: effects-weed.c:6158
get_player_size
void get_player_size(int *opwidth, int *opheight)
Definition: main.c:7720
rte_window.h
mainwindow::active_track_list
int active_track_list[MAX_TRACKS]
Definition: mainwindow.h:1689
FX_KEYS_PHYSICAL
#define FX_KEYS_PHYSICAL
FX keys, 1 - 9 normally.
Definition: mainwindow.h:198
WEED_LEAF_FREED_PLANTS
#define WEED_LEAF_FREED_PLANTS
Definition: effects-weed.h:86
weed_filter_is_resizer
WEED_GLOBAL_INLINE int weed_filter_is_resizer(weed_plant_t *filter)
Definition: weed-effects-utils.c:822
lives_thread_create
int lives_thread_create(lives_thread_t *thread, lives_thread_attr_t attr, lives_funcptr_t func, void *arg)
Definition: machinestate.c:2318
weed_param_has_value_perchannel
WEED_GLOBAL_INLINE int weed_param_has_value_perchannel(weed_plant_t *param)
Definition: weed-effects-utils.c:538
WEED_LEAF_HOST_DISABLED
#define WEED_LEAF_HOST_DISABLED
Definition: effects-weed.h:70
WEED_PLANT_IS_PARAMETER
#define WEED_PLANT_IS_PARAMETER(plant)
Definition: weed-effects-utils.h:46
weed_plant_deserialise
weed_plant_t * weed_plant_deserialise(int fd, unsigned char **mem, weed_plant_t *plant)
Definition: effects-weed.c:11770
lives_free
#define lives_free
Definition: machinestate.h:52
mt_get_pchain
void ** mt_get_pchain(void)
Definition: multitrack.c:1033
LIVES_WARN
#define LIVES_WARN(x)
Definition: main.h:1862
WEED_PLANT_IS_EVENT
#define WEED_PLANT_IS_EVENT(plant)
Definition: events.h:358
HIDDEN_KEY
#define HIDDEN_KEY
Definition: widget-helper.h:1485
weed_filter_idx_get_name
char * weed_filter_idx_get_name(int idx, boolean add_subcats, boolean add_notes)
Definition: effects-weed.c:9475
rtew_combo_set_text
void rtew_combo_set_text(int key, int mode, const char *txt)
Definition: rte_window.c:1905
weed_add_effectkey
int weed_add_effectkey(int key, const char *hashname, boolean fullname)
bind a filter_class to key/mode using its hashname
Definition: effects-weed.c:9784
ce_thumbs_liberate_clip_area_register
void ce_thumbs_liberate_clip_area_register(int area)
Definition: ce_thumbs.c:708
lives_malloc
#define lives_malloc
Definition: machinestate.h:46
rte_key_valid
boolean rte_key_valid(int key, boolean is_userkey)
returns TRUE if there is a filter bound to active mode of hotkey
Definition: effects-weed.c:9397
has_audio_filters
boolean has_audio_filters(lives_af_t af_type)
Definition: effects-weed.c:3859
rowstrides_differ
LIVES_GLOBAL_INLINE boolean rowstrides_differ(int n1, int *n1_array, int n2, int *n2_array)
Definition: colourspace.c:9647
free_audio_frame_buffer
void free_audio_frame_buffer(lives_audio_buf_t *abuf)
Definition: audio.c:207
strip_ext
#define strip_ext(fname)
Definition: main.h:261
set_key_defaults
void set_key_defaults(weed_plant_t *inst, int key, int mode)
Definition: effects-weed.c:12418
FX_LIST_HASHNAME
@ FX_LIST_HASHNAME
Definition: effects-weed.h:47
mainwindow::record
volatile boolean record
Definition: mainwindow.h:794
weed_get_blend_factor
int weed_get_blend_factor(int hotkey)
Definition: effects-weed.c:9169
mainwindow::rte_defs
LiVESWidget * rte_defs
Definition: mainwindow.h:1235
MAX_FRAME_SIZE64
#define MAX_FRAME_SIZE64
Definition: effects-weed.c:11273
weed_channel_get_audio_rate
WEED_GLOBAL_INLINE int weed_channel_get_audio_rate(weed_plant_t *channel)
Definition: weed-effects-utils.c:493
rte_keymode_get_filter
weed_plant_t * rte_keymode_get_filter(int key, int mode)
returns filter_class bound to key/mode (or NULL)
Definition: effects-weed.c:9465
weed_call_deinit_func
weed_error_t weed_call_deinit_func(weed_plant_t *instance)
Definition: effects-weed.c:7067
break_me
void break_me(const char *brkstr)
Definition: main.c:159
weed_layer_is_video
LIVES_GLOBAL_INLINE int weed_layer_is_video(weed_layer_t *layer)
Definition: colourspace.c:9669
weed_instance_get_in_params
WEED_GLOBAL_INLINE weed_plant_t ** weed_instance_get_in_params(weed_plant_t *instance, int *nparams)
Definition: weed-effects-utils.c:602
MIN_CHAN_HEIGHT
#define MIN_CHAN_HEIGHT
Definition: effects-weed.c:1026
lives_audio_buf_t
Definition: audio.h:76
PLUGIN_EFFECTS_WEED
#define PLUGIN_EFFECTS_WEED
uses WEED_PLUGIN_PATH
Definition: plugins.h:110
mainwindow::loop
boolean loop
Definition: mainwindow.h:763
lives_spin_button_set_value
WIDGET_HELPER_GLOBAL_INLINE boolean lives_spin_button_set_value(LiVESSpinButton *button, double value)
Definition: widget-helper.c:5119
version
const char * version(void)
weed_param_get_type
WEED_GLOBAL_INLINE int weed_param_get_type(weed_plant_t *param)
Definition: weed-effects-utils.c:523
ce_thumbs_reset_combo
void ce_thumbs_reset_combo(int key)
Definition: ce_thumbs.c:614
mainwindow::is_exiting
volatile boolean is_exiting
set during shutdown (inverse of only_close then)
Definition: mainwindow.h:1440
mainwindow::current_file
int current_file
Definition: mainwindow.h:727
WEED_LEAF_HOST_AUDIO_PLAYER
#define WEED_LEAF_HOST_AUDIO_PLAYER
Definition: effects-weed.h:58
IS_VALID_CLIP
#define IS_VALID_CLIP(clip)
Definition: main.h:808
lives_string_hash
LIVES_GLOBAL_INLINE uint32_t lives_string_hash(const char *st)
Definition: machinestate.c:1585
mainwindow::no_interp
boolean no_interp
block interpolation (for single frame previews)
Definition: mainwindow.h:1551
FILTER_ERROR_INVALID_TRACK
@ FILTER_ERROR_INVALID_TRACK
Definition: effects-weed.h:25
weed_plant_serialise
size_t weed_plant_serialise(int fd, weed_plant_t *plant, unsigned char **mem)
Definition: effects-weed.c:11198
DEF_GEN_HEIGHT
#define DEF_GEN_HEIGHT
Definition: mainwindow.h:150
weed_param_get_template
WEED_GLOBAL_INLINE weed_plant_t * weed_param_get_template(weed_plant_t *param)
Definition: weed-effects-utils.c:518
mainwindow::vpp
_vid_playback_plugin * vpp
video plugin
Definition: mainwindow.h:1572
weed_abi_version
int weed_abi_version
Definition: main.h:635
key_defaults
weed_plant_t *** key_defaults[FX_KEYS_MAX_VIRTUAL]
Definition: effects-weed.c:397
lives_audio_buf_t::samples_filled
volatile size_t samples_filled
number of samples filled (readonly client)
Definition: audio.h:124
weed_paramtmpl_get_gui
WEED_GLOBAL_INLINE weed_plant_t * weed_paramtmpl_get_gui(weed_plant_t *paramt, int create_if_not_exists)
Definition: weed-effects-utils.c:162
get_weed_filter
weed_plant_t * get_weed_filter(int idx)
Definition: effects-weed.c:11014
update_host_info
void update_host_info(weed_plant_t *hinfo)
Definition: effects-weed.c:459
_palette::style
int style
Definition: mainwindow.h:297
WEED_LEAF_HOST_INITED
#define WEED_LEAF_HOST_INITED
Definition: effects-weed.h:74
lives_clip_t::ext_src
void * ext_src
points to opaque source for non-disk types
Definition: main.h:1040
lives_realloc
#define lives_realloc
Definition: machinestate.h:49
cfile
#define cfile
Definition: main.h:1833
mainwindow::preview
boolean preview
Definition: mainwindow.h:757
get_audio_channel_in
weed_plant_t * get_audio_channel_in(weed_plant_t *inst, int achnum)
Definition: effects-weed.c:595
REC_AUDIO
#define REC_AUDIO
Definition: preferences.h:201
FILTER_ERROR_INVALID_PLUGIN
@ FILTER_ERROR_INVALID_PLUGIN
Definition: effects-weed.h:22
FX_LIST_EXTENDED_NAME
@ FX_LIST_EXTENDED_NAME
Definition: effects-weed.h:46
weed_layer_get_naudchans
LIVES_GLOBAL_INLINE int weed_layer_get_naudchans(weed_layer_t *layer)
Definition: colourspace.c:13998
DEF_FRAME_VSIZE_UNSCALED
#define DEF_FRAME_VSIZE_UNSCALED
Definition: mainwindow.h:144
effects.h
_prefs::bigendbug
int bigendbug
default 0; 1==use old (bad) behaviour on bigendian machines (r/w bigend ints/doubles); 2==bad reads,...
Definition: preferences.h:374
MAX_FRAME_SIZE
#define MAX_FRAME_SIZE
Definition: effects-weed.c:11272
SECLIST_VAL_KEY
#define SECLIST_VAL_KEY
Definition: widget-helper.h:1487
weed_instance_get_in_channels
WEED_GLOBAL_INLINE weed_plant_t ** weed_instance_get_in_channels(weed_plant_t *instance, int *nchans)
Definition: weed-effects-utils.c:590
weed_palette_get_nplanes
LIVES_GLOBAL_INLINE int weed_palette_get_nplanes(int pal)
Definition: colourspace.c:1417
mainwindow::new_clip
int new_clip
clip we should switch to during playback; switch will happen at the designated SWITCH POINT
Definition: mainwindow.h:1022
AUDIO_PLAYER_NONE
#define AUDIO_PLAYER_NONE
Definition: preferences.h:47
weed_layer_get_width
LIVES_GLOBAL_INLINE int weed_layer_get_width(weed_layer_t *layer)
Definition: colourspace.c:13941
weed_filter_out_paramtmpl
weed_plant_t * weed_filter_out_paramtmpl(weed_plant_t *filter, int param_num)
Definition: effects-weed.c:8831
rte_key_is_enabled
LIVES_GLOBAL_INLINE boolean rte_key_is_enabled(int key)
Definition: effects.c:1213
weed_parameter_has_variable_elements_strict
boolean weed_parameter_has_variable_elements_strict(weed_plant_t *inst, weed_plant_t *ptmpl)
Definition: effects-weed.c:724
lives_rfx_t::params
lives_param_t * params
Definition: plugins.h:649
rte_keymode_get_filter_idx
int rte_keymode_get_filter_idx(int key, int mode)
returns filter_class index of key/mode (or -1 if no filter bound)
Definition: effects-weed.c:9416
mainwindow::clip_switched
boolean clip_switched
for recording - did we switch clips ?
Definition: mainwindow.h:793
LIVES_ERROR
#define LIVES_ERROR(x)
Definition: main.h:1870
lives_clip_t::frames
frames_t frames
number of video frames
Definition: main.h:890
rte_keymode_get_category
lives_fx_cat_t rte_keymode_get_category(int key, int mode)
Definition: effects-weed.c:9290
FILTER_ERROR_DONT_THREAD
@ FILTER_ERROR_DONT_THREAD
Definition: effects-weed.h:35
set_copy_to
int set_copy_to(weed_plant_t *inst, int pnum, lives_rfx_t *rfx, boolean update)
Definition: effects-weed.c:8918
lives_clip_t::clip_type
lives_clip_type_t clip_type
Definition: main.h:886
_weed_leaf_num_elements
weed_leaf_num_elements_f _weed_leaf_num_elements
Definition: main.h:369
mainwindow::play_window
LiVESWidget * play_window
Definition: mainwindow.h:947
prefs
_prefs * prefs
Definition: preferences.h:847
lives_strcmp
LIVES_GLOBAL_INLINE boolean lives_strcmp(const char *st1, const char *st2)
returns FALSE if strings match
Definition: machinestate.c:1506
ce_thumbs_set_keych
void ce_thumbs_set_keych(int key, boolean on)
Definition: ce_thumbs.c:106
_ext_calloc
void * _ext_calloc(size_t nmemb, size_t msize)
Definition: machinestate.c:584
WEED_LEAF_HOST_TEMP_DISABLED
#define WEED_LEAF_HOST_TEMP_DISABLED
Definition: effects-weed.h:71
write_generator_sizes
boolean write_generator_sizes(int fd, int idx)
Definition: effects-weed.c:12038
_prefs::audio_player
short audio_player
Definition: preferences.h:40
pixel_size
LIVES_GLOBAL_INLINE size_t pixel_size(int pal)
Definition: colourspace.c:1391
mainwindow::record_starting
boolean record_starting
start recording at next frame
Definition: mainwindow.h:1559
get_textparm
weed_plant_t * get_textparm(void)
for rte textmode, get first string parameter for current key/mode instance we will then forward all k...
Definition: effects-weed.c:9579
LIVES_INFO
#define LIVES_INFO(x)
Definition: main.h:1854
weed_generator_start
int weed_generator_start(weed_plant_t *inst, int key)
Definition: effects-weed.c:7911
host_info_cb
weed_plant_t * host_info_cb(weed_plant_t *xhost_info, void *data)
Definition: effects-weed.c:4522
mainwindow::frame_layer
weed_plant_t * frame_layer
Definition: mainwindow.h:948
rtew_set_keygr
void rtew_set_keygr(int key)
Definition: rte_window.c:2472
has_alpha_palette
boolean has_alpha_palette(weed_plant_t *ctmpl, weed_plant_t *filter)
Definition: effects-weed.c:162
rte_keymode_get_plugin_name
char * rte_keymode_get_plugin_name(int key, int mode)
returns name of plugin package containing filter_class (or "")
Definition: effects-weed.c:9540
REALIGN_MAX
#define REALIGN_MAX
Definition: effects-weed.c:11271
PB_QUALITY_HIGH
#define PB_QUALITY_HIGH
Definition: preferences.h:34
mainwindow::blend_layer
weed_plant_t * blend_layer
Definition: mainwindow.h:977
is_layer_ready
#define is_layer_ready(layer)
Definition: main.h:1485
pconx_chain_data_internal
boolean pconx_chain_data_internal(weed_plant_t *inst)
Definition: effects-data.c:1525
weed_chantmpl_is_audio
WEED_GLOBAL_INLINE int weed_chantmpl_is_audio(weed_plant_t *chantmpl)
Definition: weed-effects-utils.c:381
lives_fx_candidate_t::list
LiVESList * list
list of filter_idx from which user can delegate
Definition: plugins.h:687
REC_EFFECTS
#define REC_EFFECTS
Definition: preferences.h:199
WEED_LEAF_HOST_ORIG_PDATA
#define WEED_LEAF_HOST_ORIG_PDATA
Definition: effects-weed.h:60
MIN_CHAN_WIDTH
#define MIN_CHAN_WIDTH
Definition: effects-weed.c:1025
lives_menu_new
WIDGET_HELPER_GLOBAL_INLINE LiVESWidget * lives_menu_new(void)
Definition: widget-helper.c:6371
FILTER_SUCCESS
@ FILTER_SUCCESS
Definition: effects-weed.h:15
WEED_LEAF_HOST_WIDTH
#define WEED_LEAF_HOST_WIDTH
Definition: effects-weed.h:63
weed_palette_is_lower_quality
boolean weed_palette_is_lower_quality(int p1, int p2)
Definition: colourspace.c:2143
_prefs::rec_opts
int rec_opts
Definition: preferences.h:196
weed_channel_get_palette
WEED_GLOBAL_INLINE int weed_channel_get_palette(weed_plant_t *channel)
Definition: weed-effects-utils.c:453
POLY_PARAMS
@ POLY_PARAMS
Definition: multitrack.h:126
lives_fx_cat_t
lives_fx_cat_t
Definition: effects.h:11
weed_palette_is_alpha
LIVES_GLOBAL_INLINE boolean weed_palette_is_alpha(int pal)
Definition: colourspace.c:1427
add_param_connections
void add_param_connections(weed_plant_t *inst)
Definition: effects-weed.c:6431
weed_channel_set_palette
WEED_GLOBAL_INLINE void weed_channel_set_palette(weed_plant_t *channel, int palette)
Definition: weed-effects-utils.c:448
_palette::menu_and_bars_fore
LiVESWidgetColor menu_and_bars_fore
Definition: mainwindow.h:328
weed_layer_get_palette_yuv
LIVES_GLOBAL_INLINE int weed_layer_get_palette_yuv(weed_layer_t *layer, int *clamping, int *sampling, int *subspace)
Definition: colourspace.c:13983
lives_fx_cat_to_text
char * lives_fx_cat_to_text(lives_fx_cat_t cat, boolean plural)
Definition: effects.c:40
WEED_ERROR_NOSUCH_PLANT
#define WEED_ERROR_NOSUCH_PLANT
Definition: effects-weed.h:361
LIVES_FX_CAT_VIDEO_GENERATOR
@ LIVES_FX_CAT_VIDEO_GENERATOR
Definition: effects.h:13
rtew_set_mode_radio
void rtew_set_mode_radio(int key, int mode)
Definition: rte_window.c:2483
TICKS_PER_SECOND_DBL
#define TICKS_PER_SECOND_DBL
actually microseconds / 100.
Definition: mainwindow.h:37
weed_call_init_func
weed_error_t weed_call_init_func(weed_plant_t *inst)
Definition: effects-weed.c:7044
_fx_dialog::key
int key
Definition: mainwindow.h:1844
mainwindow::active_sa_clips
int active_sa_clips
Definition: mainwindow.h:1686
best_palette_match
int best_palette_match(int *palette_list, int num_palettes, int palette)
check palette vs.
Definition: effects-weed.c:868
add_sorted_list_to_menu
LiVESList * add_sorted_list_to_menu(LiVESMenu *menu, LiVESList *menu_list)
Definition: widget-helper.c:11051
_weed_plant_free
weed_plant_free_f _weed_plant_free
Definition: main.h:373
weed_layer_get_height
LIVES_GLOBAL_INLINE int weed_layer_get_height(weed_layer_t *layer)
Definition: colourspace.c:13953
add_filter_init_events
weed_plant_t * add_filter_init_events(weed_plant_t *event_list, weed_timecode_t tc)
add init events for every effect which is switched on
Definition: effects-weed.c:839
AUD_PLAYER_NONE
#define AUD_PLAYER_NONE
Definition: preferences.h:41
mainwindow::osc_auto
int osc_auto
bypass user choices automatically
Definition: mainwindow.h:918
lives_random
LIVES_GLOBAL_INLINE uint64_t lives_random(void)
Definition: machinestate.c:58
cconx_chain_data_internal
boolean cconx_chain_data_internal(weed_plant_t *ichan)
Definition: effects-data.c:2166
WEED_LEAF_HOST_SUSPICIOUS
#define WEED_LEAF_HOST_SUSPICIOUS
Definition: effects-weed.h:55
lives_fx_list_t
lives_fx_list_t
Definition: effects-weed.h:44
_palette::menu_and_bars
LiVESWidgetColor menu_and_bars
Definition: mainwindow.h:327
get_token_count
size_t get_token_count(const char *string, int delim)
Definition: utils.c:5430
CLIP_TYPE_GENERATOR
@ CLIP_TYPE_GENERATOR
frames from generator plugin
Definition: main.h:766
sizdbl
ssize_t sizdbl
Definition: main.c:102
set_main_title
void set_main_title(const char *file, int untitled)
Definition: main.c:5005
num_out_params
int num_out_params(weed_plant_t *plant)
Definition: effects-weed.c:3960
read_filter_defaults
boolean read_filter_defaults(int fd)
Definition: effects-weed.c:11921
fx_dialog
_fx_dialog * fx_dialog[2]
Definition: mainwindow.h:1851
rte_switch_keymode
int rte_switch_keymode(int key, int mode, const char *hashname)
Definition: effects-weed.c:9791
weed_channel_get_height
WEED_GLOBAL_INLINE int weed_channel_get_height(weed_plant_t *channel)
Definition: weed-effects-utils.c:432
do_chdir_failed_error
void do_chdir_failed_error(const char *dir)
Definition: dialogs.c:4213
lives_widget_queue_draw
WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_queue_draw(LiVESWidget *widget)
Definition: widget-helper.c:1580
mainwindow::agen_needs_reinit
volatile boolean agen_needs_reinit
Definition: mainwindow.h:1650
enabled_in_channels
int enabled_in_channels(weed_plant_t *plant, boolean count_repeats)
Definition: effects-weed.c:3985
ABS
#define ABS(a)
Definition: videoplugin.h:63
weed_in_params_free
void weed_in_params_free(weed_plant_t **parameters, int num_parameters)
Definition: effects-weed.c:6110
EXTRA_BYTES
#define EXTRA_BYTES
TODO - split into: memory, files, sysops, threads.
Definition: machinestate.h:16
num_in_params
int num_in_params(weed_plant_t *plant, boolean skip_hidden, boolean skip_internal)
Definition: effects-weed.c:3920
weed_layer_nullify_pixel_data
LIVES_GLOBAL_INLINE weed_layer_t * weed_layer_nullify_pixel_data(weed_layer_t *layer)
Definition: colourspace.c:9753
reset_effort
void reset_effort(void)
Definition: machinestate.c:2642
read_generator_sizes
boolean read_generator_sizes(int fd)
Definition: effects-weed.c:12092
lives_thread_join
uint64_t lives_thread_join(lives_thread_t work, void **retval)
Definition: machinestate.c:2376
lives_monitor_free
void lives_monitor_free(void *p)
Definition: effects-weed.c:4417
_fx_dialog::rfx
lives_rfx_t * rfx
Definition: mainwindow.h:1843
_prefs::apply_gamma
boolean apply_gamma
Definition: preferences.h:451
update_pwindow
void update_pwindow(int key, int i, LiVESList *list)
Definition: rte_window.c:2491
LIVES_FX_CAT_SPLITTER
@ LIVES_FX_CAT_SPLITTER
Definition: effects.h:31
PLUGIN_COMPOUND_EFFECTS_CUSTOM
#define PLUGIN_COMPOUND_EFFECTS_CUSTOM
Definition: effects-weed.h:129
LIVES_FX_CAT_AUDIO_ANALYSER
@ LIVES_FX_CAT_AUDIO_ANALYSER
Definition: effects.h:36
weed_filter_hints_unstable
WEED_GLOBAL_INLINE int weed_filter_hints_unstable(weed_plant_t *filter)
Definition: weed-effects-utils.c:181
WEED_LEAF_HOST_KEEP_ADATA
#define WEED_LEAF_HOST_KEEP_ADATA
Definition: audio.h:51
weed_set_blend_factor
void weed_set_blend_factor(int hotkey)
Definition: effects-weed.c:9039
weed_leaf_num_elements_monitor
weed_size_t weed_leaf_num_elements_monitor(weed_plant_t *plant, const char *key)
Definition: effects-weed.c:4470
MAX_WEED_ELEMENTS
#define MAX_WEED_ELEMENTS
Definition: effects-weed.h:11
weed_channel_get_pixel_data_planar
WEED_GLOBAL_INLINE void ** weed_channel_get_pixel_data_planar(weed_plant_t *channel, int *nplanes)
Definition: weed-effects-utils.c:409
VPP_LOCAL_DISPLAY
#define VPP_LOCAL_DISPLAY
Definition: plugins.h:69
lives_nanosleep
#define lives_nanosleep(nanosec)
Definition: machinestate.h:307
push_audio_to_channel
boolean push_audio_to_channel(weed_plant_t *filter, weed_plant_t *achan, lives_audio_buf_t *abuf)
fill the audio channel(s) for effects with mixed audio / video
Definition: audio.c:3688
_prefs::rte_keys_virtual
short rte_keys_virtual
Definition: preferences.h:223
RECA_MONITOR
@ RECA_MONITOR
Definition: audio.h:196
mainwindow::event_list
weed_event_t * event_list
current event_list, for recording
Definition: mainwindow.h:803
weed_plant_get_type
WEED_GLOBAL_INLINE int32_t weed_plant_get_type(weed_plant_t *plant)
Definition: weed-effects-utils.c:44
letterbox_layer
boolean letterbox_layer(weed_layer_t *layer, int nwidth, int nheight, int width, int height, LiVESInterpType interp, int tpal, int tclamp)
Definition: colourspace.c:13015
_weed_instance_ref
int _weed_instance_ref(weed_plant_t *inst)
Definition: effects-weed.c:6194
mainwindow::playframe
LiVESWidget * playframe
Definition: mainwindow.h:1098
FILTER_ERROR_IS_SCRAP_FILE
@ FILTER_ERROR_IS_SCRAP_FILE
Definition: effects-weed.h:31
ticks_t
int64_t ticks_t
Definition: main.h:97
weed_inst_in_param
weed_plant_t * weed_inst_in_param(weed_plant_t *inst, int param_num, boolean skip_hidden, boolean skip_internal)
Definition: effects-weed.c:8724
WEED_LEAF_FRAME
#define WEED_LEAF_FRAME
Definition: colourspace.h:19
_prefs::startup_phase
short startup_phase
0 = normal , -1 or 1: fresh install, 2: workdir set, 3: startup tests passed, 4: aud pl chosen,...
Definition: preferences.h:216
ce_thumbs_update_current_clip
void ce_thumbs_update_current_clip(void)
Definition: ce_thumbs.c:668
read_key_defaults
boolean read_key_defaults(int fd, int nparams, int key, int mode, int ver)
Definition: effects-weed.c:12232
LIVES_FX_CAT_TRANSITION
@ LIVES_FX_CAT_TRANSITION
Definition: effects.h:20
weed_layer_set_height
LIVES_GLOBAL_INLINE weed_layer_t * weed_layer_set_height(weed_layer_t *layer, int height)
Definition: colourspace.c:9724
switch_audio_clip
boolean switch_audio_clip(int new_file, boolean activate)
Definition: main.c:9808
LIVES_FX_CAT_CONVERTER
@ LIVES_FX_CAT_CONVERTER
Definition: effects.h:32
weed_filter_get_flags
WEED_GLOBAL_INLINE int weed_filter_get_flags(weed_plant_t *filter)
Definition: weed-effects-utils.c:176
mainwindow::frame_index
frames64_t * frame_index
maps frame slots to the presentation values (if >= 0, points to a 'virtual' frame in the source clip,...
Definition: mainwindow.h:1434
get_interp_value
LiVESInterpType get_interp_value(short quality, boolean low_for_mt)
Definition: utils.c:5744
GU641
#define GU641
Definition: mainwindow.h:209
_ext_realloc
void * _ext_realloc(void *p, size_t n)
Definition: machinestate.c:575
mainwindow::fx_mutex
pthread_mutex_t fx_mutex[FX_KEYS_MAX]
used to prevent fx processing when it is scheduled for deinit
Definition: mainwindow.h:1497
weed_init_effect
boolean weed_init_effect(int hotkey)
hotkey starts at 1
Definition: effects-weed.c:6596
AF_TYPE_NONA
@ AF_TYPE_NONA
Definition: effects.h:43
threaded_dialog_spin
void threaded_dialog_spin(double fraction)
Definition: dialogs.c:3823
weed_layer_set_palette
LIVES_GLOBAL_INLINE weed_layer_t * weed_layer_set_palette(weed_layer_t *layer, int palette)
functions all return the input layer for convenience; no checking for valid values is done if layer i...
Definition: colourspace.c:9777
append_filter_init_event
weed_plant_t * append_filter_init_event(weed_plant_t *event_list, weed_timecode_t tc, int filter_idx, int num_in_tracks, int key, weed_plant_t *inst)
Definition: events.c:2731
WEED_LEAF_AUTO_EASING
#define WEED_LEAF_AUTO_EASING
Definition: effects-weed.h:94
weed_instance_obtain
LIVES_GLOBAL_INLINE weed_plant_t * weed_instance_obtain(int key, int mode)
Definition: effects-weed.c:6238
TRUE
#define TRUE
Definition: videoplugin.h:59
weed_deinit_all
void weed_deinit_all(boolean shutdown)
deinit all effects (except generators* during playback) this is called on ctrl-0 or on shutdown backg...
Definition: effects-weed.c:7404
lives_clip_t::img_type
lives_img_type_t img_type
Definition: main.h:887
DLL_NAME
#define DLL_NAME
Definition: mainwindow.h:530
lives_monitor_malloc
void * lives_monitor_malloc(size_t size)
Definition: effects-weed.c:4409
WEED_LEAF_HOST_MODE
#define WEED_LEAF_HOST_MODE
Definition: effects-weed.h:68
mainwindow::pheight
int pheight
playback height
Definition: mainwindow.h:927
FX_CANDIDATE_AUDIO_VOL
#define FX_CANDIDATE_AUDIO_VOL
Definition: plugins.h:694
SCREEN_AREA_BACKGROUND
#define SCREEN_AREA_BACKGROUND
Definition: mainwindow.h:1681
sizint
ssize_t sizint
type sizes
Definition: main.c:102
CLIP_TYPE_DISK
@ CLIP_TYPE_DISK
imported video, broken into frames
Definition: main.h:764
LIVES_FX_CAT_ANALYSER
@ LIVES_FX_CAT_ANALYSER
Definition: effects.h:34
_prefs::nfx_threads
int nfx_threads
Definition: preferences.h:356
mainwindow::clip_index
int * clip_index
Definition: mainwindow.h:1431
LIVES_FX_CAT_TAP
@ LIVES_FX_CAT_TAP
Definition: effects.h:30
weed_chantmpl_get_flags
WEED_GLOBAL_INLINE int weed_chantmpl_get_flags(weed_plant_t *chantmpl)
Definition: weed-effects-utils.c:290
WEED_LEAF_AUTHOR
#define WEED_LEAF_AUTHOR
Definition: events.h:27
append_param_change_event
weed_plant_t * append_param_change_event(weed_plant_t *event_list, weed_timecode_t tc, int pnum, weed_plant_t *param, void *init_event, void **pchain)
Definition: events.c:2919
lives_read_buffered
ssize_t lives_read_buffered(int fd, void *buf, ssize_t count, boolean allow_less)
Definition: utils.c:924
update_widget_vis
boolean update_widget_vis(lives_rfx_t *rfx, int key, int mode)
show / hide widgets set by plugin in init_func()
Definition: paramwindow.c:1893
lives_memset
#define lives_memset
Definition: machinestate.h:61
weed_palette_is_yuv
LIVES_GLOBAL_INLINE boolean weed_palette_is_yuv(int pal)
Definition: colourspace.c:1457
mainwindow::whentostop
volatile lives_whentostop_t whentostop
Definition: mainwindow.h:929
filter_mutex_lock
LIVES_GLOBAL_INLINE int filter_mutex_lock(int key)
Definition: effects-weed.c:96
_prefs::default_fps
double default_fps
Definition: preferences.h:173
weed_filter_in_paramtmpl
weed_plant_t * weed_filter_in_paramtmpl(weed_plant_t *filter, int param_num, boolean skip_internal)
Definition: effects-weed.c:8795
weed_apply_audio_effects_rt
void weed_apply_audio_effects_rt(weed_layer_t *alayer, weed_timecode_t tc, boolean analysers_only, boolean is_audio_thread)
Definition: effects-weed.c:3743
weed_filter_get_in_chantmpls
WEED_GLOBAL_INLINE weed_plant_t ** weed_filter_get_in_chantmpls(weed_plant_t *filter, int *ntmpls)
Definition: weed-effects-utils.c:245
THREADVAR
#define THREADVAR(var)
Definition: machinestate.h:531
WEED_LEAF_HOST_COMPOUND_CLASS
#define WEED_LEAF_HOST_COMPOUND_CLASS
Definition: effects-weed.h:105
is_hidden_param
boolean is_hidden_param(weed_plant_t *plant, int i)
returns the permanent (structural) state c.f check_hidden_gui() which sets flag values for params lin...
Definition: effects-weed.c:8587
WEED_LEAF_HOST_PLUGIN_PATH
#define WEED_LEAF_HOST_PLUGIN_PATH
Definition: effects-weed.h:75
LIVES_FX_CAT_DATA_VISUALISER
@ LIVES_FX_CAT_DATA_VISUALISER
Definition: effects.h:17
FILTER_ERROR_INVALID_INSTANCE
@ FILTER_ERROR_INVALID_INSTANCE
Definition: effects-weed.h:27
weed_layer_get_rowstrides
LIVES_GLOBAL_INLINE int * weed_layer_get_rowstrides(weed_layer_t *layer, int *nplanes)
Definition: colourspace.c:13928
weed_apply_effects
weed_plant_t * weed_apply_effects(weed_plant_t **layers, weed_plant_t *filter_map, weed_timecode_t tc, int opwidth, int opheight, void ***pchains)
Definition: effects-weed.c:3484
rte_fg_gen_mode
LIVES_GLOBAL_INLINE int rte_fg_gen_mode(void)
Definition: effects-weed.c:9568
get_mandatory_channel
weed_plant_t * get_mandatory_channel(weed_plant_t *filter, int which, boolean is_in)
for FILTER_CLASS
Definition: effects-weed.c:548
apply_key_defaults
void apply_key_defaults(weed_plant_t *inst, int key, int mode)
Definition: effects-weed.c:12342
weed_layer_pixel_data_free
void weed_layer_pixel_data_free(weed_layer_t *layer)
free pixel_data from layer
Definition: colourspace.c:13819
lives_rfx_t
Definition: plugins.h:625
is_pure_audio
boolean is_pure_audio(weed_plant_t *plant, boolean count_opt)
TRUE if audio in or out and no vid in/out.
Definition: effects-weed.c:714
mainwindow::cancelled
volatile lives_cancel_t cancelled
Definition: mainwindow.h:798
lives_af_t
lives_af_t
audio filter type (any, analyser only, non analyser only)
Definition: effects.h:40
get_event_pchains
GNU_PURE void *** get_event_pchains(void)
Definition: events.c:94
_prefs::audio_opts
volatile uint32_t audio_opts
Definition: preferences.h:254
is_realtime_aplayer
#define is_realtime_aplayer(ptype)
Definition: audio.h:236
rte_keymode_valid
boolean rte_keymode_valid(int key, int mode, boolean is_userkey)
returns TRUE if a filter_class is bound to key/mode, is_userkey should be set to TRUE
Definition: effects-weed.c:9407
lives_widget_set_bg_color
WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_set_bg_color(LiVESWidget *widget, LiVESWidgetState state, const LiVESWidgetColor *color)
Definition: widget-helper.c:2056
FILTER_ERROR_MISSING_CHANNEL
@ FILTER_ERROR_MISSING_CHANNEL
Definition: effects-weed.h:32
weed_palette_is_rgb
LIVES_GLOBAL_INLINE boolean weed_palette_is_rgb(int pal)
Definition: colourspace.c:1448
weed_param_get_gui
WEED_GLOBAL_INLINE weed_plant_t * weed_param_get_gui(weed_plant_t *param, int create_if_not_exists)
Definition: weed-effects-utils.c:166
weed_channel_is_disabled
WEED_GLOBAL_INLINE int weed_channel_is_disabled(weed_plant_t *channel)
Definition: weed-effects-utils.c:508
lives_utf8_strcasecmp
int lives_utf8_strcasecmp(const char *s1, const char *s2)
Definition: utils.c:5458
WEED_PLANT_IS_FILTER_CLASS
#define WEED_PLANT_IS_FILTER_CLASS(plant)
Definition: weed-effects-utils.h:36
lives_write_le_buffered
ssize_t lives_write_le_buffered(int fd, livesconstpointer buf, ssize_t count, boolean allow_fail)
is_audio_channel_in
boolean is_audio_channel_in(weed_plant_t *inst, int chnum)
Definition: effects-weed.c:577
mainwindow::blend_width
int blend_width
Definition: mainwindow.h:981
LIVES_FX_CAT_AUDIO_TRANSITION
@ LIVES_FX_CAT_AUDIO_TRANSITION
Definition: effects.h:23
mainwindow::rte_keys
int rte_keys
which effect is bound to keyboard (m) modechange and ctrl-alt-up-arrow / ctrl-alt-down-arrow param ch...
Definition: mainwindow.h:870
callbacks.h
lives_whentostop_t
lives_whentostop_t
which stream end should cause playback to finish ?
Definition: main.h:692
LIVES_FX_CAT_AV_TRANSITION
@ LIVES_FX_CAT_AV_TRANSITION
Definition: effects.h:21
weed_apply_instance
lives_filter_error_t weed_apply_instance(weed_plant_t *inst, weed_plant_t *init_event, weed_plant_t **layers, int opwidth, int opheight, weed_timecode_t tc)
process a single video filter instance
Definition: effects-weed.c:1585
mainwindow::afb
lives_audio_buf_t * afb[2]
used for buffering / feeding audio to video generators
Definition: mainwindow.h:1698
weed_get_idx_for_hashname
int weed_get_idx_for_hashname(const char *hashname, boolean fullname)
fullname includes author and version
Definition: effects-weed.c:10840
LIVES_FX_CAT_UTILITY
@ LIVES_FX_CAT_UTILITY
Definition: effects.h:27
rte_get_numfilters
int rte_get_numfilters(void)
Definition: effects-weed.c:9899
_prefs::audio_src
int audio_src
Definition: preferences.h:204
ce_thumbs_set_mode_combo
void ce_thumbs_set_mode_combo(int key, int mode)
Definition: ce_thumbs.c:117
capable
capability * capable
Definition: main.h:627
LIVES_EXT_SRC_FILTER
#define LIVES_EXT_SRC_FILTER
Definition: main.h:1045
write_filter_defaults
boolean write_filter_defaults(int fd, int idx)
Definition: effects-weed.c:11874
LIVES_FX_CAT_VIDEO_ANALYSER
@ LIVES_FX_CAT_VIDEO_ANALYSER
Definition: effects.h:35
ce_thumbs_highlight_current_clip
void ce_thumbs_highlight_current_clip(void)
Definition: ce_thumbs.c:673
weed_layer_set_width
LIVES_GLOBAL_INLINE weed_layer_t * weed_layer_set_width(weed_layer_t *layer, int width)
width in macropixels of the layer palette
Definition: colourspace.c:9717
mainwindow::preview_rendering
boolean preview_rendering
Definition: mainwindow.h:758
widget_opts_t::mnemonic_label
boolean mnemonic_label
if underscore in label text should be mnemonic accelerator
Definition: widget-helper.h:1420
d_print
void d_print(const char *fmt,...)
Definition: utils.c:2542
weed_flagset_array_count
int weed_flagset_array_count(weed_plant_t **array, boolean set_readonly)
Definition: effects-weed.c:1136
weed_reinit_all
void weed_reinit_all(void)
Definition: effects-weed.c:1288
close_current_file
void close_current_file(int file_to_switch_to)
close current file, and try to switch to file_to_switch_to
Definition: main.c:9373
mainwindow::blend_file
int blend_file
background clip details
Definition: mainwindow.h:976
switch_to_file
void switch_to_file(int old_file, int new_file)
Definition: main.c:9646
deinit_render_effects
void deinit_render_effects(void)
switch off effects after render preview during rendering/render preview, we use the "keys" FX_KEYS_MA...
Definition: effects-weed.c:7358
weed_leaf_get_monitor
weed_error_t weed_leaf_get_monitor(weed_plant_t *plant, const char *key, int32_t idx, void *value)
Definition: effects-weed.c:4433
WEED_LEAF_IN_TRACKS
#define WEED_LEAF_IN_TRACKS
Definition: events.h:47
mainwindow::afbuffer_clients_read
int afbuffer_clients_read
Definition: mainwindow.h:1700
weed_leaf_copy_or_delete
LIVES_GLOBAL_INLINE weed_error_t weed_leaf_copy_or_delete(weed_layer_t *dlayer, const char *key, weed_layer_t *slayer)
Definition: effects-weed.c:68
_prefs::prefix_dir
char prefix_dir[PATH_MAX]
Definition: preferences.h:74
MAX_CHAN_WIDTH
#define MAX_CHAN_WIDTH
Definition: effects-weed.c:1028
has_non_alpha_palette
boolean has_non_alpha_palette(weed_plant_t *ctmpl, weed_plant_t *filter)
Definition: effects-weed.c:143
CEIL
#define CEIL(a, b)
Definition: main.h:283
mainwindow::pre_src_audio_file
int pre_src_audio_file
audio file we were playing before any ext input started
Definition: mainwindow.h:972
run_process_func
lives_filter_error_t run_process_func(weed_plant_t *instance, weed_timecode_t tc, int key)
Definition: effects-weed.c:2799
VPP_CAN_RESIZE
#define VPP_CAN_RESIZE
type sepcific caps
Definition: plugins.h:67
filter_mutex_unlock
LIVES_GLOBAL_INLINE int filter_mutex_unlock(int key)
Definition: effects-weed.c:108
_weed_leaf_delete
weed_leaf_delete_f _weed_leaf_delete
Definition: main.h:375
cd_to_plugin_dir
char * cd_to_plugin_dir(weed_plant_t *filter)
change directory to plugin installation dir so it can find any data files
Definition: effects-weed.c:1148
WEED_LEAF_HOST_IDX
#define WEED_LEAF_HOST_IDX
Definition: effects-weed.h:84
weed_layer_get_palette
LIVES_GLOBAL_INLINE int weed_layer_get_palette(weed_layer_t *layer)
Definition: colourspace.c:13977
lives_rfx_t::num_params
int num_params
Definition: plugins.h:644
weed_plant_free_host
weed_error_t weed_plant_free_host(weed_plant_t *plant)
Definition: effects-weed.c:4339
FILTER_ERROR_BLANK_FRAME
@ FILTER_ERROR_BLANK_FRAME
Definition: effects-weed.h:17
WEED_LEAF_HOST_TAG
#define WEED_LEAF_HOST_TAG
Definition: effects-weed.h:66
get_new_inst_for_keymode
weed_plant_t * get_new_inst_for_keymode(int key, int mode)
get new refcounted inst (during recording playback)
Definition: effects-weed.c:9225
mainwindow::pre_src_file
int pre_src_file
video file we were playing before any ext input started
Definition: mainwindow.h:971
cconx_chain_data
boolean cconx_chain_data(int key, int mode)
Definition: effects-data.c:2129
init_audio_frame_buffers
void init_audio_frame_buffers(short aplayer)
Definition: audio.c:155
pull_frame_at_size
boolean pull_frame_at_size(weed_layer_t *layer, const char *image_ext, weed_timecode_t tc, int width, int height, int target_palette)
Definition: main.c:7172
mainwindow::playing_sel
boolean playing_sel
list of set names in current workdir, mau be NULL
Definition: mainwindow.h:756
_weed_leaf_get
weed_leaf_get_f _weed_leaf_get
Definition: main.h:365
weed_instance_ref
LIVES_GLOBAL_INLINE int weed_instance_ref(weed_plant_t *inst)
Definition: effects-weed.c:6230
AUDIO_PLAYER_JACK
#define AUDIO_PLAYER_JACK
Definition: preferences.h:49
create_empty_pixel_data
boolean create_empty_pixel_data(weed_layer_t *layer, boolean black_fill, boolean may_contig)
creates pixel data for layer
Definition: colourspace.c:9058
mainwindow::blend_palette
volatile int blend_palette
here we can store the details of the blend file at the insertion point, if nothing changes we can tar...
Definition: mainwindow.h:980
rte_keymode_get_filter_name
char * rte_keymode_get_filter_name(int key, int mode, boolean add_notes)
returns name of filter_class bound to key/mode (or "")
Definition: effects-weed.c:9531
weed_param_has_variable_size
WEED_GLOBAL_INLINE int weed_param_has_variable_size(weed_plant_t *param)
Definition: weed-effects-utils.c:533
switch_clip
void switch_clip(int type, int newclip, boolean force)
Definition: callbacks.c:6900
mainwindow::textwidget_focus
LiVESWidget * textwidget_focus
Definition: mainwindow.h:1569
mainwindow::scrap_file
int scrap_file
we throw odd sized frames here when recording in real time; used if a source is a generator or stream
Definition: mainwindow.h:874
MAX_WEED_STRLEN
#define MAX_WEED_STRLEN
Definition: effects-weed.h:10
weed_filter_get_in_paramtmpls
WEED_GLOBAL_INLINE weed_plant_t ** weed_filter_get_in_paramtmpls(weed_plant_t *filter, int *ntmpls)
Definition: weed-effects-utils.c:257
_weed_instance_obtain
weed_plant_t * _weed_instance_obtain(int line, char *file, int key, int mode)
Definition: effects-weed.c:6212
weed_paramtmpl_get_type
WEED_GLOBAL_INLINE int weed_paramtmpl_get_type(weed_plant_t *paramtmpl)
Definition: weed-effects-utils.c:312
create_cfile
lives_clip_t * create_cfile(int new_file, const char *handle, boolean is_loaded)
set default values for a clip (in memory)
Definition: saveplay.c:3656
weed_in_parameters_free
void weed_in_parameters_free(weed_plant_t *inst)
Definition: effects-weed.c:6121
mainwindow::num_tracks
int num_tracks
Definition: mainwindow.h:1430
weed_channel_get_pixel_data
WEED_GLOBAL_INLINE void * weed_channel_get_pixel_data(weed_plant_t *channel)
Definition: weed-effects-utils.c:404
lives_filter_error_t
lives_filter_error_t
filter apply errors
Definition: effects-weed.h:14
weed_layer_get_pixel_data_packed
LIVES_GLOBAL_INLINE uint8_t * weed_layer_get_pixel_data_packed(weed_layer_t *layer)
Definition: colourspace.c:13915
weed_layer_set_size
LIVES_GLOBAL_INLINE weed_layer_t * weed_layer_set_size(weed_layer_t *layer, int width, int height)
Definition: colourspace.c:9731
add_filter_deinit_events
weed_plant_t * add_filter_deinit_events(weed_plant_t *event_list)
add effect_deinit events to an event_list
Definition: effects-weed.c:803
STOP_ON_AUD_END
@ STOP_ON_AUD_END
Definition: main.h:695
WEED_LEAF_FILTER
#define WEED_LEAF_FILTER
Definition: events.h:44
weed_paramtmpl_get_flags
WEED_GLOBAL_INLINE int weed_paramtmpl_get_flags(weed_plant_t *paramtmpl)
Definition: weed-effects-utils.c:300
rte_key_setmode
boolean rte_key_setmode(int key, int newmode)
newmode has two special values, -1 = cycle forwards, -2 = cycle backwards key is 1 based,...
Definition: effects-weed.c:9626
CURRENT_CLIP_HAS_VIDEO
#define CURRENT_CLIP_HAS_VIDEO
Definition: main.h:815
weed_chantmpl_get_palette_list
WEED_GLOBAL_INLINE int * weed_chantmpl_get_palette_list(weed_plant_t *filter, weed_plant_t *chantmpl, int *nvals)
Definition: weed-effects-utils.c:386
WEED_PLANT_LAYER
#define WEED_PLANT_LAYER
Definition: colourspace.h:217
LIVES_FX_CAT_DATA_SOURCE
@ LIVES_FX_CAT_DATA_SOURCE
Definition: effects.h:19
WEED_EVENT_IS_PARAM_CHANGE
#define WEED_EVENT_IS_PARAM_CHANGE(event)
Definition: events.h:367
WEED_PLANT_IS_HOST_INFO
#define WEED_PLANT_IS_HOST_INFO(plant)
Definition: weed-effects-utils.h:34
restore_weed_instances
void restore_weed_instances(void)
Definition: effects-weed.c:423
mainwindow::playing_file
int playing_file
which number file we are playing (or -1) [generally mainw->current_file]
Definition: mainwindow.h:943
filter_mutex_trylock
LIVES_GLOBAL_INLINE int filter_mutex_trylock(int key)
Definition: effects-weed.c:74
write_key_defaults
void write_key_defaults(int fd, int key, int mode)
Definition: effects-weed.c:12369
FILTER_ERROR_INVALID_PALETTE_CONVERSION
@ FILTER_ERROR_INVALID_PALETTE_CONVERSION
Definition: effects-weed.h:19
_prefs::max_modes_per_key
int max_modes_per_key
maximum effect modes per key
Definition: preferences.h:350
mainwindow::files
lives_clip_t * files[MAX_FILES+1]
+1 for the clipboard
Definition: mainwindow.h:729
num_compound_fx
int num_compound_fx(weed_plant_t *plant)
return number of filters in a compound fx (1 if it is not compound) - works for filter or inst
Definition: effects-weed.c:132
weed_leaf_delete_host
weed_error_t weed_leaf_delete_host(weed_plant_t *plant, const char *key)
Definition: effects-weed.c:4357
FILTER_ERROR_MISSING_LAYER
@ FILTER_ERROR_MISSING_LAYER
Definition: effects-weed.h:16
LIVES_FX_CAT_AUDIO_EFFECT
@ LIVES_FX_CAT_AUDIO_EFFECT
Definition: effects.h:26
FILTER_INFO_REDRAWN
@ FILTER_INFO_REDRAWN
Definition: effects-weed.h:41
LIVES_FX_CAT_NONE
@ LIVES_FX_CAT_NONE
Definition: effects.h:12
check_filter_chain_palettes
int check_filter_chain_palettes(boolean is_bg, int *palette_list, int npals)
Definition: effects-weed.c:7545
weed_instance_from_filter
weed_plant_t * weed_instance_from_filter(weed_plant_t *filter)
Definition: effects-weed.c:6469
SLICE_ALIGN
#define SLICE_ALIGN
Definition: effects-weed.c:1331
WEED_LEAF_HOST_NORECORD
#define WEED_LEAF_HOST_NORECORD
Definition: effects-weed.h:78
CANCEL_NONE
@ CANCEL_NONE
no cancel
Definition: main.h:701
ALIGN_CEIL
#define ALIGN_CEIL(a, b)
Definition: main.h:286
weed_palette_has_alpha
LIVES_GLOBAL_INLINE boolean weed_palette_has_alpha(int pal)
Definition: colourspace.c:1466
WEED_LEAF_HOST_EASE_OUT_COUNT
#define WEED_LEAF_HOST_EASE_OUT_COUNT
Definition: effects-weed.h:93
_weed_leaf_set
weed_leaf_set_f _weed_leaf_set
Definition: main.h:366
WEED_LEAF_DEINIT_EVENT
#define WEED_LEAF_DEINIT_EVENT
Definition: events.h:76
FILTER_ERROR_COULD_NOT_REINIT
@ FILTER_ERROR_COULD_NOT_REINIT
Definition: effects-weed.h:21
weed_apply_audio_instance
lives_filter_error_t weed_apply_audio_instance(weed_plant_t *init_event, weed_layer_t **layers, int nbtracks, int nchans, int64_t nsamps, double arate, weed_timecode_t tc, double *vis)
apply an audio filter to a stack of audio tracks
Definition: effects-weed.c:3031
mainwindow::pulsed
void * pulsed
pulseaudio player
Definition: mainwindow.h:1463
weed_deinit_effect
boolean weed_deinit_effect(int hotkey)
hotkey starts at 1
Definition: effects-weed.c:7094
mainwindow::play_start
frames_t play_start
Definition: mainwindow.h:931
_prefs::weed_plugin_path
char weed_plugin_path[PATH_MAX]
Definition: preferences.h:413
_vid_playback_plugin::capabilities
uint64_t capabilities
Definition: plugins.h:177
WEED_LEAF_HOST_KEY
#define WEED_LEAF_HOST_KEY
Definition: effects-weed.h:67
lives_menu_item_set_submenu
WIDGET_HELPER_GLOBAL_INLINE boolean lives_menu_item_set_submenu(LiVESMenuItem *menuitem, LiVESWidget *menu)
Definition: widget-helper.c:6519
LIVES_FX_CAT_AUDIO_GENERATOR
@ LIVES_FX_CAT_AUDIO_GENERATOR
Definition: effects.h:15
interpolate_param
boolean interpolate_param(weed_plant_t *param, void *pchain, weed_timecode_t tc)
Definition: effects-weed.c:10187
has_video_chans_out
boolean has_video_chans_out(weed_plant_t *filter, boolean count_opt)
Definition: effects-weed.c:676
WEED_LEAF_HOST_HEIGHT
#define WEED_LEAF_HOST_HEIGHT
Definition: effects-weed.h:64
DEFAULT_AUDIO_RATE
#define DEFAULT_AUDIO_RATE
defaults for when not specifed
Definition: audio.h:23
mainwindow::event_list_mutex
pthread_mutex_t event_list_mutex
prevent simultaneous writing to event_list by audio and video threads
Definition: mainwindow.h:1499
palette
_palette * palette
interface colour settings
Definition: main.c:101
FX_WAIT_LIM
#define FX_WAIT_LIM
weed_params_create
weed_plant_t ** weed_params_create(weed_plant_t *filter, boolean in)
Definition: effects-weed.c:6318
rte_fg_gen_key
LIVES_GLOBAL_INLINE int rte_fg_gen_key(void)
Definition: effects-weed.c:9560
rte_bg_gen_mode
LIVES_GLOBAL_INLINE int rte_bg_gen_mode(void)
Definition: effects-weed.c:9564
weed_instance_get_type
LIVES_INLINE char * weed_instance_get_type(weed_plant_t *inst, boolean getsub)
Definition: effects-weed.c:9257
mainwindow::pchains
void *** pchains
Definition: mainwindow.h:1301
_prefs::force64bit
boolean force64bit
< force system clock (rather than soundcard) for timing ( better for high framerates )
Definition: preferences.h:368
LIVES_FX_CAT_DATA_GENERATOR
@ LIVES_FX_CAT_DATA_GENERATOR
Definition: effects.h:16
CLIP_NAME_MAXLEN
#define CLIP_NAME_MAXLEN
Definition: main.h:804
has_usable_palette
boolean has_usable_palette(weed_plant_t *chantmpl)
Definition: effects-weed.c:3976
rte_swap_fg_bg
void rte_swap_fg_bg(void)
Definition: effects-weed.c:9844
error
error("LSD_RANDFUNC(ptr, size) must be defined")
weed_generator_end
void weed_generator_end(weed_plant_t *inst)
Definition: effects-weed.c:8176
weed_paramtmpl_value_irrelevant
WEED_GLOBAL_INLINE int weed_paramtmpl_value_irrelevant(weed_plant_t *paramtmpl)
Definition: weed-effects-utils.c:360
weed_instance_get_out_channels
WEED_GLOBAL_INLINE weed_plant_t ** weed_instance_get_out_channels(weed_plant_t *instance, int *nchans)
Definition: weed-effects-utils.c:596
weed_palette_is_pixbuf_palette
#define weed_palette_is_pixbuf_palette(pal)
Definition: colourspace.h:296
update_all_host_info
void update_all_host_info(void)
Definition: effects-weed.c:478
FILTER_ERROR_TEMPLATE_MISMATCH
@ FILTER_ERROR_TEMPLATE_MISMATCH
Definition: effects-weed.h:33
check_layer_ready
boolean check_layer_ready(weed_layer_t *layer)
block until layer pixel_data is ready.
Definition: main.c:7528
weed_filter_highest_version
int weed_filter_highest_version(const char *pkg, const char *fxname, const char *auth, int *xversion)
Definition: effects-weed.c:10994
weed_layer_get_gamma
int weed_layer_get_gamma(weed_layer_t *layer)
Definition: colourspace.c:12002
lives_fx_candidate_t::delegate
int delegate
offset in list of current delegate
Definition: plugins.h:688
weed_palette_get_plane_ratio_vertical
LIVES_GLOBAL_INLINE double weed_palette_get_plane_ratio_vertical(int pal, int plane)
Definition: colourspace.c:1488
FX_CANDIDATE_RESIZER
#define FX_CANDIDATE_RESIZER
Definition: plugins.h:695
fill_param_vals_to
void fill_param_vals_to(weed_plant_t *param, weed_plant_t *paramtmpl, int index)
for a multi valued parameter or pchange, we will fill WEED_LEAF_VALUE up to element index with WEED_L...
Definition: effects-weed.c:9913
weed_leaf_clear_flagbits
WEED_GLOBAL_INLINE uint32_t weed_leaf_clear_flagbits(weed_plant_t *plant, const char *leaf, uint32_t flagbits)
~value ANDed with flags
Definition: weed-effects-utils.c:58
lives_get_current_ticks
LIVES_GLOBAL_INLINE ticks_t lives_get_current_ticks(void)
Definition: machinestate.c:835
WEED_LEAF_NEXT_CHANGE
#define WEED_LEAF_NEXT_CHANGE
Definition: events.h:71
get_filename
void get_filename(char *filename, boolean strip_dir)
Definition: utils.c:3205
PLUGIN_COMPOUND_EFFECTS_BUILTIN
#define PLUGIN_COMPOUND_EFFECTS_BUILTIN
Definition: effects-weed.h:128
weed_error_to_text
char * weed_error_to_text(weed_error_t error)
Definition: weed-effects-utils.c:647
ce_thumbs.h
has_key_defaults
boolean has_key_defaults(void)
Definition: effects-weed.c:12450
get_letterbox_sizes
void get_letterbox_sizes(int *pwidth, int *pheight, int *lb_width, int *lb_height, boolean player_can_upscale)
calculate sizes for letterboxing
Definition: gui.c:4406
SECLIST_KEY
#define SECLIST_KEY
Definition: widget-helper.h:1486
mainwindow::blend_sampling
int blend_sampling
Definition: mainwindow.h:982
rtew_set_keych
void rtew_set_keych(int key, boolean on)
Definition: rte_window.c:2464
splash_msg
void splash_msg(const char *msg, double pct)
Definition: gui.c:4687
lives_clip_t::ext_src_type
int ext_src_type
Definition: main.h:1051
mainwindow::jackd_read
void * jackd_read
dummy
Definition: mainwindow.h:1454
subst
char * subst(const char *string, const char *from, const char *to)
Definition: utils.c:5484
rte_keymode_get_instance
weed_plant_t * rte_keymode_get_instance(int key, int mode)
returns refcounted filter_instance bound to key/mode (or NULL)
Definition: effects-weed.c:9450
lives_strdup_printf
#define lives_strdup_printf(fmt,...)
Definition: support.c:27
after_param_text_changed
void after_param_text_changed(LiVESWidget *textwidget, lives_rfx_t *rfx)
Definition: paramwindow.c:2635
get_event_timecode
LIVES_GLOBAL_INLINE weed_timecode_t get_event_timecode(weed_plant_t *plant)
Definition: events.c:98
weed_filter_subcategorise
lives_fx_cat_t weed_filter_subcategorise(weed_plant_t *pl, lives_fx_cat_t category, boolean count_opt)
Definition: effects-weed.c:290
LIVES_IS_RENDERING
#define LIVES_IS_RENDERING
Definition: main.h:842
mainwindow::osc_block
boolean osc_block
TODO - make this a mutex and more finely grained : things we need to block are (clip switches,...
Definition: mainwindow.h:916
lives_calloc
#define lives_calloc
Definition: machinestate.h:67
weed_instance_get_filter_name
char * weed_instance_get_filter_name(weed_plant_t *inst, boolean get_compound_parent)
Definition: effects-weed.c:9519
backup_weed_instances
void backup_weed_instances(void)
for multitrack
Definition: effects-weed.c:410
is_audio_channel_out
boolean is_audio_channel_out(weed_plant_t *inst, int chnum)
Definition: effects-weed.c:656
paramwindow.h
weed_load_all
void weed_load_all(void)
load effects
Definition: effects-weed.c:5119
get_next_free_key
int get_next_free_key(void)
next free "key" for the multitrack system
Definition: effects-weed.c:9311
weed_filter_get_name
WEED_GLOBAL_INLINE char * weed_filter_get_name(weed_plant_t *filter)
Definition: weed-effects-utils.c:240
get_last_event
LIVES_GLOBAL_INLINE weed_plant_t * get_last_event(weed_plant_t *event_list)
Definition: events.c:124
WEED_LEAF_HOST_FILTER_LIST
#define WEED_LEAF_HOST_FILTER_LIST
Definition: effects-weed.h:77
weed_layer_t
weed_plant_t weed_layer_t
Definition: colourspace.h:71
lives_list_free_all
void lives_list_free_all(LiVESList **)
Definition: utils.c:4873
weed_filter_get_out_chantmpls
WEED_GLOBAL_INLINE weed_plant_t ** weed_filter_get_out_chantmpls(weed_plant_t *filter, int *ntmpls)
Definition: weed-effects-utils.c:251
get_enabled_audio_channel
weed_plant_t * get_enabled_audio_channel(weed_plant_t *inst, int which, boolean is_in)
for FILTER_INST
Definition: effects-weed.c:542
get_master_vol_param
int get_master_vol_param(weed_plant_t *filter, boolean skip_internal)
Definition: effects-weed.c:8673
lives_clip_t::hsize
int hsize
frame width (horizontal) in pixels (NOT macropixels !)
Definition: main.h:896
mainwindow::is_rendering
boolean is_rendering
Definition: mainwindow.h:821
WEED_LEAF_HOST_INTERNAL_CONNECTION
#define WEED_LEAF_HOST_INTERNAL_CONNECTION
Definition: effects-weed.h:102
weed_channel_set_gamma_type
WEED_GLOBAL_INLINE weed_plant_t * weed_channel_set_gamma_type(weed_plant_t *channel, int gamma_type)
only sets value; no conversion of pixel_data done
Definition: weed-effects-utils.c:463
num_alpha_channels
int num_alpha_channels(weed_plant_t *filter, boolean out)
Definition: effects-weed.c:321
FX_KEYS_MAX_VIRTUAL
#define FX_KEYS_MAX_VIRTUAL
must be >= FX_KEYS_PHYSICAL, and <=64 (number of bits in a 64bit int mask) (max number of keys accesi...
Definition: mainwindow.h:203
count_simple_params
int count_simple_params(weed_plant_t *plant)
Definition: effects-weed.c:8892
handle_audio_timeout
LIVES_GLOBAL_INLINE lives_cancel_t handle_audio_timeout(void)
Definition: audio.c:3971
calc_midspect
void calc_midspect(int rwidth, int rheight, int *cwidth, int *cheight)
Definition: utils.c:2216
LIVES_THRDATTR_NONE
#define LIVES_THRDATTR_NONE
Definition: machinestate.h:437
weed_playback_gen_start
boolean weed_playback_gen_start(void)
Definition: effects-weed.c:8332
enabled_out_channels
int enabled_out_channels(weed_plant_t *plant, boolean count_repeats)
Definition: effects-weed.c:4043
CANCEL_GENERATOR_END
@ CANCEL_GENERATOR_END
generator was stopped
Definition: main.h:728
weed_get_all_names
LiVESList * weed_get_all_names(lives_fx_list_t list_type)
Definition: effects-weed.c:9865
_fx_dialog::mode
int mode
Definition: mainwindow.h:1845
WEED_LEAF_HOST_INPLACE
#define WEED_LEAF_HOST_INPLACE
Definition: effects-weed.h:69
mainwindow::ascrap_file
int ascrap_file
scrap file for recording audio scraps
Definition: mainwindow.h:875
LIVES_FX_CAT_VIDEO_TRANSITION
@ LIVES_FX_CAT_VIDEO_TRANSITION
Definition: effects.h:22
lives_fx_candidate_t
Definition: plugins.h:686
PB_QUALITY_MED
#define PB_QUALITY_MED
default
Definition: preferences.h:33
weed_channel_get_audio_data
WEED_GLOBAL_INLINE float ** weed_channel_get_audio_data(weed_plant_t *channel, int *naudchans)
Definition: weed-effects-utils.c:564
get_transition_param
int get_transition_param(weed_plant_t *filter, boolean skip_internal)
Definition: effects-weed.c:8656
WEED_PLANT_IS_FILTER_INSTANCE
#define WEED_PLANT_IS_FILTER_INSTANCE(plant)
Definition: weed-effects-utils.h:38
weed_filter_categorise
lives_fx_cat_t weed_filter_categorise(weed_plant_t *pl, int in_channels, int out_channels)
Definition: effects-weed.c:243
lives_memmove
#define lives_memmove
Definition: machinestate.h:64
weed_unload_all
void weed_unload_all(void)
unload all effects
Definition: effects-weed.c:5966
weed_layer_copy
weed_layer_t * weed_layer_copy(weed_layer_t *dlayer, weed_layer_t *slayer)
copy source layer slayer to dest layer dlayer
Definition: colourspace.c:13739
SCREEN_AREA_FOREGROUND
#define SCREEN_AREA_FOREGROUND
Definition: mainwindow.h:1680
lives_memcpy
#define lives_memcpy
Definition: machinestate.h:55
mainwindow::ignore_clipswitch
boolean ignore_clipswitch
Definition: mainwindow.h:1023
DEF_FRAME_HSIZE_UNSCALED
#define DEF_FRAME_HSIZE_UNSCALED
Definition: mainwindow.h:139
lives_strlen
LIVES_GLOBAL_INLINE size_t lives_strlen(const char *s)
Definition: machinestate.c:1468
future_prefs
_future_prefs * future_prefs
Definition: preferences.h:848
ce_thumbs_update_params
void ce_thumbs_update_params(int key, int i, LiVESList *list)
Definition: ce_thumbs.c:576
weed_filter_idx_get_package_name
char * weed_filter_idx_get_package_name(int idx)
Definition: effects-weed.c:9510
weed_get_indices_from_template
int * weed_get_indices_from_template(const char *pkg, const char *fxname, const char *auth, int version)
generate a list of filter indices from a given template.
Definition: effects-weed.c:10958
weed_filter_get_package_name
WEED_GLOBAL_INLINE char * weed_filter_get_package_name(weed_plant_t *filter)
Definition: weed-effects-utils.c:154
weed_layer_get_pixel_data
LIVES_GLOBAL_INLINE void ** weed_layer_get_pixel_data(weed_layer_t *layer, int *nplanes)
Definition: colourspace.c:13908
make_weed_hashname
char * make_weed_hashname(int filter_idx, boolean fullname, boolean use_extra_authors, char sep, boolean subs)
return value should be freed after use
Definition: effects-weed.c:10730
PLUGIN_COMPOUND_DIR
#define PLUGIN_COMPOUND_DIR
Definition: mainwindow.h:597
mainwindow::multitrack
lives_mt * multitrack
holds a pointer to the entire multitrack environment; NULL in Clip Edit mode
Definition: mainwindow.h:1087
LIVES_FX_CAT_AUDIO_VOL
@ LIVES_FX_CAT_AUDIO_VOL
Definition: effects.h:33
CURRENT_CLIP_IS_VALID
#define CURRENT_CLIP_IS_VALID
Definition: main.h:809
weed_param_get_nchoices
WEED_GLOBAL_INLINE int weed_param_get_nchoices(weed_plant_t *param)
Definition: weed-effects-utils.c:553
mainwindow::inst_fps
double inst_fps
Definition: mainwindow.h:781
create_blank_layer
weed_layer_t * create_blank_layer(weed_layer_t *layer, const char *image_ext, int width, int height, int target_palette)
fills layer with default values.
Definition: colourspace.c:9611
DEF_GEN_WIDTH
#define DEF_GEN_WIDTH
Definition: mainwindow.h:149
mainwindow::record_paused
volatile boolean record_paused
pause during recording
Definition: mainwindow.h:1557
mainwindow::last_grabbable_effect
uint32_t last_grabbable_effect
Definition: mainwindow.h:869
SPLASH_LEVEL_LOAD_RTE
#define SPLASH_LEVEL_LOAD_RTE
Definition: mainwindow.h:1599
free_key_defaults
void free_key_defaults(int key, int mode)
Definition: effects-weed.c:12396
mainwindow::ce_thumbs
boolean ce_thumbs
Definition: mainwindow.h:1676
lives_read_le_buffered
ssize_t lives_read_le_buffered(int fd, void *buf, ssize_t count, boolean allow_less)
Definition: utils.c:1158
lives_standard_menu_item_new_with_label
LiVESWidget * lives_standard_menu_item_new_with_label(const char *label)
Definition: widget-helper.c:8474
on_playall_activate
void on_playall_activate(LiVESMenuItem *menuitem, livespointer user_data)
Definition: callbacks.c:4530
rte_window
LiVESWidget * rte_window
Definition: rte_window.h:58
DEF_ALIGN
#define DEF_ALIGN
Definition: main.h:629
mainwindow::num_tr_applied
int num_tr_applied
number of transitions active
Definition: mainwindow.h:871
filename_from_fd
char * filename_from_fd(char *val, int fd)
: return filename from an open fd, freeing val first
Definition: utils.c:60
mainwindow::blend_clamping
int blend_clamping
Definition: mainwindow.h:982
main.h
AUDIO_PLAYER_SOX
#define AUDIO_PLAYER_SOX
Definition: preferences.h:48
WEED_LEAF_HOST_MENU_HIDE
#define WEED_LEAF_HOST_MENU_HIDE
Definition: effects-weed.h:61
AUD_PLAYER_SOX
#define AUD_PLAYER_SOX
Definition: preferences.h:42
lives_rfx_t::source_type
lives_rfx_source_t source_type
Definition: plugins.h:650
multitrack
lives_mt * multitrack(weed_plant_t *event_list, int orig_file, double fps)
create and return lives_mt struct
Definition: multitrack.c:6448
mainwindow::play_end
frames_t play_end
Definition: mainwindow.h:931
STOP_ON_VID_END
@ STOP_ON_VID_END
Definition: main.h:694
lives_lseek_buffered_rdonly
off_t lives_lseek_buffered_rdonly(int fd, off_t offset)
Definition: utils.c:895
get_enabled_channel
weed_plant_t * get_enabled_channel(weed_plant_t *inst, int which, boolean is_in)
for FILTER_INST
Definition: effects-weed.c:536
resample.h
AUDIO_SRC_EXT
#define AUDIO_SRC_EXT
Definition: preferences.h:206
FILTER_ERROR_NEEDS_REINIT
@ FILTER_ERROR_NEEDS_REINIT
Definition: effects-weed.h:23
_prefs::vj_mode
boolean vj_mode
Definition: preferences.h:459
weed_instance_is_resizer
LIVES_GLOBAL_INLINE boolean weed_instance_is_resizer(weed_plant_t *inst)
Definition: effects-weed.c:571
mainwindow::effort
int effort
Definition: mainwindow.h:1773
append_filter_map_event
weed_plant_t * append_filter_map_event(weed_plant_t *event_list, weed_timecode_t tc, void **init_events)
Definition: events.c:2968
FILTER_ERROR_MISSING_FRAME
@ FILTER_ERROR_MISSING_FRAME
Definition: effects-weed.h:18
mainwindow::ext_playback
boolean ext_playback
using external video playback plugin
Definition: mainwindow.h:773
WEED_LEAF_CLIP
#define WEED_LEAF_CLIP
Definition: colourspace.h:18
mainw
mainwindow * mainw
Definition: main.c:103
get_image_ext_for_type
const char * get_image_ext_for_type(lives_img_type_t imgtype)
Definition: utils.c:3025
WEED_LEAF_OUT_TRACKS
#define WEED_LEAF_OUT_TRACKS
Definition: events.h:48
WEED_LEAF_HOST_IDENTIFIER
#define WEED_LEAF_HOST_IDENTIFIER
Definition: effects-weed.h:90
mainwindow::pconx
lives_pconnect_t * pconx
list of out -> in param connections
Definition: mainwindow.h:1668
FILTER_ERROR_MEMORY_ERROR
@ FILTER_ERROR_MEMORY_ERROR
Definition: effects-weed.h:34
FILTER_ERROR_INTERPOLATION_FAILED
@ FILTER_ERROR_INTERPOLATION_FAILED
Definition: effects-weed.h:26
DEF_FRAME_HSIZE_43S_UNSCALED
#define DEF_FRAME_HSIZE_43S_UNSCALED
Definition: mainwindow.h:125
LIVES_RFX_SOURCE_WEED
@ LIVES_RFX_SOURCE_WEED
Definition: plugins.h:514
lives_chdir
int lives_chdir(const char *path, boolean no_error_dlg)
Definition: utils.c:1393
FILTER_ERROR_INVALID_FILTER
@ FILTER_ERROR_INVALID_FILTER
Definition: effects-weed.h:28
LIVES_EXT_SRC_NONE
#define LIVES_EXT_SRC_NONE
Definition: main.h:1043
weed_instance_unref
LIVES_GLOBAL_INLINE int weed_instance_unref(weed_plant_t *inst)
Definition: effects-weed.c:6234
show_weed_stats
void show_weed_stats(weed_plant_t *statsplant)
Definition: effects-weed.c:4476
WEED_IS_LAYER
#define WEED_IS_LAYER(plant)
Definition: colourspace.h:224
FILTER_ERROR_IS_AUDIO
@ FILTER_ERROR_IS_AUDIO
Definition: effects-weed.h:30
weed_layer_get_audio_rate
LIVES_GLOBAL_INLINE int weed_layer_get_audio_rate(weed_layer_t *layer)
Definition: colourspace.c:13992
AUDIO_PLAYER_PULSE
#define AUDIO_PLAYER_PULSE
used in pref and for external players (e.g -ao pulse, -aplayer pulse)
Definition: preferences.h:51
mainwindow::proc_ptr
xprocess * proc_ptr
Definition: mainwindow.h:1090
WEED_LEAF_HOST_PLUGIN_NAME
#define WEED_LEAF_HOST_PLUGIN_NAME
Definition: effects-weed.h:99
convert_layer_palette_full
boolean convert_layer_palette_full(weed_layer_t *layer, int outpl, int oclamping, int osampling, int osubspace, int tgamma)
convert the palette of a layer
Definition: colourspace.c:10160
rte_set_defs_activate
void rte_set_defs_activate(LiVESMenuItem *menuitem, livespointer user_data)
Definition: rte_window.c:2513
mainwindow::audio_frame_buffer
volatile lives_audio_buf_t * audio_frame_buffer
used for buffering / feeding audio to video generators
Definition: mainwindow.h:1697
_prefs::letterbox
boolean letterbox
playback with letterbox
Definition: preferences.h:362
filter_init_add_pchanges
void ** filter_init_add_pchanges(weed_plant_t *event_list, weed_plant_t *plant, weed_plant_t *init_event, int ntracks, int leave)
Definition: events.c:2648
frames_t
int frames_t
Definition: main.h:99
resize_layer
boolean resize_layer(weed_layer_t *layer, int width, int height, LiVESInterpType interp, int opal_hint, int oclamp_hint)
resize a layer
Definition: colourspace.c:12537
ALIGN_DEF
#define ALIGN_DEF
Definition: colourspace.h:32
lives_container_add
WIDGET_HELPER_GLOBAL_INLINE boolean lives_container_add(LiVESContainer *container, LiVESWidget *widget)
Definition: widget-helper.c:4929
mainwindow::blend_gamma
int blend_gamma
Definition: mainwindow.h:983
FILTER_ERROR_COPYING_FAILED
@ FILTER_ERROR_COPYING_FAILED
Definition: effects-weed.h:36
lives_widget_set_opacity
WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_set_opacity(LiVESWidget *widget, double opacity)
Definition: widget-helper.c:1757
WEED_LEAF_HOST_NEXT_INSTANCE
#define WEED_LEAF_HOST_NEXT_INSTANCE
Definition: effects-weed.h:104
lives_write_buffered
ssize_t lives_write_buffered(int fd, const char *buf, ssize_t count, boolean allow_fail)
Definition: utils.c:1226
LIVES_FX_CAT_COMPOSITOR
@ LIVES_FX_CAT_COMPOSITOR
Definition: effects.h:28
PB_QUALITY_LOW
#define PB_QUALITY_LOW
Definition: preferences.h:32
weed_param_value_irrelevant
WEED_GLOBAL_INLINE int weed_param_value_irrelevant(weed_plant_t *param)
Definition: weed-effects-utils.c:543
weed_channel_get_template
WEED_GLOBAL_INLINE weed_plant_t * weed_channel_get_template(weed_plant_t *channel)
Definition: weed-effects-utils.c:513
weed_layer_get_audio_data
LIVES_GLOBAL_INLINE float ** weed_layer_get_audio_data(weed_layer_t *layer, int *naudchans)
Definition: colourspace.c:13921
lives_widget_show_all
WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_show_all(LiVESWidget *widget)
Definition: widget-helper.c:1523
_prefs::allow_easing
boolean allow_easing
Definition: preferences.h:461
weed_layer_free
LIVES_GLOBAL_INLINE weed_layer_t * weed_layer_free(weed_layer_t *layer)
frees pixel_data for a layer, then the layer itself
Definition: colourspace.c:13883
WEED_LEAF_HOST_REINITING
#define WEED_LEAF_HOST_REINITING
Definition: effects-weed.h:80
WEED_LEAF_HOST_REFS
#define WEED_LEAF_HOST_REFS
Definition: effects-weed.h:72
mainwindow::abuf_frame_mutex
pthread_mutex_t abuf_frame_mutex
used to synch audio buffer for generators
Definition: mainwindow.h:1496
has_video_chans_in
boolean has_video_chans_in(weed_plant_t *filter, boolean count_opt)
Definition: effects-weed.c:620
weed_param_is_hidden
WEED_GLOBAL_INLINE int weed_param_is_hidden(weed_plant_t *param, int temporary)
Definition: weed-effects-utils.c:170
weed_layer_get_width_pixels
LIVES_GLOBAL_INLINE int weed_layer_get_width_pixels(weed_layer_t *layer)
Definition: colourspace.c:13947
mainwindow::fx_candidates
lives_fx_candidate_t fx_candidates[MAX_FX_CANDIDATE_TYPES]
< effects which can have candidates from which a delegate is selected (current examples are: audio_vo...
Definition: mainwindow.h:1514
weed_bg_generator_end
void weed_bg_generator_end(weed_plant_t *inst)
Definition: effects-weed.c:8318
_prefs::pb_quality
short pb_quality
Definition: preferences.h:31
weed_palette_get_plane_ratio_horizontal
LIVES_GLOBAL_INLINE double weed_palette_get_plane_ratio_horizontal(int pal, int plane)
Definition: colourspace.c:1480
get_nth_simple_param
int get_nth_simple_param(weed_plant_t *plant, int pnum)
Definition: effects-weed.c:8850
widget_opts
widget_opts_t widget_opts
Definition: widget-helper.h:1442
interpolate_params
boolean interpolate_params(weed_plant_t *inst, void **pchains, weed_timecode_t tc)
interpolate all in_parameters for filter_instance inst, using void **pchain, which is an array of par...
Definition: effects-weed.c:10684
weed_instance_get_filter
weed_plant_t * weed_instance_get_filter(weed_plant_t *inst, boolean get_compound_parent)
Definition: effects-weed.c:180
mainwindow::rte
volatile uint64_t rte
current max for VJ mode == 64 effects on fg clip
Definition: mainwindow.h:867
lives_clip_t::vsize
int vsize
frame height (vertical) in pixels
Definition: main.h:897
resize
void resize(double scale)
Definition: main.c:10230
FX_LIST_NAME
@ FX_LIST_NAME
Definition: effects-weed.h:45
PATH_MAX
#define PATH_MAX
Definition: main.h:255
mainwindow::blend_height
int blend_height
Definition: mainwindow.h:981
wge_inner
void wge_inner(weed_plant_t *inst)
deinit and instance(s) for generator, reset instance mapping
Definition: effects-weed.c:8154
mainwindow::spinbutton_pb_fps
LiVESWidget * spinbutton_pb_fps
Definition: mainwindow.h:1391
AUD_PLAYER_PULSE
#define AUD_PLAYER_PULSE
Definition: preferences.h:44
WEED_LEAF_HOST_PIXEL_DATA_CONTIGUOUS
#define WEED_LEAF_HOST_PIXEL_DATA_CONTIGUOUS
Definition: colourspace.h:20
on_record_perf_activate
void on_record_perf_activate(LiVESMenuItem *menuitem, livespointer user_data)
Definition: callbacks.c:4605
AUD_PLAYER_JACK
#define AUD_PLAYER_JACK
Definition: preferences.h:43
WEED_LEAF_HOST_FPS
#define WEED_LEAF_HOST_FPS
Definition: effects-weed.h:65
WEED_PLANT_IS_GUI
#define WEED_PLANT_IS_GUI(plant)
Definition: weed-effects-utils.h:51
lives_hashjoint
lives_hashentry lives_hashjoint[NHASH_TYPES]
Definition: effects-weed.c:390
FILTER_ERROR_NO_IN_CHANNELS
@ FILTER_ERROR_NO_IN_CHANNELS
Definition: effects-weed.h:24
mainwindow::is_processing
boolean is_processing
states
Definition: mainwindow.h:820
weed_chantmpl_get_max_repeats
WEED_GLOBAL_INLINE int weed_chantmpl_get_max_repeats(weed_plant_t *chantmpl)
Definition: weed-effects-utils.c:373
rte_keymode_get_type
char * rte_keymode_get_type(int key, int mode)
returns a string filter/instance type (or "")
Definition: effects-weed.c:9264
weed_layer_set_rowstrides
LIVES_GLOBAL_INLINE weed_layer_t * weed_layer_set_rowstrides(weed_layer_t *layer, int *rowstrides, int nplanes)
Definition: colourspace.c:9763
get_next_compound_inst
LIVES_GLOBAL_INLINE weed_plant_t * get_next_compound_inst(weed_plant_t *inst)
Definition: effects-weed.c:1164
weed_params_to_rfx
lives_param_t * weed_params_to_rfx(int npar, weed_plant_t *inst, boolean show_reinits)
Definition: plugins.c:3201
WEED_PLANT_IS_PLUGIN_INFO
#define WEED_PLANT_IS_PLUGIN_INFO(plant)
Definition: weed-effects-utils.h:31
mainwindow::pulsed_read
void * pulsed_read
Definition: mainwindow.h:1464
lives_rfx_t::source
void * source
points to the source (e.g. a weed_plant_t)
Definition: plugins.h:651
has_audio_chans_out
boolean has_audio_chans_out(weed_plant_t *filter, boolean count_opt)
Definition: effects-weed.c:695
WEED_LEAF_HOST_CHANNEL_CONNECTION
#define WEED_LEAF_HOST_CHANNEL_CONNECTION
Definition: effects-weed.h:106
lives_nanosleep_until_nonzero
#define lives_nanosleep_until_nonzero(condition)
Definition: machinestate.h:310
pconx_chain_data
boolean pconx_chain_data(int key, int mode, boolean is_audio_thread)
Definition: effects-data.c:1390
mainwindow::blend_subspace
int blend_subspace
Definition: mainwindow.h:982
audio.h
has_video_filters
boolean has_video_filters(boolean analysers_only)
Definition: effects-weed.c:3886
weed_leaf_set_monitor
weed_error_t weed_leaf_set_monitor(weed_plant_t *plant, const char *key, uint32_t seed_type, weed_size_t num_elems, void *values)
Definition: effects-weed.c:4422
CANCEL_AUD_END
@ CANCEL_AUD_END
video playback completed
Definition: main.h:737
rte_bg_gen_key
LIVES_GLOBAL_INLINE int rte_bg_gen_key(void)
Definition: effects-weed.c:9556
gamma_convert_layer
LIVES_GLOBAL_INLINE boolean gamma_convert_layer(int gamma_type, weed_layer_t *layer)
Definition: colourspace.c:12195
mainwindow::currticks
volatile ticks_t currticks
wall clock time, updated whenever lives_get_*_ticks is called
Definition: mainwindow.h:1005
weed_add_plant_flags
void weed_add_plant_flags(weed_plant_t *plant, uint32_t flags, const char *ign_prefix)
Definition: weed-effects-utils.c:67
_prefs::show_splash
boolean show_splash
Definition: preferences.h:291
WEED_LEAF_HOST_HANDLE
#define WEED_LEAF_HOST_HANDLE
Definition: effects-weed.h:76
lives_param_t::change_blocked
boolean change_blocked
Definition: plugins.h:600
rte_key_getmode
int rte_key_getmode(int key)
returns current active mode for a key (or -1)
Definition: effects-weed.c:9424
AUDIO_OPTS_FOLLOW_CLIPS
#define AUDIO_OPTS_FOLLOW_CLIPS
Definition: preferences.h:255
weed_clear_plant_flags
void weed_clear_plant_flags(weed_plant_t *plant, uint32_t flags, const char *ign_prefix)
Definition: weed-effects-utils.c:85
mainwindow::agen_samps_count
uint64_t agen_samps_count
count of samples since init
Definition: mainwindow.h:1651
weed_layer_create_from_generator
weed_plant_t * weed_layer_create_from_generator(weed_plant_t *inst, weed_timecode_t tc, int clipno)
Definition: effects-weed.c:7607
ce_thumbs_add_param_box
void ce_thumbs_add_param_box(int key, boolean remove)
Definition: ce_thumbs.c:456
lives_widget_set_fg_color
WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_set_fg_color(LiVESWidget *widget, LiVESWidgetState state, const LiVESWidgetColor *color)
Definition: widget-helper.c:2079
mainwindow::pwidth
int pwidth
PLAYBACK.
Definition: mainwindow.h:926
mainwindow::agen_key
volatile int agen_key
which fx key is generating audio [1 based] (or 0 for none)
Definition: mainwindow.h:1649
DEF_FRAME_VSIZE_43S_UNSCALED
#define DEF_FRAME_VSIZE_43S_UNSCALED
Definition: mainwindow.h:126
_ext_free
void _ext_free(void *p)
Definition: machinestate.c:556
_future_prefs::nfx_threads
int nfx_threads
Definition: preferences.h:815
weed_param_does_wrap
WEED_GLOBAL_INLINE int weed_param_does_wrap(weed_plant_t *param)
Definition: weed-effects-utils.c:548
mainwindow::cconx
lives_cconnect_t * cconx
list of out -> in alpha channel connections
Definition: mainwindow.h:1669
LIVES_FX_CAT_EFFECT
@ LIVES_FX_CAT_EFFECT
Definition: effects.h:24
WEED_LEAF_HOST_INSTANCE
#define WEED_LEAF_HOST_INSTANCE
Definition: effects-weed.h:83
_prefs::unstable_fx
boolean unstable_fx
Definition: preferences.h:361
WEED_LEAF_HOST_INTERNAL_CONNECTION_AUTOSCALE
#define WEED_LEAF_HOST_INTERNAL_CONNECTION_AUTOSCALE
Definition: effects-weed.h:103
weed_instance_get_out_params
WEED_GLOBAL_INLINE weed_plant_t ** weed_instance_get_out_params(weed_plant_t *instance, int *nparams)
Definition: weed-effects-utils.c:608
NHASH_TYPES
#define NHASH_TYPES
Definition: effects-weed.c:388
has_audio_chans_in
boolean has_audio_chans_in(weed_plant_t *filter, boolean count_opt)
Definition: effects-weed.c:640
_prefs::config_datadir
char config_datadir[PATH_MAX]
kept in locale encoding (general config files) (default ~/.local/share/lives)
Definition: preferences.h:64
mainwindow::new_blend_file
int new_blend_file
Definition: mainwindow.h:976
rte_key_getmaxmode
int rte_key_getmaxmode(int key)
returns highest mode which is set
Definition: effects-weed.c:9433
_prefs::letterbox_mt
boolean letterbox_mt
playback with letterbox (multitrack)
Definition: preferences.h:363
WEED_LEAF_DUPLICATE
#define WEED_LEAF_DUPLICATE
Definition: effects-weed.h:79
weed_leaf_set_host
weed_error_t weed_leaf_set_host(weed_plant_t *plant, const char *key, uint32_t seed_type, weed_size_t num_elems, void *values)
Definition: effects-weed.c:4371
WEED_LEAF_HOST_UNUSED
#define WEED_LEAF_HOST_UNUSED
Definition: effects-weed.h:81
lives_thread_t
LiVESList lives_thread_t
Definition: machinestate.h:434
weed_chantmpl_is_optional
WEED_GLOBAL_INLINE int weed_chantmpl_is_optional(weed_plant_t *chantmpl)
Definition: weed-effects-utils.c:367
WEED_LEAF_HOST_REPEATS
#define WEED_LEAF_HOST_REPEATS
Definition: effects-weed.h:73
weed_filter_get_out_paramtmpls
WEED_GLOBAL_INLINE weed_plant_t ** weed_filter_get_out_paramtmpls(weed_plant_t *filter, int *ntmpls)
Definition: weed-effects-utils.c:263
_prefs::perm_audio_reader
boolean perm_audio_reader
Definition: preferences.h:426
is_perchannel_multiw
boolean is_perchannel_multiw(weed_plant_t *param)
Definition: effects-weed.c:8693
FALSE
#define FALSE
Definition: videoplugin.h:60
gamma_convert_sub_layer
boolean gamma_convert_sub_layer(int gamma_type, double fileg, weed_layer_t *layer, int x, int y, int width, int height, boolean may_thread)
alter the transfer function of a Weed layer, from current value to gamma_type
Definition: colourspace.c:12124
LIVES_FX_CAT_AV_GENERATOR
@ LIVES_FX_CAT_AV_GENERATOR
Definition: effects.h:14
WEED_LEAF_HOST_DEFAULT
#define WEED_LEAF_HOST_DEFAULT
Definition: effects-weed.h:62
TEXTWIDGET_KEY
#define TEXTWIDGET_KEY
Definition: widget-helper.h:1492
DEFAULT_AUDIO_CHANS
#define DEFAULT_AUDIO_CHANS
Definition: audio.h:24
weed_reinit_effect
lives_filter_error_t weed_reinit_effect(weed_plant_t *inst, boolean reinit_compound)
Definition: effects-weed.c:1169
weed_palette_get_pixels_per_macropixel
LIVES_GLOBAL_INLINE int weed_palette_get_pixels_per_macropixel(int pal)
Definition: colourspace.c:1403
mainwindow::audio_end
int audio_end
Definition: mainwindow.h:771
mainwindow::afbuffer_clients
int afbuffer_clients
Definition: mainwindow.h:1699
calc_maxspect
void calc_maxspect(int rwidth, int rheight, int *cwidth, int *cheight)
Definition: utils.c:2174
FILTER_INFO_REINITED
@ FILTER_INFO_REINITED
values >= 512 are info
Definition: effects-weed.h:40
FX_KEYS_MAX
#define FX_KEYS_MAX
the rest of the keys are accessible through the multitrack renderer (must, be > FX_KEYS_MAX_VIRTUAL)
Definition: mainwindow.h:206
_
#define _(String)
Definition: support.h:44
weed_channel_get_palette_yuv
WEED_GLOBAL_INLINE int weed_channel_get_palette_yuv(weed_plant_t *channel, int *clamping, int *sampling, int *subspace)
Definition: weed-effects-utils.c:469
weed_delete_effectkey
boolean weed_delete_effectkey(int key, int mode)
unbinds a filter_class from a key/mode
Definition: effects-weed.c:9326
FILTER_ERROR_INVALID_INIT_EVENT
@ FILTER_ERROR_INVALID_INIT_EVENT
Definition: effects-weed.h:29
IS_NORMAL_CLIP
#define IS_NORMAL_CLIP(clip)
Definition: main.h:833
start_playback_async
void start_playback_async(int type)
Definition: saveplay.c:96
STYLE_1
#define STYLE_1
turn on theming if set
Definition: mainwindow.h:299
mainwindow::error
boolean error
Definition: mainwindow.h:801
weed_channel_get_width
WEED_GLOBAL_INLINE int weed_channel_get_width(weed_plant_t *channel)
width in macropixels
Definition: weed-effects-utils.c:415
capability::byte_order
int byte_order
Definition: main.h:577
weed_palette_get_bits_per_macropixel
LIVES_GLOBAL_INLINE int weed_palette_get_bits_per_macropixel(int pal)
Definition: colourspace.c:1411
weed_layer_is_audio
LIVES_GLOBAL_INLINE int weed_layer_is_audio(weed_layer_t *layer)
Definition: colourspace.c:9675
weed_get_sorted_filter
LIVES_GLOBAL_INLINE int weed_get_sorted_filter(int i)
Definition: effects-weed.c:9862
has_perchannel_multiw
boolean has_perchannel_multiw(weed_plant_t *filter)
Definition: effects-weed.c:8706
_prefs::dev_show_timing
boolean dev_show_timing
Definition: preferences.h:465
gamma_conv_params
void gamma_conv_params(int gamma_type, weed_layer_t *inst, boolean is_in)
Definition: colourspace.c:12019
LIVES_INLINE
#define LIVES_INLINE
Definition: main.h:238
LIVES_FX_CAT_DATA_PROCESSOR
@ LIVES_FX_CAT_DATA_PROCESSOR
Definition: effects.h:18
weed_instance_get_gui
WEED_GLOBAL_INLINE weed_plant_t * weed_instance_get_gui(weed_plant_t *inst, int create_if_not_exists)
Definition: weed-effects-utils.c:158
rec_param_change
void rec_param_change(weed_plant_t *inst, int pnum)
record a parameter value change in our event_list
Definition: effects-weed.c:9000
mainwindow::fx_is_auto
boolean fx_is_auto
Definition: mainwindow.h:1695
weed_add_effectkey_by_idx
int weed_add_effectkey_by_idx(int key, int idx)
we will add a filter_class at the next free slot for key, and return the slot number if idx is -1 (pr...
Definition: effects-weed.c:9747
lives_widget_show
WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_show(LiVESWidget *widget)
Definition: widget-helper.c:1505
AF_TYPE_A
@ AF_TYPE_A
Definition: effects.h:42
feeds_to_audio_filters
boolean feeds_to_audio_filters(int okey, int omode)
Definition: effects-data.c:2228
NEVER_STOP
@ NEVER_STOP
Definition: main.h:693
lives_strncmp
LIVES_GLOBAL_INLINE boolean lives_strncmp(const char *st1, const char *st2, size_t len)
returns FALSE if strings match
Definition: machinestate.c:1554
_ext_malloc
void * _ext_malloc(size_t n)
Definition: machinestate.c:530
weed_layer_get_audio_length
LIVES_GLOBAL_INLINE int weed_layer_get_audio_length(weed_layer_t *layer)
Definition: colourspace.c:14004
FILTER_ERROR_UNABLE_TO_RESIZE
@ FILTER_ERROR_UNABLE_TO_RESIZE
Definition: effects-weed.h:20
reset_frame_and_clip_index
void reset_frame_and_clip_index(void)
TODO: split into player, progress, dialogs.
Definition: effects-weed.c:12219
weed_channel_get_rowstrides
WEED_GLOBAL_INLINE int * weed_channel_get_rowstrides(weed_plant_t *channel, int *nplanes)
Definition: weed-effects-utils.c:487
_prefs::show_dev_opts
boolean show_dev_opts
Definition: preferences.h:463
deinit_easing_effects
void deinit_easing_effects(void)
switch off effects in easing out state after playback ends during playback, some effects don't deinit...
Definition: effects-weed.c:7381