Previous topic

Getting Started

Next topic

Built-In Processors, Constants, and Switches (Part I)

This Page

Blocks, Ports, and Properties

Let’s get right to it with some examples.

The following code is the simplest program in Stride.

# Load platform version 0.0 on target version 0.0
use Platform version 0.0 on Hardware version 0.0

# Stream audio input 1 to audio output 1
AudioIn[1] >> AudioOut[1];

The program streams an audio signal from audio input 1 (mono) to audio output 1 (mono). Audio input 1 and audio output 1 are physical plugs on the target hardware.

Every Stride code starts with a “use PLATFORM version VERSION on HARDWARE version VERSION” expression. It tells Stride which platform descriptor file to load. The platform descriptor file contains information related to resource abstraction and functionality.

AudioIn[1] >> AudioOut[1]” is a stream expression. ‘AudioIn’ and ‘AudioOut’ are labels representing two Stride block bundles. They are both declared in the platform descriptor file and they abstract the underlying harware inputs and outputs. Stride has many block types. One of these block types is signal. Stride allows bundling blocks together. AudioIn[1] and AudioOut[1] are the first blocks in the block bunldes.

Connections between blocks can be created using the stream operator >>. For an expression to be called a stream expression, it must contain at least one stream operator.

All stream exprssions must end with a semicolons.

Connections between Stride blocks happens through ports. A port has a direction, and a type. A port can have two possible port directions: input or output. A signal block, for instance, has six ports: Five input ports and one output port. A port can be one of these port types. It can also be a hybrid port.

Signal Block

Figure: Signal Block

Ports in Stride are exposed in one of two ways, either through the block label or through properties. Connections with ports exposed through the block label are achieved using the stream operator or property assignments during other while connections with ports exposed through a property are done during a block declaration.

In case of a signal block, its label exposes the hybrid stream input port and the hybrid stream output port.

In the expression “AudioIn[1] >> AudioOut[1]”, since the label ‘AudioIn[1]’ is on the left hand side of the stream operator, it represents the hybrid stream output port of the AudioIn[1] signal block while the label ‘AudioOut[1]’ represents the hybrid stream input port of the AudioOut[1] signal block since it is on the right hand side.

In order to establish a connection and stream between an output port and an input port, their types should match or a conversion between their types should be defined in the language. The stream operator can only connect ports exposed by the label.

In the case of a signal block the output port can connect to multiple input ports but its input port can only connect to a single output port.

The hybrid stream input port of AudioIn[1] is connected to an audio hardware resource (Analog to Digital Converter). The port cannot accept any other connections. The hybrid stream output port of AudioIn[1] can connect and stream to hybrid stream input ports. In the preceding example, the hybrid stream output port of AudioIn[1] is connected to the hybrid stream input port of AudioOut[1]. Although the hybrid stream output port of AudioIn[1] is capable of establishing other connections, no such connections are made.

The hybrid stream output port of AudioOut[1] is connected to an audio hardware resource (Digital to Analog Converter) and can connect and stream to other hybrid stream input ports. In the preceding example, no such connections are made. The hybrid stream input port of AudioOut[1] is connected to the hybrid stream output port of AudioIn[1]. No further connections can be made to the hybrid stream input port of AudioOut[1].

Identifiers, like ‘AudioIn[1]’ and ‘AudioOut[1]’ whether declared by in the platform descriptor file or the user, start with an upper case letter. Identifiers are constructed using letters, digits, and underscores. Identifiers are case sensitive. A single upper case letter is the shortest possible identifier.

Comments in Stride are preceded by the number sign #.

Let’s now stream the input to two outputs creating a mono to stereo connection.

# Stream audio input 1 to audio output 1
AudioIn[1] >> AudioOut[1];
# Stream audio input 1 to audio output 2
AudioIn[1] >> AudioOut[2];

In this example the hybrid stream output port of AudioIn[1] is connected and streams to multiple hybrid stream input ports. The hybrid stream input ports are those of AudioOut[1] and AudioOut[2].

The same program can be written as follows:

# Stream audio input 1 to audio output 1 and audio output 2
AudioIn[1] >> [AudioOut[1], AudioOut[2]];

[AudioOut[1], AudioOut[2]]” represents a block bundle in Stride. Elements of a bundle block are placed between square brackets and separated by commas. Elements of a bundle must have the same block type.

Let’s now stream two inputs to two outputs creating a stereo to stereo connection.

# Stream audio input 1 and 2 to audio output 1 and 2 (one to one)
[AudioIn[1], AudioIn[2]] >> [AudioOut[1], AudioOut[2]];

