Revese TrackEvent

nonam3 wrote on 10/30/2021, 4:56 PM

Hello,

I want to reverse `TrackEvent`, in c# script, so it plays backwards, unfortunately I can't figure it out. Did seen API documentation and only method for reverse is Subclip but when doing same in Vegas I see no additional subclip so I suppose it's not the way it's done by reverse tool.

Currently I'm stuck on step when I have `TrackEvent` but can't figure out way to access media and reverse playback it.

Any advice more then welcome.
Best regards.

Comments

jetdv wrote on 10/30/2021, 8:05 PM
Did seen API documentation and only method for reverse is Subclip but when doing same in Vegas I see no additional subclip so I suppose it's not the way it's done by reverse tool.

If you right-click an event on the timeline and choose "Reverse", it DOES create a subclip! You can see the subclip in the Project Media tab.

jetdv wrote on 10/30/2021, 8:57 PM

Add a velocity envelope to the event and set it to -100%. That will play it from the beginning of the event backwards so make sure the "beginning" of the clip is set to the actual "end" position where you wish it to start once it goes backwards.

Set "PointLoc" to a timecode of 0 and "PointSpeed" to -1.

This will need to be done on a "VideoEvent" - not a "TrackEvent". But you can change a track event to a video event.

VideoEvent vevnt = (VideoEvent)TrackEvent;

 

VelEnv = new Envelope(EnvelopeType.Velocity);
vevnt.Envelopes.Add(VelEnv);

EnvelopePoint a = VelEnv.Points.GetPointAtX(PointLoc);  
if (a == null) {
    a = new EnvelopePoint(PointLoc, PointSpeed);
    VelEnv.Points.Add(a);
} else {
    a.Y = PointSpeed;
}

 

It appears you can also create a sub-clip and set it to be reversed (from the API file):

class Subclip : Media

Constructors:Summary:

Subclip

(

Project project,
String path,
Timecode start,
Timecode length,
Boolean reverse,
String displayName

)

Create a new media subclip.Parameters:

project: Project.ActiveProject or a specific project
path: full path of source media file
start: start offset in source media
length: length of subclip
reverse: whether the subclip is reversed
displayName: display name of subclip

 

nonam3 wrote on 10/31/2021, 4:32 PM

Thank You @jetdv for Your insights.

Indeed I overlooked sub clip creation because there was already such subclip in my test project.

In the spirit of sharing and for the posterity below is sample code (not tested much) with comments that does this, comments are more then welcome:

private TrackEvent duplicateEvent(TrackEvent tEvent, Timecode evStart, Timecode length, bool reverse, bool duplicateGroups = true)
{
    if (tEvent == null)
    {
        return null;
    }    

// tEvent - current event, first one
// duplicatedEvent - newly created event, second one    

TrackEvent duplicatedEvent = tEvent.Copy(tEvent.Track, tEvent.End);    
if (duplicatedEvent == null)
    {
        return null;
    }    

duplicatedEvent.Selected = true;    
// set position for start to end of original event
duplicatedEvent.Start = evStart;
duplicatedEvent.Length = length;    
tEvent.Selected = false;    

// reverse media
    if (reverse)
    {
// using SubClip to reverse source media in it
// subclips add suffix, last param, like: "- subclip 1(reversed)", below code doesn't        

// create reverse subclip
        Subclip subclip = new Subclip(tEvent.Project,
                                      tEvent.ActiveTake.Media.FilePath,
                                      new Timecode(),
                                      tEvent.ActiveTake.MediaStream.Length,
                                      true,
                                      tEvent.ActiveTake.Media.FilePath);        

// add new take with reverse subclip to list
        // TODO: proper stream detection, here just first stream is take
        Take revTake = new Take(subclip.Streams.First(), true);
        duplicatedEvent.Takes.Add(revTake);        
// make duplicated trackevent use that revese take
        duplicatedEvent.ActiveTake = revTake;        
// update offset, its reversed and substract event length
        duplicatedEvent.ActiveTake.Offset = (tEvent.ActiveTake.Media.Length - tEvent.ActiveTake.Offset) - tEvent.Length;
    }
    return duplicatedEvent;
}

