This article is a continuation of Csound check in which we introduced the creation of Csound parameters monitored by performance controls. Musical phrases were created from simple notes translated into Csound events in a straightforward manner. We now consider the creation of Csound scores based on sound-objects containing Csound instructions — which may be called "Csound objects".
Csound objects contain a Csound score with a specific tempo and duration. For example, in object "e" shown above, the tempo (line "t" of the score) is 120 beats/min. The total duration is 2 beats, or 1000 ms. Note that to calculate the total duration of this sound-object, the durations of 'E3' and 'G3' (0.667 sec) shouldn't be added to those of 'C3' and 'D3', because of the start dates.
The duration of a Csound object is independent of the duration set by MIDI events that may coexist in the sound-object prototype. In most situations, note sequences and durations are identical in the MIDI stream and the Csound score. This makes it possible to play almost the same items via MIDI and Csound. However, as we will see, Csound is open to controls that are not available in MIDI.
Calculations can be easily verified against the C-sound instrument file "‑cs.tryCsoundObjects" provided in the example set bp3-ctests-main.zip — downloadable from GitHub along with the Bol Processor BP3 interface: php-frontend-master.zip. Items can be created with the grammar "‑gr.tryCsoundObjects" using the alphabet "‑ho.tryCsoundObjects" associated with the sound-object prototype file "‑mi.tryCsoundObjects".
Let us start with sound-object "a" whose score is shown in the picture. The score is given for a tempo of 120 beats per minute, giving a total duration of 2 beats ( = 1.5 + 0.5) or 1000 ms.
The first event (note 'F0') is repeated 2 times with identical timing, a meaningless detail to check that Csound can handle this abnormal case.
Events i1 and i2, calling instruments 1 and 2, describe tonal positions in the octave point pitch-class format: octave number + semitones above C. We notice that "5.05" has been mislabelled as 'G5'. This will have no effect on the computation, as the Bol Processor will automatically correct it to 'F1'. It will also rename notes according to the convention set in the settings: English, French or Indian.
Event i3, calling instrument 3, defines pitch as frequency (in Hz). It is assumed that 643.5 Hz is 'D#5' because the diapason is 'A4' = 440 Hz. This tuning is defined in the settings (page "-se.tryCsoundObjects"). Bol Processor can change the name of this note according to the diapason.
Changes of the diapason are taken into account by BP3 when generating Csound scores, but this was not yet the case with BP2. The following examples have been produced with the default 'A4' = 440 Hz, giving identical results with BP2 and BP3. See the page Csound tuning in BP3 page to examine different cases.
Producing object "a" at a tempo of 60 beats per minute results in the following Csound score:
a
t 0.000 60.000
i1 0.000 0.250 4.05 90.000 90.000 0.000 0.000 0.000 0.000 ; F0
i1 0.000 0.250 4.05 90.000 90.000 0.000 0.000 0.000 0.000 ; F0
i2 0.750 0.250 5.05 0.000 0.000 90.000 90.000 0.000 0.000 0.000 ; F1
i3 0.750 0.100 643.50 1.000 ; D#5
Note that this score is more complete than the one contained in sound-object "a". This is because the sound-object prototype file "-so.tryCsoundObjects" is linked to a Csound instrument file "-cs.tryCsoundObjects" (see figure below).
Instrument 1 of the Csound instrument file is designed to handle 10 arguments while the score of "i1" events in "a" only contains 4. The 6 missing arguments are filled with default values of the parameters they represent. Here, for example, '90' is the default volume. Zeros represent default pitchbend or function table indexes.
Note that "5.05" has been correctly fixed to "F1". This is only relevant to human readers, as Csound ignores any text following a semicolon.
You cannot convert this and other examples to sound with the supplied Csound orchestra "default.orc", because it only handles instrument 1. The examples on this page are for visual inspection only.
In the following example, we need to look at the graph to understand why the events of "a" are delayed by 160ms compared to "b". Object "b" has a pivot set at 20% of its duration from the start date. This can be checked in "-so.tryCsoundObjects".
Although the object graphic and the pianoroll for this item indicate that "b" should start on a negative date (-160ms), the Csound score is shifted to show only positive or zero dates.
{a, b} c
i3 0.000 0.800 461.34 1.000 ; A4
i4 0.100 0.200 6.03 1.050 ; C2
i1 0.160 0.250 4.05 90.000 90.000 0.000 0.000 0.000 0.000 ; F0
i1 0.160 0.250 4.05 90.000 90.000 0.000 0.000 0.000 0.000 ; F0
i2 0.910 0.250 5.05 0.000 0.000 90.000 90.000 0.000 0.000 0.000 ; F1
i3 0.910 0.100 643.50 1.000 ; D#5
i2 1.160 0.125 9.00 0.000 0.000 90.000 90.000 0.000 0.000 0.000 ; C5
i2 1.285 0.125 9.02 0.000 0.000 62.000 62.000 0.000 0.000 0.000 ; D5
i2 1.410 0.125 9.04 0.000 0.000 90.000 90.000 0.000 0.000 0.000 ; E5
i2 1.535 0.125 9.05 0.000 0.000 90.000 90.000 0.000 0.000 0.000 ; F5
Note on pivots and relocation: sound-object "b" has its pivot shown as a full arrow, unlike other sound-objects in this set which only have a red triangle. This means that it is not relocatable. Relocation would be performed if these sound-objects had topological properties such as prohibiting the covering of their beginning/end, allowing truncation of beginning/end to a certain degree, breaking the tempo etc. A constraint-satisfaction algorithm is run on each production to produce a solution that minimises the number of constraints violated. This is best illustrated by "-gr.koto3" (read the article).
Let us now look at a phrase containing "midiobject", a sound-object with both a MIDI stream and a Csound score. The MIDI stream is ignored when constructing the score. The time resolution (10 ms) also has no effect on the accuracy of timings in the Csound score.
b midiobject
i3 0.000 0.800 461.34 1.000 ; A4
i4 0.100 0.200 6.03 1.050 ; C2
i1 1.160 0.666 7.04 90.000 90.000 0.000 0.000 0.000 0.000 ; E3
i1 1.160 1.000 7.00 90.000 90.000 0.000 0.000 0.000 0.000 ; C3
i1 2.160 1.000 7.02 90.000 90.000 0.000 0.000 0.000 0.000 ; D3
i1 2.493 0.667 7.07 90.000 90.000 0.000 0.000 0.000 0.000 ; G3
Since the score of "midiobject" has been defined with a tempo of 60 beats/min for a duration of 2 beats, the durations of the notes E3, C3, D3, G3 are unchanged.
Now consider a polymetric structure in which the first line contains 3 sound-objects and the second line contains 2 sound-objects. The structure will be forced to a symbolic duration of 3 beats — the duration of "a b a" — and the second line will arrange the objects as "two in three" with symbolic durations of 1.5 beats.
This is clear on the picture, looking at the pivots of sound-objects, if one does not get confused by the physical duration of the sound-objects. The sound-object prototype "b" has a duration of 0.8 beats, resulting in a physical duration of 800 ms.
On the second line, the symbolic duration of each object is 1.5 beats. Consequently, the sound-object "c", whose prototype has a physical duration of 500 ms, is set to physical duration = 500 * 1.5 = 750 ms. The object "c" appears as sequence "C5 D5 E5 F5" with total physical duration of 4 * 188 ms = 752 ms. These durations are reflected in the Csound score below.
{a b a, c midiobject}
i1 0.000 0.250 4.05 90.000 90.000 0.000 0.000 0.000 0.000 ; F0
i1 0.000 0.250 4.05 90.000 90.000 0.000 0.000 0.000 0.000 ; F0
i2 0.000 0.188 9.00 0.000 0.000 90.000 90.000 0.000 0.000 0.000 ; C5
i2 0.187 0.188 9.02 0.000 0.000 62.000 62.000 0.000 0.000 0.000 ; D5
i2 0.374 0.188 9.04 0.000 0.000 90.000 90.000 0.000 0.000 0.000 ; E5
i2 0.561 0.188 9.05 0.000 0.000 90.000 90.000 0.000 0.000 0.000 ; F5
i2 0.750 0.250 5.05 0.000 0.000 90.000 90.000 0.000 0.000 0.000 ; F1
i3 0.750 0.100 643.50 1.000 ; D#5
i3 0.840 0.800 461.34 1.000 ; A4
i4 0.940 0.200 6.03 1.050 ; C2
i1 1.500 0.999 7.04 90.000 90.000 0.000 0.000 0.000 0.000 ; E3
i1 1.500 1.500 7.00 90.000 90.000 0.000 0.000 0.000 0.000 ; C3
i1 2.000 0.250 4.05 90.000 90.000 0.000 0.000 0.000 0.000 ; F0
i1 2.000 0.250 4.05 90.000 90.000 0.000 0.000 0.000 0.000 ; F0
i2 2.750 0.250 5.05 0.000 0.000 90.000 90.000 0.000 0.000 0.000 ; F1
i3 2.750 0.100 643.50 1.000 ; D#5
i1 3.000 1.500 7.02 90.000 90.000 0.000 0.000 0.000 0.000 ; D3
i1 3.499 1.000 7.07 90.000 90.000 0.000 0.000 0.000 0.000 ; G3
In the following example, we combine sound-objects (containing Csound scores) with simple notes that are converted to Csound events. These notes are played on (default) MIDI channel 1, which is assigned to instrument 1.
a C4 D4 b c
i1 0.000 0.250 4.05 90.000 90.000 0.000 0.000 0.000 0.000 ; F0
i1 0.000 0.250 4.05 90.000 90.000 0.000 0.000 0.000 0.000 ; F0
i2 0.750 0.250 5.05 0.000 0.000 90.000 90.000 0.000 0.000 0.000 ; F1
i3 0.750 0.100 643.50 1.000 ; D#5
i1 1.000 1.000 8.00 90.000 90.000 0.000 0.000 0.000 0.000 ; C4
i3 2.840 0.800 461.34 1.000 ; A4
i4 2.940 0.200 6.03 1.050 ; C2
i1 2.000 1.000 8.02 90.000 90.000 0.000 0.000 0.000 0.000 ; D4
i2 4.000 0.125 9.00 0.000 0.000 90.000 90.000 0.000 0.000 0.000 ; C5
i2 4.125 0.125 9.02 0.000 0.000 62.000 62.000 0.000 0.000 0.000 ; D5
i2 4.250 0.125 9.04 0.000 0.000 90.000 90.000 0.000 0.000 0.000 ; E5
i2 4.375 0.125 9.05 0.000 0.000 90.000 90.000 0.000 0.000 0.000 ; F5
This combination is highlighted in the pianoroll. Notes that are present in both the MIDI stream and the Csound score are displayed in brown, while notes that are present only in the Csound output are displayed in green.
Let us apply a continuous pitchbend control to a sound-object containing four Csound instructions, using instrument 2, which maps the MIDI pitchbend range [0..16384] to a range of [-200..+200], both on logarithmic scales. (This mapping is therefore linear.)
In the Bol Processor score, the use of mapped values in _pitchbend() controls is possible, thanks to a _pitchrange(200) instruction at the beginning of the sequence.
The resulting Csound score makes it clear that the pitchbend should vary continuously over each Csound event : 0 to 24.997, 24.997 to 49.994 etc. Csound will further interpolate the values using its GEN 07 (linear interpolation) generator.
_pitchrange(200) _pitchcont _pitchbend(0) c _pitchbend(100)
i2 0.000 0.125 9.00 0.000 24.997 90.000 90.000 0.000 0.000 0.000 ; C5
i2 0.125 0.125 9.02 24.997 49.994 62.000 62.000 0.000 0.000 0.000 ; D5
i2 0.250 0.125 9.04 49.994 74.991 90.000 90.000 0.000 0.000 0.000 ; E5
i2 0.375 0.125 9.05 74.991 99.988 90.000 90.000 0.000 0.000 0.000 ; F5
Volume control is possible on instruments 1 and 2, but not on instrument 3. Therefore its effect is only applied to certain events of sound-object "a":
_volumecont _volume(30) a _volume(127)
i1 0.000 0.250 4.05 30.000 54.250 0.000 0.000 0.000 0.000 ; F0
i1 0.000 0.250 4.05 30.000 54.250 0.000 0.000 0.000 0.000 ; F0
i2 0.750 0.250 5.05 0.000 0.000 102.750 127.000 0.000 0.000 0.000 ; F1
i3 0.750 0.100 643.50 1.000 ; D#5
In the following example, a continuous pitchbend correction cannot be applied because instrument 5, called by "d", does not have a pitchbend parameter. However, the value of +100 cents is applied to the pitch parameter itself.
The Csound score of sound-object "d" is limited to 1 note at 440 Hz (with reference to instrument 5). This note was labelled 'A4' on the prototype, but we should remember that with a diapason of 435 Hz it will be slightly higher than 'A4'. The increase is 1200 * log2(440/435) = 24 cents. So, in the performance it will be set to 124 cents above 435 Hz, giving 435 * 2^(124/1200) = 467 Hz. As shown below:
_pitchrange(200) _pitchcont _pitchbend(100) d _pitchbend(0)
i5 0.000 0.500 466.16 ; A4
In the following example, a continuous pitchbend correction results in different adjustments of the pitchbend parameters of the instruments called by sound-objects "a", "b" and "c". Simple notes 'C4' and 'D4' call instrument 1 because it is the one assigned to the (default) channel 1. The volume is also adjusted continuously.
Note that we also apply negative values to the pitchbend parameter, expecting the Csound orchestra to do the extrapolation.
_pitchrange(200) _pitchcont _volumecont _volume(30) _pitchbend(-10) a C4 D4 b c _pitchbend(100) _volume(127)
i1 0.000 0.250 4.05 30.000 34.850 0.000 -10.000 -4.500 0.000 ; F0
i1 0.000 0.250 4.05 30.000 34.850 0.000 -10.000 -4.500 0.000 ; F0
i2 0.750 0.250 5.05 6.499 11.999 44.550 49.400 0.000 0.000 0.000 ; F1
i3 0.750 0.100 643.50 1.005 ; D#5
i1 1.000 1.000 8.00 49.400 68.800 0.000 12.000 34.000 0.000 ; C4
i3 2.840 0.800 461.34 1.069 ; A4
i4 2.940 0.200 6.03 1.151 ; C2
i1 2.000 1.000 8.02 68.800 88.200 0.000 34.000 56.000 0.000 ; D4
i2 4.000 0.125 9.00 77.990 83.490 107.600 112.450 0.000 0.000 0.000 ; C5
i2 4.125 0.125 9.02 83.490 88.989 77.466 80.807 0.000 0.000 0.000 ; D5
i2 4.250 0.125 9.04 88.989 94.488 117.300 122.150 0.000 0.000 0.000 ; E5
i2 4.375 0.125 9.05 94.488 99.988 122.150 127.000 0.000 0.000 0.000 ; F5
Let us check an arbitrary parameter "burb" which affects arguments 9, 10 and 11 of instrument 2.
This parameter is designed as additive in its combinations. The default value is '0'.
In sound-object "e", the third event 'D3' is required to set 'blurb' to a start value of 10 and to an end value of 30.
These values are added to those interpolated over the continuous 'blurb' variation: 25.6 + (100 - 25.6) * 0.5 = 62.8 and 100 at dates 0.5 and 1 sec. This gives an initial value of 62.8 + 10 = 72.8 and a final value of 100 + 30 = 130.
_cont(blurb) _value(blurb,25.6) e _value(blurb,100)
i2 0.000 0.333 7.04 8191.500 8191.500 64.000 64.000 25.600 50.375 0.000 ; E3
i2 0.000 0.500 7.00 8191.500 8191.500 64.000 64.000 25.600 62.800 0.000 ; C3
i2 0.500 0.500 7.02 8191.500 8191.500 64.000 64.000 72.800 130.000 0.000 ; D3
i2 0.666 0.334 7.07 8191.500 8191.500 64.000 64.000 75.150 99.963 0.000 ; G3
If the variation of "blurb" becomes more complex, the Bol Processor will handle it
through function tables.
_cont(blurb) _value(blurb,12) e _value(blurb,110)_ _value(blurb,130)__ _value(blurb,80)__ _value(blurb,-20)_ _value(blurb,-10)___ _value(blurb,40)
f101 0.000 256 -7 12.000 76 110.000 76 130.000 104 96.750
i2 0.000 3.330 7.04 8191.500 8191.500 64.000 64.000 12.000 96.750 101.000 ; E3
f102 0.000 256 -7 12.000 51 110.000 51 130.000 102 80.000 52 30.000
i2 0.000 5.000 7.00 8191.500 8191.500 64.000 64.000 12.000 30.000 102.000 ; C3
f103 5.000 256 -7 40.000 51 -6.000 51 8.000 154 70.000
i2 5.000 5.000 7.02 8191.500 8191.500 64.000 64.000 40.000 70.000 103.000 ; D3
f104 6.660 256 -7 -13.400 26 -10.000 230 39.917
i2 6.660 3.335 7.07 8191.500 8191.500 64.000 64.000 -13.400 39.917 104.000 ; G3
In the Csound score of "e", event 'D3' has non-zero initial values on arguments 9 and 10. These values are added to those determined by variations of the "blurb" parameter, thereby giving 40 for argument 9 (the initial value of "blurb") and 70 for argument 10 (the final value). The same calculation is applied to the attached table f103. Consequently, the first and last values of a function table always reflect the initial and final values of the parameter. This allows Csound instruments to operate in a consistent manner, either interpolating the initial and final values, or picking up (and interpolating) the values in the attached function table.
The Bol Processor combines Csound parameters either additively or multiplicatively. For predefined MIDI-mapped parameters, the combination mode is preset: all parameters, except volume, are combined additively. For additional (non-MIDI) parameters, the composer can choose both the default value and the combination mode.
For example, instrument 6 deals with an "oops" parameter that combines multiplicatively. Sound-object "f" contains calls to this instrument with values of "oops" other than the default.
f
i6 0.000 0.500 7.00 0.000 0.000 90.000 90.000 0.000 0.000 0.000 0.500 1.500 0.000 0.000 0.000 0.000 ; C3
i6 0.500 0.500 7.02 0.000 0.000 90.000 90.000 0.000 0.000 0.000 0.000 4.700 0.000 0.000 0.000 0.000 ; D3
i6 1.000 0.500 7.04 0.000 0.000 90.000 90.000 0.000 0.000 0.000 0.250 2.500 0.000 0.000 0.000 0.000 ; E3
_cont(oops) _value(oops,0) f _value(oops,4)
i6 0.000 0.500 7.00 0.000 0.000 90.000 90.000 0.000 0.000 0.000 0.000 2.000 0.000 0.000 0.000 0.000 ; C3
i6 0.500 0.500 7.02 0.000 0.000 90.000 90.000 0.000 0.000 0.000 0.000 12.533 0.000 0.000 0.000 0.000 ; D3
i6 1.000 0.500 7.04 0.000 0.000 90.000 90.000 0.000 0.000 0.000 0.667 10.000 0.000 0.000 0.000 0.000 ; E3
The "oops" parameter varies from 0 to 4 over 1500 ms. At the start of 'D3' and 'E3', its values are 4 * (500 / 1500) = 1.33 and 4 * (1000 / 1500) = 2.66 respectively.
The initial value of "oops" in 'C3' is 0 * 0.5 = 0, and its final value 1.5 * 1.33 = 2, as shown on the score.
The initial value for 'D3' will be O, and for 'E3' it will be 0.25 * 2.66 = 0.665. The value at the end of D3 is 4.7 * 2.66 = 12.5. The value at the end of D3 is 2.5 * 4 = 10.
These examples have been designed to test all the features of the Csound interface as it is implemented in Bol Processor. We expect more to come as both environments continue to explore new concepts and build tools for musicians.
We apologise for the lack of a corpus of real musical pieces created with Bol Processor and Csound. A first example of high musical quality was composed in 1996: read and listen to Sarasvati vina!