0% found this document useful (0 votes)
128 views112 pages

Computer Representation and Generation Ofkarnātak Rhythms

flkahfkj

Uploaded by

francisco
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
128 views112 pages

Computer Representation and Generation Ofkarnātak Rhythms

flkahfkj

Uploaded by

francisco
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 112

Department of Informatics

School of Science and Technology

Final Year Project


for the Award of
Music Informatics BA
(2009)

Computer Representation and Generation of


Karn.āt.ak Rhythms

Author: Supervisor:
Arthur John Rupert Carabott-Tortell (53806) Dr. Nick Collins
Abstract
Computer representations of music are generally concerned with Western styles of music and perhaps
consequentially or at least for similar reasons, most research into algorithmic composition is also con-
cerned with these styles. This dissertation gives a background on both Karn.āt.ak (South-Indian) music
and algorithmic composition, followed by an outline of requirements of a representation and algorithmic
composition system for Karn.āt.ak rhythmic activity. A system built for these purposes is described and
evaluated by musicological and blind-listener comparison with material from professional Karn.āt.ak per-
cussionists. The dissertation concludes with possible future extensions and alternate methodologies for
the system.

Declaration
This report is submitted as part requirement for the degree of Music Informatics at the University of
Sussex. It is the product of my own labour except where indicated in the text. The report may be freely
copied and distributed provided the source is acknowledged.

————————————————————–

i
Acknowledgements

Roseanna Pollen & Ferdy Carabott,


for their love and support

Suki Ferguson,
for her love and patience

Nick Collins,
for providing inspiration and encouragement

Alex Churchill,
for leading the way

Robin Watson,
for answering so many questions

George Bashi,
for the practical advice

R. N. Prakash,
for his wisdom

Ludwig Pesch and David Nelson,


for lending their expert ears

My evaluators, Freddy Rayfield, Rafi Rogans-Watson, David Tait, Oliver Levy, Matthew Adamo, Jay
Matharu, Arif Driessen, Jamie Bullock, Johnny Wildey, Bopsi Chandramouli, Ben Oliver, Camilo
Tirado, Aykut Kekilli

ii
Contents

1 Introduction 1
1.1 Structure of Dissertation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1

2 Research Topics 2
2.1 Karn.āt.ak Music . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
2.1.1 Tāl.a . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
2.1.2 Rāga . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
2.1.3 The Five Families of Rhythm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
2.1.4 Improvisation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.1.5 Instruments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.1.6 Solkat.t.u/Konakkōl . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
¯
2.2 Algorithmic Composition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
2.2.1 Algorithmic Composition Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.2.2 Motivations for Algorithmic Composition . . . . . . . . . . . . . . . . . . . . . . . 8
2.2.3 System Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9

3 Review of Relevant Work 10


3.1 Computational Systems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
3.1.1 Bol Processor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
3.1.2 SwarShala . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
3.2 Literature . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
3.2.1 Robert Brown . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
3.2.2 David Nelson . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
3.2.3 S. Rajagopala Iyer and R. Krishna Murthy . . . . . . . . . . . . . . . . . . . . . . 13
3.3 Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14

4 Specifications and Requirements Analysis 15


4.1 System Objectives . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
4.1.1 Research Requirements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
4.1.2 User Requirements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
4.2 System Requirements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
4.2.1 A platform for symbolic representations and their manipulation . . . . . . . . . . . 17
4.2.2 An audio synthesis engine for playback of materials . . . . . . . . . . . . . . . . . 17
4.3 Professional Considerations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
4.3.1 Analysis of Material Under Copyright . . . . . . . . . . . . . . . . . . . . . . . . . 18
4.3.2 System Evaluation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
4.3.3 Listener Evaluation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18

5 Design and Implementation 19


5.1 Class Structure and Interaction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
5.2 Representation Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
5.2.1 KonaWord . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
5.2.2 KonaTime . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
5.2.3 KonaTani . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27

iii
5.3 Generation and Manipulation Class and Methods . . . . . . . . . . . . . . . . . . . . . . . 27
5.3.1 Generation Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
5.3.2 Sarvalaghu Generation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
5.3.3 Kannaku Generation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
5.3.4 Micro Mutation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
5.3.5 Macro Mutation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
5.4 Tāl.a Generator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
5.5 Critique of Design and Implementation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43

6 Evaluation 46
6.1 Evaluation Method . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
6.2 Expert Listeners . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
6.2.1 Ludwig Pesch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
6.2.2 David Nelson . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
6.2.3 Sri R. N. Prakash . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
6.3 Lay Listeners . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
6.4 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
6.5 Critique of Evaluation Method . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
6.5.1 Computer Performance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
6.5.2 Example Duration and Context . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
6.5.3 Participant Uncertainty . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
6.5.4 Pride and Prejudice: The problem with discrimination . . . . . . . . . . . . . . . . 54

7 Conclusion 56
7.1 Future Improvements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
7.2 Alternative Methodologies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
7.3 Contribution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58

A Glossary 63

B System Diagram 65

C Transcriptions 67

D Source Code 70

E Project Log 98

iv
Chapter 1

Introduction

In the field of algorithmic composition systems concerned with non-western styles of music are in the
minority. While there has been some algorithmic composition of North Indian (Hindustani) percussion
music (Bel and Kippen, 1992), only the melodic aspect of South Indian (Karn.āt.ak) music has been given
any attention (Bel, 1998). To the author’s knowledge, there has been no algorithmic composition work
focused on Karn.āt.ak rhythm.
Despite the infancy of ethnomusicological study of Karn.āt.ak music (even in comparison with Hin-
dustani music), the amount of analytical work available, supplemented by instructional material from
the musicians themselves makes possible algorithmic composition of the style’s fundamental features.
This project is concerned with modelling the rhythm generation processes of the tradition. To do
this requires a useful and analogous method of representing Karn.āt.ak rhythms, as well as models of the
style’s many processes for music creation. Once developed, the system would provide an environment
for working with Karn.āt.ak rhythms, as well as partially and fully automated methods of generating
Karn.āt.ak rhythms.
While the most abundant source of rhythmic material comes from Karn.āt.ak percussionists, a level
of abstraction has been adopted so as to separate the rhythms of the tradition from the playing of a
particular instrument. This abstraction makes the resulting materials applicable to any Karn.āt.ak (or
even non-Karn.āt.ak) percussion instrument and possibly to melodic instruments.

1.1 Structure of Dissertation


This report gives a description of a system for representing and algorithmically composing Karn.āt.ak
rhythms with a computer. A background of both algorithmic composition and Karn.āt.ak music is given,
as well as a review of relevant systems and literature. Specifications and requirements of the research,
potential users and the system are outlined and used as the basis for design and implementation. The
design of the various elements of the system and their interactions are outlined, with the output evaluated
by musicological and listener based comparison with ‘real’ Karn.āt.ak music. Finally, future improvements
to the system and alternative methodologies are considered.

1
Chapter 2

Research Topics

This project is a fusion of algorithmic composition and musicological analysis of Karn.āt.ak rhythm.
Overviews of both subjects are given with discussion of the most important elements.

2.1 Karn.āt.ak Music


Indian classical music is roughly divided into two schools; the Hindustani music of the North and the
Karn.āt.ak music of the South. While the origins of Karn.āt.ak music dates back to (approximately) 500
B.C (Ayyangar, 1972, p.23), the form is a “living, developing phenomenon” (Nelson, 1991, vol.1 p.viii), in
a state of continuous evolution. A notable result of this evolution is the recent (early twentieth century)
change of performance venue from the religious temple and palace service to the more secular modern
concert stage (Viswanathan and Allen, 2004, ch.1).
As with any style of music, in-depth discussion is impossible when talking in general; it becomes
necessary to talk about forms within the style. However, it is possible to note a few general concepts
that are fundamental to Karn.āt.ak music. A feature of Karn.āt.ak music often noticeable to the western
listener is a lack of functional harmony. Harmony, the simultaneous combination of pitches to create
chords, and in turn chord progressions (Carl et al., 2008), is one of the three fundamentals of western
tonal music– along with rhythm and melody. Karn.āt.ak (as well as Hindustani) music has no concept of
a key, or modulation between keys, instead the other fundamentals: melody and rhythm, or Tāl.a and
Rāga and their subtleties that “reign supreme” (Viswanathan and Allen, 2004, p.34).
Not without its own trinity of fundamental elements, a third key concept to Karn.āt.ak music is one
shared with some western styles (such as Jazz); improvisation.

2.1.1 Tāl.a
Tāl.a is somewhat equivalent to time signature in western music in that it defines the number of beats
in a clearly definable microstructure of the music. This is only a loose equivalence as the notion of time
in western music is linear, and the time signature and tempo may change within a piece. In Karn.āt.ak
music there is no changing of tempo (Viswanathan and Allen, 2004, p.35), nor changes between Tāl.as
or in the structure of Tāl.a; Tāl.a is considered an unchanging, “regularly re-occurring cycle of beats”
(Nelson, 1991, vol.1 p.6). Tāl.a differs further as (unlike the western time signature) there are no implied
accents within a given cycle, instead they are ‘generated by musical phrases and the processes applied to
them’ (Nelson, 2008, p.2). Two examples of tāl.as are given in Figure 2.5. Tāl.as will discussed in more
detail as part of the implementation of a Tāl.a Generator in Section 5.4.

2.1.2 Rāga
Rāga can be considered a more sophisticated equivalent to Western scales. While both can be described
as a collection of pitch based musical events (notes in the West, svaras in Karn.āt.ak music) a Rāga
defines many more musical aspects than pitch alone. In a Rāga the pitch of the svaras used may change
depending on the direction (ascending or descending), movement between svaras may be stepwise or
crooked -starting in one direction, then temporarily reverse before continuing in the original direction

2
Figure 2.1: Mr.daṅgamist R. N. Prakash. Figure 2.2: Karaikudi Mani playing the mr.daṅgam.

Figure 2.3: Selvaganesh Vinayakram playing the Figure 2.4: T. H. Vikku Vinayakram playing the
kanjira ghatam

tensvaras may also be of a fixed pitch or produced with a variety of ornamentations (Gamakas) similar
to vibrato, glissandos and acciaccatura (Viswanathan and Allen, 2004, p.47).

2.1.3 The Five Families of Rhythm


In Karn.āt.ak music there are considered to be five jātis 1 (or families) of rhythm. The numbers that
constitute these jātis are four, three, seven, five and nine in order or recognition as a legitimate basis
on which to build tāl.a cycles (Viswanathan and Allen, 2004, p.35). These five families are apparent at
every level of Karn.āt.ak rhythmic thinking; the possible gatis (sub-divisions of the beat), the number
of syllables/strokes in the building block phrases of improvisation and composition and the laghu– a
variable length aṅgam (section) of the tāl.a. The five families and their names are outlined in Table 2.1.
1 This term is different from jatis which refers to syllables or groups of syllables. Jāti is also a term for hereditary social

grouping, caste (Viswanathan and Allen, 2004, p.35).

3
Ādi tāla
(caturaśra jāti triputa tāla)
Clap Clap Clap
Little Finger Ring Finger Middle Finger Wave Wave

        

Caturaśra jāti Laghu Drutam Drutam

Khanḍa cāpu

   
Clap Wave Wave
   

Figure 2.5: Two tāl.as in score notation. The first is Ādi Tāl.a (the short name for caturaśra jāti triputa
tāl.a), the most common tāl.a in Karn.āt.ak music. The second is khand.a cāpu. The kriyās (hand gestures)
used to keep track of the tāl.a are given, as are the names of the aṅgas (secions, “limbs”) of ādi tāl.a.
Source: (Pesch and Sundaresan, 1996)

Five Families of Rhythm


Number Name Meaning
4 Caturaśra “Four-sided”
3 Tiśra “Three-sided”
7 Miśra “Mixed”
5 Khand.a “Broken”
9 Sankı̄rn.a “All mixed up”

Table 2.1: The five families of rhythm and their names. From Viswanathan and Allen (2004, p.35-36)

These five basic units can be expanded by doubling (and in the case of four by halving) to achieve
further jāti numbers (Nelson, 1991, vol.1 p.18). It should be noted that numbers are not shared between
families; while 12 is a multiple of both three and four, limiting expansion to doubling renders 12 achievable
only by (twice) doubling three (Nelson, 1991, vol.1 p.19). However, phrases with pulse totals that do not
belong to these families do exist, but are considered to be concatenations; e.g. 15 would be a compound
phrase of 5 + 5 + 5 (Da di gi na dom, Da di gi na dom, Da di gi na dom), each belonging to the
family of five while the whole phrase does not (Nelson, 1991, vol.1 p.18). To provide clarity it should be
noted that a phrase can belong to a rhythmic family while having a duration that does not; see Figure 2.6
for an example.

    
Da di gi na dom
           
Da di gi na dom Da di gi na dom Da di gi na dom

Figure 2.6: Both phrases have an equal duration, yet only the top line is considered part of the five
family, the bottom is a compound phrase, of which only the inner phrases belong to the five family.

4
2.1.4 Improvisation
While there are composed pieces of music in the Karn.āt.ak tradition, these are transmitted orally from
guru to student, who adds their own individual touches. The consequence of oral as opposed to written
transmission (and the required reliance on memory) is a concept of composition with a higher level of
abstraction than in the west. While the lyrics, tāl.a, rāga and melody may be specified for a composition,
the structure and nuances may be altered by the artist; lines may be repeated as many times as desired,
with a variety of ornamentations (Viswanathan and Allen, 2004, p.65). This concept of composition
is what gives Karn.āt.ak compositions their great long-term flexibility and longevity. In the short term
(within a performance) the composed core is also considered flexible, as noted by Viswanathan and Allen
(2004, p.60) it is this “dialogue between what is fixed and what is created in the moment [that] is at the
heart of listeners’ enjoyment of Karn.āt.ak music.”

2.1.5 Instruments
The list of instruments used by Karn.āt.ak musicians is ever-growing and changing.
Traditional melodic instruments include the Voice, Veena (a fretted stringed instrument), Violin
and the Flute (made from bamboo). The adoption of of foreign instruments has become increasingly
common, the European violin approximately two centuries ago (Viswanathan and Allen, 2004, p.29),
and the recent additions of Electric Mandolin (Shrinivas, 2007), Electric Guitar (Prasanna, 2003) and
Saxophone (Palnath, 2009).
In its current state, Karn.āt.ak music’s primary percussion instruments are the Mr.daṅgam– a double
headed drum, the main percussion instrument in most Karn.āt.ak concerts (Figure 2.7), Kanjira– a small
frame drum with a pair of tiny brass jingles (Figure 2.8), Ghatam– a clay pot (Figure 2.9), Morsing–
a jaw harp idiophone (Figure 2.10) and the vocal technique Solkat.t.u/Konakkōl (Lockett (2008), p.9-11;
¯
Nelson (2008), p.1).

2.1.6 Solkat.t.u/Konakkōl
¯
Solkat.t.u is a set of percussive-sounding syllables that are learnt in tandem with the strokes and patterns
when studying a percussive instrument (Nelson, 2008, p.2). The syllables were chosen for their ability to
be smoothly recited successively at fast speeds, a feat that is impossible with English or Tamil numerals
(Viswanathan and Allen, 2004, p.36).
Solkat.t.u was developed into a musical speciality in its own right by Mannārgud.i Pakkiri Pil.l.ai (1857-
¯¯
1937) and became known Konakkōl (Pesch, 1999, p.47). Konakkōl was often featured in performance,
¯ ¯
particularly tāl.a vādya kaccēri (performances entirely dedicated to rhythm) (Pesch, 1999, Glossary), but
has become less common in recent times (Pesch, 1999, p.47). Solkau is used in teaching as the distinctive
syllables make the rhythmic groupings very clear. For example a group of four would be spoken ‘Ta ka
di mi’ whereas a group of three would be ‘Ta ki tȧ’ (Vinayakram and McLaughlin, 2007, ch.2).
There is great variations in the syllables used; usually dependent on the bān.ı̄ (musical style) of the
teacher or family, the musical context, or the instrument being played (Pesch, 1999, Glossary). In the
lessons of the author’s teacher (Mr.daṅgamist R. N. Prakash) and in Vinayakram’s (2007, Disc.2 ch.5)
‘Phrases in Ādi Taalam’ the first set of syllables for a group of four are ‘Ki ta tha ka’, while a more
generic set commonly used for non-instrument specific teaching are Ta ka di mi (Pesch and Sundaresan,
1996; Nelson, 2008; Vinayakram and McLaughlin, 2007). Ayyangar (1972, p.309) lists fifteen examples
of bi-syllabic solfa (two beat syllables) and ten examples of tri-syllabic solfa, while Brown (1965) lists
twenty-six possible stroke combinations for quad-syllabic solfa, demonstrating the extent of variation
possible.
An important reason for syllable variation is difference between ‘closed’ (short, sharp, non-resonant)
and ‘open’ (long, resonant) stokes on a drum. In Karn.āt.ak percussion playing phrases may be rhyth-
mically identical, while using different sounding strokes. The same is true for Solkat.t.u/Konakkōl where
¯
the word ‘Ta ka’ might be altered to use the arguably more sonorous ‘din’ to become ‘Ta din’ (Nelson,
2008, p.22).
A further example of variation in syllable use is shown by the possibility of phrasing a group of five
as ‘Ta ka, ta ki t.a’ a concatenation of two + three (which could be re-arranged as three + two; ‘Ta
ki t.a, ta ka’) or using the syllables ‘Da di gi na dom’ (Vinayakram and McLaughlin, 2007, ch.4).

5
Figure 2.7: A mr.daṅgam Figure 2.8: A collection of kanjiras

Figure 2.9: A ghatam Figure 2.10: A morsing

Hulzen (2002, p.12) also notes that at second speeds (doubled tempo) groupings often have their own
syllables, for example, when the density of ‘Ta ka di mi’ (first speed) is doubled (second speed) it
becomes ‘Ta ka di mi, ta ka ju na’ and not ‘Ta ka di mi, ta ka di mi’. The variation here exists
as at faster tempos it becomes necessary to use the most efficient syllables, and to alternate between
equivalents to prevent fatigue.
The extent of variation should now be clear. For the purposes of this dissertation a standard set
of syllables have been adopted and used exclusively (see Table 2.2). The syllables I chose to use are a
hybrid of the materials that formed my introduction to Karn.āt.ak music and Konakkōl; (Vinayakram and
¯
McLaughlin, 2007; Pesch and Sundaresan, 1996) and the analytical works that influenced the algorithms;
(Nelson, 2008, 1991). The strict use of this vocabulary makes generated material applicable to any
instrument, the focus being on the generation of Karn.āt.ak rhythms, and not on particular drum strokes.

2.2 Algorithmic Composition


In the paper AI Methods for Algorithmic Composition: A Survey, a Critical View and Future Prospects
Papadopoulos and Wiggins concatenate David Cope’s definitions of the two words (‘algorithmic’ and
‘composition’) given during a panel discussion at the 1993 International Computer Music Conference
to form the following definition of algorithmic composition: “A sequence (set) of rules (instructions,
operations) for solving (accomplishing) a [particular] problem (task) [in a finite number of steps] of
combining musical parts (things, elements) into a whole (composition)” (Cope, 1993b; Papadopoulos
and Wiggins, 1999).

6
No. Jatis Jatis
1 Ta
2 Ta ka
3 Ta ki t.a
4 Ta ka di mi
5 Da di gi na dom
6 Ta ki t.a ta ki t.a
7 Ta ka di mi ta ki t.a
8 Ta ka di mi ta ka ju na
9 Da di gi na dom ta ka di mi

Table 2.2: The set solkat.t.u words used throughout this project. Note that SCLang doesn’t handle
accents on letters, so the phonetic ‘tah’ is used instead of t.a in system printouts.

2.2.1 Algorithmic Composition Methods


While there are historical examples of non-computational algorithmic compositions such as the Musical
Dice Game often (but not entirely accurately) attributed to Mozart, the strengths of computers make
them particularly fit for the purpose. While not exhaustive, Papadopoulos and Wiggins provide the
following general categories of algorithmic composition methods that have been implemented within the
last decade:

• Mathematical Models

• Knowledge Based Systems


• Grammars
• Evolutionary Methods
• Systems Which Learn

• Hybrid Systems

Mathematical Models
Mathematical models of algorithmic composition are outlined as those that use mathematically founded
methods such as stochastic processes and Markov chains, as well as chaotic non-linear and iterated
functions. There are many examples of systems uses these methods, Ames and Domino’s Cybernetic
Composer (1992) is noted by Papadopoulos and Wiggins (1999) as being a representative example of
these systems.

Knowledge Based Systems


Knowledge based systems (also known as expert systems) are systems which that attempt to symbolically
model the knowledge of a human expert using rules or constraints (Papadopoulos and Wiggins, 1999;
Raynor, 2000). Ebcioglu’s CHORAL (1988), a J.S. Bach style harmonisation system tenis exemplary of
this type of system.

Grammars
Grammar systems use grammars derived from music in the same way that linguists derive grammars
from language. David Cope’s ‘Experiments in Musical Intelligence’ (Cope, 1991) uses elements of gram-
mar based composition; extracting “signatures” from multiple pieces of a composer’s work to use for
composition. Bernard Bel’s Bol Processor is a completely grammar based system, discussed in greater
depth in Section 3.1.1.

7
Evolutionary Methods
Evolutionary methods are those that use the strengths of Genetic Algorithms (GAs) (dealing with very
large search spaces, and providing multiple solutions) for the creation of musical material. Although
arguably a search tool, GAs are often regarded as a form of machine learning (Mitchell, 1997, ch.9).
There have generally been two approaches employed in regards to the fitness function of these systems;
a formally stated and computationally implemented function, and the use of a human function (often
referred to as an interactive GA) (Papadopoulos and Wiggins, 1999). A. Biles GenJam is a well known
‘genetic algorithm-based model of a novice jazz musician learning to improvise’ (Biles, 1994).

Systems Which Learn


This type of system will use various computational methods such as sub-symbolic Artificial Neural Net-
works (ANN), or symbolic Machine Learning (ML) in an attempt to teach the system how to complete
a given task rather than explicitly telling it how (Papadopoulos and Wiggins, 1999). Typically these
systems have little or no a priori knowledge of the problem and are taught by example, a method that
draws on the ideas of numerous disciplines such as artificial intelligence, probability and statistics, com-
putational complexity, information theory, psychology and neurobiology, control theory and philosophy
(Mitchell, 1997). Mozer, a melody generating system that uses an ANN is such a system (Todd, 1989).

Hybrid Systems
Hybrid systems are those that combine the approaches of previously outlined methods. As single-method
systems tend to have individual strengths, the hope of a hybrid system is to combine the different assets
of various methods into an altogether better system (Papadopoulos and Wiggins, 1999). Biles (1994)
turned his GenJam system into a hybrid system when attempting to increase efficiency of evaluation by
using an ANN as the fitness function instead of a human (Biles et al., 1996).

2.2.2 Motivations for Algorithmic Composition


There are numerous motivations for the automation of the compositional process, the disambiguation of
them has been well achieved by Pearce, Meredith and Wiggins in their paper Motivations and Method-
ologies for Automation of the Compositional Process (Pearce et al., 2002) which outlines the following
categories:

• Algorithmic Composition
• Design of Compositional Tools
• Computational Modelling of Musical Styles
• Computational Modelling of Music Cognition

Algorithmic Composition (AC)


Pearce et al. define the motivation behind algorithmic composition programs as being artistic, for the
purpose of generating ‘novel musical structures, compositional techniques, and even genres of music’.
David Cope’s Experiments in Musicical Intelligence is an example of an AC system, initially designed to
be a composing partner for the purpose of easing composers block (Cope, 1991).

Design of Compositional Tools (DCT)


The motivation for the design of compositional tools is similar to that of algorithmic composition in
that the intent is to produce music for practical purposes. While AC systems are usually only used by
the authoring composer (almost as an extension of themselves), compositional tools are designed to be
used by other composers as part of their own artistic process. Simple examples of compositional tools
are found in the notation package Sibelius (Avid, 2008), where functions can be found to create simple
harmonies to a given melody, produce retrogrades of material, or to realise figured bass.

8
Computational Modelling of Musical Styles (CMMS)
Despite producing music, the motivation behind CMMS differs from that of AC and DCT as it ‘is not to
compose aesthetically pleasing pieces of music nor to design a useful compositional tool but to propose
and verify hypotheses about the stylistic attributes defining a body of works’ (Pearce et al., 2002). An
example of this type of system is HARMONET, developed by Hild, Feulner and Menzel, which focuses
on the harmonisation of chorales in the style of J.S. Bach (Hild et al., 1992).

Computational Modelling of Music Cognition (CMMC)


The motivation behind CMMC systems is an increased understanding of ‘underlying cognitive process
involved in human composition’ (Pearce et al., 2002). As with CMMC systems, the production of
aesthetically pleasing music or of useful tools is of little interest. The system designed by Steedman
(1984) focuses on a generative grammar for jazz chord sequences and is exemplary of this type of program.

2.2.3 System Introduction


Method
The method of algorithmic composition used in this project is entirely knowledge based; Karn.āt.ak are
analysed for processes which are then turned into explicit algorithms. During the development period
experimentation with statistical modelling took place, a method which was later abandoned in favour of
the knowledge based approach. The details of the algorithmic composition methods will be discussed in
Chapter 5.

Motivation
The motivations for the system are numerous; it can be used as a standalone environment for composition
with or without adherence to Karn.āt.ak traditions, a use which would fall under the category ‘Algorithmic
Composition’ (Pearce et al., 2002). If used in conjunction with other methods of composition, the system
would be classified by Pearce et al. (2002) as a ‘Compositional Tool’. As the automation methods of the
system have been modelled on processes and structures found in Karn.āt.ak music, exclusive use of these
methods would result in a ‘Computational Modelling of Musical Style’ (Pearce et al., 2002).

9
Chapter 3

Review of Relevant Work

Algorithmic Composition is a field with many methodologies (Papadopoulos and Wiggins, 1999) and
motivations (Pearce et al., 2002) with application to any form of music. While certain musical forms
have been the subject of many attempts at automation e.g. chorales (Cope, 1991; Ebcioglu, 1988; Hild
et al., 1992), generation of Karn.āt.ak rhythms are (to the author’s knowledge) as of now un-automated.
This lack of closely related systems has resulted in investigation into work slightly further afield, as
well as looking to the musical ‘formulae’ discovered by Indian and non-Indian musicologists.

3.1 Computational Systems


There are few examples of computer music researchers working with Karn.āt.ak music. Two notable prac-
titioners are Arvindh Krishnaswamy, who has been prolific in his work on the tracking, measurement,
perception, analysis, transcription and modelling of pitch and rāgas in Karn.āt.ak music (Krishnaswamy,
2003a,b,c, 2004b,e,a,c,d), and M.Subramanian whose work on synthesising gamakams (melodic inflec-
tions) (Subramanian, 2002, 1999) has lead to his Rasika-Gaayaka educational software (Subramanian,
2008).
As is evident, the preoccupation of these researchers is pitch and melody, (with the exception of the
Tāl.a counting lessons in Subramanian’s software) and even then the work has not touched upon the
topic of Karn.āt.ak algorithmic composition.
While computational algorithmic composition of Western musical styles is a flourishing field (Cope,
2005; Roads, 1996; Miranda, 2001; Ames and Domino, 1992; Ebcioglu, 1988; Biles, 1994), there has been
far less work focused on Indian music, let alone Karn.āt.ak (South Indian) music. To the author’s knowl-
edge there exists only one example of Karn.āt.ak algorithmic composition work; grammars constructed
for Bernard Bel’s Bol Processor 2 (Bel, 2006). Again, the focus has been on melody generation, with
grammars for modelling melodic improvisation and a number of highly constrained grammars for specific
compositions. However, the Bol Processor 2 has been used extensively for the modelling of Hindustani
(North Indian) Tabla improvisation of the qa’ida form (Kippen and Bel, 1992) (see Figure 3.1), making
it a relevant system to this project.

3.1.1 Bol Processor


Note: This review of the Bol Processor is largely re-written from an essay by the author, submitted for
the Generative Creativity course, as part of the Music Informatics (BA) undergraduate degree at the
University of Sussex. Referenced as (Carabott, 2009).

The Bol Processor (BP) is a hybrid system (Papadopoulos and Wiggins, 1999) by Bernard Bel named
after its original purpose; the transcription of bols (Tabla strokes) at performance speed (Bel, 1998) (a
system commissioned by ethnomusicologist Jim Kippen).
Initially the system resembled a customised word-processor with the bol vocabulary mapped to a
keyboard. Soon an inference engine based on Chomsky’s linguistics was added, enabling Tabla music
generation from user-defined grammars (Bel, 1998). The inference engine combined generative, context-

10
free and generalising grammars as well as pattern rules (Bel, 1992a). A template matching parsing
module was built for classifying variations on a theme with a ‘membership test’ (Bel, 1992a). The aim
of the research was to ‘create a human-computer interaction where musicians themselves respond to
the output of BP grammars, and grammars are in turn modified to account for the input of musicians’
(Kippen and Bel, 1992).
The second Bol Processor (BP2) was the result of interaction with Western musicians and featured
numerous additions. The most interesting addition to the system was the symbolic machine-learning
system QAVAID (Question Answer Validated Analytical Inference Device) (Kippen and Bel, 1989).
QAVAID was given only knowledge of the grammar format not musical structure, and used an incremental
learning strategy modelled on traditional teaching methods; “an implicit model is transmitted by means
of sequences of positive instances of the ‘language’. Negative instances composed by students are rejected
or corrected.” (Kippen and Bel, 1992). The use of a machine-learning algorithm removed the musicologist
(and their individual assumptions) from the generation of grammars, making the process more analogous
to the traditional teacher and student situation.
The inference engine was improved with the addition of remote contexts, repetition patterns, logic-
numeric flags and meta-grammars (Kippen and Bel, 1992; Bel, 1992b). The language of Tabla Bols
was replaced with ‘sound-objects’ that contained any number of MIDI messages (ranging from a simple
NoteOn/NoteOff pair to a whole stream altering velocity, modulation, aftertouch etc). The move from
Bols to MIDI based ‘sound-objects’ maintained the ability to work with Tabla, opened up the system to
Western music and eased human computer interaction (via MIDI instruments).

Note: The following material is original work not found in (Carabott, 2009)

Between 1995 and 1997 work was conducted with BP2 and Karn.āt.ak musicians (Bel, 1998). Some
of this work was used as a general demonstration of BP2 at the 2006 Virtual Gamelan Graz Symposium
(Bel, 2006) but has not been the focus of any academic publications. However, a number of Karn.āt.ak
grammars that were produced are included with BP2, available from the Bol Processor Homepage (Bel,
2009). These grammars include original compositions by Kumar S. Subramanian (see Figure 3.2) and
Nadaka, a model of melodic improvisation and several well known compositions.
Unfortunately for this project, all of the Karn.āt.ak grammars are for melodic materials. While
rhythmic information is inherent in these melodies, they are not attempting to model the rhythms
played by Karn.āt.ak percussionists.
GRAM#6 [8] LEFT A’6 + <-> dhageteenakena+
GRAM#6 [9] LEFT A’8 + <-> dhatidhageteenakena+
GRAM#6 [10] LEFT A4 + <-> dheenagena+
GRAM#6 [11] LEFT C6 + <-> dhagedheenagena+
GRAM#6 [12] LEFT A8 + <-> dhatidhagedheenagena+

Figure 3.1: Part of a BP2 grammar for Hindustani Tabla playing. Note the use of bols (stroke names)
as input

GRAM#2[1] <8-2> X --> sa6 re6


GRAM#2[2] <8-2> X --> re6 ga6
GRAM#2[3] <8-1> X Y --> ga6 pa6 dha6 X X
GRAM#2[4] <8-1> X X --> sa7 dha6 pa6

Figure 3.2: Part of a BP2 grammar for an original composition Karn.āt.ak by Kumar S. Subramanian.
Note the Karn.āt.ak svara names used as input (sa, re, ga, pa, dha)

3.1.2 SwarShala
SwarShala is a proprietary software package for ‘learning, practising and composing’ Indian music (both
Hindustani and Karn.āt.ak) by Swar Systems (Swar Systems, 2009). While offering no methods algorith-

11
Figure 3.3: Bernard Bel’s Bol Processor 2 with a grammar for a vina piece.

12
mic composition, the package does provide a means of representation; a MIDI sequencer with stoke or
svara names appended to note objects, viewable either as a piano roll or in tāl.as (see Figure 3.4).

Figure 3.4: The tāl.a view of a sequence of Tabla Bols in SwarShala.

3.2 Literature
While there is a lack of computational algorithms for generating Karn.āt.ak rhythms, there are published
works of theory by Western ethnomusicologists and Indian music theorists alike. The most influential
texts are outlined below. Another useful resource not discussed in depth is Hulzen’s dissertation (Hulzen,
2002). The alternative perspective provided by Hulzen saved this project from over reliance on Nelson
(1991, 2008) and Brown (1965), the former using the latter as the foundation of his work.

3.2.1 Robert Brown


Robert Brown’s thesis (Brown, 1965) was a ground-breaking work that ‘revealed to non-Indian musi-
cologists for the first time, the structure of mr.daṅgam lessons’ (Nelson, 1991, vol.1 p.iv). It introduced
Karn.āt.ak concepts of rhythm, described the physical properties and cultural relevance of the mr.daṅgam,
provided sonograms of the various strokes, introduced solkat.t.u and provided 152 mr.daṅgam lessons.
Brown’s work is an excellent resource for general knowledge of Karn.āt.ak percussion as well as being
a plethora of documented Karn.āt.ak rhythmic materials. Brown provides the most in depth discussion
of the problem of syllable and word grouping, one of the biggest analytical difficulties of the musical
style. Brown’s work also contains some useful rhythmic analysis work, notably suffix substitutions
(Brown, 1965, p.149) for sarvalaghu (time-keeping) phrases and the beginnings of an algorithm for
mōrās, providing the groundwork for Nelson’s (1991) more analysis focused work.

3.2.2 David Nelson


David Nelson’s thesis (Nelson, 1991) uses Brown’s work as a starting point, but focuses on the perfor-
mance of the tani āvartanam (drum solo) on the mr.daṅgam. The materials used in the study were five
tanis performed by mr.daṅgamists considered to be at the top of the profession (Palghat R. Raghu, Trichy
S. Sankraran, T. K. Murthy, Vellore G. Ramabhadran and Karaikudi R. Mani) so can be taken as an
accurate survey of the tani āvartanam circa 1991 (Nelson, 1991). The tanis were filmed, transcribed,
analysed and discussed with the performer so as to get a professional opinion on the posited theories.
This thesis (Nelson, 1991) and the resulting book (Nelson, 2008) have been crucial resources because
of the depth of analysis and wealth of transcribed materials. In particular, the differentiation between
time-keeping phrases (sarvalaghu) and calculated phrases (kannakus), as well as the general formula for
mōrās and explanation of compound mōrās that would likely have been missed or misunderstood when
working with transcriptions alone.

3.2.3 S. Rajagopala Iyer and R. Krishna Murthy


Sangeetha Akshara Hridaya (A New Approach to Tāl.a Calculations) by Iyer (2000) is a theory book
aimed at the Karn.āt.ak percussionist that provides various practical methods for rhythmic calculation
and clarification of terms. The book focuses on various methods of reaching the ed.uppu (starting beat
of the melody) from any point in the cycle. Although under different names, the methods coincide with
Nelson’s theories (Nelson, 1991, 2008), confirming their suitability for implementation.