and calling it like so, this was part of the loop over selected events in selected track:

TrackEvent tEvent = track.Events.ElementAt(j);
if (!tEvent.Selected) { continue; }
// duplicate first time, reverse
TrackEvent dupEvent = duplicateEvent(tEvent, tEvent.End, tEvent.Length, true);
// duplicate second time, no reverse
duplicateEvent(tEvent, dupEvent.End, tEvent.Length, false);

Yet again @jetdv thank You !

jetdv wrote on 11/1/2021, 9:34 AM

Glad I could help point you in the right direction.

Steve_Rhoden wrote on 12/5/2023, 3:27 PM

Wanted to give this script a try, but got errors with the above info.. Would be good to get this working. Was hoping for, after clicking the script, it creates a subclip of the selected event, and then reverse it..... Similar to exactly what right clicking and then select reverse, does.... But i prefer having a script instead fa my specific workflow.

jetdv wrote on 12/5/2023, 4:02 PM

@Steve_Rhoden, this shows how to create a sub-clip with code:

Notice on the line where it creates the actual sub-clip it says "false". Change that to "true" and the sub-clip will be reversed.

 

Steve_Rhoden wrote on 12/6/2023, 9:24 AM

@jetdv Thanks Edward.... but unfortunately still keep getting a missing message or some other error pop up every time. Feels so frustrating why i can never get my head properly wrapped around script creation 😠

I went further, altering it to create a different one without needing any regions.... so as to sub-clip and reverse any selected event, (dont laugh lol).... Could you help point out the errors, Thanks:

using System;
using System.Collections.Generic;
using System.Collections;
using System.IO;
using System.Text;
using System.Windows.Forms;
using System.Globalization;
using System.Drawing;
using System.Runtime;
using System.Xml;
using ScriptPortal.Vegas;

namespace Test_Script
{
    public class Class1
    {
        public Vegas myVegas;

        public void Main(Vegas vegas)
        {
            myVegas = vegas;

            foreach (ScriptPortal.Vegas)
            {

                foreach (Track myTrack in myVegas.Project.Tracks)
                {

                    foreach (TrackEvent evnt in myTrack.Events)
                    {

                        if (evnt.Selected)
                        {

                            Take MyTake = evnt.ActiveTake;
                            String FullPath = MyTake.MediaPath;

                            Media mymedia = new Subclip(myVegas.Project, FullPath, MyTake.Offset + (Position - evnt.Start), Length, true, Label);

                         }

                    }

                }

            }

       }

   }

}

jetdv wrote on 12/6/2023, 10:17 AM

@Steve_Rhoden, a few questions:

Did you purposely just leave this off the bottom? This is the code that VEGAS actually executes when the script is started:

public class EntryPoint
{
    public void FromVegas(Vegas vegas)
    {
        Test_Script.Class1 test = new Test_Script.Class1();
        test.Main(vegas);
    }
}

What are you trying to do with this line?

foreach (ScriptPortal.Vegas)

This is what you have as the "Start" parameter to creating the new sub-clip:

MyTake.Offset + (Position - evnt.Start)

You have not defined "Position". In my example, I was using the region position as the starting place. If you're wanting the full event on the timeline then "MyTake.Offset" should be fine.

This is what you have as the "Length" parameter for creating the new sub-clip:

Length

Once again, "Length" has not been defined. I was using the region length in the example. If you want the entire event, you can just use "evnt.Length".

Finally, what you have for the last parameter is:

Label

This is also not defined. I was using the region label in the example. However, you can just use "". So that line would be better as:

Media mymedia = new Subclip(myVegas.Project, FullPath, MyTake.Offset, evnt.Length, true, "");

Please note that that creates the new "reversed" media but does not place it on the timeline.

If you use this code, it will properly reverse the entire selected event by creating the sub-clip and then add that reversed sub-clip as a new take to that selected event. Then you can select that event and just press "T" to go back and forth between forward and reversed.
 

using System;
using System.Collections.Generic;
using System.Collections;
using System.IO;
using System.Text;
using System.Windows.Forms;
using System.Globalization;
using System.Drawing;
using System.Runtime;
using System.Xml;
using ScriptPortal.Vegas;

namespace Test_Script
{
    public class Class1
    {
        public Vegas myVegas;

        public void Main(Vegas vegas)
        {
            myVegas = vegas;

            foreach (Track myTrack in myVegas.Project.Tracks)
            {
                foreach (TrackEvent evnt in myTrack.Events)
                {
                    if (evnt.Selected)
                    {
                        Take MyTake = evnt.ActiveTake;
                        String FullPath = MyTake.MediaPath;

                        Media mymedia = new Subclip(myVegas.Project, FullPath, MyTake.Offset, evnt.Length, true, "");

                        MediaStream newStream = null;
                        if (evnt.IsAudio())
                        {
                            newStream = mymedia.Streams.GetItemByMediaType(MediaType.Audio, 0);
                        }
                        else
                        {
                            newStream = mymedia.Streams.GetItemByMediaType(MediaType.Video, 0);
                        }

                        Take newTake = new Take(newStream);
                        evnt.Takes.Add(newTake);

                    }
                }
            }
        }
    }
}

public class EntryPoint
{
    public void FromVegas(Vegas vegas)
    {
        Test_Script.Class1 test = new Test_Script.Class1();
        test.Main(vegas);
    }
}

 

Steve_Rhoden wrote on 12/6/2023, 11:00 AM

@jetdv Man, i wish i had your script writing skills.... With my in depth knowledge of Vegas coupled with your script writing / programming expertise, i would simply just take over development of Vegas and leave Magix to handle the marketing side lol 😂😂.

Words cannot express my appreciation for all the years you have assisted me in this field my friend... Thank You!

Just one more thing. Do you know why after a sub-clip is created, why is there this added extra frame at the end of it? and is there a way to stop or bypass this?

 

jetdv wrote on 12/6/2023, 11:08 AM

@Steve_Rhoden In my test, I'm not seeing any extra frames.But I'm sure you could just adjust the "Length" to be (evnt.Length - Timecode.FromFrames(1)) and that will take one frame off. But I'd have to have more information.

Steve_Rhoden wrote on 12/6/2023, 1:34 PM

@jetdv My mistake..... Did some test and found out that something was actually wrong with the media i was testing the scripts on. Everything is now working beautifully!

Thiago_Sase wrote on 2/11/2025, 7:01 AM

@jetdv Hello Sir, please, if possible, can you help me?

I'm facing some issues on creating a script that involves reverse logic. After searching on this forum about the subject, I found out this Post.

I used your script to reverser a selected event, ok, it works perfect, it reverses the selected event. This is your script;
 

using System;
using System.Collections.Generic;
using System.Collections;
using System.IO;
using System.Text;
using System.Windows.Forms;
using System.Globalization;
using System.Drawing;
using System.Runtime;
using System.Xml;
using ScriptPortal.Vegas;

namespace Test_Script
{
    public class Class1
    {
        public Vegas myVegas;

        public void Main(Vegas vegas)
        {
            myVegas = vegas;

            foreach (Track myTrack in myVegas.Project.Tracks)
            {
                foreach (TrackEvent evnt in myTrack.Events)
                {
                    if (evnt.Selected)
                    {
                        Take MyTake = evnt.ActiveTake;
                        String FullPath = MyTake.MediaPath;

                        Media mymedia = new Subclip(myVegas.Project, FullPath, MyTake.Offset, evnt.Length, true, "");

                        MediaStream newStream = null;
                        if (evnt.IsAudio())
                        {
                            newStream = mymedia.Streams.GetItemByMediaType(MediaType.Audio, 0);
                        }
                        else
                        {
                            newStream = mymedia.Streams.GetItemByMediaType(MediaType.Video, 0);
                        }

                        Take newTake = new Take(newStream);
                        evnt.Takes.Add(newTake);

                    }
                }
            }
        }
    }
}

