CLAM RELEASE 0.7.0
USER AND DEVELOPMENT DOCUMENTATION
April 2004
IUA-UPF
Music Technology Group

Source: MTG
Title: CLAM RELEASE 0.7.0 USER AND DEVELOPMENT DOCUMENTATION
Revision: 3
Current Developers: Xavier Amatriain
Pau Arumí
Maarten de Boer
David García
Miquel Ramírez
Past Developers: Xavier Rubio
Enrique Robledo
Contact: clam@iua.upf.es

I Introduction

1 Disclaimer

This document is offered 'as is'. There may still be formatting mistakes or non-coherent sections or comments. Please report any such elements to the editor of the document.

2 License of this document

Copyright (c) Music Technology Group (MTG), Universitat Pompeu Fabra (UPF).

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.1 or any later version published by the Free Software Foundation; with the Invariant sections being this 'Introduction', with the Front-Cover Texts being the one herein included, and with no Back-Cover Texts. A copy of the license is available at http://www.fsf.org/licenses/fdl.txt.

3 What is CLAM?

CLAM is a Free Software framework licensed under GNU-GPL that allows to fully develop multiplatform audio applications in C++ using advanced processing algorithms. It is not limited to the processing part of your application; it can help you providing multiplatform solutions for most problems that an audio application should face:

CLAM is able to do complex audio processing involving:

And last but not least, it comprises a big repository of already done algorithms concerning areas such as:

4 What does 'CLAM' mean?

CLAM stands for C++ Library for Audio and Music and in Catalan means something like 'a continuous sound produced by a large number of people as to show approval or disapproval of a given event'. It is the best name we could find after long discussions and it is certainly much better than its original name (MTG-Classes).

5 Historical background

CLAM was formerly developed as an internal project on the Music Technology Group at UPF named MTG-Classes. The aim of the project was to create a foundation of C++ classes to be used by all the research projects at the MTG. Literally (from the first written draft) the goal was:

'To offer a complete, flexible and platform independent Sound Analysis/Synthesis C++ platform to meet current and future needs of all MTG projects.'

The three main axes of these goals were defined as:

These initial objectives have slightly changed since then mainly to accommodate to the fact that the library is no longer seen as an internal tool for the MTG but as a library that is made public under the GNU-GPL in the course of the Agnula IST European Project.

6 Supported platforms

CLAM code is standard ISO/ANSI C++. It uses multiplatform libraries to abstract platform dependant issues. Non portable code and even library dependant code is very localized and isolated. This makes it easier to port CLAM to whatever platform.

Currently, the following platforms are supported:

Linux gcc 2.95 Fully supported
gcc 3.X Fully supported
Windows VisualC++ 6 (SP5) Supported until release 0.6.1, not currently supported any longer
VisualC++ 7.1 Fully Suported
MacOSX gcc 3.X Fully Supported

Reports on CLAM ports to any other platform will be appreciated.

7 Recommended previous skills

Althought CLAM goes toward a visual environment, currently, this "visual builder" (quoting R.E. Johnson) is in beta stage and CLAM functionalities are only accessible by doing your own programs. Thus, a good level in object oriented C++ programming experience is needed, although we have tried our best to keep interfaces as simple as possible.

Of course, CLAM is a framework for audio and music processing so some knowledge in those areas (as well as some DSP basis) is also recommended.

8 Basic principles

The CLAM framework is built on top of some architectural basic elements that are used as building blocks and should therefore be mastered. Most of this document is about them but, just to have a first impression, these are the basic principles used in CLAM:

8.1 Processing architecture

A CLAM based system can be viewed as a set of Processing objects deployed as an interconnected network. Each Processing can retrieve ProcessingData tokens and modify them acording to some algorithm.

Programmers can keep control over the ProcessingData flow between Processing or they can delegate this task to one of the many automated FlowControl schedulers.

A set of Processings can be arranged to form a new processing. Thus you can use that new processing to abstract what the full bunch of Processings does and then scale up to a more complex system. Processings can be arranged on compile-time (ProcessingComposites), or dinamically on run-time (Networks).

Figure 1: CLAM Network

Networks allow to build a CLAM system without no C++ knowledge, using only the graphical interface. They can be also used to build up rapid prototypes of a later optimized system. The prototyping environment is still some how limited.

8.2 Processing classes

The Processing classes are the main building blocks of the CLAM framework. All processing in the CLAM must be performed inside a Processing class.

Interaction between Processings follows a very bounded but flexible interface. This way, CLAM can manage Processing in a very general way and it boosts the reusability of Processings between different CLAM systems.

All the Processing configuration process is done by giving it a configuration object before the Processing object is on the running state. While the Processing is running, the processing algoritm will be executed every time the Do() method is called at the processing execution rate.

While the Processings is running receive and emits two kinds of output:

When no automated FlowControl is involved, you can also overload the Do() method to pass as parameters the ProcessingData that would be otherwise accessible from the ports. This way of implementing Processing is now deprecated but still used.

The following figure illustrates all the different components of a Processing class.

Figure 2: Processing Object Representation

8.3 Dynamic Types

Both, Configurations and ProcessingData, are implemented as DynamicTypes (often DT for short). DynamicTypes are an abstraction that allows to have objects with not all attributes instantiated. DynamicType are implemented using preprocessor macros that will expand each attribute declaration in accessors and instanciation interface among other useful methods.

One of the most used features in dynamic types is that they provide some kind of introspection, and thus CLAM can provide some useful functionalities in a general way on every new DynamicType you will define. Examples of those free functionalities that you get by defining some class as DT are XML serialization, generic atribute visit, automatic interface generation...

You can see section chapter VI for more information on DynamicTypes use.

(See section 35, chapter XX, chapter IX for XML support)

8.4 Visualization Module

The CLAM Visualization Module fullfills two different developers needs. The first one is to inspect graphically CLAM objects as a debugging aid. The other one is to build a complete GUI based application that can be used in interaction with the Processing part of a CLAM system.

CLAM-VM has been designed in a very decoupled way so that it can be fully removed harmlessly from a CLAM system. It provides some general services that are toolkit independent such as thread safe data caching, model-view comunication and sincronization...

That CLAM-VM infrastructure can be used with any toolkit such as Qt, Fltk... In fact, it provides already done widgets, the toolkit dependant part. They are mostly implemented using FLTK and OpenGL but next releases will provide more support on Qt.

(See chapter XIV)

8.5 System utilities

CLAM provides integrated and platform independent support for system dependant tasks. For example:

9 Structure of this document

Although the structure of this document is a bit complex, hopefully by the time you get here you will be able to understand why the index has been set that way.

Basically, there are three parts to this document:

Part 1. User Documentation: Is the information any user of the CLAM framework should be aware of.

Part 2. Developer Documentation: Includes all the necessary information for more advanced users/developers.

Part 3. CLAM Sample Applications: In this part, we explain the most important sample applications included with CLAM.

Part 4. Migration: Is just a brief summary of the differences between the different releases (for already introduced and advanced users).

So, this document is intended to work as a more or less progressive introduction to CLAM. Start reading the first page and stop whenever you think details are becoming overwhelming. Of course for some particular users some sections may be 'skipable' and some may even prefer to start by reading about the sample applications just to get a grasp of what the framework is able to offer.

Going into a bit more details of the different parts, each of them includes the following topics.

Part 1 starts off with some information any CLAM user will need the first time he/she tries to use the framework: in the 'Deploying CLAM in your System' chapter you will be guided on how to configure CLAM in your system; and in the 'CLAM Build System Documentation'chapter you will be introduced to the features and functionalities of the rather particular build system that is used in CLAM. In the next chapter you will find a 'Usage Tutorial' (chapter IV) that introduces the basic functionality of the CLAM framework, furthermore in this same section we include a listing of other relevant examples that are kept in the repository. All following chapters focus on the different functionalities of the framework from a user's point of view (you will find chapters on Dynamic Types, Processing classes, Processing Data classes, XML Support, Audio I/O, MIDI I/O, The Application classes, and the Visualization Module (GUI)).

Part 2's first chapter, XIII. CLAM Coding conventions, gives some hints on coding recommendations and conventions for developers. The next chapters (Dynamic Types, Processing Data classes and XML) give an inside view on how to develop using the internal features of these CLAM's building blocks.

Part 3 includes an explanation of the following applications: SMSTools, SALTO, Spectral Delay and Rappid. The last chapter in this part explains how to use CLAM to develop LADSPA plug-ins. After you have read the introduction and have managed to compile CLAM, you may wish to go directly to these examples, before getting deeper into the library.

Part 4 gives a summary of the differences between this release and previous ones. You can skip this if you are not already familiar with the CLAM framework. Note: this part explains main differences between three latest releases, all the previous ones, though, have only been internal to MTG.

10 Where to find more information on CLAM

There are different sources of CLAM related information. All of them, though, are linked and updated at CLAM's website at www.iua.upf.es/mtg/clam .

USER DOCUMENTATION

II Deploying CLAM in your system

11 Roadmap

This section explains how to:

12 Obtaining the CLAM sources

CLAM source code and third party libraries binaries can be found on our web page --download area-- http://www.iua.upf.es/mtg/clam in both tarball and zip formats.

At this moment CLAM is provided as a source package which is not ment to be compiled as a binary library. Although in the future this is likely to change we provide an automatic build system in order to ease the job to the user (you will find information on this build system in the next chapter).

12.1 GNU Tools distributed with MacOS X 10.2 Specific Issues

13 Dependencies on third-party libraries

CLAM depends on other external libraries in order to implement low level task such as XML parsing or cross-platform abstractions (devices, threads, GUI, etc.). This implies that they must be present on your development environment in order to build applications with CLAM.

The full list of libraries CLAM depends on is:

The following sections will give you guidelines on how to deploy them in either GNU/Linux and Windows platforms. If, after having read these instructions, you still have problems please browse through the CLAM mailing list archives or post a new mail to the list if you find that your question has no answer there either.

13.1 External libraries on GNU/Linux

Your GNU/Linux distribution should have the suited versions for the required libraries. However, it is possible that the normal package has some problems: it is inexistent, it is a wrong version, it is compiled with the non-default compiler, or it is compiled with wrong options.

In case you run on some of the above problems, check if there is a suitable tarball in our web: We provide some compiled libraries for Debian-Woody and Red Hat 9.

If this is not your case, or you still have problems we recommend to download and compile the sources directly.

If you do that take into account these hints:

13.2 External libraries on Microsoft Windows

To make it easy for Windows users we have precompiled binaries of all the needed libraries. They are available for download in the CLAM web, download section

All of them are generated using Microsoft VisualC++ 7.1.(.NET) although we still keep the ones compiled with VisualC++ 6.0 for backwards compatibility.

Windows has no convention on how to install libraries --both precompiled binaries and development headers. We have configured our build system in order to find libraries at the same directory level than the CLAM root directory.

For example:

    devel\CLAM\
    devel\fltk\
    devel\xercesc\
    devel\fftw\
    devel\...
Note on fftw: fftw can work on two modes with different precission and speed: 'float' and 'double'. Both versions are available on the web and you must make sure that the fftw directory you place in the same level as CLAM dir must fit with the value of CLAM_DOUBLE build system variable. (See chapter III for more details on this).

CLAM uses 'float' as default so to start using CLAM extract the float-version zip.

Note on DLLs: Once you have downloaded all the development kits, you should scan the lib\ subdirectories inside each library folder, and copy all the Dynamic Linking Libraries (.dll) to some place pointed by your system PATH environment variable.

We recommend to create a directory named dll at the same level as the libraries directories. Copy there the dlls and add it to the PATH environment variable.

III CLAM Build System Documentation

14 Overview

