The Streamer Program

The streamer program (a.k.a. the counterpoint program) groups the notes of a piece into contrapuntal lines or "streams".

As input, the program requires a "note list" and a "beat list". To create the appropriate input format, we recommend running a notefile through the meter program first, then using that to generate both the note list and the beat list, which can then be piped into the counterpoint program.

As a first step, the program quantizes all note onsets and offsets to beats. Thus the input can be thought of as a grid of squares, with each square either "full" or "empty".

In choosing the best analysis, the program has a number of criteria. The "well-formedness" (hard-and-fast) criteria are these: 1) Streams must consist of a set of contiguous squares in the time dimension. 2) Streams may only be one square wide in the pitch dimension. 3) Streams cannot cross. 4) All events ("black squares") must be contained in at least one stream (however, streams may also contain white squares). 5) If part of a note is contained in a stream, it must be entirely contained in that stream. 6) There can't be more than a certain number of streams at once, given by the parameter maximum_voices. (If rule 6 conflicts with rule 4, rule 6 takes precedence; certain notes are just ignored.) The preference (flexible) rules are these: 1) Prefer to avoid streams with empty spaces. 2) Prefer to avoid streams with big leaps in pitch. 3) Prefer to avoid streams starting and stopping: that is, minimize the number of streams. 4) Prefer to avoid "collisions" - a single note occupied by more than one stream.

Parameters. Here are the user-settable parameters for the counterpoint program.
verbosity=1 With verbosity = 0, the program outputs a list of notes, as inputted. (The notes are, however, quantized to beats.) After each note, an integer is given, indicating the number of the stream to which the note was assigned. Here is a sample from a Bach fugue:
Note 23625 24010 72 4
Note 23625 24360 67 1
Note 23625 23800 51 3
Note 23800 24010 60 3
Note 24010 24185 59 3
Note 24010 24185 79 4
Note 24185 24360 78 4
Note 24185 24360 57 3
Note 24360 24745 79 4
Note 24360 24570 55 3
Note 24570 24745 53 3
Note 24745 25130 71 1
Note 24745 24920 51 3
Note 24745 25130 74 4
Note 24920 25130 50 3
Note 25130 25865 75 4
Note 25130 25515 72 1
Note 25130 25305 48 3
Note 25305 25515 50 3
Note 25515 25690 51 3
Note 25515 25690 72 1
Note 25690 25865 71 1
Note 25690 25865 50 3
Note 25865 26075 48 3
Note 25865 26250 72 1
Note 26075 26250 46 3
Note 26250 26635 76 4
Note 26250 26635 67 1
Note 26250 26425 44 3

With verbosity = 1, the program inputs a graphic display of the notes, showing the stream number for each note. Here is a sample (condensed in width) from the same fugue excerpt:

Seg   98 (3):           .  3        .      1    4           .           .   
Seg   99 (0):           .           3      1    4           .           .   
Seg  100 (1):           .          3.      1    .      4    .           .   
Seg  101 (0):           .        3  .      1    .     4     .           .   
Seg  102 (2):           .      3    .      |    .      4    .           .   
Seg  103 (0):           .    3      .      |    .      4    .           .   
Seg  104 (1):           .  3        .          1. 4         .           .   
Seg  105 (0):           . 3         .          1. 4         .           .   
Seg  106 (4):           3           .           1  4        .           .   
Seg  107 (0):           . 3         .           1  4        .           .   
Seg  108 (1):           .  3        .           1  4        .           .   
Seg  109 (0):           . 3         .          1.  4        .           .   
Seg  110 (2):           3           .           1  |        .           .   
Seg  111 (0):         3 .           .           1  |        .           .   
Seg  112 (1):       3   .           .      1    .   4       .           .   
Seg  113 (0):      3    .           .      1    .   4       .           .   

With verbosity = 2, more information is shown.

maximum_voices=6 The maximum number of simultaneous voices allowable. If a chord in the piece contains more pitches than this, certain random pitches in the chord will simply be ignored. (The higher this value, the slower the program will be; choosing a value above 6 is not recommended.)
maximum_grey_squares=6 The number of pitches in a segment that can be considered as possible stream locations when there are no notes there. The program considers white squares as possible stream locations under certain conditions - such eligible white squares are called "grey squares". In the interest of speed, however, it is desirable to limit the number of grey squares that are allowed in any given segment. 6 proves to be a good value for this variable.
maximum_with_collisions=4 When this value is set to 4, that means that collisions are allowed in a segment only when the number of voices present is 4 or less.
pitch_proximity_penalty=1 The penalty, per semitone, for a leap within a voice.
blank_square_penalty=20 The penalty for a blank square contained within a stream. This penalty is per second; with the penalty set at 20, a square of .25 seconds would carry a penalty of 5.
new_voice_penalty=20 The penalty for beginning a new stream.
collision_penalty=20 The penalty for collisions. As with the blank_square_penalty, this is a per-second penalty; the penalty imposed depends on the length of the segment in which the collision occurs.
top_new_voice_penalty=0 The penalty for beginning a new top voice above the current top voice, or for ending the current top voice.
top_blank_square_penalty=0 An extra blank_square_penalty (over and above the regular one) for blank squares in the top voice.