[Mustajuuri homepage]

Mustajuuri technical documentation

0. Disclaimer
1. Fundamentals
2. Plugins
3. APIs
4. FAQs
5. Plugin examples
6. Exporting code


0. Disclaimer

This documentation corresponds to the latest (=most bleeding edge) Mustajuuri release.

The documentation is heavily incomplete. I know this. The situation will improve within the next five years. If you feel that you would really need some documentetaion, please ask. I might then get the motivation to write it.


1. Fundamentals

Design basics are described in this overview: mj_code.pdf (241 kb).

The programming language is C++. The GUI toolkit is Qt by Troll-Tech (version 2.2.x, 2.3.x or 3.x). Mustajuuri currently requires a POSIX-compliant system. Supported platforms are Linux and IRIX. Most functionality is incorporated in the plugins. Plugins are loaded dynamically to the system.

The plugin system is meant for high-level signal processing. Within the plugins you can use any toolkits/libraries you like; STK (Synthesis toolkit), SPK (Sound processing kit), FFTW (Fastest Fourier transform in the west) etc. There is - however - a small standalone library that contains efficient implementations for few of the most common DSP operations. This library - libmjdsp - is used widely in the standard Mustajuuri plugins.

2. Plugins

Mustajuuri is based on plugin-approach. The processing elements are loaded into the system at run-time rather than being directly linked in. Requirements for DSP plugins and GUIs are behind the links. All code is based on these requirements.

Basics: All plugins inherit a common base class MJ_ModuleDsp. This class has number of virtual methods that can (and need to) be overridden to insert your own functionality. A plugin may also define a custom user interface to replace the default UI. Currently there are two sorts of UIs, graphical ones (GUI) and text-based ones (TUI, not really that supported). As with he DSP code the GUI modules are plugins that inherit a common base class MJ_ModuleDspGui

As there are different ways to use a plugin there are different requirements for the user interface. Sometimes a small simplified interface is needed (when adjusting the most important parameters) while at other times more elaborate interface is needed (giving access to all of the functionality). Thus it is necessary that the plugin may define multiple GUIs for these purposes. The GUI may of course be the same for all purposes, but such behaviour is discouraged.

Granularity of the plugin interface: Plugins are meant to be medium to large pieces of code (reverb, EQ, chorus, synth). Of course you can make very small plugins (single delay line, adder, multiplier) as well. The current master interfaces (mixer and row) do not really support this kind of small plugins well, but you can build a canvas interface (a la Max or Kyma) that can take full benefit of the them.

When it works well: If it isn't too necessary that certain samples arrive to certain module a sample or two early or late. Such applications are mixers. Often this approach can be used with DSP nets like Max and Kyma (which do buffer the audio).

When it does not work well: The buffered signal IO causes inevitable problems when it comes to making very accurate DSP systems where sample-accurate delay-times are needed and maximum processing buffer size is one sample. Such application is for example physical modeling of musical instruments. For these situations a low-level signal processing library is the proper tool.

Signal IO: Each module has some number of signal (continuous IO at fixed sampling rate) input- and output terminals. Signals are passed via these terminals from one module (module = plugin instance) to another.

Event IO: Each module can also receive messages (MIDI, string, double, arbitrary). These messages are timestamped and they also contain target address in the form of a character string.


3. APIs

Mustajuuri includes a collection of libraries. There are separate libraries for low-level DSP, widget libs etc. Some of them have been documented separately:

The API is fairly big and provides a rich set of fundamental tools. Most features that one can access are optional, not obligatory. The current API and library directly supports following features:

  1. Signal processing (ie. audio)
  2. Message passing (eg. MIDI)
  3. Undo/redo
  4. Internationalization
  5. Level of detail in (G)UI
  6. Plugin parameters can be saved to a file

Note that the plugin API is not concerned with what your plugin does or how it will be eventually displayed. All current screenshots feature mixer or row layout, but a "wires and boxes" approach (a la Kyma or Max) is also possible. Such user interface can be built by making a new plugin that does it (the mixer and row interface are themselves plugins).

There are things that could also be done:

  1. Define the parameter naming for "standard" plugins (audio/MIDI IO, EQs, reverbs). Basically define certain standard interfaces for common purposes.
  2. More work on the GUI, in particular a few extra widgets and classes to help plugin GUI development.
  3. Debug and streamline the system to make the current features work.

4. FAQs


5. Plugin examples

Probably the easiest way to understand plugin programming is to look at the example plugins. There are three example plugins.

The first example plugin is a monophonic effect that squares the input values. The plugin is created with about thirty lines of effective code. The code is hopefully self-explanatory :-)

The second example plugin is a monophonic low-pass filter. It relies on Mustajuuri to create the GUI and save all the parameters to disk. While it does not take too much code or effort to create plugin (just make a new C++ class) the result is a full-featured module: internationalization is supported, the hosting system can save the parameters to a file and undo/redo is supported. After the code is compiled to a shared library you can start using modules of this type in your mixers etc.

This GUI is generated automatically based on the plugin definition:
Screenshot of the low-pass plugin in action

The file and edit menus contain the things you might expect:
Screenshot of the low-pass plugin menus in action


The third example plugin is a stereo eight-tap delay. It defines a GUI class of its own that is tuned to make the plugin easier and faster to use. Since it is a relatively simple plugin it can still rely on Mustajuuri to save the parameters (delay times, panning etc.) to the disk.

The plugin GUI looks like this (click on the image to view a full-size version):
Screenshot of the eight-tap delay plugin in action

This is a fine example of why one might want to make a custom GUI for a plugin. The number of parameters is fairly large in this case (27 to be exact). Most of them need to grouped and weighted. Some of them are visualized in the graph. This way the plugin can be used much more effectively and easily.

While custom GUIs are nice so is code reuse. In this case the menu bar with its standard file and edit items is created with two lines of plugin code. The graphics in the middle are created with the widget extension library (libmjwidgets) that comes with Mustajuuri.


6. Exporting code

Mustajuuri contains some code which can be of interest to other developers. Usually the code depends on other Mustajuuri or Qt components, but it is often (not always) easy to remove the dependencies.

6.1 Signal processing library libmjdsp

Since some low-level DSP operations are often needed I made a small libary that provides such tools. The classes in this library are efficient, low-overhead implementations. This library is completely stand-alone - it does not depend on any other Mustajuuri library or even Qt. A few of the classes:

6.2 Widget library libmjwidgets

This Qt-based widget library depends very slightly on other Mustajuuri libraries, but the dependencies are easily removed. Some widgets contained in the library:
Tommi Ilmonen.at.hut.fi
Last modified 6.2.2004. Mustajuuri technical documentation
[Mustajuuri homepage]

Mustajuuri technical documentation

0. Disclaimer
1. Fundamentals
2. Plugins
3. APIs
4. FAQs
5. Plugin examples
6. Exporting code


0. Disclaimer

This documentation corresponds to the latest (=most bleeding edge) Mustajuuri release.

The documentation is heavily incomplete. I know this. The situation will improve within the next five years. If you feel that you would really need some documentetaion, please ask. I might then get the motivation to write it.


1. Fundamentals

Design basics are described in this overview: mj_code.pdf (241 kb).

The programming language is C++. The GUI toolkit is Qt by Troll-Tech (version 2.2.x, 2.3.x or 3.x). Mustajuuri currently requires a POSIX-compliant system. Supported platforms are Linux and IRIX. Most functionality is incorporated in the plugins. Plugins are loaded dynamically to the system.

The plugin system is meant for high-level signal processing. Within the plugins you can use any toolkits/libraries you like; STK (Synthesis toolkit), SPK (Sound processing kit), FFTW (Fastest Fourier transform in the west) etc. There is - however - a small standalone library that contains efficient implementations for few of the most common DSP operations. This library - libmjdsp - is used widely in the standard Mustajuuri plugins.

2. Plugins

Mustajuuri is based on plugin-approach. The processing elements are loaded into the system at run-time rather than being directly linked in. Requirements for DSP plugins and GUIs are behind the links. All code is based on these requirements.

Basics: All plugins inherit a common base class MJ_ModuleDsp. This class has number of virtual methods that can (and need to) be overridden to insert your own functionality. A plugin may also define a custom user interface to replace the default UI. Currently there are two sorts of UIs, graphical ones (GUI) and text-based ones (TUI, not really that supported). As with he DSP code the GUI modules are plugins that inherit a common base class MJ_ModuleDspGui

As there are different ways to use a plugin there are different requirements for the user interface. Sometimes a small simplified interface is needed (when adjusting the most important parameters) while at other times more elaborate interface is needed (giving access to all of the functionality). Thus it is necessary that the plugin may define multiple GUIs for these purposes. The GUI may of course be the same for all purposes, but such behaviour is discouraged.

Granularity of the plugin interface: Plugins are meant to be medium to large pieces of code (reverb, EQ, chorus, synth). Of course you can make very small plugins (single delay line, adder, multiplier) as well. The current master interfaces (mixer and row) do not really support this kind of small plugins well, but you can build a canvas interface (a la Max or Kyma) that can take full benefit of the them.

When it works well: If it isn't too necessary that certain samples arrive to certain module a sample or two early or late. Such applications are mixers. Often this approach can be used with DSP nets like Max and Kyma (which do buffer the audio).

When it does not work well: The buffered signal IO causes inevitable problems when it comes to making very accurate DSP systems where sample-accurate delay-times are needed and maximum processing buffer size is one sample. Such application is for example physical modeling of musical instruments. For these situations a low-level signal processing library is the proper tool.

Signal IO: Each module has some number of signal (continuous IO at fixed sampling rate) input- and output terminals. Signals are passed via these terminals from one module (module = plugin instance) to another.

Event IO: Each module can also receive messages (MIDI, string, double, arbitrary). These messages are timestamped and they also contain target address in the form of a character string.


3. APIs

Mustajuuri includes a collection of libraries. There are separate libraries for low-level DSP, widget libs etc. Some of them have been documented separately:

The API is fairly big and provides a rich set of fundamental tools. Most features that one can access are optional, not obligatory. The current API and library directly supports following features:

  1. Signal processing (ie. audio)
  2. Message passing (eg. MIDI)
  3. Undo/redo
  4. Internationalization
  5. Level of detail in (G)UI
  6. Plugin parameters can be saved to a file

Note that the plugin API is not concerned with what your plugin does or how it will be eventually displayed. All current screenshots feature mixer or row layout, but a "wires and boxes" approach (a la Kyma or Max) is also possible. Such user interface can be built by making a new plugin that does it (the mixer and row interface are themselves plugins).

There are things that could also be done:

  1. Define the parameter naming for "standard" plugins (audio/MIDI IO, EQs, reverbs). Basically define certain standard interfaces for common purposes.
  2. More work on the GUI, in particular a few extra widgets and classes to help plugin GUI development.
  3. Debug and streamline the system to make the current features work.

4. FAQs


5. Plugin examples

Probably the easiest way to understand plugin programming is to look at the example plugins. There are three example plugins.

The first example plugin is a monophonic effect that squares the input values. The plugin is created with about thirty lines of effective code. The code is hopefully self-explanatory :-)

The second example plugin is a monophonic low-pass filter. It relies on Mustajuuri to create the GUI and save all the parameters to disk. While it does not take too much code or effort to create plugin (just make a new C++ class) the result is a full-featured module: internationalization is supported, the hosting system can save the parameters to a file and undo/redo is supported. After the code is compiled to a shared library you can start using modules of this type in your mixers etc.

This GUI is generated automatically based on the plugin definition:
Screenshot of the low-pass plugin in action

The file and edit menus contain the things you might expect:
Screenshot of the low-pass plugin menus in action


The third example plugin is a stereo eight-tap delay. It defines a GUI class of its own that is tuned to make the plugin easier and faster to use. Since it is a relatively simple plugin it can still rely on Mustajuuri to save the parameters (delay times, panning etc.) to the disk.

The plugin GUI looks like this (click on the image to view a full-size version):
Screenshot of the eight-tap delay plugin in action

This is a fine example of why one might want to make a custom GUI for a plugin. The number of parameters is fairly large in this case (27 to be exact). Most of them need to grouped and weighted. Some of them are visualized in the graph. This way the plugin can be used much more effectively and easily.

While custom GUIs are nice so is code reuse. In this case the menu bar with its standard file and edit items is created with two lines of plugin code. The graphics in the middle are created with the widget extension library (libmjwidgets) that comes with Mustajuuri.


6. Exporting code

Mustajuuri contains some code which can be of interest to other developers. Usually the code depends on other Mustajuuri or Qt components, but it is often (not always) easy to remove the dependencies.

6.1 Signal processing library libmjdsp

Since some low-level DSP operations are often needed I made a small libary that provides such tools. The classes in this library are efficient, low-overhead implementations. This library is completely stand-alone - it does not depend on any other Mustajuuri library or even Qt. A few of the classes:

6.2 Widget library libmjwidgets

This Qt-based widget library depends very slightly on other Mustajuuri libraries, but the dependencies are easily removed. Some widgets contained in the library:
Tommi Ilmonen.at.hut.fi
Last modified 6.2.2004.