Computing ‘ideas’

Dwaram Venkataswamy Naidu playing a violin
Dwaram Venkataswamy Naidu play­ing a vio­lin (cred­it)

A com­po­si­tion in Carnatic musi­cal style by Srikumar K. Subramanian, June 1995. Name: "-gr.trial.mohanam".

This is a non-stop impro­vi­sa­tion of vari­a­tions in a style sim­i­lar to Carnatic music. The com­po­si­tion­al approach here is to decide that each vari­a­tion should con­tain 32 notes and can use up to 20 "ideas". To do this, a flag called Ideas is set to 20 at the begin­ning, and it is decreased by 1 unit in cer­tain rules (such as GRAM#2[2]) or 2 units in oth­ers (such as GRAM#2[3]). See the Flags in gram­mars for more details.

Rules in sub­gram­mar #3 can only be can­di­dates if there are few ideas left, but they do not reduce ideas.

Rules in sub­gram­mar #6 use wild­cards to cre­ate patterns.

Rules in sub­gram­mar #9 cre­ate "effects" by chang­ing velocities.

ORD
GRAM#1[1] S --> _transpose(-5) I /Ideas=20/ /Notes=32/ /NumR=1/

RND
GRAM#2[1] <0> I --> I /NumR+1/ [This rule is only fired on a _goto()]
GRAM#2[2] <20> /Ideas-1/ I --> R1 A R2
GRAM#2[3] <50> /Ideas-2/ I --> A B
GRAM#2[4] <20> /Ideas-1/ I --> R1 B R2
GRAM#2[5] <50> /Ideas-2/ I --> B A

RND
GRAM#3[1] <100> /Ideas/ /NumR-1/ A --> I
GRAM#3[2] <100> /Ideas/ /NumR-1/ B --> I
GRAM#3[3] <1> /Ideas/ I --> I _goto(2,1)

SUB1
GRAM#4[1] I --> lamb­da

RND
GRAM#5[1] <50-12> /Notes-4/ A --> P4
GRAM#5[2] <50-9> /Notes-3/ A --> P3
GRAM#5[3] <50-10> /Notes-2/ A --> P2
GRAM#5[4] <50-12> /Notes-4/ B --> Q4
GRAM#5[5] <50-9> /Notes-3/ B --> Q3
GRAM#5[6] <50-10> /Notes-2/ B --> Q2

RND
GRAM#6[1] R1 ?1 R2 --> ?1 ?1
GRAM#6[2] R1 ?1 ?2 R2 --> ?1 ?2 ?1 ?2
GRAM#6[3] R1 ?1 ?2 ?3 R2 --> ?1 ?2 ?3 ?1 ?2 ?3
GRAM#6[4] R1 ?1 ?2 ?3 ?4 R2 --> ?1 ?2 ?3 ?4 ?1 ?2 ?3 ?4
GRAM#6[5] R1 ?1 ?2 ?3 ?4 ?5 R2 --> ?1 ?2 ?3 ?4 ?5 ?1 ?2 ?3 ?4 ?5

RND
GRAM#7[1] P4 --> P41
GRAM#7[2] P4 --> P42
GRAM#7[3] P4 --> P43
GRAM#7[4] P4 --> P44
GRAM#7[5] P3 --> P31
GRAM#7[6] P3 --> P32
GRAM#7[7] P2 --> P21
GRAM#7[8] P2 --> P22
GRAM#7[9] Q4 --> Q41
GRAM#7[10] Q4 --> Q42
GRAM#7[11] Q4 --> Q43
GRAM#7[12] Q4 --> Q44
GRAM#7[13] Q3 --> Q31
GRAM#7[14] Q3 --> Q32
GRAM#7[15] Q3 --> Q33
GRAM#7[16] Q3 --> Q34
GRAM#7[17] Q2 --> Q21
GRAM#7[18] Q2 --> Q22
GRAM#7[19] Q2 --> Q23

RND
GRAM#8[1] R1 --> lamb­da
GRAM#8[2] R2 --> lamb­da

RND [Effects]
GRAM#9[1] Str ?1 --> _vel(110) ?1 _vel(64)
GRAM#9[2] Step3Up ?1 ?2 ?3 --> _vel(80) ?1 _vel(95) ?2 _vel(110) ?3 _vel(64)
GRAM#9[3] Step3Dn ?1 ?2 ?3 --> _vel(110) ?1 _vel(95) ?2 _vel(80) ?3 _vel(64)
GRAM#9[4] P41 --> sa6 re6 ga6 pa6
GRAM#9[5] P42 --> re6 ga6 pa6 ga6
GRAM#9[7] P43 --> dha6 pa6 ga6 pa6
GRAM#9[9] P44 --> ga6 Str dha6 pa6 Str dha6
GRAM#9[11] P31 --> ga6 pa6 dha6
GRAM#9[13] P32 --> sa6 ga6 re6
GRAM#9[14] P33 --> Str ga6 re6 sa6
GRAM#9[15] P34 --> Str sa7 dha6 pa6
GRAM#9[17] P21 --> ga6 pa6
GRAM#9[19] P22 --> sa6 Str ga6
GRAM#9[20] Q41 --> Str ga6 _ re6 sa6
GRAM#9[22] Q42 --> Str re6 ga6 _ re6
GRAM#9[24] Q43 --> ga6 _ pa6 Str dha6
GRAM#9[26] Q44 --> Str sa6 re6 _ ga6
GRAM#9[28] Q31 --> sa6 _ re6
GRAM#9[29] Q32 --> sa6 _ ga6
GRAM#9[30] Q33 --> Str sa7 dha6
GRAM#9[32] Q34 --> ga6 _ _
GRAM#9[34] Q21 --> ga6 ga6
GRAM#9[36] Q22 --> pa6 pa6
GRAM#9[38] Q23 --> Str dha6 Str dha6 

In the ‘Improvize’ mode, the val­ues of flags and rule weights can be car­ried over from one vari­a­tion to the next. This allows them to be used to trigger/inhibit events at any dis­tance from those that created/modified them.

The fol­low­ing out­put was record­ed on a Roland D-50 synthesiser.

Undetermined rests in dance performance

The polyrhyth­mic piece "765432" com­posed by Andréine Bel for her CRONOS dance pro­duc­tion (1994) illus­trates the use of unde­ter­mined rests. Six dancers were on stage: Suresh Shetty, Smriti Mishra, Olivier Rivoirard, Vijayshree Chaudhary, Arindam Dasgupta and Andréine Bel.

In this gram­mar, "SUB1" indi­cates a sub­sti­tu­tion that only needs to be per­formed once. Using it to replace "SUB" saves com­pu­ta­tion time.

Glyphs "" are unde­ter­mined rests, i.e. silences whose dura­tion is a pri­ori unknown and will be pre­cise­ly cal­cu­lat­ed by the poly­met­ric expan­sion algorithm.

The whole struc­ture is based on reg­u­lar arith­metic divi­sions. For exam­ple, Suresh moves at "speed 7", Smriti at "speed 6" and Olivier at "speed 5".

"CR47" and "C46" are patch­es from the Roland D-50 synthesiser.

ORD
GRAM#1[1] S --> Internal C47 Part1 Canon C46 _vel(90) Part2
GRAM#1[2] Part1 --> {Suresh1, Smriti1, Olivier1, Vijayshree1, Arindam1, Andreine1}
GRAM#1[3] Part2 --> {Suresh2, Smriti2 , Olivier2 , Vijayshree2 , Arindam2 , Andreine2 }
GRAM#1[4] Internal --> _script(MIDI con­troller #98 = 0 chan­nel 1) [D50 stuff]

ORD
GRAM#2[1] Suresh1 --> SuMov7x7 SuSil7x7 SuMov6x7 SuSil6x7 SuMov5x7 SuSil5x7 SuMov4x7 SuSil4x7 SuMov3x7 SuSil3x7 SuMov2x7 SuSil2x7 SuMov1x7 SuSil1x7
GRAM#2[2] Smriti1 --> SmMov6x6 SmSil6x6 SmMov5x6 SmSil5x6 SmMov4x6 SmSil4x6 SmMov3x6 SmSil3x6 SmMov2x6 SmSil2x6 SmMov1x6 SmSil1x6
GRAM#2[3] Olivier1 --> OlMov5x5 OlSil5x5 OlMov4x5 OlSil4x5 OlMov3x5 OlSil3x5 OlMov2x5 OlSil2x5 OlMov1x5 OlSil1x5
GRAM#2[4] Vijayshree1 --> ViMov4x4 ViSil4x4 ViMov3x4 ViSil3x4 ViMov2x4 ViSil2x4 ViMov1x4 ViSil1x4
GRAM#2[5] Arindam1 --> ArMov3x3 ArSil3x3 ArMov2x3 ArSil2x3 ArMov1x3 ArSil1x3
GRAM#2[6] Andreine1 --> AnMov2x2 AnSil2x2 AnMov1x2 AnSil1x2

ORD
GRAM#3[1] Suresh2 --> SuMov7x7 SuMov6x6 SuMov5x5 SuMov4x4 SuMov3x3 SuMov2x2 SuMov1x1
GRAM#3[2] Smriti2 --> SmMov6x6 SmMov5x5 SmMov4x4 SmMov3x3 SmMov2x2 SmMov1x1
GRAM#3[3] Olivier2 --> OlMov5x5 OlMov4x4 OlMov3x3 OlMov2x2 OlMov1x1
GRAM#3[4] Vijayshree2 --> ViMov4x4 ViMov3x3 ViMov2x2 ViMov1x1
GRAM#3[5] Arindam2 --> ArMov3x3 ArMov2x2 ArMov1x1
GRAM#3[6] Andreine2 --> AnMov2x2 AnMov1x1

ORD
GRAM#4[1] SuMov1x7 --> SuCycle7
GRAM#4[2] SuSil1x7 --> SuMov1x7
GRAM#4[3] SuMov2x7 --> SuCycle7 SuCycle7
GRAM#4[4] SuSil2x7 --> SuMov2x7
GRAM#4[5] SuMov3x7 --> SuCycle7 SuCycle7 SuCycle7
GRAM#4[6] SuSil3x7 --> SuMov3x7
GRAM#4[7] SuMov4x7 --> SuCycle7 SuCycle7 SuCycle7 SuCycle7
GRAM#4[8] SuSil4x7 --> SuMov4x7
GRAM#4[9] SuMov5x7 --> SuCycle7 SuCycle7 SuCycle7 SuCycle7 SuCycle7
GRAM#4[10] SuSil5x7 --> SuMov5x7
GRAM#4[11] SuMov6x7 --> SuCycle7 SuCycle7 SuCycle7 SuCycle7 SuCycle7 SuCycle7
GRAM#4[12] SuSil6x7 --> SuMov6x7
GRAM#4[13] SuMov7x7 --> SuCycle7 SuCycle7 SuCycle7 SuCycle7 SuCycle7 SuCycle7 SuCycle7
GRAM#4[14] SuSil7x7 --> SuMov7x7
GRAM#4[15] SuMov1x1 --> SuCycle1
GRAM#4[16] SuSil1x1 --> SuMov1x1
GRAM#4[17] SuMov2x2 --> SuCycle2 SuCycle2
GRAM#4[18] SuSil2x2 --> SuMov2x2
GRAM#4[19] SuMov3x3 --> SuCycle3 SuCycle3 SuCycle3
GRAM#4[20] SuSil3x3 --> SuMov3x3
GRAM#4[21] SuMov4x4 --> SuCycle4 SuCycle4 SuCycle4 SuCycle4
GRAM#4[22] SuSil4x4 --> SuMov4x4
GRAM#4[23] SuMov5x5 --> SuCycle5 SuCycle5 SuCycle5 SuCycle5 SuCycle5
GRAM#4[24] SuSil5x5 --> SuMov5x5
GRAM#4[25] SuMov6x6 --> SuCycle6 SuCycle6 SuCycle6 SuCycle6 SuCycle6 SuCycle6
GRAM#4[26] SuSil6x6 --> SuMov6x6

ORD
GRAM#5[1] SmMov1x6 --> SmCycle6
GRAM#5[2] SmSil1x6 --> SmMov1x6
GRAM#5[3] SmMov2x6 --> SmCycle6 SmCycle6
GRAM#5[4] SmSil2x6 --> SmMov2x6
GRAM#5[5] SmMov3x6 --> SmCycle6 SmCycle6 SmCycle6
GRAM#5[6] SmSil3x6 --> SmMov3x6
GRAM#5[7] SmMov4x6 --> SmCycle6 SmCycle6 SmCycle6 SmCycle6
GRAM#5[8] SmSil4x6 --> SmMov4x6
GRAM#5[9] SmMov5x6 --> SmCycle6 SmCycle6 SmCycle6 SmCycle6 SmCycle6
GRAM#5[10] SmSil5x6 --> SmMov5x6
GRAM#5[11] SmMov6x6 --> SmCycle6 SmCycle6 SmCycle6 SmCycle6 SmCycle6 SmCycle6
GRAM#5[12] SmSil6x6 --> SmMov6x6
GRAM#5[13] SmMov1x1 --> SmCycle1
GRAM#5[14] SmSil1x1 --> SmMov1x1
GRAM#5[15] SmMov2x2 --> SmCycle2 SmCycle2
GRAM#5[16] SmSil2x2 --> SmMov2x2
GRAM#5[17] SmMov3x3 --> SmCycle3 SmCycle3 SmCycle3
GRAM#5[18] SmSil3x3 --> SmMov3x3
GRAM#5[19] SmMov4x4 --> SmCycle4 SmCycle4 SmCycle4 SmCycle4
GRAM#5[20] SmSil4x4 --> SmMov4x4
GRAM#5[21] SmMov5x5 --> SmCycle5 SmCycle5 SmCycle5 SmCycle5 SmCycle5
GRAM#5[22] SmSil5x5 --> SmMov5x5

ORD
GRAM#6[1] OlMov1x5 --> OlCycle5
GRAM#6[2] OlSil1x5 --> OlMov1x5
GRAM#6[3] OlMov2x5 --> OlCycle5 OlCycle5
GRAM#6[4] OlSil2x5 --> OlMov2x5
GRAM#6[5] OlMov3x5 --> OlCycle5 OlCycle5 OlCycle5
GRAM#6[6] OlSil3x5 --> OlMov3x5
GRAM#6[7] OlMov4x5 --> OlCycle5 OlCycle5 OlCycle5 OlCycle5
GRAM#6[8] OlSil4x5 --> OlMov4x5
GRAM#6[9] OlMov5x5 --> OlCycle5 OlCycle5 OlCycle5 OlCycle5 OlCycle5
GRAM#6[10] OlSil5x5 --> OlMov5x5
GRAM#6[11] OlMov1x1 --> OlCycle1
GRAM#6[12] OlSil1x1 --> OlMov1x1
GRAM#6[13] OlMov2x2 --> OlCycle2 OlCycle2
GRAM#6[14] OlSil2x2 --> OlMov2x2
GRAM#6[15] OlMov3x3 --> OlCycle3 OlCycle3 OlCycle3
GRAM#6[16] OlSil3x3 --> OlMov3x3
GRAM#6[17] OlMov4x4 --> OlCycle4 OlCycle4 OlCycle4 OlCycle4
GRAM#6[18] OlSil4x4 --> OlMov4x4

ORD
GRAM#7[1] ViMov1x4 --> ViCycle4
GRAM#7[2] ViSil1x4 --> ViMov1x4
GRAM#7[3] ViMov2x4 --> ViCycle4 ViCycle4
GRAM#7[4] ViSil2x4 --> ViMov2x4
GRAM#7[5] ViMov3x4 --> ViCycle4 ViCycle4 ViCycle4
GRAM#7[6] ViSil3x4 --> ViMov3x4
GRAM#7[7] ViMov4x4 --> ViCycle4 ViCycle4 ViCycle4 ViCycle4
GRAM#7[8] ViSil4x4 --> ViMov4x4
GRAM#7[9] ViMov1x1 --> ViCycle1
GRAM#7[10] ViSil1x1 --> ViMov1x1
GRAM#7[11] ViMov2x2 --> ViCycle2 ViCycle2
GRAM#7[12] ViSil2x2 --> ViMov2x2
GRAM#7[13] ViMov3x3 --> ViCycle3 ViCycle3 ViCycle3
GRAM#7[14] ViSil3x3 --> ViMov3x3

ORD
GRAM#8[1] ArMov1x3 --> ArCycle3
GRAM#8[2] ArSil1x3 --> ArMov1x3
GRAM#8[3] ArMov2x3 --> ArCycle3 ArCycle3
GRAM#8[4] ArSil2x3 --> ArMov2x3
GRAM#8[5] ArMov3x3 --> ArCycle3 ArCycle3 ArCycle3
GRAM#8[6] ArSil3x3 --> ArMov3x3
GRAM#8[7] ArMov1x1 --> ArCycle1
GRAM#8[8] ArSil1x1 --> ArMov1x1
GRAM#8[9] ArMov2x2 --> ArCycle2 ArCycle2
GRAM#8[10] ArSil2x2 --> ArMov2x2

ORD
GRAM#9[1] AnMov1x2 --> AnCycle2
GRAM#9[2] AnSil1x2 --> AnMov1x2
GRAM#9[3] AnMov2x2 --> AnCycle2 AnCycle2
GRAM#9[4] AnSil2x2 --> AnMov2x2
GRAM#9[5] AnMov1x1 --> AnCycle1
GRAM#9[6] AnSil1x1 --> AnMov1x1

ORD
GRAM#10[1] Canon --> Twist Walk Stretch Bend Jump Turn
GRAM#10[2] Twist --> Sm Tik Tik Tik Tik Tik Su Tik Tik Tik Tik Ol Tik Tik Tik Ar Tik Tik Vi Tik An
GRAM#10[3] Walk --> Sm Su Tik Ol Tik Tik Ar Tik Tik Tik Vi Tik Tik Tik Tik An Tik Tik Tik Tik Tik
GRAM#10[4] Stretch --> Twist
GRAM#10[5] Bend --> Walk
GRAM#10[6] Jump --> Twist
GRAM#10[7] Turn --> Walk

SUB1
GRAM#11[1] SuCycle7 --> Su Tik Tik Tik Tik Tik Tik
GRAM#11[2] SuCycle6 --> Su Tik Tik Tik Tik Tik
GRAM#11[3] SuCycle5 --> Su Tik Tik Tik Tik
GRAM#11[4] SuCycle4 --> Su Tik Tik Tik
GRAM#11[5] SuCycle3 --> Su Tik Tik
GRAM#11[6] SuCycle2 --> Su Tik
GRAM#11[7] SuCycle1 --> Su
GRAM#11[8] SmCycle6 --> Sm - - - - -
GRAM#11[9] SmCycle5 --> Sm - - - -
GRAM#11[10] SmCycle4 --> Sm - - -
GRAM#11[11] SmCycle3 --> Sm - -
GRAM#11[12] SmCycle2 --> Sm -
GRAM#11[13] SmCycle1 --> Sm
GRAM#11[14] OlCycle5 --> Ol - - - -
GRAM#11[15] OlCycle4 --> Ol - - -
GRAM#11[16] OlCycle3 --> Ol - -
GRAM#11[17] OlCycle2 --> Ol -
GRAM#11[18] OlCycle1 --> Ol
GRAM#11[19] ViCycle4 --> Vi - - -
GRAM#11[20] ViCycle3 --> Vi - -
GRAM#11[21] ViCycle2 --> Vi -
GRAM#11[22] ViCycle1 --> Vi
GRAM#11[23] ArCycle3 --> Ar - -
GRAM#11[24] ArCycle2 --> Ar -
GRAM#11[25] ArCycle1 --> Ar
GRAM#11[26] AnCycle2 --> An -
GRAM#11[27] AnCycle1 --> An

SUB1
GRAM#12[1] Su --> {1,do4-}
GRAM#12[2] Sm --> {1,mi4-}
GRAM#12[3] Ol --> {1,sol4-}
GRAM#12[4] Vi --> {1,do5-}
GRAM#12[5] Ar --> {1,mi5-}
GRAM#12[6] An --> {1,sol5-}
GRAM#12[7] Tik --> {1,do7-}

The fol­low­ing out­put was record­ed on a Roland D-50 synthesiser.

This per­for­mance was part of the chore­o­graph­ic work CRONOS per­formed at the National Centre for the Performing Arts (Mumbai, India) and the Shri Ram Center (Delhi) in October 1994. An excerpt is shown from 4mn 50s to 5mn 10s:

References

Tutorials

No posts found.

Time patterns (smooth time)

The fol­low­ing is a sim­ple gram­mar illus­trat­ing the use of time pat­terns in smooth time. Whereas stri­at­ed time is filled with (reg­u­lar or irreg­u­lar) puls­es, smooth time does not involve counting.

_mm(120.0000) _smooth

GRAM#1[1] S --> {10 , t1 t2 , Part1 Part2}
GRAM#1[2] Part1 --> {t1 t3 t4 , C4 D4 E4 F4 - A4}
GRAM#1[3] Part2 --> {t3 t1 , B4 C5 _ E5}

TIMEPATTERNS:
t1 = 1/1  t2 = 3/2   t3 = 4/3  t4  = 1/2

In this gram­mar, "t1", "t2" etc. are the time pat­terns arranged in such a way that they define a struc­ture of (irreg­u­lar) "beats" on which notes "C4", "D4" etc. will be located.

The final arrange­ment is as follows:

{10, t1 t2, {t1 t3 t4, C4 D4 E4 F4 - A4} {t3 t1, B4 C5 _ E5}}

A sequence of sim­ple notes ‘C4’, ‘D4’,…, arranged against a lat­tice of time-objects ‘t1’, ‘t2’,…, result­ing in an irreg­u­lar "beat" struc­ture in smooth time.

Time flex­i­bil­i­ty in Bol Processor is not the effect of arbi­trary numer­i­cal func­tions.  This flex­i­bil­i­ty stems from a time struc­ture — Xenakis’ (1963) struc­ture tem­porelle — that is deeply inter­wo­ven with the syn­tac­tic descrip­tion of music.

If stri­at­ed time is select­ed, the same struc­ture will be dis­played as shown below:

The same sequence of notes in stri­at­ed time. In this case,
time-objects ‘t1’, ‘t2’, etc., have null durations.

Some time pat­terns were used in Andréine Bel's chore­o­graph­ic work: Shapes in Rhythm.

Reference

Interactive improvisation with sound-objects

Lady play­ing koto. Public domain, source: Wikimedia

This gram­mar (name­ly “-gr.koto3") is an impro­vi­sa­tion mod­el run­ning on the Bol Processor BP2 con­nect­ed to a Roland D-50 syn­the­sis­er. The choice of syn­the­sis­er was cru­cial for a good repro­duc­tion of the sound imi­tat­ing a Japanese koto.

The under­ly­ing mod­el (SUB gram­mar) is a one-dimensional cel­lu­lar automa­ton using sub­sti­tu­tion rules: at each step of the com­pu­ta­tion, a set of ran­dom­ly select­ed rules is applied to the work string. Conversely, in a RND gram­mar, a new rule would be select­ed each time the pre­vi­ous one was applied. For more details, see a pre­sen­ta­tion of "-gr.koto3" on the Bol Processor ‘BP3’ and its PHP inter­face page.

In sub­gram­mar #2 we see a com­pe­ti­tion between con­struc­tive rules, such as gram#2[8] and gram#2[11] which increase the length of the work string, and destruc­tive rules, such as gram#2[10] and gram#2[15] which decrease its length.

The weight of gram#2[12], ini­tial­ly set to 100, decreas­es by 10 each time it is applied, until the rule is invalidated.

SUB
gram#1[1] <100> S --> _vel(127) _volume(40) X X X X Y X X X X Y X X X X
gram#1[2] <K9> X --> a  [Weight is controlled by K9, see Interaction]
gram#1[3] X  --> b
-----
SUB
gram#2[1] Y --> Y
gram#2[2] #? ?1 --> #? ?1  [Keep leftmost symbol]
gram#2[3] ?1 #? --> ?1 #?  [Keep rightmost symbol]
gram#2[4] } --> }
gram#2[5] , --> ,
gram#2[6] <5> a --> a
gram#2[7] <30> a b a --> a a
gram#2[8] <100> #({) a b a --> {5,a c b,f f f - f}
gram#2[9] <5> b --> b
gram#2[10] <30> #({) b a b #(}) --> b b
gram#2[11] <100> #({) b a b --> {3,b a b c b a,f a f}
gram#2[12] <100-10> #({) #a b #(}) --> #a c b
gram#2[13] c c c -->  c a c
gram#2[14] c a c --> b a b
gram#2[15] <50> ?1 ?1 ?2 ?3 ?4 ?4 --> ?2 ?3
gram#2[16] <K9> ?1 ?1 ?1 --> ?1
gram#2[17] <K9> ?1 ?1 --> ?1
-----
SUB
gram#3[1] <40> Y --> <<f>>
gram#3[2] <50> Y --> <<chik>>
gram#3[3] <1-1> ? #? --> ? Silence _script(MIDI send Continue) #?
gram#3[4] <50> Silence --> - - - - -
gram#3[5] <15> Silence --> - - - -
gram#3[6] <8> Silence --> - - -
gram#3[7] <8> Silence --> - -

Rules in sub­gram­mar #2 are applied until none of them can be a can­di­date. Then the rules in sub­gram­mar #3 are applied, pro­duc­ing the out-time sound-objects <<f>> (a bass note) and <<chick>> (a chord).

The sound objects "a", "b", "c", "f", "chick" are defined in a sound-object pro­to­type file called "-so.koto3". Some of them have spe­cif­ic prop­er­ties that force a relo­ca­tion to sat­is­fy topo­log­i­cal con­straints. For exam­ple, "a" must main­tain con­ti­nu­ity with the pre­ced­ing object (as shown in the image), which may cause it to be moved into the past.

The time-setting algo­rithm takes into account all the con­straints to cre­ate a piece that may not fit exact­ly into the metro­nom­ic beat pat­tern. Below is an exam­ple of the final piece cre­at­ed using this gram­mar (played 3 times):

A piece gen­er­at­ed by "-gr.koto3" played on a Roland D-50 synthesiser

In this gram­mar, para­me­ter K9 is set to fol­low the posi­tion of a con­troller (e.g. the pitch­bend or a ped­al on the D-50), assign­ing a val­ue from 0 to 100. This val­ue is the weight of the rules gram#1[2], gram#2[16] and gram#2[17]. The high­er the weight, the more "a" and the less "b" in the string; in addi­tion, the final string becomes small­er due to the high­er weight of the destruc­tive rules gram#2[16] and gram#2[17].

During the impro­vi­sa­tion, the work string is played at each step of its trans­for­ma­tion. The end of the trans­for­ma­tion is indi­cat­ed by the <<f>> and <<chick>> sound-objects.

Below is an exam­ple of impro­vi­sa­tion played in real time MIDI:

An improviza­tion of "-gr.koto3" pro­duced by BP2.9.8 and played on a Roland D-50 synthesiser

The fol­low­ing video illus­trates the gram­mar at work on BP2.9.8 — unfor­tu­nate­ly with a GeneralMIDI "koto" sound:

References

A beginner's tutorial

By Harm Visser, 2007

Let us take a look to the ideas and his­tor­i­cal back­ground of BP2. At the end of the fifties the lin­guis­tic sci­en­tist Noam Chomsky wrote his famous book 'Syntactic Structures'. It was an attempt to gen­er­al­ize the struc­ture of lan­guage in a sys­tem of rewrite-rules, so called 'gram­mars':

Sentence --> NP + VP
NP --> T + N
VP --> Verb + NP
T --> The
N --> man, ball..
Verb -> hit, took…

When we com­put­er­ize such a gram­mar and we give the com­mand 'derive' we should see that Sentence became NP + VP, NP became T + N, VP became Verb + NP etc. At the end we see that N became 'man' and Verb became 'hit'. No fur­ther deriva­tion is pos­si­ble. The words 'man', 'hit' are there­fore called 'ter­mi­nal symbols'.

After deriva­tion of Sentence we should read: the man hit… (or what­ev­er). Such a Chomsky 'gram­mar' can be seen as a set of rules to gen­er­ate well-formed English sentences.

You can read a rule as 'X --> Y'. It gives the 'instruc­tion' to rewrite X as Y (X becomes Y). Maybe you can imag­ine already that such a grammar-system can also apply to musi­cal syntax.

Let us there­fore com­pare the Chomsky-example with this BP2-example:

S(entence) --> X Y
X --> Motif1
Y --> Motif2
Motif1 --> C3
Motif2 --> D3

After deriva­tion we should hear the ter­mi­nal sym­bols C3 D3.

The main dif­fer­ence between the 'Chomsky-grammar' and a BP2-grammar is that a BP2-grammar is exclu­sive. It is a for­mal­i­sa­tion of one par­tic­u­lar piece of music. Chomsky-grammars try to gen­er­al­ize lan­guage as a whole.

At the oth­er hand you can in BP2 'for­mal­ize' the sonata-form:

S --> Sonata
Sonata --> Theme1 Theme2 Development Coda
Theme1 --> Notes1
Theme2 --> Notes2
Development VariateNotes1 VariateNotes2
Coda --> HalfTheme1 HalfTheme2

When we derive the Sonata, we shall hear noth­ing, because there are no ter­mi­nal sym­bols i.c. 'real notes', like C3, D2, etc. So let's fin­ish the Sonata:

S --> Sonata
Sonata --> Theme1 Theme2 Development Coda
Theme1 --> Notes1
Theme2 --> Notes2
Development --> VariateNotes1 VariateNotes2
Coda --> HalfTheme1 HalfTheme2
Notes1 --> A3 B3 A3 G3
Notes2 --> D3 E3 F3 A3
VariateNotes1 --> _transpose(2) Notes1
VariateNotes2 --> _retro Notes2
HalfTheme1 --> A3 B3
HalfTheme2 --> D3 E3

Note that we use for VariateNotes1 and VariateNotes2 the tools _transpose(2) and _retro.

_transpose(x) trans­pos­es up or down at a giv­en inter­val: _transpose(2) (two semi­tone up), _transpose(6) (six semi­tones up) _transpose(-7) (sev­en semi­tones down). You can also use val­ues like _transpose(0.2).

The _retro tool stands of course for 'ret­ro­grade'. It turns the sym­bols back­wards. You can read com­mands like _transpose and _retro as 'trans­form­ers'.

Well, let's lis­ten to this Sonata! Select S and 'Play selection':

A3 B3 A3 G3 D3 E3 F3 A3 _transpose(2) A3 B3 A3 G3 E3 D3 B3 A3 A3 F3 E3 D3

A piano-roll dis­play of the Sonata

There are two impor­tant things to remember

  1. When you write a vari­able like Theme1 or VariateNotes2 or Sonata (yes, these are vari­ables until you give them a 'con­tent'), start the vari­able with a cap­i­tal and don't use emp­ty spaces between sym­bols. So Not 'sonata', but 'Sonata'. Not 'n1', but 'N1', not 'my piece', but 'Mypiece'.
  2. You can lis­ten to every stage or lev­el of your piece at every moment. So, instead select­ing S, you can select Notes1 or Development, or G3… In oth­er words, you can lis­ten to every com­pos­i­to­r­i­al detail! Try to make your own Sonata now!

Note that the example-Sonata is also a descrip­tion of the actu­al piece. That is to say that the first half is the descrip­tion, the sec­ond half is the 'real­i­sa­tion' of the descrip­tion. This approach means that a descrip­tion can also have a 'sub­de­scrip­tion', while the sub­de­scrip­tion can have… indeed, a sub­sub­de­crip­tion. So BP2 is the per­fect tool for hier­ar­chi­cal descrip­tions of musi­cal structures.


Random selection of an item in a fixed-cardinal set

Typical application

Select can­di­date rules in a gen­er­a­tive gram­mar ran­dom­ly and apply them to the work­string until there is no more can­di­date rule.

Problem

To stop the process it is nec­es­sary to scan the entire gram­mar and make sure that there is no more can­di­date rule. Each time the work­string has changed, the "can­di­date / non can­di­date" sta­tus of each rule in the gram­mar may vary. Since scan­ning "N" rules in the gram­mar is time con­sum­ing, it is prefer­able to do it only after "max­try" unsuc­cess­ful attempts to find a can­di­date. The prob­lem inves­ti­gat­ed here is to find a min­i­mum "max­try" mak­ing it almost sure that there is no more candidate.

Related problem

Sometimes a select­ed rule must be applied repeat­ed­ly until it is no more can­di­date. If the posi­tion of deriva­tion in the work­string is ran­dom then the prob­lem amounts to select­ing one amongst "can­di­date" or "non can­di­date" posi­tions in a set whose car­di­nal "N" is the length of the workstring.

To summarize…

The two exam­ples above may be abstract­ed to the repeat­ed ran­dom selec­tion of an item in a set con­taing N items. The algo­rithm of a gen­er­al pro­ce­dure is giv­en below. The prob­lem is to eval­u­ate "max­try" so that in the worst case the prob­a­bil­i­ty of heuris­tic [2] being true is greater than a giv­en prob­a­bil­i­ty "p".

ScanSet()
    Return number of candidate items;

FoundItem()
    Select an item;
    Return "yes" if item is candidate, "no" otherwise;

Procedure()
    Evaluate maxtry;
    Start:
    nb_candidates = ScanSet();
    if (nb_candidates = 0) exit;
    if (nb_candidates = 1)
        Use candidate item found;
        Go to Start;
        [Heuristic 1: if there was a unique candidate item
then next time there should be less than two.]
    Again:
    repeat with try = 1 to maxtry
        if (FoundItem()) then
            Use candidate item found;
            Go to Again;
            [Heuristic 2: if try < maxtry there may still be
candidate items.]
Go to Start;

Solution

Let "k" be the num­ber of can­di­date items. The prob­a­bil­i­ty to find a can­di­date item after (maxtry-1) unsuc­cess­ful attempts is:

  1 - (1 - k/N)^maxtry

If k = 1 then the Scan() pro­ce­dure will find the unique can­di­date item. Therefeore the worst case is k = 2 and the con­di­tion is:

  1 - (1 - 2/N)^maxtry > p

yield­ing:

  maxtry > Log(1 - p) / Log(1 - 2/N)

i.e., if 2/N is much small­er than 1,

  maxtry > - N/2 Log(1 - p)

In Bol Processor, we imposed p = 0.64 so that max­try > N/2.

Indeed, this method is only valid if items have equal weights.

Examples

Harm Visser's examples
A pre­sen­ta­tion and dis­cus­sion of a few exam­ples com­posed on the Bol Processor by Harm Visser in 1998 …
Interactive improvisation with sound-objects
An inter­ac­tive BP2 gram­mar using sub­sti­tu­tion rules to cre­ate a uni­di­men­sion­al cel­lu­lar automa­ton …
A polyrhyth­mic piece "765432" com­posed by Andréine Bel for her CRONOS dance pro­duc­tion (1994) illus­trates the use of unde­ter­mined rests …
Dwaram Venkataswamy Naidu playing a violin
A com­po­si­tion in Carnatic musi­cal style by Kumar S. Subramanian, June 1995 …
Grammar "-gr.ShapesInRhythm" was com­posed by Andréine Bel for her CRONOS dance pro­duc­tion (1994) …
Sarasvati vina
Full descrip­tion of a musi­cal phrase com­posed in 1995 by Srikumar Karaikudi Subramanian with the Bol Processor and Csound …
Dice animation
Bol Processor's imple­men­ta­tion of a musi­cal dice game attrib­uted to Wolfgang Amadeus Mozart …
Importing MusicXML scores
Importing MusicXML scores to Bol Processor BP3 …
Comparing temperaments
Images of tem­pered scales cre­at­ed by the Bol Processor The fol­low­ing are Bol Processor + Csound inter­pre­ta­tions of J.-S. Bach's …
The Well-tempered Clavier
The com­plete set of pre­ludes and fugues by J.S. Bach known as The Well-tempered Clavier, books II and II, inter­pret­ed with pre­sum­ably "opti­mal" tun­ing schemes …

Harm Visser's examples

In Computer Music Journal 22,2 (1998) page 63, Dutch com­pos­er Visser commented:

I think that the devel­op­ment of more and more visu­al stuff cur­tails the pos­si­bil­i­ty of "think­ing in your chair." Sometimes I devel­op gram­mars, not at the com­put­er, but sit­ting with a pen­cil and paper. With pro­grams [oth­er than BP2] this is not pos­si­ble: you must sit in front of the com­put­er. The dif­fer­ence lies in the type of atten­tion that each soft­ware envi­ron­ment demands on the part of the com­pos­er, and indeed reflects on the way s/he thinks about music.

The fol­low­ing is a pre­sen­ta­tion and dis­cus­sion of some exam­ples writ­ten on the Bol Processor by Harm Visser in 1998. All exam­ples shown on this page are avail­able in the sam­ple set bp3-ctests-main.zip shared on GitHub. Follow the instruc­tions on the Bol Processor ‘BP3’ and its PHP inter­face page to install BP3 and learn its basic oper­a­tion. Download and install Csound from its dis­tri­b­u­tion page.

Period notation

In the same way as it deals with super­im­posed sequences, the poly­met­ric expan­sion algo­rithm com­putes equal sym­bol­ic dura­tions between beat sep­a­ra­tors notat­ed ‘’ — name­ly, the peri­od nota­tion.  A note sequence in peri­od nota­tion and the context-free gram­mar from which it is derived are shown below. In this exam­ple, the beats con­tain an increas­ing num­ber of notes, result­ing in an accel­er­at­ing movement.

S --> _vel(60) A B _vel(65) C D _vel(70) E F _vel(75) G _vel(77) H _vel(80) I _vel(85) J _vel(87) K _vel(90) L
A --> E2
B --> D2 A
C --> B2 B
D --> G2 C
E --> F#2 D
F --> A#2 E
G --> C2 F
H --> G#2 G
I --> A2 H
J --> D#2 I
K --> C#2 J
L --> F2 K

The "_vel" oper­a­tor is a veloc­i­ty con­trol that pro­duces a grad­u­al­ly increas­ing vol­ume of the piece. This gram­mar pro­duces the fol­low­ing "score":

_vel(60) E2 • D2 E2 •_vel(65) B2 D2 E2 • G2 B2 D2 E2 • _vel(70) F#2 G2 B2 D2 E2 • A#2 F#2 G2 B2 D2 E2 • _vel(75) C2 A#2 F#2 G2 B2 D2 E2 • _vel(77) G#2 C2 A#2 F#2 G2 B2 D2 E2 • _vel(80) A2 G#2 C2 A#2 F#2 G2 B2 D2 E2 • _vel(85) D#2 A2 G#2 C2 A#2 F#2 G2 B2 D2 E2 • _vel(87) C#2 D#2 A2 G#2 C2 A#2 F#2 G2 B2 D2 E2 • _vel(90) F2 C#2 D#2 A2 G#2 C2 A#2 F#2 G2 B2 D2 E2 •

and the fol­low­ing piano-roll rep­re­sen­ta­tion with the sound exam­ple on a Pianoteq syn­the­sis­er:

Serial tools

The fol­low­ing gram­mar pro­duces a 10-minute piece of music with only 12 rules and 3 notes (C3, D4, F#3). It is an illus­tra­tion of Visser's mot­to: "com­pos­ing with a pen­cil and paper".

The rhyth­mic com­plex­i­ty is the result of the use of poly­met­ric expres­sions: the super­im­po­si­tion of sequences list­ed between curly brack­ets {} and the resiz­ing of "beats" thanks to the peri­od mark­er ''.

The length and com­plex­i­ty of the piece is achieved by using mutu­al­ly recur­sive rules. For exam­ple, rule gram#2[2] pro­duces "Mel1" which is rewrit­ten by rule gram#2[1].

Three "ser­i­al tools" are used:

  • _transpose(n) shifts the fol­low­ing sequence up by n semitones
  • _rotate(x) rotates the fol­low­ing sequence by x units
  • _keyxpand(basenote, ratio) mul­ti­plies melod­ic inter­vals by ratio rel­a­tive to the basenote. For exam­ple, _keyxpand(C4, 2) would replace the sequence D4 E4 F4 with E4 G#4 Bb4. This tool is applied recur­sive­ly to the fields of a poly­met­ric expres­sion.

ORD
gram#1[1] S --> _vel(80) _rndvel(20) Melos1 Melos2 Melos3
gram#1[2] Melos1 --> Mel1 Mel2 Mel3
gram#1[3] Melos2 --> _transpose(11) Melos1
gram#1[4] Melos3 --> _transpose(5) Melos1 - Melos2

ORD
gram#2[1] Mel1 --> M1 - - - - - M2 - - M3 M4 - - M5
gram#2[2] Mel2 --> _transpose(-11) Mel1
gram#2[3] Mel3 --> _transpose(6) _rotate(-1) {Mel1 - Mel2}

ORD
gram#3[1] M1 --> C3 - • D4 F#3 _keyxpand(B3,-1) C3 - D3 F#2
gram#3[2] M2 --> _transpose(2) M1
gram#3[3] M3 --> _transpose(-6) _rotate(-2) {M1 M2, _keyxpand(C3,-1) M1}
gram#3[4] M4 --> C3 D4 F#3 _keyxpand(B3,-1) C3 D3 F#2
gram#3[5] M5 --> _keyxpand(B4,-1) {M4, _vel(100) M1} {M2, M3}

Note that all the sub­gram­mars are head­ed with "ORD", which means that the rules are applied in order rather than ran­dom­ly. Thus, this gram­mar pro­duces a unique piece of music, as is the case with all exam­ples com­posed by Harm Visser. The only sto­chas­tic ele­ment in this piece is the veloc­i­ty, which can vary between 60 and 100 due to the per­for­mance con­trols _vel(80) _rndvel(20).

The sound out­put was played on a Pianoteq synthesiser:

Trills

The fol­low­ing gram­mar pro­duces trills that take advan­tage of tem­po vari­a­tions and con­tin­u­ous veloc­i­ty variations:

ORD
gram#1[1] S --> _script(Wait for space) _staccato(50) Shapes
gram#1[2] Shapes --> Part1 {_rotate(20) _transpose(2) Part1} Part2 Part3 {_tempo(0.7) Part3} Part4

ORD
gram#2[1] Part1 --> {M1 Trill1 M2 Trill2 Int1 Int2 Trill3 Int3 1/4}
gram#2[2] Part2 --> {M3 M4 M5 1/4 Trill4 1/4 Trill4 Trill4 1/4 Trill5 M6 1/4 Trill6 Trill7 Trill8 1/4 Trill9 Trill10 1/4 M5 M4 M3 M6 {_rotate(6) _transpose(23) M6} 1/4 Int3 Int2 Int1 _rotate(23) Part1} Trill3
gram#2[3] Part3 --> {1 {M3, M4} 2, _transpose(12) Trill1} _transpose(-11) {1 {M3, M4} 2, _transpose(12) Trill1}
gram#2[4] Part4 --> {Trill12, Trill11} {Trill10, Trill1} {Trill9 Trill10, Trill2} {_transpose(11) {M3, Trill2}} {M3, _transpose(12) Trill3} {Trill10, Trill1} {Trill9 Trill10, Trill2} {_tempo(2/3) Trill10} {M3, M4} {_tempo(1/2) Trill10} 1/4 _transpose(12) Trill9

ORD
gram#3[1] M1 --> {_velcont _vel(40) _transpose(12) _tempo(7) C0 C2 C4 C6 _vel(60) _tempo(6) Bb4 G3 F2 B2 G3 _vel(80) _tempo(8) A2 B1 F#1 G2 A3 C#4 E3 G2 _vel(40) _tempo(6) Bb1 C#1 G0 _tempo(5) G#1 A2 A3 Bb4 _vel(90)}
gram#3[2] M2 --> {_keyxpand(C4,-1) M1}
gram#3[3] M3 --> {_velcont _vel(40) _transpose(12) _tempo(7) C0 C2 {C4, C6} _vel(100) _tempo(6) Bb4 G3 F2 {B2, G3} _vel(80) _tempo(8) A2 B1 F#1 G2 A3 C#4 {E3, G2} _vel(50) _tempo(6) Bb1 C#1 G0 _tempo(5) G#1 A2 {A3, Bb4} _vel(70)}
gram#3[4] M4 --> {_tempo(0.7) _rotate(5) _transpose(3) M3}
gram#3[5] M5 --> {_tempo(0.7) _rotate(12) _transpose(6) M4}
gram#3[6] M6 --> {_tempo(2) M1}
gram#3[7] Int1 --> {_tempo(12) _vel(40) _transpose(3) D2 C#3 _transpose(6) D2 C#3 _transpose(9) D2 C#3}
gram#3[8] Int2 --> {_transpose(11) Int1}
gram#3[9] Int3 --> {_transpose(11) Int2}
gram#3[10] Trill1 --> {_tempo(12) _velcont _vel(10) Bb4 A5 Bb4 A5 Bb4 A5 Bb4 A5 Bb4 A5 Bb4 A5 Bb4 A5 Bb4 A5 Bb4 A5 Bb4 A5 _vel(80) Bb4 A5 Bb4 A5 Bb4 A5 Bb4 A5 Bb4 A5 Bb4 A5 Bb4 A5 Bb4 A5 Bb4 A5 Bb4 A5 _vel(10)}

“Shapes” by Harm Visserr (1998)
played on a Pianoteq physical-model synthesiser

Waves

Harm Visser had been asked to com­pose a piece à la Debussy with ruba­to rhythms giv­ing the impres­sion of wav­ing move­ments. We had expect­ed him to use the "_tempo()" tool with float­ing point val­ues (or inte­ger ratios) as arguments.

In fact he did not… In the fol­low­ing gram­mar, only the mark­ers "1/2", "1/4" indi­cate reg­u­lar speed changes applied to an entire sec­tion. The wav­ing effect is pro­duced by a clever use of (self-embedded) poly­met­ric expres­sions. As the com­pos­er indi­cat­ed: "It builds on the idea of embed­ding: {5, A B {3, A B {2, A B C D} C D} C D}."

ORD
_mm(48) _striated
S --> Frase1 1 Frase1 Frase2 1/2 {_retro _transpose(12) Frase1} {_rotate(2) _transpose(1) Frase2} {_transpose(-13) Frase3} 1/4 {_transpose(-1) Frase1} Frase4 {_retro _transpose(-1) Frase1} {_rotate(3) _transpose(-11) Frase4} 1 Frase1 {_keyxpand(C4,-1) Frase1} 1/2 {2, _keyxpand(B3,-1) _vel(40) M19, M24} 1/2 {2, _keyxpand(A#3,-1) _vel(40) M19, M24} 1/4 Frase5 {_keyxpand(B3,-1) _transpose(-1) Frase5} {_keyxpand(C4,-1) Frase1} 1/2 {2, _keyxpand(B3,-1) _vel(40) M19, M24} 1/2 {2, _keyxpand(A#3,-1) _vel(40) M19, M24} 1 Frase6 1 Frase6 F1 B3 1 {_vel(50) F1 B3} 2 {6, _vel(40) F1}

Frase1 --> _legato(100) {_velcont _vel(50) M1 M2 M3 M4 _vel(60) M5 M6 _vel(50)}
Frase2 --> _legato(100) {_velcont _vel(50) _transpose(2) M7 M8 _vel(60) M9 M10 M11 M12 _vel(50)}
Frase3 --> _legato(100) {_velcont _vel(50) _transpose(2) M13 M14 M15 _vel(60) M16 M17 M18 _vel(50)}
Frase4 --> _legato(100) {_velcont _vel(50) _transpose(2) M19 M20 M21 M22 _vel(60) M23 M24 _vel(50)}
Frase5 --> _legato(100) {_velcont _vel(50) _transpose(2) M25 _vel(60) M26 M27 M28 M29 M30 _vel(50)}
Frase6 --> _legato(100) {_velcont _vel(50) _transpose(2) M31 _vel(60) M32 M33 M34 M35 M36 M37 M38 _vel(50)}

M1 --> {5, C3 F#3
M2 --> {3, _transpose(13) C3 F#3
M3 --> {3, _transpose(1) C3 F#3
M4 --> F2 B3}
M5 --> F2 B3}
M6 --> F1 B3}
M7 --> {5, _vel(60) C3 F#3
M8 --> {3, _transpose(13) C3 F#3
M9 --> {3, _transpose(1) C3 {M8 M10} F#3
M10 --> F2 B3}
M11 --> F2 B3}
M12 --> F1 B3}
M13 --> {5, _vel(60) C3 F#3
M14 --> {5, _transpose(13) C3 {_transpose(1) M13 M17} F#3
M15 --> {5, _transpose(1) C3 {M14 M16} F#3
M16 --> F2 B3}
M17 --> F2 B3}
M18 --> F4 B3}
M19 --> {9, C3 F#3
M20 --> {9, _transpose(13) C3 {_transpose(1) M13 M17} F#3
M21 --> {9, _transpose(1) C3 {M14 M16} F#3
M22 --> F2 {18, _transpose(-11) M1 M2 M3 M4 M5 M6} B3}
M23 --> F2 B3}
M24 --> F1 B3}
M25 --> {15, _vel(60) C3 F#3
M26 --> {15, _transpose(13) C3 {_transpose(1) M1 M5} F#3
M27 --> {15, _transpose(1) C3 {M2 M4} F#3
M28 --> F2 {30, _transpose(-11) M1 {30, _transpose(-11) M1 M5 M1 M5 M3 M6} M2 M3 M4 M5 M6} B3}
M29 --> F2 B3}
M30 --> F1 B3}
M31 --> {6, C3 F#3
M32 --> {5, _transpose(13) C3 F#3
M33 --> {5, _transpose(1) C3 F#3
M34 --> {5, _transpose(1) C3 F#3
M35 --> F2 B3}
M36 --> F2 B3}
M37 --> F1 B3}
M38 --> F1 B3}

The fol­low­ing is a ren­der­ing of the piece for solo piano on a Pianoteq synthesiser:

“Waves” by Harm Visser (1998)
played on a Pianoteq physical-model synthesiser

In the final ver­sion, the com­pos­er assigned parts to a dif­fer­ent MIDI chan­nel that con­trolled a phys­i­cal­ly mod­elled syn­the­sised sax­o­phone (which he had designed himself):

“Waves” by Harm Visser (1998)
played on physical-model syn­the­sis sax­o­phone and piano

Fractals

Harm Visser sent this gram­mar with the fol­low­ing com­ment (1998):

It is com­plete­ly based on a func­tion that I have made in PatchWork. Take 3 notes and take their inter­vals to trans­pose. The result is a kind of 'auto­trans­pose'. You get a 'frac­tal' - the idea of the famous Von Koch-curve. The next step is mak­ing a recur­sive loop, so that you can set the lev­el of recur­sion. The num­ber of notes grows expo­nen­tial: 3 9 27 81 243 etc. Of course you can do the same with rhythm-values.
This gram­mar is a BP2-version of exact­ly the same idea. It has 4 recur­sion lev­els. (You might also say 'depth'. It is in fact a 'copy' of the PW-function). That's why S --> L4 (lev­el 4) (num­ber of notes 243).

The dif­fer­ence between BP2 and PW is that the func­tion in PW is fixed, which is not the case in BP2. I can easy make sub­tle changes (devi­a­tions) in the process. I can 'break in', so to speak. In his gram­mar I have set a com­ma between M10 and M11 and set M11 on the sax. The result is a poly­met­ric canon!

S --> L4
L1 --> M1 M2 M3
L2 --> M4 M5 M6
L3 --> M7 M8 M9
L4 --> _rndvel(20) _vel(80) {_tempo(1/2) _chan(9) M10, _chan(1) M11 M12}
M1 --> _tempo(1) _transpose(0) C3 B3 F3
M2 --> _tempo(2) _transpose(11) M1
M3 --> _tempo(3) _transpose(5) M1
M4 --> _tempo(1) _transpose(0) M1 M2 M3
M5 --> _tempo(2)_transpose(11) M1 M2 M3
M6 --> _tempo(3) _transpose(5) M1 M2 M3
M7 --> _tempo(1) _transpose(0) M4 M5 M6
M8 --> _tempo(2) _transpose(11) M4 M5 M6
M9 --> _tempo(3) _transpose(5) M4 M5 M6
M10 --> _tempo(1) _transpose(0) M7 M8 M9
M11 --> _tempo(2) _transpose(11) M7 M8 M9
M12 --> _tempo(3) _transpose(5) M7 M8 M9

The fol­low­ing ver­sion is with piano solo on a Pianoteq syn­the­sis­er. The ver­sion with sax­o­phone is unfor­tu­nate­ly miss­ing. It could be gen­er­at­ed by play­ing the (type-1) MIDI file Visser8.mid on a syn­the­sis­er and assign­ing MIDI chan­nel 9 to a sax­o­phone sound.

References