Harmonics

← All projects

In 1992 the author set out to find a consonance rating for musical intervals: a number, worked out from the ratio p/q alone, that says how smooth the interval sounds. The idea was to count how often each interval turns up among pairs of whole numbers, and to call the more frequent ones the more consonant. These are the programs, written in BASIC on a second-hand IBM PCjr and then translated into Fortran and C.

Several do not run as written, so each result below is what the program set out to compute, worked out again by harmonics.py with exact arithmetic. The listings are kept exactly as printed: the scans, and a transcription of each. They are the starting point of Coprime pairs and musical intervals, which takes up the same question.

Did they find a consonance rating?

Partly. The counting programs (Harmonic1, Harmonic3 and Harmonic4) do produce a rating, and it gets the top of the order right: fifth, major sixth, then the harmonic seventh and minor sixth, then the minor seventh. But the count for p/q works out to ⌊(C−1)/(p−q)⌋, so the rating depends only on p−q. Three things follow.

The 11 intervals the programs test are exactly the ratios between 3/2 and 2 with p−q from 1 to 5, plus 13/7. Set beside four rules for consonance, the rating’s rank correlation is 0.90 with three of them and 0.85 with Euler’s:

The consonance rating the counting programs produce, beside four rules for
how simple a ratio p/q is. 1 = most consonant; equal scores share a rank.
The count is how many pairs up to C = 32769 land on the interval:
floor(32768/(p-q)), so the programs' rank is the rank of p-q.

ratio  interval        count   programs  p2+q2  p+q  Tenney p*q  Euler
                                  (p-q)
  3/2  perfect 5th    32768        1       1    1           1      1
  5/3  major 6th      16384        2       2    2           2      2
  7/4  harmonic 7th   10922        3       3    3           3      4
  8/5  minor 6th      10922        3       4    4           4      3
  9/5  minor 7th       8192        4       5    5           5      4
 11/7                  8192        4       7    7           7      9
 11/6                  6553        5       6    6           6      7
 12/7                  6553        5       8    8           8      5
 13/8                  6553        5      10   10          10      8
 14/9                  6553        5      11   11          11      6
 13/7                  5461        6       9    9           9     10

Rank correlation (Spearman) of the programs' rating with each rule:
  p^2 + q^2               0.90
  p + q (Pythagorean)     0.90
  p * q (Tenney)          0.90
  Euler's gradus          0.85

Harmonic4 over all 128 ratios from the 20 x 20 grid: its counts
floor(20/(p-q)) take only 8 values, 96 ratios tie at 1, and the rank correlation
with p^2 + q^2 is 0.74.

The two programs that draw (Harmonic5 and Pattern) rate nothing, but they hold the idea that worked later: the coprime pairs are the ratios in lowest terms, each interval once, and coprime-intervals rates them by height 1/(p²+q²), which very nearly orders the consonances as Helmholtz listed them.

Harmonic1

For every pair 2 ≤ D ≤ C, works out (2C+D−3)/(C+D−2), which always lies between 3/2 and 2, and counts how often it lands exactly on each of 11 intervals. Prints the totals each time C reaches 2, 3, 5, 9, … 32769. The totals turn out to be ⌊(C−1)/(p−q)⌋, so intervals with the same p−q always tie: 7/4 with 8/5, 9/5 with 11/7, and 11/6, 12/7, 13/8 and 14/9 together.

Toward a consonance rating. The first rating: more pairs means more consonant. Its top five, the fifth, the major sixth, the harmonic seventh and minor sixth (tied), and the minor seventh, come in the order p²+q², p+q and Tenney’s p·q give. Below that it goes astray, because it sees only p−q.

As written. The BASIC should print the counts (not run here), stopping with “RETURN without GOSUB” once the loops end; reaching 32769 would take days. The Fortran and its f2c translation divide 3/2 as whole numbers, which gives 1, so every count is 0, and they stop after the first line. The C by hand puts the comparison inside fabs, never declares fabs, starts its counters at garbage and never stops.

BASIC: scan, text · Fortran: scan, text · C from f2c: scan, text · C by hand: scan, text

