{-# LANGUAGE CPP #-}
module Derive.Scale.Theory (
piano_intervals, piano_layout, diatonic_layout
, diatonic_to_chromatic
, transpose_diatonic, transpose_chromatic
, enharmonics_of
, pitch_to_semis, degree_to_semis
, semis_to_pitch, pick_enharmonic, semis_to_pitch_sharps
, semis_to_nn, fsemis_to_nn, nn_to_semis
, Key(key_tonic, key_name, key_intervals, key_signature, key_layout), key
, accidentals_at_pc
, Signature, Intervals
, layout
, layout_pc_per_octave, layout_semis_per_octave
, contains_degree
#ifndef TESTING
, Layout(layout_intervals)
#else
, Layout(..)
, calculate_signature, step_of
#endif
) where
import qualified Data.List as List
import qualified Data.Maybe as Maybe
import qualified Data.Vector as Boxed
import qualified Data.Vector as Vector
import qualified Util.Num as Num
import qualified Util.Pretty as Pretty
import qualified Util.Lists as Lists
import qualified Util.Vector as Vector
import qualified Perform.Pitch as Pitch
import Global
piano_intervals :: [Pitch.Semi]
piano_intervals :: [Int]
piano_intervals = [Int
2, Int
2, Int
1, Int
2, Int
2, Int
2, Int
1]
piano_layout :: Layout
piano_layout :: Layout
piano_layout = [Int] -> Layout
layout [Int]
piano_intervals
diatonic_layout :: Pitch.PitchClass -> Layout
diatonic_layout :: Int -> Layout
diatonic_layout Int
per_oct = [Int] -> Layout
layout forall a b. (a -> b) -> a -> b
$ forall a. Int -> a -> [a]
replicate Int
per_oct Int
1
diatonic_to_chromatic :: Key -> Pitch.Degree -> Double -> Pitch.FSemi
diatonic_to_chromatic :: Key -> Degree -> FSemi -> FSemi
diatonic_to_chromatic Key
key Degree
degree FSemi
steps
| FSemi
steps forall a. Eq a => a -> a -> Bool
== FSemi
0 = FSemi
0
| FSemi
steps forall a. Ord a => a -> a -> Bool
> FSemi
0 = forall a. (Eq a, Num a) => a -> a -> a -> a
Num.scale (Int -> FSemi
transpose Int
isteps) (Int -> FSemi
transpose (Int
istepsforall a. Num a => a -> a -> a
+Int
1)) FSemi
frac
| Bool
otherwise =
forall a. (Eq a, Num a) => a -> a -> a -> a
Num.scale (Int -> FSemi
transpose (Int
istepsforall a. Num a => a -> a -> a
-Int
1)) (Int -> FSemi
transpose Int
isteps) (FSemi
1 forall a. Num a => a -> a -> a
- forall a. Num a => a -> a
abs FSemi
frac)
where
(Int
isteps, FSemi
frac) = forall a b. (RealFrac a, Integral b) => a -> (b, a)
properFraction FSemi
steps
transpose :: Int -> FSemi
transpose = forall a b. (Integral a, Num b) => a -> b
fromIntegral forall b c a. (b -> c) -> (a -> b) -> a -> c
. Key -> Degree -> Int -> Int
chromatic_steps Key
key Degree
degree
chromatic_steps :: Key -> Pitch.Degree -> Int -> Pitch.Semi
chromatic_steps :: Key -> Degree -> Int -> Int
chromatic_steps Key
key Degree
degree Int
steps =
case Intervals
table forall a. Vector a -> Int -> Maybe a
Vector.!? (Int
middle forall a. Num a => a -> a -> a
+ Int
step forall a. Num a => a -> a -> a
+ Int
steps2) of
Just Int
val -> Int
oct_semis forall a. Num a => a -> a -> a
+ Int
val forall a. Num a => a -> a -> a
- Intervals
table forall a. Vector a -> Int -> a
Vector.! (Int
middle forall a. Num a => a -> a -> a
+ Int
step)
Maybe Int
Nothing -> forall a. HasCallStack => [Char] -> a
error forall a b. (a -> b) -> a -> b
$ [Char]
"ran out of transpose table for "
forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> [Char]
show (Int
middle, Int
step, Int
steps2) forall a. [a] -> [a] -> [a]
++ [Char]
": " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> [Char]
show Intervals
table
where
step :: Int
step = Key -> Degree -> Int
step_of Key
key Degree
degree
(Int
octaves, Int
steps2) = Int
steps forall a. Integral a => a -> a -> (a, a)
`divMod` Key -> Int
key_steps_per_octave Key
key
oct_semis :: Int
oct_semis = if Int
octaves forall a. Eq a => a -> a -> Bool
== Int
0 then Int
0
else Int
octaves forall a. Num a => a -> a -> a
* Layout -> Int
layout_semis_per_octave (Key -> Layout
key_layout Key
key)
middle :: Int
middle = forall a. Vector a -> Int
Vector.length Intervals
table forall a. Integral a => a -> a -> a
`div` Int
2
table :: Intervals
table = Key -> Intervals
key_transpose_table Key
key
transpose_diatonic :: Key -> Step -> Pitch.Pitch -> Pitch.Pitch
transpose_diatonic :: Key -> Int -> Pitch -> Pitch
transpose_diatonic Key
key Int
steps
pitch :: Pitch
pitch@(Pitch.Pitch Int
oct degree :: Degree
degree@(Pitch.Degree Int
pc Int
accs))
| Int
steps forall a. Eq a => a -> a -> Bool
== Int
0 = Pitch
pitch
| Bool
otherwise = case Key -> Maybe Intervals
key_signature Key
key of
Just Intervals
_ -> Int -> Degree -> Pitch
Pitch.Pitch (Int
oct forall a. Num a => a -> a -> a
+ Int
oct2) forall a b. (a -> b) -> a -> b
$ Int -> Int -> Degree
Pitch.Degree Int
pc2 forall a b. (a -> b) -> a -> b
$
Int
accs forall a. Num a => a -> a -> a
- Key -> Int -> Int
accidentals_at_pc Key
key Int
pc forall a. Num a => a -> a -> a
+ Key -> Int -> Int
accidentals_at_pc Key
key Int
pc2
Maybe Intervals
Nothing -> Key -> Int -> Pitch -> Pitch
transpose_chromatic
Key
key (Key -> Degree -> Int -> Int
chromatic_steps Key
key Degree
degree Int
steps) Pitch
pitch
where
(Int
oct2, Int
pc2) = (Int
pc forall a. Num a => a -> a -> a
+ Int
steps) forall a. Integral a => a -> a -> (a, a)
`divMod` Key -> Int
key_steps_per_octave Key
key
transpose_chromatic :: Key -> Pitch.Semi -> Pitch.Pitch -> Pitch.Pitch
transpose_chromatic :: Key -> Int -> Pitch -> Pitch
transpose_chromatic Key
key Int
steps Pitch
pitch
| Int
steps forall a. Eq a => a -> a -> Bool
== Int
0 = Pitch
pitch
| Bool
otherwise = Key -> Int -> Pitch
semis_to_pitch Key
key forall a b. (a -> b) -> a -> b
$ Layout -> Pitch -> Int
pitch_to_semis Layout
layout Pitch
pitch forall a. Num a => a -> a -> a
+ Int
steps
where layout :: Layout
layout = Key -> Layout
key_layout Key
key
pitch_to_semis :: Layout -> Pitch.Pitch -> Pitch.Semi
pitch_to_semis :: Layout -> Pitch -> Int
pitch_to_semis Layout
layout (Pitch.Pitch Int
oct Degree
degree) =
Int
oct forall a. Num a => a -> a -> a
* Layout -> Int
layout_semis_per_octave Layout
layout forall a. Num a => a -> a -> a
+ Layout -> Degree -> Int
degree_to_semis Layout
layout Degree
degree
degree_to_semis :: Layout -> Pitch.Degree -> Pitch.Semi
degree_to_semis :: Layout -> Degree -> Int
degree_to_semis Layout
layout (Pitch.Degree Int
pc_ Int
accs) =
forall a. Num a => Vector a -> a
Vector.sum (forall a. Int -> Vector a -> Vector a
Vector.take Int
pc (Layout -> Intervals
layout_intervals Layout
layout)) forall a. Num a => a -> a -> a
+ Int
accs
forall a. Num a => a -> a -> a
+ Int
oct forall a. Num a => a -> a -> a
* Layout -> Int
layout_semis_per_octave Layout
layout
where (Int
oct, Int
pc) = Int
pc_ forall a. Integral a => a -> a -> (a, a)
`divMod` Layout -> Int
layout_pc_per_octave Layout
layout
pick_enharmonic :: Key -> Pitch.Pitch -> Pitch.Pitch
pick_enharmonic :: Key -> Pitch -> Pitch
pick_enharmonic Key
key = Key -> Int -> Pitch
semis_to_pitch Key
key forall b c a. (b -> c) -> (a -> b) -> a -> c
. Layout -> Pitch -> Int
pitch_to_semis (Key -> Layout
key_layout Key
key)
semis_to_pitch :: Key -> Pitch.Semi -> Pitch.Pitch
semis_to_pitch :: Key -> Int -> Pitch
semis_to_pitch Key
key Int
semis = (Int, Degree) -> Pitch
mkpitch forall a b. (a -> b) -> a -> b
$ case Key -> Maybe Intervals
key_signature Key
key of
Just Intervals
sig -> case forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Maybe a
List.find (forall {a}. Intervals -> (a, Degree) -> Bool
in_scale Intervals
sig) [(Int, Degree)]
enharmonics of
Maybe (Int, Degree)
Nothing -> forall {a}. Num a => Bool -> [(a, Degree)] -> (a, Degree)
pick_enharmonic (forall {v :: * -> *} {a}. (Vector v a, Ord a, Num a) => v a -> Bool
sharp_signature Intervals
sig) [(Int, Degree)]
enharmonics
Just (Int, Degree)
pitch -> (Int, Degree)
pitch
Maybe Intervals
Nothing -> forall {a}. Num a => Bool -> [(a, Degree)] -> (a, Degree)
pick_enharmonic (Key -> Bool
sharp_tonic Key
key) [(Int, Degree)]
enharmonics
where
mkpitch :: (Int, Degree) -> Pitch
mkpitch (Int
oct, Degree
degree) = Int -> Degree -> Pitch
Pitch.Pitch (Int
octave forall a. Num a => a -> a -> a
+ Int
oct) Degree
degree
pick_enharmonic :: Bool -> [(a, Degree)] -> (a, Degree)
pick_enharmonic Bool
use_sharps [(a, Degree)]
notes = forall a. a -> Maybe a -> a
fromMaybe (a
0, Int -> Int -> Degree
Pitch.Degree (-Int
1) Int
0) forall a b. (a -> b) -> a -> b
$
forall k a. Ord k => (a -> k) -> [a] -> Maybe a
Lists.minimumOn (forall {b}. (Ord b, Num b) => b -> (Bool, b)
key forall b c a. (b -> c) -> (a -> b) -> a -> c
. Degree -> Int
Pitch.degree_accidentals forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a, b) -> b
snd) [(a, Degree)]
notes
where key :: b -> (Bool, b)
key b
accs = (if Bool
use_sharps then b
accs forall a. Ord a => a -> a -> Bool
< b
0 else b
accs forall a. Ord a => a -> a -> Bool
> b
0, forall a. Num a => a -> a
abs b
accs)
in_scale :: Intervals -> (a, Degree) -> Bool
in_scale Intervals
sig (a
_, Degree
degree) =
Intervals
sig forall a. Vector a -> Int -> Maybe a
Vector.!? Key -> Degree -> Int
step_of Key
key Degree
degree
forall a. Eq a => a -> a -> Bool
== forall a. a -> Maybe a
Just (Degree -> Int
Pitch.degree_accidentals Degree
degree)
enharmonics :: [(Int, Degree)]
enharmonics = forall a. a -> Maybe a -> a
fromMaybe [] forall a b. (a -> b) -> a -> b
$ Layout -> Vector [(Int, Degree)]
layout_enharmonics Layout
layout forall a. Vector a -> Int -> Maybe a
Boxed.!? Int
steps
(Int
octave, Int
steps) = Int
semis forall a. Integral a => a -> a -> (a, a)
`divMod` Layout -> Int
layout_semis_per_octave Layout
layout
layout :: Layout
layout = Key -> Layout
key_layout Key
key
sharp_signature :: v a -> Bool
sharp_signature v a
sig = forall (v :: * -> *) a. Vector v a => (a -> Bool) -> v a -> Int
Vector.count (forall a. Ord a => a -> a -> Bool
>a
0) v a
sig forall a. Ord a => a -> a -> Bool
>= forall (v :: * -> *) a. Vector v a => (a -> Bool) -> v a -> Int
Vector.count (forall a. Ord a => a -> a -> Bool
<a
0) v a
sig
sharp_tonic :: Key -> Bool
sharp_tonic = (forall a. Ord a => a -> a -> Bool
>=Int
0) forall b c a. (b -> c) -> (a -> b) -> a -> c
. Degree -> Int
Pitch.degree_accidentals forall b c a. (b -> c) -> (a -> b) -> a -> c
. Key -> Degree
key_tonic
semis_to_pitch_sharps :: Layout -> Pitch.Semi -> Pitch.Pitch
semis_to_pitch_sharps :: Layout -> Int -> Pitch
semis_to_pitch_sharps Layout
layout Int
semis = Int -> Degree -> Pitch
Pitch.Pitch (Int
octave forall a. Num a => a -> a -> a
+ Int
oct) Degree
degree
where
(Int
octave, Int
steps) = Int
semis forall a. Integral a => a -> a -> (a, a)
`divMod` Layout -> Int
layout_semis_per_octave Layout
layout
(Int
oct, Degree
degree) = forall a. [a] -> a
head forall a b. (a -> b) -> a -> b
$ Vector [(Int, Degree)]
enharmonics forall a. Vector a -> Int -> a
Boxed.! Int
steps
enharmonics :: Vector [(Int, Degree)]
enharmonics = Layout -> Vector [(Int, Degree)]
layout_enharmonics Layout
layout
semis_to_nn :: Pitch.Semi -> Int
semis_to_nn :: Int -> Int
semis_to_nn = (forall a. Num a => a -> a -> a
+Int
12)
fsemis_to_nn :: Pitch.FSemi -> Pitch.NoteNumber
fsemis_to_nn :: FSemi -> NoteNumber
fsemis_to_nn = FSemi -> NoteNumber
Pitch.NoteNumber forall b c a. (b -> c) -> (a -> b) -> a -> c
. (forall a. Num a => a -> a -> a
+FSemi
12)
nn_to_semis :: Int -> Pitch.Semi
nn_to_semis :: Int -> Int
nn_to_semis = forall a. Num a => a -> a -> a
subtract Int
12
enharmonics_of :: Layout -> Pitch.Pitch -> [Pitch.Pitch]
enharmonics_of :: Layout -> Pitch -> [Pitch]
enharmonics_of Layout
layout Pitch
pitch =
[ Int -> Degree -> Pitch
Pitch.Pitch (Pitch -> Int
Pitch.pitch_octave Pitch
pitch forall a. Num a => a -> a -> a
+ Int
oct) Degree
n
| (Int
oct, Degree
n) <-
Intervals -> Degree -> [(Int, Degree)]
get_enharmonics (Layout -> Intervals
layout_intervals Layout
layout) (Pitch -> Degree
Pitch.pitch_degree Pitch
pitch)
]
type Step = Int
data Key = Key {
Key -> Degree
key_tonic :: !Pitch.Degree
, Key -> Text
key_name :: !Text
, Key -> Intervals
key_intervals :: Intervals
, Key -> Maybe Intervals
key_signature :: Maybe Signature
, Key -> Intervals
key_transpose_table :: Intervals
, Key -> Layout
key_layout :: Layout
} deriving (Key -> Key -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Key -> Key -> Bool
$c/= :: Key -> Key -> Bool
== :: Key -> Key -> Bool
$c== :: Key -> Key -> Bool
Eq, Int -> Key -> ShowS
[Key] -> ShowS
Key -> [Char]
forall a.
(Int -> a -> ShowS) -> (a -> [Char]) -> ([a] -> ShowS) -> Show a
showList :: [Key] -> ShowS
$cshowList :: [Key] -> ShowS
show :: Key -> [Char]
$cshow :: Key -> [Char]
showsPrec :: Int -> Key -> ShowS
$cshowsPrec :: Int -> Key -> ShowS
Show)
type Signature = Vector.Vector Pitch.Accidentals
type Intervals = Vector.Vector Pitch.Semi
key :: Pitch.Degree -> Text -> [Pitch.Semi] -> Layout -> Key
key :: Degree -> Text -> [Int] -> Layout -> Key
key Degree
tonic Text
name [Int]
intervals Layout
layout = Key
{ key_tonic :: Degree
key_tonic = Degree
tonic
, key_name :: Text
key_name = Text
name
, key_intervals :: Intervals
key_intervals = Intervals
ints
, key_signature :: Maybe Intervals
key_signature = Degree -> Layout -> Intervals -> Maybe Intervals
generate_signature Degree
tonic Layout
layout Intervals
ints
, key_transpose_table :: Intervals
key_transpose_table = [Int] -> Intervals
make_table [Int]
intervals
, key_layout :: Layout
key_layout = Layout
layout
}
where ints :: Intervals
ints = forall a. [a] -> Vector a
Vector.fromList [Int]
intervals
make_table :: [Pitch.Semi] -> Intervals
make_table :: [Int] -> Intervals
make_table [Int]
intervals = forall a. [a] -> Vector a
Vector.fromList forall a b. (a -> b) -> a -> b
$
forall a. [a] -> [a]
reverse (forall a. Int -> [a] -> [a]
drop Int
1 (forall {a} {a}. Num a => (a -> a -> a) -> [a] -> [a]
make (-) (forall a. [a] -> [a]
reverse [Int]
intervals))) forall a. [a] -> [a] -> [a]
++ forall {a} {a}. Num a => (a -> a -> a) -> [a] -> [a]
make forall a. Num a => a -> a -> a
(+) [Int]
intervals
where make :: (a -> a -> a) -> [a] -> [a]
make a -> a -> a
f = forall a. Int -> [a] -> [a]
take (forall (t :: * -> *) a. Foldable t => t a -> Int
length [Int]
intervals forall a. Num a => a -> a -> a
* Int
2) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall b a. (b -> a -> b) -> b -> [a] -> [b]
scanl a -> a -> a
f a
0 forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. [a] -> [a]
cycle
generate_signature :: Pitch.Degree -> Layout -> Intervals -> Maybe Signature
generate_signature :: Degree -> Layout -> Intervals -> Maybe Intervals
generate_signature Degree
tonic Layout
layout Intervals
intervals
| forall a. Vector a -> Int
Vector.length (Layout -> Intervals
layout_intervals Layout
layout) forall a. Eq a => a -> a -> Bool
/= forall a. Vector a -> Int
Vector.length Intervals
intervals =
forall a. Maybe a
Nothing
| Bool
otherwise = forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$
Degree -> Intervals -> Intervals -> Intervals
calculate_signature Degree
tonic (Layout -> Intervals
layout_intervals Layout
layout) Intervals
intervals
calculate_signature :: Pitch.Degree -> Intervals -> Intervals -> Intervals
calculate_signature :: Degree -> Intervals -> Intervals -> Intervals
calculate_signature (Pitch.Degree Int
pc Int
accs) Intervals
layout Intervals
intervals =
forall a. Int -> Vector a -> Vector a
Vector.take (forall a. Vector a -> Int
Vector.length Intervals
intervals) forall a b. (a -> b) -> a -> b
$
forall a b c. (a -> b -> c) -> Vector a -> Vector b -> Vector c
Vector.zipWith forall a. Num a => a -> a -> a
subtract (forall a b. (a -> b -> a) -> a -> Vector b -> Vector a
Vector.scanl forall a. Num a => a -> a -> a
(+) Int
0 (forall a. Int -> Vector a -> Vector a
rotate Int
pc Intervals
layout))
(forall a b. (a -> b -> a) -> a -> Vector b -> Vector a
Vector.scanl forall a. Num a => a -> a -> a
(+) Int
accs Intervals
intervals)
where
rotate :: Int -> Vector a -> Vector a
rotate Int
n Vector a
xs = Vector a
post forall a. Semigroup a => a -> a -> a
<> Vector a
pre
where (Vector a
pre, Vector a
post) = forall a. Int -> Vector a -> (Vector a, Vector a)
Vector.splitAt Int
n Vector a
xs
key_is_diatonic :: Key -> Bool
key_is_diatonic :: Key -> Bool
key_is_diatonic = forall a. Maybe a -> Bool
Maybe.isJust forall b c a. (b -> c) -> (a -> b) -> a -> c
. Key -> Maybe Intervals
key_signature
instance Pretty Key where
format :: Key -> Doc
format key :: Key
key@(Key Degree
tonic Text
name Intervals
ints Maybe Intervals
sig Intervals
_table Layout
_layout) = Doc -> [(Text, Doc)] -> Doc
Pretty.record Doc
title
[ (Text
"intervals",
forall a. Pretty a => a -> Doc
Pretty.format (forall a. Int -> Vector a -> Vector a
Vector.take (Key -> Int
key_steps_per_octave Key
key) Intervals
ints))
, (Text
"signature", forall a. Pretty a => a -> Doc
Pretty.format Maybe Intervals
sig)
]
where
title :: Doc
title = Text -> Doc
Pretty.text Text
"Key" Doc -> Doc -> Doc
Pretty.<+> forall a. Pretty a => a -> Doc
Pretty.format Degree
tonic
Doc -> Doc -> Doc
Pretty.<+> Text -> Doc
Pretty.text Text
name
accidentals_at_pc :: Key -> Pitch.PitchClass -> Pitch.Accidentals
accidentals_at_pc :: Key -> Int -> Int
accidentals_at_pc Key
key Int
pc = forall a. a -> Maybe a -> a
fromMaybe Int
0 forall a b. (a -> b) -> a -> b
$ do
Intervals
sig <- Key -> Maybe Intervals
key_signature Key
key
Intervals
sig forall a. Vector a -> Int -> Maybe a
Vector.!? Key -> Int -> Int
diatonic_step_of Key
key Int
pc
key_steps_per_octave :: Key -> Step
key_steps_per_octave :: Key -> Int
key_steps_per_octave = forall a. Vector a -> Int
Vector.length forall b c a. (b -> c) -> (a -> b) -> a -> c
. Key -> Intervals
key_intervals
step_of :: Key -> Pitch.Degree -> Step
step_of :: Key -> Degree -> Int
step_of Key
key Degree
degree
| Key -> Bool
key_is_diatonic Key
key = Key -> Int -> Int
diatonic_step_of Key
key (Degree -> Int
Pitch.degree_pc Degree
degree)
| Bool
otherwise = forall (v :: * -> *). Vector v Int => Int -> v Int -> Int
Vector.find_before Int
semis (Key -> Intervals
key_intervals Key
key)
where semis :: Int
semis = Layout -> Degree -> Int
degree_to_semis (Key -> Layout
key_layout Key
key) Degree
degree
diatonic_step_of :: Key -> Pitch.PitchClass -> Step
diatonic_step_of :: Key -> Int -> Int
diatonic_step_of Key
key Int
pc =
(Int
pc forall a. Num a => a -> a -> a
- Degree -> Int
Pitch.degree_pc (Key -> Degree
key_tonic Key
key)) forall a. Integral a => a -> a -> a
`mod` Key -> Int
key_steps_per_octave Key
key
data Layout = Layout {
Layout -> Intervals
layout_intervals :: !Intervals
, Layout -> Vector [(Int, Degree)]
layout_enharmonics :: !(Boxed.Vector [(Pitch.Octave, Pitch.Degree)])
} deriving (Layout -> Layout -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Layout -> Layout -> Bool
$c/= :: Layout -> Layout -> Bool
== :: Layout -> Layout -> Bool
$c== :: Layout -> Layout -> Bool
Eq, Int -> Layout -> ShowS
[Layout] -> ShowS
Layout -> [Char]
forall a.
(Int -> a -> ShowS) -> (a -> [Char]) -> ([a] -> ShowS) -> Show a
showList :: [Layout] -> ShowS
$cshowList :: [Layout] -> ShowS
show :: Layout -> [Char]
$cshow :: Layout -> [Char]
showsPrec :: Int -> Layout -> ShowS
$cshowsPrec :: Int -> Layout -> ShowS
Show)
layout_semis_per_octave :: Layout -> Pitch.Semi
layout_semis_per_octave :: Layout -> Int
layout_semis_per_octave = forall a. Num a => Vector a -> a
Vector.sum forall b c a. (b -> c) -> (a -> b) -> a -> c
. Layout -> Intervals
layout_intervals
layout_pc_per_octave :: Layout -> Pitch.PitchClass
layout_pc_per_octave :: Layout -> Int
layout_pc_per_octave = forall a. Vector a -> Int
Vector.length forall b c a. (b -> c) -> (a -> b) -> a -> c
. Layout -> Intervals
layout_intervals
layout :: [Pitch.Semi] -> Layout
layout :: [Int] -> Layout
layout [Int]
intervals = Layout
{ layout_intervals :: Intervals
layout_intervals = Intervals
vec
, layout_enharmonics :: Vector [(Int, Degree)]
layout_enharmonics = forall a. [a] -> Vector a
Boxed.fromList forall a b. (a -> b) -> a -> b
$
forall a b. (a -> b) -> [a] -> [b]
map (\Degree
n -> (Int
0, Degree
n) forall a. a -> [a] -> [a]
: Intervals -> Degree -> [(Int, Degree)]
get_enharmonics Intervals
vec Degree
n) [Degree]
notes
}
where
vec :: Intervals
vec = forall a. [a] -> Vector a
Vector.fromList [Int]
intervals
notes :: [Degree]
notes =
[ Int -> Int -> Degree
Pitch.Degree Int
pc Int
accs
| (Int
pc, Int
int) <- forall a b. [a] -> [b] -> [(a, b)]
zip [Int
0..] [Int]
intervals, Int
accs <- [Int
0..Int
intforall a. Num a => a -> a -> a
-Int
1]
]
get_enharmonics :: Intervals -> Pitch.Degree -> [(Pitch.Octave, Pitch.Degree)]
get_enharmonics :: Intervals -> Degree -> [(Int, Degree)]
get_enharmonics Intervals
intervals (Pitch.Degree Int
note_pc Int
note_accs) =
[ forall {a}. Vector a -> Int -> Int -> (Int, Degree)
mknote Intervals
intervals (Int
note_pc forall a. Num a => a -> a -> a
+ Int
pc) (Int
note_accs forall a. Num a => a -> a -> a
+ Int
accs)
| (Int
pc, Int
accs) <- [(Int, Int)]
pcs, forall a. Num a => a -> a
abs (Int
note_accs forall a. Num a => a -> a -> a
+ Int
accs) forall a. Ord a => a -> a -> Bool
< Int
3
]
where
pcs :: [(Int, Int)]
pcs =
[ (Int
1, -[Int] -> Int
diffs [Int
0])
, (Int
2, -[Int] -> Int
diffs [Int
0, Int
1])
, (-Int
2, [Int] -> Int
diffs [-Int
2, -Int
1])
, (-Int
1, [Int] -> Int
diffs [-Int
1])
]
diffs :: [Int] -> Int
diffs = forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
Num.sum forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map (Intervals -> Int -> Int
layout_at Intervals
intervals forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Int
note_pc+))
mknote :: Vector a -> Int -> Int -> (Int, Degree)
mknote Vector a
intervals Int
pc Int
accs = (Int
oct, Int -> Int -> Degree
Pitch.Degree Int
pc2 Int
accs)
where (Int
oct, Int
pc2) = Int
pc forall a. Integral a => a -> a -> (a, a)
`divMod` forall a. Vector a -> Int
Vector.length Vector a
intervals
layout_at :: Intervals -> Pitch.PitchClass -> Pitch.Accidentals
layout_at :: Intervals -> Int -> Int
layout_at Intervals
intervals Int
pc =
forall a. a -> Maybe a -> a
fromMaybe Int
0 forall a b. (a -> b) -> a -> b
$ Intervals
intervals forall a. Vector a -> Int -> Maybe a
Vector.!? (Int
pc forall a. Integral a => a -> a -> a
`mod` forall a. Vector a -> Int
Vector.length Intervals
intervals)
contains_degree :: Intervals -> Pitch.Degree -> Bool
contains_degree :: Intervals -> Degree -> Bool
contains_degree Intervals
intervals (Pitch.Degree Int
pc Int
acc)
| Int
acc forall a. Ord a => a -> a -> Bool
>= Int
0 = Int
acc forall a. Ord a => a -> a -> Bool
< Intervals -> Int -> Int
layout_at Intervals
intervals Int
pc
| Bool
otherwise = Intervals -> Int -> Int
layout_at Intervals
intervals (Int
pc forall a. Num a => a -> a -> a
- Int
1) forall a. Num a => a -> a -> a
+ Int
acc forall a. Ord a => a -> a -> Bool
> Int
0