4 * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
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.
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.
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
22 #include "bcsignals.h"
24 #include "edlsession.h"
27 #include "keyframes.h"
29 #include "pluginautos.h"
30 #include "pluginset.h"
35 PluginSet::PluginSet(EDL *edl, Track *track)
41 PluginSet::~PluginSet()
43 while(last) delete last;
47 PluginSet& PluginSet::operator=(PluginSet& plugins)
49 printf("PluginSet::operator= 1\n");
54 void PluginSet::copy_from(PluginSet *src)
56 while(last) delete last;
57 for(Plugin *current = (Plugin*)src->first; current; current = (Plugin*)NEXT)
60 append(new_plugin = (Plugin*)create_edit());
61 new_plugin->copy_from(current);
63 this->record = src->record;
66 Plugin* PluginSet::get_first_plugin()
68 // Called when a new pluginset is added.
69 // Get first non-silence plugin in the plugin set.
70 for(Plugin *current = (Plugin*)first; current; current = (Plugin*)NEXT)
72 if(current && current->plugin_type != PLUGIN_NONE)
80 int64_t PluginSet::plugin_change_duration(int64_t input_position,
84 int result = input_length;
89 int input_start = input_position - input_length;
90 for(current = last; current; current = PREVIOUS)
92 int start = current->startproject;
93 int end = start + current->length;
94 if(end > input_start && end < input_position)
96 result = input_position - end;
100 if(start > input_start && start < input_position)
102 result = input_position - start;
109 int input_end = input_position + input_length;
110 for(current = first; current; current = NEXT)
112 int start = current->startproject;
113 int end = start + current->length;
114 if(start > input_position && start < input_end)
116 result = start - input_position;
120 if(end > input_position && end < input_end)
122 result = end - input_position;
130 void PluginSet::synchronize_params(PluginSet *plugin_set)
132 for(Plugin *this_plugin = (Plugin*)first, *that_plugin = (Plugin*)plugin_set->first;
133 this_plugin && that_plugin;
134 this_plugin = (Plugin*)this_plugin->next, that_plugin = (Plugin*)that_plugin->next)
136 this_plugin->synchronize_params(that_plugin);
140 Plugin* PluginSet::insert_plugin(const char *title,
141 int64_t unit_position,
144 SharedLocation *shared_location,
145 KeyFrame *default_keyframe,
148 Plugin *plugin = (Plugin*)paste_silence(unit_position,
149 unit_position + unit_length);
152 if(title) strcpy(plugin->title, title);
154 if(shared_location) plugin->shared_location = *shared_location;
156 plugin->plugin_type = plugin_type;
159 *plugin->keyframes->default_auto = *default_keyframe;
160 plugin->keyframes->default_auto->position = unit_position;
162 // May delete the plugin we just added so not desirable while loading.
163 if(do_optimize) optimize();
167 Edit* PluginSet::create_edit()
169 Plugin* result = new Plugin(edl, this, "");
173 Edit* PluginSet::insert_edit_after(Edit *previous_edit)
175 Plugin *current = new Plugin(edl, this, "");
176 List<Edit>::insert_after(previous_edit, current);
177 return (Edit*)current;
181 int PluginSet::get_number()
183 return track->plugin_set.number_of(this);
186 void PluginSet::clear(int64_t start, int64_t end, int edit_autos)
191 for(Plugin *current = (Plugin*)first;
193 current = (Plugin*)NEXT)
195 current->keyframes->clear(start, end, 1);
200 Edits::clear(start, end);
203 //void PluginSet::clear_recursive(int64_t start, int64_t end)
205 //printf("PluginSet::clear_recursive 1\n");
206 // clear(start, end, 1);
209 void PluginSet::shift_keyframes_recursive(int64_t position, int64_t length)
211 // Plugin keyframes are shifted in shift_effects
214 void PluginSet::shift_effects_recursive(int64_t position, int64_t length, int edit_autos)
216 // Effects are shifted in length extension
220 void PluginSet::clear_keyframes(int64_t start, int64_t end)
222 for(Plugin *current = (Plugin*)first; current; current = (Plugin*)NEXT)
224 current->clear_keyframes(start, end);
228 void PluginSet::copy_keyframes(int64_t start,
234 file->tag.set_title("PLUGINSET");
236 file->append_newline();
238 for(Plugin *current = (Plugin*)first;
240 current = (Plugin*)NEXT)
242 current->copy_keyframes(start, end, file, default_only, active_only);
245 file->tag.set_title("/PLUGINSET");
247 file->append_newline();
251 void PluginSet::paste_keyframes(int64_t start,
258 int first_keyframe = 1;
264 result = file->read_tag();
268 if(file->tag.title_is("/PLUGINSET"))
271 if(file->tag.title_is("KEYFRAME"))
273 int64_t position = file->tag.get_property("POSITION", 0);
274 if(first_keyframe && default_only)
283 // Get plugin owning keyframe
284 for(current = (Plugin*)last;
286 current = (Plugin*)PREVIOUS)
288 // We want keyframes to exist beyond the end of the last plugin to
289 // make editing intuitive, but it will always be possible to
290 // paste keyframes from one plugin into an incompatible plugin.
291 if(position >= current->startproject)
293 KeyFrame *keyframe = 0;
294 if(file->tag.get_property("DEFAULT", 0) || default_only)
296 keyframe = (KeyFrame*)current->keyframes->default_auto;
302 (KeyFrame*)current->keyframes->insert_auto(position);
307 keyframe->load(file);
308 keyframe->position = position;
320 void PluginSet::shift_effects(int64_t start, int64_t length, int edit_autos)
322 for(Plugin *current = (Plugin*)first;
324 current = (Plugin*)NEXT)
326 // Shift beginning of this effect
327 if(current->startproject >= start)
329 current->startproject += length;
332 // Extend end of this effect.
333 // In loading new files, the effect should extend to fill the entire track.
334 // In muting, the effect must extend to fill the gap if another effect follows.
335 // The user should use Settings->edit effects to disable this.
336 if(current->startproject + current->length >= start)
338 current->length += length;
341 // Shift keyframes in this effect.
342 // If the default keyframe lands on the starting point, it must be shifted
343 // since the effect start is shifted.
344 if(edit_autos && current->keyframes->default_auto->position >= start)
345 current->keyframes->default_auto->position += length;
347 if(edit_autos) current->keyframes->paste_silence(start, start + length);
351 void PluginSet::copy(int64_t start, int64_t end, FileXML *file)
353 file->tag.set_title("PLUGINSET");
354 file->tag.set_property("RECORD", record);
356 file->append_newline();
358 for(Plugin *current = (Plugin*)first; current; current = (Plugin*)NEXT)
360 current->copy(start, end, file);
363 file->tag.set_title("/PLUGINSET");
365 file->append_newline();
368 void PluginSet::save(FileXML *file)
370 copy(0, length(), file);
373 void PluginSet::load(FileXML *file, uint32_t load_flags)
376 // Current plugin being amended
377 Plugin *plugin = (Plugin*)first;
378 int64_t startproject = 0;
380 record = file->tag.get_property("RECORD", record);
382 result = file->read_tag();
387 if(file->tag.title_is("/PLUGINSET"))
392 if(file->tag.title_is("PLUGIN"))
394 int64_t length = file->tag.get_property("LENGTH", (int64_t)0);
395 int plugin_type = file->tag.get_property("TYPE", 1);
396 char title[BCTEXTLEN];
398 file->tag.get_property("TITLE", title);
399 SharedLocation shared_location;
400 shared_location.load(file);
403 if(load_flags & LOAD_EDITS)
405 plugin = insert_plugin(title,
413 startproject += length;
416 if(load_flags & LOAD_AUTOMATION)
421 plugin = (Plugin*)plugin->next;
431 int PluginSet::optimize()
434 Plugin *current_edit;
437 // Delete keyframes out of range
438 for(current_edit = (Plugin*)first;
440 current_edit = (Plugin*)current_edit->next)
442 current_edit->keyframes->default_auto->position = 0;
443 for(KeyFrame *current_keyframe = (KeyFrame*)current_edit->keyframes->last;
446 KeyFrame *previous_keyframe = (KeyFrame*)current_keyframe->previous;
447 if(current_keyframe->position >
448 current_edit->startproject + current_edit->length ||
449 current_keyframe->position < current_edit->startproject)
451 delete current_keyframe;
453 current_keyframe = previous_keyframe;
457 // Insert silence between plugins
458 for(Plugin *current = (Plugin*)last; current; current = (Plugin*)PREVIOUS)
460 if(current->previous)
462 Plugin *previous = (Plugin*)PREVIOUS;
464 if(current->startproject -
465 previous->startproject -
466 previous->length > 0)
468 Plugin *new_plugin = (Plugin*)create_edit();
469 insert_before(current, new_plugin);
470 new_plugin->startproject = previous->startproject +
472 new_plugin->length = current->startproject -
473 previous->startproject -
478 if(current->startproject > 0)
480 Plugin *new_plugin = (Plugin*)create_edit();
481 insert_before(current, new_plugin);
482 new_plugin->length = current->startproject;
487 // delete 0 length plugins
492 for(current_edit = (Plugin*)first;
493 current_edit && !result; )
495 if(current_edit->length == 0)
497 Plugin* next = (Plugin*)current_edit->next;
503 current_edit = (Plugin*)current_edit->next;
507 // merge identical plugins with same keyframes
508 for(current_edit = (Plugin*)first;
509 current_edit && current_edit->next && !result; )
511 Plugin *next_edit = (Plugin*)current_edit->next;
515 if(next_edit->identical(current_edit))
517 current_edit->length += next_edit->length;
519 for(KeyFrame *source = (KeyFrame*)next_edit->keyframes->first;
521 source = (KeyFrame*)source->next)
523 KeyFrame *dest = new KeyFrame(edl, current_edit->keyframes);
525 current_edit->keyframes->append(dest);
531 current_edit = (Plugin*)current_edit->next;
534 // delete last edit if 0 length or silence
537 if(last->silence() || !last->length)
552 void PluginSet::dump(FILE *fp)
554 fprintf(fp," PLUGIN_SET:\n");
555 for(Plugin *current = (Plugin*)first; current; current = (Plugin*)NEXT)