July 22, 2008

Exterminating signals and slots

I recently posted at the clam devel wiki some advices, conventions, traps and tips on programing with Qt within CLAM addressed to the GSoC students. The most painful trap is the one of gratuitous signals and slots usage. Signals and slots is a very powerful way of designing independent components that comunicate each other with low coupling. Is that powerful that it is very tempting for novices to use them everywhere and this can turn very harmful for you.

If a connected slot doesn't exist, you just get an error console on run-time, checks on slots are that soft, and this is bad. Also the signal slot resolution is more expensive than just a method call. But the main reason to avoid them is that they make the code very hard to follow. When you see a signal 'emit' you have to find where such signal is connected in order to find which are the objects and slots that will be called. Multiply this process by nearly 200 signal emisions that were done at the vmqt library Annotator is using and you'll understand why such components although very smartly designed in structure, they are very hard to maintain and use.

You should emit signals just when you don't know which is the receiver of an event. If you can guess the receiver, there is no use for signals. On the other side, if you cannot access the emitter code, or you don't want to couple it, then there is room for a 'connect'.

A bad smell for noticing that you are over using sigslots is having in a class you are writting a connection like this:
connect(this, signal, knownWidget, slot)

and later, maybe in a different method:
emit signal()

When that known, and later forgotten, object is the only one you are connecting to the slot you might want to just keep a reference to it and just call the slot instead of emitting the signal.
knownWidget->slot()

which is faster, compile time checked and much more traceable.

Given that bad smell locator at hand i decided to do a fast review of vmqt module. vmqt is the successor of the many Visualization Modules we had in CLAM, just annother definitive VM rewrite. I tried to use it several times, but it is very hard to have a global view of what it does because all the program flow is driven by signal connections. No joke: 180 signal emissions and a similar number of 'connect's in 30 classes.

After a first review, 110 signals emisions have been avoided just by having a pointer to the Plot2D at the Renderers (the objects that represent drawing layers of the plot such as the lines, the playhead, the grid...). Having a pointer to it, Renderers can do a direct call to the Plot2D slots (now regular functions) instead of emitting a signal whose only receiver is the plot.

70 'emit's are still wandering around. Some of them communicate the plot with the wplot (a widget containing the plot and other elements such as the sliders, the rulers...) so they are used to syncronize. Those are likely to be removed in a similar way than for renderers.

The rest are specific renderer signals that are connected and propagated by the specific wplot. Those are harder to remove and indeed they are very convenient to keep.

As the extermination goes on, one can better see how to really take profit of the nice vmqt module structure and which aspects can be enhanced.

July 12, 2008

Por qué me gusta GNU/Linux - Why I like GNU/Linux

Andá a hacer esto en Windows!!!! / Do this on Windows!!!!

July 11, 2008

---why do I get the danceablity upside down ?

 Why do I get the danceablity upside down ?

 reversedDance   reversedDance    reversedDance 

Weeks ago I implemented the detrended fluctuation analysis exponent (dfaExponent) to scale the danceablity. The dfaExponent is introduced in [1] by Streich and Herrera. However, today I happened to notice that, compared with the observation of the reference, the dfaExponent I've obtained is the hell upside down.

30s-length segmentations of 107 dance tracks and 103 classical tracks are processed, which are half less long than those of the reference. On the left is the result of dfaExponent shown in the  reference, and on the right is the funny one who stands on its hands:

Dance              DFAComponent_OnsetPeak

As the clam annotator now is taking random danceability data as one of the high-level annotations, is anybody interested in filling this fast implementation in?

July 06, 2008

Linking scripts to objects in blender

The previous python-blender script was called on FrameChanged event, and it iterates over all objects to print its information.
How to access specific object information when you assign(link) the script to, let's say, ObjectUpdate? How to know which object is calling the script? Using the variables of the Blender module.

Here I made a new script and linked the same to:
  • an object (Audio_Omni_Source2), on ObjectUpdate event
  • a scene, on FrameChanged event
  • a world, on FrameChanged event


When the animation is running, the script says on console:

July 04, 2008

Receiving OSC from the CLAM Network

CLAM supports OSC as a plugin. You can compile CLAM/plugins/osc just as the other clam modules ("scons [options]").

That, for now, compiles a simply server processing (LibloSource) using the high level API of liblo.

On NetworkEditor (click to see animation):


As you can see on the animation, it have 2 options: osc port number and osc path.
LibloSource print whatever osc pakage it receives on that port in the console[1], and if the package have the config path and contain just 3 floats, the values are sent to the three control outputs[2].

If you configure the processing to get port 7000, you will see in the console:
LibloSource::ConcreteConfigure: STARTING the server. port 7000
So, just run the blender animation and back to the clam console, it will show something like:


That's it! You have three floats from every blender object osc position package! So, you could configure your LibloSource server to receive an object position subpath[3]:





[1] catched with
lo_server_thread_add_method(st, NULL, NULL, generic_handler, this);

[2] catched with
lo_server_thread_add_method(st, _config.GetOscPath().c_str(), "fff", controls_handler, this);
(the tree "f"s are the three typespec: floats...)

[3] at the moment just once at the time, because it create a new thread server on each processing, which make the port slot be busy and clam crash. This is an IMPORTANT todo task, when see how to deal with several osc paths/objects... Another bugs in actual implementation: if you duplicate a object with the same parameters it crashes... and if you change the options there is no reload (you actually need to quit and open the file again).
I expect to strike these bugs soon, but that need to define some things: what we want to use? a processing as server with different linked (sub)processings as paths? (this could be implemented using some kind of list control messages to deal with paths) Or just a big but configurable processing to receive all paths from an osc sender (for instance, blender)?

Exploring the scene (part 2)

