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