# fJACK - a JACK Audio Connection Kit client

## Introduction

When doing audio processing in Forth systems we were dependent on a working audio handler made available by the Forth vendor or had a lot of work to do.

Modern sound systems regularly make use of a callback driven model, ALSA for linux is just one example. But ALSA is not portable and doesn't allow connecting applications together in a sound-flow environment. One popular system allowing this is the 'jack-audio-connection-kit' JACK. It is available for all major platforms, Linux, OSX. Solaris and the Windows world. Jack makes use of the available hardware driver in a real time process. There are many audio applications around using the JACK interface and Forth can now connect to all of them.

fJACK is written in Forth and uses some of the advanced techniques like threading, binding of external libraries and callbacks. So it is not ANS Forth. The good news: it's available for iForth (Linux32/64, Windows, OSX32/64) and VFX Forth (Windows and Linux).

## Installation

### Installing the jack audio connection kit

First you must install a JACK system and get it running. Read the HOWTO in the net and specialized audio groups to find out how you can get the most out of it. Getting JACK running with low latency and no drops/xruns is sometimes a bit difficult. Look out for hardware that is well supported for your environment. If available use a real-time-kernel, even with a modern general kernel and optimized settings in security.conf you will have much larger latencies or dropouts.

### Downloading jack

This is a good place to find jack: http://jackaudio.org/download or go for compiled packages for your system.

### What sort of jack?

Currently there is a change in the jack system, either the 'old' jackd which has proven to be stable and should be available for all linux distributions. Please get at least the 0.116.1 version - the jackdmp based jack2 like 1.9.4 is also fine.

For windows and OSX systems there is the new jackdmp 1.9.4 available. Setting this up including the portaudio or coreaudio driver is not covered here but all compiled binaries come with a setup utility.

fJACK works fine with both systems. You should update to either jack >=0.116.1 or jackmp 1.9.4. Earlier versions like jack 0.109 or jackdmp 0.7.1 are much more likely to leave you worried especially when you work in a mixed 64/32bit environment.. All suggested versions have the ability to auto-start a jack demon when a client wants to register and no running demon is found. As the library knows much better how to start a default demon this feature is used in fJACK - the 'KICKSTART' method in ijack is not used as default any more. I guess this is more flexible as the user can choose between three options:

- Let fJACK use the default server setting and start it automatically. This needs a correct setup of jack.
- Start the jack demon before using fJACK with a tool like qjackctl. This allows precise setups of jack according to your system and is normally done at startup. I think this is the best way.
- Use the `KICKSTART-HOOK` by defining a jack-startup word, as the whole jack system is not known in the config.frt file you will have to `EVALUATE` the code, see the example there used by marcel.

### What about the fftw3 library?

All recent fJACK versions use the fftw3 library to define the filter response of FIR filters so you really should install it even when you don't need the signal analysis fft plugin. `BAND-PASS BAND-STOP` and `USER-FIR` filters with a user-specified frequency response and the `EQUALIZER` will not work without it. Calculating the filter parameters is not a real performance problem. But doing signal analysis on large amount of data or with sizes <> 2^n depends on a 'calibrated' fftw3 system. Currently creating fftw3 plans uses `#FFTW_ESTIMATE` because in fjack only 2^n sizes are used and then there not much of a difference. See fftw3lib.frt and fftw3.frt

### Performance

fJACK 0.122 or later uses optimized sse2 code filter kernels on all platforms. This is done by including the code generated on iForth systems via very simple binary code snippets. These are included at compile time depending on the used architecture and are also used in turnkeys. So for vfx this means the same performance as iforth systems.

For iForth this also means the assembler is only needed when you want to change the optimized code snippets.

The fjack client tests the running cpu, if your machine doesn't offer sse2 code there is a fallback to forth code which gives roughly half performance in all FIR filters. This test just uses the cpuid instruction, all supported operating systems make sure, the xmm registers are safe with threading.

The jack2 future will probably bring even better support for multi-core cpus, fjack is ready for that.

### Contact, help & bug reports

Feel free to ask for help at hanno@schwalm-bremen.de

Whenever you plan to use fJACK in commercial applications read the Licence.txt and email me.

### Latest News V. 1.01

`` History

## Where to put the fjack sources?

The fJACK system sources are the fjack subdirectory containing the client and extension modules sources plus the 'loader' fjack.frt. This directory also holds the default connection files in the connections directory and some binary files in the sysfiles directory. These subdirectories should be made writable.

### iForth

All iForth versions (exept Windows64) are supported. The fJACK sources should be in - or go to - the include directory. `IN fjack` will do. The iForth fJACK system uses an environment variable FJACKCONNECTIONS, it can be set to a directory of your choice.

### VFX Forth

The fJACK sources should be in - or go to - the Examples directory. You should cd to this directory, then `INCLUDE fjack.frt` will do.

### Testing the client

loading as above starts the jack sound demon when it is not running already, compiles the basic Forth interface to jack, defines a JACK client with some ports and connects these ports.

In the shipped setting there is also a little demo also loaded. Later you probably won't use it, switch it off in

`PLAY-SNIPPETS` starts playing snippets, sample-rate is changed by random- press key to stop.

`ON-SINUS OFF-SINUS` test the sinus oscillator.

`ON-FIR OFF-FIR` test an example highpass FIR filter.

`ON-ADP OFF-ADP` test an example adaptive FIR filter.

`ON-IIR OFF-IIR` test an example IIR lowpass filter.

`ON-DELAY OFF-DELAY` test an example IIR lowpass filter.

`ON-NOTCHES OFF-NOTCHES` test a bunch of IIR notch filters.

`ON-VIB OFF-VIB` tests a vibrato effect.

`ON-MIXER OFF-MIXER` tests the mixing to channel 2.

`ON-PHASER OFF-PHASER` tests a phaser plugin

`Hurray` and `OOOOH` give some sound.

## Making fJACK Turnkey Applications

fJACK can also be used in turnkey applications, all plugin object structs and the client data are in permanent memory space. When compiling your fJACK based application the client is initialised and started.

Turnkey applications all start the client on their own, you just have to put your application 'xt' in the boot chain.

    ' application AtCold

Stopping the client and system housekeeping is done in the `AtExit` chain.

# The fJACK Client User Manual

`\ MARKER -fjack`
The ANS `MARKER -fjack` can be safely used to remove fJACK from your forth system. It's supported on all platforms.

`VOCABULARY JACKAUDIO`
The `JACKAUDIO` vocabulary holds internals of the fJACK system, it's words could be changed in next releases and should be used in end-user applications with great care.

`: .JACK-RELEASE ." v1.01 (2010-05-13)" ;`

First a very short processing overview

fJACK does real-time processing on a user defined number of audio channels (ports) `JACK-CHANNELS`, it controls and is controlled by a jack demon. You can connect any other jack-ready application via these ports with fJACK. To allow audio data processing you can define audio plugins and put them in any of the slots. So the basic overview is like this

The Signal Processing Graph

Please recognize that the processing callback has changed in version 0.115, now every processing plugin has it's history buffer. Later you will find out, that every plugin can indeed read data from `any` history buffer. This new sheme allows a lot more features for sound effects and mixing.

## What can be configured in fJACK ?

Following are some system wide parameters defined in fjack/config.frt that could be changed by You!

