Tuesday, 5 July 2011

Showreel - Almost there edition


Another late post. In the past month I've gotten a degree and moved away from University! Since finishing my audio visualization major project I decided to take a break from programming and spend some time modelling, rendering, etc etc.

Currently I have obligations to about 3 different people with regards to Source modification assets. I also have a bunch of personal projects on the go. It's nice to be given direction sometimes.

Right now I'm waiting to hear if my showreel is strong enough to be considered as a promotion to the university. There is a good chance I could end up at an animation conference in London with about 10 major companies attending. Every year attendees from my university have been employed immediately, so I'm very excited about this opportunity.

Please take a look at my showreel!

Thursday, 2 June 2011

Video update!

Quick update. Haven't posted in over a month due to major project crunch time. The following is a prototype show-reel designed specifically for a self promotion module at my university. I'd argue this video is a poor representation of my skill-set as I am a programmer and it can be very challenging to demonstrate code in a visual context:

Showreel Prototype from Chris Cameron on Vimeo.

Right now I'm rendering out last minute stuff for the university's degree show. The final video from this will be significantly more relevant to my abilities and will showcase the result of the audio visualization plugin I've mentioned over the previous posts.

Soon I will have graduated and I will be posting a greater variety of work!

Monday, 11 April 2011

Sine window function


Today I'm going to explain how to implement a simple windowing function. Window functions are used to control the shape of a graph: typically to shape the ends to zero.

Today's problem:

I'm writing an audio visualization plugin for Autodesk Maya and a central part of that involves heavy use of the Fast Fourier Transform. In order to get accurate output data from the FFT and avoid spectral leakage it is important that the input discrete samples are periodic. This means that the split second of audio I'm performing calculations on at any time must loop.

Today's solution:

By implementing a window function I can gradually bring the ends of the signal to zero, essentially making it periodic.