CLAM provides an automatic build system which allows you to generate and maintain GNU Makefiles and VisualC++ 6/7.1 project files (.dsp/.prj).

This automatic build system is most useful taking in account that at the moment CLAM is not distributed in a compiled (binary) library. Thus it manages to hide to the user all details regarding: necessary implementation files, include dirs, external libraries and compilation flags.

Consider the following source dependency graph:

A source dependency graph

Without a build system helper you would have to add by hand each .cxx file into your Makefile or Visual project in order to compile it. The CLAM automatic build system uses an small and fast application called srcdeps that finds the source files dependencies.

In the previous example, supposing we say to the srcdeps that we want to compile main.cxx. It would make the following deduction:

        'As main.cxx must be compiled and includes both blue.hxx and green.hxx
        then blue.cxx and green.cxx must be also compiled'

So, when srcdeps finds a header dependency to Foo.hxx, it looks for the Foo.cxx implementation file. And in the case that it is found, it applies the same search recursively.

Of course additional implementation files --not reachable from dependent headers-- can be specified as starting points. The common case is that only the .cxx with the main function has to be specified.

For each executable --or binary in general-- you want to generate, you must use a file named settings.cfg in order to provide those starting points and other build specifications. See section 19.1 for more details on how to do this.

Because the automatic build system relies on a compiled application srcdeps to do its job, after downloading CLAM we'll need to compile this application. Next section describes how to do it.

15 Setting up CLAM Build System

16 USE / HAS variables

In order to keep track of what external libraries to use for each project, and whether they are available, the srcdeps configuration files used by CLAM contain several USE_[feature] and HAS_[feature] variables.

On Windows, the user has to make sure that the HAS_[feature] variables reflect it's system installation, on Linux and MacOSX they are set to 1 or 0 when running the configure script in build/

When srcdeps parses the configuration files, it makes sure that all HAS_[feature] and USE_[feature] variables are consistent. In other words, it will give an error if it noticed that a specific USE_[feature] is set to 1 while the corresponding HAS_[feature] is set to 0

Sometimes, the settings may specify only the use a certain feature when it is indeed possible. This can be done by setting

USE_[feature] = $(HAS_[feature])

See section 19.3 for a full list of these variables.

16.1 Included configuration files

Looking at a typical srcdeps settings.cfg file, you can see the following files are included (directly or indirectly):

16.2 Editing the packages-win.cfg file

Before continuing, make sure that build/packages-win.cfg file reflects your installation. This file will be read (through includes) when you run srcdeps. If you make any change to this file, you will need to rerun srcdeps.

16.3 Setup on MS Visual Studio

Open the Visual workspace file srcdeps.dsw located on CLAM_DIR\build\srcdeps\, and compile the srcdeps project. Make sure you are building the binary using the "release" configuration. That's just for efficency reasons.

Visual will leave the output executable srcdeps.exe on the CLAM_DIR\build\srcdeps\ directory. Now we have to configure Visual in order it can automatically execute srcdeps when some CLAM project (.dsp) needs to be redone.

16.3.1 Configuring Visual 6 to use srcdeps

  1. Select Tools->Options ...
  2. Click on the 'Directories' tab
  3. From the combo box labeled 'Show directories' select 'Executable files'
  4. Scroll the list below labeled 'Directories' up to the bottom and double-click on the blank line.
  5. Enter or browse the path to srcdeps.exe

16.3.2 Compiling our first CLAM example

Now we are going to compile the example application "SMSTools2" that comes with CLAM. Doing so you both will be able to play with an application that gives a taste of what CLAM can do, and will confirm --hopefully-- that the CLAM environment is correctly set up.

Open the Visual project SMSTools.dsp which is on CLAM_DIR\build\Examples\SMS\Tools\ and compile it (it takes a while...)

If something went wrong check you followed the above steps and see the Windows Troubleshooting section See section 22.

You can see that the file settings.cfg appears in the project files view. This file defines settings of the project and after any change you are able to apply them to the dsp project by just right clicking over that file and choose 'compile' from the contextual menu. This execute srcdeps taking settings.cfg as a parameter

Important note:

Don't change configuration values or add files directly to the project, instead you should modifiy settings.cfg and re-run srcdeps as explained before. Otherwise you'll lose the manual changes the next time you run srcdeps

16.4 Setup on GNU/Linux

Change dir to CLAM_DIR/build/srcdeps and invoke 'make' to build the srcdeps binary.

Once srcdeps has been created, we will check if all the required external libraries. To do so, change dir to CLAM_DIR/build and type:

$ autoconf -f
$ ./configure


16.4.1 Compiling our first CLAM example

Now we are going to compile the example application "SMSTools2" that comes with CLAM. Doing so you both will be able to play with an application that gives a taste of what CLAM can do, and will confirm --hopefully-- that the CLAM environment is correctly set up.

Change dir to CLAM_DIR/build/Examples/SMS/Tools/. Execute make CONFIG=release to generate dependencies and compile the sources (it can take a while...).

If something went wrong check you followed the above steps and see the GNU/Linux Troubleshooting section See section 22.

17 How to set up your own programs using CLAM

This chapter is a little tutorial for setting up an example application using CLAM and its build system. In first place we're going to compile a given simple application --very straight. And in second place we're going to go through all possible customizations in the build settings that the user might need to set up more complicated projects.

17.1 An out-of-the-box example

Following this steps you'll get an application which performs an FFT of a random generated audio and stores its spectral equivalent in a file in XML

  1. Go into your new unpacked CLAM dir. Inside /build you'll find this dir: compiling_against_CLAM_example. Copy this dir at the same directory that contains the CLAM sources.
    Note that this copied directory, apart from the .cxx file with a main function, contains a subdir named build/ with the configuration files necessary to use the automatic CLAM build
    Hint: in linux, cp -ar <src> <dst> copies a directory recursively
  2. Edit the build/clam-location.cfg and change CLAM_PATH so it points to the CLAM dir --maybe you'll find that this value is already properly set.
  3. At this point we need to have CLAM correctly deployed and srcdeps already compiled. See section 15 for how to do it.
  4. Now our way forks depending on the choosed compiler