`TRUE VALUE ALSO-EXAMPLES?`
Include the examples code when loading fjack?

`4 CONSTANT JACK-CHANNELS`
It can be set to any number >= 1 you like. The default is 4, when you have a powerful computer and wish to use more audio channels, just set this to 8 or whatever you need. Each channel has one input and one output port defined. These ports are used for the audio processing plugins described later. There is also a programmers interface to be used by you to define your own sound processing tools. Also think about using other jack plugins available in the net to be used by your forth application. Just one hint - more channels than needed will use a lot of memory and slow down the system a bit.

`#32 CONSTANT JACK-IO-SLOTS`
Defines the maximum number of processing plugins that can be placed in the Input-Port->Output-Port processing chain for a channel. Also see `#PLUGINS`

`#32 CONSTANT #PLUGINS`
The maximum number of plugins used at the same time in the input->output processing chain.

`FALSE VALUE #JACK-VERBOSE`
jack demon information and error messages are redirected to the fjack client, you may switch off the information writing. to the console by setting this to false.

`DEFER KICKSTART-HOOK ( -- ) ' NOOP IS KICKSTART-HOOK`
Sometimes - in probably not well configured or old jack systems - the auto-starting feature of the libjack function `jack_client_open` won't work. This hook is executed when no running JACK server is found just before starting th client. There is one example how to do it added here.

I really strongly suggest not using this feature, all supported platforms offer a nice jack control software that can be started automatically and offers nice configure options.

`#2048 CONSTANT #FIR_BUFF`
This defines the maximum number of taps in adaptive and fir filters; every defined FIR filter object uses 5*#FIR_BUFF DFLOATS dynamic memory. Must be a power of 2 and at least 4. This is quite a good default as normal fir filters won't need larger buffers. When using special effect plugins using the generic fir filter routines you might need larger buffers.

`\ %0000 CONSTANT PLAY-CLICK \ 0: start-of-wav-block 1: end-of-wav block 2: start-of-bunch 3:end-of-bunch`
This is an optional compile-time bitmask CONSTANT used for debugging , when defined and one of the lowest bits 0-3 is set 'clicks' are added to the played audio signal, these clicks can be analysed - and heard - on a recorded file.

`\ %1111 CONSTANT READ-CLICK \ 0: start-of-wav-block 1: end-of-wav block 2: start-of-bunch 3:end-of-bunch`
This is an another optional compile-time bitmask CONSTANT, when defined and one of the lowest bits 0-3 is set 'clicks' are added to the recorded audio signal.

`#32 CONSTANT #jack-fifos \ MUST be a power of 2`
Gapless wav playing and writing is controlled via a FIFOs with `#jack-fifos` elements. Only in very rare occasions there is a need to change this. If an applications writes small chunks of wav data at very high speed you could increase this. More information is available in the wav handling chapter.

`$800 CONSTANT #max-frame-size \ MUST be a power of 2`
The maximum frame size suported. Only with very slow hardware you will want larger buffers as the latency gets higher. #1024 is the default for the current jack versions so it must be at least $400.

`$20000 CONSTANT #HISTORY-SIZE \ must be a power of 2 and at least 4 * #max-frame-size`
fJACK may want access to data played some time before for delaying or data analysis so data are saved in this circular buffer. This history is available in every plugin.

`FALSE VALUE AUTO-HISTORY-CLEAR?`
Whenever a plugin object is put into the processing chain the history might be cleared automatically. I don't think it's worth to set this to TRUE but it's your decision.

`0 CONSTANT DEFAULT-FIR-WINDOW`
The coefficients of FIR filters are calculated by a windowed inverse FFT, this windowing function can 0,1 or 2. See `SET-FIR-WINDOWING` for more information.

`FALSE CONSTANT EXTENDED-JACK-INFO IMMEDIATE`
For debugging sessions you might get more information with setting this flag to TRUE.

`TRUE VALUE OPTIMIZED-FILTER-CODE?`
You might prohibit usage of optimized sse2 filter kernels by setting this to false; mainly used for debugging.

`TRUE CONSTANT FJACK-LOGIN-AUDIO IMMEDIATE`
You can disable the start/stop sound by setting this flag to FALSE

## Datatypes used in the client

Datatype definitions might change in future releases, the way these definitions are used will not. Currently the object-makers all return object-pointers or are defined as `CONSTANT`s.

`: -->DSP ( object -- )`
makes the plugin object the 'current object', this is done in a USER variable so that the object is local to a thread. After doing so all the elements of this object can be used with the `TO +TO 0TO` methods.

`: @DSP ( -- object )`
This is used to get the currently selected plugin object.

`: -->FIFO ( object -- )`
make the fifo object the current.

`: @FIFO ( -- object )`
Get the current fifo object.

`: CHAN-VALUE ( addr -- addr') \ name`
Define a `VALUE` 'name' per channel; the runtime stack is `(channel -- ?? )`

`: CHAN-FVALUE ( addr -- addr') \ name`
Define a `FVALUE` 'name' per channel; the runtime stack is `(channel -- ?? )`

`: DSP-VALUE ( n -- n' ) \ name`
Define a `VALUE` 'name' the for a plugin object. When using 'name' the object must be made valie before with `-->DSP`.

`: DSP-DVALUE ( n -- n' ) \ name`
Define a `DVALUE` 'name' the for a plugin object. When using 'name' the object must be made valie before with `-->DSP`.

`: DSP-FVALUE ( n -- n' ) \ name`
Define a `FVALUE` 'name' for a plugin object. When using 'name' the object must have been made valid before with `-->DSP`.

`: FIFO-VALUE ( n -- n' )`
The wav playing and reading is done via fifo structs, these structs have named elements. When using 'name' the object must have been made valid before with `-->FIFO`.

`: IIR-FVALUE ( n -- n' ) \ name`
Only used by the iir plugin;

## Using the Client

`1e0 FVALUE PLAY-WAV-LEVEL`
The level of the WAV data played common for all channels. The default of 1.0 is ok in most situations, when you have wav files that are a) 8bit-coded b) on almost full level and c) need resampling you might set this to a smaller value like 0.9 to avoid distortions.

`1e0 FVALUE READ-WAV-LEVEL`
The level of the recorded=read WAV data common for all channels.

`1e0 FVALUE JACK-IO-LEVEL`
This level is applied to data read at the InputPort before the Input->Output processing is done, it's common for all channels. The leveler plugin uses it as an example.

`#10000 VALUE JACK-SAMPLE-RATE ( -- n )`
The sample rate the JACK demon is running. It can be changed by other applications and the fJACK client is told about these changes via a callback.

`#1024 VALUE JACK-CHKSIZE ( -- n )`
Number of samples in a process frames callback as returned by the JACK demon.

`0 VALUE JACK-XRUNS ( -- n )`
Counter for the xrun callbacks

`0 VALUE fJACK-ID ( -- )`
The client id returned by the JACK library call when registering a client is kept here.

`DEFER MIDI-PROCESS-HOOK ( -- ) ' NOOP IS MIDI-PROCESS-HOOK`
Done by the midi handler once per PROCESS-FRAMES callback.

`DEFER GRAPH-REORDER-HOOK ( -- ) ' NOOP IS GRAPH-REORDER-HOOK`
Called by the reorder callback; you can define a function watching the jack environment, for example you could make sure about connections.

`DEFER PORT-CONNECT-HOOK ( a b flag -- ) ' 3DROP IS PORT-CONNECT-HOOK`
Called be the port-connect callback; you can define a function that looks for connections. This function must take the flag and both port id's from the stack

`0 VALUE #FJACK-SAMPLE`
In the input->output processing chain you can use this value as the sample number

`: OBJECT-HISTORY ( plugin-object|channel -- addr )`
To use `@HISTORY-DATA`, `MOVE-HISTORY-DATA`, `@IDX-HISTORY-DATA`, `RECONNECT-PLUGIN` or `@INTERPOLATED-HISTORY-DATA` you need the history buffers base address, this calculates it for you. The parameter can be either the channel getting the inport history buffer or the plugin object, then the plugins private history buffers is returned. As the history holds sfloat data there is a very small precision loss compared to pre-0.115 versions.

There are always `JACK-CHANNELS` history buffers for the input ports and `#PLUGINS` buffers for the active plugin objects allocated. The size of each history buffers is `#HISTORY-SIZE SFLOATS`. See for the config.frt file to change the default values. Each history holds several groups of `JACK-CHKSIZE SFLOATS` segments

History buffers

`: *N-HISTORY ( history idx -- addr ) #HISTORY-SIZE 1- AND SFLOATS + ;`
Calculates the address inthe history buffer

`: @IDX-HISTORY-DATA ( history idx -- ) ( F -- data ) *N-HISTORY SF@ ;`
Reads the audio data in the history buffer at position idx.

`: @HISTORY-DATA ( history offset -- ) ( F -- data ) #FJACK-SAMPLE SWAP - *N-HISTORY SF@ ;`
Reads the audio data in the history buffer relative to the current position in the audio stream.

`: MOVE-HISTORY-DATA ( historybuffer startoffset size target-addr -- )`
Copies size samples of audio data from the history buffer to the target buffer. The offset marks the end of data.

`: @INTERPOLATED-HISTORY-DATA \ ( historybuffer -- ) (F time-offset -- data )`
You may read the interpolated audio data from the history buffer by this, the `time-offset` is measured in seconds. a zero time offset always references to the currently processed sample in the input->output processing chain

so it is only valid there.

`: JACK-TIME? ( -- d )`
The time of the JACK demon is always 64bit, so for portability it's a double in Forth. The time is derived from the high resolution timer.

`: JACK-UNIQUE ( -- d )`
This is a unique double telling about the position in JACKs processing queue. See for more details in the libjack sources or API documentation, not much use for this in most situations.

`: JACK-POSITION ( -- u32 )`
The position in the audio data stream, it's an unsigned 32bit integer.

`: JACK-LOAD ( -- n )`
The JACK demon measures the time spent in the clients callback by using the high-resolution-timer and calculates the 'load' as it also knows the time between callbacks. The value n is the load in percent.

`: JACK-RUNNING? ( -- flag )`
To be used by the user application testing both the client id and the state given by the callback.

`: START-JACK-TRANSPORT ( -- )`
As the name says the JACK demon transport is started.

`: STOP-JACK-TRANSPORT ( -- )`
As the name says the JACK demon transport is stopped.

## Managing blocks of 'WAV' data

`0 VALUE WAV-PLAY-MODE`
When playing wav data the audio samples are inserted in the input->output procesing stream. This can be before or after the signal processing is done. `WAV-PLAY-MODE` is used to switch between these modes , n=0 means before processing.

`1 VALUE WAV-READ-MODE`
When recording wav data from the input->output processing stream the samples can be fetched from before or after are signal processing. `WAV-READ-MODE` is used to switch between these modes , n=0 means before processing.

So wav-playing and recording uses history buffers selected by the values of `WAV-PLAY-MODE` and `WAV-READ-MODE`. In this graphics using a value of 0 uses the green buffers, red buffers otherwise.

Wav playing and reading

`: CALC-WAV-RATE ( srate -- true-sample-rate )`
The sample rate conversion when playing or recording wav data uses a rather simple linear approximation algorithm, the used 'real' sample rates can be any `truerate = n * samplerate / JACK-CHKSIZE`. This ensures a small distortion and no glitches are in recorded or played data. Another point is: there are better buffersizes than others! When you want to use resampling, `CALC-WAV-RATE` tells the true sample rate calculated from the desired one.

`: CALC-WAV-BLOCK ( srate channels mode -- n )`
As told at `CALC-WAV-RATE` there are 'better buffersizes than others'. `CALC-WAV-BLOCK` gives a good suggestion what the block size should be or you better take a multiple of this size.

`: PLAY-WAV ( addr size rate channels mode -- id ?error )`
Plays WAV data available at an addr and a size. These data are not played immediately but are inserted into a FIFO 'slot' and will be played after all before playing commands have finished. When size is negative the FIFO is cleared before inserting this block into the FIFO so playing will start at once. More precise - it will start when the next `PROCESS-FRAMES` callback is taken. A negative channel number results in reversed channels when listening, playing wav files with only one channel will be played as stereo. Thew rate can be freely choosen, the mode can be any of the 8bit/16bit/32bit/32bit-float modes supported here. Named constants for these are defined in `JACKAUDIO` these are defined `STEREO MONO 8BIT-AUDIO 16BIT-AUDIO 32BIT-AUDIO SFLOAT-AUDIO`.

The 'id' can be used to test a block of wav data in the FIFO. See: `WAV-PLAYING? STOP-PLAY-WAV`, ?error tells about the status

- 0 -- everything was ok and id is 'legal'
- 1 -- not supported mode
- 2 -- too many channels
- 3 -- FIFO overflow
- 4 -- JACK is not running or has stopped

`: READ-WAV ( addr size rate channels mode -- id ?error )`
`READ-WAV` works as `PLAY-WAV` exept it reads the data from the audio stream and puts them into the buffer at addr. More info at `PLAY-WAV`

`: STOP-PLAY-WAV ( ms id -- )`
The data that had earlier been put into the play FIFO and had returned 'id' will stop

`: STOP-READ-WAV ( ms id -- )`
The data that had earlier been put into the read FIFO and had returned 'id' will stop

### Checking for blocks of wav data

`: WAV-PLAYING? ( id -- val )`
Checks the status of the played wav block 'id'. 'val' is the remaining time until this block is played completely or zero when the fifo block is unused. A typical piece of code code be

    ( id ) BEGIN DUP WAV-PLAYING? DUP MS 0= UNTIL DROP

`: WAV-READING? ( id -- val )`
Checks the status of the recorded wav block 'id'. 'val' is the remaining time until this block is recorded completely or zero when the fifo block is unused. See `WAV-PLAYING?`

## The Callbacks

These functions are not to be used in user applications. They are functions to be called by the callbacks defined for this client. They could be used by testing tools to measure the exact performance of the io system but so far no such tools exist.

`: XT-PROCESS-FRAMES ( frames parameter -- 0 )`
The main processing callback; must return 0. When initialising the client the jack demon starts a realtime thread, this thread later calls this callback and MUST NEVER use any forth word that might add some sort of delay longer than a few ms. Otherwise the client might be terminated or lots of xruns are signalled. So No semaphores! No disk-io! No terminal-io!

The `XT-PROCESS-FRAMES` does all the signal processing defined by you in the input->output processing slots. When you make your own plugins remember the above!

`: XT-GRAPH-REORDER ( 0 -- 0 )`
Whenever the jack demons processing graph is changed this callback is executed. This happens when ports are disconnected or a new jack application is starting. The user-defined `GRAPH-REORDER-HOOK ( -- )` is executed in this callback to allow you to watch the surrounding.

`: XT-PORT-CONNECT ( a b parameter flag 0 -- 0 )`
Whenever a port is connected or reconnected this callback is executed. You can find the fJACK ports with `>inport ( idx -- id )` and `>outport ( idx -- id)`, both words are in `JACKAUDIO`. idx is the channel, the returned id is unique and given by the jack demon. I won't give any details here how to use these id's or how to use the `PORT-CONNECT-HOOK` - go and read the jack manual, you will need deeper informations to make use of it.

Prototype for the client supplied function that is called whenever a client is registered or unregistered.

a: one of two ports connected or disconnected, b: one of two ports connected or disconnected

flag non-zero if ports were connected zero if ports were disconnected

The user defined function is executed via the `PORT-CONNECT-HOOK ( a b flag -- )`

`: XT-NEW-FRAMES ( fr parameter -- 0 )`
When some other client changes the chunksize this is told here. So far i don't know ANY client that does so

`: XT-NEW-SAMPLERATE ( sr parameter -- FALSE )`
The callback when other clients change the sampling rate for the jackd. See `JACK-SAMPLE-RATE`

`: XT-CLIENT-STOPPED ( parameter -- 0 )`
A client that is forced by some other client to shut down tells all it's registered clients about the new situation.

`: XT-COUNT-XRUNS ( parameter -- 0 )`
When the JACK demon gets an interrupt by the audio master clock to do new processing and the queue of callbacks of the last interrupt has not been fully processed, this condition is noted to all clients - it's called a 'XRUN'. See `JACK-XRUNS`

`: XT-NEW-TRANSPORT ( s p parameter -- f )`
A Repositioning callback, so far the position is not used.

`: XT-SERVER-ERROR ( str -- str )`
The callback function to print a jackd error message.

`: XT-SERVER-INFO ( str -- str )`
The callback to print a jackd information message.

## Connecting the ports

There are some graphical tools around to connect ports between the different JACK clients or the playback or capture ports. You may use these nice tools to connect any ports but how can you save and restore your configuration?

`: SAVE-CONNECTIONS ( addr cnt -- )`
writes a file specified by the name 'addr cnt' holding information about all ports connected to your fJACK client. This file can later be used with `LOAD-CONNECTIONS` and `CLEAR-CONNECTIONS`. Actually the file is a usual forth source.

Please make sure the directory fjack/connections has writing enabled for you.

`: CONNECT-JACKPORTS ( -- ) \ source destination`
Connects two ports, the portname are read from the input stream.

`: UNCONNECT-JACKPORTS ( -- ) \ source destination`
Disconnects two ports, the portname are read from the input stream.

`: CLEAR-CONNECTIONS ( -- )`
Unconnects all ports of the fJACK client.

`: LOAD-CONNECTIONS ( addr len -- )`
Connects all connections specified in the file.

`: UNLOAD-CONNECTIONS ( addr len -- )`
Disconnects all connections specified in the file.

`: JACK-INFO ( -- )`
Print information about the fJACK client. You may extend the display information by configuring `EXTENDED-JACK-INFO` to true. This is probably only usefull in debugging sessions.

`: .JACK-VERSION ( -- )`
prints the current fJACK description

`: JACK-PORTS ( -- )`
Prints information about all connections to the fJACK client.

`: JACK-SERVER-RUNNING? ( -- flag )`
flag is `TRUE` when a running jack server is available

## Running the fJACK client

`: START-JACK-CLIENT ( -- )`
Starts the fJACK client - this is done automatically when fjack is compiled and also via the `AtCold` hook. If the clients name is not unique - there could be another fJACK client running already - the jack demon might choose another name like client-01. This is totally OK as all client handling is done via the client structure.

The port connections also take care about this. There is one good reason to do so:
Different applications can all use the default client fJACK and don't have to care about other names. So you may start several Forth terminals and start a fJACK client, all these clients can share the connection files - the true client name is just hidden.

`: STOP-JACK-CLIENT ( -- )`
Stops the fJACK client running.

## The Extern Stream Toolbox

`: STREAM-EXTERN-FRAMES ( rate channels #frames in-xt out-xt -- left-#frames )`
Whe the fJACK client is not running you may stream audio data through the input->output processing chain. You have to tell the sample-rate, the number of channels and number of samples to be processed.

Also there is are no defined input and output mechanisms -- instead of using the data delivered and used by the jack demon you `must` define functions to deliver input data and do with the output data whatever you like.

The `in-xt ( addr channel #frames -- )` must fill the buffer at addr with your audio data for the specified channel, it must deliver #frames SFLOATS.

The `out-xt ( addr channel #frames -- )` must take the buffer at addr with the filtered audio data for the specified channel, it must use #frames SFLOATS.

`STREAM-EXTERN-FRAMES` returns the number of non-processed frames.

What can this be used for?

Let me give two examples - not implemented - for this. You could write an application that reads data from a wav file, does the desired processing and writes a new wav file. You could also use this mechanism to use the existing fjack framework for other hardware drivers.

Please note that this framework is in alpha state, i did only a few tests and it works, if you use it and and run into trouble, let me know and i'll fix it.

## Handling .wav Files

Some constants - in `JACKAUDIO` - for better readability

        2 CONSTANT STEREO
        1 CONSTANT MONO
        8 CONSTANT 8BIT-AUDIO
      #16 CONSTANT 16BIT-AUDIO
      #32 CONSTANT 32BIT-AUDIO
     #-32 CONSTANT SFLOAT-AUDIO

`1e0 FVALUE SPEEDUP \ Allow the caller to define pitching using fJACK resampling`
Allow the caller to define pitching in playing snippets and wav filesusing fJACK resampling.

As playing and recording of complete .wav files is done in a background thread is it sometimes conveniant to have a hook when the recording/playing is actually started or stopped in the thread. The windows vfx RichEdit device is not very stable in callbacks or threads, i suggest you should not write anything to the console. Especially `$0A EMIT` and `CR` make severe problems.

    DEFER BEGIN-OF-PLAYING          ' NOOP IS BEGIN-OF-PLAYING
    DEFER END-OF-PLAYING            ' NOOP IS END-OF-PLAYING
    DEFER BEGIN-OF-RECORDING        ' NOOP IS BEGIN-OF-RECORDING
    DEFER END-OF-RECORDING          ' NOOP IS END-OF-RECORDING

`: .WAV ( c-addr u -- )`
Plays the complete file defined by the parameters in a background thread.

`: .SILENTWAV ( c-addr u -- )`
Plays the complete file defined by the parameters in a background thread, if problems are detected no messages are printed.

`: .SOUND ( samplerate channels 8/16/32/-32 c-addr u -- )`
Play any file with specified parameters.

`: STOP-PLAYING ( -- )`
Any file already playing can be stopped by this command.

`: REPOSITION-PLAY-FILE ( position relative-flag -- )`
The played wav file may be repositioned during playing. If relative-flag is `TRUE` the position is relative to the current position, otherwise it's the absolute position. The 'position' always means a sample position, so you don't have to worry about channels and mode.

`: PLAY-FILE-POSITION ( -- position|-1 )`
This tells you the current position of the played wav file, it's also a sample postion so don't care about channels and mode. If the position is negative, there is no file played at the moment.

`: START-RECORDING ( time samplerate channels mode name namelen -- )`
Starts recording a .wav file with a given file name. Also the audio parameters must be specified. time is in seconds.

`: STOP-RECORDING ( -- )`
Stops .wav file recording.

`: RECORD-WAV ( time name len -- )`
Records a .wav file with the duration of time seconds and the given file name. audio parameters are `JACK-SAMPLE-RATE STEREO 16BIT-AUDIO`

`: RECORD-SIMPLE ( time name len -- )`
Records a .wav file with the duration of time seconds and the given file name. audio parameters are `16000 MONO 8BIT-AUDIO`

`: RECORD-FLOATS ( time name len -- )`
Records a .wav file with the duration of time seconds and the given file name. audio parameters are `JACK-SAMPLE-RATE STEREO SFLOAT-AUDIO`

`: WAV-PLAYING-ON? ( -- flag )`
flag is true when fJACK is already playing a .wav file.

`: WAV-RECORDING-ON? ( -- flag )`
flag is true when fJACK is already recording a .wav file.

`: SNIPPET ( c-addr u -- ) \ name`
Expects a filename on stack and creates a word 'name'. The file must be a wavfile, it's read into allocated memory. The runtime behaviour of the defined word is: play the audio data immediatly via the fJACK client.

Snippets are defined in a linked list; audio data are also available in turnkey applications as they are reloaded in the cold-chain.

## The FFTW3 library interface

This library can be tuned for optimized performance, this implementation currently supports the import of system wisdom files - see the fftw3 docs how to generate such a wisdom file.

Without such wisdom the best algorithm is just estimated, you can change this to one of the other methods in fftw3lib.frt.

`: CHECK-FFTW-SIZE ( n -- ok-mask ) \ sizes in fftw may be multiples of primes 2-13`
Checks the desired size of a fftw3 plan. Principally all sizes are suported but many ready-compiled libraries only support a limited number range. For all

n = 2*a * 3^b * 5^c * 7^d * 11^e * 13^f

the fftw3 library has algorithms available. The 'ok' is a bit-mask about a-f being >= 1, for probably impossible sizes %000000 is returned

    %000001-a, %000010-b, %000100-c, %001000-d, %010000-e, %100000-f

    %000001 has best algorithms

    %001110 still is good

    %110000 has existing algorithms in probably all compiled libraries but will be slower

`: WINDOWING-OFF ( struct )`
The input parameters for the signal analysis may be 'windowed', this switches windowing off.

`: HAMMING-WINDOW ( struct )`
The input parameters for the signal analysis may be 'windowed', this switches to 'hamming'

`: HANN-WINDOW ( struct )`
The input parameters for the signal analysis may be 'windowed', this switches to 'hann'

`: FFT-STRUCT ( n -- struct )`
When you want to to signal analysis using the fftw3 library you must define a forth struct that defines the interface to the fftw3 library. 'n' is the number of samples to be analysed, `FFT-STRUCT` defines the struct and returns a pointer to it. This struct pointer will be used by the next words.

Internally there are arrays for real parameter data and complex results at place, a fftw-plan is calculated. See `CHECK-FFTW-SIZE` for a discussion about possible sizes.

`: INVERSE-FFT-STRUCT ( n -- struct )`
When you want to to signal analysis using the fftw3 library you must define a forth struct that defines the interface to the fftw3 library. 'n' is the number of samples to be analysed, `INVERSE-FFT-STRUCT` defines the struct and returns a pointer to it. This struct pointer will be used by the next words.

Internally there are arrays for real parameter data and complex results at place, a fftw-plan is calculated. See `CHECK-FFTW-SIZE` for a discussion about possible sizes.

`: #FFT-SIZE ( struct -- #elements )`
tells the number of samples for this struct.

`: >FFT-COMPLEXDATA ( struct idx -- addr )`
Calculates the address in a `FFT-STRUCT` result complex datastructure or `INVERSE-FFT-STRUCT` input parameter complex datastructure.

All FFT data are of `DFLOAT` type and so must be accessed with `DF@ DF!` and friends. In complex number arrays the real-part is always at the lower address.

`: >FFT-DATA ( struct idx -- addr )`
Calculates the address in a `FFT-STRUCT` input parameter datastructure or `INVERSE-FFT-STRUCT` result datastructure.

`: CALCULATE-FFT ( struct )`
After storing the input data into the `FFT-STRUCT` parameter array you can do the signal analysis with `CALCULATE-FFT`.

`: CALCULATE-INVERSE-FFT ( struct )`
After storing the input data into the `INVERSE-FFT-STRUCT` complex parameter array you can do the signal

# The fJACK Input->Output Processing

You know that you can put audio processing plugin objects in any one of the slots, this module takes care of it. The order of processing in the jack-callback is like this:

Processing order

In effect all plugins can assume, that data in a lower slot number have been completely processed already.

## Defining the plugin objects

A plugin object is a data struct, some parts of this struct are the same in all plugin objects - see the client.frt source for details. These public parts are used by the plugin manager to take care about safety, setting parameters like frequency, quality and more.

Also the structs are 'connected' to other plugin objects or the input/output jack ports via plug_input and plug_output. basically a plugin object reads samples from the plug_input history buffer, does it's specific processing and writes data to the plug_input history buffer - in the graphics it's the red arrows. Also you may read data from other history buffers by words like `@HISTORY-DATA` and friends, see the green arrow and docs in the client manual.

Plugin objects

The fjack system knows some predefined plugin object types, when you write other plugins use numbers above #256 for your private applications or let me know to include them in here.

    $01 CONSTANT LOW-PASS
    $02 CONSTANT HIGH-PASS
    $03 CONSTANT BAND-PASS
    $04 CONSTANT BAND-STOP
    $05 CONSTANT ADAPTIVE
    $06 CONSTANT DECODER
    $07 CONSTANT SIN-TONE
    $08 CONSTANT DELAYER
    $09 CONSTANT AUTOLEVEL
    $0A CONSTANT USER-FIR
    $0B CONSTANT MIXER-PLUGIN
    $0C CONSTANT LESLIE-PLUGIN
    $0D CONSTANT PHASER-PLUGIN
    $0E CONSTANT ECHO&HALL-PLUGIN
    $0F CONSTANT VIBRATO-PLUGIN
    $10 CONSTANT EQUALIZER
    $11 CONSTANT EFFECTS-FIR

`\ CONSTANT #PRIVATE-DSP ( -- n )`
All plugin objects have some data in common, the public part of the objects struct is used by the plugin handler.

The common part of a plugin object holds predefined `DSP-VALUE`s, so when you are making a plugin object definer you must leave this public part in peace. So when defining the struct you should 'start with `#PRIVATE-DSP`.

`: REORDER-PLUGINS ( -- )`
It compresses the execution token list to a zero-terminated list for faster processing in the input->output processing chain.

## Using the plugin objects in the signal processing chain

`: LIST-PLUGINS ( -- )`
prints all objects plugged into the process chain.

