routes.lib

Routing library. Its official prefix is ro.

This library provides tools for managing and organizing audio and control signal routing in Faust. It includes functions for channel mapping, splitting, merging, and dynamic routing, as well as utilities for building multichannel processing structures.

The Routes library is organized into 1 section:

References

Functions Reference


(ro.)cross

Cross N signals: (x1,x2,..,xn) -> (xn,..,x2,x1). cross is a standard Faust function.

Usage

cross(N)
_,_,_ : cross(3) : _,_,_

Where:

  • N: number of signals (int, as a constant numerical expression)

Test

ro = library("routes.lib");
os = library("oscillators.lib");
cross_test = (os.osc(200), os.osc(300), os.osc(400)) : ro.cross(3);

Note

Special case: cross2:

cross2 = _,cross(2),_;

(ro.)crossnn

Cross two bus(N)s.

Usage

(si.bus(2*N)) : crossnn(N) : (si.bus(2*N))

Where:

  • N: the number of signals in the bus (int, as a constant numerical expression)

Test

ro = library("routes.lib");
os = library("oscillators.lib");
crossnn_test = (os.osc(110), os.osc(220), os.osc(330), os.osc(440)) : ro.crossnn(2);

(ro.)crossn1

Cross bus(N) and bus(1).

Usage

(si.bus(N),_) : crossn1(N) : (_,si.bus(N))

Where:

  • N: the number of signals in the first bus (int, as a constant numerical expression)

Test

ro = library("routes.lib");
os = library("oscillators.lib");
crossn1_test = (os.osc(100), os.osc(200), os.osc(300), os.osc(400)) : ro.crossn1(3);

(ro.)cross1n

Cross bus(1) and bus(N).

Usage

(_,si.bus(N)) : crossn1(N) : (si.bus(N),_)

Where:

  • N: the number of signals in the second bus (int, as a constant numerical expression)

Test

ro = library("routes.lib");
os = library("oscillators.lib");
cross1n_test = (os.osc(150), os.osc(250), os.osc(350), os.osc(450)) : ro.cross1n(3);

(ro.)crossNM

Cross bus(N) and bus(M).

Usage

(si.bus(N),si.bus(M)) : crossNM(N,M) : (si.bus(M),si.bus(N))

Where:

  • N: the number of signals in the first bus (int, as a constant numerical expression)
  • M: the number of signals in the second bus (int, as a constant numerical expression)

Test

ro = library("routes.lib");
os = library("oscillators.lib");
crossNM_test = (os.osc(180), os.osc(280), os.osc(380), os.osc(480), os.osc(580)) : ro.crossNM(2,3);

(ro.)interleave

Interleave R x C cables from column order to row order. That is, transpose the input CxR matrix, the first R inputs is the first row.

input : x(0), x(1), x(2) ..., x(row*col-1)

output: x(0+0*row), x(0+1*row), x(0+2*row), ..., x(1+0*row), x(1+1*row), x(1+2*row), ...

Usage

si.bus(R*C) : interleave(R,C) : si.bus(R*C)

Where:

  • R: row length (int, as a constant numerical expression)
  • C: column length (int, as a constant numerical expression)

Test

ro = library("routes.lib");
os = library("oscillators.lib");
interleave_test = (os.osc(200), os.osc(300), os.osc(400), os.osc(500)) : ro.interleave(2,2);

(ro.)butterfly

Addition (first half) then substraction (second half) of interleaved signals.

Usage

si.bus(N) : butterfly(N) : si.bus(N)

Where:

  • N: size of the butterfly (N is int, even and as a constant numerical expression)

Test

ro = library("routes.lib");
os = library("oscillators.lib");
butterfly_test = (os.osc(250), os.osc(350), os.osc(450), os.osc(550)) : ro.butterfly(4);

(ro.)hadamard

Hadamard matrix function of size N = 2^k.

Usage

si.bus(N) : hadamard(N) : si.bus(N)

Where:

  • N: 2^k, size of the matrix (int, as a constant numerical expression)

Test

ro = library("routes.lib");
os = library("oscillators.lib");
hadamard_test = (os.osc(220), os.osc(330), os.osc(440), os.osc(550)) : ro.hadamard(4);