13
3.3 Review
To the author’s knowledge there has been no algorithmic composition work focused on Karn.āt.ak rhythm,
with melody only slightly less overlooked (Bel, 2006). Fortunately there is a relative abundance of
both analytical (Iyer, 2000; Ayyangar, 1972; Viswanathan and Allen, 2004; Hulzen, 2002; Nelson, 1991,
2008; Pesch and Sundaresan, 1996; Pesch, 1999) and instructional (Vinayakram and McLaughlin, 2007;
Vinayakram, 2007; Lockett, 2008; Prakash, 2009) material to forge the beginnings of algorithmic com-
position of Karn.āt.ak rhythms.

14
Chapter 4

Specifications and Requirements


Analysis

The building of any software system necessitates requirements analysis, defined by Abran et al. as “the
elicitation, analysis, specification, and validation of software requirements” (Abran et al., 2004, ch.2).
These activities are advised as “It is widely acknowledged within the software industry that software
engineering projects are critically vulnerable when these activities are performed poorly.” (Abran et al.,
2004, ch.2).
The building of a system for working with Karn.āt.ak rhythmic materials will benefit greatly from a
formal analysis of research, user and system requirements as well as attention to professional considera-
tions.

4.1 System Objectives


4.1.1 Research Requirements
Provide a suitable representation for Karn.āt.ak concepts of rhythm
For Karn.āt.ak musicians the tradition of oral teaching (Viswanathan and Allen, 2004, p.60) makes an
additional form of representation unnecessary (Nelson, 1991, vol.3, p.1), yet this has not stopped attempts
to establishing one.
Song texts have been recorded in physical form; dried palm leaves for centuries until mass printing
arrived in the mid-nineteenth century, but contain only the required rāga and tāl.a without melodic or
rhythmic notation (Viswanathan and Allen, 2004, p.25).
Not wishing to use western score notation (Nelson, 1991, vol.3, p.1) ethnomusicologists developed
their own methods of transcribing Karn.āt.ak rhythms, but as Hulzen’s (2002) adoption of, and Nelson’s
(1991) rejection of Brown’s (1965) notation demonstrates, a standard is yet to be set. On the other
hand, musicians such as Lockett (2008), Vinayakram and McLaughlin (2007) and Vinayakram (2007)
have been happy to adapt score notation to their needs.
With any form of representation there will be loss of information; a vibrato mark on a score does
not give precise timings for the motion, nor does an orally transmitted melody produce the timbre of
the instrument it is intended to be played on. The ubiquitous computer representation of music, MIDI,
may be reasonably suited to representing keyboard music, but shows its weaknesses when used for wind
instruments. Even digital recordings suffer a loss of information, albeit (usually) inaudible information.
The focus of this project being Karn.āt.ak rhythms, a suitable representation must indicate rhythmic
groupings (the konakkōl word e.g. Ta ka di mi) and timing information interpretable by the computer.
¯
For the purpose of this project information present in the source material used (percussion performances)
such as timbre and dynamics are superfluous so can be lost in representation.
For practical purposes the representation must be clearly analogous to Karn.āt.ak materials to ease
the construction of, and experimentation with the system. For the evaluation of the system it is also
necessary that the representation can be converted to an audio signal, with printing/scoring as a useful
addition.

15
It will also be necessary to represent the higher level concepts of Karn.āt.ak rhythm, namely Tāl.as
and complete performances.

Develop methods to generate rhythmic phrases in the Karn.āt.ak tradition


Modelling the traditions of Karn.āt.ak rhythm will necessitate methods to generate new material according
to a given context; tāl.a, gati (beat division) and laya (tempo). The main use of this new material will
be the modelling of sarvalaghu.
Nelson (1991, vol.1 p.28) describes sarvalaghu as ‘the shaping of time’, while Sankaran uses the term
‘flow patterns’ (Sankaran (1977) in; Nelson (1991)). The purpose of sarvalaghu is to reinforce the flow of
the tāl.a (Viswanathan and Allen, 2004, p.68) in a manner that is primarily propulsive, drawing attention
to ‘the flow of rhythmic time rather than to its design possibilities’ (Nelson, 1991, vol.1 p.29). A western
synonym for sarvalaghu might be ‘groove’ or ‘feel’, and the embellishment of these. Sarvalaghu is the
style of play that will occupy most of the percussionists stage time, especially when accompanying a
soloist (Nelson, 1991, vol.1 p.28).
These methods will be used to build archetypal structures from which variations can be generated to
create sarvalaghu passages of coherent but varied phrases. Generated phrases will also be of use when
generating rhythmic cadences.

Implement methods to generate the formalised rhythmic cadences of Karn.āt.ak music


An essential element of Karn.āt.ak drumming is the use of rhythmic cadences known as kan.akkus.
Kan.akku is a form in which the percussionist creates patterns that disrupts the perceived flow of the
tāl.a (Viswanathan and Allen, 2004, p.68). Kan.akku is used for cadential purposes, and is a broad term
for the various loosely defined forms mōrā, arudi, tı̄rmānam, kōrvai, and ta din gi n.a tom (Nelson, 1991,
vol.1 p.43).
Adapting the formulas provided by musicologists (Nelson, 1991, 2008; Iyer, 2000) to computational
methods to re-produce these cadences will be critical to this project.

Identify and implement material manipulation techniques employed in Karn.āt.ak composi-


tion and improvisation
A natural part of a Karn.āt.ak drummer’s performance is motivic development and embellishment (Nelson,
1991, vol.1 p.36). In order to model this it will be necessary to identify the various processes used and
implement computational methods to reproduce them.

4.1.2 User Requirements


As the focus of the project is research-orientated there are no intended end-users but for the researchers
themselves. However, consideration of hypothetical users would serve to guide the development in a
direction that may be of use in a number of fields. While these potential uses are to be taken into
account, for practical use some extension or customisation of the system is likely to be necessary.

Musicologists
A suitable way of representing Karn.āt.ak rhythms would be of great use to musicologists, with the
facility to make examples audible ensuring against ambiguities or misinterpretation. Transcription could
be greatly eased by a mapping of solkat.t.u word representations to an input device in a manner similar
to the Bol Processor and Tabla bols (Bel, 1998). The mapping of whole words to single input keys
would enable transcription at performance speed of music far beyond the instrumental technique of the
musicologist.
Note: (The transcription of human examples for the evaluation (Chapter 6.1) was completed using
shorthand names for the syllables/words, which were then replaced with KonaWord.new method calls using
the text editor’s find and replace function).

16
Karn.āt.ak Teachers
Combining their own input with the methods for generating variation, percussion teachers could quickly
provide students with a vast number of variations on an idea. The ability to play back the variations as
audio would keep with the tradition of oral teaching (Viswanathan and Allen, 2004, p.60).

Karn.āt.ak Musicians
Composition The automated methods of material generation and manipulation could be used as a
source of new ideas for composition. Parameters such as tāl.a, gati and laya could be used to generate
new material free from the composer’s predispositions.
Experimentation outside the tradition is increasing among Karn.āt.ak musicians; the group Shakti
has always been a combination of jazz guitarist John McLaughlin and Hindustani Tabla player Zakir
Hussain with various Karn.āt.ak musicians, while musicians Selvaganesh Vinayakram and U. Shrinivas
have both released ‘fusion’ albums (Vinayakram, 2004; Shrinivas, 2007) that display their upbringing
in the Karn.āt.ak tradition, but would not be considered a part of the classical form. For the inclined
musician the system would provide familiar materials with the precision of computer, which could be
exploited to explore and realise new and complex musical ideas outside the tradition and beyond the
musician’s ability

Accompaniment The system may be of use to the practising musician as an accompaniment tool; the
user could decide on tāl.a, laya, and gati leaving the system to generate accompaniment material with
the continuous, suble variations made by humans.

Non-Karn.āt.ak Musicians
For non-Karn.āt.ak musician the system could function as a dynamic library of new improvisational or
compositional ideas. Interesting ideas may emerge from the cross-pollination of non-Karn.āt.ak music
with Karn.āt.ak structures or methods of generating variation.

4.2 System Requirements


Having considered what will be required of the system, it is worth considering what will be required by
the system.

4.2.1 A platform for symbolic representations and their manipulation


As there are no ready made, entirely suitable methods for representing Karn.āt.ak rhythms on the com-
puter it will be necessary to create one, for which a programming language is well suited. As previously
mentioned (4.1.1) the representation will need to contain multiple pieces of information (e.g a konakkōl
¯
word, timing information etc), making a new class in an object-orientated programming language ideal.

SCLang
SCLang is the programming language and interpreter of SuperCollider (SuperCollider Homepage, 2009).
As well as being a full object-orientated programming language it makes encoding of time-based routines
trivial and has been built specifically to communicate with sound synthesis engines such as SCSynth and
Max/MSP via Open Sound Control. SCLang also provides classes for interfacing with MIDI which will
be of use when using Swar Systems’ (2009) Karn.āt.ak virtual instruments for evaluation.

4.2.2 An audio synthesis engine for playback of materials


In order to produce konakkōl audio examples it will be necessary to playback recordings of the various
¯
words. To avoid a vast number of recordings it will be necessary to vary playback rate so that overlap
is avoided at fast tempos.

17
SCSynth
SCSynth is the synthesiser half of SuperCollider (SuperCollider Homepage, 2009) and is easily capable
of variable rate playback of samples. The third party JoshUGens library by Joshua Parmenter (bundled
as an extra with SuperCollider) provides the ability to change the rate of playback while maintaining
pitch which will be useful for the sake of aesthetics.

4.3 Professional Considerations


4.3.1 Analysis of Material Under Copyright
In order to derive rules for generating Karn.āt.ak music it is necessary to analyse music from the style.
While some transcriptions are available from academic works (Nelson, 1991; Hulzen, 2002) the use of
transcriptions under copyright (Vinayakram and McLaughlin, 2007; Nelson, 2008) as well as original
transcriptions of music under copyright (Vinayakram, 2007) is necessary in ensuring a spectrum of
playing styles is accounted for.
Article 3 of the British Computer Society’s (BCS) Code of Conduct states “You shall ensure that
within your professional field/s you have knowledge and understanding of relevant legislation, regulations
and standards, and that you comply with such requirements.” (BCS, 2008a). In this instance the relevant
legislation is chapter 3 (Acts Permitted in relation to Copyright Works), section 29 (Research and private
study), article oneof the Copyright, Designs and Patents Act 1988 (OPSI, 1988) which declares “Fair
dealing with a literary, dramatic, musical or artistic work for the purposes of research or private study
does not infringe any copyright in the work or, in the case of a published edition, in the typographical
arrangement.”

4.3.2 System Evaluation


In conclusion of this project it will be critical to adhere to article 3 of the BCS code of good practice;
“Honestly summarise the mistakes made, good fortune encountered and lessons learned. Recommend
changes that will be of benefit to later projects” (BCS, 2008b). It would be unrealistic to expect the
system (or any, ever) to provide a ‘general solution’ for Karn.āt.ak rhythm, especially as it is a continually
growing art-form. As a result all possible improvements will be noted as potential future extensions.

4.3.3 Listener Evaluation


Article 9 of the BCS code of conduct begins “You shall not misrepresent or withhold information on the
performance of products, systems or services...”. In accordance with this the quality of output will not
be tampered with before being presented to the listener.
The article continues “...or take advantage of the lack of relevant knowledge or inexperience of others.”
As a relatively esoteric area of research it is likely that the knowledge of Karn.āt.ak music possessed by
evaluators will vary. So that this can be taken into account, the evaluators exposure to Karn.āt.ak music
will be noted.
In order to provide more critical evaluation of material a number of experts in the field (musicologists
Nelson and Pesch and Sundaresan and mr.daṅgamist R.N. Prakash) will included in the evaluation.

18
Chapter 5

Design and Implementation

The system that has been designed and implemented provides a SuperCollider environment for working
with Karn.āt.ak rhythmic material. Three representation classes have been built; KonaWord for represent-
ing individual konakkōl words, KonaTime for grouping multiple KonaWord objects and KonaTani which
¯
can be considered a complete performance. The class KonaGenerator was built to provide methods for
generating and manipulating KonaWord and KonaTime objects, storing them in a KonaTani instance.
As discussed in Section 2.2.3 the method of the system can be classified as Knowledge based (Pa-
padopoulos and Wiggins, 1999), while the numerous motivations include ‘Algorithmic Composition’,
‘Design of Compositional Tools’ and ‘Computational Modelling of Musical Styles’ (Pearce et al., 2002).

5.1 Class Structure and Interaction


In a typical working environment an instance of KonaTani is created, providing the necessary SynthDefs
and TempoClock for playback, as well as creating a KonaGenerator instance. Material can then be gen-
erated either by hand (instantiating KonaWords and KonaTimes) or using the KonaGenerator instance’s
generation methods and then mutated using the KonaGenerator mutation methods. KonaWord and
KonaTime instances can be played directly, or added to the KonaTani to be played back with the tāl.a
being clapped. The conceptual layout of the system is shown in Appendix B.

5.2 Representation Classes


The design of suitable representations was one of the most difficult challenges of the project. There were
some considerable grey areas, notably the classification of the basic unit of Karn.āt.ak rhythm, represented
by the KonaWord class.

5.2.1 KonaWord
Each KonaWord represents the basic unit of Karn.āt.ak rhythm; a number of pulses/syllables grouped as a
single word sometimes known as a Tattakhara (Iyer, 2000, p.12). Each instance also includes specification
of the number of jatis (syllables), the karve (relative duration of jatis), the gati (how the beat is sub-
divided) and the number of mātras it occupies (the number of sub-divisions), as well as a Routine for
playback and a method for printing.

Basic Units While existence of basic units is commonly discussed (Brown, 1965; Nelson, 1991, 2008;
Pesch and Sundaresan, 1996; Pesch, 1999; Vinayakram and McLaughlin, 2007; Viswanathan and Allen,
2004; Iyer, 2000), these studies have not required classification decisions of the same degree as necessitated
by a computer representation. The most in depth of discussion of the ambiguities of these building blocks
and their relationship to mr.daṅgam fingerings can be found in Brown (1965, ch. XIV).
Important to this discussion is an understanding of the role of the basic unit in Karn.āt.ak rhythm.
As previously mentioned (Section 2.1.1), the tāl.a and gati do not imply a particular accent structure,
any pulse may be accented as “accents are generated by phrase groupings” (Nelson, 1991, p.19). The

19
ramifications of this are twofold; the first pulse of a phrase grouping is always accented and any accent
implies the beginning of a phrase grouping, see Figure 5.1 for an example.

      
                        
Ta ki ṭa Ta ki ṭa Ta ki ṭa Ta ki ṭa Da di gi na dom Ta ka Da di gi na dom

Figure 5.1: Two bars in a three beat tāl.a. The accents all result from the use of basic units, resulting in
clearly different accent structures. From Vinayakram and McLaughlin (2007, ch.5)

There is an example found in Vinayakram and McLaughlin (2007, ch.3) that might seem to disprove
this rule, however upon deeper inspection it is easily accounted for (see Figure 5.2 for the notation).

     
               
Ta ka di mi Ta ka ju na Ta ka di mi Ta ka Ju na

Figure 5.2: A common phrase alluding to two groups of four (as on the left), in fact consisting of a group
of four with two groups of two (as on the right). From Vinayakram and McLaughlin (2007, ch.3)

From an initial assessment of this example it is possible to conclude that the single word Ta ka ju
na has two accents (Ta and ju). This is understandable as Ta ka ju na is commonly used with a
single accent in alternation with Ta ka di mi (Viswanathan and Allen, 2004, p.39). Brown (1965, p.236)
notes that a group of four such as Ta ka di mi “can be analyzed as consisting of two pairs, Ta ka and
Di mi, both of which also occur in isolation, but the combination of four syllables is at the same time
an entity in itself.” The same is true of Ta ka and Ju na, listed by Brown (1965, p.238) as possible
groups of two or combined as a group of four. It should be noted that in Vinayakram and McLaughlin
(2007) Ju na does not appear as a group of two outside of this context, what we are actually seeing is
a context sensitive, four pulse phrase made up of two, two pulse phrases. 1
So why not use less ambiguous Taka Taka? In fact this more distinct possibility crops up later in
the chapter (Vinayakram and McLaughlin, 2007, ch.3) during an improvisation, however the context is
clearly different (see Figure 5.3 for the notation). By looking at other bars in the improvisation it is
clear that variation is being generated by permuting four groups of three and two groups of two. The
separation of the two groups of two in bar 17 highlights the fact that these are separate entities, a fact
that remains in bar 10 despite their proximity. This counter-example proves that there is more to the
previous Ta ka Ju na (Figure 5.2) than just two groups of two; it is in fact two groups of two bound
together as a four pulse phrase, unlike the two groups of two found in bar 10 of Figure 5.3. This is the
only example found where a (usually single) word appears to have multiple accents, a five pulse phrase
accents on the first and third pulse is never given as DA di GI na dom but always as TA ka TA ki t.a.
While this level of disambiguation may not be necessary in most situations, it has been vital to the
design of the KonaWord class. Such discussion may also be relevant to the mr.daṅgamist, for whom Ta
ka and Ju na would indicate different fingerings (Brown, 1965, p.238).

Common ground Despite the possible ambiguities of construction for a group of four, most theoretical
or solkat.t.u focused examples (Pesch and Sundaresan, 1996; Pesch, 1999; Nelson, 2008; Iyer, 2000; Lockett,
2008; Hulzen, 2002; Ayyangar, 1972) use clearly distinct words for low numbered (1-4) phrase groupings.
While there may be alternatives used (e.g. Ta ka di na or Ta ri gi du for Ta ka di mi) these are kept
distinct from concatenations of smaller groups by associating syllables exclusively (e.g. always using di
1A pattern regarding capitalisation of solkat.t.u words in this study may have been noticed by the reader. This is fully
explained later in the paragraph relating the chosen solution to the ambiguities of these words

20

Bar 10
    
               
Ta ki ṭa Ta ki ṭa Ta ka Ta ka Ta ki ṭa Ta ki ṭa

     
Bar 17

               
Ta ki ṭa Ta ka Ta ki ṭa Ta ki ṭa Ta ka Ta ki ṭa

Figure 5.3: Two bars from an improvisation from Vinayakram and McLaughlin (2007, ch.3). The theme
apparent in both bars is the use of permutations of four groups of three with two groups of two. Bar 10
uses Ta ka Ta ka in contrast to Ta ka Ju na of Figure 5.2.

na in the context of Ta ka di na, never as a group of two) with the previously exception of Ta ka Ju
na in Vinayakram and McLaughlin (2007). Such ambiguities are usually confined to mr.daṅgam playing,
where the choice of syllable is more significantly weighted.

Variation Variation and difficulties begin to occur with numbers larger than four. For example Pesch
and Sundaresan (1996, p.13) give the word for five as Ta dhi ki na tom 2 with an alternative of Ta
ka ta ki t.a. The first word is distinctly a group of five, while the second word could be mistaken
for a group of two (Ta ka) and three (Ta ki t.a) which would have a different accent structure to the
first (as shown in Figure 5.4). This ambiguity is more apparent with numbers such as six for which
Nelson (2008, p.15) gives as Ta ka di mi ta ka (4 + 2) or Ta ki t.a ta ki t.a (3 + 3) but as Pesch
and Sundaresan (1996, p.13) point out could just as easily be Ta ka ta ka dhi na (2 + 4). Clearly
all of these examples represent six pulse phrases, however, always implementing a group of six as a
concatenation would prevent the possibility of a six pulse phrase with a single accent on the first beat.

  
         
Ta ka ta ki ṭa Ta ka Ta ki ṭa

Figure 5.4: An ambiguity; a word made from concatenating Ta ka and Ta ki t.a to get Ta ka ta ki
t.a, and a phrase made up of two words Ta ka and Ta ki t.a.

Possible Solutions The most common solution that is at least acknowledged by all sources is to
generate these longer words by concatenation, but treat them as a single word; placing an accent on the
first pulse. Usually with this method as few groups are used for concatenation as possible e.g. Iyer (2000,
p.13) and Lockett (2008, p.20) both give a group of nine as Ta ka di mi ta di gi na dom (4 + 5).
While sources such as Viswanathan and Allen (2004, p.36) and Nelson (2008, p.15) offer the possibility
of Ta ka di mi ta ka ta ki t.a (4 + 2 + 3) (almost certainly because of their use of Ta ka ta ki t.a
for five) nowhere is a group of nine given as Ta ka ta ka ta ka ta ki t.a (2 + 2 + 2 + 3) or similar,
without it being regarded as a grouping of phrases as opposed to a single phrase.
Another solution is to use unique words for these high numbered groupings. The new words result
from extending syllables of Da di gi na dom, as in Figure 5.5.
This idea is employed up to groups of seven syllables by Vinayakram and McLaughlin (2007) and
up to nine by Pesch and Sundaresan (1996, p.13). While both sources accept the possibility of creating
large numbers by concatenation, Vinayakram and McLaughlin (2007) choose to use these unique words
exclusively while Pesch and Sundaresan (1996) give them as alternatives. This solution has two main
2 This unfamiliar spelling for a group of five (usually Da di gi na dom) is exemplary of the previously mentioned (2.1.6)

variation found in Solkat.t.u words

21
5 6 7
  
                 
Da di gi na dom Da di gi na dom Da di gi na dom
8 9

                
Da di gi na dom Da di gi na dom

Figure 5.5: Da di gi na dom and various extensions for groups of six to nine. From Vinayakram and
McLaughlin (2007, ch.4) and Pesch and Sundaresan (1996, p.13)

advantages; the unique word avoids ambiguity and the shared root word Da di gi na dom significantly
eases transitions between the groups (e.g. groups of five to six) in recitation Vinayakram and McLaughlin
(2007, ch.4). While this method is successful in disambiguating phrase groupings (and thus, accents)
the use of two different syllable durations breaks the mould of these building blocks as it creates a sub-
structure, more akin to a phrase made up of words than a low-level word itself. For example the group
of seven in Figure 5.5 has a substructure of 2 + 2 + 3, which is rhythmically different from the first
solution’s Ta ka di mi ta ki t.a. This grey area between words and phrases is highlighted by Brown’s
(1965, p.241) inclusion of the phrase Ta lan - da (commonly Ta lan - gu) in his list of four syllable
groups because “the middle syllable is always long, and because it is always treated as a quadripartite
structure.” See Figure 5.6.

    
    
Ki ṭa ta ka Ta lan gu Ki ṭa ta ka Ta lan gu Tom

Figure 5.6: A quintessential phrase of fours. From Karaikudi R. Mani’s tani āvartanam in Nelson (1991,
vol.3 p.58)

Chosen Solution The solution chosen for this project has resulted from the prioritising of using one
pulse duration for each word so as to avoid sub-structures. This decision means that for numbers above
six a concatenation of words is used to create new words that are considered distinct from a concatenation
of word objects. For example, Ta ki t.a ta ki t.a is preferable to Da di - gi na dom because of its
single pulse duration, and is considered distinct from a phrase made up of two instances of Ta ki t.a i.e.
Ta ki t.a, Ta ki t.a.
For the purposes of this dissertation these basic building block words are made distinct via an en-
largement of the first letter of the first syllable, and in the case of a phrase containing multiple words a
comma is used to separate them. The use of a hyphen ‘-’ indicates an extension of the previous syllable
by an equal duration e.g Ta - ka - and Ta ka di mi are of equal durations. In score notation the first
syllable is made bold and given an accent. Beaming is generally an indication of word grouping but is
occasionally to group phrases where appropriate as with anomalies such as Ta lan - gu. See Figure 5.7
for an example. As the rhythms generated by words with more than one duration (e.g. Da - di - gi na
dom) are a phenomenon of Karn.āt.ak music, they will be accounted for in a different way (discussed in
5.2.2). The list of basic units and their jatis used for this dissertation can be found in Table 2.2.

Maximum Size In theory words of any length could be constructed in this way (e.g. a 13 pulse word
with a single accent being Ta ka di mi ta ka ju na da di gi na dom), in practice this is not the case.
The maximum number of syllables for a single word is commonly given as nine (Nelson, 2008; Lockett,

22
  
             
Ta ka di mi ta ki ṭa Ta ka di mi Ta ki ṭa

Figure 5.7: A score representation of the phrase Ta ka di mi ta ki t.a, Ta ka di mi, Ta ki t.a. Notice
how the enlargement of letters and use of commas correspond to the beginning of words/groupings and
the resulting accents and bold text. as well as the use of beaming (where possible) and bold text. Also
notice how the word for the first group of seven is a concatenation of the words for four Ta ka di mi
and three Ta ki t.a, yet this is considered a group of seven. This is in contrast to the following groups
of four and three which clearly separate entities.

2008; Iyer, 2000) which ties in with the largest of the five rhythmic families 2.1.3. As Nelson (2008,
p.15) notes “longer phrases usually include rests”, which would push such phrases out of this project’s
definition of a word (KonaWord) and into the category of a phrase (discussed later in 5.2.2)

Word / Jatis
Each KonaWord instance contains an array of jatis (syllables, stored as symbols) which are combined to
form a word. The instantiation method new has an argument for defining the number of syllables, which
determines which the of syllables and ultimately the word to be used. Storing the syllables as symbols
makes them useful for printing and playback buffer selection. The KonaTani class (5.2.3) contains an
array of all possible syllables and an array with their corresponding audio buffers. A KonaWord instance
can use the indexOf method of the syllables array with each syllable symbol to find the correct buffer
for playback.

Gati
The gati (sub-division, sometimes called Nadai) is defined at instantiation and is a determining factor
of each syllables’ duration in relation to the beat. The gati is limited to the values of the five rhythmic
families (2.1.3) four, three, seven, five and nine (see Table 2.1). The sub-divisions generated by the gati
are called mātras, so one beat in tiśra (three) gati will have three mātras 3 . For an illustration on the
role of the gati see Figure 5.8.

  3 3
       
Ta ka di mi Ta ka di mi

Figure 5.8: Notation of two four syllable KonaWord instances, the first with a gati of four, the second
with a gati of three.

Karve
The Karve is the number of mātras each jati of a word ‘occupies’ (Iyer, 2000, p.11). For example a
caturaśra gati word with a karve of two would be double the duration of a caturaśra gati word with a
karve of one, as illustrated in Figure 5.9
3 There is a disagreement in the literature as to the definition of mātra. Nelson (1991, vol.1 glossary) uses the term in

regards to the number of beats per aks.ara (count) of the tāl.a, while Pesch and Sundaresan (1996, glossary) and Iyer (2000,
p.11) use the term to describe the sub-divisions created by the gati

23
   
               
Ta ka di mi Ta ka di mi Ta ka di mi Ta ka di mi

Figure 5.9: Notation of four caturaśra gati KonaWord instances, with karves of one to four respectively.

Routine
Each KonaWord instance contains a Routine for playback via a number of possible methods. When run
the Routine will simultaneously play and print each syllable/hit of the word as well as its duration
relative to the beat, as in Figure 5.10. The default method of playback is to use the konaHit SynthDef
to play time stretched recordings (stored in buffers) of each syllable via the PV PlayBuf UGen to avoid
overlap. Alternatively, routines of MIDI signals can be sent to control a synthesiser, sampler or virtual
instrument outside of SuperCollider.
Ta 0.25 ka 0.25 di 0.25 mi 0.25

Figure 5.10: An example of printing from the Routine of a four syllable caturaśra gati KonaWord with a
karve of one.

Printing
Printing of a word is possible outside of a Routine via the postWord method. postWord is capable of
printing the syllables of the word, the duration of each syllable as a decimal relative to the beat, and
the duration as a fractional value relative to western concepts of beat values (e.g. a quaver is 1/8, a
semi-quaver is 1/16 etc). Any or all of these print options can be omitted via arguments. An example
printout is shown in Figure 5.11.

[ Da , di , gi , na , dom ]
[ 0.333 , 0.333 , 0.333 , 0.333 , 0.333 ]
[ [ 1, 12 ], [ 1, 12 ], [ 1, 12 ], [ 1, 12 ], [ 1, 12 ] ]

Figure 5.11: A printout of a five syllable tiśra gati KonaWord with a karve of one, courtesy of the postWord
method with all printing options enabled.

5.2.2 KonaTime
The KonaTime class was built to group together KonaWord as well as KonaTime instances to create
musical structures ranging from a phrase to a whole piece. Rather than use a set of more specific classes
to represent periods of time (e.g. a class for a phrase, another for a tāl.a cycle etc) the more generic
KonaTime was built. This generic class allows for all materials to be treated in the same way, with the
same methods (especially as a KonaTime can hold just a single KonaWord). The use of a generic class as
structure of time allows for unconventional treatments of material, e.g. building a traditional cadential
structure (see 5.3.3) out of a whole piece of music rather than a single phrase.

Design
KonaTime is a subclass of List, making available all of SCLang’s List, SequenceableCollection and
Collection methods for traditional (see 5.3.3) and untraditional manipulations. The availability of these
methods also eased the development process and makes the material more accessible to those familiar
with SCLang.
Konatime stores and makes accessible the following information; the words contained, the combined
and individual duration(s) and jatis of contained objects and the duration in number of tāl.as. As

24
with KonaWord a Routine for playback and a method for printing are included as well as a convenience
concatenation method.

Use
KonaWord instances can be added to a KonaTime in the same way as any object can be added to a List.
Adding multiple KonaWords will result in a short musical phrase, which may in turn be added to another
KonaTime representing a musical passage.
The ambiguous words/phrases outlined in Section 5.2.1 such as Ta lan - gu and Da - di - gi na dom
can be created using a KonaTime and multiple KonaWords as in Figure 5.12. While the syllables may be
different, the rhythm is the same and the hierarchy of syllable accents is kept inline with real KonaWords
by stacking an additional accent on the first syllable if all items in the KonaTime are KonaWords. This is
obviously a form of compromise that could be resolved as a future extension, see 7.1.

    
       
Ta Ta Ta Ta ka Ta ki ta

(Ta lan gu) (Da - di - gi na dom)

Figure 5.12: Phrases Ta lan - gu and Da - di - gi na dom as represented by KonaWords grouped in


a KonaTime notice the additional accents, imitating the accent structure of KonaWords.

25
1.
S S S
2.
S G S G S S G S G S S G S G S
3.

                        
4.

                                                             
26

Da di Ta ka di mi Dum Da di Ta ka di mi Dum Da di Ta ka di mi Da di Ta ka di mi Dum Da di Ta ka di mi Dum Da di Ta ka di mi Da di Ta ka di mi Dum Da di Ta ka di mi Dum Da di Ta ka di mi Dum


( Ta kaTaka di mi Ta Ta kaTaka di mi Ta Ta kaTaka di mi Ta kaTaka di mi Ta Ta kaTaka di mi Ta Ta kaTaka di mi Ta kaTaka di mi Ta Ta kaTaka di mi Ta Ta kaTaka di mi Ta )

Figure 5.13: A compound mōrā from Vinayakram and McLaughlin (2007, ch.6 Finale). Key: 1. KonaTime instance grouping the compound mōrā. 2.
KonaTime instances the compound mōrā statement phrases. 3. KonaTime instances grouping the constituent mōrā statement and gap phrases. 4. KonaWord
instances.
5.2.3 KonaTani
The KonaTani class represents a complete piece of music. Although it was mentioned (5.2.2) that
KonaTime was capable of this task (indeed one is used inside a KonaTani for storage), KonaTani accounts
for more musical aspects, which are required for the automated features of the system.

Design
Specifiable attributes include the laya (tempo), tāl.a, starting gati and gatis to change to (a change of
gati is a ubiquitous feature of Karn.āt.ak drum solos (Nelson, 1991, vol.1 p.90)) and the SynthDef to use
for playback; konaHit for Konakkōl syllables or MIDIPlay for MIDI playback.
¯
As with KonaWord and KonaTime, KonaTani features a routine for playback, but also contains a
TempoClock object on which the routine is played. Also stored is a second routine for clapping the tāl.a
using a SynthDef by Magnusson (2009).
As only one instance of KonaTani will be created per piece of music (unlike KonaWord), the konaHit
SynthDef and buffers for playback are loaded and allocated during KonaTani instantiation. Instantiation
also results in the creation of a KonaGenerator object, discussed in Section 5.3.

Use
A KonaTani can be instantiated with user specified settings with the new method, or with randomly
selected settings with the rand method. If the new method is used a piece can be created by hand using
KonaWord and KonaTime instances with the KonaGenerator instance.

5.3 Generation and Manipulation Class and Methods


The KonaGenerator class was built to handle all of the generation and manipulation requirements of the
system. The methods were not written in an attempt to model the mental processes of the Karn.āt.ak
musician, they are the result of analysis and as such model the output of these processes. Many of the
generation methods make use of the mutation methods, the decision was made to keep these processes
separate to maintain coherency; creating an archetypal phrase and altering it rather than continuously
creating new phrases. Almost all techniques have been implemented as methods that require manual
specification of arguments with an additional probabilistic method for automation. This separation gives
the system great flexibility, making it of use to many users (4.1.2) for many purposes (2.2.2).

5.3.1 Generation Overview


Integer Partitioning - ZS2 Algorithm
Integer partitioning has been incredibly useful for generating Karn.āt.ak music. Given a number of beats
and the gati it is trivial to calculate the total number of pulses. This value may be halved or doubled
(2.1.3) and then partitioned, with the resulting parts used to create phrase groupings which in turn
create accents (“accents are generated by phrase groupings” (Nelson, 1991, vol.1 p.19)) and a musical
structure (see Figures 5.14 and 5.15 for examples).
Integer partitioning in this system is courtesy of the ZS2 algorithm (Figure 5.16) by Zoghbi and
Stojmenović (1998). ZS2 is an unrestricted integer partition algorithm (no limitation on part size)
that produces partitions in lexicographic order with constant average delay (Zoghbi and Stojmenović,
1998). ZS2 was implemented in SCLang as allPartitions. The method has an optional minimum and
maximum part size with a cap on the maximum at nine to match the maximum size of a KonaWord.
Additionally the randomPartition method was written return a single random partition.
For integers greater than 40 the ZS2 implementation started to slow significantly, with a partition of
100 averaging 54.92 seconds. As a workaround the arrays for 40-100 were stored as files and are read
instead of calculated. Numbers up to 39 are kept as calculations as the allPartitions method has the
option to exclude certain partitions (e.g. those with too great a number of unique parts) which is more
efficient than removing such partitions afterwards, which is necessary with arrays loaded from files.

27
      
                       
Ta ki ṭa Ta ki ṭa Ta ka Ta ka di mi Ta ka di mi Ta ka di mi Ta ka di mi
     
               
Ta ka Ta ki ṭa Ta ki ṭa Ta ka Ta ki ṭa Ta ki ṭa

Figure 5.14: Three examples of pulse partitioning of four beats of caturaśra gati. The first bar sees the
16 pulses treated as eight with twice the duration, partitioned into 3 + 3 + 2. The second is a partition
of the 16 into 4 + 4 + 4 + 4. The third is a partition of 2 + 3 + 3 + 2 + 3 + 3, which is more likely a
partitioning of eight pulses into 2 + 3 + 3 with a repetition. From Vinayakram and McLaughlin (2007,
ch.2)

    
      
Tam Tom Na na Din Din na
(Ta Ta Ta ka Ta Ta ka)

