Skip to content

Instantly share code, notes, and snippets.

@drupol
Last active December 30, 2019 13:12
Show Gist options
  • Save drupol/831da434de8f69dfc684a5f9a3ab32a7 to your computer and use it in GitHub Desktop.
Save drupol/831da434de8f69dfc684a5f9a3ab32a7 to your computer and use it in GitHub Desktop.
Pythagorian and harmonic music scales using functionnal PHP and a lazy collection
<?php
/**
* @file
* Example/demo file.
* @see https://github.com/drupol/collection
*/
declare(strict_types=1);
include 'vendor/autoload.php';
use drupol\collection\Collection;
// From: https://stackoverflow.com/questions/14330713/converting-float-decimal-to-fraction
function float2rat(float $value, $tolerance = 1.e-12) {
$num=1; $h2=0;
$den=0; $k2=1;
if ($value === 0) {
return 0;
}
$b = 1/$value;
do {
$b = 1/$b;
$a = floor($b);
$aux = $num; $num = $a*$num+$h2; $h2 = $aux;
$aux = $den; $den = $a*$den+$k2; $k2 = $aux;
$b -= $a;
} while (abs($value-$num/$den) > $value*$tolerance);
return $num . '/' . $den;
}
// Harmonic scale serie generator
$harmonic = static function ($value) {
$s = 1;
for ($i = 1; $i <= $value; $i++) {
$s += 1 / $i;
}
return $s;
};
// Pythagorian scale serie generator
$pythagorian = static function ($value) {
return (3/2) ** $value;
};
$scale = Collection::range(0, 12)
// Choose the scale: $harmonic or $pythagorian
->map($harmonic)
// Scale the values between the interval 1 and 2 (logarithmic)
->map(
static function (float $value) {
while ($value > 2) {
$value /= 2;
}
return $value;
}
)
// Sort values ASC
->sort(static function ($a, $b) {return $a <=> $b;})
// Convert float to rational numbers (fraction)
->map(static function ($value) {return float2rat($value);});
print_r($scale->all());
/*
Pythagorian:
Array (
[0] => 1/1
[1] => 2187/2048
[2] => 9/8
[3] => 19683/16384
[4] => 81/64
[5] => 177147/131072
[6] => 729/512
[7] => 3/2
[8] => 6561/4096
[9] => 27/16
[10] => 59049/32768
[11] => 243/128
)
Harmonic:
Array (
[0] => 1/1
[1] => 111431/110880
[2] => 5/4
[3] => 17/12
[4] => 37/24
[5] => 197/120
[6] => 69/40
[7] => 503/280
[8] => 1041/560
[9] => 9649/5040
[10] => 9901/5040
[11] => 2/1
)
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment