Skip to main content
Participating Frequently
January 15, 2012
Answered

Unpause animation if key value equals X

  • January 15, 2012
  • 3 replies
  • 4846 views

tldr: I need an expression that plays a sequence of images on a layer (and leave it on the last image) when the value of a key (keyframe?) in another layer of the same comp equals a specific value.

I am fairly new to AE and trying to port a project I made exclusively using Processing. Wrapping my head around how Expressions work is proving difficult, and I learn best by example, and am even finding it hard to piece together how to do this from what I've found online.

The situation and what I need:

I have imported key frames from a midi file (using this script) into a layer called "midi" and a layer that is an animation of frames . The idea is that if midi's effect ch_0_pitch has a value of, in this case, 36, that the frames in layer "ds_bass" animate when they come across one of these keys.

This is basically a "bass drum" animating on a "bass note" pitch. The midi file contains references to the entirety of drum midi needs (ie hi hat, snare, bass), each having a different pitch value. While I could simply render each individual "pitch" midi sequence to a midi file and import it as keys and then use a time remap expression to unpause and pause the animation on markers, which has worked, I need the capability to specify pitches for other instruments and run specific animations based on what pitch is being hit. As well, going through and adding a marker for each midi note is tedius and inaccurate (as there are very small differences visually between two keys with different values played synchronously, ie a bass hit and a hi hat hit).

I found something online that accomplished this at first, with markers, placed in TimeRemap of the ds_bass layer. I would go note by note in the midi and add markers to the ds_bass layer for this to work, and it perfectly paused and ran the animation when I needed it:

try {
      m = thisLayer.marker.nearestKey(time);
      linear(time, m.time, outPoint, 0, outPoint - m.time);
} catch (e) {
value

}