Figure 5.15: A four beat caturaśra phrase partitioned into 6 + 2 + 2 + 2 + 4. Notice how the part value
is used as the number of mātras (sub-division parts) for each word and not necessarily the number of
pulses, e.g. the second word Tom and the third Na na have the same duration in mātras but a different
number of pulses. From Karaikudi R. Mani’s tani āvartanam (aksharas one and two from cycle three)
in Nelson (1991, vol.3 p.58). Nelson’s solkat.t.u is given as the top line, with this project’s underneath.
Note: As Nelson does not use western notation or any formatting in regards to capitalisation, the conventions
adopted for this project have been applied to both lines of solkat.t.u..

Permutation
Once a number of pulses has been partitioned, so long as there is variation in part size, a number
of variations up to the factorial of the integer can be generated by permutation. See Figure 5.17. A
method to return all permutations (allPerms) and a method to return a single (random) permutation
(randomPerm) were written.

Pruning
Number of unique parts After experimentation with partitioning and permutation for material
generation it was felt that the partitions would sometimes lack an identity. Comparison with real-
world highlighted the fact that typically no more than three unique part sizes were used, examples from
Vinayakram and McLaughlin (2007, ch.6, ch.2); Figure 5.13 is up of phrases of 4 + 4 + 2 (two unique
parts), Figure 5.14 uses 6 + 6 + 4 (three unique parts, could be seen as 3 + 3 + 2), 4 + 4 + 4 + 4 (one
unique part) and 2 + 3 + 3 + 2 + 3 + 3 (two unique parts), Figure 5.17 uses permutations of 3 + 3 +
2 (two unique parts), an example by Mani from Nelson (1991, vol.3 p.58); Figure 5.15 uses 6 + 2 + 2 +
2 + 4 (three unique parts).
As a result of this observation the removeGreaterThan method was written which will remove from
a given collection any partition with more unique parts than an given value. A weight parameter is
included with a default of 0.97 to occasionally allow partitions with a high number of unique parts.

Part sizes Although it has been said that a tāl.a and gati have no inherent accent structure (Sec-
tion 2.1.1) there are often cases where it is desirable to highlight the current environment, e.g. sarvalaghu
patterns, on which Nelson (1991, vol.1 p.29) comments “phrases are arranged in patterns that bear an
integral relation with the given aks.ara structure. These patterns are arranged into groups that bear an

28
Algorithm ZS2
1 for i ← 1 to n do x[i] ← 1; output x[1..n];
2 x[0] ← −1; x[1] ← 2; h ← 1; m ← n − 1; output x[1..n];
3 while x[1] 6= n do
4 if m − h > 1
5 then h ← h + 1; x[h] ← 2; m ← m − 1;
6 else j ← m − 2;
7 while x[j] = x[m − 1] do x[j] ← 1; j ← j − 1;
8 h ← j + 1; x[h] ← x[m − 1] + 1;
9 r ← x[m] + x[m − 1](m − h − 1); x[m] ← 1;
10 if m − h > 1
11 then x[m − 1] ← 1;
12 m←h+r−1
13 output x[1..m]

Figure 5.16: Pseudo code for the ZS2 algorithm by Zoghbi and Stojmenović (1998).

        
                       
Ta ki ṭa Ta ki ṭa Ta ka Ta ka Ta ki ṭa Ta ki ṭa Ta ki ṭa Ta ka Ta ki ṭa

Figure 5.17: Three permutations of the 3 + 3 + 2 partition of eight. From Vinayakram and McLaughlin
(2007, ch.3)

analogous relationship with the tāl.a structure.” One way to achieve this might be to use groupings of
sizes that are strongly related to the structure, e.g. groups of two, four and eight in ādi tāl.a (8 beats)
caturaśra gati. However, as Nelson (1991, vol.1 p.31) points out it is possible to “use a contrasting
organization of pulses, thereby generating a more complicated relationship with a beat or pair of beats”
with which he gives the example of a 3 + 3 + 2 pattern for two beats of caturaśra gati. The extent
to which it is desirable to use patterns that contrast with the structure of the environment is context
dependant, Nelson (1991, vol.1 p.40) gives the example in Figure 5.18 as being “closer to the kan.akku
end of the spectrum”.
To account for both of these situations the method removeThoseContaining was written which will
remove from a collection of partitions all those which contain specified part sizes. An optional argument
is provided so that each value can be given a probability of removal.

 5  5
 5 5

Ta ṇa jo ṇu Ta ṇa jo ṇu Ta ṇa jo ṇu Ta ṇa jo nu Ta ṇa jo ṇu
( Ta ka di mi Ta ka di mi Ta ka di mi Ta ka di mi Ta ka di mi )

Figure 5.18: A four aks.ara khand.a gati pattern made up of groups of four. An example of how groupings
outside of the rhythmic family of the gati can be used. From Nelson (1991, vol.1 p.40)

Converting to KonaWords
As the initial generation methods work with arrays of integers, the method partsToWords was written
to convert these into KonaWords. In addition to the partition array parameter, two boolean parameters

29
are included for control over the way KonaWords are generated. The first parameter determines whether
or not KonaWords can be created with a single jati (Ta) and a karve equal to the partition size, the
second specifies the possibility of the opposite; a KonaWord with a number of jatis equal to the partition
size and a karve of one (Figure 5.19). If both (or neither) parameter is set to true, each possibility is
given a 50% chance.



Ta

   
Ta ka di mi

Figure 5.19: Two possible conversions of the part size four into a KonaWord. The top line with one jati
and a karve of four, and the bottom line with four jatis and a karve of one.

Combining
As the length of phrases and speed increases so to does the use of larger phrase groupings. In Figure 5.20
we can see a 2 + 2 + 2 + 2 + 4 structure, while both examples in Figure 5.21 use larger groupings
(predominantly fours in the first example and eight and six in the second) and are twice the speed.
The reasons for this have not been written about, however Vinayakram and McLaughlin (2007, ch.5)
give the opinion that a subdivision as in Figure 5.20 is ‘boring’. In recitation it is also noticeably easier
to work with larger groupings at faster tempos, the reader is invited to compare repetition of Ta ka
Ta ka and Ta ka di mi at 160bpm. The use of larger groupings also reduces the total number of
mental objects being dealt with, easing memorisation (Miller, 1956) which is key to the oral tradition of
Karn.āt.ak teaching (Viswanathan and Allen, 2004, p.60).

    
           
Ta ka Ta ka Ta ka Ta ka Ta ka di mi

Figure 5.20: An phrase with an uncommon use of many groups of two as opposed to larger groupings,
yet still possible to perform at 90bpm. From Vinayakram and McLaughlin (2007, ch.5)

To account for this phenomena the method combine was written to regroup the total number of pulses
in a phrase (KonaTime) into as few KonaWords as possible. Additionally combineSimilar was written to
combine adjacent identical KonaWords, with arguments for the maximum combination size, the maximum
number of KonaWords to combine and a probability (default of one) determining combination success.

5.3.2 Sarvalaghu Generation


As previously discussed (4.1.1) sarvalaghu patterns are the time-keeping structures that reinforce the flow
of the tāl.a (Viswanathan and Allen, 2004, p.68) and form the majority of accompaniment playing. Unlike
the calculated forms of playing (5.3.3) for which formulae have been documented, accompaniment is
considered “extremely difficult to teach, and to this day is learned primarily by example and absorption.”
(Nelson, 1991, vol.1 p.iv). Sarvalaghu patterns vary between musicians and contexts. For example, in
the vilamba kāla stages of a tani āvartanam the patterns tend to use two mātra syllables/strokes with
accents on the beat or half beat, while in the madhyama kāla section one mātra syllables/strokes are
used with accents on any pulse in the beat (Nelson, 1991, vol.1 p.37) (see Figure 5.22).
The sarvalaghu generation in this project has focused on the vilamba kāla sarvalaghu styles of the
five tani āvartanams in Nelson (1991). As these tani āvartanams were all at a similar tempo and in

30
       
                       
Din Ta ri gi du Ta ri gi du Ta ri gi du Ta ri gi du Ta ri gi du Din ta Din
( Ta Ta ka di mi Ta ka da mi Ta ka di mi Ta ka di mi Ta ka di mi Ta ka Ta )

    
                
Ta ka ta ri ki ṭa ta ka Ta ri ki ṭa ta ka Tom Tom Ta
( Ta ka di mi ta ka ju na Ta ki ṭa ta ki ṭa Ta Ta Ta )

Figure 5.21: Two fast phrases using large groupings such as four, six, and eight as opposed to small
groupings of two or three. This tends to be the norm at speeds such as this (performed at 85bpm).
The first phrase is from an exposition of a composition by Palani Subramania Pillai by Vellore G.
Ramabhadran as part of his tani āvartanam in Nelson (1991, vol.3 p.9) . The second phrase is from
Trichy S. Sankaran’s tani āvartanam in Nelson (1991, vol.3 p.162)

Vilamba kāla Madhyama kāla


             
                     
Tam Tom Na na Din Din na Jo nu Ta Din Din Ta na Di na Gi na Di na Di na
( Ta Ta Ta ka Ta Ta ka ) ( Ta ka Ta Ta Ta Ta ka Ta ka Ta ka Ta ka Ta ka )

Figure 5.22: Two phrases from Karaikudi R. Mani’s tani āvartanam in Nelson (1991, vol.3 p.58, p.65),
highlighting the difference in sarvalaghu patterns between sections of an improvisation. The vilamba
kāla example primarily uses words with jatis of at least two mātras, with accents only on the whole or
half beat. The madhyama kāla example primarily uses words with one mātra jatis and contains accents
on quarter beats.

the same tāl.a and gati, additional patterns in other settings were transcribed from Vinayakram (2007)
(Appendix C).
Analysis revealed that sarvalaghu patterns were not simply improvisation within a setting, instead
an archetype phrase is set up and used as the basis for improvisation (see Figure 5.23). In some cases a
new phrase is developed from the archetype, and adopted as the new foundation for improvisation (see
Figure 5.24).

Phrase Length A prevalent feature of these phrases was a neat fitting of repetitions within the tāl.a, as
a result attempts were made to calculate phrase length as a division of the tāl.a. This model had problems
accounting for phrases at faster tempos which often occupied entire tāl.as (Figure 5.25). To take tempo
into account the length of phrases were considered in terms of absolute time (see Figure 5.26), where a
striking similarity was found between phrases; they were all between 2 and 3.375 seconds, fitting well
with the perceptual present and short-term memory of humans within which most musical and spoken
phrases fit (London, 2004, ch.2) (Collins, 2008, p.3).
vSarvaPhraseLength was written to calculate a suitable duration (in beats) for a sarvalaghu phrase.
The maximum number of beats for a phrase is calculated using the absolute time for one beat and the
maximum cognitive time for a phrase. Regardless of absolute time a limit of five beats is enforced as most
phrases stayed below this, possibly because of information load (Collins, 2008, p.3). vSarvaPhraseLength
then find the longest phrase length that fits neatly into the tāl.a once or in multiples of two.

Phrase Generation Phrase generation is split into two methods vSarvaPhrase and vSarvaPhraseAuto;
the former creating phrases according to a given phrase duration in mātras, and the later simply call-

31
     
         
Tam Ta ka Din na Ta ka Din Din ta
( Ta Ta ka Ta na Ta ka Ta Ta ka )

       
          
Tam Ki ta Din na Na ka jo nu Ta ka jo nu Ta lan gu
( Ta Ta ka Ta ka Ta ka di mi Ta ka di mi Ta Ta Ta )

Figure 5.23: Two phrases from from the vilamba kāla of Trichy S. Sankaran’s tani āvartanam in Nelson
(1991, vol.3 p.162). The second phrase can clearly be seen to be a variation on the first, with density
alteration of the last three syllables.

   
       
Na din Din na Na din Din na
( Ta ka Ta ka Ta ka Ta ka )

     
         
Tam Ki ṭa Din na Ta ka Din Din na
( Ta Ta ka Ta ka Ta ka Ta Ta ka )

Figure 5.24: Two phrases from from the vilamba kāla of Trichy S. Sankaran’s tani āvartanam in Nelson
(1991, vol.3 p.162). The first is a common basic sarvalaghu pattern (Nelson, 1991, vol.1 p.32) which is
transformed into the second phrase via minor adjustments. The second phrase is then adopted as an
archetype phrase for the rest of the vilamba kāla (Nelson, 1991, vol.3 p.162-171).

ing vSarvaPhrase passing in the results of the vSarvaPhraseLength method multiplied by the gati.
vSarvaPhrase was written to generate fundamental sarvalaghu phrases from which variations and new
motifs can be created. In accordance with Nelson’s (1991, vol.1 p.37) observation that patterns in vil-
amba kāla primarily use words with two mātra jatis, the minimum part size (for partitioning) is set to
two. The maximum value is set to the gati if the phrase is long, and the phrase duration if not, an
array is created from these values e.g. [2,3,4,5] for khand.a gati. An array of weights for each part
size is constructed with bias for part sizes that are included in the gati’s rhythmic family (2.1.3). For
khand.a (five) and mis̄ra (seven) gati part sizes two and three are given an additional bias because of


q = 84
  
       
Ta ka Dim Ta ka Dim na
( Ta ka Ta Ta ka Ta ka )

Figure 5.25: A khand.a cāpu sarvalaghu phrase by Vinayakram (2007, Disc.1 ch.6) occupying the entire
cycle.

32
Adi tāḷa tiśra gati 120 bpm from Vinayakram (2007, Disc 1, ch.6).
Time: 2 seconds
q = 120
 3
 3 3
 3
           
Tam Ta ka Ki ṭa ta ka Din ta Din na
( Ta Ta ka Ta ka di mi Ta ka Ta ka )

Rupaka tāḷa caturaśra gati 90 bpm from Vinayakram (2007, Disc 1, ch.6).
Time: 2 seconds
q = 90
   
      
Ta Ta ka Din Din na
( Ta Ta ka Ta Ta ka )

Khanḍa cāpu caturaśra gati 168 bpm from Vinayakram (2007, Disc 1, ch.6).
Time: 1.8 seconds

e = 168   
       
Ta ka Dim Ta ka Dim na
( Ta ka Ta Ta ka Ta ka )

Sankīrṇa cāpu caturaśra gati 160 bpm from Vinayakram (2007, Disc 1, ch.6).
Time: 3.375 seconds


e = 160
    
                  
Ta ka di mi Ta ka Ju na Ta ka di mi Ta ki ṭa Ta di mi
( Ta ka di mi Ta ka Ta ka Ta ka di mi Ta ki ṭa Ta ki ṭa )

Adi tāḷa caturaśra gati 96 bpm from Trichy Sankaran’s tani āvartanam in Nelson (1991, vol.3 p.162).
Time: 2.5 seconds

q = 96     
          
Tam Ki ta Din na Ta ka Din Din na
( Ta Ta ka Ta ka Ta ka Ta Ta ka )

Figure 5.26: Sarvalaghu phrases in various contexts, with absolute times all between 2 and 3.375 seconds.

33
their suitability for the gati.
The phraseMatras value is partitioned with allPartitions (passing in the maximum part size),
with any partition with more than four parts being removed by removeGreaterThan. Partitions with
particular part sizes are probabilistically removed by passing the array of part sizes and weights to
removeThoseContaining. A partition is randomly selected and finally permuted with randomPerm. A
custom transformation from integers to KonaWords then takes place; any even values greater than two
are given a 75% chance of being halved in terms of jatis and doubled in terms of karve (e.g. a four mātra
Ta becomes a two mātra per jati Ta ka), all other values become single jati (Ta) KonaWords with the
part number used for the karve. Finally the phrase is passed into combineSimilar with a maximum
combination size of four and some syllables are probabilistically muted to create variation (see Muting
Jatis in Section 5.3.4). See Figure 5.27 for an example of this process.

Phrase Development As previously mentioned (Section 5.3.2) it is common for a phrase to be varied
enough that it becomes a separate entity, which may then be adopted as a primary phrase from which
further variations are created (see Figure 5.24). This is achieved using the mutatePhrase method which
calls upon a number of sub-routines. This process is discussed in detail in Section 5.3.5.

Phrase Suffixes As Nelson (1991, vol.1 p.88) notes it is very common for sarvalaghu phrases to be
concluded with a ‘suffix’ that may also serve to provide variety as well as introduce cadences (see the
discussion of formal cadences in Section 5.3.3). See Figure 5.28 for an example.
From analysis of the suffixes in Nelson’s (1991, vol.3) five tani āvartanam it was apparent that the
most typical feature was an increase of jati density; using a greater volume of shorter notes. The
addSuffix method was written to add a suitable suffix to the end of a given phrase. This method
collects the jatis that make up the last quarter of the phrase and increases the density; double for the
first few jatis, and possible quadruple for the middle and last jatis. For a more detailed explanation of
jati density alteration see Altering Jati Density in Section 5.3.4.

Statistical Generation
Statistical generation of sarvalaghu patterns were briefly experimented with; a model was made of the first
four cycles of Trichy S. Sankaran’s tani āvartanam in Nelson (1991, vol.3 p.162). This was implemented
in as the method vSarvaStat, but was not developed beyond a basic state.

5.3.3 Kannaku Generation


Simple Mōrās
A mōrā is “the fundamental cadential structure of Karn.āt.ak music” (Nelson, 1991, vol.1 glossary). Nelson
came up with a simple formula for mōrās (Figure 5.29) and notes “a mōrā usually consists of a phrase
or statement repeated three times with separations that may be articulated. Its structure sets up a
temporary tension with that of the tāl.a that is usually resolved at an important structural point in the
cycle.” While it is necessary for the statement to be at least one pulse in duration, the gap may be 0
(Nelson, 1991, vol.1 p.46). This allowance neatly combines two of Iyer’s (2000, p.68, p.79) mōrā formulas
(Figure 5.30).
As the gap and the final resolving beat often use the same sound (as in Figure 5.31) the structure of
some Mōrās with a gap greater than 0 is easy to misinterpret as just three statements (as Brown (1965,
vol.1 p.151) did), as shown in Figure 5.31. While this example is understandable, with a mōrā such as
Figure 5.32 the interpretation is clearly invalid.

34
1 Call: vSarvaPhraseAuto
2 Call: vSarvaPhraseLength
3 return 4 //Phrase duration in beats
4

5 Call: vSarvaPhrase(vSarvaPhraseLength*gati: 16) //Total number of matras


6

7 Call: allPartitions
8 return [ [ 4, 3, 3, 3, 3 ], [ 4, 4, 2, 2, 2, 2 ],
9 [ 4, 4, 3, 3, 2 ], [ 4, 4, 4, 2, 2 ],
10 [ 4, 4, 4, 4 ].... ]
11 Call: removeGreaterThan
12 return [ [ 4, 3, 3, 3, 3 ], [ 4, 4, 2, 2, 2, 2 ],
13 [ 4, 4, 3, 3, 2 ], [ 4, 4, 4, 2, 2 ],
14 [ 4, 4, 4, 4 ]... ]
15 Call: removeThoseContaining
16 return [ [ 4, 4, 2, 2, 2, 2 ], [ 4, 4, 4, 2, 2 ],
17 [ 4, 4, 4, 4 ] ]
18

19 Call .choose
20 return [ 4, 4, 4, 2, 2 ]
21

22 Call: randomPermutation
23 return [ 4, 2, 4, 4, 2 ]
24

25 Conversion to KonaWords:
26 [ Ta , ka , Ta , Ta , ka , Ta , ka , Ta ]
27 [ 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5 ]
28

29 Call: combineSimilar
30 return
31 [ Ta , ka , Ta , Ta , ka , di , mi , Ta ]
32 [ 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5 ]
33

34 Call: randomMuteJati
35 return
36 [ Ta , ka , - , Ta , ka , di , mi , Ta ]
37 [ 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5 ]
38

39 return
40 [ Ta , ka , - , Ta , ka , di , mi , Ta ]
41 [ 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5 ]
42

Figure 5.27: An example of the phrase generation process in Ādi tāl.a at 80bpm.

35
Suffix


   
    
Din Din Tam Tom Tom Ta
( Ta Ta Ta Ta Ta Ta )

S G S G S

              
Tam Tom Tom Ta Tam Tom Tom Ta Tam Tom Tom Ta Din
( Ta Ta Ta Ta Ta Ta Ta Ta Ta Ta Ta Ta Ta )

Figure 5.28: A phrase with a suffix from Palghat R. Raghu’s tani āvartanam (Nelson, 1991, vol.3 p.104-
105) (top line), and a mōrā that appears later using the suffix for the statement sections.

xyxyx (5.1)

or

(Statement)(Gap)(Statement)(Gap)(Statement) (5.2)

Figure 5.29: Nelson’s (1991, vol.1 p.46) mōrā formula

(Jathi)(Jathi)(Jathi) (5.3)

(Jathi)(Karve)(Jathi)(Karve)(Jathi) (5.4)

Figure 5.30: Two of Iyer’s (2000, p.68, p.79) mōrā formulas that can be accounted for with Nelson’s one
(5.29). Note Iyer’s different terminology; he uses Jathi to mean syllable or group of syllables (which is
distinct from words, for which he uses Thatthakaras). He also gives karve two meanings; the first in
accordance with use in this study, and the second to mean ‘an independent Jathi to seperate two Jathis
or groups of Jathis in a mukthayam [mōrā]’.

s s s
1.
s g s g s
2.
     
   
Ta ri gi du Ta Ta ri gi du Ta Ta ri gi du Ta
( Ta ka di mi Ta Ta ka di mi Ta Ta ka di mi Ta )

Figure 5.31: Two possible interpretations of a mōrā by Karaikudi R. Mani’s tani āvartanam in Nelson
(1991, vol.3 p.59). While the first might seem plausible, it is only because the gaps and the concluding
beat are identical. See Figure 5.32 for a situation where such an interpretation is made impossible.

36
1. s s s

2. s g s g s
                            
                
37

Ta ri Ta ri Ki ṭa ta ka Ta ri Ki ṭa ta ka TomTomTaTom Ki ṭa ta ka Ta ri Ta ri Ki ṭa ta ka Ta ri Ki ṭa ta ka TomTomTa
TaTom Ki ṭa ta ka Ta ri Ta ri Ki ṭa ta ka Ta ri Ki ṭa ta ka TomTomTaTom
( Ta ka Ta ka Ta ka di mi Ta ka Ta ka di mi Ta Ta Ta Ta Ta ka di mi Ta ka Ta ka Ta ka di mi Ta ka Ta ka di mi Ta Ta Ta Ta Ta ka di mi Ta ka Ta ka Ta ka di mi Ta ka Ta ka di mi Ta Ta Ta Ta )

Figure 5.32: A long mōrā from Trichy S. Sankaran’s tani āvartanam in Nelson (1991, vol.3 p.164). While the use of only three statements was plausible in
Figure 5.31, in this case it is clearly invalid as the statements are not identical. The second grouping conforms to the formulas of Nelson (1991) and Iyer
(2000).
The task of generating mōrās is split into a number of methods; moraStatement, moraGap, and
moraOffset for generating their respective parts from a given duration in mātras, gati and karve,
createSimpleMora for combining the parts into the mōrā structure, randomMoraValues for calculat-
ing suitable durations for each section of a mōrā from a given total duration in mātras, randomMora for
generating random mōrās from a given duration in mātras, gati and karve and moraFrom for creating
mōrās from a given KonaWord/KonaTime instance for the statement and a maximum duration in mātras.
moraStatement, moraGap and moraOffset work in a similar manner; given a number of pulses, gati
and karve they will generate either a single jati KonaWord or one or more poly-jati KonaWords, filling the
given duration. The weights for the methods differ, with gaps given a greater weighting for single jati
KonaWords, and only offsets given the possibility of being entirely rests.
Given a duration in mātras, gati and karve, randomMora will randomMoraValues to calculate the
durations for each section of the mōrā and createSimpleMora with moraStatement, moraGap, and
moraOffset methods to generate a simple mōrā. If the duration is less than seven randomMora is called
recursively with the duration doubled but the karve halfed; the mōrā has the same duration but double
the density. The reason for this is Nelson’s (2008, p.23) observation that “if a mora statement is shorter
than five pulses, its gap will nearly always be at least two pulses”, any duration below seven makes this
impossible. This possibility of increased density is also given a 12.5% chance of occurring regardless of
the duration. Nelson’s (2008, p.23) observation is also taken into account when deciding statement and
gap durations; if the total duration is less than 15 the gap minimum is set to two. Once possible gap and
statement durations have been calculated and randomly selected, the required offset can be calculated.
Finally all three values are turned into KonaWords with their respective methods and returned in a
KonaTime. As mōrās are cadences always resolved with a strong beat (or at least never a rest) the
makePostMora method was written to ensure that the material that comes after the mōrā does not start
with a rest; converting rests if necessary.
The moraFrom method allows mōrās to be generated using a given phrase, which could for example
be a phrase featured earlier in a composition, a common practice made apparent through analysis of the
five tani āvartanams in Nelson (1991, vol.3). This phenomenon is noted by Nelson (1991, vol.1 p.89) in
his discussion of phrase suffixes, which “intrdouce rhythmic phrases that always hvae the potential to
become formal cadences”. The method also has the option of passing in a pre-made gap and/or offset,
any section that is not passed in is generated.

Compound Mōrās
A compound mōrā is a mōrā in which the statements themselves are also of the mōrā form (Nelson, 1991,
vol.1 p.53) (Figure 5.29), see Figure 5.13 for an example.
The randomSamaCompoundMora method was written to generate compound mōrās with a sama (equal)
yati (shape); where all three statements are identical (there are other shapes such as gopucca– ‘cow’s
tail’ which contracts with increasingly smaller statements and srotovaha– ‘river-mouth’ the opposite of
gopucca). This method uses the randomMoraValues method to determine section values, randomMora to
create the simple mōrā that will comprise the statements of the compound mōrāand moraFrom to create
the missing parts (offset and gaps if necessary) and build the mōrā structure.

Gati Changes
A change of gati is crucial to the tani āvartanam, and is usually carried out in the middle section; the
madhyama kāla (Nelson, 1991, vol.1 p.89-90). Often a whole section of music will be transposed from
the original gati to a new one, in a tani āvartanam by Palghat R. Raghu performs a 180 pulse kōrvai
(form of composition) in caturaśra, khand.a and tiśra gati (Nelson, 1991, vol.1 p.19, vol.3 p.107-108) see
Figure 5.33.
To model this process wordAtGati and phraseAtGati were written. wordAtGati takes an existing
KonaWord and desired gati and karve, from which it returns a new KonaWord equal in jatis but with
altered gati and karve. As phraseAtGati has to keep relative the karves of multiple KonaWords it takes a
gati parameter and an expansion parameter instead of karve. A distinction is made between KonaWords
and KonaTimes, the former returns a new KonaWord with the input object’s karve multiplied by the
expansion value, the later results in a recursive call on all contained objects until a KonaWord is being
dealt with.

38

Caturaśra
     
       
Ta di Ta di ki ṭa tom Ta
( Ta ka Ta Ta Ta Ta Ta Ta )
Khanḍa
 5
 5 5  5
         
Ta di Ta di ki ṭa tom Ta

Tiśra

 3 3 3  3
         
Ta di Ta di ki ṭa tom Ta

Figure 5.33: An example of gati change. The first phrase from a kōrvai in Palghat R. Raghu’s tani
āvartanam (Nelson, 1991, vol.3 p.107-108) in caturaśra, khand.a and tiśra gati.

5.3.4 Micro Mutation


A number of methods have been implemented for altering material at the micro level; the jatis of
individual KonaWords.

Altering Jati Density


A simple method of variation from an existing pattern is to increase the ‘density’ of one or more of the
jatis as shown in Figure 5.34. The densityJati method was written to accomplish this, taking as its
parameters a KonaWord, the index of the jati to be altered and the density multiplier (see Figure 5.35 for
example output). Additionally the randomDensityJati method was written to automate this process,
randomly selecting an index and choosing from acceptable multipliers for the gati (e.g. three is unsuitable
for caturaśra gati). As this process appeared frequently during analysis randomDensityJati is given a
chance of recursion which decreases with each recursive call.
This process is only designed to increase the density of a jati as decreasing the density would return
a phrase of greater duration than the input word. A different approach was used to solve this problem
(see Extending Jatis below).

   
       
Na din Din na Na din Din na
( Ta ka Ta ka Ta ka Ta ka )

     
         
Tam Ki ka Din na Ta ka Din Din na
( Ta Ta ka Ta ka Ta ka Ta Ta ka )

Figure 5.34: The first four beats from cycles two and three of Trichy S. Sankaran’s tani āvartanam in
Nelson (1991, vol.3 p.162). The first line is a common basic sarvalaghu pattern (Nelson, 1991, vol.1
p.32), the second is a variation easily produced using the densityJati method on index one of the first
word with a multiplier of two, and on index 0 of the third word with a multiplier of two.

39
    3   3 
          
Ta ka Ta Ta ka Ta ki ṭa Ta Taka di mi Ta

postWord method printout:


[ Ta , ka ] [ Ta , ki , tah ]
[ 0.5 , 0.5 ] [ 0.333 , 0.333 , 0.333 ]
[ [ 1, 8 ], [ 1, 8 ] ] [ [ 1, 12 ], [ 1, 12 ], [ 1, 12 ] ]
Becomes Becomes
[ Ta , Ta , ka ] [ Ta , Ta , ka , di , mi , Ta ]
[ 0.5 , 0.25 , 0.25 ] [ 0.333 , 0.083 , 0.083 , 0.083 , 0.083 , 0.333 ]
[ [ 1, 8 ], [ 1, 16 ], [ 1, 16 ] ] [ [ 1, 12 ], [ 1, 48 ], [ 1, 48 ], [ 1, 48 ], [ 1, 48 ], [ 1, 12 ] ]

Figure 5.35: Example output from jatiDensity. In the first example a two pulse, caturaśra gati, two
karve KonaWord has been passed in with the index of mutation as one and a density multiplier of two.
In the second example a three pulse, tiśra gati, one karve KonaWord is passed in with index of one and a
multiplier of four.

Extending Jatis
To solve the problem of decreasing the density of a jati in a KonaWord (as in Figure 5.36) the extendJati
method was written. Instead of requiring a multiplier this method takes the number of jatis to extend
a given jati by, a check is included to make sure that the extension stays within the duration of the
KonaWord. The randomExtendJati method provides automation of this process.

1-2
   
       
Na din Din na Na din Din na
(Ta ka Ta ka Ta ka Ta ka

.combine

1-2
  
       
Na din din na Na din Din na
(Ta ka di mi Ta ka Ta ka
.extendJati

   

3-4

    
Tam Ta Ta din Din na
Ta Ta Ta ka Ta ka

Figure 5.36: An example of jati contraction. The top line shows aks.aras one and two of the second
cycle of Trichy S. Sankaran’s tani āvartanam (in Nelson (1991, vol.3 p.162)). The second line shows this
phrase altered with the combine method (5.3.1 Combining). The third line is the result of extendJati
used on index 0 of the first word with an extension of two.

Muting Jatis
As an alternative method of achieving similar results as those in Figure 5.36 the muteJati method was
written. Given a KonaWord and an index this method will turn an audible jati into a rest. Despite the
difference in representation (see Figures 5.37 and 5.38) the results are identical. In Karn.āt.ak music the

40
term kārvai, which is almost analogous to the Western ‘rest’ (Nelson, 1991, vol.2 p.162) yet differs as
“unlike our rest, [kārvai] includes the syllable immediately preceding it, and in fact may be said to flow
from it as an extension”. This is probably one of the reasons that Nelson chose not to use staff notation.

 
    [ Ta
[ 0.5
, ka
, 0.5
, Ta
, 0.5
, ka
, 0.5
]
]
Na din Din na [ [ 1, 8 ], [ 1, 8 ], [ 1, 8 ], [ 1, 8 ] ]
( Ta ka Ta ka )

 
  [ Ta
[ 1.5
, Ta
, 0.5
]
]
Tam Ta [ [ 3, 8 ], [ 1, 8 ] ]
( Ta Ta )

 
    [ Ta , - , - , Ta ]
[ 0.5 , 0.5 , 0.5 , 0.5 ]
Tam Ta [ [ 1, 8 ], [ 1, 8 ], [ 1, 8 ], [ 1, 8 ] ]
( Ta Ta )

Figure 5.37: Notation and KonaWord postWord out-


put of a phrase (line one) from Trichy S. Sankaran’s
tani āvartanam (in Nelson (1991, vol.3 p.162)) al-
tered by combination and extension (line two) and Figure 5.38: Output from calling postWord on each
muting (line three). of the KonaTime instances in Figure 5.37.

Partitioning
Just as partitioning can be used to generate new phrases, it can also be used to create variations by
partitioning existing KonaWords. While many other processes feature a manual and automated method,
for this process a single optionally manual method is provided. This is due to the large number of
possible partitions for most values, if specific values were desired they could be instantiated by hand.
partitionWord takes as parameters a KonaWord, minimum and maximum part sizes, if no minimum
or maximum sizes are provided they are chosen randomly. partitionWord will randomly partition and
permute the total number of mātras (jatis * karve) of the given KonaWord, and return them as new
KonaWords in a KonaTime (Figures 5.39 and 5.40).


       [Ta , ka , di , mi , ta , ki , tah ]
[0.25 , 0.25 , 0.25 , 0.25 , 0.25 , 0.25 , 0.25 ]
[[1, 16], [1, 16], [1, 16], [1, 16], [1, 16], [1, 16], [1, 16]]
Ta ka di mi ta ki ṭa
  
       [Ta , ka , Ta , ki , tah , Ta , ka ]
[0.25 , 0.25 , 0.25 , 0.25 , 0.25 , 0.25 , 0.25 ]
[[1, 16], [1, 16], [1, 16], [1, 16], [1, 16], [1, 16], [1, 16]]
Ta ka Ta ki ṭa Ta ka

Figure 5.39: A seven jati, caturaśra gati, one karve


KonaWord (Line one) partitioned into a KonaTime
with three KonaWords, all caturaśra gati, one karve Figure 5.40: Output from calling postWord on each
with 2 + 3 + 2 jatis respectively. of the KonaTime instances in Figure 5.39.

41
5.3.5 Macro Mutation
For altering large groups of material additional methods have been implemented that make use of the
automated micro mutation methods (5.3.4).

Altering Phrase Density


Just as the density of individual jatis can be altered with densityJati, a method has been written
to alter the density of KonaWords or collections of them. atDensity takes as its parameters either a
KonaWord or KonaTime as well as a density multiplier. So that relative densities can be maintained within
a phrase, atDensity works recursively until it deals with individual KonaWords. If the altered number
of jatis is an integer and can fit into a single word (i.e. is under nine) a new KonaWord is returned to
the stack parent. If the new jati number is not an integer (e.g. a nine jati word is multiplied by 0.5) a
single jati word with a karve equal to the jatis of the input word is returned. If more than one KonaWord
is required they are returned in a KonaTime. An automated version of this method is implemented as
randomAtDensity which chooses randomly from a list of valid density multipliers for the gati, with a
maximum resulting karve of 0.5.

 5 5
         
Ta ka Ta ki ṭa Da di gi na dom
 5  5

           
Ta ka di mi Ta ki ṭa ta ki ṭa Da di gi na dom Da di gi na dom

Figure 5.41: Altering phrase density. A khand.a gati phrase (top line) is doubled in density (bottom line)
using atDensity with a multiplier of two. The phrase consists of a sub-phrase of KonaWords Ta ka +
Ta ki t.a and a KonaWord Da di gi na dom. Notice how in the mutation the density is kept relative
when doubled.

[ Ta , ka , Ta , ki , tah , Da , di , gi , na , dom ]
[ 0.2 , 0.2 , 0.2 , 0.2 , 0.2 , 0.4 , 0.4 , 0.4 , 0.4 , 0.4 ]
[ [ 1, 20 ], [ 1, 20 ], [ 1, 20 ], [ 1, 20 ], [ 1, 20 ], [ 1, 10 ], [ 1, 10 ], [ 1, 10 ], [ 1, 10 ], [ 1, 10 ] ]

[ Ta , ka , di , mi , Ta , ki , tah , ta , ki , tah ,
[ 0.1 , 0.1 , 0.1 , 0.1 , 0.1 , 0.1 , 0.1 , 0.1 , 0.1 , 0.1 ,
[ [ 1, 40 ], [ 1, 40 ], [ 1, 40 ], [ 1, 40 ], [ 1, 40 ], [ 1, 40 ], [ 1, 40 ], [ 1, 40 ], [ 1, 40 ], [ 1, 40 ],

Da , di , gi , na , dom , Da , di , gi , na , dom ]
0.2 , 0.2 , 0.2 , 0.2 , 0.2 , 0.2 , 0.2 , 0.2 , 0.2 , 0.2 ]
[ 1, 20 ], [ 1, 20 ], [ 1, 20 ], [ 1, 20 ], [ 1, 20 ], [ 1, 20 ], [ 1, 20 ], [ 1, 20 ], [ 1, 20 ], [ 1, 20 ] ]

Figure 5.42: The SuperCollider postWord output for Figure 5.41 (the mutated phrase is spread across
two lines).

Phrase Permutation
In order to create permutations of a phrase the method permutePhrase was written with an optional
parameter for permutation number, which will be random if not set. See Figures 5.43 and 5.44 for an
example.

42
3 3 3
         [Ta ,ka ,Ta ,ki ,tah ,Ta ,ka ,di ,mi ]
[0.333 ,0.333 ,0.333 ,0.333 ,0.333 ,0.333 ,0.333 ,0.333 ,0.333 ]
[[1,12],[1,12],[1,12],[1,12],[1,12],[1,12],[1,12],[1,12],[1,12]]
Ta ka Ta ki ṭa Ta ka di mi
3 3 3
         [ Ta ,ka ,di ,mi ,Ta ,ki ,tah ,Ta ,ka
[ 0.333,0.333 ,0.333,0.333 ,0.333 ,0.333 ,0.333 ,0.333 ,0.333 ]
]

[[1,12],[1,12],[1,12],[1,12],[1,12],[1,12],[1,12],[1,12],[1,12]]
Ta ka di mi Ta ki ṭa Ta ka

Figure 5.43: An example of phrase permutation. A


tiśra gati phrase consisting of Ta ka (2) + Ta ki
t.a (3) + Ta ka di mi (3) (top line) is permuted
into Ta ka di mi (4) + Ta ki t.a (3) + Ta ka (2) Figure 5.44: Output from calling postWord on each
(bottom line). of the KonaTime instances in Figure 5.43.

Phrase Mutation
To automate mutation of a phrase with multiple processes the mutatePhrase method was written,
which makes use of most of the previously mentioned automated mutation methods (randomAtDensity,
randomExtendJati, randomMuteJati, randomDensityJati, partitionWord). mutatePhrase loops
through the items in a phrase calling itself recursively for KonaTime instances and for KonaWords making
probabilistic decisions as to whether or not mutation should occur and in what form. Finally the phrase
is either returned or recursively mutated according to a probability, which if successful is halved for the
recursive call. See Figure 5.45 for examples.

Word Mutation
The more complex generation processes (5.3.2) generally require partitioning, permutation and mutation
to move from an phrase archetype to something more interesting. The methods partitionWord (which in-
cludes permutation) and mutatePhrase have been combined to achieve this in the randomPartitionMutate
method. An optional probability (defaults to 0.5) can be passed to determine whether partitioning and
permutation should take place, mutation is guaranteed (Figure 5.46 for examples).

5.4 Tāl.a Generator


A rudimentary tāl.a generator was built separately to the main system, which constructs a routine based
on a set of parameters for the tāl.a. The tāl.a generator could account for the seven elementary tāl.as
(sūl.ādi sapta tāl.as) as well as khand.a and miśra cāpu tāl.as. Each of the sūl.ādi sapta tāl.as is comprised
of a combination of kriyās; laghu– a clap followed by a variable number of finger counts (notated as In
or a vertical line followed by a number, where n is the total number of beats e.g. I4 is a clap followed by
three finger counts), drutam– a clap followed by a wave of the hand (notated as O or a full circle), and
anudrutam– a single clap (notated as U or a half circle) (Pesch and Sundaresan, 1996, p.15-16).
The tāl.a generator has a function for each of these tāl.as with parameters for the variables such as
laghu duration and gati, which generates the tāl.as technical name as well as a routine which sends
messages to Processing Homepage (2009) to display images of the relevant hand signals.

5.5 Critique of Design and Implementation


The specifications laid out (in Chapter 4) have been well met by the system; representation classes have
been built that can successfully represent the rhythmic aspects of Karn.āt.ak percussion playing, (albeit
with some with some small compromises, (see 5.2.1 and 5.2.2) and methods for generating rhythmic
phrases and cadences as well as methods to mutate them have been implemented. As well as the
automated methods that form the ‘Computational Modelling of Musical Style’ (Pearce et al., 2002) side

43
   
       
Ta ka Ta ka Ta ka Ta ka

[ Ta , ka , Ta , ka , Ta , ka , Ta , ka ]
[ 0.5 , 0.5 , 0.5 , 0.5 , 0.5 , 0.5 , 0.5 , 0.5 ]
[ [ 1, 8 ], [ 1, 8 ], [ 1, 8 ], [ 1, 8 ], [ 1, 8 ], [ 1, 8 ], [ 1, 8 ], [ 1, 8 ] ]

    
       
Ta Ta ka Ta Ta ka Ta ka di mi ta ka ju na

[ Ta ,- ,Ta ,ka , Ta ,Ta ,ka ,Ta ,ka ,di ,mi ,ta ,ka ,ju ,na ]
[ 0.5 ,0.5 ,0.25 ,0.25 , 0.5 ,0.5 ,0.5 ,0.125 ,0.125 ,0.125 ,0.125 ,0.125 ,0.125 ,0.125 ,0.125 ]
[[1,8],[1,8],[1,16],[1,16],[1,8],[1,8],[1,8],[1,32],[1,32],[1,32],[1,32],[1,32],[1,32],[1,32],[1,32]]

 
       
Ta ka Ta Ta Ta ka

[ Ta , ka , Ta , - , - , Ta , Ta , ka ]
[ 0.5 , 0.5 , 0.5 , 0.5 , 0.5 , 0.5 , 0.5 , 0.5 ]
[ [ 1, 8 ], [ 1, 8 ], [ 1, 8 ], [ 1, 8 ], [ 1, 8 ], [ 1, 8 ], [ 1, 8 ], [ 1, 8 ] ]

Figure 5.45: Examples of mutatePhrase in notation and postWord output. The first line is a ba-
sic sarvalaghu pattern (Nelson, 1991, vol.1 p.32), the second and third are variations created with
mutatePhrase.

of this project, most elements of the system can be used manually or with semi-automation, making it
useful to musicologists, Karn.āt.ak Teachers and musicians, and even-non Karn.āt.ak musicians.
The parameters for the representation classes as well as generation and mutation methods all use
values and terms that should be familiar to those versed in Karn.āt.ak music and at least be under-
standable to those who are not. While some of the design decisions, especially regarding the boundaries
KonaWord class might not suit all potential users, the areas in which there have been compromises make
no impingement on the representation of the rhythmic aspects of Karn.āt.ak music.
The system being divided into classes, eases the use or development of individual elements. While
some loose coupling of classes has been used to ease development, this is easily reversible.

44
  
 


Ta Ta ki ṭa ta ki ṭa Ta

[ Ta ] [ Ta , ki , tah , ta , ki , tah , Ta ]
[ 1.5 ] -> [ 0.125 , 0.125 , 0.125 , 0.125 , 0.125 , 0.125 , 0.75 ]
[ [ 3, 8 ] ] [ [ 1, 32 ], [ 1, 32 ], [ 1, 32 ], [ 1, 32 ], [ 1, 32 ], [ 1, 32 ], [ 3, 16 ] ]

  
    

    
Da di gi na dom Ta Ta ka di mi

[ Da , di , gi , na , dom ] [ Ta , Ta , ka , di , mi ]
[ 0.25 , 0.25 , 0.25 , 0.25 , 0.25 ] -> [ 0.75 , 0.125 , 0.125 , 0.125 , 0.125 ]
[ [1, 16], [1, 16], [1, 16], [1, 16], [1, 16] ] [ [3, 16], [1, 32], [1, 32], [1, 32], [1, 32] ]

Figure 5.46: Two examples of the randomPartitionMutate method in notation and postWord output.
Notice the equal handling of the two forms of KonaWord used in primitive generation; a single jati word
with high karve and a poly-jati word with single karve.

45
Chapter 6

Evaluation

Throughout this project the development of the system has benefited from an ongoing evaluation process;
Karn.āt.ak rhythm has been practised and studied via instructional materials (Vinayakram and McLaugh-
lin, 2007; Lockett, 2008; Vinayakram, 2007; Nelson, 2008; Prakash, 2009) and traditional mr.daṅgam
lessons under R. N. Prakash (see Section 6.2.3). As concepts became clearer through practise, their
counterpart computer implementations were been refined. The theoretical basis for these implemen-
tations was then discussed with Prakash, forming an iterative, agile development. The lessons were
typically with a group of musicians, with emphasis on interaction. The material included traditional
sarvalaghu patterns and mōrās, as well methods on adapting material for different tāl.as. Prakash also
shared the names of influential musicians to listen to, as well as the details of a concert in London fea-
turing the legendary mr.daṅgam maestro Guru Kaaraikkudi Mani, the equally acclaimed vocalist Shri T.
M. Krishna, violinist H. N. Bhaskar and kanjeera player N. Amrit. The concert was a rare opportunity
to witness highest level Karn.āt.ak music first hand.

6.1 Evaluation Method


As a means of evaluating the output of the system a discrimination test was set up in which participants
were asked to distinguish musical examples used as the basis for the system and examples from the system
itself. This method was largely inspired by one part of Pearce and Wiggins’s (2001) paper Towards a
Framework for the Evaluation of Machine Compositions. While similar to a Turing test (Turing (1950) in;
Pearce and Wiggins (2001)), Pearce and Wiggins make the distinction that while Turing test is designed
to test for machine-thinking via interaction, the form of test being used here “simply determines the
(non-)membership of a machine composition in a set of human composed pieces of music” (Pearce and
Wiggins, 2001).
As mentioned in the beginning of this dissertation (see Chapter 1) an abstraction was made from the
playing style of any particular instrument, with a focus on rhythmic content. This created a problem
during the evaluation; while the examples weren’t specified for a particular instrument, playback via
MIDI control of a sampled drums was vastly more pleasant to listen to and comprehend than time-
stretched playback of recorded konakkōl syllables. While the human examples could be replicated stroke
¯
for stroke, the computer examples contained no stroke information. While a stroke-management system
might have been a useful solution, it was not considered core to the project and so was not developed. A
possible solution would have been to use random, or semi-random strokes for both human and computer
examples, as it would would remove the advantage the human examples had of expert stroke choices. The
problem with such an approach is that it compromises the human examples with computer interference,
which would likely disturb expert listeners. To solve this problem the original strokes were used for
human examples and the strokes were set by hand for the computer examples, in the same way Harold
Cohen would hand colour drawings by early versions of AARON (Boden, 2004, p.314-315). It was made
clear at the beginning of the questionnaire that while examples may have been composed by either a
computer or human, all examples were performed by a computer.
The experts and lay listeners were both given the same set of examples, which were all generated
single run of their respective methods to avoid cherry-picking.

46
• 18 examples of basic, undeveloped vilamba sarvalaghu phrases, with computer examples generated
by vSarvaPhraseAuto using the same tāl.a, laya and gati settings as the human examples.
• 14 examples of developments of basic phrases. The purpose was to evaluate the ability to create
variations from a given phrase. The computer developments all resulted from using mutatePhrase
on the same original phrases used in the human examples of development.
• Four examples of longer developments. A basic phrase was played followed by a development
featuring two variations and a suffix. The computer examples used mutatePhrase and addSuffix
on the original human basic phrase.
• 16 examples of mōrās, including compound mōrās. The duration in mātras, the gati, karve and
laya of human mōrās were passed into randomMora and randomSamaCompoundMora to create the
computer examples.
• Three basic structures. These were short compositions composed entirely by the computer, all
following the same structure. A method basicStructure was written into KonaGenerator to
make it easier to produce multiple examples. The structure of the examples was as follows:
Cycle 1 Basic phrase, developments using mutatePhrase with a suffix.
Cycle 2 Developments generated using randomDensityJati on an already developed phrase from
Cycle 1.
Cycle 3 Half cycle of phrase developments followed by a half cycle mōrā.
Cycle 4 Phrase developments using mutatePhrase.
Cycles 5 and 6 A compound mōrā.
Cycles 7 to n-1 The whole composition again in a new gati.
Cycle n A short concluding mōrā to fill any remaining beats.

Some basic information was requested of participants; age, whether or not they were a musician,
details of musical training (if any) and exposure to/knowledge of Indian music and Karn.āt.ak music on a
scale from 1 (none) to 10 (expert). For each example listeners were asked to decide whether they thought
the example was written by a human or a computer, as well being asked for comments on any example
that felt particularly obvious either way. Additional comments were requested at the end of each set of
examples and at the end of the questionnaire, where participants were asked to rate how difficult they
found the discrimination of examples on a scale from 1 (very easy) to 10 (very difficult). The majority of
participants completed the test using an online questionnaire, a small number of evaluations were carried
out in person including the evaluation by R. N. Prakash (6.2.3).

6.2 Expert Listeners


6.2.1 Ludwig Pesch
Biography From Ludwig Pesch’s homepage Pesch (2009)
Ludwig Pesch taught music and performed with improvisation ensembles while studying music
and musicology at the Government Music College and University Freiburg (Germany). For
15 years, he was a pupil of the late Ramachandra Shastry, musical heir to the great traditions
of Tyagaraja and Sarabha Sastrigal.
A scholar under the Indo-German Cultural Exchange Programme and the German Academic
Exchange Service, he completed his Diploma Course (five years) in Carnatic Music (First
Class) at Kalakshetra. He is the co-founder of a major music documentation centre and
archive in Chennai, Sampradaya.
For many years, he performed alongside his guru. While receiving advanced training as
a Carnatic flautist in the Post-Diploma Course for two years at Kalakshetra, he also had
numerous opportunities to give solo-concerts of his own. Since then, he has performed all
over South India (Tamil Nadu, Kerala, Andhra Pradesh and Karnataka).

47
Pesch is also the author of The Oxford Illustrated Companion to South Indian Classical Music (Pesch,
1999), Eloquent Percussion (Pesch and Sundaresan, 1996) as well as a number of other books on Karn.āt.ak
music.
In the questionnaire, Pesch ranked his knowledge/exposure of both Indian and Karn.āt.ak music as
10/10 (expert) and gave as his musical background “Western music college and musicology; South Indian
(Carnatic) music diploma in Madras”.

Undeveloped Phrases Of the 18 undeveloped phrases, nine (50%) were correctly identified, of the
incorrectly identified examples four computer examples were thought to be human. Pesch provided
many constructive criticisms, of correctly identified computer generated example he said “Toy music
feel in spite of underlying complexities”, “Lack of sense of direction” and “Too plain, without apparent
direction”. Correctly identified human examples were noted for their “sense of anticipation engendered
here”, “building up [of] interest, differentiation” and for being a “grand statement (spacing and colouring)
as those loved by seniour drummers”. There were a number of positive comments on computer examples
misidentified as being human such as “Sense of deliberate friction to heighten interest” and “solicits
attention, as would be the case in a drum solo performance as it ‘takes off’.”
Of the examples as a whole Pesch said “Remarkable bits of music; some of the guesses pertain to
the computer’s ‘training’ or reference and assignment; and naturally from the brevity of samples (out of
context)”.

Phrase Developments Out of 14 examples of phrase development eight (57.14%) were correctly
identified, of which four computer examples were mistaken to be human. There were a number of
positive remarks attributed to computer examples (albeit always when mistaken to be human) including
“organic extension”, “pleasing” and “sense of fingering”.

Longer Developments Three of the four (75%) longer developments were correctly identified, with
the only mistaken example being a computer development thought to be human and described as “More
captivating than others”. Pesch commented that he found these examples hard to distinguish.

Mōrās Out of 16 examples 10 (62.5%) were correctly identified, of those misidentified four were com-
puter generated. The computer examples were correctly identified for being “too smooth”, having a
“contived feel” and being “mechanical” and “monotonous”. The only misidentified computer generated
example given a comment was said to have a “lack of beauty”, but was still considered human. Of the
set of examples Pesch noted that “The cerebral nature of drumming makes the lines blur”, a statement
backed up by his correct classification of a human example despite it noting it would be “technically
challenging”.

Basic Structures All but one of the three (66.66%) basic structures were correctly identified, with
one (correctly identified) computer example noted as being “less appealing than the others”.

Summary Pesch rated the difficulty of distinguishing examples a 9 out of 10, commenting that “In
the competitive world of Carnatic drumming, calculated patterns, often of great complexity and in need
of virtuosity, have come to stay.” This comment as well as the previous note that “The cerebral nature
of drumming makes the lines blur” (paragraph on Mōrās) seems indicative of an opinion that certain
aspects of Karn.āt.ak drumming are becoming more obviously calculable, while other aspects such as
sarvalaghu can still only be described in more abstract terms (Undeveloped Phrases paragraph).
The evaluation process as a whole was described as “Well done and challenging, with plenty of room
for doubt whether computers can conceive of the same differentiation in drumming as an ambitious
drummer’s mind, or even more. Musical context therefore matters most; greater complexity makes for
greater interchangeability between ‘man and machine’.”
For a summary of Ludwig’s results see Table 6.1.

48
6.2.2 David Nelson
Biography See also see 3.2.2.
From David Nelson’s homepage (Nelson, 2009):

David Nelson has been performing and teaching South Indian drumming since 1975. From
his principal teacher, the renowned T. Ranganathan, he learned to accompany a wide range
of styles, including Bharata Natyam, South India’s classical dance. He has a Ph.D. in Eth-
nomusicology from Wesleyan University, where he is Artist in Residence in South Indian
drumming. He has accompanied well-known artists throughout the United States, Europe,
India, and China. He has also written extensively on South Indian drumming, including a
major article in the Garland Encyclopaedia of World Music.
In the questionnaire, Nelson gave his knowledge of Indian music as 8/10, and knowledge of Karn.āt.ak
music as 10/10, musical training was given as “early training in classical and band (brass instruments,
piano), Karn.āt.ak music since 1970, voice and mr.daṅgam, several years of jazz drumset”.

Undeveloped Phrases For the undeveloped phrases Nelson correctly identified 13/18 (72.2%) exam-
ples, of the incorrectly identified examples four were computer examples labelled as human and one was
the opposite. Many examples were commented upon, the most frequent being that examples “could be
either”. For a number of the correctly identified computer examples comments regarding the mechanical
execution were given, demonstrating some difficulty in separation of composition from performance. The
comments for computer examples incorrectly identified as human included “it’s plausible, but could be
either”, “pattern human, strokes and execution mechanical” and “like something a player might do...”,
suggesting a lack of strong conviction for the given answer.
When commenting on the examples as a whole Nelson said “They’re too short and out of context
to be really convincing either way, even the ones that don’t necessarily sound like someone might play
them might be okay as part of something longer that on the whole is convincing.” This comment raises
an important issue regarding example durations that will be discussed in the critique of the evaluation
method (Section 6.5).

Phrase Developments For the phrase developments Nelson correctly identified 5/14 (35.7%) exam-
ples, of the nine incorrectly identified five were computer generated. Fewer comments were given than
for the undeveloped phrases; for the misidentified computer examples the comments “sounds pretty typ-
ically human”, “probably human, but not obvious” and “sounds believable” were given, a misidentified
human example was described as “shapeless, bland”. The comment given for this section as a whole was
“Mostly ambiguous, these could be either”.

Longer developments Nelson correctly identified all four longer developments. The two computer
examples garnered contrasting responses; “Not convicing, it sounds random” and “Somebody might do
this, but I’m sceptical”. Both human examples were given the same comment; “Not a style I know, but
somebody might play like this”, which raises the issue of performance and execution again as they are
both examples taken from the first few cycles of a tani āvartanam analysed in Nelson’s thesis (Nelson,
1991, vol.3 Trichy S. Sankaran p.162).

Mōrās Nelson correctly identified 9/16 (56.25%) mōrā examples, of the seven incorrectly identified
five were computer generated. There were many comments in regard to the execution, including a
human example described as “pretty obviously mechanical”, while a computer example was commented
as “execution sound human”. Two computer examples were subject to the extremely critical comment “I
hope it’s a computer, this one’s awful.” Additionally, one example was noted as being a pattern played
by Nelson himself.

Basic Structures All three basic structures were identified as being computer generated, with the
following comments “I don’t think anybody plays like this”, “The beginning doesn’t make musical sense
to me”, “Fingers, phrases, don’t make sense to me”, with the additional general comment “If a human
made these compositions, I really dislike the style”. These comments seem to be more focused on

49
musical style than capability, with the compositions compared to a musician with an unfavourable or
poorly formed style.

Summary In response to the evaluation as a whole Nelson said “None of this sounded like any playing
I recognize, whether computer or not.”. When it was noted that many of the human examples were taken
from transcriptions in his thesis, he replied that “The material itself may have come from my work, but
the strokes and execution were so unfamiliar as to be distracting. I guess I listen to those qualities as
much as to the ideas as such. A real musician would play ‘in a style’, meaning that there would be more
internal coherence.” Despite complaints about the effects of computer performance, human examples
were correctly identified 74.61% of the time on average, perhaps indicating that they were less influential
factors than Nelson believed. The area in which the most computer generated examples were incorrectly
identified (phrase development) was also the area in which the most human examples were incorrectly
identified. Considering the greater success of human identification in other areas of the test, it is likely
that this was a particularly difficult process to judge accurately. Nelson gave the overall difficulty of
identification a rating of 5/10. It should be noted that Nelson had the advantage of prior exposure to
many of the human examples (whether he was aware of it or not) as all ādi tāl.a caturaśra gati examples
were from the transcriptions of tani āvartanam on which his thesis was based. For a summary of David’s
results see Table 6.2.

6.2.3 Sri R. N. Prakash


Biography From the South Asian Arts website (South Asian Arts UK, 2009):
Sri R.N.Prakash is a disciple of Vidvan K.N.Krishnamurthy of Bangalore. His talents have
been promptly recongnised in India by his elevation to the prestigious grade ‘A’ artiste status
at a very young age by All India Radio.
Currently he is the resident Mr.daṅgam teacher at the London School of Carnatic Music
based at the London Sivan Kovil in Lewisham. He is a popular Mr.daṅgam and Ghatam
artiste in the UK as well as abroad. Practically every Carnatic concert in London relies
on his Ghatam accompaniment. Although his expertise is in Indian classical music, he is
versatile, adventurous and open minded. His fusion work with western pop and jazz groups,
especially with ‘Massive Attack’, illustrates his interest in building musical bridges to other
cultures.

Undeveloped Phrases Prakash correctly identified 9/18 undeveloped phrases, of which eight were
computer examples thought to be human. During this section Prakash expressed an interest in the
variety of performers the human examples were drawn from, noting after the evaluation that certain
musical settings were unusual for certain performers. For example, the fact that the miśra gati examples
were by Vikku Vinayakram was a surprise, as this is apparently a rare (and thus, unfamiliar) example
of his playing. As a result, there was an increased degree of openness to unfamiliar playing.

Phrase Developments Four of the 14 phrase developments were correctly identified, with six com-
puter examples being mistaken as human. During the discussion of the system that took place after the
evaluation, when discussing the generation of variations, Prakash said that it was fingerings that can be
‘wrong’ but not variations as long as they add up properly as “variation is just mathematics”.

Longer Developments All four longer developments were thought to be computer generated, despite
the two human examples.

Mōrās Of the 16 examples of mōrās six were correctly identified, of which five computer examples were
misidentified as human.

Basic Structures Of the three, all computer generated compositions, two were considered plausible
as human.

50
Summary In discussion of the evaluation process as a whole Prakash commented that “it can be hard
to recognise [examples as] human or computer as [they are] played on the computer... what makes Indian
music is a character, you can’t create the character.” As with Nelson (6.2.2) it seems that execution plays
too important a role to make the identification trivial. On the topic of computer performance Prakash
commented “for Karn.āt.ak music you need a lot of feel... [the computer’s lack of feel] is the reason that
computer music has not gotten into Indian or Karn.āt.ak music.” On a scale from 1-10 Prakash gave the
difficulty of identification a 6. For a summary of Prakash’s results see Table 6.3.

System Discussion Uniquely for a professional listener, the evaluation process was carried out in
person, allowing the various components of the system to be demonstrated and discussed. In discussion
of the applications of such a system Prakash was very positive; while convinced that computers can
not yet play a role in Karn.āt.ak performance, he saw great potential in the system for composition
and teaching. On the topic of teaching noted that students could be provided with a good reference
of a pattern or idea, as well as saving time spent construction permutations and combinations. The
automation of permutation and combination was also thought useful for composition, saying that “for
people who already have the knowledge of these rhythms, it can take [composition] to a different level”,
but also warning against treating it as a shortcut; that “you should have very good ears to appreciate the
[generated] rhythms”. It was also noted that the combination of very precise playback with phraseAtGati
had particularly useful applications when dealing with translating material to difficult gatis such as
khand.a (seven sub-divisions per beat) and sankı̄rn.a (nine sub-divisions per beat), or between gatis that
are very close in timing (e.g. six to seven).
Of the system as a whole Prakash said “I think it has been very good project, where computer music
can give a lot more phrases and gives a very strong rhythm sense. It gives an easy way to work out
permutations and combinations.”

6.3 Lay Listeners


In addition to the expert listeners the evaluation was carried out by 17 other participants, of which
15 rated their exposure to/knowledge of Karn.āt.ak music as below 5/10 (‘some’), with an average of
2.13/10. The two participants with exposure to/knowledge of Karn.āt.ak music higher than 5/10 gave
themselves 7/10 and 8/10 but scored no higher than the average lay participant. Of these participants,
11 were musicians with a variety of backgrounds, including “8 years trumpet, 6 years in a progressive
rock band, 1 in a metal band, Numerous years Jazz Big Band, Grade 5 Theory distinction, AS Level B
Music. Studying for a Masters in Digital Music & Sound Art 5 years mixing in a digital environment.”,
“Doctoral composer, jazz/pop/classical musician”, “Death metal drummer for 8 years” and “Self-taught.
No particular style”.
In the following discussion of results the answers always refer to the average identification.

Undeveloped Phrases Only three of the 18 examples of undeveloped phrases were misidentified,
with only one computer examples mistaken as human. Many participants commented that the computer
performance and lack of knowledge made the task very difficult, and that intuition was heavily relied
upon.

Phrase Developments Of the 14 phrase developments, only four were correctly identified. Of those
misidentified, five computer examples were thought to be human and were given comments such as “Form
seemed typical of human. Interesting Variation” and “Felt more creative”. One computer example was
regarded as human by 14/17 participants (as well as 2/3 experts), with the comments “Too groovy for a
computer, I felt very definite about this choice” and “Has human flare”. The correctly identified human
examples were often said to be too systematic and mechanical.
One participant (a non-musician with an 8/10 rating for exposure to Karnatak music) noted that
these types of variations should not be complicated, making programming of suitable methods reasonably
achievable and thus harder to distinguish results.

51
Correctly identified Incorrectly identified Correctly identified Incorrectly identified
human examples human examples computer examples computer examples
Undeveloped Phrases
5/9 55.56% 4/9 44.44% 4/9 44.44% 5/9 55.56%
Phrase Development
5/7 71.43% 2/7 28.57% 3/7 42.86% 4/7 57.14%
Long Developments
2/2 100% 0/2 0% 1/2 50% 1/2 50%
Mōrās
3/6 50% 3/6 50% 7/10 70% 3/10 30%
Basic Structures
0/0 n/a% 0/0 n/a% 2/3 66.6% 1/3 33.34%

Table 6.1: A summary of Ludwig Pesch’s evaluation

Correctly identified Incorrectly identified Correctly identified Incorrectly identified


human examples human examples computer examples computer examples
Undeveloped Phrases
8/9 88.89% 1/9 11.11% 8/9 88.89% 1/9 11.11%
Phrase Development
3/7 42.86% 4/7 57.14% 2/7 28.57% 5/7 71.43%
Long Developments
2/2 100% 0/2 0% 2/2 100% 0/2 0%
Mōrās
4/6 66.67% 2/6 33.33% 5/10 50% 5/10 50%
Basic Structures
0/0 n/a% 0/0 n/a% 3/3 100% 0/3 0%

Table 6.2: A summary of David Nelson’s evaluation

Correctly identified Incorrectly identified Correctly identified Incorrectly identified


human examples human examples computer examples computer examples
Undeveloped Phrases
8/9 88.89% 1/9 11.11% 1/9 11.11% 8/9 88.89%
Phrase Development
3/7 42.86% 4/7 57.14% 1/7 14.29% 6/7 85.71%
Long Developments
0/2 0% 2/2 100% 2/2 100% 0/2 0%
Mōrās
1/6 16.67% 5/6 83.33% 5/10 50% 5/10 50%
Basic Structures
0/0 n/a% 0/0 n/a% 1/3 33.34% 2/3 66.66%

Table 6.3: A summary of R. N. Prakash’s evaluation

52
Correctly identified Incorrectly identified Correctly identified Incorrectly identified
human examples human examples computer examples computer examples
Undeveloped Phrases
7/9 77.78% 2/9 22.22% 8/9 88.89% 1/9 11.11%
Phrase Development
3/7 42.86% 4/7 57.14% 1/7 14.29% 6/7 85.71%
Long Developments
1/2 50% 1/2 50% 1/2 50% 1/2 50%
Mōrās
4/6 66.67% 2/6 33.33% 6/10 60% 4/10 40%
Basic Structures
0/0 n/a% 0/0 n/a% 1/3 33.34% 2/3 66.66%

Table 6.4: A summary of the lay listener’s evaluations.

Longer Developments The longer developments had a fairly close balance of votes for both possi-
bilities, resulting in half of both the computer and human examples being misidentified. One Computer
example was thought to be “Too groovy and cheeky for a computer generation” as well as having “a
very human feel to the pattern”, while another was said to be “very obviously computer”.

Mōrās Six of the 16 mōrās were incorrectly identified, four of which were computer examples with
all but one being a close result. The inherent complexity of the mōrās was found by many to make
discrimination difficult.

Basic Structures Of the three basic structures only one was correctly identified as being computer
generated, and even then only by a 40/60 divide. The change of gati in the correctly identified computer
example was said to be too awkward and sparse to be human. The computer example most voted as
human was said to have “the true structure of human composition”.

Summary The average rating of difficulty of discrimination was 8.71 with the lowest being 7/10 and
five participants giving 10/10. The reasons for difficulty that cropped up numerous times were the
computer playback, lack of prior knowledge and the number of examples. For the summary results of
the lay listeners see Table 6.4.

6.4 Summary
Judging the overall success of the generational aspects of the system is difficult; the results of the experts
were varied and often contradictory (they all agreed on only 20/55 examples) and in the lay listener
evaluation many examples were identified with only a one or two vote difference. Subjectivity was
abundant with participants praising and harshly criticising both computer and human examples, as was
prejudice, with positive comments only given to examples thought to be human.

Strengths
Looking at the percentage of misidentified computer examples it is clear that the system performs best
at creating variations on material, as noted by Prakash (6.2.3) variations are a computationally inclined
area of Karn.āt.ak music. Of the 55 examples there were three computer examples (all short phrase
developments) that the experts and lay listeners mistook to be human, as well as two basic phrases and
one mōrā that the experts (but not the lay listeners) also mistaken.
Of the three experts only Prakash was able to have the system demonstrated in person to provide
feedback on the representations and compositional tools. Thoughtful of the potential applications of the
system he was very enthusiastic, citing a number of potential uses (see System Discussion in 6.2.3).

53
Weaknesses
The areas in which the system performed poorly were the longer developments and basic structures,
with worse than hoped for results in undeveloped phrase generation. A potential explanation for some
of these weaknesses is that while the system was based primarily on ādi tāl.a caturaśra gati examples, a
large proportion of the evaluation examples used different tāl.as and gatis.

6.5 Critique of Evaluation Method


A number of problems arose during the evaluation process which hindered the quality of feedback.

6.5.1 Computer Performance


The complaint from participants that appeared most frequently was the difficulty of discrimination due
to computer performance. The problem with performance strokes was discussed as part of the evaluation
process (Section 6.1), but in brief was that the system worked only with konakkōl syllables, without a
¯
stroke management system. The restriction to these syllables (Table 2.2) did not limit the capabilities
of this system, when discussed with Prakash he said that all rhythms could be represented by them,
and easily interpreted into strokes by a performer. A similar complaint was the rigidity of timing of the
performance, an issue that might have been lessened by the use of a MIDI humanise function.
If time had permitted an ideal solution to both problems would have been to adhere to the advice of
David Cope:
If one employs synthetic sounds and inflexible rhythms while replicating music, stylisti-
cally valid works may not be recognized. Proper timbral choices, use of live performers and
attention to performance practice are highly recommended. (Cope, 1993a, p.408)

Yet it is not difficult to imagine this process being criticised because of the performer’s contribution
to the material.

6.5.2 Example Duration and Context


Another common comment on the difficulty of discrimination was that many of the examples were short
and out of context. This was a real problem for many of the processes being evaluated; isolating the
individual processes while giving the participants enough material to listen to. For these short examples
they were often played twice in succession, and then repeated after a short break. Still this did not solve
the problem of context, a number of participants commented that they found it easier to discriminate
with the longer examples which had more of a sense of context.

6.5.3 Participant Uncertainty


Participants both expert and lay expressed uncertainty with a number of examples. One lay participant
commented that were there an “I don’t know” option or similar, they would have used it for a great deal
of examples. An alternative to this would have been a rating of confidence of decision for each choice,
although this would have been time consuming.

6.5.4 Pride and Prejudice: The problem with discrimination


For the purposes of evaluating Computational Modelling of Musical Styles the discrimination test (Pearce
and Wiggins, 2001) is, in theory, well suited. However, in practice there were a number of significant
issues.
There was a sense that participants felt that they, as opposed to the system, were being tested,
one musician participant commented “[the test] was very hard...[it] can hurt people’s pride”. This issue
is more significant for expert participants as decisions may be thought of as a test of their expertise;
about which any uncertainty might raise insecurities. The underlying reason for this issue seems to be
prejudices in regards to the ability of computer and the value of human creativity. Indeed the notion
that something of artistic value might be created by a computer is deemed impossible by some (Boden,

54
2004, p.321). There were a large number of comments for examples thought to be human that were
expressions of value, while examples thought to be generated by the computer were often met with
derogatory remarks. Instead it may have been wise to have concealed the involvement of a computer at
all, either asking for just qualitative feedback or pretending the computer examples were by a human
student.

55
Chapter 7

Conclusion

The system achieved the objective of representing Karn.āt.ak rhythms well as well as interesting results
from the discrimination test of the generative features. The representations and methods for manipulating
them were felt to be useful for a number of applications by a high level musician of the style. A number
of computer generated examples were of high enough quality to fool three experts and a majority of
lay listeners into believing they were of human origin, and a number of other mistaken examples were
positively commented upon.

7.1 Future Improvements


Representation The representation of the ‘words’ of Karn.āt.ak rhythm (Section 5.2) required a num-
ber of design choices that resulted in a compromise in quality of representation of some words; see
Section 5.2.2 and Figure 5.12 for the discussion of words such as Ta lan - gu and Da - di - gi na dom.
There were also well-known (Brown, 1965) difficulties in distinguishing words made by concatenation
from concatenated words (see 5.2.1). A future revision of this project could combine the KonaWord and
KonaTime classes into a single KonaPhrase class, which could have user specified syllables/strokes, their
durations and accents. This would provide a more flexible representation, able to account for the variety
found in solkat.t.u/konakkōl, but would require greater effort on the part of the user.
¯
As mentioned under Musicologists in the User Requirements (Section 4.1.2) the representations could
be mapped to an input device for faster transcription by musicologists. This could be developed further
by mapping stroke representations to an instrument equipped with sensors for automatic transcription
from a musician’s performance, as done by Kapur (2008, ch.5) with his Hindustani E-Tabla, E-Dolak
and E-Sitar.

Generation The generation and mutation methods in this version of the system only represent the tip
of the iceberg of Karn.āt.ak rhythm, and are only representative of the musicians and contexts studied.
There are countless other structures in Karn.āt.ak rhythm that time has not permitted consideration.
Drumming is also an essential feature of Karn.āt.ak dances such as the bharata nāt.ya (Pesch and Sun-
daresan, 1996, Glossary), which includes another set of traditions completely untouched in this project.

Selection Currently much of the selection process is random (e.g. partition choice), or weighted
random. Where non-weighted randomness is used, heuristics could be introduced (e.g. symmetry for
partition choice), and where weighted randomness is used the weights could be data-mined from musical
examples, as in the current version they have generally been set loosely and tweaked intuitionally.

Mutation There is much room for improvement of the automated mutation methods. While the results
of the processes may closely match those found in human examples, the automation of them has been
achieved by trial and error. A better solution would be to implement an analysis system that would use
input material to create statistical and contextual models of the use of the processes.
A particular mutation method that could be further developed is phraseAtGati. At the moment it
returns a brute conversion from one gati to another. In real situations a conversion such as this might

56
require some alteration to the output to make it fit with the tāl.a (e.g. a 16 pulse phrase in will fill four
beats in caturaśra gati, but only 3.2 in khand.a). Automation of this alteration process would make it
easy to try out compositions in different gatis and tāl.as, which may be especially useful to the Karn.āt.ak
percussion student who is not yet fully capable of calculating this transitions.

Playback The focus on rhythms as opposed to particular playing strokes means that when output
is with Karn.āt.ak instruments, an indication of whether a stroke is open (resonant) or closed (non-
resonant) is lacking. For the Karn.āt.ak musician this is not likely to be a problem, as solkat.t.u to stroke
interpretation is common (Brown, 1965, 135). For computer playback however this does pose a problem,
as was encountered with listener evaluation of the system (Chapter 6).
A future solution would be an interpreter module that would translate assign suitable strokes to the
KonaWord jatis.

Technical The ZS2 integer partitioning algorithm (Zoghbi and Stojmenović, 1998) implemented in
SCLang for generation rhythm generation (Section 5.3.1) can take considerable amounts of time for
larger numbers (partitioning 100 with a minimum part size of two and a maximum of nine averaged
54.92 seconds on an an Apple Dual 1.8GHz G5 with 4 GB of ram), which is reduced by reading from
arrays stored as files (the same partition averaged 5.73 seconds with this approach).
Implementation in a language such as C could decrease this time, Zoghbi and Stojmenović (1998)
reported their C implementation on a SUN machine (circa 1998) averaged 10.3 seconds for a partition
of 75 (Zoghbi and Stojmenović, 1998), the same procedure with the SCLang implementation took 8.37
seconds with a relatively contemporary machine.

7.2 Alternative Methodologies


The system used a completely symbolic, knowledge based approach which Papadopoulos and Wiggins
(1999) outline as having the following difficulties:

• – Knowledge elicitation is difficult and time consuming, especially in subjective domains such
as music.
– This has certainly been the case with this project, with large amounts of time spent modelling
a relatively small number of processes.
• – Since [knowledge based systems] do what we program them to do they depend on the ability of
the “expert”, who in many cases is not the same as the programmer, to clarify concepts, or
even find a flexible representation.
– For the purposes of this project the expert can be considered to be the analytical and instruc-
tional materials with the author as an intermediary. In the instance of original transcription
and analysis work. This creates a chain of dependence that includes the quality of the musi-
cian’s performance and teaching, the musicologist’s analysis and the author’s understanding.

• – [Knowledge based systems] become too complicated if we try to add all the “exceptions to the
rule” and their preconditions, something necessary in this domain.
– For the sake of accomplishing a variety of tasks at a reasonable level, not all exceptions have
been taken into account, limiting the output of the system.

Alternatives to this symbolic, knowledge based approach include using grammars, evolutionary mod-
els or machine learning techniques (Section 2.2.1). Bernard Bel’s success with grammars to model tabla
playing (Section 3.1.1), (Bel, 2006) indicates that this path is likely to be fruitful for generating Karn.āt.ak
rhythms. The mutational or ‘germinal’ (Brown, 1965) nature of Karn.āt.ak music makes an evolutionary
approach appealingly suitable. A machine learning approach has the advantage of eliminating the de-
pendence on the analyst(s) ability, with the system instead dealing with real Karn.āt.ak rhythms directly.

57
7.3 Contribution
As previously mentioned (Chapter 1) this project is the first to focus on computer representation and
generation of Karn.āt.ak rhythms. It is hoped that this preliminary work should serve as a useful starting
point for future work, as well as highlighting some of the areas of Karn.āt.ak rhythm in which computa-
tional processes would be most welcomed and beneficial. Hopefully this work will play a role in raising
the profile of Karn.āt.ak music in the field of computer music, the results of which may in turn feed back
into the Karn.āt.ak music community.

58
Bibliography

Abran, A., Moore, J. W., Bourque, P. and Dupuis, R., eds (2004), Guide to the Software Engineering
Body of Knowledge, IEEE Computer Society.
Ames, C. and Domino, M. (1992), Cybernetic composer: An overview, in M. Balaban, K. Ebcoglu and
O. Laske, eds, ‘Understanding Music with AI’, AAAI Press, pp. 186–205.
Avid (2008), ‘http://www.sibelius.com/’.
Ayyangar, R. R. (1972), History of South Indian (Carnatic) Music : From Vedic Times to the Present,
R. Rangaramanuja Ayyangar, Madras (Chennai).
BCS (2008a), ‘Code of Conduct’.
BCS (2008b), ‘Code of Good Practice’.
Bel, B. (1992a), “Modelling Improvisatory and Compositional Processes”, Languages of Design, For-
malisms for Word, Image and Sound , Vol. 1, pp. 11–26.
Bel, B. (1992b), Symbolic and Sonic Representations of Sound-Object Structures, in M. Balaban,
K. Ebcioglu and O. Laske, eds, ‘Understanding Music with AI : Perspectives on Music Cognition’,
MIT Press, pp. 64–109.
Bel, B. (1998), “Migrating Musical Concepts - An Overview of the Bol Processor”, Computer Musical
Journal , Vol. 22, pp. 56–64.
Bel, B. (2006), The Bol Processor Project: Musicological and Technical Issues, in ‘Virtual Gamelan
Graz: Rules - Grammars - Modelling Symposium’, Institute of Ethnomusicology, Graz, Austria.
Bel, B. (2009), ‘Bol Processor Homepage’.
URL: http://bolprocessor.sourceforge.net/
Bel, B. and Kippen, J. (1992), Bol Processor Grammars, in M. Balaban, K. Ebcioglu and O. Laske, eds,
‘Understanding Music with AI : Perspectives on Music Cognition’, MIT Press, pp. 366–400.
Biles, J. A. (1994), ‘GenJam: A Genetic Algorithm for Generating Jazz Solos’.
Biles, J., Anderson, P. G. and Loggi, L. W. (1996), Neural Network Fitness Functions for a Musical IGA,
Technical report, Rochester Institute of Technology.
Boden, M. A. (2004), The Creative Mind, second edn, Routledge, Abingdon.
Brown, R. (1965), The Mr.daṅga: A Study of Drumming in South India, PhD thesis, Department of
Music, University of California.
Carabott, A. (2009), Bernard Bel’s Bol Processor: An Authoritative and Critical Study. Submitted for
the Generative Creativity course, as part of the Music Informatics (BA) undergraduate degree at the
University of Sussex.
Carl, D., Julian, A., Charles, W., Richard, C. and Brian, H. (2008), ‘Harmony’.
Collins, N. (2008), ‘Perception of Rhythm Lecture Slides’.

59
Cope, D. (1991), Computers and Musical Style, Oxford University Press, Oxford.
Cope, D. (1993a), A Computer Model of Music Composition, in S. M. Schwanauer and D. A. Levitt,
eds, ‘Machine Models of Music’, MIT Press, Cambridge, Massachusetts.
Cope, D. (1993b), Panel Discussion, in ‘Proceedings of the International Computer Music Conference’.
Cope, D. (2005), Computer Models of Musical Creativity, The MIT Press. 1213294.
Ebcioglu, K. (1988), “An Expert System for Harmonizing Four-part Chorals”, Computer Musical Journal
, Vol. 12, pp. 43–51.
Hild, H., Feulner, J. and Menzel, D. (1992), “HARMONET: a neural net for harmonising chorales in the
style of J.S. Bach”, Advances in Neural Information Processing , Vol. 4, pp. 267–274.
Hulzen, R. v. (2002), Improvisation and its Guiding Principles in Percussion Playing in South Indian
Classical Music, PhD thesis.
Iyer, S. R. (2000), Sangeetha Akshara Hridaya (A New Approach to Tāl.a Calculations), Gaana Rasika
Mandali.
Kapur, A. (2008), Digitizing North Indian Music: Preservation and Extension using Multimodal Sen-
sorSystems, Machine Learning and Robotics, PhD thesis, University of Victoria.
Kippen, J. and Bel, B. (1989), “The Identification and Modelling of a Percussion ’Language’, and the
Emergence of Musical Concepts in a Machine-Learning Experimental Set-Up”, Computers and the
Humanities , Vol. 23, pp. 199–214.
Kippen, J. and Bel, B. (1992), Modelling Music With Grammars: Formal Language Representation
In The Bol Processor, in A. Marsden and A. Pople, eds, ‘Computer Representations and Models in
Music’, Academic Press, London, pp. 207–38.
Krishnaswamy, A. (2003a), Application of Pitch Tracking to South Indian Classical Music, in ‘IEEE
ICASSP’.
Krishnaswamy, A. (2003b), On the Twelve Basic Intervals in South Indian Classical Music, in ‘Audio
Engineering Society’.
Krishnaswamy, A. (2003c), Pitch Measurements Versus Perception of South Indian Classical Music, in
‘SMAC’.
Krishnaswamy, A. (2004a), Inflexions and Microtonality in South Indian Classical Music, in ‘FRSM’.
Krishnaswamy, A. (2004b), Melodic Atoms For Transcribing Carnatic Music, in ‘ISMIR’.
Krishnaswamy, A. (2004c), Multi-Dimensional Musical Atoms in South Indian Classical Music, in
‘ICMPC’.
Krishnaswamy, A. (2004d), Results in Music Cognition and Perception and Their Application to Indian
Classical Music, in ‘FRSM’.
Krishnaswamy, A. (2004e), Towards Modeling, Computer Analysis and Synthesis of Indian Ragams, in
‘FRSM’.
Lockett, P. (2008), Indian Rhythms For Drumset, Hudson Music.
London, J. (2004), Hearing in time: Psychological aspects of musical meter, Oxford University Press,
USA.
Magnusson, T. (2009), ‘Clapping SynthDef’, SC-Users Mailing List Contribution.
URL: http://www.cogs.susx.ac.uk/users/thm21/
Miller, G. (1956), “The magical number seven, plus or minus two”, Psychological review , Vol. 63,
pp. 81–97.

60
Miranda, E. (2001), Composing music with computers, Focal Press.
Mitchell, T. (1997), Machine Learning, McGraw Hill.
Nelson, D. (1991), Mr.daṅgam Mind: The Tani Āvartanam in Karn.āt.ak Music, PhD thesis.
Nelson, D. (2009), ‘David Nelson Homepage’.
URL: http://dpnelson.web.wesleyan.edu/index.html
Nelson, D. P. (2008), Solkattu Manual : An Introduction to the Rhythmic Language of South Indian
Music, Wesleyan University Press, Middletown, Connecticut.
Office of Public Sector Information (1988), ‘Copyright, Designs and Patents Act 1988’, Public Act.
Palnath, K. (2009), ‘Kadrigo Palnath Homepage’.
URL: http://www.kadrigopalnath.com/
Papadopoulos, G. and Wiggins, G. (1999), AI methods for algorithmic composition: a survey, a critical
view and future prospects, in ‘AISB Symposium on Musical Creativity’, pp. 110–117.
Pearce, M., Meredith, D. and Wiggins, G. (2002), “Motivations and methodologies for automation of
the compositional process”, Musicæ Scientiæ , Vol. 2, pp. 200–2.
Pearce, M. and Wiggins, G. (2001), ‘Towards a framework for the evaluation of machine compositions’.
22–32.
Pesch, L. (1999), The Illustrated Companion to South Indian Classical Music, Oxford University Press,
New Dehli, India.
Pesch, L. (2009), ‘Profile: Ludwig Pesch’.
URL: http://home.planet.nl/ pesch082/Ludwig/English/index.html
Pesch, L. and Sundaresan, T. (1996), Eloquent Percussion: A Guide to South Indian Rhythm, ekaóègrata,
Amsterdam.
Prakash, R. N. (2009), ‘South Indian Rhythm Fest’, DVD.
Prasanna (2003), ‘Ragamorphism’, DVD.
Processing Homepage (2009).
URL: http://www.processing.org/
Raynor, W. (2000), The International Dictionary of Artificial Intelligence, Lessons Professional Publish-
ing.
Roads, C. (1996), The Computer Music Tutorial, MIT Press.
Sankaran, T. (1977), The Art of Drumming: South Indian mrdangam, Private Edition, Toronto.
Shrinivas, U. (2007), ‘Samjanitha’, Audio CD.
South Asian Arts UK (2009), ‘Sri R. N. Prakash - Artist Profile’.
URL: http://www.saa-uk.org.uk/index.php?id=7914
Steedman, M. (1984), “A generative grammar for jazz chord sequences”, Music Perception , Vol. 2,
pp. 52–77.
Subramanian, M. (1999), “Synthesizing Carnatic Music with a Computer”, Sangeet Natak - Journal of
Sangeeet Natak Akademi , Vol. 133-134, pp. 16–24.
Subramanian, M. (2002), Analysis of Gamakams of Carnatic Music using the Computer, in ‘Sangeet
Natak - Journal of Sangeeet Natak Akademi’, Vol. 37, pp. 26–47.
Subramanian, M. (2008), ‘Carnatic Music Software - Rasika & Gaayaka’.
URL: http://carnatic2000.tripod.com/

61
SuperCollider Homepage (2009).
URL: http://supercollider.sourceforge.net/
Swar Systems (2009).
URL: http://www.swarsystems.com

Todd, P. M. (1989), “A Connectionist Approach to Algorithmic Composition”, Computer Musical Jour-


nal , Vol. 13, pp. 27–43.
Turing, A. (1950), “Computing machinery and intelligence”, Mind , Vol. 59, pp. 433–460.

Vinayakram, S. (2004), ‘Soukha’, CD.


Vinayakram, S. G. and McLaughlin, J. (2007), ‘The Gateway to Rhythm’.
Vinayakram, T. H. V. (2007), ‘The Language and Technique of South Indian Percussion’.
Viswanathan, T. and Allen, M. H. (2004), Music in South India, Global Music Series, Oxford University
Press, New York.
Zoghbi, A. and Stojmenović, I. (1998), “Fast algorithms for genegrating integer partitions”, International
Journal of Computer Mathematics , Vol. 70, Taylor & Francis, pp. 319–332.

62
Appendix A

Glossary

• Ādi Tāl.a: An eight beat tāl.a, the most predominant tāl.a in Karn.āt.ak music.
• Aks.ara: Individual beat or count (a component of tāl.a).
• Aṅga: “Limb”; a group of aks.aras, component of the tāl.a.
• Arudi: A rhythmic cadence or ending phrase.
• Bān.ı̄: A musical style or family tradition.
• Bhajan: Devotional Song.
• Caturaśra: A member of the five families of rhythm; four or “Four-sided”.
• Druta Kāla: The third degree of speed. Sometimes used to refer to the third section of the tani
āvartanam.
• Gamakas: Ornamentation.
• Gati: The beat subdivision, ‘gait’.
• Ghatam: Clay pot percussion instrument. The main supporting percussion instrument of Karn.āt.ak
music.
• Jati: A solkat.t.u/konakkōl syllable.
¯
• Jāti: “Variety”; (a) social grouping based on birth, (b) the five important numerical varieties of
Karn.āt.ak rhythm.
• Jāval.i: A genre of dance music.
• Kaccēri: The Karn.āt.ak concert.
• Kanjira: Small lizardskin frame drum with metal jingles attached to a wooden shell.
• Karn.āt.ak (often Carnatic) Music: The classical music system of South India.
• Khand.a: A member of the five families of rhythm; five or “broken”.
• Kriti: Three part compositional, central to the Karn.āt.ak concert.
• Kan.akku: Calculation. Tension creating rhythmic figures, contrasts Sarvalaghu.
• Konakkōl: Solkat.t.u performed in a concert setting.
¯
• Kōrvai: A complex rhythmic design, ending with a mōrā.
• Koraippu: A section of the tani āvartanam for two or more percussionists in which progressively
shorter groups of phrases are traded between musicians.

63
• Madhyama Kāla: Second degree of speed. Sometimes used to as the name of the middle section of
the tani āvartanam.
• Mr.daṅgam: A two headed drum, the primary percussion instrument in Karn.āt.ak music.

• Miśra: A member of the five families of rhythm; Seven or “Mixed”.


• Mōrā: A rhythmic ending or cadential figure.
• Morsing: Jaw harp idiophone.
• Padam: A dance music genre.

• Periya Mōrā: The penultimate mōrā composition in a tani āvartanam.


• Rāga: A recognizable and unique melodic entity.
• Sankı̄rn.a: A member of the five families of rhythm; nine or “All mixed up”.

• Sarvalaghu: Rhythm patterns that carry the flow of musical time.


• Solkat.t.u: The South Indian system of spoken syllables and tāl.a hand gestures.
• Svara: A musical note with pitch.
• Svara Kalpana: Improvised singing or playing of svaras.

• Ta Din Gi Na Tom: A concluding section within a piece.


• Tāl.a: The cyclical meter in Karn.āt.ak music.
• Tāna Varn.am: Musical form which gives a summary of rāga features.

• Tani Āvartanam: The percussion solo in a Karn.āt.ak music concert.


• Thatthakaras: Jatis grouped into a word.
• Tillāna: A dance music genre,.
• Tı̄rmānam: A set composition for classical dance accompanied by solkat.t.u.

• Tiśra: A member of the five families of rhythm; three or “Three-sided”.


• Vilamba Kāla: The first degree of speed. Sometimes used as the name of the first section of the
tani āvartanam.

(Ayyangar, 1972; Nelson, 2008; Pesch and Sundaresan, 1996; Pesch, 1999; Viswanathan and Allen,
2004; Iyer, 2000).

64
Appendix B

System Diagram

A class diagram for the system can be found on the next page.

65
KonaTani
-allTalas : Array
-laya : Integer
-tala : Array
-talaSym : Array
-gati : Integer
-otherGatis : Array
-gen : KonaGenerator
-store : KonaTime
-s : Server
-konaSynth : Symbol
-clock : TempoClock
-fftBuffArray : Array
-fftRout : Routine
-fftBuff : Buffer
-syls : Array
-buffers : Array
-talaRout : Routine
-pRout : Routine
-mOut : MIDIOut
+new(argLaya : Integer = 60, argTala : Array = #["I4","O","O"], argGati : Integer = 4, argOtherGatis : Array = #[3], argSynth : Symbol = konaHit) : KonaTani
+rand(argLaya : Integer, argTala : Array, argGati : Integer, argOtherGatis : Array, argSynth : Symbol = konaHit) : KonaTani
+initClass()
+konaTaniInit(argLaya : Integer, argTala : Array, argGati : Integer, argOtherGatis : Array, argSynth : Symbol) : KonaTani
+setTala(aTala : Array) : Array
+setPlayback()
+setSynthDefs()
+play()
+stop()
+makeTalaRout()
+rout()
+add(aKonaItem : KonaWord or KonaTime)
+addAll(argCollection : Collection)
+clear()
+gati_(aGati : Integer)

KonaTime
<<use>>
-tani : KonaTani
-tala : Array
-talaSum : Integer KonaWord
-rout : Routine -words : Array
-tani : KonaTani
+new(parameter : KonaTani) : KonaTime
-word : Array
+newFrom(aCol : Collection, aTani : KonaTani) : KonaTime
-jatis : Integer
+fill(size : int, function : function, argTani : KonaTani) : KonaTime
-gati : Integer
+konaTimeInit(argTani : KonaTani)
-karve : Float
+add(argItem : KonaWord or KonaTime)
-matras : Float
+addAll(argCollection : Collection)
-speed : Float
+dur() : Float
-dur : Float
+allDurs() : Array
-val : Array
+jatis() : Integer
-rout : Routine
+matras() : Float
-konaSynth : Symbol
+karve() : Float
-accent : Integer
+numTalas() : float
+rout() : Routine +initClass()
+play() +new(argSyls : Integer, argGati : Integer, argKarve : Float = 1, argTani : KonaTani, argSynth : Symbol) : KonaWord
+plusplus() : KonaTime +konaWordInit(argSyls : Integer, argGati : int, argKarve : Float, argTani : KonaTani, argSynth : Symbol) : KonaWord
+word() : Array +setRoutine(argW : Boolean = true, argD : Boolean = true, argF : Boolean = true) : Array
+postWord() : Array +play()
+accentFirst() +postWord()
+speed() : Float +accentFirst()
+gati() : Integer +plusplus(aKonaItem : KonaWord || KonaTime)
+greatestJatis() : Integer
+reverse() : KonaTime

KonaGenerator
-tani : KonaTani
-laya : Integer
-gati : Integer
-gatiPowers : Array
-tala : Array
-pMax : Integer
+new(argTani : KonaTani, argLaya : Integer, argTala : Array, argGati : Integer = 4) : KonaGenerator
+konaGeneratorInit(argTani : KonaTani, argLaya : Integer, argTala : Array, argGati : Integer) : KonaGenerator
+setGatiPowers(aGati : Integer) : Array
+allPartitions(aNum : Integer, aMin : Integer, aMax : Integer, aUParts : Integer) : Array
+randomPartition(duration : Integer, min : Integer, aMax : Integer, notSize : Boolean, seed : Integer) : Array
+allPerms(aCollection : Array) : Array
+randomPerm(partition : Array, seed : Integer) : Array
+removeGreaterThan(aCollection : Array, val : Integer, weight : Float = 0.97) : Array
+removeThoseContaining(aCollection : Array, valCol : Array, weightCol : Array) : Array
+partsToWords(aPartitionArray : Array, aKarve : Float, aOne : Boolean, aMult : Boolean) : KonaTime
+vSarvaPhraseLength() : Integer
+vSarvaPhraseAuto() : Integer
+vSarvaPhrase(phraseDur : Integer, aMin : Integer = 2) : KonaTime
+mutatePhrase(aKonaItem : KonaWord or KonaTime, aChance : Float, aRec : Float = 0.75, aNum : Integer) : KonaTime
+vSarvaStat() : KonaTime
+createSimpleMora(statement : KonaWord or KonaTime, gap : KonaWord or KonaTime, offset : KonaWord or KonaTime) : KonaTime
+moraStatement(aStateMatras : Integer, aGati : Integer, aKarve : Float) : KonaTime
+moraGap(aGapMatras : Integer, aGati : Integer, aKarve : Float) : KonaTime
+moraOffset(aOffsetMatras : Integer, aGati : Integer, aKarve : Float) : KonaTime
+randomMoraValues(aMatras : Integer, aGati : Integer, aKarve : Float, aGap : Boolean, aOffset : Boolean) : KonaTime
+randomMora(aMatras : Integer, aGati : Integer, aKarve : Float, aGap : Boolean, aOffset : Boolean) : KonaTime
+moraFrom(aStatement : KonaWord or KonaTime, aMoraMatras : Integer, aGap : Boolean, aOffset : Boolean) : KonaTime
+randomSamaCompoundMora(aMatras : Integer, aGati : Integer, aKarve : Float) : KonaTime
+basicStructure() : KonaTime
+wordAtGati(argWord : KonaWord, argGati : Integer, argKarve : Float) : KonaWord
+phraseAtGati(argObj : KonaWord or KonaTime, argGati : Integer, argGatiExp : Float) : KonaTime
+combine(aCollection : KonaTime) : KonaTime
+combineSimilar(aCol : KonaTime, alMax : Integer, avMax : Integer, aProb : Float = 1) : KonaTime
+atDensity(aKonaItem : KonaWord or KonaTime, density : Float) : KonaTime
+randomAtDensity(aKonaItem : KonaWord or KonaTime) : KonaTime
+extendJati(aKonaWord : KonaWord) : KonaTime
+randomExtendJati(aKonaItem : KonaWord or KonaTime) : KonaTime
+muteJati(aKonaWord : KonaWord, aIndex : Integer) : KonaTime
+randomMuteJati(aKonaItem : KonaWord or KonaTime) : KonaTime
+densityJati(aKonaWord : KonaWord, aIndex : Integer, aDensity : Float) : KonaTime
+randomDensityJati(aKonaItem : KonaWord or KonaTime, aRec : Float = 0.5) : KonaTime
+permutePhrase(aKonaTime : KonaTime, permutation : Integer, Seed : Integer) : KonaTime
+partitionWord(aKonaWord : KonaWord, min : Integer = 2, aMax : Integer, seed : Integer) : KonaTime
+randomPartitionMutate(aKonaWord : KonaWord, aChance : Float = 0.5, seed : Integer) : KonaTime
+addSuffix(aPhrase : KonaWord or KonaTime) : KonaTime
+fillOut(aKonaItem : KonaWord or KonaTime, aOnlyUneven : Boolean = false) : KonaTime
+makePostMora(aKonaItem : KonaWord or KonaTime) : KonaTime

66
Appendix C

Transcriptions

As part of this project a number of transcriptions of Karn.āt.ak percussionists were made. A variety of
examples follow.

q = 84 Khanda Capu T. H. Vikku Vinayakram


Solkattu

                                        

Taka dim Taka dim na ki ta tha ka din na Ta Taki ta Ta Ka Din na ki ta tha ka Din na Ta ka di mi Ta ka di mi Ta ka
6 Ghatam

      


di mi Ta ka di mi Ta ka
10

      

Figure C.1: From Vinayakram (2007, Disc.2 ch.)

Adi Tala Miśra Gati T. H. Vikku Vinayakram


q = 80

                              
7 7 7 7 7 7 7 7
Solkattu

Ta din ta g Ta din ta Ta g ta din ta g Ta din ta g Ta din ta ta g ta din ta


2
7 7 7 7 7 7 7 7
Ghatam                          

Figure C.2: From Vinayakram (2007, Disc.1 ch.6)

67
Adi Tala Caturaśra Gati
q = 80

 
Clap Wave Clap Wave Clap lf rf mf

Tāla        
3:5
5:4 5:4 5:4

Selvaganesh     
 

 

 
Da di gi na dom Da di gi na dom Da di gi na dom

Uma Shankar    

  
 
     
Groove
   
Taka ki ta ka Dom Dom mi TaKa Dom mi Ta ka di mi


Clap Wave Clap Wave Clap lf rf mf

Tāla         

Selvaganesh  
5:4 5:4

Uma Shankar       


Da di gi na dom Da di gi na dom


       
Groove
   
Ta ka ki ta ka Dom Dom mi Ta Ka Dom mi Ta ka di mi

 
Clap Wave Clap Wave Clap lf rf mf

Tāla       

Selvaganesh                      


TakadimiTakadimitakaTakadimiTakadimitakaTakadimitakaTakadimitakaTa TakadimitakaTa

Uma Shankar  


             
Groove
 
Taka kitakaDom Dom mi Ta Ka Dom mi Ta ka dimi

Figure C.3: From Vinayakram (2007, Disc.1 ch.5)

68
Adi Tala Tisra Gati T. H. Vikku Vinayakram
q. = 120
Solkattu Ghatam
Ghatam  
                       
Tam ta ka Ki tha ta ka din ta din na

Ghatam     

Ghatam                                    

10

Ghatam                                   

  
13

Ghatam                                   

17

Ghatam                                       

20

Ghatam                                      

22 4 4 4

Ghatam             

4
24 4 3

Ghatam                                           

26

Ghatam            
            

   
28

Ghatam              

Figure C.4: From Vinayakram (2007, Disc.1 ch.6)

69
Appendix D

Source Code

The source code begins on the next page.

70
1 /* ========================================================================= */ 60 val = [jatis, dur, word];
2 /* = KonaWord Class - Represents a a single Konakkol word made up of jatis = */ 61 accent = 0;
3 /* ========================================================================= */ 62
4 63 if(tani!=nil) {
5 KonaWord { 64 konaSynth = tani.konaSynth
6 classvar words; //Lookup table for syllables to use 65 } {
7 66 if(argSynth!=nil) {
8 var <tani; //The Tani that this word belongs to 67 konaSynth = argSynth
9 var <word; //The word the instance represents, an Array of symbols 68 } {
10 var <jatis; //The number of syllables in the word 69 konaSynth = \beep
11 var <gati; //The subdivision of the beat. 70 };
12 var <karve; //The number of matras each jati should occupy. 71 };
13 var <matras; //The number of pulses/sub-divisions in the word; 72
14 var <speed; //The duration wait between syllables 73 this.setRoutine;
15 var <dur; //The duration of the word (the jatis * karve) 74 }
16 var <val; //Jatis, dur and word in an array for comparison 75
17 var <rout; //The routine for playing this phrase 76 //Method to set the routine for this word. Stored in a function for re-use
18 var konaSynth; //Symbol of the SynthDef to use 77 setRoutine {
19 var <accent; //Additional accent on the first syllable 78 var ind;
20 79 var rate;
21 *initClass { 80 var amp;
22 //Set up lookup table for syllables 81
23 words = Array.newClear(10); 82 //MIDI variables
24 words[0] = ['-']; 83 var bOne; //MIDI note for first beat (always an open sound)
25 words[1] = ['Ta']; 84 var bOthers; //Chosen MIDI notes for other beats;
26 words[2] = ['Ta', 'Ka']; 85 var othersComplete; //Possible MIDI notes for other beats
27 words[3] = ['Ta', 'Ki', 'Tah']; 86 var othersTemp; //Storage for next 'other beat' MIDI note.
28 words[4] = ['Ta', 'Ka', 'Di', 'Mi']; 87 var note; //Chosen MIDI pitch.
29 words[5] = ['Da', 'Di', 'Gi', 'Na', 'Dom']; 88 var val; //Temporary storage of chosen MIDI note.
30 words[6] = ['Ta', 'Ki', 'Tah', 'Ta', 'Ki', 'Tah']; 89 var vel; //Chosen velocity for MIDI note.
31 words[7] = ['Ta', 'Ka', 'Di', 'Mi', 'Ta', 'Ki', 'Tah']; 90
71

32 words[8] = ['Ta', 'Ka', 'Di', 'Mi', 'Ta', 'Ka', 'Ju', 'Na']; 91 switch (konaSynth)
33 words[9] = ['Da', 'Di', 'Gi', 'Na', 'Dom', 'Ta', 'Ka', 'Di', 'Mi']; 92 {nil} {
34 93 rout = Routine {
35 } 94 word.size.do {|i|
36 95 amp = 0.2;
37 *new {|argSyls, argGati, argKarve=1, argTani, argSynth| 96 case
38 97 {word[i]=='-'} {amp=0}
39 //Check arguments aren't nil 98 {i==0} {amp=0.4};
40 if( (argSyls==nil) || (argGati == nil), 99
41 {^"arguments not set\n Provide (numSyllables, gati)"} 100 tani.s.bind{Synth(konaSynth, [\amp,
42 ); (amp+(accent/10)).min(1)])};
43 101 word[i].postln;
44 //Check specified group is within bounds, the gati is legit 102 speed.wait;
45 if( argSyls<=9 && ([4,3,5,7,9].includes(argGati)), 103 };
46 {^super.new.konaWordInit(argSyls, argGati, argKarve, argTani, 104 yieldAndReset(nil);
argSynth) }, 105 };
47 {^"Bad Size or Gati"} 106 }
48 ); 107
49 } 108 {\konaHit} {
50 109 rout = Routine {
51 konaWordInit { |argSyls, argGati, argKarve, argTani, argSynth| 110 word.size.do { |i|
52 tani = argTani; 111 //Index of the syllable to be played
53 word = words[argSyls]; 112 ind = tani.syls.indexOf(word[i]);
54 jatis = word.size; 113 if(i==0) {(amp=0.8+(accent/10)).min(1)} {amp=0.6};
55 gati = argGati; 114 if(word[i]!='-') {
56 karve = argKarve; 115 tani.s.bind {
57 matras = jatis*karve; 116 Synth(\konaHit, [\out, 0, \bufnum, tani.fftBuff,
58 speed = ((1/gati)*karve); \recBuf, tani.buffers[ind], \rate, ((tani.laya/60)*(0.25/speed)).max(1);]);
59 dur = speed * jatis; 117 };
118 tani.fftRout.next; 177 };
119 if(i==0) { 178 rout = Routine {
120 word[i].post; 179 word.size.do { |i|
121 } { 180 if(word[i]!='-') {
122 word[i].asString.toLower.post; 181 if(i==0) {
123 }; 182 note = bOne;
124 " ".post; 183 vel = (100+accent).min(127);
125 speed.post; " ".post; 184 word[i].post; " ".post;
126 speed.wait; 185
127 186 } {
128 } { 187 note = bOthers[i-1];
129 word[i].post; " ".post; 188 vel = (70..100).choose;
130 speed.post; " ".post; 189 word[i].asString.toLower.post; " ".post;
131 speed.wait 190
132 }; 191 };
133 }; 192 tani.mOut.noteOn(0, note, vel);
134 "".postln; 193 speed.post; " ".post;
135 yieldAndReset(nil); 194 speed.wait;
136 }; 195 tani.mOut.noteOff(0, note, vel);
137 196 } {
138 } 197 word[i].post; " ".post;
139 {\MIDITranscribe} { 198 speed.post; " ".post;
140 rout = Routine { 199 speed.wait
141 word.size.do { |i| 200 };
142 if(word[i]!='-') { 201 };
143 if(i==0) 202 " ".postln;
144 {note = 48; vel = 203 yieldAndReset(nil);
((70..100).choose+accent).min(127)} 204 };
145 {note = 52; vel = (100+accent).min(127)}; 205
146 tani.mOut.noteOn(0, note, vel); 206
147 if(i==0) { 207 };
72

148 word[i].post; 208


149 } { 209 }
150 word[i].asString.toLower.post; 210
151 }; 211 play {
152 " ".post; 212 this.rout.play(tani.clock);
153 speed.post; " ".post; 213 }
154 speed.wait; 214
155 tani.mOut.noteOff(0, note, vel); 215 //Concatonation method to return a new KonaTime with both KonaItems
156 } { 216 ++ { |aKonaItem|
157 word[i].post; " ".post; 217 var newTime = KonaTime.new();
158 speed.post; " ".post; 218 newTime.add(this).addAll(aKonaItem);
159 speed.wait 219 ^newTime
160 }; 220 }
161 }; 221
162 yieldAndReset(nil); 222 //Printing method for timing information of the word.
163 }; 223 postWord {|argW=true, argD=true, argF=true|
164 } 224 var words, decimals, fractions;
165 225 var maxItemLength;
166 //Automated mapping of strokes for Kanjira virtual instrument 226
167 {\MIDIPlay} { 227 words = Array.newClear(jatis);
168 bOne = [36, 37, 38, 39, 45, 46, 47].choose; 228 decimals = Array.newClear(jatis);
169 othersComplete = (48..55); 229 fractions = Array.newClear(jatis);
170 othersTemp = Array.newFrom(othersComplete); 230
171 bOthers = Array.newClear(word.size-1); 231 jatis.do { |i|
172 (word.size-1).do { |i| 232 words[i] = word[i].asString;
173 val = othersTemp.choose; 233 decimals[i] = speed.asString[0..4];
174 bOthers[i] = val; 234 fractions[i] = (speed/4).asFraction(100,false).asString;
175 othersTemp = Array.newFrom(othersComplete); 235 };
176 othersTemp.remove(val); 236
237 maxItemLength = [words.maxItem, decimals.maxItem,
fractions.maxItem].maxItem.size;
238
239 jatis.do { |i|
240 var numSpaces;
241 numSpaces = maxItemLength - words[i].size;
242 numSpaces.do {
243 words[i] = words[i] ++ " ";
244 };
245 numSpaces = maxItemLength - decimals[i].size;
246 numSpaces.do {
247 decimals[i] = decimals[i] ++ " ";
248 };
249 numSpaces = maxItemLength - fractions[i].size;
250 numSpaces.do {
251 fractions[i] = fractions[i] ++ " ";
252 };
253 };
254
255 if(argW) {
256 words.postln;
257 };
258 if(argD) {
259 decimals.postln;
260 };
261 if(argF) {
262 fractions.postln;
263 };
264
265 ^[words, decimals, fractions];
266
73

267 }
268
269 //For adding additional accents to the first syllable
270 accentFirst {
271 accent = accent + 10;
272 }
273
274 }
275
1 /* ======================================================================= */ 61 if(argItem==this) {
2 /* = KonaTime Class - Collection class that represents phrases of music = */ 62 super.add(KonaTime.newFrom(argItem, argItem.tani))
3 /* ======================================================================= */ 63 } {
4 64 super.add(argItem);
5 KonaTime : List { 65 };
6 66 };
7 var <tani; // The tani this belongs to 67 //Accent the first item in the phrase
8 var <tala; // The tala of the tani 68 if(this.size==1) {
9 var <talaSum; // The sum of the tala beats 69 this.accentFirst;
10 var dur; // The duration of this instance 70 gati = this[0].gati;
11 var jatis; // The total number of Jatis in this instance 71 };
12 var matras; // The total number of matras in this instance 72 }
13 var numTalas; // The number of talas this instance represents 73
14 var rout; // The playback routine 74 //Add a collection
15 var gati; // The gati of the first object. In most cases 75 addAll { |argCollection|
16 // the gati will be the same for all objects, 76 super.addAll(argCollection);
17 // but for experimental work this might be mixed. 77 }
18 78
19 *new {|argTani| 79 //Duration getter method
20 ^super.new.konaTimeInit(argTani); 80 dur {
21 } 81 var ret = 0;
22 82 this.do { |item, i|
23 //Create a new instance from a given collection of KonaItems 83 ret = ret + item.dur;
24 *newFrom{|aCol, aTani| 84 };
25 var tani; 85 ^ret;
26 var ret; 86 }
27 87
28 tani = aTani; 88 //Duration getter method for all contained objects
29 ret = this.new(tani); 89 allDurs {
30 90 allDurs = Array.newClear(this.size);
31 aCol.size.do { |i| 91
74

32 ret.add(aCol[i]) 92 this.do{ |item, i|


33 }; 93 if(item.class==KonaWord) {
34 94 allDurs[i] = Array.fill(item.jatis, item.speed);
35 ^ret 95 } {
36 } 96 allDurs[i] = item.allDurs
37 97 };
38 *fill{ |size, function, argTani| 98 }
39 var newCollection = KonaTime.new(argTani); 99
40 size.do { |i| 100 ^allDurs;
41 newCollection.add(function.()) 101 }
42 }; 102
43 ^newCollection; 103 //Jatis getter method
44 } 104 jatis {
45 105 jatis = 0;
46 konaTimeInit {|argTani| 106 this.size.do { |i|
47 tani = argTani; 107 jatis = jatis + this[i].jatis;
48 if(tani!=nil, 108 };
49 { 109 ^jatis
50 tala = tani.tala; 110 }
51 talaSum = tala.sum; 111
52 } 112 //Matras getter method
53 ); 113 matras {
54 114 matras = 0;
55 } 115 this.size.do { |i|
56 116 matras = matras + this[i].matras;
57 //Add an item 117 };
58 add {|argItem| 118 ^matras;
59 //Ensure against non-KonaItems 119 }
60 if(argItem.class==KonaWord || (argItem.class==KonaTime)) { 120
121 //Karve getter method, returns the mode karve of the instance. 181 fractions.postln;
122 karve { 182 };
123 var karves = this.collect({|item, i| item.karve}); 183 "".postln;
124 184 ^[words, decimals, fractions];
125 ^karves.maxItem({|item, i| karves.occurrencesOf(item)}) 185 }
126 } 186
127 187 //Method to accent the first syllable of the first item in the KonaWord
128 //Returns the number of cycles this instance occupies 188 //Works recursively on KonaTimes
129 numTalas { 189 accentFirst {
130 numTalas = 0; 190 if(this[0]!=nil) {
131 ^numTalas = this.dur/this.talaSum; 191 this[0].accentFirst;
132 } 192 };
133 193 }
134 //The playback routine for this instance 194
135 rout { 195 //Method to return the maximum speed in this KonaTime, works recursively
136 rout = Routine.new({}); 196 // on KonaTimes.
137 this.do { |item, i| 197 speed {
138 rout = rout++item.rout 198 var ret = this[0].speed;
139 }; 199 this.do { |item, i|
140 ^rout; 200 if(item.speed < ret) {
141 } 201 ret = item.speed;
142 202 };
143 //Play the instance routine to the parent KonaTani's clock. 203 };
144 play { 204 ^ret;
145 this.rout.play(tani.clock); 205 }
146 } 206
147 207 //Getter method, returns the gati of the first object.
148 208 gati {
149 //Concatonation method for combining KonaItems 209 ^this[0].gati
150 ++ { |aKonaItem| 210 }
151 var newTime = KonaTime.new(tani); 211
75

152 newTime.addAll(this).addAll(aKonaItem); 212 //Method to return the largest word in number of jatis (works recursively
153 ^newTime 213 // for KonaTimes)
154 } 214 greatestJatis {
155 215 var ret = 0;
156 //Getter method for the word of all of the contained objects 216 var val;
157 word { 217 this.do { |item, i|
158 word = List[]; 218 if(item.class==KonaWord) {
159 this.do({|item, i| word.add(item.word)}); 219 val = item.jatis;
160 ^word.asArray; 220 } {
161 } 221 val = item.greatestJatis;
162 222 };
163 //Method for printing the word and timing of all contained objects 223
164 postWord {|argW=true, argD=true, argF=true| 224 if(val>ret) {ret = val};
165 var words, decimals, fractions; 225 };
166 var get; 226
167 this.do {|item, i| 227 ^ret;
168 get = item.postWord(false, false, false); 228 }
169 words = words ++ get[0]; 229
170 decimals = decimals ++ get[1]; 230 //Overridden reverse method to include passing the tani into the resulting
171 fractions = fractions ++ get[2]; 231 // reversed KonaTime
172 }; 232 reverse {
173 233 ^this.class.newFrom(this.asArray.reverse, tani)
174 if(argW) { 234 }
175 words.postln; 235 }
176 }; 236
177 if(argD) { 237
178 decimals.postln;
179 };
180 if(argF) {
1 /* =========================================================================== */ 58 laya = argLaya;
2 /* = KonaTani Class - Class to contain and playback whole pieces of music = */ 59 talaSym = argTala;
3 /* =========================================================================== */ 60 tala = this.setTala(talaSym);
4 61 gati = argGati;
5 KonaTani { 62 otherGatis = argOtherGatis;
6 classvar allTalas; // A set of the common talas 63
7 64 gen = KonaGenerator.new(this, laya, tala, gati);
8 var <laya; // Tempo 65
9 var <tala; // Beats in cycle 66 oneCycleDur = tala.sum*(60/laya); //Duration of one cycle
10 var <talaSym; // The tala in symbols 67
11 var <gati; // 'Default' sub-divisions per beats 68 store = KonaTime.new(this);
12 var <otherGatis; // Sub-divisions to change to 69
13 var <gen; // Material generator 70 //Playback Variables
14 var <store; // Whole solo stored in a KonaTime 71 konaSynth = argSynth;
15 72 this.setPlayback;
16 //Playback variables 73
17 var <s; // Server 74 //Setup tala and clapping Routine
18 var <konaSynth; // Synth to use 75 this.makeTalaRout();
19 var <clock; // Playback Tempo Clock 76
20 var <fftBuffArray; // Array of buffers for PV_PlayBuf FFT 77 //Load SynthDefs
21 var <fftRout; // Routine to cycle through FFT buffers 78 this.setSynthDefs;
22 var <fftBuff; // Next FFT buffer to use 79 }
23 var <syls; // Array of syllables for opening analysis file/directory 80
24 var <buffers; // Buffers for scpv files 81 //Convert the tala from symbols to numbers
25 var <talaRout; // Routine for tala clapping 82 setTala {|aTala|
26 var <pRout; // Routine for playback; 83 var ret = List[];
27 var <mOut; // MIDIOut 84
28 85 if(aTala.every { |item, i| item.class==Integer}) {
29 86 ^aTala;
30 *initClass { 87 } {
31 allTalas = [ 88 aTala.do { |item, i|
76

32 ["I4","O","O"], // Adi Tala 89 switch (item[0].asSymbol)


33 ["U","O"], // Rupaka Tala 90 {'I'} {ret.add(item[1].digit)}
34 ["U1", "R", "W", "W", "R"], // Khanda Capu 91 {'O'} {ret.add(2)}
35 ["W", "W", "R", "U", "U"] // Misra Capu 92 {'U'} {
36 ]; 93 switch ((item[1]!=nil).and({item[1].digit}) )
37 } 94 {1} {ret.add(0.5)}
38 95 {false} {ret.add(1)};
39 *new {|argLaya=60, argTala=#["I4","O","O"], argGati=4, argOtherGatis=#[3], 96 }
argSynth=\konaHit| 97 {'W'} {ret.add(0.5)}
40 98 {'R'} {ret.add(0.5)};
41 ^super.new.konaTaniInit(argLaya, argTala, argGati, argOtherGatis, 99 };
argSynth); 100 };
42 } 101
43 102 ^ret.asArray;
44 *rand {|argLaya, argTala, argGati, argOtherGatis, argSynth=\konaHit| 103
45 104 }
46 var laya = argLaya ?? {rrand(60,140)}; 105
47 var tala = argTala ?? {allTalas.choose}; 106 //Setup playback variables
48 var gati = argGati ?? {[4,3,5,7,9].choose}; 107 setPlayback {
49 var otherGatis = argOtherGatis ?? {[4,3,5,7,9].select({|item, i| 108 s = Server.default;
item!=gati })}; 109 clock = TempoClock.new(laya/60);
50 110 //Array of buffers for FFT
51 ^super.new.konaTaniInit(laya, tala, gati, otherGatis, argSynth); 111 fftBuffArray = Array.fill(10, {Buffer.alloc(s, 1024)});
52 112
53 } 113 //Syllables Array
54 114 syls = ['Tam', 'Ta', 'Ka', 'Ki', 'Tah', 'Di', 'Mi', 'Da', 'Gi', 'Na',
55 konaTaniInit {|argLaya, argTala, argGati, argOtherGatis, argSynth| 115 'Dom', '-', 'Ju', 'Lan', 'Gu', 'Tom', 'Nam', 'Ri', 'Du', 'Din'];
56 var oneCycleDur; 116
57 117 //Buffers for PV analysis files
118 buffers=Array.newClear(syls.size); 175 stop {
119 buffers.size.do({|i| buffers[i] = Buffer.read(s, "sounds/Solkattu 176 //this.clock.stop;
/"++syls[i]++".wav.scpv")}); 177 talaRout.stop;
120 178 pRout.stop;
121 //FFT Buffers and Routine 179
122 fftBuff=fftBuffArray[0]; 180 }
123 fftRout = Routine.new({ 181
124 inf.do({|i| 182 //Generate the clapping routine for the Tala
125 fftBuff = fftBuffArray.wrapAt(i); 183 makeTalaRout {
126 0.yield; 184 var func = {|amp1, amp2, freq1, freq2, rq| s.bind {Synth(\clapping,
127 }) [\amp, rrand(amp1, amp2), \filterfreq, rrand(freq1, freq2), \rq, rq.rand]) }};
128 }); 185
129 186 talaRout = Routine {
130 //MIDI 187 inf.do {
131 MIDIClient.init(1,1); 188 talaSym.do { |item, i|
132 mOut = MIDIOut.newByName("IAC Driver", "IAC Bus 1"); 189 switch (item[0].asSymbol)
133 190 {'I'} {
134 } 191 //Clap
135 192 func.(0.4, 0.5, 2000, 2500, 0.9);
136 //Setup SynthDefs 193 1.wait;
137 setSynthDefs { 194 //Finger Taps
138 //Default SynthDef 195 (item[1].digit-1).do { |j|
139 SynthDef(\konaHit, { arg out=0, bufnum=0, recBuf=1, rate=1, amp=0.8; 196 func.(0.01, 0.05, 6000, 7000, 0.9);
140 var chain, signal; 197 1.wait;
141 chain = PV_PlayBuf(bufnum, recBuf, rate, 0, 0); 198 };
142 signal = IFFT(chain, 1)*amp; 199 }
143 DetectSilence.ar(signal, doneAction:2); 200 {'O'} {
144 Out.ar(out, signal.dup); 201 //Clap
145 }).load(s); 202 func.(0.4, 0.5, 2000, 2500, 0.9);
146 203 1.wait;
147 // Clapping SynthDef by Thor Magnusson 204 //Back of hand / wave
77

148 SynthDef(\clapping, {arg t_trig=1, amp=0.5, filterfreq=100, rq=0.1; 205 func.(0.01, 0.03, 400, 600, 0.9);
149 var env, signal, attack, noise, hpf1, hpf2; 206 1.wait;
150 noise = WhiteNoise.ar(1)+SinOsc.ar([filterfreq/2,filterfreq/2+4 ], 207 }
pi*0.5, XLine.kr(1,0.01,4)); 208 {'U'} {
151 hpf1 = RLPF.ar(noise, filterfreq, rq); 209 //Clap
152 hpf2 = RHPF.ar(noise, filterfreq/2, rq/4); 210 func.(0.4, 0.5, 2000, 2500, 0.9);
153 env = EnvGen.kr(Env.perc(0.003, 0.00035)); 211 switch ((item[1]!=nil).and({item[1].digit}) )
154 signal = (hpf1+hpf2) * env; 212 {1} {0.5.wait}
155 signal = CombC.ar(signal, 0.5, 0.03, 0.031)+CombC.ar(signal, 0.5, 213 {false} {1.wait};
0.03016, 0.06); 214 }
156 //signal = FreeVerb.ar(signal, 0.23, 0.15, 0.2); 215 {'W'} {
157 signal = Limiter.ar(signal, 0.7, 0.01); 216 //Wave
158 Out.ar(0, Pan2.ar(signal*amp, 0)); 217 func.(0.3, 0.4, 400, 600, 0.9);
159 DetectSilence.ar(signal, doneAction:2); 218 0.5.wait;
160 }).load(s) 219 }
161 } 220 {'R'} {
162 221 //Rest
163 //Playback the contained piece of music with the tala cycle 222 0.5.wait;
164 play { 223 };
165 talaRout.reset; 224 };
166 pRout.reset; 225 };
167 talaRout.play(clock); 226 };
168 { 227
169 ((60/laya)*(tala.sum)).wait; 228 }
170 pRout.play(clock); 229
171 }.fork 230 //Getter for the music routine
172 } 231 rout {
173 232 ^store.rout;
174 //Stop routine playback 233 }
234
235 //Add an item to this instance's KonaTime
236 add {|aKonaItem|
237 store.add(aKonaItem);
238 pRout = store.rout;
239 }
240
241 //Add a collection of items to this instance's KonaTime
242 addAll { |argCollection|
243 store.addAll(argCollection);
244 pRout = store.rout;
245 }
246
247 //Clear this instance's KonaTime
248 clear {
249 store = KonaTime.new(this);
250 pRout = store.rout;
251 }
252
253 //Setter method for the gati
254 gati_{|aGati|
255 gati = aGati;
256 gen.gati = aGati;
257 }
258 }
259
78
1 /* ================================================================== */ (duration)
2 /* = KonaGenerator Class - Class to generate and manipulate rhythms = */ 60 // -Uses ZS2 Algorithm from "Fast Algorithms For Generating Integer
3 /* ================================================================== */ Partitions"
4 61 // by Zoghbi and Stojmenovic
5 KonaGenerator { 62 // -Doubly restricted by default to 2 and 9, but the mininum
6 var tani; // The Tani that this KonaGenerator belongs to 63 // restriction is available as an argument
7 var laya; // The Laya (tempo) of the tani 64 // -This is because of the restriction on Konakkol word size
8 var <>gati; // The current Gati (beat subdivision) of the Tani 65
9 var <gatiPowers; // The series of powers belonging to the gati; 66 allPartitions { |aNum, aMin=2, aMax, aUParts|
10 var <tala; // The Tala of this Tani 67 var tmax; // The maxmimum size a part of a partition may be
11 var <>pMax; //Maximum perceptual time for a motif. May make this method 68 var x; // An array to store each new partition in;
specific 69 var h; // The index of the last part of partition that is > 1
12 70 var m; // The number of parts in a partition
13 *new {|argTani, argLaya, argTala, argGati=4| 71 var j; // The index of the next part to be increased
14 ^super.new.konaGeneratorInit(argTani, argLaya, argTala, argGati); 72 var r; // A variable used to calculate the next m
15 } 73 var partition; // A freshly baked partition
16 74 var add; // Boolean; whether this partition should be added.
17 konaGeneratorInit {|argTani, argLaya, argTala, argGati| 75 var ret; // The array to be returned.
18 tani = argTani; 76 var readFunc; // Function to read partitions from a file.
19 laya = argLaya; 77 var n, min, max; //vars for aNum aMin and aMax.
20 tala = argTala; 78
21 gati = argGati; 79 //Ensure against floats.
22 80 n = aNum.asInteger;
23 gatiPowers = this.setGatiPowers(argGati); 81 min = aMin.asInteger;
24 82 readFunc = {|val|
25 pMax = 5; //Rough perceptual present in seconds Object.readArchive(Platform.userExtensionDir++"/FYPClasses/partitions/"++val.asString)};
26 } 83
27 84 case
28 // setGatiPowers 85 //There are no partitions of 1
29 // Method to create the series of values to which the gati belongs 86 {n==1} {^[[1]]}
30 // 87 //If n==2 and min==2 there are no partitions of
79

31 // e.g. Series for gati 3 = [3, 6, 12, 24, 48, 96, 192] 88 {n==2 && (min==2)} {^[[2]]}
32 // Special circumstances for gati 4 to include 2 = [2, 4, 8, 16, 32, 64, 128] 89 {n>=40} {
33 setGatiPowers {|aGati| 90 if(aUParts==nil) {
34 var powers; 91 ^readFunc.(n);
35 92 } {
36 if(aGati==4, 93 ^this.removeGreaterThan(readFunc.(n), aUParts);
37 {powers = List[(aGati/2).asInteger]}, 94 };
38 {powers = List[(aGati).asInteger]} 95 };
39 ); 96
40 10.do { |i| 97 ret = List[];
41 powers.add( (powers[powers.size-1]*2).asInteger) 98 //Fill the array with n 1s
42 }; 99 x = Array.fill(n, 1);
43 100 //Add the array as it forms the first partition
44 ^powers.asArray; 101 if(min==1) {
45 102 ret.add(x[0..n]);
46 } 103 };
47 104 //Alter x; set the second element ([1]) to 2 and add the subarray x[1..n]
48 /* ======================================================= */ 105 x[1] = 2;
49 /* = Generation Methods = */ 106 if(min==1) {
50 /* ======================================================= */ 107 ret.add(x[1..n]);
51 108 };
52 /* = Maths Methods = */ 109
53 110 h = 1;
54 // allPartitions 111 m = n-1;
55 // @n Total number of beats to partition 112
56 // @min Minimum part size 113 //If the max argument is not set, use n if below 9, else use 9
57 // @max Maximum part size 114 if( aMax == nil ) {
58 // 115 if(n>9) {
59 // -Method to generate all partitions and permutations of an integer 116 tmax = 9;
117 } { 176 };
118 tmax = n; 177
119 }; 178 });
120 } { 179
121 //Else if the argument is n-1 or n, use the argument as given 180 ^ret.asArray;
122 if(aMax >= (n-1)) { 181
123 tmax = aMax.asInteger; 182 }
124 } { 183
125 //Else add 1 to the argument. 184 // randomPartition
126 //This is to ensure that the maximum argument works correctly 185 // Method to choose a random partition
127 //If used as given, a max arg of 3 would return results up to 186 //
size 3 187 // @duration number of beats for the partition
128 tmax = aMax.asInteger+1; 188 // @min minimum part size
129 }; 189 // @max maximum part size
130 190 // @notSize boolean, true means partition of 1 part equal to size will
131 }; 191 // not be returned. E.g. duration 4 can't return partition
132 [4]
133 //Generate further partitions 192 // @seed seed for random selection
134 while({x[1] != tmax}, 193
135 { 194 randomPartition { |duration, min=2, aMax, notSize=false, seed|
136 if( (m-h) > 1) { 195 var allPartitions;
137 h = h+1; 196 var max;
138 x[h] = 2; 197
139 m = (m-1); 198 if(seed!=nil) {
140 } { 199 thisThread.randSeed=seed
141 j = (m-2); 200 };
142 201
143 while({x[j] == x[m-1]}, 202 max = aMax ?? {if(duration>9) {9} {duration}};
144 { 203
145 x[j] = 1; 204 allPartitions = this.allPartitions(duration, min, max);
146 j = (j-1); 205
80

147 } 206 if(notSize && (allPartitions.size>1)) {


148 ); 207
149 h = (j+1); 208 allPartitions.do { |item, i|
150 x[h] = (x[m-1] +1); 209 if(item[0]==duration) {
151 r = (x[m] + ((x[m-1])*(m-h-1))); 210 allPartitions.removeAt(i)
152 211 };
153 x[m] = 1; 212 };
154 213 };
155 if( (m-h) > 1 ) { 214
156 x[m-1] = 1 215 ^allPartitions.choose;
157 }; 216 }
158 m = (h + (r-1)); 217
159 218 // allPerms
160 }; 219 // Method to generate all permutations of a partition
161 partition = x[1..m]; 220 //
162 //If a maximum number of unique parts has been set 221 // @aCollection The partition array to generate permutations of
163 if(aUParts!=nil) { 222
164 //If the number of unique parts is acceptable. 223 allPerms {|aCollection|
165 if(partition.asSet.size<=aUParts) { 224 var col; //Collection to permute
166 add = true 225 var ret; //Array to return permutations
167 } { 226 var perm; //Temp variable for storing permutation
168 add = false 227 col = aCollection;
169 }; 228 ret = List[];
170 } { 229
171 add = true; 230 //If the partition is not just made up of 1 unique number (e.g. [2,2,2])
172 }; 231 if(col.occurrencesOf(col[0]) != col.size) {
173 232 //Loop to create all permutations
174 if(partition.minItem >= min && (add==true)) { 233 col.size.factorial.asInteger.do { |i|
175 ret.add(partition); 234 perm = col.permute(i);
235 //If ret doesn't already contain the new permutation 295 removeThoseContaining {|aCollection, valCol, weightCol|
236 if(not(ret.any { |item, i| item.asArray == perm })) { 296
237 //Add it 297 var col; // Partitions
238 ret.add(col.permute(i)); 298 var vCol; // Values
239 }; 299 var wCol; // Weights
240 }; 300 var inds; // Indexes of partitions to remove
241 } { 301 var saveIndex;
242 //Else (if the partition IS made up of just 1 unique number) 302
243 ret.add(col); 303 col = aCollection;
244 }; 304
245 305 vCol = valCol;
246 //Return all partitions 306
247 ^ret.asArray; 307 //If no weights are supplied, remove is guaranteed
248 } 308 wCol = weightCol ?? {Array.fill(vCol.size, 1)};
249 309
250 // randomPerm 310 inds = List[];
251 // Method to choose a random permutation 311 //For each forbidden value
252 // 312 vCol.size.do { |i|
253 // @partition Partition to generate permutations from 313 //Check for partitions that include the value
254 // @seed seed for random selection 314 col.do { |jtem, j|
255 randomPerm { |partition, seed| 315 if(jtem.includes(vCol[i])) {
256 var permutation; 316 //Store the index depending on given weight
257 if(seed!=nil) { 317 if(wCol[i].coin) {
258 thisThread.randSeed=seed 318 inds.add(j);
259 }; 319 };
260 320 };
261 permutation = (partition.size+1).factorial.asInteger.rand; 321 };
262 322 };
263 ^partition.permute(permutation); 323 inds = inds.asSet.asArray.sort;
264 } 324
265 325 //If all partitions are to be removed, select one at random to keep
81

266 // removeGreaterThan 326 if(inds.size==col.size) {


267 // Method to remove all partitions from a collection 327 //Store the index of value least likely to be removed
268 // that have more than a given number of unique parts 328 saveIndex = wCol.indexOf(wCol.minItem);
269 // 329 //Select an index from those partitions that include
270 // @aCollection Collection to remove partitions from 330 // the least likely value
271 // @val Maximum number of unique partitions 331 saveIndex = inds.select({|item, i|
272 removeGreaterThan {|aCollection, val, weight=0.97| 332 col[i].includes(vCol[saveIndex]);
273 var col; // Instance collection 333 }).choose;
274 var temp; // Temporary list for checking partitions 334
275 335 inds.removeAt(saveIndex);
276 col = aCollection; 336 };
277 temp = List[]; 337 col.removeAtIndexes(inds.asArray)
278 col.do { |item, i| 338
279 if(item.asSet.size>val) { 339 //Return updated collection
280 temp.add(i) 340 ^col
281 }; 341 }
282 }; 342
283 col = col.removeAtIndexes(temp); 343 // partsToWords
284 ^col; 344 // Method to turn a partition array into KonaWords
285 } 345 //
286 346 // @aPartitionArray Partition Array
287 // removeThoseContaining 347 // @aOne Boolean; if KonaWords can be 1 syllable
288 // Method to remove all partitions from a collection 348 // @aMult Boolean; if Konawords can have syllables == part size
289 // that contain certain values 349 partsToWords {|aPartitionArray, aKarve, aOne=true, aMult=true|
290 // Individual weights can be passed for probabalistic results 350 var partitionArray;
291 // 351 var one, mult;
292 // @aCollection Collection to remove paritions from 352 var ret;
293 // @valCol Collection of taboo values 353 var chance;
294 // @weightCol Collection of weights for taboo values 354 var jatis, karve;
355 413 phraseLength = 0;
356 partitionArray = aPartitionArray; 414 val = tala.sum;
357 one = aOne; 415
358 mult = aMult; 416 while({phraseLength==0},
359 case 417 {
360 {aOne==true && (aMult==true)} {chance = 0.5} 418 phraseLength = maxBeats-(maxBeats%val);
361 {aOne==true && (aMult==false)} {chance = 1} 419 val = val/2;
362 {aOne==false && (aMult==true)} {chance = 0} 420 }
363 {aOne==false && (aMult==false)} {chance = 0.5}; 421 );
364 422
365 ret = KonaTime.new(tani); 423 Post << "phraseLength: " << phraseLength << "\n";
366 424
367 aPartitionArray.size.do { |i| 425 ^phraseLength
368 if(chance.coin) { 426 }
369 jatis = 1; 427
370 karve = aPartitionArray[i]; 428 // vSarvaPhraseAuto
371 } { 429 // Automation of vSarvaPhrase
372 jatis = aPartitionArray[i]; 430 vSarvaPhraseAuto {
373 karve = 1; 431
374 }; 432 "vSarvaPhraseLength*gati: ".post; (this.vSarvaPhraseLength*gati).postln;
375 ret.add(KonaWord.new(jatis, gati, karve*aKarve, tani)) 433
376 }; 434 ^this.vSarvaPhrase(this.vSarvaPhraseLength*gati);
377 ^ret 435 }
378 } 436
379 437 // vSarvaPhrase
380 /* ================= */ 438 // Method to generate a phrase for the Vilamba section sarvalaghu
381 /* = Music Methods = */ 439 vSarvaPhrase {|phraseDur, aMin=2|
382 /* ================= */ 440 var phraseMatras;
383 441 var jatiParts;
384 442 var min;
385 // vSarvaPhraseLength 443 var max;
82

386 // Method to determine the phrase length (in beats) 444 var partsArray, weights, maxW, maxW1, maxW2, maxW1MI;
387 // for sarvalaghu patterns for the Vilamba Kala section 445 var muteChance;
388 // Uses a tweaked perceptual present model, 446 var ret;
389 // currently uses a window of 5 seconds. 447
390 vSarvaPhraseLength { 448 if(phraseDur%1!=0) {
391 var phraseLength; 449 ret = KonaTime.new(tani);
392 var oneBeat; 450 ret.add(this.vSarvaPhrase(phraseDur.floor, aMin));
393 var maxBeats; 451 ret.add(KonaWord.new(1, gati, (phraseDur-phraseDur.floor)));
394 var val; 452 ^ret;
395 //Time in seconds for one beat 453 };
396 oneBeat = 60/laya; 454
397 Post << "oneBeat: " << oneBeat << "\n"; 455 phraseMatras = phraseDur;
398 456
399 //The number of beats that can fit into the maximum perceptual time 457 if(phraseDur<aMin) {
400 //With a maximum number of beats of 5. Even if perceptual time is 3 458 min = phraseDur;
seconds, 459 } {
401 // phrases are not usually longer than this 460 min = aMin;
402 maxBeats = (pMax/oneBeat).min(5); 461 };
403 Post << "maxBeats: " << maxBeats << "\n"; 462
404 463 if(2*gati<=phraseDur) {
405 // This algorithm attempts to find that largest phrase length that 464 max = gati;
406 // fits neatly into a full cycle. 465 } {
407 // At the moment this only works in terms of half/quarter/eigth cycles 466 max = phraseDur;
etc 467 };
408 // Could be adapted to find other durations of phrase that 468
409 // can fit neatly into a cycle 469 //Possible part sizes
410 // E.g. a 9 beat tala could be made up of 3 * 3 beat phrases 470 partsArray = (min..max);
411 // Not a huge amount of material to support this theory. 471 Post << "partsArray: " << partsArray << "\n";
412 472
473 //Parts 2 to gati. Given heaviest weightings 532 if(muteChance.coin) {
474 weights = Array.fill(partsArray.size, 0); 533 ret = this.randomMuteJati(ret);
475 534 };
476 weights.size.do { |i| 535 muteChance = muteChance/2;
477 536 };
478 if(this.gatiPowers.includes(partsArray[i]), 537 "randomMuteJati: ".postln; ret.postWord(true, true, false);
479 {weights[i] = 1.5}, 538
480 {weights[i] = 0.4} 539 ^ret;
481 ); 540
482 541 }
483 if(partsArray[i]<gati) { 542
484 weights[i] = weights[i] + 0.25; 543 // mutatePhrase
485 } { 544 // Method to mutate a given phrase using many possible
486 if(partsArray[i]!=gati) { 545 // combinations of automated manipulation methods
487 weights[i] = weights[i] - 0.4 546 //
488 }; 547 // @aKonaItem Item to manipulate;
489 }; 548 mutatePhrase {|aKonaItem, aChance, aRec=0.75, aNum|
490 549 var col; // Input collection
491 if(gati==5 || (gati==7)) { 550 var ret; // Output collection
492 if((partsArray[i]== 3) || (partsArray[i]== 2)) { 551 var change; // The chance an item will be mutated;
493 weights[i] = weights[i] + 0.25; 552 var min; // Minimum value for alteration
494 } { 553 var max; // Maximum value for alteration
495 weights[i] = weights[i] - 0.25 554 var val; // Variable used to calculate density possibilties
496 }; 555 var count; // Variable used when calculating density possibilities
497 }; 556 var index; // Index of element to mutate
498 557 var store; // Array to store indexes to be removed (atDensity)
499 if(weights[i]<0, 558 var num; // Index of process to use;
500 {weights[i] = 0} 559
501 ); 560 if(aKonaItem.class==KonaTime) {
502 561 col = aKonaItem;
503 }; 562 } {
83

504 //Scale and invert values. 563 col = KonaTime.newFrom([aKonaItem], tani);


505 weights = (weights/weights.maxItem-1).round(0.01).abs; 564 };
506 565
507 jatiParts = this.allPartitions(phraseMatras.asInteger, aMax: max); 566 change = aChance ?? {(1/col.size)*1.5};
508 567 if(aNum==nil) {
509 jatiParts = this.removeGreaterThan(jatiParts, 4); 568 num = {5.rand}
510 569 } {
511 jatiParts = this.removeThoseContaining(jatiParts, partsArray, 570 num = {aNum}
weights); 571 };
512 572 ret = KonaTime.new(tani);
513 jatiParts = jatiParts.choose; 573 col.size.do { |i|
514 574 if(change.coin,
515 jatiParts = this.randomPerm(jatiParts); 575 {
516 576 if(col[i].class==KonaWord) {
517 ret = KonaTime.new(tani); 577 switch (num.())
518 jatiParts.size.do { |i| 578 {0} {
519 if((jatiParts[i].even && (jatiParts[i]>2)) && 0.75.coin ) { 579 ret.add(this.randomAtDensity(col[i]));
520 ret.add(KonaWord.new(jatiParts[i]/2, gati, 2, tani)) 580 }
521 } { 581 {1} {
522 ret.add(KonaWord.new(1, gati, jatiParts[i], tani)) 582 ret.add(this.randomExtendJati(col[i]));
523 }; 583 }
524 }; 584 {2} {
525 "Conversion to KonaWords: ".postln;ret.postWord(true, true, false); 585 ret.add(this.randomMuteJati(col[i]));
526 586 }
527 ret = this.combineSimilar(ret, 2, 4, 0.9); 587 {3} {
528 "combineSimilar: ".postln; ret.postWord(true, true, false); 588 ret.add(this.randomDensityJati(col[i]));
529 589 }
530 muteChance = 0.75; 590 {4} {
531 3.rand.do { |i| 591 ret.add(this.partitionWord(col[i]));
592 }; 652 //
593 } { 653 // @statement KonaObject for Statement
594 ret.add(this.mutatePhrase(col[i], aRec=aRec/4)) 654 // @gap KonaObject for Gap
595 }; 655 // @offset KonaObject for Offset
596 656 createSimpleMora {|statement, gap, offset|
597 }, 657
598 { 658 var mora = KonaTime.new(tani);
599 ret.add(col[i]) 659
600 } 660 if(offset!=nil,
601 ); 661 {mora.add(offset)}
602 }; 662 );
603 663
604 //Possible recursion for more mutation. 664 2.do {
605 if(aRec.coin) { 665 mora.add(statement);
606 ^this.mutatePhrase(ret, aRec:aRec/2, aNum:aNum) 666 if(gap!=nil,
607 } { 667 {mora.add(gap)}
608 ^ret 668 );
609 }; 669 };
610 } 670 mora.add(statement);
611 671
612 // vSarvaStat 672 ^mora
613 // A method for generating Sarva Laghu material based on 673 }
614 // a statistical analysis of a performance by Trichy Sankaran; 674
615 // Currently only works with an n of 1, no context. 675 // moraStatement
616 vSarvaStat { 676 // Method to generate a mora statement
617 var stats; 677 //
618 var ret; 678 // @statePulses Statement jatis
619 679 // @aGati Gati of the statement
620 ret = KonaTime.new(tani); 680 // @aKarve Karve to use
621 681 moraStatement {|aStateMatras, aGati, aKarve|
622 stats = [ 682 var statePulses;
84

623 100, 37.5, 87.5, 68.75, 683 var statement;


624 93.75, 12.5, 100, 25, 684 var ret;
625 685 var temp;
626 100, 80, 100, 13, 686
627 100, 13, 100, 6, 687
628 688 statePulses = aStateMatras*(1/aKarve);
629 100, 0, 73, 53, 689
630 100, 0, 100, 22, 690 //Turn statements into KonaItems
631 691 //If the statement duration can be a single word
632 89, 66, 100, 22, 692 if(statePulses<=9) {
633 100, 30, 80, 30 693 statement = KonaWord.new(statePulses, aGati, aKarve, tani);
634 ]; 694 } {
635 695 //If a statement duration requires more than a single word
636 stats.size.do { |i| 696 //Generate a partition
637 if((stats[i]/100).coin) { 697 statement = this.randomPartition(statePulses.asInteger);
638 ret.add(KonaWord.new(1,4,1,tani)) 698 //Choose a permutation
639 } { 699 statement = this.randomPerm(statement);
640 ret.add(KonaWord.new(0,4,1,tani)) 700
641 }; 701 //Convert to KonaTime
642 }; 702 ret = KonaTime.new(tani);
643 703
644 ^ret 704 statement.size.do {|i|
645 } 705 //New word jatis equal to part duration
646 706 temp = KonaWord.new(statement[i], aGati, aKarve, tani);
647 ///////////////////////// Moras ///////////////////////// 707 ret.add(temp);
648 708 };
649 // createSimpleMora 709 statement = ret;
650 // Builds a mora structure from a given statement 710 };
651 // with optional gap and offset. 711 //statement = this.partitionWord(statement);
712 if(0.5.coin) { 772 var phraseMin; //Minimum part size if the offset is to be a phrase.
713 statement = this.randomDensityJati(statement); 773
714 }; 774
715 775 offsetPulses = aOffsetMatras*(1/aKarve);
716 ^statement; 776
717 } 777 if(offsetPulses!=0) {
718 778 case
719 // moraGap 779 //If the offset is greater than 2 beats, use a phrase
720 // Method to generate a mora gap. 780 {offsetPulses>(aGati*2)} {
721 // 781 if(offsetPulses>20) {
722 // @gapPulses Statement jatis 782 phraseMin = 4
723 // @aGati Gati of the statement 783 } {
724 // @aKarve Karve to use 784 phraseMin = 2;
725 moraGap {|aGapMatras, aGati, aKarve| 785 };
726 var gapPulses; 786 offset = this.vSarvaPhrase(aOffsetMatras, aMin:phraseMin);
727 var gap; 787
728 var temp; 788 }
729 789 //If the offset is less than 2 beats, has a 0.05 chance
730 gapPulses = aGapMatras*(1/aKarve); articulation.
731 790 {0.05.coin} {
732 if(gapPulses==0) { 791 offset = KonaWord.new(offsetPulses, aGati, aKarve, tani)
733 gap=nil; 792 }
734 } { 793 //Else a single syllable word is used.
735 if(gapPulses>4 && 0.95.coin) { 794 {true} {
736 gap = this.randomPartition(gapPulses.asInteger, notSize:true); 795 offset = KonaWord.new(1, aGati, aOffsetMatras, tani)
737 gap = this.randomPerm(gap); 796 };
738 797
739 temp = KonaTime.new(tani); 798 } {
740 gap.size.do { |i| 799 offset = nil;
741 if(i==0) { 800 };
742 temp.add(KonaWord.new(1, aGati, gap[i]*aKarve, tani)) 801
85

743 } { 802 ^offset


744 temp.add(KonaWord.new(gap[i], aGati, aKarve, tani)); 803 }
745 }; 804
746 }; 805 // randomMoraValues
747 //gap = this.mutatePhrase(temp); 806 // Calculation of mora values (statement, gap, offset durations).
748 gap = temp; 807 //
749 808 // @aMatras The duration of the mora in matras
750 } { 809 // @aGati The gati of the mora elements
751 //Generate single jati gap with gapPulses duration 810 // @aGati The karve of the mora elements
752 if(aKarve>=0.25 && (0.5.coin)) { 811 // @aGap Boolean, gaps or not, overridden for certain durations.
753 gap = KonaWord.new(0, aGati, gapPulses*aKarve, tani) 812 // @aOffset Boolean, offset or not
754 } { 813 randomMoraValues {|aMatras, aGati, aKarve, aGap=true, aOffset=true|
755 gap = KonaWord.new(1, aGati, gapPulses*aKarve, tani) 814 var pulses;
756 }; 815 var stateMin, gapMin;
757 }; 816 var stateMax, gapMax;
758 }; 817 var gapArray, gapWeights;
759 818 var stateMatras, gapMatras, offsetMatras;
760 ^gap 819 var totalStateMatras, totalGapMatras;
761 } 820
762 821 pulses = aMatras*(1/aKarve);
763 // moraOffset 822
764 // Method to generate a mora offset 823 // Nelson 2008 p 23
765 // 824 // 'It is a practical fact of Karnatak rhythmic behaviour that if a mora
766 // @offsetPulses Offset jatis 825 // statement is shorter than five pulses, its gap will nearly always be
767 // @aGati Gati of the statement 826 // at least two pulses'.
768 // @aKarve Karve to use 827 // This is impossible if a duration of less than 7 is used.
769 moraOffset {|aOffsetMatras, aGati, aKarve| 828 // In this instance a mora with the same duration,
770 var offsetPulses; 829 // but using double the jatis and half the karve is returned
771 var offset = nil; 830 // Moras under 2 whole beats are also given a chance of being altered.
831 889 // @aMatras The duration of the mora in matras
832 if(pulses<7 || (aMatras/aGati<=2 && 0.25.coin && (aKarve>0.5))) { 890 // @aGati The gati of the mora elements
833 ^this.randomMoraValues(aMatras, aGati, aKarve/2, aGap, aOffset); 891 // @aGap Boolean, whether there should be gaps or not
834 }; 892 // @aOffset Boolean, whether there should be an offset or not
835 893 randomMora {|aMatras, aGati, aKarve, aGap=true, aOffset=true|
836 //Any duration under 15 will result in statements less than 5 pulses 894 var values;
837 // so requires a minimum gap of 2 895 var statement, gap, offset;
838 if(pulses<15) { 896
839 gapMin = 2; 897 values = this.randomMoraValues(aMatras, aGati, aKarve, aGap, aOffset);
840 } { 898
841 gapMin = 0; 899
842 }; 900 //Convert statements/gaps/offset into KonaItems
843 901
844 // Calculate the mininum matras for the statements. 902 statement = this.moraStatement(values[0]*values[3], aGati, values[3]);
845 // If might be no gap, use a minimum size of 1/4 of the total mora 903
duration 904
846 if(gapMin==0) { 905 gap = this.moraGap(values[1]*values[3], aGati, values[3]);
847 stateMin = (pulses/(3.00, 3.05..4.00).choose).asInteger 906 if(gap!=nil) {
848 } { 907 };
849 stateMin = (pulses/5).asInteger 908
850 }; 909
851 910 offset = this.moraOffset(values[2]*values[3], aGati, values[3]);
852 //Calculate the maximum possible statement size 911 if(offset!=nil) {
853 stateMax = (pulses-(gapMin*2)/3).asInteger; 912 };
854 913
855 //Select a statement duration 914
856 stateMatras = (stateMin..stateMax).choose; 915 ^this.createSimpleMora(statement, gap, offset);
857 totalStateMatras = stateMatras*3; 916 }
858 917
859 if(aGap) { 918 // Generative method to create a mora from a given statement,
860 //Calculate the maximum possible gap size. 919 // with optional maximum mora size, gap and offset.
86

861 gapMax = (pulses-totalStateMatras)/2; 920 // Differs from createSimpleMora in that gaps and offsets will
862 921 // be calculated and generated if possible
863 gapArray = (gapMin..gapMax); 922 //
864 923 // @aStatement Kona object to use for statement
865 //Calculate weights for gap matras selection, with bias for smaller 924 // @aMoraMatras Total maximum number of matras, overidden if less
gaps. 925 // than sum of aStatement, aGap, aOffset matras
866 gapWeights = (gapArray.size..1).normalizeSum; 926 // @aGap Kona object to use for gap
867 927 // @aOffset Kona object to use for offset
868 //Choose a gap duration 928 moraFrom {|aStatement, aMoraMatras, aGap, aOffset|
869 gapMatras = gapArray.wchoose(gapWeights); 929 var statement, gap, offset;
870 } { 930 var objArray;
871 gapMatras = 0; 931 var objMatras, moraMatras, gapMatras, offsetMatras;
872 }; 932
873 totalGapMatras = gapMatras*2; 933 statement = aStatement;
874 934 gap = aGap;
875 //If there should be an offset, calculate the duration 935 offset = aOffset;
876 if(aOffset) { 936
877 offsetMatras = pulses - totalStateMatras - totalGapMatras; 937 objMatras = 0;
878 } { 938 objArray = [statement,gap,offset];
879 offsetMatras = 0; 939 //Calculate total matras of mora sections passed as arguments
880 }; 940 objArray.do { |item, i|
881 941 var val;
882 942 if(item!=nil && (item!=false)) {
883 ^[stateMatras, gapMatras, offsetMatras, aKarve]; 943 switch (item)
884 } 944 {statement} {val = 3}
885 945 {gap} {val = 2}
886 // randomMora 946 {offset} {val = 1};
887 // Generation of a mora from given parameters; 947
888 // 948 objMatras = objMatras + (item.matras*val);
949 }; 1009 } {
950 }; 1010 offsetMatras = offset.matras;
951 1011
952 //If no maximum duration has been given 1012 };
953 if(aMoraMatras==nil || (aMoraMatras ? 0 <objMatras) ) { 1013 };
954 1014 offset = offset ?? {this.moraOffset(offsetMatras, statement.gati,
955 //Calculate the new maximum duration statement.karve)};
956 moraMatras = objMatras; 1015
957 if(gap==nil || (gap==false)) { 1016 //Construct and return the mora
958 gapMatras=0; 1017 ^this.createSimpleMora(statement, gap, offset);
959 } { 1018 }
960 gapMatras=gap.matras 1019
961 }; 1020 // randomSamaCompoundMora
962 if(offset==nil) { 1021 // Generate a random compound mora with the 'sama' shape
963 offsetMatras=0; 1022 //
964 } { 1023 // @aMatras Duration in matras
965 offsetMatras = offset.matras; 1024 // @aGati The gati to use
966 }; 1025 // @aKarve The karve to use
967 } { 1026 randomSamaCompoundMora {|aMatras, aGati, aKarve|
968 //If a maximum duration has been given 1027 var values;
969 moraMatras = aMoraMatras; 1028 var stateDur, gapDur, offsetDur;
970 1029 var statement, gap, offset;
971 //Calculate the lengths of the various sections. 1030
972 //Various cases of passed in gaps and offset. 1031 values = this.randomMoraValues(aMatras, aGati, aKarve, true, true);
973 case 1032
974 {gap==nil && (offset==nil)} { 1033 stateDur = values[0];
975 gapMatras = (0..(moraMatras-objMatras)/2).choose; 1034
976 objMatras = objMatras + (gapMatras*2); 1035 gapDur = values[1];
977 offsetMatras = moraMatras - objMatras; 1036
978 objMatras = objMatras + offsetMatras; 1037 statement = this.randomMora(stateDur*values[3], aGati, values[3], true,
979 } false);
87

980 {gap==nil && (offset!=nil)} { 1038


981 offsetMatras = offset.matras; 1039 if(gapDur==0) {
982 gapMatras = (0..(moraMatras-objMatras)/2); 1040 gap = false;
983 objMatras = objMatras + gapMatras*2; 1041 } {
984 } 1042 gap = this.moraGap(gapDur*values[3], aGati, values[3]);
985 {gap!=nil && (gap!=false) && (offset==nil)} { 1043 };
986 if(gap!=false) { 1044
987 gapMatras = gap.matras; 1045 ^this.moraFrom(statement, aMatras, gap);
988 }; 1046 }
989 offsetMatras = moraMatras - objMatras; 1047
990 objMatras = objMatras + offsetMatras; 1048 // basicStructure
991 } 1049 // A method to generate a basic structure based on the tala.
992 {gap!=nil && (gap!=false) && (offset!=nil)} { 1050 // The purpose is to get a feel for the system's components in a context
993 gapMatras = gap.matras; 1051 // Always follows the same structure:
994 offsetMatras = offset.matras; 1052 // First Cycle: Basic phrase and a development with suffix
995 }; 1053 // Second Cycle: More developments of the basic phrase
996 }; 1054 // Third Cycle: Basic phrases with a half cycle mora
997 1055 // Fourth Cycle: Developed phrases
998 //If no gap has been set, create one. 1056 // Fifth/Sixth Cycle: Compound Mora
999 gap = gap ?? {this.moraGap(gapMatras, statement.gati, statement.karve)}; 1057 // Remaining Cycles: Play previous six cycles in a new gati,
1000 //If there should be no gap, set it to nil 1058 // with a final mora to fill any unfinished cycles.
1001 if(gap==false) { 1059
1002 gap = nil; 1060 basicStructure {
1003 }; 1061 var basicPhrase, developedPhrase;
1004 1062 var phraseMatras, cycleMatras, moraMatras;
1005 //If no offset has been calculate the duration and create one 1063 var phraseMult;
1006 if(offsetMatras==nil) { 1064 var newGati, newKarve, gatiChange, gatiChangeMatras, changeRemainder;
1007 if(offset==nil) { 1065 var preFinalFiller, finalMora;
1008 offsetMatras = moraMatras - objMatras; 1066 var ret;
1067 1127 preFinalFiller = (1-(gatiChangeMatras%1))*newGati;
1068 1128 ret.add(KonaWord.new(1, newGati, preFinalFiller, tani))
1069 ret = KonaTime.new(tani); 1129 };
1070 cycleMatras = tani.tala.sum*tani.gati; 1130 changeRemainder = gatiChangeMatras%cycleMatras;
1071 newGati = [3,5,7,9].wchoose([1,0.5,0.25,0.125].normalizeSum); 1131 ret.add(gatiChange);
1072 switch (newGati) 1132 Post << " gati change ret.dur: " << ret.dur << "\n";
1073 {3} {newKarve = [0.5, 1].choose} 1133
1074 {5} {newKarve = 2} 1134 Post << "changeRemainder: " << changeRemainder << "\n";
1075 {7} {newKarve = 4} 1135
1076 {9} {newKarve = 4}; 1136 //Fill remainder
1077 1137 if(changeRemainder!=0) {
1078 basicPhrase = this.vSarvaPhraseAuto; 1138 if(changeRemainder>(cycleMatras/2)) {
1079 phraseMatras = basicPhrase.matras; 1139 finalMora = changeRemainder-(cycleMatras/2);
1080 phraseMult = cycleMatras/phraseMatras; 1140 ret.add(this.vSarvaPhrase(changeRemainder-(cycleMatras/2)));
1081 developedPhrase = this.mutatePhrase(basicPhrase); 1141 } {
1082 1142 finalMora = changeRemainder;
1083 1143 };
1084 //Fill first cycle 1144 finalMora = this.randomMora(finalMora, tani.gati, [1, 0.5].choose);
1085 ret.addAll([basicPhrase,developedPhrase]); 1145 };
1086 (phraseMult-2).do { |i| 1146
1087 ret.add(this.mutatePhrase(basicPhrase)); 1147 ret.add(KonaWord.new(1, tani.gati, tani.gati, tani));
1088 }; 1148 Post << "ret.dur: " << ret.dur << "\n";
1089 ret[ret.size-1] = this.addSuffix(ret[ret.size-1])[0]; 1149
1090 1150 ^ret;
1091 Post << "1st ret.dur: " << ret.dur << "\n"; 1151 }
1092 1152
1093 //Fill second cycle 1153
1094 ret.add(this.makePostMora(developedPhrase)); 1154 /*
1095 (phraseMult-1).do { |i| ================================================================================ */
1096 ret.add(this.randomDensityJati(developedPhrase)); 1155 /* = Manipulation
1097 }; Methods = */
88

1098 Post << "2nd ret.dur: " << ret.dur << "\n"; 1156 /*
1099 ================================================================================ */
1100 //Fill third cycle 1157
1101 moraMatras = (cycleMatras/2).ceil; 1158
1102 if(cycleMatras-moraMatras!=0) { 1159
1103 ret.add(this.vSarvaPhrase(cycleMatras-moraMatras)); 1160
1104 }; 1161 // wordAtGati
1105 ret.add(this.randomMora(moraMatras, tani.gati, 1)); 1162 // @argWord Word to manipulate
1106 Post << "3rd ret.dur: " << ret.dur << "\n"; 1163 // @argGati New Gati
1107 1164 // @argKarve Number of gati divisions each jati should occupy
1108 //Fill fourth cycle 1165 //
1109 ret.add(this.makePostMora(developedPhrase)); 1166 //Method to return a word at a new Gati, including double tempo etc
1110 (phraseMult-1).do { |i| 1167 //The gati and karve arguments are taken absolutely
1111 ret.add(this.mutatePhrase(developedPhrase)); 1168 //For 4-->G3E1 A word with Gati 4, Karve 2, [0.125, 0.125], would be [0.33,
1112 }; 0.33]
1113 Post << "4th ret.dur: " << ret.dur << "\n"; 1169
1114 1170 wordAtGati { |argWord, argGati, argKarve|
1115 //Fill fifth and sixth cycles 1171 ^KonaWord.new(argWord.jatis, argGati, argKarve, tani)
1116 ret.add(this.randomSamaCompoundMora(cycleMatras*2, tani.gati, 1)); 1172 }
1117 1173
1118 Post << "5th 6th ret.dur: " << ret.dur << "\n"; 1174 // phraseAtGati
1119 //Gati Change 1175 // @argObj KonaTime (or word) to manipulate
1120 gatiChange = this.phraseAtGati(ret, newGati, newKarve); 1176 // @argGati New Gati
1121 gatiChangeMatras = (gatiChange.matras/newGati)*tani.gati; 1177 // @argGatiExpansion Karve multiple.
1122 Post << "newGati: " << newGati << "\n"; 1178 //
1123 1179 // Method to return a phrase at a new Gati, including double tempo etc
1124 Post << "gatiChangeMatras: " << gatiChangeMatras << "\n"; 1180 // The expansion value is relative to the input objects expansion,
1125 1181 // so that phrases maintain their relative values
1126 if(gatiChangeMatras%1!=0) { 1182
1183 1242 if(dur<=9) {
1184 phraseAtGati {|argObj, argGati, argGatiExp| 1243 if(allRest) {
1185 var temp = KonaTime.new(tani); 1244 ret.add(KonaWord.new(0, gati, dur, tani));
1186 1245 } {
1187 if(argObj.class==KonaWord) { 1246 ret.add(KonaWord.new(dur, gati, karve, tani));
1188 ^KonaWord.new(argObj.jatis, argGati, argObj.karve*argGatiExp, tani) 1247 };
1189 } { 1248
1190 argObj.do{ |item, i| 1249 dur = dur - dur;
1191 temp.add(this.phraseAtGati(item, argGati, argGatiExp)); 1250 } {
1192 } 1251 if(allRest) {
1193 ^temp; 1252 ret.add(KonaWord.new(0, gati, dur, tani));
1194 }; 1253 } {
1195 } 1254 ret.add(KonaWord.new(9, gati, karve, tani));
1196 1255 };
1197 // combine 1256 dur = dur - 9;
1198 // @aCollection A collection of KonaItems with a combined desired jati 1257 };
number 1258 }
1199 // 1259 );
1200 // Method to create a new KonaWord/KonaTime from the number of 1260 };
1201 // syllables of the given items 1261
1202 // Only used for KonaWords of the same karve 1262 if(ret.size==1) {
1203 1263 ^ret[0];
1204 combine {|aCollection| 1264 } {
1205 var dur; //Desired jatis for output 1265 ^ret;
1206 var karve; //Karve of the input (determines output Karve) 1266 };
1207 var ret; //KonaItems to return 1267 }
1208 var allRest; //Boolean; whether the collection is silent syllables 1268
1209 var oneSyl; //Boolean; if the collection is one syllable. 1269 // combineSimilar
1210 1270 // @aCol A KonaTime containing KonaWords.
1211 dur = 0; 1271 // @alMax Maximum number of items to combine
1212 ret = KonaTime.new(tani); 1272 // @avMax The maximum size for a combination
89

1213 oneSyl = false; 1273 // @prob Probability of combination


1214 allRest = aCollection.every { |item, i| item.word == ['-']}; 1274 //
1215 1275 // Method to combine identical adjacent KonaWords within a KonaTime
1216 if(aCollection.size>0) { 1276 combineSimilar {|aCol, alMax, avMax=9, aProb=1|
1217 karve = aCollection[0].karve; 1277
1218 } { 1278 var col; // Collecion to modify
1219 karve = nil; 1279 var lMax; // Maximum string length to combine
1220 }; 1280 var vMax; // Maximum value of a combination
1221 1281 var start, middle, newMiddle, end; // Temporary storage
1222 aCollection.size.do { |i| 1282 var n; // Item lookahead number
1223 dur = dur + aCollection[i].jatis; 1283 var i; // Iterator variabale
1224 if(i==0) { 1284 var y; // Next Iterator variable value
1225 if(aCollection[i].word==['Ta']) { 1285 var func; // Function to do most of the work
1226 oneSyl = true; 1286 var prob; // Probability the function will occur
1227 }; 1287
1228 } { 1288 col = aCol;
1229 if(aCollection[i].word!=['-']) { 1289 prob = aProb;
1230 oneSyl = false; 1290
1231 }; 1291 n=1;
1232 }; 1292 i = 0;
1233 1293
1234 }; 1294 // use argument length if provided
1235 1295 lMax = alMax ?? {col.size};
1236 1296 // set combo max
1237 if(oneSyl) { 1297 vMax = avMax;
1238 ret = KonaWord.new(1, gati, aCollection.matras, tani); 1298
1239 } { 1299 func = {
1240 while({dur!=0}, 1300
1241 { 1301 //Reduce n to the index of the last matching value
1302 n = n-1; 1361 if(col[i-1]!=nil) {
1303 //If this is not the first item/string to be evaluated 1362 if(col[i].word==['Ta'] && (col[i-1].word==['-']) ) {
1304 if(i>0) { 1363 func.();
1305 //Store the sub-array that proceeds the string/items 1364 } {
1306 start = KonaTime.newFrom(col[0..i-1], tani); 1365 //Extend string length
1307 1366 n = n+1;
1308 //Store the next index to evaluate. 1367 };
1309 y = start.size+1; 1368 } {
1310 } { 1369 func.();
1311 //Else, this this is the first item/string to be evaluated 1370 };
1312 //There are no values before the first item 1371 } {
1313 start = KonaTime.new(tani); 1372
1314 //Store next index to use: 1 1373 //Else combine all identical adjacent items.
1315 y = 1; 1374 func.();
1316 }; 1375 }
1317 1376 } {
1318 //The string of matching values 1377 //If there are no more trailing items, combine those stored.
1319 middle = KonaTime.newFrom(col[i..i+n], tani); 1378 func.();
1320 1379 };
1321 if(middle.size>4) { 1380 };
1322 prob=1 1381 };
1323 }; 1382
1324 1383 ^col;
1325 if(prob.coin) { 1384 }
1326 newMiddle = this.combine(middle); 1385
1327 } { 1386 // atDensity
1328 newMiddle = middle; 1387 // @item Item to alter density of
1329 }; 1388 // @density Density multiplier
1330 1389 //
1331 //If all elements have been evaluated or combined 1390 // Method to return the word at a new density (same duration, more notes).
1332 if(middle.includes(col[col.size-1]).not) { 1391 // E.g. Ta - Ka - Di - Mi - @ density 2 becomes TaKaDiMiTaKaJuNa
90

1333 //Use all elements after the middle 1392


1334 end = KonaTime.newFrom(col[i+n+1..col.size-1], tani); 1393 atDensity { |aKonaItem, density|
1335 } { 1394 var item;
1336 //Else. There are no values after the last element 1395 var newJatis;
1337 end = KonaTime.new(tani); 1396 var newKarve;
1338 1397 var newWords;
1339 }; 1398 var newPhraseFunc;
1340 1399 var ret;
1341 //Combine three sections, summing the middle items 1400
1342 col = start ++ newMiddle ++ end; 1401 item = this.fillOut(aKonaItem, true);
1343 //Reset n 1402 Post << "density: " << density << "\n";
1344 n = 1; 1403
1345 //Set the next index to start as; 1404 newPhraseFunc = {
1346 i = y; 1405 this.phraseAtGati(item, item.gati, 1/density)
1347 }; 1406 };
1348 1407
1349 1408 if(item.class==KonaWord) {
1350 //Evaluate the whole collection 1409
1351 col.size.do { 1410 newJatis = (item.jatis*density).max(1);
1352 if(col[i].class==KonaTime) { 1411 newKarve = (item.karve*(1/density)).min(item.matras);
1353 col[i] = this.combineSimilar(col[i], prob:0.85); 1412 //If the result can be a single word
1354 } { 1413 if(newJatis<=9) {
1355 1414 //If the adjustment results in a non Integer
1356 //If there are trailing elements 1415 if(newJatis%1!=0) {
1357 if(col[i+n]!=nil) { 1416 //A 1 syllable word with a matching duration is returned
1358 //If a value is followed by an identical value, 1417 ^KonaWord.new(1, item.gati, item.jatis, tani)
1359 // and current string length is within bounds; 1418 } {
1360 if( ( (col[i].val == col[i+n].val) || (col[i].word==['Ta'] && 1419 //Otherwise a new word with adjusted density is returned
col[i+n].word==['-']) ) && (n<lMax) && (col[i..i+n].jatis <= vMax)) { 1420 ^KonaWord.new(newJatis, item.gati, newKarve, tani)
1421 }; 1479 max = aKonaItem.speed/(0.5/aKonaItem.gati);
1422 } { 1480
1423 //If the results require multiple words, create them 1481 //Calculate all values between max and min.
1424 newWords = newJatis/item.jatis; 1482 val.add(max);
1425 ^KonaTime.fill(newWords, {newPhraseFunc.()}, tani) 1483 while({(max/xGati)>min}, {
1426 }; 1484 val.add(max/xGati);
1427 } { 1485 xGati = xGati*2;
1428 1486 });
1429 //If the item is a collection of words, call this method on each of 1487 val.add(min);
them 1488 val = val.asArray.reverse;
1430 ret = KonaTime.new(tani); 1489 //Convert whole numbers into Integers
1431 1490 val.size.do { |i|
1432 item.size.do { |i| 1491 if(val[i]==val[i].asInteger) {
1433 ret.add(this.atDensity(item[i], density)) 1492 val[i] = val[i].asInteger
1434 }; 1493 }
1435 1494 };
1436 ^ret 1495 //Remove multiplier of 1 if others are possible
1437 }; 1496 if(val.size>1) {val.remove(1)};
1438 } 1497 //Create weights from multiplier values.
1439 1498 // Positive multipliers are given the heaviest weight,
1440 // randomAtDensity 1499 // with greatest weight given to those
1441 // automation of the atDensity method 1500 // >=2. Multipliers below 0.5 are given the lowest weightings.
1442 // 1501 wVal = Array.newClear(val.size);
1443 // @aKonaItem Item to be manipulaed 1502 val.size.do { |i|
1444 randomAtDensity {|aKonaItem| 1503 if(val[i]<1) {
1445 var store; //Storage for invalid density multipliers 1504 wVal[i]=0.75;
1446 var min, max; //Min and Max multiplier values 1505 } {
1447 var val; //Array of multipliers from min to max 1506 wVal[i]=1
1448 var wVal; //Array of weights for multipliers; 1507 };
1449 var count; //Counter for the value of greatest reduction. 1508 if(val[i]<0.5 || (val[i]>2)) {
1450 var xGatiFunc; //Function to calculate the xGati, for gati=4 1509 wVal[i] = wVal[i] - 0.25;
91

exception. 1510 };
1451 var xGati; //Gati of object 1511 };
1452 1512
1453 store = List[]; 1513 val = val.wchoose(wVal.normalizeSum);
1454 val = List[]; 1514 //Return the altered item
1455 count = 1; 1515 ^this.atDensity(aKonaItem, val.asInteger);
1456 xGatiFunc = { 1516 }
1457 xGati = aKonaItem.gati; 1517
1458 if(xGati==4) {xGati=2}; //Exception for caturasra gati 1518 // extendJati
1459 }; 1519 // Method to extend the jati of a given Kona Word.
1460 xGatiFunc.(); 1520 // e.g. TaKaDiMi with index [1] extended by 1 becomes TaTa-Ta
1461 //Find largest numbers of jatis in the object 1521 //
1462 if(aKonaItem.class==KonaWord) { 1522 // @aKonaWord Word to manipulate
1463 min = aKonaItem.jatis; 1523 // @aIndex Index of jati to ext
1464 } { 1524 // @aExt Number of jatis to extend the given jati by
1465 min = aKonaItem.greatestJatis; 1525
1466 }; 1526 extendJati {|aKonaWord, aIndex, aExt|
1467 1527 var ret; // Variable to return output;
1468 //Calculate the smallest possible multiplier 1528 var start; // Jatis before the extended jati
1469 while({count*min>1}, { 1529 var middle; // Extended Jati
1470 count = 1; 1530 var end; // Jatis after extended jati
1471 count = count/xGati; 1531
1472 xGati = xGati*2; 1532 //If there is 1 jati, extension is impossible so return the input.
1473 }); 1533 if(aKonaWord.jatis==1) {
1474 //Reset the xGati; 1534 ^aKonaWord
1475 xGatiFunc.(); 1535 };
1476 min = count; 1536
1477 1537 //If overextending...
1478 //Calculate the greatest possible multiplier 1538 if( (aIndex+aExt+1)>aKonaWord.jatis,
1539 {^"Trying to extend tooo much..."} 1596 success[i]=false;
1540 ); 1597 }
1541 1598 };
1542 //If the first jatis is being extended, there are no prior jatis to store 1599 if(success.every { |item, i| item.not }) {
1543 if(aIndex==0) { 1600 success = aKonaItem.size.rand;
1544 start = nil; 1601 ret[success] = this.randomExtendJati(ret[success])
1545 } { 1602 };
1546 //Else use all jatis before the extended jati 1603 ^ret;
1547 start = KonaWord.new((0..aIndex-1).size, aKonaWord.gati, 1604 } {
aKonaWord.karve, aKonaWord.tani); 1605 index = (aKonaItem.jatis-1).rand;
1548 }; 1606 max = (aKonaItem.jatis-1 - index);
1549 1607 count = (1..max).choose;
1550 //Jati to extend 1608
1551 middle = KonaWord.new(1, aKonaWord.gati, 1+aExt*aKonaWord.karve, 1609 ^this.extendJati(aKonaItem, index, count);
aKonaWord.tani); 1610 };
1552 1611 }
1553 //If the extension will take up all of the word duration 1612
1554 if((aIndex+aExt)==(aKonaWord.jatis-1)) { 1613 // muteJati
1555 //Have no following jatis 1614 // Method to mute a jati of a given Kona Word.
1556 end = nil; 1615 // e.g. TaKaDiMi with index [1] muted becomes Ta-Taka
1557 } { 1616 //
1558 //Else use the jatis following the extension 1617 // @aKonaWord Word to manipulate
1559 end = KonaWord.new((aIndex+aExt+1..aKonaWord.jatis-1).size, 1618 // @aIndex Index of jati to mute
aKonaWord.gati, aKonaWord.karve, aKonaWord.tani); 1619 muteJati {|aKonaWord, aIndex|
1560 }; 1620 var start;
1561 1621 var middle;
1562 //Create a KonaTime, add the new KonaWords and return it 1622 var end;
1563 ret = KonaTime.new(tani); 1623 var ret;
1564 [start,middle,end].do { |item, i| 1624
1565 if(item!=nil, {ret.add(item)}); 1625 if(aIndex>=aKonaWord.jatis,
1566 }; 1626 {^"overstretched yourself a bit..."}
92

1567 ^ret; 1627 );


1568 1628 //If the first jatis is being extended, there are no prior jatis to store
1569 } 1629 if(aIndex==0) {
1570 1630 start = nil;
1571 // randomExtendJati 1631 } {
1572 // Automation of the extendJati Method 1632 //Else use all jatis before the extended jati
1573 // 1633 start = KonaWord.new((0..aIndex-1).size, aKonaWord.gati,
1574 // @aKonaItem Object to manipulate aKonaWord.karve, aKonaWord.tani);
1575 1634 };
1576 randomExtendJati{|aKonaItem| 1635
1577 var itemSize; 1636 //Muted Jati
1578 var index; 1637 middle = KonaWord.new(0, aKonaWord.gati, aKonaWord.karve, aKonaWord.tani);
1579 var max; 1638
1580 var count; 1639 //Following Jatis
1581 var ret; 1640 if(aIndex==(aKonaWord.jatis-1)) {
1582 var chance; 1641 end = nil;
1583 var success; 1642 } {
1584 1643 end = KonaWord.new((aIndex+1..(aKonaWord.jatis-1)).size,
1585 if(aKonaItem.class==KonaTime) { aKonaWord.gati, aKonaWord.karve, aKonaWord.tani)
1586 ret = KonaTime.newClear(aKonaItem.size, tani); 1644 };
1587 success = Array.newClear(aKonaItem.size); 1645
1588 chance = 1/aKonaItem.size; 1646 //Combine Jatis into a new KonaTime
1589 aKonaItem.size.do {|i| 1647 ret = KonaTime.new(tani);
1590 if(chance.coin) { 1648 [start,middle,end].do { |item, i|
1591 ret[i] = this.randomExtendJati(aKonaItem[i]); 1649 if(item!=nil, {ret.add(item)});
1592 chance = chance/2; 1650 };
1593 success[i]=true; 1651 ^ret;
1594 } { 1652 }
1595 ret[i] = aKonaItem[i]; 1653
1654 // randomMuteJati 1714 //Else use all jatis before the extended jati
1655 // Automation of the muteJati Method 1715 start = KonaWord.new((0..aIndex-1).size, aKonaWord.gati,
1656 // aKonaWord.karve, aKonaWord.tani);
1657 // @aKonaItem Object to manipulate 1716 };
1658 randomMuteJati {|aKonaItem| 1717
1659 var index; 1718 //Density altered jati;
1660 var ret; 1719 middle = this.atDensity(KonaWord.new(1, aKonaWord.gati, aKonaWord.karve,
1661 var iter; aKonaWord.tani), aDensity.max(1));
1662 var chance; 1720
1663 var success; 1721 //Following Jatis
1664 1722 if(aIndex==(aKonaWord.jatis-1)) {
1665 if(aKonaItem.class==KonaTime) { 1723 end = nil;
1666 ret = KonaTime.new(tani); 1724 } {
1667 success = Array.newClear(aKonaItem.size); 1725 end = KonaWord.new((aIndex+1..(aKonaWord.jatis-1)).size,
1668 chance = 1/aKonaItem.size; aKonaWord.gati, aKonaWord.karve, aKonaWord.tani)
1669 iter = aKonaItem.size-1; 1726 };
1670 aKonaItem.size.do { |i| 1727
1671 if(chance.coin) { 1728 //Combine Jatis into a new KonaTime
1672 ret.add(this.randomMuteJati(aKonaItem[iter])); 1729 ret = KonaTime.new(tani);
1673 chance = chance/5; 1730 [start,middle,end].do { |item, i|
1674 success[i] = true; 1731 if(item!=nil, {ret.add(item)});
1675 } { 1732 };
1676 ret.add(aKonaItem[iter]); 1733 ^ret;
1677 success[i] = false; 1734
1678 }; 1735 }
1679 iter = iter - 1; 1736
1680 }; 1737 // randomDensityJati
1681 if(success.every { |item, i| item.not }) { 1738 // Automation of the densityJati Method
1682 success = aKonaItem.size.rand; 1739 //
1683 ret[success] = this.randomMuteJati(ret[success]); 1740 // @aKonaItem Item to manipulate
1684 }; 1741 // @aRec Chance of recursion
93

1685 ret = ret.reverse; 1742 randomDensityJati {|aKonaItem, aRec=0.5|


1686 ^ret; 1743 var store;
1687 } { 1744 var index;
1688 index = aKonaItem.jatis.rand; 1745 var val;
1689 ^this.muteJati(aKonaItem, index); 1746 var wVal;
1690 }; 1747 var max;
1691 } 1748 var ret;
1692 1749 var chance;
1693 // densityJati 1750 var success;
1694 // Method to alter the density of a jati in a given Kona Word. 1751
1695 // e.g. Ta Ka Di Mi with index [1], density 2 becomes Ta TaKa Ta Ka 1752 if(aKonaItem.class==KonaTime) {
1696 // 1753 ret = KonaTime.new(tani);
1697 // @aKonaWord Word to manipulate 1754 success = Array.newClear(aKonaItem.size);
1698 // @aIndex Index of jati to mute 1755 chance = 1.5/aKonaItem.size;
1699 // @aDensity Density to alter by 1756
1700 densityJati {|aKonaWord, aIndex, aDensity| 1757 aKonaItem.size.do { |i|
1701 var start; 1758 if(chance.coin) {
1702 var middle; 1759 ret.add(this.randomDensityJati(aKonaItem[i], 0));
1703 var end; 1760 chance = chance/2;
1704 var ret; 1761 success[i] = true;
1705 1762 } {
1706 if(aIndex>=aKonaWord.jatis, 1763 ret.add(aKonaItem[i]);
1707 {^"overstretched yourself a bit..."} 1764 success[i] = false;
1708 ); 1765 };
1709 1766 };
1710 //If the first jatis is being altered, there are no prior jatis to store 1767
1711 if(aIndex==0) { 1768 if(success.every { |item, i| item.not }) {
1712 start = nil; 1769 success = aKonaItem.size.rand;
1713 } { 1770 ret[success] = this.randomDensityJati(ret[success], 0);
1771 }; 1830
1772 1831 if(aKonaTime.class==KonaTime) {
1773 } { 1832 phrase = aKonaTime;
1774 store = List[]; 1833 } {
1775 1834 phrase = KonaTime.newFrom([aKonaTime], tani)
1776 index = aKonaItem.jatis.rand; 1835 };
1777 1836
1778 max = aKonaItem.speed/(0.5/aKonaItem.gati); 1837 //Permutations 0 and size.factorial return the input, so they are ignored.
1779 val = (2..max); 1838 permuteNum = permutation ?? {if(phrase.size==1) {1}
1780 {(1..phrase.size.factorial-1).choose}};
1781 //Remove unacceptable densities (for this gati) 1839
1782 val.do { |item, i| 1840 ^phrase.permute(permuteNum.asInteger);
1783 if((aKonaItem.speed*(1/val[i])% 1841 }
(0.5/aKonaItem.gati)).round(0.001)!=0, 1842
1784 {store.add(i)} 1843 // partitionWord
1785 ); 1844 // Method to partition and permute a KonaWord
1786 }; 1845 // E.g. KonaWord(5,4,1) could be returned
1787 val.removeAtIndexes(store); 1846 // as KonaTime[KonaWord(2,4,1),KonaWord(3,4,1)];
1788 //If the item is not alterable 1847 //
1789 if(val.size==0) { 1848 // @aKonaWord Word to partition
1790 ^aKonaItem 1849 // @seed Optional seed value for randomness
1791 }; 1850 partitionWord {|aKonaWord, min=2, aMax, seed|
1792 //Select an expansion 1851 var partition;
1793 wVal = Array.newClear(val.size); 1852 var int;
1794 val.size.do { |i| 1853 var ret;
1795 if(val[i]>2) 1854 var max;
1796 { wVal[i] = 0.5 } 1855
1797 { wVal[i] = 1}; 1856 if(seed!=nil) {
1798 }; 1857 thisThread.randSeed=seed
1799 1858 };
1800 wVal = wVal.normalizeSum; 1859
94

1801 val = val.wchoose(wVal); 1860 int = aKonaWord.jatis;


1802 Post << "val: " << val << "\n"; 1861
1803 1862 max = aMax ?? {if(int>9) {9} {int}};
1804 1863
1805 ret = this.densityJati(aKonaItem, index, val); 1864 partition = this.randomPartition(int, min, max, true, seed);
1806 }; 1865
1807 1866 partition = this.randomPerm(partition, seed:seed);
1808 if(aRec.coin) { 1867
1809 ^this.randomDensityJati(ret, (aRec/2)); 1868 ret = this.partsToWords(partition, aKonaWord.karve, false);
1810 } { 1869
1811 ^ret 1870 ^ret
1812 }; 1871 }
1813 1872
1814 } 1873
1815 1874 // randomPartitionMutate
1816 // permutePhrase 1875 // Method to (possibly) partition a word and (definitely) mutate it
1817 // Method to return a permutation of a KonaTime phrase 1876 //
1818 // 1877 // @aKonaWord Word to part/mutate
1819 // @aKonaTime KonaTime to be permuted 1878 // @aChance Chance that partitioning will occur
1820 // @permutation Optional permutation specificiation 1879 // @seed Random Thread seed
1821 // @seed Optional seed for random selection; 1880 randomPartitionMutate {|aKonaWord, aChance=0.5, seed|
1822 permutePhrase { |aKonaTime, permutation, seed| 1881 var ret;
1823 var phrase; 1882 var chance;
1824 var partition; 1883
1825 var permuteNum; 1884 chance = aChance;
1826 1885 if(seed!=nil) {
1827 if(seed!=nil) { 1886 thisThread.randSeed=seed
1828 thisThread.randSeed=seed 1887 };
1829 }; 1888
1889 //Decision: Partition word or not 1947 case
1890 if(chance.coin) { 1948 {i==0} {densities[i] = 2}
1891 ret = this.partitionWord(aKonaWord, seed:seed); 1949 {i==(suffixTemp.size-1)} {densities[i] = [2,4].choose}
1892 1950 {true} {densities[i] = [2,4].choose}
1893 } { 1951 };
1894 ret = KonaTime.newFrom([aKonaWord], tani); 1952 };
1895 }; 1953
1896 1954
1897 1955 //Alter densitiy of items
1898 //Mutate the phrase for added interest 1956 densities.size.do { |i|
1899 ret = this.mutatePhrase(ret); 1957 //Protect against going too fast.
1900 ^ret 1958 if(suffixTemp[i].karve/densities[i] < densMax.(suffixTemp[i])) {
1901 } 1959 densities[i] = densMax.(suffixTemp[i]);
1902 1960 };
1903 // addSuffix 1961
1904 // Method to add a densly articulated suffix to the end of a phrase 1962 temp = this.atDensity(suffixTemp[i], densities[i]);
1905 // 1963 temp = this.randomMuteJati(temp);
1906 // @aPhrase Phrase to alter 1964
1907 addSuffix {|aPhrase| 1965 if(i==(suffixTemp.size-1)) {
1908 var phrase; //Phrase to be altered and returned 1966 "hi".postln;
1909 var iter; //Iterator 1967 temp = this.randomDensityJati(temp);
1910 var suffixMatras; //Number of matras in the suffix 1968 };
1911 var suffixTemp; //Temporary storage for items to be included in the 1969 phrase[iter+1+i] = temp;
suffix 1970
1912 var densMax; //The maximum possible density; 1971 };
1913 var densities; //Density multipliers for suffix parts 1972
1914 var temp; //Temporary storage for mutations. 1973 ^[phrase, iter+1];
1915 1974 }
1916 phrase = aPhrase.deepCopy; 1975
1917 densMax = {|item| item.speed/(0.5/item.gati); }; 1976 // fillOut
1918 1977 // Method to 'fill in' konaWords/Times
95

1919 if(phrase.class!=KonaTime) { 1978 // e.g. a KonaWord 1,4,3 (0.75) gets turned into 3,4,1.
1920 phrase = this.partitionWord(phrase, aMax:(phrase.matras/4)); 1979 //
1921 } { 1980 // @aKonaItem Item to be altered
1922 if(phrase.size==1) { 1981 // @aOnlyUneven Boolean, if only uneven parts should be filled in.
1923 phrase = this.partitionWord(phrase, aMax:(phrase.matras/4)); 1982 fillOut {|aKonaItem, aOnlyUneven=false|
1924 }; 1983 var ret;
1925 }; 1984 var mult;
1926 1985 var jatis;
1927 iter = phrase.size-1; 1986 var action;
1928 suffixMatras = 0; 1987 var i;
1929 1988 var temp;
1930 //Add up item matras from the end until a sufficient number is found 1989
1931 while({suffixMatras < (phrase.matras/4)}, { 1990 if(aKonaItem.class==KonaWord) {
1932 suffixMatras = suffixMatras + phrase[iter].matras; 1991 mult = aKonaItem.speed/(1/aKonaItem.gati);
1933 iter = iter - 1; 1992
1934 }); 1993 block {|break|
1935 1994 while({mult.round(0.0001 )%1!=0}, {
1936 //Store those KonaItems to be used for the suffix. 1995 mult = (mult*2);
1937 suffixTemp = phrase.select({|item, i| (iter+1..phrase.size- 1996 if (i==100) { break.value(999)};
1).includes(phrase.indexOf(item)) }); 1997 });
1938 densities = Array.newClear(suffixTemp.size); 1998 };
1939 1999
1940 //Store suitable densities 2000 if(mult.asInteger.odd && (mult!=1)) {
1941 if(suffixTemp.size==1) { 2001 action = true;
1942 densities[0] = 4 2002 } {
1943 } { 2003 if(aOnlyUneven) {
1944 2004 action = false;
1945 suffixTemp.do { |item, i| 2005 } {
1946 2006 action = true
2007 }; 2065 i = i + 1;
2008 }; 2066 });
2009 2067 //Calculate the duration of the overridden section that needs to be
2010 if(action) { recreated
2011 jatis = mult*aKonaItem.jatis; 2068 makeupMatras = sectionMatras - hitMatras;
2012 2069 //Generate makeup material.
2013 if(mult>9) { 2070 if(makeupMatras!=0) {
2014 ret = this.partsToWords(this.randomPartition(jatis, 2071
notSize:true), aKonaItem.karve/mult, false); 2072 if(phrase.size==1) {
2015 } { 2073 index = 0
2016 ret = KonaWord.new(jatis, aKonaItem.gati, 2074 } {
aKonaItem.karve/mult, tani) 2075 index = i-1;
2017 }; 2076 };
2018 2077 makeup = this.vSarvaPhrase(makeupMatras)
2019 } { 2078 };
2020 ret = aKonaItem.deepCopy; 2079 //Add and return all items
2021 }; 2080 ret = KonaTime.newFrom([hit], tani);
2022 } { 2081 if(makeup!=nil) {ret.add(makeup)};
2023 ret = KonaTime.new(tani); 2082 if(phrase.size>1) {
2024 aKonaItem.size.do { |i| 2083 ret.addAll(phrase[i..phrase.size-1]);
2025 temp = this.fillOut(aKonaItem[i], aOnlyUneven); 2084 };
2026 ret.add(temp); 2085
2027 }; 2086 ^ret;
2028 }; 2087 }
2029 ^ret 2088 }
2030 } 2089
2031
2032
2033 // makePostMora
2034 // Method to convert a phrase so that it's suitable after a mora,
2035 // i.e. that it starts with a strong long beat
96

