Menu

Tree [4684be] master /
 History

HTTPS access


File Date Author Commit
 examples 2013-01-05 Kristian Amlie Kristian Amlie [3fb8e0] Added some example scripts.
 m4 2018-08-26 Kristian Amlie Kristian Amlie [caf4bd] Regenerate autoconf files.
 src 2020-10-11 Kristian Amlie Kristian Amlie [4684be] Optimization: Flush simultaneous MIDI events to...
 .gitignore 2011-09-19 Kristian Amlie Kristian Amlie [2d082a] Updated .gitignore.
 AUTHORS 2007-07-25 Kristian Amlie Kristian Amlie [cd1c2f] Initial revision.
 COPYING 2009-06-14 Kristian Amlie Kristian Amlie [99e312] Updated to GPLv3.
 ChangeLog 2013-06-23 Kristian Amlie Kristian Amlie [3f5b1a] Bumped version to 0.31.
 Doxyfile 2007-07-25 Kristian Amlie Kristian Amlie [cd1c2f] Initial revision.
 INSTALL 2013-01-05 Kristian Amlie Kristian Amlie [cf4991] Updated documentation.
 Makefile.am 2013-01-06 Kristian Amlie Kristian Amlie [f89be8] Added example scripts to install.
 Makefile.cvs 2007-07-25 Kristian Amlie Kristian Amlie [cd1c2f] Initial revision.
 Makefile.in 2018-08-26 Kristian Amlie Kristian Amlie [caf4bd] Regenerate autoconf files.
 NEWS 2013-01-05 Kristian Amlie Kristian Amlie [cf4991] Updated documentation.
 README 2013-06-23 Kristian Amlie Kristian Amlie [3f5b1a] Bumped version to 0.31.
 TODO 2011-10-12 Kristian Amlie Kristian Amlie [54ddd8] Updated TODO.
 aclocal.m4 2018-08-26 Kristian Amlie Kristian Amlie [caf4bd] Regenerate autoconf files.
 compile 2018-08-26 Kristian Amlie Kristian Amlie [caf4bd] Regenerate autoconf files.
 config.guess 2013-06-23 Kristian Amlie Kristian Amlie [42c818] Updated build files.
 config.h.in 2011-09-22 Kristian Amlie Kristian Amlie [8f3f45] Added DSSI GUI support.
 config.sub 2013-06-23 Kristian Amlie Kristian Amlie [42c818] Updated build files.
 configure 2018-08-26 Kristian Amlie Kristian Amlie [caf4bd] Regenerate autoconf files.
 configure.ac 2018-08-26 Kristian Amlie Kristian Amlie [34ba67] Update autoconf settings to modern requirements.
 depcomp 2013-06-23 Kristian Amlie Kristian Amlie [42c818] Updated build files.
 install-sh 2013-06-23 Kristian Amlie Kristian Amlie [42c818] Updated build files.
 ltmain.sh 2013-05-11 Kristian Amlie Kristian Amlie [100248] Added libboost_system as library dependency.
 missing 2013-06-23 Kristian Amlie Kristian Amlie [42c818] Updated build files.
 mkinstalldirs 2013-06-23 Kristian Amlie Kristian Amlie [42c818] Updated build files.

Read Me

Jacktube v0.31
===============

   Jacktube is an advanced audio/MIDI processing program. It uses LADSPA
and DSSI plugins to process audio, MIDI events to control its operation
and Jack is used for audio connections. The exact operation is governed
by a set of customizable rules, which resembles a simple programming
language.

   Even though Jacktube is primarily meant for audio work, it can be
used in any signal processing application.

   Maintainer: Kristian Amlie <kristian at amlie.name>


Command line options
====================

   I'm too lazy maintain documentation of options both here and in
the program. This should do the trick:

   jacktube -h


Examples
========

   For some examples, see the scripts inside the examples/
subdirectory.


Language
========

   Jacktube operates by receiving audio from Jack input ports, using
plugins to process the audio and handing the result to one or more
output ports. In addition, MIDI events can be received from one or more
sequencer ports and can either be used to control the operation of the
audio path, sent to a DSSI synth plugin, or can be modified and sent
back out on a MIDI output port.


Number variables
----------------

   The rule file consists of commands telling Jacktube what to do.
A simple command may look like this:

   $variable = 1.5;

   This assigns the value 1.5 to the variable called "$variable".
Variables have no direct effect on the signal path, but are useful to
hold values in the program. All variables start with "$".

   Variables are created by simply assigning to them, but you can only
create them outside an event scope (more on event scopes later). In
other words, if you want to assign to a variable inside an event scope,
you must have assigned to it at least once outside first.


String variables
----------------

   Variables can also hold strings. This is useful in the context of
DSSI "configure" (more on that later). Note that strings are in a
separate namespace, so you can have two variables, $myVar and $myVar,
one containing a number and one containing a string. The context where
it is used decides which one is chosen.

   String variables (and string operations in general) support simple
concatenation using '+'. You can also concatenate numbers to the string
this way, like:

   $variable = "mySoundFontNumber" + int($soundFontNumber) + ".sf2";

   int() and float() are used to include numbers and numerical
variables, and strings you can refer to directly.


Audio paths
-----------

   An audio path can be constructed like this:

   >~output ~ <~input;

   This constructs a Jack output port ">~output" and an input port
"<~input", and creates a path between them, so that the signal will flow
from "<~input" to ">~output". All Jack output ports start with ">~"
(think shell redirection, you write "into" the port so that it appears
as an output port in the Jack port graph), and input ports start with
"<~" (similar redirection mnemonic). Any port can only be written to
by one other port, which means that the following command will replace
the audio path we made above.

   >~output ~ <~anotherInput;

   A port can be read by as many ports as you like. To remove an audio
path completely, use this command:

   >~output -;

   (Think "~" for audio wave, and "-" for flatline).


Plugin loading
--------------

   Audio paths are useful, but they become much more powerful when
combined with plugins. Before a plugin can be used, it must be loaded.
You can obtain a list of available plugins by using "jacktube -l" (the
normal LADSPA and DSSI environment variables apply). Once a plugin is
selected, it is loaded like this:

   %plugin = "amp_mono";

   You can identify a plugin using either its name or the name combined
with the library it resides in (if there is a naming conflict). In the
jacktube plugin listing, the name is the first word in each entry, and
the library is the name after the comma. For example:

   amp_mono, amp.so
           Description: Mono Amplifier
           Unique ID: 1048
           Real time: Yes
           Type: Filter

   In this listing, "amp_mono" is the name, and "amp.so" is the library
it resides in.

   The unique ID can also be used to load LADSPA plugins, but this
behavior is deprecated, and will only work for plugin variables with no
array subscript.

   After the loading is complete, the plugin can be referred to by the
name "%plugin". All plugin instances start with "%".


Plugin ports
------------

   LADSPA and DSSI plugins come with a number of ports, which are either
control ports or audio ports (can be obtained with "jacktube -p"). Let's
connect them:

   %plugin["gain"] = 0.5;
   %plugin["input"] ~ <~input;
   >~output ~ %plugin["output"];

   So what happened here? We assigned the control parameter "gain" a
value of 0.5. Then we connected the plugins input to the input from
Jack, followed by connecting the Jack output to the output from the
plugin. This audio path will modify the input signal so that the output
signal has its amplitude cut in half.

   Note that you can use both variables and arbitrary arithmetics in the
control port assignment. In addition the port name can be replaced by its
numeric name if you like. So this is legal:

   %plugin[0] = $variable * 2 - 0.8;

   The operators are "+", "-", "*", "/" and "^" (raise).

   But the real magic is this: A control port can receive its input from
a signal path as well, like this:

   %plugin["gain"] ~ <~anotherInput;

   The gain parameter will now vary with its input signal (see the -s
option for controlling the granularity of this processing). You cannot
use arithmetics on this path directly, but the signal can come from a
plugin as well, so you can preprocess it there before it gets to the
control port.

   Why is this useful, do you ask? Won't the control just fluctuate
wildly and create noise? In most cases, yes, but remember that the input
signal doesn't have to be audio. It could be a low frequency oscillator,
for example like this:

   %gain = "amp_mono";
   %oscillator = "sine_fcac";
   %oscillator["freq"] = 1;
   %oscillator["amplitude"] = 0.5;
   %gain["gain"] ~ %oscillator["output"];
   %gain["input"] ~ <~input;
   >~output ~ %gain["output"];

   Here, the oscillator is set to oscillate at 1Hz, and send its output
to the gain control port, causing the audio signal to rise and lower
between 0 and 0.5 gain, once per second.


Arrays
------

   Variables and plugin handles support arrays, like this:

   $array[3] = 4.3;
   %myplugin[2] = "amp";

   Any positive integer (and zero) can be used as a subscript and a
variable or arithmetic expression can be used as well. All the elements
are created on the fly, and the array does not need to be declared
first, but arrays have the same restrictions as other variables
regarding assignment within a scope.

   If you assign to a plugin port within an array, you will have to use
two brackets:

   %myplugin[2]["gain"] = 0.5;


Dynamic port names
------------------

   Jack ports do not support arrays the way that internal variables do,
however there is a different syntax which provides dynamic port names.
In short, you have to create all ports by using them in an audio path,
like described above, however after it is created you can refer to it by
any string, including a variable or concatenated string. For example:

   >~out_channel_1 ~ <~in_channel_1;
   >~out_channel_2 ~ <~in_channel_2;

   >~{"out_channel_" + int($currentchannel)} ~
           <~{"in_channel_" + int($currentchannel)};

   This becomes very useful in event scopes, where the output port may
depend on which channel the MIDI event came from.


Event scopes
------------

   As described before, MIDI events can be used to control the behavior
of Jacktube. MIDI events take the shape of an event range followed by an
event scope, which contains the commands that should be executed for that
event:

   [<@seqInput, <channel>, <type>, <key/control>, <velocity/value>]
   {
      <statements>
   }

   The first variable there is the sequencer input port (the names start
with "<@" and ">@", and have similar semantics like audio ports). After
follow four specifiers, which are either "all" (match all possible
values), a number or a range (two numbers separated by "-"). These
specify for which event values this action should trigger. The order is
channel, type, key/control, velocity/value. Type is the type of MIDI
event, which is between 0 and 127. "type[xxx]" constants can be used to
test for specific types of events, where xxx is either keyon, keyoff,
keypress, pitch, program, control or channelpress. The order is
important if you use them in a range, since everything between the two
endpoints will be matched. The rest of the ranges should be self
explanatory. For example:

   [<@seqInput, all, type[control], 1, 0-64]
   {
      %gain["gain"] = event[value];
   }

   Note that arithmetics are allowed in ranges, but if they are anything
more complicated than a simple variable or number you must put it in
parenthesis.

   After the event range comes the event scope, where you can put any
command. Inside the event scope, you can use "event[channel]" special
variables to refer to the MIDI values that triggered the event. The
types for "event[]" are again: channel, type, key/param and
velocity/value.

   All the event ranges that match are executed; Jacktube does not stop
on the first match. This can be changed, however, by putting the "final"
keyword right before the event range. If the range matches, this will
execute that scope, but no scope that follows it will be executed, even
if it matches. For example:

   final [<@seqInput, all, type[control], 1, all]
   {
      $modulation = event[value];
   }
   [<@seqInput, all, all, all, all]
   {
      # Forward the event.
      >@seqOutput = [event[channel], event[type],
            event[key], event[value]];
   }

   In this example, we intercept MIDI control messages of the Modulation
type (control message number 1), and store it in a variable. We don't
want those control messages to propagate to the catch-all scope
following it, so we put final in front of the first scope. In the second
scope, we forward all other events (more on sending events below).


