Skip to content

Instantly share code, notes, and snippets.

@ericjang
Created April 29, 2016 21:03
Show Gist options
  • Save ericjang/af35a0a814044075cd6cbdd9721ef05d to your computer and use it in GitHub Desktop.
Save ericjang/af35a0a814044075cd6cbdd9721ef05d to your computer and use it in GitHub Desktop.
audio-driven keyframes in Maya
# Author: Eric Jang
# 2013-Jul-17
# The problem with using audioWave + time nodes + audioWave bonus tool in Maya
# to drive animation is that we can't really do spectral analysis (high pass/low pass filters)
# short of implementing it using hypershade nodes, so we can't get really fine-tuned animation
# ... but Python is good for this!
# caveat: this was coded up in one night so it may be unstable. Use with caution.
# future work: instead of just the simple amplitude, we can perform FFT/spectral analysis to extract
# more interesting information, tweak the audio driving keys
# audio track: arbitrary wav file. currently uses the "World Engine" noise from Man of Steel.
import maya.cmds as cmds
import numpy as np
import random
from scipy.io import wavfile
# settings
l_sph = 12 # num copies of the sphere along each dimension
xy_s = 3 # x or y distance of each sphere from each other
afile = "/home/cello/pythonfun/wubwub/zod.wav"
width = 3
maxR = 10
###
rate, a = wavfile.read(afile)
a = np.average(a, 1) # merge audio channels into mono
nf = int((float(len(a)) / rate * 24) / width) #number of frames we will animate
spf = int(rate/24 * width) # audio samples per animation frame (1837). Increase width to smooth animation out
# normalized sine "bump" + some array comprehension
# see the heatmap_sample to get an idea of what it looks like
dz_s = [ [np.sin(i*np.pi/l_sph)*np.sin(j*np.pi/l_sph)*5.0 for j in range(l_sph)] for i in range(l_sph)]
orig = cmds.ls("JuliaSphere")[0] # we don't animate this one
for i in range(l_sph):
for j in range(l_sph):
print(str(i*l_sph+j))
cp = cmds.duplicate(orig)
pos = [i*xy_s, j*xy_s, 0.0]
cmds.makeIdentity(cp, apply=True, t=1, r=1, s=1, n=0, pn=1) #freeze transforms
for frame in range(1,nf+1):
s = (frame -1 ) * spf #start of audio sampling frame
amp = np.average(np.abs(a[s:s+spf]))/1000 - 4
z = amp * dz_s[i][j] + random.uniform(0, 1) # a bit of jitter
dr = [random.uniform(0.01, maxR) * amp for k in range(3)]
if z < 0.0:
z *= 0.3
cmds.move(0, 0, z, cp, rpr=True)
cmds.xform(cp, ws=True, ro=dr) #translate it, rotate it
for key in ["translateZ", "rotateX", "rotateY", "rotateZ"]:
cmds.setKeyframe(cp, at=key, t=frame * width)# set keyframe
cmds.move(pos[0], pos[1], 0, cp, rpr=True)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment