module Music.Theory.Tuning.Scala where
import Control.Monad
import Data.Either
import Data.List
import Data.Maybe
import Data.Ratio
import System.Directory
import System.Environment
import System.FilePath
import qualified Music.Theory.Array.Csv as Csv
import qualified Music.Theory.Directory as Directory
import qualified Music.Theory.Either as Either
import qualified Music.Theory.Function as Function
import qualified Music.Theory.Io as Io
import qualified Music.Theory.List as List
import qualified Music.Theory.Math.Prime as Prime
import qualified Music.Theory.Read as T
import qualified Music.Theory.Show as T
import qualified Music.Theory.String as T
import qualified Music.Theory.Tuning as T
import qualified Music.Theory.Tuning.Type as T
type Pitch = Either T.Cents Rational
data Pitch_Type = Pitch_Cents | Pitch_Ratio deriving (Pitch_Type -> Pitch_Type -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Pitch_Type -> Pitch_Type -> Bool
$c/= :: Pitch_Type -> Pitch_Type -> Bool
== :: Pitch_Type -> Pitch_Type -> Bool
$c== :: Pitch_Type -> Pitch_Type -> Bool
Eq,Int -> Pitch_Type -> ShowS
[Pitch_Type] -> ShowS
Pitch_Type -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Pitch_Type] -> ShowS
$cshowList :: [Pitch_Type] -> ShowS
show :: Pitch_Type -> String
$cshow :: Pitch_Type -> String
showsPrec :: Int -> Pitch_Type -> ShowS
$cshowsPrec :: Int -> Pitch_Type -> ShowS
Show)
type Epsilon = Double
pitch_type :: Pitch -> Pitch_Type
pitch_type :: Pitch -> Pitch_Type
pitch_type = forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (forall a b. a -> b -> a
const Pitch_Type
Pitch_Cents) (forall a b. a -> b -> a
const Pitch_Type
Pitch_Ratio)
pitch_cents :: Pitch -> T.Cents
pitch_cents :: Pitch -> Cents
pitch_cents Pitch
p =
case Pitch
p of
Left Cents
c -> Cents
c
Right Rational
r -> forall i. Integral i => Ratio i -> Cents
T.ratio_to_cents Rational
r
pitch_ratio :: Epsilon -> Pitch -> Rational
pitch_ratio :: Cents -> Pitch -> Rational
pitch_ratio Cents
epsilon Pitch
p =
case Pitch
p of
Left Cents
c -> Cents -> Cents -> Rational
T.reconstructed_ratio Cents
epsilon Cents
c
Right Rational
r -> Rational
r
pitch_representations :: [Pitch] -> (Int,Int)
pitch_representations :: [Pitch] -> (Int, Int)
pitch_representations =
let f :: (a, b) -> Either a b -> (a, b)
f (a
l,b
r) Either a b
p = case Either a b
p of
Left a
_ -> (a
l forall a. Num a => a -> a -> a
+ a
1,b
r)
Right b
_ -> (a
l,b
r forall a. Num a => a -> a -> a
+ b
1)
in forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl forall {a} {b} {a} {b}.
(Num a, Num b) =>
(a, b) -> Either a b -> (a, b)
f (Int
0,Int
0)
uniform_pitch_type :: [Pitch] -> Maybe Pitch_Type
uniform_pitch_type :: [Pitch] -> Maybe Pitch_Type
uniform_pitch_type [Pitch]
p =
case [Pitch] -> (Int, Int)
pitch_representations [Pitch]
p of
(Int
0,Int
_) -> forall a. a -> Maybe a
Just Pitch_Type
Pitch_Ratio
(Int
_,Int
0) -> forall a. a -> Maybe a
Just Pitch_Type
Pitch_Cents
(Int, Int)
_ -> forall a. Maybe a
Nothing
pitch_type_predominant :: [Pitch] -> Pitch_Type
pitch_type_predominant :: [Pitch] -> Pitch_Type
pitch_type_predominant [Pitch]
p =
let (Int
c,Int
r) = [Pitch] -> (Int, Int)
pitch_representations [Pitch]
p
in if Int
c forall a. Ord a => a -> a -> Bool
>= Int
r then Pitch_Type
Pitch_Cents else Pitch_Type
Pitch_Ratio
type Scale = (String,String,Int,[Pitch])
scale_name :: Scale -> String
scale_name :: Scale -> String
scale_name (String
nm,String
_,Int
_,[Pitch]
_) = String
nm
scale_description :: Scale -> String
scale_description :: Scale -> String
scale_description (String
_,String
d,Int
_,[Pitch]
_) = String
d
scale_degree :: Scale -> Int
scale_degree :: Scale -> Int
scale_degree (String
_,String
_,Int
n,[Pitch]
_) = Int
n
scale_pitches :: Scale -> [Pitch]
scale_pitches :: Scale -> [Pitch]
scale_pitches (String
_,String
_,Int
_,[Pitch]
p) = [Pitch]
p
pitch_non_oct :: Pitch -> Bool
pitch_non_oct :: Pitch -> Bool
pitch_non_oct Pitch
p =
case Pitch
p of
Left Cents
c -> Cents
c forall a. Ord a => a -> a -> Bool
< Cents
0 Bool -> Bool -> Bool
|| Cents
c forall a. Ord a => a -> a -> Bool
> Cents
1200
Right Rational
r -> Rational
r forall a. Ord a => a -> a -> Bool
< Rational
1 Bool -> Bool -> Bool
|| Rational
r forall a. Ord a => a -> a -> Bool
> Rational
2
scale_verify :: Scale -> Bool
scale_verify :: Scale -> Bool
scale_verify (String
_,String
_,Int
n,[Pitch]
p) = Int
n forall a. Eq a => a -> a -> Bool
== forall (t :: * -> *) a. Foldable t => t a -> Int
length [Pitch]
p
scale_verify_err :: Scale -> Scale
scale_verify_err :: Scale -> Scale
scale_verify_err Scale
scl = if Scale -> Bool
scale_verify Scale
scl then Scale
scl else forall a. HasCallStack => String -> a
error (String
"invalid scale: " forall a. [a] -> [a] -> [a]
++ Scale -> String
scale_name Scale
scl)
scale_octave :: Scale -> Maybe Pitch
scale_octave :: Scale -> Maybe Pitch
scale_octave (String
_,String
_,Int
_,[Pitch]
s) =
case [Pitch]
s of
[] -> forall a. Maybe a
Nothing
[Pitch]
_ -> forall a. a -> Maybe a
Just (forall a. [a] -> a
last [Pitch]
s)
scale_octave_err :: Scale -> Pitch
scale_octave_err :: Scale -> Pitch
scale_octave_err = forall a. a -> Maybe a -> a
fromMaybe (forall a. HasCallStack => String -> a
error String
"scale_octave?") forall b c a. (b -> c) -> (a -> b) -> a -> c
. Scale -> Maybe Pitch
scale_octave
perfect_octave :: Scale -> Bool
perfect_octave :: Scale -> Bool
perfect_octave Scale
s =
case Scale -> Maybe Pitch
scale_octave Scale
s of
Just (Right Rational
2) -> Bool
True
Just (Left Cents
1200.0) -> Bool
True
Maybe Pitch
_ -> Bool
False
is_scale_uniform :: Scale -> Bool
is_scale_uniform :: Scale -> Bool
is_scale_uniform = forall a. Maybe a -> Bool
isJust forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Pitch] -> Maybe Pitch_Type
uniform_pitch_type forall b c a. (b -> c) -> (a -> b) -> a -> c
. Scale -> [Pitch]
scale_pitches
is_scale_ascending :: Scale -> Bool
is_scale_ascending :: Scale -> Bool
is_scale_ascending = forall a. Ord a => [a] -> Bool
List.is_ascending forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map Pitch -> Cents
pitch_cents forall b c a. (b -> c) -> (a -> b) -> a -> c
. Scale -> [Pitch]
scale_pitches
scale_uniform :: Epsilon -> Scale -> Scale
scale_uniform :: Cents -> Scale -> Scale
scale_uniform Cents
epsilon (String
nm,String
d,Int
n,[Pitch]
p) =
case [Pitch] -> Pitch_Type
pitch_type_predominant [Pitch]
p of
Pitch_Type
Pitch_Cents -> (String
nm,String
d,Int
n,forall a b. (a -> b) -> [a] -> [b]
map (forall a b. a -> Either a b
Left forall b c a. (b -> c) -> (a -> b) -> a -> c
. Pitch -> Cents
pitch_cents) [Pitch]
p)
Pitch_Type
Pitch_Ratio -> (String
nm,String
d,Int
n,forall a b. (a -> b) -> [a] -> [b]
map (forall a b. b -> Either a b
Right forall b c a. (b -> c) -> (a -> b) -> a -> c
. Cents -> Pitch -> Rational
pitch_ratio Cents
epsilon) [Pitch]
p)
scale_cents :: Scale -> [T.Cents]
scale_cents :: Scale -> [Cents]
scale_cents Scale
s = Cents
0 forall a. a -> [a] -> [a]
: forall a b. (a -> b) -> [a] -> [b]
map Pitch -> Cents
pitch_cents (Scale -> [Pitch]
scale_pitches Scale
s)
scale_cents_i :: Scale -> [T.Cents_I]
scale_cents_i :: Scale -> [Int]
scale_cents_i = forall a b. (a -> b) -> [a] -> [b]
map forall a b. (RealFrac a, Integral b) => a -> b
round forall b c a. (b -> c) -> (a -> b) -> a -> c
. Scale -> [Cents]
scale_cents
scale_ratios :: Epsilon -> Scale -> [Rational]
scale_ratios :: Cents -> Scale -> [Rational]
scale_ratios Cents
epsilon Scale
s = Rational
1 forall a. a -> [a] -> [a]
: forall a b. (a -> b) -> [a] -> [b]
map (Cents -> Pitch -> Rational
pitch_ratio Cents
epsilon) (Scale -> [Pitch]
scale_pitches Scale
s)
scale_ratios_u :: Scale -> Maybe [Rational]
scale_ratios_u :: Scale -> Maybe [Rational]
scale_ratios_u Scale
scl =
let err :: a
err = forall a. HasCallStack => String -> a
error String
"scale_ratios_u?"
p :: [Pitch]
p = Scale -> [Pitch]
scale_pitches Scale
scl
in case [Pitch] -> Maybe Pitch_Type
uniform_pitch_type [Pitch]
p of
Just Pitch_Type
Pitch_Ratio -> forall a. a -> Maybe a
Just (Rational
1 forall a. a -> [a] -> [a]
: forall a b. (a -> b) -> [a] -> [b]
map (forall a. a -> Maybe a -> a
fromMaybe forall {a}. a
err forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall x t. Either x t -> Maybe t
Either.from_right) [Pitch]
p)
Maybe Pitch_Type
_ -> forall a. Maybe a
Nothing
scale_ratios_req :: Scale -> [Rational]
scale_ratios_req :: Scale -> [Rational]
scale_ratios_req = forall a. a -> Maybe a -> a
fromMaybe (forall a. HasCallStack => String -> a
error String
"scale_ratios_req") forall b c a. (b -> c) -> (a -> b) -> a -> c
. Scale -> Maybe [Rational]
scale_ratios_u
scale_eq :: Scale -> Scale -> Bool
scale_eq :: Scale -> Scale -> Bool
scale_eq (String
_,String
_,Int
d0,[Pitch]
p0) (String
_,String
_,Int
d1,[Pitch]
p1) = Int
d0 forall a. Eq a => a -> a -> Bool
== Int
d1 Bool -> Bool -> Bool
&& [Pitch]
p0 forall a. Eq a => a -> a -> Bool
== [Pitch]
p1
scale_eq_n :: Int -> Scale -> Scale -> Bool
scale_eq_n :: Int -> Scale -> Scale -> Bool
scale_eq_n Int
k (String
_,String
_,Int
d0,[Pitch]
p0) (String
_,String
_,Int
d1,[Pitch]
p1) = Int
d0 forall a. Eq a => a -> a -> Bool
== Int
d1 Bool -> Bool -> Bool
&& forall (t :: * -> *) a. Foldable t => t a -> Int
length ([Pitch]
p0 forall a. Eq a => [a] -> [a] -> [a]
`intersect` [Pitch]
p1) forall a. Ord a => a -> a -> Bool
>= Int
k
scale_sub :: Scale -> Scale -> Bool
scale_sub :: Scale -> Scale -> Bool
scale_sub (String
_,String
_,Int
d0,[Pitch]
p0) (String
_,String
_,Int
d1,[Pitch]
p1) = Int
d0 forall a. Ord a => a -> a -> Bool
< Int
d1 Bool -> Bool -> Bool
&& forall a. Eq a => [a] -> [a] -> [a]
intersect [Pitch]
p0 [Pitch]
p1 forall a. Eq a => a -> a -> Bool
== [Pitch]
p0
scale_eqv :: Epsilon -> Scale -> Scale -> Bool
scale_eqv :: Cents -> Scale -> Scale -> Bool
scale_eqv Cents
epsilon (String
_,String
_,Int
d0,[Pitch]
p0) (String
_,String
_,Int
d1,[Pitch]
p1) =
let ~= :: Pitch -> Pitch -> Bool
(~=) Pitch
p Pitch
q = forall a. Num a => a -> a
abs (Pitch -> Cents
pitch_cents Pitch
p forall a. Num a => a -> a -> a
- Pitch -> Cents
pitch_cents Pitch
q) forall a. Ord a => a -> a -> Bool
< Cents
epsilon
in Int
d0 forall a. Eq a => a -> a -> Bool
== Int
d1 Bool -> Bool -> Bool
&& forall (t :: * -> *). Foldable t => t Bool -> Bool
and (forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith Pitch -> Pitch -> Bool
(~=) [Pitch]
p0 [Pitch]
p1)
is_comment :: String -> Bool
String
x =
case String
x of
Char
'!':String
_ -> Bool
True
String
_ -> Bool
False
remove_eol_comments :: String -> String
= forall a. (a -> Bool) -> [a] -> [a]
takeWhile (forall a. Eq a => a -> a -> Bool
/= Char
'!')
filter_comments :: [String] -> [String]
=
forall a b. (a -> b) -> [a] -> [b]
map ShowS
remove_eol_comments forall b c a. (b -> c) -> (a -> b) -> a -> c
.
forall a. (a -> Bool) -> [a] -> [a]
filter (Bool -> Bool
not forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall t. [t -> Bool] -> t -> Bool
Function.predicate_any [String -> Bool
is_comment])
parse_pitch :: String -> Pitch
parse_pitch :: String -> Pitch
parse_pitch String
p =
if Char
'.' forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` String
p
then forall a b. a -> Either a b
Left (forall n. Read n => String -> n
T.read_fractional_allow_trailing_point_err String
p)
else forall a b. b -> Either a b
Right (forall i. (Integral i, Read i) => String -> Ratio i
T.read_ratio_with_div_err String
p)
parse_pitch_ln :: String -> Pitch
parse_pitch_ln :: String -> Pitch
parse_pitch_ln String
x =
case String -> [String]
words String
x of
String
p:[String]
_ -> String -> Pitch
parse_pitch String
p
[String]
_ -> forall a. HasCallStack => String -> a
error (forall a. Show a => a -> String
show (String
"parse_pitch_ln",String -> [String]
words String
x))
parse_scl :: String -> String -> Scale
parse_scl :: String -> String -> Scale
parse_scl String
nm String
s =
case [String] -> [String]
filter_comments (String -> [String]
lines (ShowS
T.filter_cr String
s)) of
String
t:String
n:[String]
p -> let scl :: Scale
scl = (String
nm
,ShowS
T.delete_trailing_whitespace String
t
,forall a. Read a => String -> String -> a
T.read_err_msg String
"degree" String
n
,forall a b. (a -> b) -> [a] -> [b]
map String -> Pitch
parse_pitch_ln [String]
p)
in Scale -> Scale
scale_verify_err Scale
scl
[String]
_ -> forall a. HasCallStack => String -> a
error String
"parse"
scl_get_dir :: IO [FilePath]
scl_get_dir :: IO [String]
scl_get_dir = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap String -> [String]
splitSearchPath (String -> IO String
getEnv String
"SCALA_SCL_DIR")
scl_derive_filename :: FilePath -> IO FilePath
scl_derive_filename :: String -> IO String
scl_derive_filename String
nm = do
[String]
dir <- IO [String]
scl_get_dir
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (forall (t :: * -> *) a. Foldable t => t a -> Bool
null [String]
dir) (forall a. HasCallStack => String -> a
error String
"scl_derive_filename: SCALA_SCL_DIR: nil")
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (String -> Bool
hasExtension String
nm) (forall a. HasCallStack => String -> a
error String
"scl_derive_filename: name has extension")
[String] -> String -> IO String
Directory.path_scan_err [String]
dir (String
nm String -> ShowS
<.> String
"scl")
scl_resolve_name :: String -> IO FilePath
scl_resolve_name :: String -> IO String
scl_resolve_name String
nm =
let ex_f :: Bool -> m String
ex_f Bool
x = if Bool
x then forall (m :: * -> *) a. Monad m => a -> m a
return String
nm else forall a. HasCallStack => String -> a
error String
"scl_resolve_name: file does not exist"
in if String -> Bool
isAbsolute String
nm Bool -> Bool -> Bool
&& ShowS
takeExtension String
nm forall a. Eq a => a -> a -> Bool
== String
".scl"
then String -> IO Bool
doesFileExist String
nm forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= forall {m :: * -> *}. Monad m => Bool -> m String
ex_f
else String -> IO String
scl_derive_filename String
nm
scl_load :: String -> IO Scale
scl_load :: String -> IO Scale
scl_load String
nm = do
String
fn <- String -> IO String
scl_resolve_name String
nm
String
s <- String -> IO String
Io.read_file_iso_8859_1 String
fn
forall (m :: * -> *) a. Monad m => a -> m a
return (String -> String -> Scale
parse_scl (ShowS
takeBaseName String
nm) String
s)
scl_load_dir_fn :: FilePath -> IO [(FilePath,Scale)]
scl_load_dir_fn :: String -> IO [(String, Scale)]
scl_load_dir_fn String
d = do
[String]
fn <- [String] -> String -> IO [String]
Directory.dir_subset [String
".scl"] String
d
[Scale]
scl <- forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM String -> IO Scale
scl_load [String]
fn
forall (m :: * -> *) a. Monad m => a -> m a
return (forall a b. [a] -> [b] -> [(a, b)]
zip [String]
fn [Scale]
scl)
scl_load_dir :: FilePath -> IO [Scale]
scl_load_dir :: String -> IO [Scale]
scl_load_dir = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (forall a b. (a -> b) -> [a] -> [b]
map forall a b. (a, b) -> b
snd) forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> IO [(String, Scale)]
scl_load_dir_fn
scl_load_db :: IO [Scale]
scl_load_db :: IO [Scale]
scl_load_db = do
[String]
dir <- IO [String]
scl_get_dir
[[Scale]]
r <- forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM String -> IO [Scale]
scl_load_dir [String]
dir
forall (m :: * -> *) a. Monad m => a -> m a
return (forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [[Scale]]
r)
scales_dir_txt_tbl :: [Scale] -> [[String]]
scales_dir_txt_tbl :: [Scale] -> [[String]]
scales_dir_txt_tbl =
let f :: Scale -> [String]
f Scale
s = [Scale -> String
scale_name Scale
s,forall a. Show a => a -> String
show (Scale -> Int
scale_degree Scale
s),Scale -> String
scale_description Scale
s]
in forall a b. (a -> b) -> [a] -> [b]
map Scale -> [String]
f
scales_dir_txt_csv :: [Scale] -> String
scales_dir_txt_csv :: [Scale] -> String
scales_dir_txt_csv [Scale]
db = forall a. (a -> String) -> Csv_Opt -> Csv_Table a -> String
Csv.csv_table_pp forall a. a -> a
id Csv_Opt
Csv.def_csv_opt (forall a. Maybe a
Nothing,[Scale] -> [[String]]
scales_dir_txt_tbl [Scale]
db)
scale_stat :: Scale -> [String]
scale_stat :: Scale -> [String]
scale_stat Scale
s =
let p :: [Pitch]
p = Scale -> [Pitch]
scale_pitches Scale
s
u_ty :: Maybe Pitch_Type
u_ty = [Pitch] -> Maybe Pitch_Type
uniform_pitch_type [Pitch]
p
n_ty :: String
n_ty = let p_ty :: Pitch_Type
p_ty = [Pitch] -> Pitch_Type
pitch_type_predominant [Pitch]
p
(Int
p_i,Int
p_j) = [Pitch] -> (Int, Int)
pitch_representations [Pitch]
p
in forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [String
"non-uniform (",forall a. Show a => a -> String
show Pitch_Type
p_ty,String
",",forall a. Show a => a -> String
show Int
p_i,String
":",forall a. Show a => a -> String
show Int
p_j,String
")"]
in [String
"name : " forall a. [a] -> [a] -> [a]
++ Scale -> String
scale_name Scale
s
,String
"description : " forall a. [a] -> [a] -> [a]
++ Scale -> String
scale_description Scale
s
,String
"degree : " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show (Scale -> Int
scale_degree Scale
s)
,String
"type : " forall a. [a] -> [a] -> [a]
++ forall b a. b -> (a -> b) -> Maybe a -> b
maybe String
n_ty forall a. Show a => a -> String
show Maybe Pitch_Type
u_ty
,String
"perfect-oct : " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show (Scale -> Bool
perfect_octave Scale
s)
,String
"cents-i : " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show (Scale -> [Int]
scale_cents_i Scale
s)
,if Maybe Pitch_Type
u_ty forall a. Eq a => a -> a -> Bool
== forall a. a -> Maybe a
Just Pitch_Type
Pitch_Ratio
then String
"ratios : " forall a. [a] -> [a] -> [a]
++ forall a. [a] -> [[a]] -> [a]
intercalate String
"," (forall a b. (a -> b) -> [a] -> [b]
map forall a. (Show a, Integral a) => Ratio a -> String
T.rational_pp (Scale -> [Rational]
scale_ratios_req Scale
s))
else String
""]
pitch_pp :: Pitch -> String
pitch_pp :: Pitch -> String
pitch_pp Pitch
p =
case Pitch
p of
Left Cents
c -> forall a. Show a => a -> String
show Cents
c
Right Rational
r -> forall a. Show a => a -> String
show (forall a. Ratio a -> a
numerator Rational
r) forall a. [a] -> [a] -> [a]
++ String
"/" forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show (forall a. Ratio a -> a
denominator Rational
r)
scale_pp :: Scale -> [String]
scale_pp :: Scale -> [String]
scale_pp (String
nm,String
dsc,Int
k,[Pitch]
p) =
[String
"! " forall a. [a] -> [a] -> [a]
++ String
nm forall a. [a] -> [a] -> [a]
++ String
".scl"
,String
"!"
,String
dsc
,forall a. Show a => a -> String
show Int
k
,String
"!"] forall a. [a] -> [a] -> [a]
++ forall a b. (a -> b) -> [a] -> [b]
map Pitch -> String
pitch_pp [Pitch]
p
scale_wr :: FilePath -> Scale -> IO ()
scale_wr :: String -> Scale -> IO ()
scale_wr String
fn = String -> String -> IO ()
writeFile String
fn forall b c a. (b -> c) -> (a -> b) -> a -> c
. [String] -> String
unlines forall b c a. (b -> c) -> (a -> b) -> a -> c
. Scale -> [String]
scale_pp
scale_wr_dir :: FilePath -> Scale -> IO ()
scale_wr_dir :: String -> Scale -> IO ()
scale_wr_dir String
dir Scale
scl = String -> Scale -> IO ()
scale_wr (String
dir String -> ShowS
</> Scale -> String
scale_name Scale
scl String -> ShowS
<.> String
"scl") Scale
scl
dist_get_dir :: IO String
dist_get_dir :: IO String
dist_get_dir = String -> IO String
getEnv String
"SCALA_DIST_DIR"
load_dist_file :: FilePath -> IO String
load_dist_file :: String -> IO String
load_dist_file String
nm = do
String
d <- IO String
dist_get_dir
String -> IO String
readFile (String
d String -> ShowS
</> String
nm)
load_dist_file_ln :: FilePath -> IO [String]
load_dist_file_ln :: String -> IO [String]
load_dist_file_ln = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap String -> [String]
lines forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> IO String
load_dist_file
scl_is_ji :: Scale -> Bool
scl_is_ji :: Scale -> Bool
scl_is_ji = forall a. Eq a => a -> a -> Bool
(==) (forall a. a -> Maybe a
Just Pitch_Type
Pitch_Ratio) forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Pitch] -> Maybe Pitch_Type
uniform_pitch_type forall b c a. (b -> c) -> (a -> b) -> a -> c
. Scale -> [Pitch]
scale_pitches
scl_ji_limit :: Scale -> Integer
scl_ji_limit :: Scale -> Integer
scl_ji_limit = forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
maximum forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map forall a b. (a, b) -> a
fst forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap forall i. Integral i => Ratio i -> [(i, Int)]
Prime.rational_prime_factors_m forall b c a. (b -> c) -> (a -> b) -> a -> c
. Scale -> [Rational]
scale_ratios_req
scl_cdiff_abs_sum :: [T.Cents] -> Scale -> [(Double,[T.Cents],Int)]
scl_cdiff_abs_sum :: [Cents] -> Scale -> [(Cents, [Cents], Int)]
scl_cdiff_abs_sum [Cents]
c Scale
scl =
let r :: [[Cents]]
r = forall a b. (a -> b) -> [a] -> [b]
map (forall a. Num a => a -> [a] -> [a]
List.dx_d Cents
0) (forall a. [a] -> [[a]]
List.rotations (forall a. Num a => [a] -> [a]
List.d_dx (forall a. Ord a => [a] -> [a]
sort (Scale -> [Cents]
scale_cents Scale
scl))))
ndiff :: [Cents] -> c -> (Cents, [Cents], c)
ndiff [Cents]
x c
i = let d :: [Cents]
d = forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith (-) [Cents]
c [Cents]
x in (forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum (forall a b. (a -> b) -> [a] -> [b]
map forall a. Num a => a -> a
abs [Cents]
d),[Cents]
d,c
i)
in forall a. Ord a => [a] -> [a]
sort (forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith forall {c}. [Cents] -> c -> (Cents, [Cents], c)
ndiff [[Cents]]
r [Int
0..])
scl_cdiff_abs_sum_1 :: (Double -> n) -> [T.Cents] -> Scale -> (Double,[n],Int)
scl_cdiff_abs_sum_1 :: forall n. (Cents -> n) -> [Cents] -> Scale -> (Cents, [n], Int)
scl_cdiff_abs_sum_1 Cents -> n
pp [Cents]
c Scale
scl =
case [Cents] -> Scale -> [(Cents, [Cents], Int)]
scl_cdiff_abs_sum [Cents]
c Scale
scl of
[] -> forall a. HasCallStack => String -> a
error String
"scl_cdiff_abs_sum_1"
(Cents
n,[Cents]
d,Int
r):[(Cents, [Cents], Int)]
_ -> (Cents
n,forall a b. (a -> b) -> [a] -> [b]
map Cents -> n
pp [Cents]
d,Int
r)
scl_db_query_cdiff_asc :: Ord n => (Double -> n) -> [Scale] -> [T.Cents] -> [((Double,[n],Int),Scale)]
scl_db_query_cdiff_asc :: forall n.
Ord n =>
(Cents -> n) -> [Scale] -> [Cents] -> [((Cents, [n], Int), Scale)]
scl_db_query_cdiff_asc Cents -> n
pp [Scale]
db [Cents]
c =
let n :: Int
n = forall (t :: * -> *) a. Foldable t => t a -> Int
length [Cents]
c forall a. Num a => a -> a -> a
- Int
1
db_n :: [Scale]
db_n = forall a. (a -> Bool) -> [a] -> [a]
filter ((forall a. Eq a => a -> a -> Bool
== Int
n) forall b c a. (b -> c) -> (a -> b) -> a -> c
. Scale -> Int
scale_degree) [Scale]
db
in forall a. Ord a => [a] -> [a]
sort (forall a b. (a -> b) -> [a] -> [b]
map (\Scale
scl -> (forall n. (Cents -> n) -> [Cents] -> Scale -> (Cents, [n], Int)
scl_cdiff_abs_sum_1 Cents -> n
pp [Cents]
c Scale
scl,Scale
scl)) [Scale]
db_n)
scale_cmp_ji :: ([Rational] -> [Rational] -> Bool) -> [Rational] -> Scale -> Bool
scale_cmp_ji :: ([Rational] -> [Rational] -> Bool) -> [Rational] -> Scale -> Bool
scale_cmp_ji [Rational] -> [Rational] -> Bool
cmp [Rational]
x Scale
scl =
case Scale -> Maybe [Rational]
scale_ratios_u Scale
scl of
Maybe [Rational]
Nothing -> Bool
False
Just [Rational]
r -> [Rational] -> [Rational] -> Bool
cmp [Rational]
x [Rational]
r
scl_find_ji :: ([Rational] -> [Rational] -> Bool) -> [Rational] -> [Scale] -> [Scale]
scl_find_ji :: ([Rational] -> [Rational] -> Bool)
-> [Rational] -> [Scale] -> [Scale]
scl_find_ji [Rational] -> [Rational] -> Bool
cmp [Rational]
x = forall a. (a -> Bool) -> [a] -> [a]
filter (([Rational] -> [Rational] -> Bool) -> [Rational] -> Scale -> Bool
scale_cmp_ji [Rational] -> [Rational] -> Bool
cmp [Rational]
x)
scale_to_tuning :: Scale -> T.Tuning
scale_to_tuning :: Scale -> Tuning
scale_to_tuning (String
_,String
_,Int
_,[Pitch]
p) =
case forall a b. [Either a b] -> ([a], [b])
partitionEithers [Pitch]
p of
([],[Rational]
r) -> let ([Rational]
r',Rational
o) = forall a. [a] -> ([a], a)
List.separate_last [Rational]
r
in Either [Rational] [Cents]
-> Maybe (Either Rational Cents) -> Tuning
T.Tuning (forall a b. a -> Either a b
Left (Rational
1 forall a. a -> [a] -> [a]
: [Rational]
r')) (if Rational
o forall a. Eq a => a -> a -> Bool
== Rational
2 then forall a. Maybe a
Nothing else forall a. a -> Maybe a
Just (forall a b. a -> Either a b
Left Rational
o))
([Cents], [Rational])
_ -> let ([Pitch]
c,Pitch
o) = forall a. [a] -> ([a], a)
List.separate_last [Pitch]
p
c' :: [Cents]
c' = Cents
0 forall a. a -> [a] -> [a]
: forall a b. (a -> b) -> [a] -> [b]
map Pitch -> Cents
pitch_cents [Pitch]
c
o' :: Maybe (Either Rational Cents)
o' = if Pitch
o forall a. Eq a => a -> a -> Bool
== forall a b. a -> Either a b
Left Cents
1200 Bool -> Bool -> Bool
|| Pitch
o forall a. Eq a => a -> a -> Bool
== forall a b. b -> Either a b
Right Rational
2 then forall a. Maybe a
Nothing else forall a. a -> Maybe a
Just (forall a b. Either a b -> Either b a
Either.either_swap Pitch
o)
in Either [Rational] [Cents]
-> Maybe (Either Rational Cents) -> Tuning
T.Tuning (forall a b. b -> Either a b
Right [Cents]
c') Maybe (Either Rational Cents)
o'
tuning_to_scale :: (String,String) -> T.Tuning -> Scale
tuning_to_scale :: (String, String) -> Tuning -> Scale
tuning_to_scale (String
nm,String
dsc) tn :: Tuning
tn@(T.Tuning Either [Rational] [Cents]
p Maybe (Either Rational Cents)
_) =
let n :: Int
n = forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either forall (t :: * -> *) a. Foldable t => t a -> Int
length forall (t :: * -> *) a. Foldable t => t a -> Int
length Either [Rational] [Cents]
p
p' :: [Pitch]
p' = forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (forall a b. (a -> b) -> [a] -> [b]
map forall a b. b -> Either a b
Right forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. [a] -> [a]
tail) (forall a b. (a -> b) -> [a] -> [b]
map forall a b. a -> Either a b
Left forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. [a] -> [a]
tail) Either [Rational] [Cents]
p forall a. [a] -> [a] -> [a]
++ [forall a b. Either a b -> Either b a
Either.either_swap (Tuning -> Either Rational Cents
T.tn_octave_def Tuning
tn)]
in (String
nm,String
dsc,Int
n,[Pitch]
p')
scl_load_tuning :: String -> IO T.Tuning
scl_load_tuning :: String -> IO Tuning
scl_load_tuning = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Scale -> Tuning
scale_to_tuning forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> IO Scale
scl_load