Sie sind auf Seite 1von 48

flext

C++ programming layer for cross-platform


development of PD and Max/MSP externals

An introduction

by Thomas Grill

Abschlussarbeit des Lehrgangs Computermusik und elektronische Medien


Institut für Komposition und Elektroakustik
Universität für Musik und darstellende Kunst Wien
flext - C++ programming layer for cross-platform development of PD and Max/MSP externals

Abstract

flext1 seeks to represent a uniform programming interface for extending the most common
modular real-time audio systems Max/MSP and Pure Data (PD) with external modules, or
short externals. These modules provide a way to tailor such a system for one’s special needs
and supply additional functionality. Source code based on flext is able to exploit nearly all
features of the respective real-time framework while staying completely independent of the
actual host system and platform (hardware and operating system). flext currently supports PD
for Linux, Windows and OSX as well as Max/MSP for OS9 and OSX (and shortly Windows).
Support for jMax under Linux, OSX and Windows and other systems can follow in the near
future.

flext stellt eine einheitliche Schnittstelle für die Erweiterung der verbreitetsten Echtzeit-
Audio-Systeme Max/MSP und Pure Data (PD) mit externen Modulen, oder kurz externals,
zur Verfügung. Solche Module bieten die Möglichkeit, diese Systeme für spezielle
Anforderungen maßzuschneidern bzw. um zusätzliche Funktionalität zu erweitern.
Programmcode, der auf flext basiert, kann beinahe alle Funktionen des jeweiligen
Echtzeitsystems ausschöpfen und dennoch völlig unabhängig vom tatsächlichen eingesetzten
Zielsystem oder der Plattform (Hardware und Betriebsystem) bleiben. flext unterstützt derzeit
PD für Linux, Windows und OSX, sowie Max/MSP für OS9 und OSX (und in Kürze
Windows). Unterstützung für jMax unter Linux, OSX und Windows und andere Systeme
kann in der Zukunft folgen.

page 2
flext - C++ programming layer for cross-platform development of PD and Max/MSP externals

Contents
Abstract ...................................................................................................................................... 2
Contents...................................................................................................................................... 3
I. Introduction ........................................................................................................................ 4
II. Basics ................................................................................................................................. 8
1. Prerequisites ................................................................................................................... 8
a) Build environments .................................................................................................... 9
b) Installing the real-time-system SDK ........................................................................ 10
c) Obtaining and installing the flext library.................................................................. 10
d) Programming in C++................................................................................................ 11
e) License issues ........................................................................................................... 11
2. Building blocks of a simple external............................................................................ 12
3. How to build flext-based externals............................................................................... 14
III. Examples ...................................................................................................................... 15
1. Simple message based externals .................................................................................. 15
2. More advanced message based externals ..................................................................... 18
3. Using attributes ............................................................................................................ 20
4. DSP (signal-based) externals ....................................................................................... 24
5. Using sample buffers.................................................................................................... 26
6. Using timers ................................................................................................................. 30
7. Binding to symbols....................................................................................................... 32
8. Building libraries of externals ...................................................................................... 35
9. Using threads................................................................................................................ 37
10. Interfacing to other DSP frameworks....................................................................... 40
a) STK .......................................................................................................................... 40
b) SndObj...................................................................................................................... 43
IV. Applications ................................................................................................................. 45
1. xsample......................................................................................................................... 45
2. VASP modular ............................................................................................................. 45
3. py/pyext........................................................................................................................ 45
4. others ............................................................................................................................ 46
Biography ................................................................................................................................. 47
References ................................................................................................................................ 48

page 3
flext - C++ programming layer for cross-platform development of PD and Max/MSP externals

I. Introduction

With the advent of powerful computers the task of producing and processing digital sounds
has become less tiresome than it has been in the past.
Traditionally, all operations on sampled audio material have been file-based, which means
that a transformation step takes the audio data from a source file and produces a file
consisting of the results of the operation. In the course of producing a piece of electronic
music a lot of these steps are necessary, involving a large number of intermediate files and the
related handling of data.
In order to facilitate things for the user, all of these systems (should) have scripting
capabilities, which means that a list of operations or more complex description of
transformations and their parameters can be passed to the system (as a “batch file”), which
then follows the instructions, processes the data and again produces an audio file as a result.
Examples of such computer music environments are Csound2, CDP3 or fftbox/NMS44.

Striving for increased user-friendliness two main advancements of dealing with these
descriptions of transformation processes have crystallized:

• The functional approach:


The “batch” scripting capabilities have been expanded into a fully-fledged and more
or less general programming language. The transformation steps are represented by
function-like unit generators (UGENs)a which can be combined into complex
formulas. Parameters to the processes are variables of the script language. The most
prominent example utilizing this methodology is SuperCollider5.

Figure I-1 – A relatively simple SuperCollider script with 8 parallel voices, with UGENs suffixed by .ar or .kr

• The visual approach:


Here, the transformation steps are visualized as boxes (modules) that are
interconnected. Audio data is running through cables from one box outlet (as a data
source) to another box inlet (data sink) and also the parameters controlling the
transformations are passed as “messages” through similar box chains.
Due to the intuitive handling and the shallow learning curve several systems have
become popular which are mostly based on the work of Miller Puckette6 at IRCAM.
These are the similar frameworks Pure Data (PD)7, Max/MSP8, jMax9 and not very
different from them, Reaktor10.

a
From the SuperCollider glossary: UGEN – An object that produces or processes audio data

page 4
flext - C++ programming layer for cross-platform development of PD and Max/MSP externals

Figure I-2 – A typical Max/MSP patch featuring some message and signal objects
and some graphical elements for user interaction.

In order to incorporate user input (which is made up of relatively slow parameter changes) or
other transformation-controlling parameter values into the operation in an efficient manner,
all of the newer systems have split their processing tasks into two levels:

• Calculation at control rate (the “message domain”):


Most parameters controlling a transformation do not change very fast – a fact that can
be exploited to speed up audio calculations because values steering an algorithm (like
for example a filter formula) are known to be constant for a larger number of audio
samples to be processed.
The control rate is typically no more than about 1 kHz, which results in a time
granularity of approximately 1 ms. This is supposed to be fast enough for typical non-
audio data. Furthermore, the data flow at control rate is asynchronous, which means
that data can be passed, but need not. This implies that a parameter value that is
constant over a longer period of time need not be sent at every control tick but only
when a change of the value occurs.
The message domain is for most systems also capable of handling non-numerical data,
as for PD, Max/MSP and jMax there are symbols (character strings that are internally
cached) or chunks of numbers and symbols (so called lists).

• Calculation at signal rate (the “DSP domain”):


The signal rate is related and in most cases equivalent to the sample rate of the audio
hardware, although for most systems internal up- or downsampling of audio data is
possible.
Calculation in the DSP domain is in all major systems constrained to one data type
(which typically is the IEEE 32-bit floating point format) which is handled most
efficiently by the CPU. The signal rate is always a fixed integer (power of two)
multiple of the control rate, that is, one block (vector) of audio data can be processed
page 5
flext - C++ programming layer for cross-platform development of PD and Max/MSP externals

while the steering parameters to the algorithm - determined at control rate - remain
constant, leading to the above mentioned gains in efficiency. Modern CPUs featuring a
SIMDb instruction set (like “AltiVec” on the PPC G4/G5, or “MMX” and “SSE” on
the Intel processors) can be exploited to further speed up calculation.
The data in the DSP domain is calculated synchronously – this means that each block
of audio data is continually recalculated. The data can be considered to be constantly
“streaming” through the module boxes and out of each signal box outlet into the next
box inlet.

The processing tasks of these domains are further organized into modules, or objects, which
can be simple (like the addition of two numbers) or complex (as is a Fourier transformation or
a networking interface). Quite often a module serves both domains at a time by defining inlets
and/or outlets for signals and receiving control values as messages.

Figure I-3 - The [*~ ] object in PD has a signal sent into its left inlet which is multiplied by a message value
received in the right inlet. The result of the operation is output as a signal again.

It is a good thing that most systems under examination (e.g. PD, Max/MSP, SuperCollider 3,
Aura11, GStreamer12) can be extended with external modules (a.k.a. externals) which are
made up of exactly the same building blocks as the functions or objects (internals) that the
system itself provides. Hence, there is virtually no difference between externals and internals
apart from the fact that the latter are delivered along with the system.
Due to the fact that an external can be developed by anyone, numerous collections of
extensions for the different real-time systems have evolved.

There are really very few additional major elements inside a real-time system (and these are
partly also realized by special internals):
One is a core mechanism providing the organization of the several UGENs and their
interconnection (as patches or scripts) as well as the formation of reusable building-blocks
(abstractions or macros).
Another point is the interfacing to the audio hardware and the scheduling involved to drive the
DSP and message calculation just in time.
Thirdly, the system manages resources that the transformation objects or functions can use,
for example memory buffers containing sampled audio data or, less obvious, a pool of
symbols for often-used messages etc.
Additionally there may exist a graphical user interface for the patcher system and input of
parameters or visualization of results, providing feedback for interactive operation.

b
SIMD stands for „single instruction, multiple data” – one instruction to the CPU can calculate multiple
instances of similar data

page 6
flext - C++ programming layer for cross-platform development of PD and Max/MSP externals

Figure I-4 – Typical GUI elements (sliders, bang, toggle button , radio buttons, numerical field, canvas) in PD

Typically, graphical elements can be created from within externals. They are not really special
but just utilize the graphical interface functionality provided by the real-time system to
visualize themselves as graphical rather than box-shaped. These graphics interfaces are
different from system to system and flext does not attempt to unite them. They are simply too
different. However, other independent graphics systems may (and will) be based on flext.

For the following we will concentrate on the development of externals for the systems PD and
Max/MSP, but it is once more emphasized that under the hood all the mentioned modular
real-time systems are very similar and that flext may well once cover more of these systems.

page 7
flext - C++ programming layer for cross-platform development of PD and Max/MSP externals

II. Basics
All elements in a real-time systems have to be as fast as possible to keep latency low and
allow as many voices or transformations as possible. This is the main reason why externals
are in general realized as readily compiled binary modules that are loaded into the system.
“Compiled” means that the program code (almost exclusively in the C/C++ language)
describing an external has been translated into machine code (which is directly executable by
the CPU) before actual usage.
All real-time systems that are extensible by modules provide a programming interface (API)
so that the modules can communicate with the system and vice versa. For example a module
would announce that it wants to have 2 inlets and 1 outlet by calling the respective function of
the API. Again, the real-time system would tell the module that a message has been sent to it
by using a so-called callback function. Callback functions are entry points inside the external
module, so that it can receive information from the real-time system. A module announces the
existence of such a callback function when it is created. Typically, each message (be it of type
float, list etc.) that can be received by the module needs a designated callback function, and
likewise the signal processing needs one that will be called whenever a block of audio data
wants to be processed.
There exist excellent tutorials on how to write native externals for Max/MSP13 or PD14,
respectively. However, when working through the pages it becomes obvious that there are
fundamental differences in the APIs of the different systems that make the externals
incompatible. Hence, one system is not able to use an external module made for another
system although the functionality may be exactly the same. Even worse, not even the C/C++
program code of an external module is the same for different systems (although for Max/MSP
and PD there is some resemblance due to their common origin in the works of Miller
Puckette).
This is where flext comes into play. It provides an API of its own which stays exactly the
same no matter if the external will be used for Max/MSP or PD. It is important to realize that
while the C++ source code stays the same, the external has to be targeted for one real-time
system at the time of compilation where the actual loadable module is produced.
flext does all the translation between the program code and the programming interface of the
real-time system along with the necessary callback functionality. As flext-based externals are
written in C++, they make use of inheritance, which is a handy feature of this object-oriented
programming language. Multiple objects can be derived from one more general one,
inheriting all its features, complemented by new more special ones. Furthermore there are
numerous functions built into flext which tremendously facilitate the task of developing an
external. This can be seen in the tutorial examples below, each one presenting a different
aspect of the flext library.

1. Prerequisites
flext is a programming library which implies that when using it you will have to do some
programming in C++. However, programming isn’t black magic and it need not be difficult
either – nevertheless some hurdles have to be cleared in the beginning. An important one is
the handling of a development environment that is needed to build external modules.

page 8
flext - C++ programming layer for cross-platform development of PD and Max/MSP externals

a) Build environments
flext supports all major build environments for the respective platforms. The library itself and
also the tutorial examples come with building scripts for each of them. It is beyond the scope
of this introduction to describe the several frameworks in detail but the (tested) possible
choices shall be listed shortly:

i) Microsoft Windows
Currently, PD runs on Windows and Max/MSP will follow in the near future.

• Microsoft Visual C++ 6.0 or 7.0 (.NET)


This is the most commonly used development package. Especially version 7.0 is able
to exploit all features of flext.
• Borland C++ 5.5
This compiler package is lightweight and it’s freely downloadable from the Borland
homepagec. It has a good C++ support but cannot handle the more advanced multi-
threading features of flext.
• cygwin gcc
cygwind is a Unix environment capable of running under Windows. It’s free and it
comes with the GNU C++ compiler, which is recommended if of version 3.2 and
above.

ii) Mac OS9


This operating system is not supported by Apple any longer and therefore slowly dieing. Only
Max/MSP is (still) running here, PD never will.

• Metrowerks Codewarrior, version 6 upwards


This is the standard compiler for MacOS. Be sure to have version 8.3 at least to avoid
some unpleasant bugs in the C++ language support.

Earlier versions of flext also supported the free Apple MPW environment and it may still
work but there’s no guarantee for that… (it’s simply too weak)

iii) Mac OSX


OSX has inherited a burden from its predecessor: it’s the schizophrenic case of two different
binary file formats that are totally incompatible. While Max/MSP currently needs all externals
to be built in the old OS9 CFM format, PD only wants the new Mach-O format.

• Metrowerks Codewarrior, version 6 upwards


This compiler is capable of building both CFM and Mach-O formats but currently
only Max/MSP externals can be built with it due to a deficiency of the linker.

c
Borland C++ 5.5 download - http://www.borland.com/products/downloads/download_cbuilder.html#
d
cygwin - http://www.cygwin.com

page 9
flext - C++ programming layer for cross-platform development of PD and Max/MSP externals

• Project Builder
This build environment is part of the Apple OSX Developer Toolse and it is based on
the GNU c++ 3.1 compiler and it is for free. Since it can solely produce Mach-O
binaries, only PD externals can be made.

iv) Linux
Max/MSP won’t run on Linux in the foreseeable future, but PD does very well. Luckily,
every Linux distribution comes with a standard compiler:

• GNU g++
It is freef and it is ok (however, it’s not a fast as other compilers) and it can be
recommended as working reliably from version 3.2 upwards.

b) Installing the real-time-system SDK


As already mentioned earlier, external modules need to communicate with the respective
hosting real-time-system through a well-defined programming interface. The SDK (Software
Development Kit) with one or more C-language header files that contain these definitions
doesn’t come with the standard distribution of PD or Max/MSP necessarily but you can
download them from the respective website. For PD you’ll have to download its source code
distribution packageg and for Max/MSP you’ll need the Max/MSP Software Development
Kith.

c) Obtaining and installing the flext library


After downloadingi a current flext release for your platform and unzipping the compressed file
you will find a readme.txt containing some information, the license texts license.txt and
gpl.txt as well as several build-*, config-* and make* files located in the main folder.
Building and installing the library should be as easy as editing the appropriate config-*.txt
file so that the various settings therein fit to your system and then running the matching
build-*.bat or .sh file, depending on your platform. The readme.txt tells you which
combination to choose.
For PD under Windows for example you’ll than have a subfolder flext to your pd installation
containing various *.h C-header files as well as several *.lib flext library files.
If you want to use the CodeWarrior build environment to compile flext for Max/MSP, things
are a bit different. You’ll have to open the flext.cw project file and edit or add a number of
“Source Tree” definitions to your CodeWarrior configuration. Refer to the CodeWarrior
documentation for how to do that.
Finally, flext should be usable now and you can start developing your externals. If you have
no experience of programming flext-based externals you should download the tutorial
package15 containing a number of examples (some of which are shown below) demonstrating
all major aspects of the flext framework.
Probably this preceding description is too light-minded to get you started with the
development system and the flext library. Anyhow, I’d really recommend that you find
someone to help you with the initial steps to become acquainted and comfortable with it all.

e
Apple OSX Developer Tools - http://developer.apple.com/tools
f
GNU g++ - http://gcc.gnu.org
g
PD source code packages - http://www-crca.ucsd.edu/~msp/software.html
h
Max/MSP SDK - http://www.cycling74.com/products/dlmaxmsp.html
i
flext download - http://www.parasitaere-kapazitaeten.net/ext/flext

page 10
flext - C++ programming layer for cross-platform development of PD and Max/MSP externals

d) Programming in C++
Flext massively uses nearly all aspects of the C++ language. However, this doesn’t imply that
you have to do that as well. By looking at the code of several simple flext-based objects you’ll
surely recognize the elements that these objects are made up of. In this sense it’s definitely
possible that you can start with programming externals with no prior knowledge of C++,
provided that you are not the faint of heart. You can acquire a profound knowledge of the
language by – having some patience - just using and experimenting with it, nevertheless a
good C++ textbook can help you over some beginner’s difficulties.

e) License issues
Flext is distributed under the GPL licensej, which you should carefully read. This means that
download and usage of flext is free and that the source code of flext is fully disclosed. The
GPL has several other implications, one of which is that externals programmed with flext need
to be distributed open-source under the GPL as well. This is a good thing since other people
can learn from these externals again and the common wisdom will grow and the world
become a better one.

j
GNU General Public License - http://www.gnu.org/copyleft/gpl.html

page 11
flext - C++ programming layer for cross-platform development of PD and Max/MSP externals

2. Building blocks of a simple external


In the following, the C++ source code of the example object simple1 will be analyzed. The
actual functionality of the external will be described with the examples a bit later.

First of all, the flext header file must be included. It is a part of the flext distribution and
contains all the necessary definitions used throughout a typical flext-based external.

#include <flext.h>

Immediately afterwards we check for the flext version to see if it is up to date. This is
important because some features contained in a current version of flext may not have been
present in an earlier one.
#if !defined(FLEXT_VERSION) || (FLEXT_VERSION < 400)
#error You need at least flext version 0.4.0
#endif