Let's review the previous scene with an alternative access method.
Using the Blender module:

dir (Blender)
['Armature', 'BGL', 'BezTriple', 'Camera', 'Constraint', 'CountPackedFiles', 'CurNurb', 'Curve', 'Draw', 'Effect', 'FALSE', 'Geometry', 'Get', 'GetPaths', 'Group', 'Image', 'Ipo', 'IpoCurve', 'Key', 'Lamp', 'Lattice', 'Library', 'Load', 'Material', 'Mathutils', 'Mesh', 'Metaball', 'Modifier', 'NMesh', 'Node', 'Noise', 'Object', 'PackAll', 'Particle', 'Quit', 'Redraw', 'Registry', 'Run', 'Save', 'SaveUndoState', 'Scene', 'Set', 'ShowHelp', 'Sound', 'SpaceHandlers', 'SurfNurb', 'TRUE', 'Text', 'Text3d', 'Texture', 'Types', 'UnpackAll', 'UnpackModes', 'UpdateMenus', 'Window', 'World', '__doc__', '__name__', 'bylink', 'event', 'link', 'mode', 'sys']

dir(Blender.Scene)
['Get', 'GetCurrent', 'New', 'Radio', 'Render', 'Sequence', 'TimeLine', 'Unlink', '__doc__', '__name__', 'get', 'getCurrent', 'unlink']

scene1=Blender.Scene.GetCurrent()
scene1
[Scene "Scene"]

list (scene1.objects)
[[Object "mic_condenser"], [Object "Omni_mic_mono_side"], [Object "Audio_Omni_Source3"], [Object "Audio_Omni_Source2"], [Object "Audio_Omni_Source1"], [Object "Lamp"], [Object "Omni_mic_mono_zenit"]]


We can use the following script, for instance, to get all the objects from a scene, prints their names and positions and then send it to a local Open Sound Control server (we need to have OSC.py on ~/src/osc):
#!BPY
"""

Name: 'OSCSender'
Blender: 244
"""

# use bpy module of Blender:
from bpy import data

from sys import path
from os import getenv
home=getenv("HOME")
path.append(home+"/src/liblo")

# use OSC client module for python - by Stefan Kersten
from OSC import Message

def main():
scene=data.scenes.active
for object in scene.objects:
name=object.name
location=object.getLocation()
print name
print location
Message("/blender/"+scene.name+"/"+name,location).sendlocal(7000)

# This lets you can import the script without running it
if __name__ == '__main__':
main()

We can link the previous script to the active scene (scene.addScriptLink), on FrameChanged event:


The console output, when is playing:

July 03, 2008

Exploring the scene (part 1)

How to access blender data?

I created a test scene, with some spheres (named as sound sources) some which have trajectories:


In Blender you have an internal Python console. Buggy, but still useful to test the access:


So, let's see some logs of the python console:
Using bpy module:
dir(bpy)
['__doc__', '__name__', 'config', 'data', 'libraries']

dir(bpy.data)
['__doc__', '__name__', 'actions', 'armatures', 'cameras', 'curves', 'fonts', 'groups', 'images', 'ipos', 'lamps', 'lattices', 'materials', 'meshes', 'metaballs', 'objects', 'scenes', 'sounds', 'texts', 'textures', 'worlds']

dir(bpy.data.scenes)
['__class__', '__cmp__', '__delattr__', '__doc__', '__getattribute__', '__getitem__', '__hash__', '__init__', '__iter__', '__len__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__', 'active', 'new', 'next', 'tag', 'unlink']

scene1=bpy.data.scenes.active

scene1
[Scene "Scene"]

dir(scene1)
['Layers', '__class__', '__cmp__', '__delattr__', '__doc__', '__getattribute__', '__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__', 'addScriptLink', 'clearScriptLinks', 'copy', 'cursor', 'fakeUser', 'getActiveObject', 'getChildren', 'getCurrentCamera', 'getLayers', 'getName', 'getRadiosityContext', 'getRenderingContext', 'getScriptLinks', 'getTimeLine', 'layers', 'lib', 'link', 'makeCurrent', 'name', 'objects', 'play', 'properties', 'radiosity', 'render', 'sequence', 'setCurrentCamera', 'setLayers', 'setName', 'tag', 'timeline', 'unlink', 'update', 'users', 'world']

list(scene1.objects)
[[Object "mic_condenser"], [Object "Omni_mic_mono_side"], [Object "Audio_Omni_Source3"], [Object "Audio_Omni_Source2"], [Object "Audio_Omni_Source1"], [Object "Lamp"], [Object "Omni_mic_mono_zenit"]]

