Pipe Specification
Pipe Specification
The Pipe Specification (data field "pipeSpec" in Job Description) describes audio input, audio output and audio routing (a.k.a. mixing).
JSON Structure
"pipeSpec": {
"inputGraph": [
{
...
}
],
"outputGraph": [
{
...
},
{
...
}
],
"mixer": {
...
}
}
Field | Description |
---|---|
inputGraph | An array of specifications for audio input graphs. The array should not be empty, otherwise there will be no input to process. |
outputGraph | An array of specifications for audio output graphs. The array can contain an arbitrary number of graphs (including zero, which means that all input is discarded). |
mixer | Definition of how the input data are mixed and routed to the output graphs. The mixer specification is optional - meaning it can be omitted to get a default routing, which can be applied to the most trivial input/output configurations. For more details see below in Mixer - Default Routing. |
Input and Output Graph Specification
The elements of the inputGraph
and outputGraph
arrays have the same structure:
JSON Structure
{
"name": "...",
"format": {
"sampleRate": "...",
"resolution": "...",
"channels": "..."
},
"startOffset": "hh:mm:ss.sss",
"duration": "hh:mm:ss.sss",
"filter": [
{
},
{
}
]
}
Field | Description |
---|---|
name | The name of the graph. This name must be unique for the whole PipeSpec, because it is used in the mixer specification to refer to this graph. |
format | For output graphs only: Specify the audio format, which is generated for the graph. The format is always linear audio (PCM).
|
startOffset | Optional, for input graphs only: If you have a single input graph, and a "FileReader" as source filter, you can specify a start offset and/or a duration. Audio streaming will start at the given offset into the source file, and will run for the specified duration. If the duration is omitted, it will run to to end of the source file. Note: This is a special shortcut to simplify playout of a specific part of a file. It will not work for live sources (a.g. ASIO or WASAPI) or web stream sources. |
filter | An array of one or more filter specifications, which describe the physical properties (audio sources and destinations) of the graph. |
Filter Specification
JSON Structure
{
"name": "...",
"id": "..."
...
}
Field | Description |
---|---|
name | The name describes, which type of filter is to be used. There is a fixed list of filter types known to ROAD. This list will be extended as the capabilities of ROAD grow, and currently consists of these filter names:
|
id | Optional ID, which is only necessary, if the filter is to be addressed with the filterSettings API; if set, the ID must be unique within the pipe specification |
... | All other fields of the filter specification are specific to the various filter types, as described in the pages for the filters. |
Mixer Specification
The mixer specification defines, which input audio data is delivered to which output (a.k.a. "routing"). Additionally, audio levels can be adjusted at the input and/or output side. The mixer specification can be changed while a ROAD job is running. I.e., you can send transitions, which have a PipeSpec which contains only a mixer specification. The new mixer spec will then be applied beginning with the next incoming input data.
JSON Structure
{
"inputLevel": [
{
...
}
],
"outputLevel": [
{
...
},
{
...
}
],
"inputLevelFilter": [
{
...
}
],
"outputLevelFilter": [
{
...
}
],
"route": [
{
...
},
{
...
}
]
}
Field | Description |
---|---|
inputLevel | An array of IO level specifications. Each of these specs handles one input graph. |
outputLevel | An array of IO level specifications. Each of these specs handles one output graph. |
inputLevelFilter | An array of level filter specifications. Each of these specs handles one input graph |
outputLevelFilter | An array of level filter specifications. Each of these specs handles one output graph |
route | An array of audio routes, defining one mapping of input data to output data. |
IO Level Specification
Input and output level specifications can be used to define attenuation or amplification of audio data by the mixer.
JSON Structure
{
"graph": "...",
"level": ...
}
or
JSON Structure
{
"graph": "...",
"level": [
...
],
"fadeCurve": [
{
"point": [
{
"time": "hh:mm:ss.sss",
"level": ...
},
...
]
},
...
]
}
Field | Description |
---|---|
graph | Name of the graph, to which this level specification applies. |
level | This can either be a single floating point value, or an array of floating point values.
|
fadeCurve | This is optional, and can be either a single object, or an array of objects.
A fade curve is specified by the array "point", which defines a sequence of points in time ("time") with an associated linear audio amplification ("level").
|
Level Filter Specification
A level filter, also known as a level trigger, is a means to control the audio throughput on a graph depending on the level of the audio signal. The general idea is that audio is only passed through by this filter, if there isn't just silence on the input side. Most parameters control what is perceived as "silence" by the filter.
JSON Structure
{
"graph": "...",
"channels": "...",
"startSignalLevelDb": ...,
"startSignalDurationMs": ...,
"startDelayMs": ...,
"fadeInStartLevelDb": ...,
"fadeInDurationMs": ...,
"stopSignalLevelDb": ...,
"stopSignalDurationMs": ...,
"stopAction": "...",
"active": true/false,
"inactiveState": "open"/"closed"
}
Field | Description |
---|---|
graph | Name of the graph, to which this level filter specification applies. |
channels | Comma-separated list of channel numbers (0-based). Audio from these channels is used by the level filter, all other channels of the graph are ignored. The parameter is optional, if it is not set (or explicitly set to an empty list), audio from all channels of the specified graph is used. |
startSignalLevelDb | Floating point value, which defines the audio level in dB, which shall trigger the start of the audio on the output side. |
startSignalDurationMs | Duration in milliseconds, for which the audio signal must be above the threshold defined by "startSignalLevel" to create a valid start trigger. |
startDelayMs | A "delay" in milliseconds. The parameter is optional, the default is 0.
|
fadeInStartLevelDb | See note on fade-in; the parameter is optional, default is 0 |
fadeInDurationMs | See note on fade-in; the parameter is optional, default is 0 |
stopSignalLevelDb | Floating point value, which defines the audio level in dB, which shall trigger the stop of audio on the output side, when the input level falls below it. The parameter is optional, with a default of 0 (which means don't stop at all) |
stopSignalDurationMs | Duration in milliseconds, for which the audio signal must be below the threshold defined by "stopSignalLevel" to create a valid stop trigger. The parameter is mandatory only if "stopSignalLevelDb" is not 0. |
stopAction | A string, which defines what happens with the running ROAD job after a stop trigger has been received. There are three possible values:
The parameter is optional, the default is "continue". |
active | Can be used to switch a level filter on ("active" = true ) or off ("active" = false ) during a running job. In the filter is switched off, its state is defined by field "inactiveState". The parameter is optional, default is false . |
inactiveState | Either "open" or "closed" . If "active" = false , this parameter defines if the filter is permanently open or closed. For "active" = true , the value is ignored. The parameter is optional, default is "open" . |
Notes:
- The dB levels are relative to digital 0 dB Full Scale. Therefore, the values are always negative.
- A negative "startDelayMs" is implemented by buffering the audio on the input side, so that samples from the past can still be delivered as soon as the start signal is detected. If filters further downstream in the graph are real-time filters (e.g. audio output as opposed to output to a file), the signal at the end of the output graph will be permanently delayed by the time given in "startDelayMs".
- Fade-in: Optionally, a linear fade can be applied to the first delivered audio after the start trigger has been detected. If "fadeInStartLevelDb" is < 0 and "fadeInDurationMs" is > 0, the attenuation "fadeInStartLevelDb" in dB is applied to the first sample, followed by a fade-in to 0 dB for the next "fadeInDurationMs" milliseconds. This fade-in is linear on the dB scale!
Route Specification
A route defines the mapping of a set of audio channels from one input graph to one output graph.
JSON Structure
{
"name": "...",
"level": "...",
"input": {
"graph": "...",
"channels": "..."
}
"output": {
"graph": "...",
"channels": "..."
}
}
Field | Description |
---|---|
name | Name of the route. This is used to identify the route, when updating routing data for a running job. |
level | Floating point value, defining the linear amplification of the data for this route. |
input | Defines the input channels of the route.
|
output | Defines the output channels of the route.
|
Notes:
- In an n-channel graph, the available channel indexes are always 0 .. n-1.
- The first channel in the input channel list is routed to the first channel in the output channel list, etc.
- If there are more input than output channels specified, the extra input channels are simply ignored. If there are more output than input channels, the extra output channels receive silent audio from this route.
- The "level" specified in a route is applied to all channels and is applied in addition to any levels given in "inputLevel" or "outputLevel" specifications.
Sequence of Level Adjustment, Level Filtering and Live Data Notifications
If you specify both level adjustment and level filtering, it's obviously important to know what comes first. I.e., does the level filtering act on the "original" data or on the ones modified after application of the level adjustment. Additionally, a ROAD client can subscribe to Live Data Notifications, and it's important to know which data is used as "live data".
Input Graphs
For input graphs, the sequence is as follows:
- Send out "pre-fader" (or default) live data notifications
- Apply level adjustment
- Send out "post-fader" live data notifications
- Apply level filtering
Output Graphs
For output graphs, the sequence is as follows:
- Apply level filtering
- Send out "pre-fader" live data notifications
- Apply level adjustment
- Send out "post-fader" (or default) live data notifications
Default Routing
For very simple configurations a default routing can be applied. This may be e.g. a stereo file as source and a stereo destination playout. For this no mixer specification is required in the PipeSpec.
For only changing the master gain, it is sufficient to provide a mixer spec with one route consisting only of the fields name and level.
Examples
Simple File Playout
JSON Structure
"pipeSpec": {
"inputGraph": [
{
"name": "Input",
"filter": [
{
"name": "FileReader",
"filePath": "C:\Temp\Testfile.wav"
}
]
}
],
"outputGraph": [
{
"name": "Output",
"format": {
"sampleRate": 44100,
"resolution": 16,
"channels": 2
},
"filter": [
{
"name": "SoundMapper",
}
],
},
],
"mixer": {
"route": [
{
"name": "Route",
"input": {
"graph": "Input",
"channels": "0,1"
},
"output": {
"graph": "Output",
"channels": "0,1"
}
}
]
}
}
The example plays the input file as a stereo stream on the standard output device. The output format is 44.1kHz/16 bit; the ROAD mixer will take care of any necessary sampling rate and bit width conversions.
With the above example of a PipeSpec, the client can easily implement an output level control. At any time while the playout job is running, transitions can be sent with the following PipeSpec:
JSON Structure
"pipeSpec": {
"mixer": {
"outputLevel": [
{
"graph": "Output",
"level": "..."
}
]
}
}
In the "level" field, the new output level must be given. The new mixer specification is merged with the existing one. I.e. if no "outputLevel" spec for the given graph "Output" already exists, it is added to the mixer. And if it already exists, the parameters (only "level" in this case) are modified. The modifications take effect as soon as the next block of data is transferred from the input to the output graphs.
Multi-Channel ASIO Recording
JSON Structure
"pipeSpec": {
"inputGraph": [
{
"name": "Input",
"filter": [
{
"name": "ASIO Source",
"device" : {
"name": "Hammerfall DSP",
"channels" : "0,1,4,5"
},
"format" : {
"sampleRate": 48000,
"resolution" : 16
}
}
]
}
],
"outputGraph": [
{
"name": "Output_Multi",
"format": {
"sampleRate": 48000,
"resolution": 16,
"channels": 4
},
"filter": [
{
"name": "WAVDest",
"title" : "Multi-channel file"
},
{
"name": "FileWriter",
"filePath": "C:\Temp\ROAD\Test_Multi.wav"
}
],
},
{
"name": "Output_Channel0,1",
"format": {
"sampleRate": 48100,
"resolution": 16,
"channels": 2
},
"filter": [
{
"name": "WAVDest",
"title": "Stereo file, channels 0+1"
},
{
"name": "FileWriter",
"filePath" : "C:\Temp\ROAD\Test_Stereo01.wav",
}
],
},
{
"name": "Output_Channel4,5",
"format": {
"sampleRate": 48100,
"resolution": 16,
"channels": 2
},
"filter": [
{
"name": "WAVDest",
"title": "Stereo file, channels 4+5"
},
{
"name": "FileWriter",
"filePath" : "C:\Temp\ROAD\Test_Stereo23.wav",
}
],
},
{
"name": "Output_Sound",
"format": {
"sampleRate": 44100,
"resolution": 16,
"channels": 2
},
"filter": [
{
"name": "SoundMapper",
}
],
},
],
"mixer": {
"route": [
{
"name": "Route_Multi",
"input": {
"graph": "Input",
"channels": "0,1,2,3"
},
"output": {
"graph": "Output_Multi",
"channels": "3,2,1,0"
}
},
{
"name": "Route_Stereo1",
"input": {
"graph": "Input",
"channels": "0,1"
},
"output": {
"graph": "Output_Channel0,1",
"channels": "0,1"
}
},
{
"name": "Route_Stereo2",
"input": {
"graph": "Input",
"channels": "2,3"
},
"output": {
"graph": "Output_Channel4,5",
"channels": "0,1"
}
},
{
"name": "Route_Sound",
"level": "0.5",
"input": {
"graph": "Input",
"channels": "0,1"
},
"output": {
"graph": "Output_Sound",
"channels": "0,1"
}
},
]
}
}
The example implements the following features:
- As input, 4 channels of an ASIO device are recorded. The indexes of the channels are 0, 1, 4 and 5. The result is a 4-channel input stream.
- The output graph "Output_Multi" creates a 4-channel WAVE file; the two output graphs "Output_Channel0,1" and "OutputChannel4,5" both create 2-channel (i.e. stereo) WAVE files, and output graph "Output_Sound" outputs sound to the default sound device.
- The sound output specifies a sampling rate of 44100 Hz, even though the input data is 48000 Hz. The ROAD mixer automatically inserts a sampling rate conversion here.
- The mixer has 4 routes to distribute the 4-channel input to the various output graphs.
- Route "Route_Multi" routes all 4 input channels to the 4 output channels of the 4-channel WAVE file. Additionally, it reverses the order of the channel: input channels "0,1,2,3" are mapped to output channels "3,2,1,0". Note: The channel numbers in a route always refer to the channels in a graph! In an n-channel graph, the available channel numbers are always 0 .. n-1. The mixer is not aware, that the 4 channels of the input stream were actually generated by physical channels 0,1,4,5 of the ASIO driver.
- Routes "Route_Stereo1" and "Route_Stereo2" each direct two channels of the input to the two stereo output graphs.
- Route "Route_Sound" directs the first two channels of input to the sound device. Additionally it reduces the volume to one-half by using a "level" specification of 0.5.