SF_Block

Sonic Flow libsf Reference Guide

This is the base class for all the blocks, including the blocks specified in the Sonic Flow Blocks Reference Guide and the SF_Network class. The SF_Block class is an abstract base class, i.e. there cannot be an instance of it.

This class is used to represent an abstract "block", "machine" or a "module" which can be used in signal processing networks by connecting them to other similar "blocks". It is important to realize that the block is just a small algorithm to turn its inputs into its outputs. If there are no inputs to a block but only outputs, then the block creates a signal from "nowhere", from the point of view of the dataflow diagram. Vice versa, if there are no outputs from a block, then the block can be thought of as a black hole.

SF_Block (unsigned int num_inputs, unsigned int num_outputs, bool producer, bool consumer, const char* class_name = 0, const char* instance_name = 0);

This is the constructor of a block. There is no default constructor for blocks so this constructor is used to initialize all blocks.

The num_inputs and num_outputs parameters specify the number of input terminals and the number of output terminals on the block, respectively. The input and output terminals are piled up in the inputs and outputs arrays (see below).

The producer and consumer flags indicate whether the block is a "producer" block or a "consumer" block, or neither.

The class_name field is used to initialize the name of the class the block belongs into. Example names: "Adder", "Multiplier", "Low-pass filter". In a network there can be multiple blocks with the same class name, i.e. there may be multiple adders etc. Note that the class name of a block cannot be changed after the instantiation of the block.

The instance_name field is used to differentiate between multiple blocks of the same class. The instance name field is not used by the Sonic Flow system otherwise than to allow the user to name his/her blocks comfortably. The instance_name field can be thought of as an ID for the benefit of the user.

virtual ~SF_Block ();

This is the destructor.

virtual void print (ostream& stream) const;

Used to print a textual description of the block, usually called by SF_Network::print (). An example print of an sine generator:

Sine generator: "modulator" (2 input, 1 output terminal(s))
 Input "freq" (44100 Hz): 1 connection(s)
 Input "amp" (44100 Hz): 1 connection(s)
 Output "y" (44100 Hz): "x@avib"

The printout is done to the specified output stream.

virtual bool is_functional () const;

Used to query whether the block is functional in the sense that it can be executed. In order for a block to be functional at least the following condition needs to be met:

virtual void initialize () = 0;
virtual void execute () = 0;
virtual void finish () = 0;

The initialize - execute - finish chain of function calls is used to carry out the simulation of a block. This means the actual "thing" the block is used for. To give an example, consider the addition that's being done in an "adder" block.

These are "pure virtual" functions in C++ parlance, and this means they need to be implemented in the actual block classes which are derived from this class.

The initialize function is called once before the start of the simulation. In this function the block is intended to initialize its internal state to be ready for repeated execution. It is guaranteed that the wirings, the signal frames and the sample rates of the network the block belongs to are not altered after initialization or during execution. This means that the block may prepare pointers to the output frames in order to speed up the execute function.

Source blocks and all the other blocks are handled a bit different during the initialization of a network. If the block is a source block, it may set the sample rates of its outputs at the initialize function, if needed. If the sample rates are not initialized, then they will keep whatever value they have. This way e.g. a file input block can scan the sample rate of the file and set its output rate accordingly.

If the block in question is not a source block, it should investigate the sample rates set on its input and output terminals and adapt to them if needed. As said before, the sample rates are promised not to change during simulation execution.

virtual SF_Block& operator>> (SF_Input_Terminal& dest_terminal);
virtual SF_Block& operator>> (SF_Block& dest_block);

The `>>' operators can be used to chain blocks together easily in the C++ language. For example, the following code fragment generates a cascade of a file input, a variable, an adder and file output:

SF_File_Input in;
SF_Variable var;
SF_Adder a;
SF_File_Output out;

in >> a >> out;
var >> a;

The above code connects the output of the SF_File_Input block to the input of the adder and the output of the adder to the SF_File_Output block. The output of the variable block is connected to the input of the adder as well.

In order to use the `>>' operators without specifying an input or output terminal explicitly, there must be only one input or output terminal in the respective block.

void check_sample_rates () const;

Check every sample rate of every terminal and compare it to the rates of the other terminals with respect to the relative sample rates. If the ratios of the sample rates aren't correct, throw an exception.

inline const char* get_class_name () const;

Returns the `class name' of the block, e.g. "Adder" or "Band pass filter".

inline SF_Network* get_host_network () const;
inline void set_host_network (SF_Network* host);

Inspect or set the network the block belogs to.

inline const char* get_instance_name () const;
inline void set_instance_name (const char* instance_name);

Inspect or set the `instance name' of the block. This is a name for the very instance of the block, and the user is allowed to modify it.

Set the `instance name' of the block.

inline unsigned int get_num_input_terminals () const;
inline unsigned int get_num_output_terminals () const;

Return the number of input and output terminals in the block, respectively. The sizes of the inputs[] and outputs[] arrays are determined by these numbers.

inline bool is_producer () const;
inline bool is_consumer () const;

These functions indicate whether the block is a producer or a consumer block.

A producer block is one which creates a new audio signal and a consumer block is one which somehow stores or saves an incoming audio signal. A sine generator or a file input would be examples of producer blocks and a file output or an audio output (to an amplifier and eventually a loudspeaker) would be examples of a consumer block.

Note that the consumer and producer terms differ from the source and sink terms. A source is a block which has no incoming wires, while there might be such wires in a producer, e.g. frequency input to a sine generator. A sink block is a block which has no outgoing wires. In other words you might consider "producer" to be a synonym for "potential source" and "consumer" be synonym for "potential sink."

SF_Input_Terminal* const inputs;
SF_Output_Terminal* const outputs;

These arrays contain the input and output terminals of the block. These arrays are `virtual' in the sense that the SF_Block base class doesn't define how many terminals there are in a block.


Last modified: Thu Dec 10 14:21:13 1998
jarno.seppanen@cs.tut.fi
Audio Research Group