Sunteți pe pagina 1din 122

INFORMATION TO USERS

This manuscript has been reproduced from the microfilm master. UMI
films the text directly from the original or copy submitted. Thus, some
thesis and dissertation copies are in typewriter face, while others may
be from any type of computer printer.

The quality of this reproduction is dependent upon the quality of the


copy submitted. Broken or indistinct print, colored or poor quality
illustrations and photographs, print bleedthrough, substandard margins,
and improper alignment can adversely afreet reproduction.

In the unlikely event that the author did not send UMI a complete
manuscript and there are missing pages, these will be noted. Also, if
unauthorized copyright material had to be removed, a note will indicate
the deletion.

Oversize materials (e.g., maps, drawings, charts) are reproduced by


sectioning the original, beginning at the upper left-hand comer and
continuing from left to right in equal sections with small overlaps. Each
original is also photographed in one exposure and is included in
reduced form at the back of the book.

Photographs included in the original manuscript have been reproduced


xerographically in this copy. Higher quality 6" x 9" black and white
photographic prints are available for any photographs or illustrations
appearing in this copy for an additional charge. Contact UMI directly
to order.

U niversity M icrofilm s In ternational


A Bell & Howell Inform ation C o m p a n y
3 0 0 N orth Z e e b R o a d . A nn A rbor, Ml 4 8 1 0 6 -1 3 4 6 USA
3 1 3 /7 6 1 -4 7 0 0 8 0 0 /5 2 1 -0 6 0 0

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
Reproduced with permission of the copyright owner. Further reproduction prohibited without permission.
O rder N u m b er 9 4 1 4442

A com puter system to im prove violin intonation

Meyer, Hwa-Soon, Ed.D.


Columbia University Teachers College, 1993

C op y rig h t © 1 9 9 3 b y M e y e r , H w a -S o o n . A ll rig h ts reserved .

UMI
300 N. ZeebRd.
Ann Arbor, MI 48106

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
Reproduced with permission of the copyright owner. Further reproduction prohibited without permission.
A COMPUTER SYSTEM
TO IMPROVE VIOLIN INTONATION

by

Hwa-Soon Meyer

Dissertation Committee:
Professor Robert Pace, Sponsor
Professor Harold Abeles

Approved by the Committee on the Degree of Doctor of


Education
oats SEP 2 7 1993

Submitted in partial fulfillment of the


requirements for the degree of Doctor of Education
in College Teaching of an Academic Subject
Teachers College, Columbia University

1993

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
c Copyright Hwa-Soon Meyer 1993
All Rights Reserved

ii

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
ABSTR A CT

A COMPUTER SYSTEM TO IMPROVE VIOLIN INTONATION

Hwa-Soon Meyer

A computer system was developed as an educational aid


that can help violinists of all skill levels improve their
intonation. A violinist can improve intonation by
developing a better sense of pitch discrimination, and pitch
discrimination can be improved when aural perception is
reinforced with visual perception.
The computer system developed to assist the improvement
of violin intonation consists of both hardware and software.
There are two essential hardware components. One is a
microcomputer, either an Apple Macintosh or an IBM-
compatible PC. The other is an instrument called a "Pitch
Analyzer." The Pitch Analyzer is an electronic device that
was created exclusively for the present project to detect the
fundamental frequencies of tones.
The software consists of three independent computer
programs. These programs are 1) Tuning the Open Strings, 2)
Playing Scales, and 3) Playing Musical Passages. The student
may use any one of these three programs without running the
other two, or choose all three programs in any order and/or
combination. Within each program, the student can select one

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
of two different tuning systems (i.e. either Pythagorean
tuning or equal-tempered tuning system), error tolerance
level, metronome setting, and "practice" vs. "test" session.
A "practice" session runs in real time, with instant
display and immediate feedback. For the instant display,
vertical bar graphs appear on the screen above the
corresponding notes, resembling a series of thermometers. If
the pitch of the tone being played is too high, the level of
the colored portion rises from the marked halfway point; if
the pitch is too low, it falls below the halfway point. This
display enables the student to see how far off he or she is
from the perfect pitch, and correct it before proceeding to
the next note.
In the "test" session, the student plays through a scale
or musical passage, without correcting the notes as he or she
proceeds. A score is shown upon completion of the scale or
passage, thereby monitoring the student's progress and giving
him or her incentive to improve.

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
ACKNOWLEDGEMENTS

I would like to thank Professor Robert Pace, my advisor


and sponsor, and Professor Harold Abeles for their close
attention and assistance during my doctoral studies.

I am greatly indebted to Karl Schinke, whose expertise


in electronics and electrical engineering was instrumental in
constructing the Pitch Analyzer, which was vital to this
dissertation.

Professor Rimas Vaicaitis of Columbia University served


on the doctoral thesis committee and made available his
acoustics lab and equipment for spectrum analyses.

My deepest appreciation goes to my husband, Professor


Christian Meyer, for his untiring technical and moral
support.

H.M.

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
TABLE OF CONTENTS

Chapter 1: INTRODUCTION ....................... 1


I. Rationale . . . . . . . 1
II. Purpose . . . . . . . 2
III. Related Literature and Materials . . 3
IV. Limitations . . . . . . 11
Chapter 2: SYSTEM DESCRIPTION ................... 13
I. Overview . . . . . . . 13
II. Hardware System . . . . . 15
III. Software . . . . . . . 20
Chapter 3: SYSTEM APPLICATION .................. 25
I. User's Guide . . . . . . 25
II. Tuning the Open Strings . . . . 26
III. Playing Scales . . . . . . 31
IV. Playing Passages . . . . . 34
Chapter 4: CONCLUSIONS ....................... 37
I. Preliminary Test and Evaluation . . 37
II. Summary and Conclusion . . . . 38
III. Future Development . . . . . 40
Bibliography . . . . . . . . 43
Appendix: Source Code of the Computer Programs . 46

iv

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout p erm ission .
L IST OF T A B L E S

Table 1 Five filters dividing the amplified signal


into five one-octave bands . . . 17

Table 2 Difference in frequencies between two tuning


systems . . . . . . . 22

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
L IS T OF F IG U R E S

Figure 1 : Carl E. Seashore's "Tonoscope" . . 4

Figure 2 : The hardware system . . . . . 14

Figure 3 : The Pitch Analyzer . . . . . 16

Figure 4 : Input signal passing through five filters 18

Figure 5 : Input signal and "squared signal" of the


Schmidt Trigger . . . . . 19

Figure 6 : Screen display of student tuning the E


string in the Pythagorean tuning system,
after having successfully tuned the A, D,
and G strings . . . . . . 29

Figure 7 : Screen display of student playing a C major


scale . . . . . . . 33

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
1

Chapter 1
INTRODUCTION

I . Rationale

Beginning violin students, and even some violinists who


have been studying for a long time, do not necessarily
possess a well developed sense of pitch discrimination.
Often, left on their own, they have difficulty discerning
whether a note is too high, too low, or in tune. When
students go in for the weekly lesson, the teacher must tell
them to play a note higher or lower in order to be correct.
But when alone, how does a student, without having developed
a good sense of pitch discrimination, practice playing in
tune?

Indeed, playing in tune is a major challenge for all


string players. It sets the beginner apart from the
experienced performer, the experienced performer from the
world-famous professional, and even one world-famous
professional from another. The challenge to play in tune
begins even before the students play the first note, when
they try to tune their instrument; and it never ends.

Teacher and student devote many hours of work to reach a


point where the student can finally play correct notes,

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
2

reasonably in tune, before they proceed with other elements


of music making such as dynamics, phrasing, vibrato, or
musical interpretation. The present study recognizes pitch
discrimination as a prerequisite for playing in tune.

II. Purpose

The purpose of this dissertation is to develop a


computer system that will assist violin players in improving
their intonation, regardless of their level of proficiency.

Teaching music with the help of computers is not new.


In fact, the use of computer technology in music and music
education has entered its third decade. From the earliest
educational music software developed in the late 1960's,
called "Computer-Assisted Instruction" (CAI), technology in
education has made considerable progress towards a multimedia
system, now called "Technology-Based Education" (TBE).

Music educators have recognized the value of computer


assistance in instruction, as individual learning needs can
sometimes be addressed more efficiently at the computer than
in the classroom. This frees music teachers and enables
them to direct their time and attention towards students'
aesthetic learning.

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
The present computer system is intended to assist
students' intonation, especially when they practice alone
away from their teachers. With personal computers readily
available and an integral part of everyday life, computer
literacy among young students is astounding. It is to be
hoped that students, beginning at an early age, will benefit
from the system in sharpening their sense of pitch
discrimination, with the aid of aural and visual
reinforcement. Detailed descriptions as to how this system
works will be given later in Chapters 2 and 3.

III. Related Literature and Materials

Pitch extractors that measure the accuracy of pitch in


singing or playing an instrument have interested researchers
in areas as diverse as music, acoustics, physics, and even
psychology.

One of the first of its kind was an instrument called a


"Tonoscope," constructed by Carl E. Seashore in 1930 as a
result of his study conducted at the University of Iowa.
(See Figure 1.) Seashore recognized even then the future
direction toward the application of scientific techniques in
improving and mastering the art of music. The application of
his "Tonoscope" in improving intonation was very similar to
the present study in that it measured the pitch of a singer

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
4

mmrnm

Figure 1
Carl E. Seashore's "Tonoscope" (from "The Measurement of
Pitch Intonation with the Tonoscope in Singing and Playing,"
University of Iowa Studies, 1930).

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
5

or a player and recorded it immediately in the form of a line


graph. The performer could see the accuracy of the
intonation and correct it as necessary. This instrument was
invented long before the computer age.

As computer technology in music education developed


further from the 1960's to the 1980's, there resulted several
research projects in pitch discrimination and ear training at
various college campuses.

Wolfgang Kuhn and Raynold Allvin (1967) at Stanford


University wrote one of the first Computer-Assisted
Instruction (CAI) systems, exploring the initial phase of the
interaction between student and machine. To this end, an
experimental instructional system was developed. The main
contribution of the system is the pitch extraction device,
which uses "an inaudible model tone to pick out successive
peaks of the fundamental frequency." (Kuhn, p. 307)

Using an IBM 1620 computer, Kuhn and Allvin limited


their curriculum program to a series of sight-singing
exercises in which the student was asked to sing a set of
intervals. The system was tested with college students and
received positive results. Seven years later Kuhn (1974)
developed an ear-training drill and practice program using a
Teletype Model 33 KSR terminal and an electronic organ that
could be played by the computer.

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
6

The most significant innovation in this later program


was the real time interaction. Real time refers to "the
collection of data as it becomes available and processing it
before subsequent incoming data needs to be collected and
processed, as opposed to storing incoming data for processing
at a later time." (Kolb, 1984, p. 4) Studies of intervals,
triads, rhythmic and melodic dictations, chord progressions,
and modulation were developed with the emphasis in the
individualized instruction. The material was designed for
primary school age children, and was tested with a group of
students in grades two through six. The results are not
reported.

In 1974, under the auspices of Fred Hofstetter (1975),


the University of Delaware "established a center for
computational musicology for improvement of instruction in
music courses and investigation of the nature of musical
skills. During its first year the center has developed an
interactive computing system (named GUIDO, for Graded Units
for Interactive Dictation Operations) for recording student
learning patterns in ear-training courses." (Hofstetter, p.
100)

GUIDO, a computer-based dictation system, consists of


two different programs: a drill-and-practice program and a
touch-sensitive playing program. To implement two different

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
7

programs Hofstetter needed two different computers - a


Burroughs 6700 and Plato System - with programs written in
two different languages - ALGOL and TUTOR. The experiment
conducted with a freshman ear-training class on drill-and-
practice harmonic dictation showed a positive result.

The North Texas State University has been the scene of


busy activity in CAI. Among other projects at the
institution, Robert Ottman et al. (1980) have developed ear-
training, sight-singing, and theory CAI systems for six
hundred undergraduate students using a Hewlett-Packard 2000
computer.

So far, the studies mentioned above represent what David


Peters (1992) has termed the first and second generations of
software. These music software systems were created on very
large mainframe computers, whose cost was very high if not
outright prohibitive. The high cost of the computer
equipment was the main reason why most of the studies were
conducted at colleges, which already had the equipment.
Although these computers are now obsolete, and most of the
studies were limited to sight-singing and ear-training drill
and practice, these studies were the catalyst for further
research in this area.

The 1980's mark the generation of personal mini­


computers at home as well as in the work place. From the

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
8

Louisiana State University, Randall Kolb (1984) produced and


tested a sound-to-notation translator for sight-singing
students, "capable of determining the pitch of aural tones
and displaying those pitches in music notation." (Kolb, p. 2)
The translator was to listen to a singer, extract the
fundamental pitch of the tones in real time, point out the
errors, and show the degree of accuracy of the student's
pitch as a percentage.

This project distinguished itself from others by being


affordable, which was one of the main objectives of the
developer. The microcomputer used for the project was a
Sorcerer, whose manufacturer, unfortunately, went out of
business during the course of the project. It is not known
if Kolb's project has been adapted for use with any other
computers.

Whereas most of the available tools and programs for


pitch discrimination mentioned so far are directed towards
sight-singing, Mark Eisele (1985) from Indiana University
makes reference to string instruments. Using an Apple II
Plus microcomputer, Eisele developed a computer-assisted
instructional program designed to improve pitch
discrimination of sixth, seventh, and eighth grade violin and
viola students. In this program, the student interacts with
the computer without having to play any notes on an
instrument.

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
9

Eisele chose ten notes from the D and A strings of a