This is equivalent to writing:

# Stream audio input 1 to audio output 1
AudioIn[1] >> AudioOut[1];
# Stream audio input 2 to audio output 2
AudioIn[2] >> AudioOut[2];
# Stream audio input 1 and 2 to audio output 1 and 2 (one to one) using range indexing
AudioIn[1:2] >> AudioOut[1:2];

The identifiers used so far are all defined in the platform descriptor file. What if we would like to label these identifiers to give them names that make sense in a project context like a stereo guitar effects pedal? This could be achieved by defining new signal blocks.

# Declare a signal block labeled 'Microphone'
signal Microphone {
        default:        0.0
        rate:           AudioRate
        reset:          MasterReset
        meta:           'Microphone input.'
}

# Declare a signal block bundle labeled 'MainOutput'
signal MainOutput [2] {
        default:        0.0
        rate:           AudioRate
        reset:          MasterReset
        meta:           'Main stereo output.'
}

# Stream 'AudioIn[1]' to 'Microphone'
AudioIn[1] >> Microphone;

# Stream 'MainOutput' to 'AudioOut[1]' and 'AudioOut[2]'
MainOutput >> AudioOut[1:2];

# Stream 'Microphone' to 'MainOutput'
Microphone >> MainOutput;

The first expression in the preceding code is a signal block declaration. It begins with the signal keyword followed by an identifier chosen by the user, in this case ‘Microphone’. Braces enclose the properties of a signal block and their corresponding assignments.

Like identifiers, properties in Stride expose ports to enable connections with a block. However, unlike identifiers, connections through properties can only be made during declarations.

Some properties expose a single port and others expose multiple ports. A property exposing multiple ports is a multi-port property. A multi-port property exposes ports that have the same direction. Stride establishes the proper connection by matching the port type.

If a port is to be left unconnected during declaration, its corresponding property is assigned the keyword none.

A signal block has four properties which expose all of its four ports:

TABLE GOES HERE

The input and output properties expose the hybrid stream input and output ports respectively. In the case of Microphone, its connection with AudioIn[1] is established through the input property “input: AudioIn[1]” but with MainOutput it is established using its identifier and the stream operator “Microphone >> MainOutput”.

Here’s how the connection between Microphone and AudioIn[1] could have been established using its identifier and the stream operator:

# Declare a signal block labeled 'Microphone'
signal Microphone {
        default:        0.0
        rate:           AudioRate
        reset:          MasterReset
        meta:           'Microphone input'
}

# Stream audio input 1 to 'Microphone'
AudioIn[1] >> Microphone;

The rate property, as its name indicates, sets the sampling rate of the signal block. It can accept a connection from a constant block which has an output port of type constant integer. AudioRate is a platform defined constant block. It holds the value of the hardware audio sampling rate.

The meta property holds metadata information related to the block. It can accept a connection from a constant block which has an output port of type constant string.

# Stream 'AudioIn[1]' to 'Microphone'
AudioIn[1] >> Microphone;

# Stream 'MainOutput' to 'AudioOut[1]' and 'AudioOut[2]'
MainOutput >> AudioOut[1:2];

# Stream 'Microphone' to 'MainOutput'
Microphone >> MainOutput;

Stride will automatically generate the following prefix code:

signal Microphone {}

signal MainOutput [2] {}

Automatic code generation is possible with signal blocks. When a declaration is made with empty braces, the default values are assigned to the properties.

signal Microphone {
        default:        0.0
        rate:           AudioRate
        domain:         AudioDomain
        reset:          MasterReset
        meta:           none
}

signal MainOutput [2] {
        default:        0.0
        rate:           AudioRate
        domain:         AudioDomain
        reset:          MasterReset
        meta:           none
}

Stride ignores whitespace characters (space, tab, newline) . It also ignores semicolons at the end of property assignments, block declarations.

The following code samples are equivalent:

# Sample 1
signal Microphone {
        default:        0.0
        rate:           AudioRate
        reset:          MasterReset
        meta:           'Microphone input.'
}

# Sample 2
signal Microphone {default: 0.0 rate: AudioRate reset: MasterReset meta: 'Microphone input.'}

# Sample 3
signal Microphone {
        default:        0.0;
        rate:           AudioRate;
        reset:          MasterReset;
        meta:           'Microphone input.';
};

# Sample 4
signal Microphone { default: 0.0; rate: AudioRate; reset: MasterReset; meta: 'Microphone input.'; };