Next, we can start with the object definition. A flext object is simply represented by a C++
class derived from the base class flext_base. The base class already contains a number of
essential features that are automatically inherited by simple1, in this case.
For a stand-alone external (which is not part of a library of externals) as we want to have it
here, it is important that the class name matches the name of the object we want the create. In
our case the object in PD or Max/MSP will be [simple1].
class simple1:
public flext_base
{
FLEXT_HEADER(simple1,flext_base)

The statement FLEXT_HEADER (or its variant FLEXT_HEADER_S) is necessary to include some
hidden commands (that we don’t need to care about) into the class code. Again, the current
class simple1 and its base class flext_base must be specified.

Following, we define some members of the class:


First, the constructor, a function that is called when an instance of this class is created. This
happens when an object [simple1] is placed in our PD or Max/MSP patch. The constructor is
used for initialization purposes and has always the name of the class itself.
The constructor takes no arguments and so will the [simple1] object.
public:
simple1()
{
AddInAnything(); // add one inlet for any message
AddOutFloat(); // add one float outlet (has index 0)

FLEXT_ADDMETHOD(0,m_float); // register method for inlet 0


}

As documented inline (after the // ) the constructor first creates an inlet that can receive any
type of message (the left-most inlet must be of that type) and also an outlet that can send a
float message (and nothing else).

page 12
flext - C++ programming layer for cross-platform development of PD and Max/MSP externals

The FLEXT_ADDMETHOD statement binds the m_float method (see below) to the inlet 0 (the
numbering starts with 0 for the left-most inlet). As m_float takes floating point values as
arguments, only those messages will be handled by it.

Secondly, we define the method (a function that is a member of a class) m_float already
mentioned in the constructor. It takes one parameter of the C type float, which represents a
floating point value.
The method simply calculates the inverse of an input value (= 1 / value). If the value is zero
(which can’t be inverted) an error message is output to the console (and the result is set to
zero as well). Afterwards the resulting value is output to the outlet.
void m_float(float input) // method for float values
{
float result;

if(input == 0) {
// special case 0
post("%s - zero can't be inverted!",thisName());
result = 0;
}
else
// normal case
result = 1/input;

// output value to outlet


ToOutFloat(0,result);
}

As a link to PD or Max/MSP we need to have a so called callback wrapper for a method we


want to be triggered by messages received at an inlet. In this case, we do that for the method
m_float already defined above that has 1 argument of type float.

FLEXT_CALLBACK_1(m_float,float)
};

This is all we need to define for a simple external.


At the end, we tell the system explicitly how the class shall be named and what creation
arguments it takes (none in this case).
FLEXT_NEW("simple1",simple1)

page 13
flext - C++ programming layer for cross-platform development of PD and Max/MSP externals

3. How to build flext-based externals


Now that you have flext installed on your system and the source code of an external readily at
hand the next step would be to render this source code into a usable external module that can
be loaded by your real-time system.
Two main steps have to be taken to accomplish this:
• The source code file(s) must be compiled into a machine-readable object format. This
is what a compiler does. You can do that inside the project space of a development
system (as with Microsoft Visual C++ or CodeWarrior) or at the command line of the
console (Microsoft Visual C++, BorlandC++ and all ports of GNU g++). It is beyond
our scope to go into details but a few main points have to be considered:
o You’ll have to specify so called “include file paths” (typically with the –I
command line option of the compiler) so that the compiler can find the header files
of the real-time-system SDK and of the flext library
o You’ll have to set a compiler definition (typically with the –D command line flag)
to specify the target platform of your flext-based external. For PD, you would
specify –DFLEXT_SYS=2 and for Max/MSP –DFLEXT_SYS=1 .
There are several other switches that can be set but for now we are fine with these.
• The object file(s) must be linked with the flext library and the library files of the real-
time-system SDK to a loadable so-called dynamic (or shared) library file. This is the
binary format that PD or Max/MSP can load.
It is common that the compilation and the linking is done in one step (by just omitting
the –c flag to the compiler, so that it calls the linker after producing the object files
itself or within a project space of a development environment where you hardly notice
the linking step explicitly)
The important point is that again some prerequisites have to be fulfilled:
o PD requires a special naming of the external modules. Apart of the main file name
which is just the name of the desired object (like e.g. “sine~” or “router”),
depending on the platform the extension of the binary file has to be .pd_win,
.pd_linux or .pd_darwin (the latter for OSX) so that it can be recognized as a
loadable module. Max/MSP doesn’t want an extension at all, although .mxe might
be valid in the future.
o The linker needs to find the necessary libraries to be included - for example the
flext library flext.lib for Windows or flext.a for Linux or OSX, respectively, or
the SDK library files (like pd.lib for PD under Windows or maxlib and
maxaudiolib for Max/MSP). This can be provided by specifying a “library path”
with the –L command line flag.

Once the building of an external has been successful it can be attempted to load it into the
real-time-system. For that the location must be announced to the system (with the –path
command line flag for PD or the file preferences in Max) or the file must be copied to a
standard place where externals typically reside (like the PD extra subfolder or the externals
folder for Max/MSP).

page 14
flext - C++ programming layer for cross-platform development of PD and Max/MSP externals

III. Examples
In the following you will find a few of the more representative examples of the flext tutorial
package. These shall introduce you to all of the features of the Max/MSP and PD real-time
systems that flext supports or the functionality which it additionally provides.

1. Simple message based externals


You already know the first one. It is the [simple1] object that has already been analyzed
above – but here again in full glory.

Figure III-1 – simple1, an object that takes numbers for input, calculates the inverse,
and outputs the result at the outlet. Additionally, a help text describing its usage can be displayed.

// include flext header


#include <flext.h>

// check for appropriate flext version


#if !defined(FLEXT_VERSION) || (FLEXT_VERSION < 400)
#error You need at least flext version 0.4.0
#endif

// define the class that stands for a pd/Max object


// Attention: the class name must be the same as the object name!! (without an eventual ~)
// Special names are possible with the usage of libraries (see the lib1 tutorial example)

class simple1:
// inherit from basic flext class
public flext_base
{
// obligatory flext header (class name,base class name)
FLEXT_HEADER(simple1,flext_base)

public:
// constructor
simple1()
{
// define inlets:
// first inlet must always be of type anything (or signal for dsp objects)
AddInAnything(); // add one inlet for any message

// define outlets:
AddOutFloat(); // add one float outlet (has index 0)

page 15
flext - C++ programming layer for cross-platform development of PD and Max/MSP externals

// register methods
FLEXT_ADDMETHOD(0,m_float); // register method "m_float" for inlet 0
}

protected:
void m_float(float input) // method for float values
{
float result;

if(input == 0) {
// special case 0
post("%s - zero can't be inverted!",thisName());
result = 0;
}
else
// normal case
result = 1/input;

// output value to outlet


ToOutFloat(0,result); // (0 stands for the outlet index 0 - the leftmost outlet)
}

private:
FLEXT_CALLBACK_1(m_float,float) // callback for method "m_float"
};

FLEXT_NEW("simple1",simple1) // instantiate the class

The second example of these basic message based externals is one that adds two numbers.
[simple2] has got two inlets, of which the right one just stores the input value, while the left
one takes the input and triggers the calculation. The result of the addition is sent to the outlet.
Additionally it shows that flext-based objects always understand the [help( message. Without
special measures within the class definition (overloading of the m_help virtual function) this
prints a default text to the console.

Figure III-2 – simple2 adds two numbers. The one sent into the right (“cold”) inlet is stored internally until a
number is sent into the left (“hot”) inlet. Then, the addition is calculated and the result output at the outlet.

page 16
flext - C++ programming layer for cross-platform development of PD and Max/MSP externals

/*
flext tutorial - simple 2

Copyright (c) 2002,2003 Thomas Grill (xovo@gmx.net)


For information on usage and redistribution, and for a DISCLAIMER OF ALL
WARRANTIES, see the file, "license.txt," in this distribution.

-------------------------------------------------------------------------

This is an example of a simple object doing a float addition


*/

// include flext header


#include <flext.h>

// check for appropriate flext version


#if !defined(FLEXT_VERSION) || (FLEXT_VERSION < 400)
#error You need at least flext version 0.4.0
#endif

class simple2:
public flext_base
{
FLEXT_HEADER(simple2,flext_base)

public:
// constructor with float argument
simple2(float init);

protected:
void m_float1(float f);
void m_float2(float f);

// stored argument of right inlet


float arg;

private:
// FLEXT_CALLBACK_F(...) is a shortcut for FLEXT_CALLBACK_1(...,float)
FLEXT_CALLBACK_F(m_float1) // callback for method "m_float1" (with one float argument)
FLEXT_CALLBACK_F(m_float2) // callback for method "m_float2" (with one float argument)
};

// instantiate the class (constructor has one float argument)


FLEXT_NEW_1("simple2",simple2,float)

simple2::simple2(float init):
arg(init) // store argument
{
// define inlets
AddInAnything(); // first inlet of type anything (index 0)
AddInFloat(); // additional float inlet (index 1)

// define outlets
AddOutFloat(); // one float outlet (has index 0)

// register methods
FLEXT_ADDMETHOD(0,m_float1); // register method (for floats) "m_float1" for inlet 0
FLEXT_ADDMETHOD(1,m_float2); // register method (for floats) "m_float2" for inlet 1
}

void simple2::m_float1(float f)
{
float res;
res = arg+f;

// output value to outlet


ToOutFloat(0,res); // (0 stands for the outlet index 0)
}

void simple2::m_float2(float f)
{
// store float
arg = f;
}

page 17
flext - C++ programming layer for cross-platform development of PD and Max/MSP externals

2. More advanced message based externals


The tutorial includes a few examples of more advanced treatment of PD or Max/MSP
messages. The one presented here is an adaptation of the [counter] object conceived by
IOhannes Zmölnig which he presents in his “Howto write an external for puredata”. It has
been chosen so that a direct comparison of a flext external to a native one is possible.
Most of the features of the original object translate one to one, while some must be
implemented differently with flext. This is explained in the source code comments.

Figure III-3 – adv3 is a port of the counter example from Iohannes Zmölnigs PD external tutorial.

/*
flext tutorial - advanced 3

Copyright (c) 2002,2003 Thomas Grill (xovo@gmx.net)


For information on usage and redistribution, and for a DISCLAIMER OF ALL
WARRANTIES, see the file, "license.txt," in this distribution.

-------------------------------------------------------------------------

This is a port of Iohannes Zmölnigs "counter" example to the flext paradigm.


Find the original at http://iem.kug.ac.at/pd/externals-HOWTO/node5.html

The functionality is exactly the same, with one exception:


flext doesn't support default arguments, hence a message "bound 1" will translate into
"bound 1 0" in the original example, but won't be recognized with flext.
This can be easily circumvented by using a method digesting a variable argument list, but
was omitted for the sake of clearness.

Apart from that you'll notice several differences to the original C object:
- with flext, callbacks have to be declared for all registered methods
- Flext allows the full usage of integer types
- there are no real "passive" methods with flext.
These can be emulated by methods, or more flexibly, attributes (see example "attr3")
- Help symbols can't be defined that freely. This is because in Max/MSP help files always
have the name of the object with a suffix .help appended.
However with flext, a path to the respective help file may be specified
*/

page 18
flext - C++ programming layer for cross-platform development of PD and Max/MSP externals

// include flext header


#include <flext.h>

// check for appropriate flext version


#if !defined(FLEXT_VERSION) || (FLEXT_VERSION < 401)
#error You need at least flext version 0.4.1
#endif

class adv3:
public flext_base
{
FLEXT_HEADER_S(adv3,flext_base,setup)

public:
// constructor with no arguments
adv3(int argc,t_atom *argv):
i_step(1)
{
// --- initialize bounds and step size ---
int f1 = 0,f2 = 0;
switch(argc) {
default:
case 3:
i_step = GetInt(argv[2]);
case 2:
f2 = GetInt(argv[1]);
case 1:
f1 = GetInt(argv[0]);
case 0:
;
}
if(argc < 2) f2 = f1;

m_bound(f1,f2);

i_count = i_down;

// --- define inlets and outlets ---


AddInAnything("bang, reset, etc."); // default inlet
AddInList("bounds (2 element list)"); // inlet for bounds
AddInInt("step size"); // inlet for step size

AddOutInt("counter"); // outlet for integer count


AddOutBang("overflow bang"); // outlet for bang
}

protected:

void m_reset()
{
i_count = i_down;
}

void m_set(int argc,t_atom *argv)


{
i_count = argc?GetAInt(argv[0]):0;
}

void m_bang()
{
int f = i_count;
i_count += i_step;
if(i_down != i_up) {
if((i_step > 0) && (i_count > i_up)) {
i_count = i_down;
ToOutBang(1);
}
else if(i_count < i_down) {
i_count = i_up;
ToOutBang(1);
}
}
ToOutInt(0,f);
}

void m_bound(int f1,int f2)


{

page 19
flext - C++ programming layer for cross-platform development of PD and Max/MSP externals

i_down = f1 < f2?f1:f2;


i_up = f1 > f2?f1:f2;
}

void m_step(int s)
{
i_step = s;
}

int i_count,i_down,i_up,i_step;

private:

static void setup(t_classid c)


{
// --- set up methods (class scope) ---

// register a bang method to the default inlet (0)


FLEXT_CADDBANG(c,0,m_bang);

// set up tagged methods for the default inlet (0)


// the underscore _ after CADDMETHOD indicates that a message tag is used
// no, variable list or anything and all single arguments are recognized
automatically, ...
FLEXT_CADDMETHOD_(c,0,"reset",m_reset);
FLEXT_CADDMETHOD_(c,0,"set",m_set);
// ..., more complex types (combinations of types) have to be specified explicitly
FLEXT_CADDMETHOD_II(c,0,"bound",m_bound); // two int arguments

// set up methods for inlets 1 and 2


// no message tag used
FLEXT_CADDMETHOD(c,1,m_bound); // variable arg type recognized automatically
FLEXT_CADDMETHOD(c,2,m_step); // single int arg also recognized automatically
}

// for every registered method a callback has to be declared


FLEXT_CALLBACK(m_bang)
FLEXT_CALLBACK(m_reset)
FLEXT_CALLBACK_V(m_set)
FLEXT_CALLBACK_II(m_bound)
FLEXT_CALLBACK_I(m_step)
};

// instantiate the class (constructor has a variable argument list)


// let "counter" be an alternative name
// before the colon define the name of the path to the help file
FLEXT_NEW_V("help, adv3 counter",adv3)

3. Using attributes
Another advanced feature of flext-based externals is the incorporation of the Max/Jitter16-like
attribute functionality. Attributes solve the problem of how the state of an object can be
consistently set and queried. A formalism has been introduced with Jitter which has then
consequently been adopted by flext.
Attributes can either be set by an object’s creation arguments (with e.g. @attribute 1) or by
the use of a setter message into the leftmost inlet (like for example [attribute 1( ) and can be
queried by sending a complementary getter message into this same inlet (e.g. [getattribute( ).
The current state of the attribute is then output at the rightmost outlet, which is reserved just
for attribute values. Every attribute-enabled flext external has this additional attribute outlet.
The rather lengthy source code of the example object attr2 shows how attributes can be used
with simple calculational tasks.
It also shows the usage of a setup function (defined with FLEXT_HEADER_S) which initializes
some data at the time when the external is loaded. A setup function is only called once, while
the constructor is called upon the creation of each attr2 object in a patch.

page 20
flext - C++ programming layer for cross-platform development of PD and Max/MSP externals

Figure III-4 – Attributes are an extremely useful feature introduced with Max/Jitter. With flext, attributes can be
used with plain Max/MSP and PD as well – attr2 shows how to do that

/*
flext tutorial - attributes 2

Copyright (c) 2002,2003 Thomas Grill (xovo@gmx.net)


For information on usage and redistribution, and for a DISCLAIMER OF ALL
WARRANTIES, see the file, "license.txt," in this distribution.

-------------------------------------------------------------------------

This is an example of an object doing various float operations.

Methods and attributes are registered at class level (opposed to object level in example
"attr1").
For details, see also example "adv2"

*/

// IMPORTANT: enable attribute processing (specify before inclusion of flext headers!)


// For clarity, this is done here, but you'd better specify it as a compiler definition
// FLEXT_ATTRIBUTES must be 0 or 1,
#define FLEXT_ATTRIBUTES 1

// include flext header


#include <flext.h>

// check for appropriate flext version


#if !defined(FLEXT_VERSION) || (FLEXT_VERSION < 401)
#error You need at least flext version 0.4.1
#endif

#include <math.h>

page 21
flext - C++ programming layer for cross-platform development of PD and Max/MSP externals

class attr2:
public flext_base
{
// compulsory flext header with a class setup function
FLEXT_HEADER_S(attr2,flext_base,setup)

public:
// constructor
attr2();

protected:
void m_trigger(float f);

float arg; // stored argument of operation


float res; // stored result

enum operation { op_set,op_add,op_sub,op_mul,op_div,op_pow } op;

static const t_symbol *sym_set,*sym_add,*sym_sub,*sym_div,*sym_mul,*sym_pow;

private:

static void setup(t_classid);

// callback for method "m_trigger" (with one float argument)


FLEXT_CALLBACK_F(m_trigger)

// define attribute callbacks for variable "arg" ("ATTRVAR" means GET and SET)
FLEXT_ATTRVAR_F(arg)

// define attribute callbacks for variable "res" (GET only)


FLEXT_ATTRGET_F(res)

// methods for getting/setting the operation mode


void opget(const t_symbol *&s) const;
void opset(const t_symbol *&s);

// define attribute callbacks for variable "res" (GET only)


FLEXT_CALLGET_S(opget)
FLEXT_CALLSET_S(opset)
};

// instantiate the class


FLEXT_NEW("attr2",attr2)

// instantiate static variables


const t_symbol
*attr2::sym_set,
*attr2::sym_add,*attr2::sym_sub,
*attr2::sym_div,*attr2::sym_mul,
*attr2::sym_pow;

void attr2::setup(t_classid c)
{
// Upon class creation setup some symbols
// This is done only upon creation of of the first "attr2" object
sym_set = MakeSymbol("=");
sym_add = MakeSymbol("+");
sym_sub = MakeSymbol("-");
sym_mul = MakeSymbol("*");
sym_div = MakeSymbol("/");
sym_pow = MakeSymbol("**");

// setup methods and attributes at class scope

// register method (for floats) "m_trigger" for inlet 0


FLEXT_CADDMETHOD(c,0,m_trigger);

// register attribute "arg" with the variable "arg"


FLEXT_CADDATTR_VAR1(c,"arg",arg);

// register attribute "result" with variable "res"


FLEXT_CADDATTR_GET(c,"result",res);

// register attribute "op" with methods "opget" and "opset"


FLEXT_CADDATTR_VAR(c,"op",opget,opset);
}

page 22
flext - C++ programming layer for cross-platform development of PD and Max/MSP externals

attr2::attr2():
arg(0),res(0), // initialize argument and result
op(op_set) // initialize operation
{
// define inlets
AddInAnything(); // first inlet of type anything (index 0)

// define outlets
AddOutFloat(); // one float outlet (has index 0)
}

// receive an operand, do the math operation and trigger the output


void attr2::m_trigger(float f)
{
switch(op) {
case op_set: res = f; break;
case op_add: res = f+arg; break;
case op_sub: res = f-arg; break;
case op_mul: res = f*arg; break;
case op_div:
if(arg) res = f/arg;
else {
post("%s - argument to division is 0: result set to 0",thisName());
res = 0;
}
break;
case op_pow: res = (float)pow(f,arg); break;
#ifdef FLEXT_DEBUG
default: ERRINTERNAL(); // operation not defined
#endif
}

// output value to outlet


ToOutFloat(0,res); // (0 stands for the outlet index 0)
}

// report the operation mode


void attr2::opget(const t_symbol *&s) const
{
switch(op) {
case op_set: s = sym_set; break;
case op_add: s = sym_add; break;
case op_sub: s = sym_sub; break;
case op_mul: s = sym_mul; break;
case op_div: s = sym_div; break;
case op_pow: s = sym_pow; break;
#ifdef FLEXT_DEBUG
default: ERRINTERNAL(); // operation not defined
#endif
}
}

// set the operation mode


void attr2::opset(const t_symbol *&s)
{
if(s == sym_set)
op = op_set;
else if(s == sym_add)
op = op_add;
else if(s == sym_sub)
op = op_sub;
else if(s == sym_mul)
op = op_mul;
else if(s == sym_div)
op = op_div;
else if(s == sym_pow)
op = op_pow;
else {
post("%s - operation is not defined, set to =",thisName());
op = op_set;
}
}

page 23
flext - C++ programming layer for cross-platform development of PD and Max/MSP externals

4. DSP (signal-based) externals


The main domain of most externals is, of course, some kind of signal processing. Flext fully
supports all variants of it, although it uses a slightly different approach than the PD or
Max/MSP API does.
In a flext-based signal external you simply override the m_signal virtual function. This means
that the m_signal method is trivially implemented in the flext_base class, and has to be
redefined in the (in this case signal1) child class to provide the special DSP functionality of
this class. Here it is the panning of a mono input signal to left and right stereo channels. The
amount of panning is controlled by a value sent into the right-most inlet (handled by the
method setPan).
This example has again been taken from IOhannes Zmölnigs tutorial and has been ported to
flext by Frank Barknecht17.

Figure III-5 – signal1~ illustrates the handling of signals within a flext-based external.
It’s an adaptation of the pan~ object from IOhannes Zmölnigs PD tutorial, written by Frank Barknecht

// signal1~ - a flext tutorial external written by Frank Barknecht


//
// This is a commented port of the pan~ example from the PD-Externals-Howto to
// illustrate the usage of flext. You can get the original code at
// http://iem.kug.ac.at/pd/externals-HOWTO/

#include <flext.h>

#if !defined(FLEXT_VERSION) || (FLEXT_VERSION < 401)


#error You need at least flext version 0.4.1
#endif

// A flext dsp external ("tilde object") inherits from the class flext_dsp
class signal1:
public flext_dsp
{
// Each external that is written in C++ needs to use #defines from flbase.h
//
// The define
// FLEXT_HEADER(NEW_CLASS, PARENT_CLASS)
// should be somewhere in your dsp file.
// A good place is here:

page 24
flext - C++ programming layer for cross-platform development of PD and Max/MSP externals

FLEXT_HEADER(signal1, flext_dsp)

public:
signal1():
f_pan(0) // initialize f_pan
{
// The constructor of your class is responsible for
// setting up inlets and outlets and for registering
// inlet-methods:
// The descriptions of the inlets and outlets are output
// via the Max/MSP assist method (when mousing over them in edit mode).
// PD will hopefully provide such a feature as well soon

AddInSignal("left audio in"); // left audio in


AddInSignal("right audio in"); // right audio in
AddInFloat("panning parameter"); // 1 float in
AddOutSignal("audio out"); // 1 audio out

// Now we need to bind the handler function to our


// panning inlet, which is inlet 2 (counting all inlets
// from 0). We want the function "setPan" to get
// called on incoming float messages:

FLEXT_ADDMETHOD(2,setPan);

// We're done constructing:


post("-- pan~ with flext ---");
} // end of constructor

protected:
// here we declare the virtual DSP function
virtual void m_signal(int n, float *const *in, float *const *out);
private:
float f_pan; // holds our panning factor

// Before we can use "setPan" as a handler, we must register this


// function as a callback to PD or Max. This is done using the
// FLEXT_CALLBACK* macros. There are several of them.
//
// FLEXT_CALLBACK_F is a shortcut, that registers a function
// expecting one float arg (thus ending in "_F"). There are
// other shortcuts that register other types of functions. Look
// into flext.h. No semicolon at the end of line!!!
FLEXT_CALLBACK_F(setPan)

// Now setPan can get declared and defined here.


void setPan(float f)
{
// set our private panning factor "f_pan" to the inlet
// value float "f" in the intervall [0,1]
f_pan = (f<0) ? 0.0f : (f>1) ? 1.0f : f ;

// if you want to debug if this worked, comment out the


// following line:
//post("Set panning to %.2f, maybe clipped from %.2f", f_pan,f);
} // end setPan

}; // end of class declaration for signal1

// Before we can run our signal1-class in PD, the object has to be registered as a
// PD object. Otherwise it would be a simple C++-class, and what good would
// that be for? Registering is made easy with the FLEXT_NEW_* macros defined
// in flext.h. For tilde objects without arguments call:

FLEXT_NEW_DSP("signal1~ pan~", signal1)


// T.Grill: there are two names for the object: signal1~ as main name and pan~ as its alias

// Now we define our DSP function. It gets this arguments:


//
// int n: length of signal vector. Loop over this for your signal processing.
// float *const *in, float *const *out:
// These are arrays of the signals in the objects signal inlets rsp.
// oulets. We come to that later inside the function.

page 25
flext - C++ programming layer for cross-platform development of PD and Max/MSP externals

void signal1::m_signal(int n, float *const *in, float *const *out)


{
const float *ins1 = in[0];
const float *ins2 = in[1];
// As said above "in" holds a list of the signal vectors in all inlets.
// After these two lines, ins1 holds the signal vector ofthe first
// inlet, index 0, and ins2 holds the signal vector of the second
// inlet, with index 1.

float *outs = out[0];


// Now outs holds the signal vector at the one signal outlet we have.

// We are now ready for the main signal loop


while (n--)
{
// The "++" after the pointers outs, ins1 and ins2 walks us
// through the signal vector with each n, of course. Before
// each step we change the signal value in the outlet *outs
// according to our panning factor "f_pan" and according to the
// signals at the two signal inlets, *ins1 and *ins2

*outs++ = (*ins1++) * (1-f_pan) + (*ins2++) * f_pan;


}
} // end m_signal

5. Using sample buffers


Closely related to DSP processing is the usage of sample buffers. These arrays of 32-bit
floating point values are held in the RAM of the computer and are therefore instantly
accessible (as opposed to sound files on a hard disk). Sample buffers are managed by PD or
Max/MSP but flext provides various functions to access or modify them, as can be seen in the
buffer1 example.

Figure III-6 – buffer1 shows how to access, query and modify sample buffers (arrays in PD)

page 26
flext - C++ programming layer for cross-platform development of PD and Max/MSP externals

/*
flext tutorial - buffer 1

Copyright (c) 2003 Thomas Grill (xovo@gmx.net)


For information on usage and redistribution, and for a DISCLAIMER OF ALL
WARRANTIES, see the file, "license.txt," in this distribution.

-------------------------------------------------------------------------

This is an example of a simple object doing some basic buffer operation


*/

// IMPORTANT: enable attribute processing (specify before inclusion of flext headers!)


// For clarity, this is done here, but you'd better specify it as a compiler definition
// FLEXT_ATTRIBUTES must be 0 or 1,
#define FLEXT_ATTRIBUTES 1

// include flext header


#include <flext.h>

// check for appropriate flext version


#if !defined(FLEXT_VERSION) || (FLEXT_VERSION < 400)
#error You need at least flext version 0.4.0
#endif

// define the class that stands for a pd/Max object

class buffer1:
// inherit from basic flext class
public flext_base
{
// obligatory flext header (class name,base class name) featuring a setup function
FLEXT_HEADER_S(buffer1,flext_base,setup)

public:
// constructor with a variable argument list
buffer1(int argc,const t_atom *argv);

protected:
const t_symbol *bufname;
buffer *buf;

// set new buffer (or none if name omitted)


void m_set(int argc,const t_atom *argv);

// get buffer name


void mg_buf(AtomList &lst) const;
// set buffer name (simply reuse m_set method)
inline void ms_buf(const AtomList &lst) { m_set(lst.Count(),lst.Atoms()); }

// get buffer channels


inline void mg_chns(int &chns) { chns = Check()?buf->Channels():0; }

// get buffer length in frames


inline void mg_frames(int &frames) { frames = Check()?buf->Frames():0; }
// set buffer length in frames
inline void ms_frames(int frames) { if(Check()) buf->Frames(frames); }

// get sample (index channel)


void m_peek(int argc,const t_atom *argv);
// set sample (index value channel)
void m_poke(int argc,const t_atom *argv);

// delete eventual existing buffer


void Clear();

// check and eventually update buffer reference (return true if valid)


bool Check();

private:
static void setup(t_classid c);

FLEXT_CALLBACK_V(m_set) // wrapper for method m_set (with variable argument list)


FLEXT_CALLBACK_V(m_peek) // wrapper for method m_peek (with variable argument list)
FLEXT_CALLBACK_V(m_poke) // wrapper for method m_poke (with variable argument list)

FLEXT_CALLVAR_V(mg_buf,ms_buf) // wrappers for attribute getter/setter


mg_buffer/ms_buffer (with variable argument list)

page 27
flext - C++ programming layer for cross-platform development of PD and Max/MSP externals

FLEXT_CALLGET_I(mg_chns) // wrappers for attribute getter mg_chns (with integer


arguments)
FLEXT_CALLVAR_I(mg_frames,ms_frames) // wrappers for attribute getter/setter
mg_frames/ms_frames (with integer arguments)
};

// instantiate the class


FLEXT_NEW_V("buffer1",buffer1)

void buffer1::setup(t_classid c)
{
// register methods and attributes

FLEXT_CADDMETHOD_(c,0,"set",m_set); // register method "set" for inlet 0


FLEXT_CADDMETHOD_(c,0,"peek",m_peek); // register method "peek" for inlet 0
FLEXT_CADDMETHOD_(c,0,"poke",m_poke); // register method "poke" for inlet 0

FLEXT_CADDATTR_VAR(c,"buffer",mg_buf,ms_buf); // register attribute "buffer"


FLEXT_CADDATTR_GET(c,"channels",mg_chns); // register attribute "channels"
FLEXT_CADDATTR_VAR(c,"frames",mg_frames,ms_frames); // register attribute "frames"
}

buffer1::buffer1(int argc,const t_atom *argv):


// clear buffer
buf(NULL),bufname(NULL)
{
// define inlets:
// first inlet must always be of type anything (or signal for dsp objects)
AddInAnything("message inlet"); // add one inlet for any message

// peek outlet
AddOutFloat("peek value outlet");

// set buffer according to creation arguments


m_set(argc,argv);
}

void buffer1::Clear()
{
if(buf) {
delete buf;
buf = NULL; bufname = NULL;
}
}

bool buffer1::Check()
{
if(!buf || !buf->Valid()) {
post("%s (%s) - no valid buffer defined",thisName(),GetString(thisTag()));
// return zero length
return false;
}
else {
if(buf->Update()) {
// buffer parameters have been updated
if(buf->Valid()) {
post("%s (%s) - updated buffer reference",thisName(),GetString(thisTag()));
return true;
}
else {
post("%s (%s) - buffer has become invalid",thisName(),GetString(thisTag()));
return false;
}
}
else
return true;
}
}

void buffer1::m_set(int argc,const t_atom *argv)


{
if(argc == 0) {
// argument list is empty

// clear existing buffer


Clear();
}
else if(argc == 1 && IsSymbol(argv[0])) {

page 28
flext - C++ programming layer for cross-platform development of PD and Max/MSP externals

// one symbol given as argument

// clear existing buffer


Clear();
// save buffer name
bufname = GetSymbol(argv[0]);
// make new reference to system buffer object
buf = new buffer(bufname);

if(!buf->Ok()) {
post("%s (%s) - warning: buffer is currently not
valid!",thisName(),GetString(thisTag()));
}
}
else {
// invalid argument list, leave buffer as is but issue error message to console
post("%s (%s) - message argument must be a symbol (or left
blank)",thisName(),GetString(thisTag()));
}
}

void buffer1::mg_buf(AtomList &lst) const


{
if(buf) {
// buffer exists: return buffer name
lst(1); SetSymbol(lst[0],bufname);
}
else
// no buffer: set empty list
lst(0);
}

void buffer1::m_poke(int argc,const t_atom *argv)


{
// if buffer is invalid bail out
if(!Check()) return;

bool ok = true;
int ix,chn = 0;
float val;

if(argc == 3) {
if(CanbeInt(argv[2]))
// get channel index
chn = GetAInt(argv[2]);
else
ok = false;
}

if(ok && (argc == 2 || argc == 3) && CanbeInt(argv[0]) && CanbeFloat(argv[1])) {


// get frame index
ix = GetAInt(argv[0]);
// get value
val = GetAFloat(argv[1]);
}
else
ok = false;

if(ok) {
// correct syntax, set sample
buf->Data()[ix] = val;
}
else
post("%s (%s) - syntax error - use \"poke index value
[channel]\"",thisName(),GetString(thisTag()));
}

page 29
flext - C++ programming layer for cross-platform development of PD and Max/MSP externals

void buffer1::m_peek(int argc,const t_atom *argv)


{
// if buffer is invalid bail out
if(!Check()) return;

bool ok = true;
int ix,chn = 0;

if(argc == 2) {
if(CanbeInt(argv[1]))
// get channel index
chn = GetAInt(argv[1]);
else
ok = false;
}

if(ok && (argc == 1 || argc == 2) && CanbeInt(argv[0])) {


// get frame index
ix = GetAInt(argv[0]);
}
else
ok = false;

if(ok)
// correct syntax, output value
ToOutFloat(0,buf->Data()[ix]);
else
post("%s (%s) - syntax error - use \"peek index
[channel]\"",thisName(),GetString(thisTag()));
}

6. Using timers
Another resource that is managed by the real-time system itself is the timer functionality.
Flext uses a two-fold approach to timers: First, a Timer class is present in the flext class
which can be derived for special sub-classes. For the other approach, a timer method for the
object can be registered with the FLEXT_ADDTIMER statement. Such a method must have a
special callback wrapper set up with FLEXT_CALLBACK_T. This is shown in the timer1 example,
where two timers tmrA and tmrB are controlled by messages to the object and can be set to
either one-shot or periodic operation.
Additionally, two functions for measuring time are presented which are triggered by
messages.

Figure III-7 – timer1 shows some basic operations on timers provided by the real-time-system itself.

page 30
flext - C++ programming layer for cross-platform development of PD and Max/MSP externals

/*
flext tutorial - timer 1

Copyright (c) 2003 Thomas Grill (xovo@gmx.net)


For information on usage and redistribution, and for a DISCLAIMER OF ALL
WARRANTIES, see the file, "license.txt," in this distribution.

-------------------------------------------------------------------------

This is an example of an object using timers


*/

// enable flext attributes


#define FLEXT_ATTRIBUTES 1

// include flext header


#include <flext.h>

// check for appropriate flext version


#if !defined(FLEXT_VERSION) || (FLEXT_VERSION < 403)
#error You need at least flext version 0.4.3
#endif

// define the class that stands for a pd/Max object

class timer1:
// inherit from basic flext class
public flext_base
{
// obligatory flext header (class name,base class name)
FLEXT_HEADER_S(timer1,flext_base,Setup)

public:
// constructor
timer1();

protected:
// timers
Timer tmrA,tmrB;

void m_getostime(float &f) { f = (float)GetOSTime(); } // method for operating system


time attribute
void m_getrttime(float &f) { f = (float)GetTime(); } // method for real-time system
time attribute

void m_timerA(void *) { ToOutString(0,"Timer A"); } // timer A method


void m_timerB(void *) { ToOutString(0,"Timer B"); } // timer B method

void m_resetA() { tmrA.Reset(); } // timer A reset


void m_resetB() { tmrB.Reset(); } // timer B reset
void m_oneshotA(int del) { tmrA.Delay(del*0.001); } // timer A one shot
void m_oneshotB(int del) { tmrB.Delay(del*0.001); } // timer B one shot
void m_periodicA(int del) { tmrA.Periodic(del*0.001); } // timer A periodic
void m_periodicB(int del) { tmrB.Periodic(del*0.001); } // timer B periodic

private:
static void Setup(t_classid c);

// register timer callbacks


FLEXT_CALLBACK_T(m_timerA)
FLEXT_CALLBACK_T(m_timerB)

// register method callbacks


FLEXT_CALLGET_F(m_getostime)
FLEXT_CALLGET_F(m_getrttime)
FLEXT_CALLBACK(m_resetA)
FLEXT_CALLBACK(m_resetB)
FLEXT_CALLBACK_I(m_oneshotA)
FLEXT_CALLBACK_I(m_oneshotB)
FLEXT_CALLBACK_I(m_periodicA)
FLEXT_CALLBACK_I(m_periodicB)
};

// instantiate the class


FLEXT_NEW("timer1",timer1)

page 31
flext - C++ programming layer for cross-platform development of PD and Max/MSP externals

// class setup function


void timer1::Setup(t_classid c)
{
FLEXT_CADDATTR_GET(c,"ostime",m_getostime); // register attribute for OS time
FLEXT_CADDATTR_GET(c,"time",m_getrttime); // register attribute for RT time

FLEXT_CADDMETHOD_(c,0,"resetA",m_resetA); // register reset method for timer A


FLEXT_CADDMETHOD_(c,0,"resetB",m_resetB); // register reset method for timer B
FLEXT_CADDMETHOD_(c,0,"oneshotA",m_oneshotA); // register one shot method for timer A
FLEXT_CADDMETHOD_(c,0,"oneshotB",m_oneshotB); // register one shot method for timer B
FLEXT_CADDMETHOD_(c,0,"periodicA",m_periodicA); // register periodic method for timer A
FLEXT_CADDMETHOD_(c,0,"periodicB",m_periodicB); // register periodic method for timer B
}

// class constructor
timer1::timer1():
tmrA(false),tmrB(false)
{
AddInAnything("Control timers"); // add inlet for control commands
AddOutAnything("Timer output"); // add outlet for timer output

// register methods
FLEXT_ADDTIMER(tmrA,m_timerA); // register method "m_timerA" for timer A
FLEXT_ADDTIMER(tmrB,m_timerB); // register method "m_timerB" for timer B
}

7. Binding to symbols
As stated above symbols are character strings that are cached by the real-time system for rapid
reuse. Once a symbol is used it will stay in the system until shutdown. This has pros and cons.
A problem is that one should be cautious with the usage of symbols. If too many (like a few
thousands automatically generated) different symbol strings are used, the system is likely to
slow down noticeably. The big advantage is on the other hand that information can be
attached (or bound) to a symbol and won’t be lost, since the symbol will never disappear. This
is for example used with the [send] and [receive] objects delivered with PD and Max/MSP.
The receiving part is bound to the symbol and gets a notification whenever the sender passes a
message to the symbol.
The binding functionality is more cultivated in PD than in Max/MSP but the flext
implementation tries to hide this Max weakness.
There are two possibilities to use binding within a flext-based external. First, the whole object
can be bound to a symbol (with the flext::Bind function) which means that sending
messages to the symbol (via the [send] object in PD or the [forward] object in Max/MSP)
will be the same as sending those messages directly into the object’s leftmost inlet. The other
way is (using FLEXT_BINDMETHOD) to bind a single class method to the symbol which is then
called.
Both approaches are depicted in the bind1 example object.
Another function used therein is flext::forward. It mimics a [send] or [forward] object and
passes a message to a symbol.

page 32
flext - C++ programming layer for cross-platform development of PD and Max/MSP externals

Figure III-8 – Binding objects or methods to symbols is an advanced form of communication of an external with
other elements of the real-time system. bind1 demonstrates how this is done.

/*
flext tutorial - bind 1

Copyright (c) 2003 Thomas Grill (xovo@gmx.net)


For information on usage and redistribution, and for a DISCLAIMER OF ALL
WARRANTIES, see the file, "license.txt," in this distribution.

-------------------------------------------------------------------------

This is an example of a simple object demonstrating method to symbol binding and message
forwarding
*/

// include flext header


#include <flext.h>

// check for appropriate flext version


#if !defined(FLEXT_VERSION) || (FLEXT_VERSION < 400)
#error You need at least flext version 0.4.0
#endif

// define the class that stands for a pd/Max object

class bind1:
// inherit from basic flext class
public flext_base
{
// obligatory flext header (class name,base class name) featuring a setup function
FLEXT_HEADER_S(bind1,flext_base,setup)

public:
// constructor with no arguments
bind1()
{

page 33
flext - C++ programming layer for cross-platform development of PD and Max/MSP externals

// define inlets:
// first inlet must always be of type anything (or signal for dsp objects)
AddInAnything("message inlet"); // add one inlet for any message
AddInAnything("forwarding inlet"); // add one inlet for any message

AddOutAnything("bound message"); // output received bound message


}

/*
no destructor necessary here:
flext frees all eventually remaining bound symbols when the object is destroyed
(but NOT the data that can be passed via the FLEXT_BINDMETHOD call!)
*/

protected:
const t_symbol *bufname;
buffer *buf;

// bind object
void m_bind(const t_symbol *s)
{
if(!Bind(s)) {
post("%s (%s) - Binding failed",thisName(),GetString(thisTag()));
}
}

// unbind object
void m_unbind(const t_symbol *s)
{
if(!Unbind(s)) {
post("%s (%s) - Binding failed",thisName(),GetString(thisTag()));
}
}

// bind method
void m_bindmethod(const t_symbol *s)
{
if(!FLEXT_BINDMETHOD(s,m_bound,NULL)) {
post("%s (%s) - Binding failed",thisName(),GetString(thisTag()));
}
}

// unbind method
void m_unbindmethod(const t_symbol *s)
{
if(!FLEXT_UNBINDMETHOD(s)) {
post("%s (%s) - Binding failed",thisName(),GetString(thisTag()));
}
}

// forward message
void m_forward(const t_symbol *s,int argc,const t_atom *argv)
{
Forward(s,argc,argv);
}

// method for symbol-bound messages


void m_bound(const t_symbol *sym,int argc,const t_atom *argv,void *data)
{
ToOutAnything(0,sym,argc,argv);
}

// method for binding test


void m_test(float value)
{
post("%s - TEST METHOD: value %f",thisName(),value);
}

private:
static void setup(t_classid c)
{
// register methods

FLEXT_CADDMETHOD_(c,0,"bind",m_bind); // register method "bind" for inlet 0


FLEXT_CADDMETHOD_(c,0,"unbind",m_unbind); // register method "unbind" for inlet 0
FLEXT_CADDMETHOD_(c,0,"bindmethod",m_bindmethod); // register method "bindmethod"
for inlet 0

page 34
flext - C++ programming layer for cross-platform development of PD and Max/MSP externals

FLEXT_CADDMETHOD_(c,0,"unbindmethod",m_unbindmethod); // register method


"unbindmethod" for inlet 0

FLEXT_CADDMETHOD_(c,0,"test",m_test); // register method m_test for inlet 0


FLEXT_CADDMETHOD(c,1,m_forward); // register method m_forward for inlet 1
}

FLEXT_CALLBACK_S(m_bind) // wrapper for method m_bind (with symbol argument)


FLEXT_CALLBACK_S(m_unbind) // wrapper for method m_unbind (with symbol argument)
FLEXT_CALLBACK_S(m_bindmethod) // wrapper for method m_bindmethod (with symbol
argument)
FLEXT_CALLBACK_S(m_unbindmethod) // wrapper for method m_unbindmethod (with symbol
argument)

FLEXT_CALLBACK_A(m_forward) // wrapper for method m_forward (with anything argument)

FLEXT_CALLBACK_AX(m_bound) // wrapper for method m_bound (anything+data arguments)


FLEXT_CALLBACK_F(m_test) // wrapper for method m_test (one float argument)
};

// instantiate the class


FLEXT_NEW("bind1",bind1)

8. Building libraries of externals


Libraries of external objects are usable with PD by default. Several packages (like GEMk or
zexyl) use the fact that it is handy to have all externals of a kind bundled together in one file.
PD can load all these externals at once by using the –lib command line parameter. Max/MSP
originally has no such feature but flext provides it nevertheless. Here, you would either have
to place the library in the max-startup folder or provide a object mappings file which has been
introduced with Max/MSP for OSX.

Figure III-9 – Instead of just one object per external module libraries allow the bundling of multiple objects in
one file, which simplifies inheritance of features and sharing of code and data.

k
GEM – Graphics Environment for Multimedia - http://gem.iem.at/
l
zexy - http://iem.at/pd/

page 35
flext - C++ programming layer for cross-platform development of PD and Max/MSP externals

/*
flext tutorial - library 1

Copyright (c) 2002,2003 Thomas Grill (xovo@gmx.net)


For information on usage and redistribution, and for a DISCLAIMER OF ALL
WARRANTIES, see the file, "license.txt," in this distribution.

-------------------------------------------------------------------------

This is an example of an external library containing a few simple objects.


It uses attributes, so be sure that you've already worked through attr1 and attr2
*/

// Enable attribute processing


// For clarity, this is done here, but you'd better specify it as a compiler definition
#define FLEXT_ATTRIBUTES 1

// include flext header


#include <flext.h>

// check for appropriate flext version


#if !defined(FLEXT_VERSION) || (FLEXT_VERSION < 400)
#error You need at least flext version 0.4.0
#endif

// -------------------------------------------------------------------------------------
// Define the base class
// Note that you don't have to instantiate the base class (with FLEXT_NEW or variants)

class libbase:
// inherit from basic flext class
public flext_base
{
// obligatory flext header (class name,base class name)
FLEXT_HEADER(libbase,flext_base)

public:
// constructor
libbase();

protected:
void Output(float f) const { ToOutFloat(0,f); }

// method for floats into left inlet


virtual void m_trigger(float f) = 0;

float arg; // argument variable


private:
FLEXT_CALLBACK_F(m_trigger) // callback for method "m_trigger" (with one float
argument)
FLEXT_ATTRVAR_F(arg)
};

libbase::libbase():
arg(0) // initialize argument
{
// define inlets:
// first inlet must always by of type anything (or signal for dsp objects)
AddInAnything(); // add one inlet for any message

// define outlets:
AddOutFloat(); // add one float outlet (has index 0)

// register methods
FLEXT_ADDMETHOD(0,m_trigger); // register method (for float messages) "m_float" for
inlet 0

// register attributes
FLEXT_ADDATTR_VAR1("arg",arg); // register attribute "arg"
}

// ------------------------------------------------------------------
// Define the actual library objects (derived from the base class)
// These classes have an implementation of the virtual function m_trigger

page 36
flext - C++ programming layer for cross-platform development of PD and Max/MSP externals

class libadd:
public libbase
{
// obligatory flext header, inherit from libbase
FLEXT_HEADER(libadd,libbase)
public:
virtual void m_trigger(float f) { Output(f+arg); }
};

FLEXT_LIB("lib1.+",libadd);

class libsub:
public libbase
{
// obligatory flext header, inherit from libbase
FLEXT_HEADER(libsub,libbase)
public:
virtual void m_trigger(float f) { Output(f-arg); }
};

FLEXT_LIB("lib1.-",libsub);

class libmul:
public libbase
{
// obligatory flext header, inherit from libbase
FLEXT_HEADER(libmul,libbase)
public:
virtual void m_trigger(float f) { Output(f*arg); }
};

FLEXT_LIB("lib1.*",libmul);

// ------------------------------------------------
// Do the library setup

static void lib_setup()


{
post("flext tutorial lib1, (C)2002 Thomas Grill");
post("lib1: lib1.+ lib1.- lib1.*");
post("");

// call the objects' setup routines


FLEXT_SETUP(libadd);
FLEXT_SETUP(libsub);
FLEXT_SETUP(libmul);
}

// setup the library


FLEXT_LIB_SETUP(lib1,lib_setup)

9. Using threads
Normally, real-time systems have one thread of execution, which means that no two parts of
the system or of an object can run concurrently. Multi-threading on the other hand allows the
concurrent execution of functions. This can be very handy when a function triggered by a
message runs for a longer time and would therefore block the real-time system, causing audio
drop-outs. With a FLEXT_THREAD definition for the callback wrapper a method is designated to
run as a detached thread whenever it is called. No matter how long the function takes, the
message handler immediately returns, letting the function run in the background until it
finishes operation. Multi-threading is tricky, though. Since more then one piece of code can
access object data at the same time, causing inconsistencies, the data has to be protected. This
can be done by a thread mutex which is represented by the flext::ThrMutex class.
Additionally, there is the flext::ThrCond class used to broadcast signals to other threads.
Using threads requires maximum caution, as otherwise timing problems will occur. Therefore,
it is still considered an experimental flext feature.

page 37
flext - C++ programming layer for cross-platform development of PD and Max/MSP externals

Figure III-10 – Multi-threading is another advanced flext feature. It enables an object to run in the background
for a longer time, therefore not blocking the real-time system.

/*
flext tutorial - threads 2

Copyright (c) 2002,2003 Thomas Grill (xovo@gmx.net)


For information on usage and redistribution, and for a DISCLAIMER OF ALL
WARRANTIES, see the file, "license.txt," in this distribution.

-------------------------------------------------------------------------

This shows an example of multiple threads and syncing with a thread conditional
*/

/* define FLEXT_THREADS for thread usage. Flext must also have been compiled with that
defined!
it's even better to define that as a compiler flag (-D FLEXT_THREADS) for all files of
the flext external
*/
#ifndef FLEXT_THREADS
#define FLEXT_THREADS
#endif

#include <flext.h>

#if !defined(FLEXT_VERSION) || (FLEXT_VERSION < 400)


#error You need at least flext version 0.4.0
#endif

class thread2:
public flext_base
{
FLEXT_HEADER(thread2,flext_base)

public:
thread2(int del);

protected:
void m_start(int st);
void m_stop();
void m_text();

void m_textout();

page 38
flext - C++ programming layer for cross-platform development of PD and Max/MSP externals

private:
FLEXT_THREAD_I(m_start) // define threaded callback for method m_start
FLEXT_CALLBACK(m_stop) // normal callback for m_stop
FLEXT_CALLBACK(m_text) // turn on console output

FLEXT_THREAD(m_textout) // text output

float delay;
volatile int count;

// caution: CodeWarrior seems to ignore volatile modifier!!


volatile bool stopit,running,blipping; // flags for running and stopping

// thread conditional for stop signal


ThrCond cond;
};

FLEXT_NEW_1("thread2",thread2,int)

thread2::thread2(int del):
delay(del/1000.f),
stopit(false),
running(false),blipping(false)
{
AddInAnything();
AddOutInt(2);

FLEXT_ADDMETHOD(0,m_start); // register start for integer numbers (floats in PD)


FLEXT_ADDMETHOD_(0,"text",m_text); // register m_text method for "text" tag
FLEXT_ADDMETHOD_(0,"stop",m_stop); // register m_text method for "stop" tag
}

void thread2::m_start(int st)


{
// if already running, just set back the counter
if(running) { count = st; return; }

running = true;

// loop until either the system exit flag or the "stopit" flag is set
for(count = st; !ShouldExit() && !stopit; ++count)
{
Sleep(delay);
ToOutInt(0,count); // output loop count
}

running = false; // change state flag


cond.Signal(); // signal changed flag to waiting "stop" method
}

void thread2::m_stop()
{
stopit = true; // set termination flag

while(*(&running) || *(&blipping)) // workaround for CodeWarrior (doesn't honor volatile


modifier!)
{
cond.Wait(); // wait for signal by running threads
}

// --- Here, the threads should have stopped ---

stopit = false; // reset flag


}

void thread2::m_text()
{
FLEXT_CALLMETHOD(m_textout);
}

void thread2::m_textout()
{
if(blipping) return;
blipping = true;

page 39
flext - C++ programming layer for cross-platform development of PD and Max/MSP externals

while(!ShouldExit() && !stopit) {


post("%i",count);
Sleep(1.f);
}

blipping = false; // change state flag


cond.Signal(); // signal changed flag to waiting "stop" method
}

10. Interfacing to other DSP frameworks


Besides the patcher-based DSP systems there are other ones that just consist of programming
interfaces but have no graphical representation. Externals can help here by providing an
appropriate glue layer between the patcher-based real-time system and these frameworks –
consequently, those DSP routines can be used inside PD or Max/MSP just as any other
objects. For that, flext has built-in support classes for the two major C++ DSP frameworks.

a) STK18
The Synthesis ToolKit (STK) is a set of open source audio signal processing and algorithmic
synthesis classes written in C++. It has been wisely designed to be platform-independent and
it’s free as well, so it is therefore perfectly fitted for interfacing with flext. There is a large
number of classes from simple delay and filter stuff to complex instruments based on physical
modelling.
Externals using STK objects can use the flext_stk base class providing the appropriate C++
interface. Three virtual functions have to be overridden for that: NewObjs, FreeObjs and
ProcessObjs, doing obvious things as can be seen in the stk2 example.

Figure III-11 – STK (the Synthesis Toolkit) is a powerful set of unit generators.
Flext provides an interface to access this functionality.

page 40
flext - C++ programming layer for cross-platform development of PD and Max/MSP externals

/*
flext tutorial - stk 2

Copyright (c) 2002,2003 Thomas Grill (xovo@gmx.net)


For information on usage and redistribution, and for a DISCLAIMER OF ALL
WARRANTIES, see the file, "license.txt," in this distribution.

-------------------------------------------------------------------------

This is an example of an external using the STK ("synthesis toolkit") library.


For STK see http://ccrma-www.stanford.edu/software/stk

STK needs C++ exceptions switched on.

The STK tutorial examples assume that a static stk library exists which contains all the
source files (except rt*.cpp) of the stk/src directory.
The library should be compiled multithreaded and with the appropriate compiler flags for
the respective platform (e.g. __OS_WINDOWS__ and __LITTLE_ENDIAN__ for Windows)

*/

#include <flstk.h>

#if !defined(FLEXT_VERSION) || (FLEXT_VERSION < 401)


#error You need at least flext version 0.4.1
#endif

#include "PitShift.h"

class stk2:
public flext_stk
{
FLEXT_HEADER_S(stk2,flext_stk,Setup)

public:
stk2();

void m_sh1(float f) { if(inst[0]) inst[0]->setShift(f); }


void m_sh2(float f) { if(inst[1]) inst[1]->setShift(f); }

// these are obligatory!


virtual bool NewObjs(); // create STK instruments
virtual void FreeObjs(); // destroy STK instruments
virtual void ProcessObjs(int n); // do DSP processing

PitShift *inst[2];
MY_FLOAT *vec;

private:
static void Setup(t_class *c);

FLEXT_CALLBACK_F(m_sh1)
FLEXT_CALLBACK_F(m_sh2)
};

FLEXT_NEW_DSP("stk2~",stk2)

stk2::stk2()
{
AddInSignal();
AddOutSignal(2);

inst[0] = inst[1] = NULL;


}

void stk2::Setup(t_class *c)


{
FLEXT_CADDMETHOD_F(c,0,"shL",m_sh1);
FLEXT_CADDMETHOD_F(c,0,"shR",m_sh2);
}

page 41
flext - C++ programming layer for cross-platform development of PD and Max/MSP externals

// create STK instruments


bool stk2::NewObjs()
{
bool ok = true;

try {
// set up objects
for(int i = 0; i < 2; ++i)
inst[i] = new PitShift;

// reserve one signal vector too


vec = new MY_FLOAT[Blocksize()];
}
catch (StkError &) {
post("%s - Creation failed!",thisName());
ok = false;
}
return ok;
}

// destroy the STK instruments


void stk2::FreeObjs()
{
for(int i = 0; i < 2; ++i)
if(inst[i]) delete inst[i];
if(vec) delete[] vec;
}

// this is called on every DSP block


void stk2::ProcessObjs(int n)
{
for(int i = 0; i < 2; ++i)
Outlet(i).tick(
inst[i]->tick(
Inlet(0).tick(vec,n)
,n)
,n);
}

page 42
flext - C++ programming layer for cross-platform development of PD and Max/MSP externals

b) SndObj19

From its general structure and existing objects the Sound Object Library is very similar to
STK, although it uses a slightly different way to do the DSP processing. Therefore it has been
easy to find an example that does exactly the same as the above STK object.
The base class flext_sndobj uses again the virtual functions NewObjs, FreeObjs and
ProcessObjs which have to be overridden in a derived class.

Figure III-12 – Like STK, SndObj provide a number of useful transformation objects
which can be accessed by using a special flext C++ base class.

/*
flext tutorial - sndobj 1

Copyright (c) 2002,2003 Thomas Grill (xovo@gmx.net)


For information on usage and redistribution, and for a DISCLAIMER OF ALL
WARRANTIES, see the file, "license.txt," in this distribution.

-------------------------------------------------------------------------

This is an example of an external using the SndObj library.


See http://www.may.ie/academic/music/musictec/SndObj/

The SndObj library should be compiled multithreaded.

This external features simple stereo pitch shifting.


*/

#define FLEXT_ATTRIBUTES 1

#include <flsndobj.h>

page 43
flext - C++ programming layer for cross-platform development of PD and Max/MSP externals

#if !defined(FLEXT_VERSION) || (FLEXT_VERSION < 401)


#error You need at least flext version 0.4.1
#endif

class sndobj1:
public flext_sndobj
{
FLEXT_HEADER_S(sndobj1,flext_sndobj,Setup)

public:
sndobj1();

// these are obligatory!


virtual bool NewObjs();
virtual void FreeObjs();
virtual void ProcessObjs();

// space for a few sndobjs


Pitch *obj1,*obj2;

float sh1,sh2;

private:
static void Setup(t_class *c);

FLEXT_ATTRVAR_F(sh1)
FLEXT_ATTRVAR_F(sh2)
};

FLEXT_NEW_DSP("sndobj1~",sndobj1)

sndobj1::sndobj1():
sh1(1),sh2(1),
obj1(NULL),obj2(NULL)
{
AddInSignal(2); // audio ins
AddOutSignal(2); // audio outs
}

void sndobj1::Setup(t_class *c)


{
FLEXT_CADDATTR_VAR1(c,"shL",sh1);
FLEXT_CADDATTR_VAR1(c,"shR",sh2);
}

// construct needed SndObjs


bool sndobj1::NewObjs()
{
// set up objects
obj1 = new Pitch(.1f,&InObj(0),sh1,Blocksize(),Samplerate());
obj2 = new Pitch(.1f,&InObj(1),sh2,Blocksize(),Samplerate());
return true;
}

// destroy the SndObjs


void sndobj1::FreeObjs()
{
if(obj1) delete obj1;
if(obj2) delete obj2;
}

// this is called on every DSP block


void sndobj1::ProcessObjs()
{
// set current pitch shift
obj1->SetPitch(sh1);
obj2->SetPitch(sh2);

// do processing here!!
obj1->DoProcess();
obj2->DoProcess();

// output
*obj1 >> OutObj(0);
*obj2 >> OutObj(1);
}

page 44
flext - C++ programming layer for cross-platform development of PD and Max/MSP externals

IV. Applications
Naturally, flext doesn’t stand for itself but has been created for purposes of making
developing externals easier, faster and less error-prone. It can be claimed that a large library
such as VASP would not have been ready for use in a comparable time without flext.
Although a prerequisite, flext has been developed in parallel to these external libraries,
influencing one another. Thus, by the time, flext has become more stable and feature-rich.

1. xsamplem
This was the first flext-based external library, now comprising three objects: xgroove~, xplay~
and xrecord~. The development was motivated by the fact that the sample objects built into
PD were not very comfortable, while the ones delivered with Max/MSP exhibited some bugs
that made actual usage difficult. Since then, the xsample library has emancipated and features
efficiency and functionality (like several interpolation, looping and unit modes, signal-
triggered recording, mix-in capability and a cross-fading loop zone) that is unparalleled by
other comparable externals.

2. VASP modularn
As described in more detail on the VASP website, this is a framework that complements the
hosting real-time system by supplying functions to process array-based data rather than
streaming signals. As there is hardly any such functionality delivered with standard PD or
Max/MSP (although the optional Jitter framework does similar things) VASP has to provide
numerous basic and more advanced functions, realized as individual external objects
combined in one library. The emphasis of the system lies on granular and spectral
transformations that are not limited to the usual constraints of signal block size or real-time-
capability. VASP for PD is well-documented and more examples and tutorials will follow.

3. py/pyexto
One of the major deficiencies of patcher-centered visual programming techniques is the lack
of a general structural script language. Certain things (like more complicated loop constructs
or access to computer or network resources) are notoriously difficult to solve with vanilla PD
or Max/MSP. This is where py/pyext has its strengths. It’s an external that opens up the power
of the Python20 script language to the real-time world. The external can load and execute a
Python script, while providing an interface for it resembling any other normal native C or
C++-based external object. As Python has a huge community of users, libraries and
documentation this is just another universe to discover. As a script language that doesn’t need
to be compiled, Python serves extremely well for rapid prototyping of externals or general
experimentation. Future version of Python will be capable of steering signal processing as
well, then providing much of the functionality of Supercollider or Aura. As the Python
interpreter is not cleanly real-time-capable by itself, the external makes use of flext multi-

m
xsample - extended sampling objects - http://www.parasitaere-kapazitaeten.net/ext/xsample
n
VASP modular – vector assembling signal processor - http://www.parasitaere-kapazitaeten.net/vasp
o
py/pyext – Python script externals - http://www.parasitaere-kapazitaeten.net/ext/py

page 45
flext - C++ programming layer for cross-platform development of PD and Max/MSP externals

threading techniques to let the code run in the background, therefore avoiding influences to
the real-time-system’s own flow of operation.

4. othersp
Several other externals and libraries thereof have been developed by me and others. I am
extremely thankful to the contributions that other developers made to the flext idea and i’m
happy to fix bugs as they become apparent or include new useful features to the library.

p
various externals made by Thomas Grill – http://www.parasitaere-kapazitaeten.net/ext

page 46
flext - C++ programming layer for cross-platform development of PD and Max/MSP externals

Biography21
Thomas Grill, born 1972
1990+ study of technical physics at the University of Linz/Austria
1991+ self-education at the drum set, main interest in improvised and experimental music
1993+ concerts and performances with various ensembles at various places
1995+ intense engagement in electronic music, programming of audio software
2000+ study at the Institute for Composition and Electro-Acoustics at the University of
Music in Vienna/Austria
2000+ living and working in Vienna, cooking for Maggie.

Concerts and musical activities in the years 2000-2003:

07.12.2000 Galerie Maerz/Linz - Festival Elektrokomplex:


“Masterfoods” (pickup microphone and sweets), Geräuschorchester (drums)
15.03.2001 Alte Schmiede/Wien – Geräuschorchester (drums)
18.05.2001 Ruprechtskirche/Wien – „Misterios“ of Angélica Castelló and Albert Moser (sound engineering)
21.06.2001 Musikuniversität/Wien – Klassenabend ELAK „Musik im Raum“
Premiere of „Odem“ (Video/Sound/Performance) together with Johann Neumeister
„Trio“ of Robert Kellner (drums)
12.10.2001 Künstlerhauspassage/Wien – Festival „inpotenza“:
Geräuschorchester (drums)
“Gnostische Behelligung I“ - Public performance together with Johann Neumeister
„drei plus eins“ – Castelló*2/Kellner/Grill (electronic drums)
CD recording „Trio“ with Robert Kellner and Angélica Castelló
05.06.2001 Stift St.Lambrecht – Geräuschorchester (drums)
Zuckerfabrik – Musical concept for the exhibition „Stairway to Heaven“ of Evelyn Grill
Universität Wien/Aula – Geräuschorchester (Clarinet in B)
05.03.2002 Hörgänge Konzerthaus/Wien – „Prolog: Fremd I Vertraut“ (CD recording, electronics)
17.05.2002 VHS Stöbergasse/Wien – Sound engineering for the concert evening „XN-Nachtfalter“ of Angélica
Castelló/Katharina Klement/Johannes Kretz
ELAK – CD recording with Angélica Castelló
14.05.2002 Musikuniversität Wien – X-String-Quartet (live electronics)
21.06.2002 Tanzhalle 1030 – Cooperation with Tanz*Hotel, Live electronics with Akemi Takeya
25.07.2002 Sarvar – Live electronics for Igor Lintz Maués “Kadenz”
Sound effects for the movie “All about Eve” by Martin Arnold
01.10.2002 Brucknerkonservatorium Linz – Adaptation of John Zorns “Cobra” game piece by Hannes Löschel, member
of the UNO-Ensemble (sampling, live electronics)
21.10.2002 Ruprechtskirche/Wien – Vocals for “full” of Thorunn Björnsdottir
22.10.2002 ELAK - CD recording and production with Angélica Castelló
09.11.2002 Wels/Austria – Festival “music unlimited” – Member of the UNO-Ensemble directed by Hannes Löschel
30.11.2002 Galerie 5020/Salzburg:
Member of the X-String-Quartet (live electronics), Live sound installation “stabil/labil”
30.01.2003 Musikuniversität/Wien – Klassenabend ELAK: Live sound installation “stabil/labil”
07.02.2003 Posthof/Linz – Composition and musical director of „3-Torus“ by Monika Huemer with the X-String-
Quartet
03.03.2003 MICA/Echoraum/WUK - Festival “inpotenza”: 3 times Pollack/Bruckner/Schellander/Grill (drums)
07.03.2003 Echoraum/Wien – improvising Castelló/Heginger/Grill (sampling)
13.04.2003 Tanzhalle 1020/Wien – Music for the Tanz*Hotel dance performance “Quadrat*Quadrat” together with
Florian Bogner and Gilbert Handler (11 evenings)
24.04.2003 Tanzhalle 1020/Wien – Pollack/Schellander/Grill (electronics)
10.05.2003 Lange Nacht der Musik/Wien - Pollack/Bruckner/Schellander/Grill (electronics)
22.05.2003 Gymnasium Hegelgasse/Wien – Music for the adaptation of Ravels „L’enfant et les sortileges” by Marius
Schebella (7 performances)
24.05.2003 Studio Amann/Wien – Studio concert with Angélica Castelló and Susanna Borsch (electronics)
28.05.2003 fluc/Wien - Pollack/Bruckner/Schellander/Grill (drums)
31.05.2003 Porgy&Bess/Wien – Member of the UNO-Ensemble directed by Hannes Löschel
14.06.2003 Halle 1030 Hyegasse/Wien – A tribute to Dieter Feichtner (remix)
21.06.2003 Musikuniversität/Wien – Klassenabend ELAK: „ride“ (CD piece)
24.06.2003 Grabenfesttage/Wien – „fruitmarket gallery“ (Unterpertinger/Zach/Sperlich/Grill) playing „tettigonia
viridissima”

page 47
flext - C++ programming layer for cross-platform development of PD and Max/MSP externals

References
1
flext - http://www.parasitaere-kapazitaeten.net/ext/flext
2
Csound - e.g. http://www.csounds.com
3
CDP - http://www.bath.ac.uk/~masjpf/CDP/CDP.htm
4
fftbox/NMS4 (Günther Rabl) - http://www.canto-crudo.com
5
SuperCollider (James McCartney) - http://www.audiosynth.com
6
Miller Puckette - http://crca.ucsd.edu/~msp
7
PD (Miller Puckette) - http://sf.net/projects/pure-data
8
Max/MSP (David Zicarelli) - http://www.cycling74.com
9
jMax (IRCAM) - http://www.ircam.fr/produits/logiciels/jmax-e.html
10
Reaktor (Native Instruments) - http://www.nativeinstruments.de/index.php?reaktor_us
11
Aura (Roger Dannenberg) - http://www-2.cs.cmu.edu/~music/aura
12
Gstreamer - http://www.gstreamer.net
13
“Max external tutorial” by Ichiro Fujinaga -
http://gigue.peabody.jhu.edu/~ich/classes/dmp/Max.External.Tutorial.2.pdf
14
“Howto write an external for puredata” by IOhannes Zmölnig -
http://iem.kug.ac.at/pd/externals-HOWTO
15
flext tutorial and reference – downloadable at
http://www.parasitaere-kapazitaeten.net/ext/flext
16
Max/Jitter - http://www.cycling74.com/products/jitter.html
17
Frank Barknecht – http://www.footils.org
18
STK (Perry R. Cook, Gary P. Scavone) - http://ccrma-www.stanford.edu/software/stk
19
SndObjs (Victor Lazzarini) - http://www.may.ie/academic/music/musictec/SndObj
20
Python – http://www.python.org
21
Thomas Grill – http://www.parasitaere-kapazitaeten.net/~thomas

page 48

Das könnte Ihnen auch gefallen