Pelog Musical Constraint System

268
1

description

pelog. A music application to study music counterpoint. Music programming for selfstudy.

Transcript of Pelog Musical Constraint System

1

Pelog: A Musical Constraint System

Michael DroettboomCOSC4080 Independent Study Project

Advisor: Dr. Peter Roosen-Runge

November 30, 1999

Contents

Introduction ii0.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ii0.2 Purpose . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . iii0.3 Guide to this document . . . . . . . . . . . . . . . . . . . . . . . . . iii0.4 Comparisons . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . iv

0.4.1 Musical languages . . . . . . . . . . . . . . . . . . . . . . . . iv0.4.2 Automatic composition . . . . . . . . . . . . . . . . . . . . . iv

0.5 Future Directions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . v0.5.1 Pelog . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . v0.5.2 Visual Pelog . . . . . . . . . . . . . . . . . . . . . . . . . . . v

I Pelog 1

1 The Pelog language 21.1 What is a rule set? . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21.2 Anatomy of a rule . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21.3 How rules are applied to the score . . . . . . . . . . . . . . . . . . . 41.4 Rule ordering for efficiency . . . . . . . . . . . . . . . . . . . . . . . 5

1.4.1 Put the rule class with the fewest branches first . . . . . . . . 51.4.2 When the given class and weighting system doesn’t apply, do

it yourself . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61.5 Pelog library reference . . . . . . . . . . . . . . . . . . . . . . . . . . 8

1.5.1 Comments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81.5.2 Event . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91.5.3 Global . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101.5.4 Interval . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101.5.5 Parts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121.5.6 Pitch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131.5.7 Range . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141.5.8 Scale . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15

2 Modal Counterpoint 202.1 Sources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202.2 The rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22

i

CONTENTS ii

2.2.1 Species rules . . . . . . . . . . . . . . . . . . . . . . . . . . . 222.2.2 Static rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . 232.2.3 Horizontal rules . . . . . . . . . . . . . . . . . . . . . . . . . . 24

2.3 Vertical rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262.3.1 Horizontal / Vertical rules . . . . . . . . . . . . . . . . . . . . 262.3.2 Extensions of Modal Counterpoint . . . . . . . . . . . . . . . 28

2.4 Implementation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 282.4.1 modal counterpoint.pl . . . . . . . . . . . . . . . . . . . . . . 28

3 GUIDO music notation format 353.1 Scores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 363.2 Parts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 363.3 Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 363.4 Notename . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 363.5 Accidentals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 363.6 Octave . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 373.7 Duration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 373.8 Tags . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37

3.8.1 Key . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 373.8.2 Scale . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 383.8.3 Range . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 393.8.4 Meter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 393.8.5 Accent pattern . . . . . . . . . . . . . . . . . . . . . . . . . . 393.8.6 Comment style . . . . . . . . . . . . . . . . . . . . . . . . . . 39

4 Tools 414.1 Selecting the tools . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41

4.1.1 Prolog interpreter . . . . . . . . . . . . . . . . . . . . . . . . 414.1.2 GUI development system . . . . . . . . . . . . . . . . . . . . 424.1.3 Connecting the two . . . . . . . . . . . . . . . . . . . . . . . 43

4.2 Reflections after-the-fact . . . . . . . . . . . . . . . . . . . . . . . . 444.2.1 SWI-Prolog . . . . . . . . . . . . . . . . . . . . . . . . . . . . 444.2.2 Tcl/Tk . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44

5 Data Structure 455.1 Design notes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 455.2 A worked example . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46

5.2.1 Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 485.2.2 Part . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 485.2.3 Pitch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 485.2.4 Duration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 495.2.5 Time . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 515.2.6 Previous and Next . . . . . . . . . . . . . . . . . . . . . . . . 515.2.7 Vertical . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 515.2.8 Comments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53

CONTENTS iii

5.2.9 Penalty . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 545.2.10 Other . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54

6 Code and Testing 556.1 The Pelog-GUI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55

6.1.1 pelog-gui.tcl . . . . . . . . . . . . . . . . . . . . . . . . . . . . 556.2 The Core Interpreter . . . . . . . . . . . . . . . . . . . . . . . . . . . 67

6.2.1 pelog.pl . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 676.2.2 main.pl . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 706.2.3 bi-math.pl . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 706.2.4 preprocessor.pl . . . . . . . . . . . . . . . . . . . . . . . . . . 746.2.5 rule-def.pl . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 806.2.6 score.pl . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 826.2.7 trees.pl . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84

6.3 The GUIDO parser/grammar . . . . . . . . . . . . . . . . . . . . . . 846.3.1 parser.pl . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 846.3.2 lexer.pl . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 896.3.3 grammar.pl . . . . . . . . . . . . . . . . . . . . . . . . . . . . 916.3.4 Testing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93

6.4 The Pelog library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1016.4.1 main.pl . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1016.4.2 comments.pl . . . . . . . . . . . . . . . . . . . . . . . . . . . 1026.4.3 event.pl . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1056.4.4 global.pl . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1086.4.5 interval.pl . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1106.4.6 parts.pl . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1186.4.7 pitch.pl . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1206.4.8 range.pl . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1316.4.9 scale.pl . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135

II Visual Pelog 150

7 Motivations for a visual language 1517.1 Summary of core Pelog system . . . . . . . . . . . . . . . . . . . . . 1517.2 The next step . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1517.3 The problem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1527.4 The solution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153

8 The Visual Pelog language 1548.1 Musical Constraint Graphs . . . . . . . . . . . . . . . . . . . . . . . 1548.2 Constraint primitives . . . . . . . . . . . . . . . . . . . . . . . . . . . 1568.3 Some examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157

8.3.1 Step-wise motion . . . . . . . . . . . . . . . . . . . . . . . . . 1578.3.2 Step-wise or third-wise motion . . . . . . . . . . . . . . . . . 1578.3.3 Avoiding parallel intervals . . . . . . . . . . . . . . . . . . . . 159

CONTENTS iv

8.4 Future extensions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159

9 The Visual Pelog environment 1609.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1609.2 A Visual Pelog session . . . . . . . . . . . . . . . . . . . . . . . . . . 1609.3 Opening and saving rule sets . . . . . . . . . . . . . . . . . . . . . . 1629.4 Rule manager . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162

9.4.1 Selecting rules . . . . . . . . . . . . . . . . . . . . . . . . . . 1629.4.2 Adding rules . . . . . . . . . . . . . . . . . . . . . . . . . . . 1629.4.3 Moving rules . . . . . . . . . . . . . . . . . . . . . . . . . . . 1629.4.4 Deleting rules . . . . . . . . . . . . . . . . . . . . . . . . . . . 1629.4.5 Editing rules . . . . . . . . . . . . . . . . . . . . . . . . . . . 162

9.5 Rule editor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1629.5.1 Graph editor . . . . . . . . . . . . . . . . . . . . . . . . . . . 1639.5.2 Using the musical keyboard . . . . . . . . . . . . . . . . . . . 164

9.6 Tool palette . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165

10 Graph Layout Algorithm 16610.1 Specification of problem . . . . . . . . . . . . . . . . . . . . . . . . . 16610.2 Background . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167

10.2.1 Sugiyama algorithm . . . . . . . . . . . . . . . . . . . . . . . 16710.2.2 Constraint-based extensions to the Sugiyama algorithm . . . 16810.2.3 The problem of graph stability . . . . . . . . . . . . . . . . . 16810.2.4 The problem of two-dimensionality . . . . . . . . . . . . . . . 168

10.3 GLA Implementation . . . . . . . . . . . . . . . . . . . . . . . . . . . 16910.3.1 General design . . . . . . . . . . . . . . . . . . . . . . . . . . 16910.3.2 The top-level . . . . . . . . . . . . . . . . . . . . . . . . . . . 16910.3.3 The near constraint . . . . . . . . . . . . . . . . . . . . . . . 16910.3.4 Constraint-based topological sort . . . . . . . . . . . . . . . . 16910.3.5 Conflict resolution . . . . . . . . . . . . . . . . . . . . . . . . 17010.3.6 Mapping physical coordinates to logical coordinates . . . . . 17010.3.7 Animation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17010.3.8 Creating nodes . . . . . . . . . . . . . . . . . . . . . . . . . . 170

10.4 Code related to the graph layout algorithm . . . . . . . . . . . . . . 17110.4.1 RuleEditor.py . . . . . . . . . . . . . . . . . . . . . . . . . . . 17110.4.2 Nodes.py . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17810.4.3 CanvasItems.py . . . . . . . . . . . . . . . . . . . . . . . . . . 187

11 Custom Megawidgets 19211.1 Tree Widget . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193

11.1.1 End user usage . . . . . . . . . . . . . . . . . . . . . . . . . . 19311.1.2 Developer usage . . . . . . . . . . . . . . . . . . . . . . . . . 19411.1.3 Tree.py . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194

11.2 Help Browser Widget . . . . . . . . . . . . . . . . . . . . . . . . . . . 20311.2.1 End user usage . . . . . . . . . . . . . . . . . . . . . . . . . . 203

CONTENTS v

11.2.2 Developer usage . . . . . . . . . . . . . . . . . . . . . . . . . 20311.2.3 Help.py . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204

11.3 On-screen musical keyboard Widget . . . . . . . . . . . . . . . . . . 20911.3.1 End user usage . . . . . . . . . . . . . . . . . . . . . . . . . . 20911.3.2 Developer usage . . . . . . . . . . . . . . . . . . . . . . . . . 21011.3.3 Future plans . . . . . . . . . . . . . . . . . . . . . . . . . . . 21111.3.4 MusicWidgets.py . . . . . . . . . . . . . . . . . . . . . . . . . 211

12 Implementation of other components 22012.1 Tool palette . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 220

12.1.1 Palette.py . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22012.1.2 Tools.py . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22312.1.3 IntervalTool.py . . . . . . . . . . . . . . . . . . . . . . . . . . 229

12.2 Constants and Utility functions . . . . . . . . . . . . . . . . . . . . . 23012.2.1 Constants.py . . . . . . . . . . . . . . . . . . . . . . . . . . . 23012.2.2 Util.py . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 231

III Appendices 233

A Tcl/Tk-Prolog Connector System 234A.1 The problem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 234A.2 C-language connector method . . . . . . . . . . . . . . . . . . . . . . 234

A.2.1 Tcl/Tk-Prolog Connection . . . . . . . . . . . . . . . . . . . . 235A.3 Piping method . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 236

A.3.1 Interaction Model . . . . . . . . . . . . . . . . . . . . . . . . 236A.3.2 Design . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 236A.3.3 Usage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 236A.3.4 Implementation . . . . . . . . . . . . . . . . . . . . . . . . . . 236A.3.5 pl interface.tcl . . . . . . . . . . . . . . . . . . . . . . . . . . 239A.3.6 tcl interface.pl . . . . . . . . . . . . . . . . . . . . . . . . . . 241

B The graphical user interface 244B.1 Installing the GUI . . . . . . . . . . . . . . . . . . . . . . . . . . . . 244B.2 Running the GUI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 245B.3 A quick introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . 245B.4 Visual elements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 248

B.4.1 The main window . . . . . . . . . . . . . . . . . . . . . . . . 248B.4.2 The menubar . . . . . . . . . . . . . . . . . . . . . . . . . . . 248B.4.3 The toolbar . . . . . . . . . . . . . . . . . . . . . . . . . . . . 248B.4.4 The editor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 249

B.5 Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 249B.5.1 Basic file and editing functions . . . . . . . . . . . . . . . . . 249B.5.2 Look . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 249B.5.3 Hear . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 249B.5.4 Go . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 250

CONTENTS vi

B.6 Notes about portability . . . . . . . . . . . . . . . . . . . . . . . . . 251

Introduction

There once was a brainy baboonWho always breathed down a bassoon,

For he said, “It appearsThat in billions of years

I shall certainly hit on a tune.”Ezra Pound (1885-1972)

How can we make our modern day “brainy baboon” (i.e. a computer) “hit on atune” any faster? We certainly don’t have “billions of years” to wait. The answerlies in constraining the number of possibilities. Certainly, this is what Western ArtMusic has done all along. Would Renaissance music have been the same if thechurch had not imposed strong restrictions1 on musical language? Many believethat Mozart’s genius lies not in his emotive ability, but in how he worked within therigid musical confines of his day. Even the so-called Romantic composers expressedthemselves within a rigid tonality. Despite recent years of liberalism, musical con-straints remain alive and well. Just consider the serialist and minimalist movements.The purpose of this project is to help determine exactly what makes up these vari-ous musical frameworks. In other words, what restrictions do we need to place onthe “brainy baboon” in order to arrive at the elusive tune?

0.1 Overview

The Pelog system provides an intuitive language in which to specify musical con-straints. These constraints are then “applied” by the Pelog interpreter to generateor evaluate musical scores.

The musical constraints are written in a superset of Prolog known as the Peloglanguage (see 1). Since the constraints themselves are separate from the core sys-tem, it is possible for the end user to modify or create constraints with minimaleffort. The advantage of using Prolog as the base language is that Pelog applicationsare highly declarative and accessible to the novice programmer with a musical back-ground. Just like Prolog, the complexities of solution searching and backtrackingare hidden from the programmer.

Sets of constraints can be written to represent any rule-based musical system.For example, the first set of constraints developed in Pelog is for Modal Counterpoint[20]. Future candidates include Tonal Harmonic Counterpoint and Schonberg-style

1often at the penalty of death

vii

INTRODUCTION viii

Twelve-Tone Serial Composition [26]. It is also possible to implement entirely newsystems of musical constraints.

The original textual language for musical constraints has been extended to aneditable visual representation, Visual Pelog (see part II). The Visual Pelog systemallows the user to specify musical constraints as graphs of unary and binary rela-tionships between musical events. For some users, this visual representation, withimmediate feedback about logical errors and an interactive help system, may bemore intuitive than using the text-based language.

Musical phrases are input in a musical notation language called GUIDO [15].This language has been extended to allow certain events to be variable. Thesevariable events are “filled-in” by the Pelog interpreter.

0.2 Purpose

Pelog serves a two-tiered purpose:

• Using pre-built add-ins known as Pelog rule sets, musicians can use Pelog asa counterpoint generation and evaluation system.

• For the novice programmer with a musicological bent, Pelog is a musicalconstraint specification language that can be used to test the validity of agiven musical framework or develop entirely new musical relationships. VisualPelog extends this purpose by increasing the accessibility of the language

Pelog does not pretend to produce beautiful music. At this stage, it is perceived as atest-bed for research into musical systems. Often the logic used to describe musicalconstraints is very “fuzzy” leaving a lot of room for individual interpretation. Oneonly needs to look at Gradus ad Parnassum [11] or any undergraduate counterpointclassroom for an example of this. Translating these constraints for use by a computerforces one to be meticulously precise. This exercise alone can be very illuminating.Having a computer apply these rules to musical phrases reveals the weaknesses ofa given musical constraint system in a very automatic and efficient way. Pelog cantherefore assist is asking questions such as “How precise were Fux’s definitions ofmodal counterpoint? If imprecise, what additional information is needed to matchhis intent?”

0.3 Guide to this document

This document is divided into two main parts:

1. Pelog: The core Pelog language and musical constraint interpreter. (page 2)

2. Visual Pelog: The Visual Pelog extensions to the language. (page 151)

Each part is broken down into chapters for end users of the system, followed bychapters dealing with the implementation of the system.

INTRODUCTION ix

The appendices contain reports on research conducted that proved to be obsoleteto the project as a whole.

For a general overview of the project, I suggest reading this introduction andthe first chapter of each part.

0.4 Comparisons

This section is intended to shed some light on where Pelog fits within the field ofComputer Music. It is by no means as an exhaustive survey of Computer Musictools.

0.4.1 Musical languages

Some of the more common music-specific languages are Common Music [36], KeyKit[38], CSound [40] and the commercial Max language [2]. Common Music is essen-tially Common Lisp Object System (CLOS) with a number of musical extensions.KeyKit receives its lineage from awk. CSound is the latest in a series of musicalgeneration languages based on Music V. Max is both a language and visual pro-gramming environment. The programmer can set up musical generators as unitsconnected by “wires.” What sets Pelog apart from all of these languages is itslogical semantics. It builds on the strength of Prolog by allowing the program-mer to specify “what” the output should look like rather than “how” to get there.While the application domains of these other languages is perhaps larger than thatof Pelog, Pelog takes a more natural approach to musical generation that is likelymore familiar to non-programmers.

0.4.2 Automatic composition

Automatic Counterpoint [33] appears to do one thing very well, and has in factproved to be a very valuable starting point for Pelog’s Modal Counterpoint applica-tion. Pelog’s advantage however2, is in the declarative nature and maintainability ofthe musical constraints themselves. While Schottsteadt’s work seems to be firmlygrounded in modal counterpoint, Pelog can be extended to any musical systemimaginable.

Perhaps the most popular work in automatic composition is David Cope’s Ex-periments in Musical Intelligence (EMI) [6]. His work began in the same domainas Pelog: musical constraints. This approach was quickly abandoned for one in-volving recombination of musical phrases from composers’ bodies of work. WhileCope’s work was remarkably effective at generating enjoyable and original musicin the styles of various composers, it lacks the pure musicological focus of Pelog.The research domain of Pelog is less interested in generating interesting music thantesting the effectiveness of given sets of musical constraints.

Cope’s work does, however, illustrate a fundamental weakness of the Pelog sys-tem. No composer exists in a vacuum, and therefore it is impossible to believe

2This is postulation, as Schottsteadt’s source code is not readily available

INTRODUCTION x

that effective music could be generated using constraints exclusively. (Composerand Professor James Tenney, with whom I have studied, always asserts that a goodcomposer must also be an avid listener.) Perhaps the ideal system, then, would bea combination of EMI and Pelog: a system that has both constraints and a historyof external musical experience. (Give our “brainy baboon” a collection of BachChorale recordings and he might stand a better chance.)

0.5 Future Directions

0.5.1 Pelog

Pelog is still very much a ninety-pound weakling, and there’s lots more to do.Following are some future projects I am currently considering, in approximate orderof priority.

1. Re-write the core algorithm

The rule application mechanism as it currently stands is extremelyinefficient, almost to the point of uselessness. A complete re-writeof the main rule application mechanism to take advantage of theconstraint proving theorems presented in Constraint Satisfaction inLogic Programming [39] is in order. These theorems could decreasethe time complexity by a factor of up to 10 times.

2. Improve and expand library functions

There is almost an infinite variety of library functions that wouldbe useful to rule programmers in various domains. These mightinclude texture, rhythmic accent patterns, contextualism or paral-lelism. A deeper examination of other musical languages may revealthe kinds of high-level information often deemed necessary by Pelogprogrammers.

3. Implement more rule sets

As already mentioned, there are many more musical constraint sys-tems than just modal counterpoint. Future applications could in-clude tonal counterpoint or serial composition.

0.5.2 Visual Pelog

The Visual Pelog system currently exists only as a user-interface prototype. Mostimportantly, the connection between Visual Pelog and the core Pelog system needsto be completed. Beyond the obvious to-do list, there are some other importantdirections the system could take:

1. Integrate it with musical input/output system

INTRODUCTION xi

This would most likely take the form of adding MIDI capabilityto Python. The on-screen musical keyboard widget could be ex-panded to accept input from a physical musical keyboard connectedvia MIDI. The system could output the results of the musical con-straints through a MIDI synthesiser.

2. Re-write parts of the code to take advantage of an object-oriented GUIparadigm.

It was rather late in the project when I discovered the book Object-Oriented GUI Application Development by Geoff Lee [22]. Adopt-ing a more disciplined approach to GUI development, such as theDocument-View architecture, would improve the scalability andoverall flexibility of the system.

IPelog

1

1The Pelog language

The Pelog system is completely extendible and allows the end user to modify existingrule sets or create new ones from scratch.

Editing rule sets requires at least a working knowledge of Prolog. I recommendProgramming in Prolog [5] as a good starting point, and it should provide youwith everything you need to understand this section. It is also helpful to use aprogrammer’s text editor with good support for Prolog, such as GNU Emacs.

This section provides a tutorial introduction to developing rule sets followed bya reference of built-in functions available to the Pelog programmer.

1.1 What is a rule set?

The Pelog language is nothing more than a superset of the Prolog language. There-fore, a rule set is essentially a Prolog source file containing a number of speciallydefined rule predicates. The Pelog programmer has access to all of the built-in andlibrary functions that make up SWI-Prolog, as well as the extensions provided byPelog.

The difference between a Pelog rule set and a plain-vanilla Prolog source fileis that Pelog rule sets are run through a special preprocessor before they can beinterpreted. This process is explained below.

1.2 Anatomy of a rule

Each rule in the rule set looks like a regular Prolog predicate of the form:

rule(name, class, weight) :-goal1,goal2, . . .

name is a simply a name for the rule to use for reference.

2

CHAPTER 1. THE PELOG LANGUAGE 3

class specifies the rule class that the rule belongs to.

weight is an integer value specifying the weight of the rule.

Rule classes and weights are described in the next section.The following is a rule that ensures that every event stays within the scale.

% P i t c h must be a member o f the c u r r e n t s c a l er u l e (’In scale’ , ’scale’ , 0 ) :−$ e v e n ts c a l e .

The name of this rule is ’In scale’, and its class is ’scale’, and the strength valueis 0. Following this is one goal that ensures the current event is in the scale. For alist of the Pelog library functions that are useful for writing musical goals, see thePelog library reference (page 8).

In many ways the predicate above is just like a normal Prolog predicate. Notice,however, that there are no arguments that unify with variables, and thus seeminglyno way to interact with external data. This problem is solved, however, by a specialPelog rule preprocessor. Rather than listing all of the arguments in the head ofeach and every rule predicate, which could get quite tedious and cumbersome, thepreprocessor does all that work for you. From a predicate such as the one above, itcreates a new predicate with a set of all the arguments you could possibly need tointeract with the score. These arguments are matched up with Pelog’s concept ofmetavariables, which all begin with a dollar sign “$”. Table 1.1 is a listing of theavailable metavariables. The above rule predicate, therefore, is converted internally

metavariable abbrev. description$event $e The current event$prevx $px The x th event before the cur-

rent event$vert $v An event vertically related to

the current event. (i.e. anevent occurring at the sametime as the current event)

$events $x The set of all events. Used bysome library predicates thatneed access to the enter score.

Table 1.1: Metavariables

to:r u l e (’In scale’ , s c a l e ,

a r g s (A , B , C , D , E , F , G , H , I , J , K , L ) ) :−As c a l e .

(And it actually creates an extra fact predicate, rule def/3, to keep around forinternal housekeeping.)r u l e d e f (’In scale’ , s c a l e , 0 ) .

CHAPTER 1. THE PELOG LANGUAGE 4

1.3 How rules are applied to the score

It is wise for the rule programmer to know exactly how the rules will be applied tothe score in order to maximize time efficiency.

The entire set of rules is applied to the score event-by-event. The order in whichthe events are visited is determined when the input file is read in by the GUIDOparser. A time path is generated by sorting all the events by their starting times.Therefore it’s essentially a first-events-first scheme. Figure 1.1 shows an exampletime-path. For more information on the internal data representation, see A datastructure for encoding incomplete musical fragments on page 45.

Figure 1.1: Example score showing time-path

You may have noticed above that there are no metavariables provided for eventsafter the current event. This is because those events that have not been visited yetmay contain variables. It is good practice to determine the current event based onlyon the previous events because they have already been pinned-down as non-variable.This will eliminate unnecessary backtracking due to “erroneous assumptions aboutthe future.”

The order in which the rules are applied to each event is a little bit more complex.All the rules are divided into classes. All the rules within each class are presumedto be mutually exclusive. (Though it is the rule programmer’s responsibility toensure this.) For example, you may have the rule “melodic interval of a second”and “melodic interval of a third” in the same class called “melodic interval.” Thesetwo rules should be in the same class because it is impossible for an event to haveboth a melodic interval of a second and a melodic interval of a third at the sametime (i.e. they are mutually exclusive.) It would not be a good idea to put “melodicinterval of a second” and “in c major” in the same class because it is possible for anevent to fulfill both rules simultaneously. The concept of class is important becauseit allows the interpreter to be “lazy.” If an event passes the rule “melodic intervalof a second,” the rule “melodic interval of a third” does not need to be checkedbecause we already know it to be false.

Within each class, each rule is assigned a weight. Rules with lower weights

CHAPTER 1. THE PELOG LANGUAGE 5

are “preferred” to rules with higher weights. For example, in modal counterpoint[11], steps are considered preferable to skips, so a rule for steps would have a lowerweighting than a rule for skips. Rules with the same weight are equally preferred.The interpreter will arbitrarily choose one rule as preferable to another rule withthe same weight.

Let’s examine how all of these classifications are used by the Pelog interpreter.Each event needs to pass only one rule from each of the rule classes. The ruleclasses are visited in the order they appear in the rule set file. When a class isvisited, the rule with the lowest weighting is tried first. If this rule fails, a rule withthe same weighting is tried. If all the rules with the same weighting fail, controlbacktracks through the previously visited rule classes to find an alternate solution.If all the rules at a particular weight level fail with all of the alternate solutions ofthe previously visited rule classes, then, and only then, will rules of higher weightingbe tried. If all the rules in an entire rule class still fail, control backtracks to theprevious event. Alternate solutions of the previous event may lead to successfulcompletion of the current event.

1.4 Rule ordering for efficiency

Given this, what is the best way to order the rules to maximize efficiency?

1.4.1 Put the rule class with the fewest branches first

The first rule class visited will serve as the “generating rule class.” If an eventis specified as a variable in the input score, the first-visited rule class will serveto instantiate that variable with a value. All rule classes visited thereafter willonly serve to verify that the instantiation is correct, not to generate new values.By limiting the alternative solutions in the generating rule class you can limit thenumber of values that need to be tested to arrive at a solution.

Take, for example, the following two rules:% Good i n t e r v a l sr u l e (’Good intervals’ , ’melodic intervals’ , 1 ) :−

$p re v1 = s t a r t;( member ( I , [ 2 , 3 , 4 , 5 ] ) ,

member ( IC , [ min , maj , p e r ] ) ,$p rev 1 : $ e v e n t a b s o l u t e i n t e r v a lIC ˜ I ) .

% P i t c h must be a member o f the c u r r e n t s c a l er u l e (’In scale’ , ’scale’ , 0 ) :−

$ e v e n ts c a l e .

The ’Good intervals’ rule checks for permissible melodic intervals. There are 12possible solutions for this rule. The ’In scale’ rule ensures that the event is inthe current scale. A major scale, for example, consists of seven notes. When

CHAPTER 1. THE PELOG LANGUAGE 6

you consider that Pelog handles those seven notes in sixteen octaves, this rule willgenerate 7× 16 = 112 possible solutions. It would therefore be much wiser to select’Good intervals’ as the generating rule instead of ’In scale.’

1.4.2 When the given class and weighting system doesn’t apply, do ityourself

The rule set programmer is by no means forced to follow the default weighting andclass scheme for every rule class. It is merely provided as convenience. In caseswhere it may be simpler or more declarative to override it, the rule programmer isencouraged to do so.

Let’s take another example from modal counterpoint. Events that occur atcertain times during the melody, namely the first, last and penultimate events,must be at certain degrees of the scale. What exactly these are depends on whetherthe event is in the top voice or in the bottom voice. This relationship is given inTable 1.2. Since the mutual exclusivity is a little bit hard to follow here, the entire

first event last event penultimate eventtop voice final, tenor final, third leading tonebottom voice final final 2, 4, 5

Table 1.2: Modal counterpoint rules related to chronological position

rule class has been implemented as one rule with a number of helper predicates.Don’t forget that a Pelog rule set file is really just a Prolog program in disguise./∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗

CHRONOLOGICAL POSITION

Notes at s p e c i a l p o s i t i o n s , namely t he f i r s t , p e n u l t i m a t e andl a s t n o t e s must be c e r t a i n s c a l e d e g r e e s

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

r u l e (’First-Last-Penultimate’ , ’chronological’ , 0 ) :−$ e v e n t f i r s t e v e n t −>m c f i r s t p i t c h ( $ e v e n t );$ e v e n t l a s t e v e n t −>m c l a s t p i t c h ( $ e v e n t );$ e v e n t s p e n u l t i m a t e e v e n t −>m c p e n u l t i m a t e p i t c h ( $ e v e n t );true .

% The f i r s t p i t c h depends on which v o i c e i t i s i nm c f i r s t p i t c h (E ) :−

E comment ’First pitch’ ,(E p a r t top −>m c f i r s t p i t c h t o p (E)

CHAPTER 1. THE PELOG LANGUAGE 7

;E p a r t bottom −>m c f i r s t p i t c h b o t t o m (E ) ) .

% F i r s t p i t c h i n top v o i c e must be f i n a l ( t o n i c ) o r t e n o r ( dominant )m c f i r s t p i t c h t o p (E ) :−

E f i n a l;E s c a l e d e g r e e t e n o r .

% F i r s t p i t c h i n bottom v o i c e must be f i n a l ( t o n i c )m c f i r s t p i t c h b o t t o m (E ) :−

E f i n a l .

% L a s t p i t c h depends on which v o i c e i t i s i nm c l a s t p i t c h (E ) :−

E comment ’Last pitch’ ,(E p a r t top −>

m c l a s t p i t c h t o p (E);E p a r t bottom −>m c l a s t p i t c h b o t t o m (E ) ) .

% L a s t p i t c h i n top v o i c e must be f i n a l ( t o n i c ) o r% t he t h i r d ( mediant ) i f t h e r e a r e more than t h r e e v o i c e sm c l a s t p i t c h t o p (E ) :−

E f i n a l;( num parts X , X > 2 ,E s c a l e d e g r e e 3 ) .

% L a s t p i t c h i n bottom v o i c e must be f i n a lm c l a s t p i t c h b o t t o m (E ) :−

E f i n a l .

% P e n u l t i m a t e p i t c h depends on which v o i c e i t i s i nm c p e n u l t i m a t e p i t c h (E ) :−

E comment ’Penultimate pitch’ ,(E p a r t top −>

m c p e n u l t i m a t e p i t c h t o p (E);E p a r t bottom −>m c p e n u l t i m a t e p i t c h b o t t o m (E ) ) .

% P e n u l t i m a t e p i t c h i n top v o i c e must be l e a d i n g tone o r% f o u r t h d e g r e e ( subdominant ) i f t h e r e a r e more than two v o i c e sm c p e n u l t i m a t e p i t c h t o p (E ) :−

E l e a d i n g t o n e;( num parts X , X > 2 ,E s c a l e d e g r e e 4 ) .

CHAPTER 1. THE PELOG LANGUAGE 8

% P e n u l t i m a t e p i t c h i n bottom v o i c e must be 2 nd , 4 th o r 5 th s c a l e d e g r e em c p e n u l t i m a t e p i t c h b o t t o m (E ) :−

E s c a l e d e g r e e 2;E s c a l e d e g r e e 4;E s c a l e d e g r e e 5 .

1.5 Pelog library reference

The Pelog system provides a rich set of library predicates for specifying musical rela-tionships. Most of the predicates are implemented as infix operators. For example,to ensure that the interval between two notes is a minor third, you would write:

$pr ev 1 : $ e v e n t a b s o l u t e i n t e r v a l min ˜3

Of course, this is equivalent to Prolog’s more standard notation with the functor infront:a b s o l u t e i n t e r v a l ( $pr ev 1 : $ e v e n t , min ˜3)

While the syntax may be a little different from what most Prolog programmersmay be used to, it makes the code seem more declarative. After all, one of the goalsof this project was to make the rule specifications as readable as possible.

For consistency, all library predicates follow the convention of having the eventson the left hand side of the functor and all other arguments on the right hand side.

The Pelog library predicates are listed by library below. Each section containsan introduction to the conventions used throughout the library followed by an al-phabetical listing of the user predicates.

Syntax follows the form used in a lot of Prolog documentation, including theSWI-Prolog documentation and O’Keefe.

• An argument preceded by a ‘+’ is input only (i.e. it must be instantiated)

• An argument preceded by a ‘-’ is output only (i.e. it may not be instantiated)

• An argument preceded by a ‘?’ is input or output.

1.5.1 Comments

This library provides a mechanism to store comment strings with each event. Thesecomments can be used to provide feedback about events within the score. Thesecomments are added to the output file in the style specified by the comment styletag in the input file. See the section on GUIDO Music Notation (page 35) for moreinformation.

comment

+event comment +comment

CHAPTER 1. THE PELOG LANGUAGE 9

comment(+event, +comment)If comment is instantiated, comment is added to event’s comment list.If comment is a variable, comment unifies with any comment currently in event’s

comment list.r u l e (’Step - step’ , ’contour’ , 1 ) :−

$p re v2 = s t a r t;( $pre v 2 : $pre v 1 a i n t e r v a l s t e p ,

$p rev 1 : $ e v e n t a i n t e r v a l s t e p ,$p rev 2 comment ’Step - step’ ) .

1.5.2 Event

first event

+event first eventfirst event(+event)

Succeeds if event is the first event in its part.r u l e (’First-Last-Penultimate’ , ’chronological’ , 0 ) :−

$ e v e n t f i r s t e v e n t −>m c f i r s t p i t c h ( $ e v e n t );$ e v e n t l a s t e v e n t −>m c l a s t p i t c h ( $ e v e n t );$ e v e n t p e n u l t i m a t e e v e n t −>m c p e n u l t i m a t e p i t c h ( $ e v e n t );true .

last event

+event last eventlast event(+event)

Succeeds if event is the last event in its part.

penultimate event

+events penultimate eventpenultimate event(+events)

Succeeds if the current event defined in events is the penultimate event.Note that this predicate requires $events and not $event as input.

CHAPTER 1. THE PELOG LANGUAGE 10

1.5.3 Global

The global library can be used to extend the GUIDO parser to recognize new tags.Simply add a global default predicate to your Pelog rule set file. global default

predicates are of the form:

global default(tag(tagname), default)

tagname is the name of the tag

default is the default value for the tag if the tag is not present in the input file

The value of the tag can be used in your rules at runtime using the tag predicate.

tag

+tagname tag -valuetag(+tagname, -value)

Succeeds if tagname is assigned to value.Tags that are assigned to specific parts, (i.e. not global to the score,) are re-

trieved using the form tag~part, where tag is the tag name as it occurs in the inputfile and part is the part name.

1.5.4 Interval

The relationship between two pitches.In Pelog, intervals can be specified in the form type~size, where type is a three-

character atom specifying the type of interval. The available types are listed inTable 1.3.

type meaningmaj majormin minorper perfectdim diminishedaug augmentedchr chromaticsem semitones (size field is # of semitones)tri tritone

Table 1.3: Interval types

For example, min~3 is a minor third and maj~7 is a major seventh. The semtype returns the size field as the number of semitones, regardless of note names.Therefore, maj~3 is equivalent to sem~4.

Note that either the type or size field may be left variable using Prolog’s anony-mous variable, the underscore ‘ ’. Therefore, ~3 will specify dim~3, min~3, maj~3and aug~3.

CHAPTER 1. THE PELOG LANGUAGE 11

type meaningunison Unison (the two given notes have the same pitch)step A secondskip Any interval larger than a secondconsonant Any thirds, fifths, sixths or octaves that are not diminished

or augmenteddissonant Any seconds, fourths or sevenths

Table 1.4: Interval keywords

Intervals can also be specified using any of the keywords in Table 1.4.

absolute interval

?eventa : ?eventb absolute interval ?interval?eventa : ?eventb absolute interval ?interval contour ?contourabsolute interval(?eventa : ?eventb, ?interval)absolute interval(?eventa : ?eventb, ?interval contour ?contour)?eventa : ?eventb a interval ?interval?eventa : ?eventb a interval ?interval contour ?contoura interval(?eventa : ?eventb, ?interval)a interval(?eventa : ?eventb, ?interval contour ?contour)

Succeeds if the absolute interval between two events, eventa and empheventb, isequal to interval . interval may be in any form specified in the introduction to theinterval library.

The optional contour unifies with up if empheventb is higher in pitch than eventa,down if empheventb is lower in pitch than eventa, and static if empheventb is thesame pitch as eventa.

For specifying the cyclic interval between two events (i.e. where maj~10 is equiv-alent to maj~3, see the cyclic interval predicate.)% Good i n t e r v a l sr u l e (’Good intervals’ , ’melodic intervals’ , 1 ) :−

$p re v1 = s t a r t;( member ( I , [ 2 , 3 , 4 , 5 ] ) ,

member ( IC , [ min , maj , p e r ] ) ,$p re v1 : $ e v e n t a i n t e r v a lIC ˜ I ) . $

contour

+eventa : +eventb contour ?contourcontour(+eventa : +eventb, ?contour)

contour unifies with up if empheventb is higher in pitch than eventa, down ifempheventb is lower in pitch than eventa, and static if empheventb is the same pitchas eventa.

CHAPTER 1. THE PELOG LANGUAGE 12

eventa : eventb contour contour

is much faster than the equivalent

eventa : eventb absolute interval contour contour

cyclic interval

?eventa : ?eventb cyclic interval ?interval?eventa : ?eventb cyclic interval ?interval contour ?contourcyclic interval(?eventa : ?eventb, ?interval)cyclic interval(?eventa : ?eventb, ?interval contour ?contour)?eventa : ?eventb c interval ?interval?eventa : ?eventb c interval ?interval contour ?contourc interval(?eventa : ?eventb, ?interval)c interval(?eventa : ?eventb, ?interval contour ?contour)

Succeeds if the cyclic interval between two events, eventa and eventb, is equalto interval . interval may be in any form specified in the introduction to the intervallibrary.

The optional contour unifies with up if empheventb is higher in pitch than eventa,down if empheventb is lower in pitch than eventa, and static if empheventb is thesame pitch as eventa.

For specifying the absolute interval between two events (i.e. where maj~10 isnot equivalent to maj~3, see the absolute interval predicate.)

1.5.5 Parts

Each part in a score contains a single monophonic line.A part can be referenced to by number, in which case the top part is part 1, the

next highest is part 2, etc. A part can also be referenced by a name defined by thepart def fact predicate. The built-in part names are shown in Table 1.5.

onlytopbottomcantus firmusinnersopranoaltotenorbass

Table 1.5: Built-in part names

Additional part names can be defined by adding part def predicates to the ruleset file. part def predicates have the form:

CHAPTER 1. THE PELOG LANGUAGE 13

part def(name, partno, numparts)

name is the name of the part

partno is the corresponding part number

numparts is the number of parts

The built-in part defs are listed below:p a r t d e f ( o n l y , , 1 ) :− ! .p a r t d e f ( top , 1 , X ) .p a r t d e f ( bottom , X , X) :− X > 1 .p a r t d e f ( c a n t u s f i r m u s , X , X) :− X > 1 .p a r t d e f ( i n n e r , X , Y) :− X > 1 , X \= Y .p a r t d e f ( s o p r a no , 1 , 4 ) .p a r t d e f ( a l t o , 2 , 4 ) .p a r t d e f ( t e n o r , 3 , 4 ) .p a r t d e f ( b a s s , 4 , 4 ) .

part

+event part -partpart(+event, -part)

Succeeds if event is in part.part may be an integer or a part name defined in part def.

1.5.6 Pitch

In Pelog, pitch names follow the same convention as GUIDO (see GUIDO MusicNotation on page 35 for more information.) A pitch name is defined as a letter {c,d, e, f, g, a, b} optionally followed by an accidental {#, &, ##, &&}.

An octave is an integer where octave 1 is the octave containing A440Hz.

equivalent pitch

+eventa : +eventb equivalent pitchequivalent pitch(+eventa : +eventb)

Succeeds if eventa sounds at the same pitch as eventb.For example, c# : d& equivalent pitch succeeds.

octave

+event octave -octaveoctave(+event, -octave)

Succeeds if event is in octave.

pitch name

CHAPTER 1. THE PELOG LANGUAGE 14

?event pitch name ?namepitch name(?event, ?name)

Succeeds if event has pitch name.

1.5.7 Range

Range can be specified in a number of ways.

• As an interval. See the interval library (page 10) for more information.

• As a set of two events lowevent : highevent. When using this form, the twoevents must be instantiated.

• By name

Please note that all events used with the range predicates must be instantiated.The built-in range definitions are in Table 1.6.

sopranoaltotenorbass

Table 1.6: Built-in ranges

Additional named ranges can be defined by adding range def predicates to thePelog rule set file. range def predicates have the form:

range def(name, lowpitch, highpitch)

name is the name of the range.

lowpitch is the lowest pitch in the range, given in the form pitchname~octave. See thepitch library (page 13) for details.

highpitch is the highest pitch in the range

The built-in range defs are given below:r a n g e d e f ( s o p r a no , c ˜ 1 , a ˜ 3 ) .r a n g e d e f ( a l t o , f ˜ 0 , d ˜ 3 ) .r a n g e d e f ( t e n o r , c ˜ 0 , a ˜ 1 ) .r a n g e d e f ( b a s s , f ˜ −1 , d ˜ 0 ) .

in range

+event in range +rangein range(+event, +range)

Succeeds if event is in range.event must be instantiated. in range does not generate pitches.

CHAPTER 1. THE PELOG LANGUAGE 15

range must be between two fixed points. This may be a named range or twoinstantiated events. It can not be defined as an roaming interval.

range is

+events range is ?rangerange is(+events, ?range)

Succeeds if the range of all events up to and including the current event is exactlyequal to range. The events must be instantiated.

range can be defined in any of the ways defined in the introduction to the rangelibrary.

range within

+events range within +rangerange within(+events, +range)

Succeeds if all events up to and including the current event are within rangerange. The events and the range must be instantiated.

range can be defined in any of the ways defined in the introduction to the rangelibrary.

1.5.8 Scale

A collection of pitches. In this context, the words “scale” and “mode” are usedinterchangeably.

In Pelog, scales are specified in the form tonic~pitchset, where tonic is the start-ing pitch of the scale, and pitchset the name of a set of pitches.

tonic can be any pitch name. See the pitch library (page 13) for more informa-tion.

pitchset can be any pitch set name defined in a scale def clause.The built-in pitch set definitions are given in Table 1.7.The Pelog rule set programmer can add more scale definitions by adding scale def

fact predicates to the rule set file. scale def predicates have the form:

scale def(name, pitch list, key interval).

name is the name of the scale.

pitch list is a list of pitch names that make up the scale. This list should be providedwith c as tonic. The scale library will do the work of transposing the scale totonics other than c.

key interval is the interval between the scale’s tonic and the tonic of the major key signa-ture that this scale should be written in. For example, the tonic of the dorianmode is on the second degree of the major scale, so the key interval value ismaj~2.

CHAPTER 1. THE PELOG LANGUAGE 16

majorharmonic-minornatural-minormelodic-minordorianhypo-dorianphrygianhypo-phyrgianlydianhypo-lydianmixolydianhypo-mixolydianaeolianhypo-aeolianlocrianionianhypo-ionianchromatic (-sharps, -flats)whole-tone (-sharps, -flats)gypsypentatonic (-23, -32)octatonic (-sharps, -flats)half-whole (-sharps, -flats)whole-half (-sharps, -flats)

Table 1.7: Built-in pitch sets

CHAPTER 1. THE PELOG LANGUAGE 17

The built-in scale defs are listed below.s c a l e d e f ( major , [ c , d , e , f , g , a , b ] , p e r ˜ 1 ) :− ! .s c a l e d e f ( harmonic−minor , [ c , d , e &, f , g , a &, b ] , maj ˜ 6 ) :− ! .s c a l e d e f ( n a t u r a l−minor , [ c , d , e &, f , g , a &, b & ] , maj ˜ 6 ) :− ! .s c a l e d e f ( m e l o d i c−minor , [ c , d , e &, f , g , a &, a , b &, b ] , maj ˜ 6 ) :− ! .

s c a l e d e f ( d o r i a n , [ c , d , e &, f , g , a , b &, b ] , maj ˜ 2 ) :− ! .s c a l e d e f ( hypo−d o r i a n , X , Y) :− s c a l e ( d o r i a n , X , Y ) , ! .s c a l e d e f ( p h r y g i a n , [ c , d &, e &, f , g , a &, b & ] , maj ˜ 3 ) :− ! .s c a l e d e f ( hypo−p h r y g i a n , X , Y) :− s c a l e ( p h r y g i a n , X , Y ) , ! .s c a l e d e f ( l y d i a n , [ c , d , e , f #, g , a , b ] , p e r ˜ 4 ) :− ! .s c a l e d e f ( hypo− l y d i a n , X , Y) :− s c a l e ( l y d i a n , X , Y ) , ! .s c a l e d e f ( m i x o l y d i a n , [ c , d , e , f , g , a , b &, b ] , p e r ˜ 5 ) :− ! .s c a l e d e f ( hypo−m i x o l y d i a n , X , Y) :− s c a l e ( m i x o l y d i a n , X , Y ) , ! .s c a l e d e f ( a e o l i a n , [ c , d , e &, f , g , a &, b &, a , b ] , maj ˜ 6 ) :− ! .s c a l e d e f ( hypo−a e o l i a n , X , Y) :− s c a l e ( a e o l i a n , X , Y ) , ! .s c a l e d e f ( l o c r i a n , [ c , d &, e &, f , g &, a &, b & ] , maj ˜ 7 ) :− ! .s c a l e d e f ( i o n i a n , X , Y) :− s c a l e ( major , X , Y ) , ! .s c a l e d e f ( hypo−i o n i a n , X , Y) :− s c a l e ( i o n i a n , X , Y ) , ! .

s c a l e d e f ( c h r o m a t i c , [ c , c #, d , d #, e , f , f #, g , g #, a , a #, b ] , none ) :− ! .s c a l e d e f ( c h r o m a t i c−s h a r p s , X , Y) :− s c a l e ( c h r o m a t i c , X , Y ) , ! .s c a l e d e f ( c h r o m a t i c− f l a t s , [ c , d &, d , e &, e , f , g &, g , a &, a , b &, b ] ,

none ) :− ! .

s c a l e d e f ( whole−tone , [ c , d , e , f #, g #, a # ] , none ) :− ! .s c a l e d e f ( whole−tone−s h a r p s , X , Y) :− s c a l e ( whole−tone , X , Y ) , ! .s c a l e d e f ( whole−tone− f l a t s , [ c , d , e , g &, a &, b & ] , none ) :− ! .

s c a l e d e f ( gypsy , [ c , d , e &, f #, g , a , a &, b ] , u n i s ) :− ! .

s c a l e d e f ( p e n t a t o n i c , [ c , d , f , g , a ] , u n i s ) :− ! .s c a l e d e f ( p e n t a t o n i c−a , X , Y) :− s c a l e d e f ( p e n t a t o n i c , X , Y ) , ! .s c a l e d e f ( p e n t a t o n i c−b , [ c , d , e , g , a ] , u n i s ) :− ! .

s c a l e d e f ( o c t a t o n i c , [ c , c #, d #, e , f #, g , a , a # ] , none ) :− ! .s c a l e d e f ( o c t a t o n i c−s h a r p s , X , Y) :− s c a l e d e f ( o c t a t o n i c , X , Y ) .s c a l e d e f ( o c t a t o n i c− f l a t s , [ c , d &, e &, e , g &, g , a , b & ] , none ) :− ! .

s c a l e d e f ( h a l f−whole , X , Y) :− s c a l e d e f ( o c t a t o n i c , X , Y ) , ! .s c a l e d e f ( h a l f−whole−X , Y , Z ) :− s c a l e d e f ( o c t a t o n i c−X , Y , Z ) , ! .s c a l e d e f ( whole−h a l f , [ c , d , d #, f , f #, g #, a , b ] , none ) :− ! .s c a l e d e f ( whole−h a l f−s h a r p s , X , Y) :− s c a l e d e f ( whole−h a l f , X , Y ) .s c a l e d e f ( whole−h a l f− f l a t s , [ c , d , e &, f , g &, a &, a , b ] , none ) :− ! .

s c a l e d e f ( b l u e s , [ c , d , e &, e , f , g &, g , a , b & ] , u n i s ) :− ! .

The scale library also handles scale degrees. Scale degrees can be specified as aninteger where the tonic of the scale is equal to 1. Scale degrees can also be specifiedby name. The list of built-in scale degree names, or “special tones” is given in Table1.8. Note that not all of these special tones are available for use with all scales.

CHAPTER 1. THE PELOG LANGUAGE 18

finalambitustenortonicleadingsupertonicmediantsubdominantdominantsubmediantsubtonic

Table 1.8: Built-in special tones

The Pelog rule programmer can add more special tone definitions by addingspecial tone def fact predicates to the Pelog rule set file. special tone def predicateshave the form:

special tone def(name, pitchset, pitch).

name is the name of the special tone.

pitchset specifies the scales that the special tone applies to.

pitch is the special tone in that scale with c as tonic.

The built-in special tone defs are listed below:s p e c i a l t o n e d e f ( f i n a l , , c ) :− ! .s p e c i a l t o n e d e f ( ambitus , X , Y) :− s p e c i a l t o n e d e f ( t o n i c , X , Y ) .s p e c i a l t o n e d e f ( t e n o r , hypo− , e ) :− ! .s p e c i a l t o n e d e f ( t e n o r , , g ) :− ! .s p e c i a l t o n e d e f ( t o n i c , hypo− , g ) :− ! .s p e c i a l t o n e d e f ( t o n i c , , c ) :− ! .s p e c i a l t o n e d e f ( l e a d i n g , p h r y g i a n , b & ) :− ! .s p e c i a l t o n e d e f ( l e a d i n g , hypo− l y d i a n , f # ) :− ! .s p e c i a l t o n e d e f ( l e a d i n g , hypo− , f ) :− ! .s p e c i a l t o n e d e f ( l e a d i n g , n a t u r a l−minor , b & ) :− ! .s p e c i a l t o n e d e f ( l e a d i n g , , b ) :− ! .

% Only used i n TONAL harmonic p r a c t i c es p e c i a l t o n e d e f ( s u p e r t o n i c , major , d ) :− ! .s p e c i a l t o n e d e f ( s u p e r t o n i c , −minor , d ) :− ! .s p e c i a l t o n e d e f ( mediant , major , e ) :− ! .s p e c i a l t o n e d e f ( mediant , −minor , e & ) :− ! .s p e c i a l t o n e d e f ( subdominant , major , f ) :− ! .s p e c i a l t o n e d e f ( subdominant , −minor , f ) :− ! .s p e c i a l t o n e d e f ( dominant , major , g ) :− ! .s p e c i a l t o n e d e f ( dominant , −minor , g ) :− ! .s p e c i a l t o n e d e f ( submediant , major , a ) :− ! .

CHAPTER 1. THE PELOG LANGUAGE 19

s p e c i a l t o n e d e f ( submediant , m e l o d i c−minor , a ) :− ! .s p e c i a l t o n e d e f ( submediant , −minor , a & ) :− ! .s p e c i a l t o n e d e f ( s u b t o n i c , major , b ) :− ! .s p e c i a l t o n e d e f ( s u b t o n i c , n a t u r a l−minor , b & ) :− ! .s p e c i a l t o n e d e f ( s u b t o n i c , −minor , b ) :− ! .

current scale

current scale ?scalecurrent scale(?scale)

Succeeds if emphscale is the current scale as defined by the scale tag in the inputfile.

in scale

?event in scale?event in scale +scalein scale(?event)in scale(?event, +scale)

Succeeds if event is in scale.If scale is omitted, the scale specified by the scale tag in the input file is used.

scale degree

?event scale degree +degreescale degree(?event, +degree)

Succeeds if event is the scale degree degree of the scale specified by the currentscale. (i.e. specified by the scale tag in the input file.)

degree can be

• an integer, indicating the degreeth scale degree.

• a special tone defined by special tone def

• of the form raised~n, indicating the nth scale degree, raised by a semitone

• of the form lowered~n, indicating the nth scale degree, lowered by a semitone.

2An Example Application: Modal

Counterpoint

The first stage of this project will concern itself exclusively with modal counterpoint.The system as a whole will be designed, however, to be extendible to tonal, twelve-tone and other forms of counterpoint.

2.1 Sources

There is an avalanche textbooks on modal counterpoint. To simplify the processof breaking down modal counterpoint into logical predicates, and to be somewhatstandard and correct, the sources selected for this project, as a whole, meet thefollowing criteria:

• definitive and widely-accepted standard

• precise definitions, avoiding concepts like ”feeling” and ”affect”

• complete description of counterpoint, containing no simplifications

[33] Schottstaedt, William. (1984) ”Automatic Counterpoint.” Current Directionsin Computer Music Research. Ed. Max V. Mathews and John R. Pierce. Cam-bridge, Mass.: MIT Press, 1989.

This article describes a system, similar to the present project, for solvingcounterpoint exercises. While no implementation of the system is given,it has a concise summary of Fux [11] as a list of simple rules [pp. 200-202]. The majority of the rules below are derived directly from thislist. I have translated many of these rules from somewhat logicallyambiguous language (often quoted directly from Fux) into phrases thatbetter resemble Prolog clauses.

20

CHAPTER 2. MODAL COUNTERPOINT 21

[20] Krenek, Ernst. (1953) Modal Counterpoint in the Style of the Sixteenth Century.New York: Boosey & Hawkes, 1959.

Krenek provides a very concise overview of counterpoint that is widelyregarded as the definitive modern standard. Modal Counterpoint is thefirst volume in a series which also contains Tonal Counterpoint in theStyle of the Eighteenth Century and Studies in Counterpoint based onTwelve-Tone Technique. Each volume is under thirty pages in length,making it very easy to convert the text into individual rules.

[11] Fux, Johann Joseph. (1725) The Study of Counterpoint from Johann JosephFux’s Gradus ad Parnassum, translated and edited by Alfred Mann. New York: W.W. Norton & Co., 1943.

The central role of counterpoint in classical musical education is due inlarge part to this influential book. It is used here to correct any looseends in the rules developed in Schottstaedt [33]. It is an odd, rambling,book that is for the most part presented as a dialogue.

The serious difficulty of using Fux for the purposes of this project isthat the rules are not often fully distilled. For example, consider thefollowing excerpt (page 22), where the three possible motions are direct,contrary and oblique:

First rule: From one perfect consonance to another perfect consonance onemust proceed in contrary or oblique motion.

Second rule: From a perfect consonance to an imperfect consonance one mayproceed in any of the three motions.

Third rule: From an imperfect consonance to a perfect consonance, one mustproceed in contrary or oblique motion.

Fourth rule: From one imperfect consonance to another imperfect consonanceone may proceed in any of the three motions.

By constructing these rules in a diagram, it becomes obvious that thesefour rules can be combined into one.

perfect consonance imperfect consonanceperfect consonance parallelimperfect consonance parallel

The only situation not allowed is direct motion to a perfect consonance.This, and numerous examples like it, occur frequently throughout thetext.

[37] Thakar, Markand. (1990) Counterpoint: Fundamentals of Music Making. NewHaven: Yale University Press, 1990.

Thakar takes a performers’ approach to counterpoint, which does notalways readily lend itself to this project. It does present, however, somepractical issues, such as the overall length of exercises, that are over-looked by the other texts.

CHAPTER 2. MODAL COUNTERPOINT 22

2.2 The rules

2.2.1 Species rules

Though it is not readily apparent from the overly-complex approach of Fux [11],the species of counterpoint are not very different.

Note that Krenek [20] does away with the concept of species, presenting allexamples in Fux’s fifth species.

Here, cantus firmus refers to the lowest voice.The only rules that are dependent on species are:

• Every duration in the cantus firmus is a whole note

• First species is note-against-note.

In first species, every duration in the upper voice, except the last, is equal tothe durations in the cantus firmus

• Second species is note-against-two-notes.

In second species, every duration in the upper voice, except the last, is halfthe length of the durations in the cantus firmus

• Third species is note-against-four-notes.

In third species, every duration in the upper voice, except the last, is one-quarter the length of the durations in the cantus firmus

• Fourth species is note-against-note with ligatures.

In fourth species, every duration in the upper voice, except that of the lastnote, is equal to the length of the durations in the cantus firmus. The starttimes of the notes in the upper voice are shifted forward by half of the lengthof the durations in the cantus firmus.

• Fifth species is ”free” counterpoint. If in fifth species, the durations of theupper voice may be any of the following: { whole note, half note, quarter note,eigth note } Selection of these durations must follow the rules listed below

Fifth-Species rhythmic rules

Fifth-species rhythmic rules are quite complex and involve a lot of inter-relations.

• Periodical symmetry of rhythmic values.

• More than two thirds of potentially accented beats are articulated

• More than eight quarter notes in a row

• Less than 75% of melody in half notes

CHAPTER 2. MODAL COUNTERPOINT 23

2.2.2 Static rules

Static rules are rules that involve only individual notes, not the relationships be-tween notes.

Note class

These rules involve selecting notes from a particular subset of notes. These subsetsare typically modes or scales.

Fux [11] sticks to the convention of using only one mode across all parts. Krenek[20] claims that the parts may each be in their own different modes as long as thosemodes are related.

The standard modes and scales, and their inter-relationships will be included inthe system.

• Note outside of mode or scale

• In Dorian, Mixolydian and Aeolian modes, the leading tone is not raised by asemi-tone

• In Aeolian, if leading tone is approached stepwise from below, this sixth scaledegree is not raised

Range

• Note outside the range of a per12

• Note outside the range of a per8

• Note on outer edge of range

Chronological position

Notes at certain points in time must meet certain criteria.

• First pitch is not “tonic/final” or “fifth-scale-degree” pitch

• If there are two voices, last pitch in upper voice is not the “tonic/final”

If more than two voices, last pitch in upper voice is not the ”tonic/final” or”third-scale-degree”

• Last pitch in lower voice is not the “tonic/final”

• Last note is not on downbeat

• Last duration is less than a whole note

• Penultimate pitch in the upper voice is not the leading-tone

• Penultimate pitch in lowest voice is not the fourth or fifth-scale-degree

• Penultimate pitch in lowest voice is not the second scale degree.

CHAPTER 2. MODAL COUNTERPOINT 24

Overall length

Fux [11] and Krenek [20] make no references to overall length, though Thakar [37]recommends a length of 8 to 14 whole notes. Presumably some finite limit will needto be defined or the system will continue to generate counterpoint infinitely (or atleast until running out of memory.)

2.2.3 Horizontal rules

Horizontal rules involve melodic relationships between notes occurring sequentially.Referencing between different melodic lines is not necessary to apply these rules.

In this section about “horizontal rules,” “interval” refers to “melodic interval.”

Melodic intervals

• Augmented intervals

Diminished intervals

Chromatic intervals

Intervals larger than per5, excluding min6, per8

Downward min6

• Three notes or more notes outlining a tritone: Given three notes {a, b, c},the interval a-c is a tritone and a-b and a-c are in the same direction

• Interval of per8

• Two skips that do not form a triad

• Interval of maj6 or min6

Direction / Contour

A skip is a melodic interval greater than a maj2. A step is a melodic interval ofmaj2 or min2.

• Three consecutive skips in whole or half notes

• Two consecutive skips in quarter notes

• Two eighth notes with skip

• Skip followed by motion in same direction

• Skip followed by skip in the opposite direction

• Skip followed by a skip

• Skip preceded by motion in same direction

• Step up followed by step down

• Step down followed by step up

CHAPTER 2. MODAL COUNTERPOINT 25

Repetition

• First pitch is repeated

• Repeated pattern of four notes

• Repeated pattern of three notes

• Repeated pattern of two notes

Imitation

Better melodies include sequences of three or more notes that are repeated in pitch-transposed form.

• Melody doesn’t contain an imitative sequence of three notes

• Melody doesn’t contain an imitative sequence of four notes

• Melody doesn’t contain an imitative sequence of five notes

• Melody doesn’t contain an imitative sequence of six notes

Accent Pattern

Certain rules are dependent on the beat on which they occur. In standard four-beats-per-measure counterpoint, beat 1 is the strongest, and beat 3 is slightly lessstrong. Beats 2 and 4 are weak beats. Another definition of accent pattern is thatan accented beat exists wherever two or more note onsets occur at the same time.

• If two quarter notes are on an accented beat, not preceded by at least onequarter note, followed by two quarter notes or followed by a duration greaterthan a half note

• Upward skip from accented beat in quarter notes

• In fourth species, upper voice note starts on down beat of bar

• If on downbeat, repeated note

• If on last beat in bar, repeated note

• If on downbeat of bar, preceded by a skip

Voice leading

• Leading tone not followed by tonic

• Leading tone not approached by step

CHAPTER 2. MODAL COUNTERPOINT 26

High point

• Highest note in melody occurs more than once over entire melody

2.3 Vertical rules

Vertical rules define the relationship between notes in different melodic lines at agiven moment in time. In this section, “interval” refers to “harmonic interval.”

Harmonic intervals

• Interval is aug5

• Interval is unis

• If three-part or more, pitches do not form triad

• If Lydian mode, interval is dim5

• Interval is per4 or per5

• Interval is dim5

• Interval is greater than per8 (Krenek [20] says maj10 )

Chronological position / Accent pattern

• Interval of last notes is not unis or per8

• Interval of notes on accented beat is dissonant and duration is less than a halfnote

• Penultimate interval is not maj6 or min3

• If note is on downbeat of bar, interval is unis

• per8 or per5 appear less than four quarter notes apart

Voice crossing

• Upper voice is below cantus firmus

2.3.1 Horizontal / Vertical rules

Parallel motion

Parallel motion occurs when the same harmonic interval occurs consecutively.

• Parallel per5 or per8 : Harmonic interval is per5 or per8 and previous har-monic interval is the same.

CHAPTER 2. MODAL COUNTERPOINT 27

• Parallel motion: Harmonic interval is equal to the preceding harmonic interval.

Rules which exhibit some of the properties of parallel motion are:

• Harmonic interval of per8 followed be harmonic interval of per5

• Harmonic interval is maj6 or min6 and next melodic intervals are in similarmotion

• Parallel motion of any interval over more than three consecutive tones

• Harmonic interval is maj10 or min10 and next harmonic interval is per8

• Harmonic interval is per8 or unis and previous melodic interval is a skip

• Harmonic interval is per5 or per8 and next melodic intervals are in similarmotion

• Harmonic interval is unis and next melodic interval is a skip

Direct motion

Direct motion occurs when two voices traveling in the same direction melodicallyland on an undesirable harmonic interval. Krenek [20] calls “direct” motion “simi-lar” motion.

• Direct motion to per5 or per8

• Direct motion to dim5

• Direct motion to per4 or per5

• Direct motion to maj6 or min6

• Direct motion to dim5

Scale degrees

Certain harmonic intervals are undesirable when the pitches involved are at certaindegrees in the scale.

• Harmonic interval is unis or per8 and pitch is “leading tone”

• Harmonic interval is unis or per8 and scale degree is third, fifth or sixth

Passing tone

• Dissonance must be in a passing tone: Harmonic interval is { min2, maj2,per4, min7, maj7 } (dissonant), notes preceding and following do not have amelodic interval of min3 or maj3. Passing tones must occur on unaccentedbeats.

CHAPTER 2. MODAL COUNTERPOINT 28

Cross-part imitation

Melodies that imitate the other voices in the counterpoint are preferable. At thisstage, the system will not be embedded with the logic of complex imitative formssuch as the fugue. However, it will reward counterpoints that contain embeddedimitative motifs. According to Krenek [20], the motifs can be transposed (pitch-shifted), inverted (pitches-mirror imaged), retrograde (pitches in reverse order),augmented (durations doubled) or diminished (durations halved) in order to beconsidered imitative. This is a lot of different ways to modify motifs, and mayrequire considerable processing time to search for all possible variations.

• Melody doesn’t contain a cross-part imitative sequence of three notes

• Melody doesn’t contain a cross-part imitative sequence of four notes

• Melody doesn’t contain a cross-part imitative sequence of five notes

• Melody doesn’t contain a cross-part imitative sequence of six notes

Miscellaneous

• All voices have skips at once

2.3.2 Extensions of Modal Counterpoint

Strict canon

In strictly imitative canon, the melodic lines are identical, with different start times.The parts must obey all other counterpoint rules.

2.4 Implementation

2.4.1 modal counterpoint.pl

Code

:− d i s c o n t i g u o u sr u l e d e f / 4 ,r u l e / 3 .

r u l e o r d e r ( [ ’chronological’ ,’special cases for modes’ ,’melodic intervals’ ,’scale’ ,’range’ ,’tendency’ ,’harmonic intervals’ ,’avoid harmonic intervals’ ,’two leading tones’ ,’contour’ ,

CHAPTER 2. MODAL COUNTERPOINT 29

’repeat first’ ,’repeat patterns’ ,’outline a tritone’ ] ) .

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗CHRONOLOGICAL POSITION

Notes at s p e c i a l p o s i t i o n s , namely t he f i r s t , p e n u l t i m a t e andl a s t n o t e s must be c e r t a i n s c a l e d e g r e e s

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

r u l e (’First-Last-Penultimate’ , ’chronological’ , 0 ) :−$ e v e n t f i r s t e v e n t −>m c f i r s t p i t c h ( $ e v e n t );$ e v e n t l a s t e v e n t −>m c l a s t p i t c h ( $ e v e n t );$ e v e n t s p e n u l t i m a t e e v e n t −>m c p e n u l t i m a t e p i t c h ( $ e v e n t );true .

% The f i r s t p i t c h depends on which v o i c e i t i s i nm c f i r s t p i t c h (E ) :−

E comment ’First pitch’ ,(E p a r t top −>m c f i r s t p i t c h t o p (E);E p a r t bottom −>m c f i r s t p i t c h b o t t o m (E ) ) .

% F i r s t p i t c h i n top v o i c e must be f i n a l ( t o n i c ) o r t e n o r ( dominant )m c f i r s t p i t c h t o p (E ) :−

E f i n a l;E s c a l e d e g r e e t e n o r .

% F i r s t p i t c h i n bottom v o i c e must be f i n a l ( t o n i c )m c f i r s t p i t c h b o t t o m (E ) :−

E f i n a l .

% L a s t p i t c h depends on which v o i c e i t i s i nm c l a s t p i t c h (E ) :−

E comment ’Last pitch’ ,(E p a r t top −>

m c l a s t p i t c h t o p (E);E p a r t bottom −>m c l a s t p i t c h b o t t o m (E ) ) .

CHAPTER 2. MODAL COUNTERPOINT 30

% L a s t p i t c h i n top v o i c e must be f i n a l ( t o n i c ) o r% t he t h i r d ( mediant ) i f t h e r e a r e more than t h r e e v o i c e sm c l a s t p i t c h t o p (E ) :−

E f i n a l;( num parts X , X > 2 ,E s c a l e d e g r e e 3 ) .

% L a s t p i t c h i n bottom v o i c e must be f i n a lm c l a s t p i t c h b o t t o m (E ) :−

E f i n a l .

% P e n u l t i m a t e p i t c h depends on which v o i c e i t i s i nm c p e n u l t i m a t e p i t c h (E ) :−

E comment ’Penultimate pitch’ ,(E p a r t top −>

m c p e n u l t i m a t e p i t c h t o p (E);E p a r t bottom −>m c p e n u l t i m a t e p i t c h b o t t o m (E ) ) .

% P e n u l t i m a t e p i t c h i n top v o i c e must be l e a d i n g tone o r% f o u r t h d e g r e e ( subdominant ) i f t h e r e a r e more than two v o i c e sm c p e n u l t i m a t e p i t c h t o p (E ) :−

E l e a d i n g t o n e;E s c a l e d e g r e e 2;( num parts X , X > 2 ,E s c a l e d e g r e e 4 ) .

% P e n u l t i m a t e p i t c h i n bottom v o i c e must be 2 nd , 4 th o r 5 th s c a l e d e g r e em c p e n u l t i m a t e p i t c h b o t t o m (E ) :−

E s c a l e d e g r e e 2;E s c a l e d e g r e e 4;E s c a l e d e g r e e 5 .

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗TENDENCIES

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

r u l e (’leading tone leads to tonic’ , ’tendency’ , 0 ) :−$ e v e n t l e a d i n g t o n e −>$ne x t t o n i c;true .

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗

CHAPTER 2. MODAL COUNTERPOINT 31

SPECIAL CASES FOR MODES

C e r t a i n modes have r u l e s o f t h e i r own∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

r u l e (’Aeolian’ , ’special cases for modes’ , 0 ) :−c u r r e n t s c a l e ˜ a e o l i a n −>m c a e o l i a n s p e c i a l ( $ e v e n t , $ pre v1 );true .

% I f l e a d i n g tone i s approached from below , i t must be r a i s e d .m c a e o l i a n s p e c i a l (E , P) :−

E l e a d i n g t o n e ,not P s c a l e d e g r e e 6 ,( ( P s c a l e d e g r e e r a i s e d ˜ 6 ,

P comment ’Aeolian raised 6th’ );true ) .

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗MELODIC INTERVALS

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

% Good i n t e r v a l sr u l e (’Good intervals’ , ’melodic intervals’ , 1 ) :−

$pr ev 1 = s t a r t ;( member ( I , [ 2 , 3 , 4 , 5 ] ) ,

member ( IC , [ min , maj , p e r ] ) ,$p re v1 : $ e v e n t a i n t e r v a l IC ˜ I ) .

r u l e (’Repeated note’ , ’melodic intervals’ , 1 ) :−$pr ev 1 = s t a r t ;$pr ev 1 : $ e v e n t a i n t e r v a l u n i s .

% i n t e r v a l sr u l e (’Less good intervals’ , ’melodic intervals’ , 1 0 ) :−

$pr ev 1 = s t a r t ;( $pr ev 1 : $ e v e n t a i n t e r v a l min ˜6 c o n t o u r up; $ pre v1 : $ e v e n t a i n t e r v a l p e r ˜ 8 ) .

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗IN SCALE

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

% P i t c h must be a member o f the c u r r e n t s c a l er u l e (’In scale’ , ’scale’ , 0 ) :−

$ e v e n t s c a l e .

CHAPTER 2. MODAL COUNTERPOINT 32

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗HARMONIC INTERVALS

Notes at s p e c i a l p o s i t i o n s , namely t he f i r s t , p e n u l t i m a t e andl a s t n o t e s must be c e r t a i n s c a l e d e g r e e s

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

r u l e (’Good intervals’ , ’harmonic intervals’ , 0 ) :−$ v e r t = [ ];( member ( I , [ 3 , 6 , 8 , 1 0 , 1 3 , 1 5 ] ) ,member ( IC , [ min , maj , p e r ] ) ,$ v e r t : $ e v e n t a i n t e r v a l IC ˜ I ) .

r u l e (’Diminished 5th’ , ’harmonic intervals’ , 0 ) :−$ v e r t = [ ];not c u r r e n t s c a l e ˜ l y d i a n ,$ v e r t : $ e v e n t c i n t e r v a l dim ˜ 5 .

r u l e (’Perfect intervals’ , ’harmonic intervals’ , 1 0 ) :−member ( I , [ 4 , 5 ] ) ,$ v e r t : $ e v e n t c i n t e r v a l p e r ˜ I .

r u l e (’Unison’ , ’harmonic intervals’ , 2 0 ) :−$ v e r t : $ e v e n t a i n t e r v a l u n i s .

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗AVOID CERTAIN HARMONIC INTERVALS

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

r u l e (’Penultimate maj6 or min3’ , ’avoid harmonic intervals’ , 0 ) :−$ e v e n t p e n u l t i m a t e e v e n t −>( not ( $ v e r t : $ e v e n t c i n t e r v a l maj ˜6

; $ v e r t : $ e v e n t c i n t e r v a l min ˜ 3 ) );true .

r u l e (’Avoid’ , ’two leading tones’ , 0 ) :−not ( $ v e r t l e a d i n g t o n e ,

$ e v e n t l e a d i n g t o n e ) .

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗DIRECTION / CONTOUR

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

r u l e (’Step - step’ , ’contour’ , 1 ) :−$pr ev 2 = s t a r t ;

CHAPTER 2. MODAL COUNTERPOINT 33

( $pr ev 2 : $pre v 1 a i n t e r v a l s t e p ,$pr ev 1 : $ e v e n t a i n t e r v a l s t e p ,$pr ev 2 comment ’Step - step’ ) .

r u l e (’X - skip: same direction’ , ’contour’ , 1 ) :−$pr ev 2 = s t a r t ;( $pr ev 2 : $pre v 1 c o n t o u r X ,$pr ev 1 : $ e v e n t a i n t e r v a l sk ip c o n t o u r X ,$pr ev 2 comment ’X - skip: same direction’ ) .

r u l e (’Skip - X: opposite direction’ , ’contour’ , 3 ) :−$pr ev 2 = s t a r t ;( $pr ev 2 : $pre v 1 a i n t e r v a l sk ip c o n t o u r X ,$p rev 1 : $ e v e n t c o n t o u r Y ,$p rev 2 comment ’Skip - X: opposite direction’ ,X \= Y ) .

r u l e (’Repeat - Step’ , ’contour’ , 3 ) :−$p rev 2 = s t a r t ;( $pr ev 2 : $pre v 1 c o n t o u r s t a t i c ,$p rev 1 : $ e v e n t a i n t e r v a l s t e p ,$pr ev 2 comment ’Repeat - Step’ ) .

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗OUTLINING A TRITONE

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

% O u t l i n i n g a t r i t o n er u l e (’Ensure not’ , ’outline a tritone’ , 1 ) :−

$pr ev 2 = s t a r t ;( ( $pre v 2 : $pre v 1 c o n t o u r X ,

$p rev 1 : $ e v e n t c o n t o u r X) −>( not $pr ev 2 : $ e v e n t a i n t e r v a l t r i ˜ ) ;

true ) .

% Two s k i p s t h a t form a t r i a dr u l e (’Two skips that form a triad’ , ’contour’ , 5 ) :−

( $pr ev 2 : $pre v 1 a i n t e r v a l ˜3 c o n t o u r X ,$p re v1 : $ e v e n t a i n t e r v a l ˜3 c o n t o u r X ) , ! .

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗REPEAT FIRST NOTE

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

r u l e (’Avoid the repeat’ , ’repeat first’ , 0 ) :−$pr ev 1 = s t a r t;not $p re v1 : $ e v e n t a i n t e r v a l u n i s .

r u l e (’Let it repeat’ , ’repeat first’ , 1 0 ) :−

CHAPTER 2. MODAL COUNTERPOINT 34

$pr ev 1 : $ e v e n t a i n t e r v a l u n i s .

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗REPEATING PATTERNS

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

r u l e (’Avoid two’ , ’repeat patterns’ , 0 ) :−not m c r e p e a t p a t t e r n ( $ pre v3 , $ pre v2 , $p rev 1 , $ e v e n t ) .

r u l e (’Avoid three’ , ’repeat patterns’ , 1 0 ) :−$p rev 3 comment ’repeated two-note sequence’ ,not m c r e p e a t p a t t e r n ( $ pre v5 , $ pre v4 , $p rev 3 , $pre v 2 , $pre v 1 , $ e v e n t ) .

r u l e (’Avoid four’ , ’repeat patterns’ , 2 0 ) :−$pr ev 5 comment ’repeated four-note sequence’ ,not m c r e p e a t p a t t e r n ( $ pre v7 , $ pre v6 , $p rev 5 , $pre v 4 , $pre v 3 , $pre v 2 , $ pre v1 , $ e v e n t ) .

m c r e p e a t p a t t e r n (A , B , A , B ) .m c r e p e a t p a t t e r n (A , B , C , A , B , C ) .m c r e p e a t p a t t e r n (A , B , C , D , A , B , C , D) .

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗RANGE

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

% Each note must s t a y w i t h i n i t ’ s g i v e n p a r t ’ s r ange as s p e c i f i e d i n t he i n p u t f i l er u l e (’In range’ , ’range’ , 0 ) :−

$ e v e n t p a r t Part ,rang e ˜ Part tag Range ,$ e v e n t i n r a n g e Range .

3GUIDO music notation format

The GUIDO Music Notation Format [15] was developed as a joint project betweenHolger H. Hoos at the Technical University of Darmstadt and Keith A. Hamel atthe University of British Columbia.

It was chosen as the input/output language of the Pelog system for the followingreasons:

• It is a very concise and user-friendly language

• It is simple to write a parser/grammar for it

• There are free tools available for viewing and listening to GUIDO files

• It is easily extendible to support features unique to the Pelog system

The Pelog system only supports a subset of the complete specification provided byHoos & Hamel. Therefore, while any input and output used by Pelog is in GUIDOFormat, not every file in GUIDO Format can be used by the Pelog system. Inparticular, because Pelog is only concerned with (at least at this stage) counterpointand the interaction between monophonic voices, it does not support elements suchas:

• multiple voices on one staff

• accents and other expressive markings

• strictly visual features such as beaming, staves and octava markings

This section describes all of the GUIDO language features supported by the Pelogsystem1. Using features beyond what is defined below is not recommended and mayhave unpredictable results.

1This is an adaptation of the complete specification available at http://www.informatik.tu-darmstadt.de/AFS/GUIDO

35

CHAPTER 3. GUIDO MUSIC NOTATION FORMAT 36

3.1 Scores

The entire score must be enclosed in curly braces “{ }”.

3.2 Parts

Each part, (i.e. a monophonic voice,) is enclosed in square brackets “[ ]”. Forscores with more than one part, the parts are separated by a comma “,”.{ [ c d e d c ] , [ c e g g c ] }

3.3 Events

Any note, rest or variable note is considered an event.In general, no white space should be used within each event description.The general syntax for representing notes is:

notename accidentals octave duration

For rests (events without sounding pitch):d u r a t i o n

For variable notes (pitches that are left to be filled in by the interpreter):˜ d u r a t i o n

octave and duration can be omitted. If so, they are inferred from precedingevents. The default octave is 1, and the default duration is the quarter note.

3.4 Notename

There are different systems of notenames:

1. c d e f g a h/b (diatonic or german)

2. c cis d dis e f fis g gis a ais b (chromatic)

3. cd re mi fa sol la si/ti (solfege)

3.5 Accidentals

accidentals is one of the following:

# (sharp) raises note by one semi-tone

& (flat) lowers note by one semi-tone

## (double sharp) raises note by two semi-tones

&& (double flat) lowers note by two semi-tones

CHAPTER 3. GUIDO MUSIC NOTATION FORMAT 37

3.6 Octave

octave is an integer indicating the octave of the note, where a1 is 440Hz, andmiddle c is c1.

Pelog supports octaves in the range [−8,+8], though the need for such a largerange is questionable.

If octave is omitted from the note description, it is assumed to be identical tothe last octave specified.

3.7 Duration

duration is specified in one of the following forms:

1. * enum / denom dotting

2. * enum dotting

3. / denom dotting

where enum and denom are positive integers and dotting is either empty, “.” or “..”.When either enum or denom are omitted, it is given a value of 1.If the entire duration is omitted, it is assumed to be identical to the last duration

specified. The default duration is 1/4 (quarter note).

3.8 Tags

Tags provide additional information about the score. They are of the form:\ i d <param− l i s t>

The tags must occur within parts. (i.e. inside square brackets “[ ]”.)The tags supported by Pelog are listed below. Of these, only meter and key are

part of the standard GUIDO specification. The rest are Pelog-specific extensionsto the language.

Individual rule sets may also support proprietary tags to handle unique at-tributes of a given musical genre.

3.8.1 Key

\key<i>

sets the key signature to i sharps, if i is positive, or to |i| flats, if i is negative. Fori = 0 , the key signature contains no sharps or flats.\key<s> indicates a key of s, where s is of the form “n”, “n#”, or “n&” for anynote name n. Uppercase and lowercase letters are used to denote major and minorscales, respectively.

CHAPTER 3. GUIDO MUSIC NOTATION FORMAT 38

3.8.2 Scale

scale<tonic˜scale>

indicates a scale starting on tonic . tonic is of the form notename described above.Table 3.1 contains a list of the built-in scale definitions. It is also possible to defineadditional scales for a given rule set (see Scale library on page 15).

majorharmonic-minornatural-minormelodic-minordorianhypo-dorianphrygianhypo-phrygianlydianhypo-lydianmixolydianhypo-mixolydianaeolianhypo-aeolianlocrianionianhypo-ionianchromatic (-sharps, -flats)whole-tone (-sharps, -flats)gypsypentatonic (-23, -32)octatonic (-sharps, -flats)half-whole (-sharps, -flats)whole-half (-sharps, -flats)

Table 3.1: built-in scales

A note about key vs. scale: While scale explicitly specifies the set ofpitches allowable in the score, key only specifies the number of sharps orflats in the key signature. The key and scale of a score are determinedautomatically based on the following rules:

• If an input score only specifies the key, then the scale defaults tomajor with key as the tonic.

• If an input score only specifies the scale, the key is chosen based onrules defined by the given scale. (e.g. d dorian is in the key of c.)

• If a score specifies both scale and key, both are transferred as-is tothe output score.

CHAPTER 3. GUIDO MUSIC NOTATION FORMAT 39

3.8.3 Range

\range<range>

selects the allowable range for the current part. This may be one of the built-inranges (soprano, alto, tenor, bass) or one of the custom ranges defined in the currentrule set.

3.8.4 Meter

\meter<s>

sets the time signature to s where s is of the form numerator / denominator .

3.8.5 Accent pattern

\accented beats<s>

sets the accent pattern to s where s is of the form a1, a2 . . . an, where an are theaccented beats.

The duration of each beat is equal to the denominator of the time signaturespecified by the meter tag. If accented beats is not specified, it defaults to the firstbeat of the measure.

accented beats is useful for defining things such as “French 3/4” where the ac-cented beat is not the first beat of each measure.

3.8.6 Comment style

\comment style<s>

defines the style of comments in the output file where s is one of referenced, lyricsor none.

There are three ways in which comments about the score can be presented inthe output file:

• referenced: Each event is assigned a number using the text tag which will bedisplayed under the note in GUIDO NoteViewer. The comments for each ofthese notes is listed by event number at the end of the output file. Figure 3.1shows how referenced comments are displayed in the Pelog-GUI.

• lyrics: Each comment is displayed as a lyric underneath each event.

Note: this option is not currently very useful due to a bug in GUIDO Note-Viewer which causes the lyrics to write on top of each other.

• none: No comments are added to the output file.

CHAPTER 3. GUIDO MUSIC NOTATION FORMAT 40

Figure 3.1: Pelog-GUI with referenced comments

4Tools

4.1 Selecting the tools

This project requires the following categories of development tools:

1. Prolog interpreter

2. GUI development system

3. A system connecting these two tools

The specific implementations of these tools must meet the following requirements:

• Free for educational use

• Runs on the chosen development platform (32-bit Microsoft Windows), withsupport for porting to other platforms

• As industry-standard as possible, to ensure maintainability and portability

• Creates stand-alone distributions that do not require that the entire develop-ment system is installed on the user’s machine

• Supports rapid application development (RAD) allowing edits without re-compilation

4.1.1 Prolog interpreter

Chosen toolSWI-Prolog [http://www.swi.psy.uva.nl/projects/SWI-Prolog/]

41

CHAPTER 4. TOOLS 42

SWI-Prolog was developed at the University of Amsterdam by JanWielemaker. It is free for non-commercial use and runs on Windowsand UNIX platforms. It interprets standard Edinburgh-Prolog, withlarge subsets of the ISO-standard, Quintus and SICStus libraries. Allthe included modules are upward compatible to Quintus and SICStus,and most other Quintus modules will run directly in SWI without mod-ifications. It will create stand-alone Prolog applications and has anextensive C language interface.

Other candidatesB-Prolog [http://www.cad.mse.kyutech.ac.jp/people/zhou/bprolog.html]

There is another freeware Prolog interpreter for Windows called B-Prolog developed by Neng-Fa Zhou at the Kyushu Institute in Japan.It is a strong second-choice to SWI-Prolog in most respects. However,it does not support libraries or garbage collection, nor does it claim tosupport as many standards as SWI-Prolog.

BIN-Prolog [www.binnet.com]

Bin-Prolog was originally developed as a free, portable Prolog by PaulTarau at the University of Moncton. Since 1994, it is a commercialproduct distributed by BinNet corporation in Texas. While the freeproduct is still available by FTP, it lacks some of the more advancedfeatures of SWI-Prolog, such as the creation of stand-alones. It is alsoonly available as a 16-bit Windows application, making interaction with32-bit Windows applications difficult or impossible.

Quintus Prolog and Sicstus Prolog [www.sics.com]

Quintus and SICStus Prolog seem to be the most popular commercialProlog interpreters on the market. Quintus was recently acquired bySICS and the two products appear to be gradually merging into one.The advantages of these commercial systems over SWI-Prolog are many,but few of them are significant. The commercial products have graphicalIDE’s, and will create C or Java code from Prolog source. The interfacebetween these Prologs and other languages and systems is also strongerthan their freeware counterpoints.

4.1.2 GUI development system

Chosen tool Tcl/Tk [www.scriptics.com]

Tcl/Tk is a very efficient and increasingly popular language for the au-tomation of simple tasks and the creation of graphical user interfaces.In particular, Tcl/Tk makes it easy to create new graphical widgets bycombining the functionality of existing ones. Since it is an interpreted

CHAPTER 4. TOOLS 43

language, any changes made to the code are updated instantly. Not onlyis it never necessary to recompile, it is often not necessary to restart ex-ecution of the Tcl code.

Ports of Tcl/Tk are available for virtually every major platform, in-cluding Windows, UNIX and Macintosh. The core functions are freeand open-sourced. Additional functionality, such as the generation ofstand-alone executables and object-oriented data structures, is includedas part of the commercial Tcl/Tk Pro package.

Other candidatesJava [www.java.sun.com]

Java’s new GUI system, Swing, released with Java 1.2, makes it veryeasy to create flexible and portable graphical user interfaces. While im-plementing these interfaces directly with code is quite labour-intensive,there are a number of free tools available for graphically drawing in-terface designs. Presumably, however, such tools reduce the amount offlexibility for future changes to the interface. As well, the fact that Javais a byte-compiled language means that updating and debugging thecode is a slow and tedious process.

XPCE [http://www.swi.psy.uva.nl/projects/xpce/]

XPCE is a graphical user interface system developed by the authors ofSWI-Prolog. Since it is designed from the ground up for use with Prolog,it is perhaps the most natural choice. It is available on the all of thesame platforms as SWI-Prolog. Unfortunately, XPCE is a commercialproduct, currently costing 300 euros for a single-user academic license.It is also extremely specialized and proprietary, designed only for theProlog domain.

4.1.3 Connecting the two

Connecting Tcl/Tk and Prolog is rather involved. A great deal of effort was spentimplementing a set of procedures and predicates for this purpose (see the appendixon the Tcl/Tk-Prolog Connector System on page 234). While this work was enlight-ening and a good tutorial on using piping on a Windows system, that approach wasultimately abandoned. The technique that won out was simply to use the commandline interface. The Tcl/Tk portion of the system starts the Prolog portion by callingit with all its arguments on the MS-DOS command line. It’s simple, easy to debugand directly ports to UNIX. It doesn’t provide any interactivity between Tcl/Tkand Prolog, but as it turns out, this is not a major drawback. You can see thismechanism implemented in the rules apply function in the Pelog-GUI code.

CHAPTER 4. TOOLS 44

4.2 Reflections after-the-fact

These reflections are based on my own casual observations during the developmentof the Pelog system.

4.2.1 SWI-Prolog

SWI-Prolog has proven to be a very high quality tool.Robust. It crashed only once during the development of Pelog, and that was

due to an unrelated disk access error. Most common errors such as memory overflowsdue to infinite recursion are caught before crashing the operating system.

Standard. SWI-Prolog’s high level of support for the Edinburgh Prologstandard allowed the Pelog system to reuse code from a number of different sources.For example, the binary tree structure that is so pivotal to the central Pelog datastructure (page 45) was “borrowed” from the Quintus Prolog library. It ran in SWI-Prolog with absolutely no modification. The standard also made it possible to takeadvantage of the great number of tutorial texts on Edinburgh Prolog. As someonewho is relatively new to Prolog, it would have been far more difficult to completethis project in a more proprietary language using only proprietary documentation.(The author of SWI-Prolog, Jan Wielemaker, is currently implementing the recentlyadopted ISO Prolog standard into SWI-Prolog.)

4.2.2 Tcl/Tk

Tcl/Tk was much less impressive.Instability on the Windows platform. The current Windows implementa-

tion of Tcl/Tk 8.1 has a memory allocation bug that does not free memory andsystem resources upon exit of the Tcl shell. During the development of the PelogGUI, it was typically only possible to restart the Tcl shell about four times beforethe entire operating system would crash, taking all of my unsaved work with it.It made the modify-and-test development cycle, for which scripting languages areso revered, virtually useless. While the severity of this problem should be a highpriority, according to the Tcl/Tk FAQ file on the web, this problem has existed atleast since version 7.6. Since no application should require frequent rebooting ofthe operating system, Tcl as it currently stands in highly inadequate for full-scalecommercial development for Windows.

Language issues. Tcl does not scale well. Most Tcl programs, includingthose provided as examples, rely on archaic language features such as global vari-ables. While it is possible to divide a project into multiple source files, there isno method to deal with name space problems. For this reason, the Tcl languagewould impose a considerable amount of unnecessary manual housekeeping on partof the programmer to go beyond the complexity of a simple program such as thePelog-GUI.

5A Data Structure for Encoding

Incomplete Musical Fragments inProlog

5.1 Design notes

The data structure, hereafter referred to as incomplete score, was designed with thefollowing initiatives:

• To allow the most common calculations, such as intervals and scale degrees,to be straightforward and efficient

• To access the horizontal and vertical relationships between events efficiently

• To make the conversion to and from the GUIDO music notation language [15]as elegant and trivial as possible

• To allow portions of the score to be unspecified. These unspecified parts canlater be filled in by the solver.

Incomplete score uses ”A Generalized Model for Encoding Musical Data” [32]as its starting point. From their model comes the representation of events as Prologterms and the use of Brinkman’s binomial pitch representation. Their text is theonly full length tutorial, to my knowledge, on using Prolog as a tool for musicalresearch and makes a strong case for the straightforward implementation of mu-sical expert systems. However, their data structure design is based too stronglyon Brinkman [4]. In their implementation, every musical event is asserted into theProlog database. Any changes in the database must be explicitly retracted andasserted. In most Prolog implementations, backtracking over assertions and retrac-tions does not restore the database to its previous state. Schaffer and McGee’s

45

CHAPTER 5. DATA STRUCTURE 46

fundamental design choice therefore negates one of the principle features of Prolog,namely backtracking to compute alternate solutions. Their approach is thus usefulonly for analysis, and thus inadequate for generation. By contrast, the incompletescore uses a binary tree structure to store the events, where the previous states ofvariable elements can be restored through backtracking. This allows the same codeto function both as a verifier and generator of musical events.

5.2 A worked example

The most intuitive way to present the incomplete score data structure is through acase study of how a given musical fragment is encoded. While encoding an incom-plete score by hand has been useful for preliminary testing, the next phase of theproject will include a grammar/parser to convert between the internal representa-tion and the GUIDO music notation format [15]. GUIDO has been chosen as theinput/output language for its brevity and ease of use: two things lacking in thisinternal representation designed for efficient manipulation by the Prolog system.

Figure 5.1 shows an example musical fragment. Table 5.1 shows its correspond-ing data representation.

Figure 5.1: An example score

The incomplete score data structure consists of a tree of terms of the form:

event(index, part, pitch, duration, time, previous, vertical, next, comment,penalty, other)

The tree structure itself is the binary tree implementation included with QuintusProlog [5].

Borrowing from object-oriented programming practice, users of the data struc-ture are encouraged (though not forced) to unify with the fields of each event usinga series of predicates with names such as e pitch and e duration etc.

We will now examine each of these arguments one-by-one.

CHAPTER 5. DATA STRUCTURE 47

t r e e ( e v e n t ( 1 , 1 , p i t c h ( 1 2 , 7 ) , dur ( 1 / 4 ) , time ( 0 , 3 0 0 0 ) , s t a r t ,[ ] , 2 , , , )

e v e n t ( 2 , 1 , p i t c h ( 1 1 , 6 ) , dur ( 1 / 4 ) , time ( 3 0 0 0 , 6 0 0 0 ) , 1 ,[ 1 2 , 9 ] , 3 , , , )

e v e n t ( 3 , 1 , p i t c h ( 9 , 5 ) , dur ( 1 / 4 ) , time ( 6 0 0 0 , 9 0 0 0 ) , 2 ,[ 1 2 ] , 4 , , , )

e v e n t ( 4 , 1 , p i t c h ( 5 , 3 ) , dur ( 1 / 4 ) , time ( 9 0 0 0 , 1 2 0 0 0 ) , 3 ,[ 1 0 , 1 2 ] , 5 , , , )

e v e n t ( 5 , 1 , p i t c h ( 7 , 4 ) , dur ( 1 / 8 ) , time ( 1 2 0 0 0 , 1 3 5 0 0 ) , 4 ,[ 1 0 ] , 6 , , , )

e v e n t ( 6 , 1 , p i t c h ( 9 , 5 ) , dur ( 1 / 8 ) , time ( 1 3 5 0 0 , 1 5 0 0 0 ) , 5 ,[ 1 3 , 1 0 ] , 7 , , , )

e v e n t ( 7 , 1 , p i t c h ( 1 1 , 6 ) , dur ( 1 / 4 ) , time ( 1 5 0 0 0 , 1 8 0 0 0 ) , 6 ,[ 1 3 , 1 0 ] , 8 , , , )

e v e n t ( 8 , 1 , p i t c h ( 1 2 , 7 ) , dur ( 1 / 2 ) , time ( 1 8 0 0 0 , 2 4 0 0 0 ) , 7 ,[ 1 3 ] , end , , , )

e v e n t ( 9 , 2 , p i t c h ( 4 , 2 ) , dur ( 1 / 2 ) , time ( 0 , 6 0 0 0 ) , s t a r t ,[ 1 ] , 1 0 , , , )

e v e n t ( 1 0 , 2 , p i t c h ( 2 , 1 ) , dur ( 1 / 1 ) , time ( 6 0 0 0 , 1 8 0 0 0 ) , 9 ,[ 3 , 1 2 ] , 1 1 , , , )

e v e n t ( 1 1 , 2 , p i t c h ( 0 , 0 ) , dur ( 1 / 2 ) , time ( 1 8 0 0 0 , 2 4 0 0 0 ) , 1 0 ,[ 8 , 1 3 ] , end , , , )

e v e n t ( 1 2 , 3 , p i t c h (−1 2 , −7 ) , dur ( 1 / 1 ) , time ( 0 , 1 2 0 0 0 ) , s t a r t ,[ 9 , 1 ] , 1 3 , , , )

e v e n t ( 1 3 , 3 , p i t c h (−1 2 , −7 ) , dur ( 1 / 1 ) , time ( 1 2 0 0 0 , 2 4 0 0 0 ) , 1 2 ,[ 5 , 1 0 ] , end , , , )

)

Table 5.1: Internal representation of example score

CHAPTER 5. DATA STRUCTURE 48

5.2.1 Index

e index(?Event, ?Index)Each event has a unique index reference number. The indexing of elements is

completely arbitrary, as long as all indexes are unique. All of the events are storedin a binary tree [5] so they can be retrieved by their index in O(lgn) time.1

Figure 5.2 shows example indexes that are likely to occur if the score wereinterpreted from GUIDO.

Figure 5.2: Index values of the example score

5.2.2 Part

e part(?Event, ?Part)Part is an integer value indicating which melodic line, or voice, the event belongs

to.In our example, the first staff, or soprano part, is part 1, the second staff is part

2 and the bottom staff, or cantus firmus is part 3.

5.2.3 Pitch

e pitch(?Event, ?Pitch)Pitches are stored in a format that is loosely adapted from binomial pitch rep-

resentation (BPR) [4]. BPR defines musical pitch using four key attributes: pitchclass, note class, continuous pitch class and continuous note class.

1Originally, an array implementation with constant access time [24] was considered. However,when changes are made to such an array, the old state is lost and can not be restored throughbacktracking. O’Keefe himself describes the array implementation as a “logical hack” that is notsuitable for most logic programming applications. His array implementation is therefore inade-quate for the present problem, in which many different subgoals must be examined before arrivingat a globally optimal solution. Some Prolog implementations have array libraries implementedexternally in C which may work for the present purpose.

CHAPTER 5. DATA STRUCTURE 49

Pitch class is an integer value corresponding to the frequency of the note. Onepitch class degree represents one semi-tone. Pitch class is the standard representa-tion in most electronic music applications, such as MIDI.

Note class is an integer value related to the lines and spaces on the staff. Eachnote class degree corresponds to one of the white keys on keyboard instruments. Thehistorical notation format DARMS uses only note class for pitch representation.

By maintaining both representations, a distinction is made between notes withthe same sounding pitch but different note classes (eg. c# and d&). It also makesdiatonic intervals, which are dependent on note class, much easier to calculate. Thisis an important factor when developing systems, such as the present project, withknowledge of traditional modal and tonal practice.

While pitch class is confined to the range [0 ... 11] and repeats at every octave,continuous pitch class includes the octave as a factor. The same relationship existsbetween note class and continuous note class. Octave numbering follows the con-vention adopted by GUIDO that the octave containing middle C is numbered 0.The octaves below are negative and the octaves above are positive.

The relationship between continuous and non-continuous classes is thereforedefined by the following equations:

continuous-pitch-class = pitch-class + 12 × octavecontinous-note-class = note-class + 7 × octave

Each event in the data structure stores a pitch value in a term of the form:

pitch(continuous-pitch-class, continuous-note-class)

Note that only the continuous classes are explicitly stored in the data structure.Continuous classes are used in calculating intervals, which comprises the majorityof the counterpoint rules in this project. The penalty of converting from continuousto non-continuous classes, for example to determine if a particular note is a memberof a scale, is quite minimal (modulo arithmetic.) Therefore, it is moderately moreefficient to keep track of continuous classes rather than non-continuous classes withan octave value.

Figure 5.3 shows the continuous pitch and note classes of all the events in theexample score.

5.2.4 Duration

e duration(?Event, ?Duration)Every event stores duration information in a term of the following form:

dur(numerator / denominator)

The representation used here is fairly intuitive: durations are written as fractionsof the whole note. This is the same convention used in GUIDO.

Figure 5.4 shows the duration values in the given example.

CHAPTER 5. DATA STRUCTURE 50

Figure 5.3: Pitch and note class values in the example score

Figure 5.4: Duration values in the example score

CHAPTER 5. DATA STRUCTURE 51

5.2.5 Time

e time(?Event, ?Time)Every event stores the absolute time of its onset and offset. Time is stored in a

term of the form:

time(start, end)

Absolute time is given as an integer value where 0 is the start of the score andeach whole note unit thereafter is a factor of some constant. By default, this con-stant is 12000, because it is divisible by most of the commonly occurring durationdenominators such as 2, 3, 4, 8, 9 and 16.

The time values of events can be derived automatically, when duration, previousand next are non-variable, by using the set event time/2 predicate.

Figure 5.5 shows the time values in the example using a time precision constantof 12000.

Figure 5.5: Time values in the example score

5.2.6 Previous and Next

e prev(?Event, ?Prev)e next(?Event, ?Next)

The previous and next values define the horizontal relationships between notes.The previous and next fields contain the index of the events preceding and followinga given event.

The previous field of the first event in each part contains the atom start. Thenext field in the last event of each part contains the atom end.

5.2.7 Vertical

e vertical(?Event, ?Vertical)The vertical field defines the vertical relationships between notes. Perhaps

counter-intuitively, the vertical field does not contain the indexes of all events oc-curring at the same time in other parts. Instead, the field contains directed vectors

CHAPTER 5. DATA STRUCTURE 52

Figure 5.6: Previous references in the example score

Figure 5.7: Next references in the example score

CHAPTER 5. DATA STRUCTURE 53

to other events that will require vertical relationship examination. The set of vec-tors in all events represents the minimum number of vectors required to specify allvertical relationships. The predicate build verticals creates these vectors using thefollowing criteria:

• Eliminate redundant vectors to improve efficiency. Vertical relation-ships are symmetric, therefore if the vector X → Y is defined, the vectorY → X does not need to also be defined. This will prevent the same verticalrelationship from being “tested” twice.

• No vector points to a previously unexamined event. This improvesefficiency by ensuring that vertical rules will never generate new results, butwill only verify that the results of horizontal rules meet vertical criteria.

The former criteria is simple enough to understand on its own. The explainthe latter, however, requires taking a diversion into the concept of time-paths. Theconcept of time-path presented here is generally based on Schaffer & McGee’s [32]time-spine. The time-path defines the order in which the events will be visited bythe rule-applying mechanism. For lack of a better ordering scheme, the time-pathis created by sorting all the events by their start times. (If experimentation revealsa more efficient order, this could change.) In our example, the events will be visitedin the order shown in Figure 5.8.

Figure 5.8: The time-path of the example score

As stated above, the vertical vectors should never point to unvisited events.Therefore, the vertical vectors are generated from a reversed time-path. The verticalvectors in the example are given in Figure 5.9

Note that all vectors point either vertically or backwards.

5.2.8 Comments

e comment(?Event, ?Comment)

CHAPTER 5. DATA STRUCTURE 54

Figure 5.9: The vertical relationships of the example score

The comment field contains a list of the rules that were applied to the event.This information is output as comments in the GUIDO code. This field allowsthe system to function as a primitive musical expert system, providing feedbackrevealing how pitches were chosen or penalties were applied.

This list is implemented as an improper list so that an arbitrary number ofcomments can be added throughout execution.

5.2.9 Penalty

e penalty(?Event, ?Penalty)The penalty field contains the sum of all penalties applied to the event. This, in

conjunction with the comment field, creates a simple musical expert system. Theuser can discover which events were severely penalized and in the most need ofimprovement.

5.2.10 Other

The other field is reserved for future use.

6Code and Testing

6.1 The Pelog-GUI

6.1.1 pelog-gui.tcl

Code

## PELOG−GUI#

################################################ MAIN WINDOW

###############################################

# s t a r t g u i i n i t i a l i s e s the main e d i t i n g windowpro c s t a r t g u i {} {

g l o b a l PG mainframe menuCount t c l p l a t f o r m

t o p l e v e l . mainframewm withdraw . mainframe

s e t Parent . mainframe

# Menu frames e t menuframe $Parent . menuframeframe $menuframepack $menuframe \

−anchor nw \−s i d e top \−expand 0 \− f i l l x

# Too lbar f rame

55

CHAPTER 6. CODE AND TESTING 56

s e t t o o l b a r f r a m e $Parent . b u t t o n sframe $ t o o l b a r f r a m epack $ t o o l b a r f r a m e \

−anchor nw \−s i d e top \−expand 0 \− f i l l x \−padx 5 \−pady 3

# Menu d e f i n i t i o n ss e t m e n u f i l e $menuframe . f i l es e t Menu Str ing ( $ m e n u f i l e ) {

{{ t e a r o f f } { no } {}}{{command} {New} \

{−command f i l e n e w − a c c e l e r a t o r "Ctrl+N" −u n d e r l i n e 0}}{{command} {Open . . . } \

{−command f i l e o p e n − a c c e l e r a t o r "Ctrl+O" −u n d e r l i n e 0}}{{command} {Open URL . . . } \

{−command f i l e o p e n u r l − a c c e l e r a t o r "Ctrl+U" −u n d e r l i n e 5}}{{command} { R e v e r t } \

{−command f i l e r e v e r t − a c c e l e r a t o r "Ctrl+R" −u n d e r l i n e 0}}{{ s e p a r a t o r } {} {}}{{command} { Save } \

{−command f i l e s a v e − a c c e l e r a t o r "Ctrl+S" −u n d e r l i n e 0}}{{command} { Save As . . . } \

{−command f i l e s a v e a s − a c c e l e r a t o r "Ctrl+W" −u n d e r l i n e 5}}{{ s e p a r a t o r } {} {}}{{command} { E x i t } \

{−command f i l e e x i t − a c c e l e r a t o r "Alt+F4" −u n d e r l i n e 1}}}c o n s t r u c t m e n u $ m e n u f i l e F i l e $Menu Str ing ( $ m e n u f i l e )

s e t menuedit $menuframe . e d i ts e t Menu Str ing ( $menuedit ) {

{{ t e a r o f f } { no } {}}{{command} {Cut } \

{−command e d i t c u t − a c c e l e r a t o r "Ctrl+X" −u n d e r l i n e 2}}{{command} {Copy } \

{−command e d i t c o p y − a c c e l e r a t o r "Ctrl+C" −u n d e r l i n e 0}}{{command} { Paste } \

{−command e d i t p a s t e − a c c e l e r a t o r "Ctrl+V" −u n d e r l i n e 0}}{{command} { C l e a r } \

{−command e d i t c l e a r − a c c e l e r a t o r "Del" −u n d e r l i n e 3}}}c o n s t r u c t m e n u $menuedit E d i t $Menu Str ing ( $menuedit )

s e t menuview $menuframe . v iews e t Menu Str ing ( $menuview ) {

{{ t e a r o f f } { no } {}}{{command} { Look } \

CHAPTER 6. CODE AND TESTING 57

{−command v i e w l o o k − a c c e l e r a t o r "Ctrl+L" −u n d e r l i n e 0}}{{command} {Hear } \

{−command v i e w h e a r − a c c e l e r a t o r "Ctrl+H" −u n d e r l i n e 0}}}c o n s t r u c t m e n u $menuview View $Menu Str ing ( $menuview )

s e t m e n u r u l e s $menuframe . r u l e ss e t Menu Str ing ( $menuru le s ) {

{{ t e a r o f f } { no } {}}{{command} { S e l e c t r u l e s e t . . . } \

{−command r u l e s b r o w s e − a c c e l e r a t o r "Ctrl+R" −u n d e r l i n e 0}}{{command} {Go ! } \

{−command r u l e s a p p l y − a c c e l e r a t o r "Ctrl+G" −u n d e r l i n e 0}}}c o n s t r u c t m e n u $menuru le s R u l e s $Menu Str ing ( $menuru le s )

# Too lbar but ton d e f i n i t i o n sc o n s t r u c t b u t t o n $ t o o l b a r f r a m e . new "images/filenew.gif" \

"file_new" "New"c o n s t r u c t b u t t o n $ t o o l b a r f r a m e . open "images/fileopen.gif" \

"file_open" "Open"c o n s t r u c t b u t t o n $ t o o l b a r f r a m e . s a v e "images/filesave.gif" \

"file_save" "Save"c o n s t r u c t s p a c e r $ t o o l b a r f r a m e . s p a c e r 0c o n s t r u c t b u t t o n $ t o o l b a r f r a m e . c ut "images/editcut.gif" \

"edit_cut" "Cut"c o n s t r u c t b u t t o n $ t o o l b a r f r a m e . copy "images/editcopy.gif" \

"edit_copy" "Copy"c o n s t r u c t b u t t o n $ t o o l b a r f r a m e . p a s t e "images/editpaste.gif" \

"edit_paste" "Paste"c o n s t r u c t s p a c e r $ t o o l b a r f r a m e . s p a c e r 1c o n s t r u c t b u t t o n $ t o o l b a r f r a m e . l o o k "images/viewlook.gif" \

"view_look" "Look"c o n s t r u c t b u t t o n $ t o o l b a r f r a m e . h e a r "images/viewhear.gif" \

"view_hear" "Hear"c o n s t r u c t s p a c e r $ t o o l b a r f r a m e . s p a c e r 2c o n s t r u c t b u t t o n $ t o o l b a r f r a m e . go "images/rulesapply.gif" \

"rules_apply" "Go"c o n s t r u c t s p a c e r $ t o o l b a r f r a m e . s p a c e r 3

button $ t o o l b a r f r a m e . browse \−t e x t { S e l e c t r u l e s e t : } \−command { r u l e s b r o w s e } \−c u r s o r hand2 \−h e i g h t 1

pack $ t o o l b a r f r a m e . browse \−anchor w \−s i d e l e f t \−expand 0 \− f i l l x

CHAPTER 6. CODE AND TESTING 58

c o n s t r u c t s p a c e r $ t o o l b a r f r a m e . s p a c e r 4

t e x t $ t o o l b a r f r a m e . t e x t − h e i g h t 1 − padx 5pack $ t o o l b a r f r a m e . t e x t \

−anchor w \−s i d e l e f t \−expand 1 \− f i l l x

# Main window s e t t i n g swm geometry . mainframe 640 x480wm m i n s i z e . mainframe 3 2 0 2 4 0

# Text e d i t o rc o n s t r u c t e d i t o r . mainframe

# Ready to go . . .wm d e i c o n i f y . mainframef i l e n e wu p d a t e r u l e s e tupdate

}

################################################ MENU CONSTRUCTION

###############################################

# c o n s t r u c t m e n u adds a new menu to t he menubarpro c c o n s t r u c t m e n u {Name l a b e l c m d l i s t } {

g l o b a l PG

menubutton $Name \−t e x t $ l a b e l \−u n d e r l i n e 0

i n c r PG ( menuCount ) ;s e t newmenu $Name . m$ PG( menuCount )$Name c o n f i g u r e −menu $newmenuc a t c h "destroy $newmenu"e v a l "menu $newmenu"e v a l [ l i s t a d d i t e m s t o m e n u $newmenu $ c m d l i s t ]pack $Name \

−anchor nw \−expand 0 \−i p a d x 4 \−s i d e l e f t

}

# a d d i t e m s t o m e n u adds i n d i v i d u a l i t e m s to a g i v e n menu# i n t he menu bar . Th i s p r o c e d u r e i s c a l l e d by c o n s t r u c t m e n upro c a d d i t e m s t o m e n u {menubutton cmdLis t } {

CHAPTER 6. CODE AND TESTING 59

g l o b a l PG ( menuCount )

f o r e a c h cmd $cmdLis t {s w i t c h [ l i n d e x $cmd 0 ] {

"separator" {s e t d o i t "$menubutton add separator [lindex $cmd 2]"e v a l $ d o i t

}"tearoff" {

i f { [ s t r i n g match [ l i n d e x $cmd 1 ] "no" ] } {$menubutton c o n f i g u r e − t e a r o f f no

}}"command" {

s e t d o i t "$menubutton add [lindex $cmd 0] \− l a b e l { [ l i n d e x $cmd 1 ] } \[ l i n d e x $cmd 2 ] "

e v a l $ d o i t}"cascade" {

i n c r PG ( menuCount ) ;s e t newmenu $menubutton . m$ PG( menuCount )s e t d o i t "$menubutton add cascade \

− l a b e l { [ l i n d e x $cmd 1 ] } \−menu $newmenu"

e v a l $ d o i tmenu $newmenua d d i t e m s t o m e n u $newmenu [ l i n d e x $cmd 2 ]

}}

}}

################################################ TOOLBAR BUTTON CONSTRUCTION

###############################################

# c r e a t e s an image buttonpro c c o n s t r u c t b u t t o n {Name f i l e cmd helpmsg } {

s e t im [ image c r e a t e photo − f i l e $ f i l e ]

but ton $Name \−image $im \−t e x t $helpmsg \− j u s t i f y c e n t e r \−c u r s o r hand2 \− r e l i e f r a i s e d \−command "$cmd" \−padx 0 − pady 0

pack $Name \

CHAPTER 6. CODE AND TESTING 60

−anchor nw \−s i d e l e f t \−expand 0 \− f i l l x

}

# c r e a t e s a s p a c e r f o r th e t o o l b a rpro c c o n s t r u c t s p a c e r {Name} {

l a b e l $Name − t e x t " "pack $Name \

−anchor nw \−s i d e l e f t \−expand 0 \− f i l l x

}

################################################ EDITOR CONSTRUCTION

###############################################

# c r e a t e s t he t e x t e d i t o r and s c r o l l b a rpro c c o n s t r u c t e d i t o r {Name} {

f rame $Name . textFramepack $Name . textFrame \

−anchor sw \−expand 1 \− f i l l both \−s i d e bottom

frame $Name . textFrame . r i g h tpack $Name . textFrame . r i g h t \

−anchor s e \−expand 0 \− f i l l y \−s i d e r i g h t

s c r o l l b a r $Name . textFrame . r i g h t . v e r t S c r o l l b a r \−command "$Name.textFrame.left.text yview" \−width 12

pack $Name . textFrame . r i g h t . v e r t S c r o l l b a r \−anchor c e n t e r \−expand 0 \− f i l l y \−s i d e r i g h t

frame $Name . textFrame . l e f tpack $Name . textFrame . l e f t \

−anchor c e n t e r \−expand 1 \− f i l l both \−s i d e l e f t

CHAPTER 6. CODE AND TESTING 61

t e x t $Name . textFrame . l e f t . t e x t \−ysc ro l l command "$Name.textFrame.right.vertScrollbar set" \−f o n t {{ Andale Mono} 9 { normal }}

pack $Name . textFrame . l e f t . t e x t \−anchor c e n t e r \−expand 1 \− f i l l both \−s i d e l e f t

b i n d $Name . textFrame . l e f t . t e x t <KeyPress> m a k e d i r t y

update}

################################################ SPLASH WINDOW

###############################################

# d i s p l a y s t he s p l a s h windowpro c s p l a s h {} {

wm withdraw .

t o p l e v e l . s p l a s h

frame . s p l a s h . mainframepack . s p l a s h . mainframe

wm t i t l e . s p l a s h { }wm r e s i z a b l e . s p l a s h 0 0f o c u s − f o r c e . s p l a s h

button . s p l a s h . mainframe . main \−image [ image c r e a t e photo − f i l e "images/splash.gif" ] \−b o r d e r w i d t h 0 \−command s p l a s h b u t t o n

pack . s p l a s h . mainframe . main

update}

# removes t he s p l a s h windowpro c s p l a s h b u t t o n {} {

wm withdraw . s p l a s hs t a r t g u i

}

################################################ FILE FUNCTIONS

###############################################

CHAPTER 6. CODE AND TESTING 62

# c l e a r s t he t e x t e d i t o r and f i l e n a m epro c f i l e n e w {} {

g l o b a l PG

i f { $ PG ( d i r t y ) == 1} {s e t outcome l o s e c h a n g e si f { $outcome == "no" } { r e t u r n }

}

s e t PG ( d i r t y ) 0. mainframe . textFrame . l e f t . t e x t d e l e t e 1 . 0 ends e t PG ( f i l e ) ""

u p d a t e t i t l e b a rupdate

}

# l o a d s a f i l e i n t o th e e d i t o rpro c f i l e o p e n {} {

g l o b a l PG

f i l e n e w

s e t PG ( f i l e ) [ t k g e t O p e n F i l e \−d e f a u l t e x t e n s i o n . gmn \− f i l e t y p e s {{{GUIDO Music N o t a t i o n } { . gmn}}} \−p a r e n t . mainframe \− t i t l e {Open . . . } ]

i f { $ PG ( f i l e ) == "" } { r e t u r n }i f { ! [ f i l e r e a d a b l e $ PG ( f i l e ) ] } {

s h o w e r r o r "File \[$_PG(file)\] is not readable."r e t u r n

}

i f { [ c a t c h "open $_PG(file) r" f d ] } {s h o w e r r o r "Error while opening $_PG(file): \[$fd\]"r e t u r n

}

. mainframe . textFrame . l e f t . t e x t i n s e r t end [ r e a d $fd ]c l o s e $ fd

u p d a t e t i t l e b a rupdate

}

# opens t he c u r r e n t f i l e from d i s k i n t o the e d i t o rpro c f i l e r e v e r t {} {

g l o b a l PG

CHAPTER 6. CODE AND TESTING 63

i f { $ PG ( d i r t y ) == 1} {s e t outcome l o s e c h a n g e si f { $outcome == "no" } { r e t u r n }

}

s e t PG ( d i r t y ) 0. mainframe . textFrame . l e f t . t e x t d e l e t e 1 . 0 end

i f { [ c a t c h "open $_PG(file) r" f d ] } {s h o w e r r o r "Error while opening $_PG(file): \[$fd\]"r e t u r n

}

. mainframe . textFrame . l e f t . t e x t i n s e r t end [ r e a d $fd ]c l o s e $ fd

}

# s a v e s t he c u r r e n t f i l e . I f no f i l e n a m e e x i s t s , prompts f o r onepro c f i l e s a v e {} {

g l o b a l PG

i f { $ PG ( d i r t y ) == 0} { r e t u r n }i f { $ PG ( f i l e ) == "" } { f i l e s a v e a s }i f { [ f i l e e x i s t s $ PG ( f i l e ) ] } {

i f { ! [ f i l e w r i t a b l e $ PG ( f i l e ) ] } {s h o w e r r o r "File \[$PG(file)\] is not writable."r e t u r n

}}

i f { [ c a t c h "open $_PG(file) w" f d ] } {s h o w e r r o r "Error writing to $_PG(file): \[$fd\]"r e t u r n

}

p u t s $ fd "[.mainframe.textFrame.left.text get 1.0 end]"c l o s e $ fd

s e t PG ( d i r t y ) 0}

# Prompts f o r a new f i l e n a m e and s a v e s to d i s kpro c f i l e s a v e a s {} {

g l o b a l PG

s e t PG ( f i l e ) [ t k g e t S a v e F i l e \−d e f a u l t e x t e n s i o n . gmn \− f i l e t y p e s {{{GUIDO Music N o t a t i o n } { . gmn}}} \−p a r e n t . mainframe \− t i t l e { Save As . . . } \− i n i t i a l f i l e $ PG ( f i l e ) ]

CHAPTER 6. CODE AND TESTING 64

f i l e s a v e

u p d a t e t i t l e b a rupdate

}

# c l o s e s t he Pe log GUIpro c f i l e e x i t {} {

e x i t}

# I f t he t e x t e d i t o r i s ’ d i r t y ’ , e n s u r e t h a t t he u s e r i s i n t e n d s to l o s e# changespro c l o s e c h a n g e s {} {

tk messageBox \−d e f a u l t no \−t y p e yesno \−message {Any unsaved changes w i l l be l o s t . Proceed anyway ?} \−p a r e n t . mainframe \− t i t l e { Lose changes ?}

}

################################################ EDITING ( CLIPBOARD ) FUNCTIONS

###############################################

pro c e d i t c u t {} {t k t e x t C u t . mainframe . textFrame . l e f t . t e x t

}

pro c e d i t c o p y {} {t k t e x t C o p y . mainframe . textFrame . l e f t . t e x t

}

pro c e d i t p a s t e {} {t k t e x t P a s t e . mainframe . textFrame . l e f t . t e x t

}

pro c e d i t c l e a r {} {. mainframe . textFrame . l e f t . t e x t d e l e t e s e l . f i r s t s e l . l a s t

}

################################################ VIEWING FUNCTIONS

###############################################

pro c v i e w l o o k {} {g l o b a l PGsave tempe x e c command . com / c gmnview . exe temp . gmn &

CHAPTER 6. CODE AND TESTING 65

update}

pro c v i e w h e a r {} {g l o b a l PGsave tempc a t c h "exec gmn2midi.exe temp.gmn"updatec a t c h "exec mplayer.exe -play temp.mid &"update

}

# s a v e s t he c o n t e n t s o f the e d i t o r i n a temporary f i l e so i t can# be v iewed by an e x t e r n a l programpro c save temp {} {

s e t f i l e temp . gmn

i f { [ f i l e e x i s t s $ f i l e ) ] } {i f { ! [ f i l e w r i t a b l e $ f i l e ) ] } {

s h o w e r r o r "File \[$file\] is not writable."r e t u r n

}}

i f { [ c a t c h "open $file w" f d ] } {s h o w e r r o r "Error writing to $file: \[$fd\]"r e t u r n

}

p u t s $ fd "[.mainframe.textFrame.left.text get 1.0 end]"c l o s e $ fd

}

################################################ RULES FUNCTIONS

###############################################

pro c r u l e s a p p l y {} {g l o b a l PG

i f { $ PG ( r u l e s ) == "" } {s h o w e r r o r "You need to specify a rule set before you can apply rules."r u l e s b r o w s e

}

s e t outcome [ tk messageBox \−d e f a u l t ok \−t y p e o k c a n c e l \−message "Apply $_PG(rules) to the currently open buffer?" \−p a r e n t . mainframe \− t i t l e { Apply r u l e s ?} ]

CHAPTER 6. CODE AND TESTING 66

i f { $outcome == "cancel" } { r e t u r n }

save temp

s e t o u t f i l e [ s t r i n g t r i m r i g h t $ PG ( f i l e ) . gmn ] out . gmnc a t c h "exec plcon.exe -t [main]. -g go(’temp.gmn’, ’$outfile’, $_PG(rules))."

i f { $ PG ( h a s s l a v e ) == "" } {s e t PG ( r u n s l a v e ) [ i n t e r p c r e a t e r u n s l a v e ]r u n s l a v e e v a l { l o a d {} Tk}r u n s l a v e e v a l { s o u r c e p e l o g−g u i . t c l }r u n s l a v e e v a l s p l a s h b u t t o ns e t PG ( h a s s l a v e ) y e s }

$ PG ( r u n s l a v e ) e v a l s e t PG ( f i l e ) $ o u t f i l e$ PG ( r u n s l a v e ) e v a l f i l e r e v e r t

}

pro c r u l e s b r o w s e {} {g l o b a l PG

s e t PG ( r u l e s ) [ t k g e t O p e n F i l e \−d e f a u l t e x t e n s i o n . p r s \− f i l e t y p e s {{{ Pelog r u l e s e t } { . p r s }}} \−p a r e n t . mainframe \− t i t l e { S e l e c t a Pe log r u l e s e t . . . } \− i n i t i a l f i l e $ PG ( r u l e s ) ]

u p d a t e r u l e s e t}

################################################ HELPER FUNCTIONS

###############################################

# c a l l e d when a change i s made i n the e d i t o rpro c m a k e d i r t y {} {

g l o b a l PGs e t PG ( d i r t y ) 1

}

# c a l l e d when t he name o f the open f i l e changespro c u p d a t e t i t l e b a r {} {

g l o b a l PG

wm t i t l e . mainframe "Pelog GUI - $_PG(file)"update

}

# c a l l e d when t he name o f the r u l e s e t changespro c u p d a t e r u l e s e t {} {

g l o b a l PG

CHAPTER 6. CODE AND TESTING 67

. mainframe . b u t t o n s . t e x t d e l e t e 1 . 0 end

. mainframe . b u t t o n s . t e x t i n s e r t end $ PG ( r u l e s )update

}

pro c s h o w e r r o r {message } {tk messageBox \

−t y p e ok \−message $message \−p a r e n t . mainframe \−i c o n e r r o r \− t i t l e { E r r o r }

}

################################################ INIT FUNCTIONS

###############################################

f o r e a c h g l o b a l v a r [ i n f o g l o b a l s ∗PG∗ ] {g l o b a l $ g l o b a l v a rc a t c h "unset $globalvar" dummy

}

f o r e a c h g l o b a l v a r [ i n f o g l o b a l s ∗ pg ∗ ] {g l o b a l $ g l o b a l v a rc a t c h "unset $globalvar" dummy

}

s e t PG ( menuCount ) 0 ;s e t PG ( f i l e ) ""s e t PG ( r u n s l a v e ) ""s e t PG ( f i l e ) ""s e t PG ( t e m p f i l e ) ""s e t PG ( f i l e k e y n a m e ) ""s e t PG ( d i r t y ) 0s e t PG ( r u l e s ) ""s e t PG ( h a s s l a v e ) ""

c a t c h "destroy .mainframe"d e s t r o y . t o p l e v e l

s p l a s h

6.2 The Core Interpreter

6.2.1 pelog.pl

Code

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗PRELIMINARY MAIN MODULE

CHAPTER 6. CODE AND TESTING 68

M i c ha e l DroettboomMay 1999

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗REQUIRED LIBRARIES

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

:− e n s u r e l o a d e d (’library/main.pl’ ) .:− e n s u r e l o a d e d (’core/main.pl’ ) .:− e n s u r e l o a d e d (’guido/main.pl’ ) .

:− d i s c o n t i g u o u sr u l e d e f / 3 ,r u l e / 2 ,g l o b a l d e f a u l t / 2 .

:− m u l t i f i l eg l o b a l d e f a u l t / 2 .

t e s t :− go (’thakar-p176.gmn’ , ’thakar-p176out.gmn’ , ’rule-sets/modal_counterpoint.pl’ ) .

go ( I n F i l e , O u t F i l e , R u l e F i l e ) :−l o a d r u l e s ( R u l e F i l e ) , ! ,l o a d s c o r e ( I n F i l e , T , TimePath ) , ! ,a l l s o l u t i o n s (T , TimePath ) ,b e s t r e s u l t ( P e n a l t y , Best ) ,n l , n l , w r i t e (’SUCCEEDED! ==========================>’ ) , n l ,w r i t e (’Overall Penalty: ’ ) , w r i t e ( P e n a l t y ) , n l , n l ,p r i n t t r e e ( Best ) , ! ,s a v e s c o r e ( O u t F i l e , T , TimePath ) .

p r i n t t r e e (T) :−t r e e t o l i s t (T , L i s t ) ,f o r a l l ( member ( Item , L i s t ) , ( w r i t e ( I tem ) , n l ) ) .

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗

PRIVATE PREDICATES∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

a l l s o l u t i o n s (T , TimePath ) :−s t a r t p e n a l t y , ! ,o r g a n i z e r u l e s ( R u l e s ) , n l ,w r i t e (’Time Path: ’ ) , w r i t e ( TimePath ) , n l , n l ,

CHAPTER 6. CODE AND TESTING 69

w r i t e (’Event tree as input: ’ ) , n l ,p r i n t t r e e (T ) , n l , n l ,w r i t e (’Tags: ’ ) ,l i s t i n g ( g l o b a l ) ,a p p l y r u l e s (T , TimePath , R u l e s , p e n a l t y ( 0 , P ) ) ,s t o r e r e s u l t (P , T ) .

a p p l y r u l e s ( , [ ] , , p e n a l t y (P , P ) ) .a p p l y r u l e s (T , [ ( , I n d e x ) | TimePath ] , R u l e s , p e n a l t y ( PenIn , PenOut ) ) :−

g e t l a b e l ( I n d e x , T , E ) ,e v e r t i c a l (E , V ) ,a p p l y r u l e s 0 (T , E , V , R u l e s , p e n a l t y ( PenIn , PenOut0 ) ) ,b l o c k ( I n d e x ,

a p p l y r u l e s (T , TimePath , R u l e s , p e n a l t y ( PenOut0 , PenOut ) ) ,Y) −>(Y == f a i l −> f a i l ; t r u e ) .

a p p l y r u l e s 0 (T , E , [ ] , R u l e s , P e n a l t y ) :−p a c k a g e p a r a m e t e r (T , E , [ ] , Param ) ,a p p l y r u l e s 1 (E , Param , R u l e s , P e n a l t y ) .

a p p l y r u l e s 0 (T , E , [ Ver t ] , R u l e s , P e n a l t y ) :−p a c k a g e p a r a m e t e r (T , E , Ver t , Param ) ,a p p l y r u l e s 1 (E , Param , R u l e s , P e n a l t y ) .

a p p l y r u l e s 0 (T , E , [ VertHead | V e r t T a i l ] , R u l e s , p e n a l t y ( PenIn , PenOut ) ) :−p a c k a g e p a r a m e t e r (T , E , VertHead , Param ) ,a p p l y r u l e s 1 (E , Param , R u l e s , p e n a l t y ( PenIn , PenOut0 ) ) ,a p p l y r u l e s 0 (T , E , V e r t T a i l , R u l e s , p e n a l t y ( PenOut0 , PenOut ) ) .

a p p l y r u l e s 1 ( , , [ ] , p e n a l t y (P , P ) ) .a p p l y r u l e s 1 (E , Param , [ R u l e C l a s s | R u l e T a i l ] , p e n a l t y ( PenIn , PenOut ) ) :−

g l o b a l s e t ( d i r e c t i o n , f o r w a r d ) ,a p p l y r u l e s 1 (E , Param , R u l e T a i l , p e n a l t y ( PenIn , PenOut0 ) ) ,( e p i t c h (E , P i t c h ) ,nonvar ( P i t c h ) −>

once ( ( member ( R u l e L e v e l , R u l e C l a s s ) ,a p p l y r u l e c l a s s (E , Param , R u l e L e v e l , p e n a l t y ( PenOut0 , PenOut ) ) ) )

;( member ( R u l e L e v e l , R u l e C l a s s ) ,a p p l y r u l e c l a s s (E , Param , R u l e L e v e l , p e n a l t y ( PenOut0 , PenOut ) ) ) );( [ [ ( , , , F a i l T o ) | ] | ] = R u l e C l a s s ,a p p l y r u l e c l a s s f a i l ( F a i l T o , Param ) ) .

a p p l y r u l e c l a s s (E , Param , R u l e L e v e l , P e n a l t y ) :−( member ( ( PenValue , Rule , C l a s s , F a i l T o ) , R u l e L e v e l ) ,a p p l y r u l e (E , Param , PenValue , C l a s s , Rule , F a i l T o , P e n a l t y ) ) .

a p p l y r u l e c l a s s f a i l ( 1 , ) :− ! , f a i l .a p p l y r u l e c l a s s f a i l ( 1 1 , ) :− ! , f a i l .a p p l y r u l e c l a s s f a i l ( F a i l T o , Param ) :−

g l o b a l ( d i r e c t i o n , f o r w a r d ) ,

CHAPTER 6. CODE AND TESTING 70

w r i t e (’Special Fail: ’ ) , w r i t e ( F a i l T o ) ,a rg ( F a i l T o , Param , X ) ,e i n d e x (X , F a i l T o I n d e x ) ,w r i t e (’ Going back to --> ’ ) , w r i t e ( F a i l T o I n d e x ) , n l ,g l o b a l s e t ( d i r e c t i o n , backward ) ,f a i l ( F a i l T o I n d e x ) .

a p p l y r u l e (E , Param , P e n a l t y , C l a s s , Rule , , p e n a l t y ( PenIn , PenOut ) ) :−e i n d e x (E , I n d e x ) ,g e t r e p (E , PName , Octave ) ,( r u l e ( Rule , C l a s s , Param) ∗−>

( a d d p e n a l t y ( P e n a l t y , PenIn , PenOut ) ,w r i t e (’Event ’ ) , w r i t e ( I n d e x ) , w r i t e ( ’: ’ ) ,w r i t e (PName ) , w r i t e ( Octave ) ,w r i t e ( ’ --> ’ ) ,w r i t e ( C l a s s ) , w r i t e ( ’::’ ) , w r i t e ( Rule ) , n l ) ;

( w r i t e (’Event ’ ) , w r i t e ( I n d e x ) , w r i t e ( ’: ’ ) ,w r i t e (PName ) , w r i t e ( Octave ) ,w r i t e ( ’ -/> ’ ) , w r i t e ( C l a s s ) ,w r i t e ( ’::’ ) , w r i t e ( Rule ) , n l , f a i l )

) .

g e t r e p (E , ’~’ , ’’ ) :−e p i t c h (E , P ) ,v a r (P ) , ! .

g e t r e p (E , PName , Octave ) :−p i t c h n a m e o c t a v e (E , PName , Octave ) , ! .

6.2.2 main.pl

Code

%%%%%%%%%%%%%%%%%%%%%%%% CORE MAIN MODULE%%%%%%%%%%%%%%%%%%%%%%%

% Simply e n s u r e s t h a t a l l the Pe log c o r e l i b r a r i e s a r e l o a d e d

:− e n s u r e l o a d e d ( b i−math ) .:− e n s u r e l o a d e d ( message ) .:− e n s u r e l o a d e d ( p r e p r o c e s s o r ) .:− e n s u r e l o a d e d ( r u l e−d e f ) .:− e n s u r e l o a d e d ( s c o r e ) .:− e n s u r e l o a d e d ( t r e e s ) .

6.2.3 bi-math.pl

Code

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗BI−DIRECTIONAL MATH LIBRARYG e n e r a t i v e math f u n c t i o n s

CHAPTER 6. CODE AND TESTING 71

Some o f t h e s e f u n c t i o n s a r e i n t e g e r v e r s i o n s o f t he Quintusf l o a t i n g−p o i n t math l i b r a r y , math . p l

M i c ha e l DroettboomMay 1999

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗OPPOSITE

o p p o s i t e (?X , ? Y)m a i n t a i n s X = −Y

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

o p p o s i t e (X , Y) :−nonvar (X ) ,Y i s X ∗ − 1 , ! .

o p p o s i t e (X , Y) :−nonvar (Y ) ,X i s Y ∗ − 1 , ! .

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗FACTOR

f a c t o r (?X , ? Y , ? Z , ? F )m a i n t a i n s X = Z ∗ F + Y , where Y < Z, −8 < F < 8 .

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

f a c t o r ( 0 , 0 , , 0 ) .f a c t o r (X , X , Z , 0 ) :−

nonvar (Z ) ,g e t i n t e g e r (X ) ,X > 0 ,X < Z .

f a c t o r (X , Y , Z , F ) :−nonvar (X ) ,nonvar (Z ) ,X \= 0 ,Y1 i s X mod Z ,F1 i s X / / Z ,(Y1 < 0 ∗−>

(Y i s Y1 + Z ,F i s F1 − 1)

;(Y i s Y1 , F i s F1 ) ) ,F \= 0 .

f a c t o r (X , Y , Z , F ) :−v a r (X ) ,nonvar (Y ) ,nonvar (Z ) ,

CHAPTER 6. CODE AND TESTING 72

Y < Z ,g e t i n t e g e r ( F ) ,F \= 0 ,X i s Z ∗ F + Y .

g e t i n t e g e r ( I ) :−member ( I , [ 0 , 1 , − 1 , 2 , − 2 , 3 , − 3 , 4 , − 4 , 5 , − 5 ,6 , − 6 , 7 , − 7 , 8 , − 8 , 9 , − 9 , 1 0 , − 1 0 , 1 1 , − 1 1 , 1 2 , − 1 2 ] ) .

Testing

1 ?− [ b i−math ] .

b i−math c o m p i l e d , 0 . 0 0 s e c , 2 , 2 3 6 b y t e s .

Yes2 ?− o p p o s i t e ( 5 , X ) .

X = −5 ;

No3 ?− o p p o s i t e (Y , 3 ) .

Y = −3 ;

No4 ?− o p p o s i t e (−12 , X ) .

X = 1 2 ;

No5 ?− o p p o s i t e (X , Y ) .

No6 ?− o p p o s i t e ( 5 , − 3 ) .

No7 ?− f a c t o r ( 0 , X , Y , Z ) .

X = 0Y = G297Z = 0 ;

No8 ?− f a c t o r ( 1 , X , Y , Z ) .

No9 ?− f a c t o r ( 1 , X , Y , 0 ) .

No10 ?− f a c t o r (X , Y , 3 , 0 ) .

CHAPTER 6. CODE AND TESTING 73

X = 0Y = 0 ;

X = 1Y = 1 ;

X = 2Y = 2 ;

No11 ?− f a c t o r ( 1 , Y , 3 , F ) .

Y = 1F = 0 ;

No12 ?− f a c t o r (−1 , Y , − 3 , F ) .

Y = −4F = −1 ;

No13 ?− f a c t o r (X , 3 , 5 , F ) .

X = 3F = 0 ;

X = 8F = 1 ;

X = −2F = −1 ;

X = 13F = 2 ;

X = −7F = −2 ;

X = 18F = 3 ;

X = −12F = −3 ;

X = 23F = 4 ;

X = −17F = −4 ;

CHAPTER 6. CODE AND TESTING 74

X = 28F = 5 ;

X = −22F = −5 ;

X = 33F = 6 ;

X = −27F = −6 ;

X = 38F = 7 ;

X = −32F = −7 ;

X = 43F = 8 ;

X = −37F = −8 ;

X = 48F = 9 ;

X = −42F = −9 ;

X = 53F = 1 0 ;

X = −47F = −10 ;

X = 58F = 1 1 ;

X = −52F = −11 ;

X = 63F = 1 2 ;

X = −57F = −12 ;

6.2.4 preprocessor.pl

Code

CHAPTER 6. CODE AND TESTING 75

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗PREPROCESSOR FOR RULE FILES

M i c ha e l DroettboomMay 1999

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

/∗This p r e−p r o c e s s o r module i s d e s i g n e d to make w r i t i n g r u l e s e t s as c o n c i s e asp o s s i b l e . Every r u l e i s s e n t a l a r g e number o f v a r i a b l e s by t he r u l ei n t e r p r e t e r . Rather than l i s t i n g a l l t h e s e p a r a m e t e r s w i t h e v e r yr u l e , the p r e p r o c e s s o r p e r f o r m s some magic so t h a t r u l e s o n l y need maker e f e r e n c e to ’ meta−v a r i a b l e s ’ t h a t a r e l i n k e d at c o m p i l e−t ime to t hea c t u a l v a r i a b l e s . These meta−v a r i a b l e s by c o n v e n t i o n a l w a y s b e g i nw i t h ’ $ ’ and a r e d e f i n e d i n p r e a t o m d e f / 2 .

For example , t he f o l l o w i n g r u l e d e f i n i t i o n :

r u l e ( ’ i n s c a l e ’ , min ) :−$ e v e n t s c a l e .

becomes :

r u l e d e f ( ’ i n s c a l e ’ , min ) % used o n l y f o r i n f o r m a t i o nr u l e ( ’ i n s c a l e ’ , a r g (A , B , C , D , E , F , G , H , I , J ) ) :−

A s c a l e .

s i n c e $ e v e n t i s d e f i n e d as th e f i r s t argument i n the term arg ( ) . ∗/

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗TERM EXPANSION

This i s a hook p r e d i c a t e i n t o the term r e a d i n g p r o c e s s t h a to c c u r s when c o n s u l t i n g a f i l e .

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

t e r m e x p a n s i o n ( ( r u l e (X , A , B) :− G o a l s ) ,[ ( r u l e d e f (X , A , B , C ) ) , ( r u l e (X , A , Args ) :− R e p l a c e d G o a l s ) ] ) :−

f u n c t o r ( Args , a r g s , 1 2 ) ,p r e r e p l a c e a t o m s ( G o a l s , R e p l a c e d G o a l s , Args , 0 , C ) .

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗REPLACING META−VARIABLES

p r e r e p l a c e a t o m s /3 s e a r c h e s through a l i s t o f g o a l s , r e p l a c i n ga l l ”meta−v a r i a b l e s ” d e f i n e d i n p r e a t o m d e f /2 w i t h t hea p p r o p r i a t e v a r i a b l e argument .

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

CHAPTER 6. CODE AND TESTING 76

p r e r e p l a c e a t o m s ( G o a l s , R e p l a c e d G o a l s , Args , L In , LOut ) :−G o a l s = . . G o a l L i s t ,p r e r e p l a c e a t o m s 1 ( G o a l L i s t , R e p l a c e d G o a l L i s t , Args , L In , LOut ) ,R e p l a c e d G o a l s = . . R e p l a c e d G o a l L i s t .

p r e r e p l a c e a t o m s 1 ( [ ] , [ ] , , L , L ) .p r e r e p l a c e a t o m s 1 ( [ X | I n R e s t ] , [ Y | OutRest ] , Args , L In , LOut ) :−

pre atom (X , ArgNo ) ,a rg ( ArgNo , Args , Y ) ,( ArgNo > LIn −> L0 = ArgNo ; L0 = LIn ) ,p r e r e p l a c e a t o m s 1 ( I n R e s t , OutRest , Args , L0 , LOut ) .

p r e r e p l a c e a t o m s 1 ( [ X | I n R e s t ] , [ Y | OutRest ] , Args , L In , LOut ) :−not atomic (X ) ,p r e r e p l a c e a t o m s (X , Y , Args , L In , L0 ) ,p r e r e p l a c e a t o m s 1 ( I n R e s t , OutRest , Args , L0 , LOut ) .

p r e r e p l a c e a t o m s 1 ( [ X | I n R e s t ] , [ X | OutRest ] , Args , L In , LOut ) :−p r e r e p l a c e a t o m s 1 ( I n R e s t , OutRest , Args , L In , LOut ) .

pre atom (X , Y) :−nonvar (X ) ,p r e a t o m d e f (X , Y ) .

p r e a t o m d e f ( $ e v e n t , 1 ) .p r e a t o m d e f ( $e , 1 ) .p r e a t o m d e f ( $pre v 1 , 2 ) .p r e a t o m d e f ( $p1 , 2 ) .p r e a t o m d e f ( $pre v 2 , 3 ) .p r e a t o m d e f ( $p2 , 3 ) .p r e a t o m d e f ( $pre v 3 , 4 ) .p r e a t o m d e f ( $p3 , 4 ) .p r e a t o m d e f ( $pre v 4 , 5 ) .p r e a t o m d e f ( $p4 , 5 ) .p r e a t o m d e f ( $pre v 5 , 6 ) .p r e a t o m d e f ( $p5 , 6 ) .p r e a t o m d e f ( $pre v 6 , 7 ) .p r e a t o m d e f ( $p6 , 7 ) .p r e a t o m d e f ( $pre v 7 , 8 ) .p r e a t o m d e f ( $p7 , 8 ) .p r e a t o m d e f ( $pre v 8 , 9 ) .p r e a t o m d e f ( $p8 , 9 ) .p r e a t o m d e f ( $ v e r t , 1 0 ) .p r e a t o m d e f ( $v , 1 0 ) .p r e a t o m d e f ( $ e v e n t s , 1 1 ) .p r e a t o m d e f ( $x , 1 1 ) .p r e a t o m d e f ( $ne xt , 1 2 ) .

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗PACKAGING PARAMETERS

This i s t he o t h e r s i d e o f th e p r e p r o c e s s o r . The r u l e i n t e r p r e t o ru s e s t h i s p r e d i c a t e to package a l l o f t he n e c e s s a r y i n f o r m a t i o nto send to t he r u l e s .

CHAPTER 6. CODE AND TESTING 77

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

p a c k a g e p a r a m e t e r (T , E , V , Param ) :−f u n c t o r ( Param , a r g s , 1 2 ) ,a rg ( 1 , Param , E ) ,g e t p r e v e v e n t (T , E , EP1 ) ,g e t p r e v e v e n t (T , EP1 , EP2 ) ,g e t p r e v e v e n t (T , EP2 , EP3 ) ,g e t p r e v e v e n t (T , EP3 , EP4 ) ,g e t p r e v e v e n t (T , EP4 , EP5 ) ,g e t p r e v e v e n t (T , EP5 , EP6 ) ,g e t p r e v e v e n t (T , EP6 , EP7 ) ,g e t p r e v e v e n t (T , EP7 , EP8 ) ,a rg ( 2 , Param , EP1 ) ,a rg ( 3 , Param , EP2 ) ,a rg ( 4 , Param , EP3 ) ,a rg ( 5 , Param , EP4 ) ,a rg ( 6 , Param , EP5 ) ,a rg ( 7 , Param , EP6 ) ,a rg ( 8 , Param , EP7 ) ,a rg ( 9 , Param , EP8 ) ,(V \= [] −>

( g e t l a b e l (V , T , Ver t ) ,a rg ( 1 0 , Param , Vert ) )

;a rg ( 1 0 , Param , [ ] ) ) ,a rg ( 1 1 , Param , ( T , E ) ) ,g e t n e x t e v e n t (T , E , N ) ,a rg ( 1 2 , Param , N ) .

Testing

2 ?− [ ’rule-sets/modal_counterpoint.pl’ ] .

r u l e−s e t s / m o d a l c o u n t e r p o i n t . p l c o m p i l e d , 0 . 1 7 s e c , 1 2 , 1 4 4 b y t e s .

Yes 3 ?− l i s t i n g ( r u l e ) .

r u l e (’First-Last-Penultimate’ , c h r o n o l o g i c a l , a r g s (A , B , C , D , E , F ,G , H , I , J , K , L ) ) :−

( A f i r s t e v e n t−> m c f i r s t p i t c h (A); A l a s t e v e n t−> m c l a s t p i t c h (A); K p e n u l t i m a t e e v e n t−> m c p e n u l t i m a t e p i t c h (A); t r u e) . r u l e (’leading tone leads to tonic’ , t e n d e n c y , a r g s (A , B ,

C , D , E , F , G , H , I , J , K , L ) ) :−( B l e a d i n g t o n e−> A t o n i c

CHAPTER 6. CODE AND TESTING 78

; t r u e) . r u l e (’Aeolian’ , ’special cases for modes’ , a r g s (A , B , C ,

D , E , F , G , H , I , J , K , L ) ) :−( c u r r e n t s c a l e M˜ a e o l i a n−> m c a e o l i a n s p e c i a l (A , B); t r u e) . r u l e (’Good intervals’ , ’melodic intervals’ , a r g s (A , B , C ,

D , E , F , G , H , I , J , K , L ) ) :−( B=s t a r t; member (M, [ 2 , 3 , 4 , 5 ] ) ,

member (N , [ min , maj , p e r ] ) ,B : A a i n t e r v a l N˜M

) . r u l e (’Repeated note’ , ’melodic intervals’ , a r g s (A , B , C ,D , E , F , G , H , I , J , K , L ) ) :−

( B=s t a r t; B : A a i n t e r v a l u n i s) . r u l e (’Less good intervals’ , ’melodic intervals’ , a r g s (A ,

B , C , D , E , F , G , H , I , J , K , L ) ) :−( B=s t a r t; B : A a i n t e r v a l min ˜6 c o n t o u r up; B : A a i n t e r v a l p e r ˜8) . r u l e (’In scale’ , s c a l e , a r g s (A , B , C , D , E , F , G , H , I , J ,

K , L ) ) :−A s c a l e . r u l e (’Good intervals’ , ’harmonic intervals’ , a r g s (A ,

B , C , D , E , F , G , H , I , J , K , L ) ) :−( J =[ ]; member (M, [ 3 , 6 , 8 , 1 0 , 1 3 , 1 5 ] ) ,

member (N , [ min , maj , p e r ] ) ,J : A a i n t e r v a l N˜M

) . r u l e (’Diminished 5th’ , ’harmonic intervals’ , a r g s (A , B , C ,D , E , F , G , H , I , J , K , L ) ) :−

( J =[ ]; not c u r r e n t s c a l e M˜ l y d i a n ,

J : A c i n t e r v a l dim ˜5) . r u l e (’Perfect intervals’ , ’harmonic intervals’ , a r g s (A , B ,

C , D , E , F , G , H , I , J , K , L ) ) :−member (M, [ 4 , 5 ] ) ,J : A c i n t e r v a l p e r ˜M. r u l e (’Unison’ , ’harmonic intervals’ ,

a r g s (A , B , C , D , E , F , G , H , I , J , K , L ) ) :−J : A a i n t e r v a l u n i s . r u l e (’Penultimate maj6 or min3’ , ’avoid

harmonic i n t e r v a l s ’, args(A, B, C, D, E, F, G, H, I, J, K, L)) :-( A p e n u l t i m a t e e v e n t−> not ( (

( J : A c i n t e r v a l maj ˜6; J : A c i n t e r v a l min ˜3)) )

; t r u e) . r u l e (’Avoid’ , ’two leading tones’ , a r g s (A , B , C , D , E , F ,

G , H , I , J , K , L ) ) :−not ( (

CHAPTER 6. CODE AND TESTING 79

J l e a d i n g t o n e ,A l e a d i n g t o n e) ) . r u l e (’Step - step’ , c o n t o u r , a r g s (A , B , C , D , E , F ,

G , H , I , J , K , L ) ) :−( C=s t a r t; C : B a i n t e r v a l s t e p ,

B : A a i n t e r v a l s t e p ,C comment’Step - step’

) . r u l e (’X - skip: same direction’ , c o n t o u r , a r g s (A , B , C , D,E , F , G , H , I , J , K , L ) ) :−

( C=s t a r t; C : B c o n t o u r M,

B : A a i n t e r v a l s k i p c o n t o u r M,C comment’X - skip: same direction’

) . r u l e (’Skip - skip: opposite direction’ , c o n t o u r , a r g s (A ,B , C , D , E , F , G , H , I , J , K , L ) ) :−

( C=s t a r t; C : B a i n t e r v a l s k i p c o n t o u r M,

B : A a i n t e r v a l s k i p c o n t o u r N,M\=N

) . r u l e (’Ensure not’ , ’outline a tritone’ , a r g s (A , B , C , D,E , F , G , H , I , J , K , L ) ) :−

( C=s t a r t; C : B c o n t o u r M,

B : A c o n t o u r M−> not C : A a i n t e r v a l t r i ˜N; t r u e) . r u l e (’Two skips that form a triad’ , c o n t o u r , a r g s (A , B , C ,

D , E , F , G , H , I , J , K , L ) ) :−C : B a i n t e r v a l M˜3 c o n t o u r N,B : A a i n t e r v a l O˜3 c o n t o u r N , ! . r u l e (’Avoid the repeat’ ,

’repeat first’ , a r g s (A , B , C , D , E , F , G , H , I , J , K , L ) ) :−( B=s t a r t; not B : A a i n t e r v a l u n i s) . r u l e (’Let it repeat’ , ’repeat first’ , a r g s (A , B , C , D , E ,

F , G , H , I , J , K , L ) ) :−B : A a i n t e r v a l u n i s . r u l e (’Avoid two’ , ’repeat patterns’ ,

a r g s (A , B , C , D , E , F , G , H , I , J , K , L ) ) :−not m c r e p e a t p a t t e r n (D , C , B , A ) . r u l e (’Avoid three’ ,

’repeat patterns’ , a r g s (A , B , C , D , E , F , G , H , I , J , K , L ) ) :−not m c r e p e a t p a t t e r n ( F , E , D , C , B , A ) . r u l e (’Avoid four’ ,

’repeat patterns’ , a r g s (A , B , C , D , E , F , G , H , I , J , K , L ) ) :−not m c r e p e a t p a t t e r n (H , G , F , E , D , C , B , A ) . r u l e (’In

rang e ’, range, args(A, B, C, D, E, F, G, H, I, J, K, L)) :-A p a r t M,rang e ˜M tag N,A i n r a n g e N.

Yes 4 ?− l i s t i n g ( r u l e d e f ) .

r u l e d e f (’First-Last-Penultimate’ , c h r o n o l o g i c a l , 0 ) .

CHAPTER 6. CODE AND TESTING 80

r u l e d e f (’leading tone leads to tonic’ , t e n d e n c y , 0 ) .r u l e d e f (’Aeolian’ , ’special cases for modes’ , 0 ) . r u l e d e f (’Goodi n t e r v a l s ’, ’m e l o d i c i n t e r v a l s ’, 1). rule_def(’Repeated note ’,’melodic intervals’ , 1 ) . r u l e d e f (’Less good intervals’ , ’melodici n t e r v a l s ’, 10). rule_def(’ I n s c a l e ’, scale, 0). rule_def(’Goodi n t e r v a l s ’, ’ harmonic i n t e r v a l s ’, 0). rule_def(’D i m i n i s h e d 5 th’,’harmonic intervals’ , 0 ) . r u l e d e f (’Perfect intervals’ , ’harmonici n t e r v a l s ’, 10). rule_def(’Unison ’, ’ harmonic i n t e r v a l s ’, 20).r u l e d e f (’Penultimate maj6 or min3’ , ’avoid harmonic intervals’ , 0 ) .r u l e d e f (’Avoid’ , ’two leading tones’ , 0 ) . r u l e d e f (’Step - step’ ,c o n t o u r , 1 ) . r u l e d e f (’X - skip: same direction’ , c o n t o u r , 1 ) .r u l e d e f (’Skip - skip: opposite direction’ , c o n t o u r , 3 ) .r u l e d e f (’Ensure not’ , ’outline a tritone’ , 1 ) . r u l e d e f (’Two skipst h a t form a t r i a d ’, contour, 5). rule_def(’Avoid the r e p e a t ’, ’ r e p e a tf i r s t ’, 0). rule_def(’ Let i t r e p e a t ’, ’ r e p e a t f i r s t ’, 10).r u l e d e f (’Avoid two’ , ’repeat patterns’ , 0 ) . r u l e d e f (’Avoid three’ ,’repeat patterns’ , 1 0 ) . r u l e d e f (’Avoid four’ , ’repeat patterns’ ,2 0 ) . r u l e d e f (’In range’ , r ang e , 0 ) .

Yes

This test runs the modal counterpoint.pl rule set through the preprocessor andthen lists the created rule and rule def predicates.6.2.5 rule-def.pl

Code

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗RULE DEFINITION LIBRARY

P r e d i c a t e s f o r managing t he r u l e d e f i n i t i o n d a t a b a s e .

M i c ha e l DroettboomMay 1999

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗REQUIRED LIBRARIES

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

:− e n s u r e l o a d e d ( p r e p r o c e s s o r ) .

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗LOAD RULES

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

l o a d r u l e s (X) :−c o n s u l t (X ) .

CHAPTER 6. CODE AND TESTING 81

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗MANAGEMENT FUNCTIONS

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

r u l e p e n a l t y (R , P e n a l t y ) :− r u l e d e f (R , P e n a l t y ) .

o r g a n i z e r u l e s ( RulePath ) :−r u l e o r d e r ( Order0 ) ,r e v e r s e ( Order0 , Order ) ,f i n d a l l ( L1 ,

( member (X , Order ) ,f i n d a l l ( ( S , N , X , F a i l T o ) ,

( r u l e d e f (N , X , P , F a i l T o ) ,(P = min −> S i s −1 ; S i s P ) ) ,L ) ,

s o r t ( L , L0 ) ,o r g a n i z e r u l e s 0 ( L0 , L1 ) ) ,

RulePath ) ,w r i t e (’Rule path: ’ ) , w r i t e ( RulePath ) , n l .

o r g a n i z e r u l e s 0 ( [ ] , [ ] ) .o r g a n i z e r u l e s 0 ( [ ( P , A , B ) |T ] , [ HO|TO] ) :−

o r g a n i z e r u l e s 0 (P , [ ( P , A , B ) |T ] , HO, Rest ) ,o r g a n i z e r u l e s 0 ( Rest , TO) .

o r g a n i z e r u l e s 0 (P , [ ( P , A , B ) |T ] , [ ( P , A , B ) |TO ] , Rest ) :−o r g a n i z e r u l e s 0 (P , T , TO , Rest ) .

o r g a n i z e r u l e s 0 ( P0 , [ ( P1 , A , B ) |T ] , [ ] , [ ( P1 , A , B ) |T] ) :−P0 \= P1 .

o r g a n i z e r u l e s 0 ( , [ ] , [ ] , [ ] ) .

Testing

2 ?− go (’example.gmn’ , ’exampleout.gmn’ ,’rule-sets/modal_counterpoint.pl’ ) . r u l e−s e t s / m o d a l c o u n t e r p o i n t . p lc o m p i l e d , 0 . 1 1 s e c , 1 2 , 1 4 4 b y t e s . Parse OK Rule path : [ [ [ ( 1 , Ensurenot , o u t l i n e a t r i t o n e ) ] ] , [ [ ( 0 , Avoid two , r e p e a t p a t t e r n s ) ] , [ ( 1 0 ,Avoid t h r e e , r e p e a t p a t t e r n s ) ] , [ ( 2 0 , Avoid f o u r , r e p e a t p a t t e r n s ) ] ] ,[ [ ( 0 , Avoid the r e p e a t , r e p e a t f i r s t ) ] , [ ( 1 0 , Let i t r e p e a t , r e p e a tf i r s t ) ] ] , [ [ ( 1 , Step − s t e p , c o n t o u r ) , ( 1 , X − s k i p : same d i r e c t i o n ,c o n t o u r ) ] , [ ( 3 , S k i p − s k i p : o p p o s i t e d i r e c t i o n , c o n t o u r ) ] , [ ( 5 , Twos k i p s t h a t form a t r i a d , c o n t o u r ) ] ] , [ [ ( 0 , Avoid , two l e a d i n gt o n e s ) ] ] , [ [ ( 0 , P e n u l t i m a t e maj6 o r min3 , a v o i d harmonici n t e r v a l s ) ] ] , [ [ ( 0 , D i m i n i s h e d 5 th , harmonic i n t e r v a l s ) , ( 0 , Goodi n t e r v a l s , harmonic i n t e r v a l s ) ] , [ ( 1 0 , P e r f e c t i n t e r v a l s , harmonici n t e r v a l s ) ] , [ ( 2 0 , Unison , harmonic i n t e r v a l s ) ] ] , [ [ ( 0 , l e a d i n g tonel e a d s to t o n i c , t e n d e n c y ) ] ] , [ [ ( 0 , I n s c a l e , s c a l e ) ] ] , [ [ ( 0 , I nrang e , range ) ] ] , [ [ ( 1 , Good i n t e r v a l s , m e l o d i c i n t e r v a l s ) , ( 1 ,Repeated note , m e l o d i c i n t e r v a l s ) ] , [ ( 1 0 , L e s s good i n t e r v a l s ,m e l o d i c i n t e r v a l s ) ] ] , [ [ ( 0 , A e o l i a n , s p e c i a l c a s e s f o r modes ) ] ] , [ [( 0 , F i r s t−L a s t−P e n u l t i m a t e , c h r o n o l o g i c a l ) ] ] ]

CHAPTER 6. CODE AND TESTING 82

This testing shows the rule path created for the modal counterpoint.pl rule set.6.2.6 score.pl

Code

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗SCORE DATA STRUCTURE

M i c ha e l DroettboomMay 1999

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗REQUIRED LIBRARIES

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

:− e n s u r e l o a d e d ( ’../library/event.pl’ ) .:− e n s u r e l o a d e d ( t r e e s ) .

% c r e a t e s a TimePath and s e t s up the v e r t i c a l r e l a t i o n s h i p s i n a% s c o r ei n i t s c o r e (T , TimePath ) :−

t i m e p a t h (T , TimePath ) ,b u i l d v e r t i c a l s (T , TimePath ) .

l o a d s c o r e ( F i l e , T , TimePath ) :−parse GUIDO ( F i l e , L ) , ! ,n u m b e r s c o r e ( L ) ,L0 = [ L , end−marker ] ,f l a t t e n ( L0 , F ) ,l i s t t o t r e e ( F , T ) ,t i m e p a t h (T , TimePath ) ,b u i l d v e r t i c a l s (T , TimePath ) .

s a v e s c o r e ( F i l e , T , TimePath ) :−grammar GUIDO ( F i l e , T , TimePath ) .

n u m b e r s c o r e ( L ) :−n u m b e r s c o r e ( L , 1 , ) .

n u m b e r s c o r e ( [ Head | T a i l ] , I , F ) :−number par t ( Head , s t a r t , I , N ) ,n u m b e r s c o r e ( T a i l , N , F ) .

n u m b e r s c o r e ( [ ] , X , X ) .

number par t ( [ L a s t ] , P , I , N) :−

CHAPTER 6. CODE AND TESTING 83

e i n d e x ( L a s t , I ) ,e p r e v ( L a s t , P ) ,e n e x t ( L a s t , end ) ,N i s I + 1 .

number par t ( [ Head | T a i l ] , P , I , F ) :−e i n d e x ( Head , I ) ,e p r e v ( Head , P ) ,N i s I + 1 ,e n e x t ( Head , N ) ,number par t ( T a i l , I , N , F ) .

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗TIME PATH BUILDER

This b u i l d s a l i s t o f i n d e x e s to e v e n t s s o r t e d by s t a r t t i m e s .∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

t i m e p a t h (T , TimePath ) :−t r e e s i z e (T , TSize ) ,t i m e p a t h (T , TSize , TimePath ) .

t i m e p a t h (T , TSize , TimePath ) :−t i m e p a t h 0 (T , 1 , , TSize , TimePath0 ) ,s o r t ( TimePath0 , TimePath ) .

t i m e p a t h 0 ( , E , E , E , [ ] ) .t i m e p a t h 0 (T , E l I n , ElOut , TSize , [ ( Time , E l I n ) | T a i l ] ) :−

g e t l a b e l ( E l I n , T , E ) ,s e t e v e n t t i m e (T , E ) ,t i m e s t a r t (E , Time ) ,E l I n 0 i s E l I n + 1 ,t i m e p a t h 0 (T , E l I n 0 , ElOut , TSize , T a i l ) .

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗VERTICAL RELATIONSHIPS

This c r e a t e s t he v e r t i c a l r e l a t i o n s h i p s between e v e n t s .∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

b u i l d v e r t i c a l s (T , TimePath ) :−r e v e r s e ( TimePath , TimePathP ) , ! ,b u i l d v e r t 1 (T , TimePathP ) .

b u i l d v e r t 1 ( , [ ] ) .b u i l d v e r t 1 (T , [ ( StartTime , I n d e x ) | TimePathTai l ] ) :−

g e t l a b e l ( I n d e x , T , E ) ,t i m e e n d (E , EndTime ) ,b u i l d v e r t 0 (T , StartTime , EndTime , TimePathTai l , V e r t i c a l s ) ,e v e r t i c a l (E , V e r t i c a l s ) ,b u i l d v e r t 1 (T , TimePathTai l ) .

CHAPTER 6. CODE AND TESTING 84

b u i l d v e r t 0 ( , , , [ ] , [ ] ) .b u i l d v e r t 0 (T , StartTime , EndTime ,[ ( StartTime2 , I n d e x ) | TimePathTai l ] , [ I n d e x | T a i l ] ) :−

g e t l a b e l ( I n d e x , T , E ) ,t i m e e n d (E , EndTime2 ) ,FixEndTime i s EndTime − 1 ,FixEndTime2 i s EndTime2 − 1 ,( between ( Star tTime , FixEndTime , StartTime2 );between ( Star tTime , FixEndTime , FixEndTime2 );between ( StartTime2 , FixEndTime2 , StartTime );between ( StartTime2 , FixEndTime2 , FixEndTime ) ) , ! ,b u i l d v e r t 0 (T , StartTime , EndTime , TimePathTai l , T a i l ) .

b u i l d v e r t 0 (T , StartTime , EndTime , [ | T a i l ] , V e r t i c a l s ) :−b u i l d v e r t 0 (T , StartTime , EndTime , T a i l , V e r t i c a l s ) .

Testing

For testing of this module, see the testing for the GUIDO parser/grammar.

6.2.7 trees.pl

trees.pl is from the Quintus Prolog library.

6.3 The GUIDO parser/grammar

6.3.1 parser.pl

Code

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗GUIDO LANGUAGE PARSER

M i c ha e l DroettboomJune 1999

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗REQUIRED LIBRARIES

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

:− e n s u r e l o a d e d ( l e x e r ) .:− e n s u r e l o a d e d ( ’../library/global.pl’ ) .:− e n s u r e l o a d e d ( ’../library/pitch.pl’ ) .

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗

CHAPTER 6. CODE AND TESTING 85

USER PREDICATE∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

parse GUIDO ( F i l e , L i s t ) :−s e e ( F i l e ) ,tokenise GUIDO ( Words ) , ! ,w r i t e ( Words ) ,s e e n ,parse GUIDO ( L i s t , Words , [ ] ) ,w r i t e (’Parse OK’ ) , n l .

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗

PRIVATE PREDICATES∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

% TOP LEVEL

parse GUIDO (X) −−>{ i n i t p a r s e r } ,s c o r e (X ) ,{ s e t k e y } .

s c o r e ( L) −−>( [ ’{’ ] , p a r t s ( L , 1 , L a s t P a r t ) , [ ’}’ ] ,{ g l o b a l s e t ( num parts , L a s t P a r t )} )

;( p a r t ( L , 1 ) ,{ g l o b a l s e t ( num parts , 1 ) } ) .

p a r t s ( L , PartNo , L a s t P a r t ) −−>p a r t (X , PartNo ) ,( ( [ ( , ) ] ,{NextPart i s PartNo + 1} ,p a r t s ( Xs , NextPart , L a s t P a r t ) ,{L = [X | Xs ] } )

;( [ ] ,{L = [X ] , L a s t P a r t = PartNo } ) ) .

p a r t (X , PartNo) −−>[ ’[’ ] , e v e n t s ( L , PartNo ) , [ ’]’ ] ,{ i n c r p a r t , f l a t t e n ( L , X ) } .

e v e n t s ( L , PartNo) −−>e v e n t (X , PartNo ) ,( ( e v e n t s ( Xs , PartNo ) ,{(X = ’’ , L = Xs ) ; ( L = [X | Xs ] ) } )

;

CHAPTER 6. CODE AND TESTING 86

( [ ] ,{(X = ’’ , L = [ ] ) ; ( L = X ) } ) ) .

e v e n t (E , PartNo) −−>chord (E ) ; tag (E , PartNo ) ; n o t e o r r e s t (E , PartNo ) .

% NOTE OR REST EVENTS −− t o k e n s w i t h a d i r e c t c o r r e l a t i o n to t he% Pelog data s t r u c t u r e .n o t e o r r e s t (E , PartNo) −−>

p i t c h (P ) ,( d u r a t i o n (D ) ; ( [ ] , { g l o b a l ( d u r a t i o n , D ) } ) ) , ! ,{ e p a r t (E , PartNo ) ,

e p i t c h (E , P ) ,e d u r a t i o n (E , D) } .

p i t c h (CP) −−>r e s t (CP ) ; v a r i a b l e (CP ) ; sounded (CP ) .

sounded (CP) −−>p i t c h c l a s s (P ) ,( ( o c t a v e (O ) , a c c i d e n t a l s (A ) ) ; ( a c c i d e n t a l s (A ) , o c t a v e (O ) ) ) ,{ c o n c a t (P , A , N ) ,

te rm to atom (N0 , N ) ,p i t c h n a m e o c t a v e (CP , N0 , O) } .

p i t c h c l a s s (P) −−> [P ] , { p i t c h n a m e (P , , ) } .

o c t a v e (O) −−>( [O]

; ( [ ] , { g l o b a l ( o c t a v e , O) } ) ) ,{ i n t e g e r (O) ,

O > −13,O < 1 3 ,g l o b a l s e t ( o c t a v e , O) } .

a c c i d e n t a l s (C) −−>a c c i d e n t a l (A ) ,a c c i d e n t a l (B ) ,{A = B , c o n c a t (A , B , C ) } .

a c c i d e n t a l s (C) −−> a c c i d e n t a l (C ) .a c c i d e n t a l s (’’ ) −−> [ ] .a c c i d e n t a l (A) −−> [A ] , {A = ’&’ ; A = ’#’ } .

r e s t ( r e s t ) −−> [’_’ ] .

% NOTE : v a r i a b l e p i t c h e s a r e an e x t e n s i o n to the normal GUIDO grammar ,% and w i l l c a u s e a p a r s i n g e r r o r i f v i ewed by the GUIDO NoteViewerv a r i a b l e ( ) −−> [’~’ ] .

d u r a t i o n ( Dur) −−>( ( numerator (N ) , denominator (D) )

CHAPTER 6. CODE AND TESTING 87

; ( denominator (D) −> {N i s 1}; ( numerator (N ) , {D i s 1 } ) ) ) ,

d o t s (NF , DF ) , {D0 i s D ∗ DF , N0 i s N ∗ NF} ,{dur num ( Dur , N0 ) ,

d u r d e n ( Dur , D0 ) ,g l o b a l s e t ( d u r a t i o n , Dur ) } .

numerator (N) −−> [’*’ ] , ! , [ N ] , { i n t e g e r (N) } .

denominator (D) −−> [’/’ ] , ! , [ D ] , { i n t e g e r (D) } .

% each dot l e n g t h e n s d u r a t i o n by 150%d o t s (NF , DF) −−> c o u n t d o t s (N ) ,

{N > 0 −> (DF i s N ∗ 2 , NF i s ( DF ∗ 2 − 1 ) ); ( DF i s 1 , NF i s 1 ) } .

c o u n t d o t s (N) −−> [’.’ ] , ! , c o u n t d o t s (M) , { s u c c (M,N) } .c o u n t d o t s ( 0 ) −−> [ ] .

% TAGS and ”ESCAPE SEQUENCES”tag (E , PartNo) −−>

( [ ’\\’], [Tag]),( ( [ ’<’ ] , param ( Param ) , [ ’>’ ] ) ; ( [ ] , { Param = ’’ } ) ) ,{ h a n d l e t a g ( Tag , Param ) } ,( ( [ ’(’ ] , e v e n t s (E , PartNo ) , [ ’)’ ] )

; ( [ ] , ( e v e n t s (E , PartNo ) ) ; ( [ ] , { E = ’’ } ) ) ) .

param ( I n t e g e r ) −−> [ I n t e g e r ] , { i n t e g e r ( I n t e g e r ) } .param ( Param) −−> [ S t r i n g ] , { s t r i n g t o a t o m ( S t r i n g , Param ) } .

% PREDICATES TO HANDLE CERTAIN TAGSh a n d l e t a g (X , Y) :−

% This i s f o r t a g s not r e l a t e d to p a r t snonvar (X ) ,member (X , [ key , s c a l e , p i t c h s y s t e m , meter , l a b e l , t i t l e , composer , c o m m e n t s t y l e ] ) ,a tom to te rm (Y , Y0 , ) ,g l o b a l s e t ( tag (X ) , Y0 ) .

h a n d l e t a g (X , Y) :−% This i s f o r t a g s t h a t a r e r e l a t e d to p a r t snonvar (X ) ,member (X , [ range ] ) ,g l o b a l ( p a r t , P ) ,a tom to te rm (Y , Y0 , ) ,g l o b a l s e t ( tag ( (X)˜P ) , Y0 ) .

h a n d l e t a g ( , ) . % Handle u n r e c o g n i z e d t a g s g r a c e f u l l y

% CHORD% a l w a y s f a i l . No p a r t may c o n t a i n c h o r d s .chord (’’) −−> [’{’ ] , { f a i l } .

CHAPTER 6. CODE AND TESTING 88

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗HELPER PREDICATES

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

i n i t p a r s e r :−% s e t ” g l o b a l v a r i a b l e s ” used to f o r making o c t a v e s% and d u r a t i o n s ’ s t i c k ’ u n t i l changedr e t r a c t a l l ( g l o b a l ( , ) ) ,g l o b a l s e t ( o c t a v e , 1 ) ,g l o b a l s e t ( d u r a t i o n , dur ( 1 / 4 ) ) ,g l o b a l s e t ( p a r t , 1 ) ,s e t a l l d e f a u l t s .

i n c r p a r t :−g l o b a l ( p a r t , X ) ,Y i s X + 1 ,g l o b a l s e t ( p a r t , Y ) .

s e t k e y :−not g l o b a l ( tag ( key ) , ) ,not g l o b a l ( tag ( s c a l e ) , ) , ! ,g l o b a l s e t ( tag ( key ) , 0 ) ,g l o b a l s e t ( tag ( s c a l e ) , c ˜ major ) .

s e t k e y :−not g l o b a l ( tag ( key ) , ) ,g l o b a l ( tag ( s c a l e ) , S c a l e ) , ! ,s c a l e k e y ( S c a l e , Key ) ,k e y s h a r p s f l a t s ( KeyNumber , Key ) ,g l o b a l s e t ( tag ( key ) , KeyNumber ) .

s e t k e y :−not g l o b a l ( tag ( s c a l e ) , ) ,g l o b a l ( tag ( key ) , Key ) ,i n t e g e r ( Key ) , ! ,k e y s h a r p s f l a t s ( Key , KeyName ) ,g l o b a l s e t ( tag ( s c a l e ) , KeyName˜ major ) .

s e t k e y :−not g l o b a l ( tag ( s c a l e ) , ) ,g l o b a l ( tag ( key ) , Key ) ,g l o b a l s e t ( tag ( s c a l e ) , Key˜ major ) .

/∗∗∗TEST∗∗∗/

t e s t p a r s e r g r a m m a r ( F i l e I n , F i l e O u t ) :−w r i t e (’Testing GUIDO Parser/Grammar ---->’ ) , n l ,w r i t e (’Parsing ’ ) , w r i t e ( F i l e I n ) , n l ,l o a d s c o r e ( F i l e I n , T , TimePath ) ,n l , w r i t e (’Score tree:’ ) , n l ,

CHAPTER 6. CODE AND TESTING 89

p r i n t t r e e (T ) , n l ,w r i t e (’Tags:’ ) , n l ,l i s t i n g ( g l o b a l ) ,n l , w r i t e (’Generating ’ ) , w r i t e ( F i l e O u t ) , n l ,s a v e s c o r e ( F i l e O u t , T , TimePath ) ,w r i t e (’Succeeded.’ ) , n l .

6.3.2 lexer.pl

Code

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗GUIDO LANGUAGE LEXER

M i c ha e l DroettboomJune 1999

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

/∗ ADAPTED FROM THE FOLLOWING QUINTUS LIBRARY −−> ∗/

% Module : r e a d i n% Author : R i c h a r d A . O’ Keefe% Updated : 2 1 Apr 1987% Purpose : Read i n a s e n t e n c e as a l i s t o f words .

% There i s a s h a r e d v e r s i o n o f t h i s f i l e w r i t t e n by Lawrence Byrd .% This v e r s i o n was w r i t t e n e n t i r e l y from s c r a t c h f o r Quintus .% C o p y r i g h t ( C ) 1 9 8 7 , Quintus Computer Systems , I n c . A l l r i g h t s r e s e r v e d .

% r e a d i n ( Words )% r e a d s c h a r a c t e r s u n t i l i t f i n d s a p e r i o d ( . ? o r ! ) a t t he end o f a% l i n e , t h a t i s , f o l l o w e d by any number o f s p a c e s but n o t h i n g e l s e .% Words a r e s e q u e n c e s o f l e t t e r s ( i n e i t h e r c a s e , f o r c e d to l o w e r% c a s e ) , o r s t r i n g s o f d i g i t s , o r p u n c t u a t i o n marks . Other c h a r a c t e r s% a c t as word s e p a r a t o r s , and a r e o t h e r w i s e i g n o r e d . The s u b r o u t i n e s% i n t h i s f i l e a l l s t a r t w i t h r i , to a v o i d a c o l l i s i o n w i t h a u s e r ’ s% p r e d i c a t e s . Note t h a t t h i s p r e d i c a t e may r e a d more than one% s e n t e n c e ; i t i s b e s t thought o f as r e a d i n g p a r a g r a p h s .

tokenise GUIDO ( Words ) :−get0 (C ) ,t g s e n t (C , Found ) ,Words = Found .

t g s e n t (C , Words ) :−( C < 0 −> Words = [ ]; C =< " " −> = get0 (D ) , t g s e n t (D , Words )

CHAPTER 6. CODE AND TESTING 90

; C =:= "%" −> get0 (D ) , t g l i n e c o m m e n t (D ) , t g s e n t (D , Words ); Words = [ Word | Rest ] , D i s C\/ 3 2 ,

( C =:= "." −> Word = . , get0 ( F ) , t g s t o p ( F , Rest ); C =:= "!" −> Word = ! , get0 ( F ) , t g s t o p ( F , Rest ); C =:= "?" −> Word = ? , get0 ( F ) , t g s t o p ( F , Rest ); D >= "a" , D =< "z" −> =

get0 (E ) , tg word (E , Chars , F ) ,name ( Word , [ D | Chars ] ) , t g s e n t ( F , Rest )

; C =:= "\"" −>get0 (E ) , t g s t r i n g (E , Chars ) ,Word = Chars , get0 ( F ) , t g s e n t ( F , Rest )

; C =:= "-" −>get0 (E ) , t g n e g (E , Chars , F ) ,name ( Word , [ C | Chars ] ) , t g s e n t ( F , Rest )

; C >= "0" , C =< "9" −> =get0 (E ) , tg nmbr (E , Chars , F ) ,name ( Word , [ C | Chars ] ) , t g s e n t ( F , Rest )

; ge t0 ( F ) ,name ( Word , [ C ] ) , t g s e n t ( F , Rest )

)) .

t g l i n e c o m m e n t (C ) :− % i g n o r e commentsC < " ";( ge t0 (D) ,t g l i n e c o m m e n t (D ) ) .

t g s t o p (C , Rest ) :−( C =:= " " −> get0 (D ) , t g s t o p (D , Rest ) % s p a c e; C =:= 9 −> get0 (D ) , t g s t o p (D , Rest ) % tab; C < " " −> Rest = [ ] % ” end o f l i n e ”; t g s e n t (C , Rest )) .

tg word (C , [ Lower | Lowers ] , F ) :−( C >= "a" , C =< "z" −> = Lower = C; C =:= "_" −> Lower = C; C >= "A" , C =< "Z" −> = Lower i s C−"A"+"a"/ ∗ ; C >= ”0 ” , C =< ”9 ” −> Lower = C ∗/) , ! ,ge t0 (D) ,tg word (D , Lowers , F ) .

tg word ( F , [ ] , F ) .

t g s t r i n g ( 3 4 , [ ] ) :− ! .t g s t r i n g ( Char , [ Char | Chars ] ) :−

get0 (D) ,t g s t r i n g (D , Chars ) .

CHAPTER 6. CODE AND TESTING 91

t g n e g (C , D i g i t s , F ) :−( D i g i t s = [C | D i g i t s 1 ] ,

ge t0 (D) ,tg nmbr (D , D i g i t s 1 , F )

;F = C , D i g i t s = [ ] ) .

tg nmbr (C , D i g i t s , F ) :−( C >= "0" , C =< "9" −> =

D i g i t s = [C | D i g i t s 1 ] ,ge t0 (D) ,tg nmbr (D , D i g i t s 1 , F )

; C =:= "_" −>get0 (D) ,tg nmbr (D , D i g i t s , F )

; F = C , D i g i t s = [ ]) .

6.3.3 grammar.pl

Code

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗GRAMMAR FOR GUIDO

M i c ha e l DroettboomMay 1999

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗REQUIRED LIBRARIES

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

:− e n s u r e l o a d e d ( ’../library/global.pl’ ) .:− e n s u r e l o a d e d ( ’../core/trees.pl’ ) .:− e n s u r e l o a d e d ( ’../library/pitch.pl’ ) .

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗OPTIONS

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

% c o m m e n t s t y l e = { l y r i c s | r e f e r e n c e d | none}% l y r i c s : comments a r e w r i t t e n i n as l y r i c s on t he s c o r e% r e f e r e n c e d : comments a r e added to the end o f f i l e and r e f e r e n c e d% to t he n o t e s t h e m s e l v e s by number% none : no commentsg l o b a l d e f a u l t ( tag ( c o m m e n t s t y l e ) , r e f e r e n c e d ) .

CHAPTER 6. CODE AND TESTING 92

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗GRAMMAR

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

grammar GUIDO ( F i l e , T , TimePath ) :−gg main (T , TimePath , L , [ ] ) ,t e l l ( F i l e ) ,w r i t e t o k e n s ( L ) ,t o l d .

gg main (T , TimePath) −−>g g h e a d e r ,g g s c o r e (T , TimePath ) ,g g i n f o (T ) .

g g h e a d e r −−>[ ’% GUIDO Music Notation Language v1.0\n’ ] ,[ ’%\n’ ] ,[ ’% This file was generated by the PELOG musical rule system\n’ ] ,[ ’% (c) 1999 Michael Droettboom\n\n’ ] .

g g s c o r e (T , TimePath) −−>[ ’{\n’ ] , g g p a r t (T , TimePath ) , [ ’}\n\n’ ] .

g g p a r t (T , [ ( 0 , I n d e x )]) −−>! , [ ’[’ ] , g g t a g s , g g e v e n t (T , I n d e x ) , [ ’]\n’ ] .

g g p a r t (T , [ ( 0 , I n d e x ) , ( X , ) | ]) −−>{X > 0 } , ! ,[ ’[’ ] , g g t a g s , g g e v e n t (T , I n d e x ) , [ ’]’ ] .

g g p a r t (T , [ ( 0 , I n d e x ) | T a i l ]) −−>! ,[ ’[’ ] , g g t a g s , g g e v e n t (T , I n d e x ) , [ ’]’ ] , [ ( , ) ] , [ ’\n’ ] , g g p a r t (T , T a i l ) .

g g p a r t ( , ) −−> [ ] .

g g t a g s −−>{ f i n d a l l ( (X , Y ) , g l o b a l ( tag (X ) , Y ) , L ) } ,g g t a g ( L ) .

g g t a g ( [ ] ) −−> [ ] .g g t a g ( [ ( rang e ˜ , ) | ] ) −−> ! , [ ] .g g t a g ( [ ( s c a l e , ) | ] ) −−> ! , [ ] .g g t a g ( [ ( X , Y ) | T a i l ]) −−>

[ ’\\’], [X], [’<\"’], [Y], [’\"> ’],g g t a g ( T a i l ) .

g g e v e n t ( , end) −−> [ ] .g g e v e n t (T , I n d e x ) −−>

{ g e t l a b e l ( I n d e x , T , E ) ,e p i t c h (E , P i t c h ) ,p i t c h n a m e ( P i t c h , PN ) ,

CHAPTER 6. CODE AND TESTING 93

o c t a v e ( P i t c h , Octave ) ,e d u r a t i o n (E , D u r a t i o n ) ,dur num ( D u r a t i o n , Numerator ) ,d u r d e n ( D u r a t i o n , Denominator ) ,e n e x t (E , Next ) } ,( ({ g l o b a l ( tag ( c o m m e n t s t y l e ) , l y r i c s ) ,

e p r e t t y c o m m e n t (E , Comment ) } ,gg comment ( Comment ) )

;({ g l o b a l ( tag ( c o m m e n t s t y l e ) , r e f e r e n c e d ) } ,

gg comment ( I n d e x ) ) ) ,g g e v e n t t o k e n (PN , Octave , Numerator , Denominator ) ,g g e v e n t (T , Next ) .

gg comment ( Comment) −−>[ ’\\text<\"’ ] , [ Comment ] , [ ’\">’ ] .

g g e v e n t t o k e n (PN , Octave , Numerator , Denominator) −−>[PN ] , [ Octave ] , [ ’*’ ] , [ Numerator ] , [ ’/’ ] , [ Denominator ] , [ ’ ’ ] .

g g i n f o (T) −−>{ g l o b a l ( tag ( c o m m e n t s t y l e ) , r e f e r e n c e d ) ,

l i s t t o t r e e ( L , T) } ,g g r e f e r e n c e d c o m m e n t s ( L ) .

g g i n f o ( ) −−> [ ] .

g g r e f e r e n c e d c o m m e n t s ( [ Head | T a i l ]) −−>{ e i n d e x ( Head , I n d e x ) ,

e p r e t t y c o m m e n t ( Head , Comment ) } ,[ ’% ’ ] , [ I n d e x ] , [ ’: ’ ] , [ Comment ] , [ ’\n’ ] ,g g r e f e r e n c e d c o m m e n t s ( T a i l ) .

g g r e f e r e n c e d c o m m e n t s ( [ end−marker ] ) −−> [ ] .

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗A ”REVERSE LEXER”

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

w r i t e t o k e n s ( [ ] ) .w r i t e t o k e n s ( [ Head | T a i l ] ) :−

w r i t e ( Head ) , w r i t e t o k e n s ( T a i l ) .

6.3.4 Testing

Testing the parser/grammar involved using three GUIDO BNF testing files providedby the GUIDO authors. The test parser grammar predicate parses an input file,displays the score tree and global tags, and generates a copy to an output file.If the output file is functionally identical to the input file, then one can assumethe parser/grammar is working correctly. Each test below contains the followinginformation:

• The text of the input and output files

CHAPTER 6. CODE AND TESTING 94

• A view of the input and ouput files in common music notation (cmn) asgenerated by the GUIDO NoteViewer

• The console output of the test parser grammar predicate

simple1

IN% s i m p l e GUIDO example% f i r s t enhancement% added some more n o t e s% added meter−tag

[ \ meter<"2/4">meter c1 ∗1/8 d e f g /4 g a /8 a a a g/2a /8 a a a g /2 f /8 f f f e /4 e g/8g g g c ∗ 1 ]

% s e e s i m p l e 2 . gmn v o r f u r t h e r enhacements .

OUT% GUIDO Music N o t a t i o n Language v1 . 0%% This f i l e was g e n e r a t e d by the PELOG m u s i c a l r u l e system% ( c ) 1 9 9 9 M i c h a e l Droettboom

{[\ p i t c h s y s t e m<"diatonic">p i t c h s y s t e m \ c o m m e n t s t y l e<"referenced">c o m m e n t s t y l e \meter<"2/4">meter\ key<"c">key \ s c a l e<"c~major">s c a l e \ text<"1">t e x t c 1 ∗1/8 \ text<"2">t e x t d 1 ∗1/8\ text<"3">t e x t e 1 ∗1/8 \ text<"4">t e x t f 1 ∗1/8 \ text<"5">t e x t g 1 ∗1/4 \ text<"6">t e x t g 1 ∗1/4\ text<"7">t e x t a 1 ∗1/8 \ text<"8">t e x t a 1 ∗1/8 \ text<"9">t e x t a 1 ∗1/8 \ text<"10">t e x t a 1 ∗1/8\ text<"11">t e x t g 1 ∗1/2 \ text<"12">t e x t a 1 ∗1/8 \ text<"13">t e x t a 1 ∗1/8\ text<"14">t e x t a 1 ∗1/8 \ text<"15">t e x t a 1 ∗1/8 \ text<"16">t e x t g 1 ∗1/2\ text<"17">t e x t f 1 ∗1/8 \ text<"18">t e x t f 1 ∗1/8 \ text<"19">t e x t f 1 ∗1/8\ text<"20">t e x t f 1 ∗1/8 \ text<"21">t e x t e 1 ∗1/4 \ text<"22">t e x t e 1 ∗1/4\ text<"23">t e x t g 1 ∗1/8 \ text<"24">t e x t g 1 ∗1/8 \ text<"25">t e x t g 1 ∗1/8\ text<"26">t e x t g 1 ∗1/8 \ text<"27">t e x t c 1 ∗1 / 1 ]}

% 1:

CHAPTER 6. CODE AND TESTING 95

TERMINALt e s t p a r s e r g r a m m a r (’simple1.gmn’ , ’simple1out.gmn’ ) .T e s t i n g GUIDO P a r s e r /Grammar−−−−>P a r s i n g s i m p l e 1 . gmnParse OK

Score t r e e :e v e n t ( 1 , 1 , p i t c h ( 1 2 , 7 ) , dur ( 1 / 8 ) , t ime ( 0 , 1 5 0 0 ) , s t a r t , [ ] , 2 ,G1715 , G1716 , G1717 ) e v e n t ( 2 , 1 , p i t c h ( 1 4 , 8 ) , dur ( 1 / 8 ) , t ime ( 1 5 0 0 ,

3 0 0 0 ) , 1 , [ ] , 3 , G1753 , G1754 , G1755 ) e v e n t ( 3 , 1 , p i t c h ( 1 6 , 9 ) ,dur ( 1 / 8 ) , t ime ( 3 0 0 0 , 4 5 0 0 ) , 2 , [ ] , 4 , G1791 , G1792 , G1793 ) e v e n t ( 4 ,1 , p i t c h ( 1 7 , 1 0 ) , dur ( 1 / 8 ) , t ime ( 4 5 0 0 , 6 0 0 0 ) , 3 , [ ] , 5 , G1829 ,G1830 , G1831 ) e v e n t ( 5 , 1 , p i t c h ( 1 9 , 1 1 ) , dur ( 1 / 4 ) , t ime ( 6 0 0 0 , 9 0 0 0 ) ,

4 , [ ] , 6 , G1879 , G1880 , G1881 ) e v e n t ( 6 , 1 , p i t c h ( 1 9 , 1 1 ) , dur ( 1 / 4 ) ,t ime ( 9 0 0 0 , 1 2 0 0 0 ) , 5 , [ ] , 7 , G1917 , G1918 , G1919 ) e v e n t ( 7 , 1 ,p i t c h ( 2 1 , 1 2 ) , dur ( 1 / 8 ) , t ime ( 1 2 0 0 0 , 1 3 5 0 0 ) , 6 , [ ] , 8 , G1967 , G1968 ,G1969 ) e v e n t ( 8 , 1 , p i t c h ( 2 1 , 1 2 ) , dur ( 1 / 8 ) , t ime ( 1 3 5 0 0 , 1 5 0 0 0 ) , 7 ,

[ ] , 9 , G2005 , G2006 , G2007 ) e v e n t ( 9 , 1 , p i t c h ( 2 1 , 1 2 ) , dur ( 1 / 8 ) ,t ime ( 1 5 0 0 0 , 1 6 5 0 0 ) , 8 , [ ] , 1 0 , G2043 , G2044 , G2045 ) e v e n t ( 1 0 , 1 ,p i t c h ( 2 1 , 1 2 ) , dur ( 1 / 8 ) , t ime ( 1 6 5 0 0 , 1 8 0 0 0 ) , 9 , [ ] , 1 1 , G2081 ,G2082 , G2083 ) e v e n t ( 1 1 , 1 , p i t c h ( 1 9 , 1 1 ) , dur ( 1 / 2 ) , t ime ( 1 8 0 0 0 ,

2 4 0 0 0 ) , 1 0 , [ ] , 1 2 , G2131 , G2132 , G2133 ) e v e n t ( 1 2 , 1 , p i t c h ( 2 1 ,1 2 ) , dur ( 1 / 8 ) , t ime ( 2 4 0 0 0 , 2 5 5 0 0 ) , 1 1 , [ ] , 1 3 , G2181 , G2182 , G2183 )e v e n t ( 1 3 , 1 , p i t c h ( 2 1 , 1 2 ) , dur ( 1 / 8 ) , t ime ( 2 5 5 0 0 , 2 7 0 0 0 ) , 1 2 , [ ] , 1 4 ,G2219 , G2220 , G2221 ) e v e n t ( 1 4 , 1 , p i t c h ( 2 1 , 1 2 ) , dur ( 1 / 8 ) ,

t ime ( 2 7 0 0 0 , 2 8 5 0 0 ) , 1 3 , [ ] , 1 5 , G2257 , G2258 , G2259 ) e v e n t ( 1 5 , 1 ,p i t c h ( 2 1 , 1 2 ) , dur ( 1 / 8 ) , t ime ( 2 8 5 0 0 , 3 0 0 0 0 ) , 1 4 , [ ] , 1 6 , G2295 ,G2296 , G2297 ) e v e n t ( 1 6 , 1 , p i t c h ( 1 9 , 1 1 ) , dur ( 1 / 2 ) , t ime ( 3 0 0 0 0 ,

3 6 0 0 0 ) , 1 5 , [ ] , 1 7 , G2345 , G2346 , G2347 ) e v e n t ( 1 7 , 1 , p i t c h ( 1 7 ,1 0 ) , dur ( 1 / 8 ) , t ime ( 3 6 0 0 0 , 3 7 5 0 0 ) , 1 6 , [ ] , 1 8 , G2395 , G2396 , G2397 )e v e n t ( 1 8 , 1 , p i t c h ( 1 7 , 1 0 ) , dur ( 1 / 8 ) , t ime ( 3 7 5 0 0 , 3 9 0 0 0 ) , 1 7 , [ ] , 1 9 ,G2433 , G2434 , G2435 ) e v e n t ( 1 9 , 1 , p i t c h ( 1 7 , 1 0 ) , dur ( 1 / 8 ) ,

t ime ( 3 9 0 0 0 , 4 0 5 0 0 ) , 1 8 , [ ] , 2 0 , G2471 , G2472 , G2473 ) e v e n t ( 2 0 , 1 ,p i t c h ( 1 7 , 1 0 ) , dur ( 1 / 8 ) , t ime ( 4 0 5 0 0 , 4 2 0 0 0 ) , 1 9 , [ ] , 2 1 , G2509 ,G2510 , G2511 ) e v e n t ( 2 1 , 1 , p i t c h ( 1 6 , 9 ) , dur ( 1 / 4 ) , t ime ( 4 2 0 0 0 ,

4 5 0 0 0 ) , 2 0 , [ ] , 2 2 , G2559 , G2560 , G2561 ) e v e n t ( 2 2 , 1 , p i t c h ( 1 6 , 9 ) ,dur ( 1 / 4 ) , t ime ( 4 5 0 0 0 , 4 8 0 0 0 ) , 2 1 , [ ] , 2 3 , G2597 , G2598 , G2599 )e v e n t ( 2 3 , 1 , p i t c h ( 1 9 , 1 1 ) , dur ( 1 / 8 ) , t ime ( 4 8 0 0 0 , 4 9 5 0 0 ) , 2 2 , [ ] , 2 4 ,G2647 , G2648 , G2649 ) e v e n t ( 2 4 , 1 , p i t c h ( 1 9 , 1 1 ) , dur ( 1 / 8 ) ,

t ime ( 4 9 5 0 0 , 5 1 0 0 0 ) , 2 3 , [ ] , 2 5 , G2685 , G2686 , G2687 ) e v e n t ( 2 5 , 1 ,p i t c h ( 1 9 , 1 1 ) , dur ( 1 / 8 ) , t ime ( 5 1 0 0 0 , 5 2 5 0 0 ) , 2 4 , [ ] , 2 6 , G2723 ,G2724 , G2725 ) e v e n t ( 2 6 , 1 , p i t c h ( 1 9 , 1 1 ) , dur ( 1 / 8 ) , t ime ( 5 2 5 0 0 ,

5 4 0 0 0 ) , 2 5 , [ ] , 2 7 , G2761 , G2762 , G2763 ) e v e n t ( 2 7 , 1 , p i t c h ( 1 2 , 7 ) ,dur ( 1 / 1 ) , t ime ( 5 4 0 0 0 , 6 6 0 0 0 ) , 2 6 , [ ] , end , G2811 , G2812 , G2813 )end−marker

Tags :

g l o b a l ( tag ( p i t c h s y s t e m ) , d i a t o n i c ) .g l o b a l ( tag ( c o m m e n t s t y l e ) , r e f e r e n c e d ) .g l o b a l ( tag ( meter ) , 2 / 4 ) .

CHAPTER 6. CODE AND TESTING 96

g l o b a l ( o c t a v e , 1 ) .g l o b a l ( d u r a t i o n , dur ( 1 / 1 ) ) .g l o b a l ( p a r t , 2 ) .g l o b a l ( num parts , 1 ) .g l o b a l ( tag ( key ) , c ) .g l o b a l ( tag ( s c a l e ) , c ˜ major ) .

G e n e r a t i n g s i m p l e 1 o u t . gmnSucceeded .

simple2

IN% s i m p l e GUIDO example% second enhancement% add ing a second v o i c e% and t he s t a f f O f f−Tag

{ [ \ meter<"2/4">meter c1 ∗1/8 d e f g /4 g a /8 a a a g/2a /8 a a a g /2 f /8 f f f e /4 e g/8g g g c ∗1 \ s t a f f O f f ] ,

[ \ meter<"2/4">meter \ c l e f<"bass">c l e f c0 /2 c f c f c g c g−1 c0 ] }

% s e e s i m p l e 3 . gmn v o r f u r t h e r enhacements .

OUT% GUIDO Music N o t a t i o n Language v1 . 0%% This f i l e was g e n e r a t e d by the PELOG m u s i c a l r u l e system% ( c ) 1 9 9 9 M i c h a e l Droettboom

{[\ p i t c h s y s t e m<"diatonic">p i t c h s y s t e m \ c o m m e n t s t y l e<"referenced">c o m m e n t s t y l e \meter<"2/4">meter\ key<"c">key \ s c a l e<"c~major">s c a l e \ text<"1">t e x t c 1 ∗1/8 \ text<"2">t e x t d 1 ∗1/8\ text<"3">t e x t e 1 ∗1/8 \ text<"4">t e x t f 1 ∗1/8 \ text<"5">t e x t g 1 ∗1/4 \ text<"6">t e x t g 1 ∗1/4\ text<"7">t e x t a 1 ∗1/8 \ text<"8">t e x t a 1 ∗1/8 \ text<"9">t e x t a 1 ∗1/8 \ text<"10">t e x t a 1 ∗1/8\ text<"11">t e x t g 1 ∗1/2 \ text<"12">t e x t a 1 ∗1/8 \ text<"13">t e x t a 1 ∗1/8\ text<"14">t e x t a 1 ∗1/8 \ text<"15">t e x t a 1 ∗1/8 \ text<"16">t e x t g 1 ∗1/2

CHAPTER 6. CODE AND TESTING 97

\ text<"17">t e x t f 1 ∗1/8 \ text<"18">t e x t f 1 ∗1/8 \ text<"19">t e x t f 1 ∗1/8\ text<"20">t e x t f 1 ∗1/8 \ text<"21">t e x t e 1 ∗1/4 \ text<"22">t e x t e 1 ∗1/4\ text<"23">t e x t g 1 ∗1/8 \ text<"24">t e x t g 1 ∗1/8 \ text<"25">t e x t g 1 ∗1/8\ text<"26">t e x t g 1 ∗1/8 \ text<"27">t e x t c 1 ∗ 1 / 1 ] , [ \ p i t c h s y s t e m<"diatonic">p i t c h s y s t e m\ c o m m e n t s t y l e<"referenced">c o m m e n t s t y l e \meter<"2/4">meter \ key<"c">key \ s c a l e<"c~major">s c a l e\ text<"28">t e x t c 0 ∗1/2 \ text<"29">t e x t c 0 ∗1/2 \ text<"30">t e x t f 0 ∗1/2\ text<"31">t e x t c 0 ∗1/2 \ text<"32">t e x t f 0 ∗1/2 \ text<"33">t e x t c 0 ∗1/2\ text<"34">t e x t g 0 ∗1/2 \ text<"35">t e x t c 0 ∗1/2 \ text<"36">t e x t g−1∗1/2\ text<"37">t e x t c 0 ∗1 / 2 ]}

TERMINALt e s t p a r s e r g r a m m a r (’simple2.gmn’ , ’simple2out.gmn’ ) .T e s t i n g GUIDO P a r s e r /Grammar−−−−>P a r s i n g s i m p l e 2 . gmnParse OK

Score t r e e :e v e n t ( 1 , 1 , p i t c h ( 1 2 , 7 ) , dur ( 1 / 8 ) , t ime ( 0 , 1 5 0 0 ) , s t a r t , [ ] , 2 ,G2297 , G2298 , G2299 ) e v e n t ( 2 , 1 , p i t c h ( 1 4 , 8 ) , dur ( 1 / 8 ) , t ime ( 1 5 0 0 ,

3 0 0 0 ) , 1 , [ 2 8 ] , 3 , G2335 , G2336 , G2337 ) e v e n t ( 3 , 1 , p i t c h ( 1 6 , 9 ) ,dur ( 1 / 8 ) , t ime ( 3 0 0 0 , 4 5 0 0 ) , 2 , [ 2 8 ] , 4 , G2373 , G2374 , G2375 )e v e n t ( 4 , 1 , p i t c h ( 1 7 , 1 0 ) , dur ( 1 / 8 ) , t ime ( 4 5 0 0 , 6 0 0 0 ) , 3 , [ 2 8 ] , 5 ,G2411 , G2412 , G2413 ) e v e n t ( 5 , 1 , p i t c h ( 1 9 , 1 1 ) , dur ( 1 / 4 ) ,

t ime ( 6 0 0 0 , 9 0 0 0 ) , 4 , [ ] , 6 , G2461 , G2462 , G2463 ) e v e n t ( 6 , 1 ,p i t c h ( 1 9 , 1 1 ) , dur ( 1 / 4 ) , t ime ( 9 0 0 0 , 1 2 0 0 0 ) , 5 , [ 2 9 ] , 7 , G2499 ,G2500 , G2501 ) e v e n t ( 7 , 1 , p i t c h ( 2 1 , 1 2 ) , dur ( 1 / 8 ) , t ime ( 1 2 0 0 0 ,

1 3 5 0 0 ) , 6 , [ ] , 8 , G2549 , G2550 , G2551 ) e v e n t ( 8 , 1 , p i t c h ( 2 1 , 1 2 ) ,dur ( 1 / 8 ) , t ime ( 1 3 5 0 0 , 1 5 0 0 0 ) , 7 , [ 3 0 ] , 9 , G2587 , G2588 , G2589 )e v e n t ( 9 , 1 , p i t c h ( 2 1 , 1 2 ) , dur ( 1 / 8 ) , t ime ( 1 5 0 0 0 , 1 6 5 0 0 ) , 8 , [ 3 0 ] , 1 0 ,G2625 , G2626 , G2627 ) e v e n t ( 1 0 , 1 , p i t c h ( 2 1 , 1 2 ) , dur ( 1 / 8 ) ,

t ime ( 1 6 5 0 0 , 1 8 0 0 0 ) , 9 , [ 3 0 ] , 1 1 , G2663 , G2664 , G2665 ) e v e n t ( 1 1 , 1 ,p i t c h ( 1 9 , 1 1 ) , dur ( 1 / 2 ) , t ime ( 1 8 0 0 0 , 2 4 0 0 0 ) , 1 0 , [ ] , 1 2 , G2713 ,G2714 , G2715 ) e v e n t ( 1 2 , 1 , p i t c h ( 2 1 , 1 2 ) , dur ( 1 / 8 ) , t ime ( 2 4 0 0 0 ,

2 5 5 0 0 ) , 1 1 , [ ] , 1 3 , G2763 , G2764 , G2765 ) e v e n t ( 1 3 , 1 , p i t c h ( 2 1 ,1 2 ) , dur ( 1 / 8 ) , t ime ( 2 5 5 0 0 , 2 7 0 0 0 ) , 1 2 , [ 3 2 ] , 1 4 , G2801 , G2802 ,G2803 ) e v e n t ( 1 4 , 1 , p i t c h ( 2 1 , 1 2 ) , dur ( 1 / 8 ) , t ime ( 2 7 0 0 0 , 2 8 5 0 0 ) , 1 3 ,

[ 3 2 ] , 1 5 , G2839 , G2840 , G2841 ) e v e n t ( 1 5 , 1 , p i t c h ( 2 1 , 1 2 ) ,dur ( 1 / 8 ) , t ime ( 2 8 5 0 0 , 3 0 0 0 0 ) , 1 4 , [ 3 2 ] , 1 6 , G2877 , G2878 , G2879 )

CHAPTER 6. CODE AND TESTING 98

e v e n t ( 1 6 , 1 , p i t c h ( 1 9 , 1 1 ) , dur ( 1 / 2 ) , t ime ( 3 0 0 0 0 , 3 6 0 0 0 ) , 1 5 , [ ] , 1 7 ,G2927 , G2928 , G2929 ) e v e n t ( 1 7 , 1 , p i t c h ( 1 7 , 1 0 ) , dur ( 1 / 8 ) ,

t ime ( 3 6 0 0 0 , 3 7 5 0 0 ) , 1 6 , [ ] , 1 8 , G2977 , G2978 , G2979 ) e v e n t ( 1 8 , 1 ,p i t c h ( 1 7 , 1 0 ) , dur ( 1 / 8 ) , t ime ( 3 7 5 0 0 , 3 9 0 0 0 ) , 1 7 , [ 3 4 ] , 1 9 , G3015 ,G3016 , G3017 ) e v e n t ( 1 9 , 1 , p i t c h ( 1 7 , 1 0 ) , dur ( 1 / 8 ) , t ime ( 3 9 0 0 0 ,

4 0 5 0 0 ) , 1 8 , [ 3 4 ] , 2 0 , G3053 , G3054 , G3055 ) e v e n t ( 2 0 , 1 , p i t c h ( 1 7 ,1 0 ) , dur ( 1 / 8 ) , t ime ( 4 0 5 0 0 , 4 2 0 0 0 ) , 1 9 , [ 3 4 ] , 2 1 , G3091 , G3092 ,G3093 ) e v e n t ( 2 1 , 1 , p i t c h ( 1 6 , 9 ) , dur ( 1 / 4 ) , t ime ( 4 2 0 0 0 , 4 5 0 0 0 ) , 2 0 ,

[ ] , 2 2 , G3141 , G3142 , G3143 ) e v e n t ( 2 2 , 1 , p i t c h ( 1 6 , 9 ) , dur ( 1 / 4 ) ,t ime ( 4 5 0 0 0 , 4 8 0 0 0 ) , 2 1 , [ 3 5 ] , 2 3 , G3179 , G3180 , G3181 ) e v e n t ( 2 3 , 1 ,p i t c h ( 1 9 , 1 1 ) , dur ( 1 / 8 ) , t ime ( 4 8 0 0 0 , 4 9 5 0 0 ) , 2 2 , [ ] , 2 4 , G3229 ,G3230 , G3231 ) e v e n t ( 2 4 , 1 , p i t c h ( 1 9 , 1 1 ) , dur ( 1 / 8 ) , t ime ( 4 9 5 0 0 ,

5 1 0 0 0 ) , 2 3 , [ 3 6 ] , 2 5 , G3267 , G3268 , G3269 ) e v e n t ( 2 5 , 1 , p i t c h ( 1 9 ,1 1 ) , dur ( 1 / 8 ) , t ime ( 5 1 0 0 0 , 5 2 5 0 0 ) , 2 4 , [ 3 6 ] , 2 6 , G3305 , G3306 ,G3307 ) e v e n t ( 2 6 , 1 , p i t c h ( 1 9 , 1 1 ) , dur ( 1 / 8 ) , t ime ( 5 2 5 0 0 , 5 4 0 0 0 ) , 2 5 ,

[ 3 6 ] , 2 7 , G3343 , G3344 , G3345 ) e v e n t ( 2 7 , 1 , p i t c h ( 1 2 , 7 ) , dur ( 1 / 1 ) ,t ime ( 5 4 0 0 0 , 6 6 0 0 0 ) , 2 6 , [ ] , end , G3393 , G3394 , G3395 ) e v e n t ( 2 8 , 2 ,p i t c h ( 0 , 0 ) , dur ( 1 / 2 ) , t ime ( 0 , 6 0 0 0 ) , s t a r t , [ 1 ] , 2 9 , G3652 , G3653 ,G3654 ) e v e n t ( 2 9 , 2 , p i t c h ( 0 , 0 ) , dur ( 1 / 2 ) , t ime ( 6 0 0 0 , 1 2 0 0 0 ) , 2 8 ,

[ 5 ] , 3 0 , G3690 , G3691 , G3692 ) e v e n t ( 3 0 , 2 , p i t c h ( 5 , 3 ) , dur ( 1 / 2 ) ,t ime ( 1 2 0 0 0 , 1 8 0 0 0 ) , 2 9 , [ 7 ] , 3 1 , G3728 , G3729 , G3730 ) e v e n t ( 3 1 , 2 ,p i t c h ( 0 , 0 ) , dur ( 1 / 2 ) , t ime ( 1 8 0 0 0 , 2 4 0 0 0 ) , 3 0 , [ 1 1 ] , 3 2 , G3766 ,G3767 , G3768 ) e v e n t ( 3 2 , 2 , p i t c h ( 5 , 3 ) , dur ( 1 / 2 ) , t ime ( 2 4 0 0 0 ,

3 0 0 0 0 ) , 3 1 , [ 1 2 ] , 3 3 , G3804 , G3805 , G3806 ) e v e n t ( 3 3 , 2 , p i t c h ( 0 ,0 ) , dur ( 1 / 2 ) , t ime ( 3 0 0 0 0 , 3 6 0 0 0 ) , 3 2 , [ 1 6 ] , 3 4 , G3842 , G3843 ,G3844 ) e v e n t ( 3 4 , 2 , p i t c h ( 7 , 4 ) , dur ( 1 / 2 ) , t ime ( 3 6 0 0 0 , 4 2 0 0 0 ) , 3 3 ,

[ 1 7 ] , 3 5 , G3880 , G3881 , G3882 ) e v e n t ( 3 5 , 2 , p i t c h ( 0 , 0 ) , dur ( 1 / 2 ) ,t ime ( 4 2 0 0 0 , 4 8 0 0 0 ) , 3 4 , [ 2 1 ] , 3 6 , G3918 , G3919 , G3920 ) e v e n t ( 3 6 , 2 ,p i t c h (−5 , −3 ) , dur ( 1 / 2 ) , t ime ( 4 8 0 0 0 , 5 4 0 0 0 ) , 3 5 , [ 2 3 ] , 3 7 , G3956 ,G3957 , G3958 ) e v e n t ( 3 7 , 2 , p i t c h ( 0 , 0 ) , dur ( 1 / 2 ) , t ime ( 5 4 0 0 0 ,

6 0 0 0 0 ) , 3 6 , [ 2 7 ] , end , G3994 , G3995 , G3996 ) end−marker

Tags :

g l o b a l ( tag ( p i t c h s y s t e m ) , d i a t o n i c ) .g l o b a l ( tag ( c o m m e n t s t y l e ) , r e f e r e n c e d ) .g l o b a l ( tag ( meter ) , 2 / 4 ) .g l o b a l ( d u r a t i o n , dur ( 1 / 2 ) ) .g l o b a l ( o c t a v e , 0 ) .g l o b a l ( p a r t , 3 ) .g l o b a l ( num parts , 2 ) .g l o b a l ( tag ( key ) , c ) .g l o b a l ( tag ( s c a l e ) , c ˜ major ) .

G e n e r a t i n g s i m p l e 2 o u t . gmnSucceeded .

simple3

IN% s i m p l e GUIDO example

CHAPTER 6. CODE AND TESTING 99

% t h i r d enhancement% add ing s l u r s v o i c e% and newLine−Tag

{ [ \ meter<"2/4">meter \ s l u r ( c1 ∗1/8 d e f g /4 g ) \ s l u r ( a /8 a a a g / 2 )a /8 a a a g /2 f /8 f f f \ newLine e /4 e g/8g g g c ∗1 \ s t a f f O f f ] ,

[ \ meter<"2/4">meter \ c l e f<"bass">c l e f c0 /2 c f c f c g c g−1 c0 ] }

% s e e s i m p l e 4 . gmn v o r f u r t h e r enhacements .

OUT% GUIDO Music N o t a t i o n Language v1 . 0%% This f i l e was g e n e r a t e d by the PELOG m u s i c a l r u l e system% ( c ) 1 9 9 9 M i c h a e l Droettboom

{[\ p i t c h s y s t e m<"diatonic">p i t c h s y s t e m \ c o m m e n t s t y l e<"referenced">c o m m e n t s t y l e \meter<"2/4">meter\ key<"c">key \ s c a l e<"c~major">s c a l e \ text<"1">t e x t c 1 ∗1/8 \ text<"2">t e x t d 1 ∗1/8\ text<"3">t e x t e 1 ∗1/8 \ text<"4">t e x t f 1 ∗1/8 \ text<"5">t e x t g 1 ∗1/4 \ text<"6">t e x t g 1 ∗1/4\ text<"7">t e x t a 1 ∗1/8 \ text<"8">t e x t a 1 ∗1/8 \ text<"9">t e x t a 1 ∗1/8 \ text<"10">t e x t a 1 ∗1/8\ text<"11">t e x t g 1 ∗1/2 \ text<"12">t e x t a 1 ∗1/8 \ text<"13">t e x t a 1 ∗1/8\ text<"14">t e x t a 1 ∗1/8 \ text<"15">t e x t a 1 ∗1/8 \ text<"16">t e x t g 1 ∗1/2\ text<"17">t e x t f 1 ∗1/8 \ text<"18">t e x t f 1 ∗1/8 \ text<"19">t e x t f 1 ∗1/8\ text<"20">t e x t f 1 ∗1/8 \ text<"21">t e x t e 1 ∗1/4 \ text<"22">t e x t e 1 ∗1/4\ text<"23">t e x t g 1 ∗1/8 \ text<"24">t e x t g 1 ∗1/8 \ text<"25">t e x t g 1 ∗1/8\ text<"26">t e x t g 1 ∗1/8 \ text<"27">t e x t c 1 ∗ 1 / 1 ] , [ \ p i t c h s y s t e m<"diatonic">p i t c h s y s t e m\ c o m m e n t s t y l e<"referenced">c o m m e n t s t y l e \meter<"2/4">meter \ key<"c">key \ s c a l e<"c~major">s c a l e\ text<"28">t e x t c 0 ∗1/2 \ text<"29">t e x t c 0 ∗1/2 \ text<"30">t e x t f 0 ∗1/2\ text<"31">t e x t c 0 ∗1/2 \ text<"32">t e x t f 0 ∗1/2 \ text<"33">t e x t c 0 ∗1/2\ text<"34">t e x t g 0 ∗1/2 \ text<"35">t e x t c 0 ∗1/2 \ text<"36">t e x t g−1∗1/2\ text<"37">t e x t c 0 ∗1 / 2 ]}

CHAPTER 6. CODE AND TESTING 100

TERMINAL7 ?− t e s t p a r s e r g r a m m a r (’simple3.gmn’ , ’simple3out.gmn’ ) .T e s t i n g GUIDO P a r s e r /Grammar−−−−>P a r s i n g s i m p l e 3 . gmnParse OK

Score t r e e :e v e n t ( 1 , 1 , p i t c h ( 1 2 , 7 ) , dur ( 1 / 8 ) , t ime ( 0 , 1 5 0 0 ) , s t a r t , [ ] , 2 ,G2519 , G2520 , G2521 ) e v e n t ( 2 , 1 , p i t c h ( 1 4 , 8 ) , dur ( 1 / 8 ) , t ime ( 1 5 0 0 ,

3 0 0 0 ) , 1 , [ 2 8 ] , 3 , G2557 , G2558 , G2559 ) e v e n t ( 3 , 1 , p i t c h ( 1 6 , 9 ) ,dur ( 1 / 8 ) , t ime ( 3 0 0 0 , 4 5 0 0 ) , 2 , [ 2 8 ] , 4 , G2595 , G2596 , G2597 )e v e n t ( 4 , 1 , p i t c h ( 1 7 , 1 0 ) , dur ( 1 / 8 ) , t ime ( 4 5 0 0 , 6 0 0 0 ) , 3 , [ 2 8 ] , 5 ,G2633 , G2634 , G2635 ) e v e n t ( 5 , 1 , p i t c h ( 1 9 , 1 1 ) , dur ( 1 / 4 ) ,

t ime ( 6 0 0 0 , 9 0 0 0 ) , 4 , [ ] , 6 , G2683 , G2684 , G2685 ) e v e n t ( 6 , 1 ,p i t c h ( 1 9 , 1 1 ) , dur ( 1 / 4 ) , t ime ( 9 0 0 0 , 1 2 0 0 0 ) , 5 , [ 2 9 ] , 7 , G2721 ,G2722 , G2723 ) e v e n t ( 7 , 1 , p i t c h ( 2 1 , 1 2 ) , dur ( 1 / 8 ) , t ime ( 1 2 0 0 0 ,

1 3 5 0 0 ) , 6 , [ ] , 8 , G2786 , G2787 , G2788 ) e v e n t ( 8 , 1 , p i t c h ( 2 1 , 1 2 ) ,dur ( 1 / 8 ) , t ime ( 1 3 5 0 0 , 1 5 0 0 0 ) , 7 , [ 3 0 ] , 9 , G2824 , G2825 , G2826 )e v e n t ( 9 , 1 , p i t c h ( 2 1 , 1 2 ) , dur ( 1 / 8 ) , t ime ( 1 5 0 0 0 , 1 6 5 0 0 ) , 8 , [ 3 0 ] , 1 0 ,G2862 , G2863 , G2864 ) e v e n t ( 1 0 , 1 , p i t c h ( 2 1 , 1 2 ) , dur ( 1 / 8 ) ,

t ime ( 1 6 5 0 0 , 1 8 0 0 0 ) , 9 , [ 3 0 ] , 1 1 , G2900 , G2901 , G2902 ) e v e n t ( 1 1 , 1 ,p i t c h ( 1 9 , 1 1 ) , dur ( 1 / 2 ) , t ime ( 1 8 0 0 0 , 2 4 0 0 0 ) , 1 0 , [ ] , 1 2 , G2950 ,G2951 , G2952 ) e v e n t ( 1 2 , 1 , p i t c h ( 2 1 , 1 2 ) , dur ( 1 / 8 ) , t ime ( 2 4 0 0 0 ,

2 5 5 0 0 ) , 1 1 , [ ] , 1 3 , G3012 , G3013 , G3014 ) e v e n t ( 1 3 , 1 , p i t c h ( 2 1 ,1 2 ) , dur ( 1 / 8 ) , t ime ( 2 5 5 0 0 , 2 7 0 0 0 ) , 1 2 , [ 3 2 ] , 1 4 , G3050 , G3051 ,G3052 ) e v e n t ( 1 4 , 1 , p i t c h ( 2 1 , 1 2 ) , dur ( 1 / 8 ) , t ime ( 2 7 0 0 0 , 2 8 5 0 0 ) , 1 3 ,

[ 3 2 ] , 1 5 , G3088 , G3089 , G3090 ) e v e n t ( 1 5 , 1 , p i t c h ( 2 1 , 1 2 ) ,dur ( 1 / 8 ) , t ime ( 2 8 5 0 0 , 3 0 0 0 0 ) , 1 4 , [ 3 2 ] , 1 6 , G3126 , G3127 , G3128 )e v e n t ( 1 6 , 1 , p i t c h ( 1 9 , 1 1 ) , dur ( 1 / 2 ) , t ime ( 3 0 0 0 0 , 3 6 0 0 0 ) , 1 5 , [ ] , 1 7 ,G3176 , G3177 , G3178 ) e v e n t ( 1 7 , 1 , p i t c h ( 1 7 , 1 0 ) , dur ( 1 / 8 ) ,

t ime ( 3 6 0 0 0 , 3 7 5 0 0 ) , 1 6 , [ ] , 1 8 , G3226 , G3227 , G3228 ) e v e n t ( 1 8 , 1 ,p i t c h ( 1 7 , 1 0 ) , dur ( 1 / 8 ) , t ime ( 3 7 5 0 0 , 3 9 0 0 0 ) , 1 7 , [ 3 4 ] , 1 9 , G3264 ,G3265 , G3266 ) e v e n t ( 1 9 , 1 , p i t c h ( 1 7 , 1 0 ) , dur ( 1 / 8 ) , t ime ( 3 9 0 0 0 ,

4 0 5 0 0 ) , 1 8 , [ 3 4 ] , 2 0 , G3302 , G3303 , G3304 ) e v e n t ( 2 0 , 1 , p i t c h ( 1 7 ,1 0 ) , dur ( 1 / 8 ) , t ime ( 4 0 5 0 0 , 4 2 0 0 0 ) , 1 9 , [ 3 4 ] , 2 1 , G3340 , G3341 ,G3342 ) e v e n t ( 2 1 , 1 , p i t c h ( 1 6 , 9 ) , dur ( 1 / 4 ) , t ime ( 4 2 0 0 0 , 4 5 0 0 0 ) , 2 0 ,

[ ] , 2 2 , G3390 , G3391 , G3392 ) e v e n t ( 2 2 , 1 , p i t c h ( 1 6 , 9 ) , dur ( 1 / 4 ) ,t ime ( 4 5 0 0 0 , 4 8 0 0 0 ) , 2 1 , [ 3 5 ] , 2 3 , G3428 , G3429 , G3430 ) e v e n t ( 2 3 , 1 ,

CHAPTER 6. CODE AND TESTING 101

p i t c h ( 1 9 , 1 1 ) , dur ( 1 / 8 ) , t ime ( 4 8 0 0 0 , 4 9 5 0 0 ) , 2 2 , [ ] , 2 4 , G3478 ,G3479 , G3480 ) e v e n t ( 2 4 , 1 , p i t c h ( 1 9 , 1 1 ) , dur ( 1 / 8 ) , t ime ( 4 9 5 0 0 ,

5 1 0 0 0 ) , 2 3 , [ 3 6 ] , 2 5 , G3516 , G3517 , G3518 ) e v e n t ( 2 5 , 1 , p i t c h ( 1 9 ,1 1 ) , dur ( 1 / 8 ) , t ime ( 5 1 0 0 0 , 5 2 5 0 0 ) , 2 4 , [ 3 6 ] , 2 6 , G3554 , G3555 ,G3556 ) e v e n t ( 2 6 , 1 , p i t c h ( 1 9 , 1 1 ) , dur ( 1 / 8 ) , t ime ( 5 2 5 0 0 , 5 4 0 0 0 ) , 2 5 ,

[ 3 6 ] , 2 7 , G3592 , G3593 , G3594 ) e v e n t ( 2 7 , 1 , p i t c h ( 1 2 , 7 ) , dur ( 1 / 1 ) ,t ime ( 5 4 0 0 0 , 6 6 0 0 0 ) , 2 6 , [ ] , end , G3642 , G3643 , G3644 ) e v e n t ( 2 8 , 2 ,p i t c h ( 0 , 0 ) , dur ( 1 / 2 ) , t ime ( 0 , 6 0 0 0 ) , s t a r t , [ 1 ] , 2 9 , G3874 , G3875 ,G3876 ) e v e n t ( 2 9 , 2 , p i t c h ( 0 , 0 ) , dur ( 1 / 2 ) , t ime ( 6 0 0 0 , 1 2 0 0 0 ) , 2 8 ,

[ 5 ] , 3 0 , G3912 , G3913 , G3914 ) e v e n t ( 3 0 , 2 , p i t c h ( 5 , 3 ) , dur ( 1 / 2 ) ,t ime ( 1 2 0 0 0 , 1 8 0 0 0 ) , 2 9 , [ 7 ] , 3 1 , G3950 , G3951 , G3952 ) e v e n t ( 3 1 , 2 ,p i t c h ( 0 , 0 ) , dur ( 1 / 2 ) , t ime ( 1 8 0 0 0 , 2 4 0 0 0 ) , 3 0 , [ 1 1 ] , 3 2 , G3988 ,G3989 , G3990 ) e v e n t ( 3 2 , 2 , p i t c h ( 5 , 3 ) , dur ( 1 / 2 ) , t ime ( 2 4 0 0 0 ,

3 0 0 0 0 ) , 3 1 , [ 1 2 ] , 3 3 , G4026 , G4027 , G4028 ) e v e n t ( 3 3 , 2 , p i t c h ( 0 ,0 ) , dur ( 1 / 2 ) , t ime ( 3 0 0 0 0 , 3 6 0 0 0 ) , 3 2 , [ 1 6 ] , 3 4 , G4064 , G4065 ,G4066 ) e v e n t ( 3 4 , 2 , p i t c h ( 7 , 4 ) , dur ( 1 / 2 ) , t ime ( 3 6 0 0 0 , 4 2 0 0 0 ) , 3 3 ,

[ 1 7 ] , 3 5 , G4102 , G4103 , G4104 ) e v e n t ( 3 5 , 2 , p i t c h ( 0 , 0 ) , dur ( 1 / 2 ) ,t ime ( 4 2 0 0 0 , 4 8 0 0 0 ) , 3 4 , [ 2 1 ] , 3 6 , G4140 , G4141 , G4142 ) e v e n t ( 3 6 , 2 ,p i t c h (−5 , −3 ) , dur ( 1 / 2 ) , t ime ( 4 8 0 0 0 , 5 4 0 0 0 ) , 3 5 , [ 2 3 ] , 3 7 , G4178 ,G4179 , G4180 ) e v e n t ( 3 7 , 2 , p i t c h ( 0 , 0 ) , dur ( 1 / 2 ) , t ime ( 5 4 0 0 0 ,

6 0 0 0 0 ) , 3 6 , [ 2 7 ] , end , G4216 , G4217 , G4218 )end−marker

Tags :

g l o b a l ( tag ( p i t c h s y s t e m ) , d i a t o n i c ) .g l o b a l ( tag ( c o m m e n t s t y l e ) , r e f e r e n c e d ) .g l o b a l ( tag ( meter ) , 2 / 4 ) .g l o b a l ( d u r a t i o n , dur ( 1 / 2 ) ) .g l o b a l ( o c t a v e , 0 ) .g l o b a l ( p a r t , 3 ) .g l o b a l ( num parts , 2 ) .g l o b a l ( tag ( key ) , c ) .g l o b a l ( tag ( s c a l e ) , c ˜ major ) .

G e n e r a t i n g s i m p l e 3 o u t . gmnSucceeded .

6.4 The Pelog library

6.4.1 main.pl

Code

%%%%%%%%%%%%%%%%%%%%%%%% LIBRARIES MAIN MODULE%%%%%%%%%%%%%%%%%%%%%%%

% Simply e n s u r e s t h a t a l l th e Pe log u s e r l i b r a r i e s a r e l o a d e d

:− e n s u r e l o a d e d ( comments ) .

CHAPTER 6. CODE AND TESTING 102

:− e n s u r e l o a d e d ( e v e n t ) .:− e n s u r e l o a d e d ( g l o b a l ) .:− e n s u r e l o a d e d ( i n t e r v a l ) .:− e n s u r e l o a d e d ( p a r t s ) .:− e n s u r e l o a d e d ( p e n a l t y ) .:− e n s u r e l o a d e d ( p i t c h ) .:− e n s u r e l o a d e d ( range ) .:− e n s u r e l o a d e d ( s c a l e ) .:− e n s u r e l o a d e d ( t ime ) .

6.4.2 comments.pl

Code

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗COMMENTS MANAGER

M i c ha e l Droettboom1999

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗

This l i b r a r y p r o v i d e s a mechanism to s t o r e comment s t r i n g s w i t h each e v e n t .These comments can be used to p r o v i d e f e e d b a c k about e v e n t s w i t h i n thes c o r e .

Comments a r e added to t he output f i l e i n th e s t y l e s p e c i f i e d by thec o m m e n t s t y l e tag i n the i n p u t f i l e .

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗USER PREDICATE

comment(+ e v e n t , + comment )I f comment i s i n s t a n t i a t e d , comment i s added to e v e n t ’ se v e n t l i s t .I f comment i s a v a r i a b l e , u n i f i e s w i t h any comment c u r r e n t l yi n e v e n t ’ s comment l i s t

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

:− op ( 1 5 0 , x f x , comment ) .comment (E , Comment ) :−

nonvar ( Comment ) ,add comment (E , Comment ) .

comment (E , Comment ) :−v a r ( Comment ) ,in comment (E , Comment ) .

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗

CHAPTER 6. CODE AND TESTING 103

ADDING COMMENTS TO EVENTS

Comment l i s t s a r e implemented as i m p e r f e c t P r o l o g l i s t s ( wheret he l a s t e l e m e nt i n the l i s t i s a v a r i a b l e ) .

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

add comment (E , Comment ) :− e comment (E , [ Comment | ] ) , ! .add comment (E , Comment ) :− e comment (E , X ) , add comment0 ( Comment , X ) , ! .add comment0 ( Comment , [ Comment | ] ) :− ! .add comment0 ( Comment , [ | T a i l ] ) :− add comment0 ( Comment , T a i l ) .

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗CHECKING FOR THE EXISTENCE OF A COMMENT

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

in comment (E , Comment ) :−e comment (E , CommentList ) ,in comment0 ( Comment , CommentList ) .

in comment0 ( , [ Head | ] ) :−v a r ( Head ) , ! ,f a i l .

in comment0 ( Comment , [ Head | T a i l ] ) :−Comment = Head;in comment0 ( Comment , T a i l ) .

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗OUTPUT A LIST OF COMMENTS IN USER−READABLE FORM

e p r e t t y c o m m e n t (+E, −Comment )Comment i s a P r o l o g s t r i n g c o n t a i n i n g t he e v e n t ’ s commentl i s t i s a u s e r−r e a d a b l e form

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

e p r e t t y c o m m e n t (E , Comment ) :−e comment (E , L ) ,e p r e t t y c o m m e n t 0 ( L , ’’ , Comment ) .

e p r e t t y c o m m e n t 0 ( Var , , ’’ ) :−% I f t he l i s t e l e m e nt i s a v a r i a b l e , t h e r e was an e r r o r% i n t he l i s t c r e a t i o n and we s h o u l d s t o p r e c u r s i o nv a r ( Var ) , ! .

e p r e t t y c o m m e n t 0 ( [ Head | T a i l ] , X , Y) :−% The l a s t good e le m e nt i n th e l i s tv a r ( T a i l ) , ! ,c o n c a t (X , Head , Y ) .

e p r e t t y c o m m e n t 0 ( [ Head | T a i l ] , X , Y) :−% Concatenate each e le m e nt to the output s t r i n g

CHAPTER 6. CODE AND TESTING 104

% and r e c u r s ec o n c a t (X , Head , Y0 ) ,c o n c a t (Y0 , ’, ’ , Y1 ) ,e p r e t t y c o m m e n t 0 ( T a i l , Y1 , Y ) .

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗ADDING EXTRA INFORMATION TO EVENTSThis p r e d i c a t e adds a n o t h e r b i t o f a r b i t r a r y i n f o r m a t i o nto a g i v e n e v e n t .

∗∗ There i s ( as o f y e t ) no p r a c t i c a l use f o r t h i s f e a t u r e andi t i s i n c l u d e d f o r t he s a k e o f e x p a n d i b i l i t y o n l y ∗∗

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

a d d e x t r a (E , E x t r a ) :− e e x t r a (E , [ E x t r a | ] ) , ! .a d d e x t r a (E , E x t r a ) :− e e x t r a (E , X ) , add comment0 ( E x t r a , X ) , ! .

/∗∗∗∗∗∗∗∗TEST CODE∗∗∗∗∗∗∗∗/

test comment :−add comment (E , ’Bach’ ) ,add comment (E , ’Beethoven’ ) ,w r i t e (’Event with comments Bach & Beethoven:’ ) , n l ,w r i t e (E ) , n l ,in comment (E , ’Bach’ ) ,w r i t e (’in_comment check for Bach succeeded’ ) , n l ,in comment (E , ’Beethoven’ ) ,w r i t e (’in_comment check for Beethoven succeeded’ ) , n l ,not in comment (E , ’Brahms’ ) ,w r i t e (’in_comment check for Brahms failed’ ) , n l ,e p r e t t y c o m m e n t (E , P r e t t y ) ,w r i t e (’Pretty comment:’ ) , n l ,w r i t e ( P r e t t y ) .

Testing

?− test comment .Event w i t h comments Bach & Beethoven :e v e n t ( G327 , G328 , G329 , G330 , G331 , G332 , G333 , G334 ,

[ Bach , Beethoven | G340 ] , G336 , G337 )in comment check f o r Bach s u c c e e d e din comment check f o r Beethoven s u c c e e d e din comment check f o r Brahms f a i l e dP r e t t y comment :Bach , BeethovenYes

CHAPTER 6. CODE AND TESTING 105

6.4.3 event.pl

Code

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗EVENT LIBRARY

M i c ha e l DroettboomMay 1999

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗

This i s t he c o r e module o f the e v e n t data s t r u c t u r e . For morei n f o r m a t i o n on t h i s data s t r u c t u r e , p l e a s e s e e t he i m p l e m e n t a t i o ndocumentat ion .

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗REQUIRED LIBRARIES

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

:− e n s u r e l o a d e d ( t ime ) .:− e n s u r e l o a d e d ( p i t c h ) .:− e n s u r e l o a d e d ( ’../core/trees.pl’ ) .:− e n s u r e l o a d e d ( comments ) .

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗USER PREDICATES

f i r s t e v e n t (+ e v e n t )s u c c e e d s i f e v e n t i s t he f i r s t e v e n t i n i t s p a r t

l a s t e v e n t (+ e v e n t )s u c c e e d s i f e v e n t i s t he l a s t e v e n t i n i t s p a r t

p e n u l t i m a t e e v e n t (+ e v e n t s )s u c c e e d s i f e v e n t i s t he p e n u l t i m a t e e v e n t i n i t s p a r te v e n t s i s o f th e form (T , E ) where T i s t he s c o r e t r e e and

E i s t he c u r r e n t e v e n t . Th i s i s h a n d l e d b e h i n d t he s c e n e sby t he r u l e a p p l i c a t i o n mechanism .

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

:− op ( 1 5 0 , x f , f i r s t e v e n t ) .:− op ( 1 5 0 , x f , l a s t e v e n t ) .:− op ( 1 5 0 , x f , p e n u l t i m a t e e v e n t ) .

f i r s t e v e n t (E ) :−e p r e v (E , S ) ,nonvar ( S ) ,

CHAPTER 6. CODE AND TESTING 106

S = s t a r t .

l a s t e v e n t (E ) :−e n e x t (E , S ) ,nonvar ( S ) ,S = end .

p e n u l t i m a t e e v e n t ( (T , E ) ) :−g e t n e x t e v e n t (T , E , EN ) ,EN \= end ,l a s t e v e n t (EN ) .

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗DATA STRUCTURE DEFINITION

These p r e d i c a t e s r e t r i e v e d i f f e r e n t f i e l d s o f t he data s t r u c t u r eThe data s t r u c t u r e i s d e f i n e d as f o l l o w s :

e v e n t ( I n d e x , Part , p i t c h (CPC , CNC ) , dur (Num , Den ) ,t ime ( S t a r t , End ) , P r e v I n d e x , C o n c u r r e n t I n d e x L i s t , N e x t I n d e x ,[ Comment ] , P e n a l t y , [ E x t r a ] ) .

Note t h a t t h e s e p r e d i c a t e s c o u l d have been d e f i n e d u s i n g t heb u i l t−i n p r e d i c a t e arg / 3 , but t h a t would not a l l o w the systemto g e n e r a t e new e v e n t s on−t he− f l y . For i n s t a n c e , t he qu e r y

e i n d e x (E , 1 )

c r e a t e s a new e v e n t w i t h i n d e x 1 :

E = e v e n t ( 1 , G352 , G353 , G354 , G355 , G356 , G357 , G358 ,G359 , G360 , G361 )

The e q u i v a l e n t i m p l e m e n t a t i o n u s i n g arg / 3 :

e i n d e x (E , I n d e x ) :− arg ( 1 , E , I n d e x ) .

would c a u s e an e r r o r i f E were a v a r i a b l e :

[WARNING : arg / 3 : Arguments a r e not s u f f i c i e n t l y i n s t a n t i a t e d ]E x c e p t i o n : ( 8 ) a rg ( 1 , G265 , 1 ) ?

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

e i n d e x ( e v e n t ( I n d e x , , , , , , , , , , ) , I n d e x ) .e p a r t ( e v e n t ( , Part , , , , , , , , , ) , Part ) .e p i t c h ( e v e n t ( , , P i t c h , , , , , , , , ) , P i t c h ) .e d u r a t i o n ( e v e n t ( , , , D u r a t i o n , , , , , , , ) , D u r a t i o n ) .e t i m e ( e v e n t ( , , , , Time , , , , , , ) , Time ) .e p r e v ( e v e n t ( , , , , , Prev , , , , , ) , Prev ) .e v e r t i c a l ( e v e n t ( , , , , , , V e r t i c a l , , , , ) , V e r t i c a l ) .

CHAPTER 6. CODE AND TESTING 107

e n e x t ( e v e n t ( , , , , , , , Next , , , ) , Next ) .e comment ( e v e n t ( , , , , , , , , Comment , , ) , Comment ) .e p e n a l t y ( e v e n t ( , , , , , , , , , P e n a l t y , ) , P e n a l t y ) .e e x t r a ( e v e n t ( , , , , , , , , , , E x t r a ) , E x t r a ) .

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗EVENT TRAVERSAL

g e t n e x t e v e n t (+ s c o r e−t r e e , + e v e n t , − n e x t )g e t p r e v e v e n t (+ s c o r e−t r e e , + e v e n t , − p r e v )

Note t h a t i f t h e r e i s no n e x t or p r e v i o u s e v e n t i n t he g i v e np a r t ( i . e . e v e n t i s t he f i r s t o r l a s t e v e n t ) r e t u r n s t he atoms’ s t a r t ’ o r ’ end ’ .

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

g e t n e x t e v e n t ( , end , end ) :− ! .g e t n e x t e v e n t (T , E , EN) :−

e n e x t (E , I N e x t ) ,g e t n e x t e v e n t 0 (T , I N e x t , EN ) .

g e t n e x t e v e n t 0 ( , end , end ) :− ! .g e t n e x t e v e n t 0 (T , N , EN) :−

i n t e g e r (N ) , ! ,g e t l a b e l (N , T , EN ) .

g e t p r e v e v e n t ( , s t a r t , s t a r t ) :− ! .g e t p r e v e v e n t (T , E , EP) :−

e p r e v (E , I P r e v ) ,g e t p r e v e v e n t 0 (T , I P r e v , EP ) .

g e t p r e v e v e n t 0 ( , s t a r t , s t a r t ) :− ! .g e t p r e v e v e n t 0 (T , N , EP) :−

i n t e g e r (N ) , ! ,g e t l a b e l (N , T , EP ) .

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗VERTICAL RELATIONSHIPS

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

g e t v e r t i c a l (T , E , EV) :−e v e r t i c a l (E , V L i s t ) ,member (N , V L i s t ) ,g e t l a b e l (N , T , EV ) .

g e t v e r t i c a l ( , E , [ ] ) :−e v e r t i c a l (E , [ ] ) .

CHAPTER 6. CODE AND TESTING 108

6.4.4 global.pl

Code

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗GLOBAL VARIABLE MANAGER

M i c ha e l Droettboom1999

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗

L i b r a r y f o r s i m u l a t i n g t he c o n c e p t o f g l o b a l v a r i a b l e s . G l o b a lv a r i a b l e s may h o l d o n l y one v a l u e at a g i v e n t ime .

The g l o b a l l i b r a r y can be used to e x t e n d t he GUIDO p a r s e r tor e c o g n i z e new t a g s . S imply add a g l o b a l d e f a u l t p r e d i c a t e to yourPe log r u l e s e t f i l e . g l o b a l d e f a u l t p r e d i c a t e s a r e o f t he form :

g l o b a l d e f a u l t ( tag ( tagname ) , d e f a u l t )

tagname i s the name o f t he tagd e f a u l t i s t he d e f a u l t v a l u e f o r th e tag i f the tag i s not

p r e s e n t i n t he i n p u t f i l e

The v a l u e o f the tag can be used i n your r u l e s at r u n t i m e u s i n gt he tag p r e d i c a t e .

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗PREDICATE SETTINGS

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

:− m u l t i f i l eg l o b a l / 2 ,g l o b a l d e f a u l t / 2 .

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗USER PREDICATES

tag (+tagname , − v a l u e )Succeeds i f tagname i s a s s i g n e d to v a l u e .Tags t h a t a r e a s s i g n e d to p a r t s ( i . e . not g l o b a l to t he s c o r ea r e r e t r i e v e d u s i n g the form tag ˜ p a r t where tag i s t he tagnameand p a r t i s a p a r t name .

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

:− op ( 1 5 0 , x f x , tag ) .:− op ( 1 0 0 , x f x , ˜ ) .

CHAPTER 6. CODE AND TESTING 109

tag (Name˜ Part , Value ) :−i n t e g e r ( Part ) , ! ,g l o b a l ( tag (Name˜ Part ) , Value ) .

tag (Name˜ Part , Value ) :−not i n t e g e r ( Part ) , ! ,num parts ( P a r t s ) ,p a r t d e f ( Part , PartNo , P a r t s ) ,g l o b a l ( tag (Name˜ PartNo ) , Value ) .

tag (Name , Value ) :−g l o b a l ( tag (Name ) , Value ) .

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗SETTING GLOBAL VARIABLES

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

g l o b a l s e t (X , Y) :−r e t r a c t a l l ( g l o b a l (X , ) ) ,a s s e r t ( g l o b a l (X , Y ) ) .

s e t a l l d e f a u l t s :−f o r a l l ( g l o b a l d e f a u l t (X , Y ) ,

g l o b a l s e t (X , Y ) ) .

Testing

7 ?− g l o b a l s e t ( t e s t , ’Beethoven’ ) .

Yes8 ?− g l o b a l ( t e s t , X ) .

X = ’Beethoven’ ;

No9 ?− g l o b a l s e t ( t e s t , ’Bach’ ) .

Yes10 ?− g l o b a l ( t e s t , X ) .

X = ’Bach’ ;

No11 ?− g l o b a l s e t ( tag ( composer ) , ’Mozart’ ) .

Yes12 ?− composer tag X .

X = ’Mozart’ ;

No13 ?− X tag ’Mozart’ .

CHAPTER 6. CODE AND TESTING 110

X = composer ;

6.4.5 interval.pl

Code

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗INTERVAL LIBRARY

M i c ha e l Droettboom1999

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗

L i b r a r y f o r d e a l i n g w i t h t he r e l a t i o n s h i p between two p i t c h e s .

I n Pe log , i n t e r v a l s can be s p e c i f i e d i n the form t y p e ˜ s i z e , wheret y p e i s a t h r e e−c h a r a c t e r atom s p e c i f y i n g t he t y p e o f i n t e r v a l .The a v a i l a b l e t y p e s a r e l i s t e d below .

t y p e meaning−−−− −−−−−−−maj majormin minorp e r p e r f e c tdim d i m i n i s h e daug augmentedc h r c h r o m a t i csem s e m i t o n e s ( s i z e f i e l d i s # s e m i t o n e s )t r i t r i t o n e

For example , min ˜3 i s a minor t h i r d and maj ˜7 i s a major s e v e n t h .

The sem t y p e r e t u r n s t he s i z e f i e l d as t he number o f s e m i t o n e s ,r e g a r d l e s s o f note names . T h e r e f o r e , maj ˜3 i s e q u i v a l e n t to sem ˜ 4 .

Note t h a t e i t h e r th e t y p e or s i z e f i e l d may be l e f t v a r i a b l e u s i n gP r o l o g ’ s anonymous v a r i a b l e , t he u n d e r s c o r e . T h e r e f o r e , ˜3 w i l ls p e c i f y dim ˜ 3 , min ˜ 3 , maj ˜3 and aug ˜ 3 .

I n t e r v a l s can a l s o be s p e c i f i e d u s i n g o t h e r keywords :

t y p e meaning−−−− −−−−−−−u n i s o n Unison ( the two g i v e n n o t e s have t he same p i t c h )s t e p A seconds k i p Any i n t e r v a l l a r g e r than a secondconsonant Any t h i r d s , f i f t h s , s i x t h s or o c t a v e s t h a t a r e not

d i m i n i s h e d o r augmentedd i s s o n a n t Any s e c o n d s , f o u r t h s or s e v e n t h s

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

CHAPTER 6. CODE AND TESTING 111

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗REQUIRED LIBRARIES

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

:− e n s u r e l o a d e d ( p i t c h ) .:− e n s u r e l o a d e d ( ’../core/bi-math.pl’ ) .:− e n s u r e l o a d e d (’global.pl’ ) .

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗OPERATORS

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

:− op ( 1 2 5 , x f x , ˜ ) .:− op ( 1 0 0 , f y , − ) .:− op ( 1 2 5 , x f x , : ) .

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗USER FUNCTIONS

a b s o l u t e i n t e r v a l (? e v e n t a : ? e v e n t b , ? i n t e r v a l [ c o n t o u r ? d i r ] )Succeeds i f the a b s o l u t e i n t e r v a l between two e v e n t s , e v e n t aand e v e n t b , i s e q u a l to i n t e r v a l . i n t e r v a l may be i n any forms p e c i f i e d i n the i n t r o d u c t i o n to t he i n t e r v a l l i b r a r y .

c y c l i c i n t e r v a l (? e v e n t a : ? e v e n t b , ? i n t e r v a l [ c o n t o u r ? d i r ] )Succeeds i s the c y c l i c i n t e r v a l between two e v e n t s , e v e n t a ande v e n t b , i s e q u a l to i n t e r v a l . i n t e r v a l may be i n any forms p e c i f i e d i n the i n t r o d u c t i o n to t he i n t e r v a l l i b r a r y .

The o p t i o n a l c o n t o u r u n i f i e s w i t h up i f e v e n t b i s h i g h e r i n p i t c hthan e v e n t a , down i f e v e n t b i s l o w e r i n p i t c h than e v e n t a , ands t a t i c i f e v e n t b i s t he same p i t c h as e v e n t a .

c o n t o u r (? e v e n t a : ? e v e n t b , ? d i r )De te rmine s d i r e c t i o n o f i n t e r v a l .

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

:− op ( 1 4 9 , x f x , c o n t o u r ) .:− op ( 1 5 0 , x f x , c i n t e r v a l ) .:− op ( 1 5 0 , x f x , c y c l i c i n t e r v a l ) .

c i n t e r v a l ( FromP : ToP , I c o n t o u r D i r ) :− ! ,c y c l i c i n t e r v a l ( FromP , ToP , I , D i r ) .

c i n t e r v a l ( FromP : ToP , I ) :−c y c l i c i n t e r v a l ( FromP , ToP , I , ) .

c y c l i c i n t e r v a l ( FromP : ToP , I c o n t o u r D i r ) :− ! ,

CHAPTER 6. CODE AND TESTING 112

c y c l i c i n t e r v a l ( FromP , ToP , I , D i r ) .c y c l i c i n t e r v a l ( FromP : ToP , I ) :−

c y c l i c i n t e r v a l ( FromP , ToP , I , ) .

c y c l i c i n t e r v a l ( FromP , ToP , I , D i r ) :−c o n t p i t c h c l a s s ( FromP , FromCPC ) ,c o n t n o t e c l a s s ( FromP , FromCNC ) ,c o n t p i t c h c l a s s (ToP , ToCPC ) ,c o n t n o t e c l a s s (ToP , ToCNC ) ,c y c l i c i n t e r v a l c p (FromCPC , FromCNC , ToCPC , ToCNC , I , D i r ) .

% Note : c y c l i c i n t e r v a l c p comes i n m u l t i p l e f l a v o u r s depend ing on% which arguments a r e i n s t a n t i a t e d . When the p i t c h e s a r e known , t h e i r% d i f f e r e n c e s a r e c a l c u l a t e d f i r s t . When the i n t e r v a l name i s known ,% i t s v a l u e i s c a l c u l a t e d f i r s t .c y c l i c i n t e r v a l c p (FromCPC , FromCNC , ToCPC , ToCNC , IC ˜ I , D i r ) :−

nonvar ( I ) ,I =< 8,f a c t o r ( I 0 , I , 7 , ) ,i n t e r v a l ( IC ˜ I 0 , Dir , CPC , CNC ) ,p l u s (FromCPC , CPC , ToCPC ) ,p l u s (FromCNC , CNC , ToCNC ) .

c y c l i c i n t e r v a l c p (FromCPC , FromCNC , ToCPC , ToCNC , IC ˜ I , Dir ) :−var ( I ) ,p l u s (FromCPC , CPC , ToCPC ) ,p l u s (FromCNC , CNC , ToCNC ) ,i n t e r v a l ( IC ˜ I 1 , Dir , CPC , CNC ) ,I i s ( I 1 mod 7 ) .

c y c l i c i n t e r v a l c p (FromCPC , FromCNC , ToCPC , ToCNC , I , Dir ) :−nonvar ( I ) ,atomic ( I ) ,i n t e r v a l ( I , Dir , CPC , CNC ) ,p l u s (FromCPC , CPC , ToCPC ) ,p l u s (FromCNC , CNC , ToCNC ) .

:− op ( 1 5 0 , x f x , a b s i n t e r v a l ) .:− op ( 1 5 0 , x f x , a i n t e r v a l ) .

a b s o l u t e i n t e r v a l ( FromP : ToP , I c o n t o u r Dir ) :− ! ,a b s o l u t e i n t e r v a l ( FromP , ToP , I , Dir ) .

a b s o l u t e i n t e r v a l ( FromP : ToP , I ) :−a b s o l u t e i n t e r v a l ( FromP , ToP , I , ) .

a i n t e r v a l ( FromP : ToP , I c o n t o u r Dir ) :− ! ,a b s o l u t e i n t e r v a l ( FromP , ToP , I , Dir ) .

a i n t e r v a l ( FromP : ToP , I ) :−a b s o l u t e i n t e r v a l ( FromP , ToP , I , ) .

a b s o l u t e i n t e r v a l ( FromP , ToP , I , Dir ) :−c o n t p i t c h c l a s s ( FromP , FromCPC ) ,c o n t n o t e c l a s s ( FromP , FromCNC ) ,c o n t p i t c h c l a s s (ToP , ToCPC ) ,

CHAPTER 6. CODE AND TESTING 113

c o n t n o t e c l a s s (ToP , ToCNC ) ,a b s o l u t e i n t e r v a l c p (FromCPC , FromCNC , ToCPC , ToCNC , I , Dir ) .

% Note : a b s o l u t e i n t e r v a l c p comes i n m u l t i p l e f l a v o u r s de pe nd ing on% which arguments a r e i n s t a n t i a t e d . When the p i t c h e s a r e known , t h e i r% d i f f e r e n c e s a r e c a l c u l a t e d f i r s t . When the i n t e r v a l name i s known ,% i t s v a l u e i s c a l c u l a t e d f i r s t .a b s o l u t e i n t e r v a l c p (FromCPC , FromCNC , ToCPC , ToCNC , I , Dir ) :−

nonvar (FromCPC ) , nonvar (FromCNC ) , nonvar (ToCPC ) , nonvar (ToCNC ) , ! ,p l u s (FromCPC , CPC , ToCPC ) ,p l u s (FromCNC , CNC , ToCNC ) ,i n t e r v a l ( I , Dir , CPC , CNC ) .

a b s o l u t e i n t e r v a l c p (FromCPC , FromCNC , ToCPC , ToCNC , I , Dir ) :−nonvar ( I ) ,i n t e r v a l ( I , Dir , CPC , CNC ) ,p l u s (FromCPC , CPC , ToCPC ) ,p l u s (FromCNC , CNC , ToCNC ) .

c o n t o u r ( FromP : ToP , Dir ) :−c o n t o u r ( FromP , ToP , Dir ) .

c o n t o u r ( FromP , ToP , Dir ) :−c o n t p i t c h c l a s s ( FromP , FromCPC ) ,c o n t p i t c h c l a s s (ToP , ToCPC ) ,c o n t o u r c p (FromCPC , ToCPC , Dir ) .

c o n t o u r c p (FromCPC , ToCPC , Dir ) :−(ToCPC > = FromCPC ∗−>

D i r = up;

ToCPC = FromCPC ∗−>D i r = s t a t i c

;D i r = down ) .

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗

PRIVATE PREDICATES∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗INTERVAL DEFINITION

i n t e r v a l (? I n t e r v a l C l a s s ˜? I n t e r v a l , ? PC , ? NC)I n t e r v a l i s the i n t e r v a l from ( 0 , 0 ) to ( PC , NC)

∗/

i n t e r v a l ( u n i s , up , 0 , 0 ) .

CHAPTER 6. CODE AND TESTING 114

i n t e r v a l ( I , up , PC , NC) :−( g l o b a l ( tag ( p i t c h s y s t e m ) , d i a t o n i c )

;g l o b a l ( tag ( p i t c h s y s t e m ) , german )

;g l o b a l ( tag ( p i t c h s y s t e m ) , s o l f e g e )

;g l o b a l ( tag ( p i t c h s y s t e m ) , a l l ) ) ,

i n t e r v a l t o n a l ( I , PC , NC ) .i n t e r v a l ( sem˜ I , up , I , ) :−

g l o b a l ( tag ( p i t c h s y s t e m ) , a t o n a l ) .i n t e r v a l ( sem˜ I , down , PC , ) :−

g l o b a l ( tag ( p i t c h s y s t e m ) , a t o n a l ) ,o p p o s i t e ( I , PC ) .

i n t e r v a l ( I , down , PC , NC) :−% a u t o m a t i c a l l y r e f l e c t i n t e r v a l s to% downard c o n t o u ri n t e r v a l ( I , up , PC1 , NC1 ) ,o p p o s i t e (PC1 , PC ) ,o p p o s i t e (NC1 , NC ) .

% BASIC INTERVALS WITHIN THE FIRST OCTAVE

i n t e r v a l b a s i c ( p e r ˜ 1 , 0 , 0 ) . % p e r f e c t u n i s o ni n t e r v a l b a s i c ( c h r ˜ 1 , 1 , 0 ) . % c h r o m a t i c i n t e r v a l

i n t e r v a l b a s i c ( dim ˜ 2 , 0 , 1 ) .i n t e r v a l b a s i c ( min ˜ 2 , 1 , 1 ) .i n t e r v a l b a s i c ( maj ˜ 2 , 2 , 1 ) .i n t e r v a l b a s i c ( aug ˜ 2 , 3 , 1 ) .

i n t e r v a l b a s i c ( dim ˜ 3 , 2 , 2 ) .i n t e r v a l b a s i c ( min ˜ 3 , 3 , 2 ) .i n t e r v a l b a s i c ( maj ˜ 3 , 4 , 2 ) .i n t e r v a l b a s i c ( aug ˜ 3 , 5 , 2 ) .

i n t e r v a l b a s i c ( dim ˜ 4 , 4 , 3 ) .i n t e r v a l b a s i c ( p e r ˜ 4 , 5 , 3 ) .i n t e r v a l b a s i c ( aug ˜ 4 , 6 , 3 ) .

i n t e r v a l b a s i c ( t r i ˜ 4 , 6 , 3 ) . % t r i t o n e ( aug ˜4)i n t e r v a l b a s i c ( t r i ˜ 5 , 6 , 4 ) . % t r i t o n e ( dim ˜5)

i n t e r v a l b a s i c ( dim ˜ 5 , 6 , 4 ) .i n t e r v a l b a s i c ( p e r ˜ 5 , 7 , 4 ) .i n t e r v a l b a s i c ( aug ˜ 5 , 8 , 4 ) .

i n t e r v a l b a s i c ( dim ˜ 6 , 7 , 5 ) .i n t e r v a l b a s i c ( min ˜ 6 , 8 , 5 ) .i n t e r v a l b a s i c ( maj ˜ 6 , 9 , 5 ) .i n t e r v a l b a s i c ( aug ˜ 6 , 1 0 , 5 ) .

CHAPTER 6. CODE AND TESTING 115

i n t e r v a l b a s i c ( dim ˜ 7 , 9 , 6 ) .i n t e r v a l b a s i c ( min ˜ 7 , 1 0 , 6 ) .i n t e r v a l b a s i c ( maj ˜ 7 , 1 1 , 6 ) .i n t e r v a l b a s i c ( aug ˜ 7 , 1 2 , 6 ) .

i n t e r v a l b a s i c ( dim ˜ 8 , 1 1 , 7 ) .i n t e r v a l b a s i c ( p e r ˜ 8 , 1 2 , 7 ) .i n t e r v a l b a s i c ( aug ˜ 8 , 1 3 , 7 ) .

% TONAL INTERVALS

i n t e r v a l t o n a l ( IC , PC , NC) :−i n t e r v a l b a s i c ( IC , PC , NC ) .

% COMPOUND INTERVALS

i n t e r v a l t o n a l ( IC ˜ I , PC , NC) :−nonvar (PC ) , nonvar (NC ) , v a r ( IC ) , v a r ( I ) ,PC > 1 2 ,f a c t o r (PC , PC1 , 1 2 , Oct ) ,f a c t o r (NC , NC1 , 7 , Oct ) ,i n t e r v a l b a s i c ( IC ˜ I L o c a l , PC1 , NC1 ) ,I i s I L o c a l + ( Oct ∗ 8 ) − 1 .

i n t e r v a l t o n a l ( IC ˜ I , PC , NC) :−nonvar ( IC ) , nonvar ( I ) , v a r (PC ) , v a r (NC ) ,I L o c a l 0 i s ( I mod 7 ) ,( I L o c a l 0 = 1 −> I L o c a l = 8 ; I L o c a l i s I L o c a l 0 ) ,Oct i s I / / 8 ,i n t e r v a l b a s i c ( IC ˜ I L o c a l , PC1 , NC1 ) ,f a c t o r (PC , PC1 , 1 2 , Oct ) ,PC > 1 2 ,f a c t o r (NC , NC1 , 7 , Oct ) .

i n t e r v a l t o n a l ( IC ˜ I , PC , NC) :−i n t e r v a l b a s i c ( IC ˜ I L o c a l , PC1 , NC1 ) ,f a c t o r (PC , PC1 , 1 2 , Oct ) ,PC > 1 2 ,f a c t o r (NC , NC1 , 7 , Oct ) ,I i s I L o c a l + ( Oct ∗ 7 ) .

% SKIPS AND STEPS

i n t e r v a l t o n a l ( s t e p , PC , 1 ) :−i n t e r v a l b a s i c ( ˜ 2 , PC , 1 ) .

i n t e r v a l t o n a l ( s k i p , PC , NC) :−i n t e r v a l t o n a l ( ˜ , PC , NC ) ,

NC > 1 , PC > 2 .

% CONSONANCES AND DISSONANCES

i n t e r v a l t o n a l ( consonant , PC , NC) :−

CHAPTER 6. CODE AND TESTING 116

g e t i n t e g e r ( F ) ,member ( I L o c a l , [ 3 , 5 , 6 , 8 ] ) ,f a c t o r ( I , I L o c a l , 7 , F ) ,i n t e r v a l t o n a l ( Type˜ I , PC , NC ) ,Type \= dim ,Type \= aug ,Type \= t r i .

i n t e r v a l t o n a l ( d i s s o n a n t , PC , NC) :−i n t e r v a l t o n a l ( t r i ˜ , PC , NC ) .

i n t e r v a l t o n a l ( d i s s o n a n t , PC , NC) :−g e t i n t e g e r ( F ) ,member ( I L o c a l , [ 2 , 4 , 7 ] ) ,f a c t o r ( I , I L o c a l , 7 , F ) ,i n t e r v a l t o n a l ( ˜ I , PC , NC ) .

Testing

?− g l o b a l s e t ( tag ( p i t c h s y s t e m ) , d i a t o n i c ) .

Yes

?− p i t c h ( 0 , 0 ) : p i t c h ( 7 , 5 ) c i n t e r v a l I c o n t o u r C .

I = dim ˜6C = up ;

No?− p i t c h ( 0 , 0 ) : X c i n t e r v a l dim ˜6 c o n t o u r up .

X = p i t c h ( 7 , 5 ) ;

X = p i t c h ( 1 9 , 1 2 ) ;

X = p i t c h ( 1 9 , 1 2 ) ;

X = p i t c h ( 3 1 , 1 9 ) ;

X = p i t c h ( 3 1 , 1 9 ) ;

X = p i t c h ( 4 3 , 2 6 ) ;

X = p i t c h ( 4 3 , 2 6 ) ;

X = p i t c h ( 5 5 , 3 3 ) ;

X = p i t c h ( 5 5 , 3 3 ) ;

X = p i t c h ( 6 7 , 4 0 ) ;

X = p i t c h ( 6 7 , 4 0 ) ;

X = p i t c h ( 7 9 , 4 7 ) ;

CHAPTER 6. CODE AND TESTING 117

X = p i t c h ( 7 9 , 4 7 ) ;

X = p i t c h ( 7 9 , 4 7 ) ;

X = p i t c h ( 9 1 , 5 4 ) ;

X = p i t c h ( 9 1 , 5 4 ) ;

X = p i t c h ( 1 0 3 , 6 1 ) ;

X = p i t c h ( 1 0 3 , 6 1 ) ;

X = p i t c h ( 1 1 5 , 6 8 ) ;

X = p i t c h ( 1 1 5 , 6 8 ) ;

X = p i t c h ( 1 2 7 , 7 5 ) ;

X = p i t c h ( 1 2 7 , 7 5 ) ;

X = p i t c h ( 1 3 9 , 8 2 ) ;

X = p i t c h ( 1 3 9 , 8 2 ) ;

X = p i t c h ( 1 5 1 , 8 9 ) ;

No?− p i t c h ( 1 2 , 7 ) : X a i n t e r v a l dim ˜6 c o n t o u r C .

X = p i t c h ( 1 9 , 1 2 )C = up ;

X = p i t c h ( 5 , 2 )C = down ;

No?− p i t c h ( 0 , 0 ) : p i t c h ( 2 , 1 ) a i n t e r v a l I .

I = maj ˜2 c o n t o u r up ;

I = s t e p c o n t o u r up ;

I = d i s s o n a n t c o n t o u r up ;

No?− p i t c h ( 0 , 0 ) : p i t c h ( 4 , 2 ) a i n t e r v a l I .

I = maj ˜3 c o n t o u r up ;

I = s k i p c o n t o u r up ;

CHAPTER 6. CODE AND TESTING 118

I = consonant c o n t o u r up ;

No?− p i t c h ( 0 , 0 ) : X a i n t e r v a l consonant .

X = p i t c h ( 3 , 2 ) ;

X = p i t c h ( 4 , 2 ) ;

X = p i t c h ( 7 , 4 ) ;

X = p i t c h ( 8 , 5 ) ;

X = p i t c h ( 9 , 5 ) ;

X = p i t c h ( 1 5 , 9 ) ;

X = p i t c h ( 1 6 , 9 ) ;

X = p i t c h ( 1 9 , 1 1 ) ;

X = p i t c h ( 2 0 , 1 2 ) ;

X = p i t c h ( 2 1 , 1 2 ) ;;X = p i t c h ( 2 7 , 1 6 )

Yes?− p i t c h ( 0 , 0 ) : p i t c h ( 4 , 2 ) c o n t o u r C .

C = up

Yes?− p i t c h ( 4 , 2 ) : p i t c h ( 0 , 0 ) c o n t o u r C .

C = down ;

No

6.4.6 parts.pl

Code

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗PARTS MANAGER

M i c ha e l Droettboom1999

CHAPTER 6. CODE AND TESTING 119

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗

This l i b r a r y d e a l s w i t h i n f o r m a t i o n about i n d i v i d u a l p a r t s( monophonic l i n e s ) i n the s c o r e .

A p a r t can be r e f e r e n c e d to by number , i n which c a s e the top p a r ti s p a r t 1 , the n e x t h i g h e s t i s p a r t 2 , e t c . A p a r t can a l s o ber e f e r e n c e d by a name d e f i n e d by t he p a r t d e f f a c t p r e d i c a t e .

A d d i t i o n a l p a r t names can be d e f i n e d by add ing p a r t d e f p r e d i c a t e sto t he r u l e s e t f i l e . p a r t d e f p r e d i c a t e s have the form :

p a r t d e f ( name , p a r t n o , numparts )

name i s the name o f t he p a r tp a r t n o i s t he c o r r e s p o n d i n g p a r t numbernumparts i s t he number o f p a r t s

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗REQUIRED LIBRARIES

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

:− e n s u r e l o a d e d ( e v e n t ) .

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗USER FUNCTIONS

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/:− op ( 1 5 0 , x f x , p a r t ) .:− op ( 1 5 0 , f x , num parts ) .p a r t (E , Number ) :−

e p a r t (E , Number ) .p a r t (E , Text ) :−

not i n t e g e r ( Text ) ,e p a r t (E , P ) ,p a r t (P , Text ) .

p a r t (P , Text ) :−i n t e g e r (P ) ,num parts (NP ) ,p a r t d e f ( Text , P , NP ) .

num parts ( P a r t s ) :−g l o b a l ( num parts , P a r t s ) .

p a r t d e f ( o n l y , , 1 ) :− ! .p a r t d e f ( top , 1 , ) .p a r t d e f ( bottom , X , X) :− X > 1 .p a r t d e f ( c a n t u s f i r m u s , X , X) :− X > 1 .p a r t d e f ( i n n e r , X , Y) :−

CHAPTER 6. CODE AND TESTING 120

X > 1 ,X \= Y .

p a r t d e f ( s o p r a no , 1 , 4 ) .p a r t d e f ( a l t o , 2 , 4 ) .p a r t d e f ( t e n o r , 3 , 4 ) .p a r t d e f ( b a s s , 4 , 4 ) .

Testing

?− g l o b a l s e t ( num parts , 1 ) .

Yes ?− e p a r t (E , 1 ) , p a r t (E , X ) .

E = e v e n t ( G459 , 1 , G461 , G462 , G463 , G464 , G465 , G466 , G467 ,G468 , G469 ) X = 1 ;

E = e v e n t ( G459 , 1 , G461 , G462 , G463 , G464 , G465 , G466 , G467 ,G468 , G469 ) X = o n l y ;

No ?− e p a r t (E , 4 ) , p a r t (E , 4 ) .

E = e v e n t ( G444 , 4 , G446 , G447 , G448 , G449 , G450 , G451 , G452 ,G453 , G454 ) ;

No ?− e p a r t (E , 4 ) , p a r t (E , X ) .

E = e v e n t ( G459 , 4 , G461 , G462 , G463 , G464 , G465 , G466 , G467 ,G468 , G469 ) X = 4 ;

E = e v e n t ( G459 , 4 , G461 , G462 , G463 , G464 , G465 , G466 , G467 ,G468 , G469 ) X = o n l y ;

No

6.4.7 pitch.pl

Code

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗PITCH LIBRARY

M i c h ae l Droettboom1999

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗

I n Pe log , p i t c h names f o l l o w the same c o n v e n t i o n as GUIDO ( s e et he GUIDO Documentat ion f o r more i n f o r m a t i o n . ) A p i t c h name i sd e f i n e d as a l e t t e r { c , d , e , f , g , a , b } o p t i o n a l l y f o l l o w e d by ana c c i d e n t a l {#, &, ##, &&}.

An o c t a v e i s an i n t e g e r where o c t a v e 1 i s t he o c t a v e c o n t a i n i n gA440Hz .

CHAPTER 6. CODE AND TESTING 121

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗REQUIRED LIBRARIES

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

:− e n s u r e l o a d e d ( ’../core/bi-math.pl’ ) .:− e n s u r e l o a d e d (’global.pl’ ) .

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗OPTIONS

These g l o b a l o p t i o n s a r e s e t by t he GUI system .∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

% p i t c h s y s t e m ({ d i a t o n i c | german | a t o n a l | s o l f e g e | a l l })g l o b a l d e f a u l t ( tag ( p i t c h s y s t e m ) , d i a t o n i c ) .

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗USER PREDICATES − to be used w i t h i n r u l e d e f i n i t i o n s

e q u i v a l e n t p i t c h (? e v e n t a , ? e v e n t b ) ( i . e . c# == d&)Succeeds i f e v e n t a sounds at t he same p i t c h as e v e n t b .

o c t a v e (? e v e n t , ? o c t a v e )Succeeds i f e v e n t i s i n o c t a v e .

p i t c h n a m e (? e v e n t , ? name ) ( eq . to p i t c h )Succeeds i f ’ f r i e n d l y ’ GUIDO name o f e v e n t i s name

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

:− op ( 1 5 0 , x f x , o c t a v e ) .o c t a v e (E , Oct ) :− e p i t c h (E , P ) , o c t a v e (P , Oct ) .o c t a v e ( p i t c h ( , CNC ) , Oct ) :− ! , f a c t o r (CNC , , 7 , Oct ) .

:− op ( 1 5 0 , x f x , p i t c h n a m e ) .p i t c h n a m e (P , T) :−

nonvar (T ) ,p i t c h n a m e (T , PC , NC ) ,p i t c h n o t e c l a s s (P , PC , NC ) .

p i t c h n a m e (P , T) :−v a r (T ) ,p i t c h n o t e c l a s s (P , PC , NC ) ,p i t c h n a m e (T , PC , NC ) .

:− op ( 1 5 0 , x f , e q u i v a l e n t p i t c h ) .

CHAPTER 6. CODE AND TESTING 122

e q u i v a l e n t p i t c h ( P1 : P2 ) :−p i t c h c l a s s ( P1 , PC ) ,p i t c h c l a s s ( P2 , PC ) .

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗OPERATORS

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

% & − f l a t , # − s h a r p , && − d o u b l e f l a t , ## − s h a r p% i s − a t o n a l

:− op ( 1 0 0 , y f , & ) .:− op ( 1 0 0 , y f , # ) .:− op ( 1 0 0 , y f , &&).:− op ( 1 0 0 , y f , ##).

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗DATA STRUCTUREp i t c h (CPC , CNC)

where CPC i s c o n t i n u o u s p i t c h c l a s swhere CNC i s c o n t i n u o u s note c l a s s

as d e f i n e d i n [ Brinkmann . ]∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

c o n t p i t c h c l a s s ( p i t c h (CPC , ) , CPC ) :− ! .c o n t p i t c h c l a s s (E , CPC) :− e p i t c h (E , p i t c h (CPC , ) ) , ! .

c o n t n o t e c l a s s ( p i t c h ( , CNC ) , CNC ) :− ! .c o n t n o t e c l a s s (E , CNC) :− e p i t c h (E , p i t c h ( , CNC ) ) , ! .

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗INFORMATION

p i t c h c l a s s (? P i t c h , ? P i t c h−C l a s s ) % non−c o n t i n u o u s p i t c h−c l a s sn o t e c l a s s (? P i t c h , ? Note−C l a s s ) % non−c o n t i n u o u s note−c l a s sp i t c h i n f o (? P i t c h , ? PC , ? NC , ? Oct , ? CPC , ? CNC , ? Name)v a l i d p i t c h (? P i t c h )

s u c c e e d s i f P i t c h i s v a l i d ( i . e . a v a l i d ( PC ,NC)r e l a t i o n s h i p )

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

p i t c h n a m e o c t a v e (P , T , O) :−v a r (T ) , v a r (O) ,p i t c h n o t e c l a s s o c t a v e (P , PC , NC , O) ,p i t c h n a m e (T , PC , NC ) .

p i t c h n a m e o c t a v e (P , T , O) :−nonvar (T ) ,nonvar (O) ,p i t c h n a m e (T , PC , NC ) ,

CHAPTER 6. CODE AND TESTING 123

CPC i s PC + (O ∗ 1 2 ) ,CNC i s NC + (O ∗ 7 ) ,c o n t p i t c h c l a s s (P , CPC ) ,c o n t n o t e c l a s s (P , CNC ) .

p i t c h c l a s s (P , PC) :−c o n t p i t c h c l a s s (P , CPC ) ,f a c t o r (CPC , PC , 1 2 , ) .

n o t e c l a s s (P , NC) :−c o n t n o t e c l a s s (P , CNC ) ,f a c t o r (CNC , NC , 7 , ) .

p i t c h n o t e c l a s s (P , PC , NC) :−c o n t p i t c h c l a s s (P , CPC ) ,c o n t n o t e c l a s s (P , CNC ) ,f a c t o r (CPC , PC , 1 2 , Oct ) ,f a c t o r (CNC , NC , 7 , Oct ) .

p i t c h n o t e c l a s s o c t a v e (P , PC , NC , Oct ) :−c o n t p i t c h c l a s s (P , CPC ) ,c o n t n o t e c l a s s (P , CNC ) ,f a c t o r (CPC , PC , 1 2 , Oct ) ,f a c t o r (CNC , NC , 7 , Oct ) .

p i t c h i n f o (P , PC , NC , Oct , CPC , CNC , Name) :−c o n t p i t c h c l a s s (P , CPC ) ,c o n t n o t e c l a s s (P , CNC ) ,f a c t o r (CPC , PC , 1 2 , Oct ) ,f a c t o r (CNC , NC , 7 , Oct ) ,p i t c h n a m e (Name , PC , NC ) .

v a l i d p i t c h (P) :−p i t c h c l a s s (P , PC ) ,n o t e c l a s s (P , NC ) ,p i t c h ( , PC , NC ) .

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗

PRIVATE PREDICATES∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗USER and GUIDO PITCH NAMES

p i t c h n a m e (? Text , ? P i t c h−C l a s s , ? Note−C l a s s )s u c c e e d s when t e x t d e s c r i p t i o n o f n o t e s , c o m p a t i b l e w i t h

CHAPTER 6. CODE AND TESTING 124

GUIDO N o t a t i o n Language ( Hoos/Hamel ( 1 9 9 7 ) ) , matches t hec o r r e s p o n d i n g p i t c h and note c l a s s system .( based on Brinkman ( 1 9 9 0 ) )

P i t c h c l a s s e s a r e i n t e g e r s i n the r ange { 0 . . . 1 2 }Note c l a s s e s a r e i n t e g e r s i n the range { 0 . . . 6 }

c o m p a t i b l e w i t h t he f o l l o w i n g s y s t e m s :d i a t o n i c { c , d , e , f , g , a , b } w i t h s h a r p s and f l a t sgerman { c , d , e , f , g , a , h } w i t h s h a r p s and f l a t sa t o n a l { c , c i s , d , d i s , e , f , f i s , g , g i s , a , a i s , b}s o l f e g e { do , d i , r a , r e , r i , me , mi , f a , f i , s e , s o l , s i ,

l e , l a , l i , t e , t i } ( u s i n g f i x e d ’ do ’ c o n v e n t i o n )

choose t he c u r r e n t system w i t h g l o b a l v a r i a b l e p i t c h s y s t e m .( See the g l o b a l l i b r a r y f o r i n f o on g l o b a l v a r i a b l e s . )

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

p i t c h n a m e (T , PC , NC) :−p i t c h t o n a l (T , PC , NC ) .

p i t c h n a m e (T , PC , NC) :−( g l o b a l ( tag ( p i t c h s y s t e m ) , a t o n a l )

; g l o b a l ( tag ( p i t c h s y s t e m ) , a l l ) ) ,p i t c h a t o n a l (T , PC , NC ) .

p i t c h n a m e (T , PC , NC) :−g l o b a l ( tag ( p i t c h s y s t e m ) , s o l f e g e ) ,p i t c h s o l f e g e (T , PC , NC ) .

% BASIC PITCHES f o r DIATONIC , GERMAN and ATONAL.

p i t c h b a s i c ( c , 0 , 0 ) .p i t c h b a s i c ( d , 2 , 1 ) .p i t c h b a s i c ( e , 4 , 2 ) .p i t c h b a s i c ( f , 5 , 3 ) .p i t c h b a s i c ( g , 7 , 4 ) .p i t c h b a s i c ( a , 9 , 5 ) .p i t c h b a s i c ( b , 1 1 , 6 ) .p i t c h b a s i c ( h , 1 1 , 6 ) :−

g l o b a l ( tag ( p i t c h s y s t e m ) , german ) .

% DIATONIC and GERMAN

p i t c h t o n a l (T , PC , NC) :−p i t c h b a s i c (T , PC , NC ) .

p i t c h t o n a l ( (T) & , PC , NC) :−p i t c h b a s i c (T , PC1 , NC ) ,PC i s ( PC1 + 1 1 ) mod 1 2 .

p i t c h t o n a l ( (T)#, PC , NC) :−p i t c h b a s i c (T , PC1 , NC ) ,

CHAPTER 6. CODE AND TESTING 125

PC i s ( PC1 + 1 3 ) mod 1 2 .p i t c h t o n a l ( (T)&&, PC , NC) :−

p i t c h b a s i c (T , PC1 , NC ) ,PC i s ( PC1 + 1 0 ) mod 1 2 .

p i t c h t o n a l ( (T)##, PC , NC) :−p i t c h b a s i c (T , PC1 , NC ) ,PC i s ( PC1 + 1 4 ) mod 1 2 .

% ATONAL

p i t c h a t o n a l (T , PC , NC) :−p i t c h b a s i c (T , PC , NC ) .

p i t c h a t o n a l ( c i s , 1 , 0 ) .p i t c h a t o n a l ( c i s , 1 , 1 ) .p i t c h a t o n a l ( d i s , 3 , 1 ) .p i t c h a t o n a l ( d i s , 3 , 2 ) .p i t c h a t o n a l ( f i s , 6 , 3 ) .p i t c h a t o n a l ( f i s , 6 , 4 ) .p i t c h a t o n a l ( g i s , 8 , 4 ) .p i t c h a t o n a l ( g i s , 8 , 5 ) .p i t c h a t o n a l ( a i s , 1 0 , 5 ) .p i t c h a t o n a l ( a i s , 1 0 , 6 ) .

% SOLFEGE

p i t c h s o l f e g e ( do , 0 , 0 ) .p i t c h s o l f e g e ( d i , 1 , 0 ) .p i t c h s o l f e g e ( r a , 1 , 1 ) .p i t c h s o l f e g e ( r e , 2 , 1 ) .p i t c h s o l f e g e ( r i , 3 , 1 ) .p i t c h s o l f e g e (me , 3 , 2 ) .p i t c h s o l f e g e ( mi , 4 , 2 ) .p i t c h s o l f e g e ( f a , 5 , 3 ) .p i t c h s o l f e g e ( f i , 6 , 3 ) .p i t c h s o l f e g e ( s e , 6 , 4 ) .p i t c h s o l f e g e ( s o l , 7 , 4 ) .p i t c h s o l f e g e ( so , 7 , 4 ) .p i t c h s o l f e g e ( s i , 8 , 4 ) .p i t c h s o l f e g e ( l e , 8 , 5 ) .p i t c h s o l f e g e ( l a , 9 , 5 ) .p i t c h s o l f e g e ( l i , 1 0 , 5 ) .p i t c h s o l f e g e ( t e , 1 0 , 6 ) .p i t c h s o l f e g e ( t i , 1 1 , 6 ) .

Testing

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗PITCH LIBRARY

M i c ha e l Droettboom

CHAPTER 6. CODE AND TESTING 126

1999

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗

I n Pe log , p i t c h names f o l l o w the same c o n v e n t i o n as GUIDO ( s e et he GUIDO Documentat ion f o r more i n f o r m a t i o n . ) A p i t c h name i sd e f i n e d as a l e t t e r { c , d , e , f , g , a , b } o p t i o n a l l y f o l l o w e d by ana c c i d e n t a l {#, &, ##, &&}.

An o c t a v e i s an i n t e g e r where o c t a v e 1 i s t he o c t a v e c o n t a i n i n gA440Hz .

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗REQUIRED LIBRARIES

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

:− e n s u r e l o a d e d ( ’../core/bi-math.pl’ ) .:− e n s u r e l o a d e d (’global.pl’ ) .

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗OPTIONS

These g l o b a l o p t i o n s a r e s e t by t he GUI system .∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

% p i t c h s y s t e m ({ d i a t o n i c | german | a t o n a l | s o l f e g e | a l l })g l o b a l d e f a u l t ( tag ( p i t c h s y s t e m ) , d i a t o n i c ) .

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗USER PREDICATES − to be used w i t h i n r u l e d e f i n i t i o n s

e q u i v a l e n t p i t c h (? e v e n t a , ? e v e n t b ) ( i . e . c# == d&)Succeeds i f e v e n t a sounds at t he same p i t c h as e v e n t b .

o c t a v e (? e v e n t , ? o c t a v e )Succeeds i f e v e n t i s i n o c t a v e .

p i t c h n a m e (? e v e n t , ? name ) ( eq . to p i t c h )Succeeds i f ’ f r i e n d l y ’ GUIDO name o f e v e n t i s name

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

:− op ( 1 5 0 , x f x , o c t a v e ) .o c t a v e (E , Oct ) :− e p i t c h (E , P ) , o c t a v e (P , Oct ) .o c t a v e ( p i t c h ( , CNC ) , Oct ) :− ! , f a c t o r (CNC , , 7 , Oct ) .

CHAPTER 6. CODE AND TESTING 127

:− op ( 1 5 0 , x f x , p i t c h n a m e ) .p i t c h n a m e (P , T) :−

nonvar (T ) ,p i t c h n a m e (T , PC , NC ) ,p i t c h n o t e c l a s s (P , PC , NC ) .

p i t c h n a m e (P , T) :−v a r (T ) ,p i t c h n o t e c l a s s (P , PC , NC ) ,p i t c h n a m e (T , PC , NC ) .

:− op ( 1 5 0 , x f , e q u i v a l e n t p i t c h ) .e q u i v a l e n t p i t c h ( P1 : P2 ) :−

p i t c h c l a s s ( P1 , PC ) ,p i t c h c l a s s ( P2 , PC ) .

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗OPERATORS

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

% & − f l a t , # − s h a r p , && − d o u b l e f l a t , ## − s h a r p% i s − a t o n a l

:− op ( 1 0 0 , y f , & ) .:− op ( 1 0 0 , y f , # ) .:− op ( 1 0 0 , y f , &&).:− op ( 1 0 0 , y f , ##).

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗DATA STRUCTUREp i t c h (CPC , CNC)

where CPC i s c o n t i n u o u s p i t c h c l a s swhere CNC i s c o n t i n u o u s note c l a s s

as d e f i n e d i n [ Brinkmann . ]∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

c o n t p i t c h c l a s s ( p i t c h (CPC , ) , CPC ) :− ! .c o n t p i t c h c l a s s (E , CPC) :− e p i t c h (E , p i t c h (CPC , ) ) , ! .

c o n t n o t e c l a s s ( p i t c h ( , CNC ) , CNC ) :− ! .c o n t n o t e c l a s s (E , CNC) :− e p i t c h (E , p i t c h ( , CNC ) ) , ! .

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗INFORMATION

p i t c h c l a s s (? P i t c h , ? P i t c h−C l a s s ) % non−c o n t i n u o u s p i t c h−c l a s sn o t e c l a s s (? P i t c h , ? Note−C l a s s ) % non−c o n t i n u o u s note−c l a s sp i t c h i n f o (? P i t c h , ? PC , ? NC , ? Oct , ? CPC , ? CNC , ? Name)v a l i d p i t c h (? P i t c h )

s u c c e e d s i f P i t c h i s v a l i d ( i . e . a v a l i d ( PC ,NC)

CHAPTER 6. CODE AND TESTING 128

r e l a t i o n s h i p )∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

p i t c h n a m e o c t a v e (P , T , O) :−v a r (T ) , v a r (O) ,p i t c h n o t e c l a s s o c t a v e (P , PC , NC , O) ,p i t c h n a m e (T , PC , NC ) .

p i t c h n a m e o c t a v e (P , T , O) :−nonvar (T ) ,nonvar (O) ,p i t c h n a m e (T , PC , NC ) ,CPC i s PC + (O ∗ 1 2 ) ,CNC i s NC + (O ∗ 7 ) ,c o n t p i t c h c l a s s (P , CPC ) ,c o n t n o t e c l a s s (P , CNC ) .

p i t c h c l a s s (P , PC) :−c o n t p i t c h c l a s s (P , CPC ) ,f a c t o r (CPC , PC , 1 2 , ) .

n o t e c l a s s (P , NC) :−c o n t n o t e c l a s s (P , CNC ) ,f a c t o r (CNC , NC , 7 , ) .

p i t c h n o t e c l a s s (P , PC , NC) :−c o n t p i t c h c l a s s (P , CPC ) ,c o n t n o t e c l a s s (P , CNC ) ,f a c t o r (CPC , PC , 1 2 , Oct ) ,f a c t o r (CNC , NC , 7 , Oct ) .

p i t c h n o t e c l a s s o c t a v e (P , PC , NC , Oct ) :−c o n t p i t c h c l a s s (P , CPC ) ,c o n t n o t e c l a s s (P , CNC ) ,f a c t o r (CPC , PC , 1 2 , Oct ) ,f a c t o r (CNC , NC , 7 , Oct ) .

p i t c h i n f o (P , PC , NC , Oct , CPC , CNC , Name) :−c o n t p i t c h c l a s s (P , CPC ) ,c o n t n o t e c l a s s (P , CNC ) ,f a c t o r (CPC , PC , 1 2 , Oct ) ,f a c t o r (CNC , NC , 7 , Oct ) ,p i t c h n a m e (Name , PC , NC ) .

v a l i d p i t c h (P) :−p i t c h c l a s s (P , PC ) ,n o t e c l a s s (P , NC ) ,p i t c h ( , PC , NC ) .

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗

CHAPTER 6. CODE AND TESTING 129

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗PRIVATE PREDICATES

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗USER and GUIDO PITCH NAMES

p i t c h n a m e (? Text , ? P i t c h−C l a s s , ? Note−C l a s s )s u c c e e d s when t e x t d e s c r i p t i o n o f n o t e s , c o m p a t i b l e w i t hGUIDO N o t a t i o n Language ( Hoos/Hamel ( 1 9 9 7 ) ) , matches thec o r r e s p o n d i n g p i t c h and note c l a s s system .( based on Brinkman ( 1 9 9 0 ) )

P i t c h c l a s s e s a r e i n t e g e r s i n the r ange { 0 . . . 1 2 }Note c l a s s e s a r e i n t e g e r s i n the range { 0 . . . 6 }

c o m p a t i b l e w i t h t he f o l l o w i n g s y s t e m s :d i a t o n i c { c , d , e , f , g , a , b } w i t h s h a r p s and f l a t sgerman { c , d , e , f , g , a , h } w i t h s h a r p s and f l a t sa t o n a l { c , c i s , d , d i s , e , f , f i s , g , g i s , a , a i s , b}s o l f e g e { do , d i , r a , r e , r i , me , mi , f a , f i , s e , s o l , s i ,

l e , l a , l i , t e , t i } ( u s i n g f i x e d ’ do ’ c o n v e n t i o n )

choose t he c u r r e n t system w i t h g l o b a l v a r i a b l e p i t c h s y s t e m .( See the g l o b a l l i b r a r y f o r i n f o on g l o b a l v a r i a b l e s . )

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

p i t c h n a m e (T , PC , NC) :−p i t c h t o n a l (T , PC , NC ) .

p i t c h n a m e (T , PC , NC) :−( g l o b a l ( tag ( p i t c h s y s t e m ) , a t o n a l )

; g l o b a l ( tag ( p i t c h s y s t e m ) , a l l ) ) ,p i t c h a t o n a l (T , PC , NC ) .

p i t c h n a m e (T , PC , NC) :−g l o b a l ( tag ( p i t c h s y s t e m ) , s o l f e g e ) ,p i t c h s o l f e g e (T , PC , NC ) .

% BASIC PITCHES f o r DIATONIC , GERMAN and ATONAL.

p i t c h b a s i c ( c , 0 , 0 ) .p i t c h b a s i c ( d , 2 , 1 ) .p i t c h b a s i c ( e , 4 , 2 ) .p i t c h b a s i c ( f , 5 , 3 ) .p i t c h b a s i c ( g , 7 , 4 ) .p i t c h b a s i c ( a , 9 , 5 ) .p i t c h b a s i c ( b , 1 1 , 6 ) .p i t c h b a s i c ( h , 1 1 , 6 ) :−

g l o b a l ( tag ( p i t c h s y s t e m ) , german ) .

CHAPTER 6. CODE AND TESTING 130

% DIATONIC and GERMAN

p i t c h t o n a l (T , PC , NC) :−p i t c h b a s i c (T , PC , NC ) .

p i t c h t o n a l ( (T) & , PC , NC) :−p i t c h b a s i c (T , PC1 , NC ) ,PC i s ( PC1 + 1 1 ) mod 1 2 .

p i t c h t o n a l ( (T)#, PC , NC) :−p i t c h b a s i c (T , PC1 , NC ) ,PC i s ( PC1 + 1 3 ) mod 1 2 .

p i t c h t o n a l ( (T)&&, PC , NC) :−p i t c h b a s i c (T , PC1 , NC ) ,PC i s ( PC1 + 1 0 ) mod 1 2 .

p i t c h t o n a l ( (T)##, PC , NC) :−p i t c h b a s i c (T , PC1 , NC ) ,PC i s ( PC1 + 1 4 ) mod 1 2 .

% ATONAL

p i t c h a t o n a l (T , PC , NC) :−p i t c h b a s i c (T , PC , NC ) .

p i t c h a t o n a l ( c i s , 1 , 0 ) .p i t c h a t o n a l ( c i s , 1 , 1 ) .p i t c h a t o n a l ( d i s , 3 , 1 ) .p i t c h a t o n a l ( d i s , 3 , 2 ) .p i t c h a t o n a l ( f i s , 6 , 3 ) .p i t c h a t o n a l ( f i s , 6 , 4 ) .p i t c h a t o n a l ( g i s , 8 , 4 ) .p i t c h a t o n a l ( g i s , 8 , 5 ) .p i t c h a t o n a l ( a i s , 1 0 , 5 ) .p i t c h a t o n a l ( a i s , 1 0 , 6 ) .

% SOLFEGE

p i t c h s o l f e g e ( do , 0 , 0 ) .p i t c h s o l f e g e ( d i , 1 , 0 ) .p i t c h s o l f e g e ( r a , 1 , 1 ) .p i t c h s o l f e g e ( r e , 2 , 1 ) .p i t c h s o l f e g e ( r i , 3 , 1 ) .p i t c h s o l f e g e (me , 3 , 2 ) .p i t c h s o l f e g e ( mi , 4 , 2 ) .p i t c h s o l f e g e ( f a , 5 , 3 ) .p i t c h s o l f e g e ( f i , 6 , 3 ) .p i t c h s o l f e g e ( s e , 6 , 4 ) .p i t c h s o l f e g e ( s o l , 7 , 4 ) .p i t c h s o l f e g e ( so , 7 , 4 ) .p i t c h s o l f e g e ( s i , 8 , 4 ) .

CHAPTER 6. CODE AND TESTING 131

p i t c h s o l f e g e ( l e , 8 , 5 ) .p i t c h s o l f e g e ( l a , 9 , 5 ) .p i t c h s o l f e g e ( l i , 1 0 , 5 ) .p i t c h s o l f e g e ( t e , 1 0 , 6 ) .p i t c h s o l f e g e ( t i , 1 1 , 6 ) .

6.4.8 range.pl

Code

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗RANGE LIBRARY

M i c ha e l Droettboom1999

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗

Range can be s p e c i f i e d i n a number o f ways .

− As an i n t e r v a l . See t he i n t e r v a l l i b r a r y ( page 2 2 ) f o r morei n f o r m a t i o n .

− As a s e t o f two e v e n t s l o w e v e n t : h i g h e v e n t . These two e v e n t smust be i n s t a n t i a t e d .

− By name

P l e a s e note t h a t a l l e v e n t s used w i t h t he p r e d i c a t e s i n t h i s l i b r a r ymust be i n s t a n t i a t e d . The p r e d i c a t e s w i l l not g e n e r a t e e v e n t s .

A d d i t i o n a l named r a n g e s can be d e f i n e d by add ing r a n g e d e f p r e d i c a t e sto t he Pe log r u l e s e t f i l e .

r a n g e d e f p r e d i c a t e s have the form :

r a n g e d e f ( name , l o w p i t c h , h i g h p i t c h )

name i s the name o f t he rang e .l o w p i t c h i s the l o w e s t p i t c h i n t he ran ge , g i v e n i n t he form

pitchname ˜ o c t a v e . See t he p i t c h l i b r a r y f o r d e t a i l s .h i g h p i t c h i s t he h i g h e s t p i t c h i n the range

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗REQUIRED LIBRARIES

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

:− e n s u r e l o a d e d ( e v e n t ) .

CHAPTER 6. CODE AND TESTING 132

:− e n s u r e l o a d e d ( ’../core/trees.pl’ ) .:− e n s u r e l o a d e d ( i n t e r v a l ) .

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗USER PREDICATES

i n r a n g e (+ e v e n t , + range )Succeeds i f e v e n t i s i n ran ge .e v e n t must be i n s t a n t i a t e d . i n r a n g e w i l l not g e n e r a t ep i t c h e s .rang e must be a named range o r two i n s t a n t i a t e d p i t c h e s . I tmay not be d e f i n e d as a roaming i n t e r v a l .

r a n g e i s (+ e v e n t s , ? r ange )Succeeds i f the r ange o f a l l e v e n t s up to and i n c l u d i n g thec u r r e n t e v e n t i s e x a c t l y e q u a l to range .

r a n g e w i t h i n (+ e v e n t s , + ran ge )Succeeds i f the r ange o f a l l e v e n t s up to and i n c l u d i n g thec u r r e n t e v e n t i s w i t h i n rang e . The e v e n t s must bei n s t a n t i a t e d .

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

:− op ( 1 5 0 , x f x , r a n g e w i t h i n ) .:− op ( 1 2 5 , x f x , : ) .% Named rang er a n g e w i t h i n ( (T , E ) , Range ) :−

nonvar ( Range ) ,r a n g e d e f 0 ( Range , LP , UP ) ,f i n d r a n g e (T , E , FLP , FUP ) , ! ,r a n g e i n r a n g e (FLP : FUP , LP : UP ) .

% E x p l i c i t rang er a n g e w i t h i n ( (T , E ) , LN : UN) :−

nonvar (LN ) ,nonvar (UN) ,f i n d r a n g e (T , E , FLP , FUP ) , ! ,r a n g e i n r a n g e (FLP : FUP , LN : UN) .

% ”Roaming i n t e r v a l ” rang er a n g e w i t h i n ( (T , E ) , I ) :−

f i n d r a n g e (T , E , FLP , FUP ) , ! ,a b s o l u t e i n t e r v a l (FLP : IU , I c o n t o u r up ) ,c o n t o u r ( IU , FUP , down ) .

:− op ( 1 5 0 , x f x , r a n g e i s ) .% Named Ranger a n g e i s ( (T , E ) , Range ) :−

nonvar ( Range ) ,r a n g e d e f 0 ( Range , LP , UP ) ,f i n d r a n g e (T , E , LP , UP ) .

% E x p l i c i t Range

CHAPTER 6. CODE AND TESTING 133

r a n g e i s ( (T , E ) , FLP : FUP) :−f i n d r a n g e (T , E , FLP , FUP ) .

% I n t e r v a l Ranger a n g e i s ( (T , E ) , I ) :−

f i n d r a n g e (T , E , FLP , FUP ) ,a b s o l u t e i n t e r v a l (FLP : FUP , I ) .

:− op ( 1 5 0 , x f x , i n r a n g e ) .% Named Rangei n r a n g e (E , Range ) :−

nonvar ( Range ) , nonvar (E ) ,r a n g e d e f 0 ( Range , LP , UP ) ,r a n g e i n r a n g e (E : E , LP : UP ) .

% E x p l i c i t Rangei n r a n g e (E , LP : UP) :−

r a n g e i n r a n g e (E : E , LP : UP ) .

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗HELPER PREDICATES

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

r a n g e i n r a n g e ( I L : IU , RL : RU) :−f i x r a n g e ( I L : IU , I L0 : IU0 ) ,f i x r a n g e (RL : RU , RL0 : RU0 ) ,( c o n t o u r ( I L 0 , RL0 , down ) ; c o n t o u r ( I L 0 , RL0 , s t a t i c ) ) ,( c o n t o u r ( IU0 , RU0 , up ) ; c o n t o u r ( IU0 , RU0 , s t a t i c ) ) .

f i x r a n g e ( L : U , L0 : U0 ) :−( c o n t o u r ( L , U , down) −>

( L0 = U,U0 = L )

; ( L0 = L ,U0 = U ) ) , ! .

f i n d r a n g e (T , E , FLP , FUP) :−f i n d r a n g e (T , E , E , FLP , E , FUP ) , ! .

f i n d r a n g e (T , E , X , X , Y , Y) :−g e t p r e v e v e n t (T , E , s t a r t ) .

f i n d r a n g e (T , E , FLPIn , FLPOut , FUPIn , FUPOut ) :−g e t p r e v e v e n t (T , E , Prev ) ,( c o n t o u r ( FLPIn , Prev , down) −>

FLP0 = Prev ;FLP0 = FLPIn ) ,

( c o n t o u r ( FUPIn , Prev , up) −>FUP0 = Prev ;FUP0 = FUPIn ) ,

f i n d r a n g e (T , Prev , FLP0 , FLPOut , FUP0 , FUPOut ) .

CHAPTER 6. CODE AND TESTING 134

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗NAMED RANGE DEFINITIONS

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

% C o n v e r t s t he r a n g e d e f s u s i n g GUIDO p i t c h names to t he i n t e r n a l% (PC , NC) r e p r e s e n t a t i o n used t h r o u g h o u t Pe log . The r e s u l t i s% a s s e r t e d so t h a t i t does not have to be computed t w i c e .r a n g e d e f 0 ( Range , LP , UP) :−

r a n g e d e f ( Range , LPN˜LO , UPN˜UO) ,p i t c h n a m e o c t a v e (LP , LPN , LO ) ,p i t c h n a m e o c t a v e (UP , UPN , UO) ,a s s e r t a ( r a n g e d e f 0 ( Range , LP , UP ) ) .

r a n g e d e f ( s o p r a no , c ˜ 1 , c ˜ 3 ) .r a n g e d e f ( a l t o , f ˜ 0 , g ˜ 2 ) .r a n g e d e f ( t e n o r , c ˜ 0 , a ˜ 1 ) .r a n g e d e f ( b a s s , f ˜ −1 , f ˜ 1 ) .

/∗∗∗TEST∗∗∗/

t e s t r a n g e i s ( F i l e , I n d e x , Range ) :−l o a d s c o r e ( F i l e , T , ) ,g e t l a b e l ( I n d e x , T , E ) , ! ,r a n g e i s ( (T , E ) , Range ) .

t e s t r a n g e w i t h i n ( F i l e , I n d e x , Range ) :−l o a d s c o r e ( F i l e , T , ) ,g e t l a b e l ( I n d e x , T , E ) , ! ,r a n g e w i t h i n ( (T , E ) , Range ) .

Testing

?− t e s t r a n g e i s ( ’../example.gmn’ , 8 , X ) . Parse OK

X = e v e n t ( 4 , 1 , p i t c h ( 5 , 3 ) , dur ( 1 / 4 ) , t ime ( 9 0 0 0 , 1 2 0 0 0 ) , 3 , [ 1 0 , 1 2 ] ,5 , G1331 , G1332 , G1333 ) : e v e n t ( 8 , 1 , p i t c h ( 1 2 , 7 ) , dur ( 1 / 2 ) ,t ime ( 1 6 5 0 0 , 2 2 5 0 0 ) , 7 , [ 1 3 , 1 0 ] , end , G1507 , G1508 , G1509 ) ;

X = p e r ˜5 c o n t o u r up ;

X = s k i p c o n t o u r up ;

X = consonant c o n t o u r up ;

No ?− t e s t r a n g e i s ( ’../example.gmn’ , 3 , X ) . Parse OK

X = e v e n t ( 3 , 1 , p i t c h ( 9 , 5 ) , dur ( 1 / 4 ) , t ime ( 6 0 0 0 , 9 0 0 0 ) , 2 , [ 1 2 ] , 4 ,G1272 , G1273 , G1274 ) : e v e n t ( 1 , 1 , p i t c h ( 1 2 , 7 ) , dur ( 1 / 4 ) , t ime ( 0 ,

3 0 0 0 ) , s t a r t , [ ] , 2 , G1196 , G1197 , G1198 ) ;

CHAPTER 6. CODE AND TESTING 135

X = min ˜3 c o n t o u r up ;

X = s k i p c o n t o u r up ;

X = consonant c o n t o u r up ;

No ?− t e s t r a n g e i s ( ’../example.gmn’ , 1 1 , X ) . Parse OK

X = e v e n t ( 1 1 , 2 , p i t c h ( 0 , 0 ) , dur ( 1 / 2 ) , t ime ( 1 8 0 0 0 , 2 4 0 0 0 ) , 1 0 , [ 8 ,1 3 ] , end , G1699 , G1700 , G1701 ) : e v e n t ( 9 , 2 , p i t c h ( 4 , 2 ) , dur ( 1 / 2 ) ,t ime ( 0 , 6 0 0 0 ) , s t a r t , [ 1 ] , 1 0 , G1599 , G1600 , G1601 ) ;

X = maj ˜3 c o n t o u r up ;

X = s k i p c o n t o u r up ;

X = consonant c o n t o u r up ;

No ?− t e s t r a n g e w i t h i n ( ’../example.gmn’ , 1 1 , a l t o ) . Parse OK

No 12 ?− t e s t r a n g e w i t h i n ( ’../example.gmn’ , 1 1 , t e n o r ) . Parse OK

Yes 13 ?− i n r a n g e ( p i t c h ( 1 2 , 7 ) , s o p r an o ) .

Yes 14 ?− i n r a n g e ( p i t c h ( 1 2 , 7 ) , p i t c h ( 1 3 , 8 ) : p i t c h ( 1 1 , 6 ) ) .

Yes 15 ?− i n r a n g e ( p i t c h ( 1 2 , 7 ) , p i t c h ( 1 3 , 8 ) : p i t c h ( 1 5 , 9 ) ) .

No

6.4.9 scale.pl

Code

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗SCALE LIBRARY

M i c ha e l Droettboom1999

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗

The l i b r a r y h a n d l e s c o l l e c t i o n s o f p i t c h e s . I n t h i s c o n t e x t , thewords ’ s c a l e ’ and ’ mode ’ a r e used i n t e r c h a n g e a b l y .

I n Pe log , s c a l e s names a r e s p e c i f i e d i n the form t o n i c ˜ p i t c h s e t ,where t o n i c i s t he s t a r t i n g p i t c h o f th e s c a l e , and p i t c h s e t t hename o f a s e t o f p i t c h e s .

t o n i c can be any v a l i d p i t c h name . See t he p i t c h l i b r a r y f o r morei n f o r m a t i o n .

CHAPTER 6. CODE AND TESTING 136

p i t c h s e t can be any p i t c h s e t name d e f i n e d i n a s c a l e d e f c l a u s e .

The Pe log r u l e s e t programmer can add more s c a l e d e f i n i t i o n s byadd ing s c a l e d e f f a c t p r e d i c a t e s to t he r u l e s e t f i l e . s c a l e d e fp r e d i c a t e s have t he form :

s c a l e d e f ( name , p i t c h l i s t , k e y i n t e r v a l ) .

name i s the name o f t he s c a l e .p i t c h l i s t i s a l i s t o f p i t c h names t h a t make up the s c a l e .

Th i s l i s t s h o u l d be p r o v i d e d w i t h c as t o n i c . The s c a l e l i b r a r yw i l l do t he work o f t r a n s p o s i n g th e s c a l e to t o n i c s o t h e r than c .

k e y i n t e r v a l i s t he i n t e r v a l between th e s c a l e ’ s t o n i c and the t o n i co f t he major key s i g n a t u r e t h a t t h i s s c a l e s h o u l d be w r i t t e n i n .For example , t he t o n i c o f the d o r i a n mode i s on t he secondd e g r e e o f the major s c a l e , so t he k e y i n t e r v a l v a l u e i s maj ˜ 2 .

The s c a l e l i b r a r y a l s o h a n d l e s s c a l e d e g r e e s . S c a l e d e g r e e s can bes p e c i f i e d as an i n t e g e r where t he t o n i c o f t he s c a l e i s e q u a l to 1 .S c a l e d e g r e e s can a l s o be s p e c i f i e d by name .

The Pe log r u l e programmer can add more s p e c i a l tone d e f i n i t i o n s byadd ing s p e c i a l t o n e d e f f a c t p r e d i c a t e s to the Pe log r u l e s e t f i l e .s p e c i a l t o n e d e f p r e d i c a t e s have th e form :

s p e c i a l t o n e d e f ( name , p i t c h s e t , p i t c h ) .

name i s the name o f t he s p e c i a l tone .p i t c h s e t s p e c i f i e s the s c a l e s t h a t t he s p e c i a l tone a p p l i e s to .p i t c h i s the s p e c i a l tone i n t h a t s c a l e w i t h c as t o n i c .

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗REQUIRED LIBRARIES

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

:− e n s u r e l o a d e d (’pitch’ ) .:− e n s u r e l o a d e d (’interval’ ) .

:− m u l t i f i l es c a l e d e f / 3 ,s p e c i a l t o n e d e f / 3 .

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗OPTIONS

These g l o b a l o p t i o n s a r e s e t by t he GUI system .∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

% g l o b a l d e f a u l t ( tag ( s c a l e ) , c ˜ major ) .

CHAPTER 6. CODE AND TESTING 137

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗OPERATORS

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

:− op ( 1 2 5 , y f x , ˜ ) .:− op ( 1 0 0 , y f , & ) .:− op ( 1 0 0 , y f , # ) .:− op ( 1 0 0 , y f , &&).:− op ( 1 0 0 , y f , ##).

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗USER PREDICATES

c u r r e n t s c a l e (? s c a l e )Succeeds i f s c a l e i s t he c u r r e n t s c a l e

i n s c a l e (? e v e n t , + Tonic ˜ S c a l e )Succeeds i f e v e n t i s i n Tonic ˜ S c a l e

s c a l e d e g (? e v e n t , + s c a l e , ? deg )Succeeds i f e v e n t i s t he deg−th d e g r e e o f s c a l e

s c a l e d e g (? e v e n t , ? deg )Succeeds i f e v e n t i s t he Deg−th d e g r e e o f the c u r r e n t s c a l e

l e a d i n g t o n e (? P i t c h , + S c a l e )l e a d i n g t o n e (? P i t c h )t o n i c (? P i t c h , + S c a l e )t o n i c (? P i t c h )

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

:− op ( 1 5 0 , x f , s c a l e ) .:− op ( 1 5 0 , x f x , s c a l e ) .s c a l e (P) :−

g l o b a l ( tag ( s c a l e ) , S c a l e ) ,s c a l e (P , S c a l e ) .

s c a l e (P , S c a l e ) :−v a r (P ) , % P i t c h i s v a r i a b l e , so g e n e r a t e p i t c h e sg e t s c a l e ( S c a l e , P i t c h e s ) ,member ( Octave , [ 0 , 1 , − 1 , 2 , − 2 , 3 , − 3 , 4 , − 4 ,

5 , − 5 , 6 , − 6 , 7 , − 7 , 8 , − 8 ] ) ,member ( (PC ,NC ) , P i t c h e s ) ,p i t c h n o t e c l a s s o c t a v e (P , PC , NC , Octave ) .

s c a l e (P , S c a l e ) :−nonvar (P ) , % P i t c h e s i s not v a r i a b l e , so s i m p l e v e r i f yg e t s c a l e ( S c a l e , P i t c h e s ) ,p i t c h n o t e c l a s s (P , PC , NC ) ,member ( (PC ,NC ) , P i t c h e s ) .

:− op ( 1 5 0 , f x , c u r r e n t s c a l e ) .c u r r e n t s c a l e ( S c a l e ) :−

g l o b a l ( tag ( s c a l e ) , S c a l e ) .

CHAPTER 6. CODE AND TESTING 138

:− op ( 1 5 0 , x f x , s c a l e d e g r e e ) .% r a i s e d s c a l e d e g r e es c a l e d e g r e e ( P i t c h , r a i s e d ˜Deg ) :−

g l o b a l ( tag ( s c a l e ) , S c a l e ) ,m o d i f i e d s c a l e d e g r e e ( P i t c h , S c a l e , Deg , 1 ) .

% l o w e r e d s c a l e d e g r e es c a l e d e g r e e ( P i t c h , l o w e r e d ˜Deg ) :−

g l o b a l ( tag ( s c a l e ) , S c a l e ) ,m o d i f i e d s c a l e d e g r e e ( P i t c h , S c a l e , Deg , −1 ) .

% numbered s c a l e d e g r e es c a l e d e g r e e ( P i t c h , Deg ) :−

i n t e g e r ( Deg ) ,g l o b a l ( tag ( s c a l e ) , S c a l e ) ,s c a l e d e g r e e ( P i t c h , S c a l e , Deg ) .

% named s c a l e d e g r e e ( as d e f i n e d i n s p e c i a l t o n e d e f )s c a l e d e g r e e ( P i t c h , Deg ) :−

not i n t e g e r ( Deg ) ,g l o b a l ( tag ( s c a l e ) , S c a l e ) ,s p e c i a l t o n e ( P i t c h , S c a l e , Deg ) .

% s c a l e d e g r e e i n a non−c u r r e n t s c a l es c a l e d e g r e e ( P i t c h , S c a l e , Deg ) :−

i n t e g e r ( Deg ) ,p i t c h n o t e c l a s s ( P i t c h , PC , NC ) ,g e t s c a l e ( S c a l e , P i t c h e s ) ,nth1 ( Deg , P i t c h e s , ( PC , NC ) ) .

m o d i f i e d s c a l e d e g r e e ( P i t c h , S c a l e , Deg , Mod) :−i n t e g e r ( Deg ) ,nonvar ( P i t c h ) ,p i t c h n o t e c l a s s ( P i t c h , PC1 , NC ) ,g e t s c a l e ( S c a l e , P i t c h e s ) ,PC i s PC1 − Mod ,nth1 ( Deg , P i t c h e s , ( PC , NC ) ) .

m o d i f i e d s c a l e d e g r e e ( P i t c h , S c a l e , Deg , Mod) :−i n t e g e r ( Deg ) ,v a r ( P i t c h ) ,g e t s c a l e ( S c a l e , P i t c h e s ) ,nth1 ( Deg , P i t c h e s , ( PC , NC ) ) ,PC1 i s PC + Mod ,p i t c h n o t e c l a s s ( P i t c h , PC1 , NC ) .

s p e c i a l t o n e ( P i t c h , S p e c i a l ) :−g l o b a l ( tag ( s c a l e ) , S c a l e ) ,s p e c i a l t o n e ( P i t c h , S c a l e , S p e c i a l ) .

s p e c i a l t o n e ( P i t c h , S c a l e , S p e c i a l ) :−s p e c i a l t o n e ( S c a l e , S p e c i a l , PC , NC ) ,p i t c h n o t e c l a s s ( P i t c h , PC , NC ) .

s p e i c a l t o n e ( c ˜ S c a l e , S p e c i a l , PC , NC) :−s p e c i a l t o n e d e f ( S p e c i a l , S c a l e , STN ) ,p i t c h n a m e (STN , PC , NC ) .

CHAPTER 6. CODE AND TESTING 139

s p e c i a l t o n e ( Tonic ˜ S c a l e , S p e c i a l , PC , NC) :−p i t c h n a m e ( Tonic , TPC , TNC ) ,s p e c i a l t o n e d e f ( S p e c i a l , S c a l e , STN ) ,p i t c h n a m e (STN , SPC , SNC ) ,PC i s ( SPC + TPC ) mod 1 2 ,NC i s ( SNC + TNC) mod 7 ,a s s e r t a ( ( s p e c i a l t o n e ( Tonic ˜ S c a l e , S p e c i a l , PC , NC ) :− ! ) ) .

:− op ( 1 5 0 , x f , l e a d i n g t o n e ) .l e a d i n g t o n e ( P i t c h ) :−

s p e c i a l t o n e ( P i t c h , l e a d i n g ) .

:− op ( 1 5 0 , x f , t o n i c ) .t o n i c ( P i t c h ) :−

s p e c i a l t o n e ( P i t c h , t o n i c ) .

:− op ( 1 5 0 , x f , f i n a l ) .f i n a l ( P i t c h ) :−

s p e c i a l t o n e ( P i t c h , f i n a l ) .

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗SCALE DEFINITIONS

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

% C o n v e r t s t he s c a l e d e f i n e d i n s c a l e d e f to t he b i n o m i a l r e p r e s e n t a t i o n% used t h r o u g h o u t Pe log . A l s o t r a n s p o s e s the s c a l e s to t o n i c s o t h e r% then c . The r e s u l t i s a s s e r t e d to the d a t a b a s e to a v o i d r e−computat ion .g e t s c a l e ( Tonic ˜ S c a l e , P i t c h e s ) :−

s c a l e d e f ( S c a l e , BPNs , ) ,p i t c h n a m e l i s t (BPNs , BPs ) ,p i t c h n a m e ( Tonic , TPC , TNC ) ,c r e a t e s c a l e ( BPs , TPC , TNC , P i t c h e s ) , ! ,a s s e r t a ( ( g e t s c a l e ( Tonic ˜ S c a l e , P i t c h e s ) :− ! ) ) .

p i t c h n a m e l i s t ( [ ] , [ ] ) .p i t c h n a m e l i s t ( [ PN | NTai l ] , [ ( PC , NC ) | P T a i l ] ) :−

p i t c h n a m e (PN , PC , NC ) ,p i t c h n a m e l i s t ( NTai l , P T a i l ) .

c r e a t e s c a l e ( [ ( BPC ,BNC ) |BT ] , TPC , TNC , [ ( PC ,NC ) |T] ) :−PC i s ( BPC + TPC ) mod 1 2 ,NC i s (BNC + TNC) mod 7 ,c r e a t e s c a l e (BT , TPC , TNC , T ) .

c r e a t e s c a l e ( [ ] , , , [ ] ) .

:− m u l t i f i l es c a l e d e f / 3 .

s c a l e d e f ( major , [ c , d , e , f , g , a , b ] , p e r ˜ 1 ) :− ! .

CHAPTER 6. CODE AND TESTING 140

s c a l e d e f ( h a r m o n i c m i n o r , [ c , d , e &, f , g , a &, b ] , maj ˜ 6 ) :− ! .s c a l e d e f ( n a t u r a l m i n o r , [ c , d , e &, f , g , a &, b & ] , maj ˜ 6 ) :− ! .s c a l e d e f ( m e l o d i c m i n o r , [ c , d , e &, f , g , a &, a , b &, b ] , maj ˜ 6 ) :− ! .

s c a l e d e f ( d o r i a n , [ c , d , e &, f , g , a , b &, b ] , maj ˜ 2 ) :− ! .s c a l e d e f ( h y p o d o r i a n , X , Y) :− s c a l e d e f ( d o r i a n , X , Y ) , ! .s c a l e d e f ( p h r y g i a n , [ c , d &, e &, f , g , a &, b & ] , maj ˜ 3 ) :− ! .s c a l e d e f ( h y p o p h r y g i a n , X , Y) :− s c a l e d e f ( p h r y g i a n , X , Y ) , ! .s c a l e d e f ( l y d i a n , [ c , d , e , f #, g , a , b ] , p e r ˜ 4 ) :− ! .s c a l e d e f ( h y p o l y d i a n , X , Y) :− s c a l e d e f ( l y d i a n , X , Y ) , ! .s c a l e d e f ( m i x o l y d i a n , [ c , d , e , f , g , a , b &, b ] , p e r ˜ 5 ) :− ! .s c a l e d e f ( h y p o m i x o l y d i a n , X , Y) :− s c a l e d e f ( m i x o l y d i a n , X , Y ) , ! .s c a l e d e f ( a e o l i a n , [ c , d , e &, f , g , a &, b &, a , b ] , maj ˜ 6 ) :− ! .s c a l e d e f ( h y p o a e o l i a n , X , Y) :− s c a l e d e f ( a e o l i a n , X , Y ) , ! .% Note : l o c r i a n w i l l not work w i t h modal c o u n t e r p o i n t : i t has% no p e r f e c t f i f t h .s c a l e d e f ( l o c r i a n , [ c , d &, e &, f , g &, a &, b & ] , maj ˜ 7 ) :− ! .s c a l e d e f ( i o n i a n , X , Y) :− s c a l e d e f ( major , X , Y ) , ! .s c a l e d e f ( h y p o i o n i a n , X , Y) :− s c a l e d e f ( i o n i a n , X , Y ) , ! .

s c a l e d e f ( c h r o m a t i c , [ c , c #, d , d #, e , f , f #, g , g #, a , a #, b ] , none ) :− ! .s c a l e d e f ( c h r o m a t i c s h a r p s , X , Y) :− s c a l e d e f ( c h r o m a t i c , X , Y ) , ! .s c a l e d e f ( c h r o m a t i c f l a t s , [ c , d &, d , e &, e , f , g &, g , a &, a , b &, b ] , none ) :− ! .

s c a l e d e f ( w h o l e t o n e , [ c , d , e , f #, g #, a # ] , none ) :− ! .s c a l e d e f ( w h o l e t o n e s h a r p s , X , Y) :− s c a l e d e f ( w h o l e t o n e , X , Y ) , ! .s c a l e d e f ( w h o l e t o n e f l a t s , [ c , d , e , g &, a &, b & ] , none ) :− ! .

s c a l e d e f ( gypsy , [ c , d , e &, f #, g , a , a &, b ] , u n i s ) :− ! .

s c a l e d e f ( p e n t a t o n i c , [ c , d , f , g , a ] , u n i s ) :− ! .s c a l e d e f ( p e n t a t o n i c a , X , Y) :− s c a l e d e f ( p e n t a t o n i c , X , Y ) , ! .s c a l e d e f ( p e n t a t o n i c b , [ c , d , e , g , a ] , u n i s ) :− ! .

s c a l e d e f ( o c t a t o n i c , [ c , c #, d #, e , f #, g , a , a # ] , none ) :− ! .s c a l e d e f ( o c t a t o n i c s h a r p s , X , Y) :− s c a l e d e f ( o c t a t o n i c , X , Y ) .s c a l e d e f ( o c t a t o n i c f l a t s , [ c , d &, e &, e , g &, g , a , b & ] , none ) :− ! .s c a l e d e f ( h a l f w h o l e , X , Y) :− s c a l e d e f ( o c t a t o n i c , X , Y ) , ! .s c a l e d e f ( h a l f w h o l e s h a r p s , Y , Z ) :− s c a l e d e f ( o c t a t o n i c−s h a r p s , Y , Z ) , ! .s c a l e d e f ( h a l f w h o l e f l a t s , Y , Z ) :− s c a l e d e f ( o c t a t o n i c− f l a t s , Y , Z ) , ! .s c a l e d e f ( w h o l e h a l f , [ c , d , d #, f , f #, g #, a , b ] , none ) :− ! .s c a l e d e f ( w h o l e h a l f s h a r p s , X , Y) :− s c a l e d e f ( w h o l e h a l f , X , Y ) .s c a l e d e f ( w h o l e h a l f f l a t s , [ c , d , e &, f , g &, a &, a , b ] , none ) :− ! .

s c a l e d e f ( b l u e s , [ c , d , e &, e , f , g &, g , a , b & ] , u n i s ) :− ! .

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗RELATIONSHIP OF SCALE TO KEY

Given a S c a l e , r e t u r n s t he c o r r e s p o n d i n g key .Th i s i n f o r m a t i o n i s used by the GUIDO p a r s e r .

CHAPTER 6. CODE AND TESTING 141

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

s c a l e k e y ( ˜ S c a l e , 0 ) :−s c a l e d e f ( S c a l e , , none ) .

s c a l e k e y ( Tonic ˜ S c a l e , Key ) :−s c a l e d e f ( S c a l e , , Degree ) ,g e t s c a l e ( Tonic ˜ S c a l e , [ ( PC , NC ) | R e s t ] ) ,a b s o l u t e i n t e r v a l c p (PC , NC , KPC , KNC , Degree , down ) ,p i t c h n a m e ( p i t c h (KPC , KNC ) , Key ) , ! .

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗NUMBER OF SHARPS AND FLATS FOR MAJOR KEYS

needed f o r GUIDO t r a n s l a t i o n∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

k e y s h a r p s f l a t s ( 0 , c ) .k e y s h a r p s f l a t s ( 1 , g ) .k e y s h a r p s f l a t s ( 2 , d ) .k e y s h a r p s f l a t s ( 3 , a ) .k e y s h a r p s f l a t s ( 4 , e ) .k e y s h a r p s f l a t s ( 5 , b ) .k e y s h a r p s f l a t s ( 6 , f #).k e y s h a r p s f l a t s ( 7 , c #).k e y s h a r p s f l a t s (−1 , f ) .k e y s h a r p s f l a t s (−2 , b &).k e y s h a r p s f l a t s (−3 , e &).k e y s h a r p s f l a t s (−4 , a &).k e y s h a r p s f l a t s (−5 , d &).k e y s h a r p s f l a t s (−6 , g &).k e y s h a r p s f l a t s (−7 , c &).

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗SPECIAL TONE DEFINITIONS

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

:− m u l t i f i l es p e c i a l t o n e d e f / 3 .

s p e c i a l t o n e d e f ( f i n a l , , c ) :− ! .

s p e c i a l t o n e d e f ( ambitus , X , Y) :− s p e c i a l t o n e d e f ( t o n i c , X , Y ) .

s p e c i a l t o n e d e f ( t e n o r , hypo− , e ) :− ! .s p e c i a l t o n e d e f ( t e n o r , , g ) :− ! .

s p e c i a l t o n e d e f ( t o n i c , hypo− , g ) :− ! .s p e c i a l t o n e d e f ( t o n i c , , c ) :− ! .

s p e c i a l t o n e d e f ( l e a d i n g , p h r y g i a n , b & ) :− ! .s p e c i a l t o n e d e f ( l e a d i n g , hypo− l y d i a n , f # ) :− ! .

CHAPTER 6. CODE AND TESTING 142

s p e c i a l t o n e d e f ( l e a d i n g , hypo− , f ) :− ! .s p e c i a l t o n e d e f ( l e a d i n g , n a t u r a l−minor , b & ) :− ! .s p e c i a l t o n e d e f ( l e a d i n g , , b ) :− ! .

% Only used i n TONAL harmonic p r a c t i c es p e c i a l t o n e d e f ( s u p e r t o n i c , major , d ) :− ! .s p e c i a l t o n e d e f ( s u p e r t o n i c , −minor , d ) :− ! .

s p e c i a l t o n e d e f ( mediant , major , e ) :− ! .s p e c i a l t o n e d e f ( mediant , −minor , e & ) :− ! .

s p e c i a l t o n e d e f ( subdominant , major , f ) :− ! .s p e c i a l t o n e d e f ( subdominant , −minor , f ) :− ! .

s p e c i a l t o n e d e f ( dominant , major , g ) :− ! .s p e c i a l t o n e d e f ( dominant , −minor , g ) :− ! .

s p e c i a l t o n e d e f ( submediant , major , a ) :− ! .s p e c i a l t o n e d e f ( submediant , m e l o d i c−minor , a ) :− ! .s p e c i a l t o n e d e f ( submediant , −minor , a & ) :− ! .

s p e c i a l t o n e d e f ( s u b t o n i c , major , b ) :− ! .s p e c i a l t o n e d e f ( s u b t o n i c , n a t u r a l−minor , b & ) :− ! .s p e c i a l t o n e d e f ( s u b t o n i c , −minor , b ) :− ! .

Testing

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗SCALE LIBRARY

M i c ha e l Droettboom1999

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗

The l i b r a r y h a n d l e s c o l l e c t i o n s o f p i t c h e s . I n t h i s c o n t e x t , thewords ’ s c a l e ’ and ’ mode ’ a r e used i n t e r c h a n g e a b l y .

I n Pe log , s c a l e s names a r e s p e c i f i e d i n the form t o n i c ˜ p i t c h s e t ,where t o n i c i s t he s t a r t i n g p i t c h o f the s c a l e , and p i t c h s e t t hename o f a s e t o f p i t c h e s .

t o n i c can be any v a l i d p i t c h name . See t he p i t c h l i b r a r y f o r morei n f o r m a t i o n .

p i t c h s e t can be any p i t c h s e t name d e f i n e d i n a s c a l e d e f c l a u s e .

The Pe log r u l e s e t programmer can add more s c a l e d e f i n i t i o n s byadd ing s c a l e d e f f a c t p r e d i c a t e s to t he r u l e s e t f i l e . s c a l e d e fp r e d i c a t e s have t he form :

s c a l e d e f ( name , p i t c h l i s t , k e y i n t e r v a l ) .

CHAPTER 6. CODE AND TESTING 143

name i s the name o f t he s c a l e .p i t c h l i s t i s a l i s t o f p i t c h names t h a t make up the s c a l e .

Th i s l i s t s h o u l d be p r o v i d e d w i t h c as t o n i c . The s c a l e l i b r a r yw i l l do t he work o f t r a n s p o s i n g th e s c a l e to t o n i c s o t h e r than c .

k e y i n t e r v a l i s t he i n t e r v a l between th e s c a l e ’ s t o n i c and the t o n i co f th e major key s i g n a t u r e t h a t t h i s s c a l e s h o u l d be w r i t t e n i n .For example , t he t o n i c o f the d o r i a n mode i s on t he secondd e g r e e o f the major s c a l e , so t he k e y i n t e r v a l v a l u e i s maj ˜ 2 .

The s c a l e l i b r a r y a l s o h a n d l e s s c a l e d e g r e e s . S c a l e d e g r e e s can bes p e c i f i e d as an i n t e g e r where t he t o n i c o f t he s c a l e i s e q u a l to 1 .S c a l e d e g r e e s can a l s o be s p e c i f i e d by name .

The Pe log r u l e programmer can add more s p e c i a l tone d e f i n i t i o n s byadd ing s p e c i a l t o n e d e f f a c t p r e d i c a t e s to the Pe log r u l e s e t f i l e .s p e c i a l t o n e d e f p r e d i c a t e s have th e form :

s p e c i a l t o n e d e f ( name , p i t c h s e t , p i t c h ) .

name i s the name o f t he s p e c i a l tone .p i t c h s e t s p e c i f i e s the s c a l e s t h a t t he s p e c i a l tone a p p l i e s to .p i t c h i s the s p e c i a l tone i n t h a t s c a l e w i t h c as t o n i c .

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗REQUIRED LIBRARIES

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

:− e n s u r e l o a d e d (’pitch’ ) .:− e n s u r e l o a d e d (’interval’ ) .

:− m u l t i f i l es c a l e d e f / 3 ,s p e c i a l t o n e d e f / 3 .

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗OPTIONS

These g l o b a l o p t i o n s a r e s e t by t he GUI system .∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

% g l o b a l d e f a u l t ( tag ( s c a l e ) , c ˜ major ) .

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗OPERATORS

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

:− op ( 1 2 5 , y f x , ˜ ) .

CHAPTER 6. CODE AND TESTING 144

:− op ( 1 0 0 , y f , & ) .:− op ( 1 0 0 , y f , # ) .:− op ( 1 0 0 , y f , &&).:− op ( 1 0 0 , y f , ##).

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗USER PREDICATES

c u r r e n t s c a l e (? s c a l e )Succeeds i f s c a l e i s t he c u r r e n t s c a l e

i n s c a l e (? e v e n t , + Tonic ˜ S c a l e )Succeeds i f e v e n t i s i n Tonic ˜ S c a l e

s c a l e d e g (? e v e n t , + s c a l e , ? deg )Succeeds i f e v e n t i s t he deg−th d e g r e e o f s c a l e

s c a l e d e g (? e v e n t , ? deg )Succeeds i f e v e n t i s t he Deg−th d e g r e e o f the c u r r e n t s c a l e

l e a d i n g t o n e (? P i t c h , + S c a l e )l e a d i n g t o n e (? P i t c h )t o n i c (? P i t c h , + S c a l e )t o n i c (? P i t c h )

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

:− op ( 1 5 0 , x f , s c a l e ) .:− op ( 1 5 0 , x f x , s c a l e ) .s c a l e (P) :−

g l o b a l ( tag ( s c a l e ) , S c a l e ) ,s c a l e (P , S c a l e ) .

s c a l e (P , S c a l e ) :−v a r (P ) , % P i t c h i s v a r i a b l e , so g e n e r a t e p i t c h e sg e t s c a l e ( S c a l e , P i t c h e s ) ,member ( Octave , [ 0 , 1 , − 1 , 2 , − 2 , 3 , − 3 , 4 , − 4 ,

5 , − 5 , 6 , − 6 , 7 , − 7 , 8 , − 8 ] ) ,member ( (PC ,NC ) , P i t c h e s ) ,p i t c h n o t e c l a s s o c t a v e (P , PC , NC , Octave ) .

s c a l e (P , S c a l e ) :−nonvar (P ) , % P i t c h e s i s not v a r i a b l e , so s i m p l e v e r i f yg e t s c a l e ( S c a l e , P i t c h e s ) ,p i t c h n o t e c l a s s (P , PC , NC ) ,member ( (PC ,NC ) , P i t c h e s ) .

:− op ( 1 5 0 , f x , c u r r e n t s c a l e ) .c u r r e n t s c a l e ( S c a l e ) :−

g l o b a l ( tag ( s c a l e ) , S c a l e ) .

:− op ( 1 5 0 , x f x , s c a l e d e g r e e ) .% r a i s e d s c a l e d e g r e es c a l e d e g r e e ( P i t c h , r a i s e d ˜Deg ) :−

g l o b a l ( tag ( s c a l e ) , S c a l e ) ,m o d i f i e d s c a l e d e g r e e ( P i t c h , S c a l e , Deg , 1 ) .

% l o w e r e d s c a l e d e g r e e

CHAPTER 6. CODE AND TESTING 145

s c a l e d e g r e e ( P i t c h , l o w e r e d ˜Deg ) :−g l o b a l ( tag ( s c a l e ) , S c a l e ) ,m o d i f i e d s c a l e d e g r e e ( P i t c h , S c a l e , Deg , −1 ) .

% numbered s c a l e d e g r e es c a l e d e g r e e ( P i t c h , Deg ) :−

i n t e g e r ( Deg ) ,g l o b a l ( tag ( s c a l e ) , S c a l e ) ,s c a l e d e g r e e ( P i t c h , S c a l e , Deg ) .

% named s c a l e d e g r e e ( as d e f i n e d i n s p e c i a l t o n e d e f )s c a l e d e g r e e ( P i t c h , Deg ) :−

not i n t e g e r ( Deg ) ,g l o b a l ( tag ( s c a l e ) , S c a l e ) ,s p e c i a l t o n e ( P i t c h , S c a l e , Deg ) .

% s c a l e d e g r e e i n a non−c u r r e n t s c a l es c a l e d e g r e e ( P i t c h , S c a l e , Deg ) :−

i n t e g e r ( Deg ) ,p i t c h n o t e c l a s s ( P i t c h , PC , NC ) ,g e t s c a l e ( S c a l e , P i t c h e s ) ,nth1 ( Deg , P i t c h e s , ( PC , NC ) ) .

m o d i f i e d s c a l e d e g r e e ( P i t c h , S c a l e , Deg , Mod) :−i n t e g e r ( Deg ) ,nonvar ( P i t c h ) ,p i t c h n o t e c l a s s ( P i t c h , PC1 , NC ) ,g e t s c a l e ( S c a l e , P i t c h e s ) ,PC i s PC1 − Mod ,nth1 ( Deg , P i t c h e s , ( PC , NC ) ) .

m o d i f i e d s c a l e d e g r e e ( P i t c h , S c a l e , Deg , Mod) :−i n t e g e r ( Deg ) ,v a r ( P i t c h ) ,g e t s c a l e ( S c a l e , P i t c h e s ) ,nth1 ( Deg , P i t c h e s , ( PC , NC ) ) ,PC1 i s PC + Mod ,p i t c h n o t e c l a s s ( P i t c h , PC1 , NC ) .

s p e c i a l t o n e ( P i t c h , S p e c i a l ) :−g l o b a l ( tag ( s c a l e ) , S c a l e ) ,s p e c i a l t o n e ( P i t c h , S c a l e , S p e c i a l ) .

s p e c i a l t o n e ( P i t c h , S c a l e , S p e c i a l ) :−s p e c i a l t o n e ( S c a l e , S p e c i a l , PC , NC ) ,p i t c h n o t e c l a s s ( P i t c h , PC , NC ) .

s p e i c a l t o n e ( c ˜ S c a l e , S p e c i a l , PC , NC) :−s p e c i a l t o n e d e f ( S p e c i a l , S c a l e , STN ) ,p i t c h n a m e (STN , PC , NC ) .

s p e c i a l t o n e ( Tonic ˜ S c a l e , S p e c i a l , PC , NC) :−p i t c h n a m e ( Tonic , TPC , TNC ) ,s p e c i a l t o n e d e f ( S p e c i a l , S c a l e , STN ) ,p i t c h n a m e (STN , SPC , SNC ) ,PC i s ( SPC + TPC ) mod 1 2 ,NC i s ( SNC + TNC) mod 7 ,a s s e r t a ( ( s p e c i a l t o n e ( Tonic ˜ S c a l e , S p e c i a l , PC , NC ) :− ! ) ) .

CHAPTER 6. CODE AND TESTING 146

:− op ( 1 5 0 , x f , l e a d i n g t o n e ) .l e a d i n g t o n e ( P i t c h ) :−

s p e c i a l t o n e ( P i t c h , l e a d i n g ) .

:− op ( 1 5 0 , x f , t o n i c ) .t o n i c ( P i t c h ) :−

s p e c i a l t o n e ( P i t c h , t o n i c ) .

:− op ( 1 5 0 , x f , f i n a l ) .f i n a l ( P i t c h ) :−

s p e c i a l t o n e ( P i t c h , f i n a l ) .

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗SCALE DEFINITIONS

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

% C o n v e r t s t he s c a l e d e f i n e d i n s c a l e d e f to t he b i n o m i a l r e p r e s e n t a t i o n% used t h r o u g h o u t Pe log . A l s o t r a n s p o s e s the s c a l e s to t o n i c s o t h e r% then c . The r e s u l t i s a s s e r t e d to the d a t a b a s e to a v o i d r e−computat ion .g e t s c a l e ( Tonic ˜ S c a l e , P i t c h e s ) :−

s c a l e d e f ( S c a l e , BPNs , ) ,p i t c h n a m e l i s t (BPNs , BPs ) ,p i t c h n a m e ( Tonic , TPC , TNC ) ,c r e a t e s c a l e ( BPs , TPC , TNC , P i t c h e s ) , ! ,a s s e r t a ( ( g e t s c a l e ( Tonic ˜ S c a l e , P i t c h e s ) :− ! ) ) .

p i t c h n a m e l i s t ( [ ] , [ ] ) .p i t c h n a m e l i s t ( [ PN | NTai l ] , [ ( PC , NC ) | P T a i l ] ) :−

p i t c h n a m e (PN , PC , NC ) ,p i t c h n a m e l i s t ( NTai l , P T a i l ) .

c r e a t e s c a l e ( [ ( BPC ,BNC ) |BT ] , TPC , TNC , [ ( PC ,NC ) |T] ) :−PC i s ( BPC + TPC ) mod 1 2 ,NC i s (BNC + TNC) mod 7 ,c r e a t e s c a l e (BT , TPC , TNC , T ) .

c r e a t e s c a l e ( [ ] , , , [ ] ) .

:− m u l t i f i l es c a l e d e f / 3 .

s c a l e d e f ( major , [ c , d , e , f , g , a , b ] , p e r ˜ 1 ) :− ! .s c a l e d e f ( h a r m o n i c m i n o r , [ c , d , e &, f , g , a &, b ] , maj ˜ 6 ) :− ! .s c a l e d e f ( n a t u r a l m i n o r , [ c , d , e &, f , g , a &, b & ] , maj ˜ 6 ) :− ! .s c a l e d e f ( m e l o d i c m i n o r , [ c , d , e &, f , g , a &, a , b &, b ] , maj ˜ 6 ) :− ! .

s c a l e d e f ( d o r i a n , [ c , d , e &, f , g , a , b &, b ] , maj ˜ 2 ) :− ! .s c a l e d e f ( h y p o d o r i a n , X , Y) :− s c a l e d e f ( d o r i a n , X , Y ) , ! .s c a l e d e f ( p h r y g i a n , [ c , d &, e &, f , g , a &, b & ] , maj ˜ 3 ) :− ! .

CHAPTER 6. CODE AND TESTING 147

s c a l e d e f ( h y p o p h r y g i a n , X , Y) :− s c a l e d e f ( p h r y g i a n , X , Y ) , ! .s c a l e d e f ( l y d i a n , [ c , d , e , f #, g , a , b ] , p e r ˜ 4 ) :− ! .s c a l e d e f ( h y p o l y d i a n , X , Y) :− s c a l e d e f ( l y d i a n , X , Y ) , ! .s c a l e d e f ( m i x o l y d i a n , [ c , d , e , f , g , a , b &, b ] , p e r ˜ 5 ) :− ! .s c a l e d e f ( h y p o m i x o l y d i a n , X , Y) :− s c a l e d e f ( m i x o l y d i a n , X , Y ) , ! .s c a l e d e f ( a e o l i a n , [ c , d , e &, f , g , a &, b &, a , b ] , maj ˜ 6 ) :− ! .s c a l e d e f ( h y p o a e o l i a n , X , Y) :− s c a l e d e f ( a e o l i a n , X , Y ) , ! .% Note : l o c r i a n w i l l not work w i t h modal c o u n t e r p o i n t : i t has% no p e r f e c t f i f t h .s c a l e d e f ( l o c r i a n , [ c , d &, e &, f , g &, a &, b & ] , maj ˜ 7 ) :− ! .s c a l e d e f ( i o n i a n , X , Y) :− s c a l e d e f ( major , X , Y ) , ! .s c a l e d e f ( h y p o i o n i a n , X , Y) :− s c a l e d e f ( i o n i a n , X , Y ) , ! .

s c a l e d e f ( c h r o m a t i c , [ c , c #, d , d #, e , f , f #, g , g #, a , a #, b ] , none ) :− ! .s c a l e d e f ( c h r o m a t i c s h a r p s , X , Y) :− s c a l e d e f ( c h r o m a t i c , X , Y ) , ! .s c a l e d e f ( c h r o m a t i c f l a t s , [ c , d &, d , e &, e , f , g &, g , a &, a , b &, b ] , none ) :− ! .

s c a l e d e f ( w h o l e t o n e , [ c , d , e , f #, g #, a # ] , none ) :− ! .s c a l e d e f ( w h o l e t o n e s h a r p s , X , Y) :− s c a l e d e f ( w h o l e t o n e , X , Y ) , ! .s c a l e d e f ( w h o l e t o n e f l a t s , [ c , d , e , g &, a &, b & ] , none ) :− ! .

s c a l e d e f ( gypsy , [ c , d , e &, f #, g , a , a &, b ] , u n i s ) :− ! .

s c a l e d e f ( p e n t a t o n i c , [ c , d , f , g , a ] , u n i s ) :− ! .s c a l e d e f ( p e n t a t o n i c a , X , Y) :− s c a l e d e f ( p e n t a t o n i c , X , Y ) , ! .s c a l e d e f ( p e n t a t o n i c b , [ c , d , e , g , a ] , u n i s ) :− ! .

s c a l e d e f ( o c t a t o n i c , [ c , c #, d #, e , f #, g , a , a # ] , none ) :− ! .s c a l e d e f ( o c t a t o n i c s h a r p s , X , Y) :− s c a l e d e f ( o c t a t o n i c , X , Y ) .s c a l e d e f ( o c t a t o n i c f l a t s , [ c , d &, e &, e , g &, g , a , b & ] , none ) :− ! .s c a l e d e f ( h a l f w h o l e , X , Y) :− s c a l e d e f ( o c t a t o n i c , X , Y ) , ! .s c a l e d e f ( h a l f w h o l e s h a r p s , Y , Z ) :− s c a l e d e f ( o c t a t o n i c−s h a r p s , Y , Z ) , ! .s c a l e d e f ( h a l f w h o l e f l a t s , Y , Z ) :− s c a l e d e f ( o c t a t o n i c− f l a t s , Y , Z ) , ! .s c a l e d e f ( w h o l e h a l f , [ c , d , d #, f , f #, g #, a , b ] , none ) :− ! .s c a l e d e f ( w h o l e h a l f s h a r p s , X , Y) :− s c a l e d e f ( w h o l e h a l f , X , Y ) .s c a l e d e f ( w h o l e h a l f f l a t s , [ c , d , e &, f , g &, a &, a , b ] , none ) :− ! .

s c a l e d e f ( b l u e s , [ c , d , e &, e , f , g &, g , a , b & ] , u n i s ) :− ! .

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗RELATIONSHIP OF SCALE TO KEY

Given a S c a l e , r e t u r n s t he c o r r e s p o n d i n g key .Th i s i n f o r m a t i o n i s used by the GUIDO p a r s e r .

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

s c a l e k e y ( ˜ S c a l e , 0 ) :−s c a l e d e f ( S c a l e , , none ) .

s c a l e k e y ( Tonic ˜ S c a l e , Key ) :−s c a l e d e f ( S c a l e , , Degree ) ,g e t s c a l e ( Tonic ˜ S c a l e , [ ( PC , NC ) | R e s t ] ) ,

CHAPTER 6. CODE AND TESTING 148

a b s o l u t e i n t e r v a l c p (PC , NC , KPC , KNC , Degree , down ) ,p i t c h n a m e ( p i t c h (KPC , KNC ) , Key ) , ! .

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗NUMBER OF SHARPS AND FLATS FOR MAJOR KEYS

needed f o r GUIDO t r a n s l a t i o n∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

k e y s h a r p s f l a t s ( 0 , c ) .k e y s h a r p s f l a t s ( 1 , g ) .k e y s h a r p s f l a t s ( 2 , d ) .k e y s h a r p s f l a t s ( 3 , a ) .k e y s h a r p s f l a t s ( 4 , e ) .k e y s h a r p s f l a t s ( 5 , b ) .k e y s h a r p s f l a t s ( 6 , f #).k e y s h a r p s f l a t s ( 7 , c #).k e y s h a r p s f l a t s (−1 , f ) .k e y s h a r p s f l a t s (−2 , b &).k e y s h a r p s f l a t s (−3 , e &).k e y s h a r p s f l a t s (−4 , a &).k e y s h a r p s f l a t s (−5 , d &).k e y s h a r p s f l a t s (−6 , g &).k e y s h a r p s f l a t s (−7 , c &).

/∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗SPECIAL TONE DEFINITIONS

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/

:− m u l t i f i l es p e c i a l t o n e d e f / 3 .

s p e c i a l t o n e d e f ( f i n a l , , c ) :− ! .

s p e c i a l t o n e d e f ( ambitus , X , Y) :− s p e c i a l t o n e d e f ( t o n i c , X , Y ) .

s p e c i a l t o n e d e f ( t e n o r , hypo− , e ) :− ! .s p e c i a l t o n e d e f ( t e n o r , , g ) :− ! .

s p e c i a l t o n e d e f ( t o n i c , hypo− , g ) :− ! .s p e c i a l t o n e d e f ( t o n i c , , c ) :− ! .

s p e c i a l t o n e d e f ( l e a d i n g , p h r y g i a n , b & ) :− ! .s p e c i a l t o n e d e f ( l e a d i n g , hypo− l y d i a n , f # ) :− ! .s p e c i a l t o n e d e f ( l e a d i n g , hypo− , f ) :− ! .s p e c i a l t o n e d e f ( l e a d i n g , n a t u r a l−minor , b & ) :− ! .s p e c i a l t o n e d e f ( l e a d i n g , , b ) :− ! .

% Only used i n TONAL harmonic p r a c t i c es p e c i a l t o n e d e f ( s u p e r t o n i c , major , d ) :− ! .s p e c i a l t o n e d e f ( s u p e r t o n i c , −minor , d ) :− ! .

CHAPTER 6. CODE AND TESTING 149

s p e c i a l t o n e d e f ( mediant , major , e ) :− ! .s p e c i a l t o n e d e f ( mediant , −minor , e & ) :− ! .

s p e c i a l t o n e d e f ( subdominant , major , f ) :− ! .s p e c i a l t o n e d e f ( subdominant , −minor , f ) :− ! .

s p e c i a l t o n e d e f ( dominant , major , g ) :− ! .s p e c i a l t o n e d e f ( dominant , −minor , g ) :− ! .

s p e c i a l t o n e d e f ( submediant , major , a ) :− ! .s p e c i a l t o n e d e f ( submediant , m e l o d i c−minor , a ) :− ! .s p e c i a l t o n e d e f ( submediant , −minor , a & ) :− ! .

s p e c i a l t o n e d e f ( s u b t o n i c , major , b ) :− ! .s p e c i a l t o n e d e f ( s u b t o n i c , n a t u r a l−minor , b & ) :− ! .s p e c i a l t o n e d e f ( s u b t o n i c , −minor , b ) :− ! .

IIVisual Pelog

150

7Motivations for a visual language

This chapter is a modified version of some mid-project reflections.

7.1 Summary of core Pelog system

The Pelog system provides a language in which to specify musical constraints. Theseconstraints are “applied” by an interpreter to generate or evaluate musical scores.

7.2 The next step

There are three main avenues for improvement:

1. The library of predicates for musical relationships that support the Peloglanguage.

2. The interpreter that applies sets of rules to musical scores.

3. The design of the Pelog language itself.

Of these areas, the one with perhaps the least room for improvement is thelibrary. Most of these predicates are direct translations of Brinkman’s [4] researchon musical data structures. While there is certainly room for extensions to thelibrary, the core predicates as they are now are unlikely to change significantly.

The interpreter is currently quite cumbersome. The fundamental algorithm isquite complex and still performs a lot of redundant checking despite the high factorsof improvement that have been achieved through more intelligent backtracking. Onepossible solution is to apply constraint programming theory to the problem [39].This task is by no means trivial, as it would likely involve porting the existingcode to a flavour of Prolog that supports constraints. Another solution that wasdiscussed was to make the interpreter more interactive. A user would be able to

151

CHAPTER 7. MOTIVATIONS FOR A VISUAL LANGUAGE 152

guide the solution-searching at various points in the process. This would changethe focus of the program from a counterpoint generator to a tutorial expert system.Such an approach may have limited utility, however, as most musicians tend todevelop melodies as complete phrases rather than note-by-note. Since the ability totest complete phrases for integrity within a set of rules already exists in the presentsystem, the interactive approach is perhaps merely delegating computation to theuser rather than provided the user with a valuable educational experience.

The area that interests me the most is the Pelog language design itself. Theoriginal genesis of this project was the realisation that the logical programmingparadigm is analogous to the specification of musical relationships. Distilling Fux[11] into finite musical relatinships proved to be the most interesting musicologicalpart of the project.

7.3 The problem

The Pelog language gains its power from the fact that it is a declarative logicallanguage derived from Prolog. It is relatively easy to concisely specify musical re-lationships using Pelog, as proven by the process of specifying modal counterpoint.However, what is easy to someone with a background in programming is not neces-sarily easy for the average musician. For example, take the following code for therule that specifies “a step followed by a step:”r u l e (’Step -- step’ , ’contour’ , 1 ) :−

$p re v2 : $pre v 1 a i n t e r v a l s t e p ,$p re v1 : $ e v e n t a i n t e r v a l s t e p ,$p re v2 comment ’Step followed by a step’ . $

This states that a) the absolute interval between the two notes before the currentnote must be a step, b) the absolute interval between current note and the notebefore it must be a step, and c) add a comment to the note two notes before thisone reading “Step followed by a step.” This description is not readily apparent fromthe code to someone who has not studied the Pelog library reference. A possibleimprovement might be to make it more like English:t he a b s o l u t e i n t e r v a l between $ pre v2 and $ pre v1 i s a s t e p ,t he a b s o l u t e i n t e r v a l between $ pre v1 and $ e v e n t i s a s t e p ,add comment to $pre v 2 t h a t r e a d s ’ Step f o l l o w e d by a s t e p ’ . $

The trouble with this approach is that there are often multiple English sentencesthat express the same meaning. One could just as easily have chosen the followingexpression:between $pre v 1 and $pre v 2 t h e r e i s an a b s o l u t e i n t e r v a l o f a s t e p ,between $pre v 2 and $ e v e n t t h e r e i s an a b s o l u t e i n t e r v a l o f a s t e p ,’ Step f o l l o w e d by a s t e p ’ s h o u l d be added as a comment to $ pre v2 . $

This is an extreme example, but it illustrates that a natural language approachdoes not eliminate the necessity for a programmer to study and follow certain con-ventions.

CHAPTER 7. MOTIVATIONS FOR A VISUAL LANGUAGE 153

7.4 The solution

The best solution would be do develop a visual programming1 environment. It willhave two primary functions:

1. Organize rules within the heirarchy of levels, classes and rule sets. (RuleManager)

2. Visually edit the musical relationships within each rule. (Rule Editor)

A visual environment will push the Pelog project further toward its original goalof providing an easy-to-use environment in which musicians can specify musicalrelationships. While the core interpreter still requires a significant amount of work,this new direction is more interesting from a research perspective and more likelyto break new ground.

1“Visual programming,” as defined here, refers to programming using graphical rather thantextual means. It should not be confused with Microsoft’s definition of “Visual” which refersto a GUI-builder environment on top of a traditional text-based programming system. “Visualprogramming” is not a new idea, but is experiencing somewhat of a renaissance, particularly indatabase application development [18], and was the featured topic of a recent issue of Dr. Dobb’sJournal [21].

8The Visual Pelog language

The Visual Pelog language is a visual extension of the text-based Pelog musicalconstraint language (page 2). Each problem domain, (eg. Modal Counterpoint,Twelve-Tone Counterpoint) is defined by a rule-set. A rule-set is made of up ofa number of individual rules. The rules within the rule set can be categorized bypriority, class and a number of other factors which determine how the rules will beapplied by the interpreter to a given musical score.

8.1 Musical Constraint Graphs

Each rule is defined using a special case of a directed graph called a “musical con-straint graph.” These graphs define relationships between musical events. Theseevents include a current event, the previous eight events in its part and the pre-vious eight events in another part that is occuring simultaneously. These eventscorrespond to the metavariables used in the text-based Pelog Language. For therationale behind this choice, see the Pelog Language Reference (page 2).

The user is initially presented with a set of notes representing these eighteenevents known as the note template (Figure 8.11).

Relationships are drawn between these notes in a manner that should be familiarto musicians with a background in common music notation. Relationships betweenevents that occur sequentially are drawn horizontally (Figure 8.2), and relationshipsbetween events that occur simultaneously are drawn vertically (Figure 8.3).

More complex (compound) relationships can also be created. (Figure 8.4).1All of the example diagrams were produced directly from Visual Pelog by converting then to

Postscript using Tk’s psprint function.

154

CHAPTER 8. THE VISUAL PELOG LANGUAGE 155

Figure 8.1: The basic note template.

Figure 8.2: An example horizontal relationship

Figure 8.3: An example vertical relationship

CHAPTER 8. THE VISUAL PELOG LANGUAGE 156

Figure 8.4: An example compound relationship

8.2 Constraint primitives

There are a number of different constraint types available that correspond to thelibrary predicates defined in the text-based version of the Pelog language. Theseinclude constraints for interval, pitch, range and scale.

There are also logical constraints. These include:

OR: OR is a binary relationship that connects two other constraints. It allowseither or both of the constraints to be active. It may be created between anytwo contraints.

NOT: NOT negates the effect of the constraint. The rule succeeds when theconstraint attached to NOT does not succeed. It may be applied to anyconstraint.

GREATER/LESS: GREATER/LESS is true when the value of one constraintis greater or less than another constraint. The GREATER/LESS constraintcan only be drawn between two comparable constraints. For example, twointerval constraints can be constrained so one interval is smaller than theother. However, it makes no sense for an interval constraint to be comparedto a scale constraint, for example. The same constraint functions as bothgreater and less depending on the direction in which one drags when creatingthe constraint. Always draw from the constraint with the greater value to theconstraint with the lesser value.

EQUAL: EQUAL is true when the value of two contraints are equal. Like theGREATER/LESS constraint, the EQUAL constraint may only be drawnbetween comparable constraints.

CHAPTER 8. THE VISUAL PELOG LANGUAGE 157

8.3 Some examples

8.3.1 Step-wise motion

To constrain all melodic intervals to step-wise motion, you want to constrain the“current” note and the previous note to the interval of a step.

Draw an interval constraint between the current note and the previous note andset its value to a step using the on-screen musical keyboard. The resulting rule isin Figure 8.5.

Figure 8.5: Rule for step-wise motion.

8.3.2 Step-wise or third-wise motion

Constraining all melodic intervals to a step can be quite limiting. Suppose you wantto also allow melodic intervals of a third. One can use the OR logical constructorto compose the constraint that melodic intervals can be steps or thirds.

Starting with the step-wise rule defined above, add another interval constraintbetween the same two nodes and specify the interval of a third using the on-screenmusical keyboard. Then, draw an OR constraint between the two interval con-straints. The resulting rule is in Figure 8.6.

CHAPTER 8. THE VISUAL PELOG LANGUAGE 158

Figure 8.6: Step-wise or third-wise melodic motion

CHAPTER 8. THE VISUAL PELOG LANGUAGE 159

8.3.3 Avoiding parallel intervals

Suppose you want to avoid any parallel intervals, (i.e. where a given harmonicinterval is repeated on two consecutive beats.) This would imply that the currentharmonic interval and the preceding harmonic interval are note equal.

Draw an interval constraint vertically between the current note and the noteoccuring simultaneously. Draw another one between the two notes preceding those.The interval type does not need to be specified, because we don’t care what inter-vals they are, only that they are equal. The equality is specified by drawing anEQUALS logical constraint between the two interval constraints. Finally, we wantto disallow this equality, so we can apply the NOT constraint to the EQUALSconstraint.

Figure 8.7: No parallel intervals rule.

8.4 Future extensions

The most obvious next step to improve the Visual Pelog language is the implementthe remaining constraints that are part of the core Pelog library.

As well, it may be useful to implement metaconstraints to handle commonlyoccuring combinations of the logical constraints such as parallelism or repetition.

9The Visual Pelog environment

9.1 Introduction

For this section, it is assumed you already have some basic knowledge of Pelog’sconcept of musical constraints. For this, please see The Pelog language on page 2.This section does not describe how to specify musical constraints using the VisualPelog language. For that, please see The Visual Pelog language on page 154.

At the present time, the Visual Pelog system is a prototype with many unimple-mented features. Most notably missing is the conduit between Visual Pelog and thePelog systems that would allow interpretation of musical scores. In this chapter, allunimplemented features are marked with a diamond (�).

The Visual Pelog environment allows the user to edit Pelog rule sets. Thiscomprises two main activities:

Organizing the heirarchy of rules: Changing the order and priority of ruleswithin the rule set.

Editing the musical constraints (rules): Changing the semantics of each rulein the rule set.

9.2 A Visual Pelog session

The Visual Pelog environment (Figure 9.1 is made up of a number of separatewindows:

Rule manager: The rule manager is a heirarchical tree of all the rules in the ruleset.

Rule editor: The rule editor allows editing of the semantics of individual rules.

Tool palette: The tool palette contains a number of items that can be added torules in the rule editor.

160

CHAPTER 9. THE VISUAL PELOG ENVIRONMENT 161

Figure 9.1: A Visual Pelog session

CHAPTER 9. THE VISUAL PELOG ENVIRONMENT 162

Help browser: The help browser provides on-line help on the tools in the toolpalette.

9.3 Opening and saving rule sets

� Not implemented.

9.4 Rule manager

The rule manager displays the rules in the rule set in a heirarchical tree similar toMicrosoft Windows Explorer. The tree display is collapsible, meaning you can hideand show categories of rules by clicking on the open/close folder button ( ).

9.4.1 Selecting rules

To select a rule, click on it once. Only one rule can be selected at a given time.

9.4.2 Adding rules

To add a new rule to the rule set, click on rule class (group of rules) and press theInsert key. A new rule called “Untitled Rule” is added to the rule class.

9.4.3 Moving rules

To move rules from one rule class to another, simply drag them with the mouse totheir new location. To cancel the drag operation, simply drag it over any whitespacein the Rule Manager.

9.4.4 Deleting rules

To delete a rule, select it and then press the Delete key.

9.4.5 Editing rules

To edit a rule, select it and press the Enter / Return key, or simply double-click it.

9.5 Rule editor

The rule editor window (Figure 9.2) is made up of four sections:

Description: Entry for a natural-language description of what the rule does.

Graph editor: An area where the rule itself is edited.

Status bar: Displays information about the item on the graph that the mouse iscurrently over.

Musical keyboard: Used to specify properties about items in the graph.

CHAPTER 9. THE VISUAL PELOG ENVIRONMENT 163

Figure 9.2: The rule editor window.

9.5.1 Graph editor

For information on creating musical constraints using musical constraint graphs,please see The Visual Pelog language on page 154.

Adding constraints

To add constraints, make sure that the desired constraint type is selected in thetool palette (Figure 9.5). If the constraint is a unary constraint (i.e. constrains oneevent on its own) simply click on the event you wish to constrain. If the constraintis a binary constraint (i.e. constrains the relationship between two notes) click anddrag between the two events you wish to constrain. After creating the constraint,you will be able to edit specifics of that constraint using the musical keyboard atthe bottom of the rule editor window.

Selecting constraints

Choose the Selection Tool ( ) in the tool palette. Click on the constraint you wishto select. The selected constraint will appear in reverse video (Figure 9.3). Therecan only be only selected constraint at a given time.

CHAPTER 9. THE VISUAL PELOG ENVIRONMENT 164

Figure 9.3: A selected constraint.

Obtaining information about a constraint

Move the mouse over a constraint. Detailed information about that constraint willbe displayed in the status bar.

Deleting constraints

Select the constraint you wish to delete and press the Delete key.

9.5.2 Using the musical keyboard

The musical keyboard (Figure 9.4) allows the user to modify properties about theselected constraint. For example, with the Interval constraint type, the musicalkeyboard allows the user to select the specific interval to which the events will beconstrained.

Figure 9.4: The musical keyboard

As you slide the mouse over the keys, the pitch of the key at the mouse cursoris displayed on the left-hand side.

The musical keyboard acts differently based on context. There are three mainmodes of operation (consult the constraint’s on-line documentation in the toolpalette to determine which mode is used for different types of constraints):

Single: Click on a key to select a pitch. Only one key can be selected at a giventime.

Multi: Click on a key to toggle its status. You can select as many keys as necessary.

Range: Click on a starting note and drag to an ending note to select an unbrokenrange of keys.

To make the keys themselves larger, press the zoom-in button ( ). To restorethem to their original size, press the zoom-out button ( ).

CHAPTER 9. THE VISUAL PELOG ENVIRONMENT 165

Figure 9.5: The tool palette.

9.6 Tool palette

Different types of constraints can be selected from the tool palette. The set oftools is based on the plug-ins installed on your system. In this way, new types ofconstraints can be added to the system at a later date.� Currently, only the basic logical constraints (OR, NOT, =, >) and the In-

terval Tool are implemented.

Selecting a tool

To select a tool, click on it.

Getting help on a tool

As you bring your mouse over a tool, its name is displayed in the status bar atbottom of the Tool Palette window. For more detailed help on a given tool, selectthe tool and press the question mark button ( ). A description of the tool and itsassociated constraint is opened in the on-line help browser.

10A specialized graph layout

algorithm for musical constraintgraphs

Graph layout theory is a large and active field of study [10] [8]. In general, researchhas indicated that while GLA’s can be classified into a small number of categories,extensive customization is usually necessary for each unique graph problem domain.Recent attempts at generalized graph drawing systems have been successful onlydue to their support for numerous different layout algorithms (GraphEd [13]) ortheir ability to perform minute customizations on individual constraints (EDGE[25]). Likewise, the present graph layout system is specific to the problem of whatshall be called “musical constraint graphs.”

10.1 Specification of problem

The graph layout algorithm (GLA) used by the Visual Pelog rule editor is the mostcomputationally complex part of the visual system. Its “musical constraint graphs”define relationships between a given set of musical events. For a definition of amusical constraint graph, see page 154.

Specifically, a graph layout algorithm supporting this definition must coordinatethe following constraints.

• All layout decisions should be automated. The user need only be concernedwith the semantics of the graph.

• All nodes must be visible, therefore no two nodes may overlap.

• Spatial relationships between nodes must be meaningful: eg., a node repre-senting a relationship between two other nodes must physically reside as closeas possible to the center of those two nodes.

166

CHAPTER 10. GRAPH LAYOUT ALGORITHM 167

• The algorithm must work in two dimensions: vertical relationships must bedrawn vertically, and horizontal relationships horizontally.

• Changes to the graph must be made elegantly, so that the user does not get‘lost.’

10.2 Background

10.2.1 Sugiyama algorithm

The graph layout algorithm used by Visual Pelog is loosely based on the ‘classic’Sugiyama graph layout algorithm [35] as summarized by Ivan Bowman [3]. Thisalgorithm was designed for laying out heirarchical tree-like structures. It results ingraphs which have the following properties (as summarized in Bowman [3]):

• “hierarchical” layout of vertices

• minimized edge crossings

• connected vertices are close together

• “balanced” layout of edges

The algorithm proceeds in three steps:

1. Perform a topological sort on the nodes, assigning each to a “level.” Unlike theclassical definition of a topological sort [7], more than one node may occupythe same level.

2. Within each level, the vertices are permuted to minimize line crossings.

3. Assign positions to maximize barycenters (i.e. so that children are centeredunder their parents and vice versa.)

There are some disadvantages to the basic Sugiyama algorithm that, on its own,make it unsuitable for the present task.

• No constraints. Certain nodes, such as those that make up the note templateneed to be constrained. (i.e. The notes that make up each part should be ver-tically aligned, and the notes occuring simultaneously should be horizontallyaligned.)

• Poor stability. Dramatic changes to the layout can occur when minorchanges are made to the graph itself. When too many nodes move, the useris easily confused and can lose a sense of orientation within the graph.

• One-dimensional hierarchical relationship. It assumes a straightforwardone-dimensional heirarchy between all nodes. For the problem at hand, oneneeds to specify heirarchies that work in either the horizontal or vertical di-rection: in effect a “double” Sugiyama algorithm.

CHAPTER 10. GRAPH LAYOUT ALGORITHM 168

10.2.2 Constraint-based extensions to the Sugiyama algorithm

Paulisch [25] describes a way to extend the Sugiyama algorithm to support con-straints. In his extension, the position of every node can be constrained based thepositions of an arbitrary number of other nodes. Paulisch suggests a number ofconstraint types, both simple and exotic. The constraints deemed necessary for thepresent problem are as follows:

• equal: The node must be on the same level as some other nodes.

• less: The node must be on a lesser (northwesterly) level than some othernodes.

• greater: The node must be on a greater (southeasterly) level than some othernodes.

• near: The node must be as close as possible to the artihmetic mean (center)of the listed nodes.

To support the extension to constraints, the topological sort step of the Sugiyamaalgorithm is replaced with a constraint solver. In fact, a topological sort can be per-formed without using a classical topological sort algorithm [7] simply by convertingall of the parent-child relationships to greater and less constraints.

10.2.3 The problem of graph stability

Another observation made by Paulisch is that the layout of graphs using theSugiyama algorithm tends to change dramatically when simple changes are madeto the graph. When too many nodes change positions by too much, users can easilylose their bearings. This is an important consideration for the present project, asthe graph is to be edited interactively. Paulisch proposed an elaborate solutionto this problem where the allowed movement of a given node is limited by someδ-constant and the number of nodes that can move in any iteration is also limited.

While a similar solution may be incorporated in the future, at present, thestability problem is solved using animation. When a change is made to the graph,the nodes are gradually animated from their original positions to their new positions.While occasionally the movement of nodes can be drastic, for the most part thismore naıve approach is quite acceptable. The movement of nodes also represents,in an entertaining way, the dynamic nature of the graph.

10.2.4 The problem of two-dimensionality

To apply the constraint-based Sugiyama algorithm in two dimensions, theconstraint-based sort is simply performed on one axis, and then the results areapplied to a sort on the other axis.

CHAPTER 10. GRAPH LAYOUT ALGORITHM 169

10.3 Implementation of the algorithm

10.3.1 General design

The present GLA is implemented in an object-oriented style. The algorithm, onthe most basic level, is an interaction between the rule editor, which maintains alist of nodes and operates globally on the nodes, and the nodes themselves, whichperform their own topological sorting and constraint resolution.

An attempt was also made to uncouple the algorithm itself from the underlyinggraphics architecture (in this case Tkinter.) This allows ths system to be triviallyported to other graphics libraries. One of the less obvious of such abstractions isthe differentiaion between logical and physical coordinates. Logical coordinates arethe location of the node based on the topological sort and constraint resolutionsteps. These logical coordinates are mapped to physical coordinates, in a mannerthat avoids any collisions, only after all of the basic layout has been completed.

10.3.2 The top-level

The main process is as follows:

1. Enter a loop that continues until there are no conflicts.

• Support the near constraint by moving all nodes to the average (center)of their near nodes.

• Perform a constraint-based ‘topological’ sort on each of the nodes.

• Resolve any conflicts (where two nodes occupy the same location.)

2. Map the logical coordinates from step 1 to physical coordinates.

10.3.3 The near constraint

Before performing the constraint-based topological sort, nodes are moved to theirideal near locations which is the average (center) of the locations of all the nodeson the near constraint list.

10.3.4 Constraint-based topological sort

The topological sort is performed by resolving the equal, greater and less constraints.The success of this constraint resolution is dependent on how the constraints aredetermined at the time of node creation. (see Creating nodes on 170).

At the top-level, all nodes are sorted first on the x axis, then on the y axis.As the constraints are solved, nodes are always moved southeast, so that the

graph expands outward. If nodes were allowed to move in arbitrary directions, thegraph might implode and explode on itself, creating deadlock in an infinite loop.

For example, to solve the equal constraint, the position of the current node andthe nodes on its equal list are compared. The node with the more northwesterlyposition is moved to the location of the node with the more southeasterly position.

CHAPTER 10. GRAPH LAYOUT ALGORITHM 170

10.3.5 Conflict resolution

Once the constraint-based topological sort has assigned a level in both dimensionsto all nodes, the entire set of nodes is scanned for any conflicts. A conflict existswhen two or more nodes occupy the same location.

A search is performed for nodes occupying the same location. When a pair isfound, the Node instance will move itself or its partner. The choice of which Nodeto move is determined by the average location of all nodes on the near constraintlist. For example, if node a has a more leftward near average than node b, then nodea will move left.

10.3.6 Mapping physical coordinates to logical coordinates

The grid layout subalgorithm maps the logical coordinates as determined by thetopological sort to the physical coordinates on the canvas. Since different nodeshave different physical sizes, the maximum size of the nodes in each row and columnmust be determined before assigning physical values to each row and column.

10.3.7 Animation

Once the new physical coordinates of all the nodes has been determined, the nodesare moved incrementally from their old locations to their new ones while updatingthe display. The number of animation steps is determined by a constant.

10.3.8 Creating nodes

An important part of the graph layout algorithm is how the constraints are assignedwhen nodes are created. The Visual Pelog system uses three families of nodes, fromwhich all other nodes are inherited.

Note nodes

Note nodes make up the note template. They must be aligned to other nodes, bothvertically and horizontally, to represent the sequential and concurrent relationshipsof the note in the note template. This is performed using the equals constraint. Forexample, the “current” note node and the note that occurs simultaneously mustappear directly below it. Therefore, it is on the equals constraint list on the x-axis.

Binary relations

A binary relation node is used to specify a relationship between two nodes. Inpractice, the interval constraint is an example of a binary relation.

If a binary relation node x is defined between nodes a and b, and the relativelocation of a and b are a < b, then the relative locations of all three must bea < x < b. The less and greater constraints are assigned accordingly. The node xshould also be as close as possible to the centre of the two nodes a and b. Therefore,a and b are added to the near constraint list of x.

CHAPTER 10. GRAPH LAYOUT ALGORITHM 171

Unary relations

A unary relation node is used to define a relation involving only one node. Inpractice, constraints involving pitch class are often unary relation nodes.

Unary relation nodes should be as close as possible to the nodes they are relatedto. If a unary relation node x is defined on a node a, then a is added to the nearconstraint list of x.

10.4 Code related to the graph layout algorithm

10.4.1 RuleEditor.py

Code

# V i s u a l Pe log F a l l 1 9 9 9 M i c h a e l Droettboom mdboom@mail . com############################################################# R u l e E d i t o r . py## Top− l e v e l c l a s s e s f o r e d i t i n g r u l e s

# V i s u a l Pe log i m p o r t sfrom U t i l i m p o r t ∗from C o n s t a n t s i m p o r t ∗i m p o r t Nodes , P a l e t t e , MusicWidgets

# T k i n t e r i m p o r t si m p o r t T k i n t e r , Canvas

################################################### R u l e E d i t o r## The frame i n which th e r u l e e d i t o r r e s i d e s .#c l a s s RuleEditorWindow ( T k i n t e r . T o p l e v e l ) :

#−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−# I n i t i a l i z a t i o n r o u t i n e sd e f i n i t ( s e l f , p a l e t t e , p a r e n t=None , r u l e=None ) :

s e l f . r u l e = r u l e

T k i n t e r . T o p l e v e l . i n i t (s e l f , p a r e n t ,c l a s s =’RuleEditor’ )

s e l f . t i t l e ("Rule Editor" )

# A r e f e r e n c e to t he t o o l p a l e t t e t h a t w i l l i n t e r a c t w i t h# t h i s r u l e e d i t o rs e l f . p a l e t t e = p a l e t t e

# Make t he w i d g e t s t h a t a r e put o f the r u l e e d i t o r windows e l f . m a k e w i d g e t s ( r u l e )

CHAPTER 10. GRAPH LAYOUT ALGORITHM 172

# P r e s s i n g ’ p ’ w i l l e x p o r t th e c anvas as a P o s t S c r i p t f i l es e l f . b i n d ( s e q u e n c e=’<p>’ ,

f u n c=s e l f . canvas . p s p r i n t )

# A l l o t h e r k e y s t r o k e s a r e s e n t to the c u r r e n t l y s e l e c t e d t o o ls e l f . b i n d ( s e q u e n c e=’<KeyPress>’ ,

f u n c=p a l e t t e . t o o l k e y p r e s s )

# C r e a t e s t he w i d g e t s i n th e r u l e e d i t o r windowd e f m a k e w i d g e t s ( s e l f , r u l e ) :

# The t e x t box used to d e s c r i b e the r u l e i n E n g l i s hs e l f . t e x t = T k i n t e r . Text ( h e i g h t =3, master=s e l f )i f s e l f . r u l e :

s e l f . t e x t . i n s e r t ( ’0.0’ , r e p r ( s e l f . r u l e ) )s e l f . t e x t . g r i d ( row =0, column =0, s t i c k y=’nwe’ )s e l f . t e x t . b i n d ( s e q u e n c e="<KeyRelease>" , f u n c=s e l f . update name )

# The m u s i c a l keyboards e l f . keyboard = MusicWidgets . Keyboard ( s e l f )s e l f . keyboard . g r i d (

row =5, column =0, s t i c k y=’nesw’ , columnspan =2)

# The r u l e e d i t o r i t s e l f and i t s c o r r e s p o n d i n g s c r o l l b a r ss e l f . c anvas = R u l e E d i t o r C a n v a s (

p a l e t t e=s e l f . p a l e t t e ,master=s e l f ,keyboard=s e l f . keyboard , r u l e=r u l e )

s e l f . c anvas . g r i d ( row =1, column =0, s t i c k y=’nesw’ )s e l f . v s c r o l l = T k i n t e r . S c r o l l b a r (

s e l f , o r i e n t=’vertical’ ,command=s e l f . canv as . yv i ew )

s e l f . v s c r o l l . g r i d ( row =1, column =1, s t i c k y=’ns’ )s e l f . h s c r o l l = T k i n t e r . S c r o l l b a r (

s e l f , o r i e n t=’horizontal’ ,command=s e l f . canv as . xv i ew )

s e l f . h s c r o l l . g r i d ( row =2, column =0, s t i c k y=’we’ )

s e l f . g r i d c o l u m n c o n f i g u r e ( 0 , w e i g h t =1)s e l f . g r i d r o w c o n f i g u r e ( 1 , w e i g h t =1)

s e l f . c anvas [ ’xscrollcommand’ ] = s e l f . s c r o l l Xs e l f . c anvas [ ’yscrollcommand’ ] = s e l f . s c r o l l Y

# The s t a t u s bars e l f . s t a t u s = T k i n t e r . L a b e l (

master=s e l f , r e l i e f =’sunken’ )s e l f . s t a t u s . g r i d ( row =4, column =0, columnspan =2, s t i c k y=’we’ )

#−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−# Event h a n d l e r s

CHAPTER 10. GRAPH LAYOUT ALGORITHM 173

d e f s c r o l l X ( s e l f , f i r s t , l a s t ) :s e l f . h s c r o l l . s e t ( f i r s t , l a s t )

d e f s c r o l l Y ( s e l f , f i r s t , l a s t ) :s e l f . v s c r o l l . s e t ( f i r s t , l a s t )

d e f update name ( s e l f , a r g s ) :s e l f . r u l e . update name ( s e l f . t e x t . g e t ( ’0.0’ , ’end’ ) )

################################################### R u l e E d i t o r C a n v a s## The r u l e graph d i s p l a y w i d g e t#c l a s s R u l e E d i t o r C a n v a s ( CursorManager , T k i n t e r . Canvas ) :

#−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−# I n i t i a l i z a t i o n r o u t i n e sd e f i n i t ( s e l f , p a l e t t e=None , master=None , keyboard=None , r u l e=None ) :

s e l f . r u l e = r u l e

T k i n t e r . Canvas . i n i t (s e l f , master ,background=RE COLOR CANVAS BACKGROUND ,c o n f i n e=TRUE)

s e l f . m a k e r u b b e r ( )s e l f . b i n d ( s e q u e n c e="<Motion>" , f u n c=s e l f . motion )CursorManager . i n i t ( s e l f )

# A r e f e r e n c e to t he t o o l p a l e t t e t h a t w i l l i n t e r a c t w i t h# t h i s r u l e e d i t o rs e l f . p a l e t t e = p a l e t t e

# A r e f e r e n c e to t he on−s c r e e n m u s i c a l keyboard t h a t w i l l# i n t e r a c t w i t h t h i s e d i t o rs e l f . keyboard = keyboard

# The two nodes t h a t a r e d e t e r m i n e d by d r a g g i n g between# two nodes . These nodes a r e s e n t to the c u r r e n t t o o l to# c r e a t e new p r e d i c a t e s .s e l f . s t a r t n o d e = s e l f . f i n i s h n o d e = None

# A l i s t o f a l l t he nodes i n the c anvass e l f . n o d e L i s t = r u l e . n o d e L i s t

# C r e a t e t he b o i l e r p l a t e note nodes . . .i f s e l f . n o d e L i s t = = [ ] :

s e l f . c r e a t e b a s i c n o d e s ( )e l s e :

f o r node i n s e l f . n o d e L i s t :node . master = s e l f

CHAPTER 10. GRAPH LAYOUT ALGORITHM 174

node . v i s u a l i z e ( )

# . . . and animate them to t h e i r f i n a l p o s i t i o nf o r node i n s e l f . n o d e L i s t :

node . f i n a l i z e c o o r d ( )

# C r e a t e s t he r u b b e r band l i n ed e f m a k e r u b b e r ( s e l f ) :

s e l f . r u b b e r = Canvas . L i n e (s e l f , −5 , −5 , −5 , −5 )

s e l f . r u b b e r [ ’width’ ] = 2 . 0s e l f . r u b b e r [ ’stipple’ ] = ’gray50’

# C r e a t e s t he b o i l e r p l a t e note nodesd e f c r e a t e b a s i c n o d e s ( s e l f ) :

p r e v 8 = Nodes . NoteNode ( s e l f , ’$prev8’ )s e l f . r u l e . Top row = p r e v 8p r e v 7 = Nodes . NoteNode ( s e l f , ’$prev7’ , prevX=p r e v 8 )p r e v 6 = Nodes . NoteNode ( s e l f , ’$prev6’ , prevX=p r e v 7 )p r e v 5 = Nodes . NoteNode ( s e l f , ’$prev5’ , prevX=p r e v 6 )p r e v 4 = Nodes . NoteNode ( s e l f , ’$prev4’ , prevX=p r e v 5 )p r e v 3 = Nodes . NoteNode ( s e l f , ’$prev3’ , prevX=p r e v 4 )p r e v 2 = Nodes . NoteNode ( s e l f , ’$prev2’ , prevX=p r e v 3 )p r e v 1 = Nodes . NoteNode ( s e l f , ’$prev1’ , prevX=p r e v 2 )e v e n t = Nodes . NoteNode ( s e l f , ’$event’ , prevX=p r e v 1 , box=TRUE)v e r t 8 = Nodes . NoteNode ( s e l f , ’$vert8’ , prevY=p r e v 8 )s e l f . r u l e . Bottom row = v e r t 8v e r t 7 = Nodes . NoteNode ( s e l f , ’$vert7’ , prevX=v e r t 8 , prevY=p r e v 7 )v e r t 6 = Nodes . NoteNode ( s e l f , ’$vert6’ , prevX=v e r t 7 , prevY=p r e v 6 )v e r t 5 = Nodes . NoteNode ( s e l f , ’$vert5’ , prevX=v e r t 6 , prevY=p r e v 5 )v e r t 4 = Nodes . NoteNode ( s e l f , ’$vert4’ , prevX=v e r t 5 , prevY=p r e v 4 )v e r t 3 = Nodes . NoteNode ( s e l f , ’$vert3’ , prevX=v e r t 4 , prevY=p r e v 3 )v e r t 2 = Nodes . NoteNode ( s e l f , ’$vert2’ , prevX=v e r t 3 , prevY=p r e v 2 )v e r t 1 = Nodes . NoteNode ( s e l f , ’$vert1’ , prevX=v e r t 2 , prevY=p r e v 1 )v e r t = Nodes . NoteNode ( s e l f , ’$vert’ , prevX=v e r t 1 , prevY=e v e n t )

#−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−# Event h a n d l e r sd e f p s p r i n t ( s e l f , a r g s ) :

s e l f . p o s t s c r i p t (f i l e ="e:/Pelog/Visual/test.ps" )

# P l a c e s d e s c r i p t i v e t e x t about the node i n the s t a t u s bard e f d e s c r i b e n o d e ( s e l f , node ) :

s e l f . master . s t a t u s [ ’text’ ] = node

d e f u n d e s c r i b e n o d e ( s e l f ) :s e l f . master . s t a t u s [ ’text’ ] = ’’

d e f s e t s t a r t n o d e ( s e l f , node ) :s e l f . r u b b e r . c o o r d s ( [ (−5 ,−5 ) , (−5 ,−5 ) ] )

CHAPTER 10. GRAPH LAYOUT ALGORITHM 175

s e l f . s t a r t n o d e = node

d e f s e t f i n i s h n o d e ( s e l f , node ) :s e l f . r u b b e r . c o o r d s ( [ (−5 ,−5 ) , (−5 ,−5 ) ] )s e l f . f i n i s h n o d e = node

d e f motion ( s e l f , a r g s ) :i f s e l f . s t a r t n o d e :

s e l f . r u b b e r . c o o r d s ([ ( s e l f . s t a r t n o d e . pt [ 0 ] ,

s e l f . s t a r t n o d e . pt [ 1 ] ) ,( s e l f . c a n v a s x ( a r g s . x ) ,s e l f . c a n v a s y ( a r g s . y ) ) ] )

# R e t u r n s t he node at p h y s i c a l c o o r d i n a t e s ( x , y )# I f none e x i s t s , r e t u r n s Noned e f f i n d n o d e ( s e l f , x , y ) :

x = s e l f . c a n v a s x ( x )y = s e l f . c a n v a s y ( y )s e l f . r u b b e r . c o o r d s ( [ (−5 , −5 ) , (−5 , −5 ) ] )z = s e l f . f i n d o v e r l a p p i n g ( x , y , x , y )i f z ! = ( ) :

r e t u r n s e l f . i t e m s [ z [ 0 ] ] . nodee l s e :

r e t u r n None

# Per forms an a c t i o n based on the c u r r e n t l y s e l e c t e d t o o l on# t he two nodes s t a r t n o d e and f i n i s h n o d ed e f r u n t o o l ( s e l f ) :

d e b u g p r i n t ("Running tool on:" , s e l f . s t a r t n o d e , s e l f . f i n i s h n o d e )

s e l f . p a l e t t e . r u n t o o l ( s e l f , s e l f . s t a r t n o d e , s e l f . f i n i s h n o d e )s e l f . an imate ( )s e l f . s t a r t n o d e = s e l f . f i n i s h n o d e = None

#−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−# User f u n c t i o n sd e f add node ( s e l f , node ) :

s e l f . n o d e L i s t . append ( node )s e l f . l a y o u t n o d e s ( )# s e l f . an imate ( )

d e f remove node ( s e l f , node ) :s e l f . n o d e L i s t . remove ( node )s e l f . r e m o v e r e f e r e n c e s ( node )s e l f . l a y o u t n o d e s ( )s e l f . an imate ( )

d e f r e m o v e r e f e r e n c e s ( s e l f , node ) :f o r n i n s e l f . n o d e L i s t :

i f n . a == node or n . b == node :

CHAPTER 10. GRAPH LAYOUT ALGORITHM 176

n . d e l e t e ( )

#−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−# Graph l a y o u t f u n c t i o n s

# This i s t he top− l e v e l graph l a y o u t f u n c t i o n .# F o l l o w i n g t he o b j e c t−o r i e n t e d paradigm , most o f t he ” s m a r t s ” o f t he# a l g o r i t h m a r e embedded i n the node o b j e c t s t h e m s e l v e s .d e f l a y o u t n o d e s ( s e l f , draw =0):

d e b u g p r i n t ("LAYING OUT NODES ===============" ) # Debugging i n f o r m a t i o n

c o n f l i c t s = TRUE # Assume we w i l l f i n d c o n f l i c t sw h i l e c o n f l i c t s :

# I . Guess at a good s t a r t i n g l o c a t i o n f o r the nodes by moving them# to t he a v e r a g e l o c a t i o n o f the nodes s p e c i f i e d by t he ’ n e a r ’# c o n s t r a i n tf o r node i n s e l f . n o d e L i s t :

node . g o t o n e a r ( )# I I . T o p o l o g i c a l l y s o r t nodes based on the r e l a t i o n s h i p s and# c o n s t r a i n t s d e f i n e d w i t h each node , then r e s o l v e any c o n f l i c t s# ( where two nodes occupy the same c e l l ) . Repeat p r o c e s s u n t i l# t h e r e a r e no c o n f l i c t s . Each node i s a s s i g n e d a l o c a t i o n on# a LOGICAL g r i d .w h i l e c o n f l i c t s :

s e l f . t o p o l o g i c a l s o r t ( )c o n f l i c t s = s e l f . r e s o l v e ( )

s e l f . t o p o l o g i c a l s o r t ( )c o n f l i c t s = s e l f . r e s o l v e ( )

# I I I . Map t he r e s u l t s o f th e t o p o l o g i c a l s o r t ( l o c a t i o n on a LOGICAL# GRID ) to a l o c a t i o n on the PHYSICAL GRID .s e l f . g r i d l a y o u t ( )

# Runs a t o p o l o g i c a l s o r t on a l l nodes i n the graph# The a c t u a l work o f c o n s t r a i n t r e a l i z a t i o n i s pe r fo rm e d by t he# nodes t h e m s e l v e sd e f t o p o l o g i c a l s o r t ( s e l f ) :

d e b u g p r i n t ("TOPOLOGICAL SORT ===============" )

f o r dimen i n [ 0 , 1 ] : # S o r t x then y a x id e b u g p r i n t ("Dimension " , dimen , " ---------->" )

f o r node i n s e l f . n o d e L i s t :d e b u g p r i n t ("Starting at root node:" , node )node . t o p o l o g i c a l s o r t ( dimen , RE MINGRID , RE MAXGRID)

# r e s o l v e c o n f l i c t s ( when two nodes occupy the same c e l l )d e f r e s o l v e ( s e l f ) :

d e b u g p r i n t ("RESOLVING ===============" )

CHAPTER 10. GRAPH LAYOUT ALGORITHM 177

c o n f l i c t s = FALSE # no c o n f l i c t s y e t . . .f o r node1 i n s e l f . n o d e L i s t : # Compare each node i n graph . . .

f o r node2 i n s e l f . n o d e L i s t : # . . . w i t h e v e r y o t h e r node# I f t h e s e nodes a r e not th e SAME node , but have the same# l o c a t i o n on t he LOGICAL GRID . . .i f not ( node1 i s node2 ) and node1 . t p t == node2 . t p t :

c o n f l i c t s = TRUE # . . . then we ’ ve found a c o n f l i c t !d e b u g p r i n t ("Resolving" , node1 , "vs." , node2 )node1 . r e s o l v e ( node2 ) # Let t he nodes t h e m s e l v e s duke i t outb r e a k

i f c o n f l i c t s : b r e a kr e t u r n c o n f l i c t s

# A d j u s t s t he l o g i c a l l o c a t i o n s o f a l l the nodes i n t he graph so t h a t# e v e r y node i s g r e a t e r than ( 0 , 0 ) . R e t u r n s the maximum so t h a t t he# g r i d l a y o u t a l g o r i t h m can do i t s magic .d e f a d j u s t m i n m a x ( s e l f ) :

gmax = [ RE MINGRID , RE MINGRID ]gmin = [ RE MAXGRID , RE MAXGRID ]f o r dimen i n [ 0 , 1 ] : # Do x then y a x i s

# Find t he minimum and maximum i n t h i s d i m e n s i o nf o r node i n s e l f . n o d e L i s t :

gmin [ dimen ] = min ( node . t p t [ dimen ] , gmin [ dimen ] )gmax [ dimen ] = max ( node . t p t [ dimen ] , gmax [ dimen ] )

# S h i f t a l l nodes by th e minimum v a l u ef o r node i n s e l f . n o d e L i s t :

node . t p t [ dimen ] = node . t p t [ dimen ] + −1 ∗ ( gmin [ dimen ] )# C o r r e c t t he maximum f o r t h i s s h i f tgmax [ dimen ] = gmax [ dimen ] + −1 ∗ ( gmin [ dimen ] )

r e t u r n gmax

# Dete rm ines t he PHYSICAL c o o r d i n a t e s o f e v e r y node based on t h e i r# LOGICAL c o o r d i n a t e s . S i n c e nodes a r e not o f a f i x e d s i z e , t h i s f u n c t i o n# e n s u r e s t h a t nodes do not o v e r l a p each o t h e r .d e f g r i d l a y o u t ( s e l f , draw =0):

# S h i f t t he graph to t he ( 0 , 0 ) o r i g i n , and o b t a i n the o v e r a l l s i z egmax = s e l f . a d j u s t m i n m a x ( )

# C r e a t e two empty n e s t e d l i s t s to s t o r e v a l u e s i n t orowcolmax = [ [ ] , [ ] ] # t he maximum node s i z e i n each row or columnrowcolsum = [ [ ] , [ ] ] # t he r u n n i n g sum o/ t s i z e s o f each row or columnf o r dimen i n [ 0 , 1 ] : # do x then y a x i s

f o r x i n x r a n g e ( gmax [ dimen ] + 1 ) :rowcolmax [ dimen ] . append ( 0 )rowcolsum [ dimen ] . append ( 0 )

# d e t e r m i n e t he maximum node s i z e i n each row and columnf o r dimen i n [ 0 , 1 ] : # do x then y a x i s

f o r node i n s e l f . n o d e L i s t :nodeat = node . t p t [ dimen ]rowcolmax [ dimen ] [ nodeat ] = (

CHAPTER 10. GRAPH LAYOUT ALGORITHM 178

max ( node . s p t [ dimen ] , rowcolmax [ dimen ] [ nodeat ] ) )

# S t o r e a r u n n i n g t o t a l o f each row or column s i z e , add ing padd ing# a l o n g t he way .# row ( x ) = sum ( row ( 1 ) . . . row ( x−1 ) ) + 2 ∗ ( padd ing ∗ x )o v e r a l l s u m = [ 0 , 0 ]f o r dimen i n [ 0 , 1 ] : # do x then y a x i s

sum = RE CANVAS PAD [ dimen ]f o r x i n x r a n g e ( gmax [ dimen ] + 1 ) :

sum = sum + ( rowcolmax [ dimen ] [ x ] / 2 ) + RE PAD [ dimen ]rowcolsum [ dimen ] [ x ] = sumsum = sum + ( rowcolmax [ dimen ] [ x ] / 2 ) + RE PAD [ dimen ]

o v e r a l l s u m [ dimen ] = sum + RE CANVAS PAD [ dimen ]

# S t o r e t he c o r r e s p o n d i n g PHYSICAL c o o r d i n a t e s w i t h each nodef o r dimen i n [ 0 , 1 ] :

f o r node i n s e l f . n o d e L i s t :node . npt [ dimen ] = rowcolsum [ dimen ] [ node . t p t [ dimen ] ]

s e l f [ ’scrollregion’ ] = s e l f . bbox (’all’ )

# Animates a l l t he nodes from t h e i r o l d PHYSICAL p o s i t i o n to t h e i r# new PHYSICAL p o s i t i o nd e f an imate ( s e l f ) :

# I t e r a t i o n f o r each frame o f the a n i m a t i o nf o r f a c t o r i n x r a n g e (RE ANIMATION FRAMES ) :

f = ( f a c t o r / RE ANIMATION FRAMES)f o r node i n s e l f . n o d e L i s t :

node . m o v e b y f a c t o r ( f )s e l f . master . update ( ) # update T k i n t e r window

# We’ r e done a n i m a t i n g , so update a l l the o l d c o o r d i n a t e s# to t he new c o o r d i n a t e sf o r node i n s e l f . n o d e L i s t :

node . f i n a l i z e c o o r d ( )d e b u g p r i n t ( node , ":" , node . t p t )

10.4.2 Nodes.py

Code

# V i s u a l Pe log F a l l 1 9 9 9 M i c h a e l Droettboom mdboom@mail . com############################################################# Nodes . py## Node c l a s s e s

# V i s u a l Pe log i m p o r t sfrom U t i l i m p o r t ∗from C o n s t a n t s i m p o r t ∗i m p o r t Canvas I tems , R u l e E d i t o r

CHAPTER 10. GRAPH LAYOUT ALGORITHM 179

# T k i n t e r i m p o r t si m p o r t Canvas

# Standard l i b r a r y i m p o r t si m p o r t math

################################################### V i s u a l O b j e c t## Any o b j e c t t h a t has a v i s u a l r e p r e s e n t a t i o n# on t he r u l e e d i t o r canvas i n h e r i t s from V i s u a l O b j e c tc l a s s V i s u a l O b j e c t :

s p t = ( 3 2 , 3 2 ) # s i z e o f o b j e c t

#−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−# I n i t i a l i z a t i o n f u n c t i o n sd e f i n i t ( s e l f ) :

s e l f . pt = [ 0 , 0 ] # A b s o l u t e c o o r d i n a t e o f o b j e c ts e l f . npt = [ 0 , 0 ] # New c o o r d i n a t e o f o b j e c t to an imate tos e l f . s e l e c t e d = FALSEs e l f . h i g h l i g h t e d = FALSE

d e f v i s u a l i z e ( s e l f ) :s e l f . v i s u a l = [ ]

d e f d e v i s u a l i z e ( s e l f ) :f o r i tem i n s e l f . v i s u a l :

i tem . d e l e t e ( )

#−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−# User f u n c t i o n sd e f u p d a t e v i s u a l ( s e l f ) :

f o r e l e m e nt i n s e l f . v i s u a l :e l e m e nt . update ( )

d e f m o v e v i s u a l ( s e l f ) :f o r e l e m e nt i n s e l f . v i s u a l :

e l e m e nt . m o v e t o f i n a l ( )

d e f m o v e b y f a c t o r ( s e l f , f a c t o r ) :f o r e l e m e nt i n s e l f . v i s u a l :

e l e m e nt . m o v e b y f a c t o r ( f a c t o r )

################################################### Gener icNode## Any o b j e c t t h a t must be p o s i t i o n e d on the graph# u s i n g t he graph l a y o u t a l g o r i t h mc l a s s Gener icNode ( V i s u a l O b j e c t ) :

CHAPTER 10. GRAPH LAYOUT ALGORITHM 180

#−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−# I n i t i a l i z a t i o n f u n c t i o n sEQUALITY TYPE = ""COMPARISON TYPE = ""n o d e t y p e = ’generic’

a , b = None , None

d e f i n i t ( s e l f , master , t e x t="-" , e q u a l = ( [ ] , [ ] ) ,g r e a t e r = ( [ ] , [ ] ) , l e s s = ( [ ] , [ ] ) , n e a r = [ ] ) :

V i s u a l O b j e c t . i n i t ( s e l f )

# R e f e r e n c e to t he r u l e e d i t o r c anvas t h a t owns t h i s nodes e l f . master = master

s e l f . t e x t = t e x t # l a b e l to be drawn on nodes e l f . t p t = [ 0 , 0 ] # T o p o l o g i c a l c o o r d i n a t e o f node

# c o n s t r a i n t ss e l f . e q u a l = e q u a ls e l f . l e s s = l e s ss e l f . g r e a t e r = g r e a t e rs e l f . n e a r = n e a r

# t he d i r e c t i o n i n which the l a s t r e s o l v e o p e r a t i o n# bounced−out a n o t h e r nodes e l f . l a s t r e s o l v e = 2

# add t h i s node to th e r u l e e d i t o r c anvass e l f . master . add node ( s e l f )

# c r e a t e a l l t he v i s u a l e l e m e n t s r e l a t e d to t h i s nodes e l f . v i s u a l i z e ( )

d e f d e l e t e ( s e l f ) :# remove t he v i s u a l e l e m e n t s from the c anvass e l f . d e v i s u a l i z e ( )# remove s e l f from node l i s ts e l f . master . remove node ( s e l f )

# s t r i n g r e p r e s e n t a t i o n o f t h i s node . D i s p l a y e d i n t he# s t a t u s bar when t he node i s h i g h l i g h t e dd e f r e p r ( s e l f ) :

r e t u r n s e l f . t e x t

#−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−# Event h a n d l e r s

# When t he button i s d e p r e s s e d , s e l f i s the s t a r t i n g node# o f t he drag o p e r a t i o nd e f b u t t o n p r e s s ( s e l f , a r g s ) :

CHAPTER 10. GRAPH LAYOUT ALGORITHM 181

s e l f . master . s e t s t a r t n o d e ( s e l f )

# When t he button i s r e l e a s e d , we must f i n d the node t h a t i t# was r e l e a s e d on to d e t e r m i n e the f i n i s h i n g node o f t he drag# o p e r a t i o nd e f b u t t o n r e l e a s e ( s e l f , a r g s ) :

s e l f . master . s e t f i n i s h n o d e ( s e l f . master . f i n d n o d e ( a r g s . x , a r g s . y ) )s e l f . master . r u n t o o l ( )s e l f . master . s e t s t a r t n o d e ( None )s e l f . master . s e t f i n i s h n o d e ( None )

d e f h i g h l i g h t ( s e l f , a r g s ) :p a s s

d e f u n h i g h l i g h t ( s e l f , a r g s ) :p a s s

d e f s e l e c t ( s e l f ) :p a s s

d e f u n s e l e c t ( s e l f ) :p a s s

#−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−# Graph Layout A l g o r i t h m f u n c t i o n s

# r e t u r n s t he a v e r a g e LOGICAL p o s i t i o n o f the nodesd e f f i n d a v e r a g e ( s e l f , nodes ) :

i f nodes = = [ ] :r e t u r n [ RE MAXGRID , RE MAXGRID ]

e l s e :sum = [ 0 , 0 ]f o r dimen i n [ 0 , 1 ] : # x then y a x i s

p r i n t nodesf o r node i n nodes :

# b u i l d up sum o f a x i s c o o r d i n a t e sp r i n t "Summing" , nodesum [ dimen ] = sum [ dimen ] + node . t p t [ dimen ]

# d i v i d e by t he number o f nodes# r e s u l t must be an i n t e g e r ( LOGICAL c o o r d i n a t e s a r e# a l w a y s i n t e g e r s )sum [ dimen ] = i n t ( math . c e i l ( sum [ dimen ] / l e n ( nodes ) ) )

r e t u r n sum

# Moves t he node to t he a v e r a g e LOGICAL p o s i t i o n o f t he nodes# s p e c i f i e d by t he ’ n e a r ’ c o n s t r a i n t , i f any .d e f g o t o n e a r ( s e l f ) :

avg = s e l f . f i n d a v e r a g e ( s e l f . n e a r )i f avg ! = [ RE MAXGRID , RE MAXGRID ] :

f o r dimen i n [ 0 , 1 ] :s e l f . t p t [ dimen ] = avg [ dimen ]

d e b u g p r i n t ( s e l f , "going to average of:" ,s e l f . n e a r , "=" , s e l f . t p t [ 0 ] , s e l f . t p t [ 1 ] )

CHAPTER 10. GRAPH LAYOUT ALGORITHM 182

# A s s i g n s t h i s node a l o g i c a l c o o r d i n a t e based on i t s r e l a t i o n s h i p# to o t h e r nodes s p e c i f i e d by the c o n s t r a i n t s ’ g r e a t e r ’ , ’ l e s s ’ and ’ e q u a l ’ .# C o n s t r a i n t s a r e a l w a y s s a t i s f i e d by moving nodes outward ( SE ) . Th i s# makes t he g r a p h s somewhat l e s s v i s u a l−s p a c e e f f i c i e n t , but e l i m i n a t e s# f u t u r e c o n f l i c t sd e f t o p o l o g i c a l s o r t ( s e l f , dimen , tmin , tmax ) :

# Ensure t h i s node i n between tmin and tmaxs e l f . t p t [ dimen ] = min ( max ( s e l f . t p t [ dimen ] , tmin ) , tmax )

s e l f . s o l v e e q u a l c o n s t r a i n t ( dimen )s e l f . s o l v e g r e a t e r c o n s t r a i n t ( dimen )s e l f . s o l v e l e s s c o n s t r a i n t ( dimen )

d e b u g p r i n t ( s e l f . t e x t , "sorted to:" , s e l f . t p t [ 0 ] , s e l f . t p t [ 1 ] )

# This node must have th e same l o g i c a l c o o r d i n a t e as e v e r y node l i s t e d i n i t s# ’ e q u a l ’ c o n s t r a i n t .d e f s o l v e e q u a l c o n s t r a i n t ( s e l f , dimen ) :

f o r e q u a l i n s e l f . e q u a l [ dimen ] : # For each ’ e q u a l ’ c o n s t r a i n t# I f t h i s node i s c u r r e n t l y not meet ing i t s e q u a l c o n s t r a i n t . . .i f e q u a l . t p t [ dimen ] ! = s e l f . t p t [ dimen ] :

d e b u g p r i n t ("Equal constraint" )# then move t he l e s s e r node (NW) outward ( SE ) to s a t i s f y t he# c o n s t r a i n ti f e q u a l . t p t [ dimen ] < s e l f . t p t [ dimen ] :

e q u a l . t o p o l o g i c a l s o r t ( dimen , s e l f . t p t [ dimen ] ,s e l f . t p t [ dimen ] )

e l s e :s e l f . t o p o l o g i c a l s o r t ( dimen , e q u a l . t p t [ dimen ] ,

e q u a l . t p t [ dimen ] )

# This node must have a g r e a t e r ( SE ) l o g i c a l c o o r d i n a t e than a l l t he nodes# l i s t e d i n i t s ’ g r e a t e r ’ c o n s t r a i n tdef s o l v e g r e a t e r c o n s t r a i n t ( s e l f , dimen ) :

f o r g r e a t e r i n s e l f . g r e a t e r [ dimen ] : # For each ’ g r e a t e r ’ c o n s t r a i n t# I f t h i s node i s not meet ing i t s ’ g r e a t e r ’ c o n s t r a i n t . . .i f s e l f . t p t [ dimen ] <= g r e a t e r . t p t [ dimen ] :

d e b u g p r i n t ("Greater constraint" )# move i t so i t i s g r e a t e rs e l f . t o p o l o g i c a l s o r t ( dimen , g r e a t e r . t p t [ dimen ] + 1 ,

RE MAXGRID)

# This node must have a l e s s e r (NW) l o g i c a l c o o r d i n a t e than a l l t he nodes# l i s t e d i n i t s ’ l e s s e r ’ c o n s t r a i n tdef s o l v e l e s s c o n s t r a i n t ( s e l f , dimen ) :

f o r l e s s i n s e l f . l e s s [ dimen ] : # For each ’ l e s s ’ c o n s t r a i n t# I f t he c o n s t r a i n t i s not b e i n g s a t i s f i e d . . .i f s e l f . t p t [ dimen ] > ] = l e s s . t p t [ dimen ] :

# . . . move the o t h e r node outward so i t i s g r e a t e r than t h i s nodel e s s . t o p o l o g i c a l s o r t ( dimen , s e l f . t p t [ dimen ] + 1 ,

RE MAXGRID)

CHAPTER 10. GRAPH LAYOUT ALGORITHM 183

# D e c i d e s where to move nodes when two nodes occupy t he same# LOGICAL c o o r d i n a t e based on the a v e r a g e p o s i t i o n o f t he# nodes t h a t t h i s node i s c o n s t r a i n e d to be ’ n e a r . ’r e s o l v e o p t i o n s d e f = [

(’selfavgy > node2avgy’ , # Up’node2.topological_sort(1, RE_MINGRID, self.tpt[1] - 1)’ ) ,

(’selfavgx < node2avgx’ , # R i g h t’node2.topological_sort(0, node2.tpt[0] + 1, RE_MAXGRID)’ ) ,

(’selfavgy < node2avgy’ , # Down’node2.topological_sort(1, node2.tpt[1] + 1, RE_MAXGRID)’ ) ]

# p r e−c o m p i l e t h e s e o p t i o n sr e s o l v e o p t i o n s = [ ]f o r o p t i o n i n r e s o l v e o p t i o n s d e f :

e x p r e s s i o n = c o m p i l e ( o p t i o n [ 0 ] , ’dynamic code’ , ’eval’ )s t a t e m e n t = c o m p i l e ( o p t i o n [ 1 ] , ’dynamic code’ , ’exec’ )r e s o l v e o p t i o n s . append ( ( e x p r e s s i o n , s t a t e m e n t ) )

d e f r e s o l v e ( s e l f , node2 ) :s e l f a v g x , s e l f a v g y = s e l f . f i n d a v e r a g e ( s e l f . n e a r )node2avgx , node2avgy = s e l f . f i n d a v e r a g e ( node2 . n e a r )

# Try a l l t he p o s s i b l e o p t i o n s i n o r d e r , s t a r t i n g w i t h# t he d i r e c t i o n a f t e r s e l f . l a s t r e s o l v er e s o l v e d = FALSEf o r d i r i n rang e ( 0 , l e n ( s e l f . r e s o l v e o p t i o n s ) ) :

go = ( d i r + s e l f . l a s t r e s o l v e + 1) % 3i f e v a l ( s e l f . r e s o l v e o p t i o n s [ go ] [ 0 ] ) :

e x e c s e l f . r e s o l v e o p t i o n s [ go ] [ 1 ]s e l f . l a s t r e s o l v e = gor e s o l v e d = TRUEb r e a k

# i f none o f t he o p t i o n s were taken , j u s t p i c k the# f i r s t onei f not r e s o l v e d :

go = ( s e l f . l a s t r e s o l v e + 1) % 3e x e c s e l f . r e s o l v e o p t i o n s [ go ] [ 1 ]s e l f . l a s t r e s o l v e = go

# Updates t he new p o s i t i o n i n t o the o l d p o s i t i o nd e f f i n a l i z e c o o r d ( s e l f ) :

i f ( s e l f . npt ! = s e l f . pt ) :s e l f . pt [ 0 ] , s e l f . pt [ 1 ] = s e l f . npt [ 0 ] , s e l f . npt [ 1 ]s e l f . m o v e v i s u a l ( )

################################################### H i g h t l i g h t a b l e N o d e#

CHAPTER 10. GRAPH LAYOUT ALGORITHM 184

# s u p e r c l a s s o f nodes t h a t can be h i g h l i g h t e d# ( become b o l d when th e mouse h o v e r s )c l a s s H i g h l i g h t a b l e N o d e :

d e f h i g h l i g h t ( s e l f , a r g s ) :s e l f . h i g h l i g h t e d = TRUEs e l f . u p d a t e v i s u a l ( )s e l f . master . d e s c r i b e n o d e ( s e l f )s e l f . master . s e t c u r s o r (’hand2’ )

d e f u n h i g h l i g h t ( s e l f , a r g s ) :s e l f . h i g h l i g h t e d = FALSEs e l f . u p d a t e v i s u a l ( )s e l f . master . u n d e s c r i b e n o d e ( )s e l f . master . r e s t o r e c u r s o r ( )

################################################### S e l e c t a b l e N o d e## s u p e r c l a s s o f nodes t h a t can be s e l e c t e d u s i n g# t he S e l e c t i o n t o o l .c l a s s S e l e c t a b l e N o d e :

d e f s e l e c t ( s e l f ) :s e l f . s e l e c t e d = TRUEs e l f . u p d a t e v i s u a l ( )s e l f . master . keyboard . s e t c a l l b a c k ( s e l f . k e y b o a r d c a l l b a c k )s e l f . i n i t e d i t w i d g e t s ( )

d e f u n s e l e c t ( s e l f ) :s e l f . s e l e c t e d = FALSEs e l f . u p d a t e v i s u a l ( )s e l f . master . keyboard . s e t c a l l b a c k ( None )s e l f . d e s t r o y e d i t w i d g e t s ( )

d e f i n i t e d i t w i d g e t s ( s e l f ) :p a s s

d e f d e s t r o y e d i t w i d g e t s ( s e l f ) :p a s s

d e f k e y b o a r d c a l l b a c k ( s e l f , n o t e L i s t ) :p a s s

################################################### NoteNode## The s t a t i c note nodes i n th e graphc l a s s NoteNode ( H i g h l i g h t a b l e N o d e , Gener icNode ) :

EQUALITY TYPE = "pitch"COMPARISON TYPE = "pitch"n o d e t y p e = ’note’

CHAPTER 10. GRAPH LAYOUT ALGORITHM 185

s p t = ( 1 6 , 1 6 )

d e f i n i t ( s e l f , master , m e t a v a r i a b l e ,prevX=None , prevY=None , box=FALSE ) :

# The name o f t he m e t a v a r i a b l e t h i s node r e p r e s e n t ss e l f . m e t a v a r i a b l e = m e t a v a r i a b l e

# I s t h i s t he c u r r e n t node ?s e l f . box = box

# The prevX and prevY arguments a r e c o n v e r t e d i n t o l e s s c o n s t r a i n t si f prevX == None :

prevX = [ ]e l s e :

prevX = [ prevX ]

i f prevY == None :prevY = [ ]

e l s e :prevY = [ prevY ]

Gener icNode . i n i t ( s e l f , master ,t e x t=m e t a v a r i a b l e ,g r e a t e r =(prevX , prevY ) ,e q u a l =(prevY , prevX ) )

d e f v i s u a l i z e ( s e l f ) :i f s e l f . box :

s e l f . v i s u a l = [Canvas I tems . So l idNoteBi tmap ( s e l f ) ]

e l s e :s e l f . v i s u a l = [

Canvas I tems . Hol lowNoteBitmap ( s e l f ) ]

################################################### B i n a r y R e l a t i o n## A g e n e r i c b i n a r y r e l a t i o n node from which o t h e r# b i n a r y o p e r a t o r s a r e d e r i v e dc l a s s B i n a r y R e l a t i o n ( H i g h l i g h t a b l e N o d e , S e l e c t a b l e N o d e , Gener icNode ) :

bitmap = ’binary.xbm’# C r e a t e s a new B i n a r y R e l a t i o n between nodes a and bd e f i n i t ( s e l f , master , a , b , t e x t="-" ) :

s e l f . a , s e l f . b = a , bl e s s = [ [ ] , [ ] ]g r e a t e r = [ [ ] , [ ] ]

# R e l a t i o n s h i p s between two n o t e s i n the same row s h o u l d# be c o n s t r a i n e d so t h e y don ’ t c r o s s the o t h e r rowi f a . t p t [1 ] == b . t p t [ 1 ] : # H o r i z o n t a l r e l a t i o n s h i p

i f a . t p t [1 ] == master . r u l e . Top row . t p t [ 1 ] :

CHAPTER 10. GRAPH LAYOUT ALGORITHM 186

l e s s = [ [ ] , [ master . r u l e . Bottom row ] ]e l s e :

g r e a t e r = [ [ ] , [ master . r u l e . Top row ] ]

# This node s h o u l d be c o n s t r a i n e d between the o t h e r# two nodesf o r dimen i n [ 0 , 1 ] :

i f a . t p t [ dimen ] ! = b . t p t [ dimen ] :i f a . t p t [ dimen ] < b . t p t [ dimen ] :

g r e a t e r [ dimen ] . append ( a )l e s s [ dimen ] . append ( b )

e l s e :g r e a t e r [ dimen ] . append ( b )l e s s [ dimen ] . append ( a )

Gener icNode . i n i t ( s e l f , master , t e x t=t e x t ,g r e a t e r=g r e a t e r ,l e s s=l e s s ,n e a r =[a , b ] )

# Set t he s t a r t i n g p o s i t i o n to the a v e r a g e o f t he nodes a and bf o r dimen i n [ 0 , 1 ] :

s e l f . pt [ dimen ] = ( a . pt [ dimen ] + b . pt [ dimen ] ) / 2

def v i s u a l i z e ( s e l f ) :s e l f . v i s u a l = [

Canvas I tems . Edge ( s e l f , s e l f , s e l f . a ) ,Canvas I tems . Edge ( s e l f , s e l f , s e l f . b ) ,Canvas I tems . NodeRectang le ( s e l f ) ,Canvas I tems . L a b e l ( s e l f ) ,Canvas I tems . NodeBitmap ( s e l f , s e l f . b itmap ) ]

################################################### U n a r y R e l a t i o n#c l a s s U n a r y R e l a t i o n ( H i g h l i g h t a b l e N o d e , S e l e c t a b l e N o d e , Gener icNode ) :

bitmap = ’unary.xbm’

def i n i t ( s e l f , master , a , t e x t="-" ) :s e l f . a = a

# I f t h i s node i s c o n n e c t e d to a notenode i n t he top row ,# we don ’ t want t h i s node to go below the bottom row , and# v i c e v e r s ai f a . t p t [1 ] == master . r u l e . Top row . t p t [ 1 ] :

l e s s = [ [ ] , [ master . r u l e . Bottom row ] ]e l s e :

g r e a t e r = [ [ ] , [ master . r u l e . Top row ] ]

Gener icNode . i n i t ( s e l f , master , t e x t=t e x t ,

CHAPTER 10. GRAPH LAYOUT ALGORITHM 187

n e a r =[a ] )

# s e t t he s t a r t i n g p o s i t i o n to t h a t o f node af o r dimen i n [ 0 , 1 ] :

s e l f . pt [ dimen ] = a . pt [ dimen ]

def v i s u a l i z e ( s e l f ) :s e l f . v i s u a l = [

Canvas I tems . Edge ( s e l f , s e l f , s e l f . a ) ,Canvas I tems . NodeRectang le ( s e l f ) ,Canvas I tems . L a b e l ( s e l f ) ,Canvas I tems . NodeBitmap ( s e l f , s e l f . b itmap ) ]

10.4.3 CanvasItems.py

Code

# V i s u a l Pe log F a l l 1 9 9 9 M i c h a e l Droettboom mdboom@mail . com############################################################# Canvas I tems . py## V a r i o u s g e o m e t r i c i t e m s t h a t a r e p l a c e d on t he# Rule E d i t o r canvas## A l l o f t h e s e i t e m s a r e i n h e r i t e d from t h e i r c o r r e s p o n d i n g# T k i n t e r c l a s s e s , but have been e x t e n d e d to automate# t h e i r r e l a t i o n s h i p to nodes i n the graph l a y o u t a l g o r i t h m

# V i s u a l Pe log i m p o r t sfrom U t i l i m p o r t ∗from C o n s t a n t s i m p o r t ∗

# T k i n t e r i m p o r t si m p o r t Canvasfrom TkConstants i m p o r t ∗

################################################### CanvasItem## The base c l a s s e s f o r a l l c l a s s e s i n t h i s modulec l a s s CanvasItem :

d e f i n i t ( s e l f , node ) :# The node t h a t t h i s canvas i tem b e l o n g s tos e l f . node = node

# Move t he i tem to i t s c o r r e c t p o s i t i o ns e l f . m o v e t o f i n a l ( )

# Update any c o l o r o r a p p e a r a n c e a t t r i b u t e ss e l f . update ( )

# Bind e v e n t s to t he c o r r e s p o n d i n g node

CHAPTER 10. GRAPH LAYOUT ALGORITHM 188

s e l f . b i n d ( s e q u e n c e="<Enter>" ,command=s e l f . node . h i g h l i g h t )

s e l f . b i n d ( s e q u e n c e="<Leave>" ,command=s e l f . node . u n h i g h l i g h t )

s e l f . b i n d ( s e q u e n c e="<ButtonRelease>" ,command=s e l f . node . b u t t o n r e l e a s e )

s e l f . b i n d ( s e q u e n c e="<ButtonPress>" ,command=s e l f . node . b u t t o n p r e s s )

# Move t h i s i tem to t he l o c a t i o n o f the noded e f m o v e t o f i n a l ( s e l f ) :

s e l f . move ( s e l f . node . pt [ 0 ] , s e l f . node . pt [ 1 ] )

# Move between t he o l d and new p o s i t i o n o f the node# by a g i v e n f a c t o r . Used f o r a n i m a t i o n .d e f m o v e b y f a c t o r ( s e l f , f a c t o r ) :

s e l f . move (( ( s e l f . node . npt [ 0 ] − s e l f . node . pt [ 0 ] )∗ f a c t o r + s e l f . node . pt [ 0 ] ) ,

( ( s e l f . node . npt [ 1 ] − s e l f . node . pt [ 1 ] )∗ f a c t o r + s e l f . node . pt [ 1 ] ) )

# Move t he i tem to a g i v e n p o i n td e f move ( s e l f , x , y ) :

s e l f . c o o r d s ( [ ( x , y ) ] )

# Update any c o l o r o r a p p e a r a n c e a t t r i b u t e s based on# t he c u r r e n t s t a t e o f th e c o r r e s p o n d i n g noded e f update ( s e l f ) :

p a s s

# Does some c o l o u r s e l e c t i o n magicd e f g e t c o l o r s ( s e l f ) :

i f s e l f . node . s e l e c t e d :i f s e l f . node . h i g h l i g h t e d :

o u t l i n e = RE COLOR HIGHSELECTe l s e :

o u t l i n e = RE COLOR SELECTEDf i l l = RE COLOR NODE SELECTEDt e x t = RE COLOR TEXT SELECTEDwidth = 2

e l s e :i f s e l f . node . h i g h l i g h t e d :

o u t l i n e = RE COLOR HIGHLIGHTEDwidth = 2t e x t = o u t l i n e

e l s e :o u t l i n e = RE COLOR NORMALwidth = 1t e x t = RE COLOR TEXT

f i l l = RE COLOR NODE

CHAPTER 10. GRAPH LAYOUT ALGORITHM 189

r e t u r n o u t l i n e , w idth , f i l l , t e x t

################################################### Bitmap#c l a s s Bitmap ( CanvasItem , Canvas . Bitmap ) :

bitmap = "default.xbm"

d e f i n i t ( s e l f , node ) :Canvas . Bitmap . i n i t (

s e l f , node . master ,0 , 0 ,bitmap=’@images/’+s e l f . b itmap )

CanvasItem . i n i t ( s e l f , node )

d e f update ( s e l f ) :x , y , z , c o l o r = s e l f . g e t c o l o r s ( )s e l f [ ’foreground’ ] = c o l o r

c l a s s Hol lowNoteBitmap ( Bitmap ) :bitmap = "hollownote.xbm"

c l a s s So l idNoteBi tmap ( Bitmap ) :bitmap = "solidnote.xbm"

c l a s s NodeBitmap ( Bitmap ) :d e f i n i t ( s e l f , node , bitmap ) :

s e l f . b itmap = bitmapBitmap . i n i t ( s e l f , node )

################################################### NodeRectang le#c l a s s NodeRectang le ( CanvasItem , Canvas . R e c t a n g l e ) :

d e f i n i t ( s e l f , node ) :Canvas . R e c t a n g l e . i n i t (

s e l f , node . master ,0 , 0 , 0 , 0 )

CanvasItem . i n i t ( s e l f , node )

d e f move ( s e l f , x , y ) :c1x = x − ( s e l f . node . s p t [ 0 ] / 2 )c1y = y − ( s e l f . node . s p t [ 1 ] / 2 )c2x = c1x + s e l f . node . s p t [ 0 ]c2y = c1y + s e l f . node . s p t [ 1 ]s e l f . c o o r d s ( [ ( c1x , c1y ) , ( c2x , c2y ) ] )

d e f update ( s e l f ) :o u t l i n e , w idth , f i l l , x = s e l f . g e t c o l o r s ( )s e l f [ ’fill’ ] = f i l ls e l f [ ’outline’ ] = o u t l i n e

CHAPTER 10. GRAPH LAYOUT ALGORITHM 190

s e l f [ ’width’ ] = width

################################################### L a b e l#c l a s s L a b e l ( CanvasItem , Canvas . CanvasText ) :

d e f i n i t ( s e l f , node ) :Canvas . CanvasText . i n i t (

s e l f , node . master ,0 , 0 ,j u s t i f y =’center’ ,f i l l =RE COLOR TEXT)

CanvasItem . i n i t ( s e l f , node )

d e f move ( s e l f , x , y ) :s e l f . c o o r d s ( [ ( x , y + ( s e l f . node . s p t [ 1 ] / 2 ) − 5 ) ] )

d e f update ( s e l f ) :x , y , z , c o l o r = s e l f . g e t c o l o r s ( )s e l f . c o n f i g ( t e x t=s e l f . node . t e x t )

################################################### Edge#c l a s s Edge ( CanvasItem , Canvas . L i n e ) :

d e f i n i t ( s e l f , node , a , b ) :Canvas . L i n e . i n i t (

s e l f , node . master ,0 , 0 , 0 , 0 )

s e l f . l o w e r ( )s e l f . a = as e l f . b = bCanvasItem . i n i t ( s e l f , node )

d e f m o v e t o f i n a l ( s e l f ) :x1 , y1 = t u p l e ( s e l f . a . pt )x2 , y2 = t u p l e ( s e l f . b . pt )s e l f . move ( x1 , y1 , x2 , y2 )

d e f m o v e b y f a c t o r ( s e l f , f a c t o r ) :s e l f . move (

( s e l f . a . npt [ 0 ] − s e l f . a . pt [ 0 ] ) ∗ f a c t o r + s e l f . a . pt [ 0 ] ,( s e l f . a . npt [ 1 ] − s e l f . a . pt [ 1 ] ) ∗ f a c t o r + s e l f . a . pt [ 1 ] ,( s e l f . b . npt [ 0 ] − s e l f . b . pt [ 0 ] ) ∗ f a c t o r + s e l f . b . pt [ 0 ] ,( s e l f . b . npt [ 1 ] − s e l f . b . pt [ 1 ] ) ∗ f a c t o r + s e l f . b . pt [ 1 ] )

d e f move ( s e l f , x1 , y1 , x2 , y2 ) :s e l f . c o o r d s ( [ ( x1 , y1 ) , ( x2 , y2 ) ] )

d e f update ( s e l f ) :o u t l i n e , w idth , f i l l , x = s e l f . g e t c o l o r s ( )

CHAPTER 10. GRAPH LAYOUT ALGORITHM 191

s e l f [ ’fill’ ] = o u t l i n es e l f [ ’width’ ] = width

11A collection of custom

Megawidgets implemented inPython/Tkinter

One of the unexpected bottlenecks in the Visual Pelog project was the number ofcustom megawidgets1 that were required. While pure Tcl/Tk is now quite matureand has a number of ready-made megawidgets bundled with the distribution andavailable on the internet, Python/Tkinter remains somewhat lacking in this respect.The most promising attempt to remedy this situation is Pmw (Python Megawid-gets).2 While this project aims to fill some holes, it does not yet offer many of thestandard types of controls one expects from a fully mature GUI toolkit.

The megawidgets that were implemented specifically for this project were:

• Tree widget: a heirarchical tree display similar to that found in MicrosoftWindows Explorer.

• Help browser: an on-line help browser that supports a very tiny subset ofHTML.

• On-screen musical keyboard: a standard Western musical keyboard that canbe used to display and enter pitch-related information.

1Megawidgets are user-interface elements implemented in the very high-level language itself.They are made up of the basic widgets that come ‘standard’ with of the GUI system.

2Python Megawidgets http://www.dscpl.com.au/pmw/

192

CHAPTER 11. CUSTOM MEGAWIDGETS 193

11.1 Tree Widget3

The tree widget as implemented here is quite general and is well-suited to extentionusing object-oriented inheritance.

11.1.1 End user usage

Figure 11.1: An example tree widget.

The tree widget displays structured information in a vertically-oriented heirar-chical tree (Figure 11.1). This type of widget should be familiar to users of MicrosoftWindows, as it mimics the behaviour of Microsoft Windows Explorer as closely aspossible.

Nodes appear as two types:

Leaf: A node that contains data. (In the case of Visual Pelog, it contains a rule.)When the node is double-clicked on or the Enter / Return key is pressed, thedata in the node is launched or opened for editing.

Branch: A branch node contains other nodes. It can either be open (display-ing all its children nodes) or closed. Clicking on the open/close box togglesthe open/close state of the branch.

Nodes are selected by clicking on them. A selected node appears inside a box (Figure11.2. The selected node can be dragged to other locations in the heirarchy, or itcan be deleted by pressing the Delete key.

3A fairly exhaustive internet-search revealed no ready-made general purpose tree widgets ofthis type implemented in Python. Ironically, within days of creating my own implemntation fromscratch, two separate tree widgets appeared on the Python language website. www.python.org

CHAPTER 11. CUSTOM MEGAWIDGETS 194

Figure 11.2: The appearance of a selected node.

11.1.2 Developer usage

It is important to note the distinction between the class that creates a Tkinterwidget, TreeWidget, and the class that handles the data in the widget, TreeNode.

TreeWidget class

The TreeWidget class inherits from the Tkinter.Canvas widget. To create a newTreeWidget, simply use the default constructor:newTree = Tree . TreeWidget ( master )

where master is the window that will own the TreeWidget.

TreeNode

To add nodes to the TreeWidget, you must first get the root TreeNode from theTreeWidget:r o o t = newTree . g e t n o d e ( )

Then, nodes can be arbitrarily added or deleted to the heirarchy using the followingfunctions. All changes made to the TreeNode structure are automatically reflectedin the TreeWidget. Note that TreeNode is completely polymorphic: leaf nodes cancontain any type of data. The text displayed to the user on the TreeWidget is itstext representation (i.e. returned by the built-in repr() function).

node.append(data) Adds a leaf containing data to the list node’schildren.

node a.append node(node b) Adds the arbitrary sub-tree node b to the listof node a’s children.

node.remove(data) Removes a node containing data from the listof node’s children.

node a.remove node(node b) Removes the arbitrary sub-tree node b fromthe list of node a’s children.

When the Enter key is pressed, a leaf node is launched. Launching could entailopening the data, editing the data or performing some other action. In order tosupport this functionality, the data type stored at a leaf must contain a launch()function. If the data type does not contain a launch() function, the TreeWidgetgracefully does nothing.

11.1.3 Tree.py

Code

CHAPTER 11. CUSTOM MEGAWIDGETS 195

# V i s u a l Pe log F a l l 1 9 9 9 M i c h a e l Droettboom mdboom@mail . com############################################################# Tree . py## A g e n e r a l−p u r p o s e t r e e w i d g e t f o r T k i n t e r

from U t i l i m p o r t ∗

# T k i n t e r i m p o r t si m p o r t T k i n t e r , Canvasfrom TkConstants i m p o r t ∗from C o n s t a n t s i m p o r t ∗

#−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−# C o n s t a n t sY STEP = 2X STEP = 18

FONT = ’-adobe-helvetica-medium-r-normal-*-11-80-100-100-p-56-iso8859-1’LINE = 5OPEN BOX = 5ICON = 22TEXT = 35

OPENBM MASKDATA = """#define solid_width 9\n#define solid_height 9s t a t i c u n s i g n e d c h a r s o l i d b i t s [ ] = {0 x f f , 0 x01 , 0 x f f , 0 x01 , 0 x f f , 0 x01 , 0 x f f , 0 x01 , 0 x f f , 0 x01 , 0 x f f , 0 x01 ,0 x f f , 0 x01 , 0 x f f , 0 x01 , 0 x f f , 0 x01} ; """

OPENBM DATA = """#define open_width 9\n#define open_height 9s t a t i c u n s i g n e d c h a r o p e n b i t s [ ] = {0 x f f , 0 x01 , 0 x01 , 0 x01 , 0 x01 , 0 x01 , 0 x01 , 0 x01 , 0 x7d , 0 x01 , 0 x01 , 0 x01 ,0 x01 , 0 x01 , 0 x01 , 0 x01 , 0 x f f , 0 x01} ; """

CLOSEDBM DATA = """#define closed_width 9\n#define closed_height 9s t a t i c u n s i g n e d c h a r c l o s e d b i t s [ ] = {0 x f f , 0 x01 , 0 x01 , 0 x01 , 0 x11 , 0 x01 , 0 x11 , 0 x01 , 0 x7d , 0 x01 , 0 x11 , 0 x01 ,0 x11 , 0 x01 , 0 x01 , 0 x01 , 0 x f f , 0 x01} ; """

OVER = NoneDRAGGING = FALSE

################################################### TreeWidget## A w i d g e t t h a t d i s p l a y s a n e s t e d s t r u c t u r e o f# TreeNodes i n a h e i r a r c h i c a l manner#

CHAPTER 11. CUSTOM MEGAWIDGETS 196

c l a s s TreeWidget ( T k i n t e r . T o p l e v e l ) :#−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−# I n i t i a l i z a t i o n r o u t i n e sd e f i n i t ( s e l f , master=None ) :

T k i n t e r . T o p l e v e l . i n i t ( s e l f , master )s e l f . make widgets ( )s e l f . l o a d i m a g e s ( )

s e l f . b i n d ( s e q u e n c e=’<KeyPress>’ ,f u n c=s e l f . k e y p r e s s )

# The t r e e t h a t c o n t a i n s the data to be d i s p l a y e ds e l f . t r e e = TreeNode ( p a r e n t=s e l f , data="Top" )

# Have t he t r e e b u i l d i c o n s i n t h i s c anvass e l f . t r e e . s e t p a r e n t ( s e l f )

s e l f . s e l e c t e d = None

# d i s p l a y t he t r e es e l f . b u i l d ( )

d e f make widgets ( s e l f ) :# The w i d g e t as a whole c o n s i s t s o f a c anvas and a s c r o l l b a rs e l f . c anvas = T k i n t e r . Canvas (

s e l f , background=’white’ )s e l f . v s c r o l l = T k i n t e r . S c r o l l b a r (

s e l f , o r i e n t=’vertical’ ,command=s e l f . canv as . yv i ew )

s e l f . c anvas [ ’yscrollcommand’ ] = s e l f . s c r o l l Ys e l f . c anvas . g r i d ( row =0, column =0, s t i c k y=’nesw’ )s e l f . v s c r o l l . g r i d ( row =0, column =1, s t i c k y=’ns’ )s e l f . g r i d c o l u m n c o n f i g u r e ( 0 , w e i g h t =1)

s e l f . c anvas . b i n d ( s e q u e n c e="<ButtonRelease>" ,f u n c=s e l f . r e l e a s e )

s e l f . c anvas . b i n d ( s e q u e n c e="<Motion>" ,f u n c=s e l f . motion )

# This l o a d s t he r e q u i r e d images from d i s kd e f l o a d i m a g e s ( s e l f ) :

s e l f .OPENBM = T k i n t e r . Image (’bitmap’ , data=OPENBM DATA , maskdata=OPENBM MASKDATA,f o r e g r o u n d=’black’ , background=’white’ )

s e l f .CLOSEDBM = T k i n t e r . Image (’bitmap’ , data=CLOSEDBM DATA , maskdata=OPENBM MASKDATA,f o r e g r o u n d=’black’ , background=’white’ )

s e l f .FOLDEROPEN = T k i n t e r . Image (’photo’ , fo rmat=’GIF’ , f i l e =’images/folderopen.gif’ )

s e l f . FOLDERCLOSED = T k i n t e r . Image (

CHAPTER 11. CUSTOM MEGAWIDGETS 197

’photo’ , fo rmat=’GIF’ , f i l e =’images/folderclosed.gif’ )s e l f . LEAF = T k i n t e r . Image (

’photo’ , fo rmat=’GIF’ , f i l e =’images/leaf.gif’ )

d e f s c r o l l Y ( s e l f , f i r s t , l a s t ) :s e l f . v s c r o l l . s e t ( f i r s t , l a s t )

#−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−# Event h a n d l e r s# Moves a l e a f node as i t i s b e i n g draggedd e f motion ( s e l f , a r g s ) :

i f s e l f . s e l e c t e d and DRAGGING :s e l f . s e l e c t e d . move ( a r g s . x , a r g s . y )

# Drops a l e a f node i n t o i t s new p a r e n td e f r e l e a s e ( s e l f , a r g s ) :

g l o b a l DRAGGINGDRAGGING = FALSEi f s e l f . s e l e c t e d :

i f OVER and OVER ! = s e l f . s e l e c t e d :s e l f . t r e e . remove node ( s e l f . s e l e c t e d )

OVER. append node ( s e l f . s e l e c t e d )e l s e :

s e l f . s e l e c t e d . r e s t o r e p o s ( )

d e f k e y p r e s s ( s e l f , a r g s ) :i f a r g s . keysym == ’Delete’ : # D e l e t e a node

i f s e l f . s e l e c t e d :s e l f . t r e e . remove node ( s e l f . s e l e c t e d )

e l i f a r g s . keysym == ’Return’ : # E d i t a r u l ei f s e l f . s e l e c t e d :

s e l f . s e l e c t e d . l a u n c h ( None )e l i f a r g s . keysym == ’Insert’ : # I n s e r t a r u l e

i f s e l f . s e l e c t e d :s e l f . s e l e c t e d . i n s e r t ( )

#−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−# I n f o r m a t i o n g a t h e r i n gd e f g e t t r e e ( s e l f ) :

r e t u r n s e l f . t r e e

d e f g e t s e l e c t i o n ( s e l f ) :r e t u r n s e l f . s e l e c t e d . data

d e f s e t s e l e c t i o n ( s e l f , node ) :s e l f . s e l e c t e d = nodes e l f . b u i l d ( )

#−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−# Methods# Draws t he t r e e on t he canvas

CHAPTER 11. CUSTOM MEGAWIDGETS 198

d e f b u i l d ( s e l f ) :# D e l e t e a l l t he canv as i t e m s from b e f o r es e l f . c anvas . d e l e t e (’all’ )s e l f . t r e e . b u i l d l a y e r ( s e l f . c anvas , s e l f . s e l e c t e d , 0 , 0 )s e l f . c anvas [ ’scrollregion’ ] = s e l f . canvas . bbox (’all’ )

################################################### TreeNode## Each branch or l e a f o f the t r e e i s a TreeNode# Each node c o n t a i n s data . For b r a n c h e s , t h i s# i s most o f t e n a s t r i n g . The name shown f o r# t he node i s r e p r ( data ) .c l a s s TreeNode :

#−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−# I n i t i a l i z a t i o n r o u t i n e sd e f i n i t ( s e l f , p a r e n t=None , data="NO DATA" , i c o n=None ) :

s e l f . p a r e n t = [ p a r e n t ]s e l f . c h i l d r e n = [ ]s e l f . open = FALSEs e l f . i c o n = i c o ns e l f . data = datas e l f . s e t i m a g e s ( )

d e f s e t i m a g e s ( s e l f ) :i f s e l f . p a r e n t [ 0 ] :

s e l f .OPENBM = s e l f . p a r e n t [ 0 ] . OPENBMs e l f .CLOSEDBM = s e l f . p a r e n t [ 0 ] . CLOSEDBMs e l f . LEAF = s e l f . p a r e n t [ 0 ] . LEAFs e l f .FOLDEROPEN = s e l f . p a r e n t [ 0 ] . FOLDEROPENs e l f . FOLDERCLOSED = s e l f . p a r e n t [ 0 ] . FOLDERCLOSED

e l s e :s e l f .OPENBM = s e l f .CLOSEDBM = s e l f . LEAF = Nones e l f .FOLDEROPEN = s e l f . FOLDERCLOSED = None

d e f s e t c h i l d r e n f r o m l i s t ( s e l f , l i s t ) :i f l i s t :

f o r i tem i n l i s t :i f l e n ( i tem ) == 0:

node = s e l f . append ( i tem )e l s e :

node = s e l f . append ( i tem [ 0 ] )node . s e t c h i l d r e n f r o m l i s t ( i tem [ 1 ] )

d e f s e t p a r e n t ( s e l f , p a r e n t ) :s e l f . p a r e n t . append ( p a r e n t )s e l f . s e t i m a g e s ( )

d e f s e t i c o n ( s e l f , i c o n ) :s e l f . i c o n = i c o n

CHAPTER 11. CUSTOM MEGAWIDGETS 199

#−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−# Node methodsd e f append ( s e l f , data ) :

node = TreeNode ( p a r e n t=s e l f , data=data )s e l f . append node ( node )r e t u r n node

d e f append node ( s e l f , node ) :s e l f . c h i l d r e n . append ( node )s e l f . c h i l d r e n . s o r t ( )p r i n t s e l f . c h i l d r e ns e l f . b u i l d ( )

d e f remove ( s e l f , data ) :f o r node i n s e l f . c h i l d r e n :

i f node . data == data :s e l f . c h i l d r e n . remove ( node )

e l s e :node . remove ( data )

s e l f . b u i l d ( )

d e f remove node ( s e l f , node ) :f o r n i n s e l f . c h i l d r e n :

i f n == node :s e l f . c h i l d r e n . remove ( node )

e l s e :n . remove node ( node )

s e l f . b u i l d ( )

d e f r e p r ( s e l f ) :r e t u r n s e l f . data

#−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−# Event h a n d l e r s

# Opens o r c l o s e s a branchd e f o p e n c l o s e ( s e l f , a r g s ) :

i f s e l f . open :s e l f . open = FALSE

e l s e :s e l f . open = TRUE

s e l f . b u i l d ( )

d e f p r e s s ( s e l f , a r g s ) :g l o b a l DRAGGINGs e l f . s e t s e l e c t i o n ( s e l f )s e l f . o f f s e t = (−3 , a r g s . y − s e l f . l o c [ 1 ] )DRAGGING = TRUE

d e f e n t e r ( s e l f , a r g s ) :g l o b a l OVER

CHAPTER 11. CUSTOM MEGAWIDGETS 200

OVER = s e l fs e l f . t e x t [ ’fill’ ] = ’blue’

d e f l e a v e ( s e l f , a r g s ) :g l o b a l OVEROVER = Nones e l f . t e x t [ ’fill’ ] = ’black’

d e f l a u n c h ( s e l f , a r g s ) :i f s e l f . data :

i f ’launch’ i n s e l f . data . c l a s s . d i c t . k e y s ( ) :s e l f . data . l a u n c h ( )

d e f i n s e r t ( s e l f ) :p a s s

#−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−# Drawing methods

# B u i l d s t he e n t i r e t r e e by t u n n e l i n g−up to the r o o td e f b u i l d ( s e l f ) :

f o r p a r e n t i n s e l f . p a r e n t :i f p a r e n t :

p a r e n t . b u i l d ( )

# I f a node−s p e c i f i c i c o n has not been s e t , use one o f the# s t a n d a r d onesd e f g e t i c o n ( s e l f ) :

i f s e l f . i c o n :r e t u r n s e l f . i c o n

e l s e :i f s e l f . c h i l d r e n = = [ ] :

r e t u r n s e l f . LEAFe l s e :

i f s e l f . open :r e t u r n s e l f .FOLDEROPEN

e l s e :r e t u r n s e l f . FOLDERCLOSED

# B u i l d s t h i s node at l o c a t i o n ( x , y )d e f b u i l d l a y e r ( s e l f , c anvas , s e l e c t e d , x , y , p r e v y=None ) :

i f not p r e v y :p r e v y = y

# Draw t he h o r i z o n t a l l i n eCanvas . L i n e ( canvas , x + LINE , y , x + ICON , y , f i l l =’gray50’ )

# Draw t he i c o ni c o n = s e l f . g e t i c o n ( )s e l f . b itmap = Canvas . ImageItem (

c anvas , x + ICON , y , image=i c o n )

CHAPTER 11. CUSTOM MEGAWIDGETS 201

# Draw t he t e x ts e l f . t e x t = Canvas . CanvasText (

c anvas , x + TEXT , y , anchor=’w’ )

# Draw t he s e l e c t i o n box , i f f t h i s node i s the s e l e c t e d nodei f s e l f == s e l e c t e d :

box = s e l f . t e x t . bbox ( )s e l f . r e c t a n g l e = Canvas . R e c t a n g l e (

canvas , box , f i l l =COLOR REF HIGHLIGHT ,o u t l i n e=COLOR REF HIGHLIGHT )

s e l f . r e c t a n g l e . l o w e r ( )e l s e :

s e l f . r e c t a n g l e = None

# Update t he t e x t and t he s i z e o f the s e l e c t i o n boxs e l f . u p d a t e t e x t ( )

# Save t he p h y s i c a l l o c a t i o n o f t h i s node so t h a t e v e n t s can# d e t e r m i n e which node was dropped on .s e l f . l o c = ( x , y )

# A s s i g n e v e n t s to t he v i s u a l node i t e m sf o r w i d g e t i n s e l f . b itmap , s e l f . t e x t :

w i d g e t . b i n d ( s e q u e n c e="<ButtonPress>" ,command=s e l f . p r e s s )

w i d g e t . b i n d ( s e q u e n c e="<Double-ButtonPress>" ,command=s e l f . l a u n c h )

w i d g e t . b i n d ( s e q u e n c e="<Enter>" ,command=s e l f . e n t e r )

w i d g e t . b i n d ( s e q u e n c e="<Leave>" ,command=s e l f . l e a v e )

# Draw t h i s node ’ s c h i l d r e n , i f the branch i s openn e x t y = y + i c o n . h e i g h t ( ) + Y STEPi f s e l f . c h i l d r e n ! = [ ] :

i f s e l f . open :open = Canvas . ImageItem (

c anvas , x + OPEN BOX , y , image=s e l f .OPENBM)py = yf o r c h i l d i n s e l f . c h i l d r e n :

newy = c h i l d . b u i l d l a y e r ( c anvas , s e l e c t e d ,x + X STEP , n e x t y , p r e v y=py )

py , n e x t y = n e x t y , newye l s e :

open = Canvas . ImageItem (canvas , x + OPEN BOX , y , image=s e l f .CLOSEDBM)

open . t k r a i s e ( )open . b i n d ( s e q u e n c e="<ButtonPress>" ,

command=s e l f . o p e n c l o s e )

CHAPTER 11. CUSTOM MEGAWIDGETS 202

# Draw t he v e r t i c a l l i n eCanvas . L i n e (

c anvas , x + LINE , y ,x + LINE , p r e v y , f i l l =’gray50’ ) . l o w e r ( )

r e t u r n n e x t y

# Updates t he t e x t t h a t i s d i s p l a y e d w i t h the node# I f t he r e p r ( data ) i s g r e a t e r than 3 0 c h a r a c t e r s , t he t e x t# i s t r u n c a t e d .d e f u p d a t e t e x t ( s e l f ) :

i f s e l f . t e x t :x = r e m o v e c r ( r e p r ( s e l f ) )

i f l e n ( x ) > 4 0 :x = x [ 0 : 3 9 ] + "..."

s e l f . t e x t [ ’text’ ] = xi f s e l f . r e c t a n g l e :

box = s e l f . t e x t . bbox ( )s e l f . r e c t a n g l e . c o o r d s ( box )s e l f . r e c t a n g l e . l o w e r ( )

# Moves t he node to a new l o c a t i o n . Used when d r a g g i n gd e f move ( s e l f , x , y ) :

s e l f . b itmap . t k r a i s e ( )s e l f . t e x t . t k r a i s e ( )s e l f . b itmap . c o o r d s ( [ ( x + ICON − s e l f . o f f s e t [ 0 ] ,

y − s e l f . o f f s e t [ 1 ] ) ] )s e l f . t e x t . c o o r d s ( [ ( x + TEXT − s e l f . o f f s e t [ 0 ] ,

y − s e l f . o f f s e t [ 1 ] ) ] )

# R e s t o r e node to i t s p r o p e r p o s i t i o n . Used when a d r a g g i n g# o p e r a t i o n i s ’ c a n c e l l e d . ’d e f r e s t o r e p o s ( s e l f ) :

s e l f . o f f s e t = ( 0 , 0 )s e l f . move ( s e l f . l o c [ 0 ] , s e l f . l o c [ 1 ] )

# S e t s t h i s node as t he s e l e c t e d noded e f s e t s e l e c t i o n ( s e l f , node ) :

f o r p a r e n t i n s e l f . p a r e n t :i f p a r e n t :

p a r e n t . s e t s e l e c t i o n ( node )

################################################### TESTING CODE

i f n a m e == "__main__" :i m p o r t Rulew = TreeWidget ( )n = w. g e t t r e e ( )

CHAPTER 11. CUSTOM MEGAWIDGETS 203

f o r x i n x r a n g e ( 1 , 2 0 ) :r = Rule . RuleNode ( p a r e n t=n )n . append node ( r )

w . main loop ( )

11.2 Help Browser Widget

11.2.1 End user usage

Figure 11.3: The Help Browser displaying an example document.

The Help widget is a very basic on-line help browser (Figure 11.3) similar infunctionality to a web browser (eg. Mosaic, Netscape Communicator, MicrosoftInternet Explorer.)

Help documents are displayed using a mixture of typefaces. Links to other helpdocuments are displayed in a box. Clicking on this box opens the other document.Clicking on the Back button returns to the previously viewed document.

11.2.2 Developer usage

This help browser implementation is quite low-featured, but is quite fast with asmall memory footprint. An alternative solution may have also been to provide aplatform-independant way of opening the help docuemnts in a standard web-browseras a sub-process of the application.

The help browser manages a global database of help documents stored in memoryas strings. There can only be one database per instance of an application and eachdocument in the database must have a unique string identifier. Documents can be

CHAPTER 11. CUSTOM MEGAWIDGETS 204

added to the database (usually at application start-up) using the add function:

Help . add ( s u b j e c t , document )

where subject is the unique document identifier and document is a string containingthe body of the document.

Documents are displayed using the show function:Help . show ( s u b j e c t )

where subject is a document identifier already in the database. Only one helpbrowser window will be created per application. Therefore, calling show twice willchange the subject of the already existing help browser, and not open a new helpbrowser all together.

The document strings themselves are formatted using a very tiny subset ofHTML. The supported tags are:

<b> bold text<i> italic text<bi> bold and italic text<tt> monospaced text<title> title-sized text<a href=’subject’> reference to another help document

11.2.3 Help.py

Code

# Help Browser F a l l 1 9 9 9 M i c h a e l Droettboom mdboom@mail . com############################################################# Help . py## This module p r o v i d e s a v e r y b a s i c Help b r o w s e r .

# App−s p e c i f i c i m p o r t sfrom U t i l i m p o r t ∗from C o n s t a n t s i m p o r t ∗

# Python i m p o r t si m p o r t s g m l l i b

# T k i n t e r i m p o r t si m p o r t T k i n t e rfrom TkConstants i m p o r t ∗

# To s t o r e a r e f e r e n c e to a h e l p window , i f any .helpWindow = None

# ” Help On Help ” D e f a u l t pagedocuments = {

’Default’ :("<title>Help Browser</title>\n""<b>(c) 1999 Michael Droettboom</b>\n"

CHAPTER 11. CUSTOM MEGAWIDGETS 205

"This is a very basic help browsing system that manages a ""collection of internal document strings and displays them ""with hyperlinks in a window.\n""The document strings are formatted using a very tiny subset ""of HTML. The Supported tags are:\n\n""""\t<b>b</b>: <b>bold</b> text\n""\t<b>i</b>: <i>italic</i> text\n""\t<b>bi</b>: <bi>bold and italic</bi> text\n""\t<b>tt</b>: <tt>monospaced</tt> (teletype) text\n""\t<b>title</b>: <title>title-sized</title> text\n""\t<b>a href=’<bi>subject</bi>’</b>: <a href=’Default Page 2’>""reference</a> to another subject page\n" ) ,

’Default Page 2’ :("<title>Help Browser Page 2</title>\n""Congratulations! You’ve made it to the next page.\n""<a href=’Default’>Click here</a> to go back.\n" )}

######################################### D i s p l a y s t he g i v e n s u b j e c t i n a h e l p window .# Only one h e l p window i s open f o r one a p p l i c a t i o n# at a t ime .d e f show ( s u b j e c t ) :

g l o b a l helpWindowi f helpWindow == None :

helpWindow = Window ( s u b j e c t )helpWindow . main loop ( )

e l s e :helpWindow . s e t s u b j e c t ( s u b j e c t )

######################################### Add a h e l p s u b j e c t to the d a t a b a s ed e f add ( s u b j e c t , document ) :

g l o b a l documentsdocuments [ s u b j e c t ] = document

################################################### Window## The main window to d i s p l a y h e l p#c l a s s Window ( T k i n t e r . T o p l e v e l ) :

d e f i n i t ( s e l f , s u b j e c t="Default" ) :# C r e a t e t he main Help windowT k i n t e r . T o p l e v e l . i n i t (

s e l f , None ,c l a s s =’Help’ )

s e l f . m a k e w i d g e t s ( )s e l f . s e t s u b j e c t ( s u b j e c t )

CHAPTER 11. CUSTOM MEGAWIDGETS 206

d e f m a k e w i d g e t s ( s e l f ) :# A based t e x t and v e r t i c a l s c r o l l b a r c o m b i n a t i o ns e l f . s c r o l l = T k i n t e r . S c r o l l b a r (

s e l f , o r i e n t=’vertical’ )s e l f . t e x t = TkinterHTML ( s e l f , s e l f . s c r o l l )s e l f . s c r o l l . c o n f i g u r e ( command=s e l f . t e x t . yv i ew )

# A t o o l b a r , c o n t a i n i n g o n l y the but ton ”Back”f rame = T k i n t e r . Frame ( s e l f )s e l f . back = T k i n t e r . Button (

frame , t e x t="Back" ,command=s e l f . t e x t . back )

s e l f . back . pack ( s i d e=’left’ )f rame . pack ( s i d e=’top’ , expand=’yes’ , f i l l =’x’ )

s e l f . s c r o l l . pack ( s i d e=’right’ , f i l l =’y’ )s e l f . t e x t . pack ( expand=’yes’ , f i l l =’both’ )

d e f s e t s u b j e c t ( s e l f , s u b j e c t ) :s e l f . t e x t . d i s p l a y t e x t ( s u b j e c t , documents [ s u b j e c t ] )

d e f s e t t i t l e ( s e l f , s u b j e c t ) :s e l f . t i t l e (APP NAME + " Help on " + s u b j e c t )

################################################### TkinterHTML## D i s p l a y s f o r m a t t e d t e x t u s i n g a t i n y s u b s e t o f HTML# The s u p p o r t e d t a g s a r e :# <b> : b o l d t e x t# < i > : i t a l i c t e x t# <b i > : b o l d and i t a l i c t e x t# <t t > : monospaced ( t y p e w r i t e r ) t e x t# < t i t l e > : t i t l e−s i z e d t e x t# <a h r e f=’ s u b j e c t ’> : r e f e r e n c e to a n o t h e r s u b j e c t page#c l a s s TkinterHTML ( T k i n t e r . Text , s g m l l i b . SGMLParser , CursorManager ) :

d e f i n i t ( s e l f , p a r e n t , s c r o l l ) :T k i n t e r . Text . i n i t (

s e l f , p a r e n t ,ysc ro l l command=s c r o l l . s e t ,s e t g r i d=TRUE,width =70, h e i g h t =32, wrap=’word’ )

CursorManager . i n i t ( s e l f )s e l f . p a r e n t = p a r e n t

# S t o r e s a h i s t o r y o f v i s i t e d pages .# Makes t he ”Back ” button p o s s i b l es e l f . h i s t o r y S t a c k = [ ]

CHAPTER 11. CUSTOM MEGAWIDGETS 207

s e l f . r e s e t ( )s e l f . s e t d i s p l a y t a g s ( )

# S e t s up t a g s i n Tk w i t h v a r i o u s f o r m a t t i n g p r o p e r t i e sd e f s e t d i s p l a y t a g s ( s e l f ) :

s e l f . t a g c o n f i g (’default’ , f o n t="Helvetica 10" ,s p a c i n g 1 =3, l m a r g i n 1 =2, l m a r g i n 2 =2,r m a r g i n =2)

s e l f . t a g c o n f i g (’title’ , f o n t="Helvetica 16 bold" )s e l f . t a g c o n f i g (’b’ , f o n t="Helvetica 10 bold" )s e l f . t a g c o n f i g (’i’ , f o n t="Helvetica 10 italic" )s e l f . t a g c o n f i g (’bi’ , f o n t="Helvetica 10 bold italic" )s e l f . t a g c o n f i g (’tt’ , f o n t="Courier 10" , l m a r g i n 2 =2)s e l f . t a g c o n f i g (’a’ , f o n t="Helvetica 10 bold" ,

background=COLOR REFERENCE)s e l f . known tags = [ ’default’ , ’title’ , ’b’ , ’i’ , ’bi’ , ’tt’ , ’a’ ]

d e f a d d t a g ( s e l f , tag ) :s e l f . t a g S t a c k . append ( tag )

d e f r e m o v e t a g ( s e l f , tag ) :s e l f . t a g S t a c k . remove ( tag )

# F u n n e l s data from t he SGMLParser to the T k i n t e r Text boxd e f h a n d l e d a t a ( s e l f , data ) :

s e l f . i n s e r t (’end’ , data , t u p l e ( s e l f . t a g S t a c k ) )

# C a l l e d by t he SGMLParser when i t e n c o u n t e r s a s t a r t t a g ( eg . <b>)d e f u n k n o w n s t a r t t a g ( s e l f , tag , a t t r s ) :

# I f i t ’ s one o f t he t a g s we s u p p o r t , put i t on t he tag s t a c ki f tag i n s e l f . known tags :

s e l f . a d d t a g ( tag )

# I f t h i s i s a r e f e r e n c e , we have some work to doi f tag == "a" :

f o r x i n a t t r s :i f x [0 ] == ’href’ :

s e l f . m a k e r e f e r e n c e t a g ( x [ 1 ] )

d e f m a k e r e f e r e n c e t a g ( s e l f , r e f ) :# Make a new tag w i t h th e same name as the# s u b j e c t b e i n g r e f e r e n c e d tos e l f . a d d t a g ( r e f )s e l f . r e f e r e n c e = r e f

# The g e n e r i c b i n d i n g s to b i n d t h i s tag tomake = [ ( ’set_subject’ , ’<ButtonPress>’ ) ,

(’highlight_ref’ , ’<Enter>’ ) ,(’unhighlight_ref’ , ’<Leave>’ ) ]

# Make t he b i n d i n g s s p e c i f i c to t h i s p a r t i c u l a r

CHAPTER 11. CUSTOM MEGAWIDGETS 208

# r e f e r e n c e by c r e a t i n g lambda f u n c t i o n s t h a t w i l l# c a l l t he h a n d l e r f u n c t i o n sf o r b i n d i n g i n make :

s e l f . t a g b i n d (r e f , b i n d i n g [ 1 ] ,e v a l (’lambda attr: attr.widget.’ +

b i n d i n g [ 0 ] + ’("’ + r e f + ’")’ ) )b r e a k

# C a l l e d by SGMLParser when i t e n c o u n t e r s an end tag ( eg . </ b>)d e f unknown endtag ( s e l f , tag ) :

i f tag i n s e l f . known tags :s e l f . r e m o v e t a g ( tag )

i f tag == "a" :s e l f . r e m o v e t a g ( s e l f . r e f e r e n c e )

d e f s e t s u b j e c t ( s e l f , s u b j e c t ) :s e l f . p a r e n t . s e t s u b j e c t ( s u b j e c t )

# E x t e r n a l : Loads t e x t i n t o the w i d g e td e f d i s p l a y t e x t ( s e l f , s u b j e c t , t e x t ) :

# Add t he new s u b j e c t to th e h i s t o r y s t a c ks e l f . h i s t o r y S t a c k = [ s u b j e c t ] + s e l f . h i s t o r y S t a c k

# c l e a r t he tag s t a c k ( we want to d e f a u l t to the# d e f a u l t t e x t s t y l e )s e l f . t a g S t a c k = [ ’default’ ]

# Change t he t i t l e o f t he p a r e n t window to r e f l e c t# t he new s u b j e c ti f s e l f . p a r e n t . s e t t i t l e :

s e l f . p a r e n t . s e t t i t l e ( s u b j e c t )

# Al low changes to t he t e x t b o xs e l f . c o n f i g u r e ( s t a t e=’normal’ )

# D e l e t e a l l t e x t i n t he t e x t b o xs e l f . d e l e t e ( ’1.0’ , ’end’ )

# Parse t he HTMLs e l f . f e e d ( t e x t )s e l f . c l o s e ( )

# D i s a l l o w a l l changes to th e t e x t b o xs e l f . c o n f i g u r e ( s t a t e=’disabled’ )

# Change t he s t a t e o f t he back button to r e f l e c t# t he s i z e o f t he h i s t o r y s t a c ks e l f . u p d a t e b a c k b u t t o n ( )

CHAPTER 11. CUSTOM MEGAWIDGETS 209

# Go back to t he p r e v i o u s s u b j e c t i n the h i s t o r y s t a c kd e f back ( s e l f ) :

i f l e n ( s e l f . h i s t o r y S t a c k ) > 1 :newSubject = s e l f . h i s t o r y S t a c k [ 1 ]s e l f . h i s t o r y S t a c k = s e l f . h i s t o r y S t a c k [ 2 : ]s e l f . s e t s u b j e c t ( newSubject )

s e l f . u p d a t e b a c k b u t t o n

# Change t he s t a t e o f th e back button based on the e m p t i n e s s# o f t he h i s t o r y s t a c kd e f u p d a t e b a c k b u t t o n ( s e l f ) :

i f l e n ( s e l f . h i s t o r y S t a c k ) > 1 :s e l f . p a r e n t . back . c o n f i g u r e ( s t a t e=’normal’ )

e l s e :s e l f . p a r e n t . back . c o n f i g u r e ( s t a t e=’disabled’ )

# H i g h l i g h t t he r e f e r e n c e when the mouse c u r s o r e n t e r sd e f h i g h l i g h t r e f ( s e l f , tag ) :

s e l f . s e t c u r s o r (’hand2’ )s e l f . t a g c o n f i g ( tag , background=COLOR REF HIGHLIGHT )

# U n h i g h l i g h t t he r e f e r e n c e when the mouse c u r s o r l e a v e sd e f u n h i g h l i g h t r e f ( s e l f , tag ) :

s e l f . r e s t o r e c u r s o r ( )s e l f . t a g c o n f i g ( tag , background=COLOR REFERENCE)

############################################################# SELF TEST : D i s p l a y th e d e f a u l t Help s u b j e c t .i f n a m e == "__main__" :

show ("Default" )

11.3 On-screen musical keyboard Widget

11.3.1 End user usage

Figure 11.4: Keyboard widget showing SINGLE selection

Figure 11.5: Keyboard widget showing MULTI selection

CHAPTER 11. CUSTOM MEGAWIDGETS 210

Figure 11.6: Keyboard widget showing RANGE selection

Figure 11.7: Keyboard widget in disabled mode

The on-screen musical keyboard widget (Figures 11.4 through 11.8) allows theuser to enter pitch-related information in a manner that is intuitive to most userswith a background in Western art music.

The user is presented with a standard musical keyboard. As you slide the mousecursor over the keyboard, the pitch name of the key currently being pointed at isdisplayed on the left-hand side of the keyboard. The scale of the keyboard can beincreased or decreased using the zoom-in ( ) and zoom-out ( ) buttons (Figure11.8).

By clicking or dragging on the keyboard, the user can select pitches. How pitchesare selected is determined by the current mode of the keyboard:

SINGLE: (Figure 11.4) Clicking on any key selects that key. Only one key can beselected at a time.

MULTI: (Figure 11.5) Click a key to select it. Click a selected key to unselect it.An arbitrary number of keys may be selected at any given time.

RANGE: (Figure 11.6) Click on a starting key and drag to an ending key to selecta contiguous range of keys. Only one range may be selected at any time.

11.3.2 Developer usage

The Keyboard class inherits from the Tkinter Frame class and can be used as such.To create a new Keyboard instance, use the default constructor:

kb = MusicWidgets . Keyboard ( p a r e n t , mode )

Figure 11.8: Keyboard widget zoomed in

CHAPTER 11. CUSTOM MEGAWIDGETS 211

where parent is the widget that owns the keyboard widget and mode is one of theconstants KB SINGLE, KB MULTI or KB RANGE corresponding to one of the inputmodes described above.

To retrieve information from the Keyboard widget, assign a callback functionusing:kb . s e t c a l l b a c k ( f u n c t i o n )

This callback function is called everytime there is a change made to the set ofselected keys. This function must have one argument. Depending on the mode, theargument will contain:

KB SINGLE: The pitch name of the selected key as a string.

KB MULTI: A list of the pitch names of all the selected keys, each given as a string.

KB RANGE: A list of two pitches. The first element is the highest pitch in therange, the second element is the lowest pitch in the range.

The widget as a whole can be enabled and disabled (Figure 11.7) like any otherTkinter widget using:kb [ ’state’ ] = ’disabled’bk [ ’state’ ] = ’normal’

11.3.3 Future plans

The on-screen musical keyboard can be used as the basis for a number of general-purpose widgets for musical applications. I plan to develop a MIDI library forPython (see Introduction on page ii) which will allow the Keyboard widget to in-clude:

• Selected notes and ranges using an attached MIDI keyboard as well as withthe mouse on-screen.

• Visual playback of MIDI sequences by flashing the keys on the on-screen key-board.

11.3.4 MusicWidgets.py

Code

# V i s u a l Pe log F a l l 1 9 9 9 M i c h a e l Droettboom mdboom@mail . com############################################################# MusicWidgets . py## A c o l l e c t i o n o f T k i n t e r MegaWidgets r e l a t e d to music

# V i s u a l Pe log i m p o r t sfrom U t i l i m p o r t ∗from C o n s t a n t s i m p o r t ∗

CHAPTER 11. CUSTOM MEGAWIDGETS 212

# T k i n t e r i m p o r t sfrom TkConstants i m p o r t ∗i m p o r t T k i n t e ri m p o r t Canvas

# C o n s t a n t sWKEY WIDTH = 10 # width o f w h i t e k e y sWKEY HEIGHT = 45 # h e i g h t o f w h i t e k e y sBKEY WIDTH = 6 # width o f b l a c k k e y sBKEY HEIGHT = 30 # h e i g h t o f b l a c k k e y sBKEY HALF = BKEY WIDTH / 2 # h a l f o f t he width o f b l a c k k e y s

ZOOM FACTOR = 1 . 2 5 # The f a c t o r to zoom/unzoom by

############################################################# Keyboard Widget## The keyboard w i d g e t c r e a t e s an on−s c r e e n m u s i c a l# keyboard . Notes on th e keyboard can be s e l e c t e d i n# one o f t he f o l l o w i n g modes :# KB SINGLE : One note at a t ime , by c l i c k i n g on th e# key# KB MULTI : M u l t i p l e n o t e s , by t o g g l i n g k e y s on/ o f f# KB RANGE : A c o n t i g u o u s r an ge o f n o t e s by c l i c k i n g# and d r a g g i n g on the keyboard .#

ZOOMIN DATA = """#define solid_width 13#d e f i n e s o l i d h e i g h t 13s t a t i c c h a r s o l i d b i t s [ ] = {

0 x30 , 0 x00 , 0 xcc , 0 x00 , 0 x32 , 0 x01 , 0 x32 , 0 x01 , 0 x f d , 0 x02 , 0 x f d , 0 x02 ,0 x32 , 0 x01 , 0 x32 , 0 x01 , 0 xcc , 0 x02 , 0 x30 , 0 x05 , 0 x00 , 0 x0a , 0 x00 , 0 x14 ,0 x00 , 0 x08 } ;

"""

ZOOMOUT DATA = """#define solid_width 13#d e f i n e s o l i d h e i g h t 13s t a t i c c h a r s o l i d b i t s [ ] = {

0 x30 , 0 x00 , 0 xcc , 0 x00 , 0 x02 , 0 x01 , 0 x02 , 0 x01 , 0 x79 , 0 x02 , 0 x79 , 0 x02 ,0 x02 , 0 x01 , 0 x02 , 0 x01 , 0 xcc , 0 x02 , 0 x30 , 0 x05 , 0 x00 , 0 x0a , 0 x00 , 0 x14 ,0 x00 , 0 x08 } ;

"""

c l a s s Keyboard ( T k i n t e r . Frame ) :#−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−# I n i t i a l i z a t i o n r o u t i n e sd e f i n i t ( s e l f , p a r e n t=None , mode=KB SINGLE ) :

s e l f . mode = modeT k i n t e r . Frame . i n i t (

s e l f , p a r e n t , h e i g h t =50,r e l i e f =’sunken’ )

CHAPTER 11. CUSTOM MEGAWIDGETS 213

s e l f . m a k e w i d g e t s ( )s e l f . s t a t e a l l (’disabled’ )

d e f m a k e w i d g e t s ( s e l f ) :# C r e a t e t he two s t a t u s l a b e l s on the l e f t hand s i d ef rame1 = T k i n t e r . Frame ( s e l f )s e l f . m o u s e s t a t u s = T k i n t e r . L a b e l (

master=frame1 , r e l i e f =’sunken’ ,w idth =4)

s e l f . w i d g e t s t a t u s = T k i n t e r . L a b e l (master=frame1 , r e l i e f =’sunken’ )

s e l f . m o u s e s t a t u s . g r i d ( row =0, column =0, s t i c k y=’nesw’ )s e l f . w i d g e t s t a t u s . g r i d ( row =1, column =0, s t i c k y=’nesw’ )

# C r e a t e t he zoom−i n / zoom−out b u t t o n sf rame2 = T k i n t e r . Frame ( frame1 )s e l f . zoomout image = T k i n t e r . Image (

’bitmap’ , data=ZOOMOUT DATA , maskdata=ZOOMOUT DATA,f o r e g r o u n d=’black’ , background=’white’ )

s e l f . zoomout = T k i n t e r . Button (frame2 , command=s e l f . zoom out ,image=s e l f . zoomout image )

s e l f . zoomin image = T k i n t e r . Image (’bitmap’ , data=ZOOMIN DATA , maskdata=ZOOMIN DATA ,f o r e g r o u n d=’black’ , background=’white’ )

s e l f . zoomin = T k i n t e r . Button (frame2 , command=s e l f . zoom in ,image=s e l f . zoomin image )

s e l f . zoomout . g r i d ( row =0, column =0, s t i c k y=’nesw’ )s e l f . zoomin . g r i d ( row =0, column =1, s t i c k y=’nesw’ )

f rame2 . g r i d ( row =2, column =0, s t i c k=’nesw’ )f rame1 . g r i d r o w c o n f i g u r e ( 0 , w e i g h t =1)frame1 . g r i d r o w c o n f i g u r e ( 1 , w e i g h t =1)

# C r e a t e t he keyboard c anvas i t s e l f and the s c r o l l b a rf rame3 = T k i n t e r . Frame ( s e l f )s e l f . c anvas = KeyboardCanvas (

frame3 , mode=s e l f . mode ,m o u s e s t a t u s=s e l f . m o u s e s t a t u s ,w i d g e t s t a t u s=s e l f . w i d g e t s t a t u s )

s e l f . h s c r o l l = T k i n t e r . S c r o l l b a r (f rame3 , o r i e n t=’horizontal’ ,command=s e l f . canv as . xv i ew )

s e l f . c anvas [ ’xscrollcommand’ ] = s e l f . s c r o l l Xs e l f . h s c r o l l . g r i d ( row =1, column =0, s t i c k y=’ew’ )s e l f . c anvas . g r i d ( row =0, column =0, s t i c k y=’ew’ )f rame3 . g r i d c o l u m n c o n f i g u r e ( 0 , w e i g h t =1)

frame1 . g r i d ( row =0, column =0, s t i c k y=’ns’ )

CHAPTER 11. CUSTOM MEGAWIDGETS 214

f rame3 . g r i d ( row =0, column =1, s t i c k y=’ew’ )s e l f . g r i d c o l u m n c o n f i g u r e ( 1 , w e i g h t =1)

#−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−# Event h a n d l e r sd e f s c r o l l X ( s e l f , f i r s t , l a s t ) :

s e l f . h s c r o l l . s e t ( f i r s t , l a s t )

d e f zoom in ( s e l f ) :s e l f . c anvas . s c a l e (ZOOM FACTOR)

d e f zoom out ( s e l f ) :s e l f . c anvas . s c a l e ( 1 / ZOOM FACTOR)

#−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−# S e t t i n g sd e f s e t i t e m ( s e l f , key , v a l u e ) :

i f key == ’state’ :s e l f . s t a t e a l l ( v a l u e )

e l s e :T k i n t e r . Frame . s e t i t e m ( s e l f , key , v a l u e )

d e f s t a t e a l l ( s e l f , v a l u e ) :s e l f . zoomin [ ’state’ ] = v a l u es e l f . zoomout [ ’state’ ] = v a l u es e l f . c anvas [ ’state’ ] = v a l u e

d e f s e t c a l l b a c k ( s e l f , f u n c ) :s e l f . c anvas . c a l l b a c k = f u n c

d e f set mode ( s e l f , mode ) :s e l f . c anvas . set mode ( mode )

# Keyboard Canvas h e l p e r c l a s sc l a s s KeyboardCanvas ( T k i n t e r . Canvas ) :

#−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−# I n i t i a l i z a t i o n r o u t i n e sd e f i n i t ( s e l f , p a r e n t=None , mode=KB SINGLE ,

m o u s e s t a t u s=None , w i d g e t s t a t u s=None ) :s e l f . m o u s e s t a t u s = m o u s e s t a t u ss e l f . w i d g e t s t a t u s = w i d g e t s t a t u ss e l f . xw idth = WKEY WIDTH ∗ 4 9 + 1T k i n t e r . Canvas . i n i t (

s e l f , p a r e n t ,w idth=WKEY WIDTH ∗ 4 9 ,h e i g h t=WKEY HEIGHT ,s c r o l l r e g i o n = ( 0 , 0 , s e l f . xw idth , WKEY HEIGHT) )

s e l f [ ’cursor’ ] = ’hand1’s e l f . make keys ( )s e l f . set mode ( mode )

CHAPTER 11. CUSTOM MEGAWIDGETS 215

d e f make keys ( s e l f ) :k e y s = [ ’c’ , ’c#’ , ’d’ , ’d#’ , ’e’ , ’f’ , ’f#’ , ’g’ , ’g#’ , ’a’ , ’a#’ , ’b’ ]l o c a t i o n = 0s e l f . k e y L i s t = [ ]f o r o c t a v e i n x r a n g e (− 3 , 4 ) :

f o r i v o r y i n k e y s :i f l e n ( i v o r y ) == 2:

k = BlackKey ( s e l f ,l o c a t i o n ∗ WKEY WIDTH − BKEY HALF ,i v o r y + "~" + r e p r ( o c t a v e ) )

e l i f l e n ( i v o r y ) == 1:k = WhiteKey ( s e l f ,

l o c a t i o n ∗ WKEY WIDTH,i v o r y + "~" + r e p r ( o c t a v e ) )

l o c a t i o n = l o c a t i o n + 1s e l f . k e y L i s t . append ( k )

d e f s c a l e ( s e l f , f a c t o r ) :T k i n t e r . Canvas . s c a l e ( s e l f , ’all’ , 0 , 0 , f a c t o r , 1 )s e l f . xw idth = s e l f . xw idth ∗ f a c t o rs e l f [ ’scrollregion’ ] = ( 0 , 0 , s e l f . xw idth , WKEY HEIGHT)

#−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−# Event h a n d l e r sd e f c l i c k e d o n ( s e l f , key ) :

i f s e l f . mode == KB SINGLE :i f s e l f . s e l e c t e d ! = [ ] :

s e l f . s e l e c t e d [ 0 ] . unmark ( )s e l f . s e l e c t e d = [ key ]key . mark ( )

e l i f s e l f . mode == KB MULTI :i f key . marked :

s e l f . s e l e c t e d . remove ( key )key . unmark ( )

e l s e :s e l f . s e l e c t e d . append ( key )key . mark ( )

e l i f s e l f . mode == KB RANGE :s e l f . top = keys e l f . bottom = keyf o r k i n s e l f . k e y L i s t :

k . unmark ( )key . mark ( )s e l f . d r a g g i n g = TRUE

d e f mot ion on ( s e l f , key ) :i f key ! = None and s e l f . m o u s e s t a t u s ! = None :

s e l f . m o u s e s t a t u s [ ’text’ ] = key . namei f s e l f . mode == KB RANGE and s e l f . d r a g g i n g and key ! = None :

s e l f . bottom = keykey . mark ( )

CHAPTER 11. CUSTOM MEGAWIDGETS 216

mark = FALSEf o r k i n s e l f . k e y L i s t :

i f mark :k . mark ( )

e l s e :k . unmark ( )

i f k == s e l f . top :mark = not markk . mark ( )

i f k == s e l f . bottom :mark = not markk . mark ( )

d e f r e l e a s e d o n ( s e l f , key ) :s e l f . bottom = keys e l f . d r a g g i n g = FALSEi f s e l f . c a l l b a c k :

i f s e l f . mode == KB RANGE :s e l f . c a l l b a c k ( [ s e l f . top , s e l f . bottom ] )

e l s e :s e l f . c a l l b a c k ( s e l f . s e l e c t e d )

d e f f i n d k e y ( s e l f , x , y ) :x = s e l f . c a n v a s x ( x )z = s e l f . f i n d o v e r l a p p i n g ( x , y , x , y )i f z ! = ( ) :

r e t u r n s e l f . i t e m s [ z [−1 ] ]e l s e :

r e t u r n None

#−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−# S e t t i n g sd e f set mode ( s e l f , mode ) :

s e l f . mode = modes e l f . s e l e c t e d = [ ]i f mode == KB RANGE :

s e l f . top = Nones e l f . bottom = Nones e l f . d r a g g i n g = FALSE

f o r k i n s e l f . k e y L i s t :k . unmark ( )

d e f s e t i t e m ( s e l f , key , v a l u e ) :i f key == ’state’ :

f o r k i n s e l f . k e y L i s t :k . unmark ( )k [ ’state’ ] = v a l u e

e l s e :T k i n t e r . Canvas . s e t i t e m ( s e l f , key , v a l u e )

# Key h e l p e r c l a s s

CHAPTER 11. CUSTOM MEGAWIDGETS 217

c l a s s Key ( Canvas . R e c t a n g l e ) :#−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−# I n i t i a l i z a t i o n r o u t i n e sd e f i n i t ( s e l f , p a r e n t , x , name ) :

s e l f . p a r e n t = p a r e n ts e l f . en = TRUEs e l f . b u i l d i t e m ( p a r e n t , x )s e l f . b i n d ( s e q u e n c e=’<Enter>’ , command=s e l f . e n t e r )s e l f . b i n d ( s e q u e n c e=’<Leave>’ , command=s e l f . l e a v e )s e l f . b i n d ( s e q u e n c e=’<ButtonPress>’ , command=s e l f . c l i c k )s e l f . b i n d ( s e q u e n c e=’<ButtonRelease>’ , command=s e l f . r e l e a s e )s e l f . b i n d ( s e q u e n c e=’<Motion>’ , command=s e l f . motion )s e l f . marked = FALSEs e l f . name = name

#−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−# Event h a n d l e r sd e f e n t e r ( s e l f , a r g s ) :

i f s e l f . en :s e l f [ ’fill’ ] = COLOR REFERENCE

d e f l e a v e ( s e l f , a r g s ) :i f s e l f . en :

i f s e l f . marked :s e l f [ ’fill’ ] = COLOR REF HIGHLIGHT

e l s e :s e l f [ ’fill’ ] = ’white’

d e f c l i c k ( s e l f , a r g s ) :i f s e l f . en :

s e l f . p a r e n t . c l i c k e d o n ( s e l f )

d e f r e l e a s e ( s e l f , a r g s ) :i f s e l f . en :

s e l f . p a r e n t . r e l e a s e d o n ( s e l f . p a r e n t . f i n d k e y ( a r g s . x , a r g s . y ) )

d e f motion ( s e l f , a r g s ) :i f s e l f . en :

s e l f . p a r e n t . mot ion on ( s e l f . p a r e n t . f i n d k e y ( a r g s . x , a r g s . y ) )

#−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−# S e t t i n g sd e f s e t s t a t e ( s e l f , v a l u e ) :

i f v a l u e == ’normal’ :i f s e l f . name == "c~0" :

s e l f [ ’stipple’ ] = ’gray25’e l s e :

s e l f [ ’stipple’ ] = ’’s e l f . en = TRUE

e l i f v a l u e == ’disabled’ :s e l f [ ’stipple’ ] = ’error’

CHAPTER 11. CUSTOM MEGAWIDGETS 218

s e l f . en = FALSE

d e f r e p r ( s e l f ) :r e t u r n s e l f . name

d e f s e t i t e m ( s e l f , key , v a l u e ) :i f key == ’state’ :

s e l f . s e t s t a t e ( v a l u e )e l s e :

Canvas . R e c t a n g l e . s e t i t e m ( s e l f , key , v a l u e )

d e f mark ( s e l f ) :s e l f . marked = TRUEs e l f . l e a v e ( [ ] )

d e f unmark ( s e l f ) :s e l f . marked = FALSEs e l f . l e a v e ( [ ] )

# WhiteKey h e l p e r c l a s sc l a s s WhiteKey ( Key ) :

d e f b u i l d i t e m ( s e l f , p a r e n t , x ) :Canvas . R e c t a n g l e . i n i t (

s e l f , p a r e n t , x , 0 , x + WKEY WIDTH , WKEY HEIGHT − 1)s e l f [ ’fill’ ] = ’white’s e l f [ ’outline’ ] = ’black’s e l f . l o w e r ( )

# BlackKey h e l p c l a s sc l a s s BlackKey ( Key ) :

d e f b u i l d i t e m ( s e l f , p a r e n t , x ) :Canvas . R e c t a n g l e . i n i t (

s e l f , p a r e n t , x , 0 , x + BKEY WIDTH , BKEY HEIGHT)s e l f [ ’fill’ ] = ’black’s e l f [ ’outline’ ] = ’black’s e l f . t k r a i s e ( )

d e f l e a v e ( s e l f , a r g s ) :i f s e l f . marked :

s e l f [ ’fill’ ] = COLOR REF HIGHLIGHTe l s e :

s e l f [ ’fill’ ] = ’black’

################################################### TESTING ROUTINESc l a s s Test ( T k i n t e r . T o p l e v e l ) :

d e f i n i t ( s e l f ) :T k i n t e r . T o p l e v e l . i n i t (

s e l f , None )s e l f . make widgets ( )

CHAPTER 11. CUSTOM MEGAWIDGETS 219

d e f make widgets ( s e l f ) :s e l f . keyboard = Keyboard ( s e l f , mode=KB MULTI)s e l f . keyboard . pack ( expand=’true’ , anchor=NW, f i l l =’both’ )s e l f . keyboard [ ’state’ ] = ’normal’

i f n a m e == "__main__" :t = Test ( )t . main loop ( )

12Implementation of other

components

12.1 Tool palette

The tool palette is implemented as two interacting classes. Palette organizes all thetools into a window and coordinates the behaviour of all the tools. All tools in thepalette derive from the Tool class. The tool defines its appearance in the palettewindow as well as the behaviours performed when new constraints are created etc.

The tools in the palette can be expanded by adding more source files to the plug-in directory. These files are automatically imported by the Palette class and addedto the tool palette. In this way, it is possible to expand the system without editingthe system itself. The example plug-in shown below, IntervalTool, implements theinterval constraint.

12.1.1 Palette.py

Code

# V i s u a l Pe log F a l l 1 9 9 9 M i c h a e l Droettboom mdboom@mail . com############################################################# P a l e t t e . py## The Tool P a l e t t e Window

from U t i l i m p o r t ∗i m p o r t Too l s , Help

from TkConstants i m p o r t ∗i m p o r t T k i n t e ri m p o r t s y s

220

CHAPTER 12. IMPLEMENTATION OF OTHER COMPONENTS 221

QUESTION DATA = """#define E__Pelog_Visual_images_q_width 10#d e f i n e E P e l o g V i s u a l i m a g e s q h e i g h t 10s t a t i c c h a r E P e l o g V i s u a l i m a g e s q b i t s [ ] = {

0 x78 , 0 x00 , 0 x f c , 0 x00 , 0 xcc , 0 x00 , 0 xc0 , 0 x00 , 0 x60 , 0 x00 , 0 x30 , 0 x00 ,0 x30 , 0 x00 , 0 x00 , 0 x00 , 0 x30 , 0 x00 , 0 x30 , 0 x00 } ; """

################################################### PaletteWindow#c l a s s PaletteWindow ( T k i n t e r . T o p l e v e l ) :

s t a n d a r d = [ Too l s . S e l e c t , Too l s . E q u a l s , Too l s . G r e a t e r ,Too l s . Or , Too l s . Not ]

i f s y s . p l a t f o r m == ’win32’ :co lumns = 2

e l s e :columns = 1

d e f i n i t ( s e l f , p a r e n t=None ) :T k i n t e r . T o p l e v e l . i n i t (

s e l f , p a r e n t ,c l a s s =’Palette’ )

s e l f . t i t l e (’Tools’ )s e l f . w m r e s i z a b l e ( width =0, h e i g h t =0)s e l f . r e a d y = FALSEs e l f . make widgets ( )s e l f . r e a d y = TRUE

d e f make widgets ( s e l f ) :s e l f . c u r c o l u m n = 0s e l f . c u r r o w = 0

# C r e a t e a l i s t o f t he t o o l s t h a t w i l l be# addedp l u g i n s = s e l f . g e t p l u g i n s ( )t o o l s = s e l f . s t a n d a r d + p l u g i n s

# Add t he t o o l s to th e framef rame1 = T k i n t e r . Frame ( master=s e l f )f o r t o o l i n t o o l s :

s e l f . a d d t o o l ( f rame1 , t o o l )f rame1 . pack ( f i l l =BOTH, expand =1, anchor=N)

# C r e a t e t he s t a t u s bar and h e l p but tonf rame2 = T k i n t e r . Frame ( master=s e l f )f rame2 . g r i d c o l u m n c o n f i g u r e ( 1 , w e i g h t =1)frame2 . pack ( f i l l =X , expand =1, anchor=S )

s e l f . q u e s t i o n i m a g e = T k i n t e r . Image (’bitmap’ , data=QUESTION DATA , maskdata=QUESTION DATA ,f o r e g r o u n d=’black’ , background=’white’ )

CHAPTER 12. IMPLEMENTATION OF OTHER COMPONENTS 222

s e l f . h e l p b u t t o n = T k i n t e r . Button (master=frame2 , image=s e l f . q u e s t i o n i m a g e ,command=s e l f . h e l p o n t o o l )

s e l f . h e l p b u t t o n . g r i d ( row =0, column =0, s t i c k y=’’ )

s e l f . l a b e l = T k i n t e r . L a b e l (master=frame2 , r e l i e f =’sunken’ )

s e l f . l a b e l . g r i d ( row =0, column =1, s t i c k y=’we’ )

s e l f . c u r t o o l = None

# I m p o r t s a l l o f t he p l u g g a b l e Tool modules# A l l non−b u i l t−i n t o o l s i n t he p a l e t t e a r e s t o r e d i n# t h e i r own module i n th e p l u g−i n d i r e c t o r y .p l u g i n d i r = "plug-ins"d e f g e t p l u g i n s ( s e l f ) :

i m p o r t g l o bi m p o r t os . pathi m p o r t imp

# Get a d i r e c t o r y l i s t i n g o f the p l u g−i n modulesp l u g i n s = g l o b . g l o b ( s e l f . p l u g i n d i r+’/*.py’ )r e s u l t = [ ]

# For each , i m p o r t t he module , and add the name o f# i t s c o r r e s p o n d i n g t o o l c l a s s to the r e s u l t l i s tf o r p l u g i n i n p l u g i n s :

head , pluginName = os . path . s p l i t ( p l u g i n )pluginName = s e l f . p l u g i n d i r + "/" + pluginName [ 0 :−3 ]

d e b u g p r i n t ("Loading plug-in:" , pluginName )a , b , c = imp . f i n d m o d u l e ( pluginName )module = imp . l o a d m o d u l e ( pluginName , a , b , c )r e s u l t . append ( module . Tool )

r e t u r n r e s u l t

# Adds a t o o l to t he p a l e t t ed e f a d d t o o l ( s e l f , f rame , t o o l ) :

ne w to o l = t o o l ( s e l f , f rame )newbutton = ne w to o l . c r e a t e b u t t o n ( )newbutton . g r i d ( row=s e l f . c u r r o w , column=s e l f . c u r c o l u m n , s t i c k y=’nesw’ )

s e l f . c u r c o l u m n = s e l f . c u r c o l u m n + 1i f s e l f . c u r c o l u m n > s e l f . columns :

s e l f . c u r c o l u m n = 0s e l f . c u r r o w = s e l f . c u r r o w + 1

# C a l l e d when a new t o o l i s s e l e c t e dd e f c h a n g e t o o l ( s e l f , n e w t o o l ) :

i f s e l f . c u r t o o l ! = None :s e l f . c u r t o o l . d e a c t i v a t e ( )

CHAPTER 12. IMPLEMENTATION OF OTHER COMPONENTS 223

s e l f . c u r t o o l = n e w t o o ln e w t o o l . a c t i v a t e ( )

d e f d e s c r i b e ( s e l f , s t r i n g ) :s e l f . l a b e l [ ’text’ ] = s t r i n g

d e f u n d e s c r i b e ( s e l f ) :i f s e l f . c u r t o o l ! = None :

s e l f . c u r t o o l . d e s c r i b e ( [ ] )e l s e :

s e l f . l a b e l [ ’text’ ] = ’’

d e f h e l p o n t o o l ( s e l f ) :i f s e l f . c u r t o o l ! = None :

s e l f . c u r t o o l . h e l p o n t o o l ( )

# Caused by c l i c k or drag on the Rule E d i t o r# Most o f t e n , t h i s w i l l c r e a t e a new node i n the e d i t o rd e f r u n t o o l ( s e l f , r u l e E d i t o r , s t a r t , f i n i s h ) :

i f s e l f . c u r t o o l ! = None :s e l f . c u r t o o l . r u n t o o l ( r u l e E d i t o r , s t a r t , f i n i s h )

d e f t o o l k e y p r e s s ( s e l f , a r g s ) :i f s e l f . c u r t o o l ! = None :

s e l f . c u r t o o l . k e y p r e s s ( a r g s . keysym )

p a l e t t e = PaletteWindow ( )

12.1.2 Tools.py

Code

# V i s u a l Pe log F a l l 1 9 9 9 M i c h a e l Droettboom mdboom@mail . com############################################################# Tools . py## The g e n e r i c c l a s s from which a l l t o o l s a r e d e r i v e d

from U t i l i m p o r t ∗i m p o r t Nodes

i m p o r t T k i n t e ri m p o r t Help

################################################### Tool## Base c l a s s o f a l l t o o l sc l a s s Tool :

b u t t o n b i t m a p="default.xbm"t o o l n a m e="Default Tool"

CHAPTER 12. IMPLEMENTATION OF OTHER COMPONENTS 224

d e f i n i t ( s e l f , p a l e t t e , b u t t o n s ) :s e l f . p a l e t t e = p a l e t t es e l f . b u t t o n s = b u t t o n s

d e f r e p r ( s e l f ) :r e t u r n s e l f . t o o l n a m e

d e f c r e a t e b u t t o n ( s e l f ) :s e l f . but ton = ToolButton ( s e l f , s e l f . b u t t o n s , s e l f . b u t t o n b i t m a p )r e t u r n s e l f . but ton

d e f choose ( s e l f ) :s e l f . p a l e t t e . c h a n g e t o o l ( s e l f )

d e f d e s c r i b e ( s e l f , a r g s ) :s e l f . p a l e t t e . d e s c r i b e ( s e l f )

d e f u n d e s c r i b e ( s e l f , a r g s ) :s e l f . p a l e t t e . u n d e s c r i b e ( )

d e f a c t i v a t e ( s e l f ) :s e l f . but ton . c o n f i g u r e ( r e l i e f =’sunken’ )s e l f . s e l e c t e d = Nones e l f . i n i t i a l i z e t o o l ( )

d e f d e a c t i v a t e ( s e l f ) :s e l f . but ton . c o n f i g u r e ( r e l i e f =’raised’ )i f s e l f . s e l e c t e d :

s e l f . s e l e c t e d . u n s e l e c t ( )s e l f . s e l e c t e d = Nones e l f . c l e a r t o o l ( )

d e f i n i t i a l i z e t o o l ( s e l f ) :p a s s

d e f c l e a r t o o l ( s e l f ) :p a s s

d e f r u n t o o l ( s e l f , r u l e E d i t o r , s t a r t , f i n i s h ) :d e b u g p r i n t ("Drawn from" , s t a r t , "to" , f i n i s h )

d e f h e l p o n t o o l ( s e l f ) :Help . show ( s e l f . t o o l n a m e + " Tool" )

d e f k e y p r e s s ( s e l f , key ) :i f key == ’Delete’ :

d e b u g p r i n t ("Deleting:" , s e l f . s e l e c t e d )s e l f . s e l e c t e d . d e l e t e ( )s e l f . s e l e c t e d = None

d e f s e l e c t ( s e l f , node ) :

CHAPTER 12. IMPLEMENTATION OF OTHER COMPONENTS 225

i f s e l f . s e l e c t e d :s e l f . s e l e c t e d . u n s e l e c t ( )

s e l f . s e l e c t e d = nodei f node :

node . s e l e c t ( )

################################################### ToolButton## The button i n t he t o o l p a l e t t e t h a t s e l e c t s# t he t o o l#c l a s s ToolButton ( T k i n t e r . Button ) :

s p t = ( 2 4 , 2 4 )

d e f i n i t ( s e l f , t o o l , p a l e t t e , bitmap ) :s e l f . t o o l = t o o ls e l f . p a l e t t e = p a l e t t eT k i n t e r . Button . i n i t (

s e l f ,master=p a l e t t e ,d e f a u l t=’disabled’ ,b itmap=’@images/’+bitmap ,command=t o o l . choose ,r e l i e f =’raised’ ,w idth=s e l f . s p t [ 0 ] ,h e i g h t=s e l f . s p t [ 1 ] )

s e l f . b i n d ( s e q u e n c e="<Enter>" ,f u n c=t o o l . d e s c r i b e )

s e l f . b i n d ( s e q u e n c e="<Leave>" ,f u n c=t o o l . u n d e s c r i b e )

################################################### S e l e c t## The s e l e c t i o n t o o l i s used to s e l e c t and# e d i t o r d e l e t e p r e v i o u s l y c r e a t e d nodes .#Help . add (

"Selection Tool" ,("<title>Selection Tool</title>\n""The <b>Selection Tool</b> allows you to re-edit relationships ""that have already been added to the rule.\n""With the <b>Selection Tool</b> enabled, you can click on ""existing relationships to bring up a dialog box containing ""more specific options. For instance, clicking on an <b>interval</b> ""relationship will allow you to select a specific kind of interval.\n""When a relationship is selected, it is displayed in reverse video.\n""Pressing the <b>Delete</b> key removes the selected relationship ""from the rule editor." ) )

CHAPTER 12. IMPLEMENTATION OF OTHER COMPONENTS 226

c l a s s S e l e c t ( Tool ) :b u t t o n b i t m a p="select.xbm"t o o l n a m e="Selection"

d e f r u n t o o l ( s e l f , r u l e E d i t o r , s t a r t , f i n i s h ) :s e l f . s e l e c t ( s t a r t )

################################################### E q u a l s## The E q u a l s Tool i s used to c r e a t e e q u a l s nodes# t h a t can c o n s t r a i n th e r e s u l t s o f two o t h e r# nodes to be e q u a l .#Help . add ("Equals Tool" ,

("<title>Equals Tool</title>\n""The <b>Equals Tool</b> constrains the results of two nodes ""to be equal.\n""An <b>equals</b> relationship can only be set up between two ""nodes with the same result type." ) )

c l a s s E q u a l s ( Tool ) :b u t t o n b i t m a p="equals.xbm"t o o l n a m e="Equals"

d e f r u n t o o l ( s e l f , r u l e E d i t o r , s t a r t , f i n i s h ) :i f s t a r t and s t a r t ! = f i n i s h :

i f ( s t a r t . EQUALITY TYPE ! = ’’ ands t a r t . EQUALITY TYPE == f i n i s h . EQUALITY TYPE ) :node = EqualsNode ( r u l e E d i t o r , s t a r t , f i n i s h )s e l f . s e l e c t ( node )

e l s e :e r r o r m e s s a g e (

"The nodes specified are not comparable.\n""The ’Equals’ relationship may only be created between ""two nodes with the same result type.\n""In this case, the result types were:\n"" First node: " + s t a r t . EQUALITY TYPE +" Second node: " + f i n i s h . EQUALITY TYPE +"\nPlease try again or see the help page on the " +"’Equals Tool’ for more information." )

c l a s s EqualsNode ( Nodes . B i n a r y R e l a t i o n ) :n o d e t y p e = ’equals’bitmap = ’equals.xbm’

################################################### G r e a t e r## The G r e a t e r Than Tool c r e a t e s G r e a t e r Than

CHAPTER 12. IMPLEMENTATION OF OTHER COMPONENTS 227

# nodes t h a t c o n s t r a i n the r e s u l t o f one node# to be g r e a t e r than or l e s s than a n o t h e r node .# The two nodes must have the same r e s u l t t y p e .

Help . add ("Greater Than Tool" ,("<title>Greater Than Tool</title>\n""The <b>Greater Than Tool</b> constrains the result of one node to be ""greater than that of another.\n""A <b>Greater Than</b> relationship can only be set up between ""two nodes with the same result type.\n""<b>Tip:</b> Drag <i>from</i> the node that you wish to have ""the greater result <i>to</i> the node that you wish to have ""the lesser result. In this way, the <b>Greater Than</b> tool""doubles as a <b>Less Than</b> tool." ) )

c l a s s G r e a t e r ( Tool ) :b u t t o n b i t m a p="greater.xbm"t o o l n a m e="Greater Than"

d e f r u n t o o l ( s e l f , r u l e E d i t o r , s t a r t , f i n i s h ) :i f s t a r t and s t a r t ! = f i n i s h :

i f ( s t a r t . COMPARISON TYPE ! = ’’ ands t a r t . COMPARISON TYPE == f i n i s h . COMPARISON TYPE ) :node = GreaterNode ( r u l e E d i t o r , s t a r t , f i n i s h )s e l f . s e l e c t ( node )

e l s e :e r r o r m e s s a g e (

"The nodes specified are not comparable.\n""The ’Greater Than’ relationship may only be created between ""two nodes with the same result type.\n""In this case, the result types were:\n"" First node: " + s t a r t . COMPARISON TYPE +" Second node: " + f i n i s h . COMPARISON TYPE +"\nPlease try again or see the help page on the " +"’Greater Than Tool’ for more information." )

c l a s s GreaterNode ( Nodes . B i n a r y R e l a t i o n ) :n o d e t y p e = ’greater’bitmap = ’greater.xbm’

d e f v i s u a l i z e ( s e l f ) :Nodes . B i n a r y R e l a t i o n . v i s u a l i z e ( s e l f )s e l f . u p d a t e a r r o w d i r ( )

d e f m o v e v i s u a l ( s e l f ) :Nodes . B i n a r y R e l a t i o n . m o v e v i s u a l ( s e l f )s e l f . u p d a t e a r r o w d i r ( )

d e f u p d a t e a r r o w d i r ( s e l f ) :i f s e l f . a . pt [0 ] >= s e l f . b . pt [ 0 ] :

CHAPTER 12. IMPLEMENTATION OF OTHER COMPONENTS 228

s e l f . v i s u a l [ 4 ] [ ’bitmap’ ] = ’@images/less.xbm’e l s e :

s e l f . v i s u a l [ 4 ] [ ’bitmap’ ] = ’@images/greater.xbm’

################################################### Or## The Or ToolHelp . add (

"Or Tool" ,("<title>Or Tool</title>\n""The <b>Or Tool</b> allows two constraints to be applied""independently.\n""An <b>Or Node</b> may be created between any two nodes, ""with the exception of nodes in the note template.\n" ) )

c l a s s Or ( Tool ) :b u t t o n b i t m a p="or.xbm"t o o l n a m e="Or"

d e f r u n t o o l ( s e l f , r u l e E d i t o r , s t a r t , f i n i s h ) :i f s t a r t and s t a r t ! = f i n i s h :

i f s t a r t . n o d e t y p e ! = ’note’ and f i n i s h . n o d e t y p e ! = ’note’ :node = OrNode ( r u l e E d i t o r , s t a r t , f i n i s h )s e l f . s e l e c t ( node )

e l s e :e r r o r m e s s a g e (

"The ’Or’ relationship may only be created ""between nodes that are not part of the note ""template.\n""Please try again or see the help page on the ""’Or Tool’ for more information." )

c l a s s OrNode ( Nodes . B i n a r y R e l a t i o n ) :n o d e t y p e = ’or’bitmap = ’or.xbm’

################################################### Not## The Not ToolHelp . add (

"Not Tool" ,("<title>Or Tool</title>\n""\n""An <b>Or Node</b> may be created between any two nodes, ""with the exception of nodes in the note template.\n" ) )

c l a s s Not ( Tool ) :

CHAPTER 12. IMPLEMENTATION OF OTHER COMPONENTS 229

b u t t o n b i t m a p="not.xbm"t o o l n a m e="Not"

d e f r u n t o o l ( s e l f , r u l e E d i t o r , s t a r t , f i n i s h ) :i f s t a r t :

i f s t a r t . n o d e t y p e ! = ’note’ :node = NotNode ( r u l e E d i t o r , s t a r t )s e l f . s e l e c t ( node )

e l s e :e r r o r m e s s a g e (

"The ’Not’ node may only be created ""on a node that is not part of the note ""template.\n""Please try again or see the help page on the ""’Not Tool’ for more information." )

c l a s s NotNode ( Nodes . U n a r y R e l a t i o n ) :n o d e t y p e = ’not’bitmap = ’not.xbm’

12.1.3 IntervalTool.py

Code

# V i s u a l Pe log F a l l 1 9 9 9 M i c h a e l Droettboom mdboom@mail . com############################################################# I n t e r v a l T o o l . py## A t o o l f o r c o n s t r a i n i n g the i n t e r v a l between two n o t e s

i m p o r t Too l s , Nodes , Helpfrom C o n s t a n t s i m p o r t ∗

Help . add ("Interval Tool" ,"""<title>Interval Tool</title>

The <b> I n t e r v a l Tool</b>Tool c o n s t r a i n s t he i n t e r v a l between two n o t e s . Drag a ran geon t he m u s i c a l keyboard to choose the i n t e r v a l . """)

c l a s s Tool ( Too l s . Tool ) :b u t t o n b i t m a p="interval.xbm"t o o l n a m e="Interval"

d e f r u n t o o l ( s e l f , r u l e E d i t o r , s t a r t , f i n i s h ) :i f s t a r t ! = None and s t a r t ! = f i n i s h :

node = I n t e r v a l N o d e ( r u l e E d i t o r , s t a r t , f i n i s h )s e l f . s e l e c t ( node )

c l a s s I n t e r v a l N o d e ( Nodes . B i n a r y R e l a t i o n ) :EQUALITY TYPE = "interval"COMPARISON TYPE = "interval"

CHAPTER 12. IMPLEMENTATION OF OTHER COMPONENTS 230

d e f i n i t e d i t w i d g e t s ( s e l f ) :s e l f . master . keyboard [ ’state’ ] = ’normal’s e l f . master . keyboard . set mode (KB RANGE)

d e f d e s t r o y e d i t w i d g e t s ( s e l f ) :s e l f . master . keyboard [ ’state’ ] = ’disabled’

d e f k e y b o a r d c a l l b a c k ( s e l f , k e y L i s t ) :p r i n t k e y L i s t

12.2 Constants and Utility functions

12.2.1 Constants.py

Code

# V i s u a l Pe log F a l l 1 9 9 9 M i c h a e l Droettboom mdboom@mail . com############################################################# C o n s t a n t s . py## C o n s t a n t s used t h r o u g h o u t the V i s u a l Pe log system

################################################### Used by t he g r i d l a y o u t a l g o r i t h m

# ( x , y ) p a i r : The amount o f padd ing between nodesRE PAD = ( 6 , 6 )# ( x , y ) p a i r : The amount o f padd ing around the graphRE CANVAS PAD = ( 4 , 4 )# The minimum and maximum p o s s i b l e v a l u e s f o r the t o p o l o g i c a l s o r tRE MAXGRID = 10000RE MINGRID = −10000

################################################### Used by t he r u l e e d i t o r a n i m a t o r

RE ANIMATION FRAMES = 1 0 . 0

################################################### C o l o r s ( Yes , i t ’ s th e U. S . s p e l l i n g , to be# c o n s i s t e n t w i t h Tk )

RE COLOR CANVAS BACKGROUND = ’white’ # Canvas background c o l o u r

RE COLOR NORMAL = ’#0000AA’ # o u t l i n e u n s e l e c t e d nodesRE COLOR NODE = ’#eeeeee’ # f i l l u n s e l e c t e d nodes

RE COLOR SELECTED = ’#AA0000’ # o u t l i n e s e l e c t e d nodesRE COLOR NODE SELECTED = ’black’ # f i l l i n s e l e c t e d nodes

RE COLOR HIGHLIGHTED = ’#0000ff’ # o u t l i n e h i g h l i g h t e d nodesRE COLOR HIGHSELECT = ’#FF0000’ # o u t l i n e h i g h l i g h t e d s e l e c t e d nodes

CHAPTER 12. IMPLEMENTATION OF OTHER COMPONENTS 231

RE COLOR TEXT = ’black’ # Used f o r t he c o l o r o f t e x t on nodesRE COLOR TEXT SELECTED = ’white’ # Used f o r t he c o l o r o f t e x t on s e l e c t e d nodes

COLOR REFERENCE = ’#DDDDFF’COLOR REF HIGHLIGHT = ’#AAAAFF’

################################################### On−s c r e e n keyboard c o n s t a n t sKB SINGLE = 0KB MULTI = 1KB RANGE = 2

12.2.2 Util.py

Code

from TkConstants i m p o r t ∗i m p o r t tkMessageBox

DEBUG = TRUEAPP NAME = "Visual Pelog"APP VERSION = "0.0001a"APP AUTHOR = "Michael Droettboom"

d e f d e b u g p r i n t (∗ kp ) :i f DEBUG:

f o r x i n kp :p r i n t x ,

p r i n t "\n" ,

d e f f l i p ( x ) :i f x == 1:

r e t u r n 0e l s e :

r e t u r n 1

c l a s s CursorManager :d e f i n i t ( s e l f ) :

s e l f . c u r s o r = s e l f . c g e t (’cursor’ )

d e f s e t c u r s o r ( s e l f , c u r s o r ) :s e l f . c u r s o r = s e l f . c g e t (’cursor’ )s e l f . c o n f i g u r e ( c u r s o r=c u r s o r )

d e f r e s t o r e c u r s o r ( s e l f ) :s e l f . c o n f i g u r e ( c u r s o r=s e l f . c u r s o r )

d e f e r r o r m e s s a g e ( s t r i n g ) :tkMessageBox . s h o w e r r o r (APP NAME , s t r i n g )

d e f b i n 2 h e x ( b i n ) :

CHAPTER 12. IMPLEMENTATION OF OTHER COMPONENTS 232

hx = ’’f o r c i n b i n :

hx = hx + hex ( ord ( c ) ) [ 2 : ]r e t u r n hx

d e f h e x 2 b i n ( hx ) :b i n = ’’f o r i i n x r a n g e ( 0 , l e n ( hx ) / 2 ) :

b i n = b i n + c h r ( e v a l (’0x’ + hx [ i ∗2 : ( i ∗2)+2]))r e t u r n b i n

d e f b i n 2 h e x f i l e ( b i n f i l e , h e x f i l e ) :open ( h e x f i l e , ’w’ ) . w r i t e ( b i n 2 h e x ( open ( b i n f i l e , ’r’ ) . r e a d ( ) ) )

d e f h e x 2 b i n f i l e ( h e x f i l e , b i n f i l e ) :open ( b i n f i l e , ’w’ ) . w r i t e ( h e x 2 b i n ( open ( h e x f i l e , ’r’ ) . r e a d ( ) ) )

d e f f i l t e r c r ( s ) :i f s == ’\n’ or s == ’\r’ or s == ’\t’ :

r e t u r n ’’e l s e :

r e t u r n s

d e f r e m o v e c r ( s ) :r e t u r n f i l t e r ( f i l t e r c r , s )

IIIAppendices

233

ATcl/Tk-Prolog Connector System

A.1 The problem

Now that two suitable development tools have been selected, a method of connectingthem must be chosen. Both Tcl/Tk and SWI-Prolog have built-in C-language in-terfaces. Intuitively, one might assume that connecting the two systems is a simplematter of calling the other’s external C procedures. However, certain peculiari-ties around how SWI-Prolog’s external interface works make direct communicationthrough function calls impossible. Some type of connector must be provided.

SWI-Prolog has an extensive set of C functions for doing everything from creat-ing new goals to running queries. However, these functions use custom user-definedtypes to send parameters in and out. These types have names like term t and func-tor t that directly represent Prolog-specific data structures. Unfortunately, Tcl/Tkhas no support for user-defined C data types, and thus can not call these functionsdirectly.

In order to call C from Prolog, you must provide a specially-designed C functionwhich will set-up what SWI calls “foreign language predicates.” These predicatesappear to the Prolog programmer as regular Prolog predicates, but are in factlinked to external code. The necessary elements of this system, such as callbacksand function pointers, can not be provided from Tcl/Tk.

A.2 C-language connector method

What appears to be needed, therefore, is a small dynamically-linked library writtenin C that will provide an interface between Tcl/Tk and Prolog. It would have“wrapper” functions, around the external functions of both SWI-Prolog and Tcl/Tk,that would perform all of the necessary data conversion.

Not surprisingly, there are a number of products that do exactly that. SICStusProlog includes a Tcl/Tk interface right out of the box. There is also a product

234

APPENDIX A. TCL/TK-PROLOG CONNECTOR SYSTEM 235

for Eclipse-Prolog called ProTcXl. Unfortunately, even if this interface were freelyavailable, it would require considerable effort to make it work with SWI-Prolog.The external C functions provided by SWI-Prolog are entirely different from thoseprovided by any other Prolog, even though the general concept is the same. Theconnector required for this project, therefore, must be SWI-Prolog-specific.

A.2.1 Tcl/Tk-Prolog Connection

[http://ace.ulyssis.student.kuleuven.ac.be/ jeans/tcltk/conn.html]Jan Struyf, an undergraduate student in Belgium has created a connection be-

tween SWI-Prolog and Tcl/Tk. It allows you to send commands in either directionthat are passed ”as-is” and evaluated by the respective interpreters. A list of thefunctions is in Table A.1.

Tcl/Tk Side

p r o l o g e v e n t EventName ( Parameter s , . . . )

Prolog Side

t c l n e w (− I n t e r p )t c l d e l e t e (+ I n t e r p )t c l e v a l (+ I n t e r p ,+Command,−R e s u l t )

tk new(+Opts ,− I n t e r p )t k d o o n e e v e n tt k n e x t e v e n t (+ I n t e r p ,−Event )t k m a i n l o o p

t c l e v a l f i l e /1t c l a b o u t /0t c l r e s u l t /0t c l s t r i n g /2t c l a r i t y /2t c l e x i t /0

Table A.1: Functions provided by Jan Struyf’s Tcl/Tk-Prolog Connection

This system seems quite robust, works with a number of different versions ofTcl/Tk and SWI-Prolog, and full source code is provided. Unfortunately, the systemis currently not ported to anything but MS-Windows. Committing to using thissystem, therefore, means not only committing to a specific implementation andversion of Prolog, but also to the Windows platform.

APPENDIX A. TCL/TK-PROLOG CONNECTOR SYSTEM 236

A.3 Piping method

Another solution to the Prolog-Tcl/Tk connector problem is presented in an articleby Andrea Dell’Amico at the University of Pisa1. This article describes a connectionbetween BinProlog and Tcl/Tk using piping. It takes advantage of the fact thatboth Prolog and Tcl/Tk have strong meta-programming elements.

A.3.1 Interaction Model

The Prolog system is run as a subprocess under Tcl/Tk. (Therefore, Prolog is aslave to Tcl/Tk, though this could easily be reversed.) Assertions or queries are sentto Prolog along the pipe just as a user would enter them from the keyboard. Whena query is sent to Prolog, Tcl/Tk listens to the pipe and retrieves and interpretsthe input. If the input begins with the keyword call tcl, it is sent directly to Tcl’seval function, which runs the rest of the input as a Tcl command.

While this may not seem as elegant as the C-language connector solution, itdoes have some distinct advantages:

• implemented entirely in Tcl/Tk and Prolog.

• uses only standard methods of input/output, avoiding the external C functionswhich change across implementations and platforms.

• provides as equally as much functionality as the Struyf C-language connectorimplementation.

The primary disadvantage to this approach is that all interactions between Prologand Tcl/Tk must go through an additional parsing step. Dell’Amico shows, however,that this performance hit is quite insignificant relative to the system as a whole.The higher flexibility over how and when data is sent, the tighter integration withinthe core tools and the almost instant portability of this system makes it superior toa highly Prolog-specific C-language connector.

A.3.2 Design

The design of a portable piping interface between Tcl/Tk and Prolog is describedin an article by Andrea Dell’Amico2.

A.3.3 Usage

The majority of this usage definition is defined in Dell’Amico. See Table A.2 for alist of user functions.

A.3.4 Implementation

Implementing the above solution turned out to be a relatively straight-forward task,though there were a few problems to solve.

1http://www.cli.di.unipi.it/help/prolog/BinProlog/tcl2http://www.cli.di.unipi.it/help/prolog/BinProlog/tcl

APPENDIX A. TCL/TK-PROLOG CONNECTOR SYSTEM 237

Tcl-Tk Side ...start prolog $process starts the Prolog process. The process must

have the tcl interface library loaded.halt prolog halts the Prolog process.start test allows the Tcl/Tk side to be run without the

Prolog side for testing what is being sent toProlog

p AssertPrologGoal adds a goal to the Prolog databaseq Query initiates a Prolog query. The result is read in

and interpreted by Tcl. All lines from Prologstarting with the keyword call tcl are inter-preted using eval.

Prolog Side ...start tcl server(). starts the listener loop on stdioThe listener loop reacts to the following terms:assert prolog(X). adds the goal X to the Prolog databasequery prolog(X). runs query X and displays the result on stdio.halt. halts the Prolog system.call tcl(X). provides a convenient way to run Tcl com-

mands. The first element of the list X mustbe a Tcl command. The rest of the elementsin the list are sent as arguments to that com-mand.

Table A.2: User functions of SWI-Prolog-Tcl/Tk Piping Interface

APPENDIX A. TCL/TK-PROLOG CONNECTOR SYSTEM 238

Problem 1: Poor piping implementation in Windows 9x

The piping implementation proposed by Dell’Amico uses Tcl’s addinput3 commandto call a procedure whenever there is data available to be read from the Prolog pro-cess. This is an event-driven approach: “whenever there is something to read, readit.” Unfortunately, event-driven input from pipes is not supported under Windows9x. Under UNIX and Windows NT, piping is an entirely transparent process thatis analogous to reading and writing from a file. In Windows 9x, however, there arerestrictions on what you can do with pipes. There are no events triggered whenthe buffer contains data. Also, there is no end-of-file marker when there is nothingin the buffer. There is a workaround for this, however. In the following Windows9x-compatible implementation, data is only read from Prolog after running a query.The result of every query, whether it fails or not, ends in the keyword stop tcl. Thiskeyword is used as a virtual end-of-file marker, telling Tcl to stop reading from theProlog process. The problem with this workaround is that Prolog can not triggerTcl events in the background. For the purposes of this project, this is not a majordrawback, since the interaction model is primarily:

1. user initiates a query

2. Tcl sends query to Prolog

3. Prolog responds to query, outputting a result

4. Tcl retrieves the result of the query and displays it to the user

Note also that my workarounds for Windows 9x are theoretically upward-compatibleto Windows NT and UNIX.

Another option would be to use Microsoft’s DDE (Dynamic Data Exchange)standard in place of piping. DDE is supported by both SWI-Prolog and Tcl/Tk.However, using it would eliminate any of the portability advantages of the pipingmethod.

Problem 2: Using stdio in SWI-Prolog

SWI-Prolog is a somewhat non-standard console application. It does not use stdio,(the stream which is most often used for piping,) for normal user interaction. Youcannot, for example, create an user input file and pipe it into SWI-Prolog at thecommand line. A workaround for this is to create a listener-loop that reads inputfrom stdio. Terms read by the listener-loop are then interpreted as standard Prologterms. Output from queries must likewise be explicitly printed to stdio using thewrite/1 predicate.

Once these two snags were worked out, the rest of the connector implementationfollowed easily. To ensure maximum portability, only library predicates defined aspart of the ISO standard Prolog were used.

3renamed fileevent as of Tcl/Tk v8.0

APPENDIX A. TCL/TK-PROLOG CONNECTOR SYSTEM 239

A.3.5 pl interface.tcl

Code

############################################################### Tcl /Tk s i d e o f t he SWI−P r o l o g <−−> Tcl /Tk i n t e r f a c e## W r i t t e n by : M i c h a e l Droettboom# yu143345@yorku . ca# Date : A p r i l , 1 9 9 9

# Based on an a r t i c l e d e s c r i b i n g a B i n P r o l o g <−−> Tcl /Tk# i n t e r f a c e by Andrea D e l l ’ Amico# h t t p : / /www. c l i . d i . u n i p i . i t / h e l p / p r o l o g / B i n P r o l o g / t c l

############################################################### USAGE :## % s t a r t p r o l o g p l c o n . exe −OR− % s t a r t t e s t# % q { Pro logQuery }# % p { Q u i e t P r o l o g G o a l }# % h a l t p r o l o g#

g l o b a l f

# t e s t s what Tcl would send to P r o l o gpro c s t a r t t e s t {} {

g l o b a l fs e t f s t d o u t

}

# t e r m i n a t e s t he P r o l o g p r o c e s spro c h a l t p r o l o g {} {

g l o b a l fw r i t e p r o l o g "halt"c a t c h { r e m o v e i n p u t $ f }c a t c h { c l o s e $ f }

}

# c o n n e c t s to a new P r o l o g p r o c e s s# p r o c e s s −− a s t a n d−a l o n e P r o l o g e x e c u t a b l e# t h i s P r o l o g must c o n t a i n the l i b r a r y ” t c l i n t e r f a c e . p l ”pro c s t a r t p r o l o g { p r o c e s s } {

g l o b a l fs e t f [ open "|$process" r +]f c o n f i g u r e $ f − b u f f e r i n g l i n ep u t s $ f { s t a r t t c l s e r v e r .}f l u s h $ fp u t s [ g e t s $ f ]r e t u r n $ f

APPENDIX A. TCL/TK-PROLOG CONNECTOR SYSTEM 240

}

# w r i t e s ” Something . ” to P r o l o gpro c w r i t e p r o l o g { s } {

g l o b a l fp u t s $ f $s .

}

# s e n d s to p r o l o g a g o a l to be q u i e t l y e v a l u a t e dpro c a s s e r t p r o l o g { l } {

w r i t e p r o l o g "assert_prolog(($l))"}

# s e n d s to p r o l o g a q u e ry w i t h v a r i a b l e s to be answeredpro c q u e r y p r o l o g { l } {

w r i t e p r o l o g "query_prolog(($l))"r e a d p r o l o g

}

# s h o r t h a n d f o r c a l l p r o l o gpro c p { l } {

a s s e r t p r o l o g $ l}

# s h o r t h a n d f o r q u e r y p r o l o gpro c q { l } {

q u e r y p r o l o g $ l}

# t r u e i f t he g i v e n l i n e i s to be e v a l u a t e d as a t c l command coming from P r o l o gpro c t c l c a l l { l } {

r e t u r n [ e x p r 0 == [ s t r i n g f i r s t "call_tcl " [ s t r i n g t r i m l e f t $ l ] ] ]}

# d e t e c t s i f an i n p u t l i n e c o n t a i n s a t c l c a l l# ( i . e . when i t s t a r t s w i t h ” c a l l t c l ”)# i f y e s then i t e x e c u t e s the l i n e# o t h e r w i s e i t p r i n t s i t outpro c e v a l l i n e { l } {

i f { [ t c l c a l l $ l ] } {r e t u r n [ e v a l $ l ]

} e l s e {p u t s $ l

}}

# r e a d s incoming data from P r o l o g u n t i l e n c o u n t e r i n g a ” s t o p t c l ” commandpro c r e a d p r o l o g {} {

g l o b a l fi f { $ f ! = "stdout" } {

v a r i a b l e l go

APPENDIX A. TCL/TK-PROLOG CONNECTOR SYSTEM 241

f o r {} { $ l ! = "tcl_stop" } {} {f l u s h $ fg e t s $ f le v a l l i n e $ l

}}

}A.3.6 tcl interface.pl

Code

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% P r o l o g s i d e o f t he SWI−P r o l o g <−−> Tcl /Tk i n t e r f a c e%%% W r i t t e n by : M i c h a e l Droettboom% yu143345@yorku . ca% Date : A p r i l , 1 9 9 9

% Based on an a r t i c l e d e s c r i b i n g a B i n P r o l o g <−−> Tcl /Tk% i n t e r f a c e by Andrea D e l l ’Amico% h t t p : / /www. c l i . d i . u n i p i . i t / h e l p / p r o l o g / B i n P r o l o g / t c l

%%%%%%%%%%%%%%%%%%%%%%%%% OPERATOR DEFINITIONS% ’$’ i s needed to send Tcl v a r i a b l e s to t he Tcl i n t e r p r e t e r

:−op ( 2 0 0 , f x , ( ’$’ ) ) .

%%%%%%%%%%%%%%%%%%%%%%%%% MAIN ENTRY POINT%% USAGE : s t a r t t c l s e r v e r .%% S t a r t s a l i s t e n e r l o o p to r e a c t to commands from Tcl

% main :− s t a r t t c l s e r v e r .

s t a r t t c l s e r v e r :−fo rmat (’TCL Server started.’ ) , n l , ! ,prompt ( , ’’ ) , % c r e a t e s a ’quiet’ promptr e p e a t ,n l , w r i t e (’tcl_stop.’ ) , n l ,t c l i n (X , Vs ) ,r e a c t (X , Vs ) ,! .

%%%%%%%%%%%%%%%%%%%%%%%%% INPUT%% USAGE :

APPENDIX A. TCL/TK-PROLOG CONNECTOR SYSTEM 242

% There a r e f o u r commands t h a t a r e a c c e p t e d from Tcl :% a s s e r t p r o l o g (X ) . −− add a g o a l to the d a t a b a s e% q u e r y p r o l o g (X ) . −− run a p r o l o g q u e ry% the keyword "tcl_stop" i s added% to the end o f a l l output .% h a l t o r e n d o f f i l e −− q u i t s t he i n t e r p r e t e r

r e a c t ( a s s e r t p r o l o g (X ) , ) :− ! , a s s e r t (X ) , ! , f a i l .r e a c t ( q u e r y p r o l o g (X ) , Vs ):− q u e r y p r o l o g (X , Vs ) , f a i l .r e a c t ( e n d o f f i l e , ) :− ! .r e a c t ( h a l t , ):− h a l t .

% r u n s a qu e r y , and d i s p l a y s the r e s u l t s o f a l l f r e e v a r i a b l e s .% adds "tcl_stop" to t he end .q u e r y p r o l o g (X , Vs ):−

X , member (A , Vs ) , w r i t e (A ) , n l , f a i l .q u e r y p r o l o g ( , ) :− ! .

% r e a d s terms from s t d i nt c l i n (T):− t c l i n (T , ) .

t c l i n (T , Vs ):−r e a d t e r m ( L , [ v a r i a b l e n a m e s ( Vs ) ] ) ,! ,t c l i n 1 ( L , T ) .

t c l i n 1 ( [ X | Xs ] , T):−! ,member (T , [ X | Xs ] ) .

t c l i n 1 (T , T ) .

none ( none ) .

%%%%%%%%%%%%%%%%%%%%%%%%% OUTPUT%% USAGE : c a l l t c l ( L i n e ) .% C o n v e r t s t he term L i n e i n t o output t h a t w i l l be p r o c e s s e d as% a Tcl command . The f i r s t e l e m e nt o f L i n e must t h e r e f o r e% be a p r o c e d u r e or v a r i a b l e .

c a l l t c l ( L i n e ):−w r i t e (’call_tcl ’ ) , t c l o u t ( L i n e ) .

t c l o u t ( [ X | Xs ] ) :−! , t c l o u t l i s t ( [ X | Xs ] ) .

t c l o u t (T):− t c l o u t t e r m (T ) .

t c l o u t l i s t ( L):−member (T , L ) , t c l o u t t e r m (T ) , f a i l .t c l o u t l i s t ( ) .

APPENDIX A. TCL/TK-PROLOG CONNECTOR SYSTEM 243

t c l o u t t e r m (T):− p l 2 t c l (T ) , ! .

p l 2 t c l (T):− p l 2 t c l (T , L ) , w r i t e l i s t ( L ) .

p l 2 t c l (X , L):− p l 2 t c l (X , L , [ ] ) .

% s e n d i n g f r e e v a r i a b l e s to Tcl makes no s e m a n t i c s e n s e , so e r r o r .p l 2 t c l (X)−−>{v a r (X ) } , ! , { w r i t e (’unexpected input: variable’ ) , t r u e } , [ ’error’ ] .% send atoms ’as is.’p l 2 t c l (X)−−>{atomic (X ) } , ! , [ X ] .% send atoms p r e c e d e d by $ as Tcl v a r i a b l e r e f e r e n c e sp l 2 t c l (’$’ (X))−−>!,{V=’$’ (X ) } , ! , [ V ] .% send l i s t s i n s i d e { }p l 2 t c l ( [ X | Xs ])−−> ! , [’{’ ] , p l 2 t c l (X ) , t c l c m d ( Xs ) , [ ’}’ ] .% send e x p l i c i t l y d e f i n e d { }p l 2 t c l ({Xs})−−>!,[’{’ ] , p l 2 t c l ( Xs ) , [ ’}’ ] .% send e x p l i c i t y d e f i n e d ( )p l 2 t c l ( (X , Xs))−−>!, p l 2 t c l (X ) , p l 2 t c l ( Xs ) .

t c l c m d ( [ X | Xs ])−−>!, p l 2 t c l (X ) , t c l c m d ( Xs ) .t c l c m d ( [ ] )−−> [ ] .

w r i t e l i s t ( L):−member (X , L ) ,t c l w r i t e (X ) , w r i t e ( ’ ’ ) ,f a i l .

w r i t e l i s t ( ) .

t c l w r i t e (’$’ (X ) ) :− ! , w r i t e (’$’ ) , w r i t e (X ) .t c l w r i t e (X):− w r i t e (X ) .

% :− s t a r t t c l s e r v e r .

BThe graphical user interface

This graphical user interface was designed to automate usage of the core Pelogsystem. This application will be made obsolete with the completion of the VisualPelog system.

The Pelog system includes a very basic user interface for performing the followingtasks:

• editing GUIDO Music Notation files that are used as input and output by thePelog system

• viewing the files as conventional music notation (cmn)

• listening to the files through the MIDI hardware

• applying a given set of musical rules to the file using the Pelog system

The Pelog-GUI is designed for the interactive application of pre-defined sets ofmusical rules. It does not directly provide the ability to customize or develop rulesets for Pelog. For that you’re better of using an editor with some advanced Prologsupport such as GNU Emacs. Please see The Pelog Language (page 2) for moreinformation.

For information on how to write GUIDO Music Notation files for the Pelogsystem, see GUIDO Music Notation (page 35).

B.1 Installing the GUI

The installation instructions given here are Microsoft Windows-specific. Please seeNotes about Portability (page 251) for more information.

The Pelog-GUI requires that the following freely available applications are in-stalled on your system:

244

APPENDIX B. THE GRAPHICAL USER INTERFACE 245

• Tcl/Tk version 8.1http://www.scriptics.com/

• SWI-Prologhttp://www.swi.psy.uva.nl/projects/SWI-Prolog/

• GUIDO NoteViewerhttp://www.informatik.tu-darmstadt.de/AFS/GUIDO

• gmn2midihttp://www.informatik.tu-darmstadt.de/AFS/GUIDO

Once all these applications have been successfully installed on your system, you willneed to ensure that Pelog-GUI can find all of the required executables by includingthem in your PATH environment variable. The executables that the Pelog-GUI needsare:

• wish81.exe (Tcl/Tk)

• plcon.exe (SWI-Prolog)

• gmnview.exe (GUIDO NoteViewer)

• gmn2midi.exe (gmn2midi)

An example PATH environment variable might look like this:

PATH C:\PROGRA~1\TCL\BIN;C:\PROGRA~1\SWI-PR~1\BIN;C:\PROGRA~1\GUIDO

Please consult the Microsoft Windows on-line documentation for more informationon setting your PATH environment variable.

B.2 Running the GUI

To run the Pelog-GUI, simply run the provided batch file pelog.bat. The easiestway to do this is by double-clicking on it in the Explorer. This script will start thePelog-GUI under Tcl/Tk’s wish interpreter. This will bring up the opening splashscreen in Figure B.1.

Click anywhere on the splash window to continue to the Pelog-GUI.

B.3 A quick introduction

The section will guide you through all of the basic functionality of the Pelog-GUI.The Pelog-GUI is very similar to many standard text editors such as Microsoft

Notepad included with Windows. The difference is that the Pelog-GUI is specificallytailored to edit musical scores used as input to the Pelog interpreter. For moreinformation about these files, see GUIDO Music Notation (page 35).

Let’s enter an score by typing the following line into the editor:

APPENDIX B. THE GRAPHICAL USER INTERFACE 246

Figure B.1: The Pelog-GUI splash window

{ [ c0 d e f g a b c1 ] }The outer set of curly brackets “{ }” is used to denote an entire score. The innerset of square brackets “[ ]” is used to denote an individual voice (or part) withinthat score. You can see that this score contains only one voice. In that voice thereare five notes each represented by a letter. The numbers after the letters select theoctave.

To look at the score as common music notation (cmn) press the button onthe toolbar. Figure B.2 shows the GUIDO NoteViewer displaying the score thatwe have entered:

You can also listen to the score through any available MIDI hardware by pressing

the button on the toolbar.So far, we haven’t done anything terribly exciting. The real power of the Pelog

system is in applying musical rules to scores. Before we can do that, however, wewill need to insert some variable notes into our score. Variable notes are noteswith unspecified pitch that the interpreter will fill-in in by applying musical rules.Variable notes are represented with the tilde “~” character. Change the score tolook like this:{ [ c ˜ ˜ ˜ ˜ ˜ ˜ c2 ] }This score indicates that we want the starting and ending notes to be c, but theinterpreter can fill-in the rest of the notes as it pleases. It is important to note thatthe tilde character is not supported by the view or look functions, and therefore youcannot view or listen to a score containing note variables.

The next step is to select a set of rules to use when filling in the variable notes.

Pressing the button in the toolbar brings up a dialog box containing

APPENDIX B. THE GRAPHICAL USER INTERFACE 247

Figure B.2: The GUIDO NoteViewer displaying the example score

all of the available rule sets on your system1. For now, lets choose the modalcounterpoint rule set. When you return from the dialog box you will notice thatthe text box on the right-hand side of the toolbar shows the name of the rule setwe just selected.

Now we are ready to apply the rules. Press the button on the toolbar. ThePelog system will load your score and run it through the rule set. Be patient. Thisparticular example took 30 seconds to solve on my Intel Pentium 166MHz machine.When the Pelog interpreter is finished, the results of its work are loaded into a newPelog-GUI window.

This output score can be viewed or listened to just like the input score. Youcan even revise it, including adding variable notes, and then run it through theinterpreter again.

1For a detailed explanation of rule sets, see The Pelog Language (page 2.)

APPENDIX B. THE GRAPHICAL USER INTERFACE 248

B.4 Visual elements

B.4.1 The main window

The main window should seem quite familiar to anyone accustomed to typicalWindows or Macintosh applications. It consists of a menubar, toolbar and texteditor.

B.4.2 The menubar

B.4.3 The toolbar2

2These toolbar graphics are from a set developed by IBM/Lotus and freely available fromIBM Ease of Use http://www.ibm.com/easy/. The toolbar images developed by Microsoft areperhaps more standard, but are licensed for use only in conjunction with Microsoft’s own softwaredevelopment products.

APPENDIX B. THE GRAPHICAL USER INTERFACE 249

B.4.4 The editor

The editor is a standard text editor identical in functionality and behaviour toMicrosoft Windows Notepad.

B.5 Functions

B.5.1 Basic file and editing functions

The basic file and editing functions should be old hat to anyone familiar with Win-dows. The behaviour is identical to Microsoft Windows Notepad.

B.5.2 Look

The Look function is available from the View menu or by pressing on the toolbar.This opens the GUIDO NoteViewer to display the contents of the editor in

common music notation (cmn). Notice that Look displays exactly what is in theeditor when it is activated, not the saved version of the file.

Figure B.3: The GUIDO NoteViewer window opened by the View Look function

For information about using the GUIDO NoteViewer, please see the online helpon the Help menu in the NoteViewer window.

B.5.3 Hear

The Hear function is available from the View menu or by pressing on the toolbar.This opens the Windows Media Player to play the contents of the editor. Like

the Look function, Hear plays exactly what is in the editor when it is activated.

APPENDIX B. THE GRAPHICAL USER INTERFACE 250

Figure B.4: The Windows Media Player opened by the View Hear function

The Windows Media Player plays MIDI files on currently selected MIDI device.This MIDI hardware could be a sound card, such as the popular Sound Blaster, oran external MIDI device such as a keyboard or sound module. This device can beselected using the Multimedia applet in the Windows Control Panel. See the onlinehelp in the Media Player itself for more information on using Microsoft WindowsMedia Player.

Note: At the present time, the gmn2midi application that convertsGUIDO Music Notation format files into standard MIDI files is stillin beta testing. Just from my own informal usage, it has proven tobe quite weak in certain areas. For instance, when playing the “HappyBirthday” example above, the bass part is consistently a full beat aheadof the treble.

B.5.4 Go

The Go function is available from the Rules menu or by pressing the toolbarbutton.

This function applies the currently selected Pelog rule set to the currently openedinput file.

The rule set can be chosen with a file dialog by selecting the Rules Select Rule

Set... menu item or pressing the toolbar button. The rule set namecan also be typed in directly to the text box at the right-hand side of the toolbar.

APPENDIX B. THE GRAPHICAL USER INTERFACE 251

After the Pelog interpreter is finished applying rules to the file (which may takequite some time depending on the complexity of the rule set and the number ofvariables in the input file), the result is opened in a new Pelog-GUI window. Thename of the results file is identical to the name of the input file with out appendedto the end.

B.6 Notes about portability

At the time of this writing, the Pelog-GUI has only been tested on the 32-bitMicrosoft Windows platform. While it is theoretically portable to any platformTcl/Tk runs on, certain functions remain Windows-specific:

• The Look function uses the GUIDO NoteViewer to display the music in com-mon music notation. This application is currently only available for Win-dows.3

• The Hear function uses two external applications. The first, gmn2midi con-verts GUIDO music notation format files into Standard MIDI files. This pro-gram is currently available for many platforms including Windows, Macintoshand UNIX. 4 The second application is the Media Player supplied with Win-dows to play standard MIDI files. This application could be substituted withany of the commonly available MIDI players available on many platforms.

3See http://www.informatik.tu-darmstadt.de/AFS/GUIDO for more information.4See http://www.informatik.tu-darmstadt.de/AFS/GUIDO for more information.

Bibliography

[1] —, Tcl/Tk Reference Manual. www.scriptics.com

[2] —, Max: object-oriented programming environment for mu-sic and multimedia. Mountain View, CA: Opcode Systems, Inc.http://www.opcode.com/products/max/

[3] Bowman, Ivan. “Lecture Notes on ‘Methods for Visual Understanding ofHeirarchical Systems’ Sugiyama et al.” University of Waterloo, ON, CS746G.http://plg.uwaterloo.ca/ itbowman/CS746G/Notes/Sugiyama1981/

[4] Brinkman, Alexander. Pascal Programming for Music Research. Chicago, IL:University of Chicago Press, 1990.

[5] Clocksin, William F. & Christopher S. Mellish. Programming in Prolog. NewYork: Springer-Verlag, 1987.

[6] Cope, David. Experiments in Musical Intelligence. Madison, WI: A-R Editions,1989.

[7] Cormen, Thomas H. & Leiserson, Charles E. & Rivest, Ronald L. Introductionto Algorithms. Cambridge, MA: MIT Press: 1997.

[8] Di Battista, Giuseppe & Peter Eades & Roberto Tamassia & Ioannis G. Tollis.Graph Drawing: Algorithms for the Visualization of Graphs. Englewood Cliffs,NJ: Prentice Hall, 1999.

[9] Eades, Peter & Kang Zhang, eds. Software Visualization. Singapore: WorldScientific, 1996.

[10] Eppstein, David. Geometry in Action. University of California Irvine.http://www.ics.uci.edu/ eppstein/gina/gdraw.html

[11] Fux, Johann Joseph. (1725) The Study of Counterpoint from Johann JosephFux’s Gradus ad Parnassum, translated and edited by Alfred Mann. New York:W. W. Norton & Co., 1943.

[12] Haus, Goffredo. Music Processing. Madison, WI: A-R Editions, 1992.

252

BIBLIOGRAPHY 253

[13] Himsolt, M. “GraphEd - A Graphical Platform for the Implementationof Graph Algorithms” Graph Drawing, Proceedings of DIMACS Interna-tional Workshop GD’94. Lecture Notes in Computer Science 894. New York:Springer-Verlag, 1995.

[14] Hoos, Holger & Keith Hamel & K. Renz & J. Kilian. “The GUIDO MusicNotation Format - A Novel Approach for Adequately Representing Score-levelMusic.” ICMC’98 Proceedings.

[15] Hoos, Holger H. & Keith Hamel. The GUIDO Music Notation FormatVersion 1.0: Specification Part I: Basic GUIDO. Technical Report TI20/97. Darmstadt, Germany: Technische Universitat Darmstadt, 1997.http://www.informatik.tu-darmstadt.de/AFS/GUIDO/

[16] Horton, William. The Icon Book: Visual Symbols for Computer Systems andDocumentation. New York: John Wiley & Sons, 1994.

[17] Hylands, Christopher & Edward A. Lee & H. John Reekie. “The Tycho UserInterface System.” Tcl/Tk Workshop ’97 Proceedings. Ed. Joseph A. Konstan& Brent Welch. Berkeley, CA: USENIX Association, 1997.

[18] Ibrahim, Bertrand. “Visual Languages and Visual Programming.” WWW Vir-tual Library.

[19] Kamada, Tomihisa. Visualizing Abstract Objects and Relations — AConstraint-Based Approach. Singapore: World Scientific, 1989.

[20] Krenek, Ernst. (1953) Modal Counterpoint in the Style of the Sixteenth Century.New York: Boosey & Hawkes, 1959.

[21] Lafever, Dave. “Visual Programming and Assistive Technology.” Dr. Dobb’sJournal. Aug. 1999.

[22] Lee, Geoff. Object-Oriented GUI Application Development. Englewood Cliffs,NJ: PTR Prentice Hall, 1993.

[23] Lutz, Mark. Programming Python. Sebastopol, CA: O’Reilly & Associates,1996.

[24] O’Keefe, Richard. The Craft of Prolog. Cambridge, MA: MIT Press, 1990.

[25] Paulisch, Frances Newbery. EDGE: The Design of an Extendible Graph Ed-itor. Lecture Notes in Computer Science Series, Ed. Gerhard Goos & JurisHartmanis. New York: Springer-Verlag, 1991.

[26] Randel, Don Michael, ed. The New Harvard Dictionary of Music. Cambridge,MA: Belknap Harvard, 1996.

[27] Reekie, H. John & Edward A. Lee. “The Tycho Slate: Complex Drawingand Editing in Tcl/Tk.” Tcl/Tk Workshop ’98 Proceedings. Ed. Don Libes& Michael McLennan. Berkeley, CA: USENIX Association, 1998.

BIBLIOGRAPHY 254

[28] Ross, Peter. Advanced Prolog: Techniques and Examples. Don Mills, ON:Addison-Wesley, 1989.

[29] Rowe, Neil C. Artificial Intelligence Through Prolog. Englewood Cliffs, NJ:Prentice Hall, 1988.

[30] Salus, Peter H., ed. Handbook of Programming Languages: Volume III: Lit-tle Languages and Tools. Indianapolis, IN: Macmillan Technical Publications,1998.

[31] Salus, Peter H., ed. Handbook of Programming Languages: Volume IV: Func-tional and Logic Programming Languages. Indianapolis, IN: Macmillan Tech-nical Publications, 1998.

[32] Schaffer, John & Deron McGee. Knowledge-Based Programming for Music Re-search. Madison, WI: A-R Editions, 1997.

[33] Schottstaedt, William. (1984) “Automatic Counterpoint.” Current Directionsin Computer Music Research. Ed. Max V. Mathews and John R. Pierce. Cam-bridge, MA: MIT Press, 1989.

[34] Sterling, Leon & Ehud Shapiro. The Art of Prolog: Advanced ProgrammingTechniques. Cambridge, MA: MIT Press, 1986.

[35] Sugiyama, Kozo & Shojiro, Tagawa & Toda, Mitsuhiko. “Models for VisualUnderstanding of Heirarchical System Structures.” IEEE Trans. on Systems,Man and Cybernetics. Vol SMC-11, No 2, Feb 1981, pp 109-125.

[36] Taube, Rick. Introduction to Common Music.http://cm.stanford.edu/CCRMA/Software/cm/cm.htm

[37] Thakar, Markand. (1990) Counterpoint: Fundamentals of Music Making. NewHaven, CN: Yale University Press, 1990.

[38] Thompson, Tim. Reference Manual for the KeyKit Language Version 6.2c. SanJose, CA: AT&T, 1997.

[39] Van Hentenryck, Pascal. Constraint Satisfaction in Logic Programming. Cam-bridge, MA: MIT Press, 1989.

[40] Vercoe, Barry. CSound Reference Manual. Cambridge, MA: MIT Machine Lis-tening Group, 1999.

[41] Wielemaker, Jan. SWI-Prolog 3.2 Reference Manual. Amsterdam: Depart-ment of Social Science Informatics (SWI), University of Amsterdam, 1999.http://www.swi.psy.uva.nl/projects/SWI-Prolog/

All musical examples were rendered using GUIDO NoteServer for Windows v0.2.http://www.informatik.tu-darmstadt.de/AFS/GUIDO

BIBLIOGRAPHY 255

All musical constraint graphs were rendered directly using Visual Pelog.

This document was typeset using LATEX and Carl Heinz’ exceptional listings package.