Creative Communities of the World Forums

The peer to peer support community for media production professionals.

  • Posted by Charles Cazal on January 5, 2022 at 9:22 pm

    Hello fellow creators, it’s my first post here, I hope I’m not crossing any rule.

    A little bit of context on what I’m trying to achieve:

    I’m a music maker, and I’ve decided to create video templates for my music videos (a different template depending on if it’s a remix, or an original piece, etc). For one of my templates, I wanted to make a beat counter, so that I could change a rotation value by x degrees everytime there’s a beat (cumulatively).


    Here’s what I’ve done so far:

    – I’ve created a Spectrum layer, with an Audio Spectrum effect reacting to my audio, and a Scanner Layer with a small shape in it, that I use for getting alpha information via sampleImage();

    – I’ve decided to use that instead of the AudioToKeyframes method, so that the template require less actions everytime I use it (just have to change audio, and not create the keyframes everytime, plus it lets more freedom to adapt the scanner to react to something else altogether than the kick via frequency targetting);

    – I’m using a test layer with a few Sliders on it: a Base Slider, using the expression “time*10” to get its value, an Inc Slider which gets a fixed value for increasing/decreasing the rotation, and an Output Slider, with the following expression:

    if(kick==1){x=base+inc;}else{x=base;}; x

    (where kick is the value of sampleImage[3], and other variables point to similarly named sliders)

    This slider is then used as the layer’s rotation value.


    The trouble I’m having is that the rotation increase doesn’t stick, because of course, when the kick gets out of my scanner, the expression tells the engine to go back to base value.


    So, I tried adapting Dan Ebbert’s Audio Beat Counter, but I don’t know if it’s the while loop iteration for the song’s duration, or if it’s the fact that I rely on scanImage, but the rendering of just that took forever. And that’s without all the other animations I’ve already done and hidden.


    So, yeah, is there a way to actually increment the rotation value, without spending more than 2hrs rendering a 5min video of a text layer rotating with each kick? I’m sure it’s not a processing power issue, since I usually have no trouble working with AE and Ps and Ai open, multitasking on the visuals.

    There’s got to be a simpler way, without using the audiotokeyframes way? I unfortunately can’t always separate the sounds I want my video to react to into different audiofiles for different audiotokeyframes triggers, using the spectrum+sampleImage method shows such flexibility that I’d rather stick with it.


    Sorry for the excruciatingly long post, I went for details, let me know if that’s too much and I’ll shorten my next ones 🙂


    P.S. By the way, a thousand thanks to Dan Ebbert for the real useful website and work, still available freely to this day. Dan, you’re the man.

    Andrei Popa replied 1 year, 4 months ago 2 Members · 7 Replies
  • 7 Replies
  • Andrei Popa

    January 6, 2022 at 8:33 am

    I think the sampleImage() function is pretty demanding. And the fact that you recursively use it must be what makes the render so slow. Just think that for the last frame, your expression must calculate all the values before, for each frame.

    You could either use the AudioToKeyFrames() to see if that is faster or make a script that sets keyframes each time it finds a kick. Because scripts have memory, you do not have to use while and go back in time each frame.

    For the script, you could do it like this.

    Check when kick is one and add a keyframe. The script should look similar to this

    myComp = app.project.activeItem;
    myKickSlider = myComp.layer("Kick count").effect("Slider Control")("Slider");
    //delete previous keyframes
    for (i = myKickSlider.numKeys; i >= 1; i--) {
    //add new ones
    for (var i = 1; i <= timeToFrames(myComp.duration); i++) {
        if (myKickSlider.valueAtTime(framesToTime(i)) == 1) {
            myKickSlider.setValueAtTime(framesToTime(i), 1);

    Then the OutputSlider should have an expression similar to this:

    kicks = thisComp.layer("Kick count").effect("Slider Control")("Slider");
    k = kicks.nearestKey(time);
    n = k.index;
    if (time < k.time) n--;
    addedRotation = inc * n;

    base + addedRotation;

    You should define base and inc prior to this part.

    Haven’t tested these, so they may need a little tweak.

  • Charles Cazal

    January 6, 2022 at 3:10 pm

    That’s already an alternative option I can try, and for that, thank you.

    I’ll try and post the followup here 🙂

  • Charles Cazal

    January 6, 2022 at 6:37 pm

    Ok, so I went through the install of AEST.

    The code you sent me, should I copy paste it in a new script? I’m faily new to this, so I’m curious. (probably will find the answer soon, anyways) If not, then what’s there, and what’s missing? I kind of understand the point of the script, but I wonder how this is supposed to work. I launch the script once manually and it creates the values for the entire song (but then, I don’t understand how the script tells when a kick is happening), or is it kinda working in the background everytime i launch the animation?

    Of course, my next step is to dive in documentation and ressources to try and figure it out, but the answers might come earlier from you than from deciphering every info I might find ^^

    Also, I was pretty sure that the rendering nightmare was due to that many iterations of sampleImage() EVERY FRAME, but as I said, I’m no expert, and there could have been some other reason. I’m glad I got it right instinctively ^^

    Re: using AudioToKeyFrames(), it is indeed faster, BUT cuts away such flexibility that I can’t resort to use it. I’ll try my best with the scripting option, and I’ll revisit my needs if scripting fails 😀

    Thanks again!

  • Charles Cazal

    January 7, 2022 at 12:41 pm

    Ok last update: it works! 😀

    So glad. Thanks to your idea, I managed to make my first script, and it works. I’m so proud 🙂

    I don’t know, should I explain here what I’ve made for future users? The code is quite long and I still haven’t figured out how to make more than one line of code in this forum haha 😅

    Anyways, thanks Andrei, because of your idea of using script, now I’ve got a simple and real flexible way of getting the animations to react to a certain frequency of my chosing 🙂

  • Andrei Popa

    January 7, 2022 at 12:54 pm

    I am glad you made it. If you want more advice for future scripts:

    I use Visual Studio Code to write my script and an extension made by renderTom that’s called Adobe Script Runner to run them(you can execute any piece of code, even if not yet saved). You also have an extension made by adobe to replace Extendscript Toolkit (named Extendscript Debugger), but I don’t use that. It conficts with ESTK and I like ESTK more than the extension :D. I only use Extendscript Toolkit for indepth debuggind when something is not working.

  • Charles Cazal

    January 7, 2022 at 1:03 pm

    Hey seeing you’re online, maybe you can help me with another step. The slider holding the incremented values has interpolation between key frames. I don’t want it ^^

    So I would like these key frames to act as hold key frames but Im not sure it’s possible to make it part of the script instead of changing it manually after the script (which defeats the purpose of having a script in the first place)…?

    I don’t want to use Math.round() cause it holds the value for half the duration I need it to (eg at 14.5 it becomes 15, the change doesn’t happen when there’s a new kick but when im halfway between kicks)

  • Andrei Popa

    January 7, 2022 at 3:32 pm

    You can use the following function for that.

    So after you assigned the value via .setValueAtTime(yourTime) function, you can use

    .setInterpolationTypeAtKey(nearestKey(yourTime), KeyframeInterpolationType.HOLD)

    to toggle hold keyframe for that specific key.

    I am not sure how you’re code looks, so I can’t really tell you where to put this.

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