`: LIST-ALL-PLUGINS`
prints information about all defined plugins. You may extend the display information by configuring `EXTENDED-JACK-INFO` to true. This is probably only usefull in debugging sessions.

`: REMOVE-JACK-PLUGIN ( filterobject -- )`
revoves the object from the process chain.

`: MAKE&ALLOCATE-PLUGIN-OBJECT ( initialize-xt dynmemsize objectsize -- object )`
Whenever you define a plugin object you MUST use this function to initialize it. 'size' is the objects size in bytes, the XT is the function to initialize the object.

Dynamic memory size is allocated and plug_dynmem is set.

This is done at compile time - so the object can be used at once - also this allows turnkey applications, as when booting all defined objects are initialized.

When developing your own plugins you can and definitly should use the automatic memory allocation, this is done before the initialize-xt is called.

`: SET-PLUGIN-BYPASS ( flag filterobject -- )`
You may set the objects bypass status. When the bypass flag is set - flag is `TRUE`, the plugin just passed the audio data to it's history buffer but does no processing on the data. See comments in `SET-JACK-PLUGIN`.

`: SET-JACK-PLUGIN ( filterobject slot channel -- )`
Puts the object in the slot/channel. channel must be between 0 and `JACK-CHANNELS-1`, slot must be between 0 and `JACK-IO-SLOTS`. If there are wrong parameters an abort message is displayed. If an object is already in use at that slot it is removed.

Please remember two things, at the moment you may only use `#PLUGINS` at the same time, the history buffers are allocated when starting fjack. `SET-JACK-PLUGIN` and `REMOVE-JACK-PLUGIN` change the processing order and clear the history buffers used. On slow machines the clearing might take some time resulting in audio drops when changing the plugin objects in use. To overcome this problems you could keep a plugin object in the processing chain and just toggle it's bypass status.

`: RECONNECT-PLUGIN ( history-buffer object/output-port -- )`
Due to the new input->output sheduler every plugin object or output port can get it's data from another history buffer. This function can be used to connect at runtime. See the example where the two dotted red lines show reconnected plugins, the green line shows a reconnected output port. You can get the address of the history buffer by `OBJECT-HISTORY`.

Reconnecting

`: LOCATE-JACK-PLUGIN ( object -- slot channel true | false )`
Gives information about the slot/channel for a specified object and a `TRUE` flag when the object was installed or `FALSE` when not found.

`: GET-PLUGIN-OBJECT ( slot channel -- 0|filterobject )`
Gives the object found in slot/channel, when no object has been placed there with `SET-JACK-PLUGIN` a `FALSE` flag is returned.

`: SET-OBJ-FREQUENCY ( frequency object -- )`
Many plugins have a specified tune-to-frequency function available, you can use this to do so. This sets the frequency of the specified object, the object itself known what do do, f.e. filters will be tuned to the specified frequency. A few object types have to frequencies, `BAND-PASS BAND-STOP` filters expect two integers as a special case.

`: SET-OBJ-FLOAT-FREQUENCY ( object -- ) ( F: frequency -- )`
In many situations the precision of `SET-OBJ-FREQUENCY` is not good enough, then you can set the frequency by this. BEWARE: ONLY ONE parameter possible as float!

`: SET-OBJ-QUALITY ( quality object -- )`
Many plugins have a quality - in notch filters this would be the sharpness in FIR and adaptive filters this will be the number of taps. This functions handles the objects quality in a general way so look for the special plugin docs. The effect of setting the quality can be viewed in the fft display plugin, here is a band filter with a lowpass set to ~1.5kHz with 41 and 125 poles

lowquality

high quality

`: SET-OBJ-LEVEL \ ( object -- ) (F level -- )`
All plugin objects have a specific level value this word sets it.

`: SLOT/CHANNEL-HISTORY ( slot channel -- history )`
Finds the history address of a slot/channel pair, if the slot is less than 0 it always means the input port. If a slots object is undefined the result is 0.

`: CALCULATE-FILTER-DELAY ( slot1 slot2 channel -- n )`
Calculates the phase delay in the processing chain between 2 slots for a given channel, the result is the phase shift measured in samples.

`: OBJ-BENCHMARK ( object -- )`
You can measure the performance of any filter plugin with this, define any sort of filter object and pass the object to this tool.

## The Group of Finite Impulse Response Filters

`: MAKE-FIR-FILTER ( filtype size -- object )`
Constructs a linear-phase FIR filter object and leave it's address. 'type' can be `LOW-PASS HIGH-PASS BAND-PASS BAND-STOP USER-FIR`, the 'size' is the number of taps corrected to odd. FIR filters add a signal delay by half the number of taps.

You may select a different number of taps later via `SET-OBJ-QUALITY ( taps object -- )`, also you might change the frequency response of this filter by `SET-FIR-TUNING`.

`BAND-PASS BAND-STOP USER-FIR` filters and the `SET-FIR-TUNING SET-FIR-WINDOWING SET-FIR-COEFF` are only possible when the fftw3 library is installed.

`: FIR-FILTER: ( type size -- ) \ name`
Defines a named `MAKE-FIR-FILTER` plugin object, calling 'name' returns the object address.

`: MAKE-EQUALIZER ( size -- object )`
Define an linear phase equalizer object with size taps corrected to odd, it's a special type of the generic FIR filter. It offers 256 frequency bands in the 0-JACK-SAMPLE-RATE/2 range, each band has it's own defined level. You can set these levels by `SET-EQUALIZER-BAND` and `SET-EQUALIZER-RANGE`. You may also select a different number of taps later via `SET-OBJ-QUALITY ( taps object -- )`.

For iForth users only: the showfft module now can directly control a bound equalizer filter, see `SET-FFT-EQUALIZER` in the gui/showfft module.

`: EQUALIZER: ( size -- )`
Defines a named `MAKE-EQUALIZER` plugin object, calling 'name' returns the object address.

`: SET-EQUALIZER-BAND \ ( object -- ) (F dBlevel frequency -- )`
Sets the level for the specified frequency in the equalizer object and calculates the filter coefficients.

`: SET-EQUALIZER-RANGE \ ( object -- ) (F dBlevel1 frequency1 dBlevel2 frequency2 -- )`
Sets a linear level curve between the level/frequency pairs in for the equalizer objects levels and calculates the filter coefficients. At least one point is set.

`: SET-EQUALIZER-MODE ( mode object -- )`
Sets the approximation mode for `SET-EQUALIZER-RANGE`, it can be either 0 for linear or 1 for sinoid mode.

`: EXPORT-EQUALIZER ( name len object -- )`
Exports the equalizer setings to a file

`: IMPORT-EQUALIZER ( name len object -- )`
Imports the equalizer setings from a file

`: SET-FIR-WINDOWING ( windowmode object -- )`
Calculating the filter coefficents is done with a IFFT algorithm using a windowing function. This windowing function can be set for each filter with `SET-FIR-WINDOWING`. See the literature for descriptions of these windowing functions. The default is set by `DEFAULT-FIR-WINDOW`.

The blackmann window `0` gives the deepest out-of-band suppression with a modest steepness.

The hamming window `1` has a steeper flank with less out of band suppression

The rectangle window `2` has the steepest flank, highest ripple and lowest out-of-band suppression.