for object in scene1.objects:
if object.name.lower().find('mic')!=-1:
print 'Object: '+object.name + '; '+str(dir(object))
Object: mic_condenser; ['DupEnd', 'DupGroup', 'DupObjects', 'DupOff', 'DupOn', 'DupSta', 'Layer', 'Layers', 'LocX', 'LocY', 'LocZ', 'RotX', 'RotY', 'RotZ', 'SizeX', 'SizeY', 'SizeZ', '__class__', '__cmp__', '__copy__', '__delattr__', '__doc__', '__getattribute__', '__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__', 'action', 'actionStrips', 'activeMaterial', 'activeShape', 'addProperty', 'addScriptLink', 'addVertexGroupsFromArmature', 'axis', 'boundingBox', 'buildParts', 'clearIpo', 'clearScriptLinks', 'clearTrack', 'clrParent', 'colbits', 'constraints', 'convertActionToStrip', 'copy', 'copyAllPropertiesTo', 'copyNLA', 'dLocX', 'dLocY', 'dLocZ', 'dRotX', 'dRotY', 'dRotZ', 'dSizeX', 'dSizeY', 'dSizeZ', 'data', 'dloc', 'drawMode', 'drawSize', 'drawType', 'drot', 'dsize', 'dupFacesScaleFac', 'effects', 'enableDupFaces', 'enableDupFacesScale', 'enableDupFrames', 'enableDupGroup', 'enableDupNoSpeed', 'enableDupRot', 'enableDupVerts', 'enableNLAOverride', 'evaluatePose', 'fakeUser', 'game_properties', 'getAction', 'getAllProperties', 'getBoundBox', 'getData', 'getDeltaLocation', 'getDrawMode', 'getDrawType', 'getEuler', 'getInverseMatrix', 'getIpo', 'getLocation', 'getMaterials', 'getMatrix', 'getName', 'getPIDeflection', 'getPIFalloff', 'getPIMaxDist', 'getPIPerm', 'getPIRandomDamp', 'getPIStrength', 'getPISurfaceDamp', 'getPIType', 'getPIUseMaxDist', 'getParent', 'getParentBoneName', 'getParticleSystems', 'getPose', 'getProperty', 'getSBDefaultGoal', 'getSBErrorLimit', 'getSBFriction', 'getSBGoalFriction', 'getSBGoalSpring', 'getSBGravity', 'getSBInnerSpring', 'getSBInnerSpringFriction', 'getSBMass', 'getSBMaxGoal', 'getSBMinGoal', 'getSBStiffQuads', 'getSBUseEdges', 'getSBUseGoal', 'getScriptLinks', 'getSize', 'getTimeOffset', 'getTracked', 'getType', 'insertCurrentPoseKey', 'insertIpoKey', 'insertPoseKey', 'insertShapeKey', 'ipo', 'isSB', 'isSelected', 'isSoftBody', 'join', 'layers', 'lib', 'link', 'loc', 'makeDisplayList', 'makeParent', 'makeParentBone', 'makeParentDeform', 'makeParentVertex', 'makeTrack', 'mat', 'materialUsage', 'matrix', 'matrixLocal', 'matrixOldWorld', 'matrixParentInverse', 'matrixWorld', 'modifiers', 'name', 'nameMode', 'newParticleSystem', 'parent', 'parentType', 'parentVertexIndex', 'parentbonename', 'passIndex', 'piDeflection', 'piFalloff', 'piMaxDist', 'piPermeability', 'piRandomDamp', 'piSoftbodyDamp', 'piSoftbodyIThick', 'piSoftbodyOThick', 'piStrength', 'piSurfaceDamp', 'piType', 'piUseMaxDist', 'pinShape', 'properties', 'protectFlags', 'rbFlags', 'rbHalfExtents', 'rbMass', 'rbRadius', 'rbShapeBoundType', 'removeAllProperties', 'removeProperty', 'restrictDisplay', 'restrictRender', 'restrictSelect', 'rot', 'sbDefaultGoal', 'sbErrorLimit', 'sbFriction', 'sbGoalFriction', 'sbGoalSpring', 'sbGrav', 'sbInnerSpring', 'sbInnerSpringFrict', 'sbMass', 'sbMaxGoal', 'sbMinGoal', 'sbSpeed', 'sbStiffQuads', 'sbUseEdges', 'sbUseGoal', 'sel', 'select', 'setConstraintInfluenceForBone', 'setDeltaLocation', 'setDrawMode', 'setDrawType', 'setEuler', 'setIpo', 'setLocation', 'setMaterials', 'setMatrix', 'setName', 'setPIDeflection', 'setPIFalloff', 'setPIMaxDist', 'setPIPerm', 'setPIRandomDamp', 'setPIStrength', 'setPISurfaceDamp', 'setPIType', 'setPIUseMaxDist', 'setSBDefaultGoal', 'setSBErrorLimit', 'setSBFriction', 'setSBGoalFriction', 'setSBGoalSpring', 'setSBGravity', 'setSBInnerSpring', 'setSBInnerSpringFriction', 'setSBMass', 'setSBMaxGoal', 'setSBMinGoal', 'setSBStiffQuads', 'setSBUseEdges', 'setSBUseGoal', 'setSize', 'setTimeOffset', 'shareFrom', 'size', 'tag', 'texSpace', 'timeOffset', 'track', 'trackAxis', 'transp', 'type', 'upAxis', 'users', 'wireMode', 'xRay']
Object: Omni_mic_mono_side; ['DupEnd', 'DupGroup', 'DupObjects', 'DupOff', 'DupOn', 'DupSta', 'Layer', 'Layers', 'LocX', 'LocY', 'LocZ', 'RotX', 'RotY', 'RotZ', 'SizeX', 'SizeY', 'SizeZ', '__class__', '__cmp__', '__copy__', '__delattr__', '__doc__', '__getattribute__', '__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__', 'action', 'actionStrips', 'activeMaterial', 'activeShape', 'addProperty', 'addScriptLink', 'addVertexGroupsFromArmature', 'axis', 'boundingBox', 'buildParts', 'clearIpo', 'clearScriptLinks', 'clearTrack', 'clrParent', 'colbits', 'constraints', 'convertActionToStrip', 'copy', 'copyAllPropertiesTo', 'copyNLA', 'dLocX', 'dLocY', 'dLocZ', 'dRotX', 'dRotY', 'dRotZ', 'dSizeX', 'dSizeY', 'dSizeZ', 'data', 'dloc', 'drawMode', 'drawSize', 'drawType', 'drot', 'dsize', 'dupFacesScaleFac', 'effects', 'enableDupFaces', 'enableDupFacesScale', 'enableDupFrames', 'enableDupGroup', 'enableDupNoSpeed', 'enableDupRot', 'enableDupVerts', 'enableNLAOverride', 'evaluatePose', 'fakeUser', 'game_properties', 'getAction', 'getAllProperties', 'getBoundBox', 'getData', 'getDeltaLocation', 'getDrawMode', 'getDrawType', 'getEuler', 'getInverseMatrix', 'getIpo', 'getLocation', 'getMaterials', 'getMatrix', 'getName', 'getPIDeflection', 'getPIFalloff', 'getPIMaxDist', 'getPIPerm', 'getPIRandomDamp', 'getPIStrength', 'getPISurfaceDamp', 'getPIType', 'getPIUseMaxDist', 'getParent', 'getParentBoneName', 'getParticleSystems', 'getPose', 'getProperty', 'getSBDefaultGoal', 'getSBErrorLimit', 'getSBFriction', 'getSBGoalFriction', 'getSBGoalSpring', 'getSBGravity', 'getSBInnerSpring', 'getSBInnerSpringFriction', 'getSBMass', 'getSBMaxGoal', 'getSBMinGoal', 'getSBStiffQuads', 'getSBUseEdges', 'getSBUseGoal', 'getScriptLinks', 'getSize', 'getTimeOffset', 'getTracked', 'getType', 'insertCurrentPoseKey', 'insertIpoKey', 'insertPoseKey', 'insertShapeKey', 'ipo', 'isSB', 'isSelected', 'isSoftBody', 'join', 'layers', 'lib', 'link', 'loc', 'makeDisplayList', 'makeParent', 'makeParentBone', 'makeParentDeform', 'makeParentVertex', 'makeTrack', 'mat', 'materialUsage', 'matrix', 'matrixLocal', 'matrixOldWorld', 'matrixParentInverse', 'matrixWorld', 'modifiers', 'name', 'nameMode', 'newParticleSystem', 'parent', 'parentType', 'parentVertexIndex', 'parentbonename', 'passIndex', 'piDeflection', 'piFalloff', 'piMaxDist', 'piPermeability', 'piRandomDamp', 'piSoftbodyDamp', 'piSoftbodyIThick', 'piSoftbodyOThick', 'piStrength', 'piSurfaceDamp', 'piType', 'piUseMaxDist', 'pinShape', 'properties', 'protectFlags', 'rbFlags', 'rbHalfExtents', 'rbMass', 'rbRadius', 'rbShapeBoundType', 'removeAllProperties', 'removeProperty', 'restrictDisplay', 'restrictRender', 'restrictSelect', 'rot', 'sbDefaultGoal', 'sbErrorLimit', 'sbFriction', 'sbGoalFriction', 'sbGoalSpring', 'sbGrav', 'sbInnerSpring', 'sbInnerSpringFrict', 'sbMass', 'sbMaxGoal', 'sbMinGoal', 'sbSpeed', 'sbStiffQuads', 'sbUseEdges', 'sbUseGoal', 'sel', 'select', 'setConstraintInfluenceForBone', 'setDeltaLocation', 'setDrawMode', 'setDrawType', 'setEuler', 'setIpo', 'setLocation', 'setMaterials', 'setMatrix', 'setName', 'setPIDeflection', 'setPIFalloff', 'setPIMaxDist', 'setPIPerm', 'setPIRandomDamp', 'setPIStrength', 'setPISurfaceDamp', 'setPIType', 'setPIUseMaxDist', 'setSBDefaultGoal', 'setSBErrorLimit', 'setSBFriction', 'setSBGoalFriction', 'setSBGoalSpring', 'setSBGravity', 'setSBInnerSpring', 'setSBInnerSpringFriction', 'setSBMass', 'setSBMaxGoal', 'setSBMinGoal', 'setSBStiffQuads', 'setSBUseEdges', 'setSBUseGoal', 'setSize', 'setTimeOffset', 'shareFrom', 'size', 'tag', 'texSpace', 'timeOffset', 'track', 'trackAxis', 'transp', 'type', 'upAxis', 'users', 'wireMode', 'xRay']
Object: Omni_mic_mono_zenit; ['DupEnd', 'DupGroup', 'DupObjects', 'DupOff', 'DupOn', 'DupSta', 'Layer', 'Layers', 'LocX', 'LocY', 'LocZ', 'RotX', 'RotY', 'RotZ', 'SizeX', 'SizeY', 'SizeZ', '__class__', '__cmp__', '__copy__', '__delattr__', '__doc__', '__getattribute__', '__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__', 'action', 'actionStrips', 'activeMaterial', 'activeShape', 'addProperty', 'addScriptLink', 'addVertexGroupsFromArmature', 'axis', 'boundingBox', 'buildParts', 'clearIpo', 'clearScriptLinks', 'clearTrack', 'clrParent', 'colbits', 'constraints', 'convertActionToStrip', 'copy', 'copyAllPropertiesTo', 'copyNLA', 'dLocX', 'dLocY', 'dLocZ', 'dRotX', 'dRotY', 'dRotZ', 'dSizeX', 'dSizeY', 'dSizeZ', 'data', 'dloc', 'drawMode', 'drawSize', 'drawType', 'drot', 'dsize', 'dupFacesScaleFac', 'effects', 'enableDupFaces', 'enableDupFacesScale', 'enableDupFrames', 'enableDupGroup', 'enableDupNoSpeed', 'enableDupRot', 'enableDupVerts', 'enableNLAOverride', 'evaluatePose', 'fakeUser', 'game_properties', 'getAction', 'getAllProperties', 'getBoundBox', 'getData', 'getDeltaLocation', 'getDrawMode', 'getDrawType', 'getEuler', 'getInverseMatrix', 'getIpo', 'getLocation', 'getMaterials', 'getMatrix', 'getName', 'getPIDeflection', 'getPIFalloff', 'getPIMaxDist', 'getPIPerm', 'getPIRandomDamp', 'getPIStrength', 'getPISurfaceDamp', 'getPIType', 'getPIUseMaxDist', 'getParent', 'getParentBoneName', 'getParticleSystems', 'getPose', 'getProperty', 'getSBDefaultGoal', 'getSBErrorLimit', 'getSBFriction', 'getSBGoalFriction', 'getSBGoalSpring', 'getSBGravity', 'getSBInnerSpring', 'getSBInnerSpringFriction', 'getSBMass', 'getSBMaxGoal', 'getSBMinGoal', 'getSBStiffQuads', 'getSBUseEdges', 'getSBUseGoal', 'getScriptLinks', 'getSize', 'getTimeOffset', 'getTracked', 'getType', 'insertCurrentPoseKey', 'insertIpoKey', 'insertPoseKey', 'insertShapeKey', 'ipo', 'isSB', 'isSelected', 'isSoftBody', 'join', 'layers', 'lib', 'link', 'loc', 'makeDisplayList', 'makeParent', 'makeParentBone', 'makeParentDeform', 'makeParentVertex', 'makeTrack', 'mat', 'materialUsage', 'matrix', 'matrixLocal', 'matrixOldWorld', 'matrixParentInverse', 'matrixWorld', 'modifiers', 'name', 'nameMode', 'newParticleSystem', 'parent', 'parentType', 'parentVertexIndex', 'parentbonename', 'passIndex', 'piDeflection', 'piFalloff', 'piMaxDist', 'piPermeability', 'piRandomDamp', 'piSoftbodyDamp', 'piSoftbodyIThick', 'piSoftbodyOThick', 'piStrength', 'piSurfaceDamp', 'piType', 'piUseMaxDist', 'pinShape', 'properties', 'protectFlags', 'rbFlags', 'rbHalfExtents', 'rbMass', 'rbRadius', 'rbShapeBoundType', 'removeAllProperties', 'removeProperty', 'restrictDisplay', 'restrictRender', 'restrictSelect', 'rot', 'sbDefaultGoal', 'sbErrorLimit', 'sbFriction', 'sbGoalFriction', 'sbGoalSpring', 'sbGrav', 'sbInnerSpring', 'sbInnerSpringFrict', 'sbMass', 'sbMaxGoal', 'sbMinGoal', 'sbSpeed', 'sbStiffQuads', 'sbUseEdges', 'sbUseGoal', 'sel', 'select', 'setConstraintInfluenceForBone', 'setDeltaLocation', 'setDrawMode', 'setDrawType', 'setEuler', 'setIpo', 'setLocation', 'setMaterials', 'setMatrix', 'setName', 'setPIDeflection', 'setPIFalloff', 'setPIMaxDist', 'setPIPerm', 'setPIRandomDamp', 'setPIStrength', 'setPISurfaceDamp', 'setPIType', 'setPIUseMaxDist', 'setSBDefaultGoal', 'setSBErrorLimit', 'setSBFriction', 'setSBGoalFriction', 'setSBGoalSpring', 'setSBGravity', 'setSBInnerSpring', 'setSBInnerSpringFriction', 'setSBMass', 'setSBMaxGoal', 'setSBMinGoal', 'setSBStiffQuads', 'setSBUseEdges', 'setSBUseGoal', 'setSize', 'setTimeOffset', 'shareFrom', 'size', 'tag', 'texSpace', 'timeOffset', 'track', 'trackAxis', 'transp', 'type', 'upAxis', 'users', 'wireMode', 'xRay']

