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
24static int render_choice;
25static weed_timecode_t last_rec_start_tc = -1;
26static 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
36LIVES_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
59LIVES_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
83LIVES_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
94GNU_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
98LIVES_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
103LIVES_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
109LIVES_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
114LIVES_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
119LIVES_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
124LIVES_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
129boolean 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
147int 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
165double 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
187double 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
209int 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
224frames_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
240weed_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
297void 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
311void 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
321boolean 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
334boolean 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
347void 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
356weed_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
368weed_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
380weed_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
392weed_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
404weed_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
419weed_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
434weed_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
450static LiVESList *trans_list = NULL;
451
452typedef struct {
453 weed_event_t *in_event;
454 weed_event_t *out_event;
455} trans_entry;
456
457static 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
464static 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
486void reset_ttable(void) {lives_list_free_all(&trans_list);}
487
488
489void 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
523boolean 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
546void 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
565weed_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
575weed_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
585boolean 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
622weed_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
761boolean 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
780weed_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
803boolean 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
812weed_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
821weed_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
859boolean 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
895weed_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
936void **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
1009void 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
1021void 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
1043void 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
1066boolean 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
1116void 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
1144weed_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
1243void 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
1349void 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
1382weed_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
1418weed_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
1472LIVES_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
1480void 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
1528static 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
1550LIVES_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
1560boolean 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
1570boolean 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
1590void 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
1605void 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
1623void 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
1653static 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
1708static 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
1718boolean 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
1731void 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
1784void 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
1892void 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
2030boolean 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
2103boolean 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
2176void 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
2181void set_render_choice_button(LiVESButton * button, livespointer choice) {
2182 render_choice = LIVES_POINTER_TO_INT(choice);
2183}
2184
2185
2186LiVESWidget *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
2300static 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
2313void 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
2320void 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
2329boolean 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
2435void 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
2497void 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
2583static 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
2610weed_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
2648void **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
2731weed_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
2882weed_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
2919weed_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
2968weed_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
3008void 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
3082weed_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
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 &&
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);
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++) {
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++) {
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
3408filterinit1:
3409
3410 num_params = num_in_params(inst, FALSE, FALSE);
3411
3412 if (num_params > 0) {
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
3547static 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
3609lives_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
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;
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) {
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;
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++) {
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++) {
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
4263filterinit2:
4264
4265 num_params = num_in_params(inst, FALSE, FALSE);
4266
4267 if (num_params > 0) {
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) {
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;
4445}
4446
4449 return render_events(FALSE, FALSE, FALSE);
4450}
4451
4452
4453boolean 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) {
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
4542int 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
4560frames_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
4601weed_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
4607double 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
4612weed_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
4618double 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
4623boolean 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
4635boolean 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
4659 }
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;
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);
4933 current_file = mainw->current_file;
4934 if (!save_clip_values(current_file)) {
4935 close_current_file(old_file);
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
5016rtc_done:
5022 return retval;
5023}
5024
5025
5026LIVES_INLINE void dprint_recneg(void) {d_print(_("nothing recorded.\n"));}
5027
5028boolean 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
5086static 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
5095static 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
5102void 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
5159boolean 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)
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
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) {
5235 && !mainw->clips_available) {
5236 mainw->current_file = -1;
5238 } else if (CURRENT_CLIP_IS_VALID) cfile->redoable = FALSE;
5241 sensitize();
5242 break;
5244 // preview
5245 cfile->next_event = get_first_event(mainw->event_list);
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;
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));
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;
5301 new_clip = TRUE;
5302 }
5303 break;
5305 cfile->undo_start = mainw->play_start = oplay_start;
5306 if (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) {
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
5360 // rewind scrap file to beginning
5363 }
5364 } while (render_choice == RENDER_CHOICE_PREVIEW);
5365
5366 if (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
5400double *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
5551enum {
5558
5559
5560#if GTK_CHECK_VERSION(3, 0, 0)
5561static void rowexpand(LiVESWidget * tv, LiVESTreeIter * iter, LiVESTreePath * path, livespointer ud) {
5565}
5566#endif
5567
5568
5569static 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
5582LiVESWidget *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;
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);
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) {
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
6054void 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
6060void 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
6066void 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
6072LiVESWidget *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));
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) {
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
6123static 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
6184LiVESWidget *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
6197static 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
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) {
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 {
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
6303
6304 if ((type != 1 && type != 4) || !IS_VALID_CLIP(mainw->current_file) || mainw->current_file == mainw->scrap_file) {
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
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) {
6357 // need to set a large enough default here
6358 scrollw = lives_standard_scrolled_window_new(width * .8, height * .5, top_vbox);
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"))));
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)) {
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
6475
6477
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
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
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
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
void audio_free_fnames(void)
Definition: audio.c:71
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
LIVES_GLOBAL_INLINE char * lives_get_audio_file_name(int fnum)
Definition: audio.c:55
#define is_realtime_aplayer(ptype)
Definition: audio.h:236
void on_encoder_ofmt_changed(LiVESCombo *combo, livespointer user_data)
Definition: callbacks.c:11680
void on_fade_audio_activate(LiVESMenuItem *menuitem, livespointer user_data)
Definition: callbacks.c:12133
void switch_clip(int type, int newclip, boolean force)
Definition: callbacks.c:6900
void on_preview_clicked(LiVESButton *button, livespointer user_data)
Definition: callbacks.c:10245
void on_encoder_entry_changed(LiVESCombo *combo, livespointer ptr)
Definition: callbacks.c:4779
void lives_notify(int msgnumber, const char *msgstring)
Definition: callbacks.c:49
void on_normalise_audio_activate(LiVESMenuItem *menuitem, livespointer user_data)
Definition: callbacks.c:11825
LIVES_GLOBAL_INLINE void init_conversions(int intent)
Definition: colourspace.c:1804
LIVES_GLOBAL_INLINE weed_layer_t * lives_layer_new_for_frame(int clip, frames_t frame)
Definition: colourspace.c:9833
LiVESPixbuf * layer_to_pixbuf(weed_layer_t *layer, boolean realpalette, boolean fordisplay)
boolean letterbox_layer(weed_layer_t *layer, int nwidth, int nheight, int width, int height, LiVESInterpType interp, int tpal, int tclamp)
LIVES_GLOBAL_INLINE weed_layer_t * weed_layer_free(weed_layer_t *layer)
frees pixel_data for a layer, then the layer itself
LIVES_GLOBAL_INLINE boolean weed_palette_is_alpha(int pal)
Definition: colourspace.c:1427
LIVES_GLOBAL_INLINE int weed_layer_get_height(weed_layer_t *layer)
LIVES_GLOBAL_INLINE boolean gamma_convert_layer(int gamma_type, weed_layer_t *layer)
boolean convert_layer_palette(weed_layer_t *layer, int outpl, int op_clamping)
boolean resize_layer(weed_layer_t *layer, int width, int height, LiVESInterpType interp, int opal_hint, int oclamp_hint)
resize a layer
LIVES_GLOBAL_INLINE int weed_palette_get_pixels_per_macropixel(int pal)
Definition: colourspace.c:1403
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
LIVES_GLOBAL_INLINE int weed_layer_get_width(weed_layer_t *layer)
LIVES_GLOBAL_INLINE weed_layer_t * weed_layer_nullify_pixel_data(weed_layer_t *layer)
Definition: colourspace.c:9753
void weed_layer_pixel_data_free(weed_layer_t *layer)
free pixel_data from layer
LIVES_GLOBAL_INLINE int weed_layer_get_palette(weed_layer_t *layer)
boolean create_frame_index(int fileno, boolean init, frames_t start_offset, frames_t nframes)
Definition: cvirtual.c:27
void del_frame_index(lives_clip_t *sfile)
Definition: cvirtual.c:238
boolean save_frame_index(int fileno)
Definition: cvirtual.c:56
boolean do_header_write_error(int clip)
Definition: dialogs.c:4169
void do_write_failed_error_s(const char *s, const char *addinfo)
Definition: dialogs.c:3979
void do_threaded_dialog(const char *trans_text, boolean has_cancel)
Definition: dialogs.c:3849
void do_encoder_img_fmt_error(render_details *rdet)
Definition: dialogs.c:4282
LiVESResponseType do_memory_error_dialog(char *op, size_t bytes)
Definition: dialogs.c:904
LiVESResponseType do_write_failed_error_s_with_retry(const char *fname, const char *errtext)
Definition: dialogs.c:4058
void end_threaded_dialog(void)
Definition: dialogs.c:3883
LIVES_GLOBAL_INLINE boolean do_event_list_warning(void)
Definition: dialogs.c:3707
void do_read_failed_error_s(const char *s, const char *addinfo)
Definition: dialogs.c:4034
LIVES_GLOBAL_INLINE LiVESResponseType do_error_dialog(const char *text)
Definition: dialogs.c:749
void threaded_dialog_spin(double fraction)
Definition: dialogs.c:3823
boolean check_storage_space(int clipno, boolean is_processing)
Definition: dialogs.c:1086
boolean do_progress_dialog(boolean visible, boolean cancellable, const char *text)
Definition: dialogs.c:2274
char * make_weed_hashname(int filter_idx, boolean fullname, boolean use_extra_authors, char sep, boolean subs)
return value should be freed after use
int rte_key_getmode(int key)
returns current active mode for a key (or -1)
weed_plant_t * weed_instance_get_filter(weed_plant_t *inst, boolean get_compound_parent)
Definition: effects-weed.c:180
int enabled_out_channels(weed_plant_t *plant, boolean count_repeats)
boolean has_video_chans_in(weed_plant_t *filter, boolean count_opt)
Definition: effects-weed.c:620
boolean is_perchannel_multiw(weed_plant_t *param)
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...
weed_plant_t * rte_keymode_get_instance(int key, int mode)
returns refcounted filter_instance bound to key/mode (or NULL)
char * weed_filter_idx_get_name(int idx, boolean add_subcats, boolean add_notes)
void deinit_render_effects(void)
switch off effects after render preview during rendering/render preview, we use the "keys" FX_KEYS_MA...
int weed_get_idx_for_hashname(const char *hashname, boolean fullname)
fullname includes author and version
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...
int num_in_params(weed_plant_t *plant, boolean skip_hidden, boolean skip_internal)
void weed_in_params_free(weed_plant_t **parameters, int num_parameters)
char * cd_to_plugin_dir(weed_plant_t *filter)
change directory to plugin installation dir so it can find any data files
weed_plant_t ** weed_params_create(weed_plant_t *filter, boolean in)
boolean weed_init_effect(int hotkey)
hotkey starts at 1
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)
int enabled_in_channels(weed_plant_t *plant, boolean count_repeats)
boolean interpolate_param(weed_plant_t *param, void *pchain, weed_timecode_t tc)
weed_error_t weed_call_deinit_func(weed_plant_t *instance)
int get_next_free_key(void)
next free "key" for the multitrack system
boolean weed_delete_effectkey(int key, int mode)
unbinds a filter_class from a key/mode
weed_plant_t * weed_filter_in_paramtmpl(weed_plant_t *filter, int param_num, boolean skip_internal)
boolean has_video_chans_out(weed_plant_t *filter, boolean count_opt)
Definition: effects-weed.c:676
LIVES_GLOBAL_INLINE int weed_instance_unref(weed_plant_t *inst)
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
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
weed_plant_t * get_weed_filter(int idx)
int get_transition_param(weed_plant_t *filter, boolean skip_internal)
weed_plant_t * weed_inst_in_param(weed_plant_t *inst, int param_num, boolean skip_hidden, boolean skip_internal)
boolean has_usable_palette(weed_plant_t *chantmpl)
weed_plant_t * get_enabled_channel(weed_plant_t *inst, int which, boolean is_in)
for FILTER_INST
Definition: effects-weed.c:536
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
weed_plant_t * weed_instance_from_filter(weed_plant_t *filter)
#define WEED_LEAF_HOST_EASING_END
Definition: effects-weed.h:92
#define WEED_LEAF_HOST_NEXT_INSTANCE
Definition: effects-weed.h:104
#define WEED_LEAF_HOST_SCRAP_FILE_OFFSET
Definition: effects-weed.h:88
#define WEED_LEAF_HOST_TAG
Definition: effects-weed.h:66
#define WEED_LEAF_HOST_MODE
Definition: effects-weed.h:68
#define WEED_LEAF_HOST_DISABLED
Definition: effects-weed.h:70
#define WEED_LEAF_AUTO_EASING
Definition: effects-weed.h:94
#define WEED_LEAF_HOST_INITED
Definition: effects-weed.h:74
#define WEED_LEAF_HOST_UNUSED
Definition: effects-weed.h:81
#define WEED_LEAF_HOST_KEY
Definition: effects-weed.h:67
#define WEED_LEAF_HOST_REPEATS
Definition: effects-weed.h:73
LiVESWidget * add_audio_options(LiVESWidget **cbbackaudio, LiVESWidget **cbpertrack)
Definition: events.c:6184
void set_render_choice(LiVESToggleButton *togglebutton, livespointer choice)
Definition: events.c:2176
void rdetw_spinw_changed(LiVESSpinButton *spinbutton, livespointer user_data)
Definition: events.c:6060
void remove_audio_for_track(weed_plant_t *event, int track)
Definition: events.c:1349
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
double get_audio_frame_seek(weed_plant_t *event, int track)
returns velocity for track (track==-1 is backing audio)
Definition: events.c:187
boolean has_frame_event_at(weed_plant_t *event_list, weed_timecode_t tc, weed_plant_t **shortcut)
Definition: events.c:129
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
void insert_filter_init_event_at(weed_plant_t *event_list, weed_plant_t *at_event, weed_plant_t *event)
Definition: events.c:1021
void event_list_add_end_events(weed_event_t *event_list, boolean is_final)
Definition: events.c:5102
void add_init_event_to_filter_map(weed_plant_t *fmap, weed_plant_t *event, void **hints)
Definition: events.c:1731
boolean frame_event_has_frame_for_track(weed_plant_t *event, int track)
Definition: events.c:761
void add_track_to_avol_init(weed_plant_t *filter, weed_plant_t *event, int nbtracks, boolean behind)
Definition: events.c:2435
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
void get_active_track_list(int *clip_index, int num_tracks, weed_plant_t *filter_map)
Definition: events.c:3008
boolean init_event_is_process_last(weed_plant_t *event)
Definition: events.c:1718
weed_plant_t * append_filter_map_event(weed_plant_t *event_list, weed_timecode_t tc, void **init_events)
Definition: events.c:2968
void backup_host_tags(weed_plant_t *event_list, weed_timecode_t curr_tc)
Definition: events.c:1590
void insert_filter_deinit_event_at(weed_plant_t *event_list, weed_plant_t *at_event, weed_plant_t *event)
Definition: events.c:1043
weed_plant_t * get_last_frame_event(weed_plant_t *event_list)
Definition: events.c:419
weed_plant_t * append_marker_event(weed_plant_t *event_list, weed_timecode_t tc, int marker_type)
Definition: events.c:1382
void delete_event(weed_plant_t *event_list, weed_plant_t *event)
Definition: events.c:311
void unlink_event(weed_plant_t *event_list, weed_plant_t *event)
Definition: events.c:297
weed_plant_t * get_prev_frame_event(weed_plant_t *event)
Definition: events.c:368
double event_list_get_end_secs(weed_plant_t *event_list)
Definition: events.c:4607
boolean has_audio_frame(weed_plant_t *event_list)
Definition: events.c:4623
void ** get_init_events_before(weed_plant_t *event, weed_plant_t *init_event, boolean add)
Definition: events.c:936
void insert_param_change_event_at(weed_plant_t *event_list, weed_plant_t *at_event, weed_plant_t *event)
Definition: events.c:1116
void rdetw_spinh_changed(LiVESSpinButton *spinbutton, livespointer user_data)
Definition: events.c:6054
boolean move_event_right(weed_plant_t *event_list, weed_plant_t *event, boolean can_stay, double fps)
Definition: events.c:2030
boolean render_to_clip(boolean new_clip, boolean transcode)
rendering
Definition: events.c:4635
void delete_param_changes_after_deinit(weed_plant_t *event_list, weed_plant_t *init_event)
Definition: events.c:1623
weed_timecode_t get_next_paramchange(void **pchange_next, weed_timecode_t end_tc)
Definition: events.c:565
boolean filter_init_has_owner(weed_plant_t *init_event, int track)
Definition: events.c:1570
weed_plant_t * get_next_audio_frame_event(weed_plant_t *event)
Definition: events.c:380
LIVES_GLOBAL_INLINE weed_timecode_t weed_event_get_timecode(weed_event_t *event)
Definition: events.c:89
frames_t get_frame_event_frame(weed_plant_t *event, int layer)
Definition: events.c:224
int get_frame_event_clip(weed_plant_t *event, int layer)
Definition: events.c:209
LIVES_GLOBAL_INLINE boolean init_event_in_list(void **init_events, int num_inits, weed_plant_t *event)
Definition: events.c:1550
render_details * create_render_details(int type)
Definition: events.c:6252
LIVES_GLOBAL_INLINE weed_plant_t * get_prev_event(weed_plant_t *event)
Definition: events.c:109
weed_timecode_t get_prev_paramchange(void **pchange_prev, weed_timecode_t start_tc)
Definition: events.c:575
LiVESWidget * events_rec_dialog(void)
Definition: events.c:2186
weed_plant_t * process_events(weed_plant_t *next_event, boolean process_audio, weed_timecode_t curr_tc)
Definition: events.c:3082
LIVES_GLOBAL_INLINE int weed_event_get_type(weed_event_t *event)
Definition: events.c:31
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
void insert_audio_event_at(weed_plant_t *event, int track, int clipnum, double seek, double vel)
Definition: events.c:1243
boolean deal_with_render_choice(boolean add_deinit)
Definition: events.c:5159
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
weed_timecode_t event_list_get_start_tc(weed_plant_t *event_list)
Definition: events.c:4612
lives_render_error_t render_events_cb(boolean dummy)
Definition: events.c:4447
boolean start_render_effect_events(weed_plant_t *event_list, boolean render_vid, boolean render_aud)
Definition: events.c:4453
boolean event_list_to_block(weed_plant_t *event_list, int num_events)
Definition: events.c:2329
frames_t count_resampled_events(weed_plant_t *event_list, double fps)
Definition: events.c:4560
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
LIVES_GLOBAL_INLINE weed_plant_t * get_first_event(weed_plant_t *event_list)
Definition: events.c:119
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
LIVES_GLOBAL_INLINE weed_timecode_t get_event_timecode(weed_plant_t *plant)
Definition: events.c:98
void remove_filter_from_event_list(weed_plant_t *event_list, weed_plant_t *init_event)
Definition: events.c:1480
void remove_frame_from_event(weed_plant_t *event_list, weed_plant_t *event, int track)
Definition: events.c:489
LIVES_GLOBAL_INLINE weed_plant_t * get_last_event(weed_plant_t *event_list)
Definition: events.c:124
void reset_ttable(void)
Definition: events.c:486
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
boolean is_init_pchange(weed_plant_t *init_event, weed_plant_t *pchange_event)
Definition: events.c:585
LIVES_GLOBAL_INLINE int weed_frame_event_get_tracks(weed_event_t *event, int **clips, int64_t **frames)
Definition: events.c:36
boolean backup_recording(char **esave_file, char **asave_file)
Definition: events.c:5028
boolean is_blank_frame(weed_plant_t *event, boolean count_audio)
Definition: events.c:523
LIVES_GLOBAL_INLINE int get_event_type(weed_plant_t *plant)
Definition: events.c:103
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
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
GNU_PURE void *** get_event_pchains(void)
Definition: events.c:94
double get_audio_frame_vel(weed_plant_t *event, int track)
returns velocity for track (track==-1 is backing audio)
Definition: events.c:165
void event_list_free(weed_plant_t *event_list)
Definition: events.c:2313
boolean filter_map_has_event(weed_plant_t *fmap, weed_plant_t *event)
Definition: events.c:1560
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
void rdetw_spinf_changed(LiVESSpinButton *spinbutton, livespointer user_data)
Definition: events.c:6066
weed_plant_t * get_filter_map_before(weed_plant_t *event, int ctrack, weed_plant_t *stop_event)
Definition: events.c:895
LIVES_INLINE void dprint_recneg(void)
Definition: events.c:5026
weed_plant_t * get_first_frame_event(weed_plant_t *event_list)
Definition: events.c:404
weed_plant_t * get_filter_map_after(weed_plant_t *event, int ctrack)
Definition: events.c:821
weed_plant_t * get_prev_audio_frame_event(weed_plant_t *event)
Definition: events.c:392
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
double event_list_get_start_secs(weed_plant_t *event_list)
Definition: events.c:4618
@ KEY_COLUMN
Definition: events.c:5553
@ VALUE_COLUMN
Definition: events.c:5554
@ TITLE_COLUMN
Definition: events.c:5552
@ NUM_COLUMNS
Definition: events.c:5556
@ DESC_COLUMN
Definition: events.c:5555
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
#define _get_or_zero(a, b, c)
Definition: events.c:96
void event_list_close_gaps(weed_event_t *event_list)
Definition: events.c:2365
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
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
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
boolean filter_map_after_frame(weed_plant_t *fmap)
Definition: events.c:803
LIVES_GLOBAL_INLINE weed_plant_t * get_next_event(weed_plant_t *event)
Definition: events.c:114
boolean insert_event_before(weed_plant_t *at_event, weed_plant_t *event)
Definition: events.c:321
weed_plant_t * get_next_frame_event(weed_plant_t *event)
Definition: events.c:356
boolean init_event_is_relevant(weed_plant_t *init_event, int ctrack)
Definition: events.c:859
LIVES_GLOBAL_INLINE weed_timecode_t weed_event_set_timecode(weed_event_t *event, weed_timecode_t tc)
Definition: events.c:83
void update_filter_maps(weed_plant_t *event, weed_plant_t *end_event, weed_plant_t *init_event)
Definition: events.c:1009
void replace_event(weed_plant_t *event_list, weed_plant_t *at_event, weed_plant_t *event)
Definition: events.c:347
void event_list_add_track(weed_plant_t *event_list, int layer)
Definition: events.c:2497
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
boolean insert_event_after(weed_plant_t *at_event, weed_plant_t *event)
Definition: events.c:334
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
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_event_t * lives_event_list_new(weed_event_t *elist, const char *cdate)
lib-ish stuff
Definition: events.c:240
weed_timecode_t event_list_get_end_tc(weed_plant_t *event_list)
Definition: events.c:4601
void set_render_choice_button(LiVESButton *button, livespointer choice)
Definition: events.c:2181
void restore_host_tags(weed_plant_t *event_list, weed_timecode_t curr_tc)
Definition: events.c:1605
LIVES_GLOBAL_INLINE int weed_frame_event_get_audio_tracks(weed_event_t *event, int **clips, double **seeks)
Definition: events.c:59
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
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
LiVESWidget * create_event_list_dialog(weed_plant_t *event_list, weed_timecode_t start_tc, weed_timecode_t end_tc)
Definition: events.c:5582
boolean move_event_left(weed_plant_t *event_list, weed_plant_t *event, boolean can_stay, double fps)
Definition: events.c:2103
void remove_end_blank_frames(weed_plant_t *event_list, boolean remove_filter_inits)
Definition: events.c:546
#define WEED_LEAF_HOST_AUDIO_TRANSITION
Definition: events.h:86
#define WEED_LEAF_FIRST
Definition: events.h:64
#define WEED_LEAF_NEXT
Definition: events.h:62
#define WEED_LEAF_TRACKS
Definition: events.h:80
#define EVENT_MARKER_RECORD_START
Definition: events.h:355
#define AUD_DIFF_MIN
ignore audio seek differences < than this (seconds)
Definition: events.h:94
#define WEED_EVENT_IS_FRAME(event)
Definition: events.h:361
#define AUD_DIFF_REVADJ
allow longer seek differences when audio plauback direction reverses (multiplying factor)
Definition: events.h:95
#define WEED_LEAF_LAST
Definition: events.h:65
#define WEED_LEAF_IS_DEF_VALUE
Definition: events.h:73
#define WEED_LEAF_INIT_EVENTS
Definition: events.h:55
#define WEED_LEAF_PREV_CHANGE
Definition: events.h:72
#define WEED_LEAF_LIVES_CREATED_VERSION
Definition: events.h:31
#define WEED_LEAF_AUDIO_SEEKS
Definition: events.h:41
#define WEED_LEAF_CREATED_DATE
Definition: events.h:34
#define WEED_LEAF_DEINIT_EVENT
Definition: events.h:76
#define WEED_LEAF_TC_ADJUSTMENT
Definition: events.h:68
#define RENDER_CHOICE_EVENT_LIST
Definition: events.h:270
#define WEED_EVENT_IS_AUDIO_FRAME(event)
Definition: events.h:362
#define RENDER_CHOICE_DISCARD
Definition: events.h:265
#define WEED_LEAF_EDITED_DATE
Definition: events.h:35
#define WEED_LEAF_NEXT_CHANGE
Definition: events.h:71
#define WEED_EVENT_IS_FILTER_DEINIT(event)
Definition: events.h:365
#define RENDER_CHOICE_NEW_CLIP
Definition: events.h:268
#define WEED_LEAF_AUDIO_CLIPS
Definition: events.h:40
#define RENDER_CHOICE_MULTITRACK
Definition: events.h:269
#define WEED_EVENT_IS_MARKER(event)
Definition: events.h:368
#define EVENT_MARKER_RECORD_END
Definition: events.h:356
#define RENDER_CHOICE_NONE
Definition: events.h:264
#define WEED_LEAF_INIT_EVENT
Definition: events.h:52
#define RENDER_CHOICE_PREVIEW
Definition: events.h:266
#define RENDER_CHOICE_SAME_CLIP
Definition: events.h:267
#define WEED_LEAF_WEED_EVENT_API_VERSION
parts of this may eventually become libweed-events
Definition: events.h:18
render_details * rdet
Definition: events.h:256
#define WEED_LEAF_PREVIOUS
Definition: events.h:63
#define RENDER_CHOICE_TRANSCODE
Definition: events.h:271
#define WEED_LEAF_OUT_COUNT
Definition: events.h:46
#define WEED_EVENT_IS_FILTER_INIT(event)
Definition: events.h:364
#define WEED_LEAF_FILTER
Definition: events.h:44
#define WEED_LEAF_HOST_TAG_COPY
Definition: events.h:88
#define WEED_LEAF_TCDELTA
Definition: events.h:81
#define WEED_LEAF_IN_COUNT
Definition: events.h:45
#define WEED_LEAF_IN_TRACKS
Definition: events.h:47
#define WEED_LEAF_LIVES_TYPE
Definition: events.h:79
#define WEED_PLANT_IS_EVENT_LIST(plant)
Definition: events.h:359
weed_plant_t weed_event_t
Definition: events.h:97
#define WEED_PLANT_IS_EVENT(plant)
Definition: events.h:358
#define LIVES_TRACK_ANY
Definition: events.h:92
#define WEED_LEAF_OVERLAY_TEXT
Definition: events.h:90
#define WEED_LEAF_INDEX
Definition: events.h:58
#define WEED_EVENT_IS_PARAM_CHANGE(event)
Definition: events.h:367
#define EVENT_MARKER_BLOCK_START
Definition: events.h:353
#define WEED_LEAF_OUT_TRACKS
Definition: events.h:48
#define WEED_EVENT_IS_FILTER_MAP(event)
Definition: events.h:366
#define WEED_LEAF_FRAMES
Definition: events.h:38
lives_render_error_t
various return conditions from rendering (multitrack or after recording)
Definition: events.h:100
@ LIVES_RENDER_EFFECTS_PAUSED
Definition: events.h:104
@ LIVES_RENDER_PROCESSING
Definition: events.h:103
@ LIVES_RENDER_ERROR_WRITE_FRAME
Definition: events.h:111
@ LIVES_RENDER_ERROR_NONE
Definition: events.h:101
@ LIVES_RENDER_COMPLETE
Definition: events.h:105
@ LIVES_RENDER_ERROR
Definition: events.h:108
@ LIVES_RENDER_ERROR_READ_AUDIO
Definition: events.h:109
@ LIVES_RENDER_READY
Definition: events.h:102
@ LIVES_RENDER_ERROR_WRITE_AUDIO
Definition: events.h:110
#define WEED_LEAF_LIVES_EDITED_VERSION
Definition: events.h:32
#define EVENT_MARKER_BLOCK_UNORDERED
Definition: events.h:354
#define WEED_LEAF_CLIPS
Definition: events.h:39
void add_to_clipmenu(void)
Definition: gui.c:4512
double lives_ce_update_timeline(int frame, double x)
pointer position in timeline
Definition: interface.c:207
const lives_special_aspect_t * add_aspect_ratio_button(LiVESSpinButton *sp_width, LiVESSpinButton *sp_height, LiVESBox *box)
Definition: interface.c:4963
void show_playbar_labels(int clipno)
Definition: interface.c:77
error("LSD_RANDFUNC(ptr, size) must be defined")
LIVES_GLOBAL_INLINE int lives_getgid(void)
char * lives_datetime(uint64_t secs, boolean use_local)
Definition: machinestate.c:860
LIVES_GLOBAL_INLINE boolean lives_strcmp(const char *st1, const char *st2)
returns FALSE if strings match
LIVES_GLOBAL_INLINE boolean lives_proc_thread_cancel(lives_proc_thread_t tinfo)
weed_plantptr_t lives_proc_thread_t
lives proc_threads API
LIVES_GLOBAL_INLINE size_t lives_strlen(const char *s)
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,...
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
void update_effort(int nthings, boolean badthings)
LIVES_GLOBAL_INLINE int lives_getuid(void)
LIVES_GLOBAL_INLINE void lives_proc_thread_join(lives_proc_thread_t tinfo)
off_t reget_afilesize_inner(int fileno)
LIVES_GLOBAL_INLINE boolean lives_strncmp(const char *st1, const char *st2, size_t len)
returns FALSE if strings match
void * main_thread_execute(lives_funcptr_t func, int return_type, void *retval, const char *args_fmt,...)
uint64_t lives_thread_join(lives_thread_t work, void **retval)
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
int lives_thread_create(lives_thread_t *thread, lives_thread_attr_t attr, lives_funcptr_t func, void *arg)
void reget_afilesize(int fileno)
Definition: machinestate.c:972
LiVESList lives_thread_t
Definition: machinestate.h:434
#define lives_calloc
Definition: machinestate.h:67
#define LIVES_THRDATTR_NO_GUI
Definition: machinestate.h:442
#define THREADVAR(var)
Definition: machinestate.h:531
#define lives_free
Definition: machinestate.h:52
#define lives_nanosleep_until_nonzero(condition)
Definition: machinestate.h:310
#define lives_malloc
Definition: machinestate.h:46
#define lives_memcpy
Definition: machinestate.h:55
void *(* lives_funcptr_t)(void *)
Definition: machinestate.h:378
#define PRId64
Definition: machinestate.h:169
#define lives_realloc
Definition: machinestate.h:49
#define LIVES_THRDATTR_NONE
Definition: machinestate.h:437
LIVES_GLOBAL_INLINE void free_track_decoders(void)
Definition: main.c:7826
void sensitize(void)
Definition: main.c:5078
_palette * palette
interface colour settings
Definition: main.c:101
ssize_t sizdbl
Definition: main.c:102
void load_frame_image(int frame)
Definition: main.c:7984
void init_track_decoders(void)
Definition: main.c:7816
ssize_t sizint
type sizes
Definition: main.c:102
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
boolean check_layer_ready(weed_layer_t *layer)
block until layer pixel_data is ready.
Definition: main.c:7528
void * lives_pixbuf_save_threaded(void *args)
save frame to pixbuf in a thread.
Definition: main.c:9365
mainwindow * mainw
Definition: main.c:103
void do_quick_switch(int new_file)
Definition: main.c:10066
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
void pull_frame_threaded(weed_layer_t *layer, const char *img_ext, weed_timecode_t tc, int width, int height)
Definition: main.c:7631
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
void clear_mainw_msg(void)
Definition: utils.c:1435
int lives_close_buffered(int fd)
Definition: utils.c:716
int frames_t
Definition: main.h:99
boolean load_from_scrap_file(weed_layer_t *layer, int frame)
Definition: saveplay.c:5360
#define IMG_TYPE_BEST
Definition: main.h:781
char * get_untitled_name(int number)
Definition: saveplay.c:3802
void lives_list_free_all(LiVESList **)
Definition: utils.c:4873
#define MAX_FRAME_WIDTH
Definition: main.h:220
@ UNDO_RENDER
resample/reorder/resize/apply effects
Definition: main.h:680
size_t get_token_count(const char *string, int delim)
Definition: utils.c:5430
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
double calc_time_from_frame(int clip, int frame)
Definition: utils.c:1756
#define LIVES_GLOBAL_INLINE
Definition: main.h:239
int lives_chdir(const char *path, boolean no_error_dlg)
Definition: utils.c:1393
#define AFORM_SIGNED
Definition: main.h:783
@ CANCEL_KILL
normal - kill background processes working on current clip
Definition: main.h:759
ssize_t lives_write_buffered(int fd, const char *buf, ssize_t count, boolean allow_fail)
Definition: utils.c:1226
#define DEF_FILE_PERMS
non-executable, is modified by the umask
Definition: main.h:209
#define LIVES_IS_PLAYING
Definition: main.h:840
#define IS_NORMAL_CLIP(clip)
Definition: main.h:833
void close_scrap_file(boolean remove)
Definition: saveplay.c:5583
void close_ascrap_file(boolean remove)
Definition: saveplay.c:5612
int lives_create_buffered(const char *pathname, int mode)
Definition: utils.c:698
#define LIVES_INLINE
Definition: main.h:238
int lives_system(const char *com, boolean allow_error)
Definition: utils.c:145
void set_undoable(const char *what, boolean sensitive)
Definition: utils.c:4784
ssize_t lives_write_le_buffered(int fd, livesconstpointer buf, ssize_t count, boolean allow_fail)
boolean get_new_handle(int index, const char *name)
Definition: saveplay.c:3821
#define AFORM_UNSIGNED
Definition: main.h:786
#define AFORM_LITTLE_ENDIAN
Definition: main.h:784
const char * get_image_ext_for_type(lives_img_type_t imgtype)
Definition: utils.c:3025
#define FPS_MAX
maximum fps we will allow (double)
Definition: main.h:218
boolean save_clip_values(int which_file)
Definition: saveplay.c:103
@ CLIP_DETAILS_FRAMES
Definition: main.h:1154
#define CURRENT_CLIP_HAS_VIDEO
Definition: main.h:815
struct timeval tv
Definition: main.h:1136
#define IS_VALID_CLIP(clip)
Definition: main.h:808
int lives_rm(const char *file)
Definition: utils.c:4395
void d_print_failed(void)
Definition: utils.c:2615
#define CURRENT_CLIP_IS_NORMAL
Definition: main.h:838
capability * capable
Definition: main.h:627
#define cfile
Definition: main.h:1833
void d_print(const char *fmt,...)
Definition: utils.c:2542
#define LIVES_ERROR(x)
Definition: main.h:1870
@ IMG_TYPE_PNG
Definition: main.h:777
@ IMG_TYPE_JPEG
Definition: main.h:776
int calc_frame_from_time4(int filenum, double time)
nearest frame, no maximum
Definition: utils.c:1788
void add_to_recovery_file(const char *handle)
Definition: saveplay.c:6460
#define AFORM_BIG_ENDIAN
Definition: main.h:787
#define CURRENT_CLIP_IS_VALID
Definition: main.h:809
off_t lives_lseek_buffered_rdonly_absolute(int fd, off_t offset)
Definition: utils.c:907
boolean create_event_space(int length_in_eventsb)
Definition: utils.c:4660
void calc_maxspect(int rwidth, int rheight, int *cwidth, int *cheight)
Definition: utils.c:2174
void d_print_done(void)
Definition: utils.c:2620
#define PATH_MAX
Definition: main.h:255
boolean lives_freep(void **ptr)
Definition: utils.c:1411
@ CLIP_TYPE_FILE
unimported video, not or partially broken in frames
Definition: main.h:765
@ CLIP_TYPE_DISK
imported video, broken into frames
Definition: main.h:764
#define GNU_PURE
Definition: main.h:78
#define WEED_LEAF_HOST_DECODER
Definition: main.h:801
#define myround(n)
Definition: main.h:300
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
boolean save_clip_value(int which, lives_clip_details_t, void *val)
Definition: utils.c:5175
#define CLIP_TOTAL_TIME(clip)
Definition: main.h:830
@ CANCEL_NONE
no cancel
Definition: main.h:701
@ CANCEL_KEEP
user pressed 'Keep'
Definition: main.h:734
#define MAINW_MSG_SIZE
mainw->msg bytesize
Definition: mainwindow.h:702
#define TREE_ROW_HEIGHT
(unexpanded) height of rows in treeviews
Definition: mainwindow.h:96
#define MONITOR_QUOTA
Definition: mainwindow.h:1805
#define LAYOUT_FILENAME
Definition: mainwindow.h:570
#define TICKS_PER_SECOND
ticks per second - GLOBAL TIMEBASE
Definition: mainwindow.h:36
#define SCR_HEIGHT_SAFETY
Definition: mainwindow.h:90
#define LIVES_MAIN_WINDOW_WIDGET
Definition: mainwindow.h:188
#define TICKS_PER_SECOND_DBL
actually microseconds / 100.
Definition: mainwindow.h:37
@ LIVES_STRING_CONSTANT_ANY
Definition: mainwindow.h:370
#define LIVES_FILE_EXT_LAYOUT
Definition: mainwindow.h:513
#define LIVES_FILE_EXT_MGK
Definition: mainwindow.h:489
#define DEF_GEN_HEIGHT
Definition: mainwindow.h:150
#define GUI_SCREEN_WIDTH
Definition: mainwindow.h:99
#define DEF_GEN_WIDTH
Definition: mainwindow.h:149
#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
#define STYLE_1
turn on theming if set
Definition: mainwindow.h:299
#define SCR_WIDTH_SAFETY
sepwin/screen size safety margins in pixels
Definition: mainwindow.h:89
#define LAYOUT_NUMBERING_FILENAME
Definition: mainwindow.h:572
#define FX_KEYS_MAX
the rest of the keys are accessible through the multitrack renderer (must, be > FX_KEYS_MAX_VIRTUAL)
Definition: mainwindow.h:206
#define GUI_SCREEN_HEIGHT
Definition: mainwindow.h:100
void mt_fixup_events(lives_mt *mt, weed_plant_t *old_event, weed_plant_t *new_event)
Definition: multitrack.c:19321
void recover_layout_cancelled(boolean is_startup)
Definition: multitrack.c:923
boolean save_event_list_inner(lives_mt *mt, int fd, weed_plant_t *event_list, unsigned char **mem)
Definition: multitrack.c:252
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
void stored_event_list_free_all(boolean wiped)
Definition: multitrack.c:5897
boolean check_for_layout_del(lives_mt *mt, boolean exiting)
Definition: multitrack.c:5924
char * get_track_name(lives_mt *mt, int track_num, boolean is_audio)
Definition: multitrack.c:1038
boolean on_multitrack_activate(LiVESMenuItem *menuitem, weed_plant_t *event_list)
menuitem callback
Definition: multitrack.c:11024
#define MAX_AUDIO_TRACKS
Definition: multitrack.h:1046
#define LIVES_OSC_NOTIFY_CLIP_OPENED
sent after a clip is opened
Definition: osc_notify.h:46
LIVES_GLOBAL_INLINE weed_plant_t * render_text_overlay(weed_layer_t *layer, const char *text)
Definition: pangotext.c:543
const lives_special_aspect_t * paramspecial_get_aspect()
Definition: paramspecial.c:50
LiVESList * filter_encoders_by_img_ext(LiVESList *encoders, const char *img_ext)
Definition: plugins.c:2006
LiVESList * get_plugin_list(const char *plugin_type, boolean allow_nonex, const char *plugdir, const char *filter_ext)
Definition: plugins.c:115
boolean chill_decoder_plugin(int fileno)
Definition: plugins.c:2425
void close_decoder_plugin(lives_decoder_t *dplug)
Definition: plugins.c:2361
LIVES_GLOBAL_INLINE LiVESList * plugin_request_by_line(const char *plugin_type, const char *plugin_name, const char *request)
Definition: plugins.c:59
boolean check_encoder_restrictions(boolean get_extension, boolean user_audio, boolean save_all)
Definition: plugins.c:1557
lives_decoder_t * clone_decoder(int fileno)
Definition: plugins.c:2181
#define PLUGIN_ENCODERS
Definition: plugins.h:98
@ LIVES_INTENTION_RENDER
Definition: plugins.h:48
void rdet_acodec_changed(LiVESCombo *acodec_combo, livespointer user_data)
Definition: preferences.c:2417
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
boolean pref_factory_int(const char *prefidx, int newval, boolean permanent)
Definition: preferences.c:1053
boolean pref_factory_bool(const char *prefidx, boolean newval, boolean permanent)
Definition: preferences.c:717
void set_acodec_list_from_allowed(_prefsw *prefsw, render_details *rdet)
Definition: preferences.c:2437
#define PREF_REC_EXT_AUDIO
Definition: preferences.h:892
_prefs * prefs
Definition: preferences.h:847
#define SEPWIN_TYPE_NON_STICKY
Definition: preferences.h:187
#define STARTUP_MT
Definition: preferences.h:339
#define REC_AUDIO
Definition: preferences.h:201
#define AUD_PLAYER_NONE
Definition: preferences.h:41
#define AUD_PLAYER_JACK
Definition: preferences.h:43
_future_prefs * future_prefs
Definition: preferences.h:848
#define AUDIO_SRC_EXT
Definition: preferences.h:206
#define PREF_LETTERBOXMT
Definition: preferences.h:1070
#define AUDIO_SRC_INT
Definition: preferences.h:205
#define REC_EFFECTS
Definition: preferences.h:199
#define PREF_SEPWIN_TYPE
Definition: preferences.h:894
#define AUD_PLAYER_PULSE
Definition: preferences.h:44
_resaudw * create_resaudw(short type, render_details *rdet, LiVESWidget *top_vbox)
resample audio window
Definition: resample.c:1521
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
LIVES_GLOBAL_INLINE ticks_t q_gint64(ticks_t in, double fps)
Definition: resample.c:25
_resaudw * resaudw
Definition: resample.h:38
char of_desc[128]
Definition: plugins.h:264
char name[64]
Definition: plugins.h:234
char of_name[64]
Definition: plugins.h:263
int of_allowed_acodecs
Definition: plugins.h:265
boolean letterbox_mt
Definition: preferences.h:844
short sepwin_type
Definition: preferences.h:832
_encoder encoder
Definition: preferences.h:820
LiVESWidgetColor info_base
Definition: mainwindow.h:330
int style
Definition: mainwindow.h:297
LiVESWidgetColor info_text
Definition: mainwindow.h:329
char backend[PATH_MAX *4]
Definition: preferences.h:411
int mt_def_arate
Definition: preferences.h:273
double mt_def_fps
Definition: preferences.h:271
_encoder encoder
from main.h
Definition: preferences.h:38
int startup_interface
Definition: preferences.h:336
boolean crash_recovery
TRUE==maintain mainw->recovery file.
Definition: preferences.h:259
int ocp
open_compression_percent : get/set in prefs
Definition: preferences.h:217
boolean pbq_adaptive
Definition: preferences.h:36
boolean rr_super
Definition: preferences.h:490
int audio_src
Definition: preferences.h:204
boolean event_window_show_frame_events
Definition: preferences.h:258
boolean hide_framebar
Definition: preferences.h:434
int mt_backaudio
Definition: preferences.h:279
boolean letterbox_mt
playback with letterbox (multitrack)
Definition: preferences.h:363
boolean rr_ramicro
Definition: preferences.h:495
char workdir[PATH_MAX]
kept in locale encoding
Definition: preferences.h:61
int rec_opts
Definition: preferences.h:196
boolean noframedrop
Definition: preferences.h:469
int mt_def_signed_endian
Definition: preferences.h:273
boolean letterbox
playback with letterbox
Definition: preferences.h:362
boolean show_player_stats
Definition: preferences.h:190
boolean mt_enter_prompt
Definition: preferences.h:268
LiVESList * acodec_list
Definition: preferences.h:251
int mt_def_achans
Definition: preferences.h:273
int gui_monitor
Definition: preferences.h:305
int mt_def_asamps
Definition: preferences.h:273
int mt_def_width
Definition: preferences.h:270
int mt_def_height
Definition: preferences.h:270
boolean render_audio
Definition: preferences.h:298
boolean show_dev_opts
Definition: preferences.h:463
boolean mt_pertrack_audio
Definition: preferences.h:278
boolean btgamma
allows clips to be stored with bt709 gamma - CAUTION not backwards compatible, untested
Definition: preferences.h:453
char backend_sync[PATH_MAX *4]
Definition: preferences.h:410
short audio_player
Definition: preferences.h:40
char image_ext[16]
Definition: preferences.h:78
boolean render_prompt
Definition: preferences.h:276
boolean open_maximised
Definition: preferences.h:28
boolean rr_crash
Definition: preferences.h:488
LiVESWidget * aud_checkbutton
Definition: resample.h:32
LiVESWidget * rb_signed
Definition: resample.h:23
LiVESWidget * vbox
Definition: resample.h:34
LiVESWidget * entry_asamps
Definition: resample.h:22
LiVESWidget * rb_littleend
Definition: resample.h:26
LiVESWidget * rb_unsigned
Definition: resample.h:24
LiVESWidget * rb_bigend
Definition: resample.h:25
LiVESWidget * entry_arate
Definition: resample.h:20
LiVESWidget * entry_achans
Definition: resample.h:21
pid_t mainpid
Definition: main.h:591
lives_checkstatus_t has_encoder_plugins
Definition: main.h:571
void * ext_src
points to opaque source for non-disk types
Definition: main.h:1040
lives_clip_type_t clip_type
Definition: main.h:886
lives_img_type_t img_type
Definition: main.h:887
int vsize
frame height (vertical) in pixels
Definition: main.h:897
int gamma_type
Definition: main.h:903
frames_t frameno
Definition: main.h:934
int hsize
frame width (horizontal) in pixels (NOT macropixels !)
Definition: main.h:896
char handle[256]
Definition: main.h:881
uint16_t blue
Definition: main.h:325
uint16_t green
Definition: main.h:324
uint16_t red
Definition: main.h:323
LiVESWidget * lockbutton
Definition: paramspecial.h:34
_vid_playback_plugin * vpp
video plugin
Definition: mainwindow.h:1572
volatile int agen_key
which fx key is generating audio [1 based] (or 0 for none)
Definition: mainwindow.h:1649
int num_tracks
Definition: mainwindow.h:1430
LiVESWidget * redo
Definition: mainwindow.h:1147
double aframeno
and the audio 'frame' for when we are looping
Definition: mainwindow.h:962
double vfade_in_secs
Definition: mainwindow.h:1813
pthread_mutex_t event_list_mutex
prevent simultaneous writing to event_list by audio and video threads
Definition: mainwindow.h:1499
char msg[MAINW_MSG_SIZE]
Definition: mainwindow.h:724
volatile ticks_t currticks
wall clock time, updated whenever lives_get_*_ticks is called
Definition: mainwindow.h:1005
double fixed_fpsd
<=0. means free playback
Definition: mainwindow.h:990
unsigned char * sl_undo_mem
Definition: mainwindow.h:812
boolean resizing
Definition: mainwindow.h:822
void * pulsed
pulseaudio player
Definition: mainwindow.h:1463
lives_clip_t * files[MAX_FILES+1]
+1 for the clipboard
Definition: mainwindow.h:729
volatile boolean record
Definition: mainwindow.h:794
weed_layer_t * transrend_layer
Definition: mainwindow.h:1810
int active_track_list[MAX_TRACKS]
Definition: mainwindow.h:1689
boolean is_rendering
Definition: mainwindow.h:821
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
boolean clip_switched
for recording - did we switch clips ?
Definition: mainwindow.h:793
boolean effects_paused
Definition: mainwindow.h:1055
lives_render_error_t(* progress_fn)(boolean reset)
Definition: mainwindow.h:1044
char * string_constants[NUM_LIVES_STRING_CONSTANTS]
Definition: mainwindow.h:1539
LiVESWidget * select_last
Definition: mainwindow.h:1162
lives_render_error_t render_error
Definition: mainwindow.h:1664
LiVESList * cliplist
hash table of clips in menu order
Definition: mainwindow.h:743
volatile boolean transrend_ready
Definition: mainwindow.h:1809
volatile lives_cancel_t cancelled
Definition: mainwindow.h:798
int current_file
Definition: mainwindow.h:727
boolean no_context_update
may be set temporarily to block wodget context updates
Definition: mainwindow.h:1726
boolean is_ready
Definition: mainwindow.h:787
lives_cancel_type_t cancel_type
Definition: mainwindow.h:799
int old_active_track_list[MAX_TRACKS]
Definition: mainwindow.h:1692
lives_colRGBA64_t vfade_in_col
Definition: mainwindow.h:1814
boolean ext_src_used[MAX_FILES]
Definition: mainwindow.h:1690
void * jackd
jack audio player / transport
Definition: mainwindow.h:1453
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
int untitled_number
Definition: mainwindow.h:738
LiVESWidget * spinbutton_pb_fps
Definition: mainwindow.h:1391
volatile boolean is_exiting
set during shutdown (inverse of only_close then)
Definition: mainwindow.h:1440
weed_plant_t * filter_map
Definition: mainwindow.h:1298
boolean fs
Definition: mainwindow.h:762
ticks_t last_display_ticks
Definition: mainwindow.h:1012
void *** pchains
Definition: mainwindow.h:1301
int pre_src_file
video file we were playing before any ext input started
Definition: mainwindow.h:971
int blend_file
background clip details
Definition: mainwindow.h:976
lives_colRGBA64_t vfade_out_col
Definition: mainwindow.h:1814
boolean error
Definition: mainwindow.h:801
boolean ext_playback
using external video playback plugin
Definition: mainwindow.h:773
weed_plant_t * audio_event
Definition: mainwindow.h:1300
frames_t play_start
Definition: mainwindow.h:931
volatile int rec_aclip
recording values - to be inserted at the following video frame
Definition: mainwindow.h:967
char * urgency_msg
OSD.
Definition: mainwindow.h:1643
volatile double rec_aseek
Definition: mainwindow.h:969
weed_event_t * stored_event_list
stored mt -> clip editor
Definition: mainwindow.h:804
double vfade_out_secs
Definition: mainwindow.h:1813
boolean unordered_blocks
are we recording unordered blocks ?
Definition: mainwindow.h:1488
int clips_available
Definition: mainwindow.h:740
boolean recording_recovered
Definition: mainwindow.h:1486
volatile boolean record_paused
pause during recording
Definition: mainwindow.h:1557
int ascrap_file
scrap file for recording audio scraps
Definition: mainwindow.h:875
lives_mt * multitrack
holds a pointer to the entire multitrack environment; NULL in Clip Edit mode
Definition: mainwindow.h:1087
xprocess * proc_ptr
Definition: mainwindow.h:1090
lives_proc_thread_t transrend_proc
Definition: mainwindow.h:1811
volatile boolean agen_needs_reinit
Definition: mainwindow.h:1650
boolean stored_event_list_changed
Definition: mainwindow.h:805
int * clip_index
Definition: mainwindow.h:1431
boolean internal_messaging
internal fx
Definition: mainwindow.h:1043
boolean is_processing
states
Definition: mainwindow.h:820
boolean preview_rendering
Definition: mainwindow.h:758
LiVESWidget * undo
Definition: mainwindow.h:1146
int first_free_file
Definition: mainwindow.h:728
weed_plant_t * afilter_map
Definition: mainwindow.h:1299
boolean mute
Definition: mainwindow.h:770
frames_t fps_measure
show fps stats after playback
Definition: mainwindow.h:778
int playing_file
which number file we are playing (or -1) [generally mainw->current_file]
Definition: mainwindow.h:943
uint32_t disk_mon
Definition: mainwindow.h:1807
ulong pb_fps_func
Definition: mainwindow.h:1063
ticks_t flush_audio_tc
reserved space for mbar
Definition: mainwindow.h:1735
lives_decoder_t * track_decoders[MAX_TRACKS]
Definition: mainwindow.h:1691
LiVESPixbuf * scrap_pixbuf
cached image for speeding up rendering
Definition: mainwindow.h:1724
weed_event_t * event_list
current event_list, for recording
Definition: mainwindow.h:803
ticks_t cevent_tc
timecode of currently processing event
Definition: mainwindow.h:1553
LiVESWidget * spinbutton_height
Definition: events.h:229
LiVESWidget * acodec_combo
Definition: events.h:226
LiVESWidget * afade_out
Definition: events.h:238
LiVESWidget * vfade_out
Definition: events.h:240
double fps
Definition: events.h:218
LiVESWidget * afade_in
Definition: events.h:237
boolean enc_changed
Definition: events.h:244
boolean is_encoding
Definition: events.h:248
ulong encoder_ofmt_fn
Definition: events.h:243
LiVESWidget * okbutton
Definition: events.h:221
LiVESWidget * debug
Definition: events.h:235
LiVESWidget * ofmt_combo
Definition: events.h:225
LiVESWidget * vfade_in
Definition: events.h:239
LiVESWidget * vfade_col
Definition: events.h:241
LiVESWidget * usecur_button
Definition: events.h:222
LiVESWidget * pertrack_checkbutton
Definition: events.h:231
LiVESWidget * norm_after
Definition: events.h:236
boolean ratio_fps
Definition: events.h:219
LiVESWidget * spinbutton_fps
Definition: events.h:230
LiVESWidget * encoder_combo
Definition: events.h:224
LiVESWidget * dialog
Definition: events.h:220
ulong encoder_name_fn
Definition: events.h:242
LiVESWidget * backaudio_checkbutton
Definition: events.h:232
LiVESWidget * always_checkbutton
Definition: events.h:233
LiVESWidget * clipname_entry
Definition: events.h:223
char * encoder_name
Definition: events.h:245
LiVESWidget * spinbutton_width
Definition: events.h:228
LiVESWidget * always_hbox
Definition: events.h:234
boolean suggestion_followed
Definition: events.h:246
this struct is used only when physically resampling frames on the disk we create an array of these an...
Definition: main.h:641
char * fname
Definition: main.h:1506
LiVESPixbuf * pixbuf
Definition: main.h:1504
lives_img_type_t img_type
Definition: main.h:1507
LiVESError * error
Definition: main.h:1505
LiVESWidget * last_container
container which wraps last widget created + subwidgets (READONLY)
boolean swap_label
swap label/widget position
LiVESJustification justify
justify for labels
boolean non_modal
non-modal for dialogs
int packing_height
vertical pixels between widgets
lives_expand_t expand
how much space to apply between widgets
int packing_width
horizontal pixels between widgets
boolean use_markup
whether markup should be used in labels
int border_width
border width in pixels
int apply_theme
theming variation for widget (0 -> no theme, 1 -> normal colours, 2+ -> theme variants)
LiVESWidget * processing
Definition: mainwindow.h:706
LiVESWidget * label
Definition: mainwindow.h:708
#define lives_strdup_printf(fmt,...)
Definition: support.c:27
#define _(String)
Definition: support.h:44
#define TRUE
Definition: videoplugin.h:59
#define FALSE
Definition: videoplugin.h:60
WEED_GLOBAL_INLINE weed_plant_t * weed_param_get_template(weed_plant_t *param)
WEED_GLOBAL_INLINE int weed_filter_is_process_last(weed_plant_t *filter)
WEED_GLOBAL_INLINE weed_plant_t ** weed_instance_get_in_params(weed_plant_t *instance, int *nparams)
#define WEED_PLANT_IS_FILTER_INSTANCE(plant)
boolean lives_combo_populate(LiVESCombo *combo, LiVESList *list)
WIDGET_HELPER_GLOBAL_INLINE LiVESWidget * lives_layout_new(LiVESBox *box)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_set_maximum_size(LiVESWidget *widget, int width, int height)
WIDGET_HELPER_GLOBAL_INLINE int lives_widget_get_allocation_width(LiVESWidget *widget)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_spin_button_set_value(LiVESSpinButton *button, double value)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_set_bg_color(LiVESWidget *widget, LiVESWidgetState state, const LiVESWidgetColor *color)
boolean lives_window_center(LiVESWindow *window)
WIDGET_HELPER_GLOBAL_INLINE LiVESWidget * lives_vbox_new(boolean homogeneous, int spacing)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_is_sensitive(LiVESWidget *widget)
WIDGET_HELPER_GLOBAL_INLINE LiVESWidget * lives_layout_hbox_new(LiVESLayout *layout)
WIDGET_HELPER_GLOBAL_INLINE LiVESAccelGroup * lives_accel_group_new(void)
LiVESWidget * lives_standard_entry_new(const char *labeltext, const char *txt, int dispwidth, int maxchars, LiVESBox *box, const char *tooltip)
boolean lives_button_grab_default_special(LiVESWidget *button)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_spin_button_update(LiVESSpinButton *button)
WIDGET_HELPER_GLOBAL_INLINE const char * lives_label_get_text(LiVESLabel *label)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_scrolled_window_set_min_content_width(LiVESScrolledWindow *scrolledwindow, int width)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_toggle_button_get_active(LiVESToggleButton *button)
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)
WIDGET_HELPER_GLOBAL_INLINE LiVESResponseType lives_dialog_run(LiVESDialog *dialog)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_box_pack_start(LiVESBox *box, LiVESWidget *child, boolean expand, boolean fill, uint32_t padding)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_set_text_color(LiVESWidget *widget, LiVESWidgetState state, const LiVESWidgetColor *color)
LiVESWidget * lives_standard_expander_new(const char *ltext, LiVESBox *box, LiVESWidget *child)
LiVESWidget * lives_standard_dialog_new(const char *title, boolean add_std_buttons, int width, int height)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_signal_handler_unblock(livespointer instance, unsigned long handler_id)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_queue_draw(LiVESWidget *widget)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_set_fg_color(LiVESWidget *widget, LiVESWidgetState state, const LiVESWidgetColor *color)
WIDGET_HELPER_GLOBAL_INLINE const char * lives_entry_get_text(LiVESEntry *entry)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_set_sensitive(LiVESWidget *widget, boolean state)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_table_resize(LiVESTable *table, uint32_t rows, uint32_t cols)
WIDGET_HELPER_GLOBAL_INLINE LiVESWidget * lives_table_new(uint32_t rows, uint32_t cols, boolean homogeneous)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_label_set_text(LiVESLabel *label, const char *text)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_signal_handler_block(livespointer instance, unsigned long handler_id)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_button_box_make_first(LiVESButtonBox *bbox, LiVESWidget *widget)
WIDGET_HELPER_GLOBAL_INLINE LiVESWidget * lives_layout_row_new(LiVESLayout *layout)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_object_unref(livespointer object)
decrease refcount by one: if refcount==0, object is destroyed
WIDGET_HELPER_GLOBAL_INLINE boolean lives_combo_set_active_string(LiVESCombo *combo, const char *active_str)
WIDGET_HELPER_GLOBAL_INLINE LiVESTreeStore * lives_tree_store_new(int ncols,...)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_queue_resize(LiVESWidget *widget)
WIDGET_HELPER_GLOBAL_INLINE LiVESWidget * lives_dialog_get_content_area(LiVESDialog *dialog)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_container_set_border_width(LiVESContainer *container, uint32_t width)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_set_halign(LiVESWidget *widget, LiVESAlign align)
WIDGET_HELPER_GLOBAL_INLINE LiVESCellRenderer * lives_cell_renderer_text_new(void)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_tree_store_set(LiVESTreeStore *tstore, LiVESTreeIter *titer,...)
WIDGET_HELPER_GLOBAL_INLINE LiVESWidget * lives_check_button_new(void)
LiVESWidget * add_hsep_to_box(LiVESBox *box)
LiVESWidget * add_fill_to_box(LiVESBox *box)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_set_base_color(LiVESWidget *widget, LiVESWidgetState state, const LiVESWidgetColor *color)
WIDGET_HELPER_GLOBAL_INLINE int lives_spin_button_get_value_as_int(LiVESSpinButton *button)
WIDGET_HELPER_GLOBAL_INLINE int lives_tree_view_append_column(LiVESTreeView *tview, LiVESTreeViewColumn *tvcol)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_lock_button_get_locked(LiVESButton *button)
LIVES_GLOBAL_INLINE boolean lives_widget_destroy(LiVESWidget *widget)
LiVESWidget * lives_standard_scrolled_window_new(int width, int height, LiVESWidget *child)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_scrolled_window_set_min_content_height(LiVESScrolledWindow *scrolledwindow, int height)
LiVESWidget * lives_dialog_add_button_from_stock(LiVESDialog *dialog, const char *stock_id, const char *label, int response_id)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_window_unmaximize(LiVESWindow *window)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_container_add(LiVESContainer *container, LiVESWidget *widget)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_button_box_set_layout(LiVESButtonBox *bbox, LiVESButtonBoxStyle bstyle)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_set_no_show_all(LiVESWidget *widget, boolean set)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_toggle_button_set_active(LiVESToggleButton *button, boolean active)
WIDGET_HELPER_GLOBAL_INLINE double lives_spin_button_get_value(LiVESSpinButton *button)
WIDGET_HELPER_GLOBAL_INLINE LiVESWidget * lives_bin_get_child(LiVESBin *bin)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_window_set_resizable(LiVESWindow *window, boolean resizable)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_show_all(LiVESWidget *widget)
LiVESWidget * lives_standard_frame_new(const char *labeltext, float xalign, boolean invis)
boolean lives_widget_context_update(void)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_spin_button_set_snap_to_multiples(LiVESSpinButton *button, double mult)
WIDGET_HELPER_GLOBAL_INLINE boolean toggle_sets_sensitive(LiVESToggleButton *tb, LiVESWidget *widget, boolean invert)
set callbacks
WIDGET_HELPER_GLOBAL_INLINE LiVESWidget * lives_hbox_new(boolean homogeneous, int spacing)
LiVESWidget * lives_standard_label_new(const char *text)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_entry_set_text(LiVESEntry *entry, const char *text)
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)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_set_valign(LiVESWidget *widget, LiVESAlign align)
LiVESWidget * add_spring_to_box(LiVESBox *box, int min)
boolean lives_lock_button_toggle(LiVESButton *button)
WIDGET_HELPER_GLOBAL_INLINE int lives_widget_get_allocation_height(LiVESWidget *widget)
WIDGET_HELPER_GLOBAL_INLINE LiVESWidget * lives_dialog_get_action_area(LiVESDialog *dialog)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_set_size_request(LiVESWidget *widget, int width, int height)
LiVESWidget * lives_standard_check_button_new(const char *labeltext, boolean active, LiVESBox *box, const char *tooltip)
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)
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)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_window_maximize(LiVESWindow *window)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_process_updates(LiVESWidget *widget)
WIDGET_HELPER_GLOBAL_INLINE LiVESWidget * lives_tree_view_new_with_model(LiVESTreeModel *tmod)
LiVESWidget * lives_standard_combo_new(const char *labeltext, LiVESList *list, LiVESBox *box, const char *tooltip)
WIDGET_HELPER_GLOBAL_INLINE LiVESTreeViewColumn * lives_tree_view_column_new_with_attributes(const char *title, LiVESCellRenderer *crend,...)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_tree_store_append(LiVESTreeStore *tstore, LiVESTreeIter *titer, LiVESTreeIter *parent)
void lives_general_button_clicked(LiVESButton *button, livespointer data_to_free)
LiVESWidget * lives_standard_radio_button_new(const char *labeltext, LiVESSList **rbgroup, LiVESBox *box, const char *tooltip)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_window_add_accel_group(LiVESWindow *window, LiVESAccelGroup *group)
#define LIVES_EXPAND_DEFAULT_HEIGHT
#define LIVES_EXPAND_NONE
#define LIVES_EXPAND_EXTRA_WIDTH
#define LIVES_EXPAND_DEFAULT
widget_opts_t widget_opts
#define MEDIUM_ENTRY_WIDTH
Definition: widget-helper.h:31
#define LIVES_JUSTIFY_DEFAULT