`: SET-FIR-TUNING ( 0|tuning-xt object -- )`
The `MAKE-FIR-FILTER`s frequency response curve of each filter can be tuned to your needs by adding a tuning-function-xt describing the desired freuency response. The function must have this stack effect:

    (F level frequency -- your-level )

It must be able to return values for frequencies from 0 to sample-rate/2.

`: SET-FIR-COEFF ( 0|set-coeff-xt object -- )`
The `USER-FIR MAKE-FIR-FILTER` is a very special type of FIR filter, the dsp algorithm is the same but there are many situations where you don't want to specify a frequency response of the filter but want to add effects like hall, echo, delay, averagers and more.

To use this sort of filter you will need to think about the way the filter coefficients are calculated. Whenever the filter is tuned, resized or defined there is the default function that sets x[0] to 1.0e0, all others are zero. To define a filter according to your needs you will have to tell the coefficient-calculating-function execution token xt. The calculating function must take two integer parameters `( number-of-filtertaps index)` and must return the float `(F -- coefficient)` for that tap. This automatically set the filter size, so don't use `SET-OBJ-QUALITY` after calculating. The maximum number of taps is `#FIR_BUFF` so when you need a larger range think of the generic effects plugin.

The graphics shows the signal flow, the number of taps is the number of multipliers.

The generic FIR filter signal flow

## The Adaptive Filter object

`: MAKE-ADAPTIVE-FILTER ( size -- object )`
Constructs an adaptive filter object and leave it's address, the 'size' is the number of taps corrected to even. Adaptive filters add a signal delay by half the number of taps. This filter uses a simple 'least mean square' algorithm.

You may select a different number of taps later via `SET-OBJ-QUALITY ( taps object -- )`.

`: ADAPTIVE-FILTER: ( n -- ) \ name`
Defines a named adaptive plugin object, calling 'name' returns the object address.

`: SET-FREEZE-ADAPTIVE ( flag object -- )`
You can freeze the adaptive filter coefficients - this is usefull when you have 'tuned' to a noise signal and want to stay with this filter. `FALSE` will continue adapting otherwise it will be frozen. As changing the filter qaulity means other coefficients `SET-OBJ-QUALITY` for an adaptive filter always unfreezes it.

`: SET-ADAPTIVE-SPEED ( n object -- )`
Sets the speed of the adapting algorithm, 0-100 are accepted.

## The Infinite Impulse Response Filter

`: MAKE-IIR-FILTER ( type -- filter)`
Constructs a 10pole IIR-FILTER (Butterworth) plugin object and leaves the address of the object. The freqency of this filter can be set as usual with `SET-OBJ-FREQUENCY` the quality (or sharpness) of the filter with `SET-OBJ-QUALITY`

`: IIR-FILTER: ( type -- ) \ name`
Defines a named iir-filter plugin object, calling 'name' returns the object address.

## The FFT Analyser Plugin

Quite often you will have to do a signal analysis of your audio signals somewhere in the input->output processing chain. You can define such an analyser plugin with `MAKE-FFT-PORT` and can always do an ad-hoc real time analysis of the signal.

This plugin does an fft analysis, avaraging of the spectrum, finds maxima and the average level in a defined frequency range. In the background this uses the fftw3 library.

`: FFT-PORT-SIZE ( fftport -- size )`
Tells the size of the port.

`: FFT-HAMMING ( mode fftport )`
Changes the 'windowing' function of the analyser port; 0 means no windowing, 1 is hamming and 2 hann.

`: FFT-ANARANGE ( low-frequency high-frequency fftport -- )`
Sets the frequency range in which the average signal level is calculated.

`: FFT-GET-ANARANGE ( fftport -- low-frequency-index high-frequency-index )`
Gets the frequency range for average analysis.

`: MAKE-FFT-PORT ( size -- fftport )`
Define a fft-port, this can be used as a plugin in the processing chain. For the iForth system there is a fft viewing module available `FFT-VIEWPORT:` that works perfectly with fft-ports.

The FFT viewer

`: FFT-PORT: \ ( size -- ) name`
Defines a named fft-port.

`: FFT-ANALYSIS ( fftport -- )`
Does an fft analysis of the last audio data in the stream plus avaraging and maxima finding.

`: @FFT-dB-LAST \ ( fftport idx -- ) (F -- level-dB )`
gets the average level for the last 8 `FFT-ANALYSIS` for this port.

`: @FFT-dB-AV \ ( fftport idx -- ) (F -- average-dB )`
gets the average level for the last 8 `FFT-ANALYSIS` for this port.

`: FFT-MAXIMUM? \ ( fftport idx -- flag )`
returns `TRUE` when a maximum is detected at this point.

`: FFT-GREATEST-MAXIMUM \ ( fftport -- index ) (F -- level )`
Finds the greatest maximum for the port and returns the index.

`: FIND-AVERAGE-LEVEL \ ( fftport -- ) (F -- avlevel )`
returns the average signal level in the specified frequency range measured in dB

`: FFT-IDX>FREQU \ ( index fftport -- frequency )`
Converts index for this port to frequency.

`: FFT-FREQU>IDX \ ( frequency fftport -- idx fftport )`
Converts frequency for this port to index, the port kept on the stack as this is most often used later.

`: SET-FFT-DELAY ( delay fftport -- )`
The fft analyser allows a delay in the history to compensate in fft displays.

## The Channel-Mixer (and processing) plugin object.

Allows mixing and processing of audio data.

`: MAKE-MIXER ( -- object )`
Construct a mixer plugin object and leave it's address. The value in the processing stream is calculated by the presented value plus all other slots/channels that have been added to the mixing by `SET-MIXER-LEVEL`. `SET-OBJ-LEVEL` sets the level of the original source of this plugin.

The standard way to mix the audio data is just adding all values. There is a special feature here to do some more tricks on the data, you may replace the 'adding' function by some other word with `SET-MIXER-ACTION`.

`: MIXER:`
Creates a named mixer plugin.

`: SET-MIXER-INPUT \ ( slot channel mixer -- ) (F level delay -- )`
Sets the level and delaytime (seconds) in the mixer. A slot-number <0 means the input port. You can only mix data from smaller slots than the mixer objects slot. The graph shows the mixer inputs

Mixer sources

`: SET-MIXER-ACTION ( action-xt object -- )`
This replaces the default 'adding' function of a mixer plugin object by another one.

The stack effect of the new function must be

    : my-function ( array cnt -- ) (F -- value )

The array holds cnt sfloats of input data read from all the activated mixer channels, you can do whatever you want to do with these data but you MUST take the parameters and MUST leave the floating result. All data have already been changed to the desired level, the first position in the array holds the original input stream to this slot.

`: .MIXER-INFO ( object -- )`
Show the status of the mixer object; level is absolute; delay measured in seconds.

## The generic Effect Filter

Allows the user defined definitions of effects. The generic effect plugin is just a special type of FIR filter, the dsp algorithm is the same but the coefficients are not calculated from a defined frequency response. So the `SET-OBJECT-FREQUENCY` tool is undefined, instead it uses a callback function defining the coefficient for each tap number.

