#! /usr/bin/perl -w # GENERATE THE FRACTIONS FOR PYTHAGOREAN TUNING (OR MEANTONEs ) # THIS IS JUST QUICK AND DIRTY CODE TO CACULATE THE THINGS THAT I WANT use strict; my( $num, $k, $n, $power3, $power2, %value2fraction, @ordered, $delta, $cents ); my( @noteNames, $sharps, %value2name, $p, $flats, $q, $action ); my( $tempered3rdHarm, %index2LogHarm, %index2LogRescaler, %index2PowerOf2,$count ); my( %index2Fraction, %index2NoteName, $flatString, $sharpString ); my( %index2value, $theta, $r, $factor,$theta_0, $r_0, $x, $pi ); my( $stretchForPicture ); #$num = 200; #NUMBER OF ITERATIONS -- NOW COMMAND LINE ARG $tempered3rdHarm = 3; #$tempered3rdHarm = 3 * (80/81)**(2/7); #$tempered3rdHarm = 2**(19/12); if( defined($ARGV[0] ) && defined( $ARGV[1] ) ) { $num = $ARGV[0]; $action = $ARGV[1]; } else { $action = "no args"; } #HERE WE ITERATIVELY GENERATE THE NOTE SEQUENCE @noteNames = qw( F C G D A E B ); $power2 = 2; $sharps = 0; #ASCENDING for( $k = 1; $k <= $num; $k++ ) { $power3 = $tempered3rdHarm**$k; $index2LogHarm{$k} = $k * log( $tempered3rdHarm ); $count = 1; $power2 = 2; until( $power3/$power2 < 2 ) { $power2 = 2*$power2; $count++; } $index2LogRescaler{$k} = -$count * log(2); $index2PowerOf2{$k} = -$count; #print "$k $power3\/$power2\n"; $index2value{ $k } = $power3/$power2; $value2fraction{ $power3/$power2 } = $power3." / ".$power2; $index2Fraction{ $k } = $power3." / ".$power2; $value2name{ $power3/$power2 } = $noteNames[($k+1) % 7]; if( ($k % 7) == 6 ) { $sharps++; } $sharpString = ""; $index2NoteName{$k} = $value2name{$power3/$power2 }; if( $sharps < 4 ) { for( $p=1; $p <= $sharps; $p++ ) { $value2name{$power3/$power2 } = $value2name{$power3/$power2 }."#"; $sharpString = $sharpString."#"; } } else { $sharpString = $sharps."#"; } #print "$k $power3\/$power2 $value2name{$power3/$power2 }\n"; $index2NoteName{$k} = $index2NoteName{$k}."$sharpString"; } $value2fraction{ 1 } = "1"; # MIDDLE C $value2name{1 } = $noteNames[1]; $index2LogHarm{0} = 0 * log( $tempered3rdHarm ); $index2LogRescaler{0} = 0; $index2PowerOf2{0} = 0; $index2Fraction{0} = "1"; $index2NoteName{0} = "C"; $index2value{0} = 1; $power2 = 2; #DESCENDING $flats = 0; for( $k = 1; $k <= $num; $k++ ) { $power3 = $tempered3rdHarm**$k; $index2LogHarm{-$k} = -$k * log( $tempered3rdHarm ); $count = 1; $power2 = 2; until( $power2/$power3 > 1 ) { $power2 = $power2*2; $count++; } $index2LogRescaler{-$k} = $count * log(2); $index2PowerOf2{-$k} = $count; #print "-$k $power2\/$power3\n"; $index2value{ -$k } = $power2/$power3; $value2fraction{ $power2/$power3 } = $power2." / ".$power3; $index2Fraction{ -$k } = $power2." / ".$power3; $q = $k%7; if( $q == 1 ) { $value2name{$power2/$power3 } = $noteNames[0]; } else { if( $q == 0) { $q = 7; } $value2name{$power2/$power3 } = $noteNames[8 - $q]; if( (8 - $q) == 6 ) #WE'RE ON THE NOTE B { $flats++; } } $flatString = ""; #APPEND THE STRING OF FLAT SYMBOLS $index2NoteName{-$k} = $value2name{$power2/$power3 }; if( $flats < 4 ) { for( $p=1; $p <= $flats; $p++ ) { $value2name{$power2/$power3 } = $value2name{$power2/$power3 }."b"; $flatString = $flatString."b"; } } else #JUST PUT A NUMBER { $flatString = $flats."b"; } #print "$k $power2\/$power3 $value2name{$power2/$power3 }\n"; $index2NoteName{-$k} = $index2NoteName{-$k}."$flatString"; } if( $action =~ /PLOT/ ) #- - - - - - - - - -- - - - - - - - - - - - - - - - { #THIS PLOTS THE LINES log(3^n) AND log(2^k(n)) open( FFF2, ">-"); open( FFF3, ">-"); for( $k= -$num; $k<=$num; $k++ ) # WRITE DATA FOR GNU-PLOT log(3) { write(FFF2); } print "\n"; for( $k= -$num; $k<=$num; $k++ ) # WRITE DATA FOR GNU-PLOT log(2) { write(FFF3); } close(FFF2); close(FFF3); } elsif( $action =~ /SPIRAL5THS/ ) #- - - - - - - - - -- - - - - - - - - - -- { #STANDARD SPIRAL IN POLAR CO-ORDS open( POLARIS, ">-"); $pi = 3.141592653589793; $theta_0 = $pi / 2; $factor = log(3) / ( (19/12) * log(2) ) * $pi/6; $stretchForPicture = 1.01; $r_0 = 2; #write( POLARIS ); for( $k = -$num; $k <= $num; $k++ ) # WRITE DATA FOR GNU-PLOT { $theta = $theta_0 - $k * $factor *$stretchForPicture; $r = (0.2 / $pi) * ($theta - $theta_0) + $r_0; write(POLARIS); } print "\n"; print "\n"; #for( $k=-$num*10; $k <= $num*10; $k++ ) #DATA FOR SMOOTH SPIRAL CURVE #{ # $theta = $theta_0 - $k * $factor/10; # $r = (0.2 / 3.141592653589793) * ($theta - $theta_0) + $r_0; # write(POLARIS); #} #print "\n"; close(POLARIS); } elsif( $action =~ /MINORS/ ) #- - - - - - ----- - - -- - - - - - - - - - - { &harmonicMatchingIntervals( $num, %index2NoteName ); } elsif( $action =~ /CLOSING/ ) #- - - - - - - -- - - - - - - - - - - - - - - - { &tableOfClosingValues( $num, $tempered3rdHarm, %index2value ); } elsif( $action =~ /HTMLPOWERS/ ) #- - - - - - - -- - - - - - - - - - - - - - - - { open( POWERS_HEAD, ">-"); write( POWERS_HEAD ); for( $k= $num; $k >= -$num; $k-- ) # WRITE HTML TABLES OF POWERS { &printPowers(); } close(POWERS_HEAD); print "\n<\BODY>\n\n"; } elsif( $action =~ /TABLE/ ) #- - - - - - - - - - - - - - - - - - - - - - - - - - { open( FFF_HEAD, ">-"); open( FFF, ">-"); write(FFF_HEAD); @ordered = sort( keys( %value2fraction ) ); for( $k=0; $k <= $#ordered; $k++ ) { #print "$value2fraction{$ordered[$k]}\n"; if( $k < $#ordered ) { $delta = $ordered[$k+1]/$ordered[$k]; $cents = 1200*log( $delta ) / log (2); #print " $cents cents\n"; write(FFF); } else { $cents = "*"; write(FFF); } } close( FFF ); close( FFF_HEAD ); } else #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - { print "Unknown action: $action\n"; print "Examples of correct useage:\n"; print "perl -w genPythag.pl 50 CLOSING > table.html"; print "the first argument is the number of iterations to do (here 50 so "; print "it goes from -50 to 50). The 2nd is the type of action\n"; print "perl -w genPythag.pl 30 TABLE \n"; print "perl -w genPythag.pl 30 HTLMPOWERS \n"; print "perl -w genPythag.pl 30 PLOT \n"; print "perl -w genPythag.pl 30 SPIRAL5THS \n"; } # ============================================================================== sub tableOfClosingValues() { my( $num, $tempered3rdHarmonic, %index2value ) = @_; my( %index2ClosestLowerIndexNeighbor, $n, $k,$d, $dmin, $d1min, $dOld ); my( $count, $onlyPrintChanges ); $onlyPrintChanges = "false"; &printClosingTableHeader( $tempered3rdHarmonic ); $dOld = 204; $count = 3; #D WILL BE THE 4TH NOTE GENERATED for( $n = 2; $n <= $num; $n++ ) { $x = $index2value{$n}; #POSITIVE ITERATE $count++; $dmin = 1200; for( $k = -($n-1); $k <= ($n -1); $k++ ) { $d = &distInCents( $x, $index2value{$k} ); if( $d < $dmin ) { $dmin = $d; $index2ClosestLowerIndexNeighbor{$n} = $k; } } $d = &distInCents( $x, 2 ); #EXTRA CHECK FOR C AT TOP OF OCTAVE if( $d < $dmin ) { $dmin = $d; $index2ClosestLowerIndexNeighbor{$n} = 0; } if( $dmin < $dOld - 0.000000001) { print "\n"; $dOld = $dmin; &printClosingTableRow( $count, $n, $index2PowerOf2{$n}, $index2NoteName{$n}, $index2ClosestLowerIndexNeighbor{$n}, $index2PowerOf2{ $index2ClosestLowerIndexNeighbor{$n} }, $index2NoteName{ $index2ClosestLowerIndexNeighbor{$n} }, $dmin ); } elsif( $dmin > $dOld + 0.00000001 ) { print "\n"; &printClosingTableRow( $count, $n, $index2PowerOf2{$n}, $index2NoteName{$n}, $index2ClosestLowerIndexNeighbor{$n}, $index2PowerOf2{ $index2ClosestLowerIndexNeighbor{$n} }, $index2NoteName{ $index2ClosestLowerIndexNeighbor{$n} }, $dmin ); } else { if( $onlyPrintChanges eq "false" ) { print "\n"; &printClosingTableRow( $count, $n, $index2PowerOf2{$n}, $index2NoteName{$n}, $index2ClosestLowerIndexNeighbor{$n}, $index2PowerOf2{ $index2ClosestLowerIndexNeighbor{$n} }, $index2NoteName{ $index2ClosestLowerIndexNeighbor{$n} }, $dmin ); } } $x = $index2value{-$n}; #---------------CORRESPONDING NEGATIVE ITERATE $count++; $d1min = 1200; for( $k = -($n-1); $k <= $n; $k++ ) { $d = &distInCents( $x, $index2value{$k} ); if( $d < $d1min ) { $d1min = $d; $index2ClosestLowerIndexNeighbor{-$n} = $k; } } $d = &distInCents( $x, 2 ); #EXTRA CHECK FOR C AT TOP OF OCTAVE if( $d < $d1min ) { $d1min = $d; $index2ClosestLowerIndexNeighbor{-$n} = 0; } if( $d1min < $dOld - 0.0000001) { print "\n"; $dOld = $d1min; &printClosingTableRow( $count, -$n, $index2PowerOf2{-$n}, $index2NoteName{-$n}, $index2ClosestLowerIndexNeighbor{-$n}, $index2PowerOf2{ $index2ClosestLowerIndexNeighbor{-$n} }, $index2NoteName{ $index2ClosestLowerIndexNeighbor{-$n} }, $d1min ); } elsif( $d1min > $dOld + 0.00000001) { print "\n"; &printClosingTableRow( $count, -$n, $index2PowerOf2{-$n}, $index2NoteName{-$n}, $index2ClosestLowerIndexNeighbor{-$n}, $index2PowerOf2{ $index2ClosestLowerIndexNeighbor{-$n} }, $index2NoteName{ $index2ClosestLowerIndexNeighbor{-$n} }, $d1min ); } else { if( $onlyPrintChanges eq "false" ) { print "\n"; &printClosingTableRow( $count, -$n, $index2PowerOf2{-$n}, $index2NoteName{-$n}, $index2ClosestLowerIndexNeighbor{-$n}, $index2PowerOf2{ $index2ClosestLowerIndexNeighbor{-$n} }, $index2NoteName{ $index2ClosestLowerIndexNeighbor{-$n} }, $d1min ); } } } print "\n<\BODY>\n\n"; } # ============================================================================== sub printClosingTableHeader() { my( $tempered3rdHarmonic ) = @_; print " \n"; print " \n"; print " \n"; print " \n"; print " \n"; print " \n"; print " \n"; print " \n"; print " \n"; print " \n"; print " \n"; print " \n"; print " \n"; } # ============================================================================== sub printClosingTableRow() { my( $count, $pow3new, $pow2new, $newNote, $pow3close, $pow2close, $closestNote, $dist ) = @_; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; } # ============================================================================== sub printPowers() { print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; } # ============================================================================== sub harmonicMatchingIntervals() { # LEFT RIGHT # WE SEEK TO COMPUTE d( 2^p harm[i] 3^n, 2^q harm[j] ) my( $max, %i2NoteName ) = @_; my( $n, @harmL, $indexL, @harmR, $indexR, $pq, $d, $eta, $count, $alpha ); $harmL[0] = 3; $harmL[1] = 5; $harmL[2] = 7; $harmL[3] = 9; $harmR[0] = 1; $harmR[1] = 3; $harmR[2] = 5; $harmR[3] = 7; $harmR[4] = 9; $count = 1; &printMinorTableHeader(); for( $indexR = 0; $indexR <= 4; $indexR++ ) { for( $n = -$max; $n <= $max; $n++ ) { if( $n == 0 ) { next; } for( $indexL = 0; $indexL <= 3; $indexL++ ) { for( $pq = -10; $pq <= 10; $pq++ ) # REALLY I WANT p - q { $d = &signedDistInCents( 2**$pq * $harmL[$indexL] * 3**$n, $harmR[$indexR] ); if( abs($d) < 60 ) { $eta = ( $harmR[$indexR] / (2**$pq * $harmL[$indexL]))**(1/$n); $alpha = - log( $eta/3) / log( 81/80 ); &printMinorTableRow( $i2NoteName{$n}, $n, $pq, $harmL[$indexL], $harmR[$indexR], $d, $eta, $count, $alpha ); $count++; } } } } } print "
Tempered 3rd Harmonic = $tempered3rdHarmonic
CountNew note nameNew note valueBest match valueBest match NameDistance in cents $count $newNote 3$pow3new 2$pow2new 3$pow3close 2$pow2close $closestNote $dist
$k 3$k 2$index2PowerOf2{$k} $index2Fraction{$k} $index2NoteName{$k}
\n \n\n"; } # ============================================================================== sub printMinorTableHeader() { print " \n"; print " \n"; print " \n"; print " \n"; print " \n"; print "\n"; print " \n"; print "\n"; print " \n"; print " \n"; print " \n"; print " \n"; print " \n"; print " \n"; print " \n"; print " \n"; print "\n"; } # ============================================================================== sub printMinorTableRow() { my( $noteName, $n, $pq, $harmL, $harmR, $dCents, $eta, $count, $alpha) = @_; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; } # ============================================================================== sub distInCents() { my( $f0, $f1 ) = @_; my( $cents ); $cents = (1200/log(2))*log( $f0/$f1 ); return abs($cents); } # ============================================================================== sub signedDistInCents() { my( $f0, $f1 ) = @_; my( $cents ); $cents = (1200/log(2))*log( $f0/$f1 ); return $cents; } # ============================================================================== format POLARIS = @<<<<<<<< @<<<<<<<<<< $theta, $r . # ============================================================================== format FFF_HEAD = FRACTION NOTE NAME CENTS TO NEXT NOTE ----------------------------- --------- ------------------ . format FFF = @<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @<<<<<<< @<<<<<<<<< $value2fraction{$ordered[$k]}, $value2name{$ordered[$k]}, $cents; . # ============================================================================== format FFF1 = @<<<<<<<< 3 @<<<<<< 2 @<<<<<<< @<<<<<<<<<<<<<<<<< @<<<<<<<<<<<<<<<< $k,$k, $index2PowerOf2{$k}, $index2LogHarm{$k}, $index2LogRescaler{$k}; . # ============================================================================== format FFF2 = @<<<<<<<< @<<<<<<<<<< $k, $index2LogHarm{$k}; . # ============================================================================== format FFF3 = @<<<<<<<< @<<<<<<<<<< $k, $index2LogRescaler{$k}; . #=============================================================================== format POWERS_HEAD =
Landmarks for Minor Intervals
Num Note
name
Value Harmonic Octaves Matched
Harmonic of c
Distance in cents Factor η Factor α
$count $noteName 3$n $harmL 2$pq $harmR $dCents $eta $alpha
.
Index Three Two Fractional Value Note Name