Continue to Stretch Playback Rate if it's already stretched

Thiago_Sase wrote on 9/2/2024, 7:10 AM

@jetdv Sir, please, when you have free time for this, how I solve this issue in the code below. I did a video trying to explain;



 

using System;
using ScriptPortal.Vegas;

namespace Test_Script
{
    public class Class1
    {
        public Vegas myVegas;
        public void Main(Vegas vegas)
        {
            myVegas = vegas;

            foreach (Track currentTrack in myVegas.Project.Tracks)
            {
                if (currentTrack.IsVideo())
                {
                    foreach (TrackEvent currentEvent in currentTrack.Events)
                    {
                        if (currentEvent.Selected)
                        {
                            Timecode targetLength = Timecode.FromSeconds(5);
                            Timecode currentLength = currentEvent.Length;

                            if (currentLength < targetLength)
                            {
                                double newPlaybackRate = currentLength.ToMilliseconds() / targetLength.ToMilliseconds();

                                Timecode offset = currentEvent.ActiveTake.Offset;
                                Timecode newOffset = Timecode.FromMilliseconds(offset.ToMilliseconds() / newPlaybackRate);

                                currentEvent.PlaybackRate = newPlaybackRate;
                                currentEvent.ActiveTake.Offset = newOffset;

                                currentEvent.Length = targetLength;

                                foreach (TrackEvent audioEvent in currentEvent.Group)
                                {
                                    if (audioEvent.IsAudio())
                                    {
                                        audioEvent.PlaybackRate = newPlaybackRate;

                                        Timecode audioOffset = audioEvent.ActiveTake.Offset;
                                        Timecode newAudioOffset = Timecode.FromMilliseconds(audioOffset.ToMilliseconds() / newPlaybackRate);
                                        audioEvent.ActiveTake.Offset = newAudioOffset;

                                        audioEvent.Length = targetLength;
                                    }
                                }
                            }

                            FixUnquantizedFrames(currentEvent);

                            foreach (TrackEvent groupedEvent in currentEvent.Group)
                            {
                                if (groupedEvent.IsAudio())
                                {
                                    FixUnquantizedFrames(groupedEvent);
                                }
                            }
                        }
                    }
                }
            }
        }


        private void FixUnquantizedFrames(TrackEvent evt)
        {
            double frameRate = myVegas.Project.Video.FrameRate;
            double frameDurationMs = 1000.0 / frameRate;

            double startMs = evt.Start.ToMilliseconds();
            evt.Start = new Timecode(Math.Round(startMs / frameDurationMs) * frameDurationMs);

            double lengthMs = evt.Length.ToMilliseconds();
            evt.Length = new Timecode(Math.Round(lengthMs / frameDurationMs) * frameDurationMs);
        }
    }
}


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

 

Comments

jetdv wrote on 9/2/2024, 9:57 AM

Don't change the "offset". The "Offset" is what changes the beginning of the event. So as long as the offset stays the same, the beginning frame will stay the same.

                                //Timecode newOffset = Timecode.FromMilliseconds(offset.ToMilliseconds() / newPlaybackRate); 

                                currentEvent.PlaybackRate = newPlaybackRate; 
                                //currentEvent.ActiveTake.Offset = newOffset;

 

Thiago_Sase wrote on 9/2/2024, 11:24 AM

@jetdv Sir, still changing the beginning of the event.

 

using System;
using ScriptPortal.Vegas;

namespace Test_Script
{
    public class Class1
    {
        public Vegas myVegas;
        public void Main(Vegas vegas)
        {
            myVegas = vegas;

            foreach (Track currentTrack in myVegas.Project.Tracks)
            {
                if (currentTrack.IsVideo())
                {
                    foreach (TrackEvent currentEvent in currentTrack.Events)
                    {
                        if (currentEvent.Selected)
                        {
                            Timecode targetLength = Timecode.FromSeconds(5);
                            Timecode currentLength = currentEvent.Length;

                            if (currentLength < targetLength)
                            {
                                double newPlaybackRate = currentLength.ToMilliseconds() / targetLength.ToMilliseconds();

                                Timecode offset = currentEvent.ActiveTake.Offset;
                                //Timecode newOffset = Timecode.FromMilliseconds(offset.ToMilliseconds() / newPlaybackRate);

                                currentEvent.PlaybackRate = newPlaybackRate;
                                //currentEvent.ActiveTake.Offset = newOffset;

                                currentEvent.Length = targetLength;

                                foreach (TrackEvent audioEvent in currentEvent.Group)
                                {
                                    if (audioEvent.IsAudio())
                                    {
                                        audioEvent.PlaybackRate = newPlaybackRate;

                                        Timecode audioOffset = audioEvent.ActiveTake.Offset;
                                        Timecode newAudioOffset = Timecode.FromMilliseconds(audioOffset.ToMilliseconds() / newPlaybackRate);
                                        audioEvent.ActiveTake.Offset = newAudioOffset;

                                        audioEvent.Length = targetLength;
                                    }
                                }
                            }

                            FixUnquantizedFrames(currentEvent);

                            foreach (TrackEvent groupedEvent in currentEvent.Group)
                            {
                                if (groupedEvent.IsAudio())
                                {
                                    FixUnquantizedFrames(groupedEvent);
                                }
                            }
                        }
                    }
                }
            }
        }