public class EntryPoint
{
    public void FromVegas(Vegas vegas)
    {
        Test_Script.Class1 test = new Test_Script.Class1();
        test.Main(vegas);
    }
}

But, now lies my issue;

After run the script and made the reversed logic, if I do an UNDO operation, that selected event goes black in the preview screen. Can you reproduce that? If so, how to fix it?

Last changed by Thiago_Sase on 2/11/2025, 7:02 AM, changed a total of 1 times.

OS: Windows 10 22H2
CPU: Intel Core I7 12700
MEMORY: 32GB DDR4 3200MHz
GHAPHIC CARD: RTX 3060 8GB
HARD DRIVES: SSD for System and M.2 for Media Files

nonam3 wrote on 2/11/2025, 7:16 AM

I may be wrong on this one but the reason why it goes black after undo is because event that reference that reversed track is gone but script above doesn't have undo block so the newly created event stays on track.

"Correct behaviour" of this script, with undo block, would result in that event track also being gone.

So the simple solution for this is ... just don't undo things :)

jetdv wrote on 2/11/2025, 8:52 AM

@nonam3 it doesn't have an undo block because it isn't a custom command. Undo after running a script should revert back to how it was before the script.

@Thiago_Sase I'll have to test it out. What version should I test in?

Thiago_Sase wrote on 2/11/2025, 8:56 AM

@jetdv I test it in version 22 - build 239.

Last changed by Thiago_Sase on 2/11/2025, 8:57 AM, changed a total of 1 times.

OS: Windows 10 22H2
CPU: Intel Core I7 12700
MEMORY: 32GB DDR4 3200MHz
GHAPHIC CARD: RTX 3060 8GB
HARD DRIVES: SSD for System and M.2 for Media Files

jetdv wrote on 2/11/2025, 11:28 AM

@Thiago_Sase, I can confirm the same thing happened for me. In fact, it happened to ALL events that were the same media that was initially reversed. I only reversed one event and three of them went black after the "Undo".

jetdv wrote on 2/11/2025, 12:11 PM

@Thiago_Sase I can now also confirm that it's an issue with versions 14 thru 22. I don't have older than that on this machine to test.

Thiago_Sase wrote on 2/11/2025, 12:43 PM

@jetdv Sir, I did those tests too.

Undo after run the script make the preview screen goes Black;

Vegas Pro 14 build 270 - No black screen. Undo works normal;
Vegas Pro 15 build 416 - black screen.
Vegas Pro 16 build 424 - black screen.
Vegas Pro 17 build 455 - black screen.
Vegas Pro 18 build 527 - No black screen. Undo works normal;
Vegas Pro 19 build 651 - black screen.
Vegas Pro 20 build 403 - black screen.
Vegas Pro 21 build 208 and 315 - black screen.
Vegas Pro 22 build 239 - black screen.

I have no idea why undo works normal after run the script with no black preview screen in Versions 14 & 18.

The best solution for now is indeed what @nonam3 said, right?;

So the simple solution for this is ... just don't undo things :)


 

Last changed by Thiago_Sase on 2/11/2025, 12:44 PM, changed a total of 2 times.

OS: Windows 10 22H2
CPU: Intel Core I7 12700
MEMORY: 32GB DDR4 3200MHz
GHAPHIC CARD: RTX 3060 8GB
HARD DRIVES: SSD for System and M.2 for Media Files

jetdv wrote on 2/11/2025, 12:58 PM

Or, possibly, run the script again?

I got black on every version.

Thiago_Sase wrote on 2/12/2025, 5:55 AM

@jetdv Sir, one more question, please;

And about to reverse trimmed event that has its playback rate altered, is that possible?

I know I can simply right-click in the selected event and choose the native Reverse option of Vegas, but I'm creating a script that has a section that is about reverse. I accept the Undo issue, but now I face the event that is trimmed with playback rate modified problem.
 

Thiago_Sase wrote on 2/12/2025, 7:50 AM

