recipe preparation installation hello sine ! human box

Hello sine !

A small "hello world !" that plays a sine.

The code

#include "core/MPlugin.h"
#include "core/MUserClient.h"
#include "tools/processes/MMultiBridgeProcess.h"
#include "core/MSupervisor.h"

#include 

int main ( int /*argc*/, char * /*argv[]*/ )
{

  MPlugin * sine;
  if ( ! ( sine = MPlugin::CreateFromLibrary ( "cmt.so", "sine_fcac", "sine" ) ) ) {
    exit ( EXIT_FAILURE );
  }
  sine->ControlInput ( 0 )->SetValue ( 300 );
  sine->ControlInput ( 1 )->SetValue ( 0.3 );

  MUserClient * client = MUserClient::Create ( "hello_sine" );
  client->CreateAudioInput ( "input" );
  client->CreateAudioOutput ( "output" );

  MMultiBridgeProcess * bridgeProcess = new MMultiBridgeProcess ( client );
  client->SetCallbackProcess ( bridgeProcess );

  client->Activate ( );

  client->AudioOutput ( 0 )->Connect ( Supervisor ( )->AudioInput ( 0 ) );
  client->AudioOutput ( 0 )->Connect ( Supervisor ( )->AudioInput ( 1 ) );

  sine->AudioOutput ( 0 )->Connect ( client->AudioInput ( 0 ) );

  sine->Activate ( );

  cin.get ( );

  exit ( EXIT_SUCCESS );

}

Line by line

#include "core/MPlugin.h"

To include the definition of class MPlugin. A MPlugin is a module that interfaces with an instance of a LADSPA plugin. It's one of the base classes of la Marmite and is thus a part of the core.

#include "core/MUserClient.h"

This line includes the definition of class MUserClient which is a subclass of MClient, the base class for interfacing with JACK clients. A MUserClient is having the same functionnalities as a basic MClient but is offering this functionnalities publicly ( the user of the class can create ports, change the callback process, etc. ). Futhermore, the MClient class is an abstract class and cannot be used directly.

The MUserClient class is thus a first way to access clients and it allows to modify them. The other way, through inheritance, allows to create more spécific clients that cannot be deeply modified by the user of the class ( this is the method described in the human box example ).

The MUserClient class is a part of la Marmite's core.

#include "tools/processes/MMultiBridgeProcess.h"

Our client will use a ready-made process, this is a process that copies audio data from the input ports of a client to it's output ports ( input 1 to output 1, ..., input n to output n ). This class is no more a part of the basic classes and is thus belonging to la Marmite's tools.

#include "core/MSupervisor.h"

MSupervisor is a kind of special client from the core. It proposes a bunch of functionnalities that can be used by all the modules ( plugins as well as clients ) of an application. It allows notably to access JACK's physical ports.

int main ( int /*argc*/, char * /*argv[]*/ )
{

The standard entry point of the program : the main function.

  MPlugin * sine;
  if ( ! ( sine = MPlugin::CreateFromLibrary ( "cmt.so", "sine_fcac", "sine" ) ) ) {
    exit ( EXIT_FAILURE );
  }

We are here creating a MPlugin module from the sine_fcac LADSPA plugin, included in the cmt.so library. We are not using directly, in this case, a constructor because the result of this call is unsure ( the library of the plugin could be unreachable ) and we need to check the success or the failure of the creation ( the call returns NULL if it fails ). If the creation failed we quit the program.

  sine->ControlInput ( 0 )->SetValue ( 300 );
  sine->ControlInput ( 1 )->SetValue ( 0.3 );

If the creation was successful, we can now fixe the control values of our plugin. This one is having two controls : for frequency and amplitude. Let's fix the frequency to 300 Hz and the amplitude to 0.3 ( to have a precise description of a plugin, we can you the analyseplugin command in a shell ).

We'd like now to connect the audio output of this plugin to the physical inputs of JACK ( that correspond to the output of the audio device ). Unfortunately, this cannot be done directly and we need to create at least a JACK client to be able to connect to the JACK client corresponding to the audio device.

  MUserClient * client = MUserClient::Create ( "hello_sine" );

We create, in this very simple case, a MUserClient client which will serve as a bridge to connect to JACK's physical ports.

  client->CreateAudioInput ( "input" );
  client->CreateAudioOutput ( "output" );

We create two ports for this client. An input port ( MClientAudioInput ) called "input" and an output port ( MClientAudioOutput ) called "output".

  MMultiBridgeProcess * bridgeProcess = new MMultiBridgeProcess ( client );
  client->SetCallbackProcess ( bridgeProcess );

We create a MMultiBridgeProcess process that will copy the content of the input port of the client to it's output port ( the client parameter indicates on which client to copying operation must take place ).

In order to use this process for our client, we use the SetCallbackClient method. We this, every JACK cycle, the client will automatically call the Run method of its bridgeProcess which will be in charge of doing the actual copying. We just build a bridge.

  client->Activate ( );

Activate the client. It will, from this point, be called at regular intervals by JACK and it will be during this calls, known as callbacks and redirected by la Marmite to the Run method of the client, that the client will call in turn, by default, the Run method of the process it is currently using as its callback process.

  client->AudioOutput ( 0 )->Connect ( Supervisor ( )->AudioInput ( 0 ) );
  client->AudioOutput ( 0 )->Connect ( Supervisor ( )->AudioInput ( 1 ) );

We connect the audio output port of the bridge client to the first two physical ports proposed by the Supervisor ( they should correspond to JACK's physical input ports and thus to the left and right output of the sound card ).

  sine->AudioOutput ( 0 )->Connect ( client->AudioInput ( 0 ) );

We can now connect the sine oscillator's output to the input of our bridge.

  sine->Activate ( );

Activates our plugin. That should produce a sumptuous sine, all warm and sweet in your quivering ears.

  cin.get ( );

Hit a key to go further.

  exit ( EXIT_SUCCESS );

}

Well done ! Bye bye.

Schéma

Here is a little schema of what we just build :

schema des connections

HelloSine.pro

Here is the detail of the HelloSine.pro file that was used to create the Makefile for this examples.

TEMPLATE = app

To say that we want to create an application ( and not a library for example )

LIBS += -ljack ../libmarmite.so

We need to use the JACK library as well as la Marmite's library.

INCLUDEPATH += ../..

The includes path for la Marmite is in the parent's parent directory.

SOURCES += HelloSine.cpp

The source files to use.

To create the corresponding Makefile, we only need to run the qmake command. And then make to compile :

qmake
make