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;
 
 //Amplitude
 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;
  8.    
  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.