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