There are a plethora of different window functions (many are listed here: http://en.wikipedia.org/wiki/Window_function) but I am going to use the sine wave to shape my data for a number of reasons:
  • I don't need to play with line functions (much).
  • Trig is available in pretty much every language.
  • The first 180 degrees of 1 period starts at 0, rises to 1 and then falls to 0 again.
  • The transition is gradual, my data is going to be uniformly modified.

You might think "Why a sine wave? The cosine wave is centred and reflects in the Y axis!". Well, in this situation my data is in a list and starts at an index of 0. If I multiply that by sin(0) I will get zero. Which is what I want!

The most tricky thing here is I need to scale the sine wave so the half-period ends at the same value as the length of my array of data. If I have 1000 samples, I want sin(PI) to land on X = 1000.

The line function for a sine wave is:
y = a sin [ b( x - hpi) ] + k
Where A is the Y scale, B is the X scale, H is the X shift and K is the Y shift.

I want the function to oscillate between 1 and -1 so I can leave A and K alone. I also want to start at X = 0 so I can leave H alone. This leaves me with B.

Once I have my scale value, all I need to do is feed in my X (the index of the sample) and then multiply the 0-1 result with the original sample. Performing this across an entire array will window the entire dataset!

The following is my function in Python. Sample is the current, single value I'm working with. I is the index of the value. Width is the number of values in the full array.

def window_sample(sample, i, width):
 width *= 2 #i only want the first half of the sine period
 y = math.sin((math.pi * i)/width) #value at sine(index)
 #modify sample
 sample *= y
 return sample

You'll notice I'm dividing by the scalar B rather than multiplying. This is because it scales inversely. Here are 2 examples of how this function will shape a set of samples:

As you can see (particularly with the second example) the signal is very much a strong representation of its former self despite being windowed, however it is now periodic.

Tuesday, 8 March 2011

Maya AE Template File Browser

Ok, I slept on it and I've been able to make the MEL end of the file browser work properly!

I was close before, just turns out my MEL is rusty and I didn't realize I could have a variable at the end of control declarations for use later on when I want to update the display.

Today's problem:

I want to attach a file browser to my node's string attribute.

Today's solution:

As far as I can tell, the only way to have controls other than simple attribute input/outputs is by using the callCustom command. Here's some code:

The main template function
global proc AEADANodeTemplate( string $nodeName )
 editorTemplate -beginScrollLayout;
 //File Attributes
 editorTemplate -beginLayout "File Attributes" -collapse 0;
  editorTemplate -addControl "input";
  editorTemplate -callCustom "AE_file_browse" //create the file browser
         "AE_file_browse_repeat" //update the file browser
         "AudioFile"; //file location attribute
  editorTemplate -addControl "SampW";
  editorTemplate -addControl "FrameR";
  editorTemplate -addControl "NFrames";
  editorTemplate -addControl "NChan";
 editorTemplate -endLayout;
 editorTemplate -beginLayout "Amplitude" -collapse 0;
  editorTemplate -addControl "amplitudeL";
  editorTemplate -addControl "amplitudeR"; 
 editorTemplate -endLayout;
 AEdependNodeTemplate $nodeName;
 editorTemplate -addExtraControls;
 editorTemplate -endScrollLayout;

The browser functions
global proc AE_file_browse(string $attr){
 rowLayout -nc 3;
  text -label "Audio File";
  textField  -fileName `getAttr $attr` LocationText;
  symbolButton -image "navButtonBrowse.xpm" -c ("loadPopup(\"" + $attr + "\")");
  setParent ..;

global proc AE_file_browse_repeat(string $attr){
 textField  -e -fileName `getAttr $attr` LocationText;

The browser popup function
global proc loadPopup(string $attr){
 string $loc = `fileDialog -dm "*.wav"`;
 if ($loc != ""){
  setAttr -type "string" $attr $loc;
  textField -e -fileName `getAttr $attr` LocationText;

And that's all there is to it. I still need to fix up the Python side of things so the file is loaded once the file path has been chosen.

More AE Template Stuff

Recently my time has been taken up mostly by figuring out AE Templates in Maya.

In my first post I talked about simply re-arranging information so it's a little more intuitive for the end user. Currently I'm trying to build a file browser, identical to the browser section found in the "File" and "PSDFile" Hypershade nodes. Scripting this is a LOT more involved.

Currently I'm getting frustrated with trying to keep the file location textfield in sync with the location attribute, and calling the file-load function when a file is selected. I'm sure there is a "proper" way of doing it but I'm wasting so much time with this stuff that I'm probably going to find some hacky, inelegant solution so I can get back to the fun mathsy bits.

On Friday I met a professor at my university who researched the Fourier transform for his PhD. It was reassuring to be shown that what I'm trying to accomplish in Maya is very much possible. As well as showing me first-hand how the FFT works, he explained filter-banks should I go that route. I still haven't been able to get much of a maths perspective on the algorithm, but my practical knowledge of it has improved.

Other than that, I've been working on this:
Maybe half finished?

I'm also meant to be doing asset work for some guy in the US Navy who is making a map for Obsidian Conflict, a HL2 modification. Buuut I've been kinda busy.

Wednesday, 2 March 2011

AE Node Templates

So it turns out the fancy formatting in the Maya attribute editor (shader ramps, colour choosers, file browsers, etc) are actually defined in MEL templates, found in the Maya/Scripts/AETemplates folder. The following is a quick example of how these are written.

Today's problem:

My attributes are showing up, but I'd like them to appear a little more intuitive.

Today's solution:
Granted the node isn't particularly dense so far: even lights seem to have hundreds of attributes. My assumption going into node scripting was that the layout of attributes would be coded along with the rest of the node: in the Python/C++ plugin. I had not read anything to suggest otherwise, and it was only after asking around a forum that I was directed to the Attribute Editor Templates.

If you're familiar with MEL the following will be pretty easy for you. Hell, if you're writing a custom node for Maya, this should be trivial. Here's my template until I develop the node further:

The following is saved as AEADANodeTemplate.mel, the format being AE<node_name>Template.mel. Still looking for a good html syntax highlighter.

  1. global proc AEADANodeTemplate( string $nodeName )
  2. {
  3.     editorTemplate -beginScrollLayout;
  4.     //File Attributes
  5.     editorTemplate -beginLayout "File Attributes" -collapse 0;
  6.         editorTemplate -addControl "input";
  7.     editorTemplate -endLayout;
  9.     //Amplitude
  10.     editorTemplate -beginLayout "Amplitude" -collapse 0;
  11.         editorTemplate -addControl "amplitudeL";
  12.         editorTemplate -addControl "amplitudeR";
  13.     editorTemplate -endLayout;
  14.     AEdependNodeTemplate $nodeName;
  15.     editorTemplate -addExtraControls;
  16.     editorTemplate -endScrollLayout;
  17. }

Starting to look a bit more like a real Maya node!

Tuesday, 1 March 2011

First Post

I'm completely new to blogging so please bear with me while I figure out layout and design.

This blog is a place for me to document technical challenges and solutions in the world of computing. I tend to code for small games or create visual assets such as models, textures etc. Currently I'm in my final year of a computer animation degree, so for a while this blog is going to focus mainly on my major project: an audio visualization node for Autodesk Maya.

The node is written in Python and will take a user defined wav file as input. The node will provide outputs for amplitudes, frequency data and beat detection. This will allow users to plug these values into other attributes (such as the scale of a polyCube, rotation of a joint, intensity of a light, etc) and create works of art that blur the line between sound and vision.

* * *

Python makes wav processing extremely easy: the most challenging part is converting the samples from hex to signed integers. Currently I am trying to feed the amplitude of a wav into the Maya node. This involves using a moving average to find the amplitude of a single Maya frame's worth of audio.

Today's problem:
To get a single frame's worth of audio samples I need to know how many seconds there are per frame in Maya. There is no straightforward way of doing this.

Today's solution:
Maya offers commands to fetch the current time and the current time units. Units would be ideal for calculating seconds-per-frame, unfortunately it typically returns strings such as "hour", "pal", "20fps", etc.

Google provided the following solution in the form of a MEL script:

The script works perfectly on a one-off basis. HOWEVER, when run during animation the repeated modification of animation settings causes the node to evaluate incorrectly.

I decided to just give in and write the following trivial function (I'll research syntax highlighting sometime):

#get seconds per frame
def getSpf():

    #[hour | min | sec | millisec | game | film | pal | ntsc | show | palf | ntscf]
    #values are followed by "fps"
    unit = cmds.currentUnit( query = True, time = True )
    if unit == "hour": return 360
    if unit == "min": return 60
    if unit == "sec": return 1
    if unit == "millisec": return 1.0/1000.0
    if unit == "game": return 1.0/15.0
    if unit == "film": return 1.0/24.0
    if unit == "pal": return 1.0/25.0
    if unit == "ntsc": return 1.0/30.0
    if unit == "show": return 1.0/48.0
    if unit == "palf": return 1.0/50.0
    if unit == "ntscf": return 1.0/60.0
    unit = unit.replace("fps", "")
    return 1.0/unit

So there you go, nothing complicated at all. I haven't even bothered to set up a dictionary to avoid the number of IF statements. Hopefully this function will save someone a few minutes of mindless typing.

Soon I'll hopefully be able to post a playblast of the amplitude output in use.