@jetdv I'm almost there, Sir;
 

using System;
using System.Collections.Generic;
using System.Collections;
using System.IO;
using System.Text;
using System.Windows.Forms;
using System.Globalization;
using System.Drawing;
using System.Runtime;
using System.Xml;
using ScriptPortal.Vegas;

namespace Test_Script
{
    public class Class1
    {
        public Vegas myVegas;

        public void Main(Vegas vegas)
        {
            myVegas = vegas;

            foreach (Track myTrack in myVegas.Project.Tracks)
            {
                foreach (TrackEvent evnt in myTrack.Events)
                {
                    if (evnt.Selected)
                    {
                        Take MyTake = evnt.ActiveTake;
                        String FullPath = MyTake.MediaPath;

                        // Preserve the current playback rate
                        double currentPlaybackRate = evnt.PlaybackRate;

                        // Get the correct media offset and length after trimming
                        Timecode mediaOffset = MyTake.Offset;
                        Timecode eventLength = evnt.Length;

                        // Calculate the new reversed start point
                        Timecode reversedStart = mediaOffset + MyTake.Length - eventLength;

                        // Create the reversed subclip
                        Media mymedia = new Subclip(myVegas.Project, FullPath, reversedStart, eventLength, true, "");

                        MediaStream newStream = null;
                        if (evnt.IsAudio())
                        {
                            newStream = mymedia.Streams.GetItemByMediaType(MediaType.Audio, 0);
                        }
                        else
                        {
                            newStream = mymedia.Streams.GetItemByMediaType(MediaType.Video, 0);
                        }

                        Take newTake = new Take(newStream);
                        evnt.Takes.Add(newTake);

                        // Maintain the exact playback rate without altering it
                        evnt.PlaybackRate = currentPlaybackRate;
                    }
                }
            }
        }
    }
}

public class EntryPoint
{
    public void FromVegas(Vegas vegas)
    {
        Test_Script.Class1 test = new Test_Script.Class1();
        test.Main(vegas);
    }
}

Event that has normal playback rate (full original length duration) - Works like Vegas native reverse option.

Event that has altered / modified playback rate (full original length duration) - Works like Vegas native reverse option.

Event that is trimmed and has normal playback rate (offset trimmed length duration) - Works like Vegas native reverse option.

Event that is trimmed and has ALTERED / MODIFIED playback rate (offset trimmed length duration) - Does not work like Vegas native reverse option. It is not reversing, starting from the OFFSET.

Sir, Please, if possible, can you show me where is my mistake?

Thiago_Sase wrote on 2/12/2025, 1:28 PM

I tried a lot of alternatives and methods to fix that, but I fail in all of them. In the end, the only solution that I found it was to add this;

"MessageBox.Show("Playback rate is altered. You must render the event as a new take."

// Stop execution if playback rate is altered
            if (this.ShowMessagePlaybackrateisaltered())
            {
                return;
            }


public bool ShowMessagePlaybackrateisaltered()
        {
            // Get the selected event from the timeline
            TrackEvent selectedEvent = GetSelectedEvent();
            if (selectedEvent != null && selectedEvent.PlaybackRate != 1.000)
            {
                MessageBox.Show("Playback rate is altered. You must render the event as a new take.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return true; // Stop execution
            }
            return false; // Continue execution
        }

@jetdv @nonam3 Thanks for trying to help. ✌️

jetdv wrote on 2/12/2025, 2:11 PM

It's certainly a tricky situation and that was probably the easiest option. The big problem is you're trying to "start at the end" and the "end" has been modified because of the speed change. I am somewhat surprised that creating the new sub-clip did not work but can certainly see how it would still be problematic. It would certainly take some thinking to get to the best solution.

nonam3 wrote on 2/12/2025, 2:24 PM

@Thiago_Sase

You need to correctly calculate "new start" based on playback rate and offset.
Your offset doesn't take into account playback rate, its from non reversed take, so You will need to calculate it (offset * playbackRate) to get new correct starting point of reversed track event with different playback rate, There could be more to that.