list(bpy.data.ipos)
[Ipo "fast_pass" (Object)], [Ipo "Orbit1" (Object)]]

trajectory1=bpy.data.ipos['fast_pass']

dir(trajectory1)
['EvaluateCurveOn', '__class__', '__cmp__', '__contains__', '__copy__', '__delattr__', '__delitem__', '__doc__', '__getattribute__', '__getitem__', '__hash__', '__init__', '__iter__', '__len__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__', '__str__', 'addCurve', 'blocktype', 'channel', 'copy', 'curveConsts', 'curves', 'delBezPoint', 'delCurve', 'fakeUser', 'getBlocktype', 'getCurve', 'getCurveBP', 'getCurveBeztriple', 'getCurveCurval', 'getCurves', 'getNBezPoints', 'getName', 'getNcurves', 'getRctf', 'lib', 'name', 'next', 'properties', 'rctf', 'setBlocktype', 'setCurveBeztriple', 'setName', 'setRctf', 'tag', 'users']

for i in range(10):
for o in trajectory1.curves:
frame=i*20
tempPos=o.evaluate(frame)
tempName=o.name
print 'on frame '+str(frame)+', curve '+tempName+' has interpolated pos: '+str(tempPos)
on frame 0, curve LocX has interpolated pos: -12.0658063889
on frame 0, curve LocY has interpolated pos: 15.4735555649
on frame 20, curve LocX has interpolated pos: -7.77819442749
on frame 20, curve LocY has interpolated pos: 10.7129554749
on frame 40, curve LocX has interpolated pos: -3.2807290554
on frame 40, curve LocY has interpolated pos: 5.92898416519
on frame 60, curve LocX has interpolated pos: 1.36230826378
on frame 60, curve LocY has interpolated pos: 1.14720904827
on frame 80, curve LocX has interpolated pos: 6.08232021332
on frame 80, curve LocY has interpolated pos: -3.60687565804
on frame 100, curve LocX has interpolated pos: 10.8083820343
on frame 100, curve LocY has interpolated pos: -8.30803489685
on frame 120, curve LocX has interpolated pos: 15.469367981
on frame 120, curve LocY has interpolated pos: -12.931634903
on frame 140, curve LocX has interpolated pos: 19.9961471558
on frame 140, curve LocY has interpolated pos: -17.4538326263
on frame 160, curve LocX has interpolated pos: 24.3235778809
on frame 160, curve LocY has interpolated pos: -21.851858139
on frame 180, curve LocX has interpolated pos: 28.3921985626
on frame 180, curve LocY has interpolated pos: -26.1042022705

