fix for filebox apply btn on resize
[goodguy/cinelerra.git] / cinelerra-5.1 / cinelerra / edit.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21
22 #include "asset.h"
23 #include "assets.h"
24 #include "bcsignals.h"
25 #include "clip.h"
26 #include "edit.h"
27 #include "edits.h"
28 #include "edl.h"
29 #include "edlsession.h"
30 #include "filexml.h"
31 #include "filesystem.h"
32 #include "localsession.h"
33 #include "plugin.h"
34 #include "mainsession.h"
35 #include "strack.h"
36 #include "trackcanvas.h"
37 #include "tracks.h"
38 #include "transition.h"
39 #include <string.h>
40
41
42 Edit::Edit()
43 {
44         reset();
45 }
46
47 Edit::Edit(EDL *edl, Track *track)
48 {
49         reset();
50         this->edl = edl;
51         this->track = track;
52         if(track) this->edits = track->edits;
53         id = EDL::next_id();
54 }
55
56 Edit::Edit(EDL *edl, Edits *edits)
57 {
58         reset();
59         this->edl = edl;
60         this->edits = edits;
61         if(edits) this->track = edits->track;
62         id = EDL::next_id();
63 }
64
65 Edit::~Edit()
66 {
67 //printf("Edit::~Edit 1\n");
68         if(transition) delete transition;
69 //printf("Edit::~Edit 2\n");
70 }
71
72 void Edit::reset()
73 {
74         edl = 0;
75         track = 0;
76         edits = 0;
77         startsource = 0;
78         startproject = 0;
79         length = 0;
80         asset = 0;
81         transition = 0;
82         channel = 0;
83         user_title[0] = 0;
84         nested_edl = 0;
85         is_plugin = 0;
86         is_selected = 0;
87         hard_left = 0;
88         hard_right = 0;
89         color = 0;
90         group_id = 0;
91 }
92
93 Indexable* Edit::get_source()
94 {
95         if(asset) return asset;
96         if(nested_edl) return nested_edl;
97         return 0;
98 }
99
100 int Edit::copy(int64_t start,
101         int64_t end,
102         FileXML *file,
103         const char *output_path)
104 {
105 // variables
106 //printf("Edit::copy 1\n");
107
108         int64_t endproject = startproject + length;
109         int result;
110
111         if((startproject >= start && startproject <= end) ||  // startproject in range
112                  (endproject <= end && endproject >= start) ||     // endproject in range
113                  (startproject <= start && endproject >= end))    // range in project
114         {
115 // edit is in range
116                 int64_t startproject_in_selection = startproject; // start of edit in selection in project
117                 int64_t startsource_in_selection = startsource; // start of source in selection in source
118                 //int64_t endsource_in_selection = startsource + length; // end of source in selection
119                 int64_t length_in_selection = length;             // length of edit in selection
120 //printf("Edit::copy 2\n");
121
122                 if(startproject < start)
123                 {         // start is after start of edit in project
124                         int64_t length_difference = start - startproject;
125
126                         startsource_in_selection += length_difference;
127                         startproject_in_selection += length_difference;
128                         length_in_selection -= length_difference;
129                 }
130 //printf("Edit::copy 3\n");
131
132                 if(endproject > end)
133                 {         // end is before end of edit in project
134                         length_in_selection = end - startproject_in_selection;
135                 }
136
137 //printf("Edit::copy 4\n");
138                 if(file)    // only if not counting
139                 {
140                         file->tag.set_title("EDIT");
141                         file->tag.set_property("STARTSOURCE", startsource_in_selection);
142                         file->tag.set_property("CHANNEL", (int64_t)channel);
143                         file->tag.set_property("LENGTH", length_in_selection);
144                         file->tag.set_property("HARD_LEFT", hard_left);
145                         file->tag.set_property("HARD_RIGHT", hard_right);
146                         file->tag.set_property("COLOR", color);
147                         file->tag.set_property("GROUP_ID", group_id);
148                         if(user_title[0]) file->tag.set_property("USER_TITLE", user_title);
149 //printf("Edit::copy 5\n");
150
151                         copy_properties_derived(file, length_in_selection);
152
153                         file->append_tag();
154 //                      file->append_newline();
155 //printf("Edit::copy 6\n");
156
157                         if(nested_edl)
158                         {
159                                 file->tag.set_title("NESTED_EDL");
160                                 file->tag.set_property("SRC", nested_edl->path);
161                                 file->append_tag();
162                                 file->tag.set_title("/NESTED_EDL");
163                                 file->append_tag();
164                                 file->append_newline();
165                         }
166
167                         if(asset)
168                         {
169 //printf("Edit::copy 6 %s\n", asset->path);
170                                 char stored_path[BCTEXTLEN];
171                                 char asset_directory[BCTEXTLEN];
172                                 char output_directory[BCTEXTLEN];
173                                 FileSystem fs;
174
175 //printf("Edit::copy %d %s\n", __LINE__, asset->path);
176                                 fs.extract_dir(asset_directory, asset->path);
177 //printf("Edit::copy %d %s\n", __LINE__, asset->path);
178
179                                 if(output_path)
180                                         fs.extract_dir(output_directory, output_path);
181                                 else
182                                         output_directory[0] = 0;
183 //printf("Edit::copy %s, %s %s, %s\n", asset->path, asset_directory, output_path, output_directory);
184
185                                 if(output_path && !strcmp(asset_directory, output_directory))
186                                         fs.extract_name(stored_path, asset->path);
187                                 else
188                                         strcpy(stored_path, asset->path);
189
190                                 file->tag.set_title("FILE");
191                                 file->tag.set_property("SRC", stored_path);
192                                 file->append_tag();
193                                 file->tag.set_title("/FILE");
194                                 file->append_tag();
195                         }
196
197                         if(transition && startsource_in_selection == startsource)
198                         {
199                                 transition->save_xml(file);
200                         }
201
202 //printf("Edit::copy 7\n");
203                         file->tag.set_title("/EDIT");
204                         file->append_tag();
205                         file->append_newline();
206 //printf("Edit::copy 8\n");
207                 }
208 //printf("Edit::copy 9\n");
209                 result = 1;
210         }
211         else
212         {
213                 result = 0;
214         }
215 //printf("Edit::copy 10\n");
216         return result;
217 }
218
219
220 int64_t Edit::get_source_end(int64_t default_)
221 {
222         return default_;
223 }
224
225 void Edit::insert_transition(char *title)
226 {
227 //printf("Edit::insert_transition this=%p title=%p title=%s\n", this, title, title);
228         delete transition;
229         transition = new Transition(edl, this, title,
230                 track->to_units(edl->session->default_transition_length, 1));
231 }
232
233 void Edit::detach_transition()
234 {
235         if(transition) delete transition;
236         transition = 0;
237 }
238
239 int Edit::silence()
240 {
241         return (track->data_type != TRACK_SUBTITLE ?
242                 asset || nested_edl :
243                 *((SEdit *)this)->get_text()) ? 0 : 1;
244 }
245 void Edit::mute()
246 {
247         if( track->data_type != TRACK_SUBTITLE ) {
248                 asset = 0;
249                 nested_edl = 0;
250         }
251         else
252                 *((SEdit *)this)->get_text() = 0;
253 }
254
255 void Edit::copy_from(Edit *edit)
256 {
257         this->nested_edl = edl->nested_edls.get_nested(edit->nested_edl);
258         this->asset = edl->assets->update(edit->asset);
259         this->startsource = edit->startsource;
260         this->startproject = edit->startproject;
261         this->length = edit->length;
262         this->hard_left = edit->hard_left;
263         this->hard_right = edit->hard_right;
264         this->color = edit->color;
265         this->group_id = edit->group_id;
266         strcpy (this->user_title, edit->user_title);
267
268         if(edit->transition)
269         {
270                 if(!transition) transition = new Transition(edl,
271                         this,
272                         edit->transition->title,
273                         edit->transition->length);
274                 *this->transition = *edit->transition;
275         }
276         this->channel = edit->channel;
277 }
278
279 void Edit::equivalent_output(Edit *edit, int64_t *result)
280 {
281 // End of edit changed
282         if(startproject + length != edit->startproject + edit->length)
283         {
284                 int64_t new_length = MIN(startproject + length,
285                         edit->startproject + edit->length);
286                 if(*result < 0 || new_length < *result)
287                         *result = new_length;
288         }
289
290         if(
291 // Different nested EDLs
292                 (edit->nested_edl && !nested_edl) ||
293                 (!edit->nested_edl && nested_edl) ||
294 // Different assets
295                 (edit->asset == 0 && asset != 0) ||
296                 (edit->asset != 0 && asset == 0) ||
297 // different transitions
298                 (edit->transition == 0 && transition != 0) ||
299                 (edit->transition != 0 && transition == 0) ||
300 // Position changed
301                 (startproject != edit->startproject) ||
302                 (startsource != edit->startsource) ||
303 // Transition changed
304                 (transition && edit->transition &&
305                         !transition->identical(edit->transition)) ||
306 // Asset changed
307                 (asset && edit->asset &&
308                         !asset->equivalent(*edit->asset, 1, 1, edl)) ||
309 // Nested EDL changed
310                 (nested_edl && edit->nested_edl &&
311                         strcmp(nested_edl->path, edit->nested_edl->path))
312                 )
313         {
314 // Start of edit changed
315                 if(*result < 0 || startproject < *result) *result = startproject;
316         }
317 }
318
319
320 Edit& Edit::operator=(Edit& edit)
321 {
322 //printf("Edit::operator= called\n");
323         copy_from(&edit);
324         return *this;
325 }
326
327 void Edit::synchronize_params(Edit *edit)
328 {
329         copy_from(edit);
330 }
331
332
333 // Comparison for ResourcePixmap drawing
334 int Edit::identical(Edit &edit)
335 {
336         int result = (this->nested_edl == edit.nested_edl &&
337                 this->asset == edit.asset &&
338                 this->startsource == edit.startsource &&
339                 this->startproject == edit.startproject &&
340                 this->length == edit.length &&
341                 this->transition == edit.transition &&
342                 this->channel == edit.channel);
343         return result;
344 }
345
346 int Edit::operator==(Edit &edit)
347 {
348         return identical(edit);
349 }
350
351 double Edit::frames_per_picon()
352 {
353         return Units::round(picon_w()) / frame_w();
354 }
355
356 double Edit::frame_w()
357 {
358         return track->from_units(1) *
359                 edl->session->sample_rate /
360                 edl->local_session->zoom_sample;
361 }
362
363 double Edit::picon_w()
364 {
365         int w = 0, h = 0;
366         if(asset) {
367                 w = asset->width;
368                 h = asset->height;
369         }
370         else if(nested_edl) {
371                 w = nested_edl->session->output_w;
372                 h = nested_edl->session->output_h;
373         }
374         return w>0 && h>0 ? ((double)edl->local_session->zoom_track*w)/h : 0;
375 }
376
377 int Edit::picon_h()
378 {
379         return edl->local_session->zoom_track;
380 }
381
382
383 int Edit::dump(FILE *fp)
384 {
385         fprintf(fp,"     EDIT %p\n", this); fflush(fp);
386         fprintf(fp,"      nested_edl=%p %s asset=%p %s\n",
387                 nested_edl,
388                 nested_edl ? nested_edl->path : "",
389                 asset,
390                 asset ? asset->path : "");
391         fflush(fp);
392         fprintf(fp,"      channel %d, color %08x, group_id %d, is_selected %d\n",
393                 channel, color, group_id, is_selected);
394         if(transition)
395         {
396                 fprintf(fp,"      TRANSITION %p\n", transition);
397                 transition->dump(fp);
398         }
399         fprintf(fp,"      startsource %jd startproject %jd hard lt/rt %d/%d length %jd\n",
400                 startsource, startproject, hard_left, hard_right, length); fflush(fp);
401         return 0;
402 }
403
404 int Edit::load_properties(FileXML *file, int64_t &startproject)
405 {
406         startsource = file->tag.get_property("STARTSOURCE", (int64_t)0);
407         length = file->tag.get_property("LENGTH", (int64_t)0);
408         hard_left = file->tag.get_property("HARD_LEFT", (int64_t)0);
409         hard_right = file->tag.get_property("HARD_RIGHT", (int64_t)0);
410         color = file->tag.get_property("COLOR", 0);
411         group_id = file->tag.get_property("GROUP_ID", group_id);
412         user_title[0] = 0;
413         file->tag.get_property("USER_TITLE", user_title);
414         this->startproject = startproject;
415         load_properties_derived(file);
416         return 0;
417 }
418
419 void Edit::shift(int64_t difference)
420 {
421 //printf("Edit::shift 1 %p %jd %jd\n", this, startproject, difference);
422         startproject += difference;
423 //printf("Edit::shift 2 %jd %jd\n", startproject, difference);
424 }
425
426 int Edit::shift_start_in(int edit_mode,
427         int64_t newposition,
428         int64_t oldposition,
429         int edit_edits,
430         int edit_labels,
431         int edit_plugins,
432         int edit_autos,
433         Edits *trim_edits)
434 {
435         int64_t cut_length = newposition - oldposition;
436         int64_t end_previous_source, end_source;
437
438         if(edit_mode == MOVE_ALL_EDITS)
439         {
440                 if(cut_length < length)
441                 {        // clear partial
442                         edits->clear_recursive(oldposition,
443                                 newposition,
444                                 edit_edits,
445                                 edit_labels,
446                                 edit_plugins,
447                                 edit_autos,
448                                 trim_edits);
449                 }
450                 else
451                 {        // clear entire
452                         edits->clear_recursive(oldposition,
453                                 startproject + length,
454                                 edit_edits,
455                                 edit_labels,
456                                 edit_plugins,
457                                 edit_autos,
458                                 trim_edits);
459                 }
460         }
461         else
462         if(edit_mode == MOVE_ONE_EDIT)
463         {
464 // Paste silence and cut
465 //printf("Edit::shift_start_in 1\n");
466                 if(!previous)
467                 {
468                         Edit *new_edit = edits->create_edit();
469                         new_edit->startproject = this->startproject;
470                         new_edit->length = 0;
471                         edits->insert_before(this,
472                                 new_edit);
473                 }
474 //printf("Edit::shift_start_in 2 %p\n", previous);
475
476                 end_previous_source = previous->get_source_end(previous->startsource + previous->length + cut_length);
477                 if(end_previous_source > 0 &&
478                         previous->startsource + previous->length + cut_length > end_previous_source)
479                         cut_length = end_previous_source - previous->startsource - previous->length;
480
481                 if(cut_length < length)
482                 {               // Move in partial
483                         startproject += cut_length;
484                         startsource += cut_length;
485                         length -= cut_length;
486                         previous->length += cut_length;
487 //printf("Edit::shift_start_in 2\n");
488                 }
489                 else
490                 {               // Clear entire edit
491                         cut_length = length;
492                         previous->length += cut_length;
493                         for(Edit* current_edit = this; current_edit; current_edit = current_edit->next)
494                         {
495                                 current_edit->startproject += cut_length;
496                         }
497                         edits->clear_recursive(oldposition + cut_length,
498                                 startproject + cut_length,
499                                 edit_edits,
500                                 edit_labels,
501                                 edit_plugins,
502                                 edit_autos,
503                                 trim_edits);
504                 }
505 //printf("Edit::shift_start_in 3\n");
506         }
507         else
508         if(edit_mode == MOVE_NO_EDITS)
509         {
510                 end_source = get_source_end(startsource + length + cut_length);
511                 if(end_source > 0 && startsource + length + cut_length > end_source)
512                         cut_length = end_source - startsource - length;
513
514                 startsource += cut_length;
515         }
516         return 0;
517 }
518
519 int Edit::shift_start_out(int edit_mode,
520         int64_t newposition,
521         int64_t oldposition,
522         int edit_edits,
523         int edit_labels,
524         int edit_plugins,
525         int edit_autos,
526         Edits *trim_edits)
527 {
528         int64_t cut_length = oldposition - newposition;
529
530
531         if(asset || nested_edl)
532         {
533                 int64_t end_source = get_source_end(1);
534
535 //printf("Edit::shift_start_out 1 %jd %jd\n", startsource, cut_length);
536                 if(end_source > 0 && startsource < cut_length)
537                 {
538                         cut_length = startsource;
539                 }
540         }
541
542         if(edit_mode == MOVE_ALL_EDITS)
543         {
544 //printf("Edit::shift_start_out 10 %jd\n", cut_length);
545                 startsource -= cut_length;
546                 length += cut_length;
547
548                 if(edit_autos)
549                         edits->shift_keyframes_recursive(startproject,
550                                 cut_length);
551                 if(edit_plugins)
552                         edits->shift_effects_recursive(startproject,
553                                 cut_length,
554                                 edit_autos);
555
556                 for(Edit* current_edit = next; current_edit; current_edit = current_edit->next)
557                 {
558                         current_edit->startproject += cut_length;
559                 }
560         }
561         else
562         if(edit_mode == MOVE_ONE_EDIT)
563         {
564                 if(previous)
565                 {
566                         if(cut_length < previous->length)
567                         {   // Cut into previous edit
568                                 previous->length -= cut_length;
569                                 startproject -= cut_length;
570                                 startsource -= cut_length;
571                                 length += cut_length;
572                         }
573                         else
574                         {   // Clear entire previous edit
575                                 cut_length = previous->length;
576                                 previous->length = 0;
577                                 length += cut_length;
578                                 startsource -= cut_length;
579                                 startproject -= cut_length;
580                         }
581                 }
582         }
583         else
584         if(edit_mode == MOVE_NO_EDITS)
585         {
586                 startsource -= cut_length;
587         }
588
589 // Fix infinite length files
590         if(startsource < 0) startsource = 0;
591         return 0;
592 }
593
594 int Edit::shift_end_in(int edit_mode,
595         int64_t newposition,
596         int64_t oldposition,
597         int edit_edits,
598         int edit_labels,
599         int edit_plugins,
600         int edit_autos,
601         Edits *trim_edits)
602 {
603         int64_t cut_length = oldposition - newposition;
604
605         if(edit_mode == MOVE_ALL_EDITS)
606         {
607 //printf("Edit::shift_end_in 1\n");
608                 if(newposition > startproject)
609                 {        // clear partial edit
610 //printf("Edit::shift_end_in %p %p\n", track->edits, edits);
611                         edits->clear_recursive(newposition,
612                                 oldposition,
613                                 edit_edits,
614                                 edit_labels,
615                                 edit_plugins,
616                                 edit_autos,
617                                 trim_edits);
618                 }
619                 else
620                 {        // clear entire edit
621                         edits->clear_recursive(startproject,
622                                 oldposition,
623                                 edit_edits,
624                                 edit_labels,
625                                 edit_plugins,
626                                 edit_autos,
627                                 trim_edits);
628                 }
629         }
630         else
631         if(edit_mode == MOVE_ONE_EDIT)
632         {
633                 if(next)
634                 {
635                         if(next->asset)
636                         {
637                                 int64_t end_source = next->get_source_end(1);
638
639                                 if(end_source > 0 && next->startsource - cut_length < 0)
640                                 {
641                                         cut_length = next->startsource;
642                                 }
643                         }
644
645                         if(cut_length < length)
646                         {
647                                 length -= cut_length;
648                                 next->startproject -= cut_length;
649                                 next->startsource -= cut_length;
650                                 next->length += cut_length;
651 //printf("Edit::shift_end_in 2 %d\n", cut_length);
652                         }
653                         else
654                         {
655                                 cut_length = length;
656                                 next->length += cut_length;
657                                 next->startsource -= cut_length;
658                                 next->startproject -= cut_length;
659                                 length -= cut_length;
660                         }
661                 }
662                 else
663                 {
664                         if(cut_length < length)
665                         {
666                                 length -= cut_length;
667                         }
668                         else
669                         {
670                                 cut_length = length;
671                                 edits->clear_recursive(startproject,
672                                         oldposition,
673                                         edit_edits,
674                                         edit_labels,
675                                         edit_plugins,
676                                         edit_autos,
677                                         trim_edits);
678                         }
679                 }
680         }
681         else
682 // Does nothing for plugins
683         if(edit_mode == MOVE_NO_EDITS)
684         {
685 //printf("Edit::shift_end_in 3\n");
686                 int64_t end_source = get_source_end(1);
687                 if(end_source > 0 && startsource < cut_length)
688                 {
689                         cut_length = startsource;
690                 }
691                 startsource -= cut_length;
692         }
693         return 0;
694 }
695
696 int Edit::shift_end_out(int edit_mode,
697         int64_t newposition,
698         int64_t oldposition,
699         int edit_edits,
700         int edit_labels,
701         int edit_plugins,
702         int edit_autos,
703         Edits *trim_edits)
704 {
705         int64_t cut_length = newposition - oldposition;
706         int64_t endsource = get_source_end(startsource + length + cut_length);
707
708 // check end of edit against end of source file
709         if(endsource > 0 && startsource + length + cut_length > endsource)
710                 cut_length = endsource - startsource - length;
711
712 //printf("Edit::shift_end_out 1 %jd %d %d %d\n", oldposition, newposition, this->length, cut_length);
713         if(edit_mode == MOVE_ALL_EDITS)
714         {
715 // Extend length
716                 this->length += cut_length;
717
718 // Effects are shifted in length extension
719                 if(edit_plugins)
720                         edits->shift_effects_recursive(oldposition /* startproject */,
721                                 cut_length,
722                                 edit_autos);
723                 if(edit_autos)
724                         edits->shift_keyframes_recursive(oldposition /* startproject */,
725                                 cut_length);
726
727                 for(Edit* current_edit = next; current_edit; current_edit = current_edit->next)
728                 {
729                         current_edit->startproject += cut_length;
730                 }
731         }
732         else
733         if(edit_mode == MOVE_ONE_EDIT)
734         {
735                 if(next)
736                 {
737                         if(cut_length < next->length)
738                         {
739                                 length += cut_length;
740                                 next->startproject += cut_length;
741                                 next->startsource += cut_length;
742                                 next->length -= cut_length;
743 //printf("Edit::shift_end_out %d cut_length=%d\n", __LINE__, cut_length);
744                         }
745                         else
746                         {
747 //printf("Edit::shift_end_out %d cut_length=%d next->length=%d\n", __LINE__, cut_length, next->length);
748                                 cut_length = next->length;
749                                 next->startproject += next->length;
750                                 next->startsource += next->length;
751                                 next->length = 0;
752                                 length += cut_length;
753 //track->dump();
754                         }
755                 }
756                 else
757                 {
758                         length += cut_length;
759                 }
760         }
761         else
762         if(edit_mode == MOVE_NO_EDITS)
763         {
764                 startsource += cut_length;
765         }
766         return 0;
767 }
768
769 int Edit::popup_transition(float view_start, float zoom_units, int cursor_x, int cursor_y)
770 {
771         int64_t left, right, left_unit, right_unit;
772         if(!transition) return 0;
773         get_handle_parameters(left, right, left_unit, right_unit, view_start, zoom_units);
774
775         if(cursor_x > left && cursor_x < right)
776         {
777 //              transition->popup_transition(cursor_x, cursor_y);
778                 return 1;
779         }
780         return 0;
781 }
782
783 int Edit::select_handle(float view_start, float zoom_units, int cursor_x, int cursor_y, int64_t &selection)
784 {
785         int64_t left, right, left_unit, right_unit;
786         get_handle_parameters(left, right, left_unit, right_unit, view_start, zoom_units);
787
788         int64_t pixel1, pixel2;
789         pixel1 = left;
790         pixel2 = pixel1 + 10;
791
792 // test left edit
793 // cursor_x is faked in acanvas
794         if(cursor_x >= pixel1 && cursor_x <= pixel2)
795         {
796                 selection = left_unit;
797                 return 1;     // left handle
798         }
799
800         //int64_t endproject = startproject + length;
801         pixel2 = right;
802         pixel1 = pixel2 - 10;
803
804 // test right edit
805         if(cursor_x >= pixel1 && cursor_x <= pixel2)
806         {
807                 selection = right_unit;
808                 return 2;     // right handle
809         }
810         return 0;
811 }
812
813 void Edit::get_title(char *title)
814 {
815         if( user_title[0] ) {
816                 strcpy(title, user_title);
817                 return;
818         }
819         Indexable *idxbl = asset ? (Indexable*)asset : (Indexable*)nested_edl;
820         if( !idxbl ) {
821                 title[0] = 0;
822                 return;
823         }
824         FileSystem fs;
825         fs.extract_name(title, idxbl->path);
826         if( asset || track->data_type == TRACK_AUDIO ) {
827                 char number[BCSTRLEN];
828                 sprintf(number, " #%d", channel + 1);
829                 strcat(title, number);
830         }
831 }
832