The sound data synthesis is carried out by a network of sound processing elements, each represented by an instance of a subclass of ProcessElement.
Each of these ProcessElements has a set of input and output streams each. For most of these elements, each input and output has defined semantics and their number is therefore fixed (such elements may, however, have a default behaviour for an input in case no input stream is connected to it).
Only very few elements have an undefined number of input streams or stream pairs (where each channel or channel pair then needs to be semantically equivalent). Examples for such special elements are an adder or multiplier. The indefinite stream count just makes up for an abbreviation so it is not necessary to instanciate a high number of cascaded 2-stream-elements and it's also not necessary to have distinct classes for each possible number of streams, i.e. we do not make a difference between a 2-stream-adder and a 4-stream adder, an adder can just handle an arbitrary number of streams.
Ideally every output stream of a ProcessElement can serve as an input stream for another ProcessElement (or even the same element), therefore allowing every possible element network topology. A few exceptions have proven necessary, which will be pointed out and explained below.
This goes as far as even the difference between control signals and sound signals diminishes. A volume control is just a multiplier of a volume signal and a sound signal, but as it is really only a multiplier, it can as well multply two control signals or two sounds (therefore transcending into a ring modulator). In the SoundComp language all of these situations are represented the same, by a simple multiplication.
Sound Synthesis is actually carried out sample by sample by most ProcessElements by:
synchronously (from the perspective of the sample clock, in fact of course they are calculated somehow sequentially between the sample clock edges) for the same sample for all active ProcessElements.
This implies that each element has an internal delay of at least one sample period. The aforementioned adder and multiplier (and maybe very few more elements) serve as exceptions: when asked for their output, they give the correct output for the present input stream values. This is necessary for them to be deterministic (as otherwise the result of a formula consisting of a multitude of additions and multiplications would depend on how the formula is translated into a signal path). Also, adding and multiplying are by far the most often used elements, which would lead to larger and therefore noticeable delays in most cases,
This exception means that it is not allowable for an adder or multiplier to connect its output back to an input without a delaying element in between; otherwise we would build up an endless loop (the adder would be asked for its output, which incurs calculating from its inputs, which again refers to its present output...). The calculation of even the first sample would never terminate. Ideally the parser or control logic must detect such a situation before attempting to use the element, and fail with an error.
The delay of all other elements again is necessary for making the network behaviour deterministic. If during the calculation of a sample some intermediate results would already be available for certain ProcessElements whereas other data is still used from a past sample, the outcome would depend on the order in which the elements are used for calculation, which is nothing the user can or should be able to care about and which should be considered random (from the user point of view) and irrelevant.
This also opens options for multithreading: not only the order of evaluation is irrelevant, they can also be evaluated in parallel if this saves time. The only drawback with this is that the calculatory effort varies between different elements by orders of magnitude, even between elements of the same type but varying parameters. This makes a prepared scheduling optimization a complex task. We also have to take care not to spend too much effort in this optimization: many elements may take less time to evaluate than any simple kind of scheduler might consume on its own in an attempt to save time.