#!/usr/bin/perl -w

$threshhold = 3;

$interval = 2 ** (1 / 12);

$basefreq = 220; # corresponds with $notename[0]
@notename = ( 'A', 'A#', 'B', 'C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#' );

@harmonictable = ();

for $note ( 0 .. 11 ) {
  $notefreq = $basefreq * ( $interval ** $note );
  for $harmonic ( 1 .. 5 ) {
    $harmonicfreq = $notefreq * $harmonic;
    push @harmonictable, [ $harmonicfreq, $note, $harmonic ];
  }
}

@harmonictable = sort { $$a[0] <=> $$b[0] } @harmonictable;

for $i ( 0 .. $#harmonictable ) {
  $j = $i;
  #$j -- while ($harmonictable[$j] && ($harmonictable[$i][0] - $harmonictable[$j][0]) < $threshhold);
  while ($harmonictable[++$j]) {
    $diff = $harmonictable[$j][0] - $harmonictable[$i][0] ;
    last if ( $diff > $threshhold);
    next if (!(( $harmonictable[$j][1] - $harmonictable[$i][1] ) % 12));
    #next if (abs( $harmonictable[$j][2] - $harmonictable[$i][2] ) > 1);
    print "The " .
      &nth($harmonictable[$j][2])  . " harmonic of " .
      &name($harmonictable[$j][1]) . " is " .
      abs($diff)                   . "cps " .
      (($diff > 0) ? "sharp" : "flat") . " of the "  .
      &nth($harmonictable[$i][2])  . " harmonic of " .
      &name($harmonictable[$i][1]) . "\n";
  }
}

sub nth {
  $a = "" . $_[0];
  $lastdigit = substr($a, -1);
  if ($lastdigit == 1)    { return $a . "st"; }
  elsif ($lastdigit == 2) { return $a . "nd"; }
  elsif ($lastdigit == 3) { return $a . "rd"; }
  else                    { return $a . "th"; }
}

sub name {
  return $notename[$_[0] % 12];
}

