Monday, November 21, 2011

A common confusion in Marsyas

One of the most common problems that is confusing to first time users of Marsyas happens when trying to tap into the data-flow at different parts of the network. In this post I explain how the problem arises and how it can be addressed. The examples provided are using the Marsyas swig generated python bindings but everything discussed would also apply to similar C++ code.  Even though I don't go into details I try to explain a little bit about what causes the confusion and why have not been able to address the problem yet. It is also important to note that historically the creation of a control for "tapping" into the data-flow was not part of Marsyas from the beginning.

To illustrate consider the following code (for those of you too lazy to cut and paste you can
find the corresponding source code in the Marsyas source tree under src/marsyas_python/ :

#!/usr/bin/evn python
from pylab import *
from marsyas_util import * 
import sys
import getopt
import os

spec = ["Series/net",

net = create(spec)
fname = net.getControl(


src_data = 
win_data = 

print win_data.to_realvec()

The expectation is that src_data will contain a buffer of data from the sound-file provided as the first command-line argument (the output of the SoundFileSource named src) and that win_data will contain the output of Windowing which should be the src_data multiplied by a bell-shaped window function. Unfortunately win_data contains a whole bunch of zeros (512 to be precise). Here are the corresponding figures:

What is the problem ? Without going into too much detail about the internals of Marsyas the issue is that the Windowing MarSystem is the last MarSystem in a Series composite and therefore it's output is essentially the output of the Series Composite. For reasons having to do with the automatic memory management of all buffers in a network by Marsyas and efficiency this data is allocated and managed by the enclosing Series Composite rather than the child MarSystem.

So how can you access the desired data ? You can tap the Series Composite instead.

So by replacing you now can access the data:
win_data = 
win_data = 

Here is the correct picture:

There are also two other alternatives if you insist on using the path that includes the Windowing MarSystem. You can simply add a "dummy" Gain simply so that Windowing is not the last processing object by changing the network specification to (and not replacing the control path for windata):
spec = ["Series/net",

Finally another alternative would be to explicitly link the controls by doing:

Obviously it would be nice not to have this issue and it is something we have given some thought. It probably would be possible doing the control linking automatically when adding MarSystems to a Composite. Alternatively we could solving by an extra copy of the buffer (essentially equivalent to adding the dummy Gain). One thing that complicates issues is the semantics of Composites like Fanout and Parallel for which the output does not correspond to the output of any of the children (basically part of the output realvec corresponds to each child MarSystem).

This is definitely an issue that would be good to address as it is a recurring question in emails by users. Hopefully this blog post provides reasonable workarounds to get you going and hopefully at some point we will be able to make this process more transparent.