dos_compilers/RHA (Minisystems) ALGOL v55/SCALE.ALG
2024-07-06 09:53:43 -07:00

416 lines
13 KiB
Plaintext

BEGIN ARRAY scale, freq, just[0:25], fifths[1:12];
INTEGER ARRAY major, minor[1:6], title[1:100];
INTEGER note, base, interval, char;
REAL ARRAY minorerror, majorerror[0:12];
REAL ARRAY lminorerror, lmajorerror[0:12];
REAL ARRAY tminorerror, tmajorerror[0:12];
REAL scalecents, justcents, cfreq;
REAL minorsum, majorsum, minorbigsum, majorbigsum;
REAL lminorsum, lmajorsum, lminorbigsum, lmajorbigsum;
REAL purefifth, pythag, syntonic, logmult;
INTEGER xcount, starcount, goodcount;
INTEGER outdev;
PROCEDURE format(n); VALUE n; INTEGER n; ioc(49);
PRODECURE circle heading;
BEGIN text(1,
" C-G G-D D-A A-E E-B B-F# F#-C# C#-G# G#-D# D#-A# A#-F F-C");
skip(1);
END circle heading;
PROCEDURE circle echo;
BEGIN INTEGER f, c;
text(outdev,
" C-G G-D D-A A-E E-B B-F# F#-C# C#-G# G#-D# D#-A# A#-F F-C*N ");
ioc(0); note := 0;
FOR f := 1 STEP 1 UNTIL 12 DO
BEGIN WHILE note <= &*S AND note # 13 DO note := chin(7);
FOR c := 1 STEP 1 UNTIL 7 DO
BEGIN IF note > &*S THEN
BEGIN chout(outdev, note); note := chin(7);
END
ELSE chout( outdev, &*S );
END;
END;
skip(outdev);
note := 0;
FOR f := 1 STEP 1 UNTIL 12 DO
BEGIN scalecents := abs( 3.0*freq[note] - 2.0*freq[note+7] );
rwrite( outdev, scalecents*60, 6, 0);
note := note + 7; IF note > 11 THEN note := note - 12;
END;
skip(outdev);
note := 0;
FOR f := 1 STEP 1 UNTIL 12 DO
BEGIN scalecents := abs( 3.0*freq[note] - 2.0*freq[note+7] );
rwrite( outdev, scalecents, 6, 2);
note := note + 7; IF note > 11 THEN note := note - 12;
END;
skip(outdev);
END circle echo;
PROCEDURE write note( note );
INTEGER note;
BEGIN IF note > 11 THEN note := note - 12;
CASE note OF
0: text(outdev, "C " );
1: text(outdev, "C#" );
2: text(outdev, "D " );
3: text(outdev, "D#" );
4: text(outdev, "E " );
5: text(outdev, "F " );
6: text(outdev, "F#" );
7: text(outdev, "G " );
8: text(outdev, "G#" );
9: text(outdev, "A " );
10: text(outdev, "A#" );
11: text(outdev, "B " )
ELSE text(outdev, "??" );
END write note;
PROCEDURE set just scale;
BEGIN logmult := 1200.00/ln(2);
just[0] := 0; just[12] := 1200.00; just[24] := 2400.00;
just[1] := 111.73; just[2] := logmult*ln(1.125);
just[3] := logmult*ln(1.2); just[4] := logmult*ln(1.25);
just[5] := logmult*ln(4.0/3.0); just[6] := 590.22;
just[7] := logmult*ln(1.5); just[8] := logmult*ln(1.6);
just[9] := logmult*ln(5.0/3.0); just[10] := logmult*ln(16.0/9.0);
just[11] := logmult*ln(1.875);
purefifth := just[7];
pythag := 12.00 * purefifth - 8400.00;
syntonic := 4.00 * purefifth - 2400.00 - just[4];
FOR note := 1 STEP 1 UNTIL 11 DO
just[note+12] := just[note]+1200.00;
major[1] := 2; major[2] := 4; major[3] := 5;
major[4] := 7; major[5] := 9; major[6] := 11;
minor[1] := 2; minor[2] := 3; minor[3] := 5;
minor[4] := 7; minor[5] := 8; minor[6] := 11;
END set just scale;
PROCEDURE ay38912( octave ); VALUE octave; REAL octave;
BEGIN
text(outdev, "*N ");
FOR note := 0 STEP 1 UNTIL 11 DO
rwrite( outdev, entier(125000.00/(freq[note]*octave) + 0.5), 8, 0 );
text(outdev, "*N ");
FOR note := 0 STEP 1 UNTIL 11 DO
rwrite( outdev, (freq[note]*octave), 8, 2 );
text(outdev, "*N ");
FOR note := 0 STEP 1 UNTIL 11 DO
BEGIN interval := entier(125000.00/(freq[note]*octave) + 0.5);
rwrite( outdev, 125000.00/interval, 8, 2 );
END;
text(outdev, "*N ");
cfreq := freq[0]*octave;
FOR note := 0 STEP 1 UNTIL 11 DO
BEGIN interval := entier(125000.00/(freq[note]*octave) + 0.5);
scalecents := 125000.00/interval;
rwrite( outdev, logmult*ln(scalecents/cfreq) - scale[note], 8, 2 );
END;
END ay38912;
PROCEDURE write scale error( error, lerror );
VALUE error, lerror; REAL error, lerror;
BEGIN IF error > 90.00 THEN format( 512+&X )
ELSE IF error > 60.00 THEN format( 512+&** )
ELSE IF error < 40.00 THEN format( 512+&= )
ELSE IF (error < 48.80) OR (error < 48.90 AND lerror < 33.20)
THEN format( 512+&E );
rwrite(outdev, error, 8, 2);
format( 512+&*S );
END;
PROCEDURE scale from fifths;
BEGIN scale[0] := scalecents := 0; interval := 0;
FOR note := 1 STEP 1 UNTIL 11 DO
BEGIN interval := interval + 7;
scalecents := scalecents + fifths[note];
IF interval > 11 THEN
BEGIN interval := interval - 12;
scalecents := scalecents - 1200.00;
END;
scale[interval] := scalecents;
END;
FOR note := 0 STEP 1 UNTIL 11 DO
BEGIN scale[note+12] := scale[note]+1200.00;
scalecents := scale[note] - scale[9];
freq[note] := 440.0 * exp(scalecents/logmult);
freq[note+12] := 2.0 * freq[note];
END;
END scale from fifths;
PROCEDURE readcents;
BEGIN
text( 1, "*NType 11 cent offsets from C*N" );
scale[0] := 0;
FOR note := 1 STEP 1 UNTIL 11 DO
BEGIN scale[note] := read(7);
END;
FOR note := 1 STEP 1 UNTIL 12 DO
fifths[note] := scale[note+6] - scale[note-1];
FOR note := 0 STEP 1 UNTIL 11 DO
BEGIN scale[note+12] := scale[note]+1200.00;
scalecents := scale[note] - scale[9];
freq[note] := 440.0 * exp(scalecents/logmult);
freq[note+12] := 2.0 * freq[note];
END;
END readcents;
PROCEDURE readfifths;
BEGIN text( 1, "*NCircle of 11 fifths in cents from C*N" );
circle heading;
scalecents := 0;
FOR note := 1 STEP 1 UNTIL 11 DO
BEGIN fifths[note] := read(7);
scalecents := scalecents + fifths[note];
END;
fifths[12] := 8400.00 - scalecents;
scale from fifths;
END readfifths;
PROCEDURE readcommas;
BEGIN INTEGER sign, num, den;
text(1, "*NCircle of 12 fifths in commas commas from C");
text(1, "*N0= pure, or <+|-><a/b><P|S>, e.g. +1P, -1/4P, +1/2S*N");
circle heading;
scalecents := 0;
FOR note := 1 STEP 1 UNTIL 11 DO
BEGIN
next fifth:
char := chin(7);
IF char = &0 THEN sign := 0
ELSE IF char = &- THEN sign := -1
ELSE IF char = &+ THEN sign := 1
ELSE GOTO next fifth;
IF sign = 0 THEN fifths[note] := purefifth
ELSE
BEGIN num := den := 0;
char := chin(7);
WHILE char >= &0 AND char <= &9 DO
BEGIN num := 10*num + char - &0; char := chin(7);
END;
IF char = &/ THEN
BEGIN char := chin(7);
WHILE char >= &0 AND char <= &9 DO
BEGIN den := 10*den + char - &0;
char := chin(7);
END;
IF den = 0 THEN den := 1;
END
ELSE den := 1;
interval := char MASK 223;
IF interval = &P THEN fifths[note] := pythag
ELSE fifths[note] := syntonic;
fifths[note] := purefifth+fifths[note]*sign*num/den;
END;
scalecents := scalecents + fifths[note];
END;
fifths[12] := 8400.00 - scalecents;
scale from fifths;
END readcommas;
{ Main program start }
set just scale;
outdev := 1;
get streams:
ioc(0); ioc(1); ioc(15); ioc(2);
outdev := output;
IF outdev < 0 THEN GOTO get streams;
skip(outdev);
text(1,"Title: ");
ioc(0); ioc(1); base := 1;
title char: char := chin(7);
IF char >= &*S THEN BEGIN title[base] := char; base := base+1; GOTO title char END;
title[base] := 0;
get input type:
ioc(0); ioc(1);
text(1, "*NNotes (cents), Fifths (cents) or fifths Commas N/F/C ? ");
note := chin(7) MASK 223;
IF note = &N THEN readcents
ELSE IF note = &F THEN readfifths
ELSE IF note = &C THEN readcommas
ELSE GOTO get input type;
base := 1;
WHILE title[base] # 0 DO
BEGIN chout( outdev, title[base] ); base := base+1;
END;
skip( outdev );
circle echo;
text(outdev, "*NAY3 8912, True frequency, generated frequency, error in cents*N");
FOR note := 0 STEP 1 UNTIL 11 DO
BEGIN text(outdev, " "); write note( note );
END;
ay38912( 0.25 );
skip( outdev );
ay38912( 0.5 );
skip( outdev );
ay38912( 1.0 );
skip( outdev );
ay38912( 2.0 );
skip( outdev );
ay38912( 4.0 );
text(outdev, "*NPure fifth "); rwrite(outdev, purefifth, 8, 3);
text(outdev," Pythagorean comma "); rwrite(outdev, pythag, 8, 3);
text(outdev," Syntonic comma "); rwrite(outdev, syntonic, 8, 3);
text(outdev,
"*N*NKey: E equal tempered, = just, ** error greater than 10 cents, X syntonic comma error");
text(outdev,"*N");
text(outdev,"*NJust scale (cents), this one (cents, Hz)*N");
FOR note := 0 STEP 1 UNTIL 11 DO
BEGIN text(outdev, " "); write note( note );
END;
text(outdev,"*N ");
FOR note := 0 STEP 1 UNTIL 11 DO
rwrite( outdev, just[note], 8, 2 );
text(outdev,"*N ");
FOR note := 0 STEP 1 UNTIL 11 DO
rwrite( outdev, scale[note], 8, 2 );
text(outdev,"*N ");
FOR note := 0 STEP 1 UNTIL 11 DO
rwrite( outdev, freq[note], 8, 2 );
xcount := starcount := goodcount := 0;
text(outdev, "*NIntervals from each note*N" );
FOR note := 1 STEP 1 UNTIL 11 DO
BEGIN text(outdev, " "); write note( note );
END;
FOR note := 0 STEP 1 UNTIL 11 DO
BEGIN skip( outdev ); write note( note );
FOR interval := 1 STEP 1 UNTIL 11 DO
BEGIN scalecents := scale[note+interval]-scale[note];
justcents := just[interval];
IF abs(scalecents-justcents) >= 21.49 THEN
BEGIN format( 512+&X );
xcount := xcount + 1;
END
ELSE IF abs(scalecents-justcents) > 10.00 THEN
BEGIN format( 512+&** );
starcount := starcount + 1;
END
ELSE IF abs(scalecents-justcents) < 1.00 THEN
BEGIN format( 512+&= );
goodcount := goodcount + 1;
END
ELSE IF abs(scalecents-100.0*interval) < 1.00 THEN
format( 512+&E );
rwrite( outdev, scalecents, 8, 2 );
format( 512+&*S);
END;
END;
minorsum := majorsum := minorbigsum := majorbigsum := 0;
lminorsum := lmajorsum := lminorbigsum := lmajorbigsum := 0;
text(outdev, "*N*NAccumulated errors in each major and minor scale");
text(outdev,
"*NKey: = very good, E better than equal temperament, ** poor, X intolerable");
text(outdev, "*NEqual temp");
rwrite(outdev, 48.88, 8, 2); rwrite(outdev, 48.88, 8, 2);
text(outdev, " 3rd to 6th ");
rwrite(outdev, 33.24, 8, 2);
rwrite(outdev, 33.24, 8, 2);
text(outdev, " scale+internals ");
rwrite(outdev, 168.15, 8, 2); rwrite(outdev, 207.25, 8, 2);
FOR note := 0 STEP 1 UNTIL 11 DO
BEGIN skip(outdev); write note( note );
text(outdev, " scale ");
minorerror[note] := majorerror[note] := 0;
lminorerror[note] := lmajorerror[note] := 0;
FOR interval := 1 STEP 1 UNTIL 6 DO
BEGIN
scalecents := scale[note+minor[interval]] - scale[note];
justcents := just[minor[interval]];
minorerror[note] := minorerror[note] + abs(justcents - scalecents);
IF interval > 1 AND interval < 6 THEN
lminorerror[note] := lminorerror[note] +
abs(justcents - scalecents);
scalecents := scale[note+major[interval]] - scale[note];
justcents := just[major[interval]];
majorerror[note] := majorerror[note] + abs(justcents - scalecents);
IF interval > 1 AND interval < 6 THEN
lmajorerror[note] := lmajorerror[note] +
abs(justcents - scalecents);
END;
minorsum := minorsum + minorerror[note];
majorsum := majorsum + majorerror[note];
write scale error( majorerror[note], lmajorerror[note] );
write scale error( minorerror[note], lminorerror[note] );
text(outdev, " 3rd to 6th ");
lminorsum := lminorsum + lminorerror[note];
lmajorsum := lmajorsum + lmajorerror[note];
rwrite(outdev, lmajorerror[note], 8, 2);
rwrite(outdev, lminorerror[note], 8, 2);
text(outdev, " scale+internals ");
tminorerror[note] := minorerror[note];
tmajorerror[note] := majorerror[note];
FOR base := 1 STEP 1 UNTIL 5 DO
FOR interval := base+1 STEP 1 UNTIL 6 DO
BEGIN
scalecents := scale[note+minor[interval]] - scale[note+minor[base]];
justcents := just[minor[interval]-minor[base]];
tminorerror[note] := tminorerror[note] + abs(justcents - scalecents);
scalecents := scale[note+major[interval]] - scale[note+major[base]];
justcents := just[major[interval]-major[base]];
tmajorerror[note] := tmajorerror[note] + abs(justcents - scalecents);
END;
minorbigsum := minorbigsum + tminorerror[note];
majorbigsum := majorbigsum + tmajorerror[note];
rwrite(outdev, tmajorerror[note], 8, 2);
rwrite(outdev, tminorerror[note], 8, 2);
END;
text(outdev, "*N"); write(outdev, goodcount); text(outdev,"just intervals, ");
write(outdev, starcount); text(outdev,"errors > 10 cents, and ");
write(outdev, xcount); text(outdev,"syntonic comma errors");
text(outdev, "*NTotal errors. Equal temperament ");
rwrite(outdev, 586.58, 8, 2); rwrite(outdev, 586.54, 8, 2);
text(outdev, " 3rd to 6th "); rwrite(outdev, 398.87, 8, 2);
rwrite(outdev, 398.83, 8, 2);
text(outdev, " with internal errors ");
rwrite(outdev, 2017.78, 8, 2); rwrite(outdev, 2487.04, 8, 2);
text(outdev, "*NTotal errors. This temperament ");
rwrite(outdev, majorsum, 8, 2); rwrite(outdev, minorsum, 8, 2);
text(outdev, " 3rd to 6th ");
rwrite(outdev, lmajorsum, 8, 2); rwrite(outdev, lminorsum, 8, 2);
text(outdev, " with internal errors ");
rwrite(outdev, majorbigsum, 8, 2); rwrite(outdev, minorbigsum, 8, 2);
chout( outdev, &*P );
END FINISH