LiVES  3.2.0
events.c
Go to the documentation of this file.
1 // events.c
2 // LiVES
3 // (c) G. Finch 2005 - 2020 <salsaman+lives@gmail.com>
4 // released under the GNU GPL 3 or later
5 // see file ../COPYING or www.gnu.org for licensing details
6 
7 // functions/structs for event_lists and events
8 
9 #include "main.h"
10 
11 #include "effects.h"
12 #include "interface.h"
13 #include "callbacks.h"
14 #include "resample.h"
15 #include "audio.h"
16 #include "cvirtual.h"
17 #ifdef LIBAV_TRANSCODE
18 #include "transcode.h"
19 #endif
20 
22 //#define DEBUG_EVENTS
23 
24 static int render_choice;
25 static weed_timecode_t last_rec_start_tc = -1;
26 static void **pchains[FX_KEYS_MAX]; // each pchain is an array of void *, these are parameter changes used for rendering
27 
29 
30 //lib stuff
32  if (!event || !WEED_PLANT_IS_EVENT(event)) return WEED_EVENT_TYPE_UNDEFINED;
33  return get_event_type(event);
34 }
35 
36 LIVES_GLOBAL_INLINE int weed_frame_event_get_tracks(weed_event_t *event, int **clips, int64_t **frames) {
37  int ntracks = 0, xntracks = 0;
38  if (!event || !WEED_EVENT_IS_FRAME(event)) return -1;
39  if (clips) *clips = weed_get_int_array_counted(event, WEED_LEAF_CLIPS, &ntracks);
40  else ntracks = weed_leaf_num_elements(event, WEED_LEAF_CLIPS);
41  if (frames) *frames = weed_get_int64_array_counted(event, WEED_LEAF_FRAMES, &xntracks);
42  else xntracks = weed_leaf_num_elements(event, WEED_LEAF_FRAMES);
43 
44  if (ntracks != xntracks && xntracks * ntracks > 0) {
45  if (clips) {
46  weed_free(*clips);
47  *clips = NULL;
48  }
49  if (frames) {
50  weed_free(*frames);
51  *frames = NULL;
52  }
53  return -2;
54  }
55  if (ntracks != 0) return ntracks;
56  return xntracks;
57 }
58 
59 LIVES_GLOBAL_INLINE int weed_frame_event_get_audio_tracks(weed_event_t *event, int **clips, double **seeks) {
61  int ntracks = 0, xntracks = 0;
62  if (!event || !WEED_EVENT_IS_FRAME(event)) return -1;
63  if (clips) *clips = weed_get_int_array_counted(event, WEED_LEAF_AUDIO_CLIPS, &ntracks);
64  else ntracks = weed_leaf_num_elements(event, WEED_LEAF_AUDIO_CLIPS);
65  if (seeks) *seeks = weed_get_double_array_counted(event, WEED_LEAF_AUDIO_SEEKS, &xntracks);
66  else xntracks = weed_leaf_num_elements(event, WEED_LEAF_AUDIO_SEEKS);
67 
68  if (ntracks != xntracks && xntracks * ntracks > 0) {
69  if (clips) {
70  weed_free(*clips);
71  *clips = NULL;
72  }
73  if (seeks) {
74  weed_free(*seeks);
75  *seeks = NULL;
76  }
77  return -2;
78  }
79  if (ntracks != 0) return ntracks;
80  return xntracks;
81 }
82 
83 LIVES_GLOBAL_INLINE weed_timecode_t weed_event_set_timecode(weed_event_t *event, weed_timecode_t tc) {
84  weed_timecode_t otc = get_event_timecode(event);
85  weed_set_int64_value(event, WEED_LEAF_TIMECODE, tc);
86  return otc;
87 }
88 
90  return get_event_timecode(event);
91 }
92 
93 
94 GNU_PURE void ** *get_event_pchains(void) {return pchains;}
95 
96 #define _get_or_zero(a, b, c) (a ? weed_get_##b##_value(a, c, NULL) : 0)
97 
98 LIVES_GLOBAL_INLINE weed_timecode_t get_event_timecode(weed_plant_t *plant) {
99  return _get_or_zero(plant, int64, WEED_LEAF_TIMECODE);
100 }
101 
102 
103 LIVES_GLOBAL_INLINE int get_event_type(weed_plant_t *plant) {
104  if (!plant) return 0;
105  return weed_get_int_value(plant, WEED_LEAF_EVENT_TYPE, NULL);
106 }
107 
108 
109 LIVES_GLOBAL_INLINE weed_plant_t *get_prev_event(weed_plant_t *event) {
110  return _get_or_zero(event, voidptr, WEED_LEAF_PREVIOUS);
111 }
112 
113 
114 LIVES_GLOBAL_INLINE weed_plant_t *get_next_event(weed_plant_t *event) {
115  return _get_or_zero(event, voidptr, WEED_LEAF_NEXT);
116 }
117 
118 
119 LIVES_GLOBAL_INLINE weed_plant_t *get_first_event(weed_plant_t *event_list) {
120  return _get_or_zero(event_list, voidptr, WEED_LEAF_FIRST);
121 }
122 
123 
124 LIVES_GLOBAL_INLINE weed_plant_t *get_last_event(weed_plant_t *event_list) {
125  return _get_or_zero(event_list, voidptr, WEED_LEAF_LAST);
126 }
127 
128 
129 boolean has_frame_event_at(weed_plant_t *event_list, weed_timecode_t tc, weed_plant_t **shortcut) {
130  weed_plant_t *event;
131  weed_timecode_t ev_tc;
132 
133  if (!shortcut || !*shortcut) event = get_first_frame_event(event_list);
134  else event = *shortcut;
135 
136  while ((ev_tc = get_event_timecode(event)) <= tc) {
137  if (ev_tc == tc && WEED_EVENT_IS_FRAME(event)) {
138  *shortcut = event;
139  return TRUE;
140  }
141  event = get_next_frame_event(event);
142  }
143  return FALSE;
144 }
145 
146 
147 int get_audio_frame_clip(weed_plant_t *event, int track) {
148  int numaclips, aclipnum = -1;
149  int *aclips;
150  register int i;
151 
152  if (!WEED_EVENT_IS_AUDIO_FRAME(event)) return -2;
153  aclips = weed_get_int_array_counted(event, WEED_LEAF_AUDIO_CLIPS, &numaclips);
154  for (i = 0; i < numaclips; i += 2) {
155  if (aclips[i] == track) {
156  aclipnum = aclips[i + 1];
157  break;
158  }
159  }
160  lives_freep((void **)&aclips);
161  return aclipnum;
162 }
163 
164 
165 double get_audio_frame_vel(weed_plant_t *event, int track) {
166  // vel of 0. is OFF
167  // warning - check for the clip >0 first
168  int *aclips = NULL;
169  double *aseeks = NULL, avel = 1.;
170  int numaclips;
171 
172  if (!WEED_EVENT_IS_AUDIO_FRAME(event)) return -2;
173  aclips = weed_get_int_array_counted(event, WEED_LEAF_AUDIO_CLIPS, &numaclips);
174  aseeks = weed_get_double_array(event, WEED_LEAF_AUDIO_SEEKS, NULL);
175  for (register int i = 0; i < numaclips; i += 2) {
176  if (aclips[i] == track) {
177  avel = aseeks[i + 1];
178  break;
179  }
180  }
181  lives_freep((void **)&aseeks);
182  lives_freep((void **)&aclips);
183  return avel;
184 }
185 
186 
187 double get_audio_frame_seek(weed_plant_t *event, int track) {
188  // warning - check for the clip >0 first
189  int *aclips = NULL;
190  double *aseeks = NULL, aseek = 0.;
191  int numaclips;
192 
193  if (!WEED_EVENT_IS_AUDIO_FRAME(event)) return -1000000.;
194  numaclips = weed_leaf_num_elements(event, WEED_LEAF_AUDIO_CLIPS);
195  aclips = weed_get_int_array_counted(event, WEED_LEAF_AUDIO_CLIPS, &numaclips);
196  aseeks = weed_get_double_array(event, WEED_LEAF_AUDIO_SEEKS, NULL);
197  for (register int i = 0; i < numaclips; i += 2) {
198  if (aclips[i] == track) {
199  aseek = aseeks[i];
200  break;
201  }
202  }
203  lives_freep((void **)&aseeks);
204  lives_freep((void **)&aclips);
205  return aseek;
206 }
207 
208 
209 int get_frame_event_clip(weed_plant_t *event, int layer) {
210  int numclips, clipnum;
211  int *clips;
212  if (!WEED_EVENT_IS_FRAME(event)) return -2;
213  clips = weed_get_int_array_counted(event, WEED_LEAF_CLIPS, &numclips);
214  if (numclips <= layer) {
215  lives_freep((void **)&clips);
216  return -3;
217  }
218  clipnum = clips[layer];
219  lives_free(clips);
220  return clipnum;
221 }
222 
223 
224 frames_t get_frame_event_frame(weed_plant_t *event, int layer) {
225  int numframes;
226  frames_t framenum;
227  int64_t *frames;
228  if (!WEED_EVENT_IS_FRAME(event)) return -2;
229  frames = weed_get_int64_array_counted(event, WEED_LEAF_FRAMES, &numframes);
230  if (numframes <= layer) {
231  lives_freep((void **)&frames);
232  return -3;
233  }
234  framenum = (frames_t)frames[layer];
235  lives_free(frames);
236  return framenum;
237 }
238 
239 
240 weed_event_t *lives_event_list_new(weed_event_t *elist, const char *cdate) {
241  weed_event_t *evelist;
242  weed_error_t error;
243  char *xdate = (char *)cdate;
244  char *cversion;
245 
246  if (elist) evelist = elist;
247  else {
248  evelist = weed_plant_new(WEED_PLANT_EVENT_LIST);
249  if (!evelist) return NULL;
250  error = weed_set_int_value(evelist, WEED_LEAF_WEED_EVENT_API_VERSION, WEED_EVENT_API_VERSION);
251  if (error == WEED_ERROR_MEMORY_ALLOCATION) return NULL;
252  error = weed_set_voidptr_value(evelist, WEED_LEAF_FIRST, NULL);
253  if (error == WEED_ERROR_MEMORY_ALLOCATION) return NULL;
254  error = weed_set_voidptr_value(evelist, WEED_LEAF_LAST, NULL);
255  if (error == WEED_ERROR_MEMORY_ALLOCATION) return NULL;
256  }
257 
258  if (!weed_plant_has_leaf(evelist, WEED_LEAF_WEED_API_VERSION))
259  error = weed_set_int_value(evelist, WEED_LEAF_WEED_API_VERSION, WEED_API_VERSION);
260  if (error == WEED_ERROR_MEMORY_ALLOCATION) return NULL;
261 
262  if (!weed_plant_has_leaf(evelist, WEED_LEAF_FILTER_API_VERSION))
263  error = weed_set_int_value(evelist, WEED_LEAF_FILTER_API_VERSION, WEED_FILTER_API_VERSION);
264  if (error == WEED_ERROR_MEMORY_ALLOCATION) return NULL;
265 
266  if (!xdate) {
267  struct timeval otv;
268  gettimeofday(&otv, NULL);
269  xdate = lives_datetime(otv.tv_sec, FALSE);
270  }
271  cversion = lives_strdup_printf("LiVES version %s", LiVES_VERSION);
272 
273  if (!weed_plant_has_leaf(evelist, WEED_LEAF_LIVES_CREATED_VERSION)) {
274  error = weed_set_string_value(evelist, WEED_LEAF_LIVES_CREATED_VERSION, cversion);
275  if (error == WEED_ERROR_MEMORY_ALLOCATION) return NULL;
276  }
277  if (!weed_plant_has_leaf(evelist, WEED_LEAF_CREATED_DATE)) {
278  error = weed_set_string_value(evelist, WEED_LEAF_CREATED_DATE, xdate);
279  if (error == WEED_ERROR_MEMORY_ALLOCATION) return NULL;
280  }
281 
282  if (!weed_plant_has_leaf(evelist, WEED_LEAF_LIVES_EDITED_VERSION)) {
283  error = weed_set_string_value(evelist, WEED_LEAF_LIVES_EDITED_VERSION, cversion);
284  if (error == WEED_ERROR_MEMORY_ALLOCATION) return NULL;
285  }
286  if (!weed_plant_has_leaf(evelist, WEED_LEAF_EDITED_DATE)) {
287  error = weed_set_string_value(evelist, WEED_LEAF_EDITED_DATE, xdate);
288  if (error == WEED_ERROR_MEMORY_ALLOCATION) return NULL;
289  }
290 
291  if (xdate != cdate) lives_free(xdate);
292  lives_free(cversion);
293  return evelist;
294 }
295 
296 
297 void unlink_event(weed_plant_t *event_list, weed_plant_t *event) {
298  // lives_rm event from event_list
299  // don't forget to adjust "timecode" before re-inserting !
300  weed_plant_t *prev_event = get_prev_event(event);
301  weed_plant_t *next_event = get_next_event(event);
302 
303  if (prev_event) weed_set_voidptr_value(prev_event, WEED_LEAF_NEXT, next_event);
304  if (next_event) weed_set_voidptr_value(next_event, WEED_LEAF_PREVIOUS, prev_event);
305 
306  if (get_first_event(event_list) == event) weed_set_voidptr_value(event_list, WEED_LEAF_FIRST, next_event);
307  if (get_last_event(event_list) == event) weed_set_voidptr_value(event_list, WEED_LEAF_LAST, prev_event);
308 }
309 
310 
311 void delete_event(weed_plant_t *event_list, weed_plant_t *event) {
312  // delete event from event_list
314  unlink_event(event_list, event);
315  if (mainw->multitrack) mt_fixup_events(mainw->multitrack, event, NULL);
316  weed_plant_free(event);
318 }
319 
320 
321 boolean insert_event_before(weed_plant_t *at_event, weed_plant_t *event) {
322  // insert event before at_event : returns FALSE if event is new start of event list
323  weed_plant_t *xevent = get_prev_event(at_event);
324  if (xevent) weed_set_voidptr_value(xevent, WEED_LEAF_NEXT, event);
325  weed_set_voidptr_value(event, WEED_LEAF_NEXT, at_event);
326  weed_set_voidptr_value(event, WEED_LEAF_PREVIOUS, xevent);
327  weed_set_voidptr_value(at_event, WEED_LEAF_PREVIOUS, event);
328  if (get_event_timecode(event) > get_event_timecode(at_event))
329  lives_printerr("Warning ! Inserted out of order event type %d before %d\n", get_event_type(event), get_event_type(at_event));
330  return (xevent != NULL);
331 }
332 
333 
334 boolean insert_event_after(weed_plant_t *at_event, weed_plant_t *event) {
335  // insert event after at_event : returns FALSE if event is new end of event list
336  weed_plant_t *xevent = get_next_event(at_event);
337  if (xevent) weed_set_voidptr_value(xevent, WEED_LEAF_PREVIOUS, event);
338  weed_set_voidptr_value(event, WEED_LEAF_PREVIOUS, at_event);
339  weed_set_voidptr_value(event, WEED_LEAF_NEXT, xevent);
340  weed_set_voidptr_value(at_event, WEED_LEAF_NEXT, event);
341  if (get_event_timecode(event) < get_event_timecode(at_event))
342  lives_printerr("Warning ! Inserted out of order event type %d after %d\n", get_event_type(event), get_event_type(at_event));
343  return (xevent != NULL);
344 }
345 
346 
347 void replace_event(weed_plant_t *event_list, weed_plant_t *at_event, weed_plant_t *event) {
348  // replace at_event with event; free at_event
349  if (mainw->multitrack) mt_fixup_events(mainw->multitrack, at_event, event);
350  weed_set_int64_value(event, WEED_LEAF_TIMECODE, get_event_timecode(at_event));
351  if (!insert_event_after(at_event, event)) weed_set_voidptr_value(event_list, WEED_LEAF_LAST, event);
352  delete_event(event_list, at_event);
353 }
354 
355 
356 weed_plant_t *get_next_frame_event(weed_plant_t *event) {
357  weed_plant_t *next;
358  if (!event) return NULL;
359  next = get_next_event(event);
360  while (next) {
361  if (WEED_EVENT_IS_FRAME(next)) return next;
362  next = get_next_event(next);
363  }
364  return NULL;
365 }
366 
367 
368 weed_plant_t *get_prev_frame_event(weed_plant_t *event) {
369  weed_plant_t *prev;
370  if (!event) return NULL;
371  prev = get_prev_event(event);
372  while (prev) {
373  if (WEED_EVENT_IS_FRAME(prev)) return prev;
374  prev = get_prev_event(prev);
375  }
376  return NULL;
377 }
378 
379 
380 weed_plant_t *get_next_audio_frame_event(weed_plant_t *event) {
381  weed_plant_t *next;
382  if (!event) return NULL;
383  next = get_next_event(event);
384  while (next) {
385  if (WEED_EVENT_IS_AUDIO_FRAME(next)) return next;
386  next = get_next_event(next);
387  }
388  return NULL;
389 }
390 
391 
392 weed_plant_t *get_prev_audio_frame_event(weed_plant_t *event) {
393  weed_plant_t *prev;
394  if (!event) return NULL;
395  prev = get_prev_event(event);
396  while (prev) {
397  if (WEED_EVENT_IS_AUDIO_FRAME(prev)) return prev;
398  prev = get_prev_event(prev);
399  }
400  return NULL;
401 }
402 
403 
404 weed_plant_t *get_first_frame_event(weed_plant_t *event_list) {
405  weed_plant_t *event;
406 
407  if (!event_list) return NULL;
408 
409  event = get_first_event(event_list);
410 
411  while (event) {
412  if (WEED_EVENT_IS_FRAME(event)) return event;
413  event = get_next_event(event);
414  }
415  return NULL;
416 }
417 
418 
419 weed_plant_t *get_last_frame_event(weed_plant_t *event_list) {
420  weed_plant_t *event;
421 
422  if (!event_list) return NULL;
423 
424  event = get_last_event(event_list);
425 
426  while (event) {
427  if (WEED_EVENT_IS_FRAME(event)) return event;
428  event = get_prev_event(event);
429  }
430  return NULL;
431 }
432 
433 
434 weed_plant_t *get_audio_block_start(weed_plant_t *event_list, int track, weed_timecode_t tc, boolean seek_back) {
435  // find any event which starts an audio block on track at timecode tc
436  // if seek_back is true we go back in time to find a possible start
437  // otherwise just check the current frame event
438 
439  weed_plant_t *event = get_frame_event_at_or_before(event_list, tc, NULL);
440  if (get_audio_frame_clip(event, track) > -1 && get_audio_frame_vel(event, track) != 0.) return event;
441  if (!seek_back) return NULL;
442 
443  while ((event = get_prev_frame_event(event)) != NULL) {
444  if (get_audio_frame_clip(event, track) > -1 && get_audio_frame_vel(event, track) != 0.) return event;
445  }
446 
447  return NULL;
448 }
449 
450 static LiVESList *trans_list = NULL;
451 
452 typedef struct {
453  weed_event_t *in_event;
454  weed_event_t *out_event;
455 } trans_entry;
456 
457 static void add_init_to_ttable(weed_event_t *in_event, weed_event_t *out_event) {
458  trans_entry *tr_entry = (trans_entry *)lives_malloc(sizeof(trans_entry));
459  tr_entry->in_event = in_event;
460  tr_entry->out_event = out_event;
461  trans_list = lives_list_prepend(trans_list, tr_entry);
462 }
463 
464 static weed_event_t *find_init_event_by_id(weed_plant_t *event, boolean remove) {
465  LiVESList *list = trans_list;
466  for (; list; list = list->next) {
467  trans_entry *tr_entry = (trans_entry *)list->data;
468  if (tr_entry->in_event == event) {
469  if (!remove) return tr_entry->out_event;
470  else {
471  weed_event_t *out_event = tr_entry->out_event;
472  if (list->prev) list->prev->next = list->next;
473  else trans_list = list->next;
474  if (list->next) list->next->prev = list->prev;
475  list->prev = list->next = NULL;
476  lives_free(list->data);
477  list->data = NULL;
478  lives_list_free(list);
479  return out_event;
480  }
481  }
482  }
483  return NULL;
484 }
485 
486 void reset_ttable(void) {lives_list_free_all(&trans_list);}
487 
488 
489 void remove_frame_from_event(weed_plant_t *event_list, weed_plant_t *event, int track) {
490  // TODO - memcheck
491  weed_timecode_t tc;
492 
493  int *clips;
494  int64_t *frames;
495 
496  int numframes;
497  register int i;
498 
499  if (!WEED_EVENT_IS_FRAME(event)) return;
500 
501  tc = get_event_timecode(event);
502 
503  clips = weed_get_int_array_counted(event, WEED_LEAF_CLIPS, &numframes);
504  frames = weed_get_int64_array(event, WEED_LEAF_FRAMES, NULL);
505 
506  if (track == numframes - 1) numframes--;
507  else {
508  clips[track] = -1;
509  frames[track] = 0;
510  }
511 
512  // if stack is empty, we will replace with a blank frame
513  for (i = 0; i < numframes && clips[i] < 1; i++);
514  if (i == numframes) {
515  if (event == get_last_event(event_list) && !WEED_EVENT_IS_AUDIO_FRAME(event)) delete_event(event_list, event);
516  else event_list = insert_blank_frame_event_at(event_list, tc, &event);
517  } else event_list = insert_frame_event_at(event_list, tc, numframes, clips, frames, &event);
518  lives_free(frames);
519  lives_free(clips);
520 }
521 
522 
523 boolean is_blank_frame(weed_plant_t *event, boolean count_audio) {
524  int clip, numframes;
525  int64_t frame;
526 
527  if (!WEED_EVENT_IS_FRAME(event)) return FALSE;
528  if (count_audio && WEED_EVENT_IS_AUDIO_FRAME(event)) {
529  int *aclips = weed_get_int_array(event, WEED_LEAF_AUDIO_CLIPS, NULL);
530  if (aclips[1] > 0) {
531  lives_free(aclips);
532  return FALSE; // has audio seek
533  }
534  lives_free(aclips);
535  }
536  numframes = weed_leaf_num_elements(event, WEED_LEAF_CLIPS);
537  if (numframes > 1) return FALSE;
538  clip = weed_get_int_value(event, WEED_LEAF_CLIPS, NULL);
539  frame = weed_get_int64_value(event, WEED_LEAF_FRAMES, NULL);
540 
541  if (clip < 0 || frame <= 0) return TRUE;
542  return FALSE;
543 }
544 
545 
546 void remove_end_blank_frames(weed_plant_t *event_list, boolean remove_filter_inits) {
547  // remove blank frames from end of event list
548  weed_plant_t *event = get_last_event(event_list), *prevevent;
549  while (event) {
550  prevevent = get_prev_event(event);
551  if (!WEED_EVENT_IS_FRAME(event) && !WEED_EVENT_IS_FILTER_INIT(event)) {
552  event = prevevent;
553  continue;
554  }
555  if (remove_filter_inits && WEED_EVENT_IS_FILTER_INIT(event)) remove_filter_from_event_list(event_list, event);
556  else {
557  if (!is_blank_frame(event, TRUE)) break;
558  delete_event(event_list, event);
559  }
560  event = prevevent;
561  }
562 }
563 
564 
565 weed_timecode_t get_next_paramchange(void **pchange_next, weed_timecode_t end_tc) {
566  weed_timecode_t min_tc = end_tc;
567  register int i = 0;
568  if (!pchange_next) return end_tc;
569  for (; pchange_next[i]; i++) if (get_event_timecode((weed_plant_t *)pchange_next[i]) < min_tc)
570  min_tc = get_event_timecode((weed_plant_t *)pchange_next[i]);
571  return min_tc;
572 }
573 
574 
575 weed_timecode_t get_prev_paramchange(void **pchange_prev, weed_timecode_t start_tc) {
576  weed_timecode_t min_tc = start_tc;
577  register int i = 0;
578  if (!pchange_prev) return start_tc;
579  for (; pchange_prev[i]; i++) if (get_event_timecode((weed_plant_t *)pchange_prev[i]) < min_tc)
580  min_tc = get_event_timecode((weed_plant_t *)pchange_prev[i]);
581  return min_tc;
582 }
583 
584 
585 boolean is_init_pchange(weed_plant_t *init_event, weed_plant_t *pchange_event) {
586  // a PARAM_CHANGE is an init_pchange iff both events have the same tc, and there is no frame event between the two events
587  // normally we could check the "in_params" of the init_event for a match, but here we may be rebuilding the event list
588  // so the values will not confer
589  weed_plant_t *event = init_event;
590  weed_timecode_t tc = get_event_timecode(event);
591  if (tc != get_event_timecode(pchange_event)) return FALSE;
592 
593  while (event && event != pchange_event) {
594  if (WEED_EVENT_IS_FRAME(event)) return FALSE;
595  event = get_next_event(event);
596  }
597  return TRUE;
598 }
599 
600 
622 weed_plant_t *event_copy_and_insert(weed_plant_t *in_event, weed_timecode_t out_tc, weed_plant_t *event_list,
623  weed_event_t **ret_event) {
624  void **in_pchanges;
625 
626  weed_plant_t *event;
627  weed_plant_t *event_after = NULL;
628  weed_plant_t *event_before = NULL;
629  weed_plant_t *filter;
630 
631  void *init_event, *new_init_event, **init_events;
632  char *filter_hash;
633 
634  weed_error_t error;
635 
636  int etype;
637  int num_events;
638  int idx, num_params;
639 
640  int i;
641 
642  if (!in_event) return event_list;
643 
644  if (!event_list) {
645  event_list = lives_event_list_new(NULL, NULL);
646  if (!event_list) return NULL;
647  event_before = NULL;
648  } else {
649  event_before = get_last_event(event_list);
650  while (event_before) {
651  if (get_event_timecode(event_before) < out_tc || (get_event_timecode(event_before) == out_tc
652  && (!WEED_EVENT_IS_FRAME(event_before) ||
653  WEED_EVENT_IS_FILTER_DEINIT(in_event)))) break;
654  event_before = get_prev_event(event_before);
655  }
656  }
657 
658  event = weed_plant_copy(in_event);
659  weed_event_set_timecode(event, out_tc);
660 
661  // need to repoint our avol_init_event
662  if (mainw->multitrack) mt_fixup_events(mainw->multitrack, in_event, event);
663  if (!event) return NULL;
664 
665  if (!event_before) {
666  event_after = get_first_event(event_list);
667  error = weed_set_voidptr_value(event_list, WEED_LEAF_FIRST, event);
668  if (error == WEED_ERROR_MEMORY_ALLOCATION) return NULL;
669  if (event_after == event) event_after = NULL;
670  } else {
671  event_after = get_next_event(event_before);
672  error = weed_set_voidptr_value(event_before, WEED_LEAF_NEXT, event);
673  if (error == WEED_ERROR_MEMORY_ALLOCATION) return NULL;
674  }
675 
676  error = weed_set_voidptr_value(event, WEED_LEAF_PREVIOUS, event_before);
677  if (error == WEED_ERROR_MEMORY_ALLOCATION) return NULL;
678 
679  error = weed_set_voidptr_value(event, WEED_LEAF_NEXT, event_after);
680  if (error == WEED_ERROR_MEMORY_ALLOCATION) return NULL;
681 
682  if (!event_after) error = weed_set_voidptr_value(event_list, WEED_LEAF_LAST, event);
683  else error = weed_set_voidptr_value(event_after, WEED_LEAF_PREVIOUS, event);
684  if (error == WEED_ERROR_MEMORY_ALLOCATION) return NULL;
685 
686  etype = get_event_type(in_event);
687  switch (etype) {
688  case WEED_EVENT_TYPE_FILTER_INIT:
689  /* weed_leaf_delete(event, WEED_LEAF_EVENT_ID); */
690  /* error = weed_set_voidptr_value(event, WEED_LEAF_EVENT_ID, (void *)in_event); */
691  /* if (error == WEED_ERROR_MEMORY_ALLOCATION) return NULL; */
692  add_init_to_ttable(in_event, event);
693  filter_hash = weed_get_string_value(event, WEED_LEAF_FILTER, &error);
694  if (error == WEED_ERROR_MEMORY_ALLOCATION) return NULL;
695  if ((idx = weed_get_idx_for_hashname(filter_hash, TRUE)) != -1) {
696  filter = get_weed_filter(idx);
697  if ((num_params = num_in_params(filter, FALSE, FALSE)) > 0) {
698  in_pchanges = (void **)lives_malloc((num_params + 1) * sizeof(void *));
699  if (!in_pchanges) return NULL;
700  for (i = 0; i < num_params; i++) in_pchanges[i] = NULL;
701  error = weed_set_voidptr_array(event, WEED_LEAF_IN_PARAMETERS, num_params,
702  in_pchanges); // set all to NULL, we will re-fill as we go along
703  lives_free(in_pchanges);
704  if (error == WEED_ERROR_MEMORY_ALLOCATION) {
705  lives_free(filter_hash);
706  return NULL;
707  }
708  }
709  lives_free(filter_hash);
710  }
711  break;
712  case WEED_EVENT_TYPE_FILTER_DEINIT:
713  init_event = weed_get_voidptr_value(in_event, WEED_LEAF_INIT_EVENT, NULL);
714  new_init_event = find_init_event_by_id(init_event, TRUE);
715  error = weed_set_voidptr_value(event, WEED_LEAF_INIT_EVENT, new_init_event);
716  if (error == WEED_ERROR_MEMORY_ALLOCATION) return NULL;
717  /* weed_leaf_delete((weed_plant_t *)new_init_event, WEED_LEAF_EVENT_ID); */
718  /* error = weed_set_voidptr_value((weed_plant_t *)new_init_event, WEED_LEAF_EVENT_ID, */
719  /* (void *)new_init_event); // useful later for event_list_rectify */
720  weed_leaf_delete((weed_plant_t *)new_init_event,
721  WEED_LEAF_DEINIT_EVENT); // delete since we assign a placeholder with int64 type
722  weed_set_plantptr_value((weed_plant_t *)new_init_event, WEED_LEAF_DEINIT_EVENT, event);
723  if (error == WEED_ERROR_MEMORY_ALLOCATION) return NULL;
724  break;
725  case WEED_EVENT_TYPE_FILTER_MAP:
726  // set WEED_LEAF_INIT_EVENTS property
727  init_events = weed_get_voidptr_array_counted(in_event, WEED_LEAF_INIT_EVENTS, &num_events);
728  if (error == WEED_ERROR_MEMORY_ALLOCATION) return NULL;
729  for (i = 0; i < num_events; i++) {
730  init_events[i] = find_init_event_by_id(init_events[i], FALSE);
731  }
732  error = weed_set_voidptr_array(event, WEED_LEAF_INIT_EVENTS, num_events, init_events);
733  lives_free(init_events);
734  if (error == WEED_ERROR_MEMORY_ALLOCATION) return NULL;
735  /*
736  // remove any prior FILTER_MAPs at the same timecode
737  event_before = get_prev_event(event);
738  while (event_before) {
739  weed_plant_t *event_before_event_before = get_prev_event(event_before);
740  weed_timecode_t tc = get_event_timecode(event_before);
741  if (tc < out_tc) break;
742  if (tc == out_tc && (WEED_EVENT_IS_FILTER_MAP(event_before))) delete_event(event_list, event_before);
743  event_before = event_before_event_before;
744  }*/
745  break;
746  case WEED_EVENT_TYPE_PARAM_CHANGE:
747  init_event = weed_get_voidptr_value(in_event, WEED_LEAF_INIT_EVENT, &error);
748  new_init_event = find_init_event_by_id(init_event, FALSE);
749  error = weed_set_voidptr_value(event, WEED_LEAF_INIT_EVENT, new_init_event);
750  if (error == WEED_ERROR_MEMORY_ALLOCATION) return NULL;
751  weed_set_voidptr_value(event, WEED_LEAF_NEXT_CHANGE, NULL);
752  weed_set_voidptr_value(event, WEED_LEAF_PREV_CHANGE, NULL);
753  break;
754  }
755 
756  if (ret_event) *ret_event = event;
757  return event_list;
758 }
759 
760 
761 boolean frame_event_has_frame_for_track(weed_plant_t *event, int track) {
762  int *clips, numclips;
763  int64_t *frames;
764 
765  clips = weed_get_int_array_counted(event, WEED_LEAF_CLIPS, &numclips);
766  if (numclips <= track) return FALSE;
767  frames = weed_get_int64_array(event, WEED_LEAF_FRAMES, NULL);
768 
769  if (clips[track] > 0 && frames[track] > 0) {
770  lives_free(clips);
771  lives_free(frames);
772  return TRUE;
773  }
774  lives_free(clips);
775  lives_free(frames);
776  return FALSE;
777 }
778 
779 
780 weed_plant_t *get_frame_event_at(weed_plant_t *event_list, weed_timecode_t tc, weed_plant_t *shortcut, boolean exact) {
781  // if exact is FALSE, we can get a frame event just after tc
782  weed_plant_t *event, *next_event;
783  weed_timecode_t xtc, next_tc = 0;
784 
785  if (!event_list) return NULL;
786  if (shortcut) event = shortcut;
787  else event = get_first_frame_event(event_list);
788  while (event) {
789  next_event = get_next_event(event);
790  if (next_event) next_tc = get_event_timecode(next_event);
791  xtc = get_event_timecode(event);
792  if ((labs(tc - xtc) <= 10 || ((next_tc > tc || !next_event) && !exact)) &&
793  WEED_EVENT_IS_FRAME(event)) {
794  return event;
795  }
796  if (xtc > tc) return NULL;
797  event = next_event;
798  }
799  return NULL;
800 }
801 
802 
803 boolean filter_map_after_frame(weed_plant_t *fmap) {
804  // return TRUE if filter_map follows frame at same timecode
805  weed_plant_t *frame = get_prev_frame_event(fmap);
806 
807  if (frame && get_event_timecode(frame) == get_event_timecode(fmap)) return TRUE;
808  return FALSE;
809 }
810 
811 
812 weed_plant_t *get_frame_event_at_or_before(weed_plant_t *event_list, weed_timecode_t tc, weed_plant_t *shortcut) {
813  weed_plant_t *frame_event = get_frame_event_at(event_list, tc, shortcut, FALSE);
814  while (frame_event && get_event_timecode(frame_event) > tc) {
815  frame_event = get_prev_frame_event(frame_event);
816  }
817  return frame_event;
818 }
819 
820 
821 weed_plant_t *get_filter_map_after(weed_plant_t *event, int ctrack) {
822  // get filter_map following event; if ctrack!=LIVES_TRACK_ANY then we ignore filter maps with no in_track/out_track == ctrack
823  void **init_events;
824  weed_plant_t *init_event;
825  int num_init_events;
826 
827  register int i;
828 
829  while (event) {
830  if (WEED_EVENT_IS_FILTER_MAP(event)) {
831  if (ctrack == LIVES_TRACK_ANY) return event;
832  if (!weed_plant_has_leaf(event, WEED_LEAF_INIT_EVENTS)) {
833  event = get_next_event(event);
834  continue;
835  }
836  init_events = weed_get_voidptr_array_counted(event, WEED_LEAF_INIT_EVENTS, &num_init_events);
837  if (!init_events[0]) {
838  lives_free(init_events);
839  event = get_next_event(event);
840  continue;
841  }
842  for (i = 0; i < num_init_events; i++) {
843  init_event = (weed_plant_t *)init_events[i];
844 
845  if (init_event_is_relevant(init_event, ctrack)) {
846  lives_free(init_events);
847  return event;
848  }
849 
850  }
851  lives_freep((void **)&init_events);
852  }
853  event = get_next_event(event);
854  }
855  return NULL;
856 }
857 
858 
859 boolean init_event_is_relevant(weed_plant_t *init_event, int ctrack) {
860  // see if init_event mentions ctrack as an in_track or an out_track
861 
862  int *in_tracks, *out_tracks;
863  int num_tracks;
864 
865  register int j;
866 
867  //if (init_event_is_process_last(init_event)) return FALSE;
868 
869  if (weed_plant_has_leaf(init_event, WEED_LEAF_IN_TRACKS)) {
870  in_tracks = weed_get_int_array_counted(init_event, WEED_LEAF_IN_TRACKS, &num_tracks);
871  for (j = 0; j < num_tracks; j++) {
872  if (in_tracks[j] == ctrack) {
873  lives_free(in_tracks);
874  return TRUE;
875  }
876  }
877  lives_freep((void **)&in_tracks);
878  }
879 
880  if (weed_plant_has_leaf(init_event, WEED_LEAF_OUT_TRACKS)) {
881  out_tracks = weed_get_int_array_counted(init_event, WEED_LEAF_OUT_TRACKS, &num_tracks);
882  for (j = 0; j < num_tracks; j++) {
883  if (out_tracks[j] == ctrack) {
884  lives_free(out_tracks);
885  return TRUE;
886  }
887  }
888  lives_freep((void **)&out_tracks);
889  }
890 
891  return FALSE;
892 }
893 
894 
895 weed_plant_t *get_filter_map_before(weed_plant_t *event, int ctrack, weed_plant_t *stop_event) {
896  // get filter_map preceding event; if ctrack!=LIVES_TRACK_ANY then we ignore
897  // filter maps with no in_track/out_track == ctrack
898 
899  // we will stop searching when we reach stop_event; if it is NULL we will search back to
900  // start of event list
901 
902  void **init_events;
903  weed_plant_t *init_event;
904  int num_init_events;
905 
906  register int i;
907 
908  while (event != stop_event && event) {
909  if (WEED_EVENT_IS_FILTER_MAP(event)) {
910  if (ctrack == LIVES_TRACK_ANY) return event;
911  if (!weed_plant_has_leaf(event, WEED_LEAF_INIT_EVENTS)) {
912  event = get_prev_event(event);
913  continue;
914  }
915  init_events = weed_get_voidptr_array_counted(event, WEED_LEAF_INIT_EVENTS, &num_init_events);
916  if (!init_events[0]) {
917  lives_free(init_events);
918  event = get_prev_event(event);
919  continue;
920  }
921  for (i = 0; i < num_init_events; i++) {
922  init_event = (weed_plant_t *)init_events[i];
923  if (init_event_is_relevant(init_event, ctrack)) {
924  lives_free(init_events);
925  return event;
926  }
927  }
928  lives_freep((void **)&init_events);
929  }
930  event = get_prev_event(event);
931  }
932  return event;
933 }
934 
935 
936 void **get_init_events_before(weed_plant_t *event, weed_plant_t *init_event, boolean add) {
937  // find previous FILTER_MAP event, and append or delete new init_event
938  void **init_events = NULL, **new_init_events;
939  int error, num_init_events = 0;
940  register int i, j = 0;
941 
942  while (event) {
943  if (WEED_EVENT_IS_FILTER_MAP(event)) {
944  if ((init_events = weed_get_voidptr_array_counted(event, WEED_LEAF_INIT_EVENTS, &num_init_events)) != NULL) {
945  if (add) new_init_events = (void **)lives_malloc((num_init_events + 2) * sizeof(void *));
946  else new_init_events = (void **)lives_malloc((num_init_events + 1) * sizeof(void *));
947 
948  for (i = 0; i < num_init_events; i++) if ((add || (init_event && (init_events[i] != (void *)init_event))) &&
949  init_events[0]) {
950  new_init_events[j++] = init_events[i];
951  if (add && init_events[i] == (void *)init_event) add = FALSE; // don't add twice
952  }
953 
954  if (add) {
955  char *fhash;
956  weed_plant_t *filter;
957  int k, l, tflags;
958  // add before any "process_last" events
959  k = j;
960  while (k > 0) {
961  k--;
962  if (mainw->multitrack && init_events[k] == mainw->multitrack->avol_init_event) {
963  // add before the audio mixer
964  continue;
965  }
966  fhash = weed_get_string_value((weed_plant_t *)init_events[k], WEED_LEAF_FILTER, &error);
968  lives_free(fhash);
969  if (weed_plant_has_leaf(filter, WEED_LEAF_FLAGS)) {
970  tflags = weed_get_int_value(filter, WEED_LEAF_FLAGS, &error);
971  if (tflags & WEED_FILTER_HINT_PROCESS_LAST) {
972  // add before any "process_last" filters
973  continue;
974  }
975  }
976  k++;
977  break;
978  }
979  // insert new event at slot k
980  // make gap for new filter
981  for (l = j - 1; l >= k; l--) {
982  new_init_events[l + 1] = new_init_events[l];
983  }
984  new_init_events[k] = (void *)init_event;
985  j++;
986  }
987 
988  new_init_events[j] = NULL;
989  if (init_events) lives_free(init_events);
990  return new_init_events;
991  }
992  if (init_events) lives_free(init_events);
993  }
994  event = get_prev_event(event);
995  }
996  // no previous init_events found
997  if (add) {
998  new_init_events = (void **)lives_malloc(2 * sizeof(void *));
999  new_init_events[0] = (void *)init_event;
1000  new_init_events[1] = NULL;
1001  } else {
1002  new_init_events = (void **)lives_malloc(sizeof(void *));
1003  new_init_events[0] = NULL;
1004  }
1005  return new_init_events;
1006 }
1007 
1008 
1009 void update_filter_maps(weed_plant_t *event, weed_plant_t *end_event, weed_plant_t *init_event) {
1010  // append init_event to all FILTER_MAPS between event and end_event
1011 
1012  while (event != end_event) {
1013  if (WEED_EVENT_IS_FILTER_MAP(event)) {
1014  add_init_event_to_filter_map(event, init_event, NULL);
1015  }
1016  event = get_next_event(event);
1017  }
1018 }
1019 
1020 
1021 void insert_filter_init_event_at(weed_plant_t *event_list, weed_plant_t *at_event, weed_plant_t *event) {
1022  // insert event as first event at same timecode as (FRAME_EVENT) at_event
1023  weed_timecode_t tc = get_event_timecode(at_event);
1024  weed_set_int64_value(event, WEED_LEAF_TIMECODE, tc);
1025 
1026  while (at_event) {
1027  at_event = get_prev_event(at_event);
1028  if (!at_event) break;
1029  if (get_event_timecode(at_event) < tc) {
1030  if (!insert_event_after(at_event, event)) weed_set_voidptr_value(event_list, WEED_LEAF_LAST, event);
1031 
1032  return;
1033  }
1034  }
1035 
1036  // event is first
1037  at_event = get_first_event(event_list);
1038  insert_event_before(at_event, event);
1039  weed_set_voidptr_value(event_list, WEED_LEAF_FIRST, event);
1040 }
1041 
1042 
1043 void insert_filter_deinit_event_at(weed_plant_t *event_list, weed_plant_t *at_event, weed_plant_t *event) {
1044  // insert event as last at same timecode as (FRAME_EVENT) at_event
1045  weed_timecode_t tc = get_event_timecode(at_event);
1046  weed_set_int64_value(event, WEED_LEAF_TIMECODE, tc);
1047 
1048  while (at_event) {
1049  if (WEED_EVENT_IS_FRAME(at_event)) {
1050  if (!insert_event_after(at_event, event)) weed_set_voidptr_value(event_list, WEED_LEAF_LAST, event);
1051  return;
1052  }
1053  if (get_event_timecode(at_event) > tc) {
1054  if (!insert_event_before(at_event, event)) weed_set_voidptr_value(event_list, WEED_LEAF_FIRST, event);
1055  return;
1056  }
1057  at_event = get_next_event(at_event);
1058  }
1059  // event is last
1060  at_event = get_last_event(event_list);
1061  insert_event_after(at_event, event);
1062  weed_set_voidptr_value(event_list, WEED_LEAF_LAST, event);
1063 }
1064 
1065 
1066 boolean insert_filter_map_event_at(weed_plant_t *event_list, weed_plant_t *at_event,
1067  weed_plant_t *event, boolean before_frames) {
1068  // insert event as last event at same timecode as (FRAME_EVENT) at_event
1069  weed_timecode_t tc = get_event_timecode(at_event);
1070  weed_set_int64_value(event, WEED_LEAF_TIMECODE, tc);
1071 
1072  if (before_frames) {
1073  while (at_event) {
1074  at_event = get_prev_event(at_event);
1075  if (!at_event) break;
1076  if (WEED_EVENT_IS_FILTER_MAP(at_event)) {
1077  // found an existing FILTER_MAP, we can simply replace it
1078  if (mainw->filter_map == at_event) mainw->filter_map = event;
1079  replace_event(event_list, at_event, event);
1080  return TRUE;
1081  }
1082  if (WEED_EVENT_IS_FILTER_INIT(at_event) || get_event_timecode(at_event) < tc) {
1083  if (!insert_event_after(at_event, event)) weed_set_voidptr_value(event_list, WEED_LEAF_LAST, event);
1084  return TRUE;
1085  }
1086  }
1087  // event is first
1088  at_event = get_first_event(event_list);
1089  insert_event_before(at_event, event);
1090  weed_set_voidptr_value(event_list, WEED_LEAF_FIRST, event);
1091  } else {
1092  // insert after frame events
1093  while (at_event) {
1094  at_event = get_next_event(at_event);
1095  if (!at_event) break;
1096  if (WEED_EVENT_IS_FILTER_MAP(at_event)) {
1097  // found an existing FILTER_MAP, we can simply replace it
1098  if (mainw->filter_map == at_event) mainw->filter_map = event;
1099  replace_event(event_list, at_event, event);
1100  return TRUE;
1101  }
1102  if (get_event_timecode(at_event) > tc) {
1103  if (!insert_event_before(at_event, event)) weed_set_voidptr_value(event_list, WEED_LEAF_FIRST, event);
1104  return TRUE;
1105  }
1106  }
1107  // event is last
1108  at_event = get_last_event(event_list);
1109  insert_event_after(at_event, event);
1110  weed_set_voidptr_value(event_list, WEED_LEAF_LAST, event);
1111  }
1112  return TRUE;
1113 }
1114 
1115 
1116 void insert_param_change_event_at(weed_plant_t *event_list, weed_plant_t *at_event, weed_plant_t *event) {
1117  // insert event as last at same timecode as (FRAME_EVENT) at_event, before FRAME event
1118  weed_timecode_t tc = get_event_timecode(at_event);
1119  weed_set_int64_value(event, WEED_LEAF_TIMECODE, tc);
1120 
1121  //weed_add_plant_flags(event, WEED_LEAF_READONLY_PLUGIN); // protect it for interpolation
1122 
1123  while (at_event) {
1124  if (get_event_timecode(at_event) < tc) {
1125  if (!insert_event_after(at_event, event)) weed_set_voidptr_value(event_list, WEED_LEAF_LAST, event);
1126  return;
1127  }
1128  if (WEED_EVENT_IS_FILTER_INIT(at_event)) {
1129  if (!insert_event_after(at_event, event)) weed_set_voidptr_value(event_list, WEED_LEAF_LAST, event);
1130  return;
1131  }
1132  if (WEED_EVENT_IS_FRAME(at_event)) {
1133  if (!insert_event_before(at_event, event)) weed_set_voidptr_value(event_list, WEED_LEAF_FIRST, event);
1134  return;
1135  }
1136  at_event = get_prev_event(at_event);
1137  }
1138  at_event = get_first_event(event_list);
1139  insert_event_before(at_event, event);
1140  weed_set_voidptr_value(event_list, WEED_LEAF_FIRST, event);
1141 }
1142 
1143 
1144 weed_plant_t *insert_frame_event_at(weed_plant_t *event_list, weed_timecode_t tc, int numframes, int *clips,
1145  int64_t *frames, weed_plant_t **shortcut) {
1146  // we will insert a FRAME event at timecode tc, after any other events (except for deinit events) at timecode tc
1147  // if there is an existing FRAME event at tc, we replace it with the new frame
1148 
1149  // shortcut can be a nearest guess of where the frame should be
1150 
1151  // returns NULL on memory error
1152 
1153  weed_plant_t *event = NULL, *new_event, *prev;
1154  weed_plant_t *new_event_list, *xevent_list;
1155  weed_timecode_t xtc;
1156  weed_error_t error;
1157  if (!event_list || !get_first_frame_event(event_list)) {
1158  // no existing event list, or no frames, append
1159  event_list = append_frame_event(event_list, tc, numframes, clips, frames);
1160  if (!event_list) return NULL; // memory error
1161  if (shortcut) *shortcut = get_last_event(event_list);
1162  return event_list;
1163  }
1164 
1165  // skip the next part if we know we have to add at end
1166  if (tc <= get_event_timecode(get_last_event(event_list))) {
1167  if (shortcut && *shortcut) {
1168  event = *shortcut;
1169  } else event = get_first_event(event_list);
1170 
1171  if (get_event_timecode(event) > tc) {
1172  // step backwards until we get to a frame before where we want to add
1173  while (event && get_event_timecode(event) > tc) event = get_prev_frame_event(event);
1174  // event can come out NULL (add before first frame event), in which case we fall through
1175  } else {
1176  while (event && get_event_timecode(event) < tc) event = get_next_frame_event(event);
1177 
1178  // we reached the end, so we will add after last frame event
1179  if (!event) event = get_last_frame_event(event_list);
1180  }
1181 
1182  while (event && (((xtc = get_event_timecode(event)) < tc) || (xtc == tc && (!WEED_EVENT_IS_FILTER_DEINIT(event))))) {
1183  if (shortcut) *shortcut = event;
1184  if (xtc == tc && WEED_EVENT_IS_FRAME(event)) {
1185  error = weed_set_int_array(event, WEED_LEAF_CLIPS, numframes, clips);
1186  if (error == WEED_ERROR_MEMORY_ALLOCATION) return NULL;
1187  error = weed_set_int64_array(event, WEED_LEAF_FRAMES, numframes, frames);
1188  if (error == WEED_ERROR_MEMORY_ALLOCATION) return NULL;
1189  return event_list;
1190  }
1191  event = get_next_event(event);
1192  }
1193 
1194  // we passed all events in event_list; there was one or more at tc, but none were deinits or frames
1195  if (!event) {
1196  event = get_last_event(event_list);
1197  // event is after last event, append it
1198  if (!(xevent_list = append_frame_event(event_list, tc, numframes, clips, frames))) return NULL;
1199  event_list = xevent_list;
1200  if (shortcut) *shortcut = get_last_event(event_list);
1201  return event_list;
1202  }
1203  } else {
1204  // event is after last event, append it
1205  if (!(xevent_list = append_frame_event(event_list, tc, numframes, clips, frames))) return NULL;
1206  event_list = xevent_list;
1207  if (shortcut) *shortcut = get_last_event(event_list);
1208  return event_list;
1209  }
1210 
1211  // add frame before "event"
1212 
1213  if (!(new_event_list = append_frame_event(NULL, tc, numframes, clips, frames))) return NULL;
1214  // new_event_list is now an event_list with one frame event. We will steal its event and prepend it !
1215 
1216  new_event = get_first_event(new_event_list);
1217 
1218  prev = get_prev_event(event);
1219 
1220  if (prev) {
1221  error = weed_set_voidptr_value(prev, WEED_LEAF_NEXT, new_event);
1222  if (error == WEED_ERROR_MEMORY_ALLOCATION) return NULL;
1223  }
1224  error = weed_set_voidptr_value(new_event, WEED_LEAF_PREVIOUS, prev);
1225  if (error == WEED_ERROR_MEMORY_ALLOCATION) return NULL;
1226  error = weed_set_voidptr_value(new_event, WEED_LEAF_NEXT, event);
1227  if (error == WEED_ERROR_MEMORY_ALLOCATION) return NULL;
1228  error = weed_set_voidptr_value(event, WEED_LEAF_PREVIOUS, new_event);
1229  if (error == WEED_ERROR_MEMORY_ALLOCATION) return NULL;
1230 
1231  if (get_first_event(event_list) == event) {
1232  error = weed_set_voidptr_value(event_list, WEED_LEAF_FIRST, new_event);
1233  if (error == WEED_ERROR_MEMORY_ALLOCATION) return NULL;
1234  }
1235 
1236  weed_plant_free(new_event_list);
1237 
1238  if (shortcut) *shortcut = new_event;
1239  return event_list;
1240 }
1241 
1242 
1243 void insert_audio_event_at(weed_plant_t *event, int track, int clipnum, double seek, double vel) {
1244  // insert/update audio event at (existing) frame event
1245  int *new_aclips;
1246  double *new_aseeks;
1247  double arv; // vel needs rounding to four dp (i don't know why, but otherwise we get some weird rounding errors)
1248 
1249  register int i;
1250 
1251  arv = (double)(myround(vel * 10000.)) / 10000.;
1252 
1253  if (WEED_EVENT_IS_AUDIO_FRAME(event)) {
1254  int *aclips = NULL;
1255  double *aseeks = NULL;
1256  int num_aclips = weed_frame_event_get_audio_tracks(event, &aclips, &aseeks);
1257 
1258  for (i = 0; i < num_aclips; i += 2) {
1259  if (aclips[i] == track) {
1260  if (clipnum <= 0) {
1261  if (num_aclips <= 2) {
1262  weed_leaf_delete(event, WEED_LEAF_AUDIO_CLIPS);
1263  weed_leaf_delete(event, WEED_LEAF_AUDIO_SEEKS);
1264  lives_freep((void **)&aseeks);
1265  lives_freep((void **)&aclips);
1266  return;
1267  } else {
1268  int *new_aclips = (int *)lives_malloc((num_aclips - 2) * sizint);
1269  double *new_aseeks = (double *)lives_malloc((num_aclips - 2) * sizdbl);
1270  int j, k = 0;
1271  for (j = 0; j < num_aclips; j += 2) {
1272  if (j != i) {
1273  new_aclips[k] = aclips[j];
1274  new_aclips[k + 1] = aclips[j + 1];
1275  new_aseeks[k] = aseeks[j];
1276  new_aseeks[k + 1] = aseeks[j + 1];
1277  k += 2;
1278  }
1279  }
1280 
1281  weed_set_int_array(event, WEED_LEAF_AUDIO_CLIPS, num_aclips - 2, new_aclips);
1282  weed_set_double_array(event, WEED_LEAF_AUDIO_SEEKS, num_aclips - 2, new_aseeks);
1283  lives_free(new_aclips);
1284  lives_free(new_aseeks);
1285  lives_freep((void **)&aseeks);
1286  lives_freep((void **)&aclips);
1287  return;
1288  }
1289  }
1290 
1291  // update existing values
1292  aclips[i + 1] = clipnum;
1293  aseeks[i] = seek;
1294  aseeks[i + 1] = arv;
1295 
1296  weed_set_int_array(event, WEED_LEAF_AUDIO_CLIPS, num_aclips, aclips);
1297  weed_set_double_array(event, WEED_LEAF_AUDIO_SEEKS, num_aclips, aseeks);
1298  lives_freep((void **)&aseeks);
1299  lives_freep((void **)&aclips);
1300  return;
1301  }
1302  }
1303 
1304  if (clipnum <= 0) {
1305  lives_freep((void **)&aseeks);
1306  lives_freep((void **)&aclips);
1307  return;
1308  }
1309 
1310  // append
1311  new_aclips = (int *)lives_malloc((num_aclips + 2) * sizint);
1312  for (i = 0; i < num_aclips; i++) new_aclips[i] = aclips[i];
1313  new_aclips[i++] = track;
1314  new_aclips[i] = clipnum;
1315 
1316  new_aseeks = (double *)lives_malloc((num_aclips + 2) * sizdbl);
1317  for (i = 0; i < num_aclips; i++) new_aseeks[i] = aseeks[i];
1318  new_aseeks[i++] = seek;
1319  new_aseeks[i++] = arv;
1320 
1321  weed_set_int_array(event, WEED_LEAF_AUDIO_CLIPS, i, new_aclips);
1322  weed_set_double_array(event, WEED_LEAF_AUDIO_SEEKS, i, new_aseeks);
1323 
1324  lives_free(new_aclips);
1325  lives_free(new_aseeks);
1326 
1327  lives_freep((void **)&aseeks);
1328  lives_freep((void **)&aclips);
1329  return;
1330  }
1331  // create new values
1332 
1333  new_aclips = (int *)lives_malloc(2 * sizint);
1334  new_aclips[0] = track;
1335  new_aclips[1] = clipnum;
1336 
1337  new_aseeks = (double *)lives_malloc(2 * sizdbl);
1338  new_aseeks[0] = seek;
1339  new_aseeks[1] = arv;
1340 
1341  weed_set_int_array(event, WEED_LEAF_AUDIO_CLIPS, 2, new_aclips);
1342  weed_set_double_array(event, WEED_LEAF_AUDIO_SEEKS, 2, new_aseeks);
1343 
1344  lives_free(new_aclips);
1345  lives_free(new_aseeks);
1346 }
1347 
1348 
1349 void remove_audio_for_track(weed_plant_t *event, int track) {
1350  // delete audio for a FRAME_EVENT with audio for specified track
1351  // if nothing left, delete the audio leaves
1352  int num_atracks;
1353  int *aclip_index = weed_get_int_array_counted(event, WEED_LEAF_AUDIO_CLIPS, &num_atracks);
1354  double *aseek_index = weed_get_double_array(event, WEED_LEAF_AUDIO_SEEKS, NULL);
1355  int *new_aclip_index = (int *)lives_malloc(num_atracks * sizint);
1356  double *new_aseek_index = (double *)lives_malloc(num_atracks * sizdbl);
1357 
1358  register int i, j = 0;
1359 
1360  for (i = 0; i < num_atracks; i += 2) {
1361  if (aclip_index[i] == track) continue;
1362  new_aclip_index[j] = aclip_index[i];
1363  new_aclip_index[j + 1] = aclip_index[i + 1];
1364  new_aseek_index[j] = aseek_index[i];
1365  new_aseek_index[j + 1] = aseek_index[i + 1];
1366  j += 2;
1367  }
1368  if (j == 0) {
1369  weed_leaf_delete(event, WEED_LEAF_AUDIO_CLIPS);
1370  weed_leaf_delete(event, WEED_LEAF_AUDIO_SEEKS);
1371  } else {
1372  weed_set_int_array(event, WEED_LEAF_AUDIO_CLIPS, j, new_aclip_index);
1373  weed_set_double_array(event, WEED_LEAF_AUDIO_SEEKS, j, new_aseek_index);
1374  }
1375  lives_free(aclip_index);
1376  lives_free(aseek_index);
1377  lives_free(new_aclip_index);
1378  lives_free(new_aseek_index);
1379 }
1380 
1381 
1382 weed_plant_t *append_marker_event(weed_plant_t *event_list, weed_timecode_t tc, int marker_type) {
1383  weed_plant_t *event, *prev;
1384 
1385  if (!event_list) {
1386  event_list = lives_event_list_new(NULL, NULL);
1387  if (!event_list) return NULL;
1388  }
1389 
1390  event = weed_plant_new(WEED_PLANT_EVENT);
1391  weed_set_voidptr_value(event, WEED_LEAF_NEXT, NULL);
1392 
1393  // TODO - error check
1394  weed_set_int64_value(event, WEED_LEAF_TIMECODE, tc);
1395  weed_set_int_value(event, WEED_LEAF_EVENT_TYPE, WEED_EVENT_TYPE_MARKER);
1396 
1397  weed_set_int_value(event, WEED_LEAF_LIVES_TYPE, marker_type);
1398 
1399 #ifdef DEBUG_EVENTS
1400  g_print("adding marker event %p at tc %"PRId64"\n", init_events[0], tc);
1401 #endif
1402 
1403  if (!get_first_event(event_list)) {
1404  weed_set_voidptr_value(event_list, WEED_LEAF_FIRST, event);
1405  weed_set_voidptr_value(event, WEED_LEAF_PREVIOUS, NULL);
1406  } else {
1407  weed_set_voidptr_value(event, WEED_LEAF_PREVIOUS, get_last_event(event_list));
1408  }
1409  //weed_add_plant_flags(event, WEED_LEAF_READONLY_PLUGIN);
1410  prev = get_prev_event(event);
1411  if (prev) weed_set_voidptr_value(prev, WEED_LEAF_NEXT, event);
1412  weed_set_voidptr_value(event_list, WEED_LEAF_LAST, event);
1413 
1414  return event_list;
1415 }
1416 
1417 
1418 weed_plant_t *insert_marker_event_at(weed_plant_t *event_list, weed_plant_t *at_event, int marker_type, livespointer data) {
1419  // insert marker event as first event at same timecode as (FRAME_EVENT) at_event
1420  weed_timecode_t tc = get_event_timecode(at_event);
1421  weed_plant_t *event = weed_plant_new(WEED_PLANT_EVENT);
1422  register int i;
1423 
1424  weed_set_int_value(event, WEED_LEAF_EVENT_TYPE, WEED_EVENT_TYPE_MARKER);
1425  weed_set_int_value(event, WEED_LEAF_LIVES_TYPE, marker_type);
1426  weed_set_int64_value(event, WEED_LEAF_TIMECODE, tc);
1427 
1428  if (marker_type == EVENT_MARKER_BLOCK_START || marker_type == EVENT_MARKER_BLOCK_UNORDERED) {
1429  weed_set_int_value(event, WEED_LEAF_TRACKS, LIVES_POINTER_TO_INT(data));
1430  }
1431  //weed_add_plant_flags(event, WEED_LEAF_READONLY_PLUGIN);
1432 
1433  while (at_event) {
1434  at_event = get_prev_event(at_event);
1435  if (!at_event) break;
1436  switch (marker_type) {
1439  if (WEED_EVENT_IS_MARKER(at_event) && (weed_get_int_value(at_event, WEED_LEAF_LIVES_TYPE, NULL) == marker_type)) {
1440  // add to existing event
1441  int num_tracks;
1442  int *tracks = weed_get_int_array_counted(at_event, WEED_LEAF_TRACKS, &num_tracks);
1443  int *new_tracks = (int *)lives_malloc((num_tracks + 1) * sizint);
1444  for (i = 0; i < num_tracks; i++) {
1445  new_tracks[i] = tracks[i];
1446  }
1447  new_tracks[i] = LIVES_POINTER_TO_INT(data); // add new track
1448  weed_set_int_array(at_event, WEED_LEAF_TRACKS, num_tracks + 1, new_tracks);
1449  lives_free(new_tracks);
1450  lives_free(tracks);
1451  weed_plant_free(event); // new event not used
1452  return event;
1453  }
1454  if (get_event_timecode(at_event) < tc) {
1455  // create new event
1456  if (!insert_event_after(at_event, event)) weed_set_voidptr_value(event_list, WEED_LEAF_LAST, event);
1457  return event;
1458  }
1459  break;
1460  }
1461  }
1462 
1463  // event is first
1464  at_event = get_first_event(event_list);
1465  insert_event_before(at_event, event);
1466  weed_set_voidptr_value(event_list, WEED_LEAF_FIRST, event);
1467 
1468  return event;
1469 }
1470 
1471 
1472 LIVES_GLOBAL_INLINE weed_plant_t *insert_blank_frame_event_at(weed_plant_t *event_list, weed_timecode_t tc,
1473  weed_plant_t **shortcut) {
1474  int clip = -1;
1475  int64_t frame = 0;
1476  return insert_frame_event_at(event_list, tc, 1, &clip, &frame, shortcut);
1477 }
1478 
1479 
1480 void remove_filter_from_event_list(weed_plant_t *event_list, weed_plant_t *init_event) {
1481  int error;
1482  weed_plant_t *deinit_event = weed_get_plantptr_value(init_event, WEED_LEAF_DEINIT_EVENT, &error);
1483  weed_plant_t *event = init_event;
1484  weed_plant_t *filter_map = get_filter_map_before(init_event, LIVES_TRACK_ANY, NULL);
1485  void **new_init_events;
1486  weed_timecode_t deinit_tc = get_event_timecode(deinit_event);
1487  weed_plant_t *event_next;
1488 
1489  register int i;
1490 
1491  while (event && get_event_timecode(event) <= deinit_tc) {
1492  event_next = get_next_event(event);
1493  // update filter_maps
1494  if (WEED_EVENT_IS_FILTER_MAP(event)) {
1495  new_init_events = get_init_events_before(event, init_event, FALSE);
1496  for (i = 0; new_init_events[i]; i++);
1497  if (i == 0) weed_set_voidptr_value(event, WEED_LEAF_INIT_EVENTS, NULL);
1498  else weed_set_voidptr_array(event, WEED_LEAF_INIT_EVENTS, i, new_init_events);
1499  lives_free(new_init_events);
1500 
1501  if ((!filter_map && i == 0) || (filter_map && compare_filter_maps(filter_map, event, LIVES_TRACK_ANY)))
1502  delete_event(event_list, event);
1503  else filter_map = event;
1504  }
1505  event = event_next;
1506  }
1507 
1508  // remove param_changes
1509  if (weed_plant_has_leaf(init_event, WEED_LEAF_IN_PARAMETERS)) {
1510  void *pchain_next;
1511  int num_params;
1512  void **pchain = weed_get_voidptr_array_counted(init_event, WEED_LEAF_IN_PARAMETERS, &num_params);
1513  for (i = 0; i < num_params; i++) {
1514  while (pchain[i]) {
1515  pchain_next = weed_get_voidptr_value((weed_plant_t *)pchain[i], WEED_LEAF_NEXT_CHANGE, NULL);
1516  delete_event(event_list, (weed_plant_t *)pchain[i]);
1517  pchain[i] = pchain_next;
1518  }
1519  }
1520  lives_free(pchain);
1521  }
1522 
1523  delete_event(event_list, init_event);
1524  delete_event(event_list, deinit_event);
1525 }
1526 
1527 
1528 static boolean remove_event_from_filter_map(weed_plant_t *fmap, weed_plant_t *event) {
1529  // return FALSE if result is NULL filter_map
1530  int num_inits;
1531  void **init_events = weed_get_voidptr_array_counted(fmap, WEED_LEAF_INIT_EVENTS, &num_inits);
1532  void **new_init_events;
1533 
1534  int i, j = 0;
1535 
1536  new_init_events = (void **)lives_malloc(num_inits * sizeof(void *));
1537  for (i = 0; i < num_inits; i++) {
1538  if (init_events[i] != event) new_init_events[j++] = init_events[i];
1539  }
1540 
1541  if (j == 0 || (j == 1 && (!event || !init_events[0]))) weed_set_voidptr_value(fmap, WEED_LEAF_INIT_EVENTS, NULL);
1542  else weed_set_voidptr_array(fmap, WEED_LEAF_INIT_EVENTS, j, new_init_events);
1543  lives_free(init_events);
1544  lives_free(new_init_events);
1545 
1546  return (!(j == 0 || (j == 1 && !event)));
1547 }
1548 
1549 
1550 LIVES_GLOBAL_INLINE boolean init_event_in_list(void **init_events, int num_inits, weed_plant_t *event) {
1551  register int i;
1552  if (!init_events || !init_events[0]) return FALSE;
1553  for (i = 0; i < num_inits; i++) {
1554  if (init_events[i] == (void **)event) return TRUE;
1555  }
1556  return FALSE;
1557 }
1558 
1559 
1560 boolean filter_map_has_event(weed_plant_t *fmap, weed_plant_t *event) {
1561  int num_inits;
1562  void **init_events = weed_get_voidptr_array_counted(fmap, WEED_LEAF_INIT_EVENTS, &num_inits);
1563  boolean ret = init_event_in_list(init_events, num_inits, event);
1564 
1565  lives_free(init_events);
1566  return ret;
1567 }
1568 
1569 
1570 boolean filter_init_has_owner(weed_plant_t *init_event, int track) {
1571  int *owners;
1572  int num_owners;
1573  int i;
1574 
1575  if (!weed_plant_has_leaf(init_event, WEED_LEAF_IN_TRACKS)) return FALSE;
1576 
1577  owners = weed_get_int_array_counted(init_event, WEED_LEAF_IN_TRACKS, &num_owners);
1578 
1579  for (i = 0; i < num_owners; i++) {
1580  if (owners[i] == track) {
1581  lives_free(owners);
1582  return TRUE;
1583  }
1584  }
1585  lives_free(owners);
1586  return FALSE;
1587 }
1588 
1589 
1590 void backup_host_tags(weed_plant_t *event_list, weed_timecode_t curr_tc) {
1591  // when redrawing the current frame during rendering (in multitrack mode)
1592  // host keys will change (see backup_weed_instances() in effects-weed.c)
1593  // here we backup the host_tag (which maps a filter_init to a "key" and thus to an instance)
1594 
1595  weed_plant_t *event = get_first_event(event_list);
1596  weed_timecode_t tc;
1597 
1598  while (event && (tc = get_event_timecode(event)) <= curr_tc) {
1599  if (WEED_EVENT_IS_FILTER_INIT(event)) weed_leaf_copy(event, WEED_LEAF_HOST_TAG_COPY, event, WEED_LEAF_HOST_TAG);
1600  event = get_next_event(event);
1601  }
1602 }
1603 
1604 
1605 void restore_host_tags(weed_plant_t *event_list, weed_timecode_t curr_tc) {
1606  // when redrawing the current frame during rendering (in multitrack mode)
1607  // host keys will change (see backup_weed_instances() in effects-weed.c)
1608  // here we restore the host_tag (which maps a filter_init to a "key" and thus to an instance)
1609 
1610  weed_plant_t *event = get_first_event(event_list);
1611  weed_timecode_t tc;
1612 
1613  while (event && (tc = get_event_timecode(event)) <= curr_tc) {
1614  if (WEED_EVENT_IS_FILTER_INIT(event)) {
1615  weed_leaf_copy(event, WEED_LEAF_HOST_TAG, event, WEED_LEAF_HOST_TAG_COPY);
1616  weed_leaf_delete(event, WEED_LEAF_HOST_TAG_COPY);
1617  }
1618  event = get_next_event(event);
1619  }
1620 }
1621 
1622 
1623 void delete_param_changes_after_deinit(weed_plant_t *event_list, weed_plant_t *init_event) {
1624  // delete parameter value changes following the filter_deinit
1625  // this can be called when a FILTER_DEINIT is moved
1626  void **init_events;
1627  weed_plant_t *deinit_event = weed_get_plantptr_value(init_event, WEED_LEAF_DEINIT_EVENT, NULL);
1628  weed_timecode_t deinit_tc = get_event_timecode(deinit_event);
1629  weed_timecode_t pchain_tc;
1630 
1631  void *pchain, *pchain_next;
1632 
1633  int i, num_inits;
1634 
1635  if (!weed_plant_has_leaf(init_event, WEED_LEAF_IN_PARAMETERS)) return;
1636 
1637  init_events = weed_get_voidptr_array_counted(init_event, WEED_LEAF_IN_PARAMETERS, &num_inits);
1638 
1639  for (i = 0; i < num_inits; i++) {
1640  pchain = init_events[i];
1641  while (pchain) {
1642  pchain_tc = get_event_timecode((weed_plant_t *)pchain);
1643  if (!weed_plant_has_leaf((weed_plant_t *)pchain, WEED_LEAF_NEXT_CHANGE)) pchain_next = NULL;
1644  else pchain_next = weed_get_voidptr_value((weed_plant_t *)pchain, WEED_LEAF_NEXT_CHANGE, NULL);
1645  if (pchain_tc > deinit_tc) delete_event(event_list, (weed_plant_t *)pchain);
1646  pchain = pchain_next;
1647  }
1648  }
1649  lives_free(init_events);
1650 }
1651 
1652 
1653 static void rescale_param_changes(weed_plant_t *event_list, weed_plant_t *init_event, weed_timecode_t new_init_tc,
1654  weed_plant_t *deinit_event, weed_timecode_t new_deinit_tc, double fps) {
1655  // rescale parameter value changes along the time axis
1656  // this can be called when a FILTER_INIT or FILTER_DEINIT is moved
1657 
1658  void **init_events;
1659 
1660  weed_timecode_t old_init_tc = get_event_timecode(init_event);
1661  weed_timecode_t old_deinit_tc = get_event_timecode(deinit_event);
1662  weed_timecode_t pchain_tc, new_tc;
1663 
1664  void *pchain;
1665  weed_plant_t *event;
1666 
1667  int num_inits, i;
1668 
1669  if (!weed_plant_has_leaf(init_event, WEED_LEAF_IN_PARAMETERS)) return;
1670 
1671  init_events = weed_get_voidptr_array_counted(init_event, WEED_LEAF_IN_PARAMETERS, &num_inits);
1672 
1673  if (!init_events) num_inits = 0;
1674 
1675  for (i = 0; i < num_inits; i++) {
1676  pchain = init_events[i];
1677  while (pchain) {
1678  pchain_tc = get_event_timecode((weed_plant_t *)pchain);
1679  new_tc = (weed_timecode_t)((double)(pchain_tc - old_init_tc) / (double)(old_deinit_tc - old_init_tc) *
1680  (double)(new_deinit_tc - new_init_tc)) + new_init_tc;
1681  new_tc = q_gint64(new_tc, fps);
1682  if (new_tc == pchain_tc) {
1683  if (!weed_plant_has_leaf((weed_plant_t *)pchain, WEED_LEAF_NEXT_CHANGE)) pchain = NULL;
1684  else pchain = weed_get_voidptr_value((weed_plant_t *)pchain, WEED_LEAF_NEXT_CHANGE, NULL);
1685  continue;
1686  }
1687  event = (weed_plant_t *)pchain;
1688  if (new_tc < pchain_tc) {
1689  while (event && get_event_timecode(event) > new_tc) event = get_prev_event(event);
1690  } else {
1691  while (event && get_event_timecode(event) < new_tc) event = get_next_event(event);
1692  }
1693 
1694  if (event) {
1695  unlink_event(event_list, (weed_plant_t *)pchain);
1696  insert_param_change_event_at(event_list, event, (weed_plant_t *)pchain);
1697  }
1698 
1699  if (!weed_plant_has_leaf((weed_plant_t *)pchain, WEED_LEAF_NEXT_CHANGE)) pchain = NULL;
1700  else pchain = weed_get_voidptr_value((weed_plant_t *)pchain, WEED_LEAF_NEXT_CHANGE, NULL);
1701  }
1702  }
1703 
1704  if (init_events) lives_free(init_events);
1705 }
1706 
1707 
1708 static boolean is_in_hints(weed_plant_t *event, void **hints) {
1709  register int i;
1710  if (!hints) return FALSE;
1711  for (i = 0; hints[i]; i++) {
1712  if (hints[i] == event) return TRUE;
1713  }
1714  return FALSE;
1715 }
1716 
1717 
1718 boolean init_event_is_process_last(weed_plant_t *event) {
1719  weed_plant_t *filter;
1720  char *hashname;
1721 
1722  if (!event) return FALSE;
1723 
1724  hashname = weed_get_string_value(event, WEED_LEAF_FILTER, NULL);
1725  filter = get_weed_filter(weed_get_idx_for_hashname(hashname, TRUE));
1726  lives_free(hashname);
1727  return weed_filter_is_process_last(filter);
1728 }
1729 
1730 
1731 void add_init_event_to_filter_map(weed_plant_t *fmap, weed_plant_t *event, void **hints) {
1732  // TODO - try to add at same position as in hints ***
1733 
1734  // init_events are the events we are adding to
1735  // event is what we are adding
1736 
1737  // hints is the init_events from the previous filter_map
1738 
1739  void **init_events, **new_init_events;
1740 
1741  boolean added = FALSE, plast = FALSE, mustadd = FALSE;
1742  int num_inits, i, j = 0;
1743 
1744  remove_event_from_filter_map(fmap, event);
1745 
1746  init_events = weed_get_voidptr_array_counted(fmap, WEED_LEAF_INIT_EVENTS, &num_inits);
1747 
1748  if (num_inits <= 1 && (!init_events || !init_events[0])) {
1749  weed_set_voidptr_value(fmap, WEED_LEAF_INIT_EVENTS, event);
1750  lives_free(init_events);
1751  return;
1752  }
1753 
1754  if (init_event_is_process_last(event)) plast = TRUE;
1755 
1756  new_init_events = (void **)lives_calloc((num_inits + 1), sizeof(void *));
1757 
1758  for (i = 0; i < num_inits; i++) {
1759  if (!added && init_event_is_process_last((weed_plant_t *)init_events[i])) mustadd = TRUE;
1760 
1761  if (mustadd || (!plast && !added && is_in_hints((weed_plant_t *)init_events[i], hints))) {
1762  new_init_events[j++] = event;
1763  added = TRUE;
1764  }
1765  if (init_events[i] == event) {
1766  if (!added) {
1767  added = TRUE;
1768  new_init_events[j++] = event;
1769  }
1770  } else {
1771  new_init_events[j++] = init_events[i];
1772  }
1773  }
1774  if (!added) {
1775  new_init_events[j++] = event;
1776  }
1777 
1778  weed_set_voidptr_array(fmap, WEED_LEAF_INIT_EVENTS, j, new_init_events);
1779  lives_free(init_events);
1780  lives_free(new_init_events);
1781 }
1782 
1783 
1784 void move_filter_init_event(weed_plant_t *event_list, weed_timecode_t new_tc, weed_plant_t *init_event, double fps) {
1785  int error, i, j = 0;
1786  weed_timecode_t tc = get_event_timecode(init_event);
1787  weed_plant_t *deinit_event = weed_get_plantptr_value(init_event, WEED_LEAF_DEINIT_EVENT, &error);
1788  weed_timecode_t deinit_tc = get_event_timecode(deinit_event);
1789  weed_plant_t *event = init_event, *event_next;
1790  weed_plant_t *filter_map, *copy_filter_map;
1791  void **init_events;
1792  int num_inits;
1793  void **event_types = NULL;
1794  boolean is_null_filter_map;
1795 
1796  rescale_param_changes(event_list, init_event, new_tc, deinit_event, deinit_tc, fps);
1797 
1798  if (new_tc > tc) {
1799  // moving right
1800  filter_map = get_filter_map_before(event, LIVES_TRACK_ANY, NULL);
1801  while (get_event_timecode(event) < new_tc) {
1802  event_next = get_next_event(event);
1803  if (WEED_EVENT_IS_FILTER_MAP(event)) {
1804  is_null_filter_map = !remove_event_from_filter_map(event, init_event);
1805  if ((!filter_map && is_null_filter_map) || (filter_map &&
1806  compare_filter_maps(filter_map, event, LIVES_TRACK_ANY)))
1807  delete_event(event_list, event);
1808  else filter_map = event;
1809  }
1810  event = event_next;
1811  }
1812  unlink_event(event_list, init_event);
1813  insert_filter_init_event_at(event_list, event, init_event);
1814 
1815  event = get_next_frame_event(init_event);
1816 
1817  init_events = get_init_events_before(event, init_event, TRUE);
1818  event_list = append_filter_map_event(event_list, new_tc, init_events);
1819  lives_free(init_events);
1820 
1821  filter_map = get_last_event(event_list);
1822  unlink_event(event_list, filter_map);
1823  insert_filter_map_event_at(event_list, event, filter_map, TRUE);
1824  } else {
1825  // moving left
1826  // see if event is switched on at start
1827  boolean is_on = FALSE;
1828  boolean adding = FALSE;
1829  while (event != deinit_event) {
1830  if (get_event_timecode(event) > tc) break;
1831  if (WEED_EVENT_IS_FILTER_MAP(event) && filter_map_has_event(event, init_event)) {
1832  if (weed_plant_has_leaf(event, WEED_LEAF_INIT_EVENTS)) {
1833  init_events = weed_get_voidptr_array_counted(event, WEED_LEAF_INIT_EVENTS, &num_inits);
1834  if (init_events[0]) {
1835  event_types = (void **)lives_malloc((num_inits + 1) * sizeof(void *));
1836  for (i = 0; i < num_inits; i++) {
1837  if (adding) event_types[j++] = init_events[i];
1838  if (init_events[i] == init_event) adding = TRUE;
1839  }
1840  event_types[j] = NULL;
1841  is_on = TRUE;
1842  }
1843  lives_free(init_events);
1844  }
1845  break;
1846  }
1847  event = get_next_event(event);
1848  }
1849  event = init_event;
1850  while (get_event_timecode(event) > new_tc) event = get_prev_event(event);
1851  unlink_event(event_list, init_event);
1852  insert_filter_init_event_at(event_list, event, init_event);
1853 
1854  if (is_on) {
1855  event = get_next_frame_event(init_event);
1856  filter_map = get_filter_map_before(event, LIVES_TRACK_ANY, NULL);
1857 
1858  // insert filter_map at new filter_init
1859  if (filter_map) {
1860  copy_filter_map = weed_plant_copy(filter_map);
1861  add_init_event_to_filter_map(copy_filter_map, init_event, event_types);
1862  filter_map = copy_filter_map;
1863  } else {
1864  init_events = (void **)lives_malloc(2 * sizeof(void *));
1865  init_events[0] = init_event;
1866  init_events[1] = NULL;
1867  event_list = append_filter_map_event(event_list, new_tc, init_events);
1868  lives_free(init_events);
1869  filter_map = get_last_event(event_list);
1870  unlink_event(event_list, filter_map);
1871  }
1872 
1873  insert_filter_map_event_at(event_list, event, filter_map, TRUE);
1874  event = get_next_event(filter_map);
1875 
1876  // ensure filter remains on until repositioned FILTER_INIT
1877  while (event && get_event_timecode(event) <= tc) {
1878  event_next = get_next_event(event);
1879  if (WEED_EVENT_IS_FILTER_MAP(event)) {
1880  add_init_event_to_filter_map(filter_map, init_event, event_types);
1881  if (compare_filter_maps(filter_map, event, LIVES_TRACK_ANY)) delete_event(event_list, event);
1882  else filter_map = event;
1883  }
1884  event = event_next;
1885  }
1886  if (event_types) lives_free(event_types);
1887  }
1888  }
1889 }
1890 
1891 
1892 void move_filter_deinit_event(weed_plant_t *event_list, weed_timecode_t new_tc, weed_plant_t *deinit_event,
1893  double fps, boolean rescale_pchanges) {
1894  // move a filter_deinit from old pos to new pos, remove mention of it from filter maps,
1895  // possibly add/update filter map before frame at new_tc, remove duplicate filter_maps, update param_change events
1896  int error, i, j = 0;
1897  weed_timecode_t tc = get_event_timecode(deinit_event);
1898  weed_plant_t *init_event = (weed_plant_t *)weed_get_voidptr_value(deinit_event, WEED_LEAF_INIT_EVENT, &error);
1899  weed_timecode_t init_tc = get_event_timecode(init_event);
1900  weed_plant_t *event = deinit_event, *event_next;
1901  weed_plant_t *filter_map, *copy_filter_map;
1902  weed_plant_t *xevent;
1903  void **init_events;
1904  int num_inits;
1905  void **event_types = NULL;
1906  boolean is_null_filter_map;
1907 
1908  if (new_tc == tc) return;
1909 
1910  if (rescale_pchanges) rescale_param_changes(event_list, init_event, init_tc, deinit_event, new_tc, fps);
1911 
1912  if (new_tc < tc) {
1913  // moving left
1914  //find last event at new_tc, we are going to insert deinit_event after this
1915 
1916  // first find filter_map before new end position, copy it with filter removed
1917  while (get_event_timecode(event) > new_tc) event = get_prev_event(event);
1918  filter_map = get_filter_map_before(event, LIVES_TRACK_ANY, NULL);
1919  if (filter_map) {
1920  if (get_event_timecode(filter_map) != get_event_timecode(event)) {
1921  copy_filter_map = weed_plant_copy(filter_map);
1922  if (!WEED_EVENT_IS_FRAME(event)) event = get_prev_frame_event(event);
1923  if (!event) event = get_first_event(event_list);
1924  insert_filter_map_event_at(event_list, event, copy_filter_map, FALSE);
1925  } else copy_filter_map = filter_map;
1926  remove_event_from_filter_map(copy_filter_map, init_event);
1927  if (filter_map != copy_filter_map && compare_filter_maps(filter_map, copy_filter_map, LIVES_TRACK_ANY))
1928  delete_event(event_list, copy_filter_map);
1929  else filter_map = copy_filter_map;
1930  }
1931 
1932  while (!WEED_EVENT_IS_FRAME(event)) event = get_prev_event(event);
1933  xevent = event;
1934  filter_map = get_filter_map_before(event, LIVES_TRACK_ANY, NULL);
1935 
1936  // remove from following filter_maps
1937 
1938  while (event && get_event_timecode(event) <= tc) {
1939  event_next = get_next_event(event);
1940  if (WEED_EVENT_IS_FILTER_MAP(event)) {
1941  // found a filter map, so remove the event from it
1942  is_null_filter_map = !remove_event_from_filter_map(event, init_event);
1943  if ((!filter_map && is_null_filter_map) || (filter_map &&
1944  compare_filter_maps(filter_map, event, LIVES_TRACK_ANY)))
1945  delete_event(event_list, event);
1946  else filter_map = event;
1947  }
1948  event = event_next;
1949  }
1950  unlink_event(event_list, deinit_event);
1951  insert_filter_deinit_event_at(event_list, xevent, deinit_event);
1952  if (!rescale_pchanges) delete_param_changes_after_deinit(event_list, init_event);
1953  } else {
1954  // moving right
1955  // see if event is switched on at end
1956  boolean is_on = FALSE;
1957  boolean adding = FALSE;
1958 
1959  xevent = get_prev_event(deinit_event);
1960 
1961  // get event_types so we can add filter back at guess position
1962  filter_map = get_filter_map_before(deinit_event, LIVES_TRACK_ANY, NULL);
1963  if (filter_map && filter_map_has_event(filter_map, init_event)) {
1964  init_events = weed_get_voidptr_array_counted(filter_map, WEED_LEAF_INIT_EVENTS, &num_inits);
1965  event_types = (void **)lives_malloc((num_inits + 1) * sizeof(void *));
1966  for (i = 0; i < num_inits; i++) {
1967  if (adding) {
1968  event_types[j++] = init_events[i];
1969  }
1970  if (init_events[i] == init_event) adding = TRUE;
1971  }
1972  event_types[j] = NULL;
1973  is_on = TRUE;
1974  lives_free(init_events);
1975  }
1976 
1977  // move deinit event
1978  event = deinit_event;
1979  while (event && get_event_timecode(event) < new_tc) event = get_next_event(event);
1980 
1981  unlink_event(event_list, deinit_event);
1982 
1983  if (!event) return;
1984 
1985  insert_filter_deinit_event_at(event_list, event, deinit_event);
1986 
1987  if (is_on) {
1988  // ensure filter remains on until new position
1989  event = xevent;
1990  while (event != deinit_event) {
1991  if (get_event_timecode(event) == new_tc && WEED_EVENT_IS_FRAME(event)) break;
1992  event_next = get_next_event(event);
1993  if (WEED_EVENT_IS_FILTER_MAP(event)) {
1994  add_init_event_to_filter_map(event, init_event, event_types);
1995  if (compare_filter_maps(filter_map, event, LIVES_TRACK_ANY)) delete_event(event_list, event);
1996  else filter_map = event;
1997  }
1998  event = event_next;
1999  }
2000  if (event_types) lives_free(event_types);
2001 
2002  // find last FILTER_MAP before deinit_event
2003  event = deinit_event;
2004  while (event && get_event_timecode(event) == new_tc) event = get_next_event(event);
2005  if (!event) event = get_last_event(event_list);
2006  filter_map = get_filter_map_before(event, LIVES_TRACK_ANY, NULL);
2007 
2008  if (filter_map && filter_map_has_event(filter_map, init_event)) {
2009  // if last FILTER_MAP before deinit_event mentions init_event, remove init_event,
2010  // insert FILTER_MAP after deinit_event
2011  copy_filter_map = weed_plant_copy(filter_map);
2012 
2013  remove_event_from_filter_map(copy_filter_map, init_event);
2014  insert_filter_map_event_at(event_list, deinit_event, copy_filter_map, FALSE);
2015  event = get_next_event(copy_filter_map);
2016  while (event) {
2017  // remove next FILTER_MAP if it is a duplicate
2018  if (WEED_EVENT_IS_FILTER_MAP(event)) {
2019  if (compare_filter_maps(copy_filter_map, event, LIVES_TRACK_ANY)) delete_event(event_list, event);
2020  break;
2021  }
2022  event = get_next_event(event);
2023  // *INDENT-OFF*
2024  }}}}
2025  // *INDENT-ON*
2026 
2027 }
2028 
2029 
2030 boolean move_event_right(weed_plant_t *event_list, weed_plant_t *event, boolean can_stay, double fps) {
2031  // move a filter_init or param_change to the right
2032  // this can happen for two reasons: - we are rectifying an event_list, or a block was deleted or moved
2033 
2034  // if can_stay is FALSE, event is forced to move. This is used only during event list rectification.
2035 
2036  weed_timecode_t tc = get_event_timecode(event), new_tc = tc;
2037  weed_plant_t *xevent = event;
2038 
2039  int *owners = NULL;
2040 
2041  boolean all_ok = FALSE;
2042 
2043  int num_owners = 0, num_clips, i;
2044 
2045  if (WEED_EVENT_IS_FILTER_INIT(event)) {
2046  owners = weed_get_int_array_counted(event, WEED_LEAF_IN_TRACKS, &num_owners);
2047  } else if (!WEED_EVENT_IS_PARAM_CHANGE(event)) return TRUE;
2048 
2049  if (num_owners > 0) {
2050  while (xevent) {
2051  if (WEED_EVENT_IS_FRAME(xevent)) {
2052  if ((new_tc = get_event_timecode(xevent)) > tc || (can_stay && new_tc == tc)) {
2053  all_ok = TRUE;
2054  num_clips = weed_leaf_num_elements(xevent, WEED_LEAF_CLIPS);
2055  // find timecode of next event which has valid frames at all owner tracks
2056  for (i = 0; i < num_owners; i++) {
2057  if (owners[i] < 0) continue; // ignore audio owners
2058  if (num_clips <= owners[i] || get_frame_event_clip(xevent, owners[i]) < 0 || get_frame_event_frame(xevent, owners[i]) < 1) {
2059  all_ok = FALSE;
2060  break; // blank frame, or not enough frames
2061  }
2062  }
2063  if (all_ok) break;
2064  }
2065  }
2066  xevent = get_next_event(xevent);
2067  }
2068  lives_free(owners);
2069  } else {
2070  if (can_stay) return TRUE; // bound to timeline, and allowed to stay
2071  xevent = get_next_frame_event(event); // bound to timeline, move to next frame event
2072  new_tc = get_event_timecode(xevent);
2073  }
2074 
2075  if (can_stay && (new_tc == tc) && all_ok) return TRUE;
2076 
2077  // now we have xevent, new_tc
2078 
2079  if (WEED_EVENT_IS_FILTER_INIT(event)) {
2080  weed_plant_t *deinit_event = weed_get_plantptr_value(event, WEED_LEAF_DEINIT_EVENT, NULL);
2081  if (!xevent || get_event_timecode(deinit_event) < new_tc) {
2082  // if we are moving a filter_init past its deinit event, remove it, remove deinit, remove param_change events,
2083  // remove from all filter_maps, and check for duplicate filter maps
2084  remove_filter_from_event_list(event_list, event);
2085  return FALSE;
2086  }
2087  move_filter_init_event(event_list, new_tc, event, fps);
2088  } else {
2089  // otherwise, for a param_change, just insert it at new_tc
2090  weed_plant_t *init_event = (weed_plant_t *)weed_get_voidptr_value(event, WEED_LEAF_INIT_EVENT, NULL);
2091  weed_plant_t *deinit_event = weed_get_plantptr_value(init_event, WEED_LEAF_DEINIT_EVENT, NULL);
2092  if (!xevent || get_event_timecode(deinit_event) < new_tc) {
2093  delete_event(event_list, event);
2094  return FALSE;
2095  }
2096  unlink_event(event_list, event);
2097  insert_param_change_event_at(event_list, xevent, event);
2098  }
2099  return FALSE;
2100 }
2101 
2102 
2103 boolean move_event_left(weed_plant_t *event_list, weed_plant_t *event, boolean can_stay, double fps) {
2104  // move a filter_deinit to the left
2105  // this can happen for two reasons: - we are rectifying an event_list, or a block was deleted or moved
2106 
2107  // if can_stay is FALSE, event is forced to move. This is used only during event list rectification.
2108 
2109  weed_timecode_t tc = get_event_timecode(event), new_tc = tc;
2110  weed_plant_t *xevent = event;
2111  weed_plant_t *init_event;
2112 
2113  int *owners;
2114 
2115  boolean all_ok = FALSE;
2116 
2117  int num_owners = 0, num_clips, i;
2118 
2119  if (WEED_EVENT_IS_FILTER_DEINIT(event))
2120  init_event = (weed_plant_t *)weed_get_voidptr_value(event, WEED_LEAF_INIT_EVENT, NULL);
2121  else return TRUE;
2122 
2123  owners = weed_get_int_array_counted(init_event, WEED_LEAF_IN_TRACKS, &num_owners);
2124 
2125  if (num_owners > 0) {
2126  while (xevent) {
2127  if (WEED_EVENT_IS_FRAME(xevent)) {
2128  if ((new_tc = get_event_timecode(xevent)) < tc || (can_stay && new_tc == tc)) {
2129  all_ok = TRUE;
2130  // find timecode of previous event which has valid frames at all owner tracks
2131  for (i = 0; i < num_owners; i++) {
2132  if (owners[i] < 0) continue; // ignore audio owners
2133  num_clips = weed_leaf_num_elements(xevent, WEED_LEAF_CLIPS);
2134  if (num_clips <= owners[i] || get_frame_event_clip(xevent, owners[i]) < 0 || get_frame_event_frame(xevent, owners[i]) < 1) {
2135  all_ok = FALSE;
2136  break; // blank frame
2137  }
2138  }
2139  if (all_ok) break;
2140  }
2141  }
2142  xevent = get_prev_event(xevent);
2143  }
2144  lives_freep((void **)&owners);
2145  } else {
2146  if (can_stay) return TRUE; // bound to timeline, and allowed to stay
2147  while (xevent) {
2148  // bound to timeline, just move to previous tc
2149  if ((new_tc = get_event_timecode(xevent)) < tc) break;
2150  xevent = get_prev_event(xevent);
2151  }
2152  }
2153  // now we have new_tc
2154 
2155  if (can_stay && (new_tc == tc) && all_ok) return TRUE;
2156 
2157  if (get_event_timecode(init_event) > new_tc) {
2158  // if we are moving a filter_deinit past its init event, remove it, remove init, remove param_change events,
2159  // remove from all filter_maps, and check for duplicate filter maps
2160  remove_filter_from_event_list(event_list, init_event);
2161  return FALSE;
2162  }
2163 
2164  // otherwise, go from old pos to new pos, remove mention of it from filter maps, possibly add/update filter map as last event at new_tc,
2165  // remove duplicate filter_maps, update param_change events
2166 
2167  move_filter_deinit_event(event_list, new_tc, event, fps, TRUE);
2168 
2169  return FALSE;
2170 }
2171 
2172 
2174 // rendering
2175 
2176 void set_render_choice(LiVESToggleButton * togglebutton, livespointer choice) {
2177  if (lives_toggle_button_get_active(togglebutton)) render_choice = LIVES_POINTER_TO_INT(choice);
2178 }
2179 
2180 
2181 void set_render_choice_button(LiVESButton * button, livespointer choice) {
2182  render_choice = LIVES_POINTER_TO_INT(choice);
2183 }
2184 
2185 
2186 LiVESWidget *events_rec_dialog(void) {
2187  LiVESWidget *e_rec_dialog;
2188  LiVESWidget *dialog_vbox;
2189  LiVESWidget *vbox;
2190  LiVESWidget *hbox;
2191  LiVESWidget *label;
2192  LiVESWidget *radiobutton;
2193  LiVESWidget *okbutton;
2194  LiVESWidget *cancelbutton;
2195  LiVESSList *radiobutton_group = NULL;
2196  LiVESAccelGroup *accel_group;
2197 
2198  render_choice = RENDER_CHOICE_PREVIEW;
2199 
2200  e_rec_dialog = lives_standard_dialog_new(_("Events Recorded"), FALSE, -1, -1);
2201 
2202  dialog_vbox = lives_dialog_get_content_area(LIVES_DIALOG(e_rec_dialog));
2203 
2205  lives_box_pack_start(LIVES_BOX(dialog_vbox), vbox, TRUE, TRUE, 0);
2206 
2207  label = lives_standard_label_new(_("Events were recorded. What would you like to do with them ?"));
2208 
2209  lives_box_pack_start(LIVES_BOX(vbox), label, TRUE, TRUE, 0);
2210 
2211  hbox = lives_hbox_new(FALSE, 0);
2212  lives_box_pack_start(LIVES_BOX(vbox), hbox, FALSE, FALSE, 0);
2213 
2214  radiobutton = lives_standard_radio_button_new(_("_Preview events"), &radiobutton_group, LIVES_BOX(hbox), NULL);
2215 
2216  lives_toggle_button_set_active(LIVES_TOGGLE_BUTTON(radiobutton), TRUE);
2217 
2218  lives_signal_sync_connect(LIVES_GUI_OBJECT(radiobutton), LIVES_WIDGET_TOGGLED_SIGNAL,
2219  LIVES_GUI_CALLBACK(set_render_choice),
2220  LIVES_INT_TO_POINTER(RENDER_CHOICE_PREVIEW));
2221 
2223  && (last_rec_start_tc == -1 || ((double)last_rec_start_tc / TICKS_PER_SECOND_DBL) < (cfile->frames - 1.) / cfile->fps)) {
2224  hbox = lives_hbox_new(FALSE, 0);
2225  lives_box_pack_start(LIVES_BOX(vbox), hbox, FALSE, FALSE, 0);
2226 
2227  radiobutton = lives_standard_radio_button_new(_("Render events to _same clip"), &radiobutton_group, LIVES_BOX(hbox), NULL);
2228 
2229  lives_signal_sync_connect(LIVES_GUI_OBJECT(radiobutton), LIVES_WIDGET_TOGGLED_SIGNAL,
2230  LIVES_GUI_CALLBACK(set_render_choice),
2231  LIVES_INT_TO_POINTER(RENDER_CHOICE_SAME_CLIP));
2232  }
2233 
2234  hbox = lives_hbox_new(FALSE, 0);
2235  lives_box_pack_start(LIVES_BOX(vbox), hbox, FALSE, FALSE, 0);
2236 
2237  radiobutton = lives_standard_radio_button_new(_("Render events to _new clip"), &radiobutton_group, LIVES_BOX(hbox), NULL);
2238 
2239  lives_signal_sync_connect(LIVES_GUI_OBJECT(radiobutton), LIVES_WIDGET_TOGGLED_SIGNAL,
2240  LIVES_GUI_CALLBACK(set_render_choice),
2241  LIVES_INT_TO_POINTER(RENDER_CHOICE_NEW_CLIP));
2242 
2243 #ifdef LIBAV_TRANSCODE
2244  hbox = lives_hbox_new(FALSE, 0);
2245  lives_box_pack_start(LIVES_BOX(vbox), hbox, FALSE, FALSE, 0);
2246 
2247  radiobutton = lives_standard_radio_button_new(_("Quick transcode to video clip"), &radiobutton_group, LIVES_BOX(hbox), NULL);
2248 
2249  lives_signal_sync_connect(LIVES_GUI_OBJECT(radiobutton), LIVES_WIDGET_TOGGLED_SIGNAL,
2250  LIVES_GUI_CALLBACK(set_render_choice),
2251  LIVES_INT_TO_POINTER(RENDER_CHOICE_TRANSCODE));
2252 #endif
2253 
2254  hbox = lives_hbox_new(FALSE, 0);
2255  lives_box_pack_start(LIVES_BOX(vbox), hbox, FALSE, FALSE, 0);
2256 
2257  radiobutton = lives_standard_radio_button_new(_("View/edit events in _multitrack window (test)"), &radiobutton_group,
2258  LIVES_BOX(hbox), NULL);
2259 
2260  lives_signal_sync_connect(LIVES_GUI_OBJECT(radiobutton), LIVES_WIDGET_TOGGLED_SIGNAL,
2261  LIVES_GUI_CALLBACK(set_render_choice),
2262  LIVES_INT_TO_POINTER(RENDER_CHOICE_MULTITRACK));
2263 
2265 
2266  hbox = lives_hbox_new(FALSE, 0);
2267  lives_box_pack_start(LIVES_BOX(vbox), hbox, FALSE, FALSE, 0);
2268 
2269  radiobutton = lives_standard_radio_button_new(_("View/edit events in _event window"), &radiobutton_group, LIVES_BOX(hbox),
2270  NULL);
2271 
2272  add_fill_to_box(LIVES_BOX(vbox));
2273 
2274  lives_signal_sync_connect(LIVES_GUI_OBJECT(radiobutton), LIVES_WIDGET_TOGGLED_SIGNAL,
2275  LIVES_GUI_CALLBACK(set_render_choice),
2276  LIVES_INT_TO_POINTER(RENDER_CHOICE_EVENT_LIST));
2277 
2278  cancelbutton = lives_dialog_add_button_from_stock(LIVES_DIALOG(e_rec_dialog), LIVES_STOCK_CANCEL, NULL,
2279  LIVES_RESPONSE_CANCEL);
2280 
2281  lives_signal_sync_connect(LIVES_GUI_OBJECT(cancelbutton), LIVES_WIDGET_CLICKED_SIGNAL,
2282  LIVES_GUI_CALLBACK(set_render_choice_button),
2283  LIVES_INT_TO_POINTER(RENDER_CHOICE_DISCARD));
2284 
2285  accel_group = LIVES_ACCEL_GROUP(lives_accel_group_new());
2286  lives_widget_add_accelerator(cancelbutton, LIVES_WIDGET_CLICKED_SIGNAL, accel_group,
2287  LIVES_KEY_Escape, (LiVESXModifierType)0, (LiVESAccelFlags)0);
2288 
2289  lives_window_add_accel_group(LIVES_WINDOW(e_rec_dialog), accel_group);
2290 
2291  okbutton = lives_dialog_add_button_from_stock(LIVES_DIALOG(e_rec_dialog), LIVES_STOCK_OK, NULL,
2292  LIVES_RESPONSE_OK);
2293 
2295 
2296  return e_rec_dialog;
2297 }
2298 
2299 
2300 static void event_list_free_events(weed_plant_t *event_list) {
2301  weed_plant_t *event, *next_event;
2302  event = get_first_event(event_list);
2303 
2304  while (event) {
2305  next_event = get_next_event(event);
2306  if (mainw->multitrack && event_list == mainw->multitrack->event_list) mt_fixup_events(mainw->multitrack, event, NULL);
2307  weed_plant_free(event);
2308  event = next_event;
2309  }
2310 }
2311 
2312 
2313 void event_list_free(weed_plant_t *event_list) {
2314  if (!event_list) return;
2315  event_list_free_events(event_list);
2316  weed_plant_free(event_list);
2317 }
2318 
2319 
2320 void event_list_replace_events(weed_plant_t *event_list, weed_plant_t *new_event_list) {
2321  if (!event_list || !new_event_list) return;
2322  if (event_list == new_event_list) return;
2323  event_list_free_events(event_list);
2324  weed_set_voidptr_value(event_list, WEED_LEAF_FIRST, get_first_event(new_event_list));
2325  weed_set_voidptr_value(event_list, WEED_LEAF_LAST, get_last_event(new_event_list));
2326 }
2327 
2328 
2329 boolean event_list_to_block(weed_plant_t *event_list, int num_events) {
2330  // translate our new event_list to older event blocks
2331  // by now we should have eliminated clip switches and param settings
2332 
2333  // first we count the frame events
2334  weed_plant_t *event;
2335  char *what;
2336  LiVESResponseType response;
2337  int i = 0;
2338 
2339  if (!event_list) return TRUE;
2340  what = (_("memory for the reordering operation"));
2341  // then we create event_frames
2342  do {
2343  response = LIVES_RESPONSE_OK;
2344  if (!create_event_space(num_events)) {
2345  response = do_memory_error_dialog(what, num_events * sizeof(resample_event));
2346  }
2347  } while (response == LIVES_RESPONSE_RETRY);
2348  lives_free(what);
2349  if (response == LIVES_RESPONSE_CANCEL) {
2350  return FALSE;
2351  }
2352 
2353  event = get_first_event(event_list);
2354 
2355  while (event) {
2356  if (WEED_EVENT_IS_FRAME(event)) {
2357  (cfile->resample_events + i++)->value = (int)weed_get_int64_value(event, WEED_LEAF_FRAMES, NULL);
2358  }
2359  event = get_next_event(event);
2360  }
2361  return TRUE;
2362 }
2363 
2364 
2366  // close gap at start of event list, and between record_end and record_start markers
2367  weed_event_t *event, *next_event, *first_event;
2368  weed_timecode_t tc = 0, tc_delta = 0, rec_end_tc = 0, tc_start = 0, tc_offs = 0, last_tc = 0;
2369  int marker_type;
2370 
2371  if (!mainw->clip_switched) {
2374  }
2375 
2376  if (!event_list) return;
2377 
2378  event = get_first_event(event_list);
2379  if (WEED_PLANT_IS_EVENT_LIST(event)) event = get_next_event(event);
2380 
2381  first_event = event;
2382 
2383  if (event) tc_offs = get_event_timecode(event);
2384 
2385  while (event) {
2386  next_event = get_next_event(event);
2387  last_tc = tc;
2388  tc = get_event_timecode(event) - tc_offs;
2389  if (tc < 0) tc = 0;
2390 
2391  if (weed_plant_has_leaf(event, WEED_LEAF_TC_ADJUSTMENT)) {
2392  if (next_event) {
2393  if (!weed_plant_has_leaf(next_event, WEED_LEAF_TC_ADJUSTMENT)) {
2394  weed_timecode_t ntc = get_event_timecode(next_event);
2395  tc_offs = weed_get_int64_value(event, WEED_LEAF_TC_ADJUSTMENT, NULL);
2396  if (tc + tc_offs > ntc) {
2397  tc -= tc_offs;
2398  }
2399  }
2400  } else if (last_tc + tc_offs <= tc) tc -= tc_offs;
2401  }
2402 
2403  if (WEED_EVENT_IS_MARKER(event)) {
2404  marker_type = weed_get_int_value(event, WEED_LEAF_LIVES_TYPE, NULL);
2405  if (marker_type == EVENT_MARKER_RECORD_END) {
2406  rec_end_tc = tc;
2407  delete_event(event_list, event);
2408  event = next_event;
2409  continue;
2410  } else if (marker_type == EVENT_MARKER_RECORD_START) {
2411  // squash gaps in recording, bu we note the gap for output to same clip
2412  tc_delta += tc - rec_end_tc;
2413 
2414  if (!mainw->clip_switched) {
2416  last_rec_start_tc = tc + tc_start;
2417  // if rendering to same clip, we will pick up this value and add it to the out frame tc
2418  weed_set_int64_value(event, WEED_LEAF_TCDELTA, tc_delta + tc_start);
2419  }
2420  }
2421  }
2422 
2424  tc -= tc_delta;
2425  weed_set_int64_value(event, WEED_LEAF_TC_ADJUSTMENT, tc_delta + tc_offs);
2426  weed_event_set_timecode(event, tc);
2427  event = next_event;
2428  }
2429  for (event = first_event; event; event = get_next_event(event)) {
2430  weed_leaf_delete(event, WEED_LEAF_TC_ADJUSTMENT);
2431  }
2432 }
2433 
2434 
2435 void add_track_to_avol_init(weed_plant_t *filter, weed_plant_t *event, int nbtracks, boolean behind) {
2436  // added a new video track - now we need to update our audio volume and pan effect
2437  weed_plant_t **in_ptmpls;
2438  void **pchainx, *pchange;
2439 
2440  int *new_in_tracks;
2441  int *igns, *nigns;
2442 
2443  int num_in_tracks, x = -nbtracks;
2444  int nparams, numigns;
2445 
2446  int bval, i, j;
2447 
2448  // add a new value to in_tracks
2449  num_in_tracks = weed_leaf_num_elements(event, WEED_LEAF_IN_TRACKS) + 1;
2450  new_in_tracks = (int *)lives_malloc(num_in_tracks * sizint);
2451  for (i = 0; i < num_in_tracks; i++) {
2452  new_in_tracks[i] = x++;
2453  }
2454  weed_set_int_array(event, WEED_LEAF_IN_TRACKS, num_in_tracks, new_in_tracks);
2455  lives_free(new_in_tracks);
2456 
2457  weed_set_int_value(event, WEED_LEAF_IN_COUNT, weed_get_int_value(event, WEED_LEAF_IN_COUNT, NULL) + 1);
2458 
2459  // update all param_changes
2460 
2461  pchainx = weed_get_voidptr_array_counted(event, WEED_LEAF_IN_PARAMETERS, &nparams);
2462 
2463  in_ptmpls = weed_get_plantptr_array(filter, WEED_LEAF_IN_PARAMETER_TEMPLATES, NULL);
2464 
2465  for (i = 0; i < nparams; i++) {
2466  pchange = (weed_plant_t *)pchainx[i];
2467  bval = WEED_FALSE;
2468  while (pchange) {
2469  fill_param_vals_to((weed_plant_t *)pchange, in_ptmpls[i], behind ? num_in_tracks - 1 : 1);
2470  if (weed_plant_has_leaf((weed_plant_t *)pchange, WEED_LEAF_IGNORE)) {
2471  igns = weed_get_boolean_array_counted((weed_plant_t *)pchange, WEED_LEAF_IGNORE, &numigns);
2472  nigns = (int *)lives_malloc(++numigns * sizint);
2473 
2474  for (j = 0; j < numigns; j++) {
2475  if (behind) {
2476  if (j < numigns - 1) nigns[j] = igns[j];
2477  else nigns[j] = bval;
2478  } else {
2479  if (j == 0) nigns[j] = igns[j];
2480  else if (j == 1) nigns[j] = bval;
2481  else nigns[j] = igns[j - 1];
2482  }
2483  }
2484  weed_set_boolean_array((weed_plant_t *)pchange, WEED_LEAF_IGNORE, numigns, nigns);
2485  lives_free(igns);
2486  lives_free(nigns);
2487  }
2488  pchange = weed_get_voidptr_value((weed_plant_t *)pchange, WEED_LEAF_NEXT_CHANGE, NULL);
2489  bval = WEED_TRUE;
2490  }
2491  }
2492 
2493  lives_free(in_ptmpls);
2494 }
2495 
2496 
2497 void event_list_add_track(weed_plant_t *event_list, int layer) {
2498  // in this function we insert a new track before existing tracks
2499  // TODO - memcheck
2500  weed_plant_t *event;
2501 
2502  int *clips, *newclips, i;
2503  int64_t *frames, *newframes;
2504  int *in_tracks, *out_tracks;
2505 
2506  int num_in_tracks, num_out_tracks;
2507  int numframes;
2508 
2509  if (!event_list) return;
2510 
2511  event = get_first_event(event_list);
2512  while (event) {
2513  switch (get_event_type(event)) {
2514  case WEED_EVENT_TYPE_FRAME:
2515  clips = weed_get_int_array_counted(event, WEED_LEAF_CLIPS, &numframes);
2516  frames = weed_get_int64_array(event, WEED_LEAF_FRAMES, NULL);
2517  if (numframes == 1 && clips[0] == -1 && frames[0] == 0) {
2518  // for blank frames, we don't do anything
2519  lives_free(clips);
2520  lives_free(frames);
2521  break;
2522  }
2523 
2524  newclips = (int *)lives_malloc((numframes + 1) * sizint);
2525  newframes = (int64_t *)lives_malloc((numframes + 1) * 8);
2526 
2527  newclips[layer] = -1;
2528  newframes[layer] = 0;
2529  for (i = 0; i < numframes; i++) {
2530  if (i < layer) {
2531  newclips[i] = clips[i];
2532  newframes[i] = frames[i];
2533  } else {
2534  newclips[i + 1] = clips[i];
2535  newframes[i + 1] = frames[i];
2536  }
2537  }
2538  numframes++;
2539 
2540  weed_set_int_array(event, WEED_LEAF_CLIPS, numframes, newclips);
2541  weed_set_int64_array(event, WEED_LEAF_FRAMES, numframes, newframes);
2542 
2543  lives_free(newclips);
2544  lives_free(newframes);
2545  lives_free(clips);
2546  lives_free(frames);
2547 
2548  if (WEED_EVENT_IS_AUDIO_FRAME(event)) {
2549  int *aclips = NULL;
2550  int atracks = weed_frame_event_get_audio_tracks(event, &aclips, NULL);
2551  for (i = 0; i < atracks; i += 2) {
2552  if (aclips[i] >= 0) aclips[i]++;
2553  }
2554  weed_set_int_array(event, WEED_LEAF_AUDIO_CLIPS, atracks, aclips);
2555  lives_free(aclips);
2556  }
2557  break;
2558 
2559  case WEED_EVENT_TYPE_FILTER_INIT:
2560  in_tracks = weed_get_int_array_counted(event, WEED_LEAF_IN_TRACKS, &num_in_tracks);
2561  if (num_in_tracks) {
2562  for (i = 0; i < num_in_tracks; i++) {
2563  if (in_tracks[i] >= layer) in_tracks[i]++;
2564  }
2565  weed_set_int_array(event, WEED_LEAF_IN_TRACKS, num_in_tracks, in_tracks);
2566  lives_free(in_tracks);
2567  }
2568  out_tracks = weed_get_int_array_counted(event, WEED_LEAF_OUT_TRACKS, &num_out_tracks);
2569  if (num_out_tracks) {
2570  for (i = 0; i < num_out_tracks; i++) {
2571  if (out_tracks[i] >= layer) out_tracks[i]++;
2572  }
2573  weed_set_int_array(event, WEED_LEAF_OUT_TRACKS, num_out_tracks, out_tracks);
2574  lives_free(out_tracks);
2575  }
2576  break;
2577  }
2578  event = get_next_event(event);
2579  }
2580 }
2581 
2582 
2583 static weed_plant_t *create_frame_event(weed_timecode_t tc, int numframes, int *clips, int64_t *frames) {
2584  weed_error_t error;
2585  weed_plant_t *event;
2586 
2587  event = weed_plant_new(WEED_PLANT_EVENT);
2588  if (!event) return NULL;
2589  error = weed_set_voidptr_value(event, WEED_LEAF_NEXT, NULL);
2590  if (error == WEED_ERROR_MEMORY_ALLOCATION) return NULL;
2591  error = weed_set_voidptr_value(event, WEED_LEAF_PREVIOUS, NULL);
2592  if (error == WEED_ERROR_MEMORY_ALLOCATION) return NULL;
2593 
2595 
2596  error = weed_set_int64_value(event, WEED_LEAF_TIMECODE, tc);
2597  if (error == WEED_ERROR_MEMORY_ALLOCATION) return NULL;
2598  error = weed_set_int_value(event, WEED_LEAF_EVENT_TYPE, WEED_EVENT_TYPE_FRAME);
2599  if (error == WEED_ERROR_MEMORY_ALLOCATION) return NULL;
2600 
2601  error = weed_set_int_array(event, WEED_LEAF_CLIPS, numframes, clips);
2602  if (error == WEED_ERROR_MEMORY_ALLOCATION) return NULL;
2603  error = weed_set_int64_array(event, WEED_LEAF_FRAMES, numframes, frames);
2604  if (error == WEED_ERROR_MEMORY_ALLOCATION) return NULL;
2605 
2606  return event;
2607 }
2608 
2609 
2610 weed_plant_t *append_frame_event(weed_plant_t *event_list, weed_timecode_t tc, int numframes, int *clips, int64_t *frames) {
2611  // append a frame event to an event_list
2612  weed_plant_t *event, *prev;
2613  weed_error_t error;
2614  // returns NULL on memory error
2615 
2617  if (!event_list) {
2618  event_list = lives_event_list_new(NULL, NULL);
2619  //weed_add_plant_flags(event_list, WEED_LEAF_READONLY_PLUGIN);
2620  }
2621 
2622  event = create_frame_event(tc, numframes, clips, frames);
2623  if (!event) return NULL;
2624 
2625  if (!get_first_event(event_list)) {
2626  error = weed_set_voidptr_value(event_list, WEED_LEAF_FIRST, event);
2627  if (error == WEED_ERROR_MEMORY_ALLOCATION) return NULL;
2628  error = weed_set_voidptr_value(event, WEED_LEAF_PREVIOUS, NULL);
2629  if (error == WEED_ERROR_MEMORY_ALLOCATION) return NULL;
2630  } else {
2631  error = weed_set_voidptr_value(event, WEED_LEAF_PREVIOUS, get_last_event(event_list));
2632  if (error == WEED_ERROR_MEMORY_ALLOCATION) return NULL;
2633  }
2634  //weed_add_plant_flags(event, WEED_LEAF_READONLY_PLUGIN);
2635  prev = get_prev_event(event);
2636  if (prev) {
2637  error = weed_set_voidptr_value(prev, WEED_LEAF_NEXT, event);
2638  if (error == WEED_ERROR_MEMORY_ALLOCATION) return NULL;
2639  }
2640  error = weed_set_voidptr_value(event_list, WEED_LEAF_LAST, event);
2641  if (error == WEED_ERROR_MEMORY_ALLOCATION) return NULL;
2643 
2644  return event_list;
2645 }
2646 
2647 
2648 void **filter_init_add_pchanges(weed_plant_t *event_list, weed_plant_t *plant, weed_plant_t *init_event, int ntracks,
2649  int leave) {
2650  // add the initial values for all parameters when we insert a filter_init event
2651  weed_plant_t **in_params = NULL, **in_ptmpls;
2652 
2653  void **pchain = NULL;
2654  void **in_pchanges = NULL;
2655 
2656  weed_plant_t *filter = plant, *in_param;
2657 
2658  weed_timecode_t tc = get_event_timecode(init_event);
2659 
2660  boolean is_inst = FALSE;
2661 
2662  int num_params, i;
2663 
2664  if (WEED_PLANT_IS_FILTER_INSTANCE(plant)) {
2665  filter = weed_instance_get_filter(plant, TRUE);
2666  is_inst = TRUE;
2667  }
2668 
2669  // add param_change events and set "in_params"
2670  if (!weed_get_plantptr_value(filter, WEED_LEAF_IN_PARAMETER_TEMPLATES, NULL)) return NULL;
2671 
2672  in_ptmpls = weed_get_plantptr_array_counted(filter, WEED_LEAF_IN_PARAMETER_TEMPLATES, &num_params);
2673 
2674  pchain = (void **)lives_malloc((num_params + 1) * sizeof(void *));
2675  pchain[num_params] = NULL;
2676 
2677  if (!is_inst) in_params = weed_params_create(filter, TRUE);
2678 
2679  if (leave > 0) {
2680  in_pchanges = weed_get_voidptr_array_counted(init_event, WEED_LEAF_IN_PARAMETERS, &num_params);
2681  if (leave > num_params) leave = num_params;
2682  }
2683 
2684  for (i = num_params - 1; i >= 0; i--) {
2685  if (i < leave && in_pchanges && in_pchanges[i]) {
2686  // maintain existing values
2687  pchain[i] = in_pchanges[i];
2688  continue;
2689  }
2690 
2691  pchain[i] = weed_plant_new(WEED_PLANT_EVENT);
2692  weed_set_int_value((weed_plant_t *)pchain[i], WEED_LEAF_EVENT_TYPE, WEED_EVENT_TYPE_PARAM_CHANGE);
2693  weed_set_int64_value((weed_plant_t *)pchain[i], WEED_LEAF_TIMECODE, tc);
2694 
2695  if (!is_inst) in_param = in_params[i];
2696  else in_param = weed_inst_in_param(plant, i, FALSE, FALSE);
2697 
2698  if (is_perchannel_multiw(in_param)) {
2699  // if the parameter is element-per-channel, fill up to number of channels
2700  fill_param_vals_to(in_param, in_ptmpls[i], ntracks - 1);
2701  }
2702 
2703  weed_leaf_dup((weed_plant_t *)pchain[i], in_param, WEED_LEAF_VALUE);
2704 
2705  weed_set_int_value((weed_plant_t *)pchain[i], WEED_LEAF_INDEX, i);
2706  weed_set_voidptr_value((weed_plant_t *)pchain[i], WEED_LEAF_INIT_EVENT, init_event);
2707  weed_set_voidptr_value((weed_plant_t *)pchain[i], WEED_LEAF_NEXT_CHANGE, NULL);
2708  weed_set_voidptr_value((weed_plant_t *)pchain[i], WEED_LEAF_PREV_CHANGE, NULL);
2709  weed_set_boolean_value((weed_plant_t *)pchain[i], WEED_LEAF_IS_DEF_VALUE, WEED_TRUE);
2710  //weed_add_plant_flags((weed_plant_t *)pchain[i], WEED_LEAF_READONLY_PLUGIN);
2711 
2712  insert_param_change_event_at(event_list, init_event, (weed_plant_t *)pchain[i]);
2713  }
2714 
2715  if (in_pchanges) lives_free(in_pchanges);
2716 
2717  if (!is_inst) {
2718  weed_in_params_free(in_params, num_params);
2719  lives_free(in_params);
2720  } else {
2721  lives_free(in_params);
2722  }
2723  lives_free(in_ptmpls);
2724 
2725  weed_set_voidptr_array(init_event, WEED_LEAF_IN_PARAMETERS, num_params, pchain);
2726 
2727  return pchain;
2728 }
2729 
2730 
2731 weed_plant_t *append_filter_init_event(weed_plant_t *event_list, weed_timecode_t tc, int filter_idx,
2732  int num_in_tracks, int key, weed_plant_t *inst) {
2733  weed_plant_t **ctmpl;
2734  weed_plant_t *event, *prev, *filter, *chan;
2735 
2736  char *tmp;
2737 
2738  int e_in_channels, e_out_channels, e_ins, e_outs;
2739  int total_in_channels = 0;
2740  int total_out_channels = 0;
2741  int my_in_tracks = 0;
2742 
2743  int i;
2744 
2745  if (!event_list) {
2746  event_list = lives_event_list_new(NULL, NULL);
2747  if (!event_list) return NULL;
2748  }
2749 
2750  event = weed_plant_new(WEED_PLANT_EVENT);
2751  weed_set_voidptr_value(event, WEED_LEAF_NEXT, NULL);
2752 
2753  weed_set_int64_value(event, WEED_LEAF_TIMECODE, tc);
2754  weed_set_int_value(event, WEED_LEAF_EVENT_TYPE, WEED_EVENT_TYPE_FILTER_INIT);
2755  weed_set_string_value(event, WEED_LEAF_FILTER, (tmp = make_weed_hashname(filter_idx, TRUE, FALSE, 0, FALSE)));
2756  lives_free(tmp);
2757 
2758  filter = get_weed_filter(filter_idx);
2759 
2760  ctmpl = weed_get_plantptr_array_counted(filter, WEED_LEAF_IN_CHANNEL_TEMPLATES, &total_in_channels);
2761 
2762  if (total_in_channels > 0) {
2763  int count[total_in_channels];
2764  for (i = 0; i < total_in_channels; i++) {
2765  if (weed_get_boolean_value(ctmpl[i], WEED_LEAF_HOST_DISABLED, NULL) == WEED_FALSE) {
2766  count[i] = 1;
2767  my_in_tracks++;
2768  weed_set_int_value(ctmpl[i], WEED_LEAF_HOST_REPEATS, 1);
2769  } else count[i] = 0;
2770  }
2771 
2772  // TODO ***
2773  if (my_in_tracks < num_in_tracks) {
2774  int repeats;
2775  // we need to use some repeated channels
2776  for (i = 0; i < total_in_channels; i++) {
2777  if (weed_plant_has_leaf(ctmpl[i], WEED_LEAF_MAX_REPEATS) && (count[i] > 0 || has_usable_palette(ctmpl[i]))) {
2778  repeats = weed_get_int_value(ctmpl[i], WEED_LEAF_MAX_REPEATS, NULL);
2779  if (repeats == 0) {
2780  count[i] += num_in_tracks - my_in_tracks;
2781 
2782  /*
2783  weed_set_int_value(ctmpl[i],WEED_LEAF_HOST_REPEATS,count[i]);
2784  weed_set_boolean_value(ctmpl[i],WEED_LEAF_HOST_DISABLED,WEED_FALSE);
2785  */
2786 
2787  break;
2788  }
2789  count[i] += num_in_tracks - my_in_tracks >= repeats - 1 ? repeats - 1 : num_in_tracks - my_in_tracks;
2790 
2791  /*
2792  weed_set_int_value(ctmpl[i],WEED_LEAF_HOST_REPEATS,count[i]);
2793  weed_set_boolean_value(ctmpl[i],WEED_LEAF_HOST_DISABLED,WEED_FALSE);
2794  */
2795 
2796  my_in_tracks += count[i] - 1;
2797  if (my_in_tracks == num_in_tracks) break;
2798  }
2799  }
2800  }
2801  weed_set_int_array(event, WEED_LEAF_IN_COUNT, total_in_channels, count);
2802  lives_free(ctmpl);
2803  }
2804 
2805  ctmpl = weed_get_plantptr_array_counted(filter, WEED_LEAF_OUT_CHANNEL_TEMPLATES, &total_out_channels);
2806 
2807  if (total_out_channels > 0) {
2808  int count[total_out_channels];
2809  ctmpl = weed_get_plantptr_array(filter, WEED_LEAF_OUT_CHANNEL_TEMPLATES, NULL);
2810  for (i = 0; i < total_out_channels; i++) {
2811  if (!weed_plant_has_leaf(ctmpl[i], WEED_LEAF_HOST_DISABLED) ||
2812  weed_get_boolean_value(ctmpl[i], WEED_LEAF_HOST_DISABLED, NULL) != WEED_TRUE) count[i] = 1;
2813  else count[i] = 0;
2814  }
2815  lives_free(ctmpl);
2816 
2817  weed_set_int_array(event, WEED_LEAF_OUT_COUNT, total_out_channels, count);
2818  }
2819 
2820  e_ins = e_in_channels = enabled_in_channels(get_weed_filter(filter_idx), FALSE);
2821  e_outs = e_out_channels = enabled_out_channels(get_weed_filter(filter_idx), FALSE);
2822 
2823  // discount alpha_channels (in and out)
2824  if (inst) {
2825  for (i = 0; i < e_ins; i++) {
2826  chan = get_enabled_channel(inst, i, TRUE);
2827  if (weed_palette_is_alpha(weed_layer_get_palette(chan))) e_in_channels--;
2828  }
2829 
2830  // handling for compound fx
2831  while (weed_plant_has_leaf(inst, WEED_LEAF_HOST_NEXT_INSTANCE)) inst = weed_get_plantptr_value(inst,
2833 
2834  for (i = 0; i < e_outs; i++) {
2835  chan = get_enabled_channel(inst, i, FALSE);
2836  if (weed_palette_is_alpha(weed_layer_get_palette(chan))) e_out_channels--;
2837  }
2838  }
2839 
2840  // here we map our tracks to channels
2841  if (e_in_channels != 0) {
2842  if (e_in_channels == 1) {
2843  weed_set_int_value(event, WEED_LEAF_IN_TRACKS, 0);
2844  } else {
2845  int *tracks = (int *)lives_malloc(2 * sizint);
2846  tracks[0] = 0;
2847  tracks[1] = 1;
2848  weed_set_int_array(event, WEED_LEAF_IN_TRACKS, 2, tracks);
2849  lives_free(tracks);
2850  }
2851  }
2852 
2853  if (e_out_channels > 0) {
2854  weed_set_int_value(event, WEED_LEAF_OUT_TRACKS, 0);
2855  }
2856 
2857  if (key > -1) {
2858  weed_set_int_value(event, WEED_LEAF_HOST_KEY, key);
2859  weed_set_int_value(event, WEED_LEAF_HOST_MODE, rte_key_getmode(key));
2860  }
2861 
2863 #ifdef DEBUG_EVENTS
2864  g_print("adding init event at tc %"PRId64"\n", tc);
2865 #endif
2866 
2867  if (!get_first_event(event_list)) {
2868  weed_set_voidptr_value(event_list, WEED_LEAF_FIRST, event);
2869  weed_set_voidptr_value(event, WEED_LEAF_PREVIOUS, NULL);
2870  } else {
2871  weed_set_voidptr_value(event, WEED_LEAF_PREVIOUS, get_last_event(event_list));
2872  }
2873  //weed_add_plant_flags(event, WEED_LEAF_READONLY_PLUGIN);
2874  prev = get_prev_event(event);
2875  if (prev) weed_set_voidptr_value(prev, WEED_LEAF_NEXT, event);
2876  weed_set_voidptr_value(event_list, WEED_LEAF_LAST, event);
2877 
2878  return event_list;
2879 }
2880 
2881 
2882 weed_plant_t *append_filter_deinit_event(weed_plant_t *event_list, weed_timecode_t tc, void *init_event, void **pchain) {
2883  weed_plant_t *event, *prev;
2884 
2885  if (!event_list) {
2886  event_list = lives_event_list_new(NULL, NULL);
2887  if (!event_list) return NULL;
2888  }
2889 
2890  event = weed_plant_new(WEED_PLANT_EVENT);
2891  weed_set_voidptr_value(event, WEED_LEAF_NEXT, NULL);
2892 
2893  weed_set_int64_value(event, WEED_LEAF_TIMECODE, tc);
2894  weed_set_int_value(event, WEED_LEAF_EVENT_TYPE, WEED_EVENT_TYPE_FILTER_DEINIT);
2895  weed_set_voidptr_value(event, WEED_LEAF_INIT_EVENT, init_event);
2896  weed_leaf_delete((weed_plant_t *)init_event, WEED_LEAF_DEINIT_EVENT); // delete since we assign a placeholder with int64 type
2897  weed_set_plantptr_value(init_event, WEED_LEAF_DEINIT_EVENT, (void *)event);
2898  if (pchain) {
2899  int num_params = 0;
2900  while (pchain[num_params]) num_params++;
2901  weed_set_voidptr_array(event, WEED_LEAF_IN_PARAMETERS, num_params, pchain);
2902  }
2903 
2904  if (!get_first_event(event_list)) {
2905  weed_set_voidptr_value(event_list, WEED_LEAF_FIRST, event);
2906  weed_set_voidptr_value(event, WEED_LEAF_PREVIOUS, NULL);
2907  } else {
2908  weed_set_voidptr_value(event, WEED_LEAF_PREVIOUS, get_last_event(event_list));
2909  }
2910  //weed_add_plant_flags(event, WEED_LEAF_READONLY_PLUGIN);
2911  prev = get_prev_event(event);
2912  if (prev) weed_set_voidptr_value(prev, WEED_LEAF_NEXT, event);
2913  weed_set_voidptr_value(event_list, WEED_LEAF_LAST, event);
2914 
2915  return event_list;
2916 }
2917 
2918 
2919 weed_plant_t *append_param_change_event(weed_plant_t *event_list, weed_timecode_t tc, int pnum,
2920  weed_plant_t *param, void *init_event, void **pchain) {
2921  weed_plant_t *event, *prev, *xevent;
2922  weed_plant_t *last_pchange_event;
2923 
2924  if (!event_list) {
2925  event_list = lives_event_list_new(NULL, NULL);
2926  if (!event_list) return NULL;
2927  }
2928 
2929  event = weed_plant_new(WEED_PLANT_EVENT);
2930  weed_set_voidptr_value(event, WEED_LEAF_NEXT, NULL);
2931 
2932  // TODO - error check
2933  weed_set_int64_value(event, WEED_LEAF_TIMECODE, tc);
2934  weed_set_int_value(event, WEED_LEAF_EVENT_TYPE, WEED_EVENT_TYPE_PARAM_CHANGE);
2935  weed_set_voidptr_value(event, WEED_LEAF_INIT_EVENT, init_event);
2936  weed_set_int_value(event, WEED_LEAF_INDEX, pnum);
2937  weed_leaf_copy(event, WEED_LEAF_VALUE, param, WEED_LEAF_VALUE);
2938 
2939  last_pchange_event = (weed_plant_t *)pchain[pnum];
2940  while ((xevent = (weed_plant_t *)weed_get_voidptr_value(last_pchange_event, WEED_LEAF_NEXT_CHANGE, NULL)) != NULL)
2941  last_pchange_event = xevent;
2942 
2943  if (weed_event_get_timecode(last_pchange_event) == tc && !is_init_pchange(init_event, last_pchange_event)) {
2944  weed_event_t *dup_event = last_pchange_event;
2945  last_pchange_event = (weed_plant_t *)weed_get_voidptr_value(last_pchange_event, WEED_LEAF_PREV_CHANGE, NULL);
2946  delete_event(event_list, dup_event);
2947  }
2948 
2949  weed_set_voidptr_value(last_pchange_event, WEED_LEAF_NEXT_CHANGE, event);
2950  weed_set_voidptr_value(event, WEED_LEAF_PREV_CHANGE, last_pchange_event);
2951  weed_set_voidptr_value(event, WEED_LEAF_NEXT_CHANGE, NULL);
2952 
2953  if (!get_first_event(event_list)) {
2954  weed_set_voidptr_value(event_list, WEED_LEAF_FIRST, event);
2955  weed_set_voidptr_value(event, WEED_LEAF_PREVIOUS, NULL);
2956  } else {
2957  weed_set_voidptr_value(event, WEED_LEAF_PREVIOUS, get_last_event(event_list));
2958  }
2959  //weed_add_plant_flags(event, WEED_LEAF_READONLY_PLUGIN);
2960  prev = get_prev_event(event);
2961  if (prev) weed_set_voidptr_value(prev, WEED_LEAF_NEXT, event);
2962  weed_set_voidptr_value(event_list, WEED_LEAF_LAST, event);
2963 
2964  return event_list;
2965 }
2966 
2967 
2968 weed_plant_t *append_filter_map_event(weed_plant_t *event_list, weed_timecode_t tc, void **init_events) {
2969  weed_plant_t *event, *prev;
2970  int i = 0;
2971 
2972  if (!event_list) {
2973  event_list = lives_event_list_new(NULL, NULL);
2974  if (!event_list) return NULL;
2975  }
2976 
2977  event = weed_plant_new(WEED_PLANT_EVENT);
2978  weed_set_voidptr_value(event, WEED_LEAF_NEXT, NULL);
2979 
2980  // TODO - error check
2981  weed_set_int64_value(event, WEED_LEAF_TIMECODE, tc);
2982  weed_set_int_value(event, WEED_LEAF_EVENT_TYPE, WEED_EVENT_TYPE_FILTER_MAP);
2983 
2984  if (init_events) for (i = 0; init_events[i]; i++);
2985 
2986  if (i == 0) weed_set_voidptr_value(event, WEED_LEAF_INIT_EVENTS, NULL);
2987  else weed_set_voidptr_array(event, WEED_LEAF_INIT_EVENTS, i, init_events);
2988 
2989 #ifdef DEBUG_EVENTS
2990  g_print("adding map event %p at tc %"PRId64"\n", init_events[0], tc);
2991 #endif
2992 
2993  if (!get_first_event(event_list)) {
2994  weed_set_voidptr_value(event_list, WEED_LEAF_FIRST, event);
2995  weed_set_voidptr_value(event, WEED_LEAF_PREVIOUS, NULL);
2996  } else {
2997  weed_set_voidptr_value(event, WEED_LEAF_PREVIOUS, get_last_event(event_list));
2998  }
2999  //weed_add_plant_flags(event, WEED_LEAF_READONLY_PLUGIN);
3000  prev = get_prev_event(event);
3001  if (prev) weed_set_voidptr_value(prev, WEED_LEAF_NEXT, event);
3002  weed_set_voidptr_value(event_list, WEED_LEAF_LAST, event);
3003 
3004  return event_list;
3005 }
3006 
3007 
3008 void get_active_track_list(int *clip_index, int num_tracks, weed_plant_t *filter_map) {
3009  // replace entries in clip_index with 0 if the track is not either the front track or an input to a filter
3010 
3011  // TODO *** we should ignore any filter which does not eventually output to the front track,
3012  // this involves examining the filter map in reverse order and mapping out_tracks back to in_tracks
3013  // marking those which we cover
3014 
3015  weed_plant_t **init_events;
3016  weed_plant_t *filter;
3017 
3018  char *filter_hash;
3019 
3020  int *in_tracks, *out_tracks;
3021  int ninits, nintracks, nouttracks;
3022  int idx;
3023  int front = -1;
3024 
3025  register int i, j;
3026 
3029  if (mainw->multitrack && mainw->multitrack->solo_inst && mainw->multitrack->init_event && !LIVES_IS_PLAYING) {
3030  weed_event_t *ievent = mainw->multitrack->init_event;
3031  front = weed_get_int_value(ievent, WEED_LEAF_OUT_TRACKS, NULL);
3032  }
3033 
3034  for (i = 0; i < num_tracks; i++) {
3035  if ((front == -1 || front == i) && clip_index[i] > 0) {
3036  mainw->active_track_list[i] = clip_index[i];
3037  front = i;
3038  } else mainw->active_track_list[i] = 0;
3039  }
3040 
3041  if (!filter_map || !weed_plant_has_leaf(filter_map, WEED_LEAF_INIT_EVENTS)) return;
3042  init_events = (weed_plant_t **)weed_get_voidptr_array_counted(filter_map, WEED_LEAF_INIT_EVENTS, &ninits);
3043  if (!init_events) return;
3044 
3045  for (i = ninits - 1; i >= 0; i--) {
3046  // get the filter and make sure it has video chans out, which feed to an active track
3047  if (!weed_plant_has_leaf(init_events[i], WEED_LEAF_OUT_TRACKS)
3048  || !weed_plant_has_leaf(init_events[i], WEED_LEAF_IN_TRACKS)) continue;
3049  if (mainw->multitrack && mainw->multitrack->solo_inst && mainw->multitrack->init_event
3050  && mainw->multitrack->init_event != init_events[i] && !LIVES_IS_PLAYING) continue;
3051  filter_hash = weed_get_string_value(init_events[i], WEED_LEAF_FILTER, NULL);
3052  if ((idx = weed_get_idx_for_hashname(filter_hash, TRUE)) != -1) {
3053  filter = get_weed_filter(idx);
3054  if (has_video_chans_in(filter, FALSE) && has_video_chans_out(filter, FALSE)) {
3055  boolean is_valid = FALSE;
3056  out_tracks = weed_get_int_array_counted(init_events[i], WEED_LEAF_OUT_TRACKS, &nouttracks);
3057  for (j = 0; j < nouttracks; j++) {
3058  if (j >= mainw->num_tracks) break;
3059  if (mainw->active_track_list[out_tracks[j]] != 0) {
3060  is_valid = TRUE;
3061  break;
3062  }
3063  }
3064  lives_free(out_tracks);
3065  if (is_valid) {
3066  in_tracks = weed_get_int_array_counted(init_events[i], WEED_LEAF_IN_TRACKS, &nintracks);
3067  for (j = 0; j < nintracks; j++) {
3068  if (j >= mainw->num_tracks) break;
3069  mainw->active_track_list[in_tracks[j]] = clip_index[in_tracks[j]];
3070  }
3071  lives_free(in_tracks);
3072  }
3073  }
3074  }
3075  lives_free(filter_hash);
3076  }
3077 
3078  lives_free(init_events);
3079 }
3080 
3081 
3082 weed_plant_t *process_events(weed_plant_t *next_event, boolean process_audio, weed_timecode_t curr_tc) {
3083  // here we play back (preview) with an event_list
3084  // we process all events, but drop frames (unless mainw->nodrop is set)
3085 
3086  static weed_timecode_t aseek_tc = 0;
3087  weed_timecode_t tc, next_tc;
3088 
3089  static double stored_avel = 0.;
3090 
3091  static int dframes = 0, spare_cycles = 0;
3092 
3093  int *in_count = NULL;
3094 
3095  void *init_event;
3096 
3097  weed_plant_t *next_frame_event, *return_event;
3098  weed_plant_t *filter;
3099  weed_plant_t *inst, *orig_inst;
3100 
3101  weed_plant_t **citmpl = NULL, **cotmpl = NULL;
3102  weed_plant_t **bitmpl = NULL, **botmpl = NULL;
3103  weed_plant_t **source_params, **in_params;
3104 
3105  char *filter_name;
3106  char *key_string;
3107 
3108  int current_file;
3109 
3110  int num_params, offset = 0;
3111  int num_in_count = 0;
3112  int num_in_channels = 0, num_out_channels = 0;
3113  int new_file;
3114  int etype;
3115  int key, idx;
3116  int easing;
3117 
3118  int i;
3119 
3120  if (!next_event) {
3121  aseek_tc = 0;
3122  dframes = 0;
3123  return NULL;
3124  }
3125 
3126  tc = get_event_timecode(next_event);
3127 
3128  if (mainw->playing_file != -1 && tc > curr_tc) {
3129  // next event is in our future
3130  if (mainw->multitrack && mainw->last_display_ticks > 0) {
3131  if ((mainw->fixed_fpsd > 0. && (curr_tc - mainw->last_display_ticks) / TICKS_PER_SECOND_DBL >= 1. / mainw->fixed_fpsd) ||
3132  (mainw->vpp && mainw->vpp->fixed_fpsd > 0. && mainw->ext_playback &&
3133  (curr_tc - mainw->last_display_ticks) / TICKS_PER_SECOND_DBL >= 1. / mainw->vpp->fixed_fpsd)) {
3134  // ...but playing at fixed fps, which is faster than mt fps
3135  mainw->pchains = pchains;
3136  if (prefs->pbq_adaptive) {
3137  if (dframes > 0) update_effort(dframes, TRUE);
3138  else update_effort(spare_cycles, FALSE);
3139  dframes = 0;
3140  spare_cycles = 0;
3141  }
3142  load_frame_image(cfile->last_frameno >= 1 ? cfile->last_frameno : cfile->start);
3143  if (prefs->show_player_stats) {
3144  mainw->fps_measure++;
3145  }
3146  if (mainw->last_display_ticks == 0) mainw->last_display_ticks = curr_tc;
3147  else {
3148  if (mainw->vpp && mainw->ext_playback && mainw->vpp->fixed_fpsd > 0.)
3150  else if (mainw->fixed_fpsd > 0.)
3152  else mainw->last_display_ticks = curr_tc;
3153  }
3154  mainw->pchains = NULL;
3155  } else spare_cycles++;
3156  }
3157  return next_event;
3158  }
3159 
3160  if (mainw->cevent_tc != -1)
3161  aseek_tc += (weed_timecode_t)((double)(tc - mainw->cevent_tc) * stored_avel);
3162  mainw->cevent_tc = tc;
3163 
3164  return_event = get_next_event(next_event);
3165  etype = get_event_type(next_event);
3166  switch (etype) {
3167  case WEED_EVENT_TYPE_FRAME:
3168 
3169 #ifdef DEBUG_EVENTS
3170  g_print("event: frame event at tc %"PRId64" curr_tc=%"PRId64"\n", tc, curr_tc);
3171 #endif
3172 
3174  // keep track of current seek position, for animating playback pointers
3175  int *aclips = weed_get_int_array(next_event, WEED_LEAF_AUDIO_CLIPS, NULL);
3176  double *aseeks = weed_get_double_array(next_event, WEED_LEAF_AUDIO_SEEKS, NULL);
3177 
3178  if (aclips[1] > 0) {
3179  aseek_tc = aseeks[0] * TICKS_PER_SECOND_DBL;
3180  stored_avel = aseeks[1];
3181  }
3182 
3183  lives_freep((void **)&aseeks);
3184  lives_freep((void **)&aclips);
3185  }
3186 
3187  if ((next_frame_event = get_next_frame_event(next_event))) {
3188  next_tc = get_event_timecode(next_frame_event);
3189  // drop frame if it is too far behind
3190  if (LIVES_IS_PLAYING && next_tc <= curr_tc) {
3191  if (prefs->pbq_adaptive) dframes++;
3192  if (!prefs->noframedrop) break;
3193  }
3194  if (!mainw->fs && !prefs->hide_framebar && !mainw->multitrack) {
3196  lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->spinbutton_pb_fps), cfile->pb_fps);
3198  }
3199  }
3200 
3201  lives_freep((void **)&mainw->clip_index);
3202  lives_freep((void **)&mainw->frame_index);
3203 
3204  mainw->clip_index = weed_get_int_array_counted(next_event, WEED_LEAF_CLIPS, &mainw->num_tracks);
3205  mainw->frame_index = weed_get_int64_array(next_event, WEED_LEAF_FRAMES, NULL);
3206 
3207  if (mainw->scrap_file != -1) {
3208  int nclips = mainw->num_tracks;
3209  for (i = 0; i < nclips; i++) {
3210  if (mainw->clip_index[i] == mainw->scrap_file) {
3211  int64_t offs = weed_get_int64_value(next_event, WEED_LEAF_HOST_SCRAP_FILE_OFFSET, NULL);
3213  lives_lseek_buffered_rdonly_absolute(LIVES_POINTER_TO_INT(mainw->files[mainw->scrap_file]->ext_src), offs);
3214  }
3215  }
3216  }
3217 
3218  // if we are in multitrack mode, we will just set up NULL layers and let the effects pull our frames
3219  if (mainw->multitrack) {
3220 
3221  if (!LIVES_IS_PLAYING || ((mainw->fixed_fpsd <= 0. && (!mainw->vpp || mainw->vpp->fixed_fpsd <= 0. || !mainw->ext_playback))
3222  || (mainw->fixed_fpsd > 0. && (curr_tc - mainw->last_display_ticks) / TICKS_PER_SECOND_DBL >= 1. / mainw->fixed_fpsd) ||
3223  (mainw->vpp && mainw->vpp->fixed_fpsd > 0. && mainw->ext_playback &&
3224  (curr_tc - mainw->last_display_ticks) / TICKS_PER_SECOND_DBL >= 1. / mainw->vpp->fixed_fpsd))) {
3225  mainw->pchains = pchains;
3226 
3227  if (LIVES_IS_PLAYING) {
3228  if (prefs->pbq_adaptive) {
3229  update_effort(dframes, TRUE);
3230  dframes = 0;
3231  spare_cycles = 0;
3232  }
3233  }
3234 
3235  load_frame_image(cfile->frameno);
3236 
3237  if (LIVES_IS_PLAYING) {
3238  if (prefs->show_player_stats) {
3239  mainw->fps_measure++;
3240  }
3241  if (mainw->last_display_ticks == 0) mainw->last_display_ticks = curr_tc;
3242  else {
3243  if (mainw->vpp && mainw->ext_playback && mainw->vpp->fixed_fpsd > 0.)
3245  else if (mainw->fixed_fpsd > 0.)
3247  else mainw->last_display_ticks = curr_tc;
3248  }
3249  }
3250  mainw->pchains = NULL;
3251  } else spare_cycles++;
3252  } else {
3253  if (mainw->num_tracks > 1) {
3256  } else mainw->blend_file = -1;
3257 
3258  new_file = -1;
3259  for (i = 0; i < mainw->num_tracks && new_file == -1; i++) {
3260  new_file = mainw->clip_index[i];
3261  }
3262  if (i == 2) mainw->blend_file = -1;
3263 
3264 #ifdef DEBUG_EVENTS
3265  g_print("event: front frame is %d tc %"PRId64" curr_tc=%"PRId64"\n", mainw->frame_index[0], tc, curr_tc);
3266 #endif
3267  if ((inst = weed_get_plantptr_value(next_event, WEED_LEAF_HOST_EASING_END, NULL))) {
3268  easing = weed_get_int_value(next_event, WEED_LEAF_EASE_OUT, NULL);
3269  //if (weed_get_int_value(inst, WEED_LEAF_EASE_OUT_FRAMES, NULL) > 0) {
3270  weed_set_int_value(inst, WEED_LEAF_EASE_OUT, easing);
3271  weed_set_boolean_value(inst, WEED_LEAF_AUTO_EASING, WEED_TRUE);
3272  //}
3273  }
3274 
3275  // handle case where new_file==-1: we must somehow create a blank frame in load_frame_image
3276  if (new_file == -1) new_file = mainw->current_file;
3277  if (prefs->pbq_adaptive) {
3278  if (dframes > 0) update_effort(dframes, TRUE);
3279  else update_effort(spare_cycles, FALSE);
3280  dframes = 0;
3281  }
3282  if (!mainw->urgency_msg && weed_plant_has_leaf(next_event, WEED_LEAF_OVERLAY_TEXT)) {
3283  mainw->urgency_msg = weed_get_string_value(next_event, WEED_LEAF_OVERLAY_TEXT, NULL);
3284  }
3285 
3286  if (new_file != mainw->current_file) {
3287  mainw->files[new_file]->frameno = mainw->frame_index[i - 1];
3288  if (new_file != mainw->scrap_file) {
3289  // switch to a new file
3290  do_quick_switch(new_file);
3291  cfile->next_event = return_event;
3292  return_event = NULL;
3293  } else {
3295  mainw->files[new_file]->hsize = cfile->hsize; // set size of scrap file
3296  mainw->files[new_file]->vsize = cfile->vsize;
3297  current_file = mainw->current_file;
3298  mainw->current_file = new_file;
3299  mainw->aframeno = (double)(aseek_tc / TICKS_PER_SECOND_DBL) * cfile->fps;
3300  mainw->pchains = pchains;
3301  load_frame_image(cfile->frameno);
3302  if (prefs->show_player_stats) {
3303  mainw->fps_measure++;
3304  }
3305  mainw->pchains = NULL;
3306  mainw->current_file = current_file;
3307  }
3308  break;
3309  } else {
3310  cfile->frameno = mainw->frame_index[i - 1];
3311  mainw->aframeno = (double)(aseek_tc / TICKS_PER_SECOND_DBL) * cfile->fps;
3312  mainw->pchains = pchains;
3313  load_frame_image(cfile->frameno);
3314  mainw->pchains = NULL;
3315  }
3316  }
3317  cfile->next_event = get_next_event(next_event);
3318  break;
3319  case WEED_EVENT_TYPE_FILTER_INIT:
3320  // effect init
3321  // bind the weed_fx to next free key/0
3322  filter_name = weed_get_string_value(next_event, WEED_LEAF_FILTER, NULL);
3323  idx = weed_get_idx_for_hashname(filter_name, TRUE);
3324  lives_free(filter_name);
3325 
3326  if (idx != -1) {
3327  filter = get_weed_filter(idx);
3328 
3329  if (!process_audio && is_pure_audio(filter, FALSE)) {
3330  if (weed_plant_has_leaf(next_event, WEED_LEAF_HOST_TAG)) weed_leaf_delete(next_event, WEED_LEAF_HOST_TAG);
3331  break; // audio effects are processed in the audio renderer
3332  }
3333 
3334  if (process_audio && !is_pure_audio(filter, FALSE)) break;
3335 
3336  key = get_next_free_key();
3337  weed_add_effectkey_by_idx(key + 1, idx);
3338  key_string = lives_strdup_printf("%d", key);
3339  weed_set_string_value(next_event, WEED_LEAF_HOST_TAG, key_string);
3340  lives_free(key_string);
3341 
3342 #ifdef DEBUG_EVENTS
3343  g_print("event: init effect on key %d at tc %"PRId64" curr_tc=%"PRId64"\n", key, tc, curr_tc);
3344 #endif
3345  if (weed_plant_has_leaf(next_event, WEED_LEAF_IN_COUNT)) {
3346  in_count = weed_get_int_array_counted(next_event, WEED_LEAF_IN_COUNT, &num_in_count);
3347  }
3348 
3349  citmpl = weed_get_plantptr_array_counted(filter, WEED_LEAF_IN_CHANNEL_TEMPLATES, &num_in_channels);
3350  if (num_in_channels > 0) {
3351  bitmpl = (weed_plant_t **)lives_malloc(num_in_channels * sizeof(weed_plant_t *));
3352  if (num_in_channels != num_in_count) LIVES_ERROR("num_in_count != num_in_channels");
3353  for (i = 0; i < num_in_channels; i++) {
3354  bitmpl[i] = weed_plant_copy(citmpl[i]);
3355  if (in_count[i] > 0) {
3356  weed_set_boolean_value(citmpl[i], WEED_LEAF_HOST_DISABLED, WEED_FALSE);
3357  weed_set_int_value(citmpl[i], WEED_LEAF_HOST_REPEATS, in_count[i]);
3358  } else weed_set_boolean_value(citmpl[i], WEED_LEAF_HOST_DISABLED, WEED_TRUE);
3359  }
3360  }
3361 
3362  lives_freep((void **)&in_count);
3363 
3364  cotmpl = weed_get_plantptr_array_counted(filter, WEED_LEAF_OUT_CHANNEL_TEMPLATES, &num_out_channels);
3365  if (num_out_channels > 0) {
3366  botmpl = (weed_plant_t **)lives_malloc(num_out_channels * sizeof(weed_plant_t *));
3367  for (i = 0; i < num_out_channels; i++) {
3368  botmpl[i] = weed_plant_copy(cotmpl[i]);
3369  }
3370  }
3371 
3372  weed_init_effect(key);
3373 
3374  // restore channel state / number from backup
3375 
3376  if (num_in_channels > 0) {
3377  for (i = 0; i < num_in_channels; i++) {
3378  weed_leaf_copy_or_delete(citmpl[i], WEED_LEAF_HOST_DISABLED, bitmpl[i]);
3379  weed_leaf_copy_or_delete(citmpl[i], WEED_LEAF_HOST_REPEATS, bitmpl[i]);
3380  weed_plant_free(bitmpl[i]);
3381  }
3382  lives_free(bitmpl);
3383  lives_free(citmpl);
3384  }
3385 
3386  if (num_out_channels > 0) {
3387  for (i = 0; i < num_out_channels; i++) {
3388  weed_leaf_copy_or_delete(cotmpl[i], WEED_LEAF_HOST_DISABLED, botmpl[i]);
3389  weed_leaf_copy_or_delete(cotmpl[i], WEED_LEAF_HOST_REPEATS, botmpl[i]);
3390  weed_plant_free(botmpl[i]);
3391  }
3392  lives_free(botmpl);
3393  lives_free(cotmpl);
3394  }
3395 
3396  // reinit effect with saved parameters
3397  orig_inst = inst = rte_keymode_get_instance(key + 1, 0);
3398 
3399  if (weed_plant_has_leaf(next_event, WEED_LEAF_IN_PARAMETERS)) {
3400  int nparams;
3401  void **xpchains = weed_get_voidptr_array_counted(next_event, WEED_LEAF_IN_PARAMETERS, &nparams);
3402  pchains[key] = (void **)lives_realloc(pchains[key], (nparams + 1) * sizeof(void *));
3403  for (i = 0; i < nparams; i++) pchains[key][i] = xpchains[i];
3404  pchains[key][nparams] = NULL;
3405  lives_free(xpchains);
3406  } else pchains[key] = NULL;
3407 
3408 filterinit1:
3409 
3410  num_params = num_in_params(inst, FALSE, FALSE);
3411 
3412  if (num_params > 0) {
3413  weed_call_deinit_func(inst);
3414  if (weed_plant_has_leaf(next_event, WEED_LEAF_IN_PARAMETERS)) {
3415  in_params = weed_get_plantptr_array(inst, WEED_LEAF_IN_PARAMETERS, NULL);
3416  source_params = (weed_plant_t **)pchains[key];
3417 
3418  for (i = 0; i < num_params; i++) {
3419  if (source_params && source_params[i + offset] && is_init_pchange(next_event, source_params[i + offset]))
3420  weed_leaf_dup(in_params[i], source_params[i + offset], WEED_LEAF_VALUE);
3421  }
3422  lives_free(in_params);
3423  }
3424 
3425  offset += num_params;
3426 
3427  filter = weed_instance_get_filter(inst, FALSE);
3428 
3429  if (weed_plant_has_leaf(filter, WEED_LEAF_INIT_FUNC)) {
3430  weed_init_f init_func = (weed_init_f)weed_get_funcptr_value(filter, WEED_LEAF_INIT_FUNC, NULL);
3431  if (init_func) {
3432  char *cwd = cd_to_plugin_dir(filter);
3433  (*init_func)(inst);
3434  lives_chdir(cwd, FALSE);
3435  lives_free(cwd);
3436  }
3437  }
3438 
3439  weed_set_boolean_value(inst, WEED_LEAF_HOST_INITED, WEED_TRUE);
3440  weed_set_boolean_value(inst, WEED_LEAF_HOST_UNUSED, WEED_TRUE);
3441  }
3442 
3443  if (weed_plant_has_leaf(next_event, WEED_LEAF_HOST_KEY)) {
3444  // mt events will not have this;
3445  // it is used to connect params and alpha channels during rendering
3446  // holds our original key/mode values
3447 
3448  int hostkey = weed_get_int_value(next_event, WEED_LEAF_HOST_KEY, NULL);
3449  int hostmode = weed_get_int_value(next_event, WEED_LEAF_HOST_MODE, NULL);
3450 
3451  weed_set_int_value(inst, WEED_LEAF_HOST_KEY, hostkey);
3452  weed_set_int_value(inst, WEED_LEAF_HOST_MODE, hostmode);
3453 
3454  if ((easing = weed_get_int_value(next_event, WEED_LEAF_EASE_OUT, NULL)) > 0) {
3455  g_print("precev found easing %d on %p\n", easing, next_event);
3456  weed_plant_t *deinit = weed_get_plantptr_value(next_event, WEED_LEAF_DEINIT_EVENT, NULL);
3457  if (deinit) {
3458  weed_plant_t *event = deinit;
3459  for (i = 0; i < easing && event; i++) {
3460  event = get_prev_frame_event(event);
3461  }
3462  if (event != deinit && event) {
3463  weed_set_int_value(event, WEED_LEAF_EASE_OUT, easing);
3464  weed_set_plantptr_value(event, WEED_LEAF_HOST_EASING_END, inst);
3465  // *INDENT-OFF*
3466  }}}}
3467  // *INDENT-ON*
3468 
3469  if (weed_plant_has_leaf(inst, WEED_LEAF_HOST_NEXT_INSTANCE)) {
3470  // handle compound fx
3471  inst = weed_get_plantptr_value(inst, WEED_LEAF_HOST_NEXT_INSTANCE, NULL);
3472  goto filterinit1;
3473  }
3474  weed_instance_unref(orig_inst);
3475  }
3476  break;
3477 
3478  case WEED_EVENT_TYPE_FILTER_DEINIT:
3479  init_event = weed_get_voidptr_value((weed_plant_t *)next_event, WEED_LEAF_INIT_EVENT, NULL);
3480  if (weed_plant_has_leaf((weed_plant_t *)init_event, WEED_LEAF_HOST_TAG)) {
3481  key_string = weed_get_string_value((weed_plant_t *)init_event, WEED_LEAF_HOST_TAG, NULL);
3482  key = atoi(key_string);
3483  lives_free(key_string);
3484 
3485  filter_name = weed_get_string_value((weed_plant_t *)init_event, WEED_LEAF_FILTER, NULL);
3486  idx = weed_get_idx_for_hashname(filter_name, TRUE);
3487  lives_free(filter_name);
3488 
3489  filter = get_weed_filter(idx);
3490 
3491  if (!process_audio) {
3492  if (is_pure_audio(filter, FALSE)) break; // audio effects are processed in the audio renderer
3493  }
3494 
3495  if (process_audio && !is_pure_audio(filter, FALSE)) break;
3496 
3497  if ((inst = rte_keymode_get_instance(key + 1, 0))) {
3498  //weed_deinit_effect(key);
3499  weed_delete_effectkey(key + 1, 0);
3500  weed_instance_unref(inst);
3501  }
3502  // no freep !
3503  if (pchains[key]) lives_free(pchains[key]);
3504  pchains[key] = NULL;
3505  }
3506  break;
3507 
3508  case WEED_EVENT_TYPE_FILTER_MAP:
3509  mainw->filter_map = next_event;
3510 #ifdef DEBUG_EVENTS
3511  g_print("got new effect map\n");
3512 #endif
3513  break;
3514  case WEED_EVENT_TYPE_PARAM_CHANGE:
3515  if (!mainw->multitrack) {
3516  init_event = weed_get_voidptr_value((weed_plant_t *)next_event, WEED_LEAF_INIT_EVENT, NULL);
3517  if (weed_plant_has_leaf((weed_plant_t *)init_event, WEED_LEAF_HOST_TAG)) {
3518  key_string = weed_get_string_value((weed_plant_t *)init_event, WEED_LEAF_HOST_TAG, NULL);
3519  key = atoi(key_string);
3520  lives_free(key_string);
3521 
3522  filter_name = weed_get_string_value((weed_plant_t *)init_event, WEED_LEAF_FILTER, NULL);
3523  idx = weed_get_idx_for_hashname(filter_name, TRUE);
3524  lives_free(filter_name);
3525 
3526  filter = get_weed_filter(idx);
3527 
3528  if (!process_audio) {
3529  if (is_pure_audio(filter, FALSE)) break; // audio effects are processed in the audio renderer
3530  }
3531 
3532  if (process_audio && !is_pure_audio(filter, FALSE)) break;
3533 
3534  if ((inst = rte_keymode_get_instance(key + 1, 0))) {
3535  int pnum = weed_get_int_value(next_event, WEED_LEAF_INDEX, NULL);
3536  weed_plant_t *param = weed_inst_in_param(inst, pnum, FALSE, FALSE);
3537  weed_leaf_dup(param, next_event, WEED_LEAF_VALUE);
3538  }
3539  }
3540  }
3541  break;
3542  }
3543  return return_event;
3544 }
3545 
3546 
3547 static char *set_proc_label(xprocess * proc, const char *label, boolean copy_old) {
3548  char *blabel = NULL;
3549  if (!proc) return NULL;
3550  if (copy_old) blabel = lives_strdup(lives_label_get_text(LIVES_LABEL(proc->label)));
3551  lives_label_set_text(LIVES_LABEL(proc->label), label);
3554  return blabel;
3555 }
3556 
3557 
3609 lives_render_error_t render_events(boolean reset, boolean rend_video, boolean rend_audio) {
3610 #define SAVE_THREAD
3611 #ifdef SAVE_THREAD
3612  static savethread_priv_t *saveargs = NULL;
3613  static lives_thread_t *saver_thread = NULL;
3614 #else
3615  char oname[PATH_MAX];
3616  char *tmp;
3617  LiVESError *error;
3618 #endif
3619  static weed_timecode_t rec_delta_tc, atc;
3620  static weed_plant_t *event, *eventnext;
3621  static boolean r_audio, r_video;
3622 
3623  weed_timecode_t tc, next_out_tc = 0l, out_tc, dtc = atc;
3624  void *init_event;
3625 
3626  LiVESPixbuf *pixbuf = NULL;
3627 
3628  weed_plant_t *filter;
3629  weed_plant_t **citmpl = NULL, **cotmpl = NULL;
3630  weed_plant_t **bitmpl = NULL, **botmpl = NULL;
3631  weed_plant_t *inst, *orig_inst;
3632  weed_plant_t *next_frame_event = NULL;
3633 
3634  int *in_count = NULL;
3635 
3636  weed_plant_t **source_params, **in_params;
3637  weed_plant_t **layers, *layer = NULL;
3638 
3639  weed_error_t weed_error;
3640  LiVESResponseType retval;
3641 
3642  int key, idx;
3643  int etype;
3644  int layer_palette;
3645  int num_params, offset = 0;
3646  int num_in_count = 0;
3647  int num_in_channels = 0, num_out_channels = 0;
3648  int mytrack;
3649  int scrap_track = -1;
3650  int easing;
3651 
3652  static int progress;
3653  static int xaclips[MAX_AUDIO_TRACKS];
3654  static int out_frame;
3655  static int frame;
3656  static int64_t old_scrap_frame;
3657  static int natracks, nbtracks;
3658  int blend_file = mainw->blend_file;
3659 
3660  boolean is_blank = TRUE;
3661  boolean completed = FALSE;
3662 
3663  static double chvols[MAX_AUDIO_TRACKS];
3664  static double xaseek[MAX_AUDIO_TRACKS], xavel[MAX_AUDIO_TRACKS], atime;
3665 
3666 #ifdef VFADE_RENDER
3667  static weed_timecode_t vfade_in_end;
3668  static weed_timecode_t vfade_out_start;
3669  static lives_colRGBA64_t vfade_in_col;
3670  static lives_colRGBA64_t vfade_out_col;
3671 #endif
3672 
3673  static lives_render_error_t read_write_error;
3674 
3675  static char nlabel[128];
3676 
3677  char *blabel = NULL;
3678  char *key_string, *com;
3679  char *filter_name;
3680 
3681  int i;
3682 
3683  if (reset) {
3684  LiVESList *list = NULL;
3685  r_audio = rend_audio;
3686  r_video = rend_video;
3687  progress = frame = 1;
3688  rec_delta_tc = 0;
3689  event = cfile->next_event;
3690  if (WEED_EVENT_IS_MARKER(event)) {
3691  if (weed_get_int_value(event, WEED_LEAF_LIVES_TYPE, &weed_error) == EVENT_MARKER_RECORD_START) {
3692  if (cfile->old_frames > 0) {
3695  rec_delta_tc = weed_get_int64_value(event, WEED_LEAF_TCDELTA, NULL);
3696  }
3697  }
3698  }
3699 
3701  atc = q_gint64(get_event_timecode(event), cfile->fps);
3702  atime = (double)(atc + rec_delta_tc) / TICKS_PER_SECOND_DBL;
3703  out_frame = calc_frame_from_time4(mainw->current_file, atime);
3704 
3707 
3708  if (cfile->frames < out_frame) out_frame = cfile->frames + 1;
3709  cfile->undo_start = out_frame;
3710 
3711  // store these, because if the user previews and there is no audio file yet, values may get reset
3712  cfile->undo_achans = cfile->achans;
3713  cfile->undo_arate = cfile->arate;
3714  cfile->undo_arps = cfile->arps;
3715  cfile->undo_asampsize = cfile->asampsize;
3716 
3717  // we may have set this to TRUE to stop the audio being clobbered; now we must reset it to get the correct audio filename
3718  cfile->opening = FALSE;
3719 
3720  clear_mainw_msg();
3721  mainw->filter_map = NULL;
3722  mainw->afilter_map = NULL;
3723  mainw->audio_event = event;
3724  old_scrap_frame = -1;
3725  rec_delta_tc = 0;
3726  /* end_tc */
3727  /* = get_event_timecode(get_last_frame_event(mainw->event_list)) */
3728  /* + TICKS_PER_SECOND_DBL / cfile->fps; */
3729 
3730 #ifdef VFADE_RENDER
3731  if (r_video) {
3732  if (mainw->vfade_in_secs > 0.) {
3733  vfade_in_end = q_gint64(mainw->vfade_in_secs * TICKS_PER_SECOND_DBL, cfile->fps);
3734  vfade_in_col = mainw->vfade_in_col;
3735  } else vfade_in_end = 0;
3736  if (mainw->vfade_out_secs > 0.) {
3737  vfade_out_start = q_gint64(end_tc - mainw->vfade_out_secs * TICKS_PER_SECOND_DBL, cfile->fps);
3738  vfade_out_col = mainw->vfade_out_col;
3739  } else vfade_out_start = end_tc;
3740  }
3741 #endif
3742 
3743  if (r_audio) {
3745  natracks = nbtracks = 0;
3746  if (mainw->multitrack && mainw->multitrack->audio_vols) {
3747  list = mainw->multitrack->audio_vols;
3748  nbtracks = mainw->multitrack->opts.back_audio_tracks;
3749  }
3750 
3752  for (i = 0; i < MAX_AUDIO_TRACKS; i++) {
3753  xaclips[i] = -1;
3754  xaseek[i] = xavel[i] = 0.;
3755  if (list) {
3756  natracks++;
3757  chvols[i] = (double)LIVES_POINTER_TO_INT(list->data) / 1000000.;
3758  list = list->next;
3759  } else chvols[i] = 0.;
3760  }
3761 
3762  if (!mainw->multitrack) {
3763  natracks = 1;
3764  chvols[0] = 1.;
3765  }
3767  lives_snprintf(nlabel, 128, "%s", _("Rendering audio..."));
3768  read_write_error = LIVES_RENDER_ERROR_NONE;
3770  }
3771  return LIVES_RENDER_READY;
3772  }
3773 
3775 
3776  if (mainw->flush_audio_tc != 0 || event) {
3777  if (event) etype = get_event_type(event);
3778  else etype = WEED_EVENT_TYPE_FRAME;
3779  if (mainw->flush_audio_tc == 0) {
3780  is_blank = FALSE;
3781  eventnext = get_next_event(event);
3782  } else {
3783  if (etype != WEED_EVENT_TYPE_MARKER)
3784  etype = WEED_EVENT_TYPE_FRAME;
3785  }
3786  if (!r_video && etype != WEED_EVENT_TYPE_FRAME) etype = WEED_EVENT_TYPE_UNDEFINED;
3787 
3788  switch (etype) {
3789  case WEED_EVENT_TYPE_MARKER: {
3790  int marker_type = weed_get_int_value(event, WEED_LEAF_LIVES_TYPE, &weed_error);
3791  if (marker_type == EVENT_MARKER_RECORD_START) {
3794  if (cfile->old_frames > 0) {
3795  rec_delta_tc = weed_get_int64_value(event, WEED_LEAF_TCDELTA, NULL);
3796  atime = (double)(get_event_timecode(event) + rec_delta_tc) / TICKS_PER_SECOND_DBL;
3797  out_frame = calc_frame_from_time4(mainw->current_file, atime);
3798  }
3799  }
3800  }
3801  break;
3802  case WEED_EVENT_TYPE_FRAME:
3803  out_tc = (weed_timecode_t)((out_frame - 1) / cfile->fps
3804  * TICKS_PER_SECOND_DBL - rec_delta_tc); // calculate tc of next out frame */
3805  out_tc = q_gint64(out_tc, cfile->fps);
3806  next_out_tc = (weed_timecode_t)(out_frame / cfile->fps
3807  * TICKS_PER_SECOND_DBL - rec_delta_tc); // calculate tc of next out frame */
3808  next_out_tc = q_gint64(next_out_tc, cfile->fps);
3809  if (mainw->flush_audio_tc == 0) {
3810  tc = get_event_timecode(event);
3811 
3812  if (r_video && !(!mainw->clip_switched && cfile->hsize * cfile->vsize == 0)) {
3813  lives_freep((void **)&mainw->clip_index);
3814  lives_freep((void **)&mainw->frame_index);
3815 
3816  mainw->clip_index = weed_get_int_array_counted(event, WEED_LEAF_CLIPS, &mainw->num_tracks);
3817  mainw->frame_index = weed_get_int64_array(event, WEED_LEAF_FRAMES, &weed_error);
3818 
3819  if (mainw->scrap_file != -1) {
3820  for (i = 0; i < mainw->num_tracks; i++) {
3821  if (mainw->clip_index[i] != mainw->scrap_file) {
3822  scrap_track = -1;
3823  break;
3824  }
3825  if (scrap_track == -1) scrap_track = i;
3826  }
3827  }
3828  if (scrap_track != -1) {
3829  int64_t offs;
3830  // do not apply fx, just pull frame
3831  if (mainw->frame_index[scrap_track] == old_scrap_frame && mainw->scrap_pixbuf) {
3832  pixbuf = mainw->scrap_pixbuf;
3833  } else {
3834  if (mainw->scrap_pixbuf) {
3835 #ifndef SAVE_THREAD
3837 #endif
3838  mainw->scrap_pixbuf = NULL;
3839  }
3840  old_scrap_frame = mainw->frame_index[scrap_track];
3841  layer = lives_layer_new_for_frame(mainw->clip_index[scrap_track], mainw->frame_index[scrap_track]);
3842  offs = weed_get_int64_value(event, WEED_LEAF_HOST_SCRAP_FILE_OFFSET, &weed_error);
3844  lives_lseek_buffered_rdonly_absolute(LIVES_POINTER_TO_INT(mainw->files[mainw->clip_index[scrap_track]]->ext_src),
3845  offs);
3846  if (!pull_frame(layer, get_image_ext_for_type(cfile->img_type), tc)) {
3847  weed_layer_free(layer);
3848  layer = NULL;
3849  }
3850  }
3851  } else {
3852  int oclip, nclip;
3853  layers = (weed_plant_t **)lives_malloc((mainw->num_tracks + 1) * sizeof(weed_plant_t *));
3854  // get list of active tracks from mainw->filter map
3856  for (i = 0; i < mainw->num_tracks; i++) {
3857  oclip = mainw->old_active_track_list[i];
3858  mainw->ext_src_used[oclip] = FALSE;
3859  if (oclip > 0 && oclip == (nclip = mainw->active_track_list[i])) {
3860  if (mainw->track_decoders[i] == mainw->files[oclip]->ext_src) mainw->ext_src_used[oclip] = TRUE;
3861  }
3862  }
3863 
3864  for (i = 0; i < mainw->num_tracks; i++) {
3865  if (mainw->clip_index[i] > 0 && mainw->frame_index[i] > 0 && mainw->multitrack) is_blank = FALSE;
3867  weed_layer_nullify_pixel_data(layers[i]);
3868 
3869  if ((oclip = mainw->old_active_track_list[i]) != (nclip = mainw->active_track_list[i])) {
3870  // now using threading, we want to start pulling all pixel_data for all active layers here
3871  // however, we may have more than one copy of the same clip - in this case we want to
3872  // create clones of the decoder plugin
3873  // this is to prevent constant seeking between different frames in the clip
3874 
3875  // check if ext_src survives old->new
3876 
3878  if (oclip > 0) {
3879  if (mainw->files[oclip]->clip_type == CLIP_TYPE_FILE) {
3880  if (mainw->track_decoders[i] != (lives_decoder_t *)mainw->files[oclip]->ext_src) {
3881  // remove the clone for oclip
3883  } else chill_decoder_plugin(oclip);
3884  mainw->track_decoders[i] = NULL;
3885  }
3886  }
3887 
3888  if (nclip > 0) {
3889  if (mainw->files[nclip]->clip_type == CLIP_TYPE_FILE) {
3890  if (!mainw->ext_src_used[nclip]) {
3892  mainw->ext_src_used[nclip] = TRUE;
3893  } else {
3894  // add new clone for nclip
3895  mainw->track_decoders[i] = clone_decoder(nclip);
3896  // *INDENT-OFF*
3897  }}}}
3898  // *INDENT-ON*
3899 
3901 
3902  if (nclip > 0) {
3903  const char *img_ext = get_image_ext_for_type(mainw->files[nclip]->img_type);
3904  // set alt src in layer
3905  weed_set_voidptr_value(layers[i], WEED_LEAF_HOST_DECODER, (void *)mainw->track_decoders[i]);
3906  pull_frame_threaded(layers[i], img_ext, (weed_timecode_t)mainw->currticks, 0, 0);
3907  } else {
3908  weed_layer_pixel_data_free(layers[i]);
3909  }
3910  }
3911  layers[i] = NULL;
3912 
3913  if ((inst = weed_get_plantptr_value(event, WEED_LEAF_HOST_EASING_END, NULL))) {
3914  easing = weed_get_int_value(event, WEED_LEAF_EASE_OUT, NULL);
3915  weed_set_int_value(inst, WEED_LEAF_EASE_OUT, easing);
3916  weed_set_boolean_value(inst, WEED_LEAF_AUTO_EASING, WEED_TRUE);
3917  }
3918 
3919  layer = weed_apply_effects(layers, mainw->filter_map, tc, cfile->hsize, cfile->vsize, pchains);
3920 
3921  for (i = 0; layers[i]; i++) {
3922  if (layer != layers[i]) {
3923  check_layer_ready(layers[i]);
3924  weed_layer_free(layers[i]);
3925  }
3926  }
3927  lives_free(layers);
3928  }
3929 #ifdef VFADE_RENDER
3930  if (layer) {
3931  double fadeamt;
3932  if (out_tc < vfade_in_end) {
3933  fadeamt = (double)(vfade_in_end - out_tc) / (double)vfade_in_end;
3934  weed_set_int_value(layer, "red_adjust", (double)vfade_in_col.red / 255.);
3935  weed_set_int_value(layer, "green_adjust", (double)vfade_in_col.green / 255.);
3936  weed_set_int_value(layer, "blue_adjust", (double)vfade_in_col.blue / 255.);
3937  weed_set_double_value(layer, "colorize", fadeamt);
3938  }
3939  if (out_tc > vfade_out_start) {
3940  fadeamt = (double)(out_tc - vfade_out_start) / (double)(end_tc - vfade_out_start);
3941  weed_set_int_value(layer, "red_adjust", (double)vfade_in_col.red / 255.);
3942  weed_set_int_value(layer, "green_adjust", (double)vfade_in_col.green / 255.);
3943  weed_set_int_value(layer, "blue_adjust", (double)vfade_in_col.blue / 255.);
3944  weed_set_double_value(layer, "colorize", fadeamt);
3945  }
3946  }
3947 #endif
3948  if (layer) {
3949  int lpal, width, height;
3950  boolean was_lbox = FALSE;
3951  if (mainw->transrend_proc) {
3955  mainw->transrend_layer = layer;
3957  break;
3958  }
3959  check_layer_ready(layer);
3961  height = weed_layer_get_height(layer);
3962  lpal = layer_palette = weed_layer_get_palette(layer);
3963 #ifndef ALLOW_PNG24
3964  if (cfile->img_type == IMG_TYPE_JPEG && layer_palette != WEED_PALETTE_RGB24
3965  && layer_palette != WEED_PALETTE_RGBA32)
3966  layer_palette = WEED_PALETTE_RGB24;
3967 
3968  else if (cfile->img_type == IMG_TYPE_PNG && layer_palette != WEED_PALETTE_RGBA32)
3969  layer_palette = WEED_PALETTE_RGBA32;
3970 #else
3971  layer_palette = WEED_PALETTE_RGB24;
3972 #endif
3974  calc_maxspect(cfile->hsize, cfile->vsize, &width, &height);
3975  if (layer_palette != lpal && (cfile->hsize > width || cfile->vsize > height)) {
3976  convert_layer_palette(layer, layer_palette, 0);
3977  }
3978  letterbox_layer(layer, cfile->hsize, cfile->vsize, width, height, LIVES_INTERP_BEST, layer_palette, 0);
3979  was_lbox = TRUE;
3980  } else {
3981  resize_layer(layer, cfile->hsize, cfile->vsize, LIVES_INTERP_BEST, layer_palette, 0);
3982  }
3983 
3984  convert_layer_palette(layer, layer_palette, 0);
3985 
3986  // we have a choice here, we can either render with the same gamma tf as cfile, or force it to sRGB
3987  if (!was_lbox)
3988  gamma_convert_layer(cfile->gamma_type, layer);
3989  else
3990  gamma_convert_sub_layer(cfile->gamma_type, 1.0, layer, (cfile->hsize - width) / 2,
3991  (cfile->vsize - height) / 2,
3992  width, height, TRUE);
3993 
3994  if (weed_plant_has_leaf(event, WEED_LEAF_OVERLAY_TEXT)) {
3995  char *texto = weed_get_string_value(event, WEED_LEAF_OVERLAY_TEXT, NULL);
3996  render_text_overlay(layer, texto);
3997  lives_free(texto);
3998  }
3999  pixbuf = layer_to_pixbuf(layer, TRUE, FALSE);
4000  weed_layer_free(layer);
4001  }
4002  mainw->blend_file = blend_file;
4003  }
4004  next_frame_event = get_next_frame_event(event);
4005  } else tc = mainw->flush_audio_tc;
4006 
4007  if (r_audio && (!next_frame_event || WEED_EVENT_IS_AUDIO_FRAME(event)
4008  || (mainw->flush_audio_tc != 0 && tc > mainw->flush_audio_tc)) && tc > atc) {
4009  int auditracks;
4010  for (auditracks = 0; auditracks < MAX_AUDIO_TRACKS; auditracks++) {
4011  // see if we have any audio to render
4012  if (xavel[auditracks] != 0.) break;
4013  }
4014 
4015  cfile->achans = cfile->undo_achans;
4016  cfile->arate = cfile->undo_arate;
4017  cfile->arps = cfile->undo_arps;
4018  cfile->asampsize = cfile->undo_asampsize;
4019 
4020  blabel = set_proc_label(mainw->proc_ptr, nlabel, TRUE);
4021 
4022  lives_freep((void **)&THREADVAR(read_failed_file));
4023 
4024  if (mainw->flush_audio_tc != 0) dtc = mainw->flush_audio_tc;
4025  else dtc = q_gint64(tc + rec_delta_tc, cfile->fps);
4026 
4027  if (auditracks < MAX_AUDIO_TRACKS) {
4028  // render audio
4029  render_audio_segment(natracks, xaclips, mainw->multitrack != NULL ? mainw->multitrack->render_file :
4030  mainw->current_file, xavel, xaseek, atc, dtc, chvols, 1., 1., NULL);
4031  } else {
4032  // render silence
4033  render_audio_segment(1, NULL, mainw->multitrack != NULL ? mainw->multitrack->render_file : mainw->current_file,
4034  NULL, NULL, atc, dtc, chvols, 0., 0., NULL);
4035  }
4036 
4037  atc = dtc;
4038 
4039  if (THREADVAR(write_failed)) {
4040  int outfile = (mainw->multitrack ? mainw->multitrack->render_file : mainw->current_file);
4041  char *outfilename = lives_get_audio_file_name(outfile);
4042  do_write_failed_error_s(outfilename, NULL);
4043  lives_free(outfilename);
4044  read_write_error = LIVES_RENDER_ERROR_WRITE_AUDIO;
4045  }
4046 
4047  if (THREADVAR(read_failed)) {
4048  do_read_failed_error_s(THREADVAR(read_failed_file), NULL);
4049  read_write_error = LIVES_RENDER_ERROR_READ_AUDIO;
4050  }
4051 
4052  set_proc_label(mainw->proc_ptr, blabel, FALSE);
4053  lives_freep((void **)&blabel);
4054  }
4055 
4056  if (mainw->flush_audio_tc != 0) {
4057  if (read_write_error) return read_write_error;
4058  return LIVES_RENDER_COMPLETE;
4059  } else {
4060  int *aclips = NULL;
4061  double *aseeks = NULL;
4062  int num_aclips = weed_frame_event_get_audio_tracks(event, &aclips, &aseeks);
4063 
4064  for (i = 0; i < num_aclips; i += 2) {
4065  if (aclips[i + 1] > 0) { // clipnum
4066  double mult = 1.0;
4067  mytrack = aclips[i] + nbtracks;
4068  if (mytrack < 0) mytrack = 0;
4069  //g_print("del was %f\n", xaseek[mytrack] - aseeks[i]);
4070  if (prefs->rr_super && prefs->rr_ramicro) {
4072  if (xavel[mytrack] * aseeks[i + 1] < 0.) mult *= AUD_DIFF_REVADJ;
4073  if (xaclips[mytrack] != aclips[i + 1] || fabs(xaseek[mytrack] - aseeks[i]) > AUD_DIFF_MIN * mult)
4074  xaseek[mytrack] = aseeks[i];
4075  }
4076  xaclips[mytrack] = aclips[i + 1];
4077  xavel[mytrack] = aseeks[i + 1];
4078  }
4079  }
4080  lives_freep((void **)&aseeks);
4081  lives_freep((void **)&aclips);
4082  }
4083 
4084  if (!r_video) break;
4085  if (!pixbuf) break;
4086  if (!next_frame_event && is_blank) break; // don't render final blank frame
4087 
4088  if (next_frame_event) {
4089  weed_timecode_t next_tc = get_event_timecode(next_frame_event);
4090  if (next_tc < next_out_tc || next_tc - next_out_tc < next_out_tc - tc) break;
4091  } else if (next_out_tc > tc) break;
4092 
4093 #ifndef SAVE_THREAD
4094  if (cfile->old_frames > 0) {
4095  tmp = make_image_file_name(cfile, out_frame, LIVES_FILE_EXT_MGK);
4096  } else {
4097  tmp = make_image_file_name(cfile, out_frame, get_image_ext_for_type(cfile->img_type));
4098  }
4099  lives_snprintf(oname, PATH_MAX, "%s", tmp);
4100  lives_free(tmp);
4101 
4102  do {
4103  retval = LIVES_RESPONSE_NONE;
4104  lives_pixbuf_save(pixbuf, oname, cfile->img_type, 100 - prefs->ocp, cfile->hsize, cfile->vsize, NULL);
4105 
4106  if (error) {
4107  retval = do_write_failed_error_s_with_retry(oname, error->message, NULL);
4108  lives_error_free(error);
4109  error = NULL;
4110  if (retval != LIVES_RESPONSE_RETRY) read_write_error = LIVES_RENDER_ERROR_WRITE_FRAME;
4111  }
4112  } while (retval == LIVES_RESPONSE_RETRY);
4113 
4114 #else
4115  if (!saver_thread) {
4116  if (!mainw->transrend_proc) {
4117  saveargs = (savethread_priv_t *)lives_calloc(1, sizeof(savethread_priv_t));
4118  saveargs->img_type = cfile->img_type;
4119  saveargs->compression = 100 - prefs->ocp;
4120  saveargs->width = cfile->hsize;
4121  saveargs->height = cfile->vsize;
4122  saver_thread = (lives_thread_t *)lives_calloc(1, sizeof(lives_thread_t));
4123  }
4124  } else {
4125  lives_thread_join(*saver_thread, NULL);
4126  while (saveargs->error) {
4127  retval = do_write_failed_error_s_with_retry(saveargs->fname, saveargs->error->message);
4128  lives_error_free(saveargs->error);
4129  saveargs->error = NULL;
4130  if (retval != LIVES_RESPONSE_RETRY) {
4131  read_write_error = LIVES_RENDER_ERROR_WRITE_FRAME;
4132  break;
4133  }
4134  lives_pixbuf_save(saveargs->pixbuf, saveargs->fname, saveargs->img_type, saveargs->compression,
4135  saveargs->width, saveargs->height, &saveargs->error);
4136  }
4137 
4138  if (saveargs->pixbuf && saveargs->pixbuf != pixbuf) {
4139  if (saveargs->pixbuf == mainw->scrap_pixbuf) mainw->scrap_pixbuf = NULL;
4140  lives_widget_object_unref(saveargs->pixbuf);
4141  saveargs->pixbuf = NULL;
4142  }
4143  lives_free(saveargs->fname);
4144  saveargs->fname = NULL;
4145  }
4146 
4147  if (!mainw->transrend_proc) {
4148  if (cfile->old_frames > 0) {
4149  saveargs->fname = make_image_file_name(cfile, out_frame, LIVES_FILE_EXT_MGK);
4150  } else {
4151  saveargs->fname = make_image_file_name(cfile, out_frame, get_image_ext_for_type(cfile->img_type));
4152  }
4153 
4154  saveargs->pixbuf = pixbuf;
4156  }
4157 #endif
4158 
4159  // sig_progress...
4160  lives_snprintf(mainw->msg, MAINW_MSG_SIZE, "%d", progress++);
4161 
4162  if (cfile->undo_start == -1) cfile->undo_start = out_frame;
4163  cfile->undo_end = out_frame;
4164  if (out_frame > cfile->frames) cfile->frames = out_frame;
4165  if (out_frame > cfile->end) cfile->end = out_frame;
4166  if (cfile->start == 0) cfile->start = 1;
4167  out_frame++;
4168 
4169  // if our pixbuf came from scrap file, and next frame is also from scrap file with same frame number,
4170  // save the pixbuf and re-use it
4171  if (scrap_track != -1) mainw->scrap_pixbuf = pixbuf;
4172  break;
4173 
4174  case WEED_EVENT_TYPE_FILTER_INIT:
4175  // effect init
4176  // bind the weed_fx to next free key/0
4177 
4178  filter_name = weed_get_string_value(event, WEED_LEAF_FILTER, &weed_error);
4179  // for now, assume we can find hashname
4180  idx = weed_get_idx_for_hashname(filter_name, TRUE);
4181  lives_free(filter_name);
4182 
4183  filter = get_weed_filter(idx);
4184  if (is_pure_audio(filter, FALSE)) {
4185  if (weed_plant_has_leaf(event, WEED_LEAF_HOST_TAG)) weed_leaf_delete(event, WEED_LEAF_HOST_TAG);
4186  break; // audio effects are processed in the audio renderer
4187  }
4188 
4189  key = get_next_free_key();
4190  weed_add_effectkey_by_idx(key + 1, idx);
4191  key_string = lives_strdup_printf("%d", key);
4192  weed_set_string_value(event, WEED_LEAF_HOST_TAG, key_string);
4193  lives_free(key_string);
4194 
4195  if (weed_plant_has_leaf(event, WEED_LEAF_IN_COUNT)) {
4196  in_count = weed_get_int_array_counted(event, WEED_LEAF_IN_COUNT, &num_in_count);
4197  }
4198 
4199  citmpl = weed_get_plantptr_array_counted(filter, WEED_LEAF_IN_CHANNEL_TEMPLATES, &num_in_channels);
4200  if (num_in_channels != num_in_count) {
4201  LIVES_ERROR("num_in_count != num_in_channels");
4202  } else {
4203  if (num_in_channels > 0) {
4204  bitmpl = (weed_plant_t **)lives_malloc(num_in_channels * sizeof(weed_plant_t *));
4205  for (i = 0; i < num_in_channels; i++) {
4206  bitmpl[i] = weed_plant_copy(citmpl[i]);
4207  if (in_count[i] > 0) {
4208  weed_set_boolean_value(citmpl[i], WEED_LEAF_HOST_DISABLED, WEED_FALSE);
4209  weed_set_int_value(citmpl[i], WEED_LEAF_HOST_REPEATS, in_count[i]);
4210  } else weed_set_boolean_value(citmpl[i], WEED_LEAF_HOST_DISABLED, WEED_TRUE);
4211  }
4212  }
4213  }
4214 
4215  lives_freep((void **)&in_count);
4216 
4217  cotmpl = weed_get_plantptr_array_counted(filter, WEED_LEAF_OUT_CHANNEL_TEMPLATES, &num_out_channels);
4218  if (num_out_channels > 0) {
4219  botmpl = (weed_plant_t **)lives_malloc(num_out_channels * sizeof(weed_plant_t *));
4220  for (i = 0; i < num_out_channels; i++) {
4221  botmpl[i] = weed_plant_copy(cotmpl[i]);
4222  if (!weed_plant_has_leaf(cotmpl[i], WEED_LEAF_HOST_DISABLED))
4223  weed_set_boolean_value(cotmpl[i], WEED_LEAF_HOST_DISABLED, WEED_FALSE);
4224  }
4225  }
4226 
4227  weed_init_effect(key);
4228 
4229  // restore channel state / number from backup
4230 
4231  if (num_in_channels > 0) {
4232  for (i = 0; i < num_in_channels; i++) {
4233  weed_leaf_copy_or_delete(citmpl[i], WEED_LEAF_HOST_DISABLED, bitmpl[i]);
4234  weed_leaf_copy_or_delete(citmpl[i], WEED_LEAF_HOST_REPEATS, bitmpl[i]);
4235  weed_plant_free(bitmpl[i]);
4236  }
4237  lives_free(bitmpl);
4238  lives_free(citmpl);
4239  }
4240 
4241  if (num_out_channels > 0) {
4242  for (i = 0; i < num_out_channels; i++) {
4243  weed_leaf_copy_or_delete(cotmpl[i], WEED_LEAF_HOST_DISABLED, botmpl[i]);
4244  weed_leaf_copy_or_delete(cotmpl[i], WEED_LEAF_HOST_REPEATS, botmpl[i]);
4245  weed_plant_free(botmpl[i]);
4246  }
4247  lives_free(botmpl);
4248  lives_free(cotmpl);
4249  }
4250 
4251  // reinit effect with saved parameters
4252  orig_inst = inst = rte_keymode_get_instance(key + 1, 0);
4253 
4254  if (weed_plant_has_leaf(event, WEED_LEAF_IN_PARAMETERS)) {
4255  int nparams;
4256  void **xpchains = weed_get_voidptr_array_counted(event, WEED_LEAF_IN_PARAMETERS, &nparams);
4257  pchains[key] = (void **)lives_realloc(pchains[key], (nparams + 1) * sizeof(void *));
4258  for (i = 0; i < nparams; i++) pchains[key][i] = xpchains[i];
4259  pchains[key][nparams] = NULL;
4260  lives_free(xpchains);
4261  } else pchains[key] = NULL;
4262 
4263 filterinit2:
4264 
4265  num_params = num_in_params(inst, FALSE, FALSE);
4266 
4267  if (num_params > 0) {
4268  weed_call_deinit_func(inst);
4269  if (weed_plant_has_leaf(event, WEED_LEAF_IN_PARAMETERS)) {
4270  source_params = (weed_plant_t **)pchains[key];
4271  in_params = weed_get_plantptr_array(inst, WEED_LEAF_IN_PARAMETERS, &weed_error);
4272 
4273  for (i = 0; i < num_params; i++) {
4274  if (source_params && source_params[i + offset] && is_init_pchange(event, source_params[i + offset]))
4275  weed_leaf_copy(in_params[i], WEED_LEAF_VALUE, source_params[i + offset], WEED_LEAF_VALUE);
4276  }
4277  lives_free(in_params);
4278  }
4279 
4280  offset += num_params;
4281 
4282  filter = weed_instance_get_filter(inst, FALSE);
4283 
4284  if (weed_plant_has_leaf(filter, WEED_LEAF_INIT_FUNC)) {
4285  weed_init_f init_func = (weed_init_f)weed_get_funcptr_value(filter, WEED_LEAF_INIT_FUNC, NULL);
4286  if (init_func) {
4287  char *cwd = cd_to_plugin_dir(filter);
4288  (*init_func)(inst);
4289  lives_chdir(cwd, FALSE);
4290  lives_free(cwd);
4291  }
4292  }
4293 
4294  weed_set_boolean_value(inst, WEED_LEAF_HOST_INITED, WEED_TRUE);
4295  weed_set_boolean_value(inst, WEED_LEAF_HOST_UNUSED, WEED_TRUE);
4296  }
4297 
4298  if (weed_plant_has_leaf(event, WEED_LEAF_HOST_KEY)) {
4299  // mt events will not have this;
4300  // it is used to connect params and alpha channels during rendering
4301  // holds our original key/mode values
4302 
4303  int hostkey = weed_get_int_value(event, WEED_LEAF_HOST_KEY, &weed_error);
4304  int hostmode = weed_get_int_value(event, WEED_LEAF_HOST_MODE, &weed_error);
4305 
4306  weed_set_int_value(inst, WEED_LEAF_HOST_KEY, hostkey);
4307  weed_set_int_value(inst, WEED_LEAF_HOST_MODE, hostmode);
4308 
4309  if ((easing = weed_get_int_value(event, WEED_LEAF_EASE_OUT, NULL)) > 0) {
4310  weed_plant_t *deinit = weed_get_plantptr_value(event, WEED_LEAF_DEINIT_EVENT, NULL);
4311  if (deinit) {
4312  weed_plant_t *xevent = deinit;
4313  for (i = 0; i < easing; i++) {
4314  xevent = get_prev_frame_event(xevent);
4315  }
4316  if (xevent != deinit && xevent) {
4317  weed_set_int_value(xevent, WEED_LEAF_EASE_OUT, easing);
4318  weed_set_plantptr_value(xevent, WEED_LEAF_HOST_EASING_END, inst);
4319  // *INDENT-OFF*
4320  }}}}
4321  // *INDENT-ON*
4322 
4323  if (weed_plant_has_leaf(inst, WEED_LEAF_HOST_NEXT_INSTANCE)) {
4324  // handle compound fx
4325  inst = weed_get_plantptr_value(inst, WEED_LEAF_HOST_NEXT_INSTANCE, &weed_error);
4326  goto filterinit2;
4327  }
4328  weed_instance_unref(orig_inst);
4329 
4330  break;
4331  case WEED_EVENT_TYPE_FILTER_DEINIT:
4332  init_event = weed_get_voidptr_value(event, WEED_LEAF_INIT_EVENT, &weed_error);
4333 
4334  filter_name = weed_get_string_value((weed_plant_t *)init_event, WEED_LEAF_FILTER, &weed_error);
4335  // for now, assume we can find hashname
4336  idx = weed_get_idx_for_hashname(filter_name, TRUE);
4337  lives_free(filter_name);
4338 
4339  filter = get_weed_filter(idx);
4340  if (is_pure_audio(filter, FALSE)) break; // audio effects are processed in the audio renderer
4341 
4342  key_string = weed_get_string_value((weed_plant_t *)init_event, WEED_LEAF_HOST_TAG, &weed_error);
4343  key = atoi(key_string);
4344  lives_free(key_string);
4345  if ((inst = rte_keymode_get_instance(key + 1, 0))) {
4346  weed_delete_effectkey(key + 1, 0);
4347  weed_instance_unref(inst);
4348  }
4349  // no freep !
4350  if (pchains[key]) lives_free(pchains[key]);
4351  pchains[key] = NULL;
4352  break;
4353  case WEED_EVENT_TYPE_PARAM_CHANGE:
4354  if (!mainw->multitrack) {
4355  init_event = weed_get_voidptr_value((weed_plant_t *)event, WEED_LEAF_INIT_EVENT, NULL);
4356  if (weed_plant_has_leaf((weed_plant_t *)init_event, WEED_LEAF_HOST_TAG)) {
4357  key_string = weed_get_string_value((weed_plant_t *)init_event, WEED_LEAF_HOST_TAG, NULL);
4358  key = atoi(key_string);
4359  lives_free(key_string);
4360 
4361  filter_name = weed_get_string_value((weed_plant_t *)init_event, WEED_LEAF_FILTER, NULL);
4362  idx = weed_get_idx_for_hashname(filter_name, TRUE);
4363  lives_free(filter_name);
4364 
4365  filter = get_weed_filter(idx);
4366 
4367  if (is_pure_audio(filter, FALSE)) break; // audio effects are processed in the audio renderer
4368 
4369  if ((inst = rte_keymode_get_instance(key + 1, 0))) {
4370  int pnum = weed_get_int_value(event, WEED_LEAF_INDEX, NULL);
4371  weed_plant_t *param = weed_inst_in_param(inst, pnum, FALSE, FALSE);
4372  weed_leaf_dup(param, event, WEED_LEAF_VALUE);
4373  }
4374  }
4375  }
4376  break;
4377  case WEED_EVENT_TYPE_FILTER_MAP:
4378 #ifdef DEBUG_EVENTS
4379  g_print("got new effect map\n");
4380 #endif
4381  mainw->filter_map = event;
4382  break;
4383  default: break;
4384  }
4385  event = eventnext;
4386  } else {
4388 #ifdef SAVE_THREAD
4389  if (saver_thread) {
4390  lives_thread_join(*saver_thread, NULL);
4391  while (saveargs->error) {
4392  retval = do_write_failed_error_s_with_retry(saveargs->fname, saveargs->error->message);
4393  lives_error_free(saveargs->error);
4394  saveargs->error = NULL;
4395  if (retval != LIVES_RESPONSE_RETRY) read_write_error = LIVES_RENDER_ERROR_WRITE_FRAME;
4396  else lives_pixbuf_save(saveargs->pixbuf, saveargs->fname, saveargs->img_type, saveargs->compression,
4397  saveargs->width, saveargs->height, &saveargs->error);
4398  }
4399  if (saveargs->pixbuf) {
4400  lives_widget_object_unref(saveargs->pixbuf);
4401  if (saveargs->pixbuf == mainw->scrap_pixbuf) mainw->scrap_pixbuf = NULL;
4402  }
4403  lives_freep((void **)&saveargs->fname);
4404  lives_free(saveargs);
4405  lives_free(saver_thread);
4406  saver_thread = NULL;
4407  saveargs = NULL;
4408  }
4409 #endif
4410 
4411  if (cfile->old_frames == 0) cfile->undo_start = cfile->undo_end = 0;
4412  if (r_video) {
4413 
4414  com = lives_strdup_printf("%s mv_mgk \"%s\" %d %d \"%s\"", prefs->backend, cfile->handle, cfile->undo_start,
4415  cfile->undo_end, get_image_ext_for_type(cfile->img_type));
4416 
4417  lives_rm(cfile->info_file);
4418  mainw->error = FALSE;
4420 
4421  lives_system(com, FALSE);
4422  lives_free(com);
4424 
4425  if (THREADVAR(com_failed)) {
4426  read_write_error = LIVES_RENDER_ERROR_WRITE_FRAME;
4427  // cfile->may_be_damaged = TRUE;
4428  }
4429  } else lives_snprintf(mainw->msg, MAINW_MSG_SIZE, "completed");
4430 
4431  if (r_audio) {
4432  render_audio_segment(1, NULL, mainw->multitrack != NULL
4433  ? mainw->multitrack->render_file : mainw->current_file,
4434  NULL, NULL, atc, next_out_tc, chvols, 0., 0., NULL);
4436  }
4437  mainw->filter_map = NULL;
4438  mainw->afilter_map = NULL;
4439  completed = TRUE;
4440  }
4441 
4442  if (read_write_error) return read_write_error;
4443  if (completed) return LIVES_RENDER_COMPLETE;
4444  return LIVES_RENDER_PROCESSING;
4445 }
4446 
4449  return render_events(FALSE, FALSE, FALSE);
4450 }
4451 
4452 
4453 boolean start_render_effect_events(weed_plant_t *event_list, boolean render_vid, boolean render_aud) {
4454  // this is called to begin rendering effect events from an event_list into cfile
4455  // it will do a reorder/resample/resize/effect apply all in one pass
4456 
4457  // return FALSE in case of serious error
4458 
4459  double old_pb_fps = cfile->pb_fps;
4460 
4461  int oundo_start = cfile->undo_start;
4462  int oundo_end = cfile->undo_end;
4463 
4464  char *com;
4465 
4466  if (!event_list || (!render_vid && !render_aud)) return TRUE; //oh, that was easy !
4467 
4469  cfile->next_event = get_first_event(event_list);
4470 
4472 
4474  render_events(TRUE, render_vid, render_aud);
4475 
4476  cfile->progress_start = 1;
4477  cfile->progress_end = count_resampled_events(event_list, cfile->fps);
4478 
4479  cfile->pb_fps = 1000000.;
4480 
4481  cfile->redoable = cfile->undoable = FALSE;
4484 
4485  cfile->undo_action = UNDO_RENDER;
4486 
4487  // clear up any leftover old files
4488  com = lives_strdup_printf("%s clear_tmp_files \"%s\"", prefs->backend, cfile->handle);
4489  lives_system(com, FALSE);
4490  lives_free(com);
4491 
4493 
4494  // play back the file as fast as possible, each time calling render_events()
4495  if ((!do_progress_dialog(TRUE, TRUE, render_vid ? (!mainw->transrend_proc ? _("Rendering")
4496  : _("Transcoding")) : _("Pre-rendering audio"))
4497  && mainw->cancelled != CANCEL_KEEP) || mainw->error ||
4499  ) {
4500  mainw->disk_mon = 0;
4503 
4504  if (mainw->error) {
4508  d_print_failed();
4510  cfile->undo_start = oundo_start;
4511  cfile->undo_end = oundo_end;
4512  cfile->pb_fps = old_pb_fps;
4513  cfile->frames = cfile->old_frames;
4515  mainw->resizing = FALSE;
4516  cfile->next_event = NULL;
4517  return FALSE;
4518  }
4519 
4520  mainw->disk_mon = 0;
4523  cfile->changed = TRUE;
4526 
4527  if (CLIP_TOTAL_TIME(mainw->current_file) == 0.) {
4528  d_print(_("nothing rendered.\n"));
4529  return FALSE;
4530  }
4531 
4533  cfile->undoable = TRUE;
4534  cfile->pb_fps = old_pb_fps;
4536  set_undoable(_("rendering"), TRUE);
4537  cfile->next_event = NULL;
4538  return TRUE;
4539 }
4540 
4541 
4542 int count_events(weed_plant_t *event_list, boolean all_events, weed_timecode_t start_tc, weed_timecode_t end_tc) {
4543  weed_plant_t *event;
4544  weed_timecode_t tc;
4545  int i = 0;
4546 
4547  if (!event_list) return 0;
4548  event = get_first_event(event_list);
4549 
4550  while (event) {
4551  tc = get_event_timecode(event);
4552  if ((all_events || (WEED_EVENT_IS_FRAME(event) && !WEED_EVENT_IS_AUDIO_FRAME(event))) &&
4553  (end_tc == 0 || (tc >= start_tc && tc < end_tc))) i++;
4554  event = get_next_event(event);
4555  }
4556  return i;
4557 }
4558 
4559 
4560 frames_t count_resampled_events(weed_plant_t *event_list, double fps) {
4561  weed_plant_t *event;
4562  weed_timecode_t tc, seg_start_tc = 0, seg_end_tc = 0;
4563 
4564  frames_t rframes = 0;
4565  int etype, marker_type;
4566 
4567  boolean seg_start = FALSE;
4568 
4569  if (!event_list) return 0;
4570  event = get_first_event(event_list);
4571 
4572  while (event) {
4573  etype = get_event_type(event);
4574  if (etype == WEED_EVENT_TYPE_FRAME) {
4575  tc = get_event_timecode(event);
4576  if (!seg_start) {
4577  seg_start_tc = seg_end_tc = tc;
4578  seg_start = TRUE;
4579  } else {
4580  seg_end_tc = tc;
4581  }
4582  } else {
4583  if (etype == WEED_EVENT_TYPE_MARKER) {
4584  marker_type = weed_get_int_value(event, WEED_LEAF_LIVES_TYPE, NULL);
4585  if (marker_type == EVENT_MARKER_RECORD_END) {
4586  // add (resampled) frames for one recording stretch
4587  if (seg_start) rframes += 1 + ((double)(seg_end_tc - seg_start_tc)) / TICKS_PER_SECOND_DBL * fps;
4588  seg_start = FALSE;
4589  }
4590  }
4591  }
4592  event = get_next_event(event);
4593  }
4594 
4595  if (seg_start) rframes += 1 + ((double)(seg_end_tc - seg_start_tc)) / TICKS_PER_SECOND_DBL * fps;
4596 
4597  return rframes;
4598 }
4599 
4600 
4601 weed_timecode_t event_list_get_end_tc(weed_plant_t *event_list) {
4602  if (!event_list || !get_last_event(event_list)) return 0.;
4603  return get_event_timecode(get_last_event(event_list));
4604 }
4605 
4606 
4607 double event_list_get_end_secs(weed_plant_t *event_list) {
4608  return (event_list_get_end_tc(event_list) / TICKS_PER_SECOND_DBL);
4609 }
4610 
4611 
4612 weed_timecode_t event_list_get_start_tc(weed_plant_t *event_list) {
4613  if (!event_list || !get_first_event(event_list)) return 0.;
4614  return get_event_timecode(get_first_event(event_list));
4615 }
4616 
4617 
4618 double event_list_get_start_secs(weed_plant_t *event_list) {
4619  return (event_list_get_start_tc(event_list) / TICKS_PER_SECOND_DBL);
4620 }
4621 
4622 
4623 boolean has_audio_frame(weed_plant_t *event_list) {
4624  weed_plant_t *event = get_first_frame_event(event_list);
4625  while (event) {
4626  if (WEED_EVENT_IS_AUDIO_FRAME(event)) return TRUE;
4627  event = get_next_frame_event(event);
4628  }
4629  return FALSE;
4630 }
4631 
4632 
4634 
4635 boolean render_to_clip(boolean new_clip, boolean transcode) {
4636  // this function is called to actually start rendering mainw->event_list to a new/current clip
4637  char *pname = NULL;
4638  char *com, *tmp, *clipname = NULL;
4639  double old_fps = 0.;
4640  double afade_in_secs = 0., afade_out_secs = 0.;
4641 #ifdef VFADE_RENDER
4642  double vfade_in_secs = 0., vfade_out_secs = 0.;
4643  LiVESWidgetColor fadecol;
4644  lives_colRGBA64_t vfade_rgb;
4645 #endif
4646  boolean retval = TRUE, rendaud = TRUE, response;
4647  boolean norm_after = FALSE;
4648  int xachans = 0, xarate = 0, xasamps = 0, xse = 0;
4649  int current_file = mainw->current_file;
4650 
4651  if (new_clip) {
4652  if (prefs->render_prompt) {
4653  //set file details
4654  rdet = create_render_details(transcode ? 5 : 2);
4655 
4656  if (!has_audio_frame(mainw->event_list)) {
4659  }
4660  rdet->enc_changed = FALSE;
4661  do {
4663  response = lives_dialog_run(LIVES_DIALOG(rdet->dialog));
4664  if (response == LIVES_RESPONSE_OK && rdet->enc_changed) {
4666  }
4667  } while (rdet->suggestion_followed || response == LIVES_RESPONSE_RETRY || response == LIVES_RESPONSE_RESET);
4668 
4669  xarate = (int)atoi(lives_entry_get_text(LIVES_ENTRY(resaudw->entry_arate)));
4670  xachans = (int)atoi(lives_entry_get_text(LIVES_ENTRY(resaudw->entry_achans)));
4671  xasamps = (int)atoi(lives_entry_get_text(LIVES_ENTRY(resaudw->entry_asamps)));
4672 
4673  // do we render audio ?
4674  rendaud = lives_toggle_button_get_active(LIVES_TOGGLE_BUTTON(resaudw->aud_checkbutton));
4675  norm_after = lives_toggle_button_get_active(LIVES_TOGGLE_BUTTON(rdet->norm_after));
4677  afade_in_secs = lives_spin_button_get_value(LIVES_SPIN_BUTTON(rdet->afade_in));
4679  afade_out_secs = lives_spin_button_get_value(LIVES_SPIN_BUTTON(rdet->afade_out));
4680 
4681  /* if (lives_widget_is_sensitive(rdet->vfade_in)) */
4682  /* vfade_in_secs = lives_spin_button_get_value(LIVES_SPIN_BUTTON(rdet->vfade_in)); */
4683  /* if (lives_widget_is_sensitive(rdet->vfade_out)) */
4684  /* vfade_out_secs = lives_spin_button_get_value(LIVES_SPIN_BUTTON(rdet->vfade_out)); */
4685 
4686  /* lives_color_button_get_color(LIVES_COLOR_BUTTON(rdet->vfade_col), &fadecol); */
4687  /* widget_color_to_lives_rgba(&vfade_rgb, &fadecol); */
4688 
4689  if (lives_toggle_button_get_active(LIVES_TOGGLE_BUTTON(resaudw->rb_unsigned))) {
4690  xse = AFORM_UNSIGNED;
4691  } else xse = AFORM_SIGNED;
4692  if (lives_toggle_button_get_active(LIVES_TOGGLE_BUTTON(resaudw->rb_bigend))) {
4693  xse |= AFORM_BIG_ENDIAN;
4694  } else xse |= AFORM_LITTLE_ENDIAN;
4695 
4696  if (!transcode) {
4697  clipname = lives_strdup(lives_entry_get_text(LIVES_ENTRY(rdet->clipname_entry)));
4699  if (!strcmp(clipname, tmp)) mainw->untitled_number++;
4700  lives_free(tmp);
4701  } else clipname = lives_strdup("transcode");
4702 
4704 
4705  if (response == LIVES_RESPONSE_CANCEL) {
4706  if (!transcode) lives_free(rdet->encoder_name);
4707  lives_free(clipname);
4708  lives_freep((void **)&rdet);
4709  lives_freep((void **)&resaudw);
4710  return FALSE;
4711  }
4712  } else {
4713  if (mainw->multitrack) rendaud = mainw->multitrack->opts.render_audp;
4714  else rendaud = prefs->render_audio;
4715  // TODO: prompt just for clip name
4716  }
4717 
4718  if (!(prefs->rec_opts & REC_AUDIO)) rendaud = FALSE;
4719 
4720  // create new file
4722 
4723  if (!get_new_handle(mainw->current_file, clipname)) {
4724  mainw->current_file = current_file;
4725 
4726  if (prefs->mt_enter_prompt) {
4727  if (!transcode) lives_free(rdet->encoder_name);
4728  lives_freep((void **)&rdet);
4729  lives_freep((void **)&resaudw);
4730  }
4731  lives_free(clipname);
4732  return FALSE; // show dialog again
4733  }
4734 
4735  lives_freep((void **)&clipname);
4736 
4737  cfile->opening = TRUE; // prevent audio from getting clobbered, it will be reset during rendering
4738 
4739  if (weed_plant_has_leaf(mainw->event_list, WEED_LEAF_FPS))
4740  old_fps = weed_get_double_value(mainw->event_list, WEED_LEAF_FPS, NULL);
4741 
4742  if (prefs->render_prompt) {
4743  cfile->hsize = rdet->width;
4744  cfile->vsize = rdet->height;
4745  cfile->pb_fps = cfile->fps = rdet->fps;
4746  cfile->ratio_fps = rdet->ratio_fps;
4747 
4748  cfile->arps = cfile->arate = xarate;
4749  cfile->achans = xachans;
4750  cfile->asampsize = xasamps;
4751  cfile->signed_endian = xse;
4752 
4753  if (!transcode) lives_free(rdet->encoder_name);
4754  lives_freep((void **)&rdet);
4755  lives_freep((void **)&resaudw);
4756  } else {
4757  cfile->hsize = prefs->mt_def_width;
4758  cfile->vsize = prefs->mt_def_height;
4759  cfile->pb_fps = cfile->fps = prefs->mt_def_fps;
4760  cfile->ratio_fps = FALSE;
4761  cfile->arate = cfile->arps = prefs->mt_def_arate;
4762  cfile->achans = prefs->mt_def_achans;
4763  cfile->asampsize = prefs->mt_def_asamps;
4764  cfile->signed_endian = prefs->mt_def_signed_endian;
4765  }
4766 
4767  if (old_fps != 0.) {
4768  cfile->pb_fps = cfile->fps = old_fps;
4769  cfile->ratio_fps = FALSE;
4770  }
4771 
4772  if (!rendaud) cfile->achans = cfile->arate = cfile->asampsize = 0;
4773 
4774  cfile->bpp = cfile->img_type == IMG_TYPE_JPEG ? 24 : 32;
4775  cfile->is_loaded = TRUE;
4776  if (prefs->btgamma) {
4777  if (IS_VALID_CLIP(current_file)) cfile->gamma_type = mainw->files[current_file]->gamma_type;
4778  }
4780  } else if (!mainw->multitrack) {
4781  // back up audio to audio.back (in case we overwrite it)
4782  if (rendaud) {
4783  do_threaded_dialog(_("Backing up audio..."), FALSE);
4784  com = lives_strdup_printf("%s backup_audio \"%s\"", prefs->backend_sync, cfile->handle);
4785  mainw->error = FALSE;
4787  lives_rm(cfile->info_file);
4788  lives_system(com, FALSE);
4789  lives_free(com);
4790  if (THREADVAR(com_failed)) return FALSE;
4791  } else {
4792  do_threaded_dialog(_("Clearing up clip..."), FALSE);
4793  com = lives_strdup_printf("%s clear_tmp_files \"%s\"", prefs->backend_sync, cfile->handle);
4794  lives_system(com, FALSE);
4795  lives_free(com);
4796  }
4798  }
4799 
4801  if (old_fps == 0) {
4802  weed_plant_t *qevent_list = quantise_events(mainw->event_list, cfile->fps, !new_clip);
4803  if (qevent_list) {
4805  weed_set_double_value(mainw->event_list, WEED_LEAF_FPS, cfile->fps);
4806  }
4807  }
4808  }
4809 
4810  cfile->old_frames = cfile->frames;
4811  cfile->changed = TRUE;
4813 
4814  if (new_clip) cfile->img_type = IMG_TYPE_BEST; // override the pref
4816 
4817 #ifdef LIBAV_TRANSCODE
4818  if (transcode) {
4819  if (!transcode_prep()) {
4820  close_current_file(current_file);
4821  return FALSE;
4822  }
4823 
4824  if (!transcode_get_params(&pname)) {
4825  transcode_cleanup(mainw->vpp);
4826  close_current_file(current_file);
4827  return FALSE;
4828  }
4829 
4830  cfile->nopreview = TRUE;
4831 
4832  mainw->transrend_layer = NULL;
4834 
4836  (lives_funcptr_t)transcode_clip,
4837  WEED_SEED_BOOLEAN, "iibV", 1, 0, TRUE, pname);
4840 
4841  if (rendaud) {
4842  // pre-render audio
4843  d_print(_("Pre-rendering audio..."));
4847  close_current_file(current_file);
4848  retval = FALSE;
4849  goto rtc_done;
4850  }
4851  if (norm_after) on_normalise_audio_activate(NULL, NULL);
4852  if (afade_in_secs > 0.) {
4853  cfile->undo1_int = 0; // fade in
4854  cfile->undo2_dbl = 0.;
4855  cfile->undo1_dbl = afade_in_secs;
4856  on_fade_audio_activate(NULL, NULL);
4857  }
4858  if (afade_out_secs > 0.) {
4859  cfile->undo1_int = 1; // fade out
4860  cfile->undo2_dbl = cfile->laudio_time - afade_out_secs;
4861  cfile->undo1_dbl = cfile->laudio_time;
4862  on_fade_audio_activate(NULL, NULL);
4863  }
4864  d_print_done();
4865  rendaud = FALSE;
4866  }
4867 #ifdef VFADE_RENDER
4868  // temp fix until a better system emerges
4869  if (vfade_in_secs > 0.) {
4870  mainw->vfade_in_secs = vfade_in_secs;
4871  mainw->vfade_in_col = vfade_rgb;
4872  }
4873  // temp fix until a better system emerges
4874  if (vfade_out_secs > 0.) {
4875  mainw->vfade_out_secs = vfade_out_secs;
4876  mainw->vfade_out_col = vfade_rgb;
4877  }
4878 #endif
4880  }
4881 #endif
4882 
4883  if (mainw->multitrack && !rendaud && !mainw->multitrack->opts.render_vidp) {
4884  return FALSE;
4885  }
4886 
4887  if (!transcode) d_print(_("Rendering..."));
4888  else d_print(_("Transcoding..."));
4889 
4891 
4892  if (transcode) {
4893  cfile->progress_start = 0;
4894  cfile->progress_end = cfile->frames;
4895  }
4896 
4897  if (start_render_effect_events(mainw->event_list, TRUE, rendaud)) { // re-render, applying effects
4898  // and reordering/resampling/resizing if necessary
4899  if (!transcode) {
4900  if (!mainw->multitrack && mainw->event_list) {
4901  if (!new_clip) {
4902  // this is needed in case we render to same clip, and then undo ///////
4903  if (cfile->event_list_back) event_list_free(cfile->event_list_back);
4904  cfile->event_list_back = mainw->event_list;
4906  } else event_list_free(mainw->event_list);
4907  }
4908  mainw->event_list = NULL;
4909  }
4910  if (mainw->scrap_pixbuf) {
4912  mainw->scrap_pixbuf = NULL;
4913  }
4914  if (new_clip) {
4915  char *tmp;
4916  int old_file = current_file;
4917 
4918  if (transcode) {
4921  mainw->transrend_proc = NULL;
4922  close_current_file(old_file);
4923  goto rtc_done;
4924  }
4925 
4926  if (rendaud && norm_after) on_normalise_audio_activate(NULL, NULL);
4927 
4928  cfile->start = 1;
4929  cfile->end = cfile->frames;
4930 
4931  set_undoable(NULL, FALSE);
4932  add_to_clipmenu();
4933  current_file = mainw->current_file;
4934  if (!save_clip_values(current_file)) {
4935  close_current_file(old_file);
4936  d_print_failed();
4937  retval = FALSE;
4938  goto rtc_done;
4939  }
4941  if (!mainw->multitrack) {
4942  switch_clip(1, current_file, TRUE);
4943  }
4944  d_print((tmp = lives_strdup_printf(_("rendered %d frames to new clip.\n"), cfile->frames)));
4945  lives_free(tmp);
4946  mainw->pre_src_file = mainw->current_file; // if a generator started playback, we will switch back to this file after
4948  } else {
4949  // rendered to same clip - update number of frames
4952  }
4953 
4954  if (cfile->clip_type == CLIP_TYPE_FILE) {
4955  if (cfile->undo_start == 1 && cfile->undo_end == cfile->frames) {
4956  cfile->clip_type = CLIP_TYPE_DISK;
4957  lives_freep((void **)&cfile->frame_index_back);
4958  cfile->frame_index_back = cfile->frame_index; // save for undo :: TODO
4960  } else {
4961  char *what = (_("a new file index"));
4962  LiVESResponseType response;
4963  lives_freep((void **)&cfile->frame_index_back);
4964 
4965  do {
4966  response = LIVES_RESPONSE_OK;
4967  cfile->frame_index_back = cfile->frame_index; // save for undo :: TODO
4968  cfile->frame_index = NULL;
4970  if (!cfile->frame_index) {
4971  cfile->frame_index = cfile->frame_index_back;
4972  cfile->frame_index_back = NULL;
4973  response = do_memory_error_dialog(what, cfile->frames * 4);
4974  }
4975  } while (response == LIVES_RESPONSE_RETRY);
4976  lives_free(what);
4977 
4978  if (response == LIVES_RESPONSE_CANCEL) {
4979  if (!mainw->multitrack) {
4980  if (new_clip) { // check
4981  close_current_file(current_file);
4982  } else {
4983  cfile->frame_index = cfile->frame_index_back;
4984  cfile->frame_index_back = NULL;
4985  }
4986  }
4987  return FALSE;
4988  }
4989 
4990  lives_memcpy(cfile->frame_index, cfile->frame_index_back, cfile->undo_start * sizeof(frames_t));
4991 
4992  for (int i = cfile->undo_start - 1; i < cfile->undo_end; i++) {
4993  cfile->frame_index[i] = -1;
4994  }
4995 
4996  lives_memcpy(&cfile->frame_index[cfile->undo_end], &cfile->frame_index_back[cfile->undo_end],
4997  (cfile->frames - cfile->undo_end) * sizeof(frames_t));
4998 
5000  }
5001  }
5002  if (!new_clip) d_print_done();
5003  } else {
5004  retval = FALSE; // cancelled or error, so show the dialog again
5005  if (transcode) {
5008  mainw->transrend_proc = NULL;
5009  }
5010  if (transcode || (new_clip && !mainw->multitrack)) {
5011  // for mt we are rendering to the actual mt file, so we cant close it (CHECK: did we delete all images ?)
5012  close_current_file(current_file);
5013  }
5014  }
5015 
5016 rtc_done:
5022  return retval;
5023 }
5024 
5025 
5026 LIVES_INLINE void dprint_recneg(void) {d_print(_("nothing recorded.\n"));}
5027 
5028 boolean backup_recording(char **esave_file, char **asave_file) {
5029  char *x, *y;
5030  LiVESList *clist = mainw->cliplist;
5031  double vald = 0.;
5032  int fd, i, hdlsize;
5033 
5034  if (!esave_file) esave_file = &x;
5035  if (!asave_file) asave_file = &y;
5036 
5037  *esave_file = lives_strdup_printf("%s/recorded-%s.%d.%d.%d.%s", prefs->workdir, LAYOUT_FILENAME, lives_getuid(), lives_getgid(),
5039  THREADVAR(write_failed) = FALSE;
5040  fd = lives_create_buffered(*esave_file, DEF_FILE_PERMS);
5041  if (fd >= 0) {
5042  save_event_list_inner(NULL, fd, mainw->event_list, NULL);
5044  }
5045  if (fd < 0 || THREADVAR(write_failed)) {
5046  if (mainw->is_exiting) return FALSE;
5047  THREADVAR(write_failed) = FALSE;
5048  lives_freep((void **)esave_file);
5049  *asave_file = NULL;
5050  return FALSE;
5051  }
5052 
5053  *asave_file = lives_strdup_printf("%s/recorded-%s.%d.%d.%d", prefs->workdir, LAYOUT_NUMBERING_FILENAME, lives_getuid(),
5054  lives_getgid(),
5055  capable->mainpid);
5056 
5057  fd = lives_create_buffered(*asave_file, DEF_FILE_PERMS);
5058  if (fd >= 0) {
5059  while (!THREADVAR(write_failed) && clist) {
5060  i = LIVES_POINTER_TO_INT(clist->data);
5061  if (IS_NORMAL_CLIP(i)) {
5062  lives_write_le_buffered(fd, &i, 4, TRUE);
5063  lives_write_le_buffered(fd, &vald, 8, TRUE);
5064  hdlsize = strlen(mainw->files[i]->handle);
5065  lives_write_le_buffered(fd, &hdlsize, 4, TRUE);
5066  lives_write_buffered(fd, (const char *)&mainw->files[i]->handle, hdlsize, TRUE);
5067  }
5068  clist = clist->next;
5069  }
5071  }
5072 
5073  if (fd < 0 || THREADVAR(write_failed)) {
5074  if (mainw->is_exiting) return FALSE;
5075  THREADVAR(write_failed) = FALSE;
5076  lives_rm(*esave_file);
5077  if (fd >= 0) lives_rm(*asave_file);
5078  lives_freep((void **)esave_file);
5079  lives_freep((void **)asave_file);
5080  return FALSE;
5081  }
5082  return TRUE;
5083 }
5084 
5085 
5086 static LiVESResponseType _show_rc_dlg(void) {
5087  LiVESResponseType resp;
5088  LiVESWidget *e_rec_dialog = events_rec_dialog();
5089  resp = lives_dialog_run(LIVES_DIALOG(e_rec_dialog));
5090  lives_widget_destroy(e_rec_dialog);
5091  return resp;
5092 }
5093 
5094 
5095 static LiVESResponseType show_rc_dlg(void) {
5096  LiVESResponseType resp;
5097  main_thread_execute((lives_funcptr_t)_show_rc_dlg, WEED_SEED_INT, &resp, "");
5098  return resp;
5099 }
5100 
5101 
5102 void event_list_add_end_events(weed_event_t *event_list, boolean is_final) {
5103  // for realtime recording, add filter deinit events and switch off audio
5104  // this occurs either when recording is paused (is_final == FALSE) or when playback ends (is_final == TRUE)
5105  if (event_list) {
5106  pthread_mutex_t *event_list_mutex = NULL;
5107  if (event_list == mainw->event_list) event_list_mutex = &mainw->event_list_mutex;
5108 
5109  if (prefs->rec_opts & REC_EFFECTS) {
5110  // add deinit events for all active effects
5111  // this will lock the event _list itself
5112  add_filter_deinit_events(event_list);
5113  }
5114 
5115  if (is_final) {
5116  // switch audio off
5117 #ifdef RT_AUDIO
5119  && mainw->agen_key == 0 && !mainw->agen_needs_reinit &&
5121  if (!mainw->mute) {
5122  weed_plant_t *last_frame = get_last_event(event_list);
5123  event_list = insert_blank_frame_event_at(event_list, mainw->currticks, &last_frame);
5124  if (last_frame) {
5125 #ifdef ENABLE_JACK
5127  if (mainw->jackd)
5128  jack_get_rec_avals(mainw->jackd);
5129  }
5130 #endif
5131 #ifdef HAVE_PULSE_AUDIO
5133  if (mainw->pulsed)
5134  pulse_get_rec_avals(mainw->pulsed);
5135  }
5136 #endif
5137 #if 0
5139  nullaudio_get_rec_avals();
5140  }
5141 #endif
5142  insert_audio_event_at(last_frame, -1, mainw->rec_aclip, mainw->rec_aseek, 0.);
5143  // *INDENT-OFF*
5144  }}}
5145  // *INDENT-ON*
5146 #endif
5147  } else {
5148  // write a RECORD_END marker
5149  weed_timecode_t tc;
5150  if (event_list_mutex) pthread_mutex_lock(event_list_mutex);
5151  tc = get_event_timecode(get_last_event(event_list));
5152  event_list = append_marker_event(event_list, tc, EVENT_MARKER_RECORD_END); // mark record end
5153  if (event_list_mutex) pthread_mutex_unlock(event_list_mutex);
5154  }
5155  }
5156 }
5157 
5158 
5159 boolean deal_with_render_choice(boolean add_deinit) {
5160  // this is called from saveplay.c after record/playback ends
5161  // here we deal with the user's wishes as to how to deal with the recorded events
5162 
5163  // mainw->osc_block should be TRUE during all of this, so we don't have to contend with
5164  // any incoming network messages
5165 
5166  // return TRUE if we rendered to a new clip
5167  lives_proc_thread_t info = NULL;
5168 
5169  LiVESWidget *elist_dialog;
5170 
5171  double df;
5172 
5173  char *esave_file = NULL, *asave_file = NULL;
5174 
5175  boolean new_clip = FALSE, transcode;
5176 
5177  int dh, dw, dar, das, dac, dse;
5178  int oplay_start;
5179 
5180  render_choice = RENDER_CHOICE_NONE;
5181 
5182  if (!CURRENT_CLIP_IS_VALID) {
5184  if (mainw->scrap_file != -1)
5186  else if (mainw->ascrap_file != -1)
5188  if (CURRENT_CLIP_IS_VALID) {
5189  cfile->hsize = DEF_GEN_WIDTH;
5190  cfile->vsize = DEF_GEN_HEIGHT;
5191  }
5192  }
5193 
5194  if (!CURRENT_CLIP_IS_VALID) render_choice = RENDER_CHOICE_MULTITRACK;
5195 
5196  if (count_events(mainw->event_list, FALSE, 0, 0) == 0) {
5198  mainw->event_list = NULL;
5199  }
5200 
5201  if (!mainw->event_list) {
5204  dprint_recneg();
5205  return FALSE;
5206  }
5207 
5208  last_rec_start_tc = -1;
5209 
5211 
5212  // need to retain play_start for rendering to same clip
5213  oplay_start = mainw->play_start;
5214 
5216 
5217  if (prefs->gui_monitor == 0) {
5218  // avoid an annoyance
5220  }
5221 
5222  // crash recovery -> backup the event list
5223  if (prefs->crash_recovery && prefs->rr_crash) {
5225  &esave_file, &asave_file);
5226  }
5227 
5228  do {
5229  transcode = FALSE;
5230  if (render_choice == RENDER_CHOICE_NONE || render_choice == RENDER_CHOICE_PREVIEW)
5231  if (show_rc_dlg() == LIVES_RESPONSE_CANCEL) render_choice = RENDER_CHOICE_DISCARD;
5232  switch (render_choice) {
5233  case RENDER_CHOICE_DISCARD:
5235  && !mainw->clips_available) {
5236  mainw->current_file = -1;
5237  lives_ce_update_timeline(0, 0.);
5238  } else if (CURRENT_CLIP_IS_VALID) cfile->redoable = FALSE;
5241  sensitize();
5242  break;
5243  case RENDER_CHOICE_PREVIEW:
5244  // preview
5245  cfile->next_event = get_first_event(mainw->event_list);
5246  mainw->is_rendering = TRUE;
5248  if (prefs->audio_src == AUDIO_SRC_EXT) {
5250  }
5251  on_preview_clicked(NULL, NULL);
5254  }
5259  cfile->next_event = NULL;
5260  break;
5262  transcode = TRUE;
5264  dw = prefs->mt_def_width;
5265  dh = prefs->mt_def_height;
5266  df = prefs->mt_def_fps;
5267  dar = prefs->mt_def_arate;
5268  dac = prefs->mt_def_achans;
5269  das = prefs->mt_def_asamps;
5270  dse = prefs->mt_def_signed_endian;
5272  if (cfile->hsize > 0) prefs->mt_def_width = cfile->hsize;
5273  if (cfile->vsize > 0) prefs->mt_def_height = cfile->vsize;
5274  prefs->mt_def_fps = cfile->fps;
5275  if (cfile->achans * cfile->arate * cfile->asampsize > 0) {
5276  prefs->mt_def_arate = cfile->arate;
5277  prefs->mt_def_asamps = cfile->asampsize;
5278  prefs->mt_def_achans = cfile->achans;
5279  prefs->mt_def_signed_endian = cfile->signed_endian;
5280  }
5281  }
5282  mainw->play_start = 1;
5283  if (info) {
5284  //lives_nanosleep_until_nonzero(weed_get_boolean_value(info, WEED_LEAF_DONE, NULL));
5285  lives_proc_thread_join(info);
5286  info = NULL;
5287  }
5288  if (!render_to_clip(TRUE, transcode) || render_choice == RENDER_CHOICE_TRANSCODE)
5289  render_choice = RENDER_CHOICE_PREVIEW;
5290  else {
5293  prefs->mt_def_width = dw;
5294  prefs->mt_def_height = dh;
5295  prefs->mt_def_fps = df;
5296  prefs->mt_def_arate = dar;
5297  prefs->mt_def_achans = dac;
5298  prefs->mt_def_asamps = das;
5299  prefs->mt_def_signed_endian = dse;
5301  new_clip = TRUE;
5302  }
5303  break;
5305  cfile->undo_start = mainw->play_start = oplay_start;
5306  if (info) {
5307  lives_proc_thread_join(info);
5308  info = NULL;
5309  }
5310  if (!render_to_clip(FALSE, FALSE)) render_choice = RENDER_CHOICE_PREVIEW;
5311  else {
5314  }
5316  break;
5319  if (!check_for_layout_del(NULL, FALSE)) {
5320  render_choice = RENDER_CHOICE_PREVIEW;
5321  break;
5322  }
5323  }
5327  }
5330  if (info) {
5331  lives_proc_thread_join(info);
5332  info = NULL;
5333  }
5335  if (on_multitrack_activate(NULL, (weed_plant_t *)mainw->event_list)) {
5337  mainw->event_list = NULL;
5338  new_clip = TRUE;
5339  } else render_choice = RENDER_CHOICE_PREVIEW;
5341  break;
5344  if (!do_event_list_warning()) {
5345  render_choice = RENDER_CHOICE_PREVIEW;
5346  break;
5347  }
5348  }
5349  elist_dialog = create_event_list_dialog(mainw->event_list, 0, 0);
5350  lives_dialog_run(LIVES_DIALOG(elist_dialog));
5353  render_choice = RENDER_CHOICE_PREVIEW;
5354  break;
5355  }
5356 
5357  if (CURRENT_CLIP_IS_VALID) cfile->next_event = NULL;
5358 
5359  if (IS_VALID_CLIP(mainw->scrap_file)) {
5360  // rewind scrap file to beginning
5363  }
5364  } while (render_choice == RENDER_CHOICE_PREVIEW);
5365 
5366  if (info) {
5367  lives_proc_thread_join(info);
5368  info = NULL;
5369  }
5370 
5371  if (esave_file) lives_rm(esave_file);
5372  if (asave_file) lives_rm(asave_file);
5373 
5374  if (mainw->event_list) {
5376  mainw->event_list = NULL;
5377  }
5378 
5380  if (render_choice != RENDER_CHOICE_MULTITRACK)
5382 
5383  sensitize();
5384 
5386 
5387  return new_clip;
5388 }
5389 
5390 
5400 double *get_track_visibility_at_tc(weed_plant_t *event_list, int ntracks, int nbtracks,
5401  weed_timecode_t tc, weed_plant_t **shortcut, boolean bleedthru) {
5402  static weed_plant_t *stored_fmap;
5403 
5404  weed_plant_t *frame_event, *fmap;
5405 
5406  double *vis;
5407  double *matrix[ntracks + nbtracks];
5408 
5409  int *clips = NULL;
5410  int64_t *frames = NULL;
5411 
5412  int nxtracks;
5413  int got = -1;
5414 
5415  register int i, j;
5416 
5417  ntracks += nbtracks;
5418 
5419  if (!shortcut || !*shortcut) stored_fmap = NULL;
5420 
5421  if (shortcut) *shortcut = frame_event = get_frame_event_at_or_before(event_list, tc, *shortcut);
5422  else frame_event = get_frame_event_at_or_before(event_list, tc, NULL);
5423 
5424  nxtracks = weed_leaf_num_elements(frame_event, WEED_LEAF_CLIPS);
5425 
5426  vis = (double *)lives_malloc(ntracks * sizeof(double));
5427 
5428  if (bleedthru) {
5429  for (i = 0; i < ntracks; i++) {
5430  vis[i] = 1.;
5431  }
5432  return vis;
5433  }
5434 
5435  clips = weed_get_int_array(frame_event, WEED_LEAF_CLIPS, NULL);
5436  frames = weed_get_int64_array(frame_event, WEED_LEAF_FRAMES, NULL);
5437 
5438  if (nbtracks > 0) vis[0] = 1.;
5439 
5440  if (!stored_fmap) stored_fmap = fmap = get_filter_map_before(frame_event, LIVES_TRACK_ANY, NULL);
5441  else {
5442  fmap = get_filter_map_before(frame_event, LIVES_TRACK_ANY, *shortcut);
5443  if (fmap == *shortcut) fmap = stored_fmap;
5444  }
5445 
5446  for (i = 0; i < ntracks; i++) {
5447  matrix[i] = (double *)lives_malloc(ntracks * sizeof(double));
5448  for (j = 0; j < ntracks; j++) {
5449  matrix[i][j] = 0.;
5450  }
5451  matrix[i][i] = 1.;
5452  }
5453 
5454  if (fmap) {
5455  // here we look at all init_events in fmap. If any have WEED_LEAF_HOST_AUDIO_TRANSITION set, then
5456  // we we look at the 2 in channels. We first multiply matrix[t0][...] by trans - 1
5457  // then we add matrix[t1][...] * (trans) to matrix[t3][...]
5458  // where trans is the normalised value of the transition parameter
5459  // t3 is the output channel, (this is usually the same track as t0)
5460  // thus each row in the matrix represents the contribution from each layer (track)
5461  if (weed_plant_has_leaf(fmap, WEED_LEAF_INIT_EVENTS)) {
5462  int nins;
5463  weed_plant_t **iev = (weed_plant_t **)weed_get_voidptr_array_counted(fmap, WEED_LEAF_INIT_EVENTS, &nins);
5464  for (i = 0; i < nins; i++) {
5465  weed_plant_t *ievent = iev[i];
5466  if (weed_get_boolean_value(ievent, WEED_LEAF_HOST_AUDIO_TRANSITION, NULL) == WEED_TRUE) {
5467  int *in_tracks = weed_get_int_array(ievent, WEED_LEAF_IN_TRACKS, NULL);
5468  int *out_tracks = weed_get_int_array(ievent, WEED_LEAF_OUT_TRACKS, NULL);
5469  char *filter_hash = weed_get_string_value(ievent, WEED_LEAF_FILTER, NULL);
5470  int idx;
5471  if ((idx = weed_get_idx_for_hashname(filter_hash, TRUE)) != -1) {
5472  int npch;
5473  weed_plant_t *filter = get_weed_filter(idx);
5474  int tparam = get_transition_param(filter, FALSE);
5475  weed_plant_t *inst = weed_instance_from_filter(filter);
5476  weed_plant_t **in_params = weed_instance_get_in_params(inst, NULL);
5477  weed_plant_t *ttmpl = weed_param_get_template(in_params[tparam]);
5478  void **pchains = weed_get_voidptr_array_counted(ievent, WEED_LEAF_IN_PARAMETERS, &npch);
5479  double trans;
5480 
5481  if (tparam < npch) interpolate_param(in_params[tparam], pchains[tparam], tc);
5482  lives_free(pchains);
5483 
5484  if (weed_leaf_seed_type(in_params[tparam], WEED_LEAF_VALUE) == WEED_SEED_DOUBLE) {
5485  double transd = weed_get_double_value(in_params[tparam], WEED_LEAF_VALUE, NULL);
5486  double tmin = weed_get_double_value(ttmpl, WEED_LEAF_MIN, NULL);
5487  double tmax = weed_get_double_value(ttmpl, WEED_LEAF_MAX, NULL);
5488  trans = (transd - tmin) / (tmax - tmin);
5489  } else {
5490  int transi = weed_get_int_value(in_params[tparam], WEED_LEAF_VALUE, NULL);
5491  int tmin = weed_get_int_value(ttmpl, WEED_LEAF_MIN, NULL);
5492  int tmax = weed_get_int_value(ttmpl, WEED_LEAF_MAX, NULL);
5493  trans = (double)(transi - tmin) / (double)(tmax - tmin);
5494  }
5495  lives_free(in_params);
5496  for (j = 0; j < ntracks; j++) {
5498  /* matrix[in_tracks[1] + nbtracks][j] *= lives_vol_from_linear(trans); */
5499  /* matrix[in_tracks[0] + nbtracks][j] *= lives_vol_from_linear((1. - trans)); */
5500  matrix[in_tracks[1] + nbtracks][j] *= trans;
5501  matrix[in_tracks[0] + nbtracks][j] *= 1. - trans;
5502  matrix[out_tracks[0] + nbtracks][j] = matrix[in_tracks[0] + nbtracks][j] + matrix[in_tracks[1] + nbtracks][j];
5503  }
5504 
5505  weed_instance_unref(inst);
5506  weed_instance_unref(inst);
5507  }
5508  lives_free(in_tracks);
5509  lives_free(out_tracks);
5510  lives_free(filter_hash);
5511  }
5512  }
5513  lives_free(iev);
5514  }
5515  }
5516 
5517  // now we select as visibility, whichever row is the first layer to have a non-blank frame
5518 
5519  for (i = 0; i < nxtracks; i++) {
5520  if (clips[i] >= 0 && frames[i] > 0) {
5521  got = i + nbtracks;
5522  break;
5523  }
5524  }
5525  lives_free(clips);
5526  lives_free(frames);
5527 
5528  if (got == -1) {
5529  // all frames blank - backing audio only
5530  for (i = 0; i < ntracks; i++) {
5531  if (i >= nbtracks) vis[i] = 0.;
5532  lives_free(matrix[i]);
5533  }
5534  return vis;
5535  }
5536 
5537  for (i = nbtracks; i < ntracks; i++) {
5538  vis[i] = matrix[got][i];
5539  }
5540 
5541  for (i = 0; i < ntracks; i++) {
5542  lives_free(matrix[i]);
5543  }
5544 
5545  return vis;
5546 }
5547 
5549 //GUI stuff
5550 
5551 enum {
5556  NUM_COLUMNS
5557 };
5558 
5559 
5560 #if GTK_CHECK_VERSION(3, 0, 0)
5561 static void rowexpand(LiVESWidget * tv, LiVESTreeIter * iter, LiVESTreePath * path, livespointer ud) {
5565 }
5566 #endif
5567 
5568 
5569 static void quant_clicked(LiVESButton * button, livespointer elist) {
5570  weed_plant_t *ev_list = (weed_plant_t *)elist;
5571  weed_plant_t *qevent_list = quantise_events(ev_list, cfile->fps, FALSE);
5572  if (qevent_list) {
5573  /* reset_renumbering(); */
5574  /* event_list_rectify(NULL, qevent_list); */
5575  event_list_replace_events(ev_list, qevent_list);
5576  weed_set_double_value(ev_list, WEED_LEAF_FPS, cfile->fps);
5577  }
5578  lives_general_button_clicked(button, NULL);
5579 }
5580 
5581 
5582 LiVESWidget *create_event_list_dialog(weed_plant_t *event_list, weed_timecode_t start_tc, weed_timecode_t end_tc) {
5583  // TODO - some event properties should be editable, e.g. parameter values
5584  weed_timecode_t tc, tc_secs;
5585 
5586  LiVESTreeStore *treestore;
5587  LiVESTreeIter iter1, iter2, iter3;
5588  static size_t inistrlen = 0;
5589 
5590  char **string = NULL;
5591  int *intval = NULL;
5592  void **voidval = NULL;
5593  double *doubval = NULL;
5594  int64_t *int64val = NULL;
5595 
5596  weed_plant_t *event, *ievent;
5597 
5598  LiVESWidget *event_dialog, *daa;
5599  LiVESWidget *tree;
5600  LiVESWidget *table;
5601  LiVESWidget *top_vbox;
5602  LiVESWidget *label;
5603  LiVESWidget *ok_button;
5604  LiVESWidget *scrolledwindow;
5605 
5606  LiVESCellRenderer *renderer;
5607  LiVESTreeViewColumn *column;
5608 
5609  LiVESAccelGroup *accel_group;
5610 
5611  char **propnames;
5612 
5613  char *strval = NULL, *desc = NULL;
5614  char *text, *ltext;
5615  char *oldval = NULL, *final = NULL;
5616  char *iname = NULL, *fname = NULL;
5617  char *tmp;
5618 
5619  int woat = widget_opts.apply_theme;
5620 
5621  int winsize_h;
5622  int winsize_v;
5623 
5624  int num_elems, seed_type, etype;
5625  int rows, currow = 0;
5626  int ie_idx = 0;
5627 
5628  int i, j;
5629 
5630  if (inistrlen == 0) inistrlen = lives_strlen(WEED_LEAF_INIT_EVENT);
5631 
5632  if (prefs->event_window_show_frame_events) rows = count_events(event_list, TRUE, start_tc, end_tc);
5633  else rows = count_events(event_list, TRUE, start_tc, end_tc) - count_events(event_list, FALSE, start_tc, end_tc);
5634 
5635  //event = get_first_event(event_list);
5636  event = get_first_event(event_list);
5637 
5638  winsize_h = GUI_SCREEN_WIDTH - SCR_WIDTH_SAFETY;
5639  winsize_v = GUI_SCREEN_HEIGHT - SCR_HEIGHT_SAFETY;
5640 
5641  event_dialog = lives_standard_dialog_new(_("Event List"), FALSE, winsize_h, winsize_v);
5642 
5643  accel_group = LIVES_ACCEL_GROUP(lives_accel_group_new());
5644  lives_window_add_accel_group(LIVES_WINDOW(event_dialog), accel_group);
5645 
5646  top_vbox = lives_dialog_get_content_area(LIVES_DIALOG(event_dialog));
5647 
5648  table = lives_table_new(rows, 6, FALSE);
5649  lives_widget_set_valign(table, LIVES_ALIGN_START);
5650 
5651  while (event) {
5652  // pass through all events
5653  tc = get_event_timecode(event);
5654 
5655  if (end_tc > 0) {
5656  if (tc < start_tc) {
5657  event = get_next_event(event);
5658  continue;
5659  }
5660  if (tc >= end_tc) break;
5661  }
5662 
5663  etype = get_event_type(event);
5664 
5667  // TODO - opts should be all frames, only audio frames, no frames
5668  // or even better, filter for any event types
5669  rows++;
5670  lives_table_resize(LIVES_TABLE(table), rows, 6);
5671  }
5672 
5673  treestore = lives_tree_store_new(NUM_COLUMNS, LIVES_COL_TYPE_STRING, LIVES_COL_TYPE_STRING,
5674  LIVES_COL_TYPE_STRING, LIVES_COL_TYPE_STRING);
5675 
5676  lives_tree_store_append(treestore, &iter1, NULL); /* Acquire an iterator */
5677  lives_tree_store_set(treestore, &iter1, TITLE_COLUMN, "Properties", -1);
5678 
5679  // get list of keys (property) names for this event
5680  propnames = weed_plant_list_leaves(event, NULL);
5681 
5682  for (i = 0; propnames[i]; i++) {
5683  if (!strcmp(propnames[i], WEED_LEAF_TYPE) || !strcmp(propnames[i], WEED_LEAF_EVENT_TYPE) ||
5684  !lives_strcmp(propnames[i], WEED_LEAF_TIMECODE) || !strncmp(propnames[i], "host_", 5)) {
5685  lives_free(propnames[i]);
5686  continue;
5687  }
5688  lives_tree_store_append(treestore, &iter2, &iter1); /* Acquire a child iterator */
5689 
5690  lives_freep((void **)&oldval);
5691  lives_freep((void **)&final);
5692 
5693  num_elems = weed_leaf_num_elements(event, propnames[i]);
5694  seed_type = weed_leaf_seed_type(event, propnames[i]);
5695 
5696  switch (seed_type) {
5697  // get the value
5698  case WEED_SEED_INT:
5699  intval = weed_get_int_array(event, propnames[i], NULL);
5700  break;
5701  case WEED_SEED_INT64:
5702  int64val = weed_get_int64_array(event, propnames[i], NULL);
5703  break;
5704  case WEED_SEED_BOOLEAN:
5705  intval = weed_get_boolean_array(event, propnames[i], NULL);
5706  break;
5707  case WEED_SEED_STRING:
5708  string = weed_get_string_array(event, propnames[i], NULL);
5709  break;
5710  case WEED_SEED_DOUBLE:
5711  doubval = weed_get_double_array(event, propnames[i], NULL);
5712  break;
5713  case WEED_SEED_VOIDPTR:
5714  voidval = weed_get_voidptr_array(event, propnames[i], NULL);
5715  break;
5716  case WEED_SEED_PLANTPTR:
5717  voidval = (void **)weed_get_plantptr_array(event, propnames[i], NULL);
5718  break;
5719  }
5720 
5721  ievent = NULL;
5722 
5723  for (j = 0; j < num_elems; j++) {
5724  if (etype == WEED_EVENT_TYPE_PARAM_CHANGE && (!strcmp(propnames[i], WEED_LEAF_INDEX))
5725  && seed_type == WEED_SEED_INT) {
5726  char *pname = NULL; // want the parameter name for the index
5727  weed_plant_t *ptmpl = NULL;
5728  ievent = (weed_plant_t *)weed_get_voidptr_value(event, WEED_LEAF_INIT_EVENT, NULL);
5729  if (ievent) {
5730  lives_freep((void **)&iname);
5731  iname = weed_get_string_value(ievent, WEED_LEAF_FILTER, NULL);
5732  if (iname) {
5733  ie_idx = weed_get_idx_for_hashname(iname, TRUE);
5734  }
5735  lives_freep((void **)&iname);
5736  ptmpl = weed_filter_in_paramtmpl(get_weed_filter(ie_idx), intval[j], TRUE);
5737  }
5738  if (ptmpl)
5739  pname = weed_get_string_value(ptmpl, WEED_LEAF_NAME, NULL);
5740  else pname = lives_strdup("???");
5741  strval = lives_strdup_printf("%d", intval[j]);
5742  desc = lives_strdup_printf("(%s)", pname);
5743  lives_freep((void **)&pname);
5744  } else {
5745  if (etype == WEED_EVENT_TYPE_FILTER_INIT && (!strcmp(propnames[i], WEED_LEAF_IN_TRACKS)
5746  || !strcmp(propnames[i], WEED_LEAF_OUT_TRACKS))) {
5747  if (mainw->multitrack) {
5748  iname = weed_get_string_value(event, WEED_LEAF_FILTER, NULL);
5749  if (iname) {
5750  ie_idx = weed_get_idx_for_hashname(iname, TRUE);
5751  }
5752  lives_freep((void **)&iname);
5753  strval = lives_strdup_printf("%d", intval[j]);
5754  desc = lives_strdup_printf("(%s)",
5755  (tmp = get_track_name(mainw->multitrack, intval[j],
5756  is_pure_audio(get_weed_filter(ie_idx), FALSE))));
5757  lives_free(tmp);
5758  } else {
5759  strval = lives_strdup_printf("%d", intval[j]);
5760  desc = lives_strdup_printf("(%s)", intval[j] == 0 ? _("foreground clip")
5761  : _("background_clip"));
5762  }
5763  } else {
5764  if (0);
5765  /* if (etype == WEED_EVENT_TYPE_FILTER_INIT && (!strcmp(propnames[i], WEED_LEAF_IN_COUNT) */
5766  /* || !strcmp(propnames[i], WEED_LEAF_OUT_COUNT))) { */
5767  /* iname = weed_get_string_value(event, WEED_LEAF_FILTER, NULL); */
5768  /* if (iname) { */
5769  /* ie_idx = weed_get_idx_for_hashname(iname, TRUE); */
5770  /* } */
5771  /* strval = lives_strdup_printf("%d (%s X %d)", intval[j], weed_chantmpl_get_name(...etc)); */
5772  /* lives_freep((void **)&iname); */
5773  /* } */
5774  else {
5775  switch (seed_type) {
5776  // format each element of value
5777  case WEED_SEED_INT:
5778  strval = lives_strdup_printf("%d", intval[j]);
5779  break;
5780  case WEED_SEED_INT64:
5781  strval = lives_strdup_printf("%"PRId64, int64val[j]);
5782  break;
5783  case WEED_SEED_DOUBLE:
5784  strval = lives_strdup_printf("%.4f", doubval[j]);
5785  break;
5786  case WEED_SEED_BOOLEAN:
5787  if (intval[j] == WEED_TRUE) strval = (_("TRUE"));
5788  else strval = (_("FALSE"));
5789  break;
5790  case WEED_SEED_STRING:
5791  if (etype == WEED_EVENT_TYPE_FILTER_INIT && (!strcmp(propnames[i], WEED_LEAF_FILTER))) {
5792  ie_idx = weed_get_idx_for_hashname(string[j], TRUE);
5793  strval = weed_filter_idx_get_name(ie_idx, FALSE, FALSE);
5794  } else strval = lives_strdup(string[j]);
5795  lives_free(string[j]);
5796  break;
5797  case WEED_SEED_VOIDPTR:
5798  if (etype == WEED_EVENT_TYPE_FILTER_DEINIT || etype == WEED_EVENT_TYPE_FILTER_MAP
5799  || etype == WEED_EVENT_TYPE_PARAM_CHANGE) {
5800  if (!(lives_strncmp(propnames[i], WEED_LEAF_INIT_EVENT, inistrlen))) {
5801  ievent = (weed_plant_t *)voidval[j];
5802  if (ievent) {
5803  lives_freep((void **)&iname);
5804  iname = weed_get_string_value(ievent, WEED_LEAF_FILTER, NULL);
5805  if (iname) {
5806  ie_idx = weed_get_idx_for_hashname(iname, TRUE);
5807  fname = weed_filter_idx_get_name(ie_idx, FALSE, FALSE);
5808  strval = lives_strdup_printf("%p", voidval[j]);
5809  desc = lives_strdup_printf("(%s)", fname);
5810  lives_freep((void **)&fname);
5811  }
5812  lives_freep((void **)&iname);
5813  }
5814  }
5815  }
5816  if (!strval) {
5817  if (voidval[j]) strval = lives_strdup_printf("%p", voidval[j]);
5818  else strval = lives_strdup(" - ");
5819  }
5820  break;
5821  case WEED_SEED_PLANTPTR:
5822  strval = lives_strdup_printf("%p", voidval[j]);
5823  break;
5824  default:
5825  strval = lives_strdup("???");
5826  break;
5827  // *INDENT-OFF*
5828  }}}}
5829  // *INDENT-ON*
5830 
5831  // attach to treestore
5832  if (j == 0) {
5833  if (num_elems == 1) {
5834  lives_tree_store_set(treestore, &iter2, KEY_COLUMN, propnames[i], VALUE_COLUMN, strval, -1);
5835  lives_tree_store_set(treestore, &iter2, DESC_COLUMN, desc, -1);
5836  } else {
5837  lives_tree_store_set(treestore, &iter2, KEY_COLUMN, propnames[i], VALUE_COLUMN, "", -1);
5838  lives_tree_store_append(treestore, &iter3, &iter2);
5839  lives_tree_store_set(treestore, &iter3, VALUE_COLUMN, strval, -1);
5840  lives_tree_store_set(treestore, &iter3, DESC_COLUMN, desc, -1);
5841  }
5842  } else {
5843  lives_tree_store_append(treestore, &iter3, &iter2);
5844  lives_tree_store_set(treestore, &iter3, VALUE_COLUMN, strval, -1);
5845  }
5846  lives_freep((void **)&desc);
5847  lives_freep((void **)&strval);
5848  }
5849 
5850  switch (seed_type) {
5851  // free temp memory
5852  case WEED_SEED_INT:
5853  case WEED_SEED_BOOLEAN:
5854  lives_free(intval);
5855  break;
5856  case WEED_SEED_INT64:
5857  lives_free(int64val);
5858  break;
5859  case WEED_SEED_DOUBLE:
5860  lives_free(doubval);
5861  break;
5862  case WEED_SEED_STRING:
5863  lives_free(string);
5864  break;
5865  case WEED_SEED_VOIDPTR:
5866  case WEED_SEED_PLANTPTR:
5867  lives_free(voidval);
5868  break;
5869  default: break;
5870  }
5871  lives_free(propnames[i]);
5872  }
5873 
5874  lives_free(propnames);
5875 
5876  // now add the new treeview
5877 
5878  lives_free(final);
5879 
5880  // timecode
5881  tc_secs = tc / TICKS_PER_SECOND;
5882  tc -= tc_secs * TICKS_PER_SECOND;
5883  text = lives_strdup_printf(_("Timecode=%"PRId64".%"PRId64), tc_secs, tc);
5884  label = lives_standard_label_new(text);
5885  lives_free(text);
5886  lives_widget_set_valign(label, LIVES_ALIGN_START);
5887 
5888  lives_table_attach(LIVES_TABLE(table), label, 0, 1, currow, currow + 1,
5889  (LiVESAttachOptions)(LIVES_EXPAND), (LiVESAttachOptions)(0), 0, 0);
5890 
5891  if (WEED_PLANT_IS_EVENT_LIST(event))
5892  ltext = "Event list";
5893  else {
5894  // event type
5895  switch (etype) {
5896  case WEED_EVENT_TYPE_FRAME:
5897  if (WEED_EVENT_IS_AUDIO_FRAME(event))
5898  ltext = "Frame with audio";
5899  else
5900  ltext = "Frame";
5901  break;
5902  case WEED_EVENT_TYPE_FILTER_INIT:
5903  ltext = "Filter on"; break;
5904  case WEED_EVENT_TYPE_FILTER_DEINIT:
5905  ltext = "Filter off"; break;
5906  case WEED_EVENT_TYPE_PARAM_CHANGE:
5907  ltext = "Parameter change"; break;
5908  case WEED_EVENT_TYPE_FILTER_MAP:
5909  ltext = "Filter map"; break;
5910  case WEED_EVENT_TYPE_MARKER:
5911  ltext = "Marker"; break;
5912  default:
5913  ltext = lives_strdup_printf("unknown event type %d", etype);
5914  label = lives_standard_label_new(ltext);
5915  ltext = NULL;
5916  }
5917  }
5918  if (ltext) {
5919  text = lives_strdup_printf("<big><b>%s</b></big>", ltext);
5921  label = lives_standard_label_new(text);
5923  lives_free(text);
5924  lives_widget_set_valign(label, LIVES_ALIGN_START);
5925  }
5926 
5927  lives_table_attach(LIVES_TABLE(table), label, 1, 2, currow, currow + 1,
5928  (LiVESAttachOptions)(LIVES_EXPAND), (LiVESAttachOptions)(0), 0, 0);
5929 
5930  // event id
5931  text = lives_strdup_printf(_("Event id=%p"), (void *)event);
5932  label = lives_standard_label_new(text);
5933  lives_free(text);
5934  lives_widget_set_valign(label, LIVES_ALIGN_START);
5935 
5936  lives_table_attach(LIVES_TABLE(table), label, 2, 3, currow, currow + 1,
5937  (LiVESAttachOptions)(LIVES_EXPAND),
5938  (LiVESAttachOptions)(0), 0, 0);
5939 
5940  // properties
5941  tree = lives_tree_view_new_with_model(LIVES_TREE_MODEL(treestore));
5942 
5943  if (palette->style & STYLE_1) {
5944  lives_widget_set_base_color(tree, LIVES_WIDGET_STATE_NORMAL, &palette->info_base);
5945  lives_widget_set_text_color(tree, LIVES_WIDGET_STATE_NORMAL, &palette->info_text);
5946  }
5947 
5948  renderer = lives_cell_renderer_text_new();
5950  renderer, LIVES_TREE_VIEW_COLUMN_TEXT, TITLE_COLUMN, NULL);
5951 
5952  gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
5953  lives_tree_view_append_column(LIVES_TREE_VIEW(tree), column);
5954 
5955  renderer = lives_cell_renderer_text_new();
5956  GValue gval = G_VALUE_INIT;
5957  g_value_init(&gval, G_TYPE_INT);
5958  g_value_set_int(&gval, 12);
5959  gtk_cell_renderer_set_padding(renderer, widget_opts.packing_width, 0);
5961  renderer, LIVES_TREE_VIEW_COLUMN_TEXT, KEY_COLUMN, NULL);
5962  gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
5963  gtk_tree_view_column_set_expand(column, TRUE);
5964  lives_tree_view_append_column(LIVES_TREE_VIEW(tree), column);
5965 
5966  renderer = lives_cell_renderer_text_new();
5967  gtk_cell_renderer_set_padding(renderer, widget_opts.packing_width, 0);
5968  column = lives_tree_view_column_new_with_attributes(_("Values"),
5969  renderer, LIVES_TREE_VIEW_COLUMN_TEXT, VALUE_COLUMN, NULL);
5970  gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
5971  gtk_tree_view_column_set_expand(column, TRUE);
5972  lives_tree_view_append_column(LIVES_TREE_VIEW(tree), column);
5973 
5974  renderer = lives_cell_renderer_text_new();
5975  gtk_cell_renderer_set_padding(renderer, widget_opts.packing_width, 0);
5976  column = lives_tree_view_column_new_with_attributes(_("Description"),
5977  renderer, LIVES_TREE_VIEW_COLUMN_TEXT, DESC_COLUMN, NULL);
5978  gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
5979  gtk_tree_view_column_set_expand(column, TRUE);
5980  lives_tree_view_append_column(LIVES_TREE_VIEW(tree), column);
5981 
5982  lives_table_attach(LIVES_TABLE(table), tree, 3, 6, currow, currow + 1,
5983  (LiVESAttachOptions)(LIVES_FILL | LIVES_EXPAND),
5984  (LiVESAttachOptions)(LIVES_FILL | LIVES_EXPAND), 0, 0);
5985 
5986 #if GTK_CHECK_VERSION(3, 0, 0)
5987  lives_signal_sync_connect(LIVES_GUI_OBJECT(tree), LIVES_WIDGET_ROW_EXPANDED_SIGNAL,
5988  LIVES_GUI_CALLBACK(rowexpand), NULL);
5989 
5991 #endif
5992  currow++;
5993  gtk_tree_view_set_fixed_height_mode(LIVES_TREE_VIEW(tree), TRUE);
5994  }
5995  if (event == event_list) event = get_first_event(event_list);
5996  else event = get_next_event(event);
5997  }
5998 
5999  lives_freep((void **)&iname);
6000 
6002  scrolledwindow = lives_standard_scrolled_window_new(winsize_h, winsize_v, table);
6003  widget_opts.apply_theme = woat;
6004 
6005 #if !GTK_CHECK_VERSION(3, 0, 0)
6006  if (palette->style & STYLE_1) {
6007  lives_widget_set_bg_color(top_vbox, LIVES_WIDGET_STATE_NORMAL, &palette->info_base);
6008  lives_widget_set_fg_color(top_vbox, LIVES_WIDGET_STATE_NORMAL, &palette->info_text);
6009  lives_widget_set_bg_color(lives_bin_get_child(LIVES_BIN(scrolledwindow)), LIVES_WIDGET_STATE_NORMAL, &palette->info_base);
6010  }
6011 #endif
6012 
6013  lives_box_pack_start(LIVES_BOX(top_vbox), scrolledwindow, TRUE, TRUE, widget_opts.packing_height);
6014 
6015  if (prefs->show_dev_opts) {
6016  if (CURRENT_CLIP_IS_VALID) {
6017  char *tmp = lives_strdup_printf("Quantise to %.4f fps", cfile->fps);
6018  LiVESWidget *qbutton = lives_dialog_add_button_from_stock(LIVES_DIALOG(event_dialog), NULL, tmp,
6019  LIVES_RESPONSE_OK);
6020  lives_free(tmp);
6021  lives_signal_sync_connect(LIVES_GUI_OBJECT(qbutton), LIVES_WIDGET_CLICKED_SIGNAL,
6022  LIVES_GUI_CALLBACK(quant_clicked), (livespointer)event_list);
6023  }
6024  }
6025  ok_button = lives_dialog_add_button_from_stock(LIVES_DIALOG(event_dialog), LIVES_STOCK_CLOSE, _("_Close Window"),
6026  LIVES_RESPONSE_OK);
6027 
6029 
6030  lives_widget_add_accelerator(ok_button, LIVES_WIDGET_CLICKED_SIGNAL, accel_group,
6031  LIVES_KEY_Escape, (LiVESXModifierType)0, (LiVESAccelFlags)0);
6032 
6033  lives_signal_sync_connect(LIVES_GUI_OBJECT(ok_button), LIVES_WIDGET_CLICKED_SIGNAL,
6034  LIVES_GUI_CALLBACK(lives_general_button_clicked), NULL);
6035 
6036  if (prefs->gui_monitor != 0) {
6037  lives_window_center(LIVES_WINDOW(event_dialog));
6038  }
6039 
6040  daa = lives_dialog_get_action_area(LIVES_DIALOG(event_dialog));
6041  lives_button_box_set_layout(LIVES_BUTTON_BOX(daa), LIVES_BUTTONBOX_SPREAD);
6042 
6043  if (prefs->open_maximised) {
6044  lives_window_unmaximize(LIVES_WINDOW(event_dialog));
6045  lives_window_maximize(LIVES_WINDOW(event_dialog));
6046  }
6047 
6048  lives_widget_show_all(event_dialog);
6049 
6050  return event_dialog;
6051 }
6052 
6053 
6054 void rdetw_spinh_changed(LiVESSpinButton * spinbutton, livespointer user_data) {
6055  render_details *rdet = (render_details *)user_data;
6056  rdet->height = lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(spinbutton));
6057 }
6058 
6059 
6060 void rdetw_spinw_changed(LiVESSpinButton * spinbutton, livespointer user_data) {
6061  render_details *rdet = (render_details *)user_data;
6062  rdet->width = lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(spinbutton));
6063 }
6064 
6065 
6066 void rdetw_spinf_changed(LiVESSpinButton * spinbutton, livespointer user_data) {
6067  render_details *rdet = (render_details *)user_data;
6068  rdet->fps = lives_spin_button_get_value(LIVES_SPIN_BUTTON(spinbutton));
6069 }
6070 
6071 
6072 LiVESWidget *add_video_options(LiVESWidget **spwidth, int defwidth, LiVESWidget **spheight, int defheight,
6073  LiVESWidget **spfps, double deffps, LiVESWidget **spframes, int defframes,
6074  boolean add_aspect, LiVESWidget * extra) {
6075  // add video options to multitrack enter, etc
6076  LiVESWidget *vbox, *hbox, *layout;
6077  LiVESWidget *frame = lives_standard_frame_new(_("Video"), 0., FALSE);
6078 
6079  double width_step = 4.;
6080  double height_step = 4.;
6081 
6082  vbox = lives_vbox_new(FALSE, 0);
6083  lives_container_add(LIVES_CONTAINER(frame), vbox);
6084 
6085  layout = lives_layout_new(LIVES_BOX(vbox));
6086 
6087  hbox = lives_layout_hbox_new(LIVES_LAYOUT(layout));
6089  (_("_Width"), defwidth, width_step, MAX_FRAME_WIDTH, width_step, width_step, 0, LIVES_BOX(hbox), NULL);
6090  lives_spin_button_set_snap_to_multiples(LIVES_SPIN_BUTTON(*spwidth), width_step);
6091  lives_spin_button_update(LIVES_SPIN_BUTTON(*spwidth));
6092 
6093  hbox = lives_layout_hbox_new(LIVES_LAYOUT(layout));
6094  *spheight = lives_standard_spin_button_new
6095  (_("_Height"), defheight, height_step, MAX_FRAME_WIDTH, height_step, height_step, 0, LIVES_BOX(hbox), NULL);
6096  lives_spin_button_set_snap_to_multiples(LIVES_SPIN_BUTTON(*spheight), height_step);
6097  lives_spin_button_update(LIVES_SPIN_BUTTON(*spheight));
6098 
6099  // add aspect button ?
6100  if (add_aspect && CURRENT_CLIP_IS_VALID) {
6101  // add "aspectratio" widget
6102  hbox = lives_layout_hbox_new(LIVES_LAYOUT(layout));
6103  add_aspect_ratio_button(LIVES_SPIN_BUTTON(*spwidth), LIVES_SPIN_BUTTON(*spheight), LIVES_BOX(hbox));
6104  }
6105 
6106  hbox = lives_layout_row_new(LIVES_LAYOUT(layout));
6107 
6108  if (spframes) {
6109  *spframes = lives_standard_spin_button_new
6110  (_("_Number of frames"), defframes, 1., 100000, 1., 5., 0, LIVES_BOX(hbox), NULL);
6111  hbox = lives_layout_hbox_new(LIVES_LAYOUT(layout));
6112  }
6113 
6115  (_("_Frames per second"), deffps, 1., FPS_MAX, 1., 10., 0, LIVES_BOX(hbox), NULL);
6116 
6117  if (extra) lives_box_pack_start(LIVES_BOX(vbox), extra, FALSE, FALSE, widget_opts.packing_height);
6118 
6119  return frame;
6120 }
6121 
6122 
6123 static void add_fade_elements(render_details * rdet, LiVESWidget * hbox, boolean is_video) {
6124  LiVESWidget *cb;
6125  LiVESWidget *vbox = NULL;
6126  if (is_video) {
6128  lives_box_pack_start(LIVES_BOX(hbox), vbox, FALSE, TRUE, 0);
6129  hbox = lives_hbox_new(FALSE, 0);
6130  lives_box_pack_start(LIVES_BOX(vbox), hbox, FALSE, TRUE, 0);
6131  }
6132  add_fill_to_box(LIVES_BOX(hbox));
6133 
6134  cb = lives_standard_check_button_new(_("Fade in over"), FALSE, LIVES_BOX(hbox), NULL);
6135 
6137  if (!is_video) {
6139  10., 0., 1000., 1., 1., 2,
6140  LIVES_BOX(hbox), NULL);
6141  toggle_sets_sensitive(LIVES_TOGGLE_BUTTON(cb), rdet->afade_in, FALSE);
6142  } else {
6144  10., 0., 1000., 1., 1., 2,
6145  LIVES_BOX(hbox), NULL);
6146  toggle_sets_sensitive(LIVES_TOGGLE_BUTTON(cb), rdet->vfade_in, FALSE);
6147  }
6149 
6150  add_fill_to_box(LIVES_BOX(hbox));
6151 
6152  cb = lives_standard_check_button_new(_("Fade out over"), FALSE, LIVES_BOX(hbox), NULL);
6153 
6155  if (!is_video) {
6157  10., 0., 1000., 1., 1., 2,
6158  LIVES_BOX(hbox), NULL);
6159  toggle_sets_sensitive(LIVES_TOGGLE_BUTTON(cb), rdet->afade_out, FALSE);
6160  } else {
6162  10., 0., 1000., 1., 1., 2,
6163  LIVES_BOX(hbox), NULL);
6164  toggle_sets_sensitive(LIVES_TOGGLE_BUTTON(cb), rdet->vfade_out, FALSE);
6165  }
6167 
6168  add_fill_to_box(LIVES_BOX(hbox));
6169 
6170  if (is_video) {
6171  lives_colRGBA64_t rgba;
6172  LiVESWidget *sp_red, *sp_green, *sp_blue;
6173  rgba.red = rgba.green = rgba.blue = 0;
6174  hbox = lives_hbox_new(FALSE, 0);
6175  lives_box_pack_start(LIVES_BOX(vbox), hbox, FALSE, TRUE, 0);
6176  add_fill_to_box(LIVES_BOX(hbox));
6177  rdet->vfade_col = lives_standard_color_button_new(LIVES_BOX(hbox), _("Fade Color"),
6178  FALSE, &rgba, &sp_red,
6179  &sp_green, &sp_blue, NULL);
6180  }
6181 }
6182 
6183 
6184 LiVESWidget *add_audio_options(LiVESWidget **cbbackaudio, LiVESWidget **cbpertrack) {
6185  LiVESWidget *hbox = lives_hbox_new(FALSE, 0);
6186 
6187  *cbbackaudio = lives_standard_check_button_new(_("Enable _backing audio track"), FALSE, LIVES_BOX(hbox), NULL);
6188 
6189  add_fill_to_box(LIVES_BOX(hbox));
6190 
6191  *cbpertrack = lives_standard_check_button_new(_("Audio track _per video track"), FALSE, LIVES_BOX(hbox), NULL);
6192 
6193  return hbox;
6194 }
6195 
6196 
6197 static void rdet_use_current(LiVESButton * button, livespointer user_data) {
6198  render_details *rdet = (render_details *)user_data;
6199  const lives_special_aspect_t *aspect = NULL;
6200  char *arate, *achans, *asamps;
6201  int aendian;
6202 
6203  if (!CURRENT_CLIP_IS_VALID) return;
6204 
6205  if (CURRENT_CLIP_HAS_VIDEO) {
6206  lives_spin_button_set_value(LIVES_SPIN_BUTTON(rdet->spinbutton_width), (double)cfile->hsize);
6207  lives_spin_button_set_value(LIVES_SPIN_BUTTON(rdet->spinbutton_height), (double)cfile->vsize);
6208  lives_spin_button_set_value(LIVES_SPIN_BUTTON(rdet->spinbutton_fps), cfile->fps);
6209  lives_spin_button_update(LIVES_SPIN_BUTTON(rdet->spinbutton_width));
6210 
6211  aspect = paramspecial_get_aspect();
6212 
6213  if (aspect && aspect->lockbutton) lives_widget_show_all(aspect->lockbutton);
6214 
6215  rdet->ratio_fps = cfile->ratio_fps;
6216  }
6217 
6218  if (cfile->achans > 0) {
6220 
6221  arate = lives_strdup_printf("%d", cfile->arate);
6222  lives_entry_set_text(LIVES_ENTRY(resaudw->entry_arate), arate);
6223  lives_free(arate);
6224 
6225  achans = lives_strdup_printf("%d", cfile->achans);
6226  lives_entry_set_text(LIVES_ENTRY(resaudw->entry_achans), achans);
6227  lives_free(achans);
6228 
6229  asamps = lives_strdup_printf("%d", cfile->asampsize);
6230  lives_entry_set_text(LIVES_ENTRY(resaudw->entry_asamps), asamps);
6231  lives_free(asamps);
6232 
6233  aendian = cfile->signed_endian;
6234 
6235  if (aendian & AFORM_UNSIGNED) {
6236  lives_toggle_button_set_active(LIVES_TOGGLE_BUTTON(resaudw->rb_unsigned), TRUE);
6237  } else {
6238  lives_toggle_button_set_active(LIVES_TOGGLE_BUTTON(resaudw->rb_signed), TRUE);
6239  }
6240 
6241  if (aendian & AFORM_BIG_ENDIAN) {
6242  lives_toggle_button_set_active(LIVES_TOGGLE_BUTTON(resaudw->rb_bigend), TRUE);
6243  } else {
6244  lives_toggle_button_set_active(LIVES_TOGGLE_BUTTON(resaudw->rb_littleend), TRUE);
6245  }
6246  } else {
6248  }
6249 }
6250 
6251 
6253  // type == 1 :: pre-save (specified)
6254  // type == 2 :: render to new clip (!specified)
6255  // type == 3 :: enter multitrack (!specified)
6256  // type == 4 :: change during multitrack (!specified)
6257  // type == 5 :: transcode clip (!specified) -> becomes type 2
6258 
6259  LiVESWidget *label;
6260  LiVESWidget *top_vbox;
6261  LiVESWidget *dialog_vbox;
6262  LiVESWidget *scrollw = NULL;
6263  LiVESWidget *hbox;
6264  LiVESWidget *vbox;
6265  LiVESWidget *frame;
6266  LiVESWidget *cancelbutton;
6267  LiVESWidget *alabel;
6268  LiVESWidget *daa;
6269  LiVESWidget *cb_letter;
6270  LiVESWidget *spillover;
6271 
6272  LiVESAccelGroup *rdet_accel_group;
6273 
6274  LiVESList *ofmt_all = NULL;
6275  LiVESList *ofmt = NULL;
6276  LiVESList *encoders = NULL;
6277 
6278  char **array;
6279 
6280  char *tmp, *tmp2, *tmp3;
6281  char *title;
6282 
6283  boolean needs_new_encoder = FALSE;
6284  boolean no_opts = FALSE;
6285 
6286  int width, height, dwidth, dheight, spht, maxwidth, maxheight;
6287 
6288  int scrw = GUI_SCREEN_WIDTH;
6289  int scrh = GUI_SCREEN_HEIGHT;
6290  int dbw;
6291 
6292  int i;
6293 
6294  if (type == 5) {
6295  no_opts = TRUE;
6296  type = 2;
6297  }
6299 
6301 
6302  rdet->is_encoding = FALSE;
6303 
6304  if ((type != 1 && type != 4) || !IS_VALID_CLIP(mainw->current_file) || mainw->current_file == mainw->scrap_file) {
6307  rdet->fps = prefs->mt_def_fps;
6308  rdet->ratio_fps = FALSE;
6309 
6314  } else {
6315  rdet->width = cfile->hsize;
6316  rdet->height = cfile->vsize;
6317  rdet->fps = cfile->fps;
6318  rdet->ratio_fps = cfile->ratio_fps;
6319 
6320  rdet->arate = cfile->arate;
6321  rdet->achans = cfile->achans;
6322  rdet->asamps = cfile->asampsize;
6323  rdet->aendian = cfile->signed_endian;
6324  }
6325 
6326  rdet->enc_changed = FALSE;
6327 
6328  if (type == 3 || type == 4) {
6329  title = (_("Multitrack Details"));
6330  } else if (type == 1) title = (_("Encoding Details"));
6331  else title = (_("New Clip Details"));
6332 
6333  maxwidth = width = scrw - SCR_WIDTH_SAFETY;
6334  maxheight = height = scrh - SCR_HEIGHT_SAFETY;
6335 
6336  if (type == 1) {
6337  width /= 2;
6338  height /= 2;
6339  }
6340 
6342  rdet->dialog = lives_standard_dialog_new(title, FALSE, width, height);
6344 
6345  lives_free(title);
6346 
6347  rdet_accel_group = LIVES_ACCEL_GROUP(lives_accel_group_new());
6348  lives_window_add_accel_group(LIVES_WINDOW(rdet->dialog), rdet_accel_group);
6349 
6350  dialog_vbox = lives_dialog_get_content_area(LIVES_DIALOG(rdet->dialog));
6351 
6352  top_vbox = lives_vbox_new(FALSE, 0);
6353 
6354  if (type != 1) {
6355  dbw = widget_opts.border_width;
6357  // need to set a large enough default here
6358  scrollw = lives_standard_scrolled_window_new(width * .8, height * .5, top_vbox);
6359  widget_opts.border_width = dbw;
6360  lives_box_pack_start(LIVES_BOX(dialog_vbox), scrollw, FALSE, TRUE, 0);
6361  } else lives_box_pack_start(LIVES_BOX(dialog_vbox), top_vbox, FALSE, TRUE, 0);
6362 
6363  lives_container_set_border_width(LIVES_CONTAINER(top_vbox), 0);
6364 
6365  daa = lives_dialog_get_action_area(LIVES_DIALOG(rdet->dialog));
6366 
6367  rdet->always_checkbutton = lives_standard_check_button_new((tmp = (_("_Always use these values"))), FALSE,
6368  LIVES_BOX(daa),
6369  (tmp2 = lives_strdup(
6370  H_("Check this button to always use these values when entering "
6371  "multitrack mode. "
6372  "Choice can be re-enabled from Preferences / Multitrack"))));
6373  lives_button_box_make_first(LIVES_BUTTON_BOX(daa), widget_opts.last_container);
6374 
6376  if (type == 1 || type == 2) gtk_widget_set_no_show_all(rdet->always_hbox, TRUE);
6377 
6378  lives_free(tmp); lives_free(tmp2);
6379 
6380  if (type == 4) {
6381  hbox = lives_hbox_new(FALSE, 0);
6382  cb_letter = lives_standard_check_button_new(_("Apply letterboxing"), prefs->letterbox_mt,
6383  LIVES_BOX(hbox), (tmp = H_("Defines whether black borders will be added when resizing frames\n"
6384  "in order to preserve the original aspect ratio")));
6385  lives_free(tmp);
6386  lives_signal_sync_connect(LIVES_GUI_OBJECT(cb_letter), LIVES_WIDGET_TOGGLED_SIGNAL,
6387  LIVES_GUI_CALLBACK(toggle_sets_pref), (livespointer)PREF_LETTERBOXMT);
6388  } else hbox = NULL;
6389 
6391  rdet->fps, NULL, 0., TRUE, hbox);
6392  lives_box_pack_start(LIVES_BOX(top_vbox), frame, FALSE, TRUE, 0);
6393 
6394  if (type == 4) {
6396  if (aspect && aspect->lockbutton) {
6397  if (lives_lock_button_get_locked(LIVES_BUTTON(aspect->lockbutton)))
6398  lives_lock_button_toggle(LIVES_BUTTON(aspect->lockbutton));
6399  }
6400  }
6401 
6402  if (type == 1) gtk_widget_set_no_show_all(frame, TRUE);
6403 
6404  if (type == 2) {
6405  if (mainw->event_list && weed_plant_has_leaf(mainw->event_list, WEED_LEAF_FPS)) {
6406  lives_spin_button_set_value(LIVES_SPIN_BUTTON(rdet->spinbutton_fps),
6407  weed_get_double_value(mainw->event_list, WEED_LEAF_FPS, NULL));
6409  }
6410 
6411  if (!no_opts) {
6412  // add clip name entry
6413  rdet->clipname_entry = lives_standard_entry_new((tmp = (_("New clip name"))),
6415  MEDIUM_ENTRY_WIDTH, 256, LIVES_BOX(top_vbox),
6416  (tmp3 = (_("The name to give the clip in the Clips menu"))));
6417  lives_free(tmp); lives_free(tmp2); lives_free(tmp3);
6418  }
6419 
6420  /* add_fill_to_box(LIVES_BOX(lives_bin_get_child(LIVES_BIN(frame)))); */
6421  /* hbox = lives_hbox_new(FALSE, 0); */
6422  /* lives_container_add(LIVES_CONTAINER(lives_bin_get_child(LIVES_BIN(frame))), hbox); */
6423  /* add_fill_to_box(LIVES_BOX(hbox)); */
6424  /* add_fade_elements(rdet, hbox, TRUE); */
6425  }
6426  // call these here since adding the widgets may have altered their values
6427  rdetw_spinw_changed(LIVES_SPIN_BUTTON(rdet->spinbutton_width), (livespointer)rdet);
6428  rdetw_spinh_changed(LIVES_SPIN_BUTTON(rdet->spinbutton_height), (livespointer)rdet);
6429 
6430  lives_signal_sync_connect_after(LIVES_GUI_OBJECT(rdet->spinbutton_width), LIVES_WIDGET_VALUE_CHANGED_SIGNAL,
6431  LIVES_GUI_CALLBACK(rdetw_spinw_changed), rdet);
6432 
6433  lives_signal_sync_connect_after(LIVES_GUI_OBJECT(rdet->spinbutton_height), LIVES_WIDGET_VALUE_CHANGED_SIGNAL,
6434  LIVES_GUI_CALLBACK(rdetw_spinh_changed), rdet);
6435 
6436  if (type == 4 && mainw->multitrack->event_list) lives_widget_set_sensitive(rdet->spinbutton_fps, FALSE);
6437 
6438  lives_signal_sync_connect_after(LIVES_GUI_OBJECT(rdet->spinbutton_fps), LIVES_WIDGET_VALUE_CHANGED_SIGNAL,
6439  LIVES_GUI_CALLBACK(rdetw_spinf_changed), rdet);
6440 
6443 
6445  resaudw = NULL;
6446  if (type == 3 || type == 2) resaudw = create_resaudw(3, rdet, top_vbox); // enter mt, render to clip
6447  else if (type == 4 && cfile->achans != 0) {
6448  resaudw = create_resaudw(10, rdet, top_vbox); // change during mt. Channels fixed.
6449  }
6450 
6451  if (type == 2) {
6452  add_fill_to_box(LIVES_BOX(resaudw->vbox));
6453 
6454  hbox = lives_hbox_new(FALSE, 0);
6456  rdet->norm_after = lives_standard_check_button_new(_("_Normalise audio after rendering"),
6457  TRUE, LIVES_BOX(hbox), NULL);
6459 
6460  hbox = lives_hbox_new(FALSE, 0);
6462  add_fade_elements(rdet, hbox, FALSE);
6463  }
6464 
6465  if (type == 3) {
6466  // extra opts
6467  label = lives_standard_label_new(_("Options"));
6468  lives_box_pack_start(LIVES_BOX(top_vbox), label, FALSE, FALSE, widget_opts.packing_height);
6470  lives_box_pack_start(LIVES_BOX(top_vbox), hbox, FALSE, FALSE, widget_opts.packing_height);
6472 
6474  lives_toggle_button_get_active(LIVES_TOGGLE_BUTTON(resaudw->aud_checkbutton)));
6475 
6477 
6479  lives_toggle_button_get_active(LIVES_TOGGLE_BUTTON(resaudw->aud_checkbutton)));
6480  }
6481 
6482  if (!no_opts) {
6483 #ifndef IS_MINGW
6484  if (capable->has_encoder_plugins) encoders = get_plugin_list(PLUGIN_ENCODERS, FALSE, NULL, NULL);
6485 #else
6486  if (capable->has_encoder_plugins) encoders = get_plugin_list(PLUGIN_ENCODERS, TRUE, NULL, NULL);
6487 #endif
6488 
6489  if (type != 1) encoders = filter_encoders_by_img_ext(encoders, prefs->image_ext);
6490  else {
6491  LiVESList *encs = encoders = filter_encoders_by_img_ext(encoders, get_image_ext_for_type(cfile->img_type));
6492  needs_new_encoder = TRUE;
6493  while (encs) {
6494  if (!strcmp((char *)encs->data, prefs->encoder.name)) {
6495  needs_new_encoder = FALSE;
6496  break;
6497  }
6498  encs = encs->next;
6499  }
6500  }
6501 
6502  if (type != 1) {
6503  add_hsep_to_box(LIVES_BOX(top_vbox));
6504  if (type != 3) {
6505  label = lives_standard_label_new(_("Options"));
6506  lives_box_pack_start(LIVES_BOX(top_vbox), label, FALSE, FALSE, widget_opts.packing_height);
6507  }
6508  }
6509 
6511 
6512  if (type != 1) {
6513  hbox = lives_hbox_new(FALSE, 0);
6514  lives_box_pack_start(LIVES_BOX(top_vbox), hbox, FALSE, FALSE, 0);
6515 
6516  vbox = lives_vbox_new(FALSE, 0);
6517 
6518  widget_opts.justify = LIVES_JUSTIFY_CENTER;
6519  lives_standard_expander_new(_("_Encoder preferences (optional)"), LIVES_BOX(hbox), vbox);
6521  } else vbox = top_vbox;
6522 
6523  add_fill_to_box(LIVES_BOX(vbox));
6524 
6525  widget_opts.justify = LIVES_JUSTIFY_CENTER;
6526  label = lives_standard_label_new(_("Target encoder"));
6528  lives_box_pack_start(LIVES_BOX(vbox), label, FALSE, FALSE, widget_opts.packing_height);
6529 
6530  if (type != 1) {
6532  encoders = lives_list_prepend(encoders, lives_strdup(rdet->encoder_name));
6533  } else {
6534  rdet->encoder_name = lives_strdup(prefs->encoder.name);
6535  }
6536 
6537  hbox = lives_hbox_new(FALSE, 0);
6538  add_spring_to_box(LIVES_BOX(hbox), 0);
6539  rdet->encoder_combo = lives_standard_combo_new(NULL, encoders, LIVES_BOX(hbox), NULL);
6540  lives_box_pack_start(LIVES_BOX(vbox), hbox, FALSE, FALSE, 0);
6541  lives_widget_set_halign(rdet->encoder_combo, LIVES_ALIGN_CENTER);
6542  add_spring_to_box(LIVES_BOX(hbox), 0);
6543 
6544  rdet->encoder_name_fn = lives_signal_sync_connect_after(LIVES_COMBO(rdet->encoder_combo), LIVES_WIDGET_CHANGED_SIGNAL,
6545  LIVES_GUI_CALLBACK(on_encoder_entry_changed), rdet);
6546 
6550 
6551  lives_list_free_all(&encoders);
6552 
6553  if (type != 1) {
6554  ofmt = lives_list_append(ofmt, lives_strdup(mainw->string_constants[LIVES_STRING_CONSTANT_ANY]));
6555  } else {
6556  add_fill_to_box(LIVES_BOX(vbox));
6558  // reqest formats from the encoder plugin
6559  if ((ofmt_all = plugin_request_by_line(PLUGIN_ENCODERS, prefs->encoder.name, "get_formats")) != NULL) {
6560  for (i = 0; i < lives_list_length(ofmt_all); i++) {
6561  if (get_token_count((char *)lives_list_nth_data(ofmt_all, i), '|') > 2) {
6562  array = lives_strsplit((char *)lives_list_nth_data(ofmt_all, i), "|", -1);
6563  if (!strcmp(array[0], prefs->encoder.of_name)) {
6564  prefs->encoder.of_allowed_acodecs = atoi(array[2]);
6565  }
6566  ofmt = lives_list_append(ofmt, lives_strdup(array[1]));
6567  lives_strfreev(array);
6568  }
6569  }
6570  lives_list_free_all(&ofmt_all);
6571  } else {
6573  }
6574  }
6575  }
6576 
6577  widget_opts.justify = LIVES_JUSTIFY_CENTER;
6578  label = lives_standard_label_new(_("Output format"));
6580  lives_box_pack_start(LIVES_BOX(vbox), label, FALSE, FALSE, widget_opts.packing_height);
6581 
6582  hbox = lives_hbox_new(FALSE, 0);
6583  add_spring_to_box(LIVES_BOX(hbox), 0);
6584  rdet->ofmt_combo = lives_standard_combo_new(NULL, ofmt, LIVES_BOX(hbox), NULL);
6585  lives_box_pack_start(LIVES_BOX(vbox), hbox, FALSE, FALSE, 0);
6586  lives_widget_set_halign(rdet->ofmt_combo, LIVES_ALIGN_CENTER);
6587  add_spring_to_box(LIVES_BOX(hbox), 0);
6588 
6589  lives_combo_populate(LIVES_COMBO(rdet->ofmt_combo), ofmt);
6590 
6591  lives_list_free_all(&ofmt);
6592 
6593  rdet->encoder_ofmt_fn = lives_signal_sync_connect_after(LIVES_COMBO(rdet->ofmt_combo), LIVES_WIDGET_CHANGED_SIGNAL,
6594  LIVES_GUI_CALLBACK(on_encoder_ofmt_changed), rdet);
6595 
6596  widget_opts.justify = LIVES_JUSTIFY_CENTER;
6597 
6598  alabel = lives_standard_label_new(_("Audio format"));
6600 
6601  if (type != 1) {
6602  // add "Any" string
6604 
6605  prefs->acodec_list = lives_list_append(prefs->acodec_list, lives_strdup(mainw->string_constants[LIVES_STRING_CONSTANT_ANY]));
6606  lives_box_pack_start(LIVES_BOX(vbox), alabel, FALSE, FALSE, widget_opts.packing_height);
6607  hbox = lives_hbox_new(FALSE, 0);
6608  add_spring_to_box(LIVES_BOX(hbox), 0);
6609  rdet->acodec_combo = lives_standard_combo_new(NULL, prefs->acodec_list, LIVES_BOX(hbox), NULL);
6610  lives_box_pack_start(LIVES_BOX(vbox), hbox, FALSE, FALSE, 0);
6611  lives_widget_set_halign(rdet->acodec_combo, LIVES_ALIGN_CENTER);
6612  add_spring_to_box(LIVES_BOX(hbox), 0);
6613  } else {
6614  add_fill_to_box(LIVES_BOX(vbox));
6615  lives_box_pack_start(LIVES_BOX(vbox), alabel, FALSE, FALSE, widget_opts.packing_height);
6619 
6620  hbox = lives_hbox_new(FALSE, 0);
6621  add_spring_to_box(LIVES_BOX(hbox), 0);
6622  rdet->acodec_combo = lives_standard_combo_new(NULL, NULL, LIVES_BOX(hbox), NULL);
6623  lives_box_pack_start(LIVES_BOX(vbox), hbox, FALSE, FALSE, 0);
6624  lives_widget_set_halign(rdet->acodec_combo, LIVES_ALIGN_CENTER);
6625  add_spring_to_box(LIVES_BOX(hbox), 0);
6626 
6630  }
6631  add_fill_to_box(LIVES_BOX(vbox));
6632  } else vbox = top_vbox;
6633 
6635  rdet->debug = NULL;
6636 
6637  if (type == 1 && prefs->show_dev_opts) {
6638  hbox = lives_hbox_new(FALSE, 0);
6639  //add_spring_to_box(LIVES_BOX(hbox), 0);
6640 
6641  rdet->debug = lives_standard_check_button_new((tmp = (_("Debug Mode"))), FALSE,
6642  LIVES_BOX(hbox), (tmp2 = (_("Output diagnostic information to STDERR "
6643  "instead of to the GUI."))));
6644  lives_free(tmp);
6645  lives_free(tmp2);
6646 
6647  lives_box_pack_start(LIVES_BOX(vbox), hbox, FALSE, FALSE, 0);
6648  //lives_widget_set_halign(rdet->acodec_combo, LIVES_ALIGN_CENTER);
6649  add_spring_to_box(LIVES_BOX(hbox), 0);
6650  }
6651 
6652  add_fill_to_box(LIVES_BOX(dialog_vbox));
6653  cancelbutton = NULL;
6654 
6655  if (!(prefs->startup_interface == STARTUP_MT && !mainw->is_ready)) {
6656  cancelbutton = lives_dialog_add_button_from_stock(LIVES_DIALOG(rdet->dialog), LIVES_STOCK_CANCEL, NULL,
6657  LIVES_RESPONSE_CANCEL);
6658  } else if (LIVES_IS_BOX(daa)) add_fill_to_box(LIVES_BOX(daa));
6659 
6660  if (!(prefs->startup_interface == STARTUP_MT && !mainw->is_ready)) {
6661  if (type == 2 || type == 3) {
6665  NULL, _("_Set to current clip values"), LIVES_RESPONSE_RESET);
6667  lives_signal_sync_connect(rdet->usecur_button, LIVES_WIDGET_CLICKED_SIGNAL, LIVES_GUI_CALLBACK(rdet_use_current),
6668  (livespointer)rdet);
6669  }
6670  }
6671  }
6672 
6674  if (type != 1) {
6675  rdet->okbutton = lives_dialog_add_button_from_stock(LIVES_DIALOG(rdet->dialog), LIVES_STOCK_OK, NULL, LIVES_RESPONSE_OK);
6676  } else {
6677  rdet->okbutton = lives_dialog_add_button_from_stock(LIVES_DIALOG(rdet->dialog), LIVES_STOCK_GO_FORWARD, _("_Next"),
6678  LIVES_RESPONSE_OK);
6679  }
6681 
6683 
6684  if (cancelbutton)
6685  lives_widget_add_accelerator(cancelbutton, LIVES_WIDGET_CLICKED_SIGNAL, rdet_accel_group,
6686  LIVES_KEY_Escape, (LiVESXModifierType)0, (LiVESAccelFlags)0);
6687 
6688  if (!no_opts) {
6689  if (needs_new_encoder) {
6691  lives_widget_process_updates(LIVES_MAIN_WINDOW_WIDGET); // force showing of transient window
6693  }
6694 
6695  lives_signal_sync_connect_after(LIVES_COMBO(rdet->acodec_combo), LIVES_WIDGET_CHANGED_SIGNAL,
6696  LIVES_GUI_CALLBACK(rdet_acodec_changed), rdet);
6697  }
6698 
6700 
6701  if (type != 1) {
6702  // shrinkwrap to minimum
6703  spillover = lives_vbox_new(FALSE, 0);
6704  lives_box_pack_start(LIVES_BOX(top_vbox), spillover, TRUE, TRUE, 0); // mop up extra height
6707 
6708  height = lives_widget_get_allocation_height(scrollw) - (spht = lives_widget_get_allocation_height(spillover));
6709  width = lives_widget_get_allocation_width(scrollw);
6710 
6711  dheight = lives_widget_get_allocation_height(rdet->dialog) - spht;
6713 
6714  if (dwidth > maxwidth) dwidth = maxwidth;
6715  if (dheight > maxheight) dheight = maxheight;
6716 
6717  if (width > dwidth) width = dwidth;
6718  if (height > dheight) height = dheight;
6719 
6720  lives_widget_destroy(spillover); // remove extra height
6723 
6724  if (width > 0) lives_scrolled_window_set_min_content_width(LIVES_SCROLLED_WINDOW(scrollw), width);
6725  if (height > 0) lives_scrolled_window_set_min_content_height(LIVES_SCROLLED_WINDOW(scrollw), height);
6726  //lives_widget_set_size_request(scrollw, width, height);
6727  lives_widget_set_maximum_size(scrollw, width, height);
6728 
6729  if (dwidth < width + 6. * widget_opts.border_width) dwidth = width + 6. * widget_opts.border_width;
6730  if (dheight < height + 6. * widget_opts.border_width) dheight = height + 6. * widget_opts.border_width;
6731 
6732  lives_widget_set_size_request(rdet->dialog, dwidth, dheight);
6733  lives_widget_set_maximum_size(rdet->dialog, dwidth, dheight);
6734 
6735  // for expander, need to make it resizable
6736  lives_window_set_resizable(LIVES_WINDOW(rdet->dialog), TRUE);
6737  }
6738 
6740  return rdet;
6741 }
6742 
render_details::fps
double fps
Definition: events.h:218
render_details::achans
int achans
Definition: events.h:251
lives_freep
boolean lives_freep(void **ptr)
Definition: utils.c:1411
LIVES_GLOBAL_INLINE
#define LIVES_GLOBAL_INLINE
Definition: main.h:239
widget_opts_t::packing_width
int packing_width
horizontal pixels between widgets
Definition: widget-helper.h:1410
mainwindow::jackd
void * jackd
jack audio player / transport
Definition: mainwindow.h:1453
render_details::okbutton
LiVESWidget * okbutton
Definition: events.h:221
AFORM_UNSIGNED
#define AFORM_UNSIGNED
Definition: main.h:786
clear_mainw_msg
void clear_mainw_msg(void)
Definition: utils.c:1435
render_details::encoder_name
char * encoder_name
Definition: events.h:245
mainwindow::internal_messaging
boolean internal_messaging
internal fx
Definition: mainwindow.h:1043
_prefs::mt_def_achans
int mt_def_achans
Definition: preferences.h:273
append_frame_event
weed_plant_t * append_frame_event(weed_plant_t *event_list, weed_timecode_t tc, int numframes, int *clips, int64_t *frames)
Definition: events.c:2610
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
create_frame_index
boolean create_frame_index(int fileno, boolean init, frames_t start_offset, frames_t nframes)
Definition: cvirtual.c:27
lives_window_center
boolean lives_window_center(LiVESWindow *window)
Definition: widget-helper.c:11251
WEED_LEAF_WEED_EVENT_API_VERSION
#define WEED_LEAF_WEED_EVENT_API_VERSION
parts of this may eventually become libweed-events
Definition: events.h:18
WEED_LEAF_AUDIO_SEEKS
#define WEED_LEAF_AUDIO_SEEKS
Definition: events.h:41
LIVES_RENDER_READY
@ LIVES_RENDER_READY
Definition: events.h:102
get_active_track_list
void get_active_track_list(int *clip_index, int num_tracks, weed_plant_t *filter_map)
Definition: events.c:3008
LIVES_IS_PLAYING
#define LIVES_IS_PLAYING
Definition: main.h:840
EFFORT_RANGE_MAX
#define EFFORT_RANGE_MAX
if set to TRUE during playback then a new frame (or possibly the current one) will be displayed ASAP
Definition: mainwindow.h:1770
do_event_list_warning
LIVES_GLOBAL_INLINE boolean do_event_list_warning(void)
Definition: dialogs.c:3707
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_combo_set_active_string
WIDGET_HELPER_GLOBAL_INLINE boolean lives_combo_set_active_string(LiVESCombo *combo, const char *active_str)
Definition: widget-helper.c:12290
WEED_LEAF_INIT_EVENTS
#define WEED_LEAF_INIT_EVENTS
Definition: events.h:55
pref_factory_int
boolean pref_factory_int(const char *prefidx, int newval, boolean permanent)
Definition: preferences.c:1053
mainwindow::last_display_ticks
ticks_t last_display_ticks
Definition: mainwindow.h:1012
_prefs::rr_ramicro
boolean rr_ramicro
Definition: preferences.h:495
mainwindow::cliplist
LiVESList * cliplist
hash table of clips in menu order
Definition: mainwindow.h:743
_prefs::render_prompt
boolean render_prompt
Definition: preferences.h:276
do_write_failed_error_s
void do_write_failed_error_s(const char *s, const char *addinfo)
Definition: dialogs.c:3979
_encoder::of_allowed_acodecs
int of_allowed_acodecs
Definition: plugins.h:265
mainwindow::fixed_fpsd
double fixed_fpsd
<=0. means free playback
Definition: mainwindow.h:990
lives_ce_update_timeline
double lives_ce_update_timeline(int frame, double x)
pointer position in timeline
Definition: interface.c:207
mainwindow::effects_paused
boolean effects_paused
Definition: mainwindow.h:1055
mainwindow::active_track_list
int active_track_list[MAX_TRACKS]
Definition: mainwindow.h:1689
update_effort
void update_effort(int nthings, boolean badthings)
Definition: machinestate.c:2656
lives_dialog_add_button_from_stock
LiVESWidget * lives_dialog_add_button_from_stock(LiVESDialog *dialog, const char *stock_id, const char *label, int response_id)
Definition: widget-helper.c:9892
insert_marker_event_at
weed_plant_t * insert_marker_event_at(weed_plant_t *event_list, weed_plant_t *at_event, int marker_type, livespointer data)
Definition: events.c:1418
set_undoable
void set_undoable(const char *what, boolean sensitive)
Definition: utils.c:4784
lives_lock_button_get_locked
WIDGET_HELPER_GLOBAL_INLINE boolean lives_lock_button_get_locked(LiVESButton *button)
Definition: widget-helper.c:10483
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_LEAF_TC_ADJUSTMENT
#define WEED_LEAF_TC_ADJUSTMENT
Definition: events.h:68
WEED_LEAF_HOST_DISABLED
#define WEED_LEAF_HOST_DISABLED
Definition: effects-weed.h:70
render_details::vfade_out
LiVESWidget * vfade_out
Definition: events.h:240
WEED_LEAF_INIT_EVENT
#define WEED_LEAF_INIT_EVENT
Definition: events.h:52
lives_window_set_resizable
WIDGET_HELPER_GLOBAL_INLINE boolean lives_window_set_resizable(LiVESWindow *window, boolean resizable)
Definition: widget-helper.c:2691
weed_frame_event_get_audio_tracks
LIVES_GLOBAL_INLINE int weed_frame_event_get_audio_tracks(weed_event_t *event, int **clips, double **seeks)
Definition: events.c:59
PRId64
#define PRId64
Definition: machinestate.h:169
get_audio_block_start
weed_plant_t * get_audio_block_start(weed_plant_t *event_list, int track, weed_timecode_t tc, boolean seek_back)
Definition: events.c:434
_prefs::mt_def_signed_endian
int mt_def_signed_endian
Definition: preferences.h:273
lives_free
#define lives_free
Definition: machinestate.h:52
LIVES_TRACK_ANY
#define LIVES_TRACK_ANY
Definition: events.h:92
WEED_PLANT_IS_EVENT
#define WEED_PLANT_IS_EVENT(plant)
Definition: events.h:358
weed_filter_idx_get_name
char * weed_filter_idx_get_name(int idx, boolean add_subcats, boolean add_notes)
Definition: effects-weed.c:9475
mainwindow::unordered_blocks
boolean unordered_blocks
are we recording unordered blocks ?
Definition: mainwindow.h:1488
add_init_event_to_filter_map
void add_init_event_to_filter_map(weed_plant_t *fmap, weed_plant_t *event, void **hints)
Definition: events.c:1731
MEDIUM_ENTRY_WIDTH
#define MEDIUM_ENTRY_WIDTH
Definition: widget-helper.h:31
render_details::vfade_col
LiVESWidget * vfade_col
Definition: events.h:241
lives_widget_add_accelerator
WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_add_accelerator(LiVESWidget *widget, const char *accel_signal, LiVESAccelGroup *accel_group, uint32_t accel_key, LiVESXModifierType accel_mods, LiVESAccelFlags accel_flags)
Definition: widget-helper.c:2953
WEED_LEAF_IN_COUNT
#define WEED_LEAF_IN_COUNT
Definition: events.h:45
render_details
Definition: events.h:215
plugin_request_by_line
LIVES_GLOBAL_INLINE LiVESList * plugin_request_by_line(const char *plugin_type, const char *plugin_name, const char *request)
Definition: plugins.c:59
update_filter_maps
void update_filter_maps(weed_plant_t *event, weed_plant_t *end_event, weed_plant_t *init_event)
Definition: events.c:1009
lives_malloc
#define lives_malloc
Definition: machinestate.h:46
mainwindow::is_ready
boolean is_ready
Definition: mainwindow.h:787
PREF_REC_EXT_AUDIO
#define PREF_REC_EXT_AUDIO
Definition: preferences.h:892
reset_ttable
void reset_ttable(void)
Definition: events.c:486
move_filter_deinit_event
void move_filter_deinit_event(weed_plant_t *event_list, weed_timecode_t new_tc, weed_plant_t *deinit_event, double fps, boolean rescale_pchanges)
Definition: events.c:1892
get_frame_event_at_or_before
weed_plant_t * get_frame_event_at_or_before(weed_plant_t *event_list, weed_timecode_t tc, weed_plant_t *shortcut)
Definition: events.c:812
render_details::spinbutton_width
LiVESWidget * spinbutton_width
Definition: events.h:228
lives_lock_button_toggle
boolean lives_lock_button_toggle(LiVESButton *button)
Definition: widget-helper.c:10512
resaudw
_resaudw * resaudw
Definition: resample.h:38
widget_opts_t::justify
LiVESJustification justify
justify for labels
Definition: widget-helper.h:1412
get_first_frame_event
weed_plant_t * get_first_frame_event(weed_plant_t *event_list)
Definition: events.c:404
mainwindow::audio_event
weed_plant_t * audio_event
Definition: mainwindow.h:1300
mainwindow::record
volatile boolean record
Definition: mainwindow.h:794
_prefs::render_audio
boolean render_audio
Definition: preferences.h:298
do_progress_dialog
boolean do_progress_dialog(boolean visible, boolean cancellable, const char *text)
Definition: dialogs.c:2274
lives_get_audio_file_name
LIVES_GLOBAL_INLINE char * lives_get_audio_file_name(int fnum)
Definition: audio.c:55
lives_widget_destroy
LIVES_GLOBAL_INLINE boolean lives_widget_destroy(LiVESWidget *widget)
Definition: widget-helper.c:1553
SCR_HEIGHT_SAFETY
#define SCR_HEIGHT_SAFETY
Definition: mainwindow.h:90
mainwindow::old_active_track_list
int old_active_track_list[MAX_TRACKS]
Definition: mainwindow.h:1692
close_decoder_plugin
void close_decoder_plugin(lives_decoder_t *dplug)
Definition: plugins.c:2361
xprocess::label
LiVESWidget * label
Definition: mainwindow.h:708
weed_call_deinit_func
weed_error_t weed_call_deinit_func(weed_plant_t *instance)
Definition: effects-weed.c:7067
savethread_priv_t::error
LiVESError * error
Definition: main.h:1505
lives_standard_spin_button_new
LiVESWidget * lives_standard_spin_button_new(const char *labeltext, double val, double min, double max, double step, double page, int dp, LiVESBox *box, const char *tooltip)
Definition: widget-helper.c:9397
AFORM_LITTLE_ENDIAN
#define AFORM_LITTLE_ENDIAN
Definition: main.h:784
get_prev_paramchange
weed_timecode_t get_prev_paramchange(void **pchange_prev, weed_timecode_t start_tc)
Definition: events.c:575
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
WEED_LEAF_EDITED_DATE
#define WEED_LEAF_EDITED_DATE
Definition: events.h:35
mainwindow::redo
LiVESWidget * redo
Definition: mainwindow.h:1147
mt_fixup_events
void mt_fixup_events(lives_mt *mt, weed_plant_t *old_event, weed_plant_t *new_event)
Definition: multitrack.c:19321
WEED_LEAF_HOST_TAG_COPY
#define WEED_LEAF_HOST_TAG_COPY
Definition: events.h:88
render_audio_segment
int64_t render_audio_segment(int nfiles, int *from_files, int to_file, double *avels, double *fromtime, weed_timecode_t tc_start, weed_timecode_t tc_end, double *chvol, double opvol_start, double opvol_end, lives_audio_buf_t *obuf)
render a chunk of audio, apply effects and mixing it
Definition: audio.c:1276
_prefs::workdir
char workdir[PATH_MAX]
kept in locale encoding
Definition: preferences.h:61
lives_spin_button_set_value
WIDGET_HELPER_GLOBAL_INLINE boolean lives_spin_button_set_value(LiVESSpinButton *button, double value)
Definition: widget-helper.c:5119
mainwindow::vfade_in_col
lives_colRGBA64_t vfade_in_col
Definition: mainwindow.h:1814
lives_window_maximize
WIDGET_HELPER_GLOBAL_INLINE boolean lives_window_maximize(LiVESWindow *window)
Definition: widget-helper.c:2889
WEED_LEAF_HOST_SCRAP_FILE_OFFSET
#define WEED_LEAF_HOST_SCRAP_FILE_OFFSET
Definition: effects-weed.h:88
lives_spin_button_get_value_as_int
WIDGET_HELPER_GLOBAL_INLINE int lives_spin_button_get_value_as_int(LiVESSpinButton *button)
Definition: widget-helper.c:5091
_prefs::mt_def_fps
double mt_def_fps
Definition: preferences.h:271
get_audio_frame_clip
int get_audio_frame_clip(weed_plant_t *event, int track)
returns clip number for track (track==-1 is backing audio)
Definition: events.c:147
lives_dialog_get_content_area
WIDGET_HELPER_GLOBAL_INLINE LiVESWidget * lives_dialog_get_content_area(LiVESDialog *dialog)
Definition: widget-helper.c:2479
filter_encoders_by_img_ext
LiVESList * filter_encoders_by_img_ext(LiVESList *encoders, const char *img_ext)
Definition: plugins.c:2006
lives_datetime
char * lives_datetime(uint64_t secs, boolean use_local)
Definition: machinestate.c:860
mainwindow::select_last
LiVESWidget * select_last
Definition: mainwindow.h:1162
VALUE_COLUMN
@ VALUE_COLUMN
Definition: events.c:5554
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
append_marker_event
weed_plant_t * append_marker_event(weed_plant_t *event_list, weed_timecode_t tc, int marker_type)
Definition: events.c:1382
IS_VALID_CLIP
#define IS_VALID_CLIP(clip)
Definition: main.h:808
lives_decoder_t
Definition: plugins.h:449
_prefs::crash_recovery
boolean crash_recovery
TRUE==maintain mainw->recovery file.
Definition: preferences.h:259
DEF_GEN_HEIGHT
#define DEF_GEN_HEIGHT
Definition: mainwindow.h:150
LIVES_RENDER_COMPLETE
@ LIVES_RENDER_COMPLETE
Definition: events.h:105
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
event_list_close_gaps
void event_list_close_gaps(weed_event_t *event_list)
Definition: events.c:2365
get_weed_filter
weed_plant_t * get_weed_filter(int idx)
Definition: effects-weed.c:11014
delete_event
void delete_event(weed_plant_t *event_list, weed_plant_t *event)
Definition: events.c:311
_prefs::mt_def_width
int mt_def_width
Definition: preferences.h:270
_palette::style
int style
Definition: mainwindow.h:297
render_details::usecur_button
LiVESWidget * usecur_button
Definition: events.h:222
render_details::width
int width
Definition: events.h:216
WEED_LEAF_HOST_INITED
#define WEED_LEAF_HOST_INITED
Definition: effects-weed.h:74
_resaudw::rb_unsigned
LiVESWidget * rb_unsigned
Definition: resample.h:24
render_details::afade_out
LiVESWidget * afade_out
Definition: events.h:238
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
AUD_DIFF_REVADJ
#define AUD_DIFF_REVADJ
allow longer seek differences when audio plauback direction reverses (multiplying factor)
Definition: events.h:95
on_multitrack_activate
boolean on_multitrack_activate(LiVESMenuItem *menuitem, weed_plant_t *event_list)
menuitem callback
Definition: multitrack.c:11024
get_audio_frame_seek
double get_audio_frame_seek(weed_plant_t *event, int track)
returns velocity for track (track==-1 is backing audio)
Definition: events.c:187
REC_AUDIO
#define REC_AUDIO
Definition: preferences.h:201
check_for_layout_del
boolean check_for_layout_del(lives_mt *mt, boolean exiting)
Definition: multitrack.c:5924
effects.h
lives_table_attach
WIDGET_HELPER_GLOBAL_INLINE boolean lives_table_attach(LiVESTable *table, LiVESWidget *child, uint32_t left, uint32_t right, uint32_t top, uint32_t bottom, LiVESAttachOptions xoptions, LiVESAttachOptions yoptions, uint32_t xpad, uint32_t ypad)
Definition: widget-helper.c:7035
move_filter_init_event
void move_filter_init_event(weed_plant_t *event_list, weed_timecode_t new_tc, weed_plant_t *init_event, double fps)
Definition: events.c:1784
GNU_PURE
#define GNU_PURE
Definition: main.h:78
weed_layer_get_width
LIVES_GLOBAL_INLINE int weed_layer_get_width(weed_layer_t *layer)
Definition: colourspace.c:13941
lives_lseek_buffered_rdonly_absolute
off_t lives_lseek_buffered_rdonly_absolute(int fd, off_t offset)
Definition: utils.c:907
LIVES_ERROR
#define LIVES_ERROR(x)
Definition: main.h:1870
mainwindow::clip_switched
boolean clip_switched
for recording - did we switch clips ?
Definition: mainwindow.h:793
LIVES_JUSTIFY_DEFAULT
#define LIVES_JUSTIFY_DEFAULT
Definition: widget-helper.h:1289
lives_clip_t::clip_type
lives_clip_type_t clip_type
Definition: main.h:886
cvirtual.h
lives_label_set_text
WIDGET_HELPER_GLOBAL_INLINE boolean lives_label_set_text(LiVESLabel *label, const char *text)
Definition: widget-helper.c:6064
lives_standard_dialog_new
LiVESWidget * lives_standard_dialog_new(const char *title, boolean add_std_buttons, int width, int height)
Definition: widget-helper.c:9971
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
_prefs::backend
char backend[PATH_MAX *4]
Definition: preferences.h:411
widget_opts_t::swap_label
boolean swap_label
swap label/widget position
Definition: widget-helper.h:1417
WEED_LEAF_CLIPS
#define WEED_LEAF_CLIPS
Definition: events.h:39
set_render_choice_button
void set_render_choice_button(LiVESButton *button, livespointer choice)
Definition: events.c:2181
_prefs::mt_backaudio
int mt_backaudio
Definition: preferences.h:279
_prefs::audio_player
short audio_player
Definition: preferences.h:40
lives_dialog_run
WIDGET_HELPER_GLOBAL_INLINE LiVESResponseType lives_dialog_run(LiVESDialog *dialog)
Definition: widget-helper.c:1783
get_filter_map_before
weed_plant_t * get_filter_map_before(weed_plant_t *event, int ctrack, weed_plant_t *stop_event)
Definition: events.c:895
filter_map_after_frame
boolean filter_map_after_frame(weed_plant_t *fmap)
Definition: events.c:803
insert_event_after
boolean insert_event_after(weed_plant_t *at_event, weed_plant_t *event)
Definition: events.c:334
backup_host_tags
void backup_host_tags(weed_plant_t *event_list, weed_timecode_t curr_tc)
Definition: events.c:1590
lives_layout_new
WIDGET_HELPER_GLOBAL_INLINE LiVESWidget * lives_layout_new(LiVESBox *box)
Definition: widget-helper.c:7732
REC_EFFECTS
#define REC_EFFECTS
Definition: preferences.h:199
lives_proc_thread_t
weed_plantptr_t lives_proc_thread_t
lives proc_threads API
Definition: machinestate.c:1670
NUM_COLUMNS
@ NUM_COLUMNS
Definition: events.c:5556
_resaudw::vbox
LiVESWidget * vbox
Definition: resample.h:34
mainwindow::transrend_ready
volatile boolean transrend_ready
Definition: mainwindow.h:1809
is_blank_frame
boolean is_blank_frame(weed_plant_t *event, boolean count_audio)
Definition: events.c:523
add_hsep_to_box
LiVESWidget * add_hsep_to_box(LiVESBox *box)
Definition: widget-helper.c:12355
_prefs::rec_opts
int rec_opts
Definition: preferences.h:196
RENDER_CHOICE_DISCARD
#define RENDER_CHOICE_DISCARD
Definition: events.h:265
PREF_SEPWIN_TYPE
#define PREF_SEPWIN_TYPE
Definition: preferences.h:894
get_event_type
LIVES_GLOBAL_INLINE int get_event_type(weed_plant_t *plant)
Definition: events.c:103
savethread_priv_t
Definition: main.h:1503
_prefs::btgamma
boolean btgamma
allows clips to be stored with bt709 gamma - CAUTION not backwards compatible, untested
Definition: preferences.h:453
weed_palette_is_alpha
LIVES_GLOBAL_INLINE boolean weed_palette_is_alpha(int pal)
Definition: colourspace.c:1427
WEED_LEAF_LIVES_TYPE
#define WEED_LEAF_LIVES_TYPE
Definition: events.h:79
_resaudw::entry_arate
LiVESWidget * entry_arate
Definition: resample.h:20
_prefs::backend_sync
char backend_sync[PATH_MAX *4]
Definition: preferences.h:410
TICKS_PER_SECOND_DBL
#define TICKS_PER_SECOND_DBL
actually microseconds / 100.
Definition: mainwindow.h:37
render_details::backaudio_checkbutton
LiVESWidget * backaudio_checkbutton
Definition: events.h:232
lives_button_grab_default_special
boolean lives_button_grab_default_special(LiVESWidget *button)
Definition: widget-helper.c:7587
lives_widget_set_no_show_all
WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_set_no_show_all(LiVESWidget *widget, boolean set)
Definition: widget-helper.c:4868
CANCEL_KILL
@ CANCEL_KILL
normal - kill background processes working on current clip
Definition: main.h:759
render_details::pertrack_checkbutton
LiVESWidget * pertrack_checkbutton
Definition: events.h:231
_resaudw::entry_asamps
LiVESWidget * entry_asamps
Definition: resample.h:22
weed_layer_get_height
LIVES_GLOBAL_INLINE int weed_layer_get_height(weed_layer_t *layer)
Definition: colourspace.c:13953
on_encoder_entry_changed
void on_encoder_entry_changed(LiVESCombo *combo, livespointer ptr)
Definition: callbacks.c:4779
sensitize
void sensitize(void)
Definition: main.c:5078
WEED_LEAF_OVERLAY_TEXT
#define WEED_LEAF_OVERLAY_TEXT
Definition: events.h:90
add_spring_to_box
LiVESWidget * add_spring_to_box(LiVESBox *box, int min)
Definition: widget-helper.c:12421
AUD_PLAYER_NONE
#define AUD_PLAYER_NONE
Definition: preferences.h:41
frame_event_has_frame_for_track
boolean frame_event_has_frame_for_track(weed_plant_t *event, int track)
Definition: events.c:761
get_token_count
size_t get_token_count(const char *string, int delim)
Definition: utils.c:5430
RENDER_CHOICE_NONE
#define RENDER_CHOICE_NONE
Definition: events.h:264
add_to_clipmenu
void add_to_clipmenu(void)
Definition: gui.c:4512
sizdbl
ssize_t sizdbl
Definition: main.c:102
do_quick_switch
void do_quick_switch(int new_file)
Definition: main.c:10066
widget_opts_t::apply_theme
int apply_theme
theming variation for widget (0 -> no theme, 1 -> normal colours, 2+ -> theme variants)
Definition: widget-helper.h:1409
dprint_recneg
LIVES_INLINE void dprint_recneg(void)
Definition: events.c:5026
add_fill_to_box
LiVESWidget * add_fill_to_box(LiVESBox *box)
Definition: widget-helper.c:12377
capability::mainpid
pid_t mainpid
Definition: main.h:591
check_storage_space
boolean check_storage_space(int clipno, boolean is_processing)
Definition: dialogs.c:1086
calc_time_from_frame
double calc_time_from_frame(int clip, int frame)
Definition: utils.c:1756
TICKS_PER_SECOND
#define TICKS_PER_SECOND
ticks per second - GLOBAL TIMEBASE
Definition: mainwindow.h:36
mainwindow::agen_needs_reinit
volatile boolean agen_needs_reinit
Definition: mainwindow.h:1650
lives_widget_queue_draw
WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_queue_draw(LiVESWidget *widget)
Definition: widget-helper.c:1580
enabled_in_channels
int enabled_in_channels(weed_plant_t *plant, boolean count_repeats)
Definition: effects-weed.c:3985
weed_in_params_free
void weed_in_params_free(weed_plant_t **parameters, int num_parameters)
Definition: effects-weed.c:6110
weed_frame_event_get_tracks
LIVES_GLOBAL_INLINE int weed_frame_event_get_tracks(weed_event_t *event, int **clips, int64_t **frames)
Definition: events.c:36
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
lives_thread_join
uint64_t lives_thread_join(lives_thread_t work, void **retval)
Definition: machinestate.c:2376
lives_widget_is_sensitive
WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_is_sensitive(LiVESWidget *widget)
Definition: widget-helper.c:4885
lives_button_box_make_first
WIDGET_HELPER_GLOBAL_INLINE boolean lives_button_box_make_first(LiVESButtonBox *bbox, LiVESWidget *widget)
Definition: widget-helper.c:12481
lives_proc_thread_set_cancellable
LIVES_GLOBAL_INLINE void lives_proc_thread_set_cancellable(lives_proc_thread_t tinfo)
only threads with no return value can possibly be cancellable. For threads with a value,...
Definition: machinestate.c:1938
on_fade_audio_activate
void on_fade_audio_activate(LiVESMenuItem *menuitem, livespointer user_data)
Definition: callbacks.c:12133
WEED_LEAF_TCDELTA
#define WEED_LEAF_TCDELTA
Definition: events.h:81
remove_end_blank_frames
void remove_end_blank_frames(weed_plant_t *event_list, boolean remove_filter_inits)
Definition: events.c:546
del_frame_index
void del_frame_index(lives_clip_t *sfile)
Definition: cvirtual.c:238
mainwindow::event_list
weed_event_t * event_list
current event_list, for recording
Definition: mainwindow.h:803
rdet_acodec_changed
void rdet_acodec_changed(LiVESCombo *acodec_combo, livespointer user_data)
Definition: preferences.c:2417
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
load_from_scrap_file
boolean load_from_scrap_file(weed_layer_t *layer, int frame)
Definition: saveplay.c:5360
lives_container_set_border_width
WIDGET_HELPER_GLOBAL_INLINE boolean lives_container_set_border_width(LiVESContainer *container, uint32_t width)
Definition: widget-helper.c:4947
_prefs::gui_monitor
int gui_monitor
Definition: preferences.h:305
mainwindow::sl_undo_mem
unsigned char * sl_undo_mem
Definition: mainwindow.h:812
insert_filter_map_event_at
boolean insert_filter_map_event_at(weed_plant_t *event_list, weed_plant_t *at_event, weed_plant_t *event, boolean before_frames)
Definition: events.c:1066
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
lives_label_get_text
WIDGET_HELPER_GLOBAL_INLINE const char * lives_label_get_text(LiVESLabel *label)
Definition: widget-helper.c:6056
CLIP_DETAILS_FRAMES
@ CLIP_DETAILS_FRAMES
Definition: main.h:1154
EVENT_MARKER_BLOCK_START
#define EVENT_MARKER_BLOCK_START
Definition: events.h:353
lives_widget_set_maximum_size
WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_set_maximum_size(LiVESWidget *widget, int width, int height)
Definition: widget-helper.c:1641
_future_prefs::encoder
_encoder encoder
Definition: preferences.h:820
savethread_priv_t::width
int width
Definition: main.h:1509
mainwindow::rec_aclip
volatile int rec_aclip
recording values - to be inserted at the following video frame
Definition: mainwindow.h:967
get_first_event
LIVES_GLOBAL_INLINE weed_plant_t * get_first_event(weed_plant_t *event_list)
Definition: events.c:119
mainwindow::vfade_out_secs
double vfade_out_secs
Definition: mainwindow.h:1813
set_render_choice
void set_render_choice(LiVESToggleButton *togglebutton, livespointer choice)
Definition: events.c:2176
IMG_TYPE_BEST
#define IMG_TYPE_BEST
Definition: main.h:781
_prefs::encoder
_encoder encoder
from main.h
Definition: preferences.h:38
do_error_dialog
LIVES_GLOBAL_INLINE LiVESResponseType do_error_dialog(const char *text)
Definition: dialogs.c:749
quantise_events
weed_plant_t * quantise_events(weed_plant_t *in_list, double qfps, boolean allow_gap)
quantise from event_list_t *in_list to *out_list at the new rate of qfps
Definition: resample.c:456
MONITOR_QUOTA
#define MONITOR_QUOTA
Definition: mainwindow.h:1805
get_last_frame_event
weed_plant_t * get_last_frame_event(weed_plant_t *event_list)
Definition: events.c:419
lives_standard_entry_new
LiVESWidget * lives_standard_entry_new(const char *labeltext, const char *txt, int dispwidth, int maxchars, LiVESBox *box, const char *tooltip)
Definition: widget-helper.c:9688
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
do_header_write_error
boolean do_header_write_error(int clip)
Definition: dialogs.c:4169
WEED_EVENT_IS_FRAME
#define WEED_EVENT_IS_FRAME(event)
Definition: events.h:361
weed_init_effect
boolean weed_init_effect(int hotkey)
hotkey starts at 1
Definition: effects-weed.c:6596
lives_window_add_accel_group
WIDGET_HELPER_GLOBAL_INLINE boolean lives_window_add_accel_group(LiVESWindow *window, LiVESAccelGroup *group)
Definition: widget-helper.c:2968
end_threaded_dialog
void end_threaded_dialog(void)
Definition: dialogs.c:3883
threaded_dialog_spin
void threaded_dialog_spin(double fraction)
Definition: dialogs.c:3823
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
render_details::is_encoding
boolean is_encoding
Definition: events.h:248
WEED_LEAF_AUTO_EASING
#define WEED_LEAF_AUTO_EASING
Definition: effects-weed.h:94
get_track_visibility_at_tc
double * get_track_visibility_at_tc(weed_plant_t *event_list, int ntracks, int nbtracks, weed_timecode_t tc, weed_plant_t **shortcut, boolean bleedthru)
calculate the "visibility" of each track at timecode tc
Definition: events.c:5400
mainwindow::render_error
lives_render_error_t render_error
Definition: mainwindow.h:1664
tv
struct timeval tv
Definition: main.h:1136
TRUE
#define TRUE
Definition: videoplugin.h:59
lives_clip_t::img_type
lives_img_type_t img_type
Definition: main.h:887
UNDO_RENDER
@ UNDO_RENDER
resample/reorder/resize/apply effects
Definition: main.h:680
WEED_LEAF_HOST_MODE
#define WEED_LEAF_HOST_MODE
Definition: effects-weed.h:68
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
get_frame_event_clip
int get_frame_event_clip(weed_plant_t *event, int layer)
Definition: events.c:209
mainwindow::string_constants
char * string_constants[NUM_LIVES_STRING_CONSTANTS]
Definition: mainwindow.h:1539
_prefs::mt_def_arate
int mt_def_arate
Definition: preferences.h:273
mainwindow::clip_index
int * clip_index
Definition: mainwindow.h:1431
lives_colRGBA64_t::green
uint16_t green
Definition: main.h:324
IMG_TYPE_PNG
@ IMG_TYPE_PNG
Definition: main.h:777
WEED_LEAF_PREV_CHANGE
#define WEED_LEAF_PREV_CHANGE
Definition: events.h:72
lives_special_aspect_t::lockbutton
LiVESWidget * lockbutton
Definition: paramspecial.h:34
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
WEED_LEAF_TRACKS
#define WEED_LEAF_TRACKS
Definition: events.h:80
widget_opts_t::last_container
LiVESWidget * last_container
container which wraps last widget created + subwidgets (READONLY)
Definition: widget-helper.h:1407
render_details::dialog
LiVESWidget * dialog
Definition: events.h:220
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
THREADVAR
#define THREADVAR(var)
Definition: machinestate.h:531
lives_table_new
WIDGET_HELPER_GLOBAL_INLINE LiVESWidget * lives_table_new(uint32_t rows, uint32_t cols, boolean homogeneous)
Definition: widget-helper.c:6931
init_track_decoders
void init_track_decoders(void)
Definition: main.c:7816
RENDER_CHOICE_MULTITRACK
#define RENDER_CHOICE_MULTITRACK
Definition: events.h:269
rdetw_spinw_changed
void rdetw_spinw_changed(LiVESSpinButton *spinbutton, livespointer user_data)
Definition: events.c:6060
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
lives_cell_renderer_text_new
WIDGET_HELPER_GLOBAL_INLINE LiVESCellRenderer * lives_cell_renderer_text_new(void)
Definition: widget-helper.c:5334
lives_standard_combo_new
LiVESWidget * lives_standard_combo_new(const char *labeltext, LiVESList *list, LiVESBox *box, const char *tooltip)
Definition: widget-helper.c:9544
render_details::afade_in
LiVESWidget * afade_in
Definition: events.h:237
mainwindow::untitled_number
int untitled_number
Definition: mainwindow.h:738
weed_layer_pixel_data_free
void weed_layer_pixel_data_free(weed_layer_t *layer)
free pixel_data from layer
Definition: colourspace.c:13819
filter_init_has_owner
boolean filter_init_has_owner(weed_plant_t *init_event, int track)
Definition: events.c:1570
WEED_LEAF_FRAMES
#define WEED_LEAF_FRAMES
Definition: events.h:38
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_RENDER_ERROR_READ_AUDIO
@ LIVES_RENDER_ERROR_READ_AUDIO
Definition: events.h:109
_palette::info_text
LiVESWidgetColor info_text
Definition: mainwindow.h:329
WEED_EVENT_IS_FILTER_DEINIT
#define WEED_EVENT_IS_FILTER_DEINIT(event)
Definition: events.h:365
_resaudw::rb_littleend
LiVESWidget * rb_littleend
Definition: resample.h:26
get_event_pchains
GNU_PURE void *** get_event_pchains(void)
Definition: events.c:94
lives_tree_store_new
WIDGET_HELPER_GLOBAL_INLINE LiVESTreeStore * lives_tree_store_new(int ncols,...)
Definition: widget-helper.c:5808
is_realtime_aplayer
#define is_realtime_aplayer(ptype)
Definition: audio.h:236
weed_event_get_type
LIVES_GLOBAL_INLINE int weed_event_get_type(weed_event_t *event)
Definition: events.c:31
render_details::norm_after
LiVESWidget * norm_after
Definition: events.h:236
TITLE_COLUMN
@ TITLE_COLUMN
Definition: events.c:5552
lives_special_aspect_t
Definition: paramspecial.h:31
recover_layout_cancelled
void recover_layout_cancelled(boolean is_startup)
Definition: multitrack.c:923
render_details::vfade_in
LiVESWidget * vfade_in
Definition: events.h:239
lives_combo_populate
boolean lives_combo_populate(LiVESCombo *combo, LiVESList *list)
Definition: widget-helper.c:7509
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
mainwindow::afilter_map
weed_plant_t * afilter_map
Definition: mainwindow.h:1299
LIVES_FILE_EXT_MGK
#define LIVES_FILE_EXT_MGK
Definition: mainwindow.h:489
count_events
int count_events(weed_plant_t *event_list, boolean all_events, weed_timecode_t start_tc, weed_timecode_t end_tc)
Definition: events.c:4542
chill_decoder_plugin
boolean chill_decoder_plugin(int fileno)
Definition: plugins.c:2425
mainwindow::no_context_update
boolean no_context_update
may be set temporarily to block wodget context updates
Definition: mainwindow.h:1726
close_ascrap_file
void close_ascrap_file(boolean remove)
Definition: saveplay.c:5612
lives_write_le_buffered
ssize_t lives_write_le_buffered(int fd, livesconstpointer buf, ssize_t count, boolean allow_fail)
mainwindow::cevent_tc
ticks_t cevent_tc
timecode of currently processing event
Definition: mainwindow.h:1553
_prefs::rr_crash
boolean rr_crash
Definition: preferences.h:488
mainwindow::transrend_layer
weed_layer_t * transrend_layer
Definition: mainwindow.h:1810
IMG_TYPE_JPEG
@ IMG_TYPE_JPEG
Definition: main.h:776
on_normalise_audio_activate
void on_normalise_audio_activate(LiVESMenuItem *menuitem, livespointer user_data)
Definition: callbacks.c:11825
capability::has_encoder_plugins
lives_checkstatus_t has_encoder_plugins
Definition: main.h:571
WEED_LEAF_HOST_DECODER
#define WEED_LEAF_HOST_DECODER
Definition: main.h:801
lives_layout_hbox_new
WIDGET_HELPER_GLOBAL_INLINE LiVESWidget * lives_layout_hbox_new(LiVESLayout *layout)
Definition: widget-helper.c:7757
callbacks.h
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
_prefs::ocp
int ocp
open_compression_percent : get/set in prefs
Definition: preferences.h:217
CLIP_TOTAL_TIME
#define CLIP_TOTAL_TIME(clip)
Definition: main.h:830
_prefs::audio_src
int audio_src
Definition: preferences.h:204
lives_clip_t::frameno
frames_t frameno
Definition: main.h:934
lives_colRGBA64_t::blue
uint16_t blue
Definition: main.h:325
capable
capability * capable
Definition: main.h:627
lives_proc_thread_create
lives_proc_thread_t lives_proc_thread_create(lives_thread_attr_t attr, lives_funcptr_t func, int return_type, const char *args_fmt,...)
create the specific plant which defines a background task to be run
Definition: machinestate.c:1730
lives_toggle_button_get_active
WIDGET_HELPER_GLOBAL_INLINE boolean lives_toggle_button_get_active(LiVESToggleButton *button)
Definition: widget-helper.c:4472
mainwindow::preview_rendering
boolean preview_rendering
Definition: mainwindow.h:758
pull_frame
LIVES_GLOBAL_INLINE boolean pull_frame(weed_layer_t *layer, const char *image_ext, weed_timecode_t tc)
pull a frame from an external source into a layer the WEED_LEAF_CLIP and WEED_LEAF_FRAME leaves must ...
Definition: main.c:7500
create_event_space
boolean create_event_space(int length_in_eventsb)
Definition: utils.c:4660
d_print
void d_print(const char *fmt,...)
Definition: utils.c:2542
on_encoder_ofmt_changed
void on_encoder_ofmt_changed(LiVESCombo *combo, livespointer user_data)
Definition: callbacks.c:11680
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
LIVES_RENDER_ERROR_WRITE_AUDIO
@ LIVES_RENDER_ERROR_WRITE_AUDIO
Definition: events.h:110
mainwindow::rec_aseek
volatile double rec_aseek
Definition: mainwindow.h:969
_prefs::rr_super
boolean rr_super
Definition: preferences.h:490
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_IN_TRACKS
#define WEED_LEAF_IN_TRACKS
Definition: events.h:47
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
lives_scrolled_window_set_min_content_width
WIDGET_HELPER_GLOBAL_INLINE boolean lives_scrolled_window_set_min_content_width(LiVESScrolledWindow *scrolledwindow, int width)
Definition: widget-helper.c:6300
PREF_LETTERBOXMT
#define PREF_LETTERBOXMT
Definition: preferences.h:1070
_prefs::open_maximised
boolean open_maximised
Definition: preferences.h:28
render_details::spinbutton_height
LiVESWidget * spinbutton_height
Definition: events.h:229
reget_afilesize_inner
off_t reget_afilesize_inner(int fileno)
Definition: machinestate.c:1001
lives_table_resize
WIDGET_HELPER_GLOBAL_INLINE boolean lives_table_resize(LiVESTable *table, uint32_t rows, uint32_t cols)
Definition: widget-helper.c:7011
savethread_priv_t::img_type
lives_img_type_t img_type
Definition: main.h:1507
lives_tree_store_set
WIDGET_HELPER_GLOBAL_INLINE boolean lives_tree_store_set(LiVESTreeStore *tstore, LiVESTreeIter *titer,...)
Definition: widget-helper.c:5851
lives_general_button_clicked
void lives_general_button_clicked(LiVESButton *button, livespointer data_to_free)
Definition: widget-helper.c:12306
lives_scrolled_window_set_min_content_height
WIDGET_HELPER_GLOBAL_INLINE boolean lives_scrolled_window_set_min_content_height(LiVESScrolledWindow *scrolledwindow, int height)
Definition: widget-helper.c:6288
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
mainwindow::scrap_pixbuf
LiVESPixbuf * scrap_pixbuf
cached image for speeding up rendering
Definition: mainwindow.h:1724
on_preview_clicked
void on_preview_clicked(LiVESButton *button, livespointer user_data)
Definition: callbacks.c:10245
weed_layer_get_palette
LIVES_GLOBAL_INLINE int weed_layer_get_palette(weed_layer_t *layer)
Definition: colourspace.c:13977
get_next_paramchange
weed_timecode_t get_next_paramchange(void **pchange_next, weed_timecode_t end_tc)
Definition: events.c:565
get_frame_event_frame
frames_t get_frame_event_frame(weed_plant_t *event, int layer)
Definition: events.c:224
mainwindow::msg
char msg[MAINW_MSG_SIZE]
Definition: mainwindow.h:724
WEED_LEAF_HOST_TAG
#define WEED_LEAF_HOST_TAG
Definition: effects-weed.h:66
CLIP_TYPE_FILE
@ CLIP_TYPE_FILE
unimported video, not or partially broken in frames
Definition: main.h:765
mainwindow::pre_src_file
int pre_src_file
video file we were playing before any ext input started
Definition: mainwindow.h:971
add_video_options
LiVESWidget * add_video_options(LiVESWidget **spwidth, int defwidth, LiVESWidget **spheight, int defheight, LiVESWidget **spfps, double deffps, LiVESWidget **spframes, int defframes, boolean add_aspect, LiVESWidget *extra)
Definition: events.c:6072
has_frame_event_at
boolean has_frame_event_at(weed_plant_t *event_list, weed_timecode_t tc, weed_plant_t **shortcut)
Definition: events.c:129
_resaudw::aud_checkbutton
LiVESWidget * aud_checkbutton
Definition: resample.h:32
LIVES_RENDER_EFFECTS_PAUSED
@ LIVES_RENDER_EFFECTS_PAUSED
Definition: events.h:104
lives_dialog_get_action_area
WIDGET_HELPER_GLOBAL_INLINE LiVESWidget * lives_dialog_get_action_area(LiVESDialog *dialog)
Definition: widget-helper.c:2495
lives_spin_button_get_value
WIDGET_HELPER_GLOBAL_INLINE double lives_spin_button_get_value(LiVESSpinButton *button)
Definition: widget-helper.c:5083
LAYOUT_NUMBERING_FILENAME
#define LAYOUT_NUMBERING_FILENAME
Definition: mainwindow.h:572
weed_filter_is_process_last
WEED_GLOBAL_INLINE int weed_filter_is_process_last(weed_plant_t *filter)
Definition: weed-effects-utils.c:226
pref_factory_bool
boolean pref_factory_bool(const char *prefidx, boolean newval, boolean permanent)
Definition: preferences.c:717
get_filter_map_after
weed_plant_t * get_filter_map_after(weed_plant_t *event, int ctrack)
Definition: events.c:821
lives_standard_label_new
LiVESWidget * lives_standard_label_new(const char *text)
Definition: widget-helper.c:8601
switch_clip
void switch_clip(int type, int newclip, boolean force)
Definition: callbacks.c:6900
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
insert_audio_event_at
void insert_audio_event_at(weed_plant_t *event, int track, int clipnum, double seek, double vel)
Definition: events.c:1243
mainwindow::num_tracks
int num_tracks
Definition: mainwindow.h:1430
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
EVENT_MARKER_BLOCK_UNORDERED
#define EVENT_MARKER_BLOCK_UNORDERED
Definition: events.h:354
interface.h
_prefs::image_ext
char image_ext[16]
Definition: preferences.h:78
weed_event_set_timecode
LIVES_GLOBAL_INLINE weed_timecode_t weed_event_set_timecode(weed_event_t *event, weed_timecode_t tc)
Definition: events.c:83
lives_vbox_new
WIDGET_HELPER_GLOBAL_INLINE LiVESWidget * lives_vbox_new(boolean homogeneous, int spacing)
Definition: widget-helper.c:3267
WEED_LEAF_FILTER
#define WEED_LEAF_FILTER
Definition: events.h:44
insert_event_before
boolean insert_event_before(weed_plant_t *at_event, weed_plant_t *event)
Definition: events.c:321
_encoder::of_name
char of_name[64]
Definition: plugins.h:263
do_memory_error_dialog
LiVESResponseType do_memory_error_dialog(char *op, size_t bytes)
Definition: dialogs.c:904
has_audio_frame
boolean has_audio_frame(weed_plant_t *event_list)
Definition: events.c:4623
CURRENT_CLIP_HAS_VIDEO
#define CURRENT_CLIP_HAS_VIDEO
Definition: main.h:815
d_print_failed
void d_print_failed(void)
Definition: utils.c:2615
get_prev_event
LIVES_GLOBAL_INLINE weed_plant_t * get_prev_event(weed_plant_t *event)
Definition: events.c:109
widget_opts_t::use_markup
boolean use_markup
whether markup should be used in labels
Definition: widget-helper.h:1421
WEED_EVENT_IS_PARAM_CHANGE
#define WEED_EVENT_IS_PARAM_CHANGE(event)
Definition: events.h:367
_vid_playback_plugin::fixed_fpsd
double fixed_fpsd
Definition: plugins.h:188
is_init_pchange
boolean is_init_pchange(weed_plant_t *init_event, weed_plant_t *pchange_event)
Definition: events.c:585
process_events
weed_plant_t * process_events(weed_plant_t *next_event, boolean process_audio, weed_timecode_t curr_tc)
Definition: events.c:3082
mainwindow::playing_file
int playing_file
which number file we are playing (or -1) [generally mainw->current_file]
Definition: mainwindow.h:943
widget_opts_t::border_width
int border_width
border width in pixels
Definition: widget-helper.h:1416
RENDER_CHOICE_PREVIEW
#define RENDER_CHOICE_PREVIEW
Definition: events.h:266
save_frame_index
boolean save_frame_index(int fileno)
Definition: cvirtual.c:56
mainwindow::flush_audio_tc
ticks_t flush_audio_tc
reserved space for mbar
Definition: mainwindow.h:1735
remove_audio_for_track
void remove_audio_for_track(weed_plant_t *event, int track)
Definition: events.c:1349
LIVES_RENDER_ERROR_WRITE_FRAME
@ LIVES_RENDER_ERROR_WRITE_FRAME
Definition: events.h:111
LIVES_EXPAND_DEFAULT_HEIGHT
#define LIVES_EXPAND_DEFAULT_HEIGHT
Definition: widget-helper.h:1312
mainwindow::files
lives_clip_t * files[MAX_FILES+1]
+1 for the clipboard
Definition: mainwindow.h:729
WEED_LEAF_LIVES_CREATED_VERSION
#define WEED_LEAF_LIVES_CREATED_VERSION
Definition: events.h:31
lives_widget_get_allocation_height
WIDGET_HELPER_GLOBAL_INLINE int lives_widget_get_allocation_height(LiVESWidget *widget)
Definition: widget-helper.c:5470
LIVES_STRING_CONSTANT_ANY
@ LIVES_STRING_CONSTANT_ANY
Definition: mainwindow.h:370
rdetw_spinh_changed
void rdetw_spinh_changed(LiVESSpinButton *spinbutton, livespointer user_data)
Definition: events.c:6054
save_clip_value
boolean save_clip_value(int which, lives_clip_details_t, void *val)
Definition: utils.c:5175
mainwindow::track_decoders
lives_decoder_t * track_decoders[MAX_TRACKS]
Definition: mainwindow.h:1691
weed_instance_from_filter
weed_plant_t * weed_instance_from_filter(weed_plant_t *filter)
Definition: effects-weed.c:6469
lives_spin_button_set_snap_to_multiples
WIDGET_HELPER_GLOBAL_INLINE boolean lives_spin_button_set_snap_to_multiples(LiVESSpinButton *button, double mult)
Definition: widget-helper.c:9374
main_thread_execute
void * main_thread_execute(lives_funcptr_t func, int return_type, void *retval, const char *args_fmt,...)
Definition: machinestate.c:1741
lives_standard_expander_new
LiVESWidget * lives_standard_expander_new(const char *ltext, LiVESBox *box, LiVESWidget *child)
Definition: widget-helper.c:10351
CANCEL_NONE
@ CANCEL_NONE
no cancel
Definition: main.h:701
WEED_LEAF_OUT_COUNT
#define WEED_LEAF_OUT_COUNT
Definition: events.h:46
mainwindow::fps_measure
frames_t fps_measure
show fps stats after playback
Definition: mainwindow.h:778
mainwindow::clips_available
int clips_available
Definition: mainwindow.h:740
get_next_audio_frame_event
weed_plant_t * get_next_audio_frame_event(weed_plant_t *event)
Definition: events.c:380
mainwindow::first_free_file
int first_free_file
Definition: mainwindow.h:728
AUD_DIFF_MIN
#define AUD_DIFF_MIN
ignore audio seek differences < than this (seconds)
Definition: events.h:94
WEED_LEAF_DEINIT_EVENT
#define WEED_LEAF_DEINIT_EVENT
Definition: events.h:76
mainwindow::pulsed
void * pulsed
pulseaudio player
Definition: mainwindow.h:1463
lives_close_buffered
int lives_close_buffered(int fd)
Definition: utils.c:716
mainwindow::play_start
frames_t play_start
Definition: mainwindow.h:931
delete_param_changes_after_deinit
void delete_param_changes_after_deinit(weed_plant_t *event_list, weed_plant_t *init_event)
Definition: events.c:1623
SEPWIN_TYPE_NON_STICKY
#define SEPWIN_TYPE_NON_STICKY
Definition: preferences.h:187
mainwindow::aframeno
double aframeno
and the audio 'frame' for when we are looping
Definition: mainwindow.h:962
do_encoder_img_fmt_error
void do_encoder_img_fmt_error(render_details *rdet)
Definition: dialogs.c:4282
_encoder::of_desc
char of_desc[128]
Definition: plugins.h:264
WEED_LEAF_HOST_KEY
#define WEED_LEAF_HOST_KEY
Definition: effects-weed.h:67
add_audio_options
LiVESWidget * add_audio_options(LiVESWidget **cbbackaudio, LiVESWidget **cbpertrack)
Definition: events.c:6184
widget_opts_t::packing_height
int packing_height
vertical pixels between widgets
Definition: widget-helper.h:1411
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
_encoder::name
char name[64]
Definition: plugins.h:234
add_to_recovery_file
void add_to_recovery_file(const char *handle)
Definition: saveplay.c:6460
savethread_priv_t::height
int height
Definition: main.h:1509
palette
_palette * palette
interface colour settings
Definition: main.c:101
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
weed_params_create
weed_plant_t ** weed_params_create(weed_plant_t *filter, boolean in)
Definition: effects-weed.c:6318
mainwindow::progress_fn
lives_render_error_t(* progress_fn)(boolean reset)
Definition: mainwindow.h:1044
mainwindow::pchains
void *** pchains
Definition: mainwindow.h:1301
filter_map_has_event
boolean filter_map_has_event(weed_plant_t *fmap, weed_plant_t *event)
Definition: events.c:1560
q_gint64
LIVES_GLOBAL_INLINE ticks_t q_gint64(ticks_t in, double fps)
Definition: resample.c:25
has_usable_palette
boolean has_usable_palette(weed_plant_t *chantmpl)
Definition: effects-weed.c:3976
event_list_free
void event_list_free(weed_plant_t *event_list)
Definition: events.c:2313
mainwindow::vfade_out_col
lives_colRGBA64_t vfade_out_col
Definition: mainwindow.h:1814
EVENT_MARKER_RECORD_END
#define EVENT_MARKER_RECORD_END
Definition: events.h:356
mainwindow::recording_recovered
boolean recording_recovered
Definition: mainwindow.h:1486
lives_event_list_new
weed_event_t * lives_event_list_new(weed_event_t *elist, const char *cdate)
lib-ish stuff
Definition: events.c:240
render_details::enc_changed
boolean enc_changed
Definition: events.h:244
widget_opts_t::non_modal
boolean non_modal
non-modal for dialogs
Definition: widget-helper.h:1422
error
error("LSD_RANDFUNC(ptr, size) must be defined")
lives_hbox_new
WIDGET_HELPER_GLOBAL_INLINE LiVESWidget * lives_hbox_new(boolean homogeneous, int spacing)
Definition: widget-helper.c:3253
mainwindow::stored_event_list
weed_event_t * stored_event_list
stored mt -> clip editor
Definition: mainwindow.h:804
render_details::ratio_fps
boolean ratio_fps
Definition: events.h:219
_prefs::mt_def_asamps
int mt_def_asamps
Definition: preferences.h:273
check_layer_ready
boolean check_layer_ready(weed_layer_t *layer)
block until layer pixel_data is ready.
Definition: main.c:7528
close_scrap_file
void close_scrap_file(boolean remove)
Definition: saveplay.c:5583
backup_recording
boolean backup_recording(char **esave_file, char **asave_file)
Definition: events.c:5028
_prefs::hide_framebar
boolean hide_framebar
Definition: preferences.h:434
lives_tree_view_append_column
WIDGET_HELPER_GLOBAL_INLINE int lives_tree_view_append_column(LiVESTreeView *tview, LiVESTreeViewColumn *tvcol)
Definition: widget-helper.c:5909
render_details::encoder_name_fn
ulong encoder_name_fn
Definition: events.h:242
WEED_LEAF_LAST
#define WEED_LEAF_LAST
Definition: events.h:65
calc_frame_from_time4
int calc_frame_from_time4(int filenum, double time)
nearest frame, no maximum
Definition: utils.c:1788
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
lives_layout_row_new
WIDGET_HELPER_GLOBAL_INLINE LiVESWidget * lives_layout_row_new(LiVESLayout *layout)
Definition: widget-helper.c:7791
_future_prefs::sepwin_type
short sepwin_type
Definition: preferences.h:832
WEED_LEAF_NEXT_CHANGE
#define WEED_LEAF_NEXT_CHANGE
Definition: events.h:71
render_details::arate
int arate
Definition: events.h:250
_prefs::mt_pertrack_audio
boolean mt_pertrack_audio
Definition: preferences.h:278
_prefs::show_player_stats
boolean show_player_stats
Definition: preferences.h:190
do_threaded_dialog
void do_threaded_dialog(const char *trans_text, boolean has_cancel)
Definition: dialogs.c:3849
create_resaudw
_resaudw * create_resaudw(short type, render_details *rdet, LiVESWidget *top_vbox)
resample audio window
Definition: resample.c:1521
get_total_time
void get_total_time(lives_clip_t *file)
calculate laudio, raudio and video time (may be deprecated and replaced with macros)
Definition: utils.c:3690
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
render_events
lives_render_error_t render_events(boolean reset, boolean rend_video, boolean rend_audio)
render mainw->event_list to a clip
Definition: events.c:3609
lives_strdup_printf
#define lives_strdup_printf(fmt,...)
Definition: support.c:27
WEED_LEAF_INDEX
#define WEED_LEAF_INDEX
Definition: events.h:58
GUI_SCREEN_HEIGHT
#define GUI_SCREEN_HEIGHT
Definition: mainwindow.h:100
get_event_timecode
LIVES_GLOBAL_INLINE weed_timecode_t get_event_timecode(weed_plant_t *plant)
Definition: events.c:98
insert_param_change_event_at
void insert_param_change_event_at(weed_plant_t *event_list, weed_plant_t *at_event, weed_plant_t *event)
Definition: events.c:1116
lives_calloc
#define lives_calloc
Definition: machinestate.h:67
_get_or_zero
#define _get_or_zero(a, b, c)
Definition: events.c:96
convert_layer_palette
boolean convert_layer_palette(weed_layer_t *layer, int outpl, int op_clamping)
Definition: colourspace.c:11945
lives_tree_view_column_new_with_attributes
WIDGET_HELPER_GLOBAL_INLINE LiVESTreeViewColumn * lives_tree_view_column_new_with_attributes(const char *title, LiVESCellRenderer *crend,...)
Definition: widget-helper.c:5940
lives_create_buffered
int lives_create_buffered(const char *pathname, int mode)
Definition: utils.c:698
get_next_free_key
int get_next_free_key(void)
next free "key" for the multitrack system
Definition: effects-weed.c:9311
get_last_event
LIVES_GLOBAL_INLINE weed_plant_t * get_last_event(weed_plant_t *event_list)
Definition: events.c:124
lives_list_free_all
void lives_list_free_all(LiVESList **)
Definition: utils.c:4873
WEED_LEAF_IS_DEF_VALUE
#define WEED_LEAF_IS_DEF_VALUE
Definition: events.h:73
audio_free_fnames
void audio_free_fnames(void)
Definition: audio.c:71
savethread_priv_t::compression
int compression
Definition: main.h:1508
lives_tree_store_append
WIDGET_HELPER_GLOBAL_INLINE boolean lives_tree_store_append(LiVESTreeStore *tstore, LiVESTreeIter *titer, LiVESTreeIter *parent)
Definition: widget-helper.c:5831
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
init_event_is_relevant
boolean init_event_is_relevant(weed_plant_t *init_event, int ctrack)
Definition: events.c:859
LIVES_MAIN_WINDOW_WIDGET
#define LIVES_MAIN_WINDOW_WIDGET
Definition: mainwindow.h:188
mainwindow::transrend_proc
lives_proc_thread_t transrend_proc
Definition: mainwindow.h:1811
LIVES_THRDATTR_NONE
#define LIVES_THRDATTR_NONE
Definition: machinestate.h:437
enabled_out_channels
int enabled_out_channels(weed_plant_t *plant, boolean count_repeats)
Definition: effects-weed.c:4043
lives_widget_set_valign
WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_set_valign(LiVESWidget *widget, LiVESAlign align)
Definition: widget-helper.c:3537
mainwindow::ascrap_file
int ascrap_file
scrap file for recording audio scraps
Definition: mainwindow.h:875
mainwindow::stored_event_list_changed
boolean stored_event_list_changed
Definition: mainwindow.h:805
render_details::acodec_combo
LiVESWidget * acodec_combo
Definition: events.h:226
lives_proc_thread_check
LIVES_GLOBAL_INLINE boolean lives_proc_thread_check(lives_proc_thread_t tinfo)
returns FALSE while the thread is running, TRUE once it has finished
Definition: machinestate.c:1916
LIVES_RENDER_PROCESSING
@ LIVES_RENDER_PROCESSING
Definition: events.h:103
get_transition_param
int get_transition_param(weed_plant_t *filter, boolean skip_internal)
Definition: effects-weed.c:8656
WEED_PLANT_IS_EVENT_LIST
#define WEED_PLANT_IS_EVENT_LIST(plant)
Definition: events.h:359
WEED_PLANT_IS_FILTER_INSTANCE
#define WEED_PLANT_IS_FILTER_INSTANCE(plant)
Definition: weed-effects-utils.h:38
lives_bin_get_child
WIDGET_HELPER_GLOBAL_INLINE LiVESWidget * lives_bin_get_child(LiVESBin *bin)
Definition: widget-helper.c:5514
pull_frame_threaded
void pull_frame_threaded(weed_layer_t *layer, const char *img_ext, weed_timecode_t tc, int width, int height)
Definition: main.c:7631
event_list_get_start_secs
double event_list_get_start_secs(weed_plant_t *event_list)
Definition: events.c:4618
events_rec_dialog
LiVESWidget * events_rec_dialog(void)
Definition: events.c:2186
_prefs::acodec_list
LiVESList * acodec_list
Definition: preferences.h:251
event_list_add_end_events
void event_list_add_end_events(weed_event_t *event_list, boolean is_final)
Definition: events.c:5102
lives_memcpy
#define lives_memcpy
Definition: machinestate.h:55
render_details::encoder_combo
LiVESWidget * encoder_combo
Definition: events.h:224
lives_strlen
LIVES_GLOBAL_INLINE size_t lives_strlen(const char *s)
Definition: machinestate.c:1468
_resaudw::rb_bigend
LiVESWidget * rb_bigend
Definition: resample.h:25
future_prefs
_future_prefs * future_prefs
Definition: preferences.h:848
event_list_add_track
void event_list_add_track(weed_plant_t *event_list, int layer)
Definition: events.c:2497
lives_widget_set_sensitive
WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_set_sensitive(LiVESWidget *widget, boolean state)
Definition: widget-helper.c:1477
lives_accel_group_new
WIDGET_HELPER_GLOBAL_INLINE LiVESAccelGroup * lives_accel_group_new(void)
Definition: widget-helper.c:2915
CURRENT_CLIP_IS_NORMAL
#define CURRENT_CLIP_IS_NORMAL
Definition: main.h:838
insert_filter_deinit_event_at
void insert_filter_deinit_event_at(weed_plant_t *event_list, weed_plant_t *at_event, weed_plant_t *event)
Definition: events.c:1043
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
AFORM_SIGNED
#define AFORM_SIGNED
Definition: main.h:783
create_render_details
render_details * create_render_details(int type)
Definition: events.c:6252
get_track_name
char * get_track_name(lives_mt *mt, int track_num, boolean is_audio)
Definition: multitrack.c:1038
myround
#define myround(n)
Definition: main.h:300
lives_getuid
LIVES_GLOBAL_INLINE int lives_getuid(void)
Definition: machinestate.c:2416
init_event_in_list
LIVES_GLOBAL_INLINE boolean init_event_in_list(void **init_events, int num_inits, weed_plant_t *event)
Definition: events.c:1550
mainwindow::multitrack
lives_mt * multitrack
holds a pointer to the entire multitrack environment; NULL in Clip Edit mode
Definition: mainwindow.h:1087
CURRENT_CLIP_IS_VALID
#define CURRENT_CLIP_IS_VALID
Definition: main.h:809
lives_spin_button_update
WIDGET_HELPER_GLOBAL_INLINE boolean lives_spin_button_update(LiVESSpinButton *button)
Definition: widget-helper.c:5165
get_next_frame_event
weed_plant_t * get_next_frame_event(weed_plant_t *event)
Definition: events.c:356
replace_event
void replace_event(weed_plant_t *event_list, weed_plant_t *at_event, weed_plant_t *event)
Definition: events.c:347
mainwindow::vfade_in_secs
double vfade_in_secs
Definition: mainwindow.h:1813
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
lives_widget_queue_resize
WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_queue_resize(LiVESWidget *widget)
Definition: widget-helper.c:1605
weed_event_t
weed_plant_t weed_event_t
Definition: events.h:97
do_write_failed_error_s_with_retry
LiVESResponseType do_write_failed_error_s_with_retry(const char *fname, const char *errtext)
Definition: dialogs.c:4058
render_to_clip
boolean render_to_clip(boolean new_clip, boolean transcode)
rendering
Definition: events.c:4635
transcode.h
xprocess::processing
LiVESWidget * processing
Definition: mainwindow.h:706
render_details::ofmt_combo
LiVESWidget * ofmt_combo
Definition: events.h:225
lives_tree_view_new_with_model
WIDGET_HELPER_GLOBAL_INLINE LiVESWidget * lives_tree_view_new_with_model(LiVESTreeModel *tmod)
Definition: widget-helper.c:5864
main.h
make_image_file_name
char * make_image_file_name(lives_clip_t *clip, frames_t frame, const char *img_ext)
lives_image_type can be a string, lives_img_type_t is an enumeration
Definition: utils.c:3053
lives_window_unmaximize
WIDGET_HELPER_GLOBAL_INLINE boolean lives_window_unmaximize(LiVESWindow *window)
Definition: widget-helper.c:2898
lives_colRGBA64_t
Definition: main.h:322
render_details::height
int height
Definition: events.h:217
LIVES_EXPAND_DEFAULT
#define LIVES_EXPAND_DEFAULT
Definition: widget-helper.h:1314
free_track_decoders
LIVES_GLOBAL_INLINE void free_track_decoders(void)
Definition: main.c:7826
lives_layer_new_for_frame
LIVES_GLOBAL_INLINE weed_layer_t * lives_layer_new_for_frame(int clip, frames_t frame)
Definition: colourspace.c:9833
get_audio_frame_vel
double get_audio_frame_vel(weed_plant_t *event, int track)
returns velocity for track (track==-1 is backing audio)
Definition: events.c:165
add_track_to_avol_init
void add_track_to_avol_init(weed_plant_t *filter, weed_plant_t *event, int nbtracks, boolean behind)
Definition: events.c:2435
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
mainwindow::fs
boolean fs
Definition: mainwindow.h:762
insert_filter_init_event_at
void insert_filter_init_event_at(weed_plant_t *event_list, weed_plant_t *at_event, weed_plant_t *event)
Definition: events.c:1021
stored_event_list_free_all
void stored_event_list_free_all(boolean wiped)
Definition: multitrack.c:5897
resample.h
AUDIO_SRC_EXT
#define AUDIO_SRC_EXT
Definition: preferences.h:206
_palette::info_base
LiVESWidgetColor info_base
Definition: mainwindow.h:330
get_frame_event_at
weed_plant_t * get_frame_event_at(weed_plant_t *event_list, weed_timecode_t tc, weed_plant_t *shortcut, boolean exact)
Definition: events.c:780
lives_notify
void lives_notify(int msgnumber, const char *msgstring)
Definition: callbacks.c:49
AUDIO_SRC_INT
#define AUDIO_SRC_INT
Definition: preferences.h:205
mainwindow::effort
int effort
Definition: mainwindow.h:1773
set_acodec_list_from_allowed
void set_acodec_list_from_allowed(_prefsw *prefsw, render_details *rdet)
Definition: preferences.c:2437
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
mainwindow::ext_playback
boolean ext_playback
using external video playback plugin
Definition: mainwindow.h:773
mainw
mainwindow * mainw
Definition: main.c:103
RENDER_CHOICE_EVENT_LIST
#define RENDER_CHOICE_EVENT_LIST
Definition: events.h:270
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
lives_widget_set_halign
WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_set_halign(LiVESWidget *widget, LiVESAlign align)
Definition: widget-helper.c:3504
mainwindow::pb_fps_func
ulong pb_fps_func
Definition: mainwindow.h:1063
lives_chdir
int lives_chdir(const char *path, boolean no_error_dlg)
Definition: utils.c:1393
remove_filter_from_event_list
void remove_filter_from_event_list(weed_plant_t *event_list, weed_plant_t *init_event)
Definition: events.c:1480
weed_instance_unref
LIVES_GLOBAL_INLINE int weed_instance_unref(weed_plant_t *inst)
Definition: effects-weed.c:6234
render_details::debug
LiVESWidget * debug
Definition: events.h:235
toggle_sets_sensitive
WIDGET_HELPER_GLOBAL_INLINE boolean toggle_sets_sensitive(LiVESToggleButton *tb, LiVESWidget *widget, boolean invert)
set callbacks
Definition: widget-helper.c:11427
_resaudw::rb_signed
LiVESWidget * rb_signed
Definition: resample.h:23
MAX_FRAME_WIDTH
#define MAX_FRAME_WIDTH
Definition: main.h:220
mainwindow::proc_ptr
xprocess * proc_ptr
Definition: mainwindow.h:1090
MAX_AUDIO_TRACKS
#define MAX_AUDIO_TRACKS
Definition: multitrack.h:1046
lives_standard_scrolled_window_new
LiVESWidget * lives_standard_scrolled_window_new(int width, int height, LiVESWidget *child)
Definition: widget-helper.c:10272
insert_frame_event_at
weed_plant_t * insert_frame_event_at(weed_plant_t *event_list, weed_timecode_t tc, int numframes, int *clips, int64_t *frames, weed_plant_t **shortcut)
Definition: events.c:1144
lives_button_box_set_layout
WIDGET_HELPER_GLOBAL_INLINE boolean lives_button_box_set_layout(LiVESButtonBox *bbox, LiVESButtonBoxStyle bstyle)
Definition: widget-helper.c:3355
_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
LIVES_OSC_NOTIFY_CLIP_OPENED
#define LIVES_OSC_NOTIFY_CLIP_OPENED
sent after a clip is opened
Definition: osc_notify.h:46
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
lives_entry_set_text
WIDGET_HELPER_GLOBAL_INLINE boolean lives_entry_set_text(LiVESEntry *entry, const char *text)
Definition: widget-helper.c:6211
get_init_events_before
void ** get_init_events_before(weed_plant_t *event, weed_plant_t *init_event, boolean add)
Definition: events.c:936
RENDER_CHOICE_NEW_CLIP
#define RENDER_CHOICE_NEW_CLIP
Definition: events.h:268
unlink_event
void unlink_event(weed_plant_t *event_list, weed_plant_t *event)
Definition: events.c:297
render_details::encoder_ofmt_fn
ulong encoder_ofmt_fn
Definition: events.h:243
WEED_LEAF_HOST_AUDIO_TRANSITION
#define WEED_LEAF_HOST_AUDIO_TRANSITION
Definition: events.h:86
PLUGIN_ENCODERS
#define PLUGIN_ENCODERS
Definition: plugins.h:98
lives_container_add
WIDGET_HELPER_GLOBAL_INLINE boolean lives_container_add(LiVESContainer *container, LiVESWidget *widget)
Definition: widget-helper.c:4929
lives_pixbuf_save_threaded
void * lives_pixbuf_save_threaded(void *args)
save frame to pixbuf in a thread.
Definition: main.c:9365
LIVES_FILE_EXT_LAYOUT
#define LIVES_FILE_EXT_LAYOUT
Definition: mainwindow.h:513
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
CANCEL_KEEP
@ CANCEL_KEEP
user pressed 'Keep'
Definition: main.h:734
count_resampled_events
frames_t count_resampled_events(weed_plant_t *event_list, double fps)
Definition: events.c:4560
_prefs::startup_interface
int startup_interface
Definition: preferences.h:336
_resaudw::entry_achans
LiVESWidget * entry_achans
Definition: resample.h:21
lives_system
int lives_system(const char *com, boolean allow_error)
Definition: utils.c:145
lives_widget_show_all
WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_show_all(LiVESWidget *widget)
Definition: widget-helper.c:1523
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
get_untitled_name
char * get_untitled_name(int number)
Definition: saveplay.c:3802
TREE_ROW_HEIGHT
#define TREE_ROW_HEIGHT
(unexpanded) height of rows in treeviews
Definition: mainwindow.h:96
reget_afilesize
void reget_afilesize(int fileno)
Definition: machinestate.c:972
_prefs::mt_enter_prompt
boolean mt_enter_prompt
Definition: preferences.h:268
RENDER_CHOICE_TRANSCODE
#define RENDER_CHOICE_TRANSCODE
Definition: events.h:271
has_video_chans_in
boolean has_video_chans_in(weed_plant_t *filter, boolean count_opt)
Definition: effects-weed.c:620
rdet
render_details * rdet
Definition: events.h:256
lives_funcptr_t
void *(* lives_funcptr_t)(void *)
Definition: machinestate.h:378
rdetw_spinf_changed
void rdetw_spinf_changed(LiVESSpinButton *spinbutton, livespointer user_data)
Definition: events.c:6066
xprocess
Definition: mainwindow.h:704
lives_toggle_button_set_active
WIDGET_HELPER_GLOBAL_INLINE boolean lives_toggle_button_set_active(LiVESToggleButton *button, boolean active)
Definition: widget-helper.c:4483
widget_opts
widget_opts_t widget_opts
Definition: widget-helper.h:1442
WEED_EVENT_IS_FILTER_MAP
#define WEED_EVENT_IS_FILTER_MAP(event)
Definition: events.h:366
weed_instance_get_filter
weed_plant_t * weed_instance_get_filter(weed_plant_t *inst, boolean get_compound_parent)
Definition: effects-weed.c:180
lives_entry_get_text
WIDGET_HELPER_GLOBAL_INLINE const char * lives_entry_get_text(LiVESEntry *entry)
Definition: widget-helper.c:6203
render_details::always_checkbutton
LiVESWidget * always_checkbutton
Definition: events.h:233
get_prev_frame_event
weed_plant_t * get_prev_frame_event(weed_plant_t *event)
Definition: events.c:368
lives_clip_t::vsize
int vsize
frame height (vertical) in pixels
Definition: main.h:897
init_event_is_process_last
boolean init_event_is_process_last(weed_plant_t *event)
Definition: events.c:1718
PATH_MAX
#define PATH_MAX
Definition: main.h:255
widget_opts_t::expand
lives_expand_t expand
how much space to apply between widgets
Definition: widget-helper.h:1408
restore_host_tags
void restore_host_tags(weed_plant_t *event_list, weed_timecode_t curr_tc)
Definition: events.c:1605
mainwindow::spinbutton_pb_fps
LiVESWidget * spinbutton_pb_fps
Definition: mainwindow.h:1391
WEED_LEAF_AUDIO_CLIPS
#define WEED_LEAF_AUDIO_CLIPS
Definition: events.h:40
AUD_PLAYER_PULSE
#define AUD_PLAYER_PULSE
Definition: preferences.h:44
get_next_event
LIVES_GLOBAL_INLINE weed_plant_t * get_next_event(weed_plant_t *event)
Definition: events.c:114
weed_event_get_timecode
LIVES_GLOBAL_INLINE weed_timecode_t weed_event_get_timecode(weed_event_t *event)
Definition: events.c:89
init_conversions
LIVES_GLOBAL_INLINE void init_conversions(int intent)
Definition: colourspace.c:1804
AUD_PLAYER_JACK
#define AUD_PLAYER_JACK
Definition: preferences.h:43
WEED_EVENT_IS_MARKER
#define WEED_EVENT_IS_MARKER(event)
Definition: events.h:368
do_read_failed_error_s
void do_read_failed_error_s(const char *s, const char *addinfo)
Definition: dialogs.c:4034
lives_standard_color_button_new
LiVESWidget * lives_standard_color_button_new(LiVESBox *box, const char *name, boolean use_alpha, lives_colRGBA64_t *rgba, LiVESWidget **sb_red, LiVESWidget **sb_green, LiVESWidget **sb_blue, LiVESWidget **sb_alpha)
Definition: widget-helper.c:10683
get_prev_audio_frame_event
weed_plant_t * get_prev_audio_frame_event(weed_plant_t *event)
Definition: events.c:392
check_encoder_restrictions
boolean check_encoder_restrictions(boolean get_extension, boolean user_audio, boolean save_all)
Definition: plugins.c:1557
lives_signal_handler_unblock
WIDGET_HELPER_GLOBAL_INLINE boolean lives_signal_handler_unblock(livespointer instance, unsigned long handler_id)
Definition: widget-helper.c:947
WEED_LEAF_CREATED_DATE
#define WEED_LEAF_CREATED_DATE
Definition: events.h:34
lives_colRGBA64_t::red
uint16_t red
Definition: main.h:323
mainwindow::is_processing
boolean is_processing
states
Definition: mainwindow.h:820
RENDER_CHOICE_SAME_CLIP
#define RENDER_CHOICE_SAME_CLIP
Definition: events.h:267
compare_filter_maps
boolean compare_filter_maps(weed_plant_t *fm1, weed_plant_t *fm2, int ctrack)
ctrack can be -1 to compare all events, else we cf for ctrack
Definition: multitrack.c:20384
lives_clip_t::gamma_type
int gamma_type
Definition: main.h:903
_prefs::pbq_adaptive
boolean pbq_adaptive
Definition: preferences.h:36
mainwindow::mute
boolean mute
Definition: mainwindow.h:770
GUI_SCREEN_WIDTH
#define GUI_SCREEN_WIDTH
Definition: mainwindow.h:99
lives_widget_process_updates
WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_process_updates(LiVESWidget *widget)
Definition: widget-helper.c:1658
lives_nanosleep_until_nonzero
#define lives_nanosleep_until_nonzero(condition)
Definition: machinestate.h:310
save_event_list_inner
boolean save_event_list_inner(lives_mt *mt, int fd, weed_plant_t *event_list, unsigned char **mem)
Definition: multitrack.c:252
audio.h
event_list_get_end_secs
double event_list_get_end_secs(weed_plant_t *event_list)
Definition: events.c:4607
render_text_overlay
LIVES_GLOBAL_INLINE weed_plant_t * render_text_overlay(weed_layer_t *layer, const char *text)
Definition: pangotext.c:543
mainwindow::disk_mon
uint32_t disk_mon
Definition: mainwindow.h:1807
FPS_MAX
#define FPS_MAX
maximum fps we will allow (double)
Definition: main.h:218
LIVES_INTENTION_RENDER
@ LIVES_INTENTION_RENDER
Definition: plugins.h:48
deal_with_render_choice
boolean deal_with_render_choice(boolean add_deinit)
Definition: events.c:5159
gamma_convert_layer
LIVES_GLOBAL_INLINE boolean gamma_convert_layer(int gamma_type, weed_layer_t *layer)
Definition: colourspace.c:12195
render_events_cb
lives_render_error_t render_events_cb(boolean dummy)
Definition: events.c:4447
lives_standard_check_button_new
LiVESWidget * lives_standard_check_button_new(const char *labeltext, boolean active, LiVESBox *box, const char *tooltip)
Definition: widget-helper.c:9048
EVENT_MARKER_RECORD_START
#define EVENT_MARKER_RECORD_START
Definition: events.h:355
d_print_done
void d_print_done(void)
Definition: utils.c:2620
mainwindow::currticks
volatile ticks_t currticks
wall clock time, updated whenever lives_get_*_ticks is called
Definition: mainwindow.h:1005
lives_check_button_new
WIDGET_HELPER_GLOBAL_INLINE LiVESWidget * lives_check_button_new(void)
Definition: widget-helper.c:4597
WEED_LEAF_FIRST
#define WEED_LEAF_FIRST
Definition: events.h:64
mainwindow::filter_map
weed_plant_t * filter_map
Definition: mainwindow.h:1298
mainwindow::urgency_msg
char * urgency_msg
OSD.
Definition: mainwindow.h:1643
mainwindow::cancel_type
lives_cancel_type_t cancel_type
Definition: mainwindow.h:799
LIVES_RENDER_ERROR
@ LIVES_RENDER_ERROR
Definition: events.h:108
lives_proc_thread_cancel
LIVES_GLOBAL_INLINE boolean lives_proc_thread_cancel(lives_proc_thread_t tinfo)
Definition: machinestate.c:1946
rte_key_getmode
int rte_key_getmode(int key)
returns current active mode for a key (or -1)
Definition: effects-weed.c:9424
WEED_LEAF_LIVES_EDITED_VERSION
#define WEED_LEAF_LIVES_EDITED_VERSION
Definition: events.h:32
mainwindow::resizing
boolean resizing
Definition: mainwindow.h:822
savethread_priv_t::fname
char * fname
Definition: main.h:1506
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
lives_widget_object_unref
WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_object_unref(livespointer object)
decrease refcount by one: if refcount==0, object is destroyed
Definition: widget-helper.c:815
WEED_EVENT_IS_FILTER_INIT
#define WEED_EVENT_IS_FILTER_INIT(event)
Definition: events.h:364
KEY_COLUMN
@ KEY_COLUMN
Definition: events.c:5553
mainwindow::undo
LiVESWidget * undo
Definition: mainwindow.h:1146
render_details::spinbutton_fps
LiVESWidget * spinbutton_fps
Definition: events.h:230
mainwindow::agen_key
volatile int agen_key
which fx key is generating audio [1 based] (or 0 for none)
Definition: mainwindow.h:1649
lives_getgid
LIVES_GLOBAL_INLINE int lives_getgid(void)
Definition: machinestate.c:2420
clone_decoder
lives_decoder_t * clone_decoder(int fileno)
Definition: plugins.c:2181
lives_proc_thread_join
LIVES_GLOBAL_INLINE void lives_proc_thread_join(lives_proc_thread_t tinfo)
Definition: machinestate.c:1979
lives_signal_handler_block
WIDGET_HELPER_GLOBAL_INLINE boolean lives_signal_handler_block(livespointer instance, unsigned long handler_id)
Definition: widget-helper.c:933
layer_to_pixbuf
LiVESPixbuf * layer_to_pixbuf(weed_layer_t *layer, boolean realpalette, boolean fordisplay)
Definition: colourspace.c:12210
resample_event
this struct is used only when physically resampling frames on the disk we create an array of these an...
Definition: main.h:641
_prefs::mt_def_height
int mt_def_height
Definition: preferences.h:270
DEF_FILE_PERMS
#define DEF_FILE_PERMS
non-executable, is modified by the umask
Definition: main.h:209
_prefs::letterbox_mt
boolean letterbox_mt
playback with letterbox (multitrack)
Definition: preferences.h:363
render_details::clipname_entry
LiVESWidget * clipname_entry
Definition: events.h:223
save_clip_values
boolean save_clip_values(int which_file)
Definition: saveplay.c:103
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_LEAF_HOST_REPEATS
#define WEED_LEAF_HOST_REPEATS
Definition: effects-weed.h:73
LAYOUT_FILENAME
#define LAYOUT_FILENAME
Definition: mainwindow.h:570
LIVES_THRDATTR_NO_GUI
#define LIVES_THRDATTR_NO_GUI
Definition: machinestate.h:442
is_perchannel_multiw
boolean is_perchannel_multiw(weed_plant_t *param)
Definition: effects-weed.c:8693
_prefs::event_window_show_frame_events
boolean event_window_show_frame_events
Definition: preferences.h:258
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
start_render_effect_events
boolean start_render_effect_events(weed_plant_t *event_list, boolean render_vid, boolean render_aud)
Definition: events.c:4453
lives_widget_get_allocation_width
WIDGET_HELPER_GLOBAL_INLINE int lives_widget_get_allocation_width(LiVESWidget *widget)
Definition: widget-helper.c:5455
lives_widget_set_size_request
WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_set_size_request(LiVESWidget *widget, int width, int height)
Definition: widget-helper.c:1614
LIVES_EXPAND_EXTRA_WIDTH
#define LIVES_EXPAND_EXTRA_WIDTH
Definition: widget-helper.h:1316
weed_palette_get_pixels_per_macropixel
LIVES_GLOBAL_INLINE int weed_palette_get_pixels_per_macropixel(int pal)
Definition: colourspace.c:1403
DESC_COLUMN
@ DESC_COLUMN
Definition: events.c:5555
WEED_LEAF_NEXT
#define WEED_LEAF_NEXT
Definition: events.h:62
calc_maxspect
void calc_maxspect(int rwidth, int rheight, int *cwidth, int *cheight)
Definition: utils.c:2174
render_details::always_hbox
LiVESWidget * always_hbox
Definition: events.h:234
lives_widget_set_text_color
WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_set_text_color(LiVESWidget *widget, LiVESWidgetState state, const LiVESWidgetColor *color)
Definition: widget-helper.c:2101
add_aspect_ratio_button
const lives_special_aspect_t * add_aspect_ratio_button(LiVESSpinButton *sp_width, LiVESSpinButton *sp_height, LiVESBox *box)
Definition: interface.c:4963
remove_frame_from_event
void remove_frame_from_event(weed_plant_t *event_list, weed_plant_t *event, int track)
Definition: events.c:489
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
savethread_priv_t::pixbuf
LiVESPixbuf * pixbuf
Definition: main.h:1504
_prefs::noframedrop
boolean noframedrop
Definition: preferences.h:469
toggle_sets_pref
void toggle_sets_pref(LiVESWidget *widget, livespointer prefidx)
callback to set to make a togglebutton or check_menu_item directly control a boolean pref widget is e...
Definition: preferences.c:46
lives_clip_t::handle
char handle[256]
Definition: main.h:881
_
#define _(String)
Definition: support.h:44
event_list_get_end_tc
weed_timecode_t event_list_get_end_tc(weed_plant_t *event_list)
Definition: events.c:4601
_future_prefs::letterbox_mt
boolean letterbox_mt
Definition: preferences.h:844
event_list_get_start_tc
weed_timecode_t event_list_get_start_tc(weed_plant_t *event_list)
Definition: events.c:4612
weed_delete_effectkey
boolean weed_delete_effectkey(int key, int mode)
unbinds a filter_class from a key/mode
Definition: effects-weed.c:9326
IS_NORMAL_CLIP
#define IS_NORMAL_CLIP(clip)
Definition: main.h:833
STYLE_1
#define STYLE_1
turn on theming if set
Definition: mainwindow.h:299
WEED_EVENT_IS_AUDIO_FRAME
#define WEED_EVENT_IS_AUDIO_FRAME(event)
Definition: events.h:362
mainwindow::error
boolean error
Definition: mainwindow.h:801
LIVES_RENDER_ERROR_NONE
@ LIVES_RENDER_ERROR_NONE
Definition: events.h:101
event_copy_and_insert
weed_plant_t * event_copy_and_insert(weed_plant_t *in_event, weed_timecode_t out_tc, weed_plant_t *event_list, weed_event_t **ret_event)
copy (duplicate) in_event and append it to event_list, changing the timecode to out_tc this is called...
Definition: events.c:622
lives_rm
int lives_rm(const char *file)
Definition: utils.c:4395
LIVES_INLINE
#define LIVES_INLINE
Definition: main.h:238
event_list_to_block
boolean event_list_to_block(weed_plant_t *event_list, int num_events)
Definition: events.c:2329
LIVES_EXPAND_NONE
#define LIVES_EXPAND_NONE
Definition: widget-helper.h:1311
_future_prefs::audio_src
int audio_src
Definition: preferences.h:828
render_details::aendian
int aendian
Definition: events.h:253
STARTUP_MT
#define STARTUP_MT
Definition: preferences.h:339
lives_widget_set_base_color
WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_set_base_color(LiVESWidget *widget, LiVESWidgetState state, const LiVESWidgetColor *color)
Definition: widget-helper.c:2126
AFORM_BIG_ENDIAN
#define AFORM_BIG_ENDIAN
Definition: main.h:787
load_frame_image
void load_frame_image(int frame)
Definition: main.c:7984
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
SCR_WIDTH_SAFETY
#define SCR_WIDTH_SAFETY
sepwin/screen size safety margins in pixels
Definition: mainwindow.h:89
lives_widget_context_update
boolean lives_widget_context_update(void)
Definition: widget-helper.c:11878
event_list_replace_events
void event_list_replace_events(weed_plant_t *event_list, weed_plant_t *new_event_list)
replace events in event_list with events in new_event_list
Definition: events.c:2320
WEED_LEAF_HOST_EASING_END
#define WEED_LEAF_HOST_EASING_END
Definition: effects-weed.h:92
lives_render_error_t
lives_render_error_t
various return conditions from rendering (multitrack or after recording)
Definition: events.h:100
move_event_right
boolean move_event_right(weed_plant_t *event_list, weed_plant_t *event, boolean can_stay, double fps)
Definition: events.c:2030
lives_pixbuf_save
boolean lives_pixbuf_save(LiVESPixbuf *pixbuf, char *fname, lives_img_type_t imgtype, int quality, int width, int height, LiVESError **gerrorptr)
Save a pixbuf to a file using the specified imgtype and the specified quality/compression value.
Definition: main.c:9304
render_details::suggestion_followed
boolean suggestion_followed
Definition: events.h:246
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
render_details::asamps
int asamps
Definition: events.h:252
lives_standard_radio_button_new
LiVESWidget * lives_standard_radio_button_new(const char *labeltext, LiVESSList **rbgroup, LiVESBox *box, const char *tooltip)
Definition: widget-helper.c:9265
create_event_list_dialog
LiVESWidget * create_event_list_dialog(weed_plant_t *event_list, weed_timecode_t start_tc, weed_timecode_t end_tc)
Definition: events.c:5582
MAINW_MSG_SIZE
#define MAINW_MSG_SIZE
mainw->msg bytesize
Definition: mainwindow.h:702
lives_standard_frame_new
LiVESWidget * lives_standard_frame_new(const char *labeltext, float xalign, boolean invis)
Definition: widget-helper.c:8732
mainwindow::ext_src_used
boolean ext_src_used[MAX_FILES]
Definition: mainwindow.h:1690
WEED_LEAF_PREVIOUS
#define WEED_LEAF_PREVIOUS
Definition: events.h:63
insert_blank_frame_event_at
LIVES_GLOBAL_INLINE weed_plant_t * insert_blank_frame_event_at(weed_plant_t *event_list, weed_timecode_t tc, weed_plant_t **shortcut)
Definition: events.c:1472
move_event_left
boolean move_event_left(weed_plant_t *event_list, weed_plant_t *event, boolean can_stay, double fps)
Definition: events.c:2103
show_playbar_labels
void show_playbar_labels(int clipno)
Definition: interface.c:77
_prefs::show_dev_opts
boolean show_dev_opts
Definition: preferences.h:463
paramspecial_get_aspect
const lives_special_aspect_t * paramspecial_get_aspect()
Definition: paramspecial.c:50
lives_box_pack_start
WIDGET_HELPER_GLOBAL_INLINE boolean lives_box_pack_start(LiVESBox *box, LiVESWidget *child, boolean expand, boolean fill, uint32_t padding)
Definition: widget-helper.c:3281
get_new_handle
boolean get_new_handle(int index, const char *name)
Definition: saveplay.c:3821