for object in bpy.data.objects:
if object.name.lower().find('source')!=-1:
print object.name
print object.getIpo().name
Audio_Omni_Source1
fast_pass
Audio_Omni_Source2
Orbit1
Audio_Omni_Source3
fast_pass

(it will be continued...)

June 24, 2008

Too much?



I like it. :-)


ACTUALIZATION:
I had some troubles with LADSPA/FAUST support on my usual customized UbuntuStudio Feisty... I though that the problem was because some old jack/alsa packages, so I rebooted on Hardy to test it. Not only all the problems dissapeared, but also I noted this impressive graphics difference. A network like the previous is showed here:


Isn't it beautiful? :-D

June 22, 2008

NetworkEditor Copy & Paste

One of the NE improvements which I worked on is the copy & paste processings boxes selections functionality.

You select the processings, copy (or cut) them from the processings context menu (or CTRL-C/X) and then paste it from the canvas context menu (or CTRL-V).

A graphical demonstration:



BTW, David added very nice icons to the menu items, so actually it look like this:

June 15, 2008

What do users essentially want?

DSCN1482I attended Google Developer day 2008. How colorful the day is~

One of the most impressive speech is given by Xiaosheng Tan, CTO of MySpace.cn. This guy is so funny, hehehe, that the last thing on earth I'll do is to write his joke down on my blog.??