2036 //
2037 // @aKonaItem Phrase to be altered
2038 makePostMora {|aKonaItem|
2039 var phrase; //Phrase being altered
2040 var sectionMatras; //Matras in the section being overridden
2041 var i; //Iterator
2042 var index; //Index used when calculating makeup Matras
2043 var hitMatras; //Duration of the initial beat in matras
2044 var makeupMatras; //Duration of the material being made up for
2045 var hit; //KonaWord for the initial beat
2046 var makeup; //KonaWord for the makeup
2047 var ret; //KonaTime to return the phrase
2048
2049 //If phrase is a KonaWord, convert it to a KonaTime
2050 if(aKonaItem.class==KonaTime) {
2051 phrase = aKonaItem.deepCopy;
2052 } {
2053 phrase = KonaTime.newFrom([aKonaItem], tani);
2054 };
2055
2056 sectionMatras = 0;
2057 i = 0;
2058 //Create initial hit
2059 hitMatras = aKonaItem.gati;
2060 hit = KonaWord.new(1, phrase.gati, hitMatras, tani);
2061
2062 //Count how many parts of the phrase will be overridden
2063 while({sectionMatras<hitMatras}, {
2064 sectionMatras = sectionMatras + phrase[i].matras;
1 + ArrayedCollection{
2
3 removeAtIndexes{arg indexes;
4 indexes.sort.reverse.do{arg index;
5 this.removeAt(index);
6 }
7 }
8 }

97
Appendix E

Project Log

Updated Project Log, please refer to my Interim report for prior work.

12/1/09

Re-wrote SynthDef to use PV_Playbuf for time stretching, also found very useful
DetectSilence UGen.
Solved playback from FFT analysis files.
Had to separate the file writing into a different routine from the SoundFile creating
and buffer allocation, then had to ’call’ each buffer (that had read from an FFT file)
to get it to work properly.

Changed Konakkol Class to send messages to the server via a NetAddr object instead of
creating Synth instances. This allows playback through any Synth sound, or sending
messages via MIDI by making changes to the OSCresponder. Will be fun to try the
system through drums, drumkits, beatbox instruments, melodic instruments etc...

13/1/09

Gutted Konakkol class of methods that return different speeds and Gopucca Method.
Implementing arguments when creating instances so that Konakkol class instances
have a defined form, which is returned as a Routine. This allows concatenation of
Routines.

Will implement methods to return the instance in another form so that variations
can be created. e.g. y = x.atDoubleSpeed.
Implemented Method atSpeed which returns a new Konakkol object with the same
phrase, but with a specified speed.

Realised that I don’t need a Gati argument for Konakkol class as Tisra Gati (3 per beat)
is just a speed of 1/3. But may be more intuitive to have one that just alters the speed.

14/01/09

Started writing KonaPhrase class, (re-named Konakkol class KonaWord).


Takes an indefinite number of arguments, will be KonaWords.
Will be used when a KonaWord (e.g. Ta ka di mi) is altered and requiring new syllables
(e.g. Ta - Ta Ka).
Will also be used as motivic cell.

15/01/09

98
Made KonaPhrase a subclass of List, to ease adding items and creationg. Tried Array but
had problems using instance variables.
Overwrote add method to only accept KonaWord objects
Overwrote ++ concatenation method to return a new KonaPhrase

16/01/09

Installed wslib for AutoBackup, SC Crashing at the moment.

Added dur and rout methods to KonaPhrase.


Added an at method to KonaWord for [index] access to jatis in the word

19/01/09

Added phrase method to konaphrase which returns all the words in the phrase in an array
of strings.

Read into sarvalaghu patterns with gati != chatusra (4). Wrote a method return all possible
combinations to fill a given time period with values with a minimum size of 2. E.g. input 6
returns [6, [2, 4,], [3,3], [4,2] ]

developed ideas on structure of whole program

Met with Nick Collins. Discussed structure of program


Discussed class design
Decided not to use OSC messages because of latency
should use bundles for rock solid timing
auto call init method rather than set up in new method

Task is to complete structure classes


Nick suggested using a generic ’duration of time’ class rather than specific ta etc
I feel that the naming will still be useful, especially when printing out compositions,
esp for calculations
Considering generic class with subclasses just for name.

22/01/09

Working on algorithm to return all possible combinations of groupings for a given grouping.

E.g. 5 would return [5, [3,2], [2,3]]

Hard choices about whether or not to include 1.


There are phrases that are more like 1 1 rather than 2
e.g. |na na din - | |din - jo no|
As well as phrases such as
|na tom tom ta |tom tom tom ta|

Including 1s makes the algorithm very tricky, phrases of 1 1 1 1 1 1 1 are also unlikely.

Thoughts
-Phrases could be altered later, represented as 2, but sound like 1 1
-Or Altered to be 1s, will have to change the sounds anyway.

23/01/09

99
Continuing work on partition algorithm. Tried implementing zs1 algorithm, works in C but not
sc....

Going back to own method of diving into parts of two.


Almost there, however, returning an array with all answers + an element with all answers

24/01/09

Successfully Implemented ZS1 algorithm, much faster. However with larger numbers it still
runs noticeably slower in SC than C.
Not completely sure how it works, makes modification difficult. Instead of only generating
partitions with certain values (between 2 and 9)
-I am simply removing them afterwards
-Also generates all permutations of partitions.

27/01/09

Decided not to have a distinct tala class, but to have a time period class which can return
duration
in beats and talas.
KonaTime takes the tala as an argument, a literal array of the beats; Adi Tala #[4,2,2]

Considered using KonaTime instead of KonaPhrase, but decided that KonaPhrase is not a time
duration class, it is a musical block class with musical permutations- simply a class for
concats of KonaWords

30/01/09

Started KonaTani class.


Has following variables
var <laya; // Tempo
var <tala; // Beats in cycle
var <gati; // ’Default’ sub-divisions per beats
var <otherGatis; // Sub-divisions to change to
var <eduppu; // Starting/strong beat
var <gen; // Material generator

var <duration; // Duration in minutes


var <totalTalas; // Total number of cycles

A rough duration can be passed in by the user, a more exact duration is calculated by
fitting maximum number of talas into the given duration, and multiplying them by the
duration of each tala.

02/02/09

Upgraded KonaTime class to replace KonaPhrase;

Moved synth generation from an OSC responder to the KonaWord class.


Would still like to be able to set up generic output, but maybe just have Konakol synth,
kanjira synth, and MIDI out.
Tried to have synth buffers etc as classvars set up with InitClass, but couldn’t
get it to work,had to use instance variables, not optimal.

Analysing Trichy Solo from Nelson DVDs.

100
03/02/09

Coding re-think.

Moving all alteration methods (e.g. atDensity etc) from KonaWord to KonaTime to
avoid duplication, allows manipulation of KonaTime objects rather than just words,
or call downs.

Adapting toGati method (change a word/time to a new gati) proved troublesome.


No problem for a single KonaWord, but a KonaTime provided a new problem. How to
generate phrases in the new gati with the same relative values. e.g. 0.25, 0.25,
0.125, 0.125 in triplets should be 0.33, 0.33, 0.166, 0.166
Changed KonaWord from having Gati of any value to being limited to 4,3,5,7,9,
but then using expansions (multipliers); E.g. 0.125 is gati 4, expansion 2

Added a postWord method to KonaWord which prints in the following format


[ Ta, Ka, Di, Mi ]
[ 0.33, 0.33, 0.33, 0.33 ]
[ [ 1, 12 ], [ 1, 12 ], [ 1, 12 ], [ 1, 12 ] ]

04/02/09

New priority: Get a working version, then improve it rather than going for gold

Reading material for Sarvalaghu Generation.


Hulzen and Prakash for non-Adi Tala material + adapting
Nelson + Transcriptions for Adi-Tala

Will have to adjust playback method. a word could be all rests, or all resonant.
e.g. ta-ka played rest rest, or ta din

Page 7 of Analysis 3, shows that Mora design is open for development....

05/02/09

Completed basic analysis of last of 5 solos.


Beginning Vilamba Sarvalaghu generation..

Looking at the 5 solos I have, it is clear that approaches vary but there are
some things in common.

Some solos (mani, raghu) have very obvious grooves/motifs etc from the start,
while others (sankaran, murthy) play more generic grooves for the tala,
there is repetition of ideas, but it’s less straightforward.

Some solos have constant phrase durations (sankaran)

Thoughts:

Micro level
they are all very similar : focus on 2 pulses per beat.
Macro level,
they always feature some small variations
suffixes are common

Had to fix problems with accessing routines from KonaWord and KonaTime.

101
Was overriding getter methods using the variable name within the method
e.g. getter rout { rout = 4+5, ^rout} was messing things up, didn’t declare
new variables. Testing statistical generation of Vilamba Sarvalaghu,
beats 1-4 of adi tala (2 kalai, so 8 beats) Data used :
Adi Tala 2 kallai, first 4 beats, each set of 4 represents 1 beat
y = [
100, 37.5, 87.5, 68.75,
93.75, 12.5, 100, 25,

100, 80, 100, 13,


100, 13, 100, 6,

100, 0, 73, 53,


100, 0, 100, 22,

89, 66, 100, 22,


100, 30, 80, 30
];

07/02/09

Read Sangeetha Akshara Hridaya, replaced gatiexpansion in KonaWord with karve,


which defines how many gati a jati is worth.

Transcribed grooves from Ultimate Guru DVD for examples of different Gatis,
and non-adi talas
Problems...
Only tisra gati example is played in groupings of two ([1,2],[3,1],[2,3],[1,2],[3,1],[2,3])
This is fine, and shows variety, but no example of 123 123 123 123

Considering just working with tanis that start in chatusra, can’t find
many/any examples of those that don’t.
Possibly limit to adi tala, would make life easier.

08/02/09

Big problems....
Generating 6+ KonaWords seemed to crash SCLang
Often get grey count errors

sometimes will generate but word will be


3.6351256066833e-273
or similar.
Once this happens, it happens to all new instances.

Trying to play a KonaTime routine would only play once.

09/02/09
Solved problem, was because KonaWord had [slot], thanks Jordanous for
pointing out I was doing something clever without realising it

Finally get to properly test Trichy Sankaran statistical model.


Results are ok, it feels that context wasn’t properly taken into account.’
These results might be suitable for mid/late Vilamba, but not introduction,
as they are quite busy although, some people do start this busy,
while others are much more sparse

102
The flaw of repeated generation for many cycles is that there is little
underlying theme, just statistical matching.
Going to try an approach of starting with a basic pattern and then mutating it.

12/02/09

Continuing work on Vilamba Sarvalaghu, alternating with work on moras.

Tried phrase length generation on a tala of 12 beats, gati 4, tempo 120, (partition 40)
partitioning crashed SC...
Trying to implement ZS2 Algorithm in the hope that it will be faster.
Successfully implemented ZS2. Made modifications to allow maximum and minimum
values to be set.

Now working on Moras

Improved random Mora method.


As I am unable to find instances where a gap duration is a fractional value of
the statement (e.g. s = 5, g = 3.5), i.e they are generally made up of different
numbers of jatis of the same duration. A .floor method is used to get a round
number for the gap duration, and an offset that precedes the mora is generated
if there are unused beats from the given duration. Mora generation now takes
into account Nelsons (2008 p 23) observation that if a mora statement is
shorter than 5 pulses the gap will nearly always be at least 2 pulses

13/02/09

Resuming work on VSL. Now testing ZS2 for generation of partitions.


Turns out that it’s not the ZS algorithms running slowly in SC. It’s the time needed
to add the results to the lists.
Maybe calculating P(n) (number of partitions) and creating an array of that size rather
than using a List would be more efficient.
Turns out it’s NOT adding it to the list, but the permutations that takes ages.
Changed the way minimum values were taken care of. Instead of using two loops, items
are only added if all parts are > min
Divided allParts into two methods, allParts and allPerms. allPerms takes care of
permutations.

Worked on getting playback functional again. Re-recorded syllables, added more to


the vocab and re-did scpv analysis.

16/02/09

PV Analysis problem solved, separated various actions into different loops and gave
enough time to analysis synth. Now need to incorporate time stretching.
Time stretching achieved using 3.min(1/speed) for the rate

VSL.
One problem with current phrase length generation is that it cuts at absolute
values, e.g. 119 bpm gati 4, gives 16 jati phrase while 120 bpm gives 32 jati phrase,
maybe some kind of blend would be better....

18/02/09

103
migrated remaining manipulation methods from KonaWord to KonaGenerator
Adapted atDensity method to work for KonaTime and KonaWord

19/02/09

Wrote combine method which creates new KonaItems with the number of jatis of a
given collection (e.g. ta ki ta + ta ka) returns da di gi na dom)
Worked on algorithm to search for adjacent identical values in an array and combine them
(e.g. [2,2,2,3,3] becomes [6,6])
This will be used stochastically for sarvalaghu generation

27/02/09

Included combine method in SarvaPhrase generation


Updated postWord methods to print evenly e.g
[ Ta , Ka ]
[ 0.5 , 0.5 ]
[ [ 1, 8 ], [ 1, 8 ] ]

28/02/09

Working on vilamba sl...


Implemented new method removeThoseContaining that removes any partitions that contain
a given value/set of values. Weights can be supplied for the values.

Had a bug with combination method, if all elements were combined earlier than
(1 before the end) then extra items appeared, Fixed now

01/03/09

Fixed .play methods on KonaTime and KonaWord


Added play to KonaTani
Created a Tala clapping routine usng Thor’s clapping synthdef.
Problems with trying to play Tala + Tani routine’s in sync

02/03/09
Working on manipulation methods.
Fixed Density method, wasn’t functioning properly
Working on extend jati method, to extend a particular jati in a word e.g. takadimi with
[1] extended becomes ta ta - ta
Need to have an exception for this example so that it becomes ta lan - ga
Extend Jati method complete

Working on Mute jati method


Completed mute jati method

Fixed bug in vSarvaPhrase method where 10% of the time it would bugger up.

Quickly implemented densityJati method to alter the density of a jati within a KonaWord

Working on a phraseMutation method that works through the elements of a given phrase and
potentially mutates them using the recently made methods.

04/03/09

Fixed routing issue thanks to nick.

104
Interesting problem encountered when working on automation of atDensity method.
Difficult to determine what the maximum speed should be.
Carnatic music talks of having 4 speeds (prakash), but obviously this is dependant
on tempo. E.g. @ 160 bpm it’s hard to play at 4th speed
This is also dependant on the player.
Human haptic rates can be used, but alternative techniques (chunking) can be
used to bypass these.
Current formula is speed/(0.5/col[i].gati). E.g. a 4,4,1 KonaWord
(Ta Ka Di Mi) can go up to 4,4,0.5. This seems to work reasonably well, although
creates discrepencies. E.g. At the same tempo 9 can go up to 0.055555555555556
while 4 can go to 0.125

05/03/09

Fixed all mutation methods to work with mutatePhrase automation


Could add recursion.. need to test on materials to judge output

06/03/09

Added a permutePhrase method which can return either a specified or random


permuation of a KonaTime

Working on randomMora method, updating to handle KonaItems.


Solving the problem of minimum gap sizes.
Looking for maximum gap sizes.
Largest in a single mora is 4.
Found a 6 in a compound mora with statements of 22
Found a 8 with statements of 16. But an Arudi rather than mora.
Nelson gives examples (not quotations) with long gap durations
Might not give an upper boundary

Mora Gap minimum is always 0 except in cases where statement<5


However, a gap of 1 is rare/not found.
One example found in mani solo, but it’s a gap of 1 caturasra gati, and the statement is
exclusively 1/2 or 1/4 chatusra gatis So relatively it is 2.

Going to rule out gap of 1


In the instance that the statement has density doubled, the gap could technically be 1
e.g Ta Ka Di Mi Ta Ka Ju Na (0.125) Ta (0.25)
Going to accept that this will be missed out on (ish)
Will include a % chance to recalculate Mora with 2*duration 0.5*gati

Moras generated that are just 3 * konaword == DULL


Need to make mutation 100% for them...
Same for moras that have same statement and gap length
e.g. ta ta ta ta ta all 0.5

10/03/09

Fixing bugs in randomMora method.


Splitting into sub-methods, moraStatement etc etc
Might be able to make one moraMaterial method with probabilities passed in...
Split Mora generation into sub methods
Also split mutatePhrase methods into sub-methods, each acting as an automated version of

105
their corresponding methods.

16/04/09

Wrote moraFrom method, builds moras from a given statement, optionally give max duration,
gap, offset etc

10/04/09
Added accents to KonaWord + KonaTime
KonaWord given .matras (jatis*karve);
KonaTime given .greatestJatis method, returns the item with the greatest number of jatis
(recursive for KonaTimes)
Added speed and gati methods to KonaTime for KonaGenerator compatibility.
KonaGenerator.atDensity newKarve now given .min(aKonaItem.matras) to size increase;
KonaGenerator.randomAtDensity can now handle KonaWords; for minimum size uses .jatis
for KonaWords and .greatestJatis for KonaTimes.
Also a big change to the way possible values are calculated. Gone is the complicated
method, now the max and min are calculated and all possible values calculated from them,
using multiples of the gati.

10/04/09
Fixed routines in KonaTani, now can use .add, .play, and .stop. Resets correctly

10/04/09
Changes to randomExtendJati. Now supports KonaTimes. Loops through objects with a
1/size chance of randomly extending their jati, chance is halved if successful. Returned
in a KonaTime.
Changes to randomMuteJati. Now supports KonaTime. Same as randomextendjati. half the
chance though.
Same deal with randomDensityJati. Except that recursion has been added, but not for
KonaTime items.

11/04/09

Improved weights in mora statement generation.


Split vSarvaPhrase into vSarvaPhraseAuto, which calls vSarvaPhraseLength. Now vSarvaPhrase
can be called with a manual phrase Dur.
Re-written moraOffset.
Now if dur > 2*gati, uses vSarvaPhrase, if >1*gati uses 1 syllable word. Otherwise same.
Added word to KonaWord.val, to distinguish ta 0.25 and - 0.25
Changed combine to handle combinations of rests (used to turn into articulated syllables)
and one syllable + rests.

12/04/09
RandomMora: StateMin is now (1/5) of duration is there is a gap, and 1/2.85 if there isn’t.
RandomPerm: Now simply chooses a number between 0 and partition.size.factorial and
returns that permutation.
allPartitions:
Now reads from stored files for numbers > 40.
Also includes an option for max no. unique parts. More efficient than removeGreaterThan,
but won’t work for numbers > 40. \textsc{So} removeGreaterThan is kept.
randomMora: Efficiency issues now sorted :D
Created moraFrom method. Takes a statement + optional duration, gap, offset.
Fixing partitionWord, use of jatis*karve back to just jatis.
Fixed removeThoseContaining, removed possibility of returning an empty array (all items
succesfully removed).

106
randomMora now split into randomMoraValues method for calculating values.

17/04/09

Fixes to morastatement, wasn’t mutating for instances < 9.


fixes to samaCompound mora method, removing nils passed to morapart methods.
Changing moraStatement, will never be just one syllable.
Fixed bugs with randomSamaCompoundMora. Incorrect calculation of offset. Now working for
large values, proceeding with testing
of lower values where density alteration takes place.
randomMoraValues alteration: density alteration won’t occur if karve will drop below 0.5
randomMora and randomMoraValues now have boolean gap and offset args.
Changed mora methods (moraOffset, moraGap, moraStatement) to take duration in matras
rather than number of jatis.
Fixed bug in randomSamaCompoundMora with density alterations: added a check to
vSarvaPhrase,
if a float is passed in, the .floor
is created, and a single Ta with the remainder added.
Wrote addSuffix method. Given a phrase it will return a new phrase with the last
quarter into a
suffix by increasing the density.
Added karve argument to partsToWords.
Fixed bug with partsToWords not taking karve into account.
Fixed bug with addSuffix not working with konaWords properly.
Wrote and bug fixed fillOut method. Will ’fill out’ uneven words for density alteration,
e.g. Ta 0.75 becomes ta ki ta 0.25
Wrote makePostMora. Adds a 1 beat hit to the beginning of a phrase, for phrases
preceded by a mora
randomMuteJati made to work in reverse, so that first elements less likely to be muted
reverse method overridden in KonaTime
vSarvaPhrase max reduced to gati, including randomMuteJati
Transcribed some basic phrases
Worked on section generation, with basic structure.
Fixed bug in randomSamaCompoundMora, wrong karves being used.
Written basicStructure. a mini tani, heh.
Guarantees in automated methods (randomAtDensity etc) that if no elements are altered,
one will be.
Fixed rounding error bug in fillOut
Discovered how to loop material infinitely, accompaniment style.
Transcribed skeleton phrases from real sources

20/04/09

Changed KonaTani:
No longer takes a duration.
Now takes Tala as an array of strings e.g. ["I4", "O", "O"]
Recorded a few examples into Logic via Jack + MIDI
Changed KonaTani talas. "U" can now be "U1" for a quaver clap
added "W" and "R" for wave and rest respectively.

21/04/09

Created computer examples with first runs of necessary methods and transcribed human
examples. Played all as MIDI into Logic.

107

You might also like