`: DEFINE-EFFECT-FILTER ( calc-xt|0 object -- )`
calculates the effect filter coefficients for a given plugin object with the calculating function xt. The calculating function must take two integer parameters `( number-of-filtertaps index -- )` and must return the float `(F -- coefficient)` value for the index tap. When `DEFINE-EFFECT-FILTER` is executed, it calls the function for every tap from 0 to {#HISTORY-SIZE}, so the default setting will allow processing in the ~3 seconds range for CD sampling rate. When the xt is `FALSE` the effects filter is 'just-do-nothing'.

`: MAKE-EFFECT-FILTER ( -- object )`
Constructs an effects plugin object leaves it's address. Calculation of the filter coefficients is done with `DEFINE-EFFECT-FILTER`.

This word is meant for user extensions like hall and echo effects, combs ... let's see what we will make out of it.

# Some tests

Some working plugins found in fjack/examples are here for you to start. All the plugins defined here and the test suite are NOT included in the default fjack module.

## The Sinus Tone Oszillator Object, a detailed example for writing plugin objects

When writing more plugins read this and the `types.frt` carefully, also you can use the `prototype.frt` as a starting point.

Words that are used inside the object should be defined in the `JACKAUDIO` vocabulary.

    ALSO JACKAUDIO ALSO DEFINITIONS

Now a pointer to a counted text should be defined, later this is set to the `plug_type` object-element; it's there for a) making the plug_type defined and b) the `LIST-PLUGINS` and `LIST-ALL-PLUGINS` tools gives more detailed information.

    HERE ," SINUS oscillator" CONSTANT #sin-id
    #PRIVATE-DSP
            DSP-FVALUE sin_phase
            DSP-FVALUE sin_step
            CONSTANT #sinstruct

Then the object elements are defined and the size of the whole object struct is made a `CONSTANT`

`: CHK-SIN #sin-id plug_type <> ABORT" Invalid SINUS-TONE object" ;`
Check for a correct plug_type and aborts when this not ok

Each object type MUST have a specified signal processing funtion; the execution token of this function is stored in the `plug_xt` element. The funcion MUST take one `FLOAT` as a parameter and MUST leave one `FLOAT` as a result. So the depth of the floating stack must never be changed.

    : calc_sin_val  \ ( -- ) (F val -- val' )
            sin_step sin_phase F+ REDUCE.2PI FDUP TO sin_phase FSIN plug_level F* F+ ;

Before you start writing your own audio-data-processing code remember that

- the code is executed in a JACK demon callback
- the code MUST exit with a correct stack and floating stack
- the code MUST NEVER do anything that might give larger delays than a few usecs
- the code MUST NEVER do text/graphics output, file writing, use semaphores
- the JACK demon will halt the client as 'zombified' when delay is too large

Whenever you want to do things like that: FORGET ABOUT THEM in the process function. What you could and should do: Write thread-safe buffering functions!

You may watch the jack performance with two included tools, `JACK-LOAD` and `JACK-XRUNS`.

Many - as this example plugin - can be tuned to a frequency; the io_procs module implements a generic tuning word `SET-PLUGIN-FREQUENCY` which calls a function defined in the object making phase.

    : (tune-sine-object)    ( frequency -- )
            FDUP TO plug_frequency PI F* F2* JACK-SAMPLE-RATE S>F F/ TO sin_step ;

Every object definer needs a function that initialises the plugin object when it is defined and also in the turnkey bootstrap word `INIT-ALL-JACK-OBJECTS`. If - in some cases - there is no such function needed `MAKE&ALLOCATE-PLUGIN-OBJECT` must be given 0.

    : (init-sine-object)
             ; \ nothing to do; no allocation

Now you can make an object-definer, as this should be public you should switch to `FORTH` before.

    FORTH DEFINITIONS
    : MAKE-SINE-OSCILLATOR  ( -- addr )     \ Create a sinus oszillator struct
            \ Make an object and make it the 'current' object
            ['] (init-sine-object) 0 #sinstruct MAKE&ALLOCATE-PLUGIN-OBJECT
            \ Set the correct plug_type and set a plug_filtype mode
            #sin-id TO plug_type  SIN-TONE TO plug_filtype
            \ set the execution token of the signal processing function
            ['] calc_sin_val TO plug_xt
            \ set the tuning function
            ['] (tune-sine-object) TO plug_xt_tune
            \ these data can be permanent
            0e0 TO sin_step  0e0 TO sin_phase
            \ leave the 'current' object on the stack
            @DSP ;

    \ A more simple definer makes the object and defines it as a constant
    : SINE-OSCILLATOR:      ( -- ) \ name
            MAKE-SINE-OSCILLATOR CONSTANT ;

    PREVIOUS PREVIOUS DEFINITIONS

## A Bank of notch filters

Implements a bank of notch IIR butterworth filters, the slots 15-22 in a channel are used

`8 CONSTANT #NOTCHES`
The number of notch filters available

`: GET-FREE-NOTCH ( -- object flag )`
Try to get a notch filter object from a bunch of 8, if all notches are already in use flag is `FALSE`.

`: NOTCH-THERE? ( frequ channel -- object flag )`
checks for an already used notch filter with frequency - or very close to. If such a notch is plugged in, the object and a `TRUE` flag are returned.

`: SET-NOTCH-FILTER \ ( frequ channel -- )`
Sets a notch filter from a bunch of 8. If there is a notch already plugged in it is switched off.

`: CLEAR-ALL-NOTCHES ( -- )`
removes all notches from the processing queue.

## The Delayer Object

This can add an echo to the current signal, the level of the echo and the original signal can be set.

`: MAKE-DELAYER ( -- object )`
Construct a delayer object and leave it's address.

`: DELAYER: ( -- ) \ name`
Define a named delayer object

`: SET-DELAY-TIME ( useconds object -- )`
Sets the dapay time for the delayer object. Time in usec.

`: SET-DELAY-LEVELS \ ( object -- ) (F delayed-level now-level -- )`
Sets the signal levels for a delayer object; both level must be floats.

## A Vibrato effect - you can select the vibrato frequency and the strength.

`: MAKE-VIBRATO ( -- addr )`
Make a vibrato effect plugin object and leave a pointer to it. When setting the frequency by `SET-OBJ-FREQUENCY` the argument is the frequency*1000 to allow more precise settings.

The vibrato strength is set as usual by the `SET-OBJ-LEVEL` method.

`: VIBRATO: ( -- ) \ name`
make a named vibrato effect plugin

## The Autolevel Object

This set the `JACK-IO-LEVEL` to a moderate level.

`: MAKE-AUTOLEVELER ( -- object )`
Construct a autolevel object and leave it's address.

`: AUTOLEVELER: \ ( -- ) name`
Define a named autolevel object

## The Phaser Object

The phaser plugin emulates a phaser/flanger. You can control the timing of the shifted signal, the timing is also modulated by an oszillator.

`: MAKE-PHASER ( -- object )`
Construct a phaser object and leave it's address. The default settings are a timeshift of 10msec, a strength of 0.2 and an oszillating speed of 5Hz.

`: PHASER: ( -- ) \ name`
Define a named delayer object

`: SET-PHASER-PARAMETERS \ ( object -- ) (F frequ strength timeshift -- )`
Sets parameters for the phaser object.

The strength may be choosen from 0 to 1, this controls the oszillating amount, the default of 0.2 is already pretty strong.

Timeshift in milliseconds, the maximum depends on the history size, probably up to 100 msecs are usefull.

frequency controls the shift oszillator in Hz.

`: JACK-BENCHMARK ( -- )`
A little fjack processing benchmark