Documente Academic
Documente Profesional
Documente Cultură
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.
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.
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
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
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
Hwa-Soon Meyer
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
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
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
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
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
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
II. Purpose
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.
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
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
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
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
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
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
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
IV. Limitations
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
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
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
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
"AND1
Gates
Line Driver
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
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.
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
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
Time
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
III. Software
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
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.
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.
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
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.
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
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
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
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
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
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
-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
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
R ep ro d u ced with p erm ission o f th e copyright ow ner. Further reproduction prohibited without perm ission.
32
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
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
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
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
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
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
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
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
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
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
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
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
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
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;
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}
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 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);
{**********************************************************************}
var
left, right, nx, In: 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.
52
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
^**********************************************************************}
{ 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.');
{**********************************************************************}
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
,£**********************************************************************}
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(' 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}
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 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;
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;
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;
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;
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}
£**********************************************************************}
{ Places the n 'th note and its label '1' on the music staff }
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;
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
^ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * >****}
var
left, right, nx, In: 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.
70
£**********************************************************************}
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;
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;
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
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);
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}
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}
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;
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}
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(' 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}
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
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}
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;
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#
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;
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;
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;
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 First_Setup;
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
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);
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
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);
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
var
left, right, nx, In: 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.
91
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;
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 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}
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
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}
^**********************************************************************}.
{ 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);
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;
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;
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}
^**********************************************************************}
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;
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
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;
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
^**********************************************************************}
{ 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;
{ 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;
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');
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;
^**********************************************************************}
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');
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]);
,£**********************************************************************}
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
^**********************************************************************}
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);
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}
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}
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
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
R ep ro d u ced with p erm ission o f the copyright ow ner. Further reproduction prohibited without p erm ission.