add new tracks as master, update msg txt
[goodguy/cinelerra.git] / cinelerra-5.1 / cinelerra / mwindowedit.C
index 7b49d090a972a2eeb10f5c8a5fb87992f996318e..5e4b797be1f96ead14415d179af9467b3f04116b 100644 (file)
@@ -85,7 +85,8 @@
 void MWindow::add_audio_track_entry(int above, Track *dst)
 {
        undo_before();
-       add_audio_track(above, dst);
+       Track *track = add_audio_track(above, dst);
+       track->master = 1;
        save_backup();
        undo_after(_("add track"), LOAD_ALL);
 
@@ -95,10 +96,11 @@ void MWindow::add_audio_track_entry(int above, Track *dst)
        cwindow->refresh_frame(CHANGE_EDL);
 }
 
-void MWindow::add_video_track_entry(Track *dst)
+void MWindow::add_video_track_entry(int above, Track *dst)
 {
        undo_before();
-       add_video_track(1, dst);
+       Track *track = add_video_track(above, dst);
+       track->master = 1;
        undo_after(_("add track"), LOAD_ALL);
 
        restart_brender();
@@ -109,10 +111,11 @@ void MWindow::add_video_track_entry(Track *dst)
        save_backup();
 }
 
-void MWindow::add_subttl_track_entry(Track *dst)
+void MWindow::add_subttl_track_entry(int above, Track *dst)
 {
        undo_before();
-       add_subttl_track(1, dst);
+       Track *track = add_subttl_track(above, dst);
+       track->master = 1;
        undo_after(_("add track"), LOAD_ALL);
 
        restart_brender();
@@ -124,28 +127,28 @@ void MWindow::add_subttl_track_entry(Track *dst)
 }
 
 
-int MWindow::add_audio_track(int above, Track *dst)
+Track *MWindow::add_audio_track(int above, Track *dst)
 {
-       edl->tracks->add_audio_track(above, dst);
+       Track *track = edl->tracks->add_audio_track(above, dst);
        edl->tracks->update_y_pixels(theme);
        save_backup();
-       return 0;
+       return track;
 }
 
-int MWindow::add_video_track(int above, Track *dst)
+Track *MWindow::add_video_track(int above, Track *dst)
 {
-       edl->tracks->add_video_track(above, dst);
+       Track *track = edl->tracks->add_video_track(above, dst);
        edl->tracks->update_y_pixels(theme);
        save_backup();
-       return 0;
+       return track;
 }
 
-int MWindow::add_subttl_track(int above, Track *dst)
+Track *MWindow::add_subttl_track(int above, Track *dst)
 {
-       edl->tracks->add_subttl_track(above, dst);
+       Track *track = edl->tracks->add_subttl_track(above, dst);
        edl->tracks->update_y_pixels(theme);
        save_backup();
-       return 0;
+       return track;
 }
 
 void MWindow::asset_to_all()