violin or viola (D, E, F, F#, G, A, B, C, C#, and D) for the
purpose of ear training, by comparing two pitches produced by
the computer. The student views and listens to two random
notes out of the ten above, and is instructed to choose the
lower of the two. Eisele writes that the results of the
pretest and posttest indicate that such a program can improve
students' pitch discrimination.

Meanwhile, the commercial music industry has been


diligent in producing devices that can help students' ear-
training and sight-singing. Some companies come and go, and
some products disappear from the market after a couple of
years. These companies and products are too numerous to list
them all here.

There are, however, several companies that have been


fixtures in the industry and in national conferences, where
they exhibit their latest products. Among these companies
are the Korg Company (Westbury, NY), Temporal Accuity
Products (Bellevue, WA), Electronic Courseware Systems
(Champaign, IL), Coda Music Software (Minneapolis, MN), and
Ars Nova (Kirkland, WA), to name a few.

The latest development in intonation studies is a


computer system called "Amadeus II," developed by a company

R e p r o d u c e d with p erm ission o f th e copyright ow ner. Further reproduction prohibited without perm ission.
10

called Pyware (Grapevine, TX). Standing alone as a pitch


detection device or combined with Apple Macintosh software,
Amadeus II can detect the student's pitch, display the notes,
and indicate how sharp or flat it is. Amadeus II works for
singers and wind players.

According to the president of the company, Mr. Py Kolb


(1993), at the present time Pyware is developing "Amadeus
III," which will be able to process string players' pitches,
handle rhythm and double stops, and show the frequency
numbers of notes. Unlike Amadeus II, Amadeus III will use
Past Fourier Transform analysis, which will make the above
tasks possible.

It has been stated implicitly and explicitly that the


pitch extraction of violin sounds is no easy matter. Each
violin has its own distinct, complex frequency spectrum.
Additionally, the amplitude of the overtones of a violin is
higher than that of the fundamental tone in the lower
register. Without a predominant fundamental frequency, pitch
detection becomes very difficult. There are a few methods
that can overcome this problem, such as Fast Fourier
Transform (FFT) and auto-correlation, but each method
requires a trade-off between time and cost. These methods
are either very slow or prohibitively expensive to adapt to
real-time processing. The method used to extract the
fundamental frequencies for the present project is called a

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout p erm ission .
11

"zero-crossing counter," which will be explained in more


detail in Chapter 2.

IV. Limitations

The present project is not without its own limitations.


The biggest shortcoming of the "zero-crossing counter" as the
frequency extraction method is that the device can not
process double stops.

It must be stated here that some of the system's


limitations are inherent in the physical design of the Pitch
Analyzer, such as resulting from the choice of the pitch
extraction method. Others are simply the outcome of
decisions to narrow the scope of the present study to a
manageable size, and therefore can be corrected by expanding
the scope in future studies. (See Chapter 4 - Future
Development.)

One of the limitations results from the averaging of the


frequencies. In test mode, the computer averages the
frequencies of a note over its entire duration. In this way,
vibrato oscillations are filtered out, similarly to human
perception. But when a student plays a note with major
adjustments, for example, from a very flat to a very sharp
level, then the computer’s averaging process may lead to its

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout p erm ission .
12

conclusion that the note was actually in tune. However, this


would be unlike the perception of a human observer.

The microprocessor of the Pitch Analyzer is programmed


at present to average the frequency of recorded sound over
intervals of one twentieth of a second. This time interval
is shorter than the notes that most violinists are capable of
playing. If a violinist does play more than twenty notes
per second, the system would record more than one note per
sampling interval, and would report meaningless frequencies.
This time interval can be shortened or lengthened by
reprogramming the microprocessor. There are, however,
physical limitations based on the time needed for the
microprocessor to send the measurement data over the serial
link to the computer.

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
13

Chapter 2
SYSTEM DESCRIPTION

I . Overview

The computer system developed to assist the improvement


of violin intonation consists of both hardware and software.
There are two essential hardware components. One is a
microcomputer, either an Apple Macintosh or an IBM compatible
PC. The present project uses an Apple Macintosh Ilsi with a
central core memory of 5 megabytes Random Access Memory and
80 megabytes hard disk space.

The other is an instrument called a "Pitch Analyzer."


The Pitch Analyzer is an electronic device that was created
exclusively for the project. A detailed description of the
device will be given later in the "Hardware System" section.
A modem cable connects these two components, and optional
speakers may be installed for better sound output. A
separate microphone plugs into the Pitch Analyzer for the
sound input. (See Figure 2.)

The software consists of three independent computer


programs, written in the language "THINK Pascal." Students
have the option of choosing any one of these three programs
without running the other two. The complete source code of
the three programs can be found in the Appendix.

R ep ro d u ced with p erm ission o f the copyright ow ner. Further reproduction prohibited without p erm ission.
14

Microphone

Monitor

?
* Macintosh

Pitch Analyzer
z

Speaker

Figure 2
The hardware system.

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
15

II. Hardware System

The Pitch Analyzer's main function is to detect the


fundamental frequency of a note and send this information to
the main computer through a modem cable and serial port. The
Pitch Analyzer itself consists of several parts. They are
the amplifier, filters, Schmidt Triggers, microprocessor, and
line driver. (See Figure 3.)

The sound from a violin travels through the air in the


form of sound pressure waves. When these waves reach the
microphone, the microphone converts the waves into an
electrical signal and sends this signal to the Pitch
Analyzer.

The signal arriving at the Pitch Analyzer is amplified


twice by a two-stage analog amplifier, to a sufficient
strength. The present circuit requires a strength of 2.5 to
3.0 volts to activate the Schmidt Triggers. The amplifier
used in the Pitch Analyzer has a reasonably constant response
over the range of 60hz to 6000hz, which includes the entire
frequency range of a violin.

The amplified signal is then divided into five one-


octave bands using five filters. (See Table 1.)

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
16

Microphone

1st Stage Amplifier Pitch Analyzer


2nd Stage Amplifier

"AND1
Gates

Line Driver

5-Octave Filters Microprocessor


and Schmidt Triggers

Computer

Figure 3
The Pitch Analyzer.

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout p erm ission
17

Filter Frequency Range (in Hertz)

1 125 - 250
2 250 - 500
3 500 - 1000
4 1000 - 2000
5 2000 - 4000

Table 1
Five filters dividing the amplified signal
into five one-octave bands.

This multi-band filtering is necessary to detect the


fundamental tone, and in certain situations also the
overtones to reconstruct the fundamental tone if its
amplitude is too small to activate the Schmidt Trigger, or
indeed missing altogether. (See Figure 4.)

The output of each filter is fed to its own Schmidt


Trigger to "square up" the signal. A Schmidt Trigger, much
like a light switch, is turned on when the electrical signal
reaches a critical positive voltage threshold and is turned
off when it reaches a critical negative voltage threshold.
(See Figure 5.)

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
18

Input Signal

1st Filter

2nd Filter

3rd Filter

Logical "AND" Gates


4th Filter

nnnnnnnnnnnnnnnnnnnnn
5th Filter

H n
Output Signal

Figure 4
Input signal passing through
five filters.

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
19

Voltage
Input Wave Form Positive Voltage Threshold

Time

- Negative Voltage Threshold

Output "Squared" Wave Form

Time

. Switch Switch . Switch t_ Switch


Turned On Turned Off Turned On Turned Off

Figure 5
Input signal and "squared signal"
of the Schmidt Trigger.

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
20

Finally, the on and off signal which is represented in a


"squared form" (as shown in Figure 5) causes an interrupt in
the microprocessor. The microprocessor counts the number of
interrupts, measures the time elapsed between them, and sends
this information to the microcomputer through an RS 232
serial link (a standard modem cable) twenty times per second.

The computer system is configured in such a way that the


number of interrupts in the microprocessor corresponds to the
number of zero-crossings of the fundamental frequency of the
note recorded by the microphone. The software (computer
program) is able to determine the frequency of the note in
Hertz from this data.

III. Software

The three independent computer programs are: Tuning the


Open Strings; Playing Scales; and Playing Passages. In all
three programs the student has the following options:
1. Different tuning (scale) systems
2. Error tolerance level
3. Metronome setting
4. Practice session
a. with bar graphs
b. play back student's notes
c. play back correct notes

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
21

d. practice together with computer


5. Test session with score.

1. Tuning system:
The frequencies of two different tuning systems are
incorporated into the programs. Traditionally, violin
players have favored the Pythagorean tuning system. This is
true especially when a violinist plays a solo or with other
string players. Pythagorean tuning is derived from the
consonance ratios of the harmonic series. For example, the
ratios of a fourth, fifth, and octave are 4/3, 3/2, and 2/1,
respectively. When a student tunes the open strings in the
Pythagorean system, by listening to the beats, the two
adjacent strings are in perfect consonance of fifths. This
is very desirable for string instruments.

Violin players, however, will have to become familiar


with another tuning system sooner or later: equal
temperament. Keyboard instruments are usually tuned to a
tempered scale, meaning compromised (Campbell, 1987), because
the pitches of notes can not be changed during performance.
In equal temperament, one octave is divided into twelve equal
semitones, with the fixed A string at 44 0 Hertz. The
difference in frequencies between the two tuning systems is
shown in Table 2.

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
22

G D A E
Pythagorean 195.6 293.3 440.0 660.0
Equal Tempered 196.0 293.7 440.0 659.3

Table 2
Difference in frequencies between two tuning systems.

2. Error Tolerance Level:


Especially for beginners and students with less keen
ears, an error tolerance option is provided. It is measured
in "cents." In common practice, one semitone is divided into
100 cents. Therefore the present system will recognize 50
cents sharp or flat as the maximum error. If a note is out
of tune by more than 50 cents, the computer will regard that
note as the next higher or lower note. Thestudent will set
the tolerance level according to his or her pitch
discrimination ability. The object is to reduce it
progressively as intonation improves.

According to Seashore, "the average threshold for an


unselected group of adults is about 3 Hertz at the level of
international pitch, 435 Hertz. This is 1/17 of a tone. But
a very sensitive ear can hear as small a difference as 0.5
Hertz or less, which, at this level, is less than 0.01 of a
tone." (Seashore, 1967, p. 56) One one-hundredth of a tone
represents two cents, or 1/50 of a semitone. Students are
certainly encouraged to close the gap between their pitch and

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
23

the correct pitch - in other words, decrease their error


tolerance level.

3. Metronome Setting:
If the student wishes to practice in different tempi, he
or she may enter a metronome setting, and the computer beats
the time for ten seconds before the student begins playing.

4. Practice session:
The student may decide to practice the piece with the
computer, or take a test run. One way is to start with a
test session for an initial assessment, switch to the
practice session, and then go back to the test to measure
improvement.

The practice session runs in real time with instant


display and immediate feedback. For the instant display,
vertical bar graphs appear on the screen above the
corresponding notes, resembling a series of thermometers. If
the note being played is too high, the level of the colored
portion rises from the marked halfway point; if too low, it
will fall below the halfway point. This enables the student
to see how far off he or she is from the perfect pitch, and
correct it before proceeding to the next note.

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
24

Upon completion, the student may play back his or her


pitches, listen to the correct pitches from the computer, or
practice together with the correct pitches.

5. Test session:
In the test session, the student will play through a
scale or musical passage, without correcting the notes as he
or she proceeds. In this session a scoring system is
provided for evaluation. Using the tolerance level the
student selects, if a note falls within the specified
tolerance, that note receives three points (no mistake). A
note falling within twice the tolerance level receives two
points (out of tune). Any note in excess of two tolerance
levels receives one point (very out of tune). The score for
the entire scale or passage is determined simply as the sum
of the scores for the individual notes. Obviously, the more
points, the more in tune.

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
25

Chapter 3
SYSTEM APPLICATION

I. User's Guide

Any student with a basic familiarity with the Macintosh


computer should be able to locate the program in the hard
disk drive and get it to run. Once the program is running,
the detailed textual instructions that follow should be clear
enough to proceed through the sessions. These instructions
render a user's manual or the memorizing of steps
unnecessary. Nevertheless, a brief summary of the
instructions follows.

After the hardware system is correctly connected (see


Chapter 2, Hardware System), the student turns on the
computer and selects one of the three programs. A text
window will appear and ask if the user wants detailed
instructions for the program, or if he or she is already
familiar with the instructions and elects to bypass the
detailed commentary. The student responds with either a "Y"
for yes or "N" for no, and hits the Return key.

At this point the computer will prompt the user to turn


on the Pitch Analyzer, and will wait five seconds for him or

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
26

her to do so. If the user fails to turn it on, he or she is


reminded once more.

Next the computer asks the user to select the options


one at a time (as shown under the "Software" section). When
the selection of options is complete, the computer will ask
the user to enter a "G" for go, to activate the Pitch
Analyzer, and then start the practice session. When the
computer detects a silence of five seconds, it concludes that
the user has finished that particular session and asks if he
or she wishes to practice again. Upon receiving a "Y" for
yes it asks if the user wants to change any of the options.
If another yes, it goes through the same procedure of
selecting options. After that procedure, or after "N" for no
change of options, the computer prompts the user once again
for a "G" to activate the Pitch Analyzer and start the
session. The program continues in this fashion until the
student has enough and enters "S" for stop. At the end of
the session the user is reminded to turn off the Pitch
Analyzer, and this terminates the program.

II. Tuning the Open Strings

The first program assists the student in tuning the four


open strings. The student starts with the A string at 440
cycles per second (Hertz), which is the standard concert

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
27

pitch. The frequency of the A is constant regardless of


which tuning system is selected.

First, the computer plays the A for the student to hear,


just as one would listen to a tuning fork. While the string
is being tuned, the student sees on the computer screen a bar
graph which shows where his or her pitch is in relation to
the correct pitch. The middle line on the bar graph
represents the perfect pitch. If the note is too high the
student sees a red bar filling the upper half of the bar. If
the note is too low, he or she sees a red bar filling the
lower half of the bar. How much red fills the upper or lower
halves of the bar depends on how far off the note is from the
perfect pitch.

If the student enters a tolerance level, which is


represented by lines above and below the perfect pitch line,
the bar in the graph is blue if the note stays within that
tolerance level, or red if the note is outside of the
tolerance level. If the pitch is perfect, there is no
colored bar in the graph, either red or blue.

When the student is finished with the A string, he or


she proceeds to the D string. Because the system can not
process double stops, the student must rely on the computer's
output rather than tuning the D with the A. The computer

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
28

sounds the correct D pitch, according to the choice of tuning


system.

It should be noted that the difference in the


frequencies between the two tuning systems is so minute that
only a person with an exceptionally keen sense of pitch will
be able to distinguish the difference.

As the student starts to tune the D string, a second bar


graph appears, with the tolerance level lines above and below
the middle line. The computer screen gives instant feedback
during tuning, just as with the A string. When the tuning of
the D string is completed, the student proceeds to the G and
E strings in the same manner. This completes the first
trial. (See Figure 6.)

During the process of tuning, it is possible that one or


more strings slip out of tune. The flexible nature of the
program guides the student through a follow-up session,
during which any string may be retuned as necessary. The
program determines which string the student is trying to tune
as best as possible. For example, if the A string's peg has
slipped, the system temporarily assumes that the G string is
being tuned. However, as the pitch rises, the active graph
on the screen jumps from the G to the D string and eventually
to the A string. Whenever a string is successfully tuned,

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
29

Program 1: Tuning Open Strings

-9 . —
s 5----------- *

Figure 6
Screen display of student tuning the E string in
the Pythagorean tuning system, after having
successfully tuned the A, D, and G strings.

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
30

and is held for a period of one second, a gold star appears


under that bar graph. When all four strings are in tune, as
indicated by four gold stars, a short tune signifies the end
of this follow-up session.

In an attempt to challenge and stimulate the acuteness


of the student's pitch discrimination, the program has a
final session. First, the student is asked to play any two
adjacent strings and listen to the beats closely. Next, the
student is instructed to retune the four strings to the
tuning system that was not selected originally. For example,
if the equal-tempered system was chosen the first time, the
user is now asked to retune in the Pythagorean system. The
retuning process is done in exactly the same manner as the
follow-up session. But since the differences are very small,
as shown earlier, this tuning process is likely to be
completed in a relatively short time. In fact, the
differences in frequencies are so small that trying to
distinguish two different tuning systems will be meaningless
if an error tolerance larger than 1 cent is allowed.

After retuning, the student is again instructed to play


pairs of open strings, and detect any differences by
listening to the beats. This concludes the first program.

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
31

III. Playing Scales

The practice of playing scales is an essential part of a


violinist's development. Even professional players, who
supposedly have mastered the task of playing in tune, have
developed the custom of warming up with playing scales on a
regular basis. This custom serves the purposes of reassuring
the ear and coordinating the finger movements with what the
ear perceives as the correct pitch.

Because scale practice plays a significant role in a


violinist's intonation, the second program is devoted to
addressing the practicing of scales. The program is
incorporated with all of the options mentioned earlier, i.e.,
different tuning systems, error tolerance level, metronome
setting, and choice of practice or test session. The student
is prompted to make the selections.

After the student selects one of the tuning systems, he


or she is asked to select the key and mode of the scale. The
choice of a key is necessary only if the user has selected
the Pythagorean tuning. The computer system accepts four
different modes of any given key. These are the major key
and three different minor keys: natural, melodic, and
harmonic. As soon as the student indicates his or her
choices, the computer determines the correct frequencies of
all the notes.

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited without perm ission.
32

After the selection of a tolerance level that the


student feels comfortable with, and the metronome setting,
the student is ready to play the scale. The object of a
practice session is to fine-tune the intonation by correcting
each note before the student moves on to the next note, until
the pitch is perfectly in tune or at least within the
specified tolerance. The student has as much time as
necessary to correct the notes, by watching the bar move up
or down as the pitch is being corrected. (See Figure 7.) At
the end of a scale the computer displays the average time the
student took to correct the pitch of each note. This
information is provided to monitor the progress.

When the student selects a test session, the emphasis is


shifted from correcting each note with immediate feedback to
playing the entire scale without interruption. The student
receives a score at the end of the scale. As mentioned
earlier, the more in tune the notes are, the higher the
student's scores. For example, if a student plays a one-
octave scale up and down (sixteen notes altogether), he or
she would score 48 points (16 x 3) if all the notes were
played perfectly or within the specified tolerance.

R e p r o d u c e d with p erm ission o f th e copyright ow ner. Further reproduction prohibited without perm ission.
33

Program 2: Playing Scales


C Major

P ra c tic e S ession
Scale System: 0
Tolerance Level: 10

Figure 7
Screen display of student playing
a C major scale.

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
34

With any combination of options, the student may play


any number of octaves in any direction, that is up or down or
both. The computer program automatically detects the
intentions of the student and determines with which correct
frequency the measured frequency is to be compared. After
each session, the student may change any, all, or none of the
options for the next session.

IV. Playing Passages

The ultimate goal of any violinist is to be able to play


any musical passage, easy or difficult, in tune and
artistically. The third program is written with the
objective of attaining this goal.

To be more specific, the student can practice with the


computer any piece of music he or she wishes to perfect.
Once the student plays the passage, the computer records the
notes, corrects them within the system, and plays back the
passage in tune. The student also has the option of hearing
his or her own pitches for comparison.

While the computer plays back the passage, the student


can practice together with the computer's correct pitches
just as with a teacher. The student can input any number of
musical passages and save them for future practice. In this

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
35

way he or she can create a library of musical passages


limited only by the computer disk space.

One of the available methods of inputting notes into


computers is to use a keyboard with MIDI interface. The
present program, instead, lets the student play a passage and
determines the notes that the student intended to play. This
method of inputting music may help violinists who are not
adept at the keyboard. In order to eliminate the problems
with notes that are played out of tune by more than fifty
cents (which the computer will then consider as different
notes) the following two-step process of inputting music is
used.

First the student plays a musical passage. Then the


computer displays on a staff the notes that are closest to
the frequencies played. Next, if any of the notes on the
screen are not what the student intended to play (for
example, an A interpreted as a G sharp), the program gives
the student the opportunity to correct them on the screen,
using the computer keyboard. Once the notes have been
corrected, the system will compute the correct frequencies
for these notes. This completes the input phase. Now the
whole passage is ready to be compared with the student’s
playing.

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
36

When the student is ready to practice, he or she may


select any one of these pre-recorded musical passages, or
simply choose a new piece and follow the steps as described
above. For the actual practicing, the session proceeds in
the same way as with program two. All the same options are
available for program three.

It would be beneficial if the student starts slowly,


watching the bar graphs as reference points, as if it were
the teacher's input, and try to get as close to the correct
pitch line as possible.

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
37

Chapter 4
CONCLUSIONS

I . Preliminary Test and Evaluation

The computer system has been tested with an advanced


violin player. The present configuration of the electronic
circuity of the Pitch Analyzer makes extensive testing with
young students impractical at this time. It is still lacking
the robustness needed for such purposes.

During the test it was noticed that the accuracy of the


Pitch Analyzer was difficult to assess in quantitative terms,
as the Pitch Analyzer1s results are displayed graphically
rather than numerically. This can be rectified by rewriting
the program so that the frequency number can be shown along
with the bar graphs.

The student noted that some of the notes appearing on


the staff were not the notes he played, usually in the lower
register. This could be due to a number of reasons: there
was insufficient volume to activate the Schmidt Trigger; the
student was not at the proper distance from the microphone;
the Pitch Analyzer was unable to filter out all of the
stronger overtones; or, there may have been a problem in the
transmission of data from the Pitch Analyzer, through the

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
38

serial port of the computer and input buffers, to the


application program. In general, however, the student agreed
that the bar graphs were accurate reflections of the pitches
played.

Correcting and saving a piece of music created little


problem. Notes could be inserted, deleted, or changed as the
student wished, and then saved for later recall.

In conclusion, when the student practiced with the


system, he was much more prompt in correcting the pitches,
probably because of the visual assistance, and showed an
eagerness to improve the score each time he tried. With
extensive practice with the system, students' intonation is
most likely to improve.

II. Summary and Conclusion

This project has been conceived from the idea that a


violinist can improve intonation by developing a better sense
of pitch discrimination, and pitch discrimination can be
improved when aural perception is reinforced with visual
perception.

The computer system presented here is an educational aid


that can help violinists of all skill levels improve their

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
39

intonation. Its special features and merits can be


summarized as follows.

The method of extracting the fundamental frequencies


from musical notes is fast enough to give immediate feedback
in real time. The instant graphic display of pitch permits
the eye-ear coordination to assist in sharpening the sense of
pitch discrimination.

The primary aspect of the system is the integration of


electronic circuitry (the Pitch Analyzer) with a widely used
Macintosh or PC, and a software program with potential for
expansion. In this work, three programs are presented to
illustrate the flexibility of applications for self-paced
study.

The low cost of the electronic components makes the


Pitch Analyzer an affordable alternative to other devices
that are available.

This system is not meant to be a substitute for an


experienced violin teacher, but it can very well serve as a
supplement to be utilized during personal practice. Even
though only an inanimate system, it has incorporated several
almost human capabilities, yet retains all the advantages of
mechanical systems, such as general availability,
reliability, objectivity, and consistency.

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
40

The software programs presented herein constitute only a


first step to demonstrate the potential of the system. It
was not the objective of this work to develop a full-scale
commercial-quality system. But numerous features of the
three basic programs point to the many ways in which the
program can be expanded.

An important next step would be the field testing of the


proposed system, using experimental and control groups, so
that its effectiveness can be measured through pretest and
posttest.

III. Future Development

The present computer system is intended for violin


players. However, at present, it can also be used by other
string, woodwind, and brass instrumentalists, as well as
singers, provided their frequencies fall between 125 and 4000
Hertz. With minor adjustments the frequency range can be
extended and then be used for any instrument.

Although the system's primary purpose is the improvement


of intonation, it can, with a modification in the source
code, automatically record the time for which each note is
held. This will permit the assignation of note values and
the reproduction of rhythm in the screen display. When the

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
41

student corrects wrong notes, he or she will also be able to


adjust the note values and rhythmic representation.

A speech synthesizer may be added as an output medium.


This will free the student from the task of reading the
computer screen, thereby enabling him or her to concentrate
more on listening and playing. Also, the oral instructions
from the computer will simulate a real lesson more closely.
A few PC's are manufactured with speech synthesizers already
incorporated.

At present, the system is limited to fairly uniform


input power. For this reason, the system works most
effectively if the microphone is placed at a proper distance
from the violin, and the notes are played without major
changes in dynamics. By incorporating automatic gain control
circuitry into the pitch analyzer, this restriction can be
eliminated, because the electronic circuitry will assure that
the voltage input from the microphone gets amplified the
right amount to activate the Schmidt Trigger, independent of
the sound input power level.

The three computer programs are subject to numerous


restrictions and limitations in scope, which can be improved
and expanded with future development. With a full-scale
expansion of the program, incorporating such features as
windows, pull-down menus, and mouse-activated input

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
42

capability, etc., it can result in a product that will be


easier to use and may appeal to a large number of teachers
and students at all levels of achievement.

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
43

Bibliography

Allvin, Raynold L., "Computer-assisted music instruction: a


look at the potential." Journal of Research in Music
Education #19, 1991. pp. 131-143.

Apel, Willi, Harvard Dictionary of Music. Harvard University


Press, Cambridge, 1969.

Bisel, Larry David, "Seeking a perceptual preference among


Pythagorean tuning, just intonation, one-quarter common
meantone tuning, and equal temperament." Ph. D.
dissertation, The University of Michigan, 1987.

Campbell, Murray and Clive Greated, The Musician's Guide to


Acoustics. Schirmer Books, New York, 1987.

Clendinning, Jane, "Computer recognition of pitch for musical


applications." Masters thesis, North Texas State
University, 1983.

Eisele, Mark Joseph, "Development and validation of a


computer-assisted instructional lesson for teaching
intonation discrimination skills to violin and viola
students." D.Mus.Ed. dissertation, Indiana University,
1985.

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout p erm ission
44

Hofstetter, Fred T., "GUIDO: An interactive computer-based


system for improvement of instruction and research in
ear training." Journal of Computer-Based Instruction
#1, 1975, p. 100.

Kolb, Py, Personal interview at the MENC Eastern Division.


Springfield, MA, March 19, 1993.

Kolb, Randall Martin, "A real-time microcomputer-assisted


system for translating aural, monophonic tones into
music notation as an aid in sight singing." Ph.D.
dissertation, Louisiana State University and
Agricultural and Mechanical College, 1984.

Kuhn, Wolfgang E., and Raynold L. Allvin, "Computer-assisted


teaching: a new approach to research in music." Journal
of Research in Music Education #15, Winter 1967, pp.
305-315.

Kuhn, Wolfgang E., "Computer-assisted instruction in music:


drill and practice in dictation." College Music
Symposium #14, 1974, pp. 89-101.

Ottman, Robert W., et al., "Development of a concept-centered


ear training CAI system." Journal of Computer-Based
Instruction #6, 1980, p. 80.

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
45

Peters, David G., "Music Software and Emerging Technology."


Music Educators Journal, November 1992, pp. 22-25.

Seashore, Carl E., "The Measurement of Pitch intonation with


the Tonoscope in Singing and Playing." University of
Iowa Studies, 1930.

Seashore, Carl E. ed., Objective Analysis of Musical


Performance. The University Press, Iowa City, 1936.

Seashore, Carl E., Psychology of Music. Dover Publications


Inc., New York, 1967.

Thompson, Edgar Joseph, "Sightsinging Constant Rhythm Pitch


Phrases: A Computer-Assisted Instructional System."
Ph.D. dissertation, University of Utah, 1973.

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
46

Appendix;

Source Code of the Computer Program

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
47

{**********************************************************************}
{* *>
{* Program 1 - Tuning the Open Strings *>
{* *}
{**********************************************************************}

program one;

{ Global Declarations }
{**********************************************************************}

uses
Serial; {needed to access serial ports}

type
i_array = array[1..4] of integer;
M_label = string!11];

const
hs = 1.05946; {half-step size in even-tempered system}
x = 30; {left margin of graphic screen}
length = 550; {width of graphic screen to be used}
section = 120; {width of one section, e.g. for one note}
midy = 180; {y-coord of graphic display centerline}
height = 50; {half height of graphic display box}
width = 30; {width of graphic display box}

var
names M_label; {name of student}
ntrialss integer; {number of trials to tune a string in}
{first pass}
stringfreqss array[1..4] of real;
{correct frequencies of the four strings}
flags: i_array; {the four 0=failure/l=success flags}
strnos i_array; {string numbers, 3,2,1,4}
strlab: array[1..4] of char; {string labels G,D,A,E}
ssystem: array[1..2] of M__label; {'tempered', 'Pythagorean'}
txRect, drRect: Rect; {dimensions of text and graphic windows}
scale_system: integer; {1-even tempered, 2-Pythagorean}
tols integer; {error tolerance, in cents}
ibegin, iend: longint; {begin and end of timer interval, seconds}
dur, final: longint; {parameters for system delay function}
flag: integer; {error and control flag:}
{ 1 if all is OK, 0 if not}
errorflag, returnflag: integer; {error and control flags}
inRefNum, outRefNum: integer; {reference nos for serial port drivers}
iErr: OSErr; {operating system error flag}
key: char; {character input on keyboard, G,S,N, etc}
c_key: char; {comment key, 'C' if comments are wanted}

>

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout p erm ission .
48

procedure Introduction;
begin
Writeln(' Hi, my name is Ludwig. What is your name?');
Readln(name);
Writeln( ' Hi,', name, '. Our first program will be tuning the four
strings of your violin. Let us start with the A-string. The
universally adopted A is 440 cycles per second. Let me play
it for you.');
Note(440, 300, 100);

Writeln( ' Before we start, let me explain how we will be going about
it. While you are tuning your A-string, you will notice on
the screen a bar graph indicating how close or how far off
you are from the target pitch. If you are within two cents
of the correct pitch, the bar will be blue. If you are sharp
or flat by more than that, the bar will be red. Try to tune
the A-string to within the specified tolerance. For each
trial you will have thirty seconds.');
end; {End of Introduction}

function Get_Ready; integer;

The user has two 5-second periods


to turn on the Pitch Analyzer Switch

Get_Ready = 0 Pitch Analyzer sends OK signal


= 1 Error exit; no signal received

Internal error flag = 1 successful receipt of "OK."


0 no receipt of OK so far, keep looking
-1 no receipt within 5 seconds

var
flag, ntrial: integer;

begin
Writeln( 'Whenever you are ready, turn on the switch of the Pitch
Analyzer.');
Get_Ready s= 1;
flag := 0;
Getdatetime(ibegin);
for ntrial := 1 to 2 do
begin
while flag = 0 do
begin {wait 5 sec for user to }
if ReadOK then {turn on Pitch Analyzer switch}
flag := 1;
Getdatetime(iend);
if iend - ibegin > 5 then
flag := -1;
end;
if flag = 1 then
begin
Get_Ready := 0;

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
49
ntrial ;= 2;
end
else {try a second time}
begin
if ntrial = 1 then
Writeln(1 We did not get the OK. Try again.');
flag := 0;
Getdatetime(ibegin);
end;
end;
end; {End of function Get_Ready}

{**********************************************************************}

procedure Strings;
{ >
{ Determines the correct frequencies of the four open strings }
{ It also defines the string numbers and labels }
var
tempratio, pythratio, ratio: real;
begin
tempratio := 1.4983071;
pythratio := 1.5;
if scale_system = 2 then
ratio := tempratio
else
ratio := pythratio;
stringfreqs[3] := 440.0; {A}
stringfreqs[2] := stringfreqs[3] / ratio; {D}
stringfreqs[l] := stringfreqs[2] / ratio; {G}
stringfreqs[4] := stringfreqs[3] * ratio; {E}

strno[l] := 3;
strno[2] := 2;
strno[3] := 1;
strno[4] := 4;

strlab[1] = 'G'i
strlab[2] = 'D\
strlab[3] = 'A';
strlab[4] = 'E';
end; {End of Procedure Strings}

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
50

procedure Draw_Clef (x, ys integer);


begin
pensize(2, 2);
moveto(x - 2, y + 15);
line(-l, -1);
line(-l, 1);
line(1, 1);
line(3, 0);
line(1, -4);
line(-l, -12);
line(-l, -16);
line(0, -8);
line(2, -4);
line(3, -2);
line(2, 2);
line(0, 4);
line(-2, 5);
line(-2, 3);
line(-6, 7);
line(-4, 5);
line(-l, 5);
line(1, 4);
line(4, 3);
line(4, 1);
line(4, -1);
line(3, -3);
line(2, -4);
iine(-2, -4);
line(-3, -3);
line(-4, -1);
line(-4, 2);
line(-2, 4);
line(1, 5);
pensize(l, 1);
end; {End of Procedure Draw_Clef}

procedure screen_setup;
{ >
{ Graphic screen initialization }
var
left, right, loop, y: integer;
begin
y := 280;
Fillrect(0, 0, 470, 630, white);
Moveto(80, 60);
Textsize(30);
Writedraw(1Program 1: Tuning the Open Strings'); {screen heading}
Moveto(200, 90);
Textsize(20);
Drawline(x, y, x + length, y ) ;
{five lines for one music staff}
Drawline(x, y + 8, x + length, y + 8);
Drawline(x, y + 16, x + length, y + 16);

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
51
Drawline(x, y + 24, x + length, y + 24);
Drawline(x, y + 32, x + length, y + 32);
draw_clef(x + 12, y + 24);
Textsize(O);

for loop := 1 to 4 do {the 4 frames to display freqs}


begin
left := round(loop * section - 0.5 * width);
right := round(loop * section + 0 . 5 * width);
Framerect(midy - height, left, midy + height, right);
Drawline(left - 3, midy - tol, right + 3, midy - tol);
Drawline(left - 5, midy, right + 5, midy);
Drawline(left - 3, midy + tol, right + 3, midy + tol);
Paintcircle(loop * section, y + 68 - loop * 16, 4); {the 4 notes}
Drawline(section - 6, y + 40, section + 6, y + 40);
Drawline(section - 6, y + 48, section + 6, y + 48);
end;
end; {End of procedure Screen_Setup}

{**********************************************************************}

procedure Display (n, err: integer; corr: real);


{ >
{ Graphically displays the degree of accuracy for string 'n' }

var
left, right, nx, In: integer;

procedure sharp; {pitch is sharp}


begin
if err > height - 1 then
err := height - 1;
fillrect(midy - height + 1, left, midy + height - 1, right, white);
if err > tol then
forecolor(205) {red}
else
forecolor(273); {blue}
paintrect(midy - err, left, midy, right);
forecolor(33); {black again}
end;

procedure flat; {pitch is flat}


begin
if err < -height + 1 then
err := -height + 1;
fillrect(midy - height + 1, left, midy + height - 1, right, white);
if -err > tol then
forecolor(205)
else
forecolor(273);
paintrect(midy + 1, left, midy - err, right);
forecolor(33);
end;

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
52

begin {Main part of procedure Display}


In := n;
while In > 12 do
In := In - 12;
nx := (In + 1) * section;
left := round(nx - 0.5 * width) + 1;
right := round(nx + 0.5 * width) - 1;
if err > 0 then
sharp
else if err < 0 then
flat
else
fillrect(midy - height + 1, left, midy + height - 1, right, white);

Drawline(left - 3, midy - tol, right + 3, midy - tol);


Drawline(left - 5, midy, left + 5, midy);
Drawline(left - 3, midy + tol, right + 3, midy + tol);
end; {End of Procedure Display}

r* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
}
procedure goldstar (str: integer);
{ }
{ Places a gold star under the bar graph for string 'str’ }

var
i, nx, ny: integer;
r: real;

begin
nx := str * section;
ny := midy + height + 20;
Forecolor(69);
for i := 1 to 10 do
begin
r := i / 10;
Moveto(nx, ny);
Move(0, round(-10 * r));
Line(round(6 * r), round(18 * r));
Line(round(-16 * r), round(-ll * r ) );
Line(round(20 * r), 0);
Line(round(-16 * r), round(ll * r ));
Line(round(6 * r), round(-18 * r));
end;
Forecolor(32);
end; {End of Procedure goldstar}

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
53
{**********************************************************************}

procedure Tada;
{ >
{ Plays a fanfare when all four strings are in tune }
begin
note(294, 50, 10);
note(392, 50, 10)
note(494, 50, 10)
note(587, 50, 20)
note(494, 50, 10)
note(587, 50, 40);
end; {End of Procedure Tada}

{**********************************************************************}

procedure Comments;
begin
Writeln( ' Now, before we go on to the next string I must say that
I can not process double stops, so you will not be able to
tune by playing two strings at the same time, as
violinists usually do. There is one other point. You should
know that the exact pitch of your other three strings
depends on your preferred scale system. You may choose the
even-tempered system, to which your piano is tuned, or you
may choose the Pythagorean system - the one that string
players typically prefer, unless they play together with a
piano. If you like to tune your violin in the even-tempered
system, enter 1 and Return. If you prefer the Pythagorean
system, enter 2 and Return.');
Readln(scale_system);
if scale_system <> 2 then
scale_system := 1;
end; {End of Comments)

procedure Comments2;
begin
if c_key = 'C' then
begin
Writeln( ' We have completed the first pass. Now you may tune any
one of your four strings again, whether or not they were
tuned successfully in the first pass. To stop the
session, enter "S" and Return. The session will stop
automatically when all strings are in tune or when you
stop playing.');
end
else
begin
Writeln(' Please check your four strings again. When you are
ready, enter "G" and Return. To stop at any time, enter
"S" and Return.');
end;
end; {End of Comments2}

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
54
^**********************************************************************}

procedure Openstring (str: integer);

{ This procedure gives the student }


{ ntrials to tune string 'str' }

{ Input s }
{ ntrials - number of trials }
{ str - number of string being tuned >

{ Output: }
flag - 0 for unsuccessful session
1 for successful session
-1 error
key - 'N' to continue with next string
'S’ to stop the program
'G' continue same string

var
limit: integer; {time limit for one trial, 30 sec}
onesecond: integer; {one second, about 20 freq readings}
correct: real; {correct frequency of string being tuned }
freq: real; {last frequency received from serial port}
nbuf: integer; {number of words currently in buffer}
error: integer; {frequency error, in cents}
icount: integer; {no. of consecutively correct freqs}
contr: integer; {control variable for indefinite loop}
i: integer;

begin
dur := 180; {3 second delay}
limit := 30; {30 second limit for one trial}
onesecond := 20; {one second, about 20 freq readings}
flag := 0; {initialize error flag as 'no good’}
correct := stringfreqs[str];
for i := 1 to ntrials do
begin
Writeln('Here is again the correct pitch.');
Note(round(correct), 300, 100);
WriteSP('G', returnflag); {enable pitch analyzer}
Getdatetime(ibegin); {start clock for 30 second session}
nbuf := 0;
icount := 0;
contr := 0;
while contr = 0 do
begin
ReadSP(freq, nbuf, returnflag);
{get next frequency from serial port}
if (freq = 0) and (icount = 0) then
begin {something went wrong,}
flag := -1; {or nothing found in S.P. for 5 sec}
exit(Openstring);
end;
error := round((freq / correct - 1.0) * 1730.0);
Display(str, error, correct);

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
55
if aba(error) <= tol then
icount := icount + 1
else
icount := 0; {error too large, start counting again}
if icount = onesecond then
begin {success if correct pitch is held for 1 sec)
flag := 1; {this means all is well}
i := ntrials;
contr := 1;
end;
Getdatetime(iend);
if iend - ibegin >= limit then
contr := 1; {30 sec time limit is up}
end;
WriteSP('S', returnflag); {disable pitch analyzer}
Delay(dur, final); {wait for 3 sec before commenting}
if flag = 1 then
begin
Writeln('Very nice name, ', you got it.');
key := 'N'; {get set for the next string}
end
else if i < ntrials then
begin
SysBeep(O);
Writeln('Well,', name, ', the 30 seconds are up.');
Writeln('If you wish to try again, enter a "G" and Return. If
you wish to try another string, enter "N" and Return.
If you wish to stop, enter "S" and Return.');
Readln(key);
if key <> 'G' then
i := ntrials; {terminate session upon user request}
end;
end;
end; {End of Procedure Openstring}

{**********************************************************************}

procedure First_Pass;
{ >
{ This procedure controls the first pass }
{ of tuning the four open strings. }
{ >

var
correct: real; {correct frequency of string str}
str: integer; {string number, 1=G, 2=D, 3=A, 4=E}
slabel: char; {string label, G,D,A,E}
i : integer;

begin
Writeln( ' Please enter the maximum number of trials you wish to tune
one string. ’);
Readln(ntrials);
Screen_Setup;
Writeln(' When you are ready, enter the letter "G" and Return.');
Readln(key);
flag := 0;
if key <> 'G' then

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
56
exit(First_Pass);
tol := 2;
stringfreqs[3] := 440.0; {we start with the A-string}
Openstring(3);
if (flag = -1) or (key = 'S’) then
exit(First_Pass);
flags[3] := flag;
if flag = 0 then
Writeln('I am sorry you did not succeed this time. We will
try again later.');

if c_key = 'C' then


Comments;
Strings; {adjust correct string frequencies}
for i := 2 to 4 do {for new scale system}
begin
str s= strno[i ];
slabel := strlab[str];
correct ;= stringfreqs[str];
Writeln('Whenever you are ready, enter the letter "G" and
Return. Then proceed with tuning your', slabel, '-
string.');
Readln(key);
flag := 0;
if key <> 'G' then
exit(First_Pass);
Openstring(str);
if (flag = -1) or (key = 'S') then
exit(First_Pass);
flags[str] := flag;
if flag = 0 then
Writeln(' Sorry, you did not succeed. We will come back again
later.');
end;
flag := 1; {this is the pass into the follow-up session}
end; {End of Procedure First_Pass}

{**********************************************************************}

function Jump (var str: integer; freq: real): Boolean;

{ This function determines the string 'str' the student is }


{ tuning. It returns the value 'true' if strings are crossed }
{ or if the frequency crosses the half-way mark between the }
{ correct frequencies of two adjacent strings. }
var
oldstr: integer;
begin
Jump := false;
oldstr := str;
str := 1;
if (freq > 239.9) and (freq <359.5) then
str := 2; {guess student is tuning the D}
if (freq > 359.5) and (freq <538.6) then
str := 3; {guess student is tuning the A}
if freq > 538.6 then
str := 4; {guess student is tuning the E}
if str <> oldstr then

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
57
Jump := true;
end; {End of Function Jump}

{**********************************************************************}

procedure Follow_up;
{ }
{ This procedure gives the student the opportunity to tune an }
{ string, and in any sequence, regardless whether or not the }
{ strings had been tuned successfully in the first pass }
{ }
var
onesecond: integer; {one second, about 20 freq readings}
corrects real; {correct frequency of string being tuned }
freq: real; {last frequency received from serial port}
nbuf: integer; {number of words currently in buffer}
error: integer; {frequency error, in cents}
icount: integer; {no. of consecutively correct freqs}
contr s integer; {control variable for indefinite loop}
rcount: integer; {no of freqs in Register, max=10}
lpointer s integer; {pointer into Register}
i: integer; {Do-loop index}
Registers array[1..10] of real; {up to 10 most recent frequencies}
accmean, rmean: real; {mean value of up to 10 frequencies}
str: integer; {number of string that is being tuned}
checks integer; {sum of the 4 failure/sucess flags}

begin
nbuf := 0;
onesecond := 20;
for i := 1 to 4 do
flagsfi] := 0;
flag := 0;
Screen_Setup;
Readln(key);
if key <> 'G' then
exit(Follow_Up);
WriteSP('G', returnflag);
contr := 0;
while contr = 0 do
begin
ReadSP(freq, nbuf, returnflag);
if (freq = 0.0) or (returnflag = -1) then
exit(Follow_Up);
if Jump(str, freq) then
begin {we start on a new string, str}
icount s= 0;
rcount s= 1;
lpointer := 1;
Register[l] := freq;
accmean := freq;
correct := stringfreqs[str];
flags[str] := 0;
end
else
begin {we continue with the same string}
lpointer := lpointer + 1;
if lpointer > 10 then

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
58
lpointer := lpointer - 10;
rcount := rcount + 1;
if rcount > 10 then {update the Register}
accmean := accmean - Register[lpointer];
Register[lpointer] := freq;
if rcount >= 10 then (compute the running mean frequency}
rmean := 0.1 * accmean
else
rmean := accmean / rcount;
end;
error ;= round((rmean / correct - 1.0) * 1730.0);
Display(str, error, correct); {display the frequency graphically}
if abs(error) <= tol then
icount := icount + 1 {number of consecutive correct freqs}
else
icount := 0; {error too large, start counting again}
if icount >= onesecond then
begin
flags[str] := 1; {success, string str is in tune}
Goldstar(str); {give him a gold star for it}
check := flags[l] + flags[2] + flags[3] + flags[4];
if check = 4 then
begin
Tada; {all 4 strings are in tune}
flag := 1;
exit(Follow_Up);
end;
end;
end;
end; {End of Procedure Follow_up}

{**********************************************************************}

procedure Comments3;
begin
flag := 0;
a system[1] s= 'even-tempered';
ssystem[2] := 'Pythagorean';
Writeln(' Well, you succeeded in tuning your four strings perfectly
within the', (ssystem[scale_system], ’ system that you had
selected. Now play any two adjacent strings and listen
carefully. This is how violinists usually tune. When you
are done, just hit the Return key.');
Readln(key);
if key <> 'G' then
exit(Comments3);
if scale__system = 1 then
scale_system := 2
else
scale_system := 1;
Writeln(' Okay. Do you remember how those fifths sounded? Now tune
your violin to the scale system that you did not select in
the first round; that is, the ', ssystem[ scale_system], '
system. You can terminate the session at any time by
entering an "S" and hitting the Return key.');
flag := 1;
end; {End of Comments3}

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
59
,£**********************************************************************}

begin {Main Program - Program 1}

SetRect(txRect, 225, 420, 615, 478);{set up graphic display and)


SetTextRect(txRect); {text windows}
ShowText;
SetRect(drRect, 5, 40, 635, 475);
SetDrawingRect(drRect);
ShowDrawing;
Writeln( ' If you wish to obtain a detailed description of this
program, enter a "C" and Return. If you wish to skip the
introductory comments, just hit Return.');
Read(c_key);
if c_key = 'C' then
Introduction;
errorflag ;= 1;
if Open_SerialDriver = noErr then {open Serial Port}
errorflag := Get_Ready; {wait for OK from Pitch Analyzer}
if errorflag = 0 then {start Program 1 only if switch is on}
First_Pass; {i.e. if errorflag=0}
if flag = 1 then {follow up only if first pass was OK}
begin
Comments2;
if flag = 1 then
Follow_Up;
end;
if flag = 1 then
begin {we repeat the follow-upsession}
Comments3; {with the different tuning system}
Follow_Up;
if flag = 1 then
begin
Writeln(' Now play those fifths again and try to remember how
they sounded the first time. Can you tell the
difference? When you are done, sign off. You have
successfully completed the first program.’);
end;
end;
Close_Port; {close Serial Ports}
Writeln('Please turn off the Pitch Analyzer switch.');
end.

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
60

{* *>
{* Program 2 - Playing Scales *>
{* *}

program two;

.£**********************************************************************}
{ Global Declarations }
{**********************************************************************}

uses
Serial; {needed to access serial ports}

type
i_array = array[1..200] of integer;
j_array = array]0..12] of integer;
r_array = array[1..37] of real;
N_label = string[2];
s_array = array]0..12] of N_label;

const
hs = 1.05946; {half-step size in even-tempered system}
x = 30; {left margin of graphic screen}
length = 550; {width of graphic screen to be used}
section = 40; {width of one section, e.g. for one note}
midy = 150; {y-coord of graphic display centerline}
height = 50; {half height of graphic display box}
width = 20; {width of graphic display box}

var
Recording: array]1..1200] of real;
{recording of student's frequencies}
sharps, flats: s_array; {labels for notes of one octave}
notes: i_array; {ID numbers for all notes of a scale}
Scale: r_array; {correct freqs of 5 chromatic scales}
Bins: r_array; {half-way marks between adjacent notes}
txRect, drRect: Rect; {dimensions of text and graphic windows}
option: integer; {1-practice, 2-test, 3-replay,}
{4-play in tune}
scale_system: integer; {1-even tempered, 2-Pythagorean}
tol: integer; {error tolerance, in cents}
mode: integer; {0-major, 1-natural, 2-melodic minor,}
{3-harmonic minor}
metr: integer; {metronome number}
key: integer; {1-G, 2-G#, 3-A, ..., 12-F#}
ch: N_label; {hey character, like G#, Bb, C , ...}
jtotal: integer; {total number of recorded frequencies}
ibegin, iend:longint; {begin and end of timer interval, seconds}
dur, final: longint; {parameters for system delay function}
first: Boolean; {true for first run, false thereafter}
nn: integer; {total number of notes in a scale}
gflag, control: integer; {error and control flags}
errorflag, returnflag: integer; {error and control flags}
inRefNum, outRefNum: integer;

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
61
{reference nos for serial port drivers}
iErr: OSErr; {operating system error flag}
c_key, Yes, Go: char; {characters input on the keyboard}

procedure Introduction;
begin
Writeln( ' This is the second program, in which you will have the
opportunity to improve your intonation by playing scales.
Before we start, let me explain the various options you
have. You may play as many scales as often as you wish. Each
time you may change any one or all of the various options.
If there are no changes, just enter the letter "G" on your
keyboard and Return. You may play as many octaves as you
like. You may even play them up and down or only up oronly
down. Now some comments on the specific options.');

Writeln( ' First, you may choose the type of session. There are two
types, a practice session and a test session. The object of
a practice session is to correct each note until it is in
tune. You may take as much time as you wish to play each
note, as in program one. Watch the bar graph that is
displayed for each note, indicating whether you are too
high, too low, or just right. Try to reach the correct pitch
before proceeding to the next note. After you have finished
a practice session, I will display the average time it took
you to find the correct pitch of each note.');

Writeln( ' In a test session, you will receive a score on how in


tune you played. Here it is the average pitch of each note
you played, which is compared with the correct pitch and
evaluated, using as a reference the tolerance level that you
yourself specify, which I will explain in a moment. The
score is based on a point system. An error of less than the
specified tolerance level will receive 3 points. An error
between one and two tolerance levels will receive 2 points.
And an error in excess of two tolerance levels will receive
1 point. The score for an entire scale is simply the sum of
the points for the individual notes. I suggest that you
choose a test session only when you think you are ready to
score yourself.');

Writeln(' Your second option is the tolerance level, measured in


cents. 50 cents is the largest error you can make. This
represents the half-way mark between two notes one half-tone
apart, say between a G and G-sharp. A note with an error
larger than 50 cents will be interpreted as the next higher
or lower note. If you think your intonation requires a lot
of improvement, you may wish to start with a high tolerance
level. As you improve your intonation, you may wish to
reduce the tolerance level progressively. If you can master
a 2 cent tolerance, the vast majority of listeners will
accept your intonation as correct.');

Writeln(' The third option gives you the choice between the various
scale systems. You may select the even tempered scale, or

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
62
the Pythagorean scale system. Note that your violin should
be tuned in the scale system you choose here.');

Writeln(' If you wish to practice with different tempi, you may input
a metronome setting, and I will mark the tempo for you
before you begin playing.');

Writeln(' You may select any key and mode of the scale you wish to
practice. Just enter the appropriate letter, followed
immediately by a # or b sign as applicable. You also may
select the mode, that is, either a major key or any one of
the three minor keys - natural, melodic, or harmonic. The
key designation is the only option for which no default
value will be specified, so you must enter a key.');

Writeln(' After you finish one scale, you may continue as often as
you feel like, with or without changing any one of these
options and entering the letter G. When you wish to stop,
enter the letter S and Return. Do not forget to turn off
the Pitch Analyzer after youare done.');
end; {End of Introduction}

function Get_Ready: integer;

The user has two 5-second periods


to turn on the Pitch Analyzer Switch

GetJReady = 0 Pitch Analyzer sends OK signal


= 1 Error exit; no signal received

Internal error flag = 1 successful receipt of "OK."


0 no receipt of OK so far, keep looking
-1 no receipt within 5 seconds

var
flag, ntrial: integer;

begin
Writeln('Whenever you are ready, turn on the switch of the Pitch
Analyzer.');
GetJReady := 1;
flag := 0;
Getdatetime(ibegin);
for ntrial := 1 to 2 do
begin
while flag = 0 do
begin {wait 5 sec for user to }
if ReadOK then {turn on Pitch Analyzer switch}
flag := 1;
Getdatetime(iend);
if iend - ibegin > 5 then
flag := -1;
end;
if flag = 1 then
begin
Get_Ready := 0;

R ep ro d u ced with p erm ission o f the copyright ow ner. Further reproduction prohibited without p erm ission.
ntrial := 2;
end
else {try a second time}
begin
if ntrial = 1 then
Writeln(' We did not get the OK. Try again.');
flag := 0;
Getdatetime(ibegin);
end;
end;
end; {End of function Get_Ready>

{*****************************************************************

procedure metronome (met: integer);


var
loop: integer;
begin
for loop := 1 to round(met / 6) do
begin
note(1760, 255, 2);
note(1760, 0, round(3600 / met) - 2);
end;
end; {End of procedure Metronome}

^*****************************************************************

procedure Assign_Labels;
{
{ This procedure initializes various arrays
{
var
loop: integer;
begin
sharps[0] := 'F#';
sharps[1] := 'G ';
sharps[2] := 'G#';
sharps[3] *= 'A '»
sharps[4] := ’A # ';
sharps!5] := 'B ';
sharps[6] := 'C ';
sharps[7] := 'C#';
sharps[8] := 'D ';
sharps[9] := 'D#';
sharps!10] := 'E ';
sharps!11] := 'F ';
sharps!12] := 'F#';

flats[0] = ■F '
flats[1] = 'G '
flats[2] = 'Ab'
flats[3] _ ,A .
flats!4] = 'Bb'
flatsf5] = 'Cb'
flats[6] = 'C '
flats[7] = 'Db'
flats[8] = 'D '

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
flats[9] = ’Eb';
£lats[10] := 'E
flats[11] := 'F
flats[12] := 'Gb';

for loop := 1 to 37 do
notes[loop] := 0;
end; {End of Procedure Assign_Labels}

^********************************************************************

procedure Right_Notes;

This procedure determines the correct frequencies for scales


and stores these in array Scales. It also defines the half-way
marks between adjacent notes and stores these in array Bins.

Input
scale_system - 1 for even-tempered
2 for Pythagorean
key scale key ID number
1 for G
2 for G#
3 for A

12 for F#
mode 0 for major
1 for natural minor
2 for melodic minor
3 for harmonic minor

var
loop: integer;
root: real;
roots: array[1..12] of real;

procedure calc_temp_root; {Fundamental frequencies}


begin {in even-tempered system}
roots[1] = 196; {G}
roots[2] = 207.65;
roots[3] = 220; {A}
roots[4] = 233.08;
roots[5] = 246.94; {B}
roots[6] = 261.63; {C}
roots[7] = 277.18;
roots[8] = 293.66; {D}
roots[9] = 311.13;
roots[10] :== 329.63; {E}
roots[11] :== 349.23; {F}
roots[12 ] :== 369.99;
end;

procedure calc_pyth_root; {Fundamental frequencies}


begin {in Pythagorean system}
roots[l] := 195.56; {G>
roots[2] := 208.83;
roots[3] := 220; {A}

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited without perm ission.
roots[4] = 231.77;
roots[5] = 247.5; {B>
roots[6] = 260.74 {C>
roots[7] = 278.44
roots[8 j = 293.33 {D}
roots[9] = 309.03
roots[10] := 330; {E}
roots[ll] := 347.65; {F>
roots[12] s= 371.25;
end;

procedure calc_temp; {4 octaves of even-tempered scales}


var
loop: integer;
begin
scale[l] := root;
scale[2] := scale[l] * hs * hs; {major 2}
if mode = 0 then
scale[3] := scale[2] * hs * hs {major 3}
else
scale[3] := scale[2] * hs; {minor 3}
scale[4] := scale[2] * hs *hs * hs; {perfect 4}
scale[5] := scale[4] * hs *hs; {perfect 5}
if (mode = 0) or (mode = 2) then
scale[6] := scale[5] * hs * hs {major 6}
else
scale[6] := scale[5] * hs; {minor 6}
if mode = 3 then
scale[7] := scale[6] * hs * hs * hs {major 7}
else
scale[7] := scale[6] * hs * hs; {major or minor 7}
for loop := 8 to 29 do
scale[loop] := scale[loop - 7] * 2;
scale[30] := scale[5] * hs; {minor 6}
scale[3lj := scale[30] * hs* hs; {minor 7}
for loop := 32 to 37 do
scale[loop] := scale[loop - 2] * 2;
end;

procedure calc_pyth; {4 octaves of Pythagorean scales}


var
loop: integer;
begin
scale[l] := root;
scale[2] := root * 9 / 8 ; {major 2}
if mode - 0 then
scale[3] := root * 8 1 / 6 4 {major 3}
else
scale[3] := root * 3 2 / 2 7 ; {minor 3}
scale[4] := root * 4 / 3 ; {perfect 4}
scale[5] := root * 3 / 2 ; {perfect 5}
if (mode = 0) or (mode = 2) then
scale[6] := root * 2 7 / 1 6 {major 6}
else
scale[6] := root * 128 / 81; {minor 6}
if mode = 1 then
scale[7] := root * 1 6 / 9 {minor 7}
else

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited without perm ission.
scale[7] := root * 243 / 128; {major 7}
for loop := 8 to 29 do
scale[loop] := scale[loop - 7] * 2;
scale[30] := root * 128 / 81; {minor 6}
scale[31] ;= root * 1 6 / 9 ; {minor 7}
for loop := 32 to 37 do
scale[loop] := scale[loop - 2] * 2;
end;

begin {Main part of procedure Right_Notes}


if scale_system = 1 then
calc_temp_root
else if scale_system = 2 then
calc_pyth_root;
root := roots[key];

if scale_system = 1 then
calc_temp
else if scale_system = 2 then
calc_pyth;

binsfl] := 190.5;
for loop := 2 to 37 do
bins[loop] ;= (scalefloop - 1] + scalefloop]) / 2;
end; {End of Procedure Right_Notes}

^******************************************************************
procedure Draw_Clef (x, y: integer);
begin
pensize(2, 2);
moveto(x - 2, y + 15);
line -1# -i);
line -1# 1);
line If i);
line 3, 0);
line If -4);
line -If -12);
line -If -16);
line 0, -8);
line 2, -4);
line 3, -2);
line 2, 2);
line 0, 4);
line -2, 5);
line -2, 3);
line -6, 7);
line -4, 5);
line -If 5);
line If 4);
line 4, 3);
line 4, 1);
line 4, -i);
line 3, -3);
line 2, -4);
line -2, -4);
line -3, -3);

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
67
line(-4, -1);
line(-4, 2);
line(-2, 4);
line(l, 5);
pensize(l, 1);
end; {End of Procedure Draw_Clef}

procedure screen_setup;
{ >
{ Graphic screen initialization for practice or test run }

var
y: integer;
begin
y := 280;
Fillrect(0, 0, 470, 630, white);
Moveto(80, 60);
Textsize(30);
Writedraw('Program 2: Playing Scales'); {screen heading}
Moveto(200, 90);
Textsize(20);
if mode = 0 then
Writedraw(ch, ' Major')
else
Writedraw(ch, ' minor');
Drawline(x, y, x + length, y); {five lines for one music staff}
Drawline(x, y + 8, x + length, y + 8);
Drawline(x, y + 16, x +length, y +16);
Drawline(x, y + 24, x +length, y +24)
Drawline(x, y + 32, x +length, y +32);
draw_clef(x + 12, y + 24);
Textsize(O);
Moveto(30, 380);
if option = 2 then
WriteDraw('Test Session')
else
WriteDraw( 'Practice Session');
Moveto(30, 400);
WriteDraw( 'Scale System: ', scale_system);
Moveto(30, 420);
WriteDraw('Tolerance Level: ', tol);
end; {End of Procedure Screen_Setup}

£*******************************************************★**************}
procedure Draw_Boxes;
{ >
{ Draws the frames for the graphic display of frequencies }

var
left, right, loop: integer;
begin
for loop := 2 to 13 do
begin
left := round(loop * section - 0.5 * width);
right := round(loop * section + 0 . 5 * width);

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
68
framerect(midy - height, left, midy + height, right);
drawline(left - 3, midy - tol, right + 3, midy - tol);
drawline(left - 5,midy, right + 5, midy);
drawline(left - 3, midy + tol,right + 3, midy + t ol);
end;
end; {End of procedure Draw_Boxes}

£**********************************************************************}

procedure Show_Note (thenote, n; integer);

{ Places the n 'th note and its label '1' on the music staff }

{ n - determines the horizontal position }


{ thenote - determines the vertical position >
{ 1 - two-character label of note }

var
nx, oct, y, ny: integer;
begin
nx := x + ((n - 1) mod 1 2 + 1 ) * section; {calculate position of}
y := 280; {the new note}
ny := y + 52 + thenote * 4;

fillrect(y - 30, nx - 12, y + 68, nx + 12, white);


drawline(x, y, x + length, y ) ; {take the old note out}
drawline(x, y+ 8, x + length, y + 8);
drawline(x, y+ 16, x + length, y +16);
drawline(x, y+ 24, x + length, y +24);
drawline(x, y+ 32, x + length, y +32);
if thenote = 0 then
exit(Show_Note);

paintcircle(nx, ny, 4);


if ny - y >= 40 then
{draw extra ledger lines}
drawline(nx - 6, y + 40, nx + 6, y + 40);
if ny - y >= 48 then
drawline(nx - 6 , y + 4 8 , n x + 6 , y + 4 8 ) ;
if y - ny >= 8 then
drawline(nx-6, y - 8 , n x + 6 , y - 8 ) ;
if y - ny >= 16 then
drawline(nx - 6, y - 16, n x + 6 , y - 16);
if y - ny >= 24 then
drawline(nx - 6, y - 24, nx + 6, y - 24);
if y - ny >= 32 then
drawline(nx - 6, y - 32, nx + 6, y - 32);
end; {End of Procedure Show_Note}

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
69
^ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * >****}

procedure Display (n, err: integer; corr: real);


{ >
{ Graphically displays the degree of accuracy for note 'n* >

var
left, right, nx, In: integer;

procedure sharp; {pitch is sharp}


begin
if err > height - 1 then
err := height - 1;
fillrect(midy - height + 1, left, midy + height - 1, right, white);
if err > tol then
forecolor(205) {red}
else
forecolor(273); {blue}
paintrect(midy - err, left, midy, right);
forecolor(33); {black again}
end;

procedure flat; {pitch is flat}


begin
if err < -height + 1 then
err := -height + 1;
fillrect(midy - height + 1, left, midy + height - 1, right, white);
if -err > tol then
forecolor(205)
else
forecolor(273);
paintrect(midy + 1, left, midy - err, right);
forecolor(33);
end;

begin {Main part of procedure Display}


In := n;
while In > 12 do
In := In - 12;
nx := (In + 1) * section;
left := round(nx - 0.5 * width) + 1;
right := round(nx + 0 . 5 * width) - 1;
if err > 0 then
sharp
else if err < 0 then
flat
else
fillrect(midy - height + 1 , left, midy + height - 1, right, white);

drawline(left - 3, midy - tol, right + 3, midy - tol);


drawline(left - 5, midy,left + 5, midy);
drawline(left - 3, midy + tol, right + 3, midy + tol);
end; {End of procedure Display}

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
70
£**********************************************************************}

procedure Input (first: Boolean);

This procedure prompts the user for input parameters


for a new run/session

Input
first true, if this is the first time playing the scale }
false, if this is not the first time }
Output
option 1 for a practice session }
2 for a test run >
3 for an exact replay ofstudent's notes }
4 for playing the scale perfectly in tune }
tol tolerance level (in cent) }
scale_system - 1 for even-tempered or even >
2 for Pythagorean }
metr metronome number }
key scale key ID number >
1 for G }
2 for G# }
3 for A }

12 for F# >
mode 0 for major }
1 for natural minor }
2 for melodic minor }
3 for harmonic minor }