MySpace.cn is an OpenSocial website, where users can embed all sorts of gadgets in their web pages. There is a gadget code competition on MySpace.cn. A lot of nice works are received and two of them are extraordinary.
One is "a clock that can stretch". One guy developed it in an afternoon when he got bored of his daily work and just wanna have fun for a while.
The other is "E-Album" by MagicBox, which is developed by a team of molihe.com, and is very versatile, powerful, and with profound technics of photoshop, 3D effects, etc.
It turns out the winner is "a clock that can stretch", whose user-setup amount achieves 10683 till now, far beyond the number of 8577 of "E-Album".

          StretchingClock2               E_Album_MagicBox                       
Why does the little pink lazy clock beat the brilliant magic E-Album down? Mr.Tan gave us a vivid illustration about what do users essentially want:

  • If users are the mass, simpleness and intuitive are especially crutial.
  • The tool must appear as CUTE as possible, always!
  • Fancy& design> Technic.
As to the myspace.cn users, one big bonus of the clock is-- "Emm, it apears cool!".

June 14, 2008

Getting Blender positions in CLAM via OSC

A very first attempt to access Blender parameters within CLAM, via Open Sound Control. A sphere traveling around the origin of coordinates in Blender, and CLAM printing the values. Nothing new, but... IT WORKS! :-)

Just a screenshot. It would be better to capture a video, but I don't know how to do it.

June 09, 2008

Network Scalability

Let's start describing a little of my CLAM GSoC first main area: the Network Scalability.

To be honest, one of the things that I dislike about visual object oriented DSP designers like Network Editor, Pd, etc, is the (visual) complexity that a network/patch sometimes can reach with a simple design that uses so many objects and correspondent "cables" connections, when the same design in a text code language could be a lot simpler to write, read and understand. That is the main reason to had choosen the network scalability proposed idea, because I think is one of the best ways to solve that issue. Beyond it seems to be a good solution because its logic, several years of similar implementations on both Max/MSP and Pd can prove that it really is. And that is the reason because my ideas about the implementation are closer to the Pd models. [1]

Subnetworks will allows the users to encapsulate networks onto new single processings. Once they finish a functional block, they can simplify it onto new "black boxes", improving the networks in a modular way.

To do that, I think to use network's level audio and control "sinks" and "sources" processings boxes, which will be appear as inlets and outlets on the newer encapsulated network-processings. [2]
A first approach could be making some "wireless" processings boxes, which can interconnect distant processings (at first) on the same network, using a key name as identifier, like a "variable". [3]

Those improvements are close related with the networks flow task of the proposed idea on the wiki. Once done that, and defined the infrastructure to use for recursive networks [4], I'll need to search a way to finish the integration of composite objects-subnetworks within the Network Editor.

As an intermediate task I though to allow some kind of grouping management on a same-level network. For now, the user can only selects objects in NE canvas to move, delete and copy/cut to clipboard. So, managing the processings as groups could be extended then to layers and later to subnetworks.

Well, this is an overview of the scalability area. Insofar as I involve further on developing these ideas I'll found more issues. For now, I'd been dedicated to make NE canvas interface improvements, so I think those related tasks don't be difficult. Let's see about the CLAM specific flow management...

[1] But of course, any suggestion against, or improving these models are welcome.
[2] Like "inlet" and "outlet" Pd objects.
[3] Like "send" and "receive" Pd objects.
[4] Writing this, I realize that my previous question on the devel-list has no much sense, because we are not talking about a defined limited levels, but recursion...

June 08, 2008

Standards for 3D Scene Description

What can you do if you want to describe a 3D scene including audio and graphics using some kind of standard? This is the result of a quick survey we did for CLAM, feedback is welcomed!

There are several standards and open languages to describe 3D graphics, but what if you want to add 3D audio description into the scene? Well, that limits your choices but there are still some possibilities.

First, you can take a look at MPEG4's BIFS and AudioBIFS. BIFS is in fact an extension of VRML. MPEG4's SAOL (Structured Audio Orchestra Language) can also be included inside AudioBIFS. Unfortunately I don't know of any Open Source reference implementation of this, although parts of it have been implemented, for instance, in Ross Bencina's Audio Mulch.