@@ -179,7 +182,7 @@ void MWindow::asset_to_all()
 
                        for( Track *current=edl->tracks->first; current; current=NEXT ) {
                                if( current->data_type == TRACK_VIDEO /* &&
-                                       current->record */  ) {
+                                       current->is_armed() */  ) {
                                        current->track_w = w;
                                        current->track_h = h;
                                }
@@ -761,19 +764,40 @@ void MWindow::insert(double position, FileXML *file,
 //printf("MWindow::insert 6 %p\n", vwindow->get_edl());
 }
 
-void MWindow::insert_effects_canvas(double start,
-       double length)
+void MWindow::insert_effects_canvas(Track *dest_track, double start, double length)
 {
-       Track *dest_track = session->track_highlighted;
-       if( !dest_track ) return;
-
        undo_before();
 
-       for( int i=0; i<session->drag_pluginservers->total; ++i ) {
-               PluginServer *plugin = session->drag_pluginservers->values[i];
-               insert_effect(plugin->title, 0, dest_track,
-                       i == 0 ? session->pluginset_highlighted : 0,
-                       start, length, PLUGIN_STANDALONE);
+       ArrayList<SharedLocation> shared_locations;
+       PluginSet *pluginset = session->pluginset_highlighted;
+       int gang = edl->session->gang_tracks != GANG_NONE ? 1 : 0;
+       int data_type = dest_track->data_type;
+       int first_track = 1;
+
+       for( Track *track=dest_track; track; track=track->next ) {
+               if( gang && track->master && !first_track ) break;
+               if( track->data_type != data_type ) continue;
+               if( !track->is_armed() ) continue;
+               int module = edl->tracks->number_of(track);
+               for( int i=0; i<session->drag_pluginservers->total; ++i ) {
+                       PluginServer *plugin = session->drag_pluginservers->values[i];
+                       int shared = gang; // && plugin->multichannel ? 1 : 0;
+                       int plugin_type = !first_track && shared ?
+                               PLUGIN_SHAREDPLUGIN : PLUGIN_STANDALONE;
+                       SharedLocation *shared_location = !first_track ?
+                               &shared_locations[i] : &shared_locations.append();
+                       insert_effect(plugin->title, shared_location, track,
+                                       pluginset, start, length, plugin_type);
+                       if( first_track && shared ) {
+                               shared_location->module = module;
+                               shared_location->plugin = pluginset ?
+                                       track->plugin_set.number_of(pluginset) :
+                                       track->plugin_set.total-1 ;
+                       }
+               }
+               if( !gang ) break;
+               first_track = 0;
+               pluginset = 0;
        }
 
        save_backup();
@@ -787,8 +811,6 @@ void MWindow::insert_effects_cwindow(Track *dest_track)
 {
        if( !dest_track ) return;
 
-       undo_before();
-
        double start = 0;
        double length = dest_track->get_length();
 
@@ -799,55 +821,45 @@ void MWindow::insert_effects_cwindow(Track *dest_track)
                        edl->local_session->get_selectionstart();
        }
 
-       for( int i=0; i<session->drag_pluginservers->total; ++i ) {
-               PluginServer *plugin = session->drag_pluginservers->values[i];
-               insert_effect(plugin->title, 0, dest_track, 0,
-                       start, length, PLUGIN_STANDALONE);
-       }
-
-       save_backup();
-       undo_after(_("insert effect"), LOAD_EDITS | LOAD_PATCHES);
-       restart_brender();
-       sync_parameters(CHANGE_EDL);
+       insert_effects_canvas(dest_track, start, length);
        gui->update(1, NORMAL_DRAW, 0, 0, 1, 0, 0);
 }
 
-void MWindow::insert_effect(char *title,
-       SharedLocation *shared_location,
-       int data_type,
-       int plugin_type,
-       int single_standalone)
+void MWindow::insert_effect(char *title, SharedLocation *shared_location,
+               int data_type, int plugin_type, int single_standalone)
 {
        Track *current = edl->tracks->first;
        SharedLocation shared_location_local;
        shared_location_local.copy_from(shared_location);
        int first_track = 1;
+       double start_pos = edl->local_session->get_selectionstart(1);
+       double end_pos = edl->local_session->get_selectionend(1);
        for( ; current; current=NEXT ) {
-               if( current->data_type == data_type &&
-                       current->record ) {
-                       insert_effect(title, &shared_location_local,
-                               current, 0, 0, 0, plugin_type);
-
-                       if( first_track ) {
-                               if( plugin_type == PLUGIN_STANDALONE && single_standalone ) {
-                                       plugin_type = PLUGIN_SHAREDPLUGIN;
-                                       shared_location_local.module = edl->tracks->number_of(current);
-                                       shared_location_local.plugin = current->plugin_set.total - 1;
-                               }
-                               first_track = 0;
+               if( current->data_type != data_type ) continue;
+               if( !current->is_armed() ) continue;
+               double start = start_pos, end = end_pos;
+               if( plugin_type == PLUGIN_STANDALONE && start >= end ) {
+                       start = 0;
+                       end = current->get_length();
+               }
+               double length = end - start;
+               insert_effect(title, &shared_location_local,
+                               current, 0, start, length, plugin_type);
+               if( first_track ) {
+                       if( plugin_type == PLUGIN_STANDALONE && single_standalone ) {
+                               plugin_type = PLUGIN_SHAREDPLUGIN;
+                               shared_location_local.module = edl->tracks->number_of(current);
+                               shared_location_local.plugin = current->plugin_set.total - 1;
+                               start_pos = start;  end_pos = end;
                        }
+                       first_track = 0;
                }
        }
 }
 
-
 void MWindow::insert_effect(char *title,
-       SharedLocation *shared_location,
-       Track *track,
-       PluginSet *plugin_set,
-       double start,
-       double length,
-       int plugin_type)
+               SharedLocation *shared_location, Track *track, PluginSet *plugin_set,
+               double start, double length, int plugin_type)
 {
        KeyFrame *default_keyframe = 0;
        PluginServer *server = 0;
@@ -860,9 +872,8 @@ void MWindow::insert_effect(char *title,
                server->save_data(default_keyframe);
        }
 // Insert plugin object
-       track->insert_effect(title, shared_location,
-               default_keyframe, plugin_set,
-               start, length, plugin_type);
+       track->insert_effect(title, shared_location, default_keyframe,
+                       plugin_set, start, length, plugin_type);
        track->optimize();
 
        if( plugin_type == PLUGIN_STANDALONE ) {
@@ -1250,10 +1261,16 @@ void MWindow::overwrite(EDL *source, int all)
 // so we need to clear only when not using both io points
 // FIXME: need to write simple overwrite_edl to be used for overwrite function
        if( edl->local_session->get_inpoint() < 0 ||
-               edl->local_session->get_outpoint() < 0 )
-               edl->clear(dst_start, dst_start + overwrite_len, 0, 0, 0);
+           edl->local_session->get_outpoint() < 0 )
+               edl->clear(dst_start, dst_start + overwrite_len,
+                               edl->session->labels_follow_edits,
+                               edl->session->plugins_follow_edits,
+                               edl->session->autos_follow_edits);
 
-       paste(dst_start, dst_start + overwrite_len, &file, 0, 0, 0, 0, 0);
+       paste(dst_start, dst_start + overwrite_len, &file,
+                               edl->session->labels_follow_edits,
+                               edl->session->plugins_follow_edits,
+                               edl->session->autos_follow_edits, 0, 0);
 
        edl->local_session->set_selectionstart(dst_start + overwrite_len);
        edl->local_session->set_selectionend(dst_start + overwrite_len);
@@ -1371,7 +1388,7 @@ if( debug ) printf("MWindow::load_assets %d\n", __LINE__);
        for( int i=0; i<new_assets->total; ++i ) {
                Indexable *indexable = new_assets->get(i);
                if( indexable->is_asset ) {
-                       remove_asset_from_caches((Asset*)indexable);
+                       remove_from_caches(indexable);
                }
                EDL *new_edl = new EDL;
                new_edl->create_objects();
@@ -1516,6 +1533,7 @@ int MWindow::paste_edls(ArrayList<EDL*> *new_edls, int load_mode,
                need_new_tracks = 1;
                for( int i=0; i<new_edls->total; ++i ) {
                        EDL *new_edl = new_edls->values[i];
+                       int first_track = 1;
                        for( Track *current=new_edl->tracks->first; current; current=NEXT ) {
                                switch( current->data_type ) {
                                case TRACK_VIDEO:
@@ -1531,6 +1549,10 @@ int MWindow::paste_edls(ArrayList<EDL*> *new_edls, int load_mode,
                                default:
                                        continue;
                                }
+                               if( first_track ) {
+                                       edl->tracks->last->master = 1;
+                                       first_track = 0;
+                               }
 // re-label only if not already labeled
                                if( new_edl->local_session->asset2edl )
                                        strcpy(current->title, edl->tracks->last->title);
@@ -1545,11 +1567,10 @@ int MWindow::paste_edls(ArrayList<EDL*> *new_edls, int load_mode,
        else
 // Recycle existing tracks of master EDL
        if( load_mode == LOADMODE_CONCATENATE ||
-           load_mode == LOADMODE_PASTE ||
-           load_mode == LOADMODE_NESTED ) {
+           load_mode == LOADMODE_PASTE ) {
                Track *current = first_track ? first_track : edl->tracks->first;
                for( ; current; current=NEXT ) {
-                       if( current->record ) {
+                       if( current->is_armed() ) {
                                destination_tracks.append(current);
                        }
                }
@@ -1583,13 +1604,15 @@ int MWindow::paste_edls(ArrayList<EDL*> *new_edls, int load_mode,
 // Add assets and prepare index files
                for( Asset *new_asset=new_edl->assets->first;
                     new_asset; new_asset=new_asset->next ) {
-                       mainindexes->add_next_asset(0, new_asset);
+                       mainindexes->add_indexable(new_asset);
                }
 // Capture index file status from mainindex test
                edl->update_assets(new_edl);
 //PRINT_TRACE
 // Get starting point of insertion.  Need this to paste labels.
                switch( load_mode ) {
+               case LOADMODE_NOTHING:
+                       continue;
                case LOADMODE_REPLACE:
                        current_position = 0;
                        break;
@@ -1608,7 +1631,6 @@ int MWindow::paste_edls(ArrayList<EDL*> *new_edls, int load_mode,
                        break;
 
                case LOADMODE_PASTE:
-               case LOADMODE_NESTED:
                        destination_track = 0;
                        if( i == 0 ) {
                                for( int j=0; j<destination_tracks.total; ++j ) {
@@ -1628,7 +1650,7 @@ int MWindow::paste_edls(ArrayList<EDL*> *new_edls, int load_mode,
                    load_mode != LOADMODE_ASSETSONLY ) {
 // Insert labels
                        if( edit_labels ) {
-                               if( load_mode == LOADMODE_PASTE || load_mode == LOADMODE_NESTED )
+                               if( load_mode == LOADMODE_PASTE )
                                        edl->labels->insert_labels(new_edl->labels,
                                                destination_tracks.total ? paste_position[0] : 0.0,
                                                edl_length, 1);
@@ -1652,14 +1674,14 @@ int MWindow::paste_edls(ArrayList<EDL*> *new_edls, int load_mode,
                                if( destination_track < destination_tracks.total &&
                                    destination_tracks.values[destination_track]->data_type == new_track->data_type ) {
                                        Track *track = destination_tracks.values[destination_track];
-
 // Replace default keyframes if first EDL and new tracks were created.
 // This means data copied from one track and pasted to another won't retain
 // the camera position unless it's a keyframe.  If it did, previous data in the
 // track might get unknowingly corrupted.  Ideally we would detect when differing
 // default keyframes existed and create discrete keyframes for both.
                                        int replace_default = (i == 0) && need_new_tracks;
-
+// master tracks are the first track in each new edl when new tracks are created
+                                       int master = track->master;
 //printf("MWindow::paste_edls 1 %d\n", replace_default);
 // Insert new track at current position
                                        switch( load_mode ) {
@@ -1669,7 +1691,6 @@ int MWindow::paste_edls(ArrayList<EDL*> *new_edls, int load_mode,
                                                break;
 
                                        case LOADMODE_PASTE:
-                                       case LOADMODE_NESTED:
                                                current_position = paste_position[destination_track];
                                                paste_position[destination_track] += new_track->get_length();
                                                break;
@@ -1686,6 +1707,7 @@ int MWindow::paste_edls(ArrayList<EDL*> *new_edls, int load_mode,
 //PRINT_TRACE
                                        track->insert_track(new_track, current_position, replace_default,
                                                edit_plugins, edit_autos, edl_length);
+                                       if( master ) track->master = 1;
 //PRINT_TRACE
                                }
 
@@ -1696,8 +1718,7 @@ int MWindow::paste_edls(ArrayList<EDL*> *new_edls, int load_mode,
                        }
                }
 
-               if( load_mode == LOADMODE_PASTE ||
-                   load_mode == LOADMODE_NESTED )
+               if( load_mode == LOADMODE_PASTE )
                        current_position += edl_length;
        }
 
@@ -2160,7 +2181,7 @@ void MWindow::save_clip(EDL *new_edl, const char *txt)
        Track *track = new_edl->tracks->first;
        const char *path = edl->path;
        for( ; (!path || !*path) && track; track=track->next ) {
-               if( !track->record ) continue;
+               if( !track->is_armed() ) continue;
                Edit *edit = track->edits->first;
                if( !edit ) continue;
                Indexable *indexable = edit->get_source();
@@ -2171,28 +2192,24 @@ void MWindow::save_clip(EDL *new_edl, const char *txt)
         time_t now;  time(&now);
         struct tm dtm;   localtime_r(&now, &dtm);
        char *cp = new_edl->local_session->clip_notes;
-       int n, sz = sizeof(new_edl->local_session->clip_notes)-1;
-       if( txt && *txt ) {
-               n = snprintf(cp, sz, "%s", txt);
-               cp += n;  sz -= n;
-       }
-       n = snprintf(cp, sz,
+       char *ep = cp + sizeof(new_edl->local_session->clip_notes)-1;
+       if( txt && *txt )
+               cp += snprintf(cp, ep-cp, "%s", txt);
+       cp += snprintf(cp, ep-cp,
                "%02d/%02d/%02d %02d:%02d:%02d,  +%s\n",
                dtm.tm_year+1900, dtm.tm_mon+1, dtm.tm_mday,
                dtm.tm_hour, dtm.tm_min, dtm.tm_sec, duration);
-       cp += n;  sz -= n;
        if( path && *path ) {
                FileSystem fs;
                char title[BCTEXTLEN];
                fs.extract_name(title, path);
-               n = snprintf(cp, sz, "%s", title);
-               cp += n;  sz -= n;
+               cp += snprintf(cp, ep-cp, "%s", title);
        }
-       cp[n] = 0;
        sprintf(new_edl->local_session->clip_icon,
-               "clip_%02d%02d%02d-%02d%02d%02d.png",
+               "clip_%02d%02d%02d-%02d%02d%02d-%d.png",
                dtm.tm_year+1900, dtm.tm_mon+1, dtm.tm_mday,
-               dtm.tm_hour, dtm.tm_min, dtm.tm_sec);
+               dtm.tm_hour, dtm.tm_min, dtm.tm_sec,
+               new_edl->id);
        new_edl->folder_no = AW_CLIP_FOLDER;
        edl->update_assets(new_edl);
        int cur_x, cur_y;
@@ -2391,7 +2408,7 @@ void MWindow::remap_audio(int pattern)
        int current_track = 0;
        for( Track *current=edl->tracks->first; current; current=NEXT ) {
                if( current->data_type == TRACK_AUDIO &&
-                       current->record ) {
+                       current->is_armed() ) {
                        Autos *pan_autos = current->automation->autos[AUTOMATION_PAN];
                        PanAuto *pan_auto = (PanAuto*)pan_autos->get_auto_for_editing(-1);
 
@@ -2445,19 +2462,20 @@ void MWindow::add_proxy(ArrayList<Indexable*> *orig_assets, ArrayList<Indexable*
 }
 
 void MWindow::start_convert(Asset *format_asset, const char *suffix,
-               float beep, int remove_originals)
+               float beep, int to_proxy, int remove_originals)
 {
        if( !convert_render )
-               convert_render = new ConvertRender(this, suffix);
-       convert_render->set_format(format_asset);
+               convert_render = new ConvertRender(this);
+       convert_render->set_format(format_asset, suffix, to_proxy);
        int found = convert_render->find_convertable_assets(edl);
        if( convert_render->needed_idxbls.size() > 0 )
                convert_render->start_convert(beep, remove_originals);
        else if( found > 0 )
                finish_convert(remove_originals);
-       else {
+       else if( found < 0 )
+               eprintf(_("convert assets format error"));
+       else
                eprintf(_("No convertable assets found"));
-       }
 }
 
 void MWindow::finish_convert(int remove_originals)
@@ -2556,3 +2574,89 @@ int MWindow::speed_after(int done)
        return result;
 }
 
+void MWindow::collect_effects()
+{
+       FileXML file;
+       const char *file_string = "";
+       EDL *group = 0;
+       int ret = edl->collect_effects(group);
+       switch( ret ) {
+       case COLLECT_EFFECTS_RECORD:
+               eprintf(_("Selected edit track not armed."));
+               break;
+       case COLLECT_EFFECTS_MULTIPLE:
+               eprintf(_("More than one edit selected on a track."));
+               break;
+       case COLLECT_EFFECTS_MISSING:
+               eprintf(_("No effects under selected edit."));
+               break;
+       case COLLECT_EFFECTS_EMPTY:
+               eprintf(_("No edits selected."));
+               break;
+       case COLLECT_EFFECTS_MASTER:
+               eprintf(_("Shared effect added without master."));
+               break;
+       case 0:
+               group->save_xml(&file, "");
+               file_string = file.string();
+               group->remove_user();
+       }
+       long file_length = strlen(file_string);
+       gui->to_clipboard(file_string, file_length, BC_PRIMARY_SELECTION);
+       gui->to_clipboard(file_string, file_length, SECONDARY_SELECTION);
+}
+
+void MWindow::paste_effects()
+{
+       char *string = 0;
+       int64_t len = gui->clipboard_len(BC_PRIMARY_SELECTION);
+       if( len ) {
+               string = new char[len];
+               gui->from_clipboard(string, len, BC_PRIMARY_SELECTION);
+       }
+       if( !string || !string[0] ) {
+               eprintf(_("Error clipboard buffer empty."));
+               return;
+       }
+       FileXML file;
+       file.read_from_string(string);
+       EDL *group = new EDL();
+       group->create_objects();
+       if( !group->load_xml(&file, LOAD_ALL) ) {
+               undo_before();
+               int ret = edl->insert_effects(group);
+               switch( ret ) {
+               case INSERT_EFFECTS_RECORD:
+                       eprintf(_("Selected edit track not armed."));
+                       break;
+               case INSERT_EFFECTS_TYPE:
+                       eprintf(_("Track type mismatched."));
+                       break;
+               case INSERT_EFFECTS_MULTIPLE:
+                       eprintf(_("More than one edit selected on a track."));
+                       break;
+               case INSERT_EFFECTS_MISSING:
+                       eprintf(_("Too few target edits to add group effects."));
+                       break;
+               case INSERT_EFFECTS_EXTRA:
+                       eprintf(_("Too many target edits to add group effects."));
+                       break;
+               case INSERT_EFFECTS_MASTER:
+                       eprintf(_("Shared effect added without master."));
+                       break;
+               case 0:
+                       break;
+               }
+               save_backup();
+               undo_after(_("paste effects"), LOAD_ALL);
+               restart_brender();
+               cwindow->refresh_frame(CHANGE_EDL);
+               update_plugin_guis();
+               gui->update(1, NORMAL_DRAW, 1, 0, 0, 0, 0);
+       }
+       else
+               eprintf(_("Error loading clip from clipboard buffer."));
+       delete [] string;
+       group->remove_user();
+}
+