00001 #include "aedit.h"
00002 #include "asset.h"
00003 #include "assets.h"
00004 #include "automation.h"
00005 #include "cache.h"
00006 #include "clip.h"
00007 #include "edit.h"
00008 #include "edits.h"
00009 #include "edl.h"
00010 #include "edlsession.h"
00011 #include "file.h"
00012 #include "filexml.h"
00013 #include "filesystem.h"
00014 #include "localsession.h"
00015 #include "plugin.h"
00016 #include "strategies.inc"
00017 #include "track.h"
00018 #include "transition.h"
00019 #include "transportque.inc"
00020
00021 #include <string.h>
00022
00023 Edits::Edits(EDL *edl, Track *track)
00024 : List<Edit>()
00025 {
00026 this->edl = edl;
00027 this->track = track;
00028 }
00029
00030 Edits::~Edits()
00031 {
00032 }
00033
00034
00035 void Edits::equivalent_output(Edits *edits, int64_t *result)
00036 {
00037
00038
00039
00040 for(Edit *current = first, *that_current = edits->first;
00041 current || that_current;
00042 current = NEXT,
00043 that_current = that_current->next)
00044 {
00045
00046 if(!current && that_current)
00047 {
00048 int64_t position1 = (last ? last->startproject + last->length : 0);
00049 int64_t position2 = that_current->startproject;
00050 if(*result < 0 || *result > MIN(position1, position2))
00051 *result = MIN(position1, position2);
00052 break;
00053 }
00054 else
00055 if(current && !that_current)
00056 {
00057 int64_t position1 = (edits->last ? edits->last->startproject + edits->last->length : 0);
00058 int64_t position2 = current->startproject;
00059 if(*result < 0 || *result > MIN(position1, position2))
00060 *result = MIN(position1, position2);
00061 break;
00062 }
00063 else
00064 {
00065
00066 current->equivalent_output(that_current, result);
00067
00068 }
00069 }
00070 }
00071
00072 void Edits::copy_from(Edits *edits)
00073 {
00074 while(last) delete last;
00075 for(Edit *current = edits->first; current; current = NEXT)
00076 {
00077 Edit *new_edit = append(create_edit());
00078 new_edit->copy_from(current);
00079 }
00080 }
00081
00082
00083 Edits& Edits::operator=(Edits& edits)
00084 {
00085 printf("Edits::operator= 1\n");
00086 copy_from(&edits);
00087 return *this;
00088 }
00089
00090
00091 void Edits::insert_asset(Asset *asset,
00092 int64_t length,
00093 int64_t position,
00094 int track_number)
00095 {
00096 Edit *new_edit = insert_new_edit(position);
00097
00098 new_edit->asset = asset;
00099 new_edit->startsource = 0;
00100 new_edit->startproject = position;
00101 new_edit->length = length;
00102
00103 if(asset->audio_data)
00104 new_edit->channel = track_number % asset->channels;
00105 else
00106 if(asset->video_data)
00107 new_edit->channel = track_number % asset->layers;
00108
00109
00110 for(Edit *current = new_edit->next; current; current = NEXT)
00111 {
00112 current->startproject += length;
00113 }
00114 }
00115
00116 void Edits::insert_edits(Edits *source_edits, int64_t position)
00117 {
00118 int64_t clipboard_length =
00119 track->to_units(source_edits->edl->local_session->clipboard_length, 1);
00120 int64_t clipboard_end = position + clipboard_length;
00121
00122
00123
00124
00125 if(position > length())
00126 {
00127 paste_silence(length(), position);
00128 }
00129
00130
00131 for(Edit *source_edit = source_edits->first;
00132 source_edit;
00133 source_edit = source_edit->next)
00134 {
00135
00136 Asset *dest_asset = edl->assets->update(source_edit->asset);
00137
00138 Edit *dest_edit = insert_new_edit(position + source_edit->startproject);
00139
00140 dest_edit->copy_from(source_edit);
00141 dest_edit->asset = dest_asset;
00142 dest_edit->startproject = position + source_edit->startproject;
00143
00144
00145
00146
00147
00148 dest_edit->shift_keyframes(position);
00149
00150
00151
00152
00153
00154 for(Edit *future_edit = dest_edit->next;
00155 future_edit;
00156 future_edit = future_edit->next)
00157 {
00158 future_edit->startproject += dest_edit->length;
00159 future_edit->shift_keyframes(dest_edit->length);
00160 }
00161
00162
00163 if(!source_edit->next &&
00164 dest_edit->startproject + dest_edit->length < clipboard_end)
00165 {
00166 paste_silence(dest_edit->startproject + dest_edit->length,
00167 clipboard_end);
00168 }
00169 }
00170 }
00171
00172
00173
00174
00175 Edit* Edits::insert_new_edit(int64_t position)
00176 {
00177 Edit *current = 0;
00178
00179 current = split_edit(position);
00180
00181
00182 if(current) current = PREVIOUS;
00183
00184
00185 Edit *new_edit = create_edit();
00186
00187 insert_after(current, new_edit);
00188 new_edit->startproject = position;
00189
00190 return new_edit;
00191 }
00192
00193
00194 Edit* Edits::split_edit(int64_t position)
00195 {
00196
00197 Edit *edit = editof(position, PLAY_FORWARD, 0);
00198
00199
00200 if(!edit)
00201 if (!last || last->startproject + last->length <= position)
00202 {
00203
00204 Edit *empty = create_edit();
00205 if (last)
00206 empty->startproject = last->startproject + last->length;
00207 else
00208 empty->startproject = 0;
00209 empty->length = position - empty->startproject;
00210 insert_after(last, empty);
00211 edit = empty;
00212 } else
00213 {
00214 printf("ERROR!\n");
00215 printf("Trying to insert edit at position, but failed: %lli\n", position);
00216 printf("Dump is here:\n");
00217 track->dump();
00218 return 0;
00219 }
00220
00221
00222
00223
00224 Edit *new_edit = create_edit();
00225 insert_after(edit, new_edit);
00226 new_edit->copy_from(edit);
00227 new_edit->length = new_edit->startproject + new_edit->length - position;
00228 edit->length = position - edit->startproject;
00229 new_edit->startproject = edit->startproject + edit->length;
00230 new_edit->startsource += edit->length;
00231
00232
00233
00234 if(edit->length && edit->transition)
00235 {
00236 delete new_edit->transition;
00237 new_edit->transition = 0;
00238 }
00239
00240 if(edit->transition && edit->transition->length > edit->length)
00241 edit->transition->length = edit->length;
00242 if(new_edit->transition && new_edit->transition->length > new_edit->length)
00243 new_edit->transition->length = new_edit->length;
00244 return new_edit;
00245 }
00246
00247 int Edits::save(FileXML *xml, char *output_path)
00248 {
00249 copy(0, length(), xml, output_path);
00250 return 0;
00251 }
00252
00253 void Edits::resample(double old_rate, double new_rate)
00254 {
00255 for(Edit *current = first; current; current = NEXT)
00256 {
00257 current->startproject = Units::to_int64((double)current->startproject /
00258 old_rate *
00259 new_rate);
00260 if(PREVIOUS) PREVIOUS->length = current->startproject - PREVIOUS->startproject;
00261 current->startsource = Units::to_int64((double)current->startsource /
00262 old_rate *
00263 new_rate);
00264 if(!NEXT) current->length = Units::to_int64((double)current->length /
00265 old_rate *
00266 new_rate);
00267 if(current->transition)
00268 {
00269 current->transition->length = Units::to_int64(
00270 (double)current->transition->length /
00271 old_rate *
00272 new_rate);
00273 }
00274 current->resample(old_rate, new_rate);
00275 }
00276 }
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291 int Edits::optimize()
00292 {
00293 int result = 1;
00294 Edit *current;
00295
00296
00297
00298 while(result)
00299 {
00300 result = 0;
00301
00302 for(current = first; current; current = NEXT)
00303 {
00304 Edit *next_edit = NEXT;
00305
00306 if(next_edit && next_edit->startproject < current->startproject)
00307 {
00308 swap(next_edit, current);
00309 result = 1;
00310 }
00311 }
00312 }
00313
00314
00315 for(current = last; current; current = current->previous)
00316 {
00317 if(current->previous)
00318 {
00319 Edit *previous_edit = current->previous;
00320 if(current->startproject -
00321 previous_edit->startproject -
00322 previous_edit->length > 0)
00323 {
00324 Edit *new_edit = create_edit();
00325 insert_before(current, new_edit);
00326 new_edit->startproject = previous_edit->startproject + previous_edit->length;
00327 new_edit->length = current->startproject -
00328 previous_edit->startproject -
00329 previous_edit->length;
00330 }
00331 }
00332 else
00333 if(current->startproject > 0)
00334 {
00335 Edit *new_edit = create_edit();
00336 insert_before(current, new_edit);
00337 new_edit->length = current->startproject;
00338 }
00339 }
00340
00341 result = 1;
00342 while(result)
00343 {
00344 result = 0;
00345
00346
00347
00348 for(current = first;
00349 current && !result; )
00350 {
00351 if(current->length == 0)
00352 {
00353 Edit* next = current->next;
00354 delete current;
00355 result = 1;
00356 current = next;
00357 }
00358 else
00359 current = current->next;
00360 }
00361
00362
00363 for(current = first;
00364 current && current->next && !result; )
00365 {
00366
00367 Edit *next_edit = current->next;
00368 if(current->asset == next_edit->asset &&
00369 (!current->asset ||
00370 (current->startsource + current->length == next_edit->startsource &&
00371 current->channel == next_edit->channel)
00372 )
00373 )
00374 {
00375
00376 current->length += next_edit->length;
00377 remove(next_edit);
00378 result = 1;
00379 }
00380
00381 current = (Plugin*)current->next;
00382 }
00383
00384
00385 if(last &&
00386 (last->silence() ||
00387 !last->length))
00388 {
00389 delete last;
00390 result = 1;
00391 }
00392 }
00393
00394
00395 return 0;
00396 }
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419 int Edits::load(FileXML *file, int track_offset)
00420 {
00421 int result = 0;
00422 int64_t startproject = 0;
00423
00424 do{
00425 result = file->read_tag();
00426
00427
00428 if(!result)
00429 {
00430 if(!strcmp(file->tag.get_title(), "EDIT"))
00431 {
00432 load_edit(file, startproject, track_offset);
00433 }
00434 else
00435 if(!strcmp(file->tag.get_title(), "/EDITS"))
00436 {
00437 result = 1;
00438 }
00439 }
00440 }while(!result);
00441
00442
00443 optimize();
00444 }
00445
00446 int Edits::load_edit(FileXML *file, int64_t &startproject, int track_offset)
00447 {
00448 Edit* current;
00449
00450
00451 current = append_new_edit();
00452
00453
00454 current->load_properties(file, startproject);
00455
00456 startproject += current->length;
00457
00458 int result = 0;
00459
00460
00461 do{
00462
00463 result = file->read_tag();
00464
00465
00466 if(!result)
00467 {
00468 if(file->tag.title_is("FILE"))
00469 {
00470 char filename[1024];
00471 sprintf(filename, SILENCE);
00472 file->tag.get_property("SRC", filename);
00473
00474
00475 if(strcmp(filename, SILENCE))
00476 {
00477 char directory[BCTEXTLEN], edl_directory[BCTEXTLEN];
00478 FileSystem fs;
00479 fs.set_current_dir("");
00480 fs.extract_dir(directory, filename);
00481 if(!strlen(directory))
00482 {
00483 fs.extract_dir(edl_directory, file->filename);
00484 fs.join_names(directory, edl_directory, filename);
00485 strcpy(filename, directory);
00486 }
00487 current->asset = edl->assets->get_asset(filename);
00488 }
00489 else
00490 {
00491 current->asset = edl->assets->get_asset(SILENCE);
00492 }
00493
00494 }
00495 else
00496 if(file->tag.title_is("TRANSITION"))
00497 {
00498 current->transition = new Transition(edl,
00499 current,
00500 "",
00501 track->to_units(edl->session->default_transition_length, 1));
00502 current->transition->load_xml(file);
00503 }
00504 else
00505 if(file->tag.title_is(SILENCE))
00506 {
00507
00508 current->asset = edl->assets->get_asset(SILENCE);
00509
00510 }
00511 else
00512 if(file->tag.title_is("/EDIT"))
00513 {
00514 result = 1;
00515 }
00516 }
00517
00518 }while(!result);
00519
00520
00521
00522 if(!current->asset) current->asset = edl->assets->get_asset(SILENCE);
00523 return 0;
00524 }
00525
00526
00527
00528 int64_t Edits::length()
00529 {
00530 if(last)
00531 return last->startproject + last->length;
00532 else
00533 return 0;
00534 }
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547 Edit* Edits::editof(int64_t position, int direction, int use_nudge)
00548 {
00549 Edit *current = 0;
00550 if(use_nudge && track) position += track->nudge;
00551
00552 if(direction == PLAY_FORWARD)
00553 {
00554 for(current = last; current; current = PREVIOUS)
00555 {
00556 if(current->startproject <= position && current->startproject + current->length > position)
00557 return current;
00558 }
00559 }
00560 else
00561 if(direction == PLAY_REVERSE)
00562 {
00563 for(current = first; current; current = NEXT)
00564 {
00565 if(current->startproject < position && current->startproject + current->length >= position)
00566 return current;
00567 }
00568 }
00569
00570 return 0;
00571 }
00572
00573 Edit* Edits::get_playable_edit(int64_t position, int use_nudge)
00574 {
00575 Edit *current;
00576 if(track && use_nudge) position += track->nudge;
00577
00578
00579 for(current = first; current; current = NEXT)
00580 {
00581 if(current->startproject <= position &&
00582 current->startproject + current->length > position)
00583 break;
00584 }
00585
00586
00587 if(current)
00588 {
00589 if(!current->asset)
00590 current = 0;
00591 }
00592
00593 return current;
00594 }
00595
00596
00597
00598
00599
00600 int Edits::copy(int64_t start, int64_t end, FileXML *file, char *output_path)
00601 {
00602 Edit *current_edit;
00603
00604 file->tag.set_title("EDITS");
00605 file->append_tag();
00606 file->append_newline();
00607
00608 for(current_edit = first; current_edit; current_edit = current_edit->next)
00609 {
00610 current_edit->copy(start, end, file, output_path);
00611 }
00612
00613 file->tag.set_title("/EDITS");
00614 file->append_tag();
00615 file->append_newline();
00616 }
00617
00618
00619
00620 void Edits::clear(int64_t start, int64_t end)
00621 {
00622 Edit* edit1 = editof(start, PLAY_FORWARD, 0);
00623 Edit* edit2 = editof(end, PLAY_FORWARD, 0);
00624 Edit* current_edit;
00625
00626 if(end == start) return;
00627 if(!edit1 && !edit2) return;
00628
00629
00630 if(!edit2)
00631 {
00632 edit2 = last;
00633 end = this->length();
00634 }
00635
00636 if(edit1 != edit2)
00637 {
00638
00639
00640
00641 edit1->length = start - edit1->startproject;
00642 edit2->length -= end - edit2->startproject;
00643 edit2->startsource += end - edit2->startproject;
00644 edit2->startproject += end - edit2->startproject;
00645
00646
00647 for(current_edit = edit1->next; current_edit && current_edit != edit2;)
00648 {
00649 Edit* next = current_edit->next;
00650 remove(current_edit);
00651 current_edit = next;
00652 }
00653
00654 for(current_edit = edit2; current_edit; current_edit = current_edit->next)
00655 {
00656 current_edit->startproject -= end - start;
00657 }
00658 }
00659 else
00660 {
00661
00662
00663 current_edit = split_edit(start);
00664
00665 current_edit->length -= end - start;
00666 current_edit->startsource += end - start;
00667
00668
00669 for(current_edit = current_edit->next;
00670 current_edit;
00671 current_edit = current_edit->next)
00672 {
00673 current_edit->startproject -= end - start;
00674 }
00675 }
00676
00677 optimize();
00678 }
00679
00680
00681
00682 void Edits::clear_recursive(int64_t start,
00683 int64_t end,
00684 int edit_edits,
00685 int edit_labels,
00686 int edit_plugins,
00687 Edits *trim_edits)
00688 {
00689
00690 track->clear(start,
00691 end,
00692 edit_edits,
00693 edit_labels,
00694 edit_plugins,
00695 0,
00696 trim_edits);
00697 }
00698
00699
00700 int Edits::clear_handle(double start,
00701 double end,
00702 int edit_plugins,
00703 double &distance)
00704 {
00705 Edit *current_edit;
00706
00707 distance = 0.0;
00708 for(current_edit = first;
00709 current_edit && current_edit->next;
00710 current_edit = current_edit->next)
00711 {
00712
00713
00714
00715 if(current_edit->asset &&
00716 current_edit->next->asset)
00717 {
00718
00719 if(current_edit->asset->equivalent(*current_edit->next->asset,
00720 0,
00721 0))
00722 {
00723
00724
00725 if(edl->equivalent(track->from_units(current_edit->next->startproject),
00726 start))
00727 {
00728
00729 int length = -current_edit->length;
00730 current_edit->length = current_edit->next->startsource - current_edit->startsource;
00731 length += current_edit->length;
00732
00733
00734 track->automation->paste_silence(current_edit->next->startproject,
00735 current_edit->next->startproject + length);
00736
00737
00738 if(edit_plugins)
00739 track->shift_effects(current_edit->next->startproject,
00740 length,
00741 0);
00742
00743 for(current_edit = current_edit->next; current_edit; current_edit = current_edit->next)
00744 {
00745 current_edit->startproject += length;
00746 }
00747
00748 distance = track->from_units(length);
00749 optimize();
00750 break;
00751 }
00752 }
00753 }
00754 }
00755
00756 return 0;
00757 }
00758
00759 int Edits::modify_handles(double oldposition,
00760 double newposition,
00761 int currentend,
00762 int edit_mode,
00763 int edit_edits,
00764 int edit_labels,
00765 int edit_plugins,
00766 Edits *trim_edits)
00767 {
00768 int result = 0;
00769 Edit *current_edit;
00770
00771
00772 if(currentend == 0)
00773 {
00774
00775 for(current_edit = first; current_edit && !result;)
00776 {
00777 if(edl->equivalent(track->from_units(current_edit->startproject),
00778 oldposition))
00779 {
00780
00781
00782 oldposition = track->from_units(current_edit->startproject);
00783 result = 1;
00784
00785 if(newposition >= oldposition)
00786 {
00787
00788
00789 current_edit->shift_start_in(edit_mode,
00790 track->to_units(newposition, 0),
00791 track->to_units(oldposition, 0),
00792 edit_edits,
00793 edit_labels,
00794 edit_plugins,
00795 trim_edits);
00796 }
00797 else
00798 {
00799
00800
00801 current_edit->shift_start_out(edit_mode,
00802 track->to_units(newposition, 0),
00803 track->to_units(oldposition, 0),
00804 edit_edits,
00805 edit_labels,
00806 edit_plugins,
00807 trim_edits);
00808 }
00809 }
00810
00811 if(!result) current_edit = current_edit->next;
00812 }
00813 }
00814 else
00815 {
00816
00817 for(current_edit = first; current_edit && !result;)
00818 {
00819 if(edl->equivalent(track->from_units(current_edit->startproject) +
00820 track->from_units(current_edit->length), oldposition))
00821 {
00822 oldposition = track->from_units(current_edit->startproject) +
00823 track->from_units(current_edit->length);
00824 result = 1;
00825
00826
00827 if(newposition <= oldposition)
00828 {
00829
00830
00831 current_edit->shift_end_in(edit_mode,
00832 track->to_units(newposition, 0),
00833 track->to_units(oldposition, 0),
00834 edit_edits,
00835 edit_labels,
00836 edit_plugins,
00837 trim_edits);
00838
00839 }
00840 else
00841 {
00842
00843
00844 current_edit->shift_end_out(edit_mode,
00845 track->to_units(newposition, 0),
00846 track->to_units(oldposition, 0),
00847 edit_edits,
00848 edit_labels,
00849 edit_plugins,
00850 trim_edits);
00851
00852 }
00853 }
00854
00855 if(!result) current_edit = current_edit->next;
00856
00857 }
00858 }
00859
00860 optimize();
00861 return 0;
00862 }
00863
00864
00865
00866
00867
00868
00869 void Edits::paste_silence(int64_t start, int64_t end)
00870 {
00871
00872
00873
00874
00875 Edit *new_edit = editof(start, PLAY_FORWARD, 0);
00876 if (!new_edit) return;
00877
00878 if (!new_edit->asset)
00879 {
00880 new_edit->length += end - start;
00881 } else
00882 {
00883 new_edit = insert_new_edit(start);
00884 new_edit->length = end - start;
00885 }
00886 for(Edit *current = new_edit->next; current; current = NEXT)
00887 {
00888 current->startproject += end - start;
00889 }
00890 return;
00891 }
00892
00893
00894
00895 Edit *Edits::create_and_insert_edit(int64_t start, int64_t end)
00896 {
00897 Edit *new_edit = insert_new_edit(start);
00898 new_edit->length = end - start;
00899 for(Edit *current = new_edit->next; current; current = NEXT)
00900 {
00901 current->startproject += end - start;
00902 }
00903 return new_edit;
00904 }
00905
00906 Edit* Edits::shift(int64_t position, int64_t difference)
00907 {
00908 Edit *new_edit = split_edit(position);
00909
00910 for(Edit *current = first;
00911 current;
00912 current = NEXT)
00913 {
00914 if(current->startproject >= position)
00915 {
00916 current->shift(difference);
00917 }
00918 }
00919 return new_edit;
00920 }
00921
00922
00923 void Edits::shift_keyframes_recursive(int64_t position, int64_t length)
00924 {
00925 track->shift_keyframes(position, length, 0);
00926 }
00927
00928 void Edits::shift_effects_recursive(int64_t position, int64_t length)
00929 {
00930 track->shift_effects(position, length, 0);
00931 }
00932