X3D is a W3 standard that is also a sucessor of VRML (with the advantage of using an new XML format), in which the sound is integrated too. There are no complete implementations of X3D available and all of them are written in Java. X3D shares a lot with BIFS. As a matter of fact the MPEG standard already includes a link to X3D.

Another possibility is using VML from the Verse project. This project is very much related to Blender. Using VML can tie you into their data model. However Verse is released with a BSD license.

Finally, SpatDIF, is an extension of the SDIF format for sound interchange. It uses OSC for real-time communication and SDIF as the intermediate file format. There are no available implementations yet and it is unclear whether it can be easily extended to include 3D graphics. However, SDIF can be transcoded into SAOL and, as already mentioned, SAOL can be included inside MPEG4's BIFS.

So, in summary, it looks as there are several competing and complementary efforts but none is sufficiently mature yet. Again, any feedback on related experiences will be appreciated.

June 07, 2008

Introducing CLAM

As I announced previously in the blog, I will start writing write about my CLAM Google Summer of Code project.[1]

My proposed project is focused in two main areas:
All right then, but... what does it means?

Let's introduce the subject describing very quickly some CLAM basic concepts: a network is a main central platform which manage and coordinate the use of black boxes signal and control processors units called processings. You can edit the networks very easily with the tool called Network Editor. Within the Network Editor (NE) you have a graphical canvas where you can put graphical instances of the processings (called processings boxes), and interconnect them as you want.



As you can see, a network within a NE canvas is some kind similar to a Pd, Max/MSP or Reaktor patch. But in certain aspects is more powerful because their expandability, as you can easily make your own processings just as your own graphical interfaces using the Qt Designer.[2]

So... after this quickly introduction the next post will start talking about the project itself.


[1] If you don't know what CLAM is, go here. If you don't know what GSoC is, here is an nice article about it. You can find further information about all CLAM selected projects here.
[2] You can read more about the framework advantages in the FAQ.

June 05, 2008

TypePlugin methods

No pain, no gain-- To be generally used, the SchemaAttribute of Clam_annotator has to support all sorts of attribute types: Enumerated, Float, Int, String, Segmentation, FrameDivision, FloatArray.

Why is it a type dependant task over the pool of the annotator? Well, if you are writing a name of an artist such as "Avril" into the pool, you should take the String type; if you are writing a danceability degree of a song, say 9.9, which means that the song is perfect for your dance-party??, you should take the Float type; if an algorithm are writing detected onsets of a song...well, this will mention the Segmentation, which is boring and complicated! I just give up explaining it.?????
All those types have different related methods: to add the new attribute, to validate whether the data is legal and to init the attribute instance.

Emm, as to the Segmentation type attribute initiation, it uses "pool.GetWritePool<CLAM::DataArray>" instead of "pool.GetWritePool<CLAM::Segmentation>", which is different from the other types.

It appears that there is none of CLAM::Segmentation's bussiness with the pool, but only with the SegmentationPane and auralizer. How and where is those segmentation classes converted from the DataArray outside the pool? This is done in the method "refreshSegmentation" of the class "SegmentationPane" by:
const CLAM::DataArray & descriptorsMarks = _pool?
            _pool->GetReadPool<CLAM::DataArray>("Song",currentSegmentation)[0]
            : nullSegmentation;

The Segmentation classes DiscontinuousSegmentation, UnsizedSegmentation, etc., have some validation functions which kinda overlap with the related ValidateData methods of SegmentationTypePlugin. The next Todo is to consider and realize a proper integration of Segmentation classes into the Pool/Schema.







June 01, 2008

Some words about my Google Summer of Code project.

In this post I'm going to talk a bit about what I'm doing at my GSoC project.
Basically it consists of 2 main goals:

  1. Implement MIDI in the Network Editor (NE from here)
  2. Implement Typed Controls.

Since the Typed Controls implementation is necessary for the MIDI stuff I'm giving it some priority.
I'm going to avoid all the CLAM background because it's well explained in the project's page and its tutorials.
CLAM uses Controls to modify Processing's internal parameters.
The basic problem with Controls is that at this moment they only manage float as data type, this hardly limits what you can do with them,
The idea of my project is to extend this functionality to have the possibility to use any data type that the programmer wishes. (float, integers, MIDI, OSC ;) )
For this i'm using the loved (and hated by many) C++ Templates.
Basically i wrote two classes called TypedInControl and TypedOutControl, which will replace InControl and OutControl in the future, but, to avoid compatibility issues, we decided not to touch the existent classes.
I'm using a design pattern for typed data connection that is already implemented in CLAM with the Ports (which are typed streams like audio, etc.). The data pattern has as main goal to let a non typed connector to generate typed connections correctly and with type check. To achieve this we divide the tasks in two clases, a base class (non-typed) and a child typed class, the type cheching is delegated to the child class, while the actual connection is being made with the base class.
At the moment all this is already implemented and working well.
Now I'm in charge of a more advanced step, the control registry for the processings. I'll write about this soon.

