Creative Communities of the World Forums

The peer to peer support community for media production professionals.

Activity Forums Adobe After Effects Expressions Using a CSV with time information to determine layer and comp timings

  • Using a CSV with time information to determine layer and comp timings

    Posted by Perry Sheppard on July 10, 2020 at 3:40 am

    I’m new to expressions (and coding), but have worked through controlling alignment, parented font styles, linking csv data dynamically using the comp name as the variable, expression controls and a number of other simple things with master controls, but I’m beginning to think I have a fundamental misunderstanding of a couple of key elements, so my apologies if this is super basic.

    I’ve set up an excel spreadsheet where my team can enter textual content for ‘text-style’ animations for social media (the simple square videos that are primarily text with some images or video in the background). There are three text boxes in each excel row that are used as three separate text layers in an AE comp. Each row of text is a separate ‘slide’ (a comp in AE). The excel sheet is set up to automatically calculate the timings for the slide in and out points, as well as for each text layer based on standard reading rates as well as generate a caption file for accessibility.

    My goal is to create a mogrt for Premiere to simplify my team’s creation process. My team would use the excel file to enter their text, which would generate a csv for the mogrt in Premiere, as well as export a timed caption file. The audio and background video/images would be handled in Premiere (I’ll look into scripting that as my next step).

    So, my project is set up so that I can make changes to a single comp (comp 0) and then duplicate it as many times as I need to and place those ‘slide comps’ into a master comp as layers. The csv data is linked using the comp name as a guide so the csv data updates to match. My plan was to have all the slide comps (0,1,2,3…) run the entire length of the mogrt and adjust the “start, in, out, off” timings for each layer in the ‘slide comps’ as well as the start time/opacity for each comp layer in the master comp using the data from the csv. The project is working in all respects with the exception of the timing expressions.

    My setup right now doesn’t really use keyframes, but I’ve successfully used a linear expression as a test in controlling keyframes to shift the time, but that seems to be limited to two keyframes and I need to control 4. Start, In, Out, Off. So, I looked at startTime, InPoint, Offset, etc. There seems to be a lot of information about using a controller to adjust keyframes, but I haven’t been able to find anything to just use a new time provided dynamically.

    Which is why I think I’m probably experiencing a fundamental misunderstanding of how AE handles time. If anyone has any insight into how I might be able to just override timing using dynamic values, please let me know.

    Perry Sheppard replied 5 years, 10 months ago 2 Members · 10 Replies
  • 10 Replies
  • Perry Sheppard

    July 10, 2020 at 4:24 am

    For code reference, see below. I was planning to add 4 keyframes to the relevant layers/sub-properties where necessary and use the code below. I know this doesn’t work (valueAtTime is the wrong parameter to use for this), but thought I’d include it in case it clarifies what I’m trying to accomplish.

    keyAnimationStart = 1;
    keyAnimationIn = 2;
    keyAnimationOut = 3;
    keyAnimationEnd = 4;

    startTimeText = comp("Master").layer("SlideContent2.csv")("Data")("Outline")("Text1Start")("Text1Start 0"); //only need to change these values
    endTimeText = comp("Master").layer("SlideContent2.csv")("Data")("Outline")("Text1End")("Text1End 0"); //only need to change these values
    slideStart = comp("Master").layer("SlideContent2.csv")("Data")("Outline")("SlideStart")("SlideStart 0"); //only need to change these values
    slideEnd = comp("Master").layer("SlideContent2.csv")("Data")("Outline")("SlideEnd")("SlideEnd 0"); //only need to change these values

    myAnimationStart = startTimeText;
    myAnimationIn = startTimeText + valueAtTime(key(keyAnimationIn).time);
    myAnimationOut = slideEnd - valueAtTime(key(keyAnimationEnd).time) - valueAtTime(key(keyAnimationOut).time);
    myAnimationEnd = slideEnd;

    valueAtTime(key(keyAnimationStart).time + myAnimationStart);
    valueAtTime(key(keyAnimationIn).time + myAnimationIn);
    valueAtTime(key(keyAnimationOut).time == myAnimationOut);
    valueAtTime(key(keyAnimationEnd).time == myAnimationEnd);

  • Filip Vandueren

    July 10, 2020 at 10:33 am

    If I understand correctly, you are trying to accomplish that the expression would move your four keyframes to a different time ?

    Expressions cannot “physically” do that (a script could though). An expression is just a calculation that gives you a ‘(numeric) value of what the property it is on should be “now”.

    So you need to look at the current Time, and calculate a correct value from that.
    In your case, if you provide 4 keyframes, then we can look up their values.

    Let’s say we’re talking about the position of your slides, and you already set up 4 keyframes: between keyframe 1 and 2 the layer slides in, and between 3 and 4 it slides out.


    slideStart = comp("Master").layer("SlideContent2.csv")("Data")("Outline")("SlideStart")("SlideStart 0");
    slideEnd = comp("Master").layer("SlideContent2.csv")("Data")("Outline")("SlideEnd")("SlideEnd 0");

    move_in_duration = key(2).time - key(1).time;
    move_out_duration = key(4).time - key(3).time;

    if (time < slideStart + move_in_duration) { //
    valueAtTime(time-key(1).time);

    } else if (time < slideEnd - move_out_duration) {
    key(2).value; // hold at key 2

    } else {
    valueAtTime(time-key(3).time);
    }

  • Filip Vandueren

    July 10, 2020 at 10:43 am

    Sorry, I forgot a few things in my previous code:


    slideStart = comp("Master").layer("SlideContent2.csv")("Data")("Outline")("SlideStart")("SlideStart 0");
    slideEnd = comp("Master").layer("SlideContent2.csv")("Data")("Outline")("SlideEnd")("SlideEnd 0");

    move_in_duration = key(2).time - key(1).time;
    move_out_duration = key(4).time - key(3).time;

    if (time < slideStart + move_in_duration) { //
    valueAtTime(time + key(1).time - slideStart);

    } else if (time < slideEnd - move_out_duration) {
    key(2).value; // hold at key 2

    } else {
    valueAtTime(time + key(3).time - (slideEnd - move_out_duration))
    }

  • Perry Sheppard

    July 10, 2020 at 6:33 pm

    Thanks Filip. Given what you’ve said, and that I only have one layer animator with keyframes, I suspect I’d be better off writing an expression to set the values using expressions without the need for keyframes.

    Is there an example where I could set values at specific times like I would using a linear expression, but that would work with four points on the layer instead of just two?

    This would be:
    1. Start time of the layer and its value
    2. In time of the layer and its value
    3. Out time of the layer and its value
    4. Off time of the layer and its value

    Thanks again. I cannot tell you how much I’ve benefited from the shared knowledge available here. It’s much appreciated.

    Best,
    Perry

  • Filip Vandueren

    July 10, 2020 at 7:52 pm

    There is no method built in for a sort of “timeline” with multiple times and values.
    If you know in advance how many different interpolations you need,
    You would use if/then::

    pseudocode:
    If time is less than t2
    Linear (time, t1, t2, value1, value2)
    Else if time is less than t3
    Linear(time, t2,t3, value2, value3)
    Else
    Linear(time, t3, t4, value3, vue4)

    Downside is that you are limited to linear/ease/easeIn/easeOut.
    If you supply the keyframes as in my previous example, then you also get any fancy non-linear interpolation curves between the keyframes.

  • Perry Sheppard

    July 10, 2020 at 7:53 pm

    I took another look at the code you provided and I think I understand how it’s working. I added the start and end times for the specific text item because I need to stagger the three animations for the three text layers, but they all have the same out time. I’ll sort that out once I have an understanding of the base code you provided.

    I took a stab at modifying the code you provided, so it doesn’t rely on keyframes, but I know I haven’t gotten this right. I think I’m misunderstanding the valueAtTime, how to declare a time value, and how to declare a value and reference it at a specific time.

    slideStart = comp("Master").layer("SlideContent2.csv")("Data")("Outline")("SlideStart")("SlideStart 0");
    startTimeText = comp("Master").layer("SlideContent2.csv")("Data")("Outline")("Text1Start")("Text1Start 0");
    endTimeText = comp("Master").layer("SlideContent2.csv")("Data")("Outline")("Text1End")("Text1End 0");
    slideEnd = comp("Master").layer("SlideContent2.csv")("Data")("Outline")("SlideEnd")("SlideEnd 0");

    slideOn = slideStart
    slideIn = startTimeText + 2
    slideOut = slideOff - 2
    slideOff = slideEnd

    move_in_duration = slideIn - slideOn; //could also set this as a number for the transition length
    move_out_duration = slideOff - slideOut; //could also set this as a number for the transition length

    if (time &lt; slideStart + move_in_duration) { //
    valueAtTime(time + slideOn - slideStart);

    } else if (time &lt; slideEnd - move_out_duration) {
    slideIn; // hold at key 2

    } else {
    valueAtTime(time + slideOut - (slideEnd - move_out_duration))
    }

  • Perry Sheppard

    July 10, 2020 at 7:58 pm

    Oh. I think I get it now. Because the property ‘time’ is constantly being evaluated, and if/else statement can be used to change the value of a layer multiple times.

  • Perry Sheppard

    July 14, 2020 at 8:10 pm

    So, I finally broke down and went with the keyframe control option for a position property on an expression selector. I’ve modified the timing code a little bit to hold on key3 because I want to use this expression from Dan Ebberts for the position bounce (code below).

    The timing code (inserted below) and the bounce code work on their own, but I cannot for the life of me get them to work together (six hours of research, tutorials and code attempts and no glory). If there’s a tutorial on something like this, I’d be happy to go that route, but I haven’t been able to find anything.

    If there’s a way to integrate the two I’d appreciate the help. Thanks!

    transitionLength1 = key(3).time - key(1).time;
    transitionLength2 = key(4).time - key(3).time;

    t1 = startTimeText;
    t6 = mySlideEnd - transitionLength2;

    //if statement for timing

    if (time &lt; t1 + transitionLength1)
    {
    valueAtTime(time + key(1).time - t1);
    }
    else if (time &lt; t6) {
    key(3).value; // hold at key 3 because the bounce continues to key 3 and t6 is slideEnd - transitionLength2
    }
    else {
    valueAtTime(time + key(4).time - t6) //t6 is slide end - transitionLength2
    }

    //bounce statement
    freq = 3;
    decay = 4.5;

    n = 0;
    if (numKeys &gt; 0){
    n = nearestKey(time).index;
    if (key(n).time &gt; time) n--;
    }
    if (n &gt; 0){
    t = time - key(n).time;
    amp = velocityAtTime(key(n).time - .001);
    w = freq*Math.PI*2;
    value + amp*(Math.sin(t*w)/Math.exp(decay*t)/w);
    }else
    value

  • Filip Vandueren

    July 14, 2020 at 10:10 pm

    Something like this:


    transitionLength1 = key(3).time - key(1).time;
    transitionLength2 = key(4).time - key(3).time;

    t1 = 3;
    t6 = 10 - transitionLength2;

    //if statement for timing

    if (time < t1 + transitionLength1)
    {
    time_offset = time + key(1).time - t1;
    //bounce statement
    freq = 3;
    decay = 4.5;

    n = 0;
    if (numKeys > 0){
    n = nearestKey(time_offset).index;
    if (key(n).time > time_offset) n--;
    }
    if (n > 0){
    t = time_offset - key(n).time;
    amp = velocityAtTime(key(n).time - .001);
    w = freq*Math.PI*2;
    valueAtTime(time_offset) + amp*(Math.sin(t*w)/Math.exp(decay*t)/w);
    }else
    valueAtTime(time_offset);
    // valueAtTime(time + key(1).time - t1);
    }
    else if (time < t6) {
    key(3).value; // hold at key 3 because the bounce continues to key 3 and t6 is slideEnd - transitionLength2
    }
    else {
    valueAtTime(time + key(3).time - t6) //t6 is slide end - transitionLength2
    }

  • Perry Sheppard

    July 14, 2020 at 11:15 pm

    Thanks Filip. That did the trick. I was about to resort to TypeArray, but I’m really trying to learn as much as I can before I start relying on pre-built solutions.

    Based on the code changes you made, defining ‘time_offset’ cleaned things up quite a bit. I was trying something similar, but wrote it out in longform in each instance and then started adding ‘t1’ to key(n).time everywhere. It also looks like I need to do some additional reading on ‘nearestKey’ because I was trying n = nearestKey(time + t1).index.

    Really appreciate the assistance on this. This was the last thing I wanted to add to this project, so I should have a working solution in the next couple of days to help my colleagues out (this isn’t actually part of my job, but they’re so busy right now I wanted to see if I could help them out). Thanks!

We use anonymous cookies to give you the best experience we can.
Our Privacy policy | GDPR Policy