(ro.)recursivize

Create a recursion from two arbitrary processors p and q.

Usage

_,_ : recursivize(p,q) : _,_

Where:

  • p: the forward arbitrary processor
  • q: the feedback arbitrary processor

Test

ro = library("routes.lib");
os = library("oscillators.lib");
recursivize_test = (os.osc(220), os.osc(330)) : ro.recursivize(*(0.5), *(0.3));

(ro.)bubbleSort

Sort a set of N parallel signals in ascending order on-the-fly through the Bubble Sort algorithm.

Mechanism: having a set of N parallel signals indexed from 0 to N - 1, compare the first pair of signals and swap them if sig[0] > sig[1]; repeat the pair comparison for the signals sig[1] and sig[2], then again recursively until reaching the signals sig[N - 2] and sig[N - 1]; by the end, the largest element in the set will be placed last; repeat the process for the remaining N - 1 signals until there is a single pair left.

Note that this implementation will always perform the worst-case computation, O(n^2).

Even though the Bubble Sort algorithm is one of the least efficient ones, it is a useful example of how automatic sorting can be implemented at the signal level.

Usage

si.bus(N) : bubbleSort(N) : si.bus(N)

Where:

  • N: the number of signals to be sorted (must be an int >= 0, as a constant numerical expression)

Test

ro = library("routes.lib");
bubbleSort_test = (
    hslider("bubbleSort:x0", 0.3, -1, 1, 0.01),
    hslider("bubbleSort:x1", -0.2, -1, 1, 0.01),
    hslider("bubbleSort:x2", 0.8, -1, 1, 0.01),
    hslider("bubbleSort:x3", -0.5, -1, 1, 0.01)
) : ro.bubbleSort(4);

References


(ro.)bitonicSort

A bitonic sorter is a parallel sorting network that performs comparisons and swaps on signal pairs iteratively. The pairs are selected according to different index gaps determined by the current state and pass indices, while the sorting direction of each pair depends on the current stage index.

The algorithm first builds a bitonic sequence with the input values, that is, a sequence that is ascending for the first half, and descending for the second half. Then, it applies a bitonic merger to sort the bitonic list in ascending or descending order.

The algorithm has O(log2(N) ^ 2) depth complexity, and O(N * log2(N) ^ 2) work complexity. Specifically, the bitonic sorter algorithm requires N inputs to be a power-of-two. The algorithm has a total of log2(N) * ((log2(N) + 1) / 2) stages, and each stage requires N / 2 comparators. Each comparator has one min() and one max() function.

For comparison, the Bubble Sort algorithm has N - 1 stages, and N * (N - 1) / 2 comparators. For N = 32, Bitonic Sort has 15 stages and 240 comparators, Bubble Sort has 31 stages and 496 comparators.

The sorting process is zero-latency.

Usage

si.bus(N) : bitonicSort(N) : si.bus(N)

Where:

  • N: the number of signals to be sorted (it must be a power-of-two compile-time numerical expression)

Test

ro = library("routes.lib");
bitonicSort_test = (
    hslider("bubbleSort:x0", 0.3, -1, 1, 0.01),
    hslider("bubbleSort:x1", -0.2, -1, 1, 0.01),
    hslider("bubbleSort:x2", 0.8, -1, 1, 0.01),
    hslider("bubbleSort:x3", -0.5, -1, 1, 0.01)
) : ro.bitonicSort(4);

References


(ro.)bitonicSortIdx

This function is based on the bitonicSort function, except it returns the set of indices for the ordered input values. This is useful if you want to sort one set based on another one.

Usage

si.bus(N) : bitonicSortIdx(N) : si.bus(N)

Where:

  • N: the number of signals to be sorted (it must be a power-of-two compile-time numerical expression)

Test

ro = library("routes.lib");
bitonicSortIdx_test = (
    hslider("bubbleSort:x0", 0.3, -1, 1, 0.01),
    hslider("bubbleSort:x1", -0.2, -1, 1, 0.01),
    hslider("bubbleSort:x2", 0.8, -1, 1, 0.01),
    hslider("bubbleSort:x3", -0.5, -1, 1, 0.01)
) : ro.bitonicSortIdx(4);

References