Harmonic1: how many pairs 2 <= D <= C give (2C+D-3)/(C+D-2) = p/q,
totals printed each time C reaches 2, 3, 5, 9, ... 32769.
Counted pair by pair up to C = 1025; above that from the formula
floor((C-1)/(p-q)), which the counting confirms exactly.

  ratio    3/2    5/3    7/4    8/5    9/5   11/7   11/6   12/7   13/8   14/9   13/7
  cents    702    884    969    814   1018    782   1049    933    841    765   1072
      C
      2      1      0      0      0      0      0      0      0      0      0      0
      3      2      1      0      0      0      0      0      0      0      0      0
      5      4      2      1      1      1      1      0      0      0      0      0
      9      8      4      2      2      2      2      1      1      1      1      1
     17     16      8      5      5      4      4      3      3      3      3      2
     33     32     16     10     10      8      8      6      6      6      6      5
     65     64     32     21     21     16     16     12     12     12     12     10
    129    128     64     42     42     32     32     25     25     25     25     21
    257    256    128     85     85     64     64     51     51     51     51     42
    513    512    256    170    170    128    128    102    102    102    102     85
   1025   1024    512    341    341    256    256    204    204    204    204    170
   2049   2048   1024    682    682    512    512    409    409    409    409    341
   4097   4096   2048   1365   1365   1024   1024    819    819    819    819    682
   8193   8192   4096   2730   2730   2048   2048   1638   1638   1638   1638   1365
  16385  16384   8192   5461   5461   4096   4096   3276   3276   3276   3276   2730
  32769  32768  16384  10922  10922   8192   8192   6553   6553   6553   6553   5461

Harmonic2

Reads a start, an end and a number of steps, walks along sin(x), and lists where the curve turns over. Shown for 0 to 20 in 200 steps.

Toward a consonance rating. No rating. It looks at a single sine wave, not at two notes together.

As written. Records nothing useful in any form: once the curve is rising it never checks for a turn, and when falling it writes every point to the same slot. The Fortran and f2c versions also write outside the array (W(0), w[−1]).

BASIC: scan, text · Fortran: scan, text · C from f2c: scan, text

Harmonic2: turning points of sin(x) from 0 to 20 in 200 steps
(step 0.1). Each is the sample where the curve turns over, with the
true turning point (k + 1/2)pi beside it.

        x     sin(x)   kind     true x
   1.6000    0.99957   peak      1.5708
   4.7000   -0.99992   trough    4.7124
   7.9000    0.99894   peak      7.8540
  11.0000   -0.99999   trough   10.9956
  14.1000    0.99931   peak     14.1372
  17.3000   -0.99977   trough   17.2788

Harmonic3

Harmonic1’s count, started again from zero each time the limit doubles. The listing never stops; the result stops at 1025.

Toward a consonance rating. The same rating as Harmonic1. Recounting each pass shows it settles early: from B = 17 on, the order of the 11 intervals never changes.

As written. The BASIC should work, and runs for ever as designed. The Fortran and f2c versions make one pass of zeros (3/2 divided as whole numbers again). The C by hand has Harmonic1’s fabs mistakes and its listing stops partway.

BASIC: scan, text · Fortran: scan, text · C from f2c: scan, text · C by hand: scan, text

Harmonic3: B, then the interval counts for every pair 2 <= D <= C <= B,
recounted from scratch each pass. The listing never stops; this
stops at B = 1025.

  ratio    3/2    5/3    7/4    8/5    9/5   11/7   11/6   12/7   13/8   14/9   13/7
  cents    702    884    969    814   1018    782   1049    933    841    765   1072
      B
      2      1      0      0      0      0      0      0      0      0      0      0
      3      2      1      0      0      0      0      0      0      0      0      0
      5      4      2      1      1      1      1      0      0      0      0      0
      9      8      4      2      2      2      2      1      1      1      1      1
     17     16      8      5      5      4      4      3      3      3      3      2
     33     32     16     10     10      8      8      6      6      6      6      5
     65     64     32     21     21     16     16     12     12     12     12     10
    129    128     64     42     42     32     32     25     25     25     25     21
    257    256    128     85     85     64     64     51     51     51     51     42
    513    512    256    170    170    128    128    102    102    102    102     85
   1025   1024    512    341    341    256    256    204    204    204    204    170

Harmonic4

Lists every distinct ratio (2X+Y)/(X+Y) of at least 3/2 for X and Y up to 20, then counts how often each occurs. The listing counts only up to 10, where most of the ratios never occur; counted over the same grid up to 20, every ratio occurs at least once.

Toward a consonance rating. The widest attempt: it rates every ratio the grid makes, 128 of them, rather than 11 chosen ones. But the counts are ⌊20/(p−q)⌋ again, with only 8 different values: 96 ratios tie at 1, and the major seventh 15/8 ties with 20/13.

As written. Does not run: its 210 entries overflow a 100-place array, line 90 reads IF N= THEN 110, it tallies only the first two ratios, and its print loop opens with FOR X but closes with NEXT O.

BASIC: scan, text