        private void FixUnquantizedFrames(TrackEvent evt)
        {
            double frameRate = myVegas.Project.Video.FrameRate;
            double frameDurationMs = 1000.0 / frameRate;

            double startMs = evt.Start.ToMilliseconds();
            evt.Start = new Timecode(Math.Round(startMs / frameDurationMs) * frameDurationMs);

            double lengthMs = evt.Length.ToMilliseconds();
            evt.Length = new Timecode(Math.Round(lengthMs / frameDurationMs) * frameDurationMs);
        }
    }
}


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

 

bvideo wrote on 9/2/2024, 12:49 PM

@Thiago_Sase I'm guessing this is a better match to your intention (add):

newPlaybackRate *= currentEvent.PlaybackRate;

Also there is a scripting API: AdjustPlaybackRate (member of TrackEvent) that includes an option for changing the start or the end. I'm not sure what the advantage is over modifying rate and length yourself, but it seems clear what it intends.

 

Thiago_Sase wrote on 9/2/2024, 1:20 PM

@bvideo Thanks for trying to help as well. I added that but behaves the same.
I'll read Timecode Class from the API, and I'll try to understand.

If the Playback rate of the selected event is set to default 1,000 the script works as expected. But if I select an event and its playback rate is 0,300 for example, when I run the script the start frame of the event (Offset ?) will change.

jetdv wrote on 9/2/2024, 1:54 PM

@Thiago_Sase, your initial code in the first post worked fine for me. The first frame did not change (and I made sure my first frame was not the beginning of the media.)

Thiago_Sase wrote on 9/2/2024, 2:02 PM

@jetdv Sir, you're right, the initial code works fine if the playback rate is set as the default value 1,000. But the initial code will change the first frame if the playback rate of the selected event is set to 0,300, for example.

jetdv wrote on 9/2/2024, 2:54 PM

@Thiago_Sase see if this fixes it. If the initial playback rate is not 1, convert it back to 1 and then convert it to the new playback rate:

                                Timecode offset = currentEvent.ActiveTake.Offset;
                                if (currentEvent.PlaybackRate != 1.0)
                                {
                                    offset = Timecode.FromMilliseconds(offset.ToMilliseconds() * currentEvent.PlaybackRate);
                                }

                                Timecode newOffset = Timecode.FromMilliseconds(offset.ToMilliseconds() / newPlaybackRate);

 

Thiago_Sase wrote on 9/2/2024, 4:04 PM

@jetdvSir, It worked!
 I also added these lines before yours;

// Decrease playback rate further if it's already lower than the calculated newPlaybackRate
if (currentEvent.PlaybackRate < newPlaybackRate)
  {
    newPlaybackRate = currentEvent.PlaybackRate * (currentLength.ToMilliseconds() / targetLength.ToMilliseconds());
  }

Now works exactly like doing manually (Ctrl+drag).

Thank you very much.

Last changed by Thiago_Sase on 9/2/2024, 4:06 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

bvideo wrote on 9/2/2024, 7:20 PM

@Thiago_Sase A few other issues come to mind when changing an event length or rate:

  • effect keyframes on the event do not get automatically scaled by the scripting API.
  • an audio event grouped to the video event being changed does not get changed, nor its keyframes.
  • the events that follow on the track do not get rippled (same on the track of a grouped audio event)
  • the track keyframes don't follow the length change of the one event (same for grouped etc.)

Of course, if you don't use rippling or if you don't elect track keyframes follow event, the last two items don't matter. I don't know how one would find out about those settings from the scripting API.

By the way, code following your "Decrease further" needs to be done for larger newrate also. That was the purpose of my previous suggestion (newPlaybackRate *= currentEvent.PlaybackRate;). But now I see you only want to operate on shorter events:

if (currentLength < targetLength) { ...

 

Thiago_Sase wrote on 9/2/2024, 7:51 PM

@bvideo Thanks for the information. For sure, I'll keep those notes in mind next time I need to create a script that involve event length or rate.

 But now I see you only want to operate on shorter events:
 

Yes, the reason of this script was to deal specifically with shorter events. I'll try by one step at a time to learn from the scripting API. It's a long road ahead.