Talking about the MIDI implementation, the mail idea is to create 2 basic processings: MIDISource and MIDISink. MIDISource will be the one in charge of getting external MIDI messages and letting them flow in the CLAM network. Inversely, MIDISing will send MIDI messages generated (or modified) in CLAM to the external world. Both are going to use the Typed Controls, instantiated with MIDI messages as data type.
Besides these basic processings I've planned to create some processings that use them to have usefull functionality for musicians. For example, I'm already working on a MIDINote to Frequency and Amplitude translator called MIDINoteOutControlSender (I'll talk about this soon). At the beginning of the project I coded the MIDIMon, which basically reads MIDI messages and translates them into floats to see that MIDI is working.
I'm planning to code the MIDIControlSender, which will be in charge to read the MIDI control messages and translate them into floats to control parameters of existing processings.
Also I've a MIDIArp in mind, it's a MIDI arpeggiator (very useful to be used in MIDI controlled synths) and some other things i think will be interesting (maybe delays and that kind of stuff).

May 27, 2008

Agile Methodologies in Telefonica R&D

Some time ago I started having interesting but informal conversations with a manager in Telefonica R&D who was also interested in Software Engineering and methodologies. My point was that in a company like ours where innovation is a key issue and almost all development is geared toward bleeding edge products, Agile methodologies should be used. Besides, development teams are usually small, requirements are not clear at the beginning, and there is a need for having working prototypes soon in the development cycle... there was no doubt.

After not much we managed to convince some key people, including our Methodologies Division (who had had bad experiences in the past with Agile).
Although I was much for starting with eXtreme Programming and do a bottom up approach it soon became obvious for them that in such a large organization as ours they needed a slightly more structured approach with a focus more on management and less on development. That is why we chose to go for Scrum.

Actually, what we are deploying is a mixture of Scrum for the management layer and xP practices on the development layer. This seems to be a favored approach nowadays in many companies (see here, here or here, for example).

Just a couple of months afterwards we have more than 10 projects that are successfully working Agile. And so far everything seems to be positive: developers feel better and even some of our clients are now turning to us for implementing agile methodologies in their companies. It is still a bit soon but things look bright!

Bottom line, be careful with informal conversations you have by the coffee machine at work... they might become true and end up having a huge impact :-)

ps. I hope I have some time to blog a bit more about how to combine xP and Scrum but I have many posts in the queue right now.

May 25, 2008

CLAMs GSoC 08 Projects Announced


We are very happy to announce the final list of this year’s projects in the Google Summer of Code. We have been extremely fortunate to have a large number of great students apply for CLAM this year and we are confident that the 5 projects outlined below will have a huge impact on the project and the CLAM “family”:

Natanael Olaiz UNQ, Argentina
“Network scalability and Blender integration”
This is a two sided project. The first part will improve the usability of CLAM networks allowing users to hierarchically embed networks as a processing units. The second part consists in developing a set of Blender plugins and CLAM networks to drive audio spacialization based on direct
sound from Blender 3D geometries.

Yushen Han (Indiana University, US)
“Real-time woodwind instrument synthesizer using SMS models”
The project consists in building a real-time synthesizer based on CLAM processing plugins, using SMS models, allowing flexible sound timber manipulation. This project is a continuation to Greg Kellum’s 2007 GSoC project.

Francisco Tufro (UBA, Argentina)
“MIDI Implementation for Network Editor”
This project is both about developing all the needed and most common MIDI processings and also about doing all the required refactorings to the Framework in order to achieve this (i.e. Typed Controls).

Pawel Bartkiewicz (AGH University, Poland)
“Standalone chord extractor application”
This project is about adapting CLAM’s chord extraction technology into an standalone application focusing on usability for instrument players. This project will integrate existing visual and processing components and it will have impact on the interaction between realtime and offline CLAM components.

Wang Jun (Chinese Academy of Science, China)
“AnnMerger-to stand on the shoulders of the masses”
This project goal is add into Annotator the ability of combining several sources of several kinds (webservice, database, files, extractors) into a single project. Secondary goals are providing new data sources and polishing the program workflow.

Read here for more details on the projects:

May 24, 2008

Translanting MIDI Notes to frequencies in the diatonic scale using the central A (440hz) as reference

One of the plug-ins that i'm programming for my GSoC project is a MIDI Note to frecuency and velocity translator.
Beyond the technical background of the problem, i'm writing down the theoretical aspects of it, nothing hard, but usefull to have as a reference for the future.

It's not even a mystery to know that to obtain the frequency of a note in the diatonic scale separated by n semitones from the reference frequency we can use the next formula:

Freq_{Note} = Freq_{Ref} + 2^{(\frac{n}{12})}

So, also knowing that MIDI notes are represented with integers, in which for consecutive notes have one semitone of difference, and that the 440hz A is the note 69 (so, 69 is A, 70 is A#, and so..), doing some simple replacements we have that:

Freq_{Note} = Freq_{Ref} + 2^{(\frac{n-69}{12})}

And this is just what we were looking for, (n-69 generates an offset from the reference note)
Now, only by replacing the reference frequency for the 440hz we obtain:

Freq_{Nota} = 440hz + 2^{(\frac{n-69}{12})}

Here I give you the C++ code that I used in the MIDINoteOutControlSender:

 
frequency = 440 * pow(2.0,(note-69.0)/12.0)

Hordia wrote last year on his blog the inverse formula to translate from fundamental frequencies to MIDI notes.

May 21, 2008

Some words about my Google Summer of Code project

Since my GSoC project was approved I'll start writing about it. As the world use English universally, that's the language i'll use for my posts and, if I have time, i'll translate them into Spanish so that everyone understands.

For those who do not know what i'm talking about i'll explain this briefly: Google has a program to promote Open Source called Google Summer Of Code. You can read about it on the program FAQ. One of the mentoring organizations selected this year (like last year) to be part of GSoC is CLAM, a C++ framework that helps creating music and audio related applications. My project consists basically in incorporate a class to handle typed controls (at this time it only uses floats) to the framework's core, so in the future CLAM will be able to control parameters with virtually any data type. The idea is to use this with MIDI and OSC, as well as any future control protocol that may become available. This enhancement is necessary for the ultimate goal of my project: achieving a MIDI implementation for NetworkEditor, allowing CLAM to have a big approach towards music.

My idea is to write about my project and to show updates here. I hope this will be useful and enjoyable for you as it is for me!!