Hopefully we've been able to run the example and play with spectral data in XML. From here we'll see how to customize the build options and to create more complex projects

17.2 Customizing your project

Here we're going to go through the things you should know when setting your own project that compiles against CLAM and using its automatic build system.

First of all, we assume that you allready have created a root directory for your project

That's it, hopefully you are compiling your project agains CLAM, without dealing in manualy finding the CLAM sources it needs.

18 CLAM and QT toolkit library

CLAM gives to the user complete support if he wants to use QT to develop his graphical user interfaces. This library uses a special kind of macros in its code that needs a preprocessing step in order to work correctly. In order to activate this support USE_QT=1 must be declared in the settings.cfg file of the project.. There are two kinds of actions:

19 CLAM build system configuration variables reference

There are two main kinds of config variables depending on the values they may take:

Note for Windows users: you should use frontslashes '/', as directory separator, instead of backslashes '\', which is the usual way in Windows.

Depending on the effect, there are three kinds of variables:

Now we will see a detailed explanation for each of the variables meaning and possible values.

19.1 Build system variables reference

Note that textual variable values should follow the GNU Makefile variable syntax. See section 21 if you are unfamiliar with GNU Makefile. If you are not working with GNU development tools and you are not interested in learning how to write Makefile scripts then take into account the following.

Note that you can assign several tokens (variable values separated by spaces) to the same variable as in:

PRJ_SEARCH_INCLUDES= ../../../foo/bar/whatever ../../../foo/bar/stuff ../../../foo/bar/thingamajig

sometimes you could have so many tokens that reading the variable assigned value can be hard. Then you may break the tokens into several lines as in:

PRJ_SEARCH_INCLUDES= \
        ../../../foo/bar/whatever \
        ../../../foo/bar/stuff \
        ../../../foo/bar/thingamajig \

note that the backslash, '\', tells srcdeps that the values assigned to PRJ_SEARCH_INCLUDES variable span several lines. Note that whenever you begin a new line you must type in a 'tab' character (spaces are not enough) and when you finish the last line you must ensure it finishes in a newline character (pressing Return should suffice).

19.2 CLAM configuration variables

19.3 External libraries variables

20 Generating CLAM binaries

TODO: No information about generating a CLAM library binary is available yet

21 Some useful links

To get some insight on the 'source dependencies issue' and GNU Makefile syntax you may visit the following links:

http://www.eng.hawaii.edu/Tutor/Make/

22 Build system troubleshooting

23 Some common problems while using Microsoft Visual C++

23.1 Getting lots of LNK2001 errors: redefinition of C/C++ Standard Library symbols

Microsoft C/C++ ANSI Standard Library run-time binaries come in six different versions: Single Threaded Release, Single Threaded Debug, Multi Threaded Release, Multi Threaded Debug and Multi-threaded with Dynamic Linking Release and Multi-threaded with Dynamic Linking Debug. This multiplicity makes possible the following pitfall: suppose you have some external library, such as FLTK which links statically against, say, the Single Threaded Release version, and then you try to link against FLTK binary ( and, of course the standard library binary ) you get a number of linking errors about duplicate symbols such as malloc, realloc, etc. The way of getting rid of this is to make your project link dynamically against the Multithreaded Dynamic Linking Library. This can be achieved by doing the following: go to Project->Settings ( or ALT+F7 ), select your project from the project browser on the left and then click on the C/C++ tab on the right, select Code Generation option on the Category combo-box and then you will see another combo-box labelled "Use run-time library:". Select there the "Debug Multithreaded DLL" option if your project is in Debug or the "Multithreaded DLL" option if otherwise. Note that this phenomenon not only arises with FLTK: it would be wise configure always the projects in this manner, since it is unharmful and saves many headaches about obscure linking errors.