Sending MIDI events
-------------------

In addition to the already mentioned actions, MIDI events can be sent out
too. Here is how that looks:

   [<@seqInput, all, type[control], 1, all]
   {
      >@seqOutput = [3, event[type], event[key], event[value]];
   }

   This sends the same MIDI message back out on ">@seqOutput", except
that it is always sent on channel 3. MIDI messages are only allowed
inside an event scope.

   MIDI messages for DSSI synth plugins are sent in the exact same way,
except that you replace the sequencer port name with a plugin name, such
as:

   [<@seqInput, all, type[control], 1, all]
   {
      %plugin = [3, event[type], event[key], event[value]];
   }


"If" logic
----------

   One can also put if statements inside the event scopes, and they look
more or less exactly like a C/C++ if statement, with some exceptions:
First, the braces are required, and second, you write "elseif" instead of
"else if". For example:

   [<@seqInput, all, type[control], 1, all]
   {
      if (event[value] > 64) {
         >@seqOutput = [3, event[type], event[key], event[value]];
      } else {
         >@seqOutput = [4, event[type], event[key], event[value]];
      }
   }

   This will make events with values above 64 go to channel 3, while the
rest go to channel 4. Like C/C++, the else clause is optional. Jacktube
provides the <, <=, ==, >=, > and != operators for use in if statements.


DSSI operations
---------------

   DSSI plugins come with some extra capabilities in addition to ports
and accepting MIDI messages.

   "configure" is a call that is used to configure the plugin in some
way. It consists of two strings, a key and a value. The meaning of these
strings is completely plugin dependent (but see "show_gui" below). For
example:

   %fluid = "FluidSynth-DSSI";
   %fluid.configure("load", "mysoundfonts.sf2");

   This loads the DSSI plugin of FluidSynth, and then tells it to load
a certain soundfont using FluidSynth custom configure call.

   In accordance with the DSSI specification, if any configure key
starts with "GLOBAL:", configure will propogate that key and value pair
to all plugins of the same type.

   Another call is "show_gui", which, surprisingly, shows the GUI of
the plugin, if it has one. It takes two parameters: The first is a
label which the plugin can display in order to separate it from other
instances of the same plugin. The other is an optional parameter,
"configure_print", which causes it to print any configure calls received
from the GUI to the console. This is a good way to find out which types
of configure calls a plugin supports, for use with the configure call
described above. The corresponding call to close the GUI is "hide_gui".
For example:

   %fluid = "FluidSynth-DSSI";
   [<@seqInput, all, type[control], 64, 64-127]
   {
      %fluid.show_gui("Fluid 1");
   }
   [<@seqInput, all, type[control], 64, 0-63]
   {
      %fluid.hide_gui();
   }
   [<@seqInput, all, type[control], 66, 64-127]
   {
      %fluid.show_gui("Fluid 1", configure_print);
   }
   [<@seqInput, all, type[control], 66, 0-63]
   {
      %fluid.hide_gui();
   }

   In this example, we listen to the control messages 64 and 66, which
are the sustain and sustenuto pedals. If we press the first pedal
down we launch the GUI with no printouts, and we close it when releasing
the pedal. If we press the second pedal down, we launch the GUI as well,
but this time it will print all configure calls received from the GUI.
Again, we close the GUI when releasing the pedal.

   The last DSSI specific call is programs(), which returns a string
with a list of the programs (instruments) offered by the plugin. This is
useful together with the "print" statement, which is described in the
"Debugging" section.


Comments
--------

   Comments in the rule file start with "#", continue to the next newline
and are accepted everywhere.


Debugging
=========

   For debugging scripts, Jacktube provides the "print" statement, which
accepts any string as its argument, like so:

   [<@seqInput, all, all, all, all]
   {
      print("Event received on channel " + int(event[channel]));
   }


Disclaimer
==========

   This program is provided as is, with no warranty whatsoever.
Use the program at your own risk. The authors are not responsible for
the malfunction of this program, nor any of its consequences.