var
i, j, newtol, new_scale: integer;

begin
Writeln(' Please indicate the type of session you want. Enter 1 for
a practice session, or 2 for a test run.');
if not first then
begin
Writeln('Enter 3 if you want me to replay the scale exactly as
you just played it. Enter 4 if you want me to play the
scale in tune.');
end;
Readln(option);
if (option < 1) or (option > 4) then
option := 1;

if option < 3 then


begin
Writeln(' Now enter the error tolerance level, in cents. Note that
the maximum error is 50 cents.');
if not first then
Writeln('If you want to keep the previous tolerance level, just
hit Return.');
Readln(newtol);
if first then
begin
if newtol > 50 then

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
newtol := 50;
if newtol < 1 then
newtol := 1;
tol := newtol;
end
else if (newtol > 0) and (newtol <= 50) then
tol := newtol;
end;

if option <> 3 then


begin
Writeln(' Please indicate the scale system of your choice. For
even-tempered scales, enter 1. For Pythagorean
scales enter 2.');
if not first then
Writeln('If you want no change, just hit Return.');
Readln(new_scale);
if first then
if (new_scale < 2) or (new_scale > 3) then
scale_system := 1
else
scale_system := new_scale
else if (new_scale > 0) and (new_scale < 4) then
scale_system := new_scale;
end;

if option <> 3 then


begin
Writeln(' If you want a specific tempo, enter the metronome
number. If you do not want any, just hit Return.');
Readln(metr);
end;

Writeln(' Now enter the two-character key of the scale you wish to
play, such as "C#" or "F ".');
if not first then
Writeln('If you want to try the same key, just hit Return.’);
Readln(ch);
if (first) or (ch <> ' ') then
begin
key s= 0;
for j s= 1 to 3 do
begin
for i := 1 to 12 do
if ch = sharps[i] then
begin
key := i;
i := 12;
end;
if key = 0 then
for i := 1 to 12 do
if ch = flats[i] then
begin
key := i;
i := 12;
end;
if key = 0 then
if ch = 'H ' then

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
72
begin
Writeln('Ach, sprechen Sie deutsch? Let us call the H a
B . ’);
key := 5;
end;
if key = 0 then
begin
Writeln(ch, ' is not a valid note identifier.');
if j < 3 then
begin
Writeln(’Try again.');
Readln(ch);
end;
end
else
j := 3;
end;
if key = 0 then
begin
Writeln('OK. Why don't we just call it C.');
key := 6;
end;
end;

Writeln( ' What scale mode do you want to play? For a major key
enter 0 or blank. For a natural minor, enter 1. For a
melodic minor, enter 2. For a harmonic minor, enter 3.
Default: major.');
Readln(mode);
if (mode < 1) or (mode > 3) then
mode := 0;
end; {End of procedure Input}

^**********************************************************************^
procedure Result (score, n, time: integer; ave_metr: real);
{ >
{ Summarizes the results of a practice or test run }

var
avetime: integer;
begin
if option = 1 then {if practice}
begin
avetime := round(time / n);
moveto(30, 360);
WriteDraw( 'You needed on average',avetime, ' ticks to find the
correct pitch.'); {1 tick = 1/60 second}
end
else
{if test}
begin
moveto(30, 360);
WriteDraw( 'Your total score for this test run was', score);
end;
end; {End of procedure Result}

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
73

function Jump (var thenote,change: integer; mean_freq: real): boolean;

This function determines whether the latest mean frequency is


closer to the correct frequency of the note above or below.

Input
thenote - the note ID number for the previous mean frequency
mean_freq - the new mean frequency
Bins - the frequencies separating adjacent notes

Output
thenote - the updated note number (if updating was necessary)
change 0 no change
1 we moved up one note
-1 we moved down one note

begin
Jump := false;
if mean_freq > Bins[thenote + 1] then
begin
thenote := thenote + 1;
change := 1;
Jump := true;
end;
if mean_freq < Bins[thenote] then
begin
thenote := thenote - 1;
change := -1;
Jump := true;
end;
end; {End of function Jump}

{
procedure Scales (var gflag: integer);

This procedure executes one test/practice run of a scale

Input:
option - session option (practice or test)
mode - major or minor
key - key of scale being played
Scales - array with correct frequencies of chromatic scale

Output
gflag - 1 successful or nonfatal run; try again
-1 no input received from pitch analyzer

var
register: array[l. .10] of real; {up to 10 most recent frequencies}
n: integer; {note number, from 1 to nn}
thenote: integer; {ID number of note n}
time: integer; {total time to reach correct pitch}
lset: integer; {0 if clock is ticking for time}
error: integer; {frequency error, in cents}
rcount: integer; {number of freqs forming rmean}
gcount: integer; {total number of freqs for note n}

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
74
lpointer: integer; {pointer to Register}
grade: integer; {grade for note n)
score: integer; {total score for this run}
nbuf: integer; {no. of words currently in buffer}
change: integer; {1 if jump up, -1 jump down a note}
jj: integer; {frequency number}
j, nx, flag, contr, returnflag: integer;
{local loop indices and flags}
gbegin, gend, lbegin, lend, tend: longint;
{local and global clock readings}
freq: real; {last freq rec'd from Serial Port}
correct: real; {correct frequency of thenote}
accmean, m e a n , gmean: real; {local and global means of freq}
ave_metr: rea1; {student's average metronome play}
newnote, firstfreq: Boolean; {true if first freq or new note}

begin
dur := 180; {3 second wait}
gflag := 1; {return flag to Main Program - }
Writeln('At the beep you may start playing.'); {1 for success}
{-1 for error exit}
Draw_Boxes;
Delay(dur, final);
SysBeep(0);
time := 0;
score := 0; {total score for run, if test run}
nbuf := 0; {no of bytes currently in buffer}
n := 0; {note number, from 1 to nn}
jj := 0; {recorded frequency number}

for j := 1 to 3 do {allow 3 starts with a wrong note}


begin
m e a n := 0.0;
for i := 1 to 5 do
begin
ReadSP(freq, nbuf, returnflag); {read the first 5 frequencies}
Registerfi] := freq;
m e a n := m e a n + freq;
end;
freq := freq / 5.0;
if (freq = 0.0) or (returnflag = -1) then
begin {something went wrong or nothing}
gflag := -1; {was found in Serial Port}
WriteSP('S', returnflag);
exit(Scales);
end;
thenote := 1; {pointer to Scale array with}
{correct freqs}
flag := 1; {flag = 0 only if}
for i := 1 to 4 do {user starts on the right note}

begin
correct := Scale[thenote]; {the expected first frequency}
error := round((freq / correct - 1) * 1730.0);
if abs(error) < 60 then
begin
flag := 0;
i := 4;

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
75
notes[l] := thenote;
j := 3;
end
else {check if user starts with a higher}
thenote := thenote + 7; {octave}
end;

if flag = 1 then
if j < 3 then
begin
Writeln('You must start this scale with a ch,
Try again.');
WriteSP('S', returnflag);
WriteSP('G', returnflag);
end
else
begin
gflag := -1;
exit(Scales);
end;
end; {end of starter loop}

firstfreq := true; {we start with the first 5 readings}


gbegin := tickcount; {start the clock}
contr := 0;
while contr = 0 do {indefinite loop for reading next}
begin {frequency}
if not firstfreq then
ReadSP(freq, nbuf, returnflag); {read next frequency}
if freq = 0.0 then {no freq received for 5 seconds}
if n < 5 then {we expect at least 5 notes}
begin
gflag := -1;
exit(Scales);
end
else
begin
nn := n;
gend := tickcount - 300; {total time adjusted for 5 sec}
{waiting}
ave_metr := (n * 60 / (gend - gbegin)) * 60;
{metronome count of student's scale}
Result(score, n, time, ave_metr); {display the results}
exit(Scales);
end;
newnote := firstfreq;
if not firstfreq then
newnote := Jump(thenote, change, rmean);{do we have a new note?}
if newnote then
begin
if firstfreq then
begin
firstfreq := false;
change := 0; {if it is the first note, there is}
end {no change of thenote}
else
begin {process the last note}
gmean :=gmean / gcount; {score is based on global mean freq}

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
76
error := round((gmean / correct - 1) * 1730.0);
grade := 1;
if abs(error) < 2 . 0 * tol then
grade := 2;
if abs(error) < tol then
grade := 3;
score := score + grade;
tend := tickcount;
if lset = 0 then
lend := tend;
time := time + lend - lbegin;
jtotal := jj;
if option = 2 then
begin
nx := ((n - 1) mod 1 2 + 1 ) * section + 10;
moveto(nx, midy + height + 15);
WriteDraw( grade); {add score for note n to display}
end;
end;

n := n + 1; {initialization for the new note}


lbegin s= tickcount;
lset := 0; {reset the clock for the new note}
rcount ;= 1; {no of freqs in register for running mean}
gcount ;= 1; {total no of readings for note n}
lpointer := 1; {pointer to Register}
thenote := thenote + change;
notes[n] := thenote;
correct := Scale[thenote]; {correct frequency of new note}
if (mode = 2) and (change = -1) then
begin {special case of melodic minor down}
if (thenote + 1) mod 7 = (thenote + 1) then
correct := Scale[(thenote div 7) * 2 + 29];
if thenote mod 7 = thenote then
correct := Scale[(thenote div 7) * 2 + 28];
end;
Register!1] := freq;
accmean := freq;
rmean := freq; {running mean of up to last 10 readings}
gmean := freq; {overall mean frequency of note n}
jj s= jj + i;
Recording!jj] := freq; {record of frequencies as played}
Show_Note(thenote, n); {display the new note}
end {end of case that a jump occurred}

else

begin
lpointer :=lpointer + 1 ; {a new freq for the same note n}
if lpointer > 10 then
lpointer := lpointer - 10;
rcount := rcount + 1; {number of frequencies in register}
gcount := gcount + 1 ; {total no of readings for note n}
gmean := gmean + freq; {global mean}
accmean := accmean + freq; {running mean of up to last 10
if rcount > 10 then {readings}
accmean := accmean - Register!lpointer];
Register!lpointer] := freq;

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
77
if rcount >= 10 then
m e a n := 0.1 * accmean
else
rmean := accmean / rcount;
error :=round((rmean /correct - 1) * 1730.0);
if(abs(error) < tol) and (lset = 0) then
begin {success; time = lend-lbegin}
lend := tickcount;
lset := 1;
end;
Display(nf error, correct); {display frequency graphically)
end;
end; {end of loop for reading a freq)
end; {End of Procedure Scales)

procedure Play_Back;
{ >
{ This procedure plays the scale exactly the way the user )
{ has just played - like a tape-recording )

var
jj, ifreq: integer;

begin
dur := 180;
Writeln('This is exactly the way you played the piece last.');
Delay(dur, final);
for jj := 1 to jtotal do
begin
ifreq := round(Recording[jj]);
Note(ifreq, 255, 3);
end;
Delay(dur, final);
end; {End of Procedure Play_Back)

procedure Play_Correct;
{ >
{ This procedure plays the scale perfectly in tune }
{ within the scale system selected by the user. }

var
n, ifreq, met: integer;

begin
dur := 180;
Writeln( 'As you requested, I will now play one octave of your scale
perfectly in tune within the scale system that you had
selected. You may either want to play along or just
listen.');
met := 60;
if metr > 0 then
met := metr;
Delay(dur, final);
for n := 1 to 8 do

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
78
begin
ifreq := round(Scale[n]);
Note(ifreq, 255, met);
end;
ifreq := round(Scale[7]);
if mode = 2 then
ifreq := round(Scale[29]);
Note(ifreq, 255, met);
ifreq := round(Scale[6]);
if mode = 2 then
ifreq := round(Scale[2 8]);
Note(ifreq, 255, met);
for n := 5 to 1 do
begin
ifreq ;= round(Scale[n]);
Note(ifreq, 255, met);
end;
Delay(dur, final);
end; {End of Procedure Play_Correct}

^**********************************************************************}.
begin {Main Program - Program 2}

SetRect(txRect, 225, 420, 615, 478); {set up graphic display)


SetTextRect(txRect); {and text windows)
ShowText;
SetRect(drRect, 5, 40, 635, 475);
SetDrawingRect(drRect);
ShowDrawing;
Writeln(' If you want a detailed description of this program,
enter a "C" and Return. If you want to skip the
introductory comments, just hit Return.');
Read(c_key);
if c_key = 'C' then
Introduction;
Assign_Labels;

first := true; {indicates the first run)


control := 0; {initialize control flag)
errorflag := 1;
if Open_SerialDriver = noErr then {open Serial Port)
errorflag := Get_Ready;
{wait for OK from Pitch Analyzer)
while (errorflag = 0)and(control = 0) do
begin {start Program 2 only if switch is)
if first then {turned on, i.e. if errorflag=0)
Input(first)
else
begin
Writeln(Do you want to change any input parameters?');
Writeln('Enter "Y" for Yes or "N" for No.');
Readln(Yes);
if Yes = 'Y' then
Input(first);
end;
Right_Notes;
Screen_Setup;

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
79
if option < 3 then
begin
if metr > 0 then
begin
Writeln('This is the metronome tempo you requested.');
Metronome(metr);
end;
Writeln('When you are ready, enter the letter "G" and Return.');
Readln(Go);
if Go = 'G' then
begin
WriteSP('G ', returnflag);
Scales(gflag);
end
else
gflag := -1;
end
else if (option = 3) and (not first) then
Play_Back
else if option = 4 then
Play_Correct;
if gflag = -1 then
control := 1
else
begin
Writeln(Do you want to try again? If yes, enter "Y" and "N"
for n o .’);
control := 1;
Readln(Yes);
if Yes = 'Y' then
control := 0;
end;
first := false;
end;
Close_Port; {close Serial Ports}
SysBeep(O);
Writeln('Please turn off the Pitch Analyzer switch.');
end. {End of Main Program - Program 2}

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
80

{**********************************************************************}

{* *}
{* Program 3 - Playing Passages *}
{* . *>

program three;

{ Global Declarations }

uses
Serial; {needed to access serial ports}

type
i_array = array[1..200] of integer;
j_array = array[0..12] of integer;
r_array = array[1..63] of real;
N_label = string[2];
c_array = array[l..200] of N_label;
s_array = array[0..12] of N_label;
i_file = file of integer;
c_file = file of string[2];
str_file = file of string]80];

const
hs = 1.05946; {half-step size in even-tempered system)
x = 30; {left margin of graphic screen}
length = 550; {width of graphic screen to be used}
section = 40; {width of one section, e.g. for one note}
midy = 150; {y-coord of graphic display centerline}
height = 50; {half height of graphic display box}
width = 2 0 ; {width of graphic display box}

var
pointerfile, notesfiles i_file; {files with user's library of}
labelsfile: c_file; {practice pieces}
titlesfile: str_file;
Recording: array[1..1200] of real; {recording of student's freqs}
times: i_array; {durations of notes played by student}
sharps, flats: s_array; {labels for notes of one octave}
labels: c_array; {labels for all notes of a piece}
notes: i_array; {ID nos for all notes of a music piece}
pos: j_array; {vertical position array for notes}
Scale: r_array; {correct freqs of 5 chromatic scales}
Bins: r_array; {half-way marks between adjacent notes}
txRect, drRect: Rect; {dimensions of text and graphic windows}
option: integer; {option: 1-practice, 2-test}
scale_system: integer; {1-even tempered, 2-Pythagorean}
tol: integer; {error tolerance, in cents}
mode: integer; {0-major,1-natural,2-melodic,3-harm.minor}
metr: integer; {metronome number}
key: integer; {1-G, 2-G#, 3-A, ..., 12-F#}
jtotal: integer; {total number of recorded frequencies}
ibegin, iend: longint; {begin and end of timer interval, in sec}

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
81
dur, final: longint; {parameters for system delay function}
loop: integer; {local do-loop variable}
nn: integer; {total number of notes in a music piece}
gflag, control, errorflag: integer; {error and control flags}
inRefNum, outRefNum: integer; {reference nos for serial port drivers}
iErr: OSErr; {operating system error flag}
c_key, Yes: char; {characters input on the keyboard}

procedure Introduction;
begin
Writeln(' Welcome to our third program! Earlier you had an
opportunity to tune your strings and practice scales. You
may now select any musical passage, and I will assist you in
improving your intonation when playing it.’);

Writeln(' Before we start, you have to let me know what you want to
play. After turning on the pitch analyzer and entering a G
on your keyboard, play your piece as in tune as you can.
I will determine the notes you are playing by finding
the notes whose frequencies come closest, and display them
on the screen. My guesses will be accurate as long as you
do not play off by more than a quarter note. This initial
playing session will be followed by a correction phase, when
you will have the opportunity to correct any wrong notes.');

Writeln(' Once you are satisfied with the notes displayed on the
screen, you may practice the piece in exactly the same way
as you did when you practiced scales in the second program.
That means you may choose a practice or a test session,
enter a tolerance level and a metronome number. If you
select a scale system other than even-tempered, then you
also must tell me the key in which the passage is
written.');

Writeln(' Again, you do not have to memorize anything, because I


will guide you step by step. You may play and replay the
same piece as many times as you wish. When you want to stop,
simply enter an "S”.');

Writeln(' After you are done you may want to save the piece you just
practiced, so that you do not have to reenter it in case
you wish to practice it again later. This way you can build
your own library of practice pieces, and at the beginning of
a new session, instead of entering a new piece and
correcting it, you simply retrieve any one of the prestored
pieces.1);
end; {End of Introduction}

function Get_Ready: integer;


{ >
{ Theuser has two 5-second periods }
{ to turn on the Pitch Analyzer Switch }
{ >
{ GetJReady= 0 Pitch Analyzer sends OKsignal }

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
82
= 1 Error exit; no signal received

Internal error flag = 1 successful receipt of "OK."


0 no receipt of OK so far, keep looking
-1 no receipt within 5 seconds

var
flag, ntrial: integer;

begin
Writeln( 'Whenever you are ready, turn on the switch of the Pitch
Analyzer.');
Get_Ready := 1;
flag := 0;
Getdatetime(ibegin);
for ntrial := 1 to 2 do
begin
while flag = 0 do
begin {wait 5 sec for user to }
if ReadOK then {turn on Pitch Analyzer switch}
flag ;= 1;
Getdatetime(iend);
if iend - ibegin > 5 then
flag := -1;
end;
if flag = 1 then
begin
GetJReady := 0;
ntrial := 2;
end
else {try a second time}
begin
if ntrial = 1 then
Writeln(' We did not get the O K . Try again.');
flag := 0;
Getdatetime(ibegin);
end;
end;
end; {End of function Get_Ready}

procedure metronome (met: integer);


var
loop: integer;
begin
for loop := 1 to round(met / 6) do
begin
note(1760, 255, 2);
note(1760, 0, round(3600 / met) - 2);
end;
end; {End of procedure Metronome}

r* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 1

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
83

procedure Assign_Labels;

This procedure initializes various arrays

var
loops integer;
begin
sharps[0] = 'F#'
sharps[1] = 'G ’
sharps[2] = 'G#'
sharps[3] _ .A .
sharps[4] = 'A#'
sharps[5] = 'B '
sharps[6] = *C '
sharps[7] = ’C#'
sharps!8] = 'D '
sharps[9] = 'D#'
sharps[10] := 'E
sharps[11] s= 'F
sharps[12] := 'F#

flats[0] = 'F ';


flats[l] = 'G ';
flats[2] = 'A b ';
flats[3] = 'A ';
flats[4] = 'Bb1;
flats[5] = 'Cb';
flats[6] = 'C •;
flats[7] = 'Db';
flats[8] = 'D ';
flats[9] = 'Eb';
flats[10] .E ■
flats[11] := 'F '
flats[12] := 'Gb1

pos[0 = 6
pos[ 1 = 0
pos[ 2 = 0
pos[3 = 1
pos[ 4 = 1
pos[5 = 2
pos[ 6 = 3
pos[ 7 = 3
post 8 = 4
pos[ 9 = 4;
pos[10] = 5;
posfll] = 6;
pos[12] = 6;

for loop := 1 to 36 do
begin
notes Iloop] := 0;
labels[loop] := ' '
end;
end; {End of Procedure Assign_Labels}

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
84
procedure Right_Notes;

This procedure determines the correct frequencies for


chromatic scales and stores these in array Scales.
It also defines the half-way marks between adjacent notes
and stores these in array Bins.

Input
scale_system - 1 for even-tempered
2 for Pythagorean
key - scale key ID number
1 for G
2 for G#
3 for A

12 for F#
mode 0 for major
1 for natural minor
2 for melodic minor
3 for harmonic minor

var
loops integer;
roots real;
rootss array[1..12] of real;

procedure calc_temp_root; {Fundamental freqs in even-tempered system}


begin
roots[l] = 196; {G}
roots[2] = 207.65;
roots[3] = 220; {A}
roots[4] = 233.08;
roots[5] = 246.94; (B)
roots[6] = 261.63; {C}
roots[7] = 277.18;
roots[8] = 293.66; {D}
roots[9] = 311.13;
roots[10] s= 329.63; {E}
roots[11] s= 349.23; {F}
roots[12] s= 369.99;
end;

procedure calc_pyth_root; {Fundamental freqs in Pythagorean system}


begin
roots[1] = 195.56; {G}
roots[2] = 208.83;
roots[3] = 220; {A}
roots[4] = 231.77;
roots[5] = 247.5; {B}
roots[6] = 260.74; {C}
roots[7] = 278.44;
roots[8] = 293.33; {D}
roots[9] = 309.03;
roots[10] :== 330; {E}
roots[11] :== 347.65; {F}
roots[12] :== 371.25;

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
85
end;

procedure calc_temp; {5 octaves of even-tempered scales in key "key"}


var
loops integer;
begin
scale[l] := root;
for loop ;= 2 to 12 do
scale[loop] := scale[loop - 1] * hs;
end;

procedure calc_pyth; {5 octaves of Pythagorean scales in key "key”}


begin
scale[l] :=root;
scale[2] :=root * 256 / 243; {minor 2}
scale[3] :=root * 9 / 8 ; {major 2}
scale[4] :=root * 32 / 27; {minor 3}
scale[5] :=root * 81 / 64; {major 3}
scale[6] :=root * 4 / 3 ; {perfect 4}
scale[7] :=root * 729 / 512; {aug 4}
scale[8] :=root * 3 / 2 ; {perfect 5}
scale[9]:= root * 128 / 81; {minor 6}
scale[10] := root * 27 / 16; {major 6}
scale[ll] := root * 1 6 / 9 ; {minor 7}
scale[12] := root * 243 / 128; {major 7}
end;

begin {Main part of procedure Right_Notes}


if scale_system = 1 then
calc_temp_root
else if scale_system = 2 then
calc_pyth_root;
root s= roots[key];

if scale_system = 1 then
calc_temp
else if scale_system = 2 then
calc_pyth;

for loop := 13 to 63 do
{fill higher octaves}
scale[loop] := scale[loop - 12] * 2;
for loop := 1 to 51 do
{shift scales to always start with G}
scale[loop] := scale[loop + 13 - key] / 2;

bins[l] := 190.5;
for loop := 2 to 51 do
bins[loop] ;= (scale[loop - 1] + scale[loop]) / 2;
end; {End of Procedure Right_Notes}

{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * \

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
86

procedure Draw_Clef (x, y: integer);


begin
pensize(2, 2);
moveto(x - 2, y + 15);
line(-l, -1);
line(-l, 1);
line (.1, 1);
line(3, 0);
line(1, -4);
line(-l, -12);
line(-l, -16);
line(0, -8);
line(2, -4);
line(3, -2);
line(2, 2);
line(0, 4);
line(-2, 5);
line(-2, 3);
line(-6, 7);
line(-4, 5);
line(-l, 5);
line(l, 4);
line(4, 3);
line(4, 1);
line(4, -1);
line(3, -3);
line(2, -4);
line(-2, -4);
line(-3, -3)
line(-4, -1);
line(-4, 2);
line(-2, 4);
line(l, 5);
pensize(l, 1);
end; {End of Procedure Draw_Clef}

procedure First_Setup;

Graphic screen initialization for music input phase

var
Y, loop: integer;
begin
moveto(80, 60);
textsize(30);
drawstring( 'Program 3 Playing Passages'); {screen heading}
textsize(O);
for loop := 1 to 3 do
begin
y := loop * 100; {three five-line music staffs}
drawline(x, y, x + length, y);
drawline(x, y + 8, x + length, y + 8);
drawline(x, y + 16, x + length, y + 16);
drawline(x, 24, + length, 24);
drawline(x, 32, + length, 32);

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
87
draw_clef(x + 12, y + 24);
end;
end; {End of Procedure First_Setup}

procedure Second_Setup;
{ >
{ Graphic screen initialization for practice or test run }

var
y: integer;
begin
y := 280;
fillrect(0, 0, 470, 630, white);
moveto(80, 60);
textsize(30);
drawstring( 'Program 3s Playing Passages'); {screen heading}
drawline(x, y, x + length, y ) ; {five lines for one music staff}
drawline(x, y + 8, x + length, y + 8);
drawline(x, y + 16,x +length,y +16);
drawline(x, y + 24,x +length,y +24);
drawline(x, y + 32,x +length,y +32);
draw_clef(x +12, y + 24);
textsize(O);
moveto(30, 380);
if option = 1 then
WriteDraw('Practice Session')
else
WriteDraw('Test Session');
moveto(30, 400);
WriteDraw( 'Scale Systems ', scale_system);
moveto(30, 420);
WriteDraw('Tolerance Levels ', tol);
end; {End of Procedure Second_Setup}

procedure Draw_Boxes;
{ >
{ Draws the frames for the graphic display of frequencies }

var
left, right, loops integer;
begin
for loop s= 2 to 13 do
begin
left s= round(loop * section - 0.5 * width);
right s= round(loop * section + 0 . 5 * width);
framerect(midy - height, left, midy + height, right);
drawline(left - 3, midy - tol, right + 3, midy - tol);
drawline(left - 5,midy, right + 5, midy);
drawline(left - 3,midy + tol,right + 3, midy + tol);
end;
end; {End of procedure Draw_Boxes}

R ep ro d u ced with p erm ission o f the copyright ow ner. Further reproduction prohibited w ithout perm ission.
procedure First_Show_Note (note, n: integer; 1: n_label);

PlaceB the n'th note and its label '1' on the music staff

n - determines the horizontal position


note - determines the vertical position

var
nx, oct, y, ny: integer;
begin
nx := x + ((n - 1) mod 12 + 1) * section; {calc, position of new note}
oct := (note - 1) div 12;
y := ((n - 1) div 1 2 + 1 ) * 100;
ny := y + 52 - (oct * 28) - (pos[note mod 12] * 4);

fillrect(y - 30, nx - 12, y + 68, nx + 12, white);


drawline(x, y, x + length, y ) ; {take the old note out}
drawline(x, y + 8, x + length, y + 8);
drawline(x, y + 16, x + length, y + 16);
drawline(x, y + 24, x + length, y + 24);
drawline(x, y + 32, x + length, y + 32);
if note = 0 then
exit(first_show_note);

paintcircle(nx, ny, 4);


if ny - y >= 40 then
{draw extra ledger lines}
drawline(nx - 6, y + 40, nx + 6, y + 40);
if ny - y >= 48 then
drawline(nx - 6, y + 48, nx + 6/ y + 48);
if y - ny >= 8 then
drawline(nx - 6, y - 8, nx + €i, y -■ 8);
if y - ny >= 16 then
drawline (nx - 6, y - 16, nx + 6, y - 16);
if y - ny >= 24 then
drawline(nx - 6, y - 24, nx + 6, y - 24);
if y - ny >= 32 then
drawline(nx - 6, y - 32, nx + 6, y - 32);
if labels[loop][2] = '#' then {add sharp symbol }
begin
moveto(nx - 13, ny + 6);
textsize(15);
drawstring('#');
textsize(0);
end;
moveto(nx - 6, y + 68);
{add label }
drawstring(l);
end; {End of Procedure First_Show_Note}

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
89

procedure Second_Show_Note (n : integer);


{ >
{ This procedure draws a set of 12 notes and their labels '1’ }
{ in their proper positions on the musical staff }

var
loop, y, nx, ny, left, right, oct, finish: integer;

begin
fillrect(midy - height - 1, 0, y + 70, 600, white);
second_setup;
draw_boxes;
y := 280;

finish := n + 11;
for loop := n to finish do
begin
if notes[loop] = 0 then
exit(second_show_note);
nx := ((loop - 1) mod 1 2 + 2 ) * section; {calc. pos. of new note)
oct := (notes[loop] - 1) div 12;
ny := y + 52 - (oct * 28) - (pos[notes[loop] mod 12] * 4);
paintcircle(nx, ny, 4);

if ny - y >= 40 then {draw extra ledger lines)


drawline(nx - 6, y + 40, nx + 6, y + 40);
if ny - y >= 48 then
drawline(nx - 6, y + 48, nx + 6, y + 48);
if y - ny >= 8 then
drawline(nx- 6, y - 8, n x + 6, y - 8);
if y - ny >= 16 then
drawline(nx - 6, y - 16, nx + 6, y - 16);
if y - ny >= 24 then
drawline(nx - 6, y - 24, nx + 6, y - 24)
if y - ny >= 32 then
drawline(nx - 6, y - 32, nx + 6, y - 32);
if labels[loop][2] = '#' then {add sharpsymbol }
begin
moveto(nx - 13, ny + 6);
textsize(15);
drawstring(’#');
textsize(O);
end;
moveto(nx - 6, y + 68); {add label }
drawstring(labels[loop]);
end;
end; {End of Procedure Second_Show_Note)

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
90

procedure Display (n, errs integer; corrs real);


{ >
{ Graphically displays the degree of accuracy for note 'n' }

var
left, right, nx, In: integer;

procedure sharp; {pitch is sharp}


begin
if err > height - 1 then
err := height - 1;
fillrect(midy - height + 1, left, midy + height - 1, right, white);
if err > tol then
forecolor (205) {rec*}
else
forecolor(273); {blue}
paintrect(midy - err, left, midy, right);
forecolor(33); {black again}
end;

procedure flat; {pitch is flat}


begin
if err < -height + 1 then
err := -height + 1;
fillrect(midy - height + 1, left, midy + height - 1, right, white);
if -err > tol then
forecolor(205)
else
forecolor(273);
paintrect(midy + 1, left, midy - err, right);
forecolor(33);
end;

begin {Main part of procedure Display}


In := n;
while In > 12 do
In := In - 12;
nx := (In + 1) * section;
left := round(nx - 0.5 * width) + 1;
right := round(nx + 0.5 * width) - 1;
if err > 0 then
sharp
else if err < 0 then
flat
else
fillrect(midy - height + 1, left, midy + height - 1, right, white);

drawline(left -3, midy - tol, right + 3, midy - tol);


drawline(left -5, midy, left + 5, midy);
drawline(left -3, midy + tol, right + 3, midy + tol);
end; {End of procedure Display}

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
91

procedure Input (first: Boolean);

This procedure prompts the user for input parameters


for a new run/session

Input
first true, if this is the first pass of the piece
false, if this is not the first time
Output
option 1 for a practice session
2 for a test run
3 for an exact replay ofstudent'snotes
4 for playing the piece perfectly in tune
tol tolerance level (in cent)
scale_system 1 for even-tempered
2 for Pythagorean
metr metronome number
key scale key ID number
1 for G
2 for G#
3 for A

12 for F#
mode - 0 for major
1 for natural minor
2 for melodic minor
3 for harmonic minor

var
i, j, newtol, new_scale: integer;
c h : N_Label;

begin
Writeln(' Please indicate the type of session you want. Enter a 1 for
a practice session, and a 2 for a test run.');
if not first then
begin
Writeln( 'Enter a 3 if you want me to replay the piece exactly as
you just played it. Enter a 4 if you want me to play the
piece perfectly in tune.');
end;
Readln(option);
if (option < 1) or (option > 4) then
option := 1;

if option < 3 then


begin
Writeln(' Now enter the error tolerance level, in cents.');
Writeln(' Note that the maximum error is 50 cents.');
if not first then
Writeln(’If you want to keep the previous tolerance level, just
hit Return.');
Readln(newtol);
if first then
begin
if newtol > 50 then

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
92
newtol := 50;
if newtol < 1 then
newtol s= 1;
tol := newtol;
end
else if (newtol > 0) and (newtol <= 50) then
tol ;= newtol;
end;

if option <> 3 then


begin
Writeln(' Please indicate the scale system of your choice. For
even-tempered scales, enter 1. For Pythagorean
scales enter 2.');
if not first then
Writeln('If you want no change, just hit Return.’);
Readln(new_scale);
if first then
if (new_scale < 2) or (new_scale > 3) then
scale_system := 1
else
scale_system := new_scale
else if (new_scale > 0) and (new_scale < 4) then
scale_system := new_scale;
end;

if option < 3 then


begin
Writeln( ' If you want a specific tempo, enter the metronome
number. If you do not want any, just hit Return.');
Readln(metr);
end;

if first then
begin
Writeln( ' Now enter the two-character key of the piece you wish to
play, such as "C#" or "F ".');
key := 0;
for j ;= 1 to 3 do
begin
Readln(ch);
for i := 1 to 12 do
if ch = sharpsji] then
begin
key := i;
i := 12;
end;
if key = 0 then
for i := 1 to 12 do
if ch = flats[i] then
begin
key := i;
i := 12;
end;
if key = 0 then
begin
Writeln(ch, ' is not a valid note identifier.');
if j < 3 then

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
93
Writeln('Try again.');
end
else
j := 3;
end;
if key = 0 then
begin
Writeln('OK. Why dont we just call it C.');
key := 6;
end;

Writeln( ' What mode is your piece written in? For a major key
enter 0 or blank. For a natural minor, enter 1. For a
melodic minor, enter 2. For a harmonic minor, enter 3.
Default: major.’);
Readln(mode);
if (mode < 1) or (mode > 3) then
mode := 0;
end;
end; {End of procedure Input}

procedure Result (score, n, time: integer; ave_metr: real);


{ >
{ Summarizes the results of a practice or test run }

var
avetime: integer;
begin
if option = 1 then {if practice}
begin
avetime := round(time / n);
moveto(30, 360);
WriteDraw('You needed on average', avetime, ' ticks to find the
correct pitch.'); {1 tick = 1/60second}
end
else {if test}
begin
moveto(30, 360);
WriteDraw('Your total score for this test run was', score);
end;
end; {End of procedure Result}

£************★★********★***********************************************}.

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
94

function Jump (var note, change: integer; mean_freq: real): boolean;

This function determines whether the latest mean frequency is


closer to the correct frequency of the note above or below.

Input
note the note ID number for the previous mean frequency
mean_freq the new mean frequency
Bins the frequencies separating adjacent notes

Output
note the updated note ID no (if updating was necessary)
change 0 no change
1 we moved up one note
-1 we moved down one note

begin
Jump := false;
if mean_freq > Bins[note + 1] then
begin
note := note + 1 ;
change := 1;
jump := true;
end;
if mean_freq < Bins[note] then
begin
note := note - 1;
change := -1;
jump := true;
end;
end; {End of function Jump}

^**********************************************************************}.

procedure Identify (var mnote: integer; freq: real);

{ This procedure identifies the closest note ID number }


{ for a given frequency }

{ Input }
{ freq - frequency of note to be identified }
{ Bins - frequencies separating adjacent notes }

{ Output }
{ mnote - note ID number }

var
k, 1, m: integer;
begin
1 := 1 ;
k := 50;
while k > 1 + 1 do
begin
m := (k + 1) div 2;
if freq > Bins[m] then
1 := m
else

R ep ro d u ced with p erm ission o f the copyright ow ner. Further reproduction prohibited w ithout p erm ission.
95
k := m;
end;
nrnote := (k + 1) div 2;
end; {End of Procedure Identify}

{
procedure First_Pass (var localflag: integer);

This procedure processes an arbitrary piece of music in a first pass

Input
freq frequency received from the Pitch Analyzer
Bins frequencies separating adjacent notes
sharps the 12 note labels with sharps

Output
nn number of notes that define this piece of music
notes - array with the nn note ID numbers
labels - musical characters identifying the nn notes (e.g. G#)
localflag- exit flag
1 successful completion
-1 no input received from Pitch Analyzer

var
nbuf: integer; {number of bytes currently in buffer}
counts integer; {number of freq readings for same note}
returnflag: integer; {error flag returned from SP procedures}
Register: array[1..10] of real;{array with up to 10 last readings}
lpointer, contr, difference: integer;
change, i, mnote, timelimit, n: integer;
freq, accmean, mean_freq: real;
mlabel: N_label;

begin
dur := 180; {delay time 180 ticks = 3 seconds}
Writeln('At the beep you may start playing.');
WriteSP('G ', returnflag); {enable pitch analyzer}
localflag := returnflag;
if returnflag = 1 then
begin
Writeln('Error in Serial Port Write.');
SysBeep(O);
exit(First_Pass);
end;

Delay(dur, final); {wait 3 seconds}


SysBeep(0);
timelimit := 5; {initialization}
n := 0; {note no.; the last one will be nn}
mean_freq := 1.0;
accmean := 0.0;
nbuf := 0; {number of words in buffer}
count := 1; {no. of freq readings for same note}
lpointer := 1;
contr := 0;
while contr = 0 do {indefinite loop for new freq read}
begin

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
96
localflag := 1;
ReadSP(freq, nbuf, returnflag); {read next frequency}
if (freq = 0) or (returnflag = -1) then
begin
if (n = 0) or (returnflag = -1) then
localflag j = - 1;
if n > 0 then
begin
notes[n] := mnote;
labels[n] := mlabel {save ID no and label of last note}
end;
nn := n; {we received data for nn notes}
WriteSP('S', returnflag); {disable Pitch Analyzer}
exit(First_Pass); {normal exit from First_Pass}
end;

difference := round((freq / mean_freq - 1) * 1730);


{we got a new non-zero frequency}
if abs(difference) < 50 then
begin {the new freq is close to the previous one}
count := count + 1 ; {i.e. it continues the current note}
lpointer := lpointer + 1 ;
if lpointer > 10 then
lpointer := lpointer - 10;
accmean := accmean + freq;
if count > 10 then
accmean := accmean - Register[lpointer]; {update running}
Register!lpointer] := freq; {mean frequency}
if count > = 1 0 then
mean_freq := 0.1 * accmean {the user is allowed to adjust}
else {the freq until the "right one"}
mean_freq := accmean / count;{appears on screen}
if Jump(mnote, change, mean_freq) then
begin {check if we jumped to the}
i := mnote mod 12; {next higher or lower note}
mlabel := sharps[i]; {get label for new note n}
First_Show_Note(mnote, n, mlabel);
end; {display the new note with its label}
end

else
begin {we got a new note, it could be the first one}
if n > 0 then
begin
notes[n] := mnote;
labels[n] := mlabel {save ID number and label of last note}
end;
n := n + 1;
lpointer := 1; {initialization for the new note}
count := 1;
mean_freq := freq;
accmean := freq;
Register!1] := freq;
Identify(mnote, freq); {identify what note fits the new freq}
i := mnote mod 12;
mlabel := sharps!i]; {get it's label}
First_Show_Note(mnote, n, mlabel);
end; {display new note with its label}

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
97
end; {continue to read the next frequency}
end; {End of Procedure First_Pass}

^**********************************************************************}

procedure Correct (n, octave: integer; ch: n_label);

The user wants to change the n'th note to a note identified


by character ch and octave. This procedure finds the
ID number of a new note.

Input
n - position number of note to be corrected
ch - correct note label
octave - the octave over open G of correct note
sharps - the 12 note labels with sharps
flats - the 12 note labels with flats

Input/Output
notes - old/new note ID numbers
labels - old/new note labels

var
i, j: integer;

begin {find note ID in first octave}


j s= 0;
for i := 1 to 12 do
if ch = sharps[i] then
begin
j := i;
i := 12;
end;
if j = 0 then
for i := 1 to 12 do
if ch = flats[i] then
begin
j := i;
i := 12;
end;
if j = 0 then
begin
Writeln(ch, ' is not a valid note identifier. Try again. ');
exit(Correct);
end;

i := octave;
if (octave < 0) or (octave > 4) then
i := 0;
notes[n] := j + i * 12;
{add octaves}
labels[n] := ch;
first_show_note(notes[n), n, ch);
end; {End of Procedure Correct}

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
98

procedure Insert (var n, octave, nn: integer; ch: n_label);

The user wants to insert a note after the n'th note, identified by
character ch and octave. This procedure updates the notes
and labels arrays.

Input
n position number of note to be followed by a new note
ch note label
octave the octave over open G of new note
sharps the 12 note labels with sharps
flats the 12 note labels with flats

Input/Output
nn total number of notes making up this music piece
notes old/new note ID numbers
labels - old/new note labels

var
i, j, k: integer;

begin {find note ID for added note}


j := 0;
for i := 1 to 12 do
if ch = sharps[i] then
begin
j := i;
i := 12;
end;
if j = 0 then
for i := 1 to 12 do
if ch = flats[i] then
begin
j := i;
i := 12;
end;
if j = 0 then
begin
Writeln(ch, ' is not a valid note identifier. Try again. ');
exit(Insert);
end;

k := octave;
if (k < 0) or (k > 4) then
k := 0;
nn := nn + 1;
if nn >= n + 2 then {insert new note into arrays}
for i := nn downto n + 2 do
begin
notes[i ] := notes[i - 1];
labels[i] := labels[i - 1];
First_Show_Note(notesfi], i/ labelsli]);
end;
notesfn + 1 ] := j + k * 12;
labels[n + 1 ] := ch; {update graphic display}
First_Show_Note(notes[n + 1 ] , n + 1, labels[n + 1]);
end; {End of Procedure Insert}

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
99
^**********************************************************************}

procedure Remove (var n, nn: integer);

{ The user wants to remove the n'th note . }

{ Input }
{ n - position number of note to beremoved }

{ Input/Output >
{ nn - total number of notes making up this music piece }
{ notes - old/new note ID numbers }
{ labels - old/new note labels }

var
i: integer;

begin
if n > nn then
begin
Writeln('You cannot remove note', n, '. There are only', nn, '
notes. Try again.');
exit(Remove);
end;
nn := nn - 1;
for i := n to nn do
begin
notes[i] := notes[i + 1];
labels[i] := labels[i + 1 ] ;
first_show_note(notes[i], i, labels[i]);
end;
notes[nn + 1 ] := 0;
first_show_note(0, nn + 1, labels[nn + 1]);
end; {End of Procedure Remove}

,£**********************************************************************}.

procedure Corrections;

{ This procedure processes the various user requests }


{ to correct music input during the first phase }

{ Input }
{ sharps - the 12 note labels with sharps }
{ flats - the 12 note labels with flats }

{ Input/Output }
{ nn total number of notes making up this music piece }
{ notes - note ID numbers }
{ labels - note labels }

var
commd: char; {C for correction}
{I for insertion}
{R for removal}
{D for done or finished}
n : integer; {note number to be corrected, deleted,}

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
{deleted, or followed by another note}
octave: integer; {octave of note}
ch: string[2]; {label of a note}
contr: integer;

begin
Writeln(' Now you may correct any notes that you see on the
screen. You may also remove notes or add notes. For example,
if the 15th note is shown as an F#2, but should be a G2,
enter "C" for "correcting" and then "15 G 2".');

contr := 0;
while contr = 0 do
begin
Writeln('Enter your command character: C for correcting a note, I
for inserting a note, R for removing a note, and D when you
are done.');
Readln(commd);
if commd = 'D' then
contr := 1
else if commd = 'C' then
begin
Writeln('Enter note number, character, and octave number.');
Readln(n);
Readln(ch);
Readln(octave);
Correct(n, octave, ch);
end
else if commd = 'I ' then
begin
Writeln('Enter note number, character, and octave number.');
Readln(n);
Readln(ch);
Readln(octave);
Insert(n, octave, nn, ch);
end
else if commd = 'R' then
begin
Writeln('Enter number of note to be removed.');
Readln(n);
Remove(n, nn);
end
else
Writeln('Wrong control symbol. Try again.');
end;
end; {End of Procedure Corrections}

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited without perm ission.
101

procedure Save_It;

This procedure saves a piece of music in the library file

Input
nn - total number of notes making up this music piece
notes - note ID numbers
labels - note labels

var
yes: char;
npieces, i, j, k: integer;
ch; n_label;
npointer; i_array;
heading; string[80];

begin
Open(pointerfile, 'Music_Libl');
Open(notesfile, 'Music_Lib2');
Open(labelsfile, 'Music_Lib3');
Open(titlesfile, 'Music_Lib4');

Writeln('Have you started already a library earlier? Enter "Y" or


•'N'*.');
Readln(Yes);
if Yes = 'Y' then
Read(pointerfile, npieces)
else
npieces := 0;
if npieces > 0 then
begin {position file pointers}
Read(pointerfile, npointer[1]);
for i ;= 1 to npieces do
begin
Read(pointerfile, npointer[i + 1 ] ) ;
Read(titlesfile, Heading);
end;
for j := 1 to npointer[npieces + 1 ] - 1 do
begin
Read(notesfile, k ) ;
Read(labelsfile, ch);
end;
Rewrite(pointerfile);
end;

npieces ;= npieces + 1; {update pointer file}


Write(pointerfile, npieces);
npointer[1] ;= 1;
for i ;= 1 to npieces do
Write(pointerfile, npointer[i ]);
npointer [npieces + 1] ;= npointer [npieces] + nn;
Write(pointerfile, npointer[npieces + 1]);
{add new piece to library}
for i ;= 1 to nn do
begin
Write(notesfile, notes[i]);
Write(labelsfile, labels[i]);

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
102
end;

Writeln('Please enter a description of your new piece, using up to 80


characters.’);
Readln(Heading);
Write(titlesfile, Heading);

Close(pointerfile); {close files}


Close{notesfile);
Close(labelsfile);
Close(titlesfile);
end; {End of Procedure Save_It}

^**********************************************************************}

procedure Retrieve (var localflag: integer; ID: integer);

This procedure retrieves from the music library


a piece of music identified by ID

Input
ID - ID number ofrequested music piece
npieces - number of music pieces inuser's library
pointerfile - contains pointers to the other files
notesfile - contains the note numbers of all pieces in library
labelsfile - contains note labels of all pieces in library
titlesfile - contains the headings of all pieces in library

Output
Heading - 80-character heading of new piece 'ID'
nn - total number of notes making up this music piece
notes - note numbers
labels - note labels
localflag - error flag
-1 after three bad ID inputs
1 if everything is okay

var
npieces, i, j, nshift: integer;
npointer: array[1..20] of integer;
Heading: string[8 0];
ch: string[2];

begin
Open(pointerfile, ’Music_Libl');
Open(notesfile, 'Music_Lib2');
Open(labelsfile, 'Music_Lib3');
Open(titlesfile, 'Music_Lib4');

Read(pointerfile, npieces); {the first word on pointerfile is}


localflag := 1; {the number of pieces}
if (ID > npieces) or (ID <= 0) then
begin
Writeln(ID, ' is not a valid ID number. Your library has
currently’, npieces, ' pieces. Try again. Enter a number
between 1 and ', npieces);
Readln(ID);
if (ID > npieces) or (ID <= 0) then

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
103
begin
localflag := -1;
exit(Retrieve);
end;
end;
for i := 1 to ID + 1 do {position file pointers)
Read(pointerfile, npointer[i ]);
nshift := npointer[ID] - 1;
if nshift > 0 then
for i := 1 to nshift do
begin
Read(notesfile, j);
Read(labelsfile, ch);
end;
nn s= npointer[ID + 1] - npointer[ID];
for i := 1 to nn do {retrieve requested piece 'ID' from files)
begin
Read(notesfile, notes[i]);
Read(labelsfile, labels[i]);
end;
for i := 1 to ID do
Read(titlesfile, Heading);
Writeln('Library piece number’, ID);
Writeln(Heading);

for i := 1 to nn do
first_show_note(notes[i], i, labels[i]);

Close(pointerfile); {close files)


Close(notesfile);
Close(labelsfile);
Close(titlesfile);
end; {End of Procedure Retrieve)

,£**********************************************************************}

procedure Entry_Phase (var gflag: integer);

{ This procedure prompts the user to play a piece of music. }


{ It attempts to identify the notes being played from the measured )
{ frequencies. Then it allows the user to correct the input. }

{ output gflag = -1 error exit }


{ 1 successful exit )

var
G o : char;
ID, returnflag, localflag: integer;

begin
First_Setup;
Writeln(' Whenever you are ready, enter the letter "G", hit Return,
enter 0 and Return. Then just play the piece of music you
wish to practice. Or, if you wish to retrieve from your
library a piece that you have saved previously, type the
letter "R" and Return, then enter the piece identification
number and Return.');

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited without perm ission.
104
Read(Go, ID);
gflag := 1;
if Go = 'G' then
begin
scale_system := 1;
mode := 1;
key := 1;
Right_Notes; {determine even-tempered freqs of all notes)
First_Pass(localflag); {user enters his piece)
gflag := localflag;
if gflag = -1 then
exit(Entry_Phase);
end

else if Go = 'R' then


begin
Retrieve(localflag, ID);
gflag := localflag;
end
else
gflag := -1;

if gflag <> -1 then


begin
Corrections; {user makes corrections if any)
Writeln('Do you want to save this piece? Enter "Y" or "N" and
Return.');
Readln(Go);
if Go = 'Y' then
Save_It;
end;
end; {End of Procedure Entry_Phase)

^**********************************************************************}

function Jump_2 (freq, mean_freq, corr_freq: real): boolean;


{ >
{ This function returns the value 'True' if the latest measured }
{ frequency is closer to the correct frequency of the next note )
{ than the mean frequency of the last note }
{ >
{ Input }
{ freq - latest measured frequency )
{ mean_freq - mean frequency of last note }
{ corr_freq - the correct frequency of next note 'n + 1 ' }

var
diffl, diff2: real;
begin
Jump_2 := False;
diffl := freq / mean_freq - 1.0;
diff2 := freq / corr_freq - 1.0;
if abs(diffl) > abs(diff2) then
Jump_2 := True;
end; {End of function Jump_2)

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
105
procedure Run (nn: integer; var gflag: integer);

This is the main part of procedure Practice.


It controls a typical run, during which the user practices
one musical piece once or takes a test on it.

Input:
option - session option (practice or test)
mode - major or minor
key - key of scale being played
Scales - array with correct frequencies of chromatic scale
nn - number of notes of piece being practiced

Output
flag - 1 successful or nonfatal run; try again
-1 no input received from pitch analyzer

var
register: array[1..10] of real;
n, time, lset, error, rcount, ifreq: integer;
gcount, lpointer, sflag, score, grade, change: integer;
jj, nx, contr, nbuf, returnflag: integer;
gbegin, gend, lbegin, lend, tend: longint;
freq, next, correct, accmean, rmean, gmean, ave_metr: real;

begin
dur := 180;
gflag := 1;
Writeln('At the beep you may start playing.');
Draw_Boxes;
Delay(dur, final);
SysBeep(0);
score := 0; {total score for this run}
nbuf := 0; {no of words currently in buffer}
n := 1; {note number, from 1 to nn}
if (n mod 12) = 1 then
Second_Show_Note(n);
jj s= 0; {recorded frequency number}

ReadSP(freq, nbuf, returnflag); {read the very first frequency}


if (freq = 0.0) or (returnflag = -1) then
begin
gflag := -1; {error exit; no frequency received}
WriteSP('S', returnflag);
exit(Run);
end;

gbegin := tickcount; {initialize time for entire piece}


lbegin := gbegin; {initialize time to find correct note}
time := 0; {total of local times}
lset := 0;
{set the clock}
correct := Scale[notes[1]]; {that's what the first note should be}
Register!1] := freq;
rcount := 1; {no. of freqs in register for running mean}
gcount := 1; {total number of readings for note n}
lpointer := 1; {pointer to Register}
accmean := freq;

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
106
rmean := freq; {running mean of up to last 10 readings}
gmean := freq; {overall mean frequency of note n}
contr ;= 0; {controls the loop for the next frequency}
jj := jj + l;
Recording!jj] := freq; {record of frequencies as played}

while contr = 0 do {loop to read next frequency}


begin
gflag := 1;
ReadSP(freq, nbuf, returnflag); {read next frequency}
if (freq = 0.0) or (returnflag = -1) then
begin {we get here after playing the last}
gend := tickcount; {note or because of a read error}
if (n < nn) or (returnflag = -1) then
begin
gflag := -1;
exit(Run);
end

else
begin
gmean := gmean / gcount;
error := round((gmean / correct - 1) * 1730.0);
grade ;= 2;
if abs(error) < 2 . 0 * tol then
grade := 1;
if abs(error) < tol then
grade := 0;
score := score + grade;
if lset = 0 then
lend := gend;
time := time + lend - lbegin;
times[n] := lend - lbegin;
jtotal := jj;
if option = 2 then
begin
nx s= |(n - 1) mod 1 2 + 1 ) * section + 10;
moveto(nx, midy + height + 15);
WriteDraw(grade); {add score for note n to display}
end;
ave_metr := (n * 60 / (gend - gbegin)) * 60;
Result(score, n, time, ave_metr);
exit(Run); {if piece was played, display result}
end;
end;

if n + 1 > nn then
next := 1.0
else
next := Scale[notes[n + 1]];

jj s= jj + i;
Recording!jj] != freq; {record the frequencies}
if Jump_2(freq, rmean, next) then
begin {if jump to the next note is detected,}
gmean := gmean / gcount; {determine score for previous note}
error := round((gmean / correct - 1) * 1730.0);
grade := 2;

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
107
if abs(error) < 2 . 0 * tol then
grade := 1;
if abs(error) < tol then
grade := 0;
score := score + grade;
tend := tickcount;
if lset = 0 then
lend := tend;
time := time + lend - lbegin;
times[n] := tend - lbegin; {duration of note n}
if option = 2 then
begin
nx := ((n - 1) mod 1 2 + 1 ) * section + 10;
movetojnx, midy + height + 15);
WriteDraw( grade); {add score for note n to display}
end;

n := n + 1;
if (n mod 12) = 1 then {initialization for the new note}
Second_Show_Note(n);
correct := next;
Register[1] := freq;
rcount := 1; {no. of freqs in register for running mean}
gcount := 1; {total no of readings for note n}
lpointer ;= 1; {pointer to Register}
accmean := freq;
rmean := freq; {running mean of up t*-* last 10 readings}
gmean := freq; {overall mean o„ note n frequency}
lbegin := tickcount;
lset := 0; {reset the clock for the new note}
end {end of case that jump to new note occurred}

else

begin
lpointer := lpointer + 1 ; {a new frequency for the same note n}
if lpointer > 10 then
lpointer := lpointer - 10;
rcount ••= rcount + 1; {number of frequencies in register}
gcount := gcount + 1; {total no of readings for note n}
gmean := gmean + freq; {global mean}
accmean := accmean + freq; {running mean of up to}
if rcount > 10 then {10 last readings}
accmean j= accmean - Register[lpointer];
Register[lpointer] := freq;
if rcount >= 10 then
rmean := 0.1 * accmean
else
rmean := accmean / rcount;
error := round((rmean / correct - 1) * 1730.0);
if (abs(error) < tol) and (lset = 0) then
begin {success; time = lend-lbegin}
lend := tickcount;
lset := 1;
end;
Display(n, error, correct);
end;
end; {end of loop for reading a frequency}

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
108
end; {End of Procedure Run}

.j**********************************************************************}

procedure Play_Back;
{ >
{ This procedure plays the piece of music exactly the way }
{ the user has just played - like a tape-recorder }

var
jj, ifreq; integer;

begin
dur := 180;
Writeln('This is exactly the way you played the piece last.');
Delay(dur, final);
for jj := 1 to jtotal do
begin
i freq := round(Recording[j j]);
Note(ifreq, 255, 3);
end;
Delay(dur, final);
end; {End of Procedure Play_Back}

^** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * }

procedure Play_Correct;
{ >
{ This procedure plays the piece of music perfectly in tune }
{ within the scale system selected by the user. The rhythm is }
{ the same as the user entered in his first practice run. }

var
n, nnote, ifreq, time: integer;

begin
dur := 180;
Writeln('As you requested, I will now play the same piece of music
perfectly in tune within the scale system that you had
selected. You may either want to play along or just
listen.');
Delay(dur, final);
for n := 1 to nn do
begin
nnote := notes[nj;
ifreq := round(Scale[nnote]);
time := times[n];
Note(ifreq, 255, time);
end;
Delay(dur, final);
end; {End of Procedure Play_Correct}

R ep ro d u ced with p erm ission o f the copyright ow ner. Further reproduction prohibited without perm ission.
109

procedure Practice (gflag: integer);


{ , >
{ Driver procedure for a practice/test run >

var
Go: char;
contr, returnflag: integer;
first: Boolean;

begin
first := true;
contr := 0;
while contr = 0 do
begin
Input(first);
Second_Setup;
Right_Notes;
if option < 3 then
begin
if metr > 0 then
begin
Writeln('This is the metronome tempo you requested.');
Metronome(metr);
end;
Writeln('When you are ready, enter the letter "G" and
Return.');
Readln(Go);
if Go = 'G' then
begin
WriteSP('G', returnflag);
Run(nn, gflag);
end
else
gflag := -1;
end
else if (option = 3) and (not first) then
Play_Back
else if option = 4 then
Play_Correct;
if gflag = -1 then
exit(Practice);
Writeln('Would you like to play the same piece again?');
Writeln('Enter "Y" for yes or "N" for no.');
Readln(Go);
if Go <> 'Y' then
contr := 1;
first := false;
end;
end; {End of Procedure Practice}

1
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited w ithout perm ission.
110

begin {Main Program - Program 3}

SetRect(txRect, 225, 420, 615, 478); {set up graphic display and}


SetTextRect(txRect); {text windows}
ShowText;
SetRect(drRect, 5, 40, 635, 475);
SetDrawingRect(drRect);
ShowDrawing;
Writeln( ' If you wish to obtain a detailed description of this
program, enter a "C" and Return. If you wish to skip the
introductory comments, just hit Return.');
Read(c_key);
if c_key = 'C' then
Introduction;
Assign_Labels;

control := 0; {initialize control flag}


errorflag := 1;
if Open_SerialDriver = noErr then {open Serial Port}
errorflag := Get_Ready; {wait for OKfrom Pitch Analyzer}
while (errorflag = 0) and(control = 0) do
begin {start Program 3 only if switch is turned on}
Entry_Phase(gflag); {i.e. if errorflag=0}
if gflag = 1 then {we loop through the sessions until}
begin {user stops it, or an error occurs}
Practice(gflag);
if gflag = -1 then
control := 1
else
begin
Writeln('Would you like to practice another piece? If yes,
enter "Y" and "N" for no.');
control := 1;
Readln(Yes);
if Yes = 'Y' then
control := 0;
end;
end
else
control := 1;
end;
Close_Port; {close Serial Ports}
end. {End of Main Program - Program 3}

R ep ro d u ced with p erm ission o f the copyright ow ner. Further reproduction prohibited without p erm ission.

S-ar putea să vă placă și