#!/usr/bin/env perl
#
# Determine how well the ratios in arbitrary Scala scale files fit to
# those from a given Scala scale file. (One use: to see how well overtone-
# based ratio sequences fit other extant scale systems, and what the
# worst of these fits is, to find scale systems least similar to the
# overtone series.)
#
# For example, checking against a 53-note overtone-based scale:
#
#   perl fitness --ref=sparschuh_53in13lim.scl \
#     | grep '1200$' | sort -nr | sed 22q
#
# Finds that the worst fits include various gamelan temperaments--this
# comes as no surprise to me, as they have their own scale systems
# independent of the Western tradition. Reverse some fortunes in
# history, and would gamelan scholars then be asking questions about
# curious Western systems and how poorly they fit the justifications
# for the gamelan theory?
#
# For an even worse fit, use a 10-note overtone-based scale. This gets
# back to the question of where one gets off the overtone-go-round
# before Gotterdamerung--a 53-note scale will better match other scales,
# simply because it has four to 10 times the resolution of 12 to 5 note
# overtone scales:
#
#   perl fitness --ref=harmf9.scl   | grep '1200$' | sort -nr | sed 22q
#   perl fitness --ref=malcolms.scl | grep '1200$' | sort -nr | sed 22q
#
# Malcolm's Monochord and Riley's Albion scale (also proposed by
# Hindemith in "Unterweisung im Tonsatz") shows some 800+ octave-ending
# scales that have a >= 25 cent mean delta! Such scales do not match the
# overtone series, so one again we find things overtones cannot explain.

use strict;
use warnings;
use feature qw/say/;

use Getopt::Long qw/GetOptions/;
use List::Util qw/min sum/;
use Music::Scala ();

GetOptions( 'ref=s' => \my $reference_scala )
  or die "Usage: $0 --ref=foo.scl\n";

my $s = Music::Scala->new( file => $reference_scala );

my @ref_cents = $s->get_cents;

FILE: for my $file ( grep { $_ ne $reference_scala } glob('*.scl') ) {
  my @cents        = $s->read_scala($file)->get_cents;
  my $note_count   = @cents;
  my $ratio_ultima = sprintf "%.0f", $cents[-1];

  my @fits;
  my $prev_c = 0;
  for my $c (@cents) {
    # some scales have negative cents--skip these, want ascending-
    # only scales (nor subharmonic or whatever scales that repeat)
    next FILE if $c < 0 or $c <= $prev_c;

    #push @fits, min map { my $delta = ( $c - $_ )**2; $delta } @ref_cents;
    push @fits, min map { my $delta = abs( $c - $_ ); $delta } @ref_cents;

    $prev_c = $c;
  }

  # do not care about perfect fits (presumably subsets of the
  # reference scale)
  my $sum = sum @fits;
  next FILE if $sum == 0;

  # Mean delta (might also look at deeper stats, see which has the worst
  # outliers, histogram things up, etc.)
  say sprintf( "%.2f", $sum / @fits ),
    " $file notes $note_count ur $ratio_ultima";
}
