VJing with Python?

Time for another update on AteBitVJ. The latest addition to it’s arsenal is the ability to create your own effect modules from scratch. Anyone who knows me or has read this blog will know that I am a big fan of Processing. I love it’s immediacy – that I can very quickly prototype and test out ideas. Several of the effects modules in AteBitVJ started out as Processing sketches before being re-written in C++ and HLSL. In fact, it was partly due to me wanting to take my audio visual Processing experiments further that led to me creating AteBitVJ in the first place. So it’s fitting that I’ve added a Processing-like scripting library to the app. The cool thing is that these scripted modules are immediately fully integrated into AteBitVJ, giving you access to a wide range of filters, modules and synchronisation options.

The scripting language I chose to use is Python, but it was a close call between Python and Lua. I’ve embedded Lua a lot in the past, mostly in various commercial games like Crackdown, and have always liked it. I find that it’s very easy to embed and is pretty safe and simple for non-technical people (like game artists and designers) to pick up. Python is a newer discovery for me and I’ve only been using it in anger for a few months. I’ve been using it a lot in my day job, so it’s advantageous for me to take a more in-depth interest in it, but I’m also aware that a lot of artists are getting into it through scripting in packages like Maya, Max and C4D.

So here’s a quick video of the latest version of AteBitVJ. It not only shows off the immediacy of the UI (the whole video is shot in one take) but also the Python scripting – the main visual effect you see is Python scripted.

And here’s the script itself:

from atebitvj import *
 
colBackground = color(0)
colCircleStroke = color(255,255,0)
colCircelFill = color(255)
colLinesLow = color(255,0,0)
colLinesHi = color(255,255,0)
 
def setup():
	addParamFloat("offset", 0, 0, 1)
	addParamFloat("length", 1, 0, 1)
	ellipseMode(CENTER)
 
def draw():
	background(colBackground)
	translate(screenWidth()/2, screenHeight()/2)
 
	# draw the central ball
	ellipseScale = 0
	for i in range(64, 128):
		ellipseScale = max(ellipseScale, getFFT(i))
	strokeScale = 1-(elapsedBeats() % 1)
	strokeWeight(strokeScale * 20)
	stroke(lerpColor(colLinesLow, colLinesHi, strokeScale))
	fill(colCircelFill)
	ellipseSize = ellipseScale * 300
	ellipse(0, 0, ellipseSize, ellipseSize)
 
	# draw the lines coming out to show the energy at different frequencies
	strokeWeight(5)
	rotate(-HALF_PI)
	rotationStep = TWO_PI / 128
	offset = 250 + getParamFloat("offset") * 50
	lengthScale = getParamFloat("length") * 200;
	for i in range(128):
		band = i / 2 if i < 64 else 64 - i / 2
		audioScale = getFFT(band * 256 / 64)
		stroke(lerpColor(colLinesLow, colLinesHi, audioScale))
		line(offset, 0, offset + lengthScale * audioScale, 0)
		rotate(rotationStep)

If you’ve seen Processing before then this should pretty much make sense, even if you’re completely new to Python. There are a couple of AteBitVJ functions that deserve some further explanation though:

You can add named parameters (with initial and min/max values) to the module which are then exposed to the same UI and automation facilities as everything else. Of course, they’re also saved along with the rest of project. Not shown here are the other parameter types that are available, like colour:

addParamFloat("name", 0, 0, 1)
getParamFloat("name")

Read various times values, allowing you to sync your script to the audio:

elapsedTime()
elapsedBeats()
elapsedBeatsInBar()
elapsedBars()
beatsPerBar()

Read the current value of the audio FFT. This lets you sync your script to the audio volume.. to some extent:

getFFT(band)

So that’s it for now. The scripting only allows you to produce 2D content at the moment, but 3D will be added over the next couple of weeks – I’m still adding new functionality to this app on an almost daily basis.

This entry was posted in atebit, Computers, Development, Music. Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *