Trying to collapse tracks without removing previous whitespace

gir489 wrote on 2/16/2024, 4:31 PM

I wrote the following script for one of my editor friends.


 

using System.Collections.Generic;
using ScriptPortal.Vegas;
using System.Windows.Forms;

public class EntryPoint
{
    public void FromVegas(Vegas vegas)
    {
        Dictionary<Timecode, Timecode> timecodes = new Dictionary<Timecode, Timecode>();

        Timecode lastStart = null;

        foreach (Marker marker in vegas.Project.Markers)
        {
            if (marker.Label == "Start")
            {
                lastStart = marker.Position;
            }
            else if (marker.Label == "End")
            {
                timecodes[lastStart] = marker.Position;
            }
            else
            {
                MessageBox.Show("Invalid Marker: \"" + marker.Label + "\" detected at timecode: " + marker.Position.ToString());
                vegas.Transport.CursorPosition = marker.Position;
                return;
            }
        }

        foreach (KeyValuePair<Timecode, Timecode> kvp in timecodes)
        {
            foreach (Track track in vegas.Project.Tracks)
            {
                foreach (TrackEvent trackEvent in track.Events)
                {
                    if ((trackEvent.Start < kvp.Key) && ((trackEvent.Start + trackEvent.Length) > kvp.Key))
                    {
                        var newLength = kvp.Key - trackEvent.Start;
                        trackEvent.Split(newLength);
                        track.Events.Remove(trackEvent);
                    }
                }
            }

            foreach (Track track in vegas.Project.Tracks)
            {
                foreach (TrackEvent trackEvent in track.Events)
                {
                    if ((trackEvent.Start < kvp.Value) && ((trackEvent.Start + trackEvent.Length) > kvp.Value))
                    {
                        var newLength = kvp.Value - trackEvent.Start;
                        trackEvent.Split(newLength);
                    }
                }

            }
        }
        foreach (Track track in vegas.Project.Tracks)
        {
            if (track.Events.Count > 0)
            {
                TrackEvent lastEvent = track.Events[track.Events.Count - 1];
                track.Events.Remove(lastEvent);
            }
        }

        /*foreach (Track track in vegas.Project.Tracks)
        {
            Timecode tracktime = new Timecode(0);
            foreach (TrackEvent trackEvent in track.Events)
            {
                trackEvent.Start = tracktime;
                trackEvent.End = tracktime + trackEvent.Length;
                tracktime = trackEvent.End;
            }
        }*/

        /*vegas.Project.Markers.Clear();*/

    }
}

However, the problem with it is trying to close the gaps that the Split makes.

 

Currently, if the entire track had footage/audio, it works fine when it goes to iterate through all the tracks and collapse them. However, if there was a track above it that had a sound effect there, the script will try to collapse the entire amount of whitespace between 0:00:00 and where the sound effect starts, basically shoving it all the way to the left.

Is there a way to just make it split the tracks, collapse all the whitespace and preserve where the track was?

Comments

jetdv wrote on 2/17/2024, 8:36 AM

@gir489 So you're wanting to move the sound effects in relation to the other tracks - just not all the way to the left?

First of all, you don't need this:

trackEvent.End = tracktime + trackEvent.Length;

If you change the "Start" time, the "End" time will move correspondingly. The event will be "moved" so the end point will follow.

Secondly, why not just move everything "right" of the area marked by the two markers LEFT the distance between the markers. Then everything would remain in sync.

Say you have this:

Split everything at Marker 1 as you are doing. Split everything as Marker 2 as you are doing. Delete the events between markers 1 and 2 as you are doing. Now let's do something different:

  1. Calculate the distance between markers 1 and 2.
  2. Move everything right of marker 1 left that distance (i.e. event.Start = event.Start - DistanceBetweenMarker;)

So this will work with all marker pairings (as the markers would no longer be above the same areas of the events on the timeline after moving everything left) process the regions backwards! Start with the right-most pair and then process the pairs going left.

Honestly, this would probably be easier using regions instead of markers... The you won't have to create the pairings and you can easily go through the list of regions backwards..

gir489 wrote on 2/17/2024, 2:36 PM

Split everything at Marker 1 as you are doing. Split everything as Marker 2 as you are doing. Delete the events between markers 1 and 2 as you are doing. Now let's do something different:

  1. Calculate the distance between markers 1 and 2.
  2. Move everything right of marker 1 left that distance (i.e. event.Start = event.Start - DistanceBetweenMarker;)

So this will work with all marker pairings (as the markers would no longer be above the same areas of the events on the timeline after moving everything left) process the regions backwards! Start with the right-most pair and then process the pairs going left.

So there's two problems with your method here. One, you're assuming there's only one pair of markers, which there are hundreds (as the need for the dictionary implies) and two, there isn't a relatively easy way of determining which part of the track to move after the splice.

I will make screenshots to show the problem.

So track 4, 5, 6 and 7 all have multiple events on them, and the splits are wholly between them, so there is an event for each split. However, track 3 just has the one event, with your solution which I tried before, it will only move it once, because I have to do a range check to see if the split occurs within the track event.

The problem occurs with the fact the script doesn't know the difference between a track that is full and a track that isn't full, and there isn't a way that I can see given the awful SDK documentation that I can determine this at runtime. Ideally, the way it SHOULD work, is make the split, take everything to the right, and collapse it to the left of whatever space was there, including tracks that are outside the boundaries of the markers. That way, when it encounters another marker selection, it will just keep slicing and moving each time. However, the problem I ran into with THIS "solution" was now the markers don't match up! So then I had to move the markers, and then I just wound up back where I started, I can't tell which markers belong to what piece at runtime, because I can't tell what's to the left and what's to the right of where I am and if that segment is a full track or a segment track...

jetdv wrote on 2/17/2024, 7:33 PM

One, you're assuming there's only one pair of markers, which there are hundreds (as the need for the dictionary implies)

@gir489 No. I was assuming there were multiple sets. That's why I said to process them "backwards" - i.e. right to left. My process will work with hundreds of markers.

and two, there isn't a relatively easy way of determining which part of the track to move after the splice.

You would move everything on every track to the right of the "start" marker you are processing left the distance between "start" and "end".

However, track 3 just has the one event, with your solution which I tried before, it will only move it once, because I have to do a range check to see if the split occurs within the track event.

No, it would move it left a little bit for each area left of it that is removed. The same amount that all of the other tracks are moved.

  1. Start with the right-most area to remove
  2. Split everything at the beginning of that area
  3. Split everything at the end of that area
  4. Delete everything inside that area
  5. Now move everything right of that beginning on every track to the left the distance between the start and the end.
  6. Next move to the next area to the left and continue processing them BACKWARDS.

That will work and keep everything in sync. However, in your image I don't see any "Start" markers. I see "Yes" markers and "End" markers. It appears your script is searching for a marker named "Start" to indicate areas to be removed but your example images appears to have a marker named "Yes" indicating areas to keep?

In your image, it appears you've "deleted" the areas but you have "moved" anything. I'm proposing that you "move" at the same time as you "delete". But start from the right and move EVERY track the same distance.

In the above example, (since I can't see the end of the timeline assume that the events after marker 87 is the end) you would have first delete everything between markers 86 and 87 (which you have done). Now, calculate the distance between 86 and 87 and move everything on EVERY track to the right of 86 left that distance.

Now do the same thing using markers 84 and 85. Delete everything between 84 and 85, get the distance between 84 and 85, and move everything on EVERY track to the right of 84 left that distance.

Yes, some events will be moved MANY times but that's OK.

 

You could still do it as two steps. Now that you have the first step with the areas deleted, go through using the same process above processing the markers backwards. But still everything after 86 move left the distance between 86 and 87. Then everything after 84 move left the distance between 84 and 85. And just continue left until you've processed all markers the second time.

jetdv wrote on 2/20/2024, 8:09 AM

@gir489, did you ever figure this out?