But seeing as I needed more to automate this process (this is a four minute piece with a lot of instrumentation and I'd like to be able to use this as a template for another project), I looked at the reference and other resources and the best I could come up with was something like this, which doesn't cause errors but also doesn't do anything (as well on TimeRemap of ds_bass layer in the same comp as midi):

try {

     if (thisComp.layer("midi").effect("ch_0_pitch").nearestKey(value) == 36) {

          m = thisComp.layer("midi").nearestKey(time);

          linear(time, m.time, outPoint, 0, outPoint - m.time);

     }

} catch (e) {

value

}

In Processing this was all handled with a switch in a method that brought in midi info on noteOn signals, and that checked for pitch values and ran methods based on pitch which ran sequences of images. Maybe I am going about this the wrong way, admittedly, as I am terribly new to AE, but this seems like it should be completely possible to automate all of this for very solid and automated timing mechanisms based directly off of the midi data.

Many of the other animations will be dependent on running a sequence based on pitch, in the sense of having a puppet that can animate ArmL to ArmLPlaySnare OR ArmLPlayHat - having a single "resting" frame that executes different animations (these are sets of 1-5 .pngs) dependent on midi pitch. Again, how it was managed in Processing.

If anyone can give some insight I would greatly appreciate it. I moved to AE as I found I'd need to render visuals in non-realtime (from midi data), and it seemed superior to learn AE as it has render capabilities that are more inline and intuitive with this project. At the moment I am stuck. Thanks for your time.

Edit - If I could simply copy the key frames I need to the ds_bass layer and then use the marker script (first above) with nearest key instead I figure it would work fine, though that's merely a more satisfactory convenience, not a proper fix. I'd still have to easily render dozens of midi files and do this for each. Best case scenario would be that I have one keyframed midi file with all channels in it (in my "master comp?") that can be referenced by the individual compositions. At the moment I'm putting instrument specific midi-keyed layers into each instrument specific comp.


Message was edited by: cheerbot: added references online to resources used

This topic has been closed for replies.
Correct answer Dan Ebberts

I think it's all very do-able, but you have a number of issues to deal with. This is the basic expression that will calulate how long it has been since a note 36 keyframe:

myId = 36;

note = thisComp.layer("midi").effect("ch_0_pitch")("Slider");

n = 0;

if (note.numKeys > 0){

  n = note.nearestKey(time).index;

  if (note.key(n).time > time) n--;

}

if (n > 0){

  while (n > 0){

    if (note.key(n).value == myId) break;

    n--;

  }

}

if (n > 0)

  time - note.key(n).time

else

  0

The problem is that the script generates keys for note on and note off and there doesn't seem to be a good way to know which is which. So the note off keys are going to mess up the timing.

So maybe you need to modify the script to leave those out. That should work for animations that start when the note sounds (like animating the drum, for example), but your other animations need to start before the note (like an arm moving to strike the drum). So you probably need a marker on the animation layer to denote where the animation needs to be when the note fires. Then your expression needs to calculate the timing that will syncronize the drum key to the marker on the animation.  I did a tutorial over at Creative Cow a while back that discusses synchronizing with markers that might be of some help:

http://library.creativecow.net/articles/ebberts_dan/audio_sync.php

Dan

3 replies

cheerbotAuthor
Participating Frequently
January 19, 2012

Thanks, looks like this is successful but will just take some work and tweaking. I still need some experience with rendering and uploading to Vimeo/YouTube apparently, hah, not sure why it doesn't sync properly after uploading...

With some time echo and slight wiggles on body and instrument aligned to the tempo of the song, if comes off as a really fantastic effect, despite its simplicity. Anyway I'm amazed but I'm an AE amateur.

Dan, I really appreciate you going through my verbosity. That last tutorial link ( http://www.motionscript.com/design-guide/marker-sync.html ) was exactly what I needed for the majority of the actor's animations. I ended up restructuring the precomp animations with an extra "rest" marker after each animation otherwise it would oddly jump to the first frame of the next marked sequence as a rest (or "norm" as you have it). Otherwise I had to change some of the timing on the codes, adding 0.1 of a second to make sure all animations hit at the right times. So again, thanks! This was indeed the answer I needed, though I wonder if it could be automated moreso to read the values of the markers without setting comments.

David, thanks for stopping in, I'll keep checking your blog to see when/if you put up a marker based version to help with the workflow at the moment. The original script has helped significantly, though.

I'll put together a little page that just shows all the steps involved and what's needed and update this post with a link once I put out the full project so if anyone's curious they can replicate it.

You guys were completely helpful, thanks again.

Edit - I found three useful free scripts online after trying to brute force 4 minutes of instrumentation. These definitely help if anyone is trying to do something along the same lines. With segmented, specific midi files this is a breeze.

rd_CopyMarkers - copy markers from one layer to another.

rd_keyMarkers - copy keys to markers (+ assign comment).

Layer Marker Batch Editor - batch edit markers on a layer (in this case used for changing all markers to the same word).

Known Participant
January 19, 2012

This has been very helpful. Nice project.

I had just discovered Davids script and also wanted to create keyframes for the note on event only. I'm just painting notes like a pianoroll, but with just one keyframe for every pitch you can decide to paint a bezier curve or linear curve instead. Thanks everyone involved.

Inspiring
January 17, 2012

Cheerbot -- I love the animation you linked http://andsuch.org/pub/saturn_v4_test.mov !

Dan -- Looks like you found a good fix for his needs, eliminating the note-offs. I'll definitely add a checkbox for that (or maybe just remove all the note-offs, they're not so interesting with the Duration track...)

Is there any benefit to using Markers instead of Keyframes? The Keyframes carry values, which seems nice.

Cheerbot -- my thought was that in some cases one could use the music authoring tool to construct a reduced or altered MIDI track that was specifically for the AE import. Polyphony makes for confusing keyframes. Very simple scores (like the Two Part Invention example I used) work ok as-is.

Dan Ebberts
Community Expert
Community Expert
January 17, 2012

I was thinking markers might be a good choice because you can stuff the note, velocity, and duration in the parameters of one marker. That way you wouldn't have to correlate separate streams of keyframes.

Dan

Inspiring
January 17, 2012

Oh! I... I never used markers. They can hold multiple attributes. Ok. Awesome. Got it. Thanks.

Dan Ebberts
Community Expert
Community Expert
January 15, 2012

Interesting. So will your ch_0_pitch effect have keys for multiple drums? If so, the the bass time remapping expression needs to start at the current time and go backwards in time, key-by-key, until it finds a key that matches that drum. Then it will know how far along in the animation the time remapping should be. If there's only one instrument in the set of keys, the expression just needs to find the most recent, previous key, which is pretty easy.  Are there keys for both note on and note off events? With a little more info on the nature of the keyframe values, we can probably zero in on this.

Dan

cheerbotAuthor
Participating Frequently
January 16, 2012

Short reply: The midi files can be structured with one instrument (one channel), one drum (one pitch of a channel) or the entirety of the song with different referenced channels (say 10 channels, with multiple pitches/ key values for each). The first is current and is do able as most instruments other than the drum set are structured this way, the second is inconvenient but doable and the third is the most preferable. In each case a pitch is tied to the keyframe as its value. There are three different effects for each channel when imported to AE: pitch, velocity and duration. Pitch and Velocity both have a keyframe created for noteOn and noteOff while duration only has a keyframe for noteOn.

Long reply:

This should illustrate it better.

This was done with Processing using real time midi data coming from Logic as it also played the music. After rendering this I ended up fleshing out both actors with a lot more frames for smoother actions, but ended up dropping them in favor of a different aesthetic once I implemented environmental visuals (a more current version can be found on vimeo though it's synced terribly - the main reason I am trying AE as I just can't do this in real time and had to use screen cap for Processing with several memory eaters).

Let me see if I can answer you, Dan, without being too verbose, using a few examples.

There is a different external midi track that sums up each instrument in Logic and assigns it to a different channel (Channel 0 would be for beats only, Channel 1 for guitar notes, Channel 2 for drum set, 3 = bass, 4 = keyboard, Channel 5+ for environment graphics). So, four instruments, each with a different midi file for triggering animations.

This is how two of them worked in Processing and how the midi is set up:

The drum set midi track would have a different pitch associated with each drum: A pitch of 36 would be a bass drum, a pitch of 42 a hi hat, a pitch of 38 a snare. When a noteOn comes from Channel 2, it triggers both the specific drum to animate as well as the arm to animate a sequence of images that show it hitting that drum.

If two arms hit the same drum, I have the drum image cycle each time but with an appropriate arm sequence (so I'd have pitch 42 and 43 both hit the same drum, but would animate different arms).

The guitar midi track (, however, simply has pitches that are all relative to the guitar instrument, pitches it plays (so 60 is simply middle C, 72 is one octave above). If any Channel 1 noteOns come in, it triggers the left arm to do a play animation, while triggering the right arm to "play a specific note" by playing a different sequence of images.

Environmental graphics have pitches like the guitar but they were used to relay positions on the screen (which I'll probably just try to do with regular AE animations at this point).

Thus ultimately any instrument needs to animate only when a key has a specific value. I think the way you put it at first seems appropriate then?

In AE, I render the individual midi tracks for each instrument, and import it using the script to a composition that is a singular instrument. So, a composition per midi channel, instead, although ultimately it would be great to just dump one large midi of the entire song into a main comp file and reference it by midi channel for each individual instrument comp.

The way the script seems to work is that it drops the midi channel in with three "effects" per channel: ch_0_pitch, ch_0_velocity and ch_0_duration. Pitch and Velocity both create a key for noteOn and noteOff, while duration seems to only have a noteOn. If I bring in a midi with more than one channel, they are simply numbered appropriately and have keys created for each.

As I have not been using the noteOff values (I simply cycle the animation at a defined rate, and format the notes to be as small as possible), I really just need the noteOn to trigger it, so duration would most likely be used. I would however like to be able to properly use noteOff for environmental graphics or better timed instrument animations.

Many of these animations, as well, have the "down beat" about halfway through the cycle. I've been cycling them within about 150ms so it's unnoticable, but if I could interpolate a ~5 frame sequence to hit the 3rd frame right on the needed key that would be fantastic, since the only way to do that previously would be to read a midi file through text and sequence things individually through time codes so I've forgone the ability to show "the future" in any of these projects.

I hope that helps clarify.

Just as an aside the animations I keep refering to are numbered cells in .png format that I import as a sequence and then assign to a layer. I do wonder if I'm thinking too along the lines of working in Processing and that there might be a better way to do all of this within AE, but I also have been working on this project for awhile learning code and would like to just finish it and then learn more on a new project.

Dan Ebberts
Community Expert
Dan EbbertsCommunity ExpertCorrect answer
Community Expert
January 16, 2012

I think it's all very do-able, but you have a number of issues to deal with. This is the basic expression that will calulate how long it has been since a note 36 keyframe:

myId = 36;

note = thisComp.layer("midi").effect("ch_0_pitch")("Slider");

n = 0;

if (note.numKeys > 0){

  n = note.nearestKey(time).index;

  if (note.key(n).time > time) n--;

}

if (n > 0){

  while (n > 0){

    if (note.key(n).value == myId) break;

    n--;

  }

}

if (n > 0)

  time - note.key(n).time

else

  0

The problem is that the script generates keys for note on and note off and there doesn't seem to be a good way to know which is which. So the note off keys are going to mess up the timing.

So maybe you need to modify the script to leave those out. That should work for animations that start when the note sounds (like animating the drum, for example), but your other animations need to start before the note (like an arm moving to strike the drum). So you probably need a marker on the animation layer to denote where the animation needs to be when the note fires. Then your expression needs to calculate the timing that will syncronize the drum key to the marker on the animation.  I did a tutorial over at Creative Cow a while back that discusses synchronizing with markers that might be of some help:

http://library.creativecow.net/articles/ebberts_dan/audio_sync.php

Dan