Harmonic4: every distinct ratio (2X+Y)/(X+Y) of at least 3/2 for X, Y
from 1 to 20, smallest first, with how often it occurs in that grid.
128 ratios.

  ratio    cents  count
    3/2    702.0     20
  59/39    716.7      1
  56/37    717.5      1
  53/35    718.4      1
  50/33    719.4      1
  47/31    720.5      1
  44/29    721.7      1
  41/27    723.2      1
  38/25    724.9      1
  35/23    726.9      1
  32/21    729.2      1
  29/19    732.1      2
  55/36    733.7      1
  26/17    735.6      2
  49/32    737.7      1
  23/15    740.0      2
  43/28    742.7      1
  20/13    745.8      2
  57/37    748.1      1
  37/24    749.4      1
  54/35    750.7      1
  17/11    753.6      3
  48/31    756.9      1
  31/20    758.7      1
  45/29    760.6      1
   14/9    764.9      4
  53/34    768.5      1
  39/25    769.9      1
  25/16    772.6      2
  36/23    775.6      1
  47/30    777.2      1
   11/7    782.5      5
  52/33    787.3      1
  41/26    788.5      1
  30/19    790.8      1
  49/31    792.6      1
  19/12    795.6      2
  46/29    798.7      1
  27/17    800.9      2
  35/22    803.8      1
  43/27    805.7      1
  51/32    806.9      1
    8/5    813.7      6
  53/33    820.2      1
  45/28    821.4      1
  37/23    823.1      1
  29/18    825.7      1
  50/31    827.6      1
  21/13    830.3      2
  34/21    834.2      1
  47/29    835.9      1
   13/8    840.5      4
  44/27    845.5      1
  31/19    847.5      1
  49/30    849.4      1
  18/11    852.6      2
  41/25    856.4      1
  23/14    859.4      2
  51/31    861.9      1
  28/17    863.9      1
  33/20    867.0      1
  38/23    869.2      1
  43/26    871.0      1
  48/29    872.4      1
    5/3    884.4     10
  47/28    896.7      1
  42/25    898.2      1
  37/22    900.0      1
  32/19    902.5      1
  27/16    905.9      1
  49/29    908.1      1
  22/13    910.8      2
  39/23    914.2      1
  17/10    918.6      2
  46/27    922.4      1
  29/17    924.6      1
  41/24    927.1      1
   12/7    933.1      4
  43/25    938.9      1
  31/18    941.1      1
  19/11    946.2      2
  45/26    949.7      1
  26/15    952.3      1
  33/19    955.8      1
  40/23    958.0      1
  47/27    959.6      1
    7/4    968.8      6
  44/25    978.7      1
  37/21    980.6      1
  30/17    983.3      1
  23/13    987.7      2
  39/22    991.2      1
   16/9    996.1      2
  41/23   1000.8      1
  25/14   1003.8      1
  34/19   1007.4      1
  43/24   1009.6      1
    9/5   1017.6      5
  38/21   1026.7      1
  29/16   1029.6      1
  20/11   1035.0      2
  31/17   1040.1      1
  42/23   1042.5      1
   11/6   1049.4      4
  35/19   1057.6      1
  24/13   1061.4      1
  37/20   1065.0      1
   13/7   1071.7      3
  41/22   1077.7      1
  28/15   1080.6      1
  43/23   1083.2      1
   15/8   1088.3      2
  32/17   1095.0      1
   17/9   1101.0      2
  36/19   1106.4      1
  19/10   1111.2      2
  40/21   1115.5      1
  21/11   1119.5      2
  23/12   1126.3      1
  25/13   1132.1      1
  27/14   1137.0      1
  29/15   1141.3      1
  31/16   1145.0      1
  33/17   1148.3      1
  35/18   1151.2      1
  37/19   1153.8      1
  39/20   1156.2      1
  41/21   1158.3      1

Harmonic5

Gives each screen row to a number, splits it into primes, and puts a dot at every multiple of each prime along the row. A dot means the column and row share a factor, so the dark gaps are the coprime pairs.

Toward a consonance rating. No rating, but a different idea: the coprime pairs are the ratios in lowest terms, each interval exactly once. This is the map coprime-intervals later rates by height.

As written. Draws nothing: the lines that store a new prime can never be reached. The Fortran does not compile.

BASIC: scan, text · Fortran: scan, text

Harmonic5 result

Pattern

Prints every point (X, Y) up to 199 where X and Y are both multiples of some A from 2 to 199: every pair with a common factor, 24,471 lines in all.

Toward a consonance rating. No rating: the same map as Harmonic5, from the other side, listing the pairs that are not in lowest terms.

As written. The BASIC and the C by hand work. The Fortran and its f2c translation stop after A = 2, for want of a jump back.

BASIC: scan, text · Fortran: scan, text · C from f2c: scan, text · C by hand: scan, text

Pattern result

The full listing of points.