23.2 Getting lots of compiling errors not related to your Project (What's config.h about?)

It is common practice amongst library developers to allow library users to alter some inner mechanisms or configure the library for a concrete platform (either OS, hardware or compiler) by "prefixing" all library source files with a C header file containing some macros that define a concrete behaviour or policy for the library binary. Then the users can undefine or define the necessary macros for obtaining its desired configuration. However, especially under Microsoft Visual Studio it is easy to forget about including this prefixing file. Whenever you get some unexpected or unrelated to your work compiler errors it is wise to check that Visual Studio is prefixing Library sources by doing this: go to Project->Settings (or ALT+F7), select your project from the project browser on the left and then click on the C/C++ tab on the right, and check that inside the Project Options textbox on the right appears the following /FI"config.h". If it doesn't appear add it. If it is there check that your "Additional Include Directories" on the "Pre-processor" category are pointing to.../../src/Defines/Windows. If the compiler still complains then the problem could be elsewhere and that is beyond the scope of this document :).

23.3 Not finding a user defined header

Usually this pitfall is caused by having not specified to the compiler the needed additional include directories. This can be done by: go to Project->Settings (or ALT+F7), select your project from the project browser on the left and then click on the C/C++ tab on the right, select on the "Category:" combo-box on the right the "Pre-processor" option. Then appears on the right a textbox labelled "Additional include directories:", and then just add the path RELATIVE TO THE DIRECTORY WHERE THE .DSP FILE IS IN YOUR HARD DISK. This could have the form ".../../draft/mything" or something similar.

23.4 My dynamic_cast's are failing for no apparent reason

Just check that your C/C++ Project Settings, on the category Language enable RTTI (Run Time Type Information). If this setting is already set then you should revise your code (and remember that temporaries have not a reliable virtual function table).

23.5 I am getting an Internal Compiler Error message!!!

The dreaded error messages 'par excellence'. These 'errors' are signalled by Microsoft IDE whenever the compiler dies ungracefully due to a Segmentation Fault. These compiler crashes happen whenever the parser found something extremely standard or some of extremely convoluted C++ code. Here you have a list of possible causes for these errors:

23.6 My Visual C++ is behaving weirdly and signalling non-sense error messages

Visual C++ hosts a quite impressive list of bugs, so this is clearly a sign that you have uncovered some particularly nasty or weird. We cannot give you any outright solutions, since many times we are hassled by this kind of issues. But sometimes rebuilding your project from scratch or disable function-level linking (Incremental linking feature) helps to make thins saner. Good Luck!

23.7 The compiler does not find FL/Flxxxx.H or DOM/xxxx.hpp

Note that when in your code you use #include <something.h> you are telling the compiler that that header can be found in the System Headers path. This feature has a lot of sense under UNIX where you have a /usr/include or similar dir where all headers are neatly deployed. But under Microsoft Visual Studio this can mean two things: that either you have to copy manually the folders with the includes into Microsoft Visual Studio directory/VC98/Include dir or follow our guidelines for creating a sandbox.

This FAQ-like section does not covers all possible issues you might find while using Visual C++ but we hope they solve the most typical of them. Feedback about new issues or alternative solutions to situations described above is welcomed.

24 Some common problems while using GNU/Linux and GNU C++ Compiler

The motivation of executing autoconf & configure in CLAM_PATH/build is to check if your system configuration will be able to compile and execute CLAM applications. You can get a lot of different problems related to external libraries, so we have created a compilation of the most common, classified by the step where this problem arises.

24.1 FFTW

24.1.1 Getting error when trying to locate fftw header/libs

You can search in config.log where is the error if the configure stops at the lib checking. Surely it will be related to the installation of fftw, because CLAM needs both versions (float and double) of libs and headers. Please check that.

24.2 FLTK

24.2.1 Checking fltk libs fails and config.log contains compiler errors

Check that you use fltk-1.1.4, because some interface has been changed (and some has been created), so the errors can be related to the fltk version you are trying to compile against.

24.2.2 Checking fltk libs fails and config.log contains linking errors, or the program test couldn't be executed.

Make sure you have LD_LIBRARY_PATH pointing to all the locations needed

24.2.3 fltk-config not found

You have a fltk version without this utility (older than 1.1), or the PATH variable doesn't point against its location. Set PATH correctly or download a new version from fltk official web (or the binaries you can get in CLAM web). Anyway, it should work without this program if you have fltk-1.1.4 or newer.

24.3 QT

24.3.1 No qt headers found! having qt installed correctly in the system

Use QTDIR variable to tell the configure where you have qt (like export QTDIR=/usr/qt/3).

24.3.2 Found qt headers but crashed testing lib because library (qt or qt-mt) not found.

Make sure QTDIR is correctly pointed, and you have a qt version newer to 3.0.

24.3.3 Compiler errors related to exit and throw functions

Remove config.cache and rerun autoconf with 2.5X version. (like autoconf-2.57).

24.4 XERCES

24.4.1 Checking xerces libs fails and config.log contains compiler errors

You'll need exactly xerces 2.3, because in newer versions they have broken the interface, and CLAM won't be capable of link against it.

24.4.2 Checking xerces libs fails and config.log contains linking errors, or the program test couldn't be executed

Make sure you have LD_LIBRARY_PATH pointing to all the locations needed

24.5 STL

24.5.1 Getting these errors:

checking for std::vector::at() method in libstdc++... no
checking for standard sstream header in libstdc++... no
checking if stringstream::str() returns std::string in libstdc++... no

Remove config.cache and rerun autoconf with 2.5X version. This error is related to a bug inside autoconf-2.1X combined with gcc-3.X, so you'll need to run an autoconf version newer in order to create a correct configure for this compiler version.

24.6 Common problems trying to compile and execute CLAM applications

24.6.1 Compiling is ok but getting errors trying to link/execute the program

Make sure you have LD_LIBRARY_PATH pointing to all the locations needed. It's needed when you have installed external libraries in a local location. If you have, for example, fltk and xerces installed in the same directory where you have CLAM, you should set LD_LIBRARY_PATH in this way:

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/path/to/xerces/lib:/path/to/fltk/lib/

IV Usage tutorial

25 Introduction

This document provides a first glance to the usage of CLAM as a signal processing and sound synthesis framework for C++ applications, following several simple code example. The source code this the examples is included with the source code of the library (in the directory examples/Tutorial.

CLAM consists of a set of C++ classes. There are two main kinds of classes in the library:

  1. Processing Classes, which perform the signal processing operations.
  2. Processing Data Classes, which are placeholders for the data that flows between Processing objects.

A Processing class has a set of data inputs and a set of data outputs. Each of them will receive Processing Data of an specific type. Several such data types exist (also as C++ classes): Audio, Spectrum, statistical descriptors, etc.

A processing class can also have a set of input and output controls. These are attributes that can be used to change the Processing object behavior once it is ``running'' setting internal run-time execution variables.

Finally, a Processing Object is created and configured using a configuration object, which may define its architecture and its behavior. This configuration may be set at object construction time, or later.

26 Instanciating Processing objects

Each processing class (and its configuration class) is defined in a different library header file. To instanciate an FFT processing object, for example, you should do the operations shown below.

// We include the FFT class and associated Processing Data objects
#include <FFT.hxx>
#include <Audio.hxx>
#include <Spectrum.hxx>

// And C++ input-output library to write the output message.
#include <iostream>

int main(void)

{

   // This creates an FFT configuration object
   CLAM::FFTConfig my_fft_config;

   // This sets some configuration parameters.
   my_fft_config.SetAudioSize(1024);
   // And this finally creates the FFT object.
   CLAM::FFT my_fft(my_fft_config);
   std::cout << my_fft.GetClassName() << std::endl;
}

If you have a look at the declaration of the FFTConfig class in the FFTConfig.hxx file (you will find this header files in the src/Processing/Analysis directory of CLAM sources), you will notice that it is not declared as a standard C++ class. This is because FFTConfig is a so called DynamicType. More information about CLAM dynamic types is provided in the specific chapter in this document, although some useful features will be described below.

This example also shows that all the CLAM related classes are declared in the CLAM namespace. Thus you must either include the CLAM:: prefix in each of the names, or include the following line of code at the beginning of your program, to avoid prefixing:

using namespace CLAM;

Note: Importing a namespace globally as it is done in the previous line though is not usually a good idea in a less than trivial project.

27 Processing Data

Instanciation of processing data objects is usually simpler that the creation of processing objects, as shown below.

#include <Spectrum.hxx>
#include <iostream>

int main()
{
// We just need to declare the data object
CLAM::Spectrum spec;
// And we can start accessing its attributes
spec.SetSpectralRange(4000);
if ( spec.GetScale() != CLAM::EScale::eLinear )
{
std::cout << "This can not happen!" << std::endl
<< "Spectrums are linear by default!" << std::endl;
}

When working with processing data, you must keep in mind that the data classes are Dynamic Types. This allows you to add or remove data attributes at run time (which means that memory for those attributes is allocated/freed at run time).

Both SpectralRange and Scale are dynamic attributes in the spectrum class, and as such they can be accessed using Set and Get methods like in the sample code above.

Some complex processing data classes, like the Spectrum, provide dynamic attributes for alternative representations of the same data. You can have the spectral samples stored as CLAM::Complex objects (Cartesian coordinates), as CLAM::Polar objects, or as separate magnitude an phase floating point arrays. You can add or remove these dynamic attributes to fit your application.

   // This "tags" the "Complex" dynamic attribute for addition.
spec.AddComplexArray();

// This "tags" the "Polar" dynamic attribute for addition.
spec.AddPolarArray();

// This "tags" the default Magnitude and phase attributes
// for removal.
spec.RemoveMagBuffer();
spec.RemovePhaseBuffer();

// This actually performs the previous addition/removal
// operations.
spec.UpdateData();

// Finally, we set the size for the spectrum object, so that all
// the added attributes (ComplexArray and PolarArray, in this
// example) get resized.
spec.SetSize(1024);

The AddAttributeName(), RemoveAttributeName() and UpdateData() methods are the general mechanism for adding and removing dynamic attributes to/from dynamic types.

Some complex data classes, such as the Spectrum, also provide a configuration class, which can be used to ease the construction of multiple objects with common settings.

For example, if you know what dynamic attributes you need when you construct the object, you can specify them in the configuration object. The SpectrumConfig has a Type attribute, which stores a set of Boolean Flags describing which dynamic attributes in the Spectrum object are to be "added" at construction time. This is shown in below.

   // SECOND ALTERNATIVE: creation of the spec2 object using type flags.

// First we specify the desired attributes.
CLAM::SpecTypeFlags flags;
flags.bComplex=1;
flags.bPolar=1;
flags.bMagPhase=0;

// Now we build the settings object
CLAM::SpectrumConfig cfg2;
cfg2.SetType(flags);
cfg2.SetSize(1024);
cfg2.SetSpectralRange(4000);

// spec2 will have the same attributes as spec.
// Note that when using this method the added attributes
// already have the right size.
CLAM::Spectrum spec2(cfg2);

return 0;
}

You have two different ways to set or change the value of a dynamic attribute. The easiest one is completely overwriting the previous value. This is illustrated in below. It also introduces a new processing data class (Audio).

#include <Audio.hxx>
#include <Array.hxx>
#include <iostream>
#include <cmath>

int main()
{
// We specify this to avoid typing the CLAM:: prefix
using namespace CLAM;

try {
// We first create and configure the data object.
Audio au;
au.SetSize(1024);
au.SetSampleRate(8000);

// Now we create a real array
// We reserve a 2048 samples buffer, just in case
Array<TData> array(2048);

// But for now we set the logical size of the array
// to just 1024 samples
array.SetSize(1024);

// We initialize it...
int i;
for (i=0; i<1024; i++)
array[i]=sin(2*3.141592*10.5*i/(1024));

// And we use it to set the real attribute
// in our Audio data object, by making a copy.
au.SetBuffer(array);

// Now, if we want, we can modify the data in the Audio object
// (This does not change the original "array" object):
for (i=0; i<1024; i++)
au.GetBuffer()[i]*=1.5;

// And, of course, we can copy it into a different array.
Array<TData> array2 = au.GetBuffer();
}
catch (std::exception &e)
{
std::cerr << e.what() << std::endl;
return 1;
}
return 0;
}

This example has also introduced the class Array<T>. This is one of the many utility template classes defined in the library. Some of them are similar to some STL classes. Array<T>, for example, is similar in functionality to the std::vector<T> class (the reasons for not actually using the std vector have been thoroughly discussed and are still a matter of controversy between CLAM developers). The attributes which contain sample chunks in both the Spectrum and the Audio classes are Array attributes. Note that the Array<T> class is not a ProcessingData class (i.e., it cannot be fed directly to a processing object).

In the example shown below, we can see the other way to access dynamic attributes: getting a reference to them and modifying it. This is a bit more obscure, but more efficient. Back to the Spectrum class, the example shows how to convert the complex samples among the different representations (which are stored as different dynamic attributes in the Spectrum object).

int main()
{
using namespace CLAM;

SpecTypeFlags flags;
flags.bMagPhase=false;
flags.bComplex=true;
SpectrumConfig spec_cfg;
spec_cfg.SetSize(513);
spec_cfg.SetType(flags);

Spectrum spec(spec_cfg);

// Instead of creating and initialize our own array, like in
// example 3, we get a reference to the uninitialized complex
// array (which already has the right size)
Array<Complex<TData> > &cplx = spec.GetComplexArray();

// ... and we initialize it directly.
for (int i=0; i<513; i++)
{
cplx[i].SetReal(1.0);
cplx[i].SetImag(1.0);
}

// We now add the Polar array attribute using the dynamic type
// mechanism.
spec.AddPolarArray();
spec.UpdateData();

// Beware: The following is easy to forget.
// When adding an attribute with the AddXXX() method,
// its size is not initialised. You must do it manually:
spec.SetSize(513);

// We finally force the spectrum object to set the new attribute
// to the right values. The flags argument has the bComplex member
// set to "true", indicating that the ComplexArray attribute is
// the one from which values will be taken.
spec.SynchronizeTo(flags);

return 0;
}

28 Usage examples

Now that we are familiar with ProcessingData classes, we can start to use Processing Objects to perform computations on data objects. This is best shown through some examples.

The first one, in shows how to perform the FFT of an Audio object and store it in a Spectrum object. The key parts are the calls to the Start and Do methods of the FFT.

#include"FFT.hxx"
#include<iostream>
#include<cmath>

int main()
{
int i,Size=1024;
float SampleRate=8000.0;

// Audio creation
CLAM::Audio myaudio;
myaudio.SetSize(Size);
for (i=0;i<Size;i++)
myaudio.GetBuffer()[i]=
0.625+0.5*sin(2.0*PI*400.0*(((float)i)/SampleRate));

// Spectrum settings
CLAM::SpectrumConfig ssettings;
ssettings.GetType().bMagPhase=false;
ssettings.GetType().bComplex=true;
ssettings.SetSize(Size/2+1);

// Spectrum creation
CLAM::Spectrum myspectrum(ssettings);

// Processing object configuration
CLAM::FFTConfig fconfig;
fconfig.SetAudioSize(Size);

// Processing object creation
CLAM::FFT myfft(fconfig);

// Processing object execution
std::cout << "Running object " << myfft.GetClassName() << std::endl;

// This puts the object in execution mode.
myfft.Start();

// And this performs the computation.
myfft.Do(myaudio,myspectrum);

return 0;
}

If you are wondering about the strange data sizes used in this examples, you should take in account that the FFT processing class actually performs a real DFT. Because of spectrum symmetry, only the first half of the spectrum is needed, so the second half is not calculated.

The next example illustrates how to use controls in a processing object. A Frequency Domain Filter is created, and the filter characteristics are set using its input controls.

#include <FDFilterGen.hxx>
#include <Spectrum.hxx>

int main()
{
using namespace CLAM;

FDFilterGenConfig gconf;

gconf.SetType(EFDFilterType::eLowPass);
gconf.SetSpectralRange(4000.0);
gconf.SetGain(1.0);
gconf.SetStopBandSlope(12.0);

FDFilterGen generator(gconf);

Spectrum filter;
filter.AddMagBPF();
filter.AddPhaseBPF();
filter.RemoveMagBuffer();
filter.RemovePhaseBuffer();
filter.UpdateData();

generator.Start();

generator.DoControl(2,1000.0); // Low Cutoff

generator.Do(filter);

return 0;
}

V Usage examples

Appart from the previous tutorial the CLAM repository also includes some examples in order to show how can you do the basic operations with CLAM: loading audio files, playing sounds, using Processing class... This is the list of related examples, each one of them fully detailed with comments.


VI Dynamic Types

29 Scope

This section is addressed to the users that want to learn the basics aspects and usage of Dynamic Types (DTs for short). You may also find a section devoted to Dynamic Types in the "Developers" part of this document. This latter is aimed to explain how to create new classes that derive from the base DT, and goes into some details regarding their functionality.

30 Why Dynamic Types ?

Though it might be a quite controversial issue, there are three main reasons for the decision of implementing and using DTs in CLAM.

  1. There is a need in some core classes of the library, of working with types with a large number of attributes, i.e.: the descriptors of audio segments, that in some cases only a small subset is needed, and so could represent a waste of space if its memory is always allocated. DT can instantiate and de-instantiate attributes at run-time, and do it in such a way that its interface is the same as if they where C++ normal attributes.
  2. We want support for working with hierarchic or tree structures. That means not only composition of DTs but also aggregates of them (lists, vectors, etc. of DTs). With such compositions of DTs, we can use assignation, and two clone member functions: ShallowCopy () and DeepCopy(), the good thing is that they come free; we don't need to write these members in none of the DT concrete classes.
  3. We obtain introspection of each DT object. That is the ability to know the name and type of each dynamic attribute, to iterate through theses attributes, of having some type specific handlers for each. One clear application of introspection is storage support for loading from, and storing to a file, of a tree of DTs. Of course all this is implemented generically, so appears transparent to the user. At this point we have XML support implemented. Other profits we take from introspection in DT are debugging aids.

31 Where can DT be found within the CLAM library?

All classes deriving from ProcessingData base class are DT. The concrete ProcessingConfig classes as well as the ProcessingDataConfig classes are also DT.

32 Declaring a DT

When we say that dynamic attributes can be instantiated at run time, we mean that we can do so with the previously declared dynamic attributes. Let's see an example. Imagine we want to model a musical note with a DT. We declare it like this:

class Note : public DynamicType
{
public:
DYNAMIC_TYPE (Note, 5)

DYN_ATTRIBUTE (0, public, float, Pitch)
DYN_ATTRIBUTE (1, public, unsigned, NSines)
DYN_ATTRIBUTE (2, public, ADSR, Envolvent)
DYN_CONTAINER_ATTRIBUTE (3, public, std::list<Sine>, Sines,
harmonic)
DYN_ATTRIBUTE (4, private, Audio, Wave)
};

This is a macro-based declaration, right now there are three different macros: DYNAMIC_TYPE for expanding the concrete DT constructors, DYN_ATTRIBUTE for declaring each dynamic attribute and DYN_CONTAINER_ATTRIBUTE for declaring any STL interface compliant container.

We will now explain these three more in depth:

1. DYNAMIC_TYPE this macro expands the default constructor of the concrete DT being declared. The first parameter is the total number of dynamic attributes, and the second one the class name.

If the writer of a DT derived class sees the need of writing a customized default constructor or other constructors it can be done using the initializers. See section 82.

2. DYN_ATTRIBUTE it is used to declare a dynamic attribute. It has four parameters, the first one is the attribute order (needed for technical reasons of the DT implementation), the second one is the accessibility (public, protected or private) the third one is the type: it can be any C++ valid type including typedef definitions but not references (& finished) or pointers (* finished). If you still think you need pointers as dynamic attributes then read the pointers section (section 85).

The forth and last parameter is the attribute name, it is important to begin in upper-case because this name (let's call it XXX) will be used to form the attribute accessors GetXXX() and SetXXX(.), thus the XXX must start in upper-case, following the coding style of the library (See chapter XVI)

Returning to the example above, each DYN_ATTRIBUTE macro will expand a set of usable methods:

float& GetPitch(), void SetPitch(const float&),
void AddPitch(), void RemovePitch(), bool HasPitch()
void StorePitch(Storage&) const, bool LoadPitch(Storage&)

Of course GetPitch and SetPitch are the usual accessors to the data. AddPitch and RemovePitch, combined with UpdateData that will be explained latter on, will instantiate and de-instantiate the attribute. HasPitch returns whether Pitch is instantiated at this moment. Finally StorePitch and LoadPitch are for storage purposes, and will be explained in section 35

3. DYN_CONTAINER_ATTR: The purpose of this macro is to give storage (only XML by now) support to attributes declared as containers of objects. For providing this service, we need that container to fulfill the STL container interface, so all the STL collection of containers is usable. This macro has five parameters, one more that DYN_ATTRIBUTE: the attribute numeration, accessibility, the type, the name of the attribute and finally the new one: the label of each contained element that will be stored.

33 Basic usage

Once, the concrete DT Note has been declared, we can use it like this:

Note myNote; // create an instance of the DT Note

Now myNote, have no attribute instanciate. We can activate attributes this way:

myNote.AddPitch(); myNote.AddNSines(); myNote.AddSines();

Or in the case that we want all of them, it is better to use AddAll. (This method is not macro generated as AddPitch, but is a DT member available in any concrete DT.

)
myNote.AddAll();

As this kind of operations require memory management, we want to update the data, with its possible reallocations only once for every modification of the DT shape or structure (which can imply many individual adds and removes). We'll use the DynamicType UpdateData operation for that purpose:

std::cout << myNote.HasPitch() // writes out: 'false'
myNote.UpdateData();
std::cout << myNote.HasPitch() // writes out: 'true'

And now all the instantiated attributes can be accessed as usual, using the accessors GetXXX and SetXXX. For example:

myNote.SetNSines(10);
myNote.SetPitch(440);

// lets use some std::list operations:
myNote.GetSines().push_back(440).push_back(440*2);
myNote.GetSines().push_back(440*3).push_back(440*4); // etc.

int i=myNote.GetPitch(); // error! GetPitch() returns float
int j=myNote.GetNSines(); // ok.

More about adding, removing and updating attributes:

It is important to learn the exact behaviour of adding and removing DT attributes. It can be summed up to three ideas:

GetXXX and SetXXX operations over non-instantiated attributes will rise an exception ErrDynamicType. So these operations should be protected with an if (HasXXX()) clause in places of the code where there is no safety about the presence of XXX.

• Besides, AddXXX and RemoveXXX can be used safely (don't rise any exception). Basically what they do is set and unset internal flags. For example, if the attribute Pitch exists and we do RemovePitch() it will be marked as "removed" (waiting for the UpdateData() to perform the actual removal). Now, if before updating data we call AddPitch(), then it detects the mark and the effect is just to unset this flag. If we insist with another AddPitch() it will have no effect (and no flag will be set), because it is allready instantiated. The case of adding a non-instantiated attribute is symmetric as the case of removing an instantiated one.

UpdateData() is a safe and efficient operation: with safe what we mean is that it has no effect (and doesn't rise exceptions) in case that the DT needs no memory update, and it is efficient in the sense that the checking for changes in the dynamic shape doesn't involve any traversal of the attributes but only cheking a global flag. Moreover, UpdataData() returns a boolean that says if it has been necessary to update the data. Sometimes it is very useful do things such as :

// here we don't know if Pitch exist.
myNote.AddPitch();
if (myNote.UpdateData()) {
// yes, it existed
// ...
}
else {
// no, it didn't was there till now.
// ...
}

34 Prototypes and copy constructors

It's been said that a the dynamic shape of a DT is the set of instantiated attributes. The description of this shape is stored in a table and can be shared between various DTs. Thus this brings us to the idea of prototypes and creating objects by cloning the dynamic shape of others, this is exactly how the default copy constructor works.

Note n1(myNote), n2(myNote), n3(myNote), n4(myNote);

Now n1, n2, n3 and n4 all share both static information of their type and the dynamic shape information, and we say that myNote is their prototype, or that they all share the same prototype. It is important to notice that this happens even if the prototype (myNote) doesn't have its data updated. If we decide to change the shape of one of these objects, i.e. we want to add new attributes to n4, this operation will automatically create a new prototype and so a new dynamic shape as the next figure shows:

Of course, the copy constructor also copies the data of each instantiated attribute from the source object into the new object. This copy is made using the corresponding copy constructor. This means that the copy constructor makes a so-called "deep copy" (that means recursives copies of its sub-elements) of any composition of DT and aggregates (i.e. using STL containers) of DTs.

More on copy constructors (i.e. with the shareMemory flag) can be learnt directly from the javadoc source documentation.

35 Storing and Loading DTs

This section only explores a feature that is particular to the Dynamic Types: debug-time information. If you should need more details about how to store and load DT from and to XML please refer to chapter IX.

35.1 How to explore a DT at debug time

Since the dynamic data of a DT is not stored as regular C++ attributes, it might be difficult to explore in the usual way from the debugger. Thus we have provided the DT base class with a Debug() method that